File: CBattleInterface.h

package info (click to toggle)
vcmi 0.99%2Bdfsg%2Bgit20190113.f06c8a87-1
  • links: PTS, VCS
  • area: contrib
  • in suites: buster
  • size: 11,096 kB
  • sloc: cpp: 142,605; sh: 315; objc: 248; makefile: 32; ansic: 28; python: 13
file content (407 lines) | stat: -rw-r--r-- 17,318 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
/*
 * CBattleInterface.h, part of VCMI engine
 *
 * Authors: listed in file AUTHORS in main folder
 *
 * License: GNU General Public License v2.0 or later
 * Full text of license available in license.txt file, in main folder
 *
 */
#pragma once

#include "../../lib/ConstTransitivePtr.h" //may be reundant
#include "../../lib/GameConstants.h"

#include "CBattleAnimations.h"

#include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation

class CLabel;
class CCreatureSet;
class CGHeroInstance;
class CStack;
class CCallback;
class CButton;
class CToggleButton;
class CToggleGroup;
struct BattleResult;
struct BattleSpellCast;
struct CObstacleInstance;
template <typename T> struct CondSh;
struct SetStackEffect;
class BattleAction;
class CGTownInstance;
struct CatapultAttack;
struct CatapultProjectileInfo;
struct BattleTriggerEffect;
class CBattleAnimation;
class CBattleHero;
class CBattleConsole;
class CBattleResultWindow;
class CStackQueue;
class CPlayerInterface;
class CCreatureAnimation;
struct ProjectileInfo;
class CClickableHex;
struct BattleHex;
struct InfoAboutHero;
class CBattleGameInterface;
struct CustomEffectInfo;
class CAnimation;
class IImage;

/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo
{
	const CStack *defender; //attacked stack
	int64_t dmg; //damage dealt
	unsigned int amountKilled; //how many creatures in stack has been killed
	const CStack *attacker; //attacking stack
	bool indirectAttack; //if true, stack was attacked indirectly - spell or ranged attack
	bool killed; //if true, stack has been killed
	bool rebirth; //if true, play rebirth animation after all
	bool cloneKilled;
};

/// Struct for battle effect animation e.g. morale, prayer, armageddon, bless,...
struct BattleEffect
{
	int x, y; //position on the screen
	float currentFrame;
	std::shared_ptr<CAnimation> animation;
	int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
	BattleHex position; //Indicates if effect which hex the effect is drawn on
};

struct BattleObjectsByHex
{
	typedef std::vector<int> TWallList;
	typedef std::vector<const CStack *> TStackList;
	typedef std::vector<const BattleEffect *> TEffectList;
	typedef std::vector<std::shared_ptr<const CObstacleInstance>> TObstacleList;

	struct HexData
	{
		TWallList walls;
		TStackList dead;
		TStackList alive;
		TEffectList effects;
		TObstacleList obstacles;
	};

	HexData beforeAll;
	HexData afterAll;
	std::array<HexData, GameConstants::BFIELD_SIZE> hex;
};

/// Small struct which is needed for drawing the parabolic trajectory of the catapult cannon
struct CatapultProjectileInfo
{
	CatapultProjectileInfo(Point from, Point dest);

	double facA, facB, facC;

	double calculateY(double x);
};

/// Big class which handles the overall battle interface actions and it is also responsible for
/// drawing everything correctly.
class CBattleInterface : public WindowBase
{
	enum PossibleActions // actions performed at l-click
	{
		INVALID = -1, CREATURE_INFO,
		MOVE_TACTICS, CHOOSE_TACTICS_STACK,
		MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
		NO_LOCATION, ANY_LOCATION, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
		FREE_LOCATION, //used with Force Field and Fire Wall - all tiles affected by spell must be free
		CATAPULT, HEAL, RISE_DEMONS,
		AIMED_SPELL_CREATURE
	};
private:
	SDL_Surface *background, *menu, *amountNormal, *amountNegative, *amountPositive, *amountEffNeutral, *cellBorders, *backgroundWithHexes;

	std::shared_ptr<CButton> bOptions;
	std::shared_ptr<CButton> bSurrender;
	std::shared_ptr<CButton> bFlee;
	std::shared_ptr<CButton> bAutofight;
	std::shared_ptr<CButton> bSpell;
	std::shared_ptr<CButton> bWait;
	std::shared_ptr<CButton> bDefence;
	std::shared_ptr<CButton> bConsoleUp;
	std::shared_ptr<CButton> bConsoleDown;
	std::shared_ptr<CButton> btactNext;
	std::shared_ptr<CButton> btactEnd;

	std::shared_ptr<CBattleConsole> console;
	std::shared_ptr<CBattleHero> attackingHero;
	std::shared_ptr<CBattleHero> defendingHero;
	std::shared_ptr<CStackQueue> queue;

