PlayerTemplate.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: PlayerTemplate.cpp /////////////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: PlayerTemplate.cpp
  36. //
  37. // Created: Steven Johnson, October 2001
  38. //
  39. // Desc: @todo
  40. //
  41. //-----------------------------------------------------------------------------
  42. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  43. #define DEFINE_VETERANCY_NAMES // for TheVeterancyNames[]
  44. #include "Common/GameCommon.h"
  45. #include "Common/PlayerTemplate.h"
  46. #include "Common/Player.h"
  47. #include "Common/INI.h"
  48. #include "Common/Science.h"
  49. #include "GameClient/Image.h"
  50. #ifdef _INTERNAL
  51. // for occasional debugging...
  52. //#pragma optimize("", off)
  53. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  54. #endif
  55. ///////////////////////////////////////////////////////////////////////////////////////////////////
  56. // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
  57. ///////////////////////////////////////////////////////////////////////////////////////////////////
  58. ///////////////////////////////////////////////////////////////////////////////////////////////////
  59. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
  60. ///////////////////////////////////////////////////////////////////////////////////////////////////
  61. //-------------------------------------------------------------------------------------------------
  62. /*static*/ const FieldParse* PlayerTemplate::getFieldParse()
  63. {
  64. static const FieldParse TheFieldParseTable[] =
  65. {
  66. { "Side", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_side ) },
  67. { "BaseSide", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_baseSide ) },
  68. { "PlayableSide", INI::parseBool, NULL, offsetof( PlayerTemplate, m_playableSide ) },
  69. { "DisplayName", INI::parseAndTranslateLabel, NULL, offsetof( PlayerTemplate, m_displayName) },
  70. { "StartMoney", PlayerTemplate::parseStartMoney, NULL, offsetof( PlayerTemplate, m_money ) },
  71. { "PreferredColor", INI::parseRGBColor, NULL, offsetof( PlayerTemplate, m_preferredColor ) },
  72. { "StartingBuilding", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingBuilding ) },
  73. { "StartingUnit0", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[0] ) },
  74. { "StartingUnit1", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[1] ) },
  75. { "StartingUnit2", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[2] ) },
  76. { "StartingUnit3", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[3] ) },
  77. { "StartingUnit4", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[4] ) },
  78. { "StartingUnit5", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[5] ) },
  79. { "StartingUnit6", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[6] ) },
  80. { "StartingUnit7", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[7] ) },
  81. { "StartingUnit8", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[8] ) },
  82. { "StartingUnit9", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[9] ) },
  83. { "ProductionCostChange", PlayerTemplate::parseProductionCostChange, NULL, 0 },
  84. { "ProductionTimeChange", PlayerTemplate::parseProductionTimeChange, NULL, 0 },
  85. { "ProductionVeterancyLevel", PlayerTemplate::parseProductionVeterancyLevel, NULL, 0 },
  86. { "IntrinsicSciences", INI::parseScienceVector, NULL, offsetof( PlayerTemplate, m_intrinsicSciences ) },
  87. { "PurchaseScienceCommandSetRank1",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_purchaseScienceCommandSetRank1 ) },
  88. { "PurchaseScienceCommandSetRank3",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_purchaseScienceCommandSetRank3 ) },
  89. { "PurchaseScienceCommandSetRank8",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_purchaseScienceCommandSetRank8 ) },
  90. { "SpecialPowerShortcutCommandSet",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_specialPowerShortcutCommandSet ) },
  91. { "SpecialPowerShortcutWinName" ,INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_specialPowerShortcutWinName) },
  92. { "SpecialPowerShortcutButtonCount",INI::parseInt, NULL, offsetof( PlayerTemplate, m_specialPowerShortcutButtonCount ) },
  93. { "IsObserver", INI::parseBool, NULL, offsetof( PlayerTemplate, m_observer ) },
  94. { "OldFaction", INI::parseBool, NULL, offsetof( PlayerTemplate, m_oldFaction ) },
  95. { "IntrinsicSciencePurchasePoints", INI::parseInt, NULL, offsetof( PlayerTemplate, m_intrinsicSPP ) },
  96. { "ScoreScreenImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_scoreScreenImage ) },
  97. { "LoadScreenImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_loadScreenImage ) },
  98. { "LoadScreenMusic", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_loadScreenMusic ) },
  99. { "ScoreScreenMusic", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_scoreScreenMusic ) },
  100. { "HeadWaterMark", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_headWaterMark ) },
  101. { "FlagWaterMark", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_flagWaterMark ) },
  102. { "EnabledImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_enabledImage ) },
  103. //{ "DisabledImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_disabledImage ) },
  104. //{ "HiliteImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_hiliteImage ) },
  105. //{ "PushedImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_pushedImage ) },
  106. { "SideIconImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_sideIconImage ) },
  107. { "GeneralImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_generalImage ) },
  108. { "BeaconName", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_beaconTemplate ) },
  109. { "ArmyTooltip", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_tooltip ) },
  110. { "Features", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_strGeneralFeatures ) },
  111. { "MedallionRegular", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_strMedallionNormal ) },
  112. { "MedallionHilite", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_strMedallionHilite ) },
  113. { "MedallionSelect", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_strMedallionSelected ) },
  114. { NULL, NULL, NULL, 0 },
  115. };
  116. return TheFieldParseTable;
  117. }
  118. AsciiString PlayerTemplate::getStartingUnit( Int i ) const
  119. {
  120. if (i<0 || i>= MAX_MP_STARTING_UNITS)
  121. return AsciiString::TheEmptyString;
  122. return m_startingUnits[i];
  123. }
  124. //-------------------------------------------------------------------------------------------------
  125. // This is is a Template, and a percent change to the cost of producing it.
  126. /*static*/ void PlayerTemplate::parseProductionCostChange( INI* ini, void *instance, void *store, const void* /*userData*/ )
  127. {
  128. PlayerTemplate* self = (PlayerTemplate*)instance;
  129. NameKeyType buildTemplateKey = NAMEKEY(ini->getNextToken());
  130. Real percentChange = INI::scanPercentToReal(ini->getNextToken());
  131. self->m_productionCostChanges[buildTemplateKey] = percentChange;
  132. }
  133. //-------------------------------------------------------------------------------------------------
  134. /*static*/ void PlayerTemplate::parseProductionTimeChange( INI* ini, void *instance, void *store, const void* /*userData*/ )
  135. {
  136. PlayerTemplate* self = (PlayerTemplate*)instance;
  137. NameKeyType buildTemplateKey = NAMEKEY(ini->getNextToken());
  138. Real percentChange = INI::scanPercentToReal(ini->getNextToken());
  139. self->m_productionTimeChanges[buildTemplateKey] = percentChange;
  140. }
  141. //-------------------------------------------------------------------------------------------------
  142. /*static*/ void PlayerTemplate::parseProductionVeterancyLevel( INI* ini, void *instance, void *store, const void* /*userData*/ )
  143. {
  144. PlayerTemplate* self = (PlayerTemplate*)instance;
  145. // Format is ThingTemplatename VeterancyName
  146. AsciiString HACK = AsciiString(ini->getNextToken());
  147. NameKeyType buildTemplateKey = NAMEKEY(HACK.str());
  148. VeterancyLevel startLevel = (VeterancyLevel)INI::scanIndexList(ini->getNextToken(), TheVeterancyNames);
  149. self->m_productionVeterancyLevels[buildTemplateKey] = startLevel;
  150. }
  151. //-------------------------------------------------------------------------------------------------
  152. /** Parse integer money and deposit in the m_money */
  153. //-------------------------------------------------------------------------------------------------
  154. /*static*/ void PlayerTemplate::parseStartMoney( INI* ini, void *instance, void *store, const void* /*userData*/ )
  155. {
  156. Int money = 0;
  157. // parse the money as a regular "FIELD = <integer>"
  158. INI::parseInt( ini, instance, &money, NULL );
  159. // assign the money into the 'Money' (m_money) pointed to at 'store'
  160. Money *theMoney = (Money *)store;
  161. theMoney->init();
  162. theMoney->deposit( money );
  163. } // end parseStartMoney
  164. ///////////////////////////////////////////////////////////////////////////////////////////////////
  165. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  166. ///////////////////////////////////////////////////////////////////////////////////////////////////
  167. //-----------------------------------------------------------------------------
  168. PlayerTemplate::PlayerTemplate() :
  169. m_nameKey(NAMEKEY_INVALID),
  170. m_observer(false),
  171. m_playableSide(false),
  172. m_oldFaction(false),
  173. m_intrinsicSPP(0),
  174. m_specialPowerShortcutButtonCount(0)
  175. {
  176. m_preferredColor.red = m_preferredColor.green = m_preferredColor.blue = 0.0f;
  177. m_beaconTemplate.clear();
  178. }
  179. //-----------------------------------------------------------------------------
  180. const Image *PlayerTemplate::getHeadWaterMarkImage( void ) const
  181. {
  182. return TheMappedImageCollection->findImageByName(m_headWaterMark);
  183. }
  184. //-----------------------------------------------------------------------------
  185. const Image *PlayerTemplate::getFlagWaterMarkImage( void ) const
  186. {
  187. return TheMappedImageCollection->findImageByName(m_flagWaterMark);
  188. }
  189. //-----------------------------------------------------------------------------
  190. const Image *PlayerTemplate::getSideIconImage( void ) const
  191. {
  192. return TheMappedImageCollection->findImageByName(m_sideIconImage);
  193. }
  194. //-----------------------------------------------------------------------------
  195. const Image *PlayerTemplate::getGeneralImage( void ) const
  196. {
  197. return TheMappedImageCollection->findImageByName(m_generalImage);
  198. }
  199. //-----------------------------------------------------------------------------
  200. const Image *PlayerTemplate::getEnabledImage( void ) const
  201. {
  202. return TheMappedImageCollection->findImageByName(m_enabledImage);
  203. }
  204. //-----------------------------------------------------------------------------
  205. //const Image *PlayerTemplate::getDisabledImage( void ) const
  206. //{
  207. // return TheMappedImageCollection->findImageByName(m_disabledImage);
  208. //}
  209. //-----------------------------------------------------------------------------
  210. //const Image *PlayerTemplate::getHiliteImage( void ) const
  211. //{
  212. // return TheMappedImageCollection->findImageByName(m_hiliteImage);
  213. //}
  214. //-----------------------------------------------------------------------------
  215. //const Image *PlayerTemplate::getPushedImage( void ) const
  216. //{
  217. // return TheMappedImageCollection->findImageByName(m_pushedImage);
  218. //}
  219. //-----------------------------------------------------------------------------
  220. //-----------------------------------------------------------------------------
  221. //-----------------------------------------------------------------------------
  222. /*extern*/ PlayerTemplateStore *ThePlayerTemplateStore = NULL;
  223. //-----------------------------------------------------------------------------
  224. PlayerTemplateStore::PlayerTemplateStore()
  225. {
  226. // nothing
  227. }
  228. //-----------------------------------------------------------------------------
  229. PlayerTemplateStore::~PlayerTemplateStore()
  230. {
  231. // nothing
  232. }
  233. //-----------------------------------------------------------------------------
  234. void PlayerTemplateStore::init()
  235. {
  236. m_playerTemplates.clear();
  237. }
  238. //-----------------------------------------------------------------------------
  239. void PlayerTemplateStore::reset()
  240. {
  241. // don't reset this list here; we want to retain this info.
  242. // m_playerTemplates.clear();
  243. }
  244. //-----------------------------------------------------------------------------
  245. void PlayerTemplateStore::update()
  246. {
  247. // nothing
  248. }
  249. Int PlayerTemplateStore::getTemplateNumByName(AsciiString name) const
  250. {
  251. for (Int num = 0; num < m_playerTemplates.size(); num++)
  252. {
  253. if (m_playerTemplates[num].getName().compareNoCase(name.str()) == 0)
  254. return num;
  255. }
  256. DEBUG_ASSERTCRASH(NULL, ("Template doesn't exist for given name"));
  257. return -1;
  258. }
  259. //-----------------------------------------------------------------------------
  260. const PlayerTemplate* PlayerTemplateStore::findPlayerTemplate(NameKeyType namekey) const
  261. {
  262. // begin ugly, hokey code to quietly load old maps...
  263. static NameKeyType a0 = NAMEKEY("FactionAmerica");
  264. static NameKeyType a1 = NAMEKEY("FactionAmericaChooseAGeneral");
  265. static NameKeyType a2 = NAMEKEY("FactionAmericaTankCommand");
  266. static NameKeyType a3 = NAMEKEY("FactionAmericaSpecialForces");
  267. static NameKeyType a4 = NAMEKEY("FactionAmericaAirForce");
  268. static NameKeyType c0 = NAMEKEY("FactionChina");
  269. static NameKeyType c1 = NAMEKEY("FactionChinaChooseAGeneral");
  270. static NameKeyType c2 = NAMEKEY("FactionChinaRedArmy");
  271. static NameKeyType c3 = NAMEKEY("FactionChinaSpecialWeapons");
  272. static NameKeyType c4 = NAMEKEY("FactionChinaSecretPolice");
  273. static NameKeyType g0 = NAMEKEY("FactionGLA");
  274. static NameKeyType g1 = NAMEKEY("FactionGLAChooseAGeneral");
  275. static NameKeyType g2 = NAMEKEY("FactionGLATerrorCell");
  276. static NameKeyType g3 = NAMEKEY("FactionGLABiowarCommand");
  277. static NameKeyType g4 = NAMEKEY("FactionGLAWarlordCommand");
  278. if (namekey == a1 || namekey == a2 || namekey == a3 || namekey == a4)
  279. namekey = a0;
  280. else if (namekey == c1 || namekey == c2 || namekey == c3 || namekey == c4)
  281. namekey = c0;
  282. else if (namekey == g1 || namekey == g2 || namekey == g3 || namekey == g4)
  283. namekey = g0;
  284. // end ugly, hokey code to quietly load old maps...
  285. #ifdef _DEBUG
  286. AsciiString nn = KEYNAME(namekey);
  287. #endif
  288. for (PlayerTemplateVector::const_iterator it = m_playerTemplates.begin(); it != m_playerTemplates.end(); ++it)
  289. {
  290. #ifdef _DEBUG
  291. AsciiString n = KEYNAME((*it).getNameKey());
  292. #endif
  293. if ((*it).getNameKey() == namekey)
  294. return &(*it);
  295. }
  296. return NULL;
  297. }
  298. //-----------------------------------------------------------------------------
  299. const PlayerTemplate* PlayerTemplateStore::getNthPlayerTemplate(Int i) const
  300. {
  301. if (i >= 0 && i < m_playerTemplates.size())
  302. return &m_playerTemplates[i];
  303. return NULL;
  304. }
  305. //-------------------------------------------------------------------------------------------------
  306. // @todo: PERF_EVALUATE Get a perf timer on this.
  307. // If this function is called frequently, there are some relatively trivial changes we could make to
  308. // have it run a lot faster.
  309. void PlayerTemplateStore::getAllSideStrings(AsciiStringList *outStringList)
  310. {
  311. if (!outStringList)
  312. return;
  313. // should outStringList be cleared first? If so, that would go here
  314. AsciiStringList tmpList;
  315. Int numTemplates = getPlayerTemplateCount();
  316. for ( Int i = 0; i < numTemplates; ++i )
  317. {
  318. const PlayerTemplate *pt = getNthPlayerTemplate(i);
  319. // Sanity
  320. if (!pt)
  321. continue;
  322. if (std::find(tmpList.begin(), tmpList.end(), pt->getSide()) == tmpList.end())
  323. tmpList.push_back(pt->getSide());
  324. }
  325. // tmpList is now filled with all unique sides found in the player templates.
  326. // splice is a constant-time function which takes all elements from tmpList and
  327. // inserts them before outStringList->end(), and also removes them from tmpList
  328. outStringList->splice(outStringList->end(), tmpList);
  329. // all done
  330. }
  331. //-------------------------------------------------------------------------------------------------
  332. /*static*/ void PlayerTemplateStore::parsePlayerTemplateDefinition( INI* ini )
  333. {
  334. const char* c = ini->getNextToken();
  335. NameKeyType namekey = NAMEKEY(c);
  336. PlayerTemplate* pt = const_cast<PlayerTemplate*>(ThePlayerTemplateStore->findPlayerTemplate(namekey));
  337. if (pt)
  338. {
  339. ini->initFromINI(pt, pt->getFieldParse() );
  340. pt->setNameKey(namekey);
  341. }
  342. else
  343. {
  344. PlayerTemplate npt;
  345. ini->initFromINI( &npt, npt.getFieldParse() );
  346. npt.setNameKey(namekey);
  347. ThePlayerTemplateStore->m_playerTemplates.push_back(npt);
  348. }
  349. }
  350. //-------------------------------------------------------------------------------------------------
  351. void INI::parsePlayerTemplateDefinition( INI* ini )
  352. {
  353. PlayerTemplateStore::parsePlayerTemplateDefinition(ini);
  354. }