1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (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                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 
20 #ifndef game_logic_upgradecalculatorH
21 #define game_logic_upgradecalculatorH
22 
23 #include <map>
24 
25 #include "utility/signal/signal.h"
26 
27 class cResearch;
28 class cUnitUpgrade;
29 struct sUnitData;
30 
31 //------------------------------------------------------------------------------
32 /**
33  * A singleton class for calculating costs for upgrades and research and
34  * for getting the results of such upgrades and research.
35  * In M.A.X. research and gold upgrades have no direct influence on each other.
36  * Their effects are simply added.
37  * Example:
38  * The first step for the armor 10 upgrade is 5 gold
39  * to get from armor 10 to 11.
40  * If you research armor till you have 50% you will have armor 15.
41  * But the first gold upgrade step will still cost 5 gold.
42  * And it will go up from 15 to 16.
43  * Other example:
44  * If you have gold-upgraded the speed of an awac from 18 to 32 and
45  * do now a speed research,
46  * then you will still get only an additional bonus of 1
47  * for the first research (and not 3).
48  * This is because the research benefit is always calculated
49  * on the basis of the start value and not of the current value.
50 
51  * To use this class, simply call:
52  * cUpdateCalculator::instance().theMethodINeed()
53 
54  * @author Paul Grathwohl
55  */
56 //------------------------------------------------------------------------------
57 class cUpgradeCalculator
58 {
59 public:
60 	static cUpgradeCalculator& instance();
61 
62 	enum UpgradeTypes
63 	{
64 		kHitpoints = 0,
65 		kArmor,
66 		kAmmo,
67 		kAttack,
68 		kSpeed,
69 		kShots,
70 		kRange,
71 		kScan,
72 		kCost
73 	};
74 
75 	enum
76 	{
77 		kNoPriceAvailable = 0,
78 		kNoResearchAvailable = 66666
79 	};
80 
81 	/**
82 	 * Calculates the price (gold) to upgrade from the given value.
83 	 * @param curValue the value the unit currently has
84 	 *                 (without boni by research!)
85 	 * @param orgValue the value the unit has as a base value
86 	 * @param upgradeType the area of the upgrade
87 	 * @param researchLevel the research level of the player
88 	 *                      that has to be taken into account
89 	 * @return the costs for this upgrade or kNoPriceAvailable
90 	 *         if the values are unknown
91 	 */
92 	int calcPrice (int curValue, int orgValue, int upgradeType, const cResearch& researchLevel) const;
93 
94 	/**
95 	 * Calculates the increase of a unit value, when an upgrade is bought.
96 	 * Examples: If orgValue is 10, the increase will be 2.
97 	 * If orgValue is 28, the increase will be 5.
98 	 * The increase is not growing, if the unit has already some upgrades!
99 	 * The only needed thing for the calculation is the value,
100 	 * at which the unit started.
101 	 * @param startValue the value, the unit has in it's base version
102 	 * @return the increase of the unit's value, when an upgrade is bought
103 	*/
104 	int calcIncreaseByUpgrade (int startValue) const;
105 
106 	/**
107 	 * Calculates the price (gold) for upgrading a unit,
108 	 * that started with orgValue and has currently curValue, to newValue.
109 	 * @param orgValue the value the unit has as a base value
110 	 * @param curValue the value the unit currently has
111 	 * @param newValue the value the unit wants to reach
112 	 * @upgradeType the area of the upgrade
113 	 * @param researchLevel the research level of the player
114 	 *                      that has to be taken into account
115 	 * @return the costs for this upgrade or kNoPriceAvailable
116 	 *         if such an upgrade is impossible
117 	 */
118 	int getCostForUpgrade (int orgValue, int curValue, int newValue, int upgradeType, cResearch& researchLevel) const;
119 
120 	/**
121 	 * Calculates the turns needed for one research center
122 	 * to reach the next level.
123 	 * @param curResearchLevel the level this research area currently has
124 	 *                         (e.g. 20 for 20%)
125 	 * @param upgradeType the area of the upgrade
126 	 * @return the turns needed to reach the next level
127 	 *         with one research center
128 	 *         or kNoResearchAvailable if the passed values are out of range
129 	 */
130 	int calcResearchTurns (int curResearchLevel, int upgradeType) const;
131 
132 	/**
133 	 * Calculates the raw-material needed for upgrading a unit,
134 	 * that costs unitCost, to the current version.
135 	 * The costs in original M.A.X. are simply
136 	 * a fourth of the costs (rounded down) needed to build that unit.
137 	 * The costs do not depend on the quality of the upgrade
138 	 * (e.g. upgrading hitpoints from 18 to 20 costs the same as
139 	 * upgrading the basic version of the unit to an ultra fat version
140 	 * with all values upgraded to a maximum).
141 	 * @param unitCost the raw-material cost to build the unit
142 	 *                 that will be upgraded (e.g. 24 for a mine-building)
143 	 * @return the raw-material needed to upgrade to the current version
144 	 */
145 	int getMaterialCostForUpgrading (int unitCost) const;
146 
147 	enum UnitTypes
148 	{
149 		kBuilding = 0, // Mines, Research Centers, Storage, Generators...
150 		kInfantry, // Infantry and Infiltrator
151 		kStandardUnit // all other, like Tank, Ground Attack Plane, Scanner...
152 	};
153 
154 	/**
155 	 * Calculates the change of the given startValue,
156 	 * with the given researchLevel.
157 	 * This change is independent of the upgradeType,
158 	 * only kCost has a special handling,
159 	 * because it actually decreases the value
160 	 * (so you will get a negative value as return value).
161 	 * @param startValue the value, the unit has in it's base version
162 	 * @param curResearchLevel the level for which you want to know the change
163 	 *                         (e.g. 10 for 10%)
164 	 * @param upgradeType optional, set it to kCost
165 	 *                    if you need to know the changes in cost
166 	 * @param unitType optional, needed for upgradeType kCost because
167 	 *                           the behaviour changes for the unit types
168 	 * @return the change of the startValue
169 	 * (can be negative if kCost is the upgradeType)
170 	 */
171 	int calcChangeByResearch (int startValue, int curResearchLevel,
172 							  int upgradeType = -1, int unitType = kBuilding) const;
173 
174 	/**
175 	 * Prints some upgrade values to the standard log on debug-level.
176 	 * Expand the implementation to test, if all works fine.
177 	 */
178 	void printAllToLog() const;
179 
180 private:
181 	cUpgradeCalculator();
182 
183 	typedef std::map<int, int> PriceMap;
184 
185 	PriceMap hitpointsArmorAmmo_2;
186 	PriceMap hitpointsArmorAmmo_4;
187 	PriceMap hitpointsArmorAmmo_6;
188 	PriceMap hitpointsArmorAmmo_7;
189 	PriceMap hitpointsArmorAmmo_8;
190 	PriceMap hitpointsArmorAmmo_9;
191 	PriceMap hitpointsArmorAmmo_10;
192 	PriceMap hitpointsArmorAmmo_12;
193 	PriceMap hitpointsArmorAmmo_14;
194 	PriceMap hitpointsArmorAmmo_16;
195 	PriceMap hitpointsArmorAmmo_18;
196 	PriceMap hitpointsArmorAmmo_20;
197 	PriceMap hitpointsArmorAmmo_24;
198 	PriceMap hitpointsArmorAmmo_26;
199 	PriceMap hitpointsArmorAmmo_28;
200 	PriceMap hitpointsArmorAmmo_32;
201 	PriceMap hitpointsArmorAmmo_36;
202 	PriceMap hitpointsArmorAmmo_40;
203 	PriceMap hitpointsArmorAmmo_56;
204 
205 	PriceMap attackSpeed_5;
206 	PriceMap attackSpeed_6;
207 	PriceMap attackSpeed_7;
208 	PriceMap attackSpeed_8;
209 	PriceMap attackSpeed_9;
210 	PriceMap attackSpeed_10;
211 	PriceMap attackSpeed_11;
212 	PriceMap attackSpeed_12;
213 	PriceMap attackSpeed_14;
214 	PriceMap attackSpeed_15;
215 	PriceMap attackSpeed_16;
216 	PriceMap attackSpeed_17;
217 	PriceMap attackSpeed_18;
218 	PriceMap attackSpeed_20;
219 	PriceMap attackSpeed_22;
220 	PriceMap attackSpeed_24;
221 	PriceMap attackSpeed_28;
222 	PriceMap attackSpeed_30;
223 	PriceMap attackSpeed_36;
224 
225 	PriceMap rangeScan_3;
226 	PriceMap rangeScan_4;
227 	PriceMap rangeScan_5;
228 	PriceMap rangeScan_6;
229 	PriceMap rangeScan_7;
230 	PriceMap rangeScan_8;
231 	PriceMap rangeScan_9;
232 	PriceMap rangeScan_10;
233 	PriceMap rangeScan_11;
234 	PriceMap rangeScan_12;
235 	PriceMap rangeScan_14;
236 	PriceMap rangeScan_16;
237 	PriceMap rangeScan_18;
238 	PriceMap rangeScan_20;
239 	PriceMap rangeScan_24;
240 
241 	PriceMap shots_1;
242 	PriceMap shots_2;
243 
244 	int lookupPrice (const PriceMap& prices, int value) const;
245 	void setupLookupTables();
246 
247 	int getNearestPossibleCost (float realCost, int costDifference) const;
248 
249 	void printToLog (const char* str, int value = -1000) const;
250 
251 	bool setupDone;
252 };
253 
254 
255 
256 //-------------------------------------------
257 /** Stores the current research state of a player. */
258 //-------------------------------------------
259 class cResearch
260 {
261 public:
262 	enum ResearchArea
263 	{
264 		kAttackResearch = 0,
265 		kShotsResearch,
266 		kRangeResearch,
267 		kArmorResearch,
268 		kHitpointsResearch,
269 		kSpeedResearch,
270 		kScanResearch,
271 		kCostResearch,
272 		kNrResearchAreas
273 	};
274 
275 	cResearch();
276 
277 	/**
278 	 * Adds researchPoints to the current research points of
279 	 * the specified researchArea.
280 	 * @return true, if the next research level was reached
281 	 */
282 	bool doResearch (int researchPoints, int researchArea);
283 
284 	int getCurResearchLevel (int researchArea) const;  ///< 0, 10, 20, 30, ...
285 	/// Number of research-center turns the player invested in an area
286 	int getCurResearchPoints (int researchArea) const;
287 	/// Number of research-center turns needed to reach the next level
288 	int getNeededResearchPoints (int researchArea) const;
getRemainingResearchPoints(int researchArea)289 	int getRemainingResearchPoints (int researchArea) const { return getNeededResearchPoints (researchArea) - getCurResearchPoints (researchArea); }
290 
291 	/// returns the needed number of turns to reach the next level
292 	/// with the given nr of research centers
293 	int getRemainingTurns (int researchArea, int centersWorkingOn) const;
294 
295 	/// will also set the neededResearchPoints if necessary
296 	void setCurResearchLevel (int researchLevel, int researchArea);
297 	/// if researchPoints >= neededResearchPoints, nothing will be done
298 	void setCurResearchPoints (int researchPoints, int researchArea);
299 
300 	int getUpgradeCalculatorUpgradeType (int researchArea) const;
301 	int getResearchArea (int upgradeCalculatorType) const;
302 
303 	mutable cSignal<void (ResearchArea)> currentResearchLevelChanged;
304 	mutable cSignal<void (ResearchArea)> currentResearchPointsChanged;
305 	mutable cSignal<void (ResearchArea)> neededResearchPointsChanged;
306 	//-------------------------------------------
307 protected:
308 	void init();  ///< sets all research information to the initial values
309 
310 	int curResearchLevel[kNrResearchAreas]; ///< 0, 10, 20, 30, ...
311 	/// Number of research-center turns the player invested in an area
312 	int curResearchPoints[kNrResearchAreas];
313 	/// Number of research-center turns needed to reach the next level
314 	// (remainingResearchPoints == neededResearchPoints - curResearchPoints)
315 	int neededResearchPoints[kNrResearchAreas];
316 };
317 
318 /**
319  * A struct that contains information about the upgrades of a unit.
320  *@author alzi
321  */
322 struct sUnitUpgrade
323 {
sUnitUpgradesUnitUpgrade324 	sUnitUpgrade() :
325 		nextPrice (0), purchased (0),
326 		curValue (-1), startValue (0), type (UPGRADE_TYPE_NONE) {}
327 
328 	int purchase (const cResearch& researchLevel);
329 	int cancelPurchase (const cResearch& researchLevel);
330 	int computedPurchasedCount (const cResearch& researchLevel);
331 
332 	/** The different values of a unit that can be upgraded */
333 	enum eUpgradeTypes
334 	{
335 		UPGRADE_TYPE_DAMAGE,
336 		UPGRADE_TYPE_SHOTS,
337 		UPGRADE_TYPE_RANGE,
338 		UPGRADE_TYPE_AMMO,
339 		UPGRADE_TYPE_ARMOR,
340 		UPGRADE_TYPE_HITS,
341 		UPGRADE_TYPE_SCAN,
342 		UPGRADE_TYPE_SPEED,
343 		UPGRADE_TYPE_NONE
344 	};
345 
getCurValuesUnitUpgrade346 	int getCurValue() const { return curValue; }
getTypesUnitUpgrade347 	eUpgradeTypes getType() const { return type; }
getNextPricesUnitUpgrade348 	int getNextPrice() const { return nextPrice; }
getPurchasedsUnitUpgrade349 	int getPurchased() const { return purchased; }
350 private:
351 	friend class cUnitUpgrade;
352 	/** what will the next upgrade cost */
353 	int nextPrice;
354 	/** how many upgrades of this type has the player purchased */
355 	int purchased;
356 	/** what is the current value */
357 	int curValue;
358 	/** the value that this unit would have without all upgrades */
359 	int startValue;
360 	/** the type of the upgrade */
361 	eUpgradeTypes type;
362 };
363 
364 class cUnitUpgrade
365 {
366 public:
367 	void init (const sUnitData& origData, const sUnitData& curData, const cResearch& researchLevel);
368 	sUnitUpgrade* getUpgrade (sUnitUpgrade::eUpgradeTypes type);
369 	const sUnitUpgrade* getUpgrade (sUnitUpgrade::eUpgradeTypes type) const;
370 
371 	int computedPurchasedCount (const cResearch& researchLevel);
372 	bool hasBeenPurchased() const;
373 	int getValueOrDefault (sUnitUpgrade::eUpgradeTypes upgradeType, int defaultValue) const;
374 	void updateUnitData (sUnitData& data) const;
375 public:
376 	sUnitUpgrade upgrades[8];
377 };
378 
379 #endif // game_logic_upgradecalculatorH
380