ProductionPrerequisite.cpp 10 KB

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