Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
KGoldrunner
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Games
KGoldrunner
Commits
d83f6329
Commit
d83f6329
authored
Feb 23, 2009
by
Ian Wadham
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enemies starting to run and search for the hero.
svn path=/branches/work/kgoldrunner/; revision=930313
parent
646f0471
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
691 additions
and
99 deletions
+691
-99
src/kgrcanvas.cpp
src/kgrcanvas.cpp
+4
-8
src/kgrcanvas.h
src/kgrcanvas.h
+1
-1
src/kgrgame.cpp
src/kgrgame.cpp
+32
-0
src/kgrgame.h
src/kgrgame.h
+1
-0
src/kgrglobals.h
src/kgrglobals.h
+1
-1
src/kgrlevelgrid.cpp
src/kgrlevelgrid.cpp
+1
-1
src/kgrlevelgrid.h
src/kgrlevelgrid.h
+1
-1
src/kgrlevelplayer.cpp
src/kgrlevelplayer.cpp
+68
-24
src/kgrlevelplayer.h
src/kgrlevelplayer.h
+16
-13
src/kgrrulebook.cpp
src/kgrrulebook.cpp
+395
-13
src/kgrrulebook.h
src/kgrrulebook.h
+29
-14
src/kgrrunner.cpp
src/kgrrunner.cpp
+119
-9
src/kgrrunner.h
src/kgrrunner.h
+21
-12
src/kgrtimer.cpp
src/kgrtimer.cpp
+1
-1
src/kgrtimer.h
src/kgrtimer.h
+1
-1
No files found.
src/kgrcanvas.cpp
View file @
d83f6329
...
...
@@ -498,22 +498,18 @@ QPoint KGrCanvas::getMousePos()
return
(
QPoint
(
i
,
j
));
}
void
KGrCanvas
::
setMousePos
(
int
i
,
int
j
)
void
KGrCanvas
::
setMousePos
(
const
int
i
,
const
int
j
)
{
// In KGoldrunner, the top-left visible cell is [1,1]: in KGrSprite [0,0].
i
--
;
j
--
;
m
->
setPos
(
mapToGlobal
(
QPoint
(
topLeft
.
x
()
+
i
*
imgW
+
imgW
/
2
,
topLeft
.
y
()
+
j
*
imgH
+
imgH
/
2
)));
m
->
setPos
(
mapToGlobal
(
QPoint
(
topLeft
.
x
()
+
(
i
-
1
)
*
imgW
+
imgW
/
2
,
topLeft
.
y
()
+
(
j
-
1
)
*
imgH
+
imgH
/
2
)));
}
void
KGrCanvas
::
animate
(
bool
missed
)
{
foreach
(
KGrSprite
*
sprite
,
(
*
sprites
))
{
if
(
sprite
!=
0
)
{
if
(
sprite
->
spriteType
()
!=
ENEMY
)
{
sprite
->
animate
(
missed
);
// Animate the hero and dug bricks.
}
sprite
->
animate
(
missed
);
}
}
}
...
...
src/kgrcanvas.h
View file @
d83f6329
...
...
@@ -46,7 +46,6 @@ public:
virtual
~
KGrCanvas
();
QPoint
getMousePos
();
void
setMousePos
(
int
,
int
);
void
setBaseScale
();
...
...
@@ -74,6 +73,7 @@ public:
inline
void
setGoldEnemiesRule
(
bool
showIt
)
{
enemiesShowGold
=
showIt
;}
public
slots
:
void
setMousePos
(
const
int
,
const
int
);
void
animate
(
bool
missed
);
void
paintCell
(
const
int
i
,
const
int
j
,
const
char
type
,
const
int
offset
=
0
);
...
...
src/kgrgame.cpp
View file @
d83f6329
...
...
@@ -376,6 +376,23 @@ void KGrGame::incScore (int n)
emit
showScore
(
score
);
// collect gold 250, complete the level 1500.
}
void
KGrGame
::
endLevel
(
const
int
result
)
{
if
(
levelPlayer
)
{
// Delete the level-player, hero, enemies, grid, rule-book, etc.
// Delete sprites in KGrCanvas later, so they stay visible for a while.
delete
levelPlayer
;
levelPlayer
=
0
;
}
if
(
result
==
WON_LEVEL
)
{
levelCompleted
();
}
else
if
(
result
==
DEAD
)
{
herosDead
();
}
}
void
KGrGame
::
herosDead
()
{
if
((
level
<
1
)
||
(
lives
<=
0
))
...
...
@@ -383,7 +400,9 @@ void KGrGame::herosDead()
// Lose a life.
if
(
--
lives
>
0
)
{
#ifdef ENABLE_SOUND_SUPPORT
effects
->
play
(
fx
[
DeathSound
]);
#endif
// Still some life left, so PAUSE and then re-start the level.
emit
showLives
(
lives
);
gameFrozen
=
true
;
// Freeze the animation and let
...
...
@@ -393,7 +412,9 @@ void KGrGame::herosDead()
}
else
{
// Game over.
#ifdef ENABLE_SOUND_SUPPORT
effects
->
play
(
fx
[
GameOverSound
]);
#endif
emit
showLives
(
lives
);
freeze
();
QString
gameOver
=
"<NOBR><B>"
+
i18n
(
"GAME OVER !!!"
)
+
"</B></NOBR>"
;
...
...
@@ -458,7 +479,9 @@ void KGrGame::showHiddenLadders()
void
KGrGame
::
levelCompleted
()
{
#ifdef ENABLE_SOUND_SUPPORT
effects
->
play
(
fx
[
CompletedSound
]);
#endif
connect
(
view
,
SIGNAL
(
fadeFinished
()),
this
,
SLOT
(
goUpOneLevel
()));
view
->
fadeOut
();
}
...
...
@@ -721,6 +744,10 @@ int KGrGame::loadLevel (int levelNo)
return
0
;
}
// Clean up any sprites remaining from a previous level. This is done late,
// so that the end-state of the sprites will be visible for a short while.
view
->
deleteAllSprites
();
view
->
setLevel
(
levelNo
);
// Switch and render background if reqd.
view
->
fadeIn
();
// Then run the fade-in animation.
startScore
=
score
;
// The score we will save, if asked.
...
...
@@ -779,6 +806,11 @@ int KGrGame::loadLevel (int levelNo)
gameGroup
.
sync
();
// Ensure that the entry goes to disk.
}
// Use a queued connection here, to ensure that levelPlayer has finished
// executing when control goes to the endLevel (const int heroStatus) slot.
connect
(
levelPlayer
,
SIGNAL
(
endLevel
(
const
int
)),
this
,
SLOT
(
endLevel
(
const
int
)),
Qt
::
QueuedConnection
);
// Re-enable player input.
loading
=
false
;
...
...
src/kgrgame.h
View file @
d83f6329
...
...
@@ -103,6 +103,7 @@ public slots:
void
showHighScores
();
// Show high scores for current game.
void
incScore
(
int
);
// Update the score.
void
endLevel
(
const
int
result
);
// Hero completed the level or he died.
void
herosDead
();
// Hero was caught or he quit (key Q).
void
showHiddenLadders
();
// Show hidden ladders (nuggets gone).
void
levelCompleted
();
// Hero completed the level.
...
...
src/kgrglobals.h
View file @
d83f6329
...
...
@@ -83,6 +83,6 @@ enum DebugCodes {
const
int
TickTime
=
20
;
enum
HeroStatus
{
WON_LEVEL
,
CAUGHT_IN_BRICK
,
NO_ACTION
,
STATIONARY
,
MOVING
};
NORMAL
,
WON_LEVEL
,
DEAD
};
#endif // KGRGLOBALS_H
src/kgrlevelgrid.cpp
View file @
d83f6329
/****************************************************************************
* Copyright 2009 Ian Wadham <ian
w
au@gmail.com> *
* Copyright 2009 Ian Wadham <ian
dw.
au@gmail.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
...
...
src/kgrlevelgrid.h
View file @
d83f6329
/****************************************************************************
* Copyright 2009 Ian Wadham <ian
w
au@gmail.com> *
* Copyright 2009 Ian Wadham <ian
dw.
au@gmail.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
...
...
src/kgrlevelplayer.cpp
View file @
d83f6329
/****************************************************************************
* Copyright 2009 Ian Wadham <ian
w
au@gmail.com> *
* Copyright 2009 Ian Wadham <ian
dw.
au@gmail.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
...
...
@@ -56,6 +56,10 @@ KGrLevelPlayer::KGrLevelPlayer (QObject * parent,
KGrLevelPlayer
::~
KGrLevelPlayer
()
{
while
(
!
dugBricks
.
isEmpty
())
{
delete
dugBricks
.
takeFirst
();
}
// TODO - Do we need this delete?
// while (! enemies.isEmpty()) {
// delete enemies.takeFirst();
...
...
@@ -92,8 +96,13 @@ void KGrLevelPlayer::init (KGrCanvas * view, const Control mode)
connect
(
this
,
SIGNAL
(
makeSprite
(
char
,
int
,
int
)),
view
,
SLOT
(
makeSprite
(
char
,
int
,
int
)));
// Connect to the mouse-positioning code in the graphics.
connect
(
this
,
SIGNAL
(
setMousePos
(
const
int
,
const
int
)),
view
,
SLOT
(
setMousePos
(
const
int
,
const
int
)));
// Show the layout of this level in the view (KGrCanvas).
int
wall
=
ConcreteWall
;
int
enemyCount
=
0
;
for
(
int
j
=
wall
;
j
<
levelData
->
height
+
wall
;
j
++
)
{
for
(
int
i
=
wall
;
i
<
levelData
->
width
+
wall
;
i
++
)
{
char
type
=
grid
->
cellType
(
i
,
j
);
...
...
@@ -108,47 +117,61 @@ void KGrLevelPlayer::init (KGrCanvas * view, const Control mode)
nuggets
++
;
}
// TODO - Do hero in pass 1 and enemies in pass 2, to ensure the hero has id 0.
// Either, create a hero and paint him on the background ...
// If the hero is here, leave the tile empty.
if
(
type
==
HERO
)
{
emit
paintCell
(
i
,
j
,
FREE
,
0
);
grid
->
changeCellAt
(
i
,
j
,
FREE
);
// Hero becomes sprite.
}
// If an enemy is here, count him and leave the tile empty.
else
if
(
type
==
ENEMY
)
{
enemyCount
++
;
emit
paintCell
(
i
,
j
,
FREE
,
0
);
}
// Or, just paint this tile.
else
{
emit
paintCell
(
i
,
j
,
type
,
0
);
}
}
}
// Set the timing rules, maybe based on the number of enemies.
rules
->
setTiming
(
enemyCount
);
rules
->
getDigTimes
(
digCycleTime
,
digCycleCount
);
// TODO - Do hero in pass 1 and enemies in pass 2, to ensure the hero has id 0.
// Create the hero (always sprite 0), with the proper timing.
for
(
int
j
=
wall
;
j
<
levelData
->
height
+
wall
;
j
++
)
{
for
(
int
i
=
wall
;
i
<
levelData
->
width
+
wall
;
i
++
)
{
char
type
=
grid
->
cellType
(
i
,
j
);
if
(
type
==
HERO
)
{
if
(
hero
==
0
)
{
targetI
=
i
;
targetJ
=
j
;
heroID
=
emit
makeSprite
(
HERO
,
i
,
j
);
hero
=
new
KGrHero
(
this
,
grid
,
i
,
j
,
heroID
,
rules
);
// TODO - Iff mouse mode, setMousePos();
view
->
setMousePos
(
targetI
,
targetJ
);
// ??????????
emit
setMousePos
(
targetI
,
targetJ
);
grid
->
changeCellAt
(
i
,
j
,
FREE
);
// Hero now a sprite.
}
}
}
}
// Or, create an enemy and paint him on the background ..
.
else
if
(
type
==
ENEMY
)
{
emit
paintCell
(
i
,
j
,
FREE
,
0
);
grid
->
changeCellAt
(
i
,
j
,
FREE
);
// Enemy becomes sprite.
// Create the enemies (sprites 1-n), with the proper timing
.
for
(
int
j
=
wall
;
j
<
levelData
->
height
+
wall
;
j
++
)
{
for
(
int
i
=
wall
;
i
<
levelData
->
width
+
wall
;
i
++
)
{
char
type
=
grid
->
cellType
(
i
,
j
);
if
(
type
==
ENEMY
)
{
KGrEnemy
*
enemy
;
int
id
=
emit
makeSprite
(
ENEMY
,
i
,
j
);
enemy
=
new
KGrEnemy
(
this
,
grid
,
i
,
j
,
id
,
rules
);
enemies
.
append
(
enemy
);
}
// Or, just paint this tile.
else
{
emit
paintCell
(
i
,
j
,
type
,
0
);
grid
->
changeCellAt
(
i
,
j
,
FREE
);
// Enemy now a sprite.
}
}
}
if
(
rules
->
variableTiming
())
{
// Game-speed depends on number of enemies (as in Traditional rules).
rules
->
setTiming
(
enemies
.
count
());
}
rules
->
getDigTimes
(
digCycleTime
,
digCycleCount
);
// Connect the hero's and enemies' efforts to the graphics.
connect
(
this
,
SIGNAL
(
gotGold
(
int
,
int
,
int
,
bool
)),
view
,
SLOT
(
gotGold
(
int
,
int
,
int
,
bool
)));
...
...
@@ -266,7 +289,7 @@ void KGrLevelPlayer::prepareToPlay()
{
// TODO - Should this be a signal?
kDebug
()
<<
"Set mouse to:"
<<
targetI
<<
targetJ
;
mView
->
setMousePos
(
targetI
,
targetJ
);
emit
setMousePos
(
targetI
,
targetJ
);
playState
=
Ready
;
}
...
...
@@ -372,6 +395,14 @@ Direction KGrLevelPlayer::getDirection (int heroI, int heroJ)
return
direction
;
}
Direction
KGrLevelPlayer
::
getEnemyDirection
(
int
enemyI
,
int
enemyJ
)
{
int
heroI
,
heroJ
,
point
,
pointsPerCell
;
pointsPerCell
=
hero
->
whereAreYou
(
heroI
,
heroJ
,
point
);
return
rules
->
findBestWay
(
enemyI
,
enemyJ
,
heroI
,
heroJ
,
grid
);
}
void
KGrLevelPlayer
::
tick
(
bool
missed
,
int
scaledTime
)
{
if
(
playState
!=
Playing
)
{
...
...
@@ -383,11 +414,23 @@ void KGrLevelPlayer::tick (bool missed, int scaledTime)
}
HeroStatus
status
=
hero
->
run
(
scaledTime
);
if
((
status
==
WON_LEVEL
)
||
(
status
==
DEAD
))
{
timer
->
pause
();
// TODO ? If caught in a brick, brick-closing animation is unfinished.
// Queued connection ensures KGrGame slot runs AFTER return from here.
emit
endLevel
(
status
);
kDebug
()
<<
"END OF LEVEL"
;
return
;
}
foreach
(
KGrEnemy
*
enemy
,
enemies
)
{
enemy
->
run
(
scaledTime
);
}
emit
animation
(
missed
);
}
void
KGrLevelPlayer
::
runnerGotGold
(
const
int
spriteID
,
int
KGrLevelPlayer
::
runnerGotGold
(
const
int
spriteID
,
const
int
i
,
const
int
j
,
const
bool
hasGold
)
{
...
...
@@ -402,6 +445,7 @@ void KGrLevelPlayer::runnerGotGold (const int spriteID,
grid
->
placeHiddenLadders
();
}
}
return
nuggets
;
}
void
KGrLevelPlayer
::
pause
(
bool
stop
)
...
...
src/kgrlevelplayer.h
View file @
d83f6329
/****************************************************************************
* Copyright 2009 Ian Wadham <ian
w
au@gmail.com> *
* Copyright 2009 Ian Wadham <ian
dw.
au@gmail.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
...
...
@@ -39,26 +39,29 @@ class KGrLevelPlayer : public QObject
{
Q_OBJECT
public:
KGrLevelPlayer
(
QObject
*
parent
,
KGrGameData
*
theGameData
,
KGrLevelData
*
theLevelData
);
KGrLevelPlayer
(
QObject
*
parent
,
KGrGameData
*
theGameData
,
KGrLevelData
*
theLevelData
);
~
KGrLevelPlayer
();
void
init
(
KGrCanvas
*
view
,
const
Control
mode
);
void
prepareToPlay
();
void
init
(
KGrCanvas
*
view
,
const
Control
mode
);
void
prepareToPlay
();
inline
void
setControlMode
(
const
Control
mode
)
{
controlMode
=
mode
;
}
inline
void
setControlMode
(
const
Control
mode
)
{
controlMode
=
mode
;
}
void
setTarget
(
int
pointerI
,
int
pointerJ
);
void
setDirectionByKey
(
Direction
dirn
);
Direction
getDirection
(
int
heroI
,
int
heroJ
);
void
setTarget
(
int
pointerI
,
int
pointerJ
);
void
setDirectionByKey
(
Direction
dirn
);
Direction
getDirection
(
int
heroI
,
int
heroJ
);
Direction
getEnemyDirection
(
int
enemyI
,
int
enemyJ
);
void
runnerGotGold
(
const
int
spriteID
,
const
int
i
,
const
int
j
,
const
bool
hasGold
);
int
runnerGotGold
(
const
int
spriteID
,
const
int
i
,
const
int
j
,
const
bool
hasGold
);
void
pause
(
bool
stop
);
void
dbgControl
(
int
code
);
// Authors' debugging aids.
void
pause
(
bool
stop
);
void
dbgControl
(
int
code
);
// Authors' debugging aids.
signals:
void
endLevel
(
const
int
result
);
void
setMousePos
(
const
int
i
,
const
int
j
);
void
animation
(
bool
missed
);
void
paintCell
(
int
i
,
int
j
,
char
tileType
,
int
diggingStage
=
0
);
int
makeSprite
(
char
spriteType
,
int
i
,
int
j
);
...
...
src/kgrrulebook.cpp
View file @
d83f6329
/****************************************************************************
* Copyright 2009 Ian Wadham <ian
w
au@gmail.com> *
* Copyright 2009 Ian Wadham <ian
dw.
au@gmail.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
...
...
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************/
#include "kgrlevelgrid.h"
#include "kgrrulebook.h"
KGrRuleBook
::
KGrRuleBook
(
QObject
*
parent
)
...
...
@@ -48,12 +49,12 @@ void KGrRuleBook::setTiming (const int enemyCount)
if
(
mVariableTiming
)
{
choice
=
(
enemyCount
<
0
)
?
0
:
enemyCount
;
choice
=
(
enemyCount
>
5
)
?
5
:
enemyCount
;
times
=
varTiming
[
enemyCount
];
times
=
varTiming
[
choice
];
}
}
// Initialise the
static
flags for the rules.
// Initialise the flags for the rules.
KGrTraditionalRules
::
KGrTraditionalRules
(
QObject
*
parent
)
:
...
...
@@ -76,13 +77,388 @@ KGrTraditionalRules::~KGrTraditionalRules()
{
}
Direction
KGrTraditionalRules
::
findBestWay
(
const
QPoint
&
enemyPosition
,
const
QPoint
&
heroPosition
,
const
KGrLevelGrid
&
grid
)
Direction
KGrTraditionalRules
::
findBestWay
(
const
int
eI
,
const
int
eJ
,
const
int
hI
,
const
int
hJ
,
KGrLevelGrid
*
pGrid
)
// TODO - Should be const ... const KGrLevelGrid * pGrid)
{
return
RIGHT
;
grid
=
pGrid
;
if
(
grid
->
cellType
(
eI
,
eJ
)
==
USEDHOLE
)
{
// Could not get out of hole
return
UP
;
// (e.g. brick above is closed):
}
// but keep trying.
// TODO - Add !standOnEnemy() && as a condition here.
// TODO - And maybe !((*playfield)[x][y+1]->whatIam() == HOLE)) not just out of hole,
bool
canStand
=
(
grid
->
enemyMoves
(
eI
,
eJ
)
&
dFlag
[
STAND
]);
if
(
!
canStand
)
{
return
DOWN
;
}
// Traditional search strategy.
Direction
dirn
=
STAND
;
if
(
eJ
==
hJ
)
{
dirn
=
getHero
(
eI
,
eJ
,
hI
);
// Hero on same row.
if
(
dirn
!=
STAND
)
{
return
dirn
;
// Can go towards him.
}
}
if
(
eJ
>=
hJ
)
{
// Hero above or on same row.
dirn
=
searchUp
(
eI
,
eJ
,
hJ
);
// Find a way that leads up.
}
else
{
// Hero below enemy.
dirn
=
searchDown
(
eI
,
eJ
,
hJ
);
// Find way that leads down.
if
(
dirn
==
STAND
)
{
dirn
=
searchUp
(
eI
,
eJ
,
hJ
);
// No go: try going up first.
}
}
if
(
dirn
==
STAND
)
{
// When all else fails, look for
dirn
=
searchDown
(
eI
,
eJ
,
eJ
-
1
);
// a way below the hero.
}
return
dirn
;
}
Direction
KGrTraditionalRules
::
searchUp
(
int
ew
,
int
eh
,
int
hh
)
{
int
i
,
ilen
,
ipos
,
j
,
jlen
,
jpos
,
deltah
,
rungs
;
deltah
=
eh
-
hh
;
// Get distance up to hero's level.
// Search for the best ladder right here or on the left.
i
=
ew
;
ilen
=
0
;
ipos
=
-
1
;
while
(
i
>=
1
)
{
rungs
=
distanceUp
(
i
,
eh
,
deltah
);
if
(
rungs
>
ilen
)
{
ilen
=
rungs
;
// This the best yet.
ipos
=
i
;
}
if
(
searchOK
(
-
1
,
i
,
eh
))
i
--
;
// Look further to the left.
else
i
=
-
1
;
// Cannot go any further to the left.
}
// Search for the best ladder on the right.
j
=
ew
;
jlen
=
0
;
jpos
=
-
1
;
while
(
j
<
FIELDWIDTH
)
{
if
(
searchOK
(
+
1
,
j
,
eh
))
{
j
++
;
// Look further to the right.
rungs
=
distanceUp
(
j
,
eh
,
deltah
);
if
(
rungs
>
jlen
)
{
jlen
=
rungs
;
// This the best yet.
jpos
=
j
;
}
}
else
j
=
FIELDWIDTH
+
1
;
// Cannot go any further to the right.
}
if
((
ilen
==
0
)
&&
(
jlen
==
0
))
// No ladder found.
return
STAND
;
// Choose a ladder to go to.
if
(
ilen
!=
jlen
)
{
// If the ladders are not the same
// length, choose the longer one.
if
(
ilen
>
jlen
)
{
if
(
ipos
==
ew
)
// If already on the best ladder, go up.
return
UP
;
else
return
LEFT
;
}
else
return
RIGHT
;
}
else
{
// Both ladders are the same length.
if
(
ipos
==
ew
)
// If already on the best ladder, go up.
return
UP
;
else
if
(
ilen
==
deltah
)
{
// If both reach the hero's level,
if
((
ew
-
ipos
)
<=
(
jpos
-
ew
))
// choose the closest.
return
LEFT
;
else
return
RIGHT
;
}
else
return
LEFT
;
// Else choose the left ladder.
}
}
Direction
KGrTraditionalRules
::
searchDown
(
int
ew
,
int
eh
,
int
hh
)
{
int
i
,
ilen
,
ipos
,
j
,
jlen
,
jpos
,
deltah
,
rungs
,
path
;
deltah
=
hh
-
eh
;
// Get distance down to hero's level.
// Search for the best way down, right here or on the left.
ilen
=
0
;
ipos
=
-
1
;
i
=
(
willNotFall
(
ew
,
eh
))
?
ew
:
-
1
;
rungs
=
distanceDown
(
ew
,
eh
,
deltah
);
if
(
rungs
>
0
)
{
ilen
=
rungs
;
ipos
=
ew
;
}
while
(
i
>=
1
)
{
rungs
=
distanceDown
(
i
-
1
,
eh
,
deltah
);
if
(((
rungs
>
0
)
&&
(
ilen
==
0
))
||
((
deltah
>
0
)
&&
(
rungs
>
ilen
))
||
((
deltah
<=
0
)
&&
(
rungs
<
ilen
)
&&
(
rungs
!=
0
)))
{
ilen
=
rungs
;
// This the best way yet.
ipos
=
i
-
1
;
}
if
(
searchOK
(
-
1
,
i
,
eh
))
i
--
;
// Look further to the left.
else
i
=
-
1
;
// Cannot go any further to the left.
}
// Search for the best way down, on the right.
j
=
ew
;
jlen
=
0
;
jpos
=
-
1
;
while
(
j
<
FIELDWIDTH
)
{
rungs
=
distanceDown
(
j
+
1
,
eh
,
deltah
);
if
(((
rungs
>
0
)
&&
(
jlen
==
0
))
||
((
deltah
>
0
)
&&
(
rungs
>
jlen
))
||
((
deltah
<=
0
)
&&
(
rungs
<
jlen
)
&&
(
rungs
!=
0
)))
{
jlen
=
rungs
;
// This the best way yet.
jpos
=
j
+
1
;
}
if
(
searchOK
(
+
1
,
j
,
eh
))
{
j
++
;
// Look further to the right.
}
else
j
=
FIELDWIDTH
+
1
;
// Cannot go any further to the right.
}
if
((
ilen
==
0
)
&&
(
jlen
==
0
))
// Found no way down.
return
STAND
;
// Choose a way down to follow.
if
(
ilen
==
0
)
path
=
jpos
;
else
if
(
jlen
==
0
)
path
=
ipos
;
else
if
(
ilen
!=
jlen
)
{
// If the ways down are not same length,
// choose closest to hero's level.
if
(
deltah
>
0
)
{
if
(
jlen
>
ilen
)
path
=
jpos
;
else
path
=
ipos
;
}
else
{
if
(
jlen
>
ilen
)
path
=
ipos
;
else
path
=
jpos
;
}
}
else
{
// Both ways down are the same length.
if
((
deltah
>
0
)
&&
// If both reach the hero's level,
(
ilen
==
deltah
))
{
// choose the closest.
if
((
ew
-
ipos
)
<=
(
jpos
-
ew
))
path
=
ipos
;
else
path
=
jpos
;
}
else
path
=
ipos
;
// Else, go left or down.
}
if
(
path
==
ew
)
return
DOWN
;
else
if
(
path
<
ew
)
return
LEFT
;
else
return
RIGHT
;
}
Direction
KGrTraditionalRules
::
getHero
(
int
eI
,
int
eJ
,
int
hI
)
{
int
i
,
inc
,
returnValue
;
inc
=
(
eI
>
hI
)
?
-
1
:
+
1
;
i
=
eI
;
while
(
i
!=
hI
)
{
returnValue
=
canWalkLR
(
inc
,
i
,
eJ
);
if
(
returnValue
>
0
)
i
=
i
+
inc
;
// Can run further towards the hero.
else
if
(
returnValue
<
0
)
break
;
// Will run into a wall regardless.
else
return
STAND
;
// Won't run over a hole.
}
if
(
i
<
eI
)
return
LEFT
;
else
if
(
i
>
eI
)
return
RIGHT
;
else
return
STAND
;
}
int
KGrTraditionalRules
::
distanceUp
(
int
x
,
int
y
,
int
deltah
)
{
int
rungs
=
0
;
// If there is a ladder at (x,y), return its length, else return zero.
while
(
grid
->
cellType
(
x
,
y
-
rungs
)
==
LADDER
)
{
rungs
++
;
if
(
rungs
>=
deltah
)
{
// To hero's level is enough.
break
;
}
}
return
rungs
;
}
int
KGrTraditionalRules
::
distanceDown
(
int
x
,
int
y
,
int
deltah
)
{
// When deltah > 0, we want an exit sideways at the hero's level or above.