PlayerList.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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: PlayerList.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: PlayerList.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/Errors.h"
  44. #include "Common/DataChunk.h"
  45. #include "Common/GameState.h"
  46. #include "Common/GlobalData.h"
  47. #include "Common/Player.h"
  48. #include "Common/PlayerList.h"
  49. #include "Common/PlayerTemplate.h"
  50. #include "Common/Team.h"
  51. #include "Common/WellKnownKeys.h"
  52. #include "Common/Xfer.h"
  53. #ifdef _DEBUG
  54. #include "GameLogic/Object.h"
  55. #endif
  56. #include "GameLogic/SidesList.h"
  57. #include "GameNetwork/NetworkDefs.h"
  58. #ifdef _INTERNAL
  59. // for occasional debugging...
  60. //#pragma optimize("", off)
  61. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  62. #endif
  63. //-----------------------------------------------------------------------------
  64. /*extern*/ PlayerList *ThePlayerList = NULL;
  65. //-----------------------------------------------------------------------------
  66. PlayerList::PlayerList() :
  67. m_local(NULL),
  68. m_playerCount(0)
  69. {
  70. // we only allocate a few of these, so don't bother pooling 'em
  71. for (Int i = 0; i < MAX_PLAYER_COUNT; i++)
  72. m_players[ i ] = NEW Player( i );
  73. init();
  74. }
  75. //-----------------------------------------------------------------------------
  76. PlayerList::~PlayerList()
  77. {
  78. try {
  79. // the world is happier if we reinit things before destroying them,
  80. // to avoid debug warnings
  81. init();
  82. } catch (...) {
  83. // nothing
  84. }
  85. for( Int i = 0; i < MAX_PLAYER_COUNT; ++i )
  86. delete m_players[ i ];
  87. }
  88. //-----------------------------------------------------------------------------
  89. Player *PlayerList::getNthPlayer(Int i)
  90. {
  91. if( i < 0 || i >= MAX_PLAYER_COUNT )
  92. {
  93. // DEBUG_CRASH( ("Illegal player index\n") );
  94. return NULL;
  95. }
  96. return m_players[i];
  97. }
  98. //-----------------------------------------------------------------------------
  99. Player *PlayerList::findPlayerWithNameKey(NameKeyType key)
  100. {
  101. for (Int i = 0; i < m_playerCount; i++)
  102. {
  103. if (m_players[i]->getPlayerNameKey() == key)
  104. {
  105. return m_players[i];
  106. }
  107. }
  108. return NULL;
  109. }
  110. //-----------------------------------------------------------------------------
  111. void PlayerList::reset()
  112. {
  113. TheTeamFactory->clear(); // cleans up energy, among other things
  114. init();
  115. }
  116. //-----------------------------------------------------------------------------
  117. void PlayerList::newGame()
  118. {
  119. Int i;
  120. DEBUG_ASSERTCRASH(this != NULL, ("null this"));
  121. TheTeamFactory->clear(); // cleans up energy, among other things
  122. // first, re-init ourselves.
  123. init();
  124. // ok, now create the rest of players we need.
  125. Bool setLocal = false;
  126. for( i = 0; i < TheSidesList->getNumSides(); i++)
  127. {
  128. Dict *d = TheSidesList->getSideInfo(i)->getDict();
  129. AsciiString pname = d->getAsciiString(TheKey_playerName);
  130. if (pname.isEmpty())
  131. continue; // it's neutral, which we've already done, so skip it.
  132. /// @todo The Player class should have a reset() method, instead of directly calling initFromDict() (MSB)
  133. Player* p = m_players[m_playerCount++];
  134. p->initFromDict(d);
  135. // Multiplayer override
  136. Bool exists; // throwaway, since we don't care if it exists
  137. if (d->getBool(TheKey_multiplayerIsLocal, &exists))
  138. {
  139. DEBUG_LOG(("Player %s is multiplayer local\n", pname.str()));
  140. setLocalPlayer(p);
  141. setLocal = true;
  142. }
  143. if (!setLocal && !TheNetwork && d->getBool(TheKey_playerIsHuman))
  144. {
  145. setLocalPlayer(p);
  146. setLocal = true;
  147. }
  148. // Set the build list.
  149. p->setBuildList(TheSidesList->getSideInfo(i)->getBuildList());
  150. // Build list is attached to player now, so release it from the side info.
  151. TheSidesList->getSideInfo(i)->releaseBuildList();
  152. }
  153. if (!setLocal)
  154. {
  155. DEBUG_ASSERTCRASH(TheNetwork, ("*** Map has no human player... picking first nonneutral player for control\n"));
  156. for( i = 0; i < TheSidesList->getNumSides(); i++)
  157. {
  158. Player* p = getNthPlayer(i);
  159. if (p != getNeutralPlayer())
  160. {
  161. p->setPlayerType(PLAYER_HUMAN, false);
  162. setLocalPlayer(p);
  163. setLocal = true;
  164. break;
  165. }
  166. }
  167. }
  168. // must reset teams *after* creating players.
  169. TheTeamFactory->initFromSides(TheSidesList);
  170. for( i = 0; i < TheSidesList->getNumSides(); i++)
  171. {
  172. Dict *d = TheSidesList->getSideInfo(i)->getDict();
  173. Player* p = findPlayerWithNameKey(NAMEKEY(d->getAsciiString(TheKey_playerName)));
  174. AsciiString tok;
  175. AsciiString enemies = d->getAsciiString(TheKey_playerEnemies);
  176. while (enemies.nextToken(&tok))
  177. {
  178. Player *p2 = findPlayerWithNameKey(NAMEKEY(tok));
  179. if (p2)
  180. {
  181. p->setPlayerRelationship(p2, ENEMIES);
  182. }
  183. else
  184. {
  185. DEBUG_LOG(("unknown enemy %s\n",tok.str()));
  186. }
  187. }
  188. AsciiString allies = d->getAsciiString(TheKey_playerAllies);
  189. while (allies.nextToken(&tok))
  190. {
  191. Player *p2 = findPlayerWithNameKey(NAMEKEY(tok));
  192. if (p2)
  193. {
  194. p->setPlayerRelationship(p2, ALLIES);
  195. }
  196. else
  197. {
  198. DEBUG_LOG(("unknown ally %s\n",tok.str()));
  199. }
  200. }
  201. // finally, make sure self & neutral are correct.
  202. p->setPlayerRelationship(p, ALLIES);
  203. if (p != getNeutralPlayer())
  204. p->setPlayerRelationship(getNeutralPlayer(), NEUTRAL);
  205. p->setDefaultTeam();
  206. }
  207. }
  208. //-----------------------------------------------------------------------------
  209. void PlayerList::init()
  210. {
  211. m_playerCount = 1;
  212. m_players[0]->init(NULL);
  213. for (int i = 1; i < MAX_PLAYER_COUNT; i++)
  214. m_players[i]->init(NULL);
  215. // call setLocalPlayer so that becomingLocalPlayer() gets called appropriately
  216. setLocalPlayer(m_players[0]);
  217. }
  218. //-----------------------------------------------------------------------------
  219. void PlayerList::update()
  220. {
  221. // update all players
  222. for( Int i = 0; i < MAX_PLAYER_COUNT; i++ )
  223. {
  224. m_players[i]->update();
  225. } // end for i
  226. }
  227. //-----------------------------------------------------------------------------
  228. void PlayerList::newMap()
  229. {
  230. // update all players
  231. for( Int i = 0; i < MAX_PLAYER_COUNT; i++ )
  232. {
  233. m_players[i]->newMap();
  234. } // end for i
  235. }
  236. // ------------------------------------------------------------------------
  237. void PlayerList::teamAboutToBeDeleted(Team* team)
  238. {
  239. for( Int i = 0; i < MAX_PLAYER_COUNT; i++ )
  240. {
  241. m_players[i]->removeTeamRelationship(team);
  242. }
  243. }
  244. //=============================================================================
  245. void PlayerList::updateTeamStates(void)
  246. {
  247. // Clear team flags for all players.
  248. for( Int i = 0; i < MAX_PLAYER_COUNT; i++ )
  249. {
  250. m_players[i]->updateTeamStates();
  251. } // end for i
  252. }
  253. //-----------------------------------------------------------------------------
  254. Team *PlayerList::validateTeam( AsciiString owner )
  255. {
  256. // owner could be a player or team. first, check team names.
  257. Team *t = TheTeamFactory->findTeam(owner);
  258. if (t)
  259. {
  260. //DEBUG_LOG(("assigned obj %08lx to team %s\n",obj,owner.str()));
  261. }
  262. else
  263. {
  264. DEBUG_CRASH(("no team or player named %s could be found!\n", owner.str()));
  265. t = getNeutralPlayer()->getDefaultTeam();
  266. }
  267. return t;
  268. }
  269. //-----------------------------------------------------------------------------
  270. void PlayerList::setLocalPlayer(Player *player)
  271. {
  272. // can't set local player to null -- if you try, you get neutral.
  273. if (player == NULL)
  274. {
  275. DEBUG_CRASH(("local player may not be null"));
  276. player = getNeutralPlayer();
  277. }
  278. if (player != m_local)
  279. {
  280. // m_local can be null the very first time we call this.
  281. if (m_local)
  282. m_local->becomingLocalPlayer(false);
  283. m_local = player;
  284. player->becomingLocalPlayer(true);
  285. }
  286. #ifdef INTENSE_DEBUG
  287. if (player)
  288. {
  289. DEBUG_LOG(("\n----------\n"));
  290. // did you know? you can use "%ls" to print a doublebyte string, even in a single-byte printf...
  291. DEBUG_LOG(("Switching local players. The new player is named '%ls' (%s) and owns the following objects:\n",
  292. player->getPlayerDisplayName().str(),
  293. TheNameKeyGenerator->keyToName(player->getPlayerNameKey()).str()
  294. ));
  295. for (Object *obj = player->getFirstOwnedObject(); obj; obj = obj->getNextOwnedObject())
  296. {
  297. DEBUG_LOG(("Obj %08lx is of type %s",obj,obj->getTemplate()->getName().str()));
  298. if (!player->canBuild(obj->getTemplate()))
  299. {
  300. DEBUG_LOG((" (NOT BUILDABLE)"));
  301. }
  302. DEBUG_LOG(("\n"));
  303. }
  304. DEBUG_LOG(("\n----------\n"));
  305. }
  306. #endif
  307. }
  308. //-----------------------------------------------------------------------------
  309. Player *PlayerList::getPlayerFromMask( PlayerMaskType mask )
  310. {
  311. Player *player = NULL;
  312. Int i;
  313. for( i = 0; i < MAX_PLAYER_COUNT; i++ )
  314. {
  315. player = getNthPlayer( i );
  316. if( player && player->getPlayerMask() == mask )
  317. return player;
  318. } // end for i
  319. DEBUG_CRASH( ("Player does not exist for mask\n") );
  320. return NULL; // mask not found
  321. } // end getPlayerFromMask
  322. //-----------------------------------------------------------------------------
  323. Player *PlayerList::getEachPlayerFromMask( PlayerMaskType& maskToAdjust )
  324. {
  325. Player *player = NULL;
  326. Int i;
  327. for( i = 0; i < MAX_PLAYER_COUNT; i++ )
  328. {
  329. player = getNthPlayer( i );
  330. if ( player && BitTest(player->getPlayerMask(), maskToAdjust ))
  331. {
  332. maskToAdjust &= (~player->getPlayerMask());
  333. return player;
  334. }
  335. } // end for i
  336. DEBUG_CRASH( ("No players found that contain any matching masks.\n") );
  337. maskToAdjust = 0;
  338. return NULL; // mask not found
  339. }
  340. //-------------------------------------------------------------------------------------------------
  341. PlayerMaskType PlayerList::getPlayersWithRelationship( Int srcPlayerIndex, UnsignedInt allowedRelationships )
  342. {
  343. PlayerMaskType retVal = 0;
  344. if (allowedRelationships == 0)
  345. return retVal;
  346. Player *srcPlayer = getNthPlayer(srcPlayerIndex);
  347. if (!srcPlayer)
  348. return retVal;
  349. if (BitTest(allowedRelationships, ALLOW_SAME_PLAYER))
  350. BitSet(retVal, srcPlayer->getPlayerMask());
  351. for ( Int i = 0; i < getPlayerCount(); ++i )
  352. {
  353. Player *player = getNthPlayer(i);
  354. if (!player)
  355. continue;
  356. if (player == srcPlayer)
  357. continue;
  358. switch (srcPlayer->getRelationship(player->getDefaultTeam()))
  359. {
  360. case ENEMIES:
  361. if (BitTest(allowedRelationships, ALLOW_ENEMIES))
  362. BitSet(retVal, player->getPlayerMask());
  363. break;
  364. case ALLIES:
  365. if (BitTest(allowedRelationships, ALLOW_ALLIES))
  366. BitSet(retVal, player->getPlayerMask());
  367. break;
  368. case NEUTRAL:
  369. if (BitTest(allowedRelationships, ALLOW_NEUTRAL))
  370. BitSet(retVal, player->getPlayerMask());
  371. break;
  372. }
  373. }
  374. return retVal;
  375. }
  376. // ------------------------------------------------------------------------------------------------
  377. /** CRC */
  378. // ------------------------------------------------------------------------------------------------
  379. void PlayerList::crc( Xfer *xfer )
  380. {
  381. xfer->xferInt( &m_playerCount );
  382. for( Int i = 0; i < m_playerCount; ++i )
  383. xfer->xferSnapshot( m_players[ i ] );
  384. }
  385. // ------------------------------------------------------------------------------------------------
  386. /** Xfer Method
  387. * Version Info:
  388. * 1: Initial version */
  389. // ------------------------------------------------------------------------------------------------
  390. void PlayerList::xfer( Xfer *xfer )
  391. {
  392. // version
  393. XferVersion currentVersion = 1;
  394. XferVersion version = currentVersion;
  395. xfer->xferVersion( &version, currentVersion );
  396. // xfer the player count
  397. Int playerCount = m_playerCount;
  398. xfer->xferInt( &playerCount );
  399. //
  400. // sanity, the player count read from the file should match our player count that
  401. // was setup from the bare bones map load since that data can't change during run time
  402. //
  403. if( playerCount != m_playerCount )
  404. {
  405. DEBUG_CRASH(( "Invalid player count '%d', should be '%d'\n", playerCount, m_playerCount ));
  406. throw SC_INVALID_DATA;
  407. } // end if
  408. // xfer each of the player data
  409. for( Int i = 0; i < playerCount; ++i )
  410. xfer->xferSnapshot( m_players[ i ] );
  411. } // end xfer
  412. // ------------------------------------------------------------------------------------------------
  413. /** Load post process */
  414. // ------------------------------------------------------------------------------------------------
  415. void PlayerList::loadPostProcess( void )
  416. {
  417. } // end postProcessLoad