GUIUtil.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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: GUIUtil.cpp //////////////////////////////////////////////////////
  24. // Author: Matthew D. Campbell, Sept 2002
  25. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  26. #include "GameNetwork/GUIUtil.h"
  27. #include "GameNetwork/NetworkDefs.h"
  28. #include "GameClient/GameWindowManager.h"
  29. #include "GameClient/MapUtil.h"
  30. #include "Common/NameKeyGenerator.h"
  31. #include "Common/MultiplayerSettings.h"
  32. #include "GameClient/GadgetListBox.h"
  33. #include "GameClient/GadgetComboBox.h"
  34. #include "GameClient/GadgetTextEntry.h"
  35. #include "GameClient/GadgetStaticText.h"
  36. #include "GameClient/GadgetPushButton.h"
  37. #include "GameClient/GameText.h"
  38. #include "GameLogic/GameLogic.h" // SUPERWEAPON_RESTRICT_COUNT
  39. #include "GameNetwork/GameInfo.h"
  40. #include "Common/PlayerTemplate.h"
  41. #include "GameNetwork/LANAPICallbacks.h" // for acceptTrueColor, etc
  42. #include "GameClient/ChallengeGenerals.h"
  43. #ifdef _INTERNAL
  44. // for occasional debugging...
  45. //#pragma optimize("", off)
  46. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  47. #endif
  48. // -----------------------------------------------------------------------------
  49. static Bool winInitialized = FALSE;
  50. void EnableSlotListUpdates( Bool val )
  51. {
  52. winInitialized = val;
  53. }
  54. Bool AreSlotListUpdatesEnabled( void )
  55. {
  56. return winInitialized;
  57. }
  58. // -----------------------------------------------------------------------------
  59. void EnableAcceptControls(Bool Enabled, GameInfo *myGame, GameWindow *comboPlayer[],
  60. GameWindow *comboColor[], GameWindow *comboPlayerTemplate[],
  61. GameWindow *comboTeam[], GameWindow *buttonAccept[], GameWindow *buttonStart,
  62. GameWindow *buttonMapStartPosition[], Int slotNum)
  63. {
  64. if(slotNum == -1 || slotNum >= MAX_SLOTS )
  65. slotNum = myGame->getLocalSlotNum();
  66. Bool isObserver = myGame->getConstSlot(slotNum)->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER;
  67. if( !myGame->amIHost() && (buttonStart != NULL) )
  68. buttonStart->winEnable(Enabled);
  69. if(comboColor[slotNum])
  70. {
  71. if (isObserver)
  72. {
  73. GadgetComboBoxHideList(comboColor[slotNum]);
  74. }
  75. comboColor[slotNum]->winEnable(Enabled && !isObserver);
  76. }
  77. if(comboPlayerTemplate[slotNum])
  78. comboPlayerTemplate[slotNum]->winEnable(Enabled);
  79. if(comboTeam[slotNum])
  80. {
  81. if (isObserver)
  82. {
  83. GadgetComboBoxHideList(comboTeam[slotNum]);
  84. }
  85. comboTeam[slotNum]->winEnable(Enabled && !isObserver);
  86. }
  87. Bool canChooseStartSpot = FALSE;
  88. if (!isObserver)
  89. canChooseStartSpot = TRUE;
  90. for (Int i=0; i<MAX_SLOTS && !canChooseStartSpot && myGame->amIHost(); ++i)
  91. {
  92. if (myGame->getConstSlot(i) && myGame->getConstSlot(i)->isAI())
  93. canChooseStartSpot = TRUE;
  94. }
  95. if (slotNum == myGame->getLocalSlotNum())
  96. {
  97. if (myGame->getConstSlot(myGame->getLocalSlotNum())->hasMap())
  98. {
  99. for (Int i=0; i<MAX_SLOTS; ++i)
  100. {
  101. if (buttonMapStartPosition[i])
  102. {
  103. buttonMapStartPosition[i]->winEnable(Enabled && canChooseStartSpot);
  104. }
  105. }
  106. }
  107. else
  108. {
  109. for (Int i=0; i<MAX_SLOTS; ++i)
  110. {
  111. if (buttonMapStartPosition[i])
  112. buttonMapStartPosition[i]->winEnable(FALSE);
  113. }
  114. }
  115. }
  116. }
  117. // -----------------------------------------------------------------------------
  118. void ShowUnderlyingGUIElements( Bool show, const char *layoutFilename, const char *parentName,
  119. const char **gadgetsToHide, const char **perPlayerGadgetsToHide )
  120. {
  121. AsciiString parentNameStr;
  122. parentNameStr.format("%s:%s", layoutFilename, parentName);
  123. NameKeyType parentID = NAMEKEY(parentNameStr);
  124. GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
  125. if (!parent)
  126. {
  127. DEBUG_CRASH(("Window %s not found\n", parentNameStr.str()));
  128. return;
  129. }
  130. // hide some GUI elements of the screen underneath
  131. GameWindow *win;
  132. Int player;
  133. const char **text;
  134. text = gadgetsToHide;
  135. while (*text)
  136. {
  137. AsciiString gadgetName;
  138. gadgetName.format("%s:%s", layoutFilename, *text);
  139. win = TheWindowManager->winGetWindowFromId( parent, NAMEKEY(gadgetName) );
  140. //DEBUG_ASSERTCRASH(win, ("Cannot find %s to show/hide it", gadgetName.str()));
  141. if (win)
  142. {
  143. win->winHide( !show );
  144. }
  145. ++text;
  146. }
  147. text = perPlayerGadgetsToHide;
  148. while (*text)
  149. {
  150. for (player = 0; player < MAX_SLOTS; ++player)
  151. {
  152. AsciiString gadgetName;
  153. gadgetName.format("%s:%s%d", layoutFilename, *text, player);
  154. win = TheWindowManager->winGetWindowFromId( parent, NAMEKEY(gadgetName) );
  155. //DEBUG_ASSERTCRASH(win, ("Cannot find %s to show/hide it", gadgetName.str()));
  156. if (win)
  157. {
  158. win->winHide( !show );
  159. }
  160. }
  161. ++text;
  162. }
  163. }
  164. // -----------------------------------------------------------------------------
  165. void PopulateColorComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool isObserver)
  166. {
  167. Int numColors = TheMultiplayerSettings->getNumColors();
  168. UnicodeString colorName;
  169. std::vector<bool> availableColors;
  170. for (Int i = 0; i < numColors; i++)
  171. availableColors.push_back(true);
  172. for (i = 0; i < MAX_SLOTS; i++)
  173. {
  174. GameSlot *slot = myGame->getSlot(i);
  175. if( slot && (i != comboBox) && (slot->getColor() >= 0 )&& (slot->getColor() < numColors))
  176. {
  177. DEBUG_ASSERTCRASH(slot->getColor() >= 0,("We've tried to access array %d and that ain't good",slot->getColor()));
  178. availableColors[slot->getColor()] = false;
  179. }
  180. }
  181. Bool wasObserver = (GadgetComboBoxGetLength(comboArray[comboBox]) == 1);
  182. GadgetComboBoxReset(comboArray[comboBox]);
  183. MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
  184. Int newIndex = GadgetComboBoxAddEntry(comboArray[comboBox],
  185. (isObserver)?TheGameText->fetch("GUI:None"):TheGameText->fetch("GUI:???"), def->getColor());
  186. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)-1);
  187. if (isObserver)
  188. {
  189. GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
  190. return;
  191. }
  192. for (Int c=0; c<numColors; ++c)
  193. {
  194. def = TheMultiplayerSettings->getColor(c);
  195. if (!def || availableColors[c] == false)
  196. continue;
  197. colorName = TheGameText->fetch(def->getTooltipName().str());
  198. newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], colorName, def->getColor());
  199. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)c);
  200. }
  201. if (wasObserver)
  202. GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
  203. }
  204. // -----------------------------------------------------------------------------
  205. void PopulatePlayerTemplateComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool allowObservers)
  206. {
  207. Int numPlayerTemplates = ThePlayerTemplateStore->getPlayerTemplateCount();
  208. UnicodeString playerTemplateName;
  209. GadgetComboBoxReset(comboArray[comboBox]);
  210. MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
  211. Int newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch("GUI:Random"), def->getColor());
  212. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)PLAYERTEMPLATE_RANDOM);
  213. std::set<AsciiString> seenSides;
  214. for (Int c=0; c<numPlayerTemplates; ++c)
  215. {
  216. const PlayerTemplate *fac = ThePlayerTemplateStore->getNthPlayerTemplate(c);
  217. if (!fac)
  218. continue;
  219. if (fac->getStartingBuilding().isEmpty())
  220. continue;
  221. if ( myGame->oldFactionsOnly() && !fac->isOldFaction() )
  222. continue;
  223. // Prevent players from selecting the disabled Generals for use.
  224. // This is also enforced at game loading (GameLogic.cpp and UserPreferences.cpp).
  225. // @todo: unlock these when something rad happens
  226. Bool disallowLockedGenerals = TRUE;
  227. const GeneralPersona *general = TheChallengeGenerals->getGeneralByTemplateName(fac->getName());
  228. Bool startsLocked = general ? !general->isStartingEnabled() : FALSE;
  229. if (disallowLockedGenerals && startsLocked)
  230. continue;
  231. AsciiString side;
  232. side.format("SIDE:%s", fac->getSide().str());
  233. if (seenSides.find(side) != seenSides.end())
  234. continue;
  235. seenSides.insert(side);
  236. newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch(side), def->getColor());
  237. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)c);
  238. }
  239. seenSides.clear();
  240. // disabling observers for Multiplayer test
  241. if (allowObservers)
  242. {
  243. def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_OBSERVER);
  244. newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch("GUI:Observer"), def->getColor());
  245. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)PLAYERTEMPLATE_OBSERVER);
  246. }
  247. GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
  248. }
  249. // -----------------------------------------------------------------------------
  250. void PopulateTeamComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool isObserver)
  251. {
  252. Int numTeams = MAX_SLOTS/2;
  253. UnicodeString teamName;
  254. GadgetComboBoxReset(comboArray[comboBox]);
  255. MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
  256. Int newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch("Team:0"), def->getColor());
  257. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)-1);
  258. if (isObserver)
  259. {
  260. GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
  261. return;
  262. }
  263. for (Int c=0; c<numTeams; ++c)
  264. {
  265. AsciiString teamStr;
  266. teamStr.format("Team:%d", c + 1);
  267. teamName = TheGameText->fetch(teamStr.str());
  268. newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], teamName, def->getColor());
  269. GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)c);
  270. }
  271. GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
  272. }
  273. // -----------------------------------------------------------------------------
  274. static UnicodeString formatMoneyForStartingCashComboBox( const Money & moneyAmount )
  275. {
  276. UnicodeString rtn;
  277. rtn.format( TheGameText->fetch( "GUI:StartingMoneyFormat" ), moneyAmount.countMoney() );
  278. return rtn;
  279. }
  280. void PopulateStartingCashComboBox(GameWindow *comboBox, GameInfo *myGame)
  281. {
  282. GadgetComboBoxReset(comboBox);
  283. const MultiplayerStartingMoneyList & startingCashMap = TheMultiplayerSettings->getStartingMoneyList();
  284. Int currentSelectionIndex = -1;
  285. for ( MultiplayerStartingMoneyList::const_iterator it = startingCashMap.begin(); it != startingCashMap.end(); it++ )
  286. {
  287. Int newIndex = GadgetComboBoxAddEntry(comboBox, formatMoneyForStartingCashComboBox( *it ),
  288. comboBox->winGetEnabled() ? comboBox->winGetEnabledTextColor() : comboBox->winGetDisabledTextColor());
  289. GadgetComboBoxSetItemData(comboBox, newIndex, (void *)it->countMoney());
  290. if ( myGame->getStartingCash().amountEqual( *it ) )
  291. {
  292. currentSelectionIndex = newIndex;
  293. }
  294. }
  295. if ( currentSelectionIndex == -1 )
  296. {
  297. DEBUG_CRASH( ("Current selection for starting cash not found in list") );
  298. currentSelectionIndex = GadgetComboBoxAddEntry(comboBox, formatMoneyForStartingCashComboBox( myGame->getStartingCash() ),
  299. comboBox->winGetEnabled() ? comboBox->winGetEnabledTextColor() : comboBox->winGetDisabledTextColor());
  300. GadgetComboBoxSetItemData(comboBox, currentSelectionIndex, (void *)it->countMoney() );
  301. }
  302. GadgetComboBoxSetSelectedPos(comboBox, currentSelectionIndex);
  303. }
  304. // -----------------------------------------------------------------------------
  305. // -----------------------------------------------------------------------------------------
  306. // The slot list displaying function
  307. //-------------------------------------------------------------------------------------------------
  308. void UpdateSlotList( GameInfo *myGame, GameWindow *comboPlayer[],
  309. GameWindow *comboColor[], GameWindow *comboPlayerTemplate[],
  310. GameWindow *comboTeam[], GameWindow *buttonAccept[],
  311. GameWindow *buttonStart, GameWindow *buttonMapStartPosition[] )
  312. {
  313. if(!AreSlotListUpdatesEnabled())
  314. return;
  315. //LANGameInfo *myGame = TheLAN->GetMyGame();
  316. const MapMetaData *mapData = TheMapCache->findMap( myGame->getMap() );
  317. Bool willTransfer = TRUE;
  318. if (mapData)
  319. {
  320. willTransfer = !mapData->m_isOfficial;
  321. }
  322. else
  323. {
  324. willTransfer = WouldMapTransfer(myGame->getMap());
  325. }
  326. if (myGame)
  327. {
  328. for( int i =0; i < MAX_SLOTS; i++ )
  329. {
  330. GameSlot * slot = myGame->getSlot(i);
  331. // if i'm host, enable the controls for AI
  332. if(myGame->amIHost() && slot && slot->isAI())
  333. {
  334. EnableAcceptControls(TRUE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
  335. comboTeam, buttonAccept, buttonStart, buttonMapStartPosition, i);
  336. }
  337. else if (slot && myGame->getLocalSlotNum() == i)
  338. {
  339. if(slot->isAccepted() && !myGame->amIHost())
  340. {
  341. EnableAcceptControls(FALSE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
  342. comboTeam, buttonAccept, buttonStart, buttonMapStartPosition);
  343. }
  344. else
  345. {
  346. if (slot->hasMap()) {
  347. EnableAcceptControls(TRUE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
  348. comboTeam, buttonAccept, buttonStart, buttonMapStartPosition);
  349. }
  350. else
  351. {
  352. EnableAcceptControls(willTransfer, myGame, comboPlayer, comboColor, comboPlayerTemplate,
  353. comboTeam, buttonAccept, buttonStart, buttonMapStartPosition);
  354. }
  355. }
  356. }
  357. else if(myGame->amIHost())
  358. {
  359. EnableAcceptControls(FALSE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
  360. comboTeam, buttonAccept, buttonStart, buttonMapStartPosition, i);
  361. }
  362. if(slot && slot->isHuman())
  363. {
  364. UnicodeString newName = slot->getName();
  365. UnicodeString oldName = GadgetComboBoxGetText(comboPlayer[i]);
  366. if (comboPlayer[i] && newName.compare(oldName))
  367. {
  368. GadgetComboBoxSetText(comboPlayer[i], newName);
  369. }
  370. if(i!= 0 && buttonAccept && buttonAccept[i])
  371. {
  372. buttonAccept[i]->winHide(FALSE);
  373. //Color In the little accepted boxes
  374. if(slot->isAccepted())
  375. {
  376. if(BitTest(buttonAccept[i]->winGetStatus(), WIN_STATUS_IMAGE ))
  377. buttonAccept[i]->winEnable(TRUE);
  378. else
  379. GadgetButtonSetEnabledColor(buttonAccept[i], acceptTrueColor );
  380. }
  381. else
  382. {
  383. if(BitTest(buttonAccept[i]->winGetStatus(), WIN_STATUS_IMAGE ))
  384. buttonAccept[i]->winEnable(FALSE);
  385. else
  386. GadgetButtonSetEnabledColor(buttonAccept[i], acceptFalseColor );
  387. }
  388. }
  389. }
  390. else
  391. {
  392. GadgetComboBoxSetSelectedPos(comboPlayer[i], slot->getState(), TRUE);
  393. if( buttonAccept && buttonAccept[i] )
  394. buttonAccept[i]->winHide(TRUE);
  395. }
  396. /*
  397. if (myGame->getLocalSlotNum() == i && i!=0)
  398. {
  399. if (comboPlayer[i])
  400. comboPlayer[i]->winEnable( TRUE );
  401. }
  402. else*/ if (!myGame->amIHost())
  403. {
  404. if (comboPlayer[i])
  405. comboPlayer[i]->winEnable( FALSE );
  406. }
  407. //if( i == myGame->getLocalSlotNum())
  408. if((comboColor[i] != NULL) && BitTest(comboColor[i]->winGetStatus(), WIN_STATUS_ENABLED))
  409. PopulateColorComboBox(i, comboColor, myGame, myGame->getConstSlot(i)->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER);
  410. Int max, idx;
  411. if (comboColor[i] != NULL) {
  412. max = GadgetComboBoxGetLength(comboColor[i]);
  413. for (idx=0; idx<max; ++idx)
  414. {
  415. Int color = (Int)GadgetComboBoxGetItemData(comboColor[i], idx);
  416. if (color == slot->getColor())
  417. {
  418. GadgetComboBoxSetSelectedPos(comboColor[i], idx, TRUE);
  419. break;
  420. }
  421. }
  422. }
  423. if (comboTeam[i] != NULL) {
  424. max = GadgetComboBoxGetLength(comboTeam[i]);
  425. for (idx=0; idx<max; ++idx)
  426. {
  427. Int team = (Int)GadgetComboBoxGetItemData(comboTeam[i], idx);
  428. if (team == slot->getTeamNumber())
  429. {
  430. GadgetComboBoxSetSelectedPos(comboTeam[i], idx, TRUE);
  431. break;
  432. }
  433. }
  434. }
  435. if (comboPlayerTemplate[i] != NULL) {
  436. max = GadgetComboBoxGetLength(comboPlayerTemplate[i]);
  437. for (idx=0; idx<max; ++idx)
  438. {
  439. Int playerTemplate = (Int)GadgetComboBoxGetItemData(comboPlayerTemplate[i], idx);
  440. if (playerTemplate == slot->getPlayerTemplate())
  441. {
  442. GadgetComboBoxSetSelectedPos(comboPlayerTemplate[i], idx, TRUE);
  443. break;
  444. }
  445. }
  446. }
  447. }
  448. }
  449. }
  450. // -----------------------------------------------------------------------------