PlayerTemplate.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /*
  2. ** Command & Conquer Generals(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. { "PlayableSide", INI::parseBool, NULL, offsetof( PlayerTemplate, m_playableSide ) },
  68. { "DisplayName", INI::parseAndTranslateLabel, NULL, offsetof( PlayerTemplate, m_displayName) },
  69. { "StartMoney", PlayerTemplate::parseStartMoney, NULL, offsetof( PlayerTemplate, m_money ) },
  70. { "PreferredColor", INI::parseRGBColor, NULL, offsetof( PlayerTemplate, m_preferredColor ) },
  71. { "StartingBuilding", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingBuilding ) },
  72. { "StartingUnit0", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[0] ) },
  73. { "StartingUnit1", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[1] ) },
  74. { "StartingUnit2", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[2] ) },
  75. { "StartingUnit3", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[3] ) },
  76. { "StartingUnit4", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[4] ) },
  77. { "StartingUnit5", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[5] ) },
  78. { "StartingUnit6", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[6] ) },
  79. { "StartingUnit7", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[7] ) },
  80. { "StartingUnit8", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[8] ) },
  81. { "StartingUnit9", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_startingUnits[9] ) },
  82. { "ProductionCostChange", PlayerTemplate::parseProductionCostChange, NULL, 0 },
  83. { "ProductionTimeChange", PlayerTemplate::parseProductionTimeChange, NULL, 0 },
  84. { "ProductionVeterancyLevel", PlayerTemplate::parseProductionVeterancyLevel, NULL, 0 },
  85. { "IntrinsicSciences", INI::parseScienceVector, NULL, offsetof( PlayerTemplate, m_intrinsicSciences ) },
  86. { "PurchaseScienceCommandSetRank1",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_purchaseScienceCommandSetRank1 ) },
  87. { "PurchaseScienceCommandSetRank3",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_purchaseScienceCommandSetRank3 ) },
  88. { "PurchaseScienceCommandSetRank8",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_purchaseScienceCommandSetRank8 ) },
  89. { "SpecialPowerShortcutCommandSet",INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_specialPowerShortcutCommandSet ) },
  90. { "SpecialPowerShortcutWinName" ,INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_specialPowerShortcutWinName) },
  91. { "SpecialPowerShortcutButtonCount",INI::parseInt, NULL, offsetof( PlayerTemplate, m_specialPowerShortcutButtonCount ) },
  92. { "IsObserver", INI::parseBool, NULL, offsetof( PlayerTemplate, m_observer ) },
  93. { "IntrinsicSciencePurchasePoints", INI::parseInt, NULL, offsetof( PlayerTemplate, m_intrinsicSPP ) },
  94. { "ScoreScreenImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_scoreScreenImage ) },
  95. { "LoadScreenImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_loadScreenImage ) },
  96. { "LoadScreenMusic", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_loadScreenMusic ) },
  97. { "HeadWaterMark", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_headWaterMark ) },
  98. { "FlagWaterMark", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_flagWaterMark ) },
  99. { "EnabledImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_enabledImage ) },
  100. //{ "DisabledImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_disabledImage ) },
  101. //{ "HiliteImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_hiliteImage ) },
  102. //{ "PushedImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_pushedImage ) },
  103. { "SideIconImage", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_sideIconImage ) },
  104. { "BeaconName", INI::parseAsciiString, NULL, offsetof( PlayerTemplate, m_beaconTemplate ) },
  105. { NULL, NULL, NULL, 0 },
  106. };
  107. return TheFieldParseTable;
  108. }
  109. AsciiString PlayerTemplate::getStartingUnit( Int i ) const
  110. {
  111. if (i<0 || i>= MAX_MP_STARTING_UNITS)
  112. return AsciiString::TheEmptyString;
  113. return m_startingUnits[i];
  114. }
  115. //-------------------------------------------------------------------------------------------------
  116. // This is is a Template, and a percent change to the cost of producing it.
  117. /*static*/ void PlayerTemplate::parseProductionCostChange( INI* ini, void *instance, void *store, const void* /*userData*/ )
  118. {
  119. PlayerTemplate* self = (PlayerTemplate*)instance;
  120. NameKeyType buildTemplateKey = NAMEKEY(ini->getNextToken());
  121. Real percentChange = INI::scanPercentToReal(ini->getNextToken());
  122. self->m_productionCostChanges[buildTemplateKey] = percentChange;
  123. }
  124. //-------------------------------------------------------------------------------------------------
  125. /*static*/ void PlayerTemplate::parseProductionTimeChange( INI* ini, void *instance, void *store, const void* /*userData*/ )
  126. {
  127. PlayerTemplate* self = (PlayerTemplate*)instance;
  128. NameKeyType buildTemplateKey = NAMEKEY(ini->getNextToken());
  129. Real percentChange = INI::scanPercentToReal(ini->getNextToken());
  130. self->m_productionTimeChanges[buildTemplateKey] = percentChange;
  131. }
  132. //-------------------------------------------------------------------------------------------------
  133. /*static*/ void PlayerTemplate::parseProductionVeterancyLevel( INI* ini, void *instance, void *store, const void* /*userData*/ )
  134. {
  135. PlayerTemplate* self = (PlayerTemplate*)instance;
  136. // Format is ThingTemplatename VeterancyName
  137. AsciiString HACK = AsciiString(ini->getNextToken());
  138. NameKeyType buildTemplateKey = NAMEKEY(HACK.str());
  139. VeterancyLevel startLevel = (VeterancyLevel)INI::scanIndexList(ini->getNextToken(), TheVeterancyNames);
  140. self->m_productionVeterancyLevels[buildTemplateKey] = startLevel;
  141. }
  142. //-------------------------------------------------------------------------------------------------
  143. /** Parse integer money and deposit in the m_money */
  144. //-------------------------------------------------------------------------------------------------
  145. /*static*/ void PlayerTemplate::parseStartMoney( INI* ini, void *instance, void *store, const void* /*userData*/ )
  146. {
  147. Int money = 0;
  148. // parse the money as a regular "FIELD = <integer>"
  149. INI::parseInt( ini, instance, &money, NULL );
  150. // assign the money into the 'Money' (m_money) pointed to at 'store'
  151. Money *theMoney = (Money *)store;
  152. theMoney->init();
  153. theMoney->deposit( money );
  154. } // end parseStartMoney
  155. ///////////////////////////////////////////////////////////////////////////////////////////////////
  156. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  157. ///////////////////////////////////////////////////////////////////////////////////////////////////
  158. //-----------------------------------------------------------------------------
  159. PlayerTemplate::PlayerTemplate() :
  160. m_nameKey(NAMEKEY_INVALID),
  161. m_observer(false),
  162. m_playableSide(false),
  163. m_intrinsicSPP(0),
  164. m_specialPowerShortcutButtonCount(0)
  165. {
  166. m_preferredColor.red = m_preferredColor.green = m_preferredColor.blue = 0.0f;
  167. m_beaconTemplate.clear();
  168. }
  169. //-----------------------------------------------------------------------------
  170. const Image *PlayerTemplate::getHeadWaterMarkImage( void ) const
  171. {
  172. return TheMappedImageCollection->findImageByName(m_headWaterMark);
  173. }
  174. //-----------------------------------------------------------------------------
  175. const Image *PlayerTemplate::getFlagWaterMarkImage( void ) const
  176. {
  177. return TheMappedImageCollection->findImageByName(m_flagWaterMark);
  178. }
  179. //-----------------------------------------------------------------------------
  180. const Image *PlayerTemplate::getSideIconImage( void ) const
  181. {
  182. return TheMappedImageCollection->findImageByName(m_sideIconImage);
  183. }
  184. //-----------------------------------------------------------------------------
  185. const Image *PlayerTemplate::getEnabledImage( void ) const
  186. {
  187. return TheMappedImageCollection->findImageByName(m_enabledImage);
  188. }
  189. //-----------------------------------------------------------------------------
  190. //const Image *PlayerTemplate::getDisabledImage( void ) const
  191. //{
  192. // return TheMappedImageCollection->findImageByName(m_disabledImage);
  193. //}
  194. //-----------------------------------------------------------------------------
  195. //const Image *PlayerTemplate::getHiliteImage( void ) const
  196. //{
  197. // return TheMappedImageCollection->findImageByName(m_hiliteImage);
  198. //}
  199. //-----------------------------------------------------------------------------
  200. //const Image *PlayerTemplate::getPushedImage( void ) const
  201. //{
  202. // return TheMappedImageCollection->findImageByName(m_pushedImage);
  203. //}
  204. //-----------------------------------------------------------------------------
  205. //-----------------------------------------------------------------------------
  206. //-----------------------------------------------------------------------------
  207. /*extern*/ PlayerTemplateStore *ThePlayerTemplateStore = NULL;
  208. //-----------------------------------------------------------------------------
  209. PlayerTemplateStore::PlayerTemplateStore()
  210. {
  211. // nothing
  212. }
  213. //-----------------------------------------------------------------------------
  214. PlayerTemplateStore::~PlayerTemplateStore()
  215. {
  216. // nothing
  217. }
  218. //-----------------------------------------------------------------------------
  219. void PlayerTemplateStore::init()
  220. {
  221. m_playerTemplates.clear();
  222. }
  223. //-----------------------------------------------------------------------------
  224. void PlayerTemplateStore::reset()
  225. {
  226. // don't reset this list here; we want to retain this info.
  227. // m_playerTemplates.clear();
  228. }
  229. //-----------------------------------------------------------------------------
  230. void PlayerTemplateStore::update()
  231. {
  232. // nothing
  233. }
  234. //-----------------------------------------------------------------------------
  235. const PlayerTemplate* PlayerTemplateStore::findPlayerTemplate(NameKeyType namekey) const
  236. {
  237. // begin ugly, hokey code to quietly load old maps...
  238. static NameKeyType a0 = NAMEKEY("FactionAmerica");
  239. static NameKeyType a1 = NAMEKEY("FactionAmericaChooseAGeneral");
  240. static NameKeyType a2 = NAMEKEY("FactionAmericaTankCommand");
  241. static NameKeyType a3 = NAMEKEY("FactionAmericaSpecialForces");
  242. static NameKeyType a4 = NAMEKEY("FactionAmericaAirForce");
  243. static NameKeyType c0 = NAMEKEY("FactionChina");
  244. static NameKeyType c1 = NAMEKEY("FactionChinaChooseAGeneral");
  245. static NameKeyType c2 = NAMEKEY("FactionChinaRedArmy");
  246. static NameKeyType c3 = NAMEKEY("FactionChinaSpecialWeapons");
  247. static NameKeyType c4 = NAMEKEY("FactionChinaSecretPolice");
  248. static NameKeyType g0 = NAMEKEY("FactionGLA");
  249. static NameKeyType g1 = NAMEKEY("FactionGLAChooseAGeneral");
  250. static NameKeyType g2 = NAMEKEY("FactionGLATerrorCell");
  251. static NameKeyType g3 = NAMEKEY("FactionGLABiowarCommand");
  252. static NameKeyType g4 = NAMEKEY("FactionGLAWarlordCommand");
  253. if (namekey == a1 || namekey == a2 || namekey == a3 || namekey == a4)
  254. namekey = a0;
  255. else if (namekey == c1 || namekey == c2 || namekey == c3 || namekey == c4)
  256. namekey = c0;
  257. else if (namekey == g1 || namekey == g2 || namekey == g3 || namekey == g4)
  258. namekey = g0;
  259. // end ugly, hokey code to quietly load old maps...
  260. #ifdef _DEBUG
  261. AsciiString nn = KEYNAME(namekey);
  262. #endif
  263. for (PlayerTemplateVector::const_iterator it = m_playerTemplates.begin(); it != m_playerTemplates.end(); ++it)
  264. {
  265. #ifdef _DEBUG
  266. AsciiString n = KEYNAME((*it).getNameKey());
  267. #endif
  268. if ((*it).getNameKey() == namekey)
  269. return &(*it);
  270. }
  271. return NULL;
  272. }
  273. //-----------------------------------------------------------------------------
  274. const PlayerTemplate* PlayerTemplateStore::getNthPlayerTemplate(Int i) const
  275. {
  276. if (i >= 0 && i < m_playerTemplates.size())
  277. return &m_playerTemplates[i];
  278. return NULL;
  279. }
  280. //-------------------------------------------------------------------------------------------------
  281. // @todo: PERF_EVALUATE Get a perf timer on this.
  282. // If this function is called frequently, there are some relatively trivial changes we could make to
  283. // have it run a lot faster.
  284. void PlayerTemplateStore::getAllSideStrings(AsciiStringList *outStringList)
  285. {
  286. if (!outStringList)
  287. return;
  288. // should outStringList be cleared first? If so, that would go here
  289. AsciiStringList tmpList;
  290. Int numTemplates = getPlayerTemplateCount();
  291. for ( Int i = 0; i < numTemplates; ++i )
  292. {
  293. const PlayerTemplate *pt = getNthPlayerTemplate(i);
  294. // Sanity
  295. if (!pt)
  296. continue;
  297. if (std::find(tmpList.begin(), tmpList.end(), pt->getSide()) == tmpList.end())
  298. tmpList.push_back(pt->getSide());
  299. }
  300. // tmpList is now filled with all unique sides found in the player templates.
  301. // splice is a constant-time function which takes all elements from tmpList and
  302. // inserts them before outStringList->end(), and also removes them from tmpList
  303. outStringList->splice(outStringList->end(), tmpList);
  304. // all done
  305. }
  306. //-------------------------------------------------------------------------------------------------
  307. /*static*/ void PlayerTemplateStore::parsePlayerTemplateDefinition( INI* ini )
  308. {
  309. const char* c = ini->getNextToken();
  310. NameKeyType namekey = NAMEKEY(c);
  311. PlayerTemplate* pt = const_cast<PlayerTemplate*>(ThePlayerTemplateStore->findPlayerTemplate(namekey));
  312. if (pt)
  313. {
  314. ini->initFromINI(pt, pt->getFieldParse() );
  315. pt->setNameKey(namekey);
  316. }
  317. else
  318. {
  319. PlayerTemplate npt;
  320. ini->initFromINI( &npt, npt.getFieldParse() );
  321. npt.setNameKey(namekey);
  322. ThePlayerTemplateStore->m_playerTemplates.push_back(npt);
  323. }
  324. }
  325. //-------------------------------------------------------------------------------------------------
  326. void INI::parsePlayerTemplateDefinition( INI* ini )
  327. {
  328. PlayerTemplateStore::parsePlayerTemplateDefinition(ini);
  329. }