ProductionPrerequisite.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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: ProductionPrerequisite.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: ProductionPrerequisite.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. #include "Common/ProductionPrerequisite.h"
  44. #include "Common/Player.h"
  45. #include "Common/ThingFactory.h"
  46. #include "Common/ThingTemplate.h"
  47. #include "GameLogic/Object.h"
  48. #include "GameClient/Drawable.h"
  49. #include "GameClient/GameText.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. ProductionPrerequisite::ProductionPrerequisite()
  57. {
  58. init();
  59. }
  60. //-----------------------------------------------------------------------------
  61. ProductionPrerequisite::~ProductionPrerequisite()
  62. {
  63. }
  64. //-----------------------------------------------------------------------------
  65. void ProductionPrerequisite::init()
  66. {
  67. m_prereqUnits.clear();
  68. m_prereqSciences.clear();
  69. }
  70. //=============================================================================
  71. void ProductionPrerequisite::resolveNames()
  72. {
  73. for (Int i = 0; i < m_prereqUnits.size(); i++)
  74. {
  75. //
  76. // note that this will find the template at the "top most" level (not override
  77. // sub-temlates), which is what we want ... we conceptually only have one
  78. // template for any given thing, it's only the *data* that is overridden
  79. //
  80. if( m_prereqUnits[ i ].name.isNotEmpty() )
  81. {
  82. m_prereqUnits[i].unit = TheThingFactory->findTemplate(m_prereqUnits[i].name); // might be null
  83. /** @todo for now removing this assert until we can completely remove
  84. the GDF stuff, the problem is that some INI files refer to GDF names, and they
  85. aren't yet loaded in the world builder but will all go away later anyway etc */
  86. DEBUG_ASSERTCRASH(m_prereqUnits[i].unit,("could not find prereq %s\n",m_prereqUnits[i].name.str()));
  87. m_prereqUnits[i].name.clear(); // we're done with it
  88. }
  89. }
  90. }
  91. //-----------------------------------------------------------------------------
  92. Int ProductionPrerequisite::calcNumPrereqUnitsOwned(const Player *player, Int counts[MAX_PREREQ]) const
  93. {
  94. const ThingTemplate *tmpls[MAX_PREREQ];
  95. Int cnt = m_prereqUnits.size();
  96. if (cnt > MAX_PREREQ)
  97. cnt = MAX_PREREQ;
  98. for (int i = 0; i < cnt; i++)
  99. tmpls[i] = m_prereqUnits[i].unit;
  100. player->countObjectsByThingTemplate(cnt, tmpls, false, counts);
  101. return cnt;
  102. }
  103. //-----------------------------------------------------------------------------
  104. Int ProductionPrerequisite::getAllPossibleBuildFacilityTemplates(const ThingTemplate* tmpls[], Int maxtmpls) const
  105. {
  106. Int count = 0;
  107. for (int i = 0; i < m_prereqUnits.size(); i++)
  108. {
  109. if (i > 0 && !(m_prereqUnits[i].flags & UNIT_OR_WITH_PREV))
  110. break;
  111. if (count >= maxtmpls)
  112. break;
  113. tmpls[count++] = m_prereqUnits[i].unit;
  114. }
  115. return count;
  116. }
  117. //-----------------------------------------------------------------------------
  118. const ThingTemplate *ProductionPrerequisite::getExistingBuildFacilityTemplate( const Player *player ) const
  119. {
  120. DEBUG_ASSERTCRASH(player, ("player may not be null"));
  121. if (m_prereqUnits.size())
  122. {
  123. Int ownCount[MAX_PREREQ];
  124. Int cnt = calcNumPrereqUnitsOwned(player, ownCount);
  125. for (int i = 0; i < cnt; i++)
  126. {
  127. if (i > 0 && !(m_prereqUnits[i].flags & UNIT_OR_WITH_PREV))
  128. break;
  129. if (ownCount[i])
  130. return m_prereqUnits[i].unit;
  131. }
  132. }
  133. return NULL;
  134. }
  135. //-----------------------------------------------------------------------------
  136. Bool ProductionPrerequisite::isSatisfied(const Player *player) const
  137. {
  138. Int i;
  139. if (!player)
  140. return false;
  141. // gotta have all the prereq sciences.
  142. for (i = 0; i < m_prereqSciences.size(); i++)
  143. {
  144. if (!player->hasScience(m_prereqSciences[i]))
  145. return false;
  146. }
  147. // the player must have at least one instance of each prereq unit.
  148. Int ownCount[MAX_PREREQ];
  149. Int cnt = calcNumPrereqUnitsOwned(player, ownCount);
  150. // fix up the "or" cases. (start at 1!)
  151. for (i = 1; i < cnt; i++)
  152. {
  153. if (m_prereqUnits[i].flags & UNIT_OR_WITH_PREV)
  154. {
  155. ownCount[i] += ownCount[i-1]; // lump 'em together for prereq purposes
  156. ownCount[i-1] = -1; // flag for "ignore me"
  157. }
  158. }
  159. for (i = 0; i < cnt; i++)
  160. {
  161. if (ownCount[i] == -1) // the magic "ignore me" flag
  162. continue;
  163. if (ownCount[i] == 0) // everything not ignored, is required
  164. return false;
  165. }
  166. return true;
  167. }
  168. //-------------------------------------------------------------------------------------------------
  169. /** Add a unit prerequisite, if 'orWithPrevious' is set then this unit is said
  170. * to be an alternate prereq to the previously added unit, otherwise this becomes
  171. * a new 'block' and is required in ADDDITION to other entries.
  172. * Return FALSE if no space left to add unit */
  173. //-------------------------------------------------------------------------------------------------
  174. void ProductionPrerequisite::addUnitPrereq( AsciiString unit, Bool orUnitWithPrevious )
  175. {
  176. PrereqUnitRec info;
  177. info.name = unit;
  178. info.flags = orUnitWithPrevious ? UNIT_OR_WITH_PREV : 0;
  179. info.unit = NULL;
  180. m_prereqUnits.push_back(info);
  181. } // end addUnitPrereq
  182. //-------------------------------------------------------------------------------------------------
  183. /** Add a unit prerequisite, if 'orWithPrevious' is set then this unit is said
  184. * to be an alternate prereq to the previously added unit, otherwise this becomes
  185. * a new 'block' and is required in ADDDITION to other entries.
  186. * Return FALSE if no space left to add unit */
  187. //-------------------------------------------------------------------------------------------------
  188. void ProductionPrerequisite::addUnitPrereq( const std::vector<AsciiString>& units )
  189. {
  190. Bool orWithPrevious = false;
  191. for (int i = 0; i < units.size(); ++i)
  192. {
  193. addUnitPrereq(units[i], orWithPrevious);
  194. orWithPrevious = true;
  195. }
  196. } // end addUnitPrereq
  197. //-------------------------------------------------------------------------------------------------
  198. // returns an asciistring which is a list of all the prerequisites
  199. // not satisfied yet
  200. UnicodeString ProductionPrerequisite::getRequiresList(const Player *player) const
  201. {
  202. // if player is invalid, return empty string
  203. if (!player)
  204. return UnicodeString::TheEmptyString;
  205. UnicodeString requiresList = UnicodeString::TheEmptyString;
  206. // check the prerequired units
  207. Int ownCount[MAX_PREREQ];
  208. Int cnt = calcNumPrereqUnitsOwned(player, ownCount);
  209. Int i;
  210. Bool orRequirements[MAX_PREREQ];
  211. //Added for fix below in getRequiresList
  212. //By Sadullah Nader
  213. //Initializes the OR_WITH_PREV structures
  214. for (i = 0; i < MAX_PREREQ; i++)
  215. {
  216. orRequirements[i] = FALSE;
  217. }
  218. //
  219. // account for the "or" unit cases, start for loop at 1
  220. for (i = 1; i < cnt; i++)
  221. {
  222. if (m_prereqUnits[i].flags & UNIT_OR_WITH_PREV)
  223. {
  224. orRequirements[i] = TRUE; // set the flag for this unit to be "ored" with previous
  225. ownCount[i] += ownCount[i-1]; // lump 'em together for prereq purposes
  226. ownCount[i-1] = -1; // flag for "ignore me"
  227. }
  228. }
  229. // check to see if anything is required
  230. const ThingTemplate *unit;
  231. UnicodeString unitName;
  232. Bool firstRequirement = true;
  233. for (i = 0; i < cnt; i++)
  234. {
  235. // we have an unfulfilled requirement
  236. if (ownCount[i] == 0) {
  237. if(orRequirements[i])
  238. {
  239. unit = m_prereqUnits[i-1].unit;
  240. unitName = unit->getDisplayName();
  241. unitName.concat( L" " );
  242. unitName.concat(TheGameText->fetch("CONTROLBAR:OrRequirement", NULL));
  243. unitName.concat( L" " );
  244. requiresList.concat(unitName);
  245. }
  246. // get the requirement and then its name
  247. unit = m_prereqUnits[i].unit;
  248. unitName = unit->getDisplayName();
  249. // gets command button, and then modifies unitName
  250. //CommandButton *cmdButton = TheControlBar->findCommandButton(unit->getName());
  251. //if (cmdButton)
  252. //unitName.translate(TheGameText->fetch(cmdButton->m_textLabel.str()));
  253. // format name appropriately with 'returns' if necessary
  254. if (firstRequirement)
  255. firstRequirement = false;
  256. else
  257. unitName.concat(L"\n");
  258. // add it to the list
  259. requiresList.concat(unitName);
  260. }
  261. }
  262. Bool hasSciences = TRUE;
  263. // gotta have all the prereq sciences.
  264. for (i = 0; i < m_prereqSciences.size(); i++)
  265. {
  266. if (!player->hasScience(m_prereqSciences[i]))
  267. hasSciences = FALSE;
  268. }
  269. if (hasSciences == FALSE) {
  270. if (firstRequirement) {
  271. firstRequirement = false;
  272. } else {
  273. unitName.concat(L"\n");
  274. }
  275. requiresList.concat(TheGameText->fetch("CONTROLBAR:GeneralsPromotion", NULL));
  276. }
  277. // return final list
  278. return requiresList;
  279. }