1 // ==============================================================
2 //	This file is part of Glest (www.glest.org)
3 //
4 //	Copyright (C) 2001-2008 Martiño Figueroa
5 //
6 //	You can redistribute this code and/or modify it under
7 //	the terms of the GNU General Public License as published
8 //	by the Free Software Foundation; either version 2 of the
9 //	License, or (at your option) any later version
10 // ==============================================================
11 
12 /**
13  * @file
14  * Classified the Upgrade type (which is sort of like a class for upgrades). Each upgrade has a
15  * type that details the stats that it boosts and the units that it affects. Also has TotalUpgrade,
16  * which is a sum of all upgrades applied to a particular unit (and is what determines how units
17  * stats are modified by an upgrade.
18  */
19 
20 #ifndef _GLEST_GAME_UPGRADETYPE_H_
21 #define _GLEST_GAME_UPGRADETYPE_H_
22 
23 #ifdef WIN32
24     #include <winsock2.h>
25     #include <winsock.h>
26 #endif
27 
28 #include "element_type.h"
29 #include "checksum.h"
30 #include "conversion.h"
31 #include "xml_parser.h"
32 #include "leak_dumper.h"
33 #include <set>
34 
35 using Shared::Util::Checksum;
36 using namespace Shared::Util;
37 using namespace Shared::Xml;
38 
39 namespace Glest { namespace Game {
40 
41 class TechTree;
42 class FactionType;
43 class UnitType;
44 class Unit;
45 class SkillType;
46 class AttackSkillType;
47 class MoveSkillType;
48 class ProduceSkillType;
49 class Faction;
50 
51 /**
52  * Groups all information used for upgrades. Attack boosts also use this class for modifying stats.
53  */
54 class UpgradeTypeBase {
55 protected:
56 	string upgradename;
57     int maxHp;
58     bool maxHpIsMultiplier;
59 	int maxHpRegeneration;
60 	//bool maxHpRegenerationIsMultiplier;
61 
62     int sight;
63     bool sightIsMultiplier;
64 
65     int maxEp;
66     bool maxEpIsMultiplier;
67 	int maxEpRegeneration;
68 	//bool maxEpRegenerationIsMultiplier;
69 
70     int armor;
71     bool armorIsMultiplier;
72 
73     int attackStrength;
74     bool attackStrengthIsMultiplier;
75 	/**
76 	 * List of the values (for each skill type) that the stat was boosted by. This is used so
77 	 * that we can restore the original values when the upgrade is removed (eg, an attack
78 	 * boost wears off).
79 	 */
80     std::map<string,int> attackStrengthMultiplierValueList;
81 
82     int attackRange;
83     bool attackRangeIsMultiplier;
84     std::map<string,int> attackRangeMultiplierValueList; /**< @see #attackStrengthMultiplierValueList */
85 
86     int moveSpeed;
87     bool moveSpeedIsMultiplier;
88     std::map<string,int> moveSpeedIsMultiplierValueList; /**< @see #attackStrengthMultiplierValueList */
89 
90     int prodSpeed;
91     bool prodSpeedIsMultiplier;
92     std::map<string,int> prodSpeedProduceIsMultiplierValueList; /**< @see #attackStrengthMultiplierValueList */
93     std::map<string,int> prodSpeedUpgradeIsMultiplierValueList; /**< @see #attackStrengthMultiplierValueList */
94     std::map<string,int> prodSpeedMorphIsMultiplierValueList; /**< @see #attackStrengthMultiplierValueList */
95 
96 	int attackSpeed;
97 	bool attackSpeedIsMultiplier;
98 	std::map<string,int> attackSpeedIsMultiplierValueList;
99 
100 protected:
101 
getAttackStrength()102 	virtual int getAttackStrength() const { return attackStrength; }
getAttackRange()103 	virtual int getAttackRange() const { return attackRange; }
getMoveSpeed()104 	virtual int getMoveSpeed() const { return moveSpeed; }
getProdSpeed()105 	virtual int getProdSpeed() const { return prodSpeed; }
getAttackSpeed()106 	virtual int getAttackSpeed() const { return attackSpeed; }
107 
getMaxHpFromBoosts()108     virtual int getMaxHpFromBoosts() const { return 0; }
getMaxHpRegenerationFromBoosts()109     virtual int getMaxHpRegenerationFromBoosts() const { return 0; }
getSightFromBoosts()110     virtual int getSightFromBoosts() const { return 0; }
getMaxEpFromBoosts()111     virtual int getMaxEpFromBoosts() const { return 0; }
getMaxEpRegenerationFromBoosts()112     virtual int getMaxEpRegenerationFromBoosts() const { return 0; }
getArmorFromBoosts()113     virtual int getArmorFromBoosts() const { return 0; };
getAttackStrengthFromBoosts(const AttackSkillType * st)114     virtual int getAttackStrengthFromBoosts(const AttackSkillType *st) const { return 0; }
getAttackRangeFromBoosts(const AttackSkillType * st)115     virtual int getAttackRangeFromBoosts(const AttackSkillType *st) const { return 0; }
getMoveSpeedFromBoosts(const MoveSkillType * st)116     virtual int getMoveSpeedFromBoosts(const MoveSkillType *st) const { return 0; }
getProdSpeedFromBoosts(const SkillType * st)117     virtual int getProdSpeedFromBoosts(const SkillType *st) const { return 0; }
getAttackSpeedFromBoosts(const AttackSkillType * st)118     virtual int getAttackSpeedFromBoosts(const AttackSkillType *st) const { return 0; }
119 
120 public:
121 	/**
122 	 * Creates an UpgradeTypeBase with values such that there are no stat changes.
123 	 */
UpgradeTypeBase()124     UpgradeTypeBase() {
125         maxHp = 0;;
126         maxHpIsMultiplier = false;
127     	maxHpRegeneration = 0;
128         sight = 0;
129         sightIsMultiplier = false;
130         maxEp = 0;;
131         maxEpIsMultiplier = false;
132     	maxEpRegeneration = 0;
133         armor = 0;
134         armorIsMultiplier = false;
135         attackStrength = 0;
136         attackStrengthIsMultiplier = false;
137         attackRange = 0;
138         attackRangeIsMultiplier = false;
139         moveSpeed = 0;
140         moveSpeedIsMultiplier = false;
141         prodSpeed = 0;
142         prodSpeedIsMultiplier = false;
143         attackSpeed = 0;
144         attackSpeedIsMultiplier = false;
145     }
~UpgradeTypeBase()146     virtual ~UpgradeTypeBase() {}
147 
148 	virtual void copyDataFrom(UpgradeTypeBase *source);
149 
getUpgradeName()150     virtual string getUpgradeName() const { return upgradename; }
getMaxHp()151     virtual int getMaxHp() const			{return maxHp;}
getMaxHpRegeneration()152     virtual int getMaxHpRegeneration() const			{return maxHpRegeneration;}
getSight()153     virtual int getSight() const			{return sight;}
getMaxEp()154     virtual int getMaxEp() const			{return maxEp;}
getMaxEpRegeneration()155     virtual int getMaxEpRegeneration() const			{return maxEpRegeneration;}
getArmor()156     virtual int getArmor() const			{return armor;}
157     virtual int getAttackStrength(const AttackSkillType *st) const;
158     virtual int getAttackRange(const AttackSkillType *st) const;
159     virtual int getMoveSpeed(const MoveSkillType *st) const;
160     virtual int getProdSpeed(const SkillType *st) const;
161     virtual int getAttackSpeed(const AttackSkillType *st) const;
162 
getAttackStrengthIsMultiplier()163 	virtual bool getAttackStrengthIsMultiplier() const	{return attackStrengthIsMultiplier;}
getMaxHpIsMultiplier()164 	virtual bool getMaxHpIsMultiplier() const			{return maxHpIsMultiplier;}
getSightIsMultiplier()165 	virtual bool getSightIsMultiplier() const			{return sightIsMultiplier;}
getMaxEpIsMultiplier()166 	virtual bool getMaxEpIsMultiplier() const			{return maxEpIsMultiplier;}
getArmorIsMultiplier()167 	virtual bool getArmorIsMultiplier() const			{return armorIsMultiplier;}
getAttackRangeIsMultiplier()168 	virtual bool getAttackRangeIsMultiplier() const		{return attackRangeIsMultiplier;}
getMoveSpeedIsMultiplier()169 	virtual bool getMoveSpeedIsMultiplier() const		{return moveSpeedIsMultiplier;}
getProdSpeedIsMultiplier()170 	virtual bool getProdSpeedIsMultiplier() const		{return prodSpeedIsMultiplier;}
getAttackSpeedIsMultiplier()171 	virtual bool getAttackSpeedIsMultiplier() const		{return attackSpeedIsMultiplier;}
172 
173 	/**
174 	 * Loads the upgrade values (stat boosts and whether or not the boosts use a multiplier) from an
175 	 * XML node.
176 	 * @param upgradeNode Node containing the stat boost elements (`max-hp`, `attack-strength`, etc).
177 	 * @param upgradename Unique identifier for the upgrade.
178 	 */
179 
180     virtual void load(const XmlNode *upgradeNode, string upgradename);
181 
182 	/**
183 	 * Creates a string representation of the upgrade. All stat boosts are detailed on their own line
184 	 * with their corresponding boosts.
185 	 * @param translatedValue If true, the description is translated. Otherwise the description uses
186 	 * names as they appear in the XMLs.
187 	 */
188     virtual string getDesc(bool translatedValue) const;
189 
190 	/**
191 	 * Returns a string representation of this object. Lists all the value that the object stores.
192 	 * For debugging purposes, only.
193 	 */
toString()194     virtual std::string toString() const {
195 		std::string result = "";
196 
197 		result += "upgradename =" + getUpgradeName();
198 		result += "maxHp = " + intToStr(getMaxHp());
199 		result += "maxHpIsMultiplier = " + intToStr(getMaxHpIsMultiplier());
200 		result += "maxHpRegeneration = " + intToStr(getMaxHpRegeneration());
201 		//result += "maxHpRegenerationIsMultiplier = " + intToStr(maxHpRegenerationIsMultiplier);
202 
203 		result += " sight = " + intToStr(getSight());
204 		result += "sightIsMultiplier = " + intToStr(getSightIsMultiplier());
205 
206 		result += " maxEp = " + intToStr(getMaxEp());
207 		result += " maxEpIsMultiplier = " + intToStr(getMaxEpIsMultiplier());
208 		result += " maxEpRegeneration = " + intToStr(getMaxEpRegeneration());
209 		//result += "maxEpRegenerationIsMultiplier = " + intToStr(maxEpRegenerationIsMultiplier);
210 
211 		result += " armor = " + intToStr(getArmor());
212 		result += " armorIsMultiplier = " + intToStr(getArmorIsMultiplier());
213 		result += " attackStrength = " + intToStr(getAttackStrength());
214 		result += " attackStrengthIsMultiplier = " + intToStr(getAttackStrengthIsMultiplier());
215 		result += " attackRange = " + intToStr(getAttackRange());
216 		result += " attackRangeIsMultiplier = " + intToStr(getAttackRangeIsMultiplier());
217 		result += " moveSpeed = " + intToStr(getMoveSpeed());
218 		result += " moveSpeedIsMultiplier = " + intToStr(getMoveSpeedIsMultiplier());
219 		result += " prodSpeed = " + intToStr(getProdSpeed());
220 		result += " prodSpeedIsMultiplier = " + intToStr(getProdSpeedIsMultiplier());
221 
222 		return result;
223 	}
224 
225 	// TODO: It's not clear if these save game methods are being used, currently. I think
226 	// attack boosts might use the few lines that aren't commented out.
227 	virtual void saveGame(XmlNode *rootNode) const;
228 	virtual void saveGameBoost(XmlNode *rootNode) const;
229 	static const UpgradeType * loadGame(const XmlNode *rootNode, Faction *faction);
230 	void loadGameBoost(const XmlNode *rootNode);
231 
232 	/**
233 	 * Generates a checksum value for the upgrade.
234 	 */
getCRC()235 	virtual Checksum getCRC() {
236 		Checksum crcForUpgradeType;
237 
238 		crcForUpgradeType.addString(getUpgradeName());
239 		crcForUpgradeType.addInt(getMaxHp());
240 		crcForUpgradeType.addInt(getMaxHpIsMultiplier());
241 	    crcForUpgradeType.addInt(getMaxHpRegeneration());
242 
243 	    crcForUpgradeType.addInt(getSight());
244 	    crcForUpgradeType.addInt(getSightIsMultiplier());
245 
246 	    crcForUpgradeType.addInt(getMaxEp());
247 	    crcForUpgradeType.addInt(getMaxEpIsMultiplier());
248 	    crcForUpgradeType.addInt(getMaxEpRegeneration());
249 
250 	    crcForUpgradeType.addInt(getArmor());
251 	    crcForUpgradeType.addInt(getArmorIsMultiplier());
252 
253 	    crcForUpgradeType.addInt(getAttackStrength());
254 	    crcForUpgradeType.addInt(getAttackStrengthIsMultiplier());
255 	    //std::map<string,int> attackStrengthMultiplierValueList;
256 	    crcForUpgradeType.addInt64((int64)attackStrengthMultiplierValueList.size());
257 
258 	    crcForUpgradeType.addInt(getAttackRange());
259 	    crcForUpgradeType.addInt(getAttackRangeIsMultiplier());
260 	    //std::map<string,int> attackRangeMultiplierValueList;
261 	    crcForUpgradeType.addInt64((int64)attackRangeMultiplierValueList.size());
262 
263 	    crcForUpgradeType.addInt(getMoveSpeed());
264 	    crcForUpgradeType.addInt(getMoveSpeedIsMultiplier());
265 	    //std::map<string,int> moveSpeedIsMultiplierValueList;
266 	    crcForUpgradeType.addInt64((int64)moveSpeedIsMultiplierValueList.size());
267 
268 	    crcForUpgradeType.addInt(getProdSpeed());
269 	    crcForUpgradeType.addInt(getProdSpeedIsMultiplier());
270 	    //std::map<string,int> prodSpeedProduceIsMultiplierValueList;
271 	    crcForUpgradeType.addInt64((int64)prodSpeedProduceIsMultiplierValueList.size());
272 	    //std::map<string,int> prodSpeedUpgradeIsMultiplierValueList;
273 	    crcForUpgradeType.addInt64((int64)prodSpeedUpgradeIsMultiplierValueList.size());
274 	    //std::map<string,int> prodSpeedMorphIsMultiplierValueList;
275 	    crcForUpgradeType.addInt64((int64)prodSpeedMorphIsMultiplierValueList.size());
276 
277 	    crcForUpgradeType.addInt(getAttackSpeed());
278 	    crcForUpgradeType.addInt(getAttackSpeedIsMultiplier());
279 
280 		return crcForUpgradeType;
281 	}
282 };
283 
284 /**
285  * Represents the type of upgrade. That is, the single upgrade as it appears in the faction's XML
286  * files. Each upgrade has a single `UpgradeType`. Contains information about what units are
287  * affected by the upgrade.
288  */
289 class UpgradeType: public UpgradeTypeBase, public ProducibleType {
290 private:
291 	/**
292 	* Set of unit types (the "classes" of units, eg, swordman) that are affected by this upgrade.
293 	*/
294     std::set<const UnitType*> effects;
295     std::set<string> tags;
296 
297 public:
298 	/**
299 	 * Sets the upgrade name to the directory name (the base name of `dir`).
300 	 * @param dir Path of the upgrade directory.
301 	 */
302 	void preLoad(const string &dir);
303 
304 	/**
305 	 * Loads an upgrade from an XML file.
306 	 * @param dir Path of the upgrade directory. The file name is determined from this.
307 	 * @param techTree The techtree that this upgrade is in. Used to access the common data
308 	 * directory and to access resources.
309 	 * @param factionType The faction type (a unique type for each faction) that the upgrade belongs
310 	 * to. Used for accessing unit types that are in the unit requirements list.
311 	 * @param checksum Will have the checksum of the upgrade path added to it (treated the same way
312 	 * as the `techtreeChecksum`).
313 	 * @param techtreeChecksum Cumulative checksum for the techtree. The path of loaded upgrades
314 	 * is added to this checksum.
315 	 */
316     void load(const string &dir, const TechTree *techTree,
317     		const FactionType *factionType, Checksum* checksum,
318     		Checksum* techtreeChecksum,
319     		std::map<string,vector<pair<string, string> > > &loadedFileList,
320     		bool validationMode=false);
321 
322 	/**
323 	 * Obtains the upgrade name.
324 	 * @param translatedValue If true, the name is translated. Otherwise the name is returned as it
325 	 * appears in the XMLs.
326 	 */
327     virtual string getName(bool translatedValue=false) const;
328 	string getTagName(string tag, bool translatedValue=false) const;
329 
330 	/**
331 	 * Determines if a unit is affected by this upgrade.
332 	 * @param unitType The UnitType we are checking (to see if they're affected).
333 	 * @return True if the unit is affected, false otherwise.
334 	 */
335 	bool isAffected(const UnitType *unitType) const;
336 
337     /**
338 	 * Creates a description for this upgrade. Lists the affected units.
339 	 */
340 	virtual string getReqDesc(bool translatedValue) const;
341 
342 	//virtual void saveGame(XmlNode *rootNode) const;
343 	//virtual void loadGame(const XmlNode *rootNode);
344 };
345 
346 /**
347  * Keeps track of the cumulative effects of upgrades on units. This allows us to apply multiple
348  * upgrades to a unit with the effects stacking.
349  */
350 class TotalUpgrade: public UpgradeTypeBase {
351 
352 private:
353 
354 	// List of boosts
355 	const UpgradeTypeBase *boostUpgradeBase;
356 	int boostUpgradeSourceUnit;
357 	int boostUpgradeDestUnit;
358 	std::vector<TotalUpgrade *> boostUpgrades;
359 
360 public:
361 	TotalUpgrade();
~TotalUpgrade()362 	virtual ~TotalUpgrade() {}
363 
364 	/**
365 	 * Resets all stat boosts (so there's effectively no upgrade).
366 	 */
367 	void reset();
368 
369 	/**
370 	 * Adds an upgrade to this one, stacking the effects. Note that multipliers are stacked
371 	 * by multiplying by the original, unboosted amount, and then adding that to the TotalUpgrade.
372 	 * @param ut The upgrade to apply.
373 	 * @param unit The unit this TotalUpgrade is associated with (since when we use a multiplier,
374 	 * the stats raise by an amount relative to the unit's base stats).
375 	 */
376 	void sum(const UpgradeTypeBase *ut, const Unit *unit, bool boostMode=false);
377 
378 	/**
379 	 * Increases the level of the unit. Doing so results in their HP, EP, and armour going up by
380 	 * 50% while their sight goes up by 20%.
381 	 * @param ut The unit type to get the original stats from (so we can determine just how much
382 	 * to increase the stats by on level up).
383 	 */
384 	void incLevel(const UnitType *ut);
385 
386 	/**
387 	 * Applies the upgrade. Just a delegate to TotalUpgrade::sum.
388 	 */
389 	void apply(int sourceUnitId, const UpgradeTypeBase *ut, const Unit *unit);
390 
391 	/**
392 	 * Removes the effect of an upgrade to a specific unit. Using this after applying the upgrade
393 	 * is an invariant. ie,
394 	 *
395 	 *     totalUpgrade->apply(upgrade, unit);
396 	 *     totalUpgrade->deapply(upgrade, unit);
397 	 *     // totalUpgrade is now the same as before the call to apply()
398 	 *
399 	 * @param ut The upgrade to remove.
400 	 * @param unit The unit this TotalUpgrade is associated with (since when we use a multiplier,
401 	 * the stats were raise by an amount relative to the unit's base stats).
402 	 */
403 	void deapply(int sourceUnitId, const UpgradeTypeBase *ut,int destUnitId);
404 
405     virtual int getMaxHp() const;
406     virtual int getMaxHpRegeneration() const;
407     virtual int getSight() const;
408     virtual int getMaxEp() const;
409     virtual int getMaxEpRegeneration() const;
410     virtual int getArmor() const;
411     virtual int getAttackStrength(const AttackSkillType *st) const;
412     virtual int getAttackRange(const AttackSkillType *st) const;
413     virtual int getMoveSpeed(const MoveSkillType *st) const;
414     virtual int getProdSpeed(const SkillType *st) const;
415     virtual int getAttackSpeed(const AttackSkillType *st) const;
416 
417     virtual int getMaxHpFromBoosts() const;
418     virtual int getMaxHpRegenerationFromBoosts() const;
419     virtual int getSightFromBoosts() const;
420     virtual int getMaxEpFromBoosts() const;
421     virtual int getMaxEpRegenerationFromBoosts() const;
422     virtual int getArmorFromBoosts() const;
423     virtual int getAttackStrengthFromBoosts(const AttackSkillType *st) const;
424     virtual int getAttackRangeFromBoosts(const AttackSkillType *st) const;
425     virtual int getMoveSpeedFromBoosts(const MoveSkillType *st) const;
426     virtual int getProdSpeedFromBoosts(const SkillType *st) const;
427     virtual int getAttackSpeedFromBoosts(const AttackSkillType *st) const;
428 
429 	/**
430 	 * Creates the XML for the save game file. Essentially just stores everything about its state.
431 	 * @rootNode The node of the unit that this TotalUpgrade object belongs to.
432 	 */
433 	void saveGame(XmlNode *rootNode) const;
434 
435 	/**
436 	 * Reloads the object's state from a saved game.
437 	 * @rootNode The node of the unit that this TotalUpgrade object belongs to.
438 	 */
439 	void loadGame(const XmlNode *rootNode);
440 };
441 
442 }}//end namespace
443 
444 #endif
445