1 /*
2     SPDX-FileCopyrightText: 2009 Ian Wadham <iandw.au@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #ifndef KGRRUNNER_H
8 #define KGRRUNNER_H
9 
10 #include "kgrglobals.h"
11 
12 #include <QObject>
13 #include <QElapsedTimer> // IDW
14 
15 class KGrLevelPlayer;
16 class KGrLevelGrid;
17 class KGrRuleBook;
18 class KGrEnemy;
19 
20 enum  Situation {NotTimeYet, CaughtInBrick, MidCell, EndCell};
21 
22 /**
23  * This class provides the shared features of all runners (hero and enemies).
24  */
25 class KGrRunner : public QObject
26 {
27     Q_OBJECT
28 public:
29     /**
30      * The constructor of the KGrRunner virtual class.
31      *
32      * @param pLevelPlayer The object that owns the runner and will destroy it
33      *                     if the KGoldrunner application is terminated during
34      *                     play.  The object also provides helper functions to
35      *                     the runners.
36      * @param pGrid        The grid on which the runner is playing.
37      * @param i            The starting column-number (>=1).
38      * @param j            The starting row-number (>=1).
39      * @param pSpriteId    The sprite ID of the runner, as used in animation.
40      * @param pRules       The rules that apply to this game and level.
41      * @param startDelay   The starting-time advantage enemies give to the hero.
42      */
43     KGrRunner (KGrLevelPlayer * pLevelPlayer, KGrLevelGrid * pGrid,
44                int i, int j, const int pSpriteId,
45                KGrRuleBook  * pRules, const int startDelay);
46     ~KGrRunner() override;
47 
48     /**
49      * Returns the exact position of a runner (in grid-points or cell
50      * sub-divisions) and the number of grid-points per cell, from which the
51      * cell's column-number and row-number can be calculated if required.
52      *
53      * @param x            X-coordinate in grid-points (return by reference).
54      * @param y            Y-coordinate in grid-points (return by reference).
55      *
56      * @return             The number of grid-points per cell.
57      */
whereAreYou(int & x,int & y)58     inline int whereAreYou (int & x, int & y) {
59                             x = gridX; y = gridY; return pointsPerCell; }
60 
61 Q_SIGNALS:
62     /**
63      * Requests the KGoldrunner game to add to the human player's score.
64      *
65      * @param n            The amount to add to the score.
66      */
67     void incScore          (const int n);
68 
69     /**
70      * Requests the view-object to display an animation of a runner at a
71      * particular cell, cancelling and superseding any current animation.
72      *
73      * @param spriteId     The ID of the sprite (hero or enemy).
74      * @param repeating    If true, repeat the animation until the next signal.
75      * @param i            The column-number of the cell to start at.
76      * @param j            The row-number of the cell to start at.
77      * @param time         The time in which to traverse one cell.
78      * @param dirn         The direction of motion, or STAND.
79      * @param type         The type of animation (walk, climb. etc.).
80      */
81     void startAnimation    (const int spriteId, const bool repeating,
82                             const int i, const int j, const int time,
83                             const Direction dirn, const AnimationType type);
84 
85 protected:
86     KGrLevelPlayer * levelPlayer;
87     KGrLevelGrid *   grid;
88     KGrRuleBook *    rules;
89 
90     int              spriteId;
91 
92     int              gridI;
93     int              gridJ;
94     int              gridX;
95     int              gridY;
96     int              deltaX;
97     int              deltaY;
98 
99     int              pointCtr;
100     int              pointsPerCell;
101     bool             turnAnywhere;
102 
103     void             getRules();
104 
105     Situation        situation (const int scaledTime);
106     char             nextCell();
107     bool             setNextMovement (const char spriteType,
108                                       const char cellType,
109                                       Direction & dir,
110                                       AnimationType & anim, int & interval);
111 
112     bool             falling;
113     KGrEnemy *       onEnemy;		// If standing or riding on an enemy.
114     Direction        currDirection;
115     AnimationType    currAnimation;
116 
117     int              runTime;		// Time interval for hero/enemy running.
118     int              fallTime;		// Time interval for hero/enemy falling.
119     int              enemyFallTime;	// Time interval for enemy falling.
120     int              trapTime;		// Time interval for which an enemy can
121 					// stay trapped in a brick.
122 
123     int              interval;		// The runner's current time interval.
124     int              timeLeft;		// Time till the runner's next action.
125 
126     bool             leftRightSearch;	// KGoldrunner-rules enemy search-mode.
127 
128     QElapsedTimer            t; // IDW
129 };
130 
131 
132 /**
133  * This class models the behaviour of the hero.  It inherits from KGrRunner.
134  *
135  * The hero's main functions are running, digging holes in bricks and collecting
136  * gold.  If he is caught by an enemy or trapped in a closing brick, he dies.
137  * If he collects all the gold and runs to the top row, he wins the level.
138  */
139 class KGrHero : public KGrRunner
140 {
141     Q_OBJECT
142 public:
143     /**
144      * The constructor of the KGrHero class.  The parameters are the same as
145      * for the KGrRunner constructor, which does most of the work, but this
146      * constructor also initialises the hero's timing, which depends on the
147      * rules being used.
148      *
149      * @param pLevelPlayer The object that owns the hero and will destroy him
150      *                     if the KGoldrunner application is terminated during
151      *                     play.  The object also provides helper functions to
152      *                     the hero.
153      * @param pGrid        The grid on which the hero is playing.
154      * @param i            The starting column-number (>=1).
155      * @param j            The starting row-number (>=1).
156      * @param pSpriteId    The sprite ID of the hero, as used in animation.
157      * @param pRules       The rules that apply to this game and level.
158      */
159     KGrHero (KGrLevelPlayer * pLevelPlayer, KGrLevelGrid * pGrid,
160                 int i, int j, int pSpriteId, KGrRuleBook  * pRules);
161     ~KGrHero() override;
162 
163     /**
164      * Makes the hero run, under control of a pointer or the keyboard and
165      * guided by the layout of the grid.  The method is invoked by a periodic
166      * timer and returns NORMAL status while play continues.  If the hero is
167      * caught by an enemy or trapped in a brick, it returns DEAD status, or
168      * if he collects all the gold and reaches the top row, the method returns
169      * WON_LEVEL status.  Otherwise it changes the hero's position as required
170      * and decides the type of animation to display (run left, climb, etc.).
171      *
172      * @param scaledTime   The amount by which to adjust the time, scaled
173      *                     according to the current game-speed setting.  Smaller
174      *                     times cause slower running in real-time: larger times
175      *                     cause faster running.
176      *
177      * @return             The hero's status: NORMAL, DEAD or WON_LEVEL.
178      */
179     HeroStatus       run (const int scaledTime);
180 
181     /**
182      * Decides whether the hero can dig as is required by pressing a key or a
183      * mouse-button.  If OK, the KGrLevelPlayer will control the dug brick.
184      *
185      * @param dirn         The direction in which to dig: L or R of the hero.
186      * @param digI         The column-number of the brick (return by reference).
187      * @param digJ         The row-number of the brick (return by reference).
188      *
189      * @return             If true, a hole can be dug in the direction required.
190      */
191     bool             dig (const Direction dirn, int & digI, int & digJ);
192 
193     /**
194      * Tells the hero whether dig while falling is allowed, or not.
195      */
setDigWhileFalling(const bool dwf)196     inline void      setDigWhileFalling (const bool dwf)
197                                         { digWhileFalling = dwf; }
198 
199     /**
200      * Tells the hero how many gold nuggets are remaining.
201      *
202      * @param nGold        The number of gold nuggets remaining.
203      */
setNuggets(const int nGold)204     inline void      setNuggets (const int nGold) { nuggets = nGold; }
205 
206     /**
207      * Implements the author's debugging aid that shows the hero's state.
208      */
209     void             showState();
210 
211 Q_SIGNALS:
212     void             soundSignal (const int n, const bool onOff = true);
213     void             invalidDig();	// Warning re dig while falling.
214 
215 private:
216     bool             digWhileFalling;	// If dig while falling is allowed.
217     int              nuggets;		// Number of gold pieces remaining.
218 };
219 
220 
221 /**
222  * This class models the behaviour of an enemy.  It inherits from KGrRunner.
223  *
224  * An enemy's main functions are running, chasing the hero and collecting or
225  * dropping gold.  If he comes to a dug brick, he must fall in and give up any
226  * gold he is carrying.  If he is trapped in a closing brick, he dies but
227  * reappears elsewhere on the grid.
228  */
229 class KGrEnemy :     public KGrRunner
230 {
231     Q_OBJECT
232 public:
233     /**
234      * The constructor of the KGrEnemy class.
235      *
236      * @param pLevelPlayer The object that owns the enemy and will destroy him
237      *                     if the KGoldrunner application is terminated during
238      *                     play.  The object also provides helper functions to
239      *                     the enemies.
240      * @param pGrid        The grid on which the enemy is playing.
241      * @param i            The starting column-number (>=1).
242      * @param j            The starting row-number (>=1).
243      * @param pSpriteId    The sprite ID of the enemy, as used in animation.
244      * @param pRules       The rules that apply to this game and level.
245      */
246     KGrEnemy (KGrLevelPlayer * pLevelPlayer, KGrLevelGrid * pGrid,
247                  int i, int j, int pSpriteId, KGrRuleBook  * pRules);
248     ~KGrEnemy() override;
249 
250     /**
251      * Makes an enemy run, guided by the position of the hero and the layout of
252      * the grid.  The method is invoked by a periodic timer.  If the enemy is
253      * trapped in a brick, he reappears somewhere else on the grid, depending
254      * on the rules for the game and level.  While running, the enemy picks up
255      * and randomly drops gold.  If he comes to a dug brick, he must fall in
256      * and give up any gold he is carrying.  He can climb out after a time: or
257      * the hole might close first.  Otherwise the method changes the enemy's
258      * position as required, avoids collisions and decides the type of animation
259      * to display (run left, climb, etc.).
260      *
261      * @param scaledTime   The amount by which to adjust the time, scaled
262      *                     according to the current game-speed setting.  Smaller
263      *                     times cause slower running in real-time: larger times
264      *                     cause faster running.
265      */
266     void             run (const int scaledTime);
267 
268     /**
269      * Returns the direction in which the enemy is running: used for avoiding
270      * collisions with other enemies.
271      */
direction()272     inline Direction direction() { return (currDirection); }
273 
274     /**
275      * Returns the ID of an enemy who already occupied the same cell (or -1).
276      */
getPrevInCell()277     inline int       getPrevInCell()  { return (prevInCell); }
278 
279     /**
280      * Sets the ID of an enemy who already occupied the same cell (or -1).
281      *
282      * @param prevEnemy    The sprite ID of the previous enemy (or -1).
283      */
setPrevInCell(const int prevEnemy)284     inline void      setPrevInCell (const int prevEnemy) {
285                                     prevInCell = prevEnemy; }
286 
287     /**
288      * Returns true if the enemy is falling.
289      */
isFalling()290     inline bool      isFalling() { return falling; }
291 
292     /**
293      * Implements the author's debugging aid that shows the enemy's state.
294      */
295     void             showState();
296 
297 private:
298     char             rulesType;		// Rules type and enemy search method.
299 
300     int              nuggets;		// Number of gold pieces an enemy holds.
301     int              birthI;		// Enemy's starting position (used in
302     int              birthJ;		// KGoldrunner rules for re-birth).
303     int              prevInCell;	// ID of previous enemy in cell or -1.
304 
305     void             dropGold();
306     void             checkForGold();
307     void             dieAndReappear();
308 
309     void             reserveCell (const int i, const int j);
310     void             releaseCell (const int i, const int j);
311 };
312 
313 #endif // KGRRUNNER_H
314