GameInfo.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621
  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: 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_useStats = TRUE;
  273. m_surrendered = FALSE;
  274. m_oldFactionsOnly = FALSE;
  275. // Added By Sadullah Nader
  276. // Initializations missing and needed
  277. // m_localIP = 0; // BGC - actually we don't want this to be reset since the m_localIP is
  278. // set properly in the constructor of LANGameInfo which uses this as a base class.
  279. m_mapCRC = 0;
  280. m_mapSize = 0;
  281. m_superweaponRestriction = 0;
  282. m_startingCash = TheGlobalData->m_defaultStartingCash;
  283. //
  284. for (Int i=0; i<MAX_SLOTS; ++i)
  285. {
  286. if (m_slot[i])
  287. m_slot[i]->reset();
  288. }
  289. m_preorderMask = 0;
  290. }
  291. Bool GameInfo::isPlayerPreorder(Int index)
  292. {
  293. if (index >= 0 && index < MAX_SLOTS)
  294. return ((m_preorderMask & (1 << index)) != 0);
  295. return FALSE;
  296. }
  297. void GameInfo::markPlayerAsPreorder(Int index)
  298. {
  299. if (index >= 0 && index < MAX_SLOTS)
  300. m_preorderMask |= 1 << index;
  301. }
  302. void GameInfo::clearSlotList( void )
  303. {
  304. for (int i=0; i<MAX_SLOTS; ++i)
  305. {
  306. if (m_slot[i])
  307. m_slot[i]->setState(SLOT_CLOSED);
  308. }
  309. }
  310. Int GameInfo::getNumPlayers( void ) const
  311. {
  312. Int numPlayers = 0;
  313. for (int i=0; i<MAX_SLOTS; ++i)
  314. {
  315. if (m_slot[i] && m_slot[i]->isOccupied())
  316. numPlayers++;
  317. }
  318. return numPlayers;
  319. }
  320. Int GameInfo::getNumNonObserverPlayers( void ) const
  321. {
  322. Int numPlayers = 0;
  323. for (int i=0; i<MAX_SLOTS; ++i)
  324. {
  325. if (m_slot[i] && m_slot[i]->isOccupied() && m_slot[i]->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  326. numPlayers++;
  327. }
  328. return numPlayers;
  329. }
  330. Int GameInfo::getMaxPlayers( void ) const
  331. {
  332. if (!TheMapCache)
  333. return -1;
  334. AsciiString lowerMap = m_mapName;
  335. lowerMap.toLower();
  336. MapCache::iterator it = TheMapCache->find(lowerMap);
  337. if (it == TheMapCache->end())
  338. return -1;
  339. MapMetaData data = it->second;
  340. return data.m_numPlayers;
  341. }
  342. void GameInfo::enterGame( void )
  343. {
  344. DEBUG_ASSERTCRASH(!m_inGame && !m_inProgress, ("Entering game at a bad time!"));
  345. reset();
  346. m_inGame = true;
  347. m_inProgress = false;
  348. }
  349. void GameInfo::leaveGame( void )
  350. {
  351. DEBUG_ASSERTCRASH(m_inGame && !m_inProgress, ("Leaving game at a bad time!"));
  352. reset();
  353. }
  354. void GameInfo::startGame( Int gameID )
  355. {
  356. DEBUG_ASSERTCRASH(m_inGame && !m_inProgress, ("Starting game at a bad time!"));
  357. m_gameID = gameID;
  358. closeOpenSlots();
  359. m_inProgress = true;
  360. }
  361. void GameInfo::endGame( void )
  362. {
  363. DEBUG_ASSERTCRASH(m_inGame && m_inProgress, ("Ending game without playing one!"));
  364. m_inGame = false;
  365. m_inProgress = false;
  366. }
  367. void GameInfo::setSlot( Int slotNum, GameSlot slotInfo )
  368. {
  369. DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::setSlot - Invalid slot number"));
  370. if (slotNum < 0 || slotNum >= MAX_SLOTS)
  371. return;
  372. DEBUG_ASSERTCRASH( m_slot[slotNum], ("NULL slot pointer"));
  373. if (!m_slot[slotNum])
  374. return;
  375. // Bool isHuman = slotInfo.isHuman();
  376. // Bool wasHuman = m_slot[slotNum]->isHuman();
  377. if (slotNum == 0)
  378. {
  379. slotInfo.setAccept();
  380. slotInfo.setMapAvailability(true);
  381. }
  382. *m_slot[slotNum] = slotInfo;
  383. #ifdef DEBUG_LOGGING
  384. UnsignedInt ip = slotInfo.getIP();
  385. #endif
  386. DEBUG_LOG(("GameInfo::setSlot - setting slot %d to be player %ls with IP %d.%d.%d.%d\n", slotNum, slotInfo.getName().str(),
  387. ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff));
  388. }
  389. GameSlot* GameInfo::getSlot( Int slotNum )
  390. {
  391. DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::getSlot - Invalid slot number"));
  392. if (slotNum < 0 || slotNum >= MAX_SLOTS)
  393. return NULL;
  394. return m_slot[slotNum];
  395. }
  396. const GameSlot* GameInfo::getConstSlot( Int slotNum ) const
  397. {
  398. DEBUG_ASSERTCRASH( slotNum >= 0 && slotNum < MAX_SLOTS, ("GameInfo::getSlot - Invalid slot number"));
  399. if (slotNum < 0 || slotNum >= MAX_SLOTS)
  400. return NULL;
  401. return m_slot[slotNum];
  402. }
  403. Int GameInfo::getLocalSlotNum( void ) const
  404. {
  405. DEBUG_ASSERTCRASH(m_inGame, ("Looking for local game slot while not in game"));
  406. if (!m_inGame)
  407. return -1;
  408. for (Int i=0; i<MAX_SLOTS; ++i)
  409. {
  410. const GameSlot *slot = getConstSlot(i);
  411. if (slot == NULL) {
  412. continue;
  413. }
  414. if (slot->isPlayer(m_localIP))
  415. return i;
  416. }
  417. return -1;
  418. }
  419. Int GameInfo::getSlotNum( AsciiString userName ) const
  420. {
  421. DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game"));
  422. if (!m_inGame)
  423. return -1;
  424. UnicodeString uName;
  425. uName.translate(userName);
  426. for (Int i=0; i<MAX_SLOTS; ++i)
  427. {
  428. const GameSlot *slot = getConstSlot(i);
  429. if (slot->isPlayer( uName ))
  430. return i;
  431. }
  432. return -1;
  433. }
  434. Bool GameInfo::amIHost( void ) const
  435. {
  436. DEBUG_ASSERTCRASH(m_inGame, ("Looking for game slot while not in game"));
  437. if (!m_inGame)
  438. return false;
  439. return getConstSlot(0)->isPlayer(m_localIP);
  440. }
  441. void GameInfo::setMap( AsciiString mapName )
  442. {
  443. m_mapName = mapName;
  444. if (m_inGame && amIHost())
  445. {
  446. const MapMetaData *mapData = TheMapCache->findMap( mapName );
  447. if (mapData)
  448. {
  449. m_mapMask = 1;
  450. AsciiString path = mapName;
  451. path.removeLastChar();
  452. path.removeLastChar();
  453. path.removeLastChar();
  454. path.concat("tga");
  455. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  456. File *fp = TheFileSystem->openFile(path.str());
  457. if (fp)
  458. {
  459. m_mapMask |= 2;
  460. fp->close();
  461. fp = NULL;
  462. }
  463. AsciiString newMapName;
  464. if (mapName.getLength() > 0)
  465. {
  466. AsciiString token;
  467. mapName.nextToken(&token, "\\/");
  468. // add all the tokens except the last one.
  469. // that way we don't add the filename, just the
  470. // directory name, we can do this since the filename
  471. // is just the directory name with the file extention
  472. // added onto it.
  473. while (mapName.find('\\') != NULL)
  474. {
  475. if (newMapName.getLength() > 0)
  476. {
  477. newMapName.concat('/');
  478. }
  479. newMapName.concat(token);
  480. mapName.nextToken(&token, "\\/");
  481. }
  482. }
  483. newMapName.concat("/map.ini");
  484. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", newMapName.str()));
  485. fp = TheFileSystem->openFile(newMapName.str());
  486. if (fp)
  487. {
  488. m_mapMask |= 4;
  489. fp->close();
  490. fp = NULL;
  491. }
  492. path = GetStrFileFromMap(m_mapName);
  493. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  494. fp = TheFileSystem->openFile(path.str());
  495. if (fp)
  496. {
  497. m_mapMask |= 8;
  498. fp->close();
  499. fp = NULL;
  500. }
  501. path = GetSoloINIFromMap(m_mapName);
  502. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  503. fp = TheFileSystem->openFile(path.str());
  504. if (fp)
  505. {
  506. m_mapMask |= 16;
  507. fp->close();
  508. fp = NULL;
  509. }
  510. path = GetAssetUsageFromMap(m_mapName);
  511. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  512. fp = TheFileSystem->openFile(path.str());
  513. if (fp)
  514. {
  515. m_mapMask |= 32;
  516. fp->close();
  517. fp = NULL;
  518. }
  519. path = GetReadmeFromMap(m_mapName);
  520. DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str()));
  521. fp = TheFileSystem->openFile(path.str());
  522. if (fp)
  523. {
  524. m_mapMask |= 64;
  525. fp->close();
  526. fp = NULL;
  527. }
  528. }
  529. else
  530. {
  531. m_mapMask = 0;
  532. }
  533. }
  534. }
  535. void GameInfo::setMapContentsMask( Int mask )
  536. {
  537. m_mapMask = mask;
  538. }
  539. void GameInfo::setMapCRC( UnsignedInt mapCRC )
  540. {
  541. m_mapCRC = mapCRC;
  542. if (!TheMapCache)
  543. return;
  544. // check the map cache
  545. if (m_inGame && getLocalSlotNum() >= 0)
  546. {
  547. //TheMapCache->updateCache();
  548. AsciiString lowerMap = m_mapName;
  549. lowerMap.toLower();
  550. //DEBUG_LOG(("GameInfo::setMapCRC - looking for map file \"%s\" in the map cache\n", lowerMap.str()));
  551. std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(lowerMap);
  552. if (it == TheMapCache->end())
  553. {
  554. /*
  555. DEBUG_LOG(("GameInfo::setMapCRC - could not find map file.\n"));
  556. it = TheMapCache->begin();
  557. while (it != TheMapCache->end())
  558. {
  559. DEBUG_LOG(("\t\"%s\"\n", it->first.str()));
  560. ++it;
  561. }
  562. */
  563. getSlot(getLocalSlotNum())->setMapAvailability(false);
  564. }
  565. else if (m_mapCRC != it->second.m_CRC)
  566. {
  567. DEBUG_LOG(("GameInfo::setMapCRC - map CRC's do not match (%X/%X).\n", m_mapCRC, it->second.m_CRC));
  568. getSlot(getLocalSlotNum())->setMapAvailability(false);
  569. }
  570. else
  571. {
  572. //DEBUG_LOG(("GameInfo::setMapCRC - map CRC's match.\n"));
  573. getSlot(getLocalSlotNum())->setMapAvailability(true);
  574. }
  575. }
  576. }
  577. void GameInfo::setMapSize( UnsignedInt mapSize )
  578. {
  579. m_mapSize = mapSize;
  580. if (!TheMapCache)
  581. return;
  582. // check the map cache
  583. if (m_inGame && getLocalSlotNum() >= 0)
  584. {
  585. //TheMapCache->updateCache();
  586. AsciiString lowerMap = m_mapName;
  587. lowerMap.toLower();
  588. std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(lowerMap);
  589. if (it == TheMapCache->end())
  590. {
  591. DEBUG_LOG(("GameInfo::setMapSize - could not find map file.\n"));
  592. getSlot(getLocalSlotNum())->setMapAvailability(false);
  593. }
  594. else if (m_mapCRC != it->second.m_CRC)
  595. {
  596. DEBUG_LOG(("GameInfo::setMapSize - map CRC's do not match.\n"));
  597. getSlot(getLocalSlotNum())->setMapAvailability(false);
  598. }
  599. else
  600. {
  601. //DEBUG_LOG(("GameInfo::setMapSize - map CRC's match.\n"));
  602. getSlot(getLocalSlotNum())->setMapAvailability(true);
  603. }
  604. }
  605. }
  606. void GameInfo::setSeed( Int seed )
  607. {
  608. m_seed = seed;
  609. }
  610. void GameInfo::setSlotPointer( Int index, GameSlot *slot )
  611. {
  612. if (index < 0 || index >= MAX_SLOTS)
  613. return;
  614. m_slot[index] = slot;
  615. }
  616. void GameInfo::setSuperweaponRestriction( UnsignedShort restriction )
  617. {
  618. m_superweaponRestriction = restriction;
  619. }
  620. void GameInfo::setStartingCash( const Money & startingCash )
  621. {
  622. m_startingCash = startingCash;
  623. }
  624. Bool GameInfo::isColorTaken(Int colorIdx, Int slotToIgnore ) const
  625. {
  626. for (Int i=0; i<MAX_SLOTS; ++i)
  627. {
  628. const GameSlot *slot = getConstSlot(i);
  629. if (slot && slot->getColor() == colorIdx && i != slotToIgnore)
  630. return true;
  631. }
  632. return false;
  633. }
  634. Bool GameInfo::isStartPositionTaken(Int positionIdx, Int slotToIgnore ) const
  635. {
  636. for (Int i=0; i<MAX_SLOTS; ++i)
  637. {
  638. const GameSlot *slot = getConstSlot(i);
  639. if (slot && slot->getStartPos() == positionIdx && i != slotToIgnore)
  640. return true;
  641. }
  642. return false;
  643. }
  644. void GameInfo::resetAccepted( void )
  645. {
  646. GameSlot *slot = getSlot(0);
  647. if (slot)
  648. slot->setAccept();
  649. for(int i = 1; i< MAX_SLOTS; i++)
  650. {
  651. slot = getSlot(i);
  652. if (slot)
  653. slot->unAccept();
  654. }
  655. }
  656. void GameInfo::resetStartSpots()
  657. {
  658. GameSlot *slot = NULL;
  659. for (Int i = 0; i < MAX_SLOTS; ++i)
  660. {
  661. slot = getSlot(i);
  662. if (slot != NULL)
  663. {
  664. slot->setStartPos(-1);
  665. }
  666. }
  667. }
  668. // adjust the slots in the game to open or closed
  669. // depending on the players in there now and the number of
  670. // players the map can hold.
  671. void GameInfo::adjustSlotsForMap()
  672. {
  673. const MapMetaData *md = TheMapCache->findMap(m_mapName);
  674. if (md != NULL)
  675. {
  676. // get the number of players allowed from the map.
  677. Int numPlayers = md->m_numPlayers;
  678. Int numPlayerSlots = 0;
  679. // first get the number of occupied slots.
  680. for (Int i = 0; i < MAX_SLOTS; ++i)
  681. {
  682. GameSlot *tempSlot = getSlot(i);
  683. if (tempSlot->isOccupied())
  684. {
  685. ++numPlayerSlots;
  686. }
  687. }
  688. // now go through and close the appropriate number of slots.
  689. // note that no players are kicked in this process, we leave
  690. // that up to the user.
  691. for (i = 0; i < MAX_SLOTS; ++i)
  692. {
  693. // we have room for more players, if this slot is unoccupied, set it to open.
  694. GameSlot *slot = getSlot(i);
  695. if (numPlayers > numPlayerSlots)
  696. {
  697. if (!(slot->isOccupied()))
  698. {
  699. GameSlot newSlot;
  700. newSlot.setState(SLOT_OPEN);
  701. setSlot(i, newSlot);
  702. ++numPlayerSlots;
  703. }
  704. }
  705. else
  706. {
  707. if (!(slot->isOccupied()))
  708. {
  709. // we don't have any more room, set this slot to closed.
  710. GameSlot newSlot;
  711. newSlot.setState(SLOT_CLOSED);
  712. setSlot(i, newSlot);
  713. }
  714. }
  715. }
  716. }
  717. }
  718. void GameInfo::closeOpenSlots()
  719. {
  720. for (Int i = 0; i < MAX_SLOTS; ++i)
  721. {
  722. GameSlot *slot = getSlot(i);
  723. if (!(slot->isOccupied()))
  724. {
  725. GameSlot newSlot;
  726. newSlot.setState(SLOT_CLOSED);
  727. setSlot(i, newSlot);
  728. }
  729. }
  730. }
  731. static Bool isSlotLocalAlly(GameInfo *game, const GameSlot *slot)
  732. {
  733. const GameSlot *localSlot = game->getConstSlot(game->getLocalSlotNum());
  734. if (!localSlot)
  735. return TRUE;
  736. if (slot == localSlot)
  737. return TRUE;
  738. if (slot->getTeamNumber() < 0)
  739. return FALSE;
  740. return slot->getTeamNumber() == localSlot->getTeamNumber();
  741. }
  742. Bool GameInfo::isSkirmish(void)
  743. {
  744. Bool sawAI = FALSE;
  745. for (Int i=0; i<MAX_SLOTS; ++i)
  746. {
  747. if (i == getLocalSlotNum())
  748. continue;
  749. if (getConstSlot(i)->isHuman())
  750. return FALSE;
  751. if (getConstSlot(i)->isAI())
  752. {
  753. if (isSlotLocalAlly(getConstSlot(i)))
  754. return FALSE;
  755. sawAI = TRUE;
  756. }
  757. }
  758. return sawAI;
  759. }
  760. Bool GameInfo::isMultiPlayer(void)
  761. {
  762. for (Int i=0; i<MAX_SLOTS; ++i)
  763. {
  764. if (i == getLocalSlotNum())
  765. continue;
  766. if (getConstSlot(i)->isHuman())
  767. return TRUE;
  768. }
  769. return FALSE;
  770. }
  771. Bool GameInfo::isSandbox(void)
  772. {
  773. Int localSlotNum = getLocalSlotNum();
  774. Int localTeam = getConstSlot(localSlotNum)->getTeamNumber();
  775. for (Int i=0; i<MAX_SLOTS; ++i)
  776. {
  777. if (i == localSlotNum)
  778. continue;
  779. const GameSlot *slot = getConstSlot(i);
  780. if (slot->isOccupied() && (slot->getTeamNumber() < 0 || slot->getTeamNumber() != localTeam))
  781. return FALSE;
  782. }
  783. return TRUE;
  784. }
  785. // Convenience Functions ----------------------------------------
  786. static const char slotListID = 'S';
  787. AsciiString GameInfoToAsciiString( const GameInfo *game )
  788. {
  789. if (!game)
  790. return AsciiString::TheEmptyString;
  791. AsciiString mapName = game->getMap();
  792. mapName = TheGameState->realMapPathToPortableMapPath(mapName);
  793. AsciiString newMapName;
  794. if (mapName.getLength() > 0)
  795. {
  796. AsciiString token;
  797. mapName.nextToken(&token, "\\/");
  798. // add all the tokens except the last one.
  799. // that way we don't add the filename, just the
  800. // directory name, we can do this since the filename
  801. // is just the directory name with the file extention
  802. // added onto it.
  803. while (mapName.find('\\') != NULL)
  804. {
  805. if (newMapName.getLength() > 0)
  806. {
  807. newMapName.concat('/');
  808. }
  809. newMapName.concat(token);
  810. mapName.nextToken(&token, "\\/");
  811. }
  812. DEBUG_LOG(("Map name is %s\n", mapName.str()));
  813. }
  814. AsciiString optionsString;
  815. optionsString.format("US=%d;M=%2.2x%s;MC=%X;MS=%d;SD=%d;C=%d;SR=%u;SC=%u;O=%c;", game->getUseStats(), game->getMapContentsMask(), newMapName.str(),
  816. game->getMapCRC(), game->getMapSize(), game->getSeed(), game->getCRCInterval(), game->getSuperweaponRestriction(),
  817. game->getStartingCash().countMoney(), game->oldFactionsOnly() ? 'Y' : 'N' );
  818. //add player info for each slot
  819. optionsString.concat(slotListID);
  820. optionsString.concat('=');
  821. for (Int i=0; i<MAX_SLOTS; ++i)
  822. {
  823. const GameSlot *slot = game->getConstSlot(i);
  824. AsciiString str;
  825. if (slot && slot->isHuman())
  826. {
  827. AsciiString tmp; //all this data goes after name
  828. tmp.format( ",%X,%d,%c%c,%d,%d,%d,%d,%d:",
  829. slot->getIP(), slot->getPort(),
  830. (slot->isAccepted()?'T':'F'),
  831. (slot->hasMap()?'T':'F'),
  832. slot->getColor(), slot->getPlayerTemplate(),
  833. slot->getStartPos(), slot->getTeamNumber(),
  834. slot->getNATBehavior() );
  835. //make sure name doesn't cause overflow of m_lanMaxOptionsLength
  836. int lenCur = tmp.getLength() + optionsString.getLength() + 2; //+2 for H and trailing ;
  837. int lenRem = m_lanMaxOptionsLength - lenCur; //length remaining before overflowing
  838. int lenMax = lenRem / (MAX_SLOTS-i); //share lenRem with all remaining slots
  839. AsciiString name = WideCharStringToMultiByte(slot->getName().str()).c_str();
  840. while( name.getLength() > lenMax )
  841. name.removeLastChar(); //what a horrible way to truncate. I hate AsciiString.
  842. str.format( "H%s%s", name.str(), tmp.str() );
  843. }
  844. else if (slot && slot->isAI())
  845. {
  846. Char c;
  847. if (slot->getState() == SLOT_EASY_AI)
  848. c = 'E';
  849. else if (slot->getState() == SLOT_MED_AI)
  850. c = 'M';
  851. else
  852. c = 'H';
  853. str.format("C%c,%d,%d,%d,%d:", c,
  854. slot->getColor(), slot->getPlayerTemplate(),
  855. slot->getStartPos(), slot->getTeamNumber());
  856. }
  857. else if (slot && slot->getState() == SLOT_OPEN)
  858. {
  859. str = "O:";
  860. }
  861. else if (slot && slot->getState() == SLOT_CLOSED)
  862. {
  863. str = "X:";
  864. }
  865. else
  866. {
  867. DEBUG_ASSERTCRASH(false, ("Bad slot type"));
  868. str = "X:";
  869. }
  870. optionsString.concat(str);
  871. }
  872. optionsString.concat(';');
  873. DEBUG_ASSERTCRASH(!TheLAN || (optionsString.getLength() < m_lanMaxOptionsLength),
  874. ("WARNING: options string is longer than expected! Length is %d, but max is %d!\n",
  875. optionsString.getLength(), m_lanMaxOptionsLength));
  876. return optionsString;
  877. }
  878. static Int grabHexInt(const char *s)
  879. {
  880. char tmp[5] = "0xff";
  881. tmp[2] = s[0];
  882. tmp[3] = s[1];
  883. Int b = strtol(tmp, NULL, 16);
  884. return b;
  885. }
  886. Bool ParseAsciiStringToGameInfo(GameInfo *game, AsciiString options)
  887. {
  888. // Parse game options
  889. char *buf = strdup(options.str());
  890. char *bufPtr = buf;
  891. char *strPos, *keyValPair;
  892. GameSlot newSlot[MAX_SLOTS];
  893. Bool optionsOk = true;
  894. AsciiString mapName;
  895. Int mapContentsMask;
  896. UnsignedInt mapCRC, mapSize;
  897. Int seed = 0;
  898. Int crc = 100;
  899. Bool sawCRC = FALSE;
  900. Bool oldFactionsOnly = FALSE;
  901. Int useStats = TRUE;
  902. Money startingCash = TheGlobalData->m_defaultStartingCash;
  903. UnsignedShort restriction = 0; // Always the default
  904. Bool sawMap, sawMapCRC, sawMapSize, sawSeed, sawSlotlist, sawUseStats, sawSuperweaponRestriction, sawStartingCash, sawOldFactions;
  905. sawMap = sawMapCRC = sawMapSize = sawSeed = sawSlotlist = sawUseStats = sawSuperweaponRestriction = sawStartingCash = sawOldFactions = FALSE;
  906. //DEBUG_LOG(("Saw options of %s\n", options.str()));
  907. DEBUG_LOG(("ParseAsciiStringToGameInfo - parsing [%s]\n", options.str()));
  908. while ( (keyValPair = strtok_r(bufPtr, ";", &strPos)) != NULL )
  909. {
  910. bufPtr = NULL; // strtok within the same string
  911. AsciiString key, val;
  912. char *pos = NULL;
  913. char *keyPtr, *valPtr;
  914. keyPtr = (strtok_r(keyValPair, "=", &pos));
  915. valPtr = (strtok_r(NULL, "\n", &pos));
  916. if (keyPtr)
  917. key = keyPtr;
  918. if (valPtr)
  919. val = valPtr;
  920. if (val.isEmpty())
  921. {
  922. optionsOk = false;
  923. DEBUG_LOG(("ParseAsciiStringToGameInfo - saw empty value, quitting\n"));
  924. break;
  925. }
  926. if (key.compare("US") == 0)
  927. {
  928. useStats = atoi(val.str());
  929. sawUseStats = true;
  930. }
  931. else
  932. if (key.compare("M") == 0)
  933. {
  934. if (val.getLength() < 3)
  935. {
  936. optionsOk = FALSE;
  937. DEBUG_LOG(("ParseAsciiStringToGameInfo - saw bogus map; quitting\n"));
  938. break;
  939. }
  940. mapContentsMask = grabHexInt(val.str());
  941. AsciiString tempstr;
  942. AsciiString token;
  943. tempstr = val.str()+2;
  944. tempstr.nextToken(&token, "\\/");
  945. while (tempstr.getLength() > 0)
  946. {
  947. mapName.concat(token);
  948. mapName.concat('\\');
  949. tempstr.nextToken(&token, "\\/");
  950. }
  951. mapName.concat(token);
  952. mapName.concat('\\');
  953. mapName.concat(token);
  954. mapName.concat('.');
  955. mapName.concat(TheMapCache->getMapExtension());
  956. mapName = TheGameState->portableMapPathToRealMapPath(mapName);
  957. sawMap = true;
  958. DEBUG_LOG(("ParseAsciiStringToGameInfo - map name is %s\n", mapName.str()));
  959. }
  960. else if (key.compare("MC") == 0)
  961. {
  962. mapCRC = 0;
  963. sscanf(val.str(), "%X", &mapCRC);
  964. sawMapCRC = true;
  965. }
  966. else if (key.compare("MS") == 0)
  967. {
  968. mapSize = atoi(val.str());
  969. sawMapSize = true;
  970. }
  971. else if (key.compare("SD") == 0)
  972. {
  973. seed = atoi(val.str());
  974. sawSeed = true;
  975. // DEBUG_LOG(("ParseAsciiStringToGameInfo - random seed is %d\n", seed));
  976. }
  977. else if (key.compare("C") == 0)
  978. {
  979. crc = atoi(val.str());
  980. sawCRC = TRUE;
  981. }
  982. else if (key.compare("SR") == 0 )
  983. {
  984. restriction = (UnsignedShort)atoi(val.str());
  985. sawSuperweaponRestriction = TRUE;
  986. }
  987. else if (key.compare("SC") == 0 )
  988. {
  989. UnsignedInt startingCashAmount = strtoul( val.str(), NULL, 10 );
  990. startingCash.init();
  991. startingCash.deposit( startingCashAmount, FALSE );
  992. sawStartingCash = TRUE;
  993. }
  994. else if (key.compare("O") == 0 )
  995. {
  996. oldFactionsOnly = ( val.compareNoCase( "Y" ) == 0 );
  997. sawOldFactions = TRUE;
  998. }
  999. else if (key.getLength() == 1 && *key.str() == slotListID)
  1000. {
  1001. sawSlotlist = true;
  1002. /// @TODO: Need to read in all the slot info... big mess right now.
  1003. char *rawSlotBuf = strdup(val.str());
  1004. char *freeMe = NULL;
  1005. AsciiString rawSlot;
  1006. // Bool slotsOk = true; //flag that lets us know whether or not the slot list is good.
  1007. // DEBUG_LOG(("ParseAsciiStringToGameInfo - Parsing slot list\n"));
  1008. for (int i=0; i<MAX_SLOTS; ++i)
  1009. {
  1010. rawSlot = strtok_r(rawSlotBuf,":",&pos);
  1011. if( rawSlotBuf )
  1012. freeMe = rawSlotBuf;
  1013. rawSlotBuf = NULL;
  1014. switch (*rawSlot.str())
  1015. {
  1016. case 'H':
  1017. {
  1018. // DEBUG_LOG(("ParseAsciiStringToGameInfo - Human player\n"));
  1019. char *slotPos = NULL;
  1020. //Parse out the Name
  1021. AsciiString slotValue(strtok_r((char *)rawSlot.str(),",",&slotPos));
  1022. if(slotValue.isEmpty())
  1023. {
  1024. optionsOk = false;
  1025. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue name is empty, quitting\n"));
  1026. break;
  1027. }
  1028. UnicodeString name;
  1029. name.set(MultiByteToWideCharSingleLine(slotValue.str() +1).c_str());
  1030. //DEBUG_LOG(("ParseAsciiStringToGameInfo - name is %s\n", slotValue.str()+1));
  1031. //Parse out the IP
  1032. slotValue = strtok_r(NULL,",",&slotPos);
  1033. if(slotValue.isEmpty())
  1034. {
  1035. optionsOk = false;
  1036. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue IP address is empty, quitting\n"));
  1037. break;
  1038. }
  1039. UnsignedInt playerIP = 0;
  1040. sscanf(slotValue.str(),"%x", &playerIP);
  1041. //DEBUG_LOG(("ParseAsciiStringToGameInfo - IP address is %x\n", playerIP));
  1042. //set the state of the slot
  1043. newSlot[i].setState(SLOT_PLAYER, name, playerIP);
  1044. // parse out the port
  1045. slotValue = strtok_r(NULL, ",", &slotPos);
  1046. if (slotValue.isEmpty())
  1047. {
  1048. optionsOk = false;
  1049. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue port is empty, quitting\n"));
  1050. break;
  1051. }
  1052. UnsignedInt playerPort = 0;
  1053. sscanf(slotValue.str(), "%d", &playerPort);
  1054. newSlot[i].setPort(playerPort);
  1055. DEBUG_LOG(("ParseAsciiStringToGameInfo - port is %d\n", playerPort));
  1056. //Read if it's accepted or not
  1057. slotValue = strtok_r(NULL,",",&slotPos);
  1058. if(slotValue.getLength() != 2)
  1059. {
  1060. optionsOk = false;
  1061. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue accepted is mis-sized, quitting\n"));
  1062. break;
  1063. }
  1064. const char *svs = slotValue.str();
  1065. if(*svs == 'T') {
  1066. newSlot[i].setAccept();
  1067. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player has accepted\n"));
  1068. } else if (*svs == 'F') {
  1069. newSlot[i].unAccept();
  1070. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player has not accepted\n"));
  1071. }
  1072. ++svs;
  1073. if(*svs == 'T') {
  1074. newSlot[i].setMapAvailability(TRUE);
  1075. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player has map\n"));
  1076. } else {
  1077. newSlot[i].setMapAvailability(FALSE);
  1078. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player does not have map\n"));
  1079. }
  1080. //Read color index
  1081. slotValue = strtok_r(NULL,",",&slotPos);
  1082. if(slotValue.isEmpty())
  1083. {
  1084. optionsOk = false;
  1085. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue color is empty, quitting\n"));
  1086. break;
  1087. }
  1088. Int color = atoi(slotValue.str());
  1089. if (color < -1 || color >= TheMultiplayerSettings->getNumColors())
  1090. {
  1091. optionsOk = false;
  1092. DEBUG_LOG(("ParseAsciiStringToGameInfo - player color was invalid, quitting\n"));
  1093. break;
  1094. }
  1095. newSlot[i].setColor(color);
  1096. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player color set to %d\n", color));
  1097. //Read playerTemplate index
  1098. slotValue = strtok_r(NULL,",",&slotPos);
  1099. if(slotValue.isEmpty())
  1100. {
  1101. optionsOk = false;
  1102. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue player template is empty, quitting\n"));
  1103. break;
  1104. }
  1105. Int playerTemplate = atoi(slotValue.str());
  1106. if (playerTemplate < PLAYERTEMPLATE_MIN || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount())
  1107. {
  1108. optionsOk = false;
  1109. DEBUG_LOG(("ParseAsciiStringToGameInfo - player template value is invalid, quitting\n"));
  1110. break;
  1111. }
  1112. newSlot[i].setPlayerTemplate(playerTemplate);
  1113. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player template is %d\n", playerTemplate));
  1114. //Read start position index
  1115. slotValue = strtok_r(NULL,",",&slotPos);
  1116. if(slotValue.isEmpty())
  1117. {
  1118. optionsOk = false;
  1119. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue start position is empty, quitting\n"));
  1120. break;
  1121. }
  1122. Int startPos = atoi(slotValue.str());
  1123. if (startPos < -1 || startPos >= MAX_SLOTS)
  1124. {
  1125. optionsOk = false;
  1126. DEBUG_LOG(("ParseAsciiStringToGameInfo - player start position is invalid, quitting\n"));
  1127. break;
  1128. }
  1129. newSlot[i].setStartPos(startPos);
  1130. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player start position is %d\n", startPos));
  1131. //Read team index
  1132. slotValue = strtok_r(NULL,",",&slotPos);
  1133. if(slotValue.isEmpty())
  1134. {
  1135. optionsOk = false;
  1136. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue team number is empty, quitting\n"));
  1137. break;
  1138. }
  1139. Int team = atoi(slotValue.str());
  1140. if (team < -1 || team >= MAX_SLOTS/2)
  1141. {
  1142. optionsOk = false;
  1143. DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is invalid, quitting\n"));
  1144. break;
  1145. }
  1146. newSlot[i].setTeamNumber(team);
  1147. //DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is %d\n", team));
  1148. // Read the NAT behavior
  1149. slotValue = strtok_r(NULL, ",",&slotPos);
  1150. if (slotValue.isEmpty())
  1151. {
  1152. optionsOk = false;
  1153. DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is empty, quitting\n"));
  1154. break;
  1155. }
  1156. FirewallHelperClass::FirewallBehaviorType NATType = (FirewallHelperClass::FirewallBehaviorType)atoi(slotValue.str());
  1157. if ((NATType < FirewallHelperClass::FIREWALL_MIN) ||
  1158. (NATType > FirewallHelperClass::FIREWALL_MAX)) {
  1159. optionsOk = false;
  1160. DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is invalid, quitting\n"));
  1161. break;
  1162. }
  1163. newSlot[i].setNATBehavior(NATType);
  1164. DEBUG_LOG(("ParseAsciiStringToGameInfo - NAT behavior is %X\n", NATType));
  1165. }// case 'H':
  1166. break;
  1167. case 'C':
  1168. {
  1169. DEBUG_LOG(("ParseAsciiStringToGameInfo - AI player\n"));
  1170. char *slotPos = NULL;
  1171. //Parse out the Name
  1172. AsciiString slotValue(strtok_r((char *)rawSlot.str(),",",&slotPos));
  1173. if(slotValue.isEmpty())
  1174. {
  1175. optionsOk = false;
  1176. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue AI Type is empty, quitting\n"));
  1177. break;
  1178. }
  1179. switch(*(slotValue.str() + 1))
  1180. {
  1181. case 'E':
  1182. {
  1183. newSlot[i].setState(SLOT_EASY_AI);
  1184. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Easy AI\n"));
  1185. }
  1186. break;
  1187. case 'M':
  1188. {
  1189. newSlot[i].setState(SLOT_MED_AI);
  1190. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Medium AI\n"));
  1191. }
  1192. break;
  1193. case 'H':
  1194. {
  1195. newSlot[i].setState(SLOT_BRUTAL_AI);
  1196. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Brutal AI\n"));
  1197. }
  1198. break;
  1199. default:
  1200. {
  1201. optionsOk = false;
  1202. DEBUG_LOG(("ParseAsciiStringToGameInfo - Unknown AI, quitting\n"));
  1203. }
  1204. break;
  1205. }//switch(*rawSlot.str()+1)
  1206. //Read color index
  1207. slotValue = strtok_r(NULL,",",&slotPos);
  1208. if(slotValue.isEmpty())
  1209. {
  1210. optionsOk = false;
  1211. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue color is empty, quitting\n"));
  1212. break;
  1213. }
  1214. Int color = atoi(slotValue.str());
  1215. if (color < -1 || color >= TheMultiplayerSettings->getNumColors())
  1216. {
  1217. optionsOk = false;
  1218. DEBUG_LOG(("ParseAsciiStringToGameInfo - player color was invalid, quitting\n"));
  1219. break;
  1220. }
  1221. newSlot[i].setColor(color);
  1222. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player color set to %d\n", color));
  1223. //Read playerTemplate index
  1224. slotValue = strtok_r(NULL,",",&slotPos);
  1225. if(slotValue.isEmpty())
  1226. {
  1227. optionsOk = false;
  1228. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue player template is empty, quitting\n"));
  1229. break;
  1230. }
  1231. Int playerTemplate = atoi(slotValue.str());
  1232. if (playerTemplate < PLAYERTEMPLATE_MIN || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount())
  1233. {
  1234. optionsOk = false;
  1235. DEBUG_LOG(("ParseAsciiStringToGameInfo - player template value is invalid, quitting\n"));
  1236. break;
  1237. }
  1238. newSlot[i].setPlayerTemplate(playerTemplate);
  1239. //DEBUG_LOG(("ParseAsciiStringToGameInfo - player template is %d\n", playerTemplate));
  1240. //Read start pos
  1241. slotValue = strtok_r(NULL,",",&slotPos);
  1242. if(slotValue.isEmpty())
  1243. {
  1244. optionsOk = false;
  1245. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue start pos is empty, quitting\n"));
  1246. break;
  1247. }
  1248. Int startPos = atoi(slotValue.str());
  1249. Bool isStartPosBad = FALSE;
  1250. if (startPos < -1 || startPos >= MAX_SLOTS)
  1251. {
  1252. isStartPosBad = TRUE;
  1253. }
  1254. for (Int j=0; j<i; ++j)
  1255. {
  1256. if (startPos >= 0 && startPos == newSlot[i].getStartPos())
  1257. {
  1258. isStartPosBad = TRUE; // can't have multiple people using the same start pos
  1259. }
  1260. }
  1261. if (isStartPosBad)
  1262. {
  1263. optionsOk = false;
  1264. DEBUG_LOG(("ParseAsciiStringToGameInfo - start pos is invalid, quitting\n"));
  1265. break;
  1266. }
  1267. newSlot[i].setStartPos(startPos);
  1268. //DEBUG_LOG(("ParseAsciiStringToGameInfo - start spot is %d\n", startPos));
  1269. //Read team index
  1270. slotValue = strtok_r(NULL,",",&slotPos);
  1271. if(slotValue.isEmpty())
  1272. {
  1273. optionsOk = false;
  1274. DEBUG_LOG(("ParseAsciiStringToGameInfo - slotValue team number is empty, quitting\n"));
  1275. break;
  1276. }
  1277. Int team = atoi(slotValue.str());
  1278. if (team < -1 || team >= MAX_SLOTS/2)
  1279. {
  1280. optionsOk = false;
  1281. DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is invalid, quitting\n"));
  1282. break;
  1283. }
  1284. newSlot[i].setTeamNumber(team);
  1285. //DEBUG_LOG(("ParseAsciiStringToGameInfo - team number is %d\n", team));
  1286. }//case 'C':
  1287. break;
  1288. case 'O':
  1289. {
  1290. newSlot[i].setState( SLOT_OPEN );
  1291. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Slot is open\n"));
  1292. }// case 'O':
  1293. break;
  1294. case 'X':
  1295. {
  1296. newSlot[i].setState( SLOT_CLOSED );
  1297. //DEBUG_LOG(("ParseAsciiStringToGameInfo - Slot is closed\n"));
  1298. }// case 'X':
  1299. break;
  1300. default:
  1301. {
  1302. optionsOk = false;
  1303. DEBUG_LOG(("ParseAsciiStringToGameInfo - unrecognized slot entry, quitting\n"));
  1304. }
  1305. break;
  1306. }
  1307. }
  1308. if(freeMe)
  1309. free(freeMe);
  1310. }
  1311. else
  1312. {
  1313. optionsOk = false;
  1314. break;
  1315. }
  1316. }
  1317. if( buf )
  1318. free(buf);
  1319. //DEBUG_LOG(("Options were ok == %d\n", optionsOk));
  1320. if (optionsOk && sawMap && sawMapCRC && sawMapSize && sawSeed && sawSlotlist && sawCRC && sawUseStats && sawSuperweaponRestriction && sawStartingCash && sawOldFactions )
  1321. {
  1322. // We were setting the Global Data directly here, but Instead, I'm now
  1323. // first setting the data in game. We'll set the global data when
  1324. // we start a game.
  1325. if (!game)
  1326. return true;
  1327. //DEBUG_LOG(("ParseAsciiStringToGameInfo - game options all good, setting info\n"));
  1328. for(Int i = 0; i<MAX_SLOTS; i++)
  1329. game->setSlot(i,newSlot[i]);
  1330. game->setMap(mapName);
  1331. game->setMapCRC(mapCRC);
  1332. game->setMapSize(mapSize);
  1333. game->setMapContentsMask(mapContentsMask);
  1334. game->setSeed(seed);
  1335. game->setCRCInterval(crc);
  1336. game->setUseStats(useStats);
  1337. game->setSuperweaponRestriction(restriction);
  1338. game->setStartingCash( startingCash );
  1339. game->setOldFactionsOnly( oldFactionsOnly );
  1340. return true;
  1341. }
  1342. DEBUG_LOG(("ParseAsciiStringToGameInfo - game options messed up\n"));
  1343. return false;
  1344. }
  1345. //----------------------------------------------------------------------------------------------------------
  1346. //----------------------------------------------------------------------------------------------------------
  1347. //------------------------- SkirmishGameInfo ---------------------------------------------------------------
  1348. // ------------------------------------------------------------------------------------------------
  1349. /** CRC */
  1350. // ------------------------------------------------------------------------------------------------
  1351. void SkirmishGameInfo::crc( Xfer *xfer )
  1352. {
  1353. } // end crc
  1354. // ------------------------------------------------------------------------------------------------
  1355. /** Xfer Method */
  1356. // ------------------------------------------------------------------------------------------------
  1357. void SkirmishGameInfo::xfer( Xfer *xfer )
  1358. {
  1359. const XferVersion currentVersion = 4;
  1360. XferVersion version = currentVersion;
  1361. xfer->xferVersion( &version, currentVersion );
  1362. xfer->xferInt(&m_preorderMask);
  1363. xfer->xferInt(&m_crcInterval);
  1364. xfer->xferBool(&m_inGame);
  1365. xfer->xferBool(&m_inProgress);
  1366. xfer->xferBool(&m_surrendered);
  1367. xfer->xferInt(&m_gameID);
  1368. Int slot = MAX_SLOTS;
  1369. xfer->xferInt(&slot);
  1370. DEBUG_ASSERTCRASH(slot==MAX_SLOTS, ("MAX_SLOTS changed, need to change version. jba."));
  1371. for (slot = 0; slot < MAX_SLOTS; slot++)
  1372. {
  1373. Int state = m_slot[slot]->getState();
  1374. xfer->xferInt(&state);
  1375. UnicodeString name=m_slot[slot]->getName();
  1376. if (version >= 2)
  1377. {
  1378. xfer->xferUnicodeString(&name);
  1379. }
  1380. Bool isAccepted=m_slot[slot]->isAccepted();
  1381. xfer->xferBool(&isAccepted);
  1382. Bool isMuted=m_slot[slot]->isMuted();
  1383. xfer->xferBool(&isMuted);
  1384. m_slot[slot]->mute(isMuted);
  1385. Int color=m_slot[slot]->getColor();
  1386. xfer->xferInt(&color);
  1387. Int startPos=m_slot[slot]->getStartPos();
  1388. xfer->xferInt(&startPos);
  1389. Int playerTemplate=m_slot[slot]->getPlayerTemplate();
  1390. xfer->xferInt(&playerTemplate);
  1391. Int teamNumber=m_slot[slot]->getTeamNumber();
  1392. xfer->xferInt(&teamNumber);
  1393. Int origColor=m_slot[slot]->getOriginalColor();
  1394. xfer->xferInt(&origColor);
  1395. Int origStartPos=m_slot[slot]->getOriginalStartPos();
  1396. xfer->xferInt(&origStartPos);
  1397. Int origPlayerTemplate=m_slot[slot]->getOriginalPlayerTemplate();
  1398. xfer->xferInt(&origPlayerTemplate);
  1399. if( xfer->getXferMode() == XFER_LOAD ) {
  1400. m_slot[slot]->setState((SlotState)state, name);
  1401. if (isAccepted) m_slot[slot]->setAccept();
  1402. m_slot[slot]->setPlayerTemplate(origPlayerTemplate);
  1403. m_slot[slot]->setStartPos(origStartPos);
  1404. m_slot[slot]->setColor(origColor);
  1405. m_slot[slot]->saveOffOriginalInfo();
  1406. m_slot[slot]->setTeamNumber(teamNumber);
  1407. m_slot[slot]->setColor(color);
  1408. m_slot[slot]->setStartPos(startPos);
  1409. m_slot[slot]->setPlayerTemplate(playerTemplate);
  1410. }
  1411. }
  1412. xfer->xferUnsignedInt(&m_localIP);
  1413. xfer->xferMapName(&m_mapName);
  1414. xfer->xferUnsignedInt(&m_mapCRC);
  1415. xfer->xferUnsignedInt(&m_mapSize);
  1416. xfer->xferInt(&m_mapMask);
  1417. xfer->xferInt(&m_seed);
  1418. if ( version >= 3 )
  1419. {
  1420. xfer->xferUnsignedShort( &m_superweaponRestriction );
  1421. if ( version == 3 )
  1422. {
  1423. // Version 3 had a bool which is now gone
  1424. Bool obsoleteBool;
  1425. xfer->xferBool( &obsoleteBool );
  1426. }
  1427. xfer->xferSnapshot( &m_startingCash );
  1428. }
  1429. else if ( xfer->getXferMode() == XFER_LOAD )
  1430. {
  1431. m_superweaponRestriction = 0;
  1432. m_startingCash = TheGlobalData->m_defaultStartingCash;
  1433. }
  1434. } // end xfer
  1435. // ------------------------------------------------------------------------------------------------
  1436. /** Load post process */
  1437. // ------------------------------------------------------------------------------------------------
  1438. void SkirmishGameInfo::loadPostProcess( void )
  1439. {
  1440. } // end loadPostProcess