	const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
	const CGHeroInstance *attackingHeroInstance, *defendingHeroInstance;
	std::map<int32_t, std::shared_ptr<CCreatureAnimation>> creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)

	std::map<int, std::shared_ptr<CAnimation>> idToProjectile;

	std::map<std::string, std::shared_ptr<CAnimation>> animationsCache;
	std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations;

	std::map<int, bool> creDir; // <creatureID, if false reverse creature's animation> //TODO: move it to battle callback
	ui8 animCount;
	const CStack *activeStack; //number of active stack; nullptr - no one
	const CStack *mouseHoveredStack; // stack below mouse pointer, used for border animation
	const CStack *stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; nullptr of none
	const CStack *selectedStack; //for Teleport / Sacrifice
	void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
	std::vector<BattleHex> occupyableHexes, //hexes available for active stack
		attackableHexes; //hexes attackable by active stack
	bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
	BattleHex previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
	BattleHex currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
	int attackingHex; //hex from which the stack would perform attack with current cursor

	std::shared_ptr<CPlayerInterface> tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
	bool tacticsMode;
	bool stackCanCastSpell; //if true, active stack could possibly cast some target spell
	bool creatureCasting; //if true, stack currently aims to cats a spell
	bool spellDestSelectMode; //if true, player is choosing destination for his spell - only for GUI / console
	std::shared_ptr<BattleAction> spellToCast; //spell for which player is choosing destination
	const CSpell *sp; //spell pointer for convenience
	si32 creatureSpellToCast;
	std::vector<PossibleActions> possibleActions; //all actions possible to call at the moment by player
	std::vector<PossibleActions> localActions; //actions possible to take on hovered hex
	std::vector<PossibleActions> illegalActions; //these actions display message in case of illegal target
	PossibleActions currentAction; //action that will be performed on l-click
	PossibleActions selectedAction; //last action chosen (and saved) by player
	PossibleActions illegalAction; //most likely action that can't be performed here

	void setActiveStack(const CStack *stack);
	void setHoveredStack(const CStack *stack);

	void requestAutofightingAIToTakeAction();

	void getPossibleActionsForStack (const CStack *stack, const bool forceCast); //called when stack gets its turn
	void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)

	//force active stack to cast a spell if possible
	void enterCreatureCastingMode();

	void printConsoleAttacked(const CStack *defender, int dmg, int killed, const CStack *attacker, bool Multiple);

	std::list<ProjectileInfo> projectiles; //projectiles flying on battlefield
	void giveCommand(EActionType action, BattleHex tile = BattleHex(), si32 additional = -1);
	void sendCommand(BattleAction *& command, const CStack * actor = nullptr);

	bool isTileAttackable(const BattleHex & number) const; //returns true if tile 'number' is neighboring any tile from active stack's range or is one of these tiles
	bool isCatapultAttackable(BattleHex hex) const; //returns true if given tile can be attacked by catapult

	std::list<BattleEffect> battleEffects; //different animations to display on the screen like spell effects

	/// Class which is responsible for drawing the wall of a siege during battle
	class SiegeHelper
	{
	private:
		SDL_Surface* walls[18];
		const CBattleInterface *owner;
	public:
		const CGTownInstance *town; //besieged town

		SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface *_owner);
		~SiegeHelper();

		std::string getSiegeName(ui16 what) const;
		std::string getSiegeName(ui16 what, int state) const; // state uses EWallState enum

		void printPartOfWall(SDL_Surface *to, int what);

		enum EWallVisual
		{
			BACKGROUND = 0,
			BACKGROUND_WALL = 1,
			KEEP,
			BOTTOM_TOWER,
			BOTTOM_WALL,
			WALL_BELLOW_GATE,
			WALL_OVER_GATE,
			UPPER_WALL,
			UPPER_TOWER,
			GATE,
			GATE_ARCH,
			BOTTOM_STATIC_WALL,
			UPPER_STATIC_WALL,
			MOAT,
			BACKGROUND_MOAT,
			KEEP_BATTLEMENT,
			BOTTOM_BATTLEMENT,
			UPPER_BATTLEMENT
		};

		friend class CBattleInterface;
	} *siegeH;

	std::shared_ptr<CPlayerInterface> attackerInt, defenderInt; //because LOCPLINT is not enough in hotSeat
	std::shared_ptr<CPlayerInterface> curInt; //current player interface
	const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell

	/** Methods for displaying battle screen */
	void showBackground(SDL_Surface *to);

	void showBackgroundImage(SDL_Surface *to);
	void showAbsoluteObstacles(SDL_Surface *to);
	void showHighlightedHexes(SDL_Surface *to);
	void showHighlightedHex(SDL_Surface *to, BattleHex hex, bool darkBorder = false);
	void showInterface(SDL_Surface *to);

	void showBattlefieldObjects(SDL_Surface *to);

	void showAliveStacks(SDL_Surface *to, std::vector<const CStack *> stacks);
	void showStacks(SDL_Surface *to, std::vector<const CStack *> stacks);
	void showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance>> &obstacles);
	void showPiecesOfWall(SDL_Surface *to, std::vector<int> pieces);

	void showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects);
	void showProjectiles(SDL_Surface *to);

	BattleObjectsByHex sortObjectsByHex();
	void updateBattleAnimations();

	std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi);

	Point getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle);

	void redrawBackgroundWithHexes(const CStack *activeStack);
	/** End of battle screen blitting methods */

	PossibleActions getCasterAction(const CSpell *spell, const spells::Caster *caster, spells::Mode mode) const;

	void setHeroAnimation(ui8 side, int phase);
