35 #include <KMessageBox>
36 #include <KRandomSequence>
42 randomGen (pRandomGen),
68 int KGrLevelPlayer::playerCount = 0;
72 qDeleteAll(dugBricks);
74 kDebug() <<
"LEVEL PLAYER BEING DELETED.";
80 for (
int i = 0; i <= (recIndex + 1); i ++) {
86 dbe1 "\n%d bytes\n", recIndex + 1);
88 while (j < recording->draws.size()) {
89 ch = (uchar)(recording->
draws.
at(j));
95 dbe1 "\n%d bytes\n", j);
102 const bool pPlayback,
103 const bool gameFrozen)
107 if (playerCount > 1) {
108 KMessageBox::information (view,
109 QString(
"ERROR: KGrLevelPlayer Count = %1").arg(playerCount),
113 recording = pRecording;
114 playback = pPlayback;
125 levelWidth = recording->
width;
126 levelHeight = recording->
height;
128 reappearIndex = levelWidth;
129 reappearPos.
fill (1, levelWidth);
132 switch (recording->
rules) {
171 for (
int j = wall ; j < levelHeight + wall; j++) {
172 for (
int i = wall; i < levelWidth + wall; i++) {
191 else if (type ==
ENEMY) {
208 for (
int j = wall ; j < levelHeight + wall; j++) {
209 for (
int i = wall; i < levelWidth + wall; i++) {
216 hero =
new KGrHero (
this, grid, i, j, heroId, rules);
218 if ((controlMode ==
MOUSE) || (controlMode ==
LAPTOP)) {
228 for (
int j = wall ; j < levelHeight + wall; j++) {
229 for (
int i = wall; i < levelWidth + wall; i++) {
234 enemy =
new KGrEnemy (
this, grid, i, j,
id, rules);
247 connect (view, SIGNAL (mouseClick(
int)), SLOT (doDig(
int)));
255 foreach (
KGrEnemy * enemy, enemies) {
263 connect (hero, SIGNAL (incScore(
int)),
264 game, SLOT (incScore(
int)));
265 foreach (
KGrEnemy * enemy, enemies) {
266 connect (enemy, SIGNAL (incScore(
int)),
267 game, SLOT (incScore(
int)));
271 connect (hero, SIGNAL (soundSignal(
int,
bool)),
272 game, SLOT (playSound(
int,
bool)));
295 connect (timer, SIGNAL (tick(
bool,
int)),
this, SLOT (tick(
bool,
int)));
297 view->
gameScene(), SLOT (animate(
bool)));
301 recordInitialWaitTime (1500);
305 void KGrLevelPlayer::startDigging (
Direction diggingDirection)
311 if (hero->
dig (diggingDirection, digI, digJ)) {
320 DugBrick * thisBrick =
new DugBrick;
321 DugBrick brick = {id, digCycleTime, digI, digJ,
322 (digCycleCount + digOpeningCycles + digClosingCycles - 1),
324 (* thisBrick) = brick;
325 dugBricks.
append (thisBrick);
329 void KGrLevelPlayer::processDugBricks (
const int scaledTime)
334 while (iterator.hasNext()) {
335 dugBrick = iterator.next();
336 dugBrick->cycleTimeLeft -= scaledTime;
337 if (dugBrick->cycleTimeLeft < scaledTime) {
338 dugBrick->cycleTimeLeft += digCycleTime;
339 if (--dugBrick->countdown == digClosingCycles) {
342 dugBrick->digI, dugBrick->digJ,
343 (digClosingCycles * digCycleTime),
346 if (dugBrick->countdown == digKillingTime) {
350 if (dugBrick->countdown <= 0) {
362 if ((controlMode ==
MOUSE) || (controlMode ==
LAPTOP)) {
387 if ((pointerI == targetI) && (pointerJ == targetJ)) {
392 else if (! playback) {
399 record (3, pointerI, pointerJ);
407 void KGrLevelPlayer::doDig (
int button)
416 if ((playState == NotReady) || (controlMode !=
MOUSE)) {
420 uchar recordByte = 0;
425 startDigging (DIG_LEFT);
427 case Qt::RightButton:
429 startDigging (DIG_RIGHT);
434 if (recordByte != 0) {
436 record (1, recordByte);
446 if (playback || (playState == NotReady) || (controlMode ==
MOUSE)) {
452 if (playState == Ready) {
458 newDirection =
STAND;
464 if (playState == Ready) {
469 if ((holdKeyOption ==
CLICK_KEY) && pressed && (dirn != direction)) {
472 else if (holdKeyOption ==
HOLD_KEY) {
473 int sign = pressed ? +1 : -1;
475 dY = dY + sign * movement [dirn][
Y];
482 if ((controlMode ==
MOUSE) || (controlMode ==
LAPTOP)) {
483 int index = (playback) ? recIndex : recIndex - 2;
484 dbe2 "T %04d recIndex %03d hero at [%02d, %02d] aiming at [%02d, %02d]\n",
485 T, index, heroI, heroJ, targetI, targetJ);
490 direction = setDirectionByDelta (targetI - heroI, targetJ - heroJ,
498 direction = setDirectionByDelta (dX, dY, heroI, heroJ);
499 dbe2 "T %04d recIndex %03d delta [%02d, %02d] "
500 "hero at [%02d, %02d] direction %d\n",
501 T, recIndex - 1, dX, dY, heroI, heroJ, direction);
507 Direction KGrLevelPlayer::setDirectionByDelta (
const int di,
const int dj,
508 const int heroI,
const int heroJ)
530 void KGrLevelPlayer::recordInitialWaitTime (
const int ms)
537 recording->
content [recIndex] = (uchar) recCount;
541 recording->
content [recIndex++] = (uchar) targetI;
542 recording->
content [recIndex++] = (uchar) targetJ;
543 recording->
content [recIndex] = (uchar) recCount;
548 void KGrLevelPlayer::record (
const int bytes,
const int n1,
const int n2)
556 dbe3 "recCount %d bytes %d n1 %d n2 %d [recIndex-1] %d [recIndex-2] %d\n",
557 recCount, bytes, n1, n2, (uchar) recording->
content.
at (recIndex - 1),
558 (uchar) recording->
content.
at (recIndex - 2));
559 if ((recCount > 0) && (bytes > 1) && (recCount < (
END_CODE - 1)) &&
560 (((bytes == 2) && (n1 == (uchar) recording->
content [recIndex - 1])) ||
561 ((bytes == 3) && (n1 == (uchar) recording->
content [recIndex - 2]) &&
562 (n2 == (uchar) recording->
content [recIndex - 1]))
565 recording->
content [recIndex] = (uchar) (++recCount);
567 dbe2 "T %04d recIndex %03d REC: codes --- %3d %3d - recCount++\n",
568 T, recIndex - 1, (uchar)(recording->
content.
at (recIndex-1)),
569 (uchar)(recording->
content.
at (recIndex)));
571 else if (bytes == 3) {
572 dbe2 "T %04d recIndex %03d REC: codes %3d %3d %3d - recCount++\n",
573 T, recIndex - 2, (uchar)(recording->
content.
at (recIndex-2)),
574 (uchar)(recording->
content.
at (recIndex-1)),
575 (uchar)(recording->
content.
at (recIndex)));
582 recording->
content [++recIndex] = (uchar) n1;
586 recording->
content [++recIndex] = (uchar) n2;
592 recording->
content [++recIndex] = (uchar) recCount;
597 dbe2 "T %04d recIndex %03d REC: singleton %3d %x\n",
598 T, recIndex, n1, n1);
601 dbe2 "T %04d recIndex %03d REC: codes %3d %3d %3d - NEW DIRECTION\n",
602 T, recIndex - 1, direction,
603 (uchar)(recording->
content.
at (recIndex-1)),
604 (uchar)(recording->
content.
at (recIndex)));
607 dbe2 "T %04d recIndex %03d REC: codes %3d %3d %3d - NEW TARGET\n",
608 T, recIndex - 2, (uchar)(recording->
content.
at (recIndex-2)),
609 (uchar)(recording->
content.
at (recIndex-1)),
610 (uchar)(recording->
content.
at (recIndex)));
622 bool leftRightSearch)
624 int heroX, heroY, pointsPerCell;
628 heroX / pointsPerCell, heroY / pointsPerCell,
629 grid, leftRightSearch);
634 if (enemies.
count() == 0) {
637 int enemyX, enemyY, pointsPerCell_1;
638 foreach (
KGrEnemy * enemy, enemies) {
639 pointsPerCell_1 = enemy->
whereAreYou (enemyX, enemyY) - 1;
640 if (((heroX < enemyX) ? ((heroX + pointsPerCell_1) >= enemyX) :
641 (heroX <= (enemyX + pointsPerCell_1))) &&
642 ((heroY < enemyY) ? ((heroY + pointsPerCell_1) > enemyY) :
643 (heroY <= (enemyY + pointsPerCell_1)))) {
653 const int x,
const int y)
655 int minEnemies = (spriteId == heroId) ? 1 : 2;
656 if (enemies.
count() < minEnemies) {
659 int enemyX, enemyY, pointsPerCell;
660 foreach (
KGrEnemy * enemy, enemies) {
661 pointsPerCell = enemy->
whereAreYou (enemyX, enemyY);
662 if (((enemyY == (y + pointsPerCell)) ||
663 (enemyY == (y + pointsPerCell - 1))) &&
664 (enemyX > (x - pointsPerCell)) &&
665 (enemyX < (x + pointsPerCell))) {
673 const int gridI,
const int gridJ)
697 if (otherEnemy > 0) {
698 dbk3 << otherEnemy <<
"at" << (gridI + dI) << gridJ
699 <<
"dirn" << ((otherEnemy > 0) ?
700 (enemies.
at (otherEnemy - 1)->direction()) : 0)
701 <<
"me" << spriteId <<
"dirn" << dirn;
702 if (enemies.
at (otherEnemy - 1)->direction() != dirn) {
703 dbk3 << spriteId <<
"wants" << dirn <<
":" << otherEnemy
704 <<
"at" << (gridI + dI) << gridJ <<
"wants"
705 << (enemies.
at (otherEnemy - 1)->direction());
712 if (otherEnemy > 0) {
713 dbk3 << otherEnemy <<
"at" << gridI << (gridJ + dJ)
714 <<
"dirn" << ((otherEnemy > 0) ?
715 (enemies.
at (otherEnemy - 1)->direction()) : 0)
716 <<
"me" << spriteId <<
"dirn" << dirn;
717 if (enemies.
at (otherEnemy - 1)->direction() != dirn) {
718 dbk3 << spriteId <<
"wants" << dirn <<
":" << otherEnemy
719 <<
"at" << gridI << (gridJ + dJ) <<
"wants"
720 << (enemies.
at (otherEnemy - 1)->direction());
729 const int gridI,
const int gridJ,
732 dbe2 "KGrLevelPlayer::unstackEnemy (%02d at [%02d,%02d] prevEnemy %02d)\n",
733 spriteId, gridI, gridJ, prevEnemy);
737 prevId = enemies.
at (nextId - 1)->getPrevInCell();
738 dbe2 "Next %02d prev %02d\n", nextId, prevId);
739 if (prevId == spriteId) {
740 dbe2 " SET IDs - id %02d prev %02d\n", nextId, prevEnemy);
741 enemies.
at (nextId - 1)->setPrevInCell (prevEnemy);
748 void KGrLevelPlayer::tick (
bool missed,
int scaledTime)
755 if ((i == -1) && (playback || (controlMode !=
KEYBOARD))) {
760 if (! doRecordedMove()) {
763 dbk <<
"Unexpected END_OF_RECORDING - or KILL_HERO ACTION.";
767 else if ((controlMode ==
MOUSE) || (controlMode ==
LAPTOP)) {
772 if (newDirection != direction) {
773 direction = newDirection;
777 else if (holdKeyOption ==
HOLD_KEY) {
781 direction = d [(3 * (dY + 1)) + (dX + 1)];
784 if ((direction !=
NO_DIRECTION) && (playState == Playing)) {
792 if (playState != Playing) {
797 if (dugBricks.
count() > 0) {
798 processDugBricks (scaledTime);
809 kDebug() <<
"END OF LEVEL";
813 foreach (
KGrEnemy * enemy, enemies) {
814 enemy->
run (scaledTime);
821 const int i,
const int j,
822 const bool hasGold,
const bool lost)
825 dbk2 <<
"GOLD COLLECTED BY" << spriteId <<
"AT" << i << j;
828 dbk2 <<
"GOLD LOST BY" << spriteId <<
"AT" << i << j;
831 dbk2 <<
"GOLD DROPPED BY" << spriteId <<
"AT" << i << j;
836 emit
gotGold (spriteId, i, j, hasGold, lost);
839 if ((spriteId == heroId) || lost) {
840 if (--nuggets <= 0) {
850 void KGrLevelPlayer::makeReappearanceSequence()
858 for (
int k = 0; k < levelWidth; k++) {
859 reappearPos [k] = k + 1;
863 int left = levelWidth;
867 for (
int k = 0; k < levelWidth; k++) {
871 temp = reappearPos [z];
872 reappearPos [z] = reappearPos [left - 1];
873 reappearPos [left - 1] = temp;
876 dbk2 <<
"Randoms" << reappearPos;
889 for (k = 1; ((k <= 3) && looking); k++) {
890 if (reappearIndex >= levelWidth) {
891 makeReappearanceSequence();
893 i = reappearPos [reappearIndex++];
905 while ((j < levelHeight) && looking) {
908 while ((i < levelWidth) && looking) {
920 dbk2 <<
"Reappear at" << i << j;
928 uchar value = randomGen->getLong ((
unsigned long) limit);
930 dbe2 "Draw %03d, index %04d, limit %02d\n", value, randIndex, limit);
931 recording->
draws [randIndex++] = value + 1;
935 dbe2 "Draw %03d, index %04d, limit %02d\n",
936 (recording->
draws.
at (randIndex) - 1), randIndex, limit);
938 return ((uchar) recording->
draws.
at (randIndex++) - 1);
942 bool KGrLevelPlayer::doRecordedMove()
945 uchar code = recording->
content [recIndex];
948 if ((code ==
END_CODE) || (code == 0)) {
949 dbe2 "T %04d recIndex %03d PLAY - END of recording\n",
960 j = (uchar)(recording->
content [recIndex + 1]);
963 recCount = (uchar)(recording->
content [recIndex + 2]);
964 dbe2 "T %04d recIndex %03d PLAY codes %d %d %d - NEW TARGET\n",
965 T, recIndex, i, j, recCount);
971 dbe2 "T %04d recIndex %03d PLAY codes %d %d %d\n",
972 T, recIndex, targetI, targetJ, recCount);
974 if (--recCount <= 0) {
975 recIndex = recIndex + 3;
976 dbe2 "T %04d recIndex %03d PLAY - next index\n",
985 if (code != direction) {
989 dbe2 "T %04d recIndex %03d PLAY dig code %d\n",
993 code = recording->
content [recIndex];
999 recCount = (uchar)(recording->
content [recIndex + 1]);
1000 dbe2 "T %04d recIndex %03d PLAY codes %d %d - KEY PRESS\n",
1001 T, recIndex, code, recCount);
1007 dbe2 "T %04d recIndex %03d PLAY codes %d %d mode %d\n",
1008 T, recIndex, code, recCount, controlMode);
1010 if (--recCount <= 0) {
1011 recIndex = recIndex + 2;
1012 dbe2 "T %04d recIndex %03d PLAY - next index\n",
1021 dbe2 "T %04d recIndex %03d PLAY control-mode code %d\n",
1025 code = recording->
content [recIndex];
1032 dbe2 "T %04d recIndex %03d PLAY key-option code %d\n",
1036 code = recording->
content [recIndex];
1044 dbe2 "T %04d recIndex %03d PLAY kill-hero code %d\n",
1053 dbe2 "T %04d recIndex %03d PLAY speed-change code %d\n",
1057 code = recording->
content [recIndex];
1068 if (playState != Playing) {
1072 uchar code = recording->
content [recIndex];
1074 if ((code ==
END_CODE) || (code == 0)) {
1079 dbk2 <<
"recIndex" << recIndex <<
"recCount" << recCount
1080 <<
"randIndex" << randIndex;
1083 while (i < recording->content.size()) {
1090 dbe2 "\n%d bytes\n", i - 1);
1092 while (i < recording->draws.size()) {
1093 ch = (uchar)(recording->
draws.
at(i));
1099 dbe2 "\n%d bytes\n", i - 1);
1103 if ((code >= DIRECTION_CODE) && (code < (DIRECTION_CODE +
nDirections)))
1106 recCount = (uchar)(recording->
content [recIndex + 1]) - recCount;
1107 recording->
content [recIndex + 1] = (uchar) (recCount);
1108 recIndex = recIndex + 1;
1110 else if (code < DIRECTION_CODE) {
1112 recCount = (uchar)(recording->
content [recIndex + 2]) - recCount;
1113 recording->
content [recIndex + 2] = (uchar) (recCount);
1114 recIndex = recIndex + 2;
1119 for (
int i = (recIndex + 2); i < recording->
content.
size(); i++) {
1122 for (
int i = randIndex; i < recording->
draws.
size(); i++) {
1123 recording->
draws [i] = 0;
1127 dbk2 <<
"recIndex" << recIndex <<
"recCount" << recCount
1128 <<
"randIndex" << randIndex;
1130 while (i < recording->content.size()) {
1137 dbe2 "\n%d bytes\n", i - 1);
1139 while (i < recording->draws.size()) {
1140 ch = (uchar)(recording->
draws.
at(i));
1146 dbe2 "\n%d bytes\n", i - 1);
1151 dbk <<
"INTERRUPT - emit interruptDemo();";
1161 kDebug() <<
"END OF LEVEL";
1177 holdKeyOption = option;
1187 timer->
setScale ((
float) (timeScale * 0.1));
1211 showFigurePositions();
1220 showEnemyState (code -
ENEMY_0);
1225 void KGrLevelPlayer::bugFix()
1230 fprintf (stderr,
">> Bug fix is %s\n", (
KGrGame::bugFix) ?
"ON" :
"OFF\n");
1233 void KGrLevelPlayer::startLogging()
1238 fprintf (stderr,
">> Logging is %s\n", (
KGrGame::logging) ?
"ON" :
"OFF\n");
1241 void KGrLevelPlayer::showFigurePositions()
1244 foreach (
KGrEnemy * enemy, enemies) {
1249 void KGrLevelPlayer::showObjectState()
1257 int enter = (access &
ENTERABLE) ? 1 : 0;
1258 int stand = (access &
dFlag [
STAND]) ? 1 : 0;
1259 int u = (access &
dFlag [
UP]) ? 1 : 0;
1260 int d = (access &
dFlag [
DOWN]) ? 1 : 0;
1261 int l = (access &
dFlag [
LEFT]) ? 1 : 0;
1264 "[%02d,%02d] [%c] %02x E %d S %d U %d D %d L %d R %d occ %02d\n",
1265 i, j, here, access, enter, stand, u, d, l, r, enemyId);
1268 if (eAccess != access) {
1272 u = (access &
dFlag [
UP]) ? 1 : 0;
1277 "[%02d,%02d] [%c] %02x E %d S %d U %d D %d L %d R %d Enemy\n",
1278 i, j, here, access, enter, stand, u, d, l, r);
1282 void KGrLevelPlayer::showEnemyState (
int enemyId)
1284 if (enemyId < enemies.
count()) {
1285 enemies.
at(enemyId)->showState();
1290 #include "kgrlevelplayer.moc"
void prepareToPlay()
Indicate that setup is complete and the human player can start playing at any time, by moving the pointer device or pressing a key.
void unstackEnemy(const int spriteId, const int gridI, const int gridJ, const int prevEnemy)
Helper function to remove an enemy from among several stacked in a cell.
bool heroCaught(const int heroX, const int heroY)
Helper function to determine whether the hero has collided with an enemy and must lose a life (unless...
void endLevel(const int result)
void enemyReappear(int &gridI, int &gridJ)
Helper function to determine where an enemy should reappear after being trapped in a brick...
char rules
Rules that applied at time of recording.
int enemyOccupied(int i, int j)
Flags heroMoves(int i, int j)
void placeHiddenLadders()
void setScale(const float pScale)
char cellType(int i, int j)
int controlMode
Control mode during recording (mouse, etc).
void calculateAccess(bool pRunThruHole)
QVector< T > & fill(const T &value, int size)
void setHoldKeyOption(const int option)
Change the keyboard click/hold option during play.
const T & at(int i) const
KGrScene * gameScene() const
int runnerGotGold(const int spriteId, const int i, const int j, const bool hasGold, const bool lost=false)
Helper function for an enemy to pick up or drop gold or the hero to collect gold. ...
void pause(bool stop)
Pause or resume the gameplay in this level.
Flags enemyMoves(int i, int j)
void interruptPlayback()
Stop playback of a recorded level and adjust the content of the recording so that the user can contin...
void animation(bool missed)
Requests the view to update animated sprites.
void setGoldEnemiesRule(bool showIt)
bool bumpingFriend(const int spriteId, const Direction dirn, const int gridI, const int gridJ)
Helper function to determine whether an enemy is colliding with another enemy.
const char TraditionalRules
Codes for the rules of the selected game and level.
void changeCellAt(const int i, const int j, const char type)
This class models the behaviour of the hero.
void getDigTimes(int &digTime, int &digCounter)
void setEnemyOccupied(int i, int j, const int spriteId)
int count(const T &value) const
void append(const T &value)
void deleteSprite(const int spriteId)
const char ScavengerRules
void getMousePos(int &i, int &j)
HeroStatus run(const int scaledTime)
Makes the hero run, under control of a pointer or the keyboard and guided by the layout of the grid...
void dbgControl(int code)
Implement author's debugging aids, which are activated only if the level is paused and the KConfig fi...
void gotGold(const int spriteId, const int i, const int j, const bool hasGold, const bool lost)
KGrRecording structure: contains a record of play in a KGoldrunner level.
const int movement[EndDirection][nAxes]
void setDirectionByKey(const Direction dirn, const bool pressed)
Set a direction for the hero to move or dig when using keyboard control.
void setTimeScale(const int timeScale)
Set the overall speed of gameplay.
int whereAreYou(int &x, int &y)
Returns the exact position of a runner (in grid-points or cell sub-divisions) and the number of grid-...
virtual Direction findBestWay(const int eI, const int eJ, const int hI, const int hJ, KGrLevelGrid *pGrid, bool leftRightSearch=true)=0
uchar randomByte(const uchar limit)
Helper function to provide enemies with random numbers for reappearing and deciding whether to pick u...
Direction getDirection(int heroI, int heroJ)
Helper function for the hero to find his next direction when using mouse or touchpad control...
KGrLevelPlayer(QObject *parent, KRandomSequence *pRandomGen)
The constructor of KGrLevelPlayer.
void showState()
Implements the author's debugging aid that shows the hero's state.
const char KGoldrunnerRules
int makeSprite(char spriteType, int i, int j)
void setNuggets(const int nGold)
Tells the hero how many gold nuggets are remaining.
void killHero()
If not in playback mode, add a code to the recording and kill the hero.
void paintCell(int i, int j, char tileType)
Requests the view to display a particular type of tile at a particular cell, or make it empty and sho...
QByteArray draws
The random numbers used during play.
bool dig(const Direction dirn, int &digI, int &digJ)
Decides whether the hero can dig as is required by pressing a key or a mouse-button.
void setMousePos(const int i, const int j)
void gotGold(const int i, const int j, const bool runnerHasGold)
void setTiming(const int enemyCount=0)
int width
Width of grid, in cells (at rec time).
void setControlMode(const int mode)
Change the input-mode during play.
int keyOption
Click/hold option for keyboard mode.
const AccessFlag ENTERABLE
bool enemiesShowGold() const
void showState()
Implements the author's debugging aid that shows the enemy's state.
void startAnimation(const int spriteId, const bool repeating, const int i, const int j, const int time, const Direction dirn, const AnimationType type)
Requests the view to display an animation of a dug brick at a particular cell, cancelling and superse...
void run(const int scaledTime)
Makes an enemy run, guided by the position of the hero and the layout of the grid.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int height
Height of grid, in cells (at rec time).
QByteArray content
The encoded recording of play.
Direction getEnemyDirection(int enemyI, int enemyJ, bool leftRightSearch)
Helper function for an enemy to find his next direction, based on where the hero is and the search al...
void setTarget(int pointerI, int pointerJ)
Set a point for the hero to aim at when using mouse or touchpad control.
This class models the behaviour of an enemy.
const DirectionFlag dFlag[nDirections]
KGrEnemy * standOnEnemy(const int spriteId, const int x, const int y)
Helper function to determine whether the hero or an enemy is standing on an enemy's head...
void init(KGrView *view, KGrRecording *pRecording, const bool pPlayback, const bool gameFrozen)
The main initialisation of KGrLevelPlayer.