• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kgoldrunner

kgrfigure.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                      kgrfigure.cpp  -  description                      *
00003  *                           -------------------                           *
00004  *    Copyright 2003 Marco Krüger <grisuji@gmx.de>                         *
00005  *    Copyright 2003 Ian Wadham <ianw2@optusnet.com.au>                    *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  ***************************************************************************/
00012 
00013 /*
00014  * Many thanks to Kevin Krammer and Alex Sopicki for translating the
00015  * original comments in this program code from German into English.
00016  */
00017 
00018 #include "kgrfigure.h"
00019 
00020 #include "kgrconsts.h"
00021 #include "kgrobject.h"
00022 #include "kgrcanvas.h"
00023 
00024 #include <stdio.h>
00025 #include <QList>
00026 
00027 KGrFigure::KGrFigure (int px, int py) : direction (RIGHT)
00028 {
00029     x = mem_x = px;
00030     y = mem_y = py;
00031     relx = mem_relx = 0;
00032     rely = mem_rely = 0;
00033 
00034     absx = px*16;
00035     absy = py*16;
00036 
00037     nuggets = 0;
00038     status = STANDING;
00039 
00040     walkTimer = new QTimer (this);
00041     fallTimer = new QTimer (this);
00042 }
00043 
00044 // Initialise the global settings flags.
00045 bool           KGrFigure::variableTiming = true;
00046 bool           KGrFigure::alwaysCollectNugget    = true;
00047 bool           KGrFigure::runThruHole    = true;
00048 bool           KGrFigure::reappearAtTop  = true;
00049 SearchStrategy KGrFigure::searchStrategy = LOW;
00050 
00051 int KGrFigure::herox = 0;
00052 int KGrFigure::heroy = 0;
00053 
00054 // Initialise the global game-speed factors.
00055 int KGrFigure::speed = NSPEED;
00056 int KGrBrick::speed  = NSPEED;
00057 
00058 // Initialise constants for fixed (KGoldrunner) and variable (Traditional)
00059 // timing.  Each row contains timings for hero walk and fall, enemy walk and
00060 // fall, enemy captured in hole and dug brick.
00061 
00062 Timing KGrFigure::fixedTiming = {45, 50, 55, 100, 500, 40}; // KGr original.
00063 
00064 Timing KGrFigure::varTiming[6] = {              // Traditional.
00065                                 {40, 58, 78, 88, 170, 23},  // No enemies.
00066                                 {50, 68, 78, 88, 170, 32},  // 1 enemy.
00067                                 {57, 67, 114, 128, 270, 37},    // 2 enemies.
00068                                 {60, 70, 134, 136, 330, 40},    // 3 enemies.
00069                                 {63, 76, 165, 150, 400, 46},    // 4 enemies.
00070                                 {70, 80, 189, 165, 460, 51} // >4 enemies.
00071 };
00072 
00073 int KGrBrick::HOLETIME = 0;
00074 
00075 int KGrFigure::getx()
00076 {
00077     return absx;
00078 }
00079 
00080 int KGrFigure::gety()
00081 {
00082     return absy;
00083 }
00084 
00085 Status KGrFigure::getStatus()
00086 {
00087     return status;
00088 }
00089 
00090 void KGrFigure::init (int a,int b)
00091 {
00092     walkTimer->stop();
00093     fallTimer->stop();
00094     x = mem_x = a;
00095     y = mem_y = b;
00096     relx = mem_relx = 0;
00097     rely = mem_rely = 0;
00098     nuggets = 0;
00099     status = STANDING;
00100 }
00101 
00102 void KGrFigure:: setNuggets (int n)
00103 {
00104     nuggets = n;
00105 }
00106 
00107 
00108 bool KGrFigure::canWalkRight()
00109 {
00110     return (((*playfield)[x+1][y]->whatIam() != BRICK) &&
00111             ((*playfield)[x+1][y]->whatIam() != BETON) &&
00112             ((*playfield)[x+1][y]->whatIam() != FBRICK));
00113 }
00114 
00115 bool KGrFigure::canWalkLeft()
00116 {
00117     return (((*playfield)[x-1][y]->whatIam() != BRICK) &&
00118             ((*playfield)[x-1][y]->whatIam() != BETON) &&
00119             ((*playfield)[x-1][y]->whatIam() != FBRICK));
00120 }
00121 
00122 bool KGrFigure::canWalkUp()
00123 {
00124     return (((*playfield)[x][y-1]->whatIam() != BRICK) &&
00125             ((*playfield)[x][y-1]->whatIam() != BETON) &&
00126             ((*playfield)[x][y-1]->whatIam() != FBRICK) &&
00127             ((*playfield)[x][y]->whatIam() == LADDER));
00128 }
00129 
00130 bool KGrFigure::canWalkDown()
00131 {
00132     return (((*playfield)[x][y+1]->whatIam() != BRICK) &&
00133             ((*playfield)[x][y+1]->whatIam() != BETON) &&
00134             // v0.3 FIX - Let figure step down into FBRICK from a ladder.
00135             //    ((*playfield)[x][y+1]->whatIam() != FBRICK)&&
00136             (((*playfield)[x][y+1]->whatIam() == LADDER)||
00137              ((*playfield)[x][y]->whatIam() == LADDER)));
00138 }
00139 
00140 bool KGrFigure::canStand()
00141 {
00142     return (((*playfield)[x][y+1]->whatIam() == BRICK) ||
00143             ((*playfield)[x][y+1]->whatIam() == BETON) ||
00144             ((*playfield)[x][y+1]->whatIam() == USEDHOLE)||
00145             ((*playfield)[x][y+1]->whatIam() == LADDER)||
00146             ((*playfield)[x][y]->whatIam() == LADDER)||
00147             standOnEnemy());
00148 }
00149 
00150 bool KGrFigure::hangAtPole()
00151 {
00152     return ((*playfield)[x][y]->whatIam() == POLE);
00153 }
00154 
00155 void KGrFigure::walkUp (int WALKDELAY)
00156 {
00157     actualPixmap = (actualPixmap == CLIMB1) ? CLIMB2 : CLIMB1;
00158     if (actualPixmap == CLIMB1) {
00159         emit stepDone (true);
00160     }
00161     if (walkCounter++ < gameCycle) {
00162         // Not end of 4-step cycle: move one step up, if possible.
00163         if (canWalkUp()) {
00164             rely -= STEP;
00165             absy -= STEP;
00166         }
00167         walkTimer->setSingleShot (true);
00168         walkTimer->start ((WALKDELAY * NSPEED) / speed);
00169     }
00170     else {
00171         // End of 4-step cycle: move up to next cell, if possible.
00172         if (canWalkUp()) {
00173             y--;
00174         }
00175         // Always reset position, in case we are stuck partly into a brick.
00176         rely = 0;
00177         absy = y*16;
00178 
00179         // Wait for caller to set next direction.
00180         status = STANDING;
00181     }
00182 }
00183 
00184 void KGrFigure::walkDown (int WALKDELAY, int FALLDELAY)
00185 {
00186     if (hangAtPole() || (! canStand())) {
00187         // On bar or no firm ground underneath: so must fall.
00188         initFall (FALL2, FALLDELAY);
00189     }
00190     else {
00191         actualPixmap = (actualPixmap == CLIMB1) ? CLIMB2 : CLIMB1;
00192     if (actualPixmap == CLIMB1) {
00193             emit stepDone (true);
00194     }
00195         if (walkCounter++ < gameCycle) {
00196             // Not end of 4-step cycle: move one step down, if possible.
00197             if (canWalkDown()) {
00198                 rely += STEP;
00199                 absy += STEP;
00200             }
00201             walkTimer->setSingleShot (true);
00202             walkTimer->start ((WALKDELAY * NSPEED) / speed);
00203         }
00204         else {
00205             // End of 4-step cycle: move down to next cell, if possible.
00206             if (canWalkDown()) {
00207                 y++;
00208             }
00209             // Always reset position, in case we are stuck partly into a brick.
00210             rely = 0;
00211             absy = y*16;
00212 
00213             // Must be able to halt at a pole when going down.
00214             if (! (canStand() || hangAtPole()))
00215                 initFall (FALL2, FALLDELAY);    // Nothing to hold: so fall.
00216             else
00217                 // Wait for caller to set next direction.
00218                 status = STANDING;
00219         }
00220     }
00221 }
00222 
00223 void KGrFigure::walkLeft (int WALKDELAY, int FALLDELAY)
00224 {
00225     // If counter != 0, the figure is walking, otherwise he is turning around.
00226     if (walkCounter++ != 0) {
00227         // Change to the next pixmap in the animation.
00228         if ((++actualPixmap % gameCycle) != 0) {
00229             // Not end of 4-pixmap cycle: move one step left, if possible.
00230             if (canWalkLeft()) {
00231                 relx -= STEP;
00232                 absx -=STEP;
00233             }
00234             walkTimer->setSingleShot (true);
00235             walkTimer->start ((WALKDELAY * NSPEED) / speed);
00236         }
00237         else {
00238             // Check if we are half way through the 8-frame graphics cycle.
00239             alternateStepGraphics = true;
00240             if ((actualPixmap % graphicsCycle) == 0) {
00241                 alternateStepGraphics = false;  // Finished the 8-frame cycle.
00242                 actualPixmap -= graphicsCycle;  // Repeat it.
00243             }
00244 
00245             if (canWalkLeft()) {
00246                 x--;
00247             }
00248             // Always reset position, in case we are stuck partly into a brick.
00249             relx = 0;
00250             absx = x*16;
00251 
00252         int frame = actualPixmap % graphicsCycle;
00253         if ((frame == 0) || (frame == 4)) {
00254                 emit stepDone(hangAtPole());
00255         }
00256             // If cannot stand or hang, start fall, else await next assignment.
00257             if (! (canStand() || hangAtPole()))
00258                 initFall (FALL1, FALLDELAY);
00259             else
00260                 status = STANDING;  // Caller should set next direction.
00261         }
00262     }
00263     else {
00264         status = STANDING;      // The figure is turning around.
00265     }
00266 }
00267 
00268 void KGrFigure::walkRight (int WALKDELAY, int FALLDELAY)
00269 {
00270     if (walkCounter++) {        // If 0, just turn the figure around.
00271         if ((++actualPixmap % gameCycle) != 0)  {
00272             // The 4-frame cycle per playfield tile is incomplete.
00273             if (canWalkRight()) {   // Move right, if it's possible.
00274                 relx += STEP;
00275                 absx += STEP;
00276             }
00277             walkTimer->setSingleShot (true);
00278             walkTimer->start ((WALKDELAY * NSPEED) / speed);
00279         }
00280         else {
00281             // Check if we are half way through the 8-frame graphics cycle.
00282             alternateStepGraphics = true;
00283             if ((actualPixmap % graphicsCycle) == 0) {
00284                 alternateStepGraphics = false;  // Finished the 8-frame cycle.
00285                 actualPixmap -= graphicsCycle;  // Repeat it.
00286             }
00287 
00288             if (canWalkRight()) {
00289                 x++;
00290             }               // Set the figure's new position.
00291             // Always reset position, in case we are stuck partly into a brick.
00292             relx = 0;
00293             absx = x*16;
00294         int frame = actualPixmap % graphicsCycle;
00295         if ((frame == 0) || (frame == 4)) {
00296                 emit stepDone(hangAtPole());
00297         }
00298 
00299             if (!(canStand()||hangAtPole())) // Cannot hold on: so fall.
00300                 initFall (FALL2, FALLDELAY);
00301             else
00302                 status = STANDING;       // Else, stand.
00303         }
00304     }
00305     else {
00306         status = STANDING;      // Just turn the figure around.
00307     }
00308 }
00309 
00310 void KGrFigure::initFall (int apm, int FALLDELAY)
00311 {
00312     emit falling (true);
00313     status = FALLING;
00314     actualPixmap = apm;
00315     walkCounter=1;
00316     walkTimer->stop();
00317     fallTimer->setSingleShot (true);
00318     fallTimer->start ((FALLDELAY * NSPEED) / speed);
00319 }
00320 
00321 void KGrFigure::showFigure()
00322 {
00323 }
00324 
00325 void KGrFigure::setPlayfield (KGrObject * (*p)[30][22])
00326 {
00327     playfield = p;
00328 }
00329 
00330 KGrFigure::~KGrFigure()
00331 {
00332 }
00333 
00334 KGrHero::KGrHero (KGrCanvas * view, int x, int y)
00335     :KGrFigure (x, y)
00336 {
00337     heroView = view;
00338     status = STANDING;
00339     actualPixmap = FALL1;
00340 
00341     herox = x;
00342     heroy = y;
00343 
00344     started = false;
00345     mouseMode = true;
00346     walkCounter = 1;
00347 
00348     walkFrozen = false;
00349     fallFrozen = false;
00350     alternateStepGraphics = false;
00351 
00352     connect (walkTimer, SIGNAL (timeout()), SLOT (walkTimeDone()));
00353     connect (fallTimer, SIGNAL (timeout()), SLOT (fallTimeDone()));
00354 }
00355 
00356 int KGrHero::WALKDELAY = 0;
00357 int KGrHero::FALLDELAY = 0;
00358 
00359 /* It is necessary to execute startWalk before the timer-function code, in order
00360     to take changes of direction into account when doing the animation steps.
00361 */
00362 void KGrHero::startWalk()
00363 {
00364     switch (nextDir) {
00365         case UP:
00366             if ((*playfield)[x][y]->whatIam() == LADDER) {
00367                 walkCounter = 1;
00368                 direction = UP;
00369             }
00370             break;
00371         case RIGHT:
00372             if (hangAtPole()) 
00373                 actualPixmap = (alternateStepGraphics)? RIGHTCLIMB5:RIGHTCLIMB1;
00374             else 
00375                 actualPixmap = (alternateStepGraphics)? RIGHTWALK5 : RIGHTWALK1;
00376             if (direction != RIGHT)
00377                 walkCounter = 0;
00378             else
00379                 walkCounter = 1;
00380             direction = RIGHT;
00381             break;
00382         case DOWN:
00383             if (((*playfield)[x][y]->whatIam() == LADDER)||
00384                 ((*playfield)[x][y+1]->whatIam() == LADDER))
00385             {walkCounter = 1;
00386             direction = DOWN;}
00387         else            // If the hero is hanging from a pole and there
00388                                   // is nothing to stand on, let him fall.
00389             if (hangAtPole() && (!canStand())) {
00390                 status = STANDING;
00391                 actualPixmap = (direction==RIGHT) ? FALL2 : FALL1;
00392                 walkCounter = 1;
00393                 direction = STAND;
00394                 walkTimer->stop();
00395             }
00396             break;
00397         case LEFT:
00398             if (hangAtPole())
00399                 actualPixmap = (alternateStepGraphics)? LEFTCLIMB5 : LEFTCLIMB1;
00400             else
00401                 actualPixmap = (alternateStepGraphics)? LEFTWALK5 : LEFTWALK1;
00402             if (direction != LEFT)
00403                 walkCounter = 0;
00404             else
00405                 walkCounter = 1;
00406             direction = LEFT;
00407             break;
00408         default :
00409             direction = STAND;
00410             status = FALLING;
00411             break;
00412     }
00413     nextDir = STAND;
00414     if (status != FALLING) {    // Always execute, unless we are falling, in
00415         status = WALKING;   // which case the state change would be wrong
00416         showFigure();       // and the wrong timer would be triggered.
00417     }
00418 } // END KGrHero::startWalk
00419 
00420 void KGrHero::setKey (Direction key)
00421 {
00422     // Keyboard control of hero: direction is fixed until next key is pressed.
00423     // Sets a simulated mouse-pointer above, below, left, right or on the hero.
00424     mouseMode = false;
00425     stopped = false;
00426     switch (key) {
00427     case UP:    mousex = x; mousey = 0; break;
00428     case DOWN:  mousex = x; mousey = FIELDHEIGHT + 1; break;
00429     case LEFT:  mousex = 0; mousey = y; break;
00430     case RIGHT: mousex = FIELDWIDTH + 1; mousey = y; break;
00431     case STAND: stopped = true;  mousex = x; mousey = y; break;
00432     }
00433 }
00434 
00435 void KGrHero::setDirection (int i, int j)
00436 {
00437     // Mouse control of hero: direction is updated continually on a timer.
00438     mouseMode = true;
00439     stopped = false;
00440     mousex = i;
00441     mousey = j;
00442 }
00443 
00444 void KGrHero::setNextDir()
00445 {
00446     int dx, dy;
00447 
00448     if (! mouseMode) {
00449         // Keyboard control of hero: adjust simulated mouse-pointer.
00450         if (stopped) {
00451             mousex = x;
00452             mousey = y;
00453         }
00454         if ((mousey < 1) || (mousey > FIELDHEIGHT)) {
00455             mousex = x;     // Stay directly above/below the hero.
00456         }
00457         else if ((mousex < 1) || (mousex > FIELDWIDTH)) {
00458             mousey = y;     // Stay directly left/right of the hero.
00459         }
00460     }
00461 
00462     dx = mousex - x; dy = mousey - y;
00463 
00464     if ((dy == 0) && (y == 1) && (nuggets <= 0)) {
00465         nextDir = UP;
00466     }
00467     else if ((dy > 0) &&
00468              (canWalkDown() ||
00469               // Permanent fix.  Removing the next test makes enemies
00470               // behave like bricks if you are standing, walking or falling on
00471               // their heads.  So you cannot die when walking over a trapped
00472               // enemy in mouse-mode, preventing a common beginner's problem.
00473               // standOnEnemy() ||  // Removed, 10 Aug 07.
00474               (hangAtPole() && ((*playfield)[x][y+1]->whatIam() != BRICK) &&
00475                                ((*playfield)[x][y+1]->whatIam() != BETON)))) {
00476         nextDir = DOWN;
00477     }
00478     else if ((dy < 0) && canWalkUp()) {
00479         nextDir = UP;
00480     }
00481     else if (dx > 0) {
00482         nextDir = RIGHT;
00483     }
00484     else if (dx < 0) {
00485         nextDir = LEFT;
00486     }
00487     else if (dx == 0) {
00488         nextDir = STAND;
00489     }
00490 }
00491 
00492 void KGrHero::doStep() {
00493     if (walkFrozen) {
00494         walkFrozen = false;
00495         walkTimeDone();
00496     }
00497     if (fallFrozen) {
00498         fallFrozen = false;
00499         fallTimeDone();
00500     }
00501 }
00502 
00503 void KGrHero::showState (char option)
00504 {
00505     printf ("(%02d,%02d) - Hero      ", x, y);
00506     switch (option) {
00507         case 'p': printf ("\n"); break;
00508         case 's': printf (" nuggets %02d status %d walk-ctr %d ",
00509                           nuggets, status, walkCounter);
00510             printf ("dirn %d next dirn %d\n", direction, nextDir);
00511             printf ("                     rel (%02d,%02d) abs (%03d,%03d)",
00512                         relx, rely, absx, absy);
00513             printf (" pix %02d", actualPixmap);
00514             printf (" mem %d %d %d %d", mem_x, mem_y, mem_relx, mem_rely);
00515             if (walkFrozen) printf (" wBlock");
00516             if (fallFrozen) printf (" fBlock");
00517             printf ("\n");
00518             break;
00519     }
00520 }
00521 
00522 void KGrHero::init (int a,int b)
00523 {
00524     walkTimer->stop();
00525     fallTimer->stop();
00526     walkCounter = 1;
00527     started = false;
00528 
00529     x = mem_x = a;
00530     y = mem_y = b;
00531     relx = mem_relx = 0;
00532     rely = mem_rely = 0;
00533 
00534     absx = 16*x;
00535     absy = 16*y;
00536 
00537     nuggets = 0;
00538 
00539     if (herox < 1) {                // If first call to init, ...
00540         heroView->makeHeroSprite (x, y, actualPixmap);
00541     }
00542     herox = x;
00543     heroy = y;
00544 
00545     actualPixmap = FALL2;
00546     heroView->moveHero (absx, absy, actualPixmap);
00547 }
00548 
00549 void KGrHero::start()
00550 {
00551     started = true;
00552     walkFrozen = false;
00553     fallFrozen = false;
00554 
00555     if (!(canStand()||hangAtPole())) {      // Hero must fall ...
00556         status = FALLING;
00557         fallTimeDone();
00558     }
00559     else {
00560         status = STANDING;
00561         walkTimeDone();
00562     }
00563 }
00564 
00565 void KGrHero::setSpeed (int gamespeed)
00566 {
00567     if (gamespeed >= 0) {
00568         if (gamespeed < MINSPEED)
00569             speed++;        // Increase speed.
00570         else
00571             speed = gamespeed;  // Set selected speed.
00572         if (speed > MAXSPEED)
00573             speed = MAXSPEED;   // Set upper limit.
00574     }
00575     else {
00576         speed--;            // Reduce speed.
00577         if (speed < MINSPEED)
00578             speed = MINSPEED;   // Set lower limit.
00579     }
00580     
00581     KGrBrick::speed = speed;    // Make a copy for bricks.
00582 }
00583     
00584 void KGrHero::walkTimeDone()
00585 {
00586     if (! started) return;  // Ignore signals from earlier play.
00587     if (KGrObject::frozen) {
00588         walkFrozen = true;
00589         return;
00590     }
00591 
00592     if ((*playfield)[x][y]->whatIam() == BRICK) {
00593         emit caughtHero();  // Brick closed over hero.
00594         return;
00595     }
00596 
00597     if ((y == 1) && (nuggets <= 0)) {// If on top row and all nuggets collected,
00598         emit leaveLevel();  // the hero has won and can go to next level.
00599         return;
00600     }
00601 
00602     if (status == STANDING)
00603         setNextDir();
00604     if ((status == STANDING) && (nextDir != STAND)) {
00605         if ((standOnEnemy()) && (nextDir == DOWN)) {
00606             emit caughtHero();  // Hero is going to step down into an enemy.
00607             return;
00608         }
00609         startWalk();
00610     }
00611     if (status != STANDING) {
00612         switch (direction) {
00613         case UP:        walkUp (WALKDELAY); break;
00614         case DOWN:  walkDown (WALKDELAY, FALLDELAY); break;
00615         case RIGHT: walkRight (WALKDELAY, FALLDELAY); break;
00616         case LEFT:  walkLeft (WALKDELAY, FALLDELAY); break;
00617         default :
00618         // The following code is strange.  It makes the hero fall off a pole.
00619         // It works because of other strange code in "startWalk(), case DOWN:".
00620             if (!canStand() || hangAtPole()) // falling
00621                 initFall (FALL1, FALLDELAY);
00622             else  status = STANDING;
00623         break;
00624         }
00625         herox=x; heroy=y;       // Set the hero's new position.
00626         if ((relx==0)&&(rely==0)) { // If he has just completed a move, see
00627             collectNugget();        // if there is a nugget to collect.
00628         }
00629     }
00630     if (status == STANDING)
00631         if (!canStand()&&!hangAtPole())
00632             initFall (FALL1, FALLDELAY);
00633         else {
00634             walkTimer->setSingleShot (true);
00635             walkTimer->start ((WALKDELAY * NSPEED) / speed);
00636         }
00637     
00638     // This additional showFigure() is to update the hero position after it is
00639     // altered by the hero-enemy deadlock fix in standOnEnemy().  Messy, but ...
00641     showFigure();
00642     if (isInEnemy()) {
00643         walkTimer->stop();
00644         emit caughtHero();
00645     }
00646 }
00647     
00648 void KGrHero::fallTimeDone()
00649 {
00650     if (! started) return;      // Ignore signals from earlier play.
00651     if (KGrObject::frozen) {
00652         fallFrozen = true;
00653         return;
00654     }
00655 
00656     if (!standOnEnemy()) {
00657         if (walkCounter++ < gameCycle) {// The hero must fall four steps.
00658             fallTimer->setSingleShot (true);
00659             fallTimer->start ((FALLDELAY * NSPEED) / speed);
00660             rely+=STEP;
00661             absy+=STEP;
00662         }
00663         else {              // When done, move to the start position
00664                                         // of the next object (brick, etc.).
00665             heroy = ++y;
00666             rely = 0;
00667             absy = y*16;
00668             collectNugget();        // See if there is a nugget to collect.
00669             if (! (canStand()||hangAtPole())) { // The hero goes on falling.
00670                 fallTimer->setSingleShot (true);
00671                 fallTimer->start ((FALLDELAY * NSPEED) / speed);
00672                 walkCounter = 1;
00673             }
00674             else {          // The hero can stand or hang on a pole,
00675                 status = STANDING;  // so change his state to STANDING.
00676                 walkTimer->setSingleShot (true);
00677                 walkTimer->start ((WALKDELAY * NSPEED) / speed);
00678                 direction = (actualPixmap == FALL2) ? RIGHT : LEFT;
00679                 if ((*playfield)[x][y]->whatIam() == POLE)
00680                     actualPixmap = (direction == RIGHT)? RIGHTCLIMB1:LEFTCLIMB1;
00681                 // else
00682                     // Reduce jerkiness when descending over a falling enemy.
00683                     // actualPixmap = (direction==RIGHT)? RIGHTWALK1:LEFTWALK1;
00684             }
00685         }
00686         showFigure();
00687     }
00688     else {
00689         if (rely == 0) {
00690             // If at the bottom of a cell, try to walk or just stand still.
00691             status = STANDING;
00692             direction = (actualPixmap == FALL2) ? RIGHT : LEFT;
00693             if ((*playfield)[x][y]->whatIam() == POLE)
00694                 actualPixmap = (direction == RIGHT)? RIGHTCLIMB1:LEFTCLIMB1;
00695             // else
00696                 // Reduce jerkiness when descending over a falling enemy.
00697                 // actualPixmap = (direction == RIGHT)? RIGHTWALK1:LEFTWALK1;
00698             walkTimer->setSingleShot (true);
00699             walkTimer->start ((WALKDELAY * NSPEED) / speed);
00700         }
00701         else {
00702             // Else, freeze hero until enemy moves out of the way.
00703             fallTimer->setSingleShot (true);
00704             fallTimer->start ((FALLDELAY * NSPEED) / speed);
00705         }
00706     }
00707     if (status != FALLING) {
00708         emit falling (false);
00709     }
00710     if (isInEnemy() && (! standOnEnemy()))
00711         emit caughtHero();
00712 }
00713 
00714 
00715 void KGrHero::showFigure() {
00716 
00717     heroView->moveHero (absx, absy, actualPixmap);
00718 
00719     // Save old values for when we delete the figure from its old position later.
00720     mem_x = x;
00721     mem_y = y;
00722     mem_relx = relx;
00723     mem_rely = rely;
00724 }
00725 
00726 void KGrHero::dig()
00727 {
00728     if (direction == LEFT)
00729         digLeft();
00730     else if (direction == RIGHT)
00731         digRight();
00732 }
00733         
00734 void KGrHero::digLeft()
00735 {
00736     int i = 1;      // If stationary or moving up/down, dig at x-1.
00737     if (status == STANDING)
00738         setNextDir();
00739     if ((status == WALKING) ||
00740         ((status == STANDING) && ((nextDir == LEFT) || (nextDir == RIGHT)))) {
00741         if ((direction == LEFT) && canWalkLeft())
00742             i = 2;  // If walking left, dig at x-2 and stop at x-1.
00743         else if ((direction == RIGHT) && canWalkRight())
00744             i = 0;  // If walking right, dig at x and stop at x+1.
00745     }
00746     int tileType = (*playfield)[x - i][y + 1]->whatIam();
00747     int tile2Type = (*playfield)[x - i][y]->whatIam();
00748     if ((tileType == BRICK) &&
00749         ((tile2Type == HLADDER) || (tile2Type == FREE) || (tile2Type == HOLE))) {
00750         ((KGrBrick*)(*playfield)[x-i][y+1])->dig();
00751         emit digs();
00752     }
00753 }
00754 
00755 void KGrHero::digRight()
00756 {
00757     int i = 1;      // If stationary or moving up/down, dig at x+1.
00758     if (status == STANDING)
00759         setNextDir();
00760     if ((status == WALKING) ||
00761         ((status == STANDING) && ((nextDir == LEFT) || (nextDir == RIGHT)))) {
00762         if ((direction == LEFT) && canWalkLeft())
00763             i = 0;  // If walking left, dig at x and stop at x-1.
00764         else if ((direction == RIGHT) && canWalkRight())
00765             i = 2;  // If walking right, dig at x+2 and stop at x+1.
00766     }
00767     int tileType = (*playfield)[x + i][y + 1]->whatIam();
00768     int tile2Type = (*playfield)[x + i][y]->whatIam();
00769     if ((tileType == BRICK) &&
00770         ((tile2Type == HLADDER) || (tile2Type == FREE) || (tile2Type == HOLE))) {
00771         ((KGrBrick*)(*playfield)[x+i][y+1])->dig();
00772         emit digs();
00773     }
00774 }
00775 
00776 void KGrHero::setEnemyList (QList<KGrEnemy *> * e)
00777 {
00778     enemies = e;
00779 }
00780 
00781 bool KGrHero::standOnEnemy()
00782 {
00783     int c = 0;
00784     int range = enemies->count();
00785     if (range > 0) {
00786         for (KGrEnemy * enemy = enemies->at (c); c < range;) {
00787             enemy = enemies->at (c++);
00788             // Test if hero's foot is at or just below enemy's head (tolerance
00789             // of 4 pixels) and the two figures overlap in the X direction.
00790             if ((((absy + 16) == enemy->gety()) ||
00791                 ((absy + 12) == enemy->gety())) &&
00792                (((absx - 16) <  enemy->getx()) &&
00793                 ((absx + 16) >  enemy->getx()))) {
00794                if (((absy + 12) == enemy->gety()) &&
00795                     (enemy->getStatus() != FALLING)) {
00796                     absy = absy - rely; // Bounce back from overlap, to avoid
00797                     rely = 0;           // hero-enemy mid-cycle deadlock.
00798