1 /* GemRB - Infinity Engine Emulator
2  * Copyright (C) 2003 The GemRB Project
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  */
20 
21 /**
22  * @file Game.h
23  * Declares Game class, object representing current game state.
24  * @author The GemRB Project
25  */
26 
27 
28 
29 #ifndef GAME_H
30 #define GAME_H
31 
32 #include "exports.h"
33 #include "ie_types.h"
34 
35 #include "Callback.h"
36 #include "Resource.h"
37 #include "Scriptable/Scriptable.h"
38 #include "Scriptable/PCStatStruct.h"
39 #include "Variables.h"
40 #include "Video.h"
41 
42 #include <atomic>
43 #include <vector>
44 
45 namespace GemRB {
46 
47 class Actor;
48 class Map;
49 class Particles;
50 class TableMgr;
51 
52 //the size of the bestiary register
53 #define BESTIARY_SIZE 260
54 
55 //ShareXP flags
56 #define SX_DIVIDE  1   //divide XP among team members
57 #define SX_CR      2   //use challenge rating resolution
58 #define SX_COMBAT  4   //combat xp, adjusted by difficulty
59 
60 //joinparty flags
61 #define JP_JOIN     1  //refresh join time
62 #define JP_INITPOS  2  //init startpos
63 #define JP_SELECT   4  //select the actor after joining
64 
65 //protagonist mode
66 #define PM_NO       0  //no death checks
67 #define PM_YES      1  //if protagonist dies, game over
68 #define PM_TEAM     2  //if team dies, game over
69 
70 // Flags bits for SelectActor()
71 // !!! Keep these synchronized with GUIDefines.py !!!
72 #define SELECT_NORMAL   0x00
73 #define SELECT_REPLACE  0x01 // when selecting actor, deselect all others
74 #define SELECT_QUIET    0x02 // do not run handler when changing selection
75 
76 // Flags bits for EveryoneNearPoint()
77 #define ENP_CANMOVE     1    // also check if the PC can move
78 #define ENP_ONLYSELECT  2    // check only selected PC
79 
80 // GUI Control Status flags (saved in game)
81 #define CS_PARTY_AI  1   //enable party AI
82 #define CS_MEDIUM    2   //medium dialog
83 #define CS_LARGE     6   //large dialog, both bits set
84 #define CS_DIALOGSIZEMASK 6
85 #define CS_DIALOG    8   //dialog is running
86 #define CS_HIDEGUI   16  //hide all gui
87 #define CS_ACTION    32  //hide action pane
88 #define CS_PORTRAIT  64  //hide portrait pane
89 #define CS_MAPNOTES  128 //hide mapnotes
90 
91 //Weather bits
92 #define WB_NORMAL    0
93 #define WB_RAIN      1
94 #define WB_SNOW      2
95 #define WB_FOG       3
96 #define WB_TYPEMASK  3
97 #define WB_LIGHTRAIN 4
98 #define WB_MEDIUMRAIN 8
99 #define WB_HEAVYRAIN 12
100 #define WB_RAINMASK  12
101 #define WB_LIGHTWIND 0x10
102 #define WB_MEDWIND   0x20
103 #define WB_STRONGWING 0x30
104 #define WB_WINDMASK  0x30
105 
106 #define WB_RARELIGHTNING 0x40
107 #define WB_MEDLIGHTNING  0x80
108 #define WB_HEAVYLIGHTNING 0xc0
109 #define WB_LIGHTNINGMASK 0xc0
110 #define WB_INCREASESTORM   0x100
111 #define WB_HASWEATHER 0x200
112 
113 //Rest flags
114 #define REST_NOCHECKS 0
115 #define REST_AREA     1 // area checks
116 #define REST_SCATTER  2 // scattered party check
117 #define REST_CONTROL  4 // control check
118 #define REST_CRITTER  8 // hostiles check
119 
120 //Song types (hardcoded)
121 #define SONG_DAY        0
122 #define SONG_NIGHT      1
123 #define SONG_BATTLE     3
124 
125 /**
126  * @struct PCStruct
127  * Information about party member.
128  */
129 
130 struct PCStruct {
131 	ieWord   Selected;
132 	ieWord   PartyOrder;
133 	ieDword  OffsetToCRE;
134 	ieDword  CRESize;
135 	ieResRef CREResRef;
136 	ieDword  Orientation;
137 	ieResRef Area;
138 	ieWord   XPos;
139 	ieWord   YPos;
140 	ieWord   ViewXPos;
141 	ieWord   ViewYPos;
142 	ieWord   ModalState;
143 	ieWordSigned   Happiness;
144 	ieDword  Interact[MAX_INTERACT];
145 	ieWord   QuickWeaponSlot[MAX_QUICKWEAPONSLOT];
146 	ieWord   QuickWeaponHeader[MAX_QUICKWEAPONSLOT];
147 	ieResRef QuickSpellResRef[MAX_QSLOTS];
148 	ieWord   QuickItemSlot[MAX_QUICKITEMSLOT];
149 	ieWord   QuickItemHeader[MAX_QUICKITEMSLOT];
150 	char Name[32];
151 	ieDword  TalkCount;
152 	ieByte QSlots[GUIBT_COUNT];
153 	ieByte QuickSpellClass[MAX_QSLOTS];
154 };
155 
156 #define IE_GAM_JOURNAL 0
157 #define IE_GAM_QUEST_UNSOLVED 1
158 #define IE_GAM_QUEST_DONE  2
159 #define IE_GAM_JOURNAL_USER 3
160 
161 /**
162  * @struct GAMJournalEntry
163  * Single entry in a journal
164  */
165 
166 struct GAMJournalEntry {
167 	ieStrRef Text;
168 	ieDword  GameTime; // in game time seconds
169 	ieByte   Chapter;
170 	ieByte   unknown09;
171 	ieByte   Section;
172 	ieByte   Group;   // this is a GemRB extension
173 };
174 
175 // Saved location of party member.
176 struct GAMLocationEntry {
177 	ieResRef AreaResRef;
178 	Point Pos;
179 };
180 
181 //pst maze data structures (TODO: create a separate class?)
182 struct maze_entry {
183 	ieDword me_override;
184 	ieDword accessible;
185 	ieDword valid;
186 	ieDword trapped;
187 	ieDword traptype;
188 	ieWord walls;
189 	ieDword visited;
190 };
191 
192 struct maze_header {
193 	ieDword maze_sizex, maze_sizey;
194 	ieDword pos1x, pos1y;  //nordom's position
195 	ieDword pos2x, pos2y;  //main hall position
196 	ieDword pos3x, pos3y;  //foyer entrance
197 	ieDword pos4x, pos4y;  //unknown
198 	ieDword trapcount;     //based on map size
199 	ieDword initialized;   //set to 1
200 	ieDword unknown2c;     //unknown
201 	ieDword unknown30;     //unknown
202 };
203 
204 #define MAZE_ENTRY_SIZE sizeof(maze_entry)
205 #define MAZE_HEADER_SIZE sizeof(maze_header)
206 #define MAZE_MAX_DIM 8
207 #define MAZE_ENTRY_COUNT (MAZE_MAX_DIM*MAZE_MAX_DIM)
208 #define MAZE_DATA_SIZE (MAZE_ENTRY_COUNT*MAZE_ENTRY_SIZE+MAZE_HEADER_SIZE)
209 #define MAZE_DATA_SIZE_HARDCODED 1720
210 
211 //maze header indices
212 #define MH_POS1X      0
213 #define MH_POS1Y      1
214 #define MH_POS2X      2
215 #define MH_POS2Y      3
216 #define MH_POS3X      4
217 #define MH_POS3Y      5
218 #define MH_POS4X      6
219 #define MH_POS4Y      7
220 #define MH_TRAPCOUNT  8
221 #define MH_INITED     9
222 #define MH_UNKNOWN2C  10
223 #define MH_UNKNOWN30  11
224 
225 //maze entry indices
226 #define ME_OVERRIDE   0
227 #define ME_VALID      1
228 #define ME_ACCESSIBLE 2
229 #define ME_TRAP       3
230 #define ME_WALLS      4
231 #define ME_VISITED    5
232 
233 //ME_WALL bitfields
234 #define WALL_SOUTH    1
235 #define WALL_NORTH    2
236 #define WALL_EAST     4
237 #define WALL_WEST     8
238 
239 #define MAX_CRLEVEL 32
240 
241 typedef int CRRow[MAX_CRLEVEL];
242 
243 /**
244  * @class Game
245  * Object representing current game state, mostly party.
246  */
247 
248 class GEM_EXPORT Game : public Scriptable {
249 public:
250 	Game(void);
251 	~Game(void) override;
252 private:
253 	std::vector< Actor*> PCs;
254 	std::vector< Actor*> NPCs;
255 	std::vector< Map*> Maps;
256 	std::vector< GAMJournalEntry*> Journals;
257 	std::vector< GAMLocationEntry*> savedpositions;
258 	std::vector< GAMLocationEntry*> planepositions;
259 	std::vector< char*> mastarea;
260 	std::vector<std::vector<ResRef> > npclevels;
261 	int *bntchnc;
262 	int bntrows;
263 	CRRow *crtable = nullptr;
264 	ieResRef restmovies[8];
265 	ieResRef daymovies[8];
266 	ieResRef nightmovies[8];
267 	int MapIndex;
268 public:
269 	std::vector< Actor*> selected;
270 	int version;
271 	Variables* kaputz;
272 	ieByte* beasts;
273 	ieByte* mazedata; //only in PST
274 	ieResRef Familiars[9];
275 	ieDword CombatCounter;
276 	ieDword StateOverrideFlag, StateOverrideTime;
277 	ieDword BanterBlockFlag, BanterBlockTime;
278 
279 	/** Index of PC selected in non-walking environment (shops, inventory...) */
280 	int SelectedSingle;
281 	/** 0 if the protagonist's death doesn't cause game over */
282 	/** 1 if the protagonist's death causes game over */
283 	/** 2 if no check is needed (pst) */
284 	int protagonist;
285 	/** if party size exceeds this amount, a callback will be called */
286 	size_t partysize;
287 	ieDword Ticks;
288 	ieDword interval; // 1000/AI_UPDATE (a tenth of a round in ms)
289 	std::atomic_uint32_t GameTime {0};
290 	ieDword LastScriptUpdate; // GameTime at which UpdateScripts last ran
291 	ieDword RealTime;
292 	ieWord  WhichFormation;
293 	ieWord  Formations[5];
294 	ieDword PartyGold;
295 	ieWord NPCAreaViewed = 0;
296 	ieWord WeatherBits;
297 	ieDword CurrentLink; //named currentLink in original engine (set to -1)
298 	ieDword Reputation;
299 	ieDword ControlStatus; // used in bg2, iwd (where you can switch panes off)
300 	ieDword Expansion; // mostly used by BG2. IWD games set it to 3 on newgame
301 	ieResRef AnotherArea;
302 	ieResRef CurrentArea;
303 	ieResRef PreviousArea; //move here if the worldmap exit is illegal?
304 	ieResRef LoadMos;
305 	ieResRef TextScreen;
306 	Particles *weather;
307 	int event_timer;
308 	EventHandler event_handler;
309 	bool hasInfra = false;
310 	bool familiarBlock = false;
311 	bool PartyAttack = false;
312 	bool HOFMode = false;
313 private:
314 	/** reads the challenge rating table */
315 	void LoadCRTable();
316 	Actor *timestop_owner;
317 	ieDword timestop_end;
318 public:
319 	/** Returns the PC's slot count for partyID */
320 	int FindPlayer(unsigned int partyID) const;
321 	/** Returns actor by slot */
322 	Actor* GetPC(unsigned int slot, bool onlyalive) const;
323 	/** Finds an actor in party by party ID, returns Actor, if not there, returns NULL*/
324 	Actor* FindPC(unsigned int partyID) const;
325 	Actor* FindNPC(unsigned int partyID) const;
326 	/** Finds a global actor by global ID */
327 	Actor *GetGlobalActorByGlobalID(ieDword globalID) const;
328 	/** Finds an actor in party, returns slot, if not there, returns -1*/
329 	int InParty(const Actor *pc) const;
330 	/** Finds an actor in store, returns slot, if not there, returns -1*/
331 	int InStore(const Actor *pc) const;
332 	/** Finds an actor in party by scripting name*/
333 	Actor* FindPC(const char *deathvar) const;
334 	/** Finds an actor in store by scripting name*/
335 	Actor* FindNPC(const char *deathvar) const;
336 	/** Sets the area and position of the actor to the starting position */
337 	void InitActorPos(Actor *actor) const;
338 	/** Joins party */
339 	int JoinParty(Actor* pc, int join=JP_JOIN);
340 	/** Return current party size */
341 	int GetPartySize(bool onlyalive) const;
342 	/** Returns the npcs count */
GetNPCCount()343 	int GetNPCCount() const { return (int)NPCs.size(); }
344 	/** Sends the hotkey trigger to all selected pcs */
345 	void SendHotKey(unsigned long Key) const;
346 	/** Select PC for non-walking environment (shops, inventory, ...) */
347 	bool SelectPCSingle(int index);
348 	/** Get index of selected PC for non-walking env (shops, inventory, ...) */
349 	int GetSelectedPCSingle() const;
350 	Actor* GetSelectedPCSingle(bool onlyalive) const;
351 	/** (De)selects actor. */
352 	bool SelectActor( Actor* actor, bool select, unsigned flags );
353 
354 	/** Return current party level count for xp calculations */
355 	int GetTotalPartyLevel(bool onlyalive) const;
356 	/** Reassigns inparty numbers, call it after party creation */
357 	void ConsolidateParty() const;
358 	/** Removes actor from party (if in there) */
359 	int LeaveParty(Actor* pc);
360 	/** Returns slot*/
361 	int DelPC(unsigned int slot, bool autoFree = false);
362 	int DelNPC(unsigned int slot, bool autoFree = false);
363 	/** Returns map in index */
364 	Map* GetMap(unsigned int index) const;
365 	/** Returns a map from area name, loads it if needed
366 	 * use it for the biggest safety, change = true will change the current map */
367 	Map* GetMap(const char *areaname, bool change);
368 	/** Returns slot of the map if found */
369 	int FindMap(const char *ResRef) const;
370 	int AddMap(Map* map);
371 	/** Determine if area is master area*/
372 	bool MasterArea(const char *area) const;
373 	/** Dynamically adding an area to master areas*/
374 	void SetMasterArea(const char *area);
375 	/** Guess the master area of the given area*/
376 	//Map* GetMasterArea(const char *area);
377 	/** place persistent actors in the fresly loaded area*/
378 	void PlacePersistents(Map *map, const char *ResRef);
379 	/** Returns slot of the map, if it was already loaded,
380 	 * don't load it again, set changepf == true,
381 	 * if you want to change the pathfinder too. */
382 	int LoadMap(const char* ResRef, bool loadscreen);
383 	int DelMap(unsigned int index, int forced = 0);
384 	int AddNPC(Actor* npc);
385 	Actor* GetNPC(unsigned int Index) const;
386 	void SwapPCs(unsigned int pc1, unsigned int pc2) const;
387 	bool IsDay() const;
388 	/** checks if the actor should be replaced via npclevel.2da and then does it */
389 	bool CheckForReplacementActor(int i);
390 
391 	//journal entries
392 	/** Deletes one or all journal entries if strref is -1 */
393 	void DeleteJournalEntry(ieStrRef strref);
394 	/** Delete entries of the same group */
395 	void DeleteJournalGroup(int Group);
396 	/** Adds a journal entry from dialog data.
397 	 * Time and chapter are calculated on the fly
398 	 * Returns false if the entry already exists */
399 	bool AddJournalEntry(ieStrRef strref, int section, int group);
400 	/** Adds a journal entry while loading the .gam structure */
401 	void AddJournalEntry(GAMJournalEntry* entry);
402 	unsigned int GetJournalCount() const;
403 	GAMJournalEntry* FindJournalEntry(ieStrRef strref) const;
404 	GAMJournalEntry* GetJournalEntry(unsigned int Index) const;
405 
406 	//saved locations
407 	unsigned int GetSavedLocationCount() const;
408 	void ClearSavedLocations();
409 	GAMLocationEntry* GetSavedLocationEntry(unsigned int Index);
410 
411 	//plane locations
412 	unsigned int GetPlaneLocationCount() const;
413 	void ClearPlaneLocations();
414 	GAMLocationEntry* GetPlaneLocationEntry(unsigned int Index);
415 
416 	char *GetFamiliar(unsigned int Index);
417 
IsBeastKnown(unsigned int Index)418 	bool IsBeastKnown(unsigned int Index) const {
419 		if (!beasts) {
420 			return false;
421 		}
422 		if (Index>=BESTIARY_SIZE) {
423 			return false;
424 		}
425 		return beasts[Index] != 0;
426 	}
SetBeastKnown(unsigned int Index)427 	void SetBeastKnown(unsigned int Index) {
428 		if (!beasts) {
429 			return;
430 		}
431 		if (Index>=BESTIARY_SIZE) {
432 			return;
433 		}
434 		beasts[Index] = 1;
435 	}
GetFormation()436 	ieWord GetFormation() const {
437 		if (WhichFormation>4) {
438 			return 0;
439 		}
440 		return Formations[WhichFormation];
441 	}
442 
443 	/** converts challenge rating to xp */
444 	int GetXPFromCR(int cr) const;
445 	/** shares XP among all party members */
446 	void ShareXP(int XP, int flags) const;
447 	/** returns true if we should start the party overflow window */
448 	bool PartyOverflow() const;
449 	/** returns true if any pc is attacker or being attacked */
450 	bool AnyPCInCombat() const;
451 	/** returns true if the party death condition is true */
452 	bool EveryoneDead() const;
453 	/** returns true if no one moves */
454 	bool EveryoneStopped() const;
455 	bool EveryoneNearPoint(const Map *map, const Point &p, int flags) const;
456 	/** a party member just died now */
457 	void PartyMemberDied(const Actor *);
458 	/** Increments chapter variable and refreshes kill stats */
459 	void IncrementChapter() const;
460 	/** Sets party reputation */
461 	void SetReputation(ieDword r);
462 	/** Sets the gamescreen control status (pane states, dialog textarea size) */
463 	bool SetControlStatus(unsigned int value, int operation);
464 	/** Sets party size (1-32000) */
465 	void SetPartySize(int value);
466 	/** Sets a guiscript function to happen after x AI cycles have elapsed */
467 	void SetTimedEvent(EventHandler func, int count);
468 	/** Sets protagonist mode to 0-none,1-protagonist,2-team */
469 	void SetProtagonistMode(int value);
470 	void StartRainOrSnow(bool conditional, int weather);
GetLoadedMapCount()471 	size_t GetLoadedMapCount() const { return Maps.size(); }
472 	/** Adds or removes gold */
473 	void AddGold(int add);
474 	/** Adds ticks to game time */
475 	void AdvanceTime(ieDword add, bool fatigue=true);
476 	/** Runs the script engine on the global script and the area scripts
477 	areas run scripts on door, infopoint, container, actors too */
478 	void UpdateScripts();
479 	/** checks if resting is possible */
480 	int CanPartyRest(int checks) const;
481 	/** runs area functionality, sets partyrested trigger */
482 	bool RestParty(int checks, int dream, int hp);
483 	/** timestop effect initiated by actor */
484 	void TimeStop(Actor *actor, ieDword end);
485 	/** check if the passed actor is a victim of timestop */
486 	bool TimeStoppedFor(const Actor* target = nullptr) const;
487 	/** updates the infravision info */
488 	void Infravision();
489 	/** applies the global tint if it is needed */
490 	void ApplyGlobalTint(Color &tint, BlitFlags &flags) const;
491 	/** gets the colour which should be applied over the game area,
492 	may return NULL */
493 	const Color *GetGlobalTint() const;
494 	/** returns true if party has infravision */
PartyHasInfravision()495 	bool PartyHasInfravision() const { return hasInfra; }
496 	/** draw weather */
497 	void DrawWeather(bool update);
498 	/** updates current area music */
499 	void ChangeSong(bool always = true, bool force = true) const;
500 	/** sets expansion mode */
501 	void SetExpansion(ieDword value);
502 	/** Dumps information about the object */
503 	void dump() const;
504 	/** Finds an actor by global ID */
505 	Actor *GetActorByGlobalID(ieDword objectID) const;
506 	/** Allocates maze data */
507 	ieByte *AllocateMazeData();
508 	/** Checks if any timestop effects are active */
509 	bool IsTimestopActive() const;
510 	int RemainingTimestop() const;
GetTimestopOwner()511 	Actor *GetTimestopOwner() const { return timestop_owner; };
SetTimestopOwner(Actor * owner)512 	void SetTimestopOwner(Actor *owner) { timestop_owner = owner; };
513 	/** Checks the bounty encounters (used in bg1) */
514 	bool RandomEncounter(ieResRef &BaseArea);
515 	/** Resets the area and bored comment timers of the whole party */
516 	void ResetPartyCommentTimes() const;
517 	void ReversePCs() const;
518 	bool OnlyNPCsSelected() const;
519 private:
520 	bool DetermineStartPosType(const TableMgr *strta) const;
521 	ieResRef *GetDream(Map *area);
522 	void CastOnRest() const;
523 	void PlayerDream();
524 	void TextDream();
525 };
526 
527 }
528 
529 #endif  // ! GAME_H
530