GameInfo.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545
  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: GameInfo.cpp //////////////////////////////////////////////////////
  24. // game setup state info
  25. // Author: Matthew D. Campbell, December 2001
  26. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  27. #include "Common/CRCDebug.h"
  28. #include "Common/File.h"
  29. #include "Common/FileSystem.h"
  30. #include "Common/GameState.h"
  31. #include "GameClient/GameText.h"
  32. #include "GameClient/MapUtil.h"
  33. #include "Common/MultiplayerSettings.h"
  34. #include "Common/PlayerTemplate.h"
  35. #include "Common/Xfer.h"
  36. #include "GameNetwork/FileTransfer.h"
  37. #include "GameNetwork/GameInfo.h"
  38. #include "GameNetwork/GameSpy/ThreadUtils.h"
  39. #include "GameNetwork/GameSpy/StagingRoomGameInfo.h"
  40. #include "GameNetwork/LANAPI.h" // for testing packet size
  41. #include "GameNetwork/LANAPICallbacks.h" // for testing packet size
  42. #include "strtok_r.h"
  43. #ifdef _INTERNAL
  44. // for occasional debugging...
  45. //#pragma optimize("", off)
  46. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  47. #endif
  48. GameInfo *TheGameInfo = NULL;
  49. // GameSlot ----------------------------------------
  50. GameSlot::GameSlot()
  51. {
  52. reset();
  53. }
  54. void GameSlot::reset()
  55. {
  56. m_state = SLOT_CLOSED; // decent default
  57. m_isAccepted = false;
  58. m_hasMap = true;
  59. m_color = -1;
  60. m_startPos = -1;
  61. m_playerTemplate = -1;
  62. m_teamNumber = -1;
  63. m_NATBehavior = FirewallHelperClass::FIREWALL_TYPE_SIMPLE;
  64. m_lastFrameInGame = 0;
  65. m_disconnected = FALSE;
  66. m_port = 0;
  67. m_isMuted = FALSE;
  68. m_origPlayerTemplate = -1;
  69. m_origStartPos = -1;
  70. m_origColor = -1;
  71. }
  72. void GameSlot::saveOffOriginalInfo( void )
  73. {
  74. DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - orig was color=%d, pos=%d, house=%d\n",
  75. m_origColor, m_origStartPos, m_origPlayerTemplate));
  76. m_origPlayerTemplate = m_playerTemplate;
  77. m_origStartPos = m_startPos;
  78. m_origColor = m_color;
  79. DEBUG_LOG(("GameSlot::saveOffOriginalInfo() - color=%d, pos=%d, house=%d\n",
  80. m_color, m_startPos, m_playerTemplate));
  81. }
  82. static Int getSlotIndex(const GameSlot *slot)
  83. {
  84. for (Int i=0; i<MAX_SLOTS; ++i)
  85. {
  86. if (TheGameInfo->getConstSlot(i) == slot)
  87. return i;
  88. }
  89. return -1;
  90. }
  91. static Bool isSlotLocalAlly(const GameSlot *slot)
  92. {
  93. Int slotIndex = getSlotIndex(slot);
  94. Int localIndex = TheGameInfo->getLocalSlotNum();
  95. const GameSlot *localSlot = TheGameInfo->getConstSlot(localIndex);
  96. // if either doesn't exist, not an ally
  97. if (slotIndex < 0 || localIndex < 0)
  98. return FALSE;
  99. // if slot is us, ally
  100. if (slotIndex == localIndex)
  101. return TRUE;
  102. // if slot is same team as us, ally
  103. if (slot->getTeamNumber() == localSlot->getTeamNumber() && slot->getTeamNumber() >= 0)
  104. return TRUE;
  105. // if we're an observer, we see all
  106. if (localSlot->getOriginalPlayerTemplate() == PLAYERTEMPLATE_OBSERVER)
  107. return TRUE;
  108. // nope
  109. return FALSE;
  110. }
  111. UnicodeString GameSlot::getApparentPlayerTemplateDisplayName( void ) const
  112. {
  113. if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomPlayerTemplate() &&
  114. m_origPlayerTemplate == PLAYERTEMPLATE_RANDOM && !isSlotLocalAlly(this))
  115. {
  116. return TheGameText->fetch("GUI:Random");
  117. }
  118. else if (m_origPlayerTemplate == PLAYERTEMPLATE_OBSERVER)
  119. {
  120. return TheGameText->fetch("GUI:Observer");
  121. }
  122. DEBUG_LOG(("Fetching player template display name for player template %d (orig is %d)\n",
  123. m_playerTemplate, m_origPlayerTemplate));
  124. if (m_playerTemplate < 0)
  125. {
  126. return TheGameText->fetch("GUI:Random");
  127. }
  128. return ThePlayerTemplateStore->getNthPlayerTemplate(m_playerTemplate)->getDisplayName();
  129. }
  130. Int GameSlot::getApparentPlayerTemplate( void ) const
  131. {
  132. if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomPlayerTemplate() &&
  133. !isSlotLocalAlly(this))
  134. {
  135. return m_origPlayerTemplate;
  136. }
  137. return m_playerTemplate;
  138. }
  139. Int GameSlot::getApparentColor( void ) const
  140. {
  141. if (TheMultiplayerSettings && m_origPlayerTemplate == PLAYERTEMPLATE_OBSERVER)
  142. return TheMultiplayerSettings->getColor(PLAYERTEMPLATE_OBSERVER)->getColor();
  143. if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomColor() &&
  144. !isSlotLocalAlly(this))
  145. {
  146. return m_origColor;
  147. }
  148. return m_color;
  149. }
  150. Int GameSlot::getApparentStartPos( void ) const
  151. {
  152. if (TheMultiplayerSettings && TheMultiplayerSettings->showRandomStartPos() &&
  153. !isSlotLocalAlly(this))
  154. {
  155. return m_origStartPos;
  156. }
  157. return m_startPos;
  158. }
  159. void GameSlot::unAccept( void )
  160. {
  161. if (isHuman())
  162. {
  163. m_isAccepted = false;
  164. }
  165. }
  166. void GameSlot::setMapAvailability( Bool hasMap )
  167. {
  168. if (isHuman())
  169. {
  170. m_hasMap = hasMap;
  171. }
  172. }
  173. void GameSlot::setState( SlotState state, UnicodeString name, UnsignedInt IP )
  174. {
  175. if (!(isAI() && (state == SLOT_EASY_AI || state == SLOT_MED_AI || state == SLOT_BRUTAL_AI)))
  176. {
  177. m_color = -1;
  178. m_startPos = -1;
  179. m_playerTemplate = -1;
  180. m_teamNumber = -1;
  181. if (state == SLOT_OPEN && TheGameSpyGame && TheGameSpyGame->getConstSlot(0) == this)
  182. {
  183. DEBUG_CRASH(("Game Is Hosed!\n"));
  184. }
  185. }
  186. if (state == SLOT_PLAYER)
  187. {
  188. reset();
  189. m_state = state;
  190. m_name = name;
  191. }// state == SLOT_PLAYER
  192. else
  193. {
  194. m_state = state;
  195. m_isAccepted = true;
  196. m_hasMap = true;
  197. switch(state)
  198. {
  199. case SLOT_OPEN:
  200. m_name = TheGameText->fetch("GUI:Open");
  201. break;
  202. case SLOT_EASY_AI:
  203. m_name = TheGameText->fetch("GUI:EasyAI");
  204. break;
  205. case SLOT_MED_AI:
  206. m_name = TheGameText->fetch("GUI:MediumAI");
  207. break;
  208. case SLOT_BRUTAL_AI:
  209. m_name = TheGameText->fetch("GUI:HardAI");
  210. break;
  211. case SLOT_CLOSED:
  212. default:
  213. m_name = TheGameText->fetch("GUI:Closed");
  214. break;
  215. }
  216. }
  217. m_IP = IP;
  218. }
  219. // Various tests
  220. Bool GameSlot::isHuman( void ) const
  221. {
  222. return m_state == SLOT_PLAYER;
  223. }
  224. Bool GameSlot::isOccupied( void ) const
  225. {
  226. return m_state == SLOT_PLAYER || m_state == SLOT_EASY_AI || m_state == SLOT_MED_AI || m_state == SLOT_BRUTAL_AI;
  227. }
  228. Bool GameSlot::isAI( void ) const
  229. {
  230. return m_state == SLOT_EASY_AI || m_state == SLOT_MED_AI || m_state == SLOT_BRUTAL_AI;
  231. }
  232. Bool GameSlot::isPlayer( AsciiString userName ) const
  233. {
  234. UnicodeString uName;
  235. uName.translate(userName);
  236. return (m_state == SLOT_PLAYER && !m_name.compareNoCase(uName));
  237. }
  238. Bool GameSlot::isPlayer( UnicodeString userName ) const
  239. {
  240. return (m_state == SLOT_PLAYER && !m_name.compareNoCase(userName));
  241. }
  242. Bool GameSlot::isPlayer( UnsignedInt ip ) const
  243. {
  244. return (m_state == SLOT_PLAYER && m_IP == ip);
  245. }
  246. Bool GameSlot::isOpen( void ) const
  247. {
  248. return m_state == SLOT_OPEN;
  249. }
  250. // GameInfo ----------------------------------------
  251. GameInfo::GameInfo()
  252. {
  253. for (int i=0; i<MAX_SLOTS; ++i)
  254. {
  255. m_slot[i] = NULL;
  256. }
  257. reset();
  258. }
  259. void GameInfo::init( void )
  260. {
  261. reset();
  262. }
  263. void GameInfo::reset( void )
  264. {
  265. m_crcInterval = NET_CRC_INTERVAL;
  266. m_inGame = false;
  267. m_inProgress = false;
  268. m_gameID = 0;
  269. m_mapName = AsciiString("NOMAP");
  270. m_mapMask = 0;
  271. m_seed = GetTickCount(); //GameClientRandomValue(0, INT_MAX - 1);
  272. m_surrendered = FALSE;
  273. // Added By Sadullah Nader
  274. // Initializations missing and needed
  275. // m_localIP = 0; // BGC - actually we don't want this to be reset since the m_localIP is
  276. // set properly in the constructor of LANGameInfo which uses this as a base class.
  277. m_mapCRC = 0;
  278. m_mapSize = 0;
  279. //
  280. for (Int i=0; i<MAX_SLOTS; ++i)
  281. {
  282. if (m_slot[i])
  283. m_slot[i]->reset();
  284. }
  285. m_preorderMask = 0;
  286. }
  287. Bool GameInfo::isPlayerPreorder(Int index)
  288. {
  289. if (index >= 0 && index < MAX_SLOTS)
  290. return ((m_preorderMask & (1 << index)) != 0);
  291. return FALSE;
  292. }
  293. void GameInfo::markPlayerAsPreorder(Int index)
  294. {
  295. if (index >= 0 && index < MAX_SLOTS)
  296. m_preorderMask |= 1 << index;
  297. }
  298. void GameInfo::clearSlotList( void )
  299. {
  300. for (int i=0; i<MAX_SLOTS; ++i)
  301. {
  302. if (m_slot[i])
  303. m_slot[i]->setState(SLOT_CLOSED);
  304. }
  305. }
  306. Int GameInfo::getNumPlayers( void ) const
  307. {
  308. Int numPlayers = 0;
  309. for (int i=0; i<MAX_SLOTS; ++i)
  310. {
  311. if (m_slot[i] && m_slot[i]->isOccupied())
  312. numPlayers++;
  313. }
  314. return numPlayers;
  315. }
  316. Int GameInfo::getNumNonObserverPlayers( void ) const
  317. {
  318. Int numPlayers = 0;
  319. for (int i=0; i<MAX_SLOTS; ++i)
  320. {
  321. if (m_slot[i] && m_slot[i]->isOccupied() && m_slot[i]->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  322. numPlayers++;
  323. }
  324. return numPlayers;
  325. }
  326. Int GameInfo::getMaxPlayers( void ) const
  327. {
  328. if (!TheMapCache)
  329. return -1;
  330. AsciiString lowerMap = m_mapName;
  331. lowerMap.toLower();
  332. MapCache::iterator it = TheMapCache->find(lowerMap);
  333. if (it == TheMapCache->end())
  334. return -1;
  335. MapMetaData data = it->second;
  336. return data.m_numPlayers;
  337. }
  338. void GameInfo::enterGame( void )
  339. {
  340. DEBUG_ASSERTCRASH(!m_inGame && !m_inProgress, ("Entering game at a bad time!"));
  341. reset();
  342. m_inGame = true;
  343. m_inProgress = false;
  344. }
  345. void GameInfo::leaveGame( void )
  346. {
  347. DEBUG_ASSERTCRASH(m_inGame && !m_inProgress, ("Leaving game at a bad time!"));
  348. reset();
  349. }
  350. void GameInfo::startGame( Int gameID )
  351. {
  352. DEBUG_ASSERTCRASH(m_inGame && !m_inProgress, ("Starting game at a bad time!"));
  353. m_gameID = gameID;
  354. closeOpenSlots();
  355. m_inProgress = true;
  356. }
  357. void GameInfo::endGame( void )
  358. {
  359. DEBUG_ASSERTCRASH(m_inGame && m_inProgress, ("Ending game without playing one!"));
  360. m_inGame = false;
  361. m_inProgress = false;
  362. }
  363. void GameInfo::setSlot( Int slotNum, GameSlot slotInfo )
  364. {
  365. DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::setSlot - Invalid slot number"));
  366. if (slotNum < 0 || slotNum >= MAX_SLOTS)
  367. return;
  368. DEBUG_ASSERTCRASH( m_slot[slotNum], ("NULL slot pointer"));
  369. if (!m_slot[slotNum])
  370. return;
  371. // Bool isHuman = slotInfo.isHuman();
  372. // Bool wasHuman = m_slot[slotNum]->isHuman();
  373. if (slotNum == 0)
  374. {
  375. slotInfo.setAccept();
  376. slotInfo.setMapAvailability(true);
  377. }
  378. *m_slot[slotNum] = slotInfo;
  379. #ifdef DEBUG_LOGGING
  380. UnsignedInt ip = slotInfo.getIP();
  381. #endif
  382. DEBUG_LOG(("GameInfo::setSlot - setting slot %d to be player %ls with IP %d.%d.%d.%d\n", slotNum, slotInfo.getName().str(),
  383. ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff));
  384. }
  385. GameSlot* GameInfo::getSlot( Int slotNum )
  386. {
  387. DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::getSlot - Invalid slot number"));
  388. if (slotNum < 0 || slotNum >= MAX_SLOTS)
  389. return NULL;
  390. return m_slot[slotNum];
  391. }
  392. const GameSlot* GameInfo::getConstSlot( Int slotNum ) const
  393. {
  394. DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::getSlot - Invalid slot number"));
  395. if (slotNum < 0 || slotNum >= MAX_SLOTS)
  396. return NULL;
  397. return m_slot[slotNum];
  398. }
  399. Int GameInfo::getLocalSlotNum( void ) const
  400. {
  401. DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game"));
  402. if (!m_inGame)
  403. return -1;
  404. for (Int i=0; i<MAX_SLOTS; ++i)
  405. {
  406. const GameSlot *slot = getConstSlot(i);
  407. if (slot == NULL) {
  408. continue;
  409. }
  410. if (slot->isPlayer(m_localIP))
  411. return i;
  412. }
  413. return -1;
  414. }
  415. Int GameInfo::getSlotNum( AsciiString userName ) const
  416. {
  417. DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game"));
  418. if (!m_inGame)
  419. return -1;
  420. UnicodeString uName;
  421. uName.translate(userName);
  422. for (Int i=0; i<MAX_SLOTS; ++i)
  423. {
  424. const GameSlot *slot = getConstSlot(i);
  425. if (slot->isPlayer( uName ))
  426. return i;
  427. }
  428. return -1;
  429. }
  430. Bool GameInfo::amIHost( void ) const
  431. {
  432. DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game"));
  433. if (!m_inGame)
  434. return false;
  435. return getConstSlot(0)->isPlayer(m_localIP);
  436. }
  437. void GameInfo::setMap( AsciiString mapName )
  438. {
  439. m_mapName = mapName;
  440. if (m_inGame && amIHost())
  441. {
  442. const MapMetaData *mapData = TheMapCache->findMap( mapName );
  443. if (mapData)
  444. {
  445. m_mapMask = 1;
  446. AsciiString path = mapName;
  447. path.removeLastChar();
  448. path.removeLastChar();
  449. path.removeLastChar();
  450. path.concat("tga");
  451. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  452. File *fp = TheFileSystem->openFile(path.str());
  453. if (fp)
  454. {
  455. m_mapMask |= 2;
  456. fp->close();
  457. fp = NULL;
  458. }
  459. AsciiString newMapName;
  460. if (mapName.getLength() > 0)
  461. {
  462. AsciiString token;
  463. mapName.nextToken(&token, "\\/");
  464. // add all the tokens except the last one.
  465. // that way we don't add the filename, just the
  466. // directory name, we can do this since the filename
  467. // is just the directory name with the file extention
  468. // added onto it.
  469. while (mapName.find('\\') != NULL)
  470. {
  471. if (newMapName.getLength() > 0)
  472. {
  473. newMapName.concat('/');
  474. }
  475. newMapName.concat(token);
  476. mapName.nextToken(&token, "\\/");
  477. }
  478. }
  479. newMapName.concat("/map.ini");
  480. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", newMapName.str()));
  481. fp = TheFileSystem->openFile(newMapName.str());
  482. if (fp)
  483. {
  484. m_mapMask |= 4;
  485. fp->close();
  486. fp = NULL;
  487. }
  488. path = GetStrFileFromMap(m_mapName);
  489. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  490. fp = TheFileSystem->openFile(path.str());
  491. if (fp)
  492. {
  493. m_mapMask |= 8;
  494. fp->close();
  495. fp = NULL;
  496. }
  497. path = GetSoloINIFromMap(m_mapName);
  498. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  499. fp = TheFileSystem->openFile(path.str());
  500. if (fp)
  501. {
  502. m_mapMask |= 16;
  503. fp->close();
  504. fp = NULL;
  505. }
  506. path = GetAssetUsageFromMap(m_mapName);
  507. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  508. fp = TheFileSystem->openFile(path.str());
  509. if (fp)
  510. {
  511. m_mapMask |= 32;
  512. fp->close();
  513. fp = NULL;
  514. }
  515. path = GetReadmeFromMap(m_mapName);
  516. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  517. fp = TheFileSystem->openFile(path.str());
  518. if (fp)
  519. {
  520. m_mapMask |= 64;
  521. fp->close();
  522. fp = NULL;
  523. }
  524. }
  525. else
  526. {
  527. m_mapMask = 0;
  528. }
  529. }
  530. }
  531. void GameInfo::setMapContentsMask( Int mask )
  532. {
  533. m_mapMask = mask;
  534. }
  535. void GameInfo::setMapCRC( UnsignedInt mapCRC )
  536. {
  537. m_mapCRC = mapCRC;
  538. if (!TheMapCache)
  539. return;
  540. // check the map cache
  541. if (m_inGame && getLocalSlotNum() >= 0)
  542. {
  543. //TheMapCache->updateCache();
  544. AsciiString lowerMap = m_mapName;
  545. lowerMap.toLower();
  546. //DEBUG_LOG(("GameInfo::setMapCRC - looking for map file \"%s\" in the map cache\n", lowerMap.str()));
  547. std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(lowerMap);
  548. if (it == TheMapCache->end())
  549. {
  550. /*
  551. DEBUG_LOG(("GameInfo::setMapCRC - could not find map file.\n"));
  552. it = TheMapCache->begin();
  553. while (it != TheMapCache->end())
  554. {
  555. DEBUG_LOG(("\t\"%s\"\n", it->first.str()));
  556. ++it;
  557. }
  558. */
  559. getSlot(getLocalSlotNum())->setMapAvailability(false);
  560. }
  561. else if (m_mapCRC != it->second.m_CRC)
  562. {
  563. DEBUG_LOG(("GameInfo::setMapCRC - map CRC's do not match (%X/%X).\n", m_mapCRC, it->second.m_CRC));
  564. getSlot(getLocalSlotNum())->setMapAvailability(false);
  565. }
  566. else
  567. {
  568. //DEBUG_LOG(("GameInfo::setMapCRC - map CRC's match.\n"));
  569. getSlot(getLocalSlotNum())->setMapAvailability(true);
  570. }
  571. }
  572. }
  573. void GameInfo::setMapSize( UnsignedInt mapSize )
  574. {
  575. m_mapSize = mapSize;
  576. if (!TheMapCache)
  577. return;
  578. // check the map cache
  579. if (m_inGame && getLocalSlotNum() >= 0)
  580. {
  581. //TheMapCache->updateCache();
  582. AsciiString lowerMap = m_mapName;
  583. lowerMap.toLower();
  584. std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(lowerMap);
  585. if (it == TheMapCache->end())
  586. {
  587. DEBUG_LOG(("GameInfo::setMapSize - could not find map file.\n"));
  588. getSlot(getLocalSlotNum())->setMapAvailability(false);
  589. }
  590. else if (m_mapCRC != it->second.m_CRC)
  591. {
  592. DEBUG_LOG(("GameInfo::setMapSize - map CRC's do not match.\n"));
  593. getSlot(getLocalSlotNum())->setMapAvailability(false);
  594. }
  595. else
  596. {
  597. //DEBUG_LOG(("GameInfo::setMapSize - map CRC's match.\n"));
  598. getSlot(getLocalSlotNum())->setMapAvailability(true);
  599. }
  600. }
  601. }
  602. void GameInfo::setSeed( Int seed )
  603. {
  604. m_seed = seed;
  605. }
  606. void GameInfo::setSlotPointer( Int index, GameSlot *slot )
  607. {
  608. if (index < 0 || index >= MAX_SLOTS)
  609. return;
  610. m_slot[index] = slot;
  611. }
  612. Bool GameInfo::isColorTaken(Int colorIdx, Int slotToIgnore ) const
  613. {
  614. for (Int i=0; i<MAX_SLOTS; ++i)
  615. {
  616. const GameSlot *slot = getConstSlot(i);
  617. if (slot && slot->getColor() == colorIdx && i != slotToIgnore)
  618. return true;
  619. }
  620. return false;
  621. }
  622. Bool GameInfo::isStartPositionTaken(Int positionIdx, Int slotToIgnore ) const
  623. {
  624. for (Int i=0; i<MAX_SLOTS; ++i)
  625. {
  626. const GameSlot *slot = getConstSlot(i);
  627. if (slot && slot->getStartPos() == positionIdx && i != slotToIgnore)
  628. return true;
  629. }
  630. return false;
  631. }
  632. void GameInfo::resetAccepted( void )
  633. {
  634. GameSlot *slot = getSlot(0);
  635. if (slot)
  636. slot->setAccept();
  637. for(int i = 1; i< MAX_SLOTS; i++)
  638. {
  639. slot = getSlot(i);
  640. if (slot)
  641. slot->unAccept();
  642. }
  643. }
  644. void GameInfo::resetStartSpots()
  645. {
  646. GameSlot *slot = NULL;
  647. for (Int i = 0; i < MAX_SLOTS; ++i)
  648. {
  649. slot = getSlot(i);
  650. if (slot != NULL)
  651. {
  652. slot->setStartPos(-1);
  653. }
  654. }
  655. }
  656. // adjust the slots in the game to open or closed
  657. // depending on the players in there now and the number of
  658. // players the map can hold.
  659. void GameInfo::adjustSlotsForMap()
  660. {
  661. const MapMetaData *md = TheMapCache->findMap(m_mapName);
  662. if (md != NULL)
  663. {
  664. // get the number of players allowed from the map.
  665. Int numPlayers = md->m_numPlayers;
  666. Int numPlayerSlots = 0;
  667. // first get the number of occupied slots.
  668. for (Int i = 0; i < MAX_SLOTS; ++i)
  669. {
  670. GameSlot *tempSlot = getSlot(i);
  671. if (tempSlot->isOccupied())
  672. {
  673. ++numPlayerSlots;
  674. }
  675. }
  676. // now go through and close the appropriate number of slots.
  677. // note that no players are kicked in this process, we leave
  678. // that up to the user.
  679. for (i = 0; i < MAX_SLOTS; ++i)
  680. {
  681. // we have room for more players, if this slot is unoccupied, set it to open.
  682. GameSlot *slot = getSlot(i);
  683. if (numPlayers > numPlayerSlots)
  684. {
  685. if (!(slot->isOccupied()))
  686. {
  687. GameSlot newSlot;
  688. newSlot.setState(SLOT_OPEN);
  689. setSlot(i, newSlot);
  690. ++numPlayerSlots;
  691. }
  692. }
  693. else
  694. {
  695. if (!(slot->isOccupied()))
  696. {
  697. // we don't have any more room, set this slot to closed.
  698. GameSlot newSlot;
  699. newSlot.setState(SLOT_CLOSED);
  700. setSlot(i, newSlot);
  701. }
  702. }
  703. }
  704. }
  705. }
  706. void GameInfo::closeOpenSlots()
  707. {
  708. for (Int i = 0; i < MAX_SLOTS; ++i)
  709. {
  710. GameSlot *slot = getSlot(i);
  711. if (!(slot->isOccupied()))
  712. {
  713. GameSlot newSlot;
  714. newSlot.setState(SLOT_CLOSED);
  715. setSlot(i, newSlot);
  716. }
  717. }
  718. }
  719. static Bool isSlotLocalAlly(GameInfo *game, const GameSlot *slot)
  720. {
  721. const GameSlot *localSlot = game->getConstSlot(game->getLocalSlotNum());
  722. if (!localSlot)
  723. return TRUE;
  724. if (slot == localSlot)
  725. return TRUE;
  726. if (slot->getTeamNumber() < 0)
  727. return FALSE;
  728. return slot->getTeamNumber() == localSlot->getTeamNumber();
  729. }
  730. Bool GameInfo::isSkirmish(void)
  731. {
  732. Bool sawAI = FALSE;
  733. for (Int i=0; i<MAX_SLOTS; ++i)
  734. {
  735. if (i == getLocalSlotNum())
  736. continue;
  737. if (getConstSlot(i)->isHuman())
  738. return FALSE;
  739. if (getConstSlot(i)->isAI())
  740. {
  741. if (isSlotLocalAlly(getConstSlot(i)))
  742. return FALSE;
  743. sawAI = TRUE;
  744. }
  745. }
  746. return sawAI;
  747. }
  748. Bool GameInfo::isMultiPlayer(void)
  749. {
  750. for (Int i=0; i<MAX_SLOTS; ++i)
  751. {
  752. if (i == getLocalSlotNum())
  753. continue;
  754. if (getConstSlot(i)->isHuman())
  755. return TRUE;
  756. }
  757. return FALSE;
  758. }
  759. Bool GameInfo::isSandbox(void)
  760. {
  761. Int localSlotNum = getLocalSlotNum();
  762. Int localTeam = getConstSlot(localSlotNum)->getTeamNumber();
  763. for (Int i=0; i<MAX_SLOTS; ++i)
  764. {
  765. if (i == localSlotNum)
  766. continue;
  767. const GameSlot *slot = getConstSlot(i);
  768. if (slot->isOccupied() && (slot->getTeamNumber() < 0 || slot->getTeamNumber() != localTeam))
  769. return FALSE;
  770. }
  771. return TRUE;
  772. }
  773. // Convenience Functions ----------------------------------------
  774. static const char slotListID = 'S';
  775. AsciiString GameInfoToAsciiString( const GameInfo *game )
  776. {
  777. if (!game)
  778. return AsciiString::TheEmptyString;
  779. AsciiString mapName = game->getMap();
  780. mapName = TheGameState->realMapPathToPortableMapPath(mapName);
  781. AsciiString newMapName;
  782. if (mapName.getLength() > 0)
  783. {
  784. AsciiString token;
  785. mapName.nextToken(&token, "\\/");
  786. // add all the tokens except the last one.
  787. // that way we don't add the filename, just the
  788. // directory name, we can do this since the filename
  789. // is just the directory name with the file extention
  790. // added onto it.
  791. while (mapName.find('\\') != NULL)
  792. {
  793. if (newMapName.getLength() > 0)
  794. {
  795. newMapName.concat('/');
  796. }
  797. newMapName.concat(token);
  798. mapName.nextToken(&token, "\\/");
  799. }
  800. DEBUG_LOG(("Map name is %s\n", mapName.str()));
  801. }
  802. AsciiString optionsString;
  803. optionsString.format("M=%2.2x%s;MC=%X;MS=%d;SD=%d;C=%d;", game->getMapContentsMask(), newMapName.str(),
  804. game->getMapCRC(), game->getMapSize(), game->getSeed(), game->getCRCInterval());
  805. optionsString.concat(slotListID);
  806. optionsString.concat('=');
  807. for (Int i=0; i<MAX_SLOTS; ++i)
  808. {
  809. const GameSlot *slot = game->getConstSlot(i);
  810. AsciiString str;
  811. if (slot && slot->isHuman())
  812. {
  813. AsciiString name = WideCharStringToMultiByte(slot->getName().str()).c_str();
  814. str.format( "H%s,%X,%d,%c%c,%d,%d,%d,%d,%d:",
  815. name.str(), slot->getIP(), slot->getPort(),
  816. (slot->isAccepted()?'T':'F'),
  817. (slot->hasMap()?'T':'F'),
  818. slot->getColor(), slot->getPlayerTemplate(),
  819. slot->getStartPos(), slot->getTeamNumber(),
  820. slot->getNATBehavior() );
  821. }
  822. else if (slot && slot->isAI())
  823. {
  824. Char c;
  825. if (slot->getState() == SLOT_EASY_AI)
  826. c = 'E';
  827. else if (slot->getState() == SLOT_MED_AI)
  828. c = 'M';
  829. else
  830. c = 'H';
  831. str.format("C%c,%d,%d,%d,%d:", c,
  832. slot->getColor(), slot->getPlayerTemplate(),
  833. slot->getStartPos(), slot->getTeamNumber());
  834. }
  835. else if (slot && slot->getState() == SLOT_OPEN)
  836. {
  837. str = "O:";
  838. }
  839. else if (slot && slot->getState() == SLOT_CLOSED)
  840. {
  841. str = "X:";
  842. }
  843. else
  844. {
  845. DEBUG_ASSERTCRASH(false, ("Bad slot type"));
  846. str = "X:";
  847. }
  848. optionsString.concat(str);
  849. }
  850. optionsString.concat(';');
  851. DEBUG_ASSERTCRASH(!TheLAN || (optionsString.getLength() < m_lanMaxOptionsLength),
  852. ("WARNING: options string is longer than expected! Length is %d, but max is %d!\n",
  853. optionsString.getLength(), m_lanMaxOptionsLength));
  854. return optionsString;
  855. }
  856. static Int grabHexInt(const char *s)
  857. {
  858. char tmp[5] = "0xff";
  859. tmp[2] = s[0];
  860. tmp[3] = s[1];
  861. Int b = strtol(tmp, NULL, 16);
  862. return b;
  863. }
  864. Bool ParseAsciiStringToGameInfo(GameInfo *game, AsciiString options)
  865. {
  866. // Parse game options
  867. char *buf = strdup(options.str());
  868. char *bufPtr = buf;
  869. char *strPos, *keyValPair;
  870. GameSlot newSlot[MAX_SLOTS];
  871. Bool optionsOk = true;
  872. AsciiString mapName;
  873. Int mapContentsMask;
  874. UnsignedInt mapCRC, mapSize;
  875. Int seed = 0;
  876. Int crc = 100;
  877. Bool sawCRC = FALSE;
  878. Bool sawMap, sawMapCRC, sawMapSize, sawSeed, sawSlotlist;
  879. sawMap = sawMapCRC = sawMapSize = sawSeed = sawSlotlist = FALSE;
  880. //DEBUG_LOG(("Saw options of %s\n", options.str()));
  881. DEBUG_LOG(("ParseAsciiStringToGameInfo - parsing [%s]\n", options.str()));
  882. while ( (keyValPair = strtok_r(bufPtr, ";", &strPos)) != NULL )
  883. {
  884. bufPtr = NULL; // strtok within the same string
  885. AsciiString key, val;
  886. char *pos = NULL;
  887. char *keyPtr, *valPtr;
  888. keyPtr = (strtok_r(keyValPair, "=", &pos));
  889. valPtr = (strtok_r(NULL, "\n", &pos));
  890. if (keyPtr)
  891. key = keyPtr;
  892. if (valPtr)
  893. val = valPtr;
  894. if (val.isEmpty())
  895. {
  896. optionsOk = false;
  897. DEBUG_LOG(("ParseAsciiStringToGameInfo - saw empty value, quitting\n"));
  898. break;
  899. }
  900. if (key.compare("M") == 0)
  901. {
  902. if (val.getLength() < 3)
  903. {
  904. optionsOk = FALSE;
  905. DEBUG_LOG(("ParseAsciiStringToGameInfo - saw bogus map; quitting\n"));
  906. break;
  907. }
  908. mapContentsMask = grabHexInt(val.str());
  909. AsciiString tempstr;
  910. AsciiString token;
  911. tempstr = val.str()+2;
  912. tempstr.nextToken(&token, "\\/");
  913. while (tempstr.getLength() > 0)
  914. {
  915. mapName.concat(token);
  916. mapName.concat('\\');
  917. tempstr.nextToken(&token, "\\/");
  918. }
  919. mapName.concat(token);
  920. mapName.concat('\\');
  921. mapName.concat(token);
  922. mapName.concat('.');
  923. mapName.concat(TheMapCache->getMapExtension());
  924. mapName = TheGameState->portableMapPathToRealMapPath(mapName);
  925. sawMap = true;
  926. DEBUG_LOG(("ParseAsciiStringToGameInfo - map name is %s\n", mapName.str()));
  927. }
  928. else if (key.compare("MC") == 0)
  929. {
  930. mapCRC = 0;
  931. sscanf(val.str(), "%X", &mapCRC);
  932. sawMapCRC = true;
  933. }
  934. else if (key.compare("MS") == 0)
  935. {
  936. mapSize = atoi(val.str());
  937. sawMapSize = true;
  938. }
  939. else if (key.compare("SD") == 0)
  940. {
  941. seed = atoi(val.str());
  942. sawSeed = true;
  943. // DEBUG_LOG(("ParseAsciiStringToGameInfo - random seed is %d\n", seed));
  944. }
  945. else if (key.compare("C") == 0)
  946. {
  947. crc = atoi(val.str());
  948. sawCRC = TRUE;
  949. }
  950. else if (key.getLength() == 1 && *key.str() == slotListID)
  951. {
  952. sawSlotlist = true;
  953. /// @TODO: Need to read in all the slot info... big mess right now.
  954. char *rawSlotBuf = strdup(val.str());
  955. char *freeMe = NULL;
  956. AsciiString rawSlot;
  957. // Bool slotsOk = true; //flag that lets us know whether or not the slot list is good.
  958. // DEBUG_LOG(("ParseAsciiStringToGameInfo - Parsing slot list\n"));
  959. for (int i=0; i<MAX_SLOTS; ++i)
  960. {
  961. rawSlot = strtok_r(rawSlotBuf,":",&pos);
  962. if( rawSlotBuf )
  963. freeMe = rawSlotBuf;
  964. rawSlotBuf = NULL;
  965. switch (*rawSlot.str())
  966. {
  967. case 'H':
  968. {
  969. // DEBUG_LOG(("ParseAsciiStringToGameInfo - Human player\n"));
  970. char *slotPos = NULL;
  971. //Parse out the Name
  972. AsciiString slotValue(strtok_r((char *)rawSlot.str(),",",&slotPos));
  973. if(slotValue.isEmpty())
  974. {
  975. optionsOk = false;
  976. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue name is empty, quitting\n"));
  977. break;
  978. }
  979. UnicodeString name;
  980. name.set(MultiByteToWideCharSingleLine(slotValue.str() +1).c_str());
  981. //DEBUG_LOG(("ParseAsciiStringToGameInfo - name is %s\n", slotValue.str()+1));
  982. //Parse out the IP
  983. slotValue = strtok_r(NULL,",",&slotPos);
  984. if(slotValue.isEmpty())
  985. {
  986. optionsOk = false;
  987. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue IP address is empty, quitting\n"));
  988. break;
  989. }
  990. UnsignedInt playerIP = 0;
  991. sscanf(slotValue.str(),"%x", &playerIP);
  992. //DEBUG_LOG(("ParseAsciiStringToGameInfo - IP address is %x\n", playerIP));
  993. //set the state of the slot
  994. newSlot[i].setState(SLOT_PLAYER, name, playerIP);
  995. // parse out the port
  996. slotValue = strtok_r(NULL, ",", &slotPos);
  997. if (slotValue.isEmpty())
  998. {
  999. optionsOk = false;
  1000. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue port is empty, quitting\n"));
  1001. break;
  1002. }
  1003. UnsignedInt playerPort = 0;
  1004. sscanf(slotValue.str(), "%d", &playerPort);
  1005. newSlot[i].setPort(playerPort);
  1006. DEBUG_LOG(("ParseAsciiStringToGameInfo - port is %d\n", playerPort));
  1007. //Read if it's accepted or not
  1008. slotValue = strtok_r(NULL,",",&slotPos);
  1009. if(slotValue.getLength() != 2)
  1010. {
  1011. optionsOk = false;
  1012. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue accepted is mis-sized, quitting\n"));
  1013. break;
  1014. }
  1015. const char *svs = slotValue.str();
  1016. if(*svs == 'T') {
  1017. newSlot[i].setAccept();
  1018. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player has accepted\n"));
  1019. } else if (*svs == 'F') {
  1020. newSlot[i].unAccept();
  1021. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player has not accepted\n"));
  1022. }
  1023. ++svs;
  1024. if(*svs == 'T') {
  1025. newSlot[i].setMapAvailability(TRUE);
  1026. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player has map\n"));
  1027. } else {
  1028. newSlot[i].setMapAvailability(FALSE);
  1029. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player does not have map\n"));
  1030. }
  1031. //Read color index
  1032. slotValue = strtok_r(NULL,",",&slotPos);
  1033. if(slotValue.isEmpty())
  1034. {
  1035. optionsOk = false;
  1036. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue color is empty, quitting\n"));
  1037. break;
  1038. }
  1039. Int color = atoi(slotValue.str());
  1040. if (color < -1 || color >= TheMultiplayerSettings->getNumColors())
  1041. {
  1042. optionsOk = false;
  1043. DEBUG_LOG(("ParseAsciiStringToGameInfo - player color was invalid, quitting\n"));
  1044. break;
  1045. }
  1046. newSlot[i].setColor(color);
  1047. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player color set to %d\n", color));
  1048. //Read playerTemplate index
  1049. slotValue = strtok_r(NULL,",",&slotPos);
  1050. if(slotValue.isEmpty())
  1051. {
  1052. optionsOk = false;
  1053. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue player template is empty, quitting\n"));
  1054. break;
  1055. }
  1056. Int playerTemplate = atoi(slotValue.str());
  1057. if (playerTemplate < PLAYERTEMPLATE_MIN || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount())
  1058. {
  1059. optionsOk = false;
  1060. DEBUG_LOG(("ParseAsciiStringToGameInfo - player template value is invalid, quitting\n"));
  1061. break;
  1062. }
  1063. newSlot[i].setPlayerTemplate(playerTemplate);
  1064. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player template is %d\n", playerTemplate));
  1065. //Read start position index
  1066. slotValue = strtok_r(NULL,",",&slotPos);
  1067. if(slotValue.isEmpty())
  1068. {
  1069. optionsOk = false;
  1070. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue start position is empty, quitting\n"));
  1071. break;
  1072. }
  1073. Int startPos = atoi(slotValue.str());
  1074. if (startPos < -1 || startPos >= MAX_SLOTS)
  1075. {
  1076. optionsOk = false;
  1077. DEBUG_LOG(("ParseAsciiStringToGameInfo - player start position is invalid, quitting\n"));
  1078. break;
  1079. }
  1080. newSlot[i].setStartPos(startPos);
  1081. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player start position is %d\n", startPos));
  1082. //Read team index
  1083. slotValue = strtok_r(NULL,",",&slotPos);
  1084. if(slotValue.isEmpty())
  1085. {
  1086. optionsOk = false;
  1087. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue team number is empty, quitting\n"));
  1088. break;
  1089. }
  1090. Int team = atoi(slotValue.str());
  1091. if (team < -1 || team >= MAX_SLOTS/2)
  1092. {
  1093. optionsOk = false;
  1094. DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is invalid, quitting\n"));
  1095. break;
  1096. }
  1097. newSlot[i].setTeamNumber(team);
  1098. //DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is %d\n", team));
  1099. // Read the NAT behavior
  1100. slotValue = strtok_r(NULL, ",",&slotPos);
  1101. if (slotValue.isEmpty())
  1102. {
  1103. optionsOk = false;
  1104. DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is empty, quitting\n"));
  1105. break;
  1106. }
  1107. FirewallHelperClass::FirewallBehaviorType NATType = (FirewallHelperClass::FirewallBehaviorType)atoi(slotValue.str());
  1108. if ((NATType < FirewallHelperClass::FIREWALL_MIN) ||
  1109. (NATType > FirewallHelperClass::FIREWALL_MAX)) {
  1110. optionsOk = false;
  1111. DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is invalid, quitting\n"));
  1112. break;
  1113. }
  1114. newSlot[i].setNATBehavior(NATType);
  1115. DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is %X\n", NATType));
  1116. }// case 'H':
  1117. break;
  1118. case 'C':
  1119. {
  1120. DEBUG_LOG(("ParseAsciiStringToGameInfo - AI player\n"));
  1121. char *slotPos = NULL;
  1122. //Parse out the Name
  1123. AsciiString slotValue(strtok_r((char *)rawSlot.str(),",",&slotPos));
  1124. if(slotValue.isEmpty())
  1125. {
  1126. optionsOk = false;
  1127. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue AI Type is empty, quitting\n"));
  1128. break;
  1129. }
  1130. switch(*(slotValue.str() + 1))
  1131. {
  1132. case 'E':
  1133. {
  1134. newSlot[i].setState(SLOT_EASY_AI);
  1135. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Easy AI\n"));
  1136. }
  1137. break;
  1138. case 'M':
  1139. {
  1140. newSlot[i].setState(SLOT_MED_AI);
  1141. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Medium AI\n"));
  1142. }
  1143. break;
  1144. case 'H':
  1145. {
  1146. newSlot[i].setState(SLOT_BRUTAL_AI);
  1147. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Brutal AI\n"));
  1148. }
  1149. break;
  1150. default:
  1151. {
  1152. optionsOk = false;
  1153. DEBUG_LOG(("ParseAsciiStringToGameInfo - Unknown AI, quitting\n"));
  1154. }
  1155. break;
  1156. }//switch(*rawSlot.str()+1)
  1157. //Read color index
  1158. slotValue = strtok_r(NULL,",",&slotPos);
  1159. if(slotValue.isEmpty())
  1160. {
  1161. optionsOk = false;
  1162. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue color is empty, quitting\n"));
  1163. break;
  1164. }
  1165. Int color = atoi(slotValue.str());
  1166. if (color < -1 || color >= TheMultiplayerSettings->getNumColors())
  1167. {
  1168. optionsOk = false;
  1169. DEBUG_LOG(("ParseAsciiStringToGameInfo - player color was invalid, quitting\n"));
  1170. break;
  1171. }
  1172. newSlot[i].setColor(color);
  1173. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player color set to %d\n", color));
  1174. //Read playerTemplate index
  1175. slotValue = strtok_r(NULL,",",&slotPos);
  1176. if(slotValue.isEmpty())
  1177. {
  1178. optionsOk = false;
  1179. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue player template is empty, quitting\n"));
  1180. break;
  1181. }
  1182. Int playerTemplate = atoi(slotValue.str());
  1183. if (playerTemplate < PLAYERTEMPLATE_MIN || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount())
  1184. {
  1185. optionsOk = false;
  1186. DEBUG_LOG(("ParseAsciiStringToGameInfo - player template value is invalid, quitting\n"));
  1187. break;
  1188. }
  1189. newSlot[i].setPlayerTemplate(playerTemplate);
  1190. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player template is %d\n", playerTemplate));
  1191. //Read start pos
  1192. slotValue = strtok_r(NULL,",",&slotPos);
  1193. if(slotValue.isEmpty())
  1194. {
  1195. optionsOk = false;
  1196. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue start pos is empty, quitting\n"));
  1197. break;
  1198. }
  1199. Int startPos = atoi(slotValue.str());
  1200. Bool isStartPosBad = FALSE;
  1201. if (startPos < -1 || startPos >= MAX_SLOTS)
  1202. {
  1203. isStartPosBad = TRUE;
  1204. }
  1205. for (Int j=0; j<i; ++j)
  1206. {
  1207. if (startPos >= 0 && startPos == newSlot[i].getStartPos())
  1208. {
  1209. isStartPosBad = TRUE; // can't have multiple people using the same start pos
  1210. }
  1211. }
  1212. if (isStartPosBad)
  1213. {
  1214. optionsOk = false;
  1215. DEBUG_LOG(("ParseAsciiStringToGameInfo - start pos is invalid, quitting\n"));
  1216. break;
  1217. }
  1218. newSlot[i].setStartPos(startPos);
  1219. //DEBUG_LOG(("ParseAsciiStringToGameInfo - start spot is %d\n", startPos));
  1220. //Read team index
  1221. slotValue = strtok_r(NULL,",",&slotPos);
  1222. if(slotValue.isEmpty())
  1223. {
  1224. optionsOk = false;
  1225. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue team number is empty, quitting\n"));
  1226. break;
  1227. }
  1228. Int team = atoi(slotValue.str());
  1229. if (team < -1 || team >= MAX_SLOTS/2)
  1230. {
  1231. optionsOk = false;
  1232. DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is invalid, quitting\n"));
  1233. break;
  1234. }
  1235. newSlot[i].setTeamNumber(team);
  1236. //DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is %d\n", team));
  1237. }//case 'C':
  1238. break;
  1239. case 'O':
  1240. {
  1241. newSlot[i].setState( SLOT_OPEN );
  1242. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Slot is open\n"));
  1243. }// case 'O':
  1244. break;
  1245. case 'X':
  1246. {
  1247. newSlot[i].setState( SLOT_CLOSED );
  1248. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Slot is closed\n"));
  1249. }// case 'X':
  1250. break;
  1251. default:
  1252. {
  1253. optionsOk = false;
  1254. DEBUG_LOG(("ParseAsciiStringToGameInfo - unrecognized slot entry, quitting\n"));
  1255. }
  1256. break;
  1257. }
  1258. }
  1259. if(freeMe)
  1260. free(freeMe);
  1261. }
  1262. else
  1263. {
  1264. optionsOk = false;
  1265. break;
  1266. }
  1267. }
  1268. if( buf )
  1269. free(buf);
  1270. //DEBUG_LOG(("Options were ok == %d\n", optionsOk));
  1271. if (optionsOk && sawMap && sawMapCRC && sawMapSize && sawSeed && sawSlotlist && sawCRC)
  1272. {
  1273. // We were setting the Global Data directly here, but Instead, I'm now
  1274. // first setting the data in game. We'll set the global data when
  1275. // we start a game.
  1276. if (!game)
  1277. return true;
  1278. //DEBUG_LOG(("ParseAsciiStringToGameInfo - game options all good, setting info\n"));
  1279. for(Int i = 0; i<MAX_SLOTS; i++)
  1280. game->setSlot(i,newSlot[i]);
  1281. game->setMap(mapName);
  1282. game->setMapCRC(mapCRC);
  1283. game->setMapSize(mapSize);
  1284. game->setMapContentsMask(mapContentsMask);
  1285. game->setSeed(seed);
  1286. game->setCRCInterval(crc);
  1287. return true;
  1288. }
  1289. DEBUG_LOG(("ParseAsciiStringToGameInfo - game options messed up\n"));
  1290. return false;
  1291. }
  1292. //----------------------------------------------------------------------------------------------------------
  1293. //----------------------------------------------------------------------------------------------------------
  1294. //------------------------- SkirmishGameInfo ---------------------------------------------------------------
  1295. // ------------------------------------------------------------------------------------------------
  1296. /** CRC */
  1297. // ------------------------------------------------------------------------------------------------
  1298. void SkirmishGameInfo::crc( Xfer *xfer )
  1299. {
  1300. } // end crc
  1301. // ------------------------------------------------------------------------------------------------
  1302. /** Xfer Method */
  1303. // ------------------------------------------------------------------------------------------------
  1304. void SkirmishGameInfo::xfer( Xfer *xfer )
  1305. {
  1306. const XferVersion currentVersion = 2;
  1307. XferVersion version = currentVersion;
  1308. xfer->xferVersion( &version, currentVersion );
  1309. xfer->xferInt(&m_preorderMask);
  1310. xfer->xferInt(&m_crcInterval);
  1311. xfer->xferBool(&m_inGame);
  1312. xfer->xferBool(&m_inProgress);
  1313. xfer->xferBool(&m_surrendered);
  1314. xfer->xferInt(&m_gameID);
  1315. Int slot = MAX_SLOTS;
  1316. xfer->xferInt(&slot);
  1317. DEBUG_ASSERTCRASH(slot==MAX_SLOTS, ("MAX_SLOTS changed, need to change version. jba."));
  1318. for (slot = 0; slot < MAX_SLOTS; slot++)
  1319. {
  1320. Int state = m_slot[slot]->getState();
  1321. xfer->xferInt(&state);
  1322. UnicodeString name=m_slot[slot]->getName();
  1323. if (version >= 2)
  1324. {
  1325. xfer->xferUnicodeString(&name);
  1326. }
  1327. Bool isAccepted=m_slot[slot]->isAccepted();
  1328. xfer->xferBool(&isAccepted);
  1329. Bool isMuted=m_slot[slot]->isMuted();
  1330. xfer->xferBool(&isMuted);
  1331. m_slot[slot]->mute(isMuted);
  1332. Int color=m_slot[slot]->getColor();
  1333. xfer->xferInt(&color);
  1334. Int startPos=m_slot[slot]->getStartPos();
  1335. xfer->xferInt(&startPos);
  1336. Int playerTemplate=m_slot[slot]->getPlayerTemplate();
  1337. xfer->xferInt(&playerTemplate);
  1338. Int teamNumber=m_slot[slot]->getTeamNumber();
  1339. xfer->xferInt(&teamNumber);
  1340. Int origColor=m_slot[slot]->getOriginalColor();
  1341. xfer->xferInt(&origColor);
  1342. Int origStartPos=m_slot[slot]->getOriginalStartPos();
  1343. xfer->xferInt(&origStartPos);
  1344. Int origPlayerTemplate=m_slot[slot]->getOriginalPlayerTemplate();
  1345. xfer->xferInt(&origPlayerTemplate);
  1346. if( xfer->getXferMode() == XFER_LOAD ) {
  1347. m_slot[slot]->setState((SlotState)state, name);
  1348. if (isAccepted) m_slot[slot]->setAccept();
  1349. m_slot[slot]->setPlayerTemplate(origPlayerTemplate);
  1350. m_slot[slot]->setStartPos(origStartPos);
  1351. m_slot[slot]->setColor(origColor);
  1352. m_slot[slot]->saveOffOriginalInfo();
  1353. m_slot[slot]->setTeamNumber(teamNumber);
  1354. m_slot[slot]->setColor(color);
  1355. m_slot[slot]->setStartPos(startPos);
  1356. m_slot[slot]->setPlayerTemplate(playerTemplate);
  1357. }
  1358. }
  1359. xfer->xferUnsignedInt(&m_localIP);
  1360. xfer->xferMapName(&m_mapName);
  1361. xfer->xferUnsignedInt(&m_mapCRC);
  1362. xfer->xferUnsignedInt(&m_mapSize);
  1363. xfer->xferInt(&m_mapMask);
  1364. xfer->xferInt(&m_seed);
  1365. } // end xfer
  1366. // ------------------------------------------------------------------------------------------------
  1367. /** Load post process */
  1368. // ------------------------------------------------------------------------------------------------
  1369. void SkirmishGameInfo::loadPostProcess( void )
  1370. {
  1371. } // end loadPostProcess