• Skip to content
  • Skip to link menu
KDE 4.0 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 (walkCounter++ < gameCycle) {
00159     // Not end of 4-step cycle: move one step up, if possible.
00160     if (canWalkUp()) {
00161         rely -= STEP;
00162         absy -= STEP;
00163     }
00164     walkTimer->setSingleShot( true );
00165     walkTimer->start ((WALKDELAY * NSPEED) / speed);
00166     }
00167     else {
00168     // End of 4-step cycle: move up to next cell, if possible.
00169     if (canWalkUp()) {
00170         y--;
00171     }
00172     // Always reset position, in case we are stuck partly into a brick.
00173     rely = 0;
00174     absy = y*16;
00175 
00176     // Wait for caller to set next direction.
00177     status = STANDING;
00178     }
00179 }
00180 
00181 void KGrFigure::walkDown(int WALKDELAY, int FALLDELAY)
00182 {
00183     if (hangAtPole() || (! canStand())) {
00184     // On bar or no firm ground underneath: so must fall.
00185     initFall (FALL2, FALLDELAY);
00186     }
00187     else {
00188     actualPixmap = (actualPixmap == CLIMB1) ? CLIMB2 : CLIMB1;
00189     if (walkCounter++ < gameCycle) {
00190         // Not end of 4-step cycle: move one step down, if possible.
00191         if (canWalkDown()) {
00192         rely += STEP;
00193         absy += STEP;
00194         }
00195         walkTimer->setSingleShot( true );
00196         walkTimer->start ((WALKDELAY * NSPEED) / speed);
00197     }
00198     else {
00199         // End of 4-step cycle: move down to next cell, if possible.
00200         if (canWalkDown()) {
00201         y++;
00202         }
00203         // Always reset position, in case we are stuck partly into a brick.
00204         rely = 0;
00205         absy = y*16;
00206 
00207         // Must be able to halt at a pole when going down.
00208         if (! (canStand() || hangAtPole()))
00209         initFall(FALL2, FALLDELAY); // Nothing to hold: so fall.
00210         else
00211         // Wait for caller to set next direction.
00212         status = STANDING;
00213     }
00214     }
00215 }
00216 
00217 void KGrFigure::walkLeft (int WALKDELAY, int FALLDELAY)
00218 {
00219     // If counter != 0, the figure is walking, otherwise he is turning around.
00220     if (walkCounter++ != 0) {
00221     // Change to the next pixmap in the animation.
00222     if ((++actualPixmap % gameCycle) != 0) {
00223         // Not end of 4-pixmap cycle: move one step left, if possible.
00224         if (canWalkLeft()) {
00225         relx -= STEP;
00226         absx -=STEP;
00227         }
00228         walkTimer->setSingleShot( true );
00229         walkTimer->start ((WALKDELAY * NSPEED) / speed);
00230     }
00231     else {
00232         // Check if we are half way through the 8-frame graphics cycle.
00233             alternateStepGraphics = true;
00234             if ((actualPixmap % graphicsCycle) == 0) {
00235                 alternateStepGraphics = false;  // Finished the 8-frame cycle.
00236                 actualPixmap -= graphicsCycle;  // Repeat it.
00237             }
00238 
00239         if (canWalkLeft()) {
00240         x--;
00241         }
00242         // Always reset position, in case we are stuck partly into a brick.
00243         relx = 0;
00244         absx = x*16;
00245 
00246         // If cannot stand or hang, start fall, else await next assignment.
00247         if (! (canStand() || hangAtPole()))
00248         initFall (FALL1, FALLDELAY);
00249         else
00250         status = STANDING;  // Caller should set next direction.
00251     }
00252     }
00253     else {
00254     status = STANDING;      // The figure is turning around.
00255     }
00256 }
00257 
00258 void KGrFigure::walkRight(int WALKDELAY, int FALLDELAY)
00259 {
00260     if (walkCounter++) {        // If 0, just turn the figure around.
00261     if ((++actualPixmap % gameCycle) != 0)  {
00262             // The 4-frame cycle per playfield tile is incomplete.
00263         if (canWalkRight()) {   // Move right, if it's possible.
00264         relx += STEP;
00265         absx += STEP;
00266         }
00267         walkTimer->setSingleShot( true );
00268         walkTimer->start ((WALKDELAY * NSPEED) / speed);
00269     }
00270     else {
00271         // Check if we are half way through the 8-frame graphics cycle.
00272             alternateStepGraphics = true;
00273             if ((actualPixmap % graphicsCycle) == 0) {
00274                 alternateStepGraphics = false;  // Finished the 8-frame cycle.
00275                 actualPixmap -= graphicsCycle;  // Repeat it.
00276             }
00277 
00278         if (canWalkRight()) {
00279         x++;
00280         }               // Set the figure's new position.
00281         // Always reset position, in case we are stuck partly into a brick.
00282         relx = 0;
00283         absx = x*16;
00284 
00285         if (!(canStand()||hangAtPole())) // Cannot hold on: so fall.
00286         initFall (FALL2, FALLDELAY);
00287         else
00288         status = STANDING;       // Else, stand.
00289     }
00290     }
00291     else {
00292     status = STANDING;      // Just turn the figure around.
00293     }
00294 }
00295 
00296 void KGrFigure::initFall(int apm, int FALLDELAY)
00297 {
00298   status = FALLING;
00299   actualPixmap = apm;
00300   walkCounter=1;
00301   walkTimer->stop();
00302   fallTimer->setSingleShot( true );
00303   fallTimer->start((FALLDELAY * NSPEED) / speed);
00304 }
00305 
00306 void KGrFigure::showFigure ()
00307 {
00308 }
00309 
00310 void KGrFigure::setPlayfield (KGrObject * (*p)[30][22])
00311 {
00312   playfield = p;
00313 }
00314 
00315 KGrFigure :: ~KGrFigure ()
00316 {
00317 }
00318 
00319 KGrHero :: KGrHero (KGrCanvas * view, int x, int y)
00320   :KGrFigure (x, y)
00321 {
00322   heroView = view;
00323   status = STANDING;
00324   actualPixmap = FALL1;
00325 
00326   herox = x;
00327   heroy = y;
00328 
00329   started = false;
00330   mouseMode = true;
00331   walkCounter = 1;
00332 
00333   walkFrozen = false;
00334   fallFrozen = false;
00335   alternateStepGraphics = false;
00336 
00337   connect (walkTimer, SIGNAL (timeout ()), SLOT (walkTimeDone ()));
00338   connect (fallTimer, SIGNAL (timeout ()), SLOT (fallTimeDone ()));
00339 }
00340 
00341 int KGrHero::WALKDELAY = 0;
00342 int KGrHero::FALLDELAY = 0;
00343 
00344 /* It is necessary to execute startWalk before the timer-function code, in order
00345    to take changes of direction into account when doing the animation steps.
00346 */
00347 void KGrHero::startWalk ()
00348 {
00349   switch (nextDir) {
00350     case UP:
00351       if ((*playfield)[x][y]->whatIam () == LADDER)
00352     {walkCounter = 1;
00353     direction = UP;}
00354       break;
00355     case RIGHT:
00356       if (hangAtPole()) 
00357     actualPixmap = (alternateStepGraphics) ? RIGHTCLIMB5 : RIGHTCLIMB1;
00358        else 
00359     actualPixmap = (alternateStepGraphics) ? RIGHTWALK5 : RIGHTWALK1;
00360       if (direction != RIGHT)
00361     walkCounter = 0;
00362       else
00363     walkCounter = 1;
00364       direction = RIGHT;
00365       break;
00366     case DOWN:
00367       if (((*playfield)[x][y]->whatIam () == LADDER)||
00368       ((*playfield)[x][y+1]->whatIam () == LADDER))
00369     {walkCounter = 1;
00370     direction = DOWN;}
00371       else          // If the hero is hanging from a pole and there
00372                 // is nothing to stand on, let him fall.
00373     if (hangAtPole() && (!canStand()))
00374       { status = STANDING;
00375       actualPixmap = (direction==RIGHT)?FALL2:FALL1;
00376       walkCounter=1;
00377       direction=STAND;
00378       walkTimer->stop();
00379       }
00380       break;
00381     case LEFT:
00382       if (hangAtPole())
00383     actualPixmap = (alternateStepGraphics) ? LEFTCLIMB5 : LEFTCLIMB1;
00384       else
00385     actualPixmap = (alternateStepGraphics) ? LEFTWALK5 : LEFTWALK1;
00386       if (direction != LEFT)
00387     walkCounter = 0;
00388       else
00389     walkCounter = 1;
00390       direction = LEFT;
00391       break;
00392     default :
00393       direction = STAND;
00394       status = FALLING;
00395       break;
00396     }
00397   nextDir = STAND;
00398   if (status != FALLING)    // Always execute, unless we are falling, in
00399     { status = WALKING;     // which case the state change would be wrong
00400     showFigure ();      // and the wrong timer would be triggered.
00401     }
00402 } // END KGrHero::startWalk
00403 
00404 void KGrHero::setKey(Direction key)
00405 {
00406     // Keyboard control of hero: direction is fixed until next key is pressed.
00407     // Sets a simulated mouse-pointer above, below, left, right or on the hero.
00408     mouseMode = false;
00409     stopped = false;
00410     switch (key) {
00411     case UP:    mousex = x; mousey = 0; break;
00412     case DOWN:  mousex = x; mousey = FIELDHEIGHT + 1; break;
00413     case LEFT:  mousex = 0; mousey = y; break;
00414     case RIGHT: mousex = FIELDWIDTH + 1; mousey = y; break;
00415     case STAND: stopped = true;  mousex = x; mousey = y; break;
00416     }
00417 }
00418 
00419 void KGrHero::setDirection(int i, int j)
00420 {
00421     // Mouse control of hero: direction is updated continually on a timer.
00422     mouseMode = true;
00423     stopped = false;
00424     mousex = i;
00425     mousey = j;
00426 }
00427 
00428 void KGrHero::setNextDir()
00429 {
00430     int dx, dy;
00431 
00432     if (! mouseMode) {
00433     // Keyboard control of hero: adjust simulated mouse-pointer.
00434     if (stopped) {
00435         mousex = x;
00436         mousey = y;
00437     }
00438     if ((mousey < 1) || (mousey > FIELDHEIGHT)) {
00439         mousex = x;     // Stay directly above/below the hero.
00440     }
00441     else if ((mousex < 1) || (mousex > FIELDWIDTH)) {
00442         mousey = y;     // Stay directly left/right of the hero.
00443     }
00444     }
00445 
00446     dx = mousex - x; dy = mousey - y;
00447 
00448     if ((dy == 0) && (y == 1) && (nuggets <= 0)) {
00449     nextDir = UP;
00450     }
00451     else if ((dy > 0) &&
00452          (canWalkDown() ||
00453           // Trial fix, 10 Aug 07.  Removing the next test makes enemies
00454           // behave like bricks if you are standing, walking or falling on
00455           // their heads.  So you cannot die when walking over a trapped
00456           // enemy in mouse-mode, preventing a common beginner's problem.
00457           // standOnEnemy() ||
00458           (hangAtPole() && ((*playfield)[x][y+1]->whatIam() != BRICK) &&
00459                    ((*playfield)[x][y+1]->whatIam() != BETON)))) {
00460     nextDir = DOWN;
00461     }
00462     else if ((dy < 0) && canWalkUp ()) {
00463     nextDir = UP;
00464     }
00465     else if (dx > 0) {
00466     nextDir = RIGHT;
00467     }
00468     else if (dx < 0) {
00469     nextDir = LEFT;
00470     }
00471     else if (dx == 0) {
00472     nextDir = STAND;
00473     }
00474 }
00475 
00476 void KGrHero::doStep() {
00477     if (walkFrozen) {
00478     walkFrozen = false;
00479     walkTimeDone();
00480     }
00481     if (fallFrozen) {
00482     fallFrozen = false;
00483     fallTimeDone();
00484     }
00485 }
00486 
00487 void KGrHero::showState(char option)
00488 {
00489   printf("(%02d,%02d) - Hero      ", x, y);
00490   switch (option) {
00491       case 'p': printf ("\n"); break;
00492       case 's': printf (" nuggets %02d status %d walk-ctr %d ",
00493             nuggets, status, walkCounter);
00494         printf ("dirn %d next dirn %d\n", direction, nextDir);
00495         printf ("                     rel (%02d,%02d) abs (%03d,%03d)",
00496             relx, rely, absx, absy);
00497         printf (" pix %02d", actualPixmap);
00498         printf (" mem %d %d %d %d", mem_x, mem_y, mem_relx, mem_rely);
00499         if (walkFrozen) printf (" wBlock");
00500         if (fallFrozen) printf (" fBlock");
00501         printf ("\n");
00502         break;
00503   }
00504 }
00505 
00506 void KGrHero::init(int a,int b)
00507 {
00508     walkTimer->stop();
00509     fallTimer->stop();
00510     walkCounter = 1;
00511     started = false;
00512 
00513     x = mem_x = a;
00514     y = mem_y = b;
00515     relx = mem_relx = 0;
00516     rely = mem_rely = 0;
00517 
00518     absx = 16*x;
00519     absy = 16*y;
00520 
00521     nuggets = 0;
00522 
00523     if (herox < 1) {                // If first call to init, ...
00524     heroView->makeHeroSprite (x, y, actualPixmap);
00525     }
00526     herox = x;
00527     heroy = y;
00528 
00529     actualPixmap = FALL2;
00530     heroView->moveHero (absx, absy, actualPixmap);
00531 }
00532 
00533 void KGrHero::start()
00534 {
00535     started = true;
00536     walkFrozen = false;
00537     fallFrozen = false;
00538 
00539     if (!(canStand()||hangAtPole())) {      // Hero must fall ...
00540     status = FALLING;
00541     fallTimeDone();
00542     }
00543     else {
00544     status = STANDING;
00545     walkTimeDone();
00546     }
00547 }
00548 
00549 void KGrHero::setSpeed (int gamespeed)
00550 {
00551   if (gamespeed >= 0) {
00552     if (gamespeed < MINSPEED)
00553     speed++;        // Increase speed.
00554     else
00555     speed = gamespeed;  // Set selected speed.
00556     if (speed > MAXSPEED)
00557     speed = MAXSPEED;   // Set upper limit.
00558   }
00559   else {
00560     speed--;            // Reduce speed.
00561     if (speed < MINSPEED)
00562     speed = MINSPEED;   // Set lower limit.
00563   }
00564 
00565   KGrBrick::speed = speed;  // Make a copy for bricks.
00566 }
00567 
00568 void KGrHero::walkTimeDone ()
00569 {
00570   if (! started) return;    // Ignore signals from earlier play.
00571   if (KGrObject::frozen) {walkFrozen = true; return; }
00572 
00573   if ((*playfield)[x][y]->whatIam() == BRICK) {
00574     emit caughtHero();      // Brick closed over hero.
00575     return;
00576   }
00577 
00578   if ((y==1)&&(nuggets<=0)) {   // If on top row and all nuggets collected,
00579     emit leaveLevel();      // the hero has won and can go to next level.
00580     return;
00581   }
00582 
00583   if (status == STANDING)
00584     setNextDir();
00585   if ((status == STANDING) && (nextDir != STAND)) {
00586     if ((standOnEnemy()) && (nextDir == DOWN)) {
00587     emit caughtHero();  // Hero is going to step down into an enemy.
00588     return;
00589     }
00590     startWalk();
00591   }
00592   if (status != STANDING) {
00593       switch (direction) {
00594       case UP:      walkUp (WALKDELAY); break;
00595       case DOWN:    walkDown (WALKDELAY, FALLDELAY); break;
00596       case RIGHT:   walkRight (WALKDELAY, FALLDELAY); break;
00597       case LEFT:    walkLeft (WALKDELAY, FALLDELAY); break;
00598       default :
00599     // The following code is strange.  It makes the hero fall off a pole.
00600     // It works because of other strange code in "startWalk(), case DOWN:".
00601     if (!canStand()||hangAtPole()) // falling
00602       initFall(FALL1, FALLDELAY);
00603     else  status = STANDING;
00604       break;
00605       }
00606     herox=x; heroy=y;           // Set the hero's new position.
00607     if ((relx==0)&&(rely==0)) {     // If he has just completed a move, see
00608       collectNugget();          // if there is a nugget to collect.
00609       }
00610   }
00611   if (status == STANDING)
00612     if (!canStand()&&!hangAtPole())
00613       initFall(FALL1, FALLDELAY);
00614     else
00615     {
00616         walkTimer->setSingleShot( true );
00617         walkTimer->start ((WALKDELAY * NSPEED) / speed);
00618     }
00619 
00620   // This additional showFigure() is to update the hero position after it is
00621   // altered by the hero-enemy deadlock fix in standOnEnemy().  Messy, but ...
00623   showFigure();
00624   if(isInEnemy()) {
00625     walkTimer->stop();
00626     emit caughtHero();
00627   }
00628 }
00629 
00630 void KGrHero::fallTimeDone()
00631 {
00632     if (! started) return;      // Ignore signals from earlier play.
00633     if (KGrObject::frozen) {fallFrozen = true; return; }
00634 
00635     if (!standOnEnemy()) {
00636     if (walkCounter++ < gameCycle) {// The hero must fall four steps.
00637         fallTimer->setSingleShot(true);
00638         fallTimer->start((FALLDELAY * NSPEED) / speed);
00639         rely+=STEP;
00640         absy+=STEP;
00641     }
00642     else {              // When done, move to the start position
00643                     // of the next object (brick, etc.).
00644         heroy = ++y;
00645         rely = 0;
00646         absy = y*16;
00647         collectNugget();        // See if there is a nugget to collect.
00648         if (! (canStand()||hangAtPole())) { // The hero goes on falling.
00649         fallTimer->setSingleShot(true);
00650         fallTimer->start((FALLDELAY * NSPEED) / speed);
00651         walkCounter = 1;
00652         }
00653         else {          // The hero can stand or hang on a pole,
00654         status = STANDING;  // so change his state to STANDING.
00655         walkTimer->setSingleShot(true);
00656         walkTimer->start((WALKDELAY * NSPEED) / speed);
00657         direction = (actualPixmap == FALL2) ? RIGHT : LEFT;
00658         if ((*playfield)[x][y]->whatIam() == POLE)
00659             actualPixmap = (direction == RIGHT)? RIGHTCLIMB1:LEFTCLIMB1;
00660         // else
00661             // Reduce jerkiness when descending over a falling enemy.
00662             // actualPixmap = (direction == RIGHT)? RIGHTWALK1:LEFTWALK1;
00663         }
00664     }
00665     showFigure();
00666     }
00667     else {
00668     if (rely == 0) {
00669         // If at the bottom of a cell, try to walk or just stand still.
00670         status = STANDING;
00671         direction = (actualPixmap == FALL2) ? RIGHT : LEFT;
00672         if ((*playfield)[x][y]->whatIam() == POLE)
00673         actualPixmap = (direction == RIGHT)? RIGHTCLIMB1:LEFTCLIMB1;
00674         // else
00675         // Reduce jerkiness when descending over a falling enemy.
00676         // actualPixmap = (direction == RIGHT)? RIGHTWALK1:LEFTWALK1;
00677         walkTimer->setSingleShot( true );
00678         walkTimer->start((WALKDELAY * NSPEED) / speed);
00679     }
00680     else {
00681         // Else, freeze hero until enemy moves out of the way.
00682         fallTimer->setSingleShot(true);
00683         fallTimer->start((FALLDELAY * NSPEED) / speed);
00684     }
00685     }
00686     if (isInEnemy() && (! standOnEnemy()))
00687     emit caughtHero();
00688 }
00689 
00690 
00691 void KGrHero::showFigure () {
00692 
00693   heroView->moveHero (absx, absy, actualPixmap);
00694 
00695   // Save old values for when we delete the figure from its old position later.
00696   mem_x = x;
00697   mem_y = y;
00698   mem_relx = relx;
00699   mem_rely = rely;
00700 }
00701 
00702 void KGrHero::dig(){
00703   if (direction == LEFT)
00704     digLeft();
00705   else
00706     if (direction == RIGHT)
00707       digRight();
00708 }
00709 
00710 void KGrHero::digLeft(){
00711   int i = 1;        // If stationary or moving up/down, dig at x-1.
00712   if (status == STANDING)
00713       setNextDir();
00714   if ((status == WALKING) ||
00715       ((status == STANDING) && ((nextDir == LEFT) || (nextDir == RIGHT)))) {
00716       if ((direction == LEFT) && canWalkLeft())
00717           i = 2;    // If walking left, dig at x-2 and stop at x-1.
00718       else if ((direction == RIGHT) && canWalkRight())
00719           i = 0;    // If walking right, dig at x and stop at x+1.
00720   }
00721   if (((*playfield)[x-i][y+1]->whatIam() == BRICK)&&
00722       (((*playfield)[x-i][y]->whatIam() == HLADDER)||
00723        ((*playfield)[x-i][y]->whatIam() == FREE)||
00724        ((*playfield)[x-i][y]->whatIam() == HOLE)))
00725     ((KGrBrick*)(*playfield)[x-i][y+1])->dig();
00726 }
00727 
00728 void KGrHero::digRight(){
00729   int i = 1;        // If stationary or moving up/down, dig at x+1.
00730   if (status == STANDING)
00731       setNextDir();
00732   if ((status == WALKING) ||
00733       ((status == STANDING) && ((nextDir == LEFT) || (nextDir == RIGHT)))) {
00734       if ((direction == LEFT) && canWalkLeft())
00735           i = 0;    // If walking left, dig at x and stop at x-1.
00736       else if ((direction == RIGHT) && canWalkRight())
00737           i = 2;    // If walking right, dig at x+2 and stop at x+1.
00738   }
00739   if (((*playfield)[x+i][y+1]->whatIam() == BRICK)&&
00740       (((*playfield)[x+i][y]->whatIam() == HLADDER)||
00741        ((*playfield)[x+i][y]->whatIam() == FREE)||
00742        ((*playfield)[x+i][y]->whatIam() == HOLE)))
00743     ((KGrBrick*)(*playfield)[x+i][y+1])->dig();
00744 }
00745 
00746 void KGrHero::setEnemyList(QList<KGrEnemy *> * e)
00747 {
00748   enemies = e;
00749 }
00750 
00751 bool KGrHero::standOnEnemy()
00752 {
00753     int c = 0;
00754     int range = enemies->count();
00755     if (range > 0) {
00756     for (KGrEnemy * enemy = enemies->at (c); c < range;  ) {
00757         enemy = enemies->at(c++);
00758         // Test if hero's foot is at or just below enemy's head (tolerance
00759         // of 4 pixels) and the two figures overlap in the X direction.
00760         if ((((absy + 16) == enemy->gety()) ||
00761          ((absy + 12) == enemy->gety())) &&
00762         (((absx - 16) <  enemy->getx()) &&
00763          ((absx + 16) >  enemy->getx()))) {
00764                 if (((absy + 12) == enemy->gety()) &&
00765                     (enemy->getStatus() != FALLING)) {
00766                     absy = absy - rely; // Bounce back from overlap, to avoid
00767                     rely = 0;           // hero-enemy mid-cycle deadlock.
00768                     walkCounter = 1;
00769         }
00770         return true;
00771         }
00772     }
00773     }
00774     return false;
00775 }
00776 
00777 void KGrHero::collectNugget(){
00778 
00779   if ((*playfield)[x][y]->whatIam() == NUGGET)
00780     {
00781       ((KGrFree *)(*playfield)[x][y])->setNugget(false);
00782       if (!(--nuggets))
00783     emit haveAllNuggets();  // Tell the application that all the nuggets are
00784                 // gone, so that it can show the hidden ladders.
00785       emit gotNugget(250);  // Tell the application to increase the score.
00786 
00787     }
00788 }
00789 
00790 void KGrHero::loseNugget() {
00791 
00792     // Enemy trapped or dead and could not drop nugget (NO SCORE for this).
00793     if (! (--nuggets))
00794     emit haveAllNuggets();  // Tell the application that all the nuggets are
00795                 // gone, so that it can show the hidden ladders.
00796 }
00797 
00798 bool KGrHero::isInEnemy(){
00799 
00800   int c=0;
00801   int range=enemies->count();
00802   if (range)
00803     for (KGrEnemy *enemy=enemies->at(c);c<range; )
00804       {enemy = enemies->at(c++);
00805       if (isInside(enemy->getx(),enemy->gety())||
00806       isInside(enemy->getx()-15,enemy->gety())||
00807       isInside(enemy->getx(),enemy->gety()-15))
00808     return true;}
00809   return false;
00810 }
00811 
00812 bool KGrHero::isInside(int enemyx, int enemyy){
00813 
00814  return ((absx >= enemyx)&&
00815       (absx <= enemyx+15)&&
00816       (absy >= enemyy)&&
00817       (absy