public:
	static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
	static CondSh<BattleAction *> givenCommand; //data != nullptr if we have i.e. moved current unit

	std::list<std::pair<CBattleAnimation *, bool>> pendingAnims; //currently displayed animations <anim, initialized>
	void addNewAnim(CBattleAnimation *anim); //adds new anim to pendingAnims
	ui32 animIDhelper; //for giving IDs for animations


	CBattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const SDL_Rect & myRect, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
	virtual ~CBattleInterface();

	//std::vector<TimeInterested*> timeinterested; //animation handling
	void setPrintCellBorders(bool set); //if true, cell borders will be printed
	void setPrintStackRange(bool set); //if true,range of active stack will be printed
	void setPrintMouseShadow(bool set); //if true, hex under mouse will be shaded
	void setAnimSpeed(int set); //speed of animation; range 1..100
	int getAnimSpeed() const; //speed of animation; range 1..100
	CPlayerInterface *getCurrentPlayerInterface() const;

	std::vector<std::shared_ptr<CClickableHex>> bfield; //11 lines, 17 hexes on each
	SDL_Surface *cellBorder, *cellShade;

	bool myTurn; //if true, interface is active (commands can be ordered)

	bool moveStarted; //if true, the creature that is already moving is going to make its first step
	int moveSoundHander; // sound handler used when moving a unit

	const BattleResult *bresult; //result of a battle; if non-zero then display when all animations end

	// block all UI elements, e.g. during enemy turn
	// unlike activate/deactivate this method will correctly grey-out all elements
	void blockUI(bool on);

	//button handle funcs:
	void bOptionsf();
	void bSurrenderf();
	void bFleef();
	void reallyFlee(); //performs fleeing without asking player
	void reallySurrender(); //performs surrendering without asking player
	void bAutofightf();
	void bSpellf();
	void bWaitf();
	void bDefencef();
	void bConsoleUpf();
	void bConsoleDownf();
	void bTacticNextStack(const CStack *current = nullptr);
	void bEndTacticPhase();
	//end of button handle funcs
	//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem
	void activate() override;
	void deactivate() override;
	void keyPressed(const SDL_KeyboardEvent & key) override;
	void mouseMoved(const SDL_MouseMotionEvent &sEvent) override;
	void clickRight(tribool down, bool previousState) override;

	void show(SDL_Surface *to) override;
	void showAll(SDL_Surface *to) override;

	//call-ins
	void startAction(const BattleAction* action);
	void unitAdded(const CStack * stack); //new stack appeared on battlefield
	void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
	void stackActivated(const CStack *stack); //active stack has been changed
	void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance); //stack with id number moved to destHex
	void waitForAnims();
	void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos, const std::vector<MetaString> & battleLog); //called when a certain amount of stacks has been attacked
	void stackAttacking(const CStack *attacker, BattleHex dest, const CStack *attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
	void newRoundFirst( int round );
	void newRound(int number); //caled when round is ended; number is the number of round
	void hexLclicked(int whichOne); //hex only call-in
	void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
	void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
	void displayBattleFinished(); //displays battle result
	void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell
	void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
	void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook

	void displayBattleLog(const std::vector<MetaString> & battleLog);
	void displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects);

	void displayEffect(ui32 effect, BattleHex destTile); //displays custom effect on the battlefield

	void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation
	void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
	void displaySpellHit(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation

	void displaySpellAnimation(const CSpell::TAnimation & animation, BattleHex destinationTile);

	void battleTriggerEffect(const BattleTriggerEffect & bte);
	void setBattleCursor(const int myNumber); //really complex and messy, sets attackingHex
	void endAction(const BattleAction* action);
	void hideQueue();
	void showQueue();

	Rect hexPosition(BattleHex hex) const;

	void handleHex(BattleHex myNumber, int eventType);
	bool isCastingPossibleHere (const CStack *sactive, const CStack *shere, BattleHex myNumber);
	bool canStackMoveHere (const CStack *sactive, BattleHex MyNumber); //TODO: move to BattleState / callback

	BattleHex fromWhichHexAttack(BattleHex myNumber);
	void obstaclePlaced(const CObstacleInstance & oi);

	void gateStateChanged(const EGateState state);

	void initStackProjectile(const CStack * stack);

	const CGHeroInstance *currentHero() const;
	InfoAboutHero enemyHero() const;

	friend class CPlayerInterface;
	friend class CButton;
	friend class CInGameConsole;

	friend class CBattleResultWindow;
	friend class CBattleHero;
	friend class CEffectAnimation;
	friend class CBattleStackAnimation;
	friend class CReverseAnimation;
	friend class CDefenceAnimation;
	friend class CMovementAnimation;
	friend class CMovementStartAnimation;
	friend class CAttackAnimation;
	friend class CMeleeAttackAnimation;
	friend class CShootingAnimation;
	friend class CCastAnimation;
	friend class CClickableHex;
};