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