gamedata.cpp 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513
  1. /*
  2. ** Command & Conquer Renegade(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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/gamedata.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 11/01/02 4:32p $*
  29. * *
  30. * $Revision:: 221 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "gamedata.h"
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include "win.h"
  39. #include "miscutil.h"
  40. #include "cnetwork.h"
  41. #include "chatshre.h"
  42. #include "wwdebug.h"
  43. #include "netinterface.h"
  44. #include "translatedb.h"
  45. #include "playertype.h"
  46. #include "teammanager.h"
  47. #include "playermanager.h"
  48. #include "assets.h"
  49. #include "translatedb.h"
  50. #include "string_ids.h"
  51. #include "gamemode.h"
  52. #include "savegame.h"
  53. #include "bandwidth.h"
  54. #include "gametype.h"
  55. #include "systimer.h"
  56. #include "objlibrary.h"
  57. #include "scriptzone.h"
  58. #include "aabox.h"
  59. #include "rendobj.h"
  60. #include "weaponbag.h"
  61. #include "multihud.h"
  62. #include "wwaudio.h"
  63. #include "textdisplay.h"
  64. #include "render2d.h"
  65. #include "render2dsentence.h"
  66. #include "wwprofile.h"
  67. #include "winevent.h"
  68. #include "realcrc.h"
  69. #include "useroptions.h"
  70. #include "gdsingleplayer.h"
  71. #include "gdcnc.h"
  72. #include "wolgmode.h"
  73. #include "font3d.h"
  74. #include "nat.h"
  75. #include "csdamageevent.h"
  76. #include "sctextobj.h"
  77. #include "widestring.h"
  78. #include "vehicle.h"
  79. #include "wolgameinfo.h"
  80. #include "spawn.h"
  81. #include "dlgcncwinscreen.h"
  82. #include "dialogmgr.h"
  83. #include "rawfile.h"
  84. #include "consolemode.h"
  85. #include "gamedataupdateevent.h"
  86. #include "stylemgr.h"
  87. #include "modpackagemgr.h"
  88. #include "modpackage.h"
  89. #include "bandwidthcheck.h"
  90. #include "serversettings.h"
  91. #include "gamespyadmin.h"
  92. #include "specialbuilds.h"
  93. #include "demosupport.h"
  94. #include "specialbuilds.h"
  95. const int cGameData::MAX_TIME_LIMIT = 999;
  96. cGameData * PTheGameData = NULL;
  97. static WideStringClass renderer_time_text;
  98. static WideStringClass renderer_dedicated_server_label;
  99. static WideStringClass renderer_gameplay_label;
  100. static unsigned renderer_dedicated_server_color;
  101. static unsigned renderer_gameplay_color;
  102. //
  103. // Class statics
  104. //
  105. const StringClass cGameData::INI_SECTION_NAME = "Settings";
  106. const float cGameData::LIMITS_X_POS = 0.8f;
  107. Render2DSentenceClass * cGameData::PTextRenderer = NULL;
  108. int cGameData::HostedGameNumber = 0;
  109. bool cGameData::IsManualRestart = false;
  110. bool cGameData::IsManualExit = false;
  111. WideStringClass cGameData::WinText;
  112. //
  113. // hack
  114. //
  115. ULONG g_ip_override = INADDR_NONE;
  116. //------------------------------------------------------------------------------------
  117. void cGameData::Onetime_Init(void)
  118. {
  119. WWDEBUG_SAY(("cGameData::Onetime_Init\n"));
  120. if (!ConsoleBox.Is_Exclusive()) {
  121. PTextRenderer = new Render2DSentenceClass;
  122. StyleMgrClass::Assign_Font(PTextRenderer, StyleMgrClass::FONT_INGAME_TXT);
  123. PTextRenderer->Set_Mono_Spaced(true);
  124. PTextRenderer->Set_Clipping_Rect(Render2DClass::Get_Screen_Resolution());
  125. }
  126. }
  127. //------------------------------------------------------------------------------------
  128. void cGameData::Onetime_Shutdown(void)
  129. {
  130. WWDEBUG_SAY(("cGameData::Onetime_Shutdown\n"));
  131. if (!ConsoleBox.Is_Exclusive()) {
  132. WWASSERT(PTextRenderer != NULL);
  133. delete PTextRenderer;
  134. PTextRenderer = NULL;
  135. }
  136. }
  137. //-----------------------------------------------------------------------------
  138. cGameData::cGameData(void) :
  139. DoExeVersionsMatch (true),
  140. DoStringVersionsMatch (true),
  141. DoMapsLoop (true),
  142. IsMapCycleOver (false),
  143. MapCycleIndex(0)
  144. {
  145. //WWDEBUG_SAY(("cGameData::cGameData\n"));
  146. IsIntermission.Set( false);
  147. IsDedicated.Set( false);
  148. IsAutoRestart.Set( false);
  149. IsFriendlyFirePermitted.Set( false);
  150. IsTeamChangingAllowed.Set( true);
  151. IsPassworded.Set( false);
  152. IsFreeWeapons.Set( false);
  153. IsLaddered.Set( false);
  154. IsClanGame.Set( false);
  155. IsClientTrusted.Set( true);
  156. RemixTeams.Set( false);
  157. CanRepairBuildings.Set( true);
  158. DriverIsAlwaysGunner.Set( true);
  159. SpawnWeapons.Set( false);
  160. mWinnerID = -1;
  161. MaxPlayers = 16;
  162. TimeLimitMinutes = 0;
  163. RadarMode = RADAR_ALL;
  164. IniFilename = "";
  165. Motd.Format(L"");
  166. Set_Password( L"");
  167. //Set_Owner( "UNOWNED");
  168. Set_Owner( cNetInterface::Get_Nickname());
  169. IntermissionTimeSeconds = 15;
  170. Set_Version_Number( cNetwork::Get_Exe_Key());
  171. Set_Ip_Address(0);
  172. Set_Port( 4848);//TSS - hardcoded port
  173. Set_Current_Players(0);
  174. IntermissionTimeRemaining = 0;
  175. TimeRemainingSeconds = 0;
  176. MaximumWorldDistance = 0;
  177. MinQualifyingTimeMinutes = 2;
  178. IsQuickMatchServer = false;
  179. //ServerIsGameplayPermitted = false;
  180. WinType = WIN_TYPE_TIME;
  181. GameDurationS = 0;
  182. LastServerConfigModTime = 0;
  183. SettingsDescription = TRANSLATE(IDS_SERVER_SAVELOAD_CUSTOM_DEFAULT);
  184. Clear_Clans();
  185. MvpCount = 0;
  186. #ifdef MULTIPLAYERDEMO
  187. MapName.Format("C&C_Under.mix");
  188. #endif // MULTIPLAYERDEMO
  189. }
  190. //-----------------------------------------------------------------------------
  191. cGameData::~cGameData(void)
  192. {
  193. //WWDEBUG_SAY(("cGameData::~cGameData\n"));
  194. }
  195. //-----------------------------------------------------------------------------
  196. cGameData& cGameData::operator=(const cGameData& rhs)
  197. {
  198. IsIntermission = rhs.IsIntermission;
  199. IsDedicated = rhs.IsDedicated;
  200. IsAutoRestart = rhs.IsAutoRestart;
  201. IsFriendlyFirePermitted = rhs.IsFriendlyFirePermitted;
  202. IsTeamChangingAllowed = rhs.IsTeamChangingAllowed;
  203. IsPassworded = rhs.IsPassworded;
  204. IsFreeWeapons = rhs.IsFreeWeapons;
  205. IsLaddered = rhs.IsLaddered;
  206. IsClanGame = rhs.IsClanGame;
  207. IsClientTrusted = rhs.IsClientTrusted;
  208. RemixTeams = rhs.RemixTeams;
  209. CanRepairBuildings = rhs.CanRepairBuildings;
  210. DriverIsAlwaysGunner = rhs.DriverIsAlwaysGunner;
  211. SpawnWeapons = rhs.SpawnWeapons;
  212. Password = rhs.Password;
  213. GameTitle = rhs.GameTitle;
  214. Motd = rhs.Motd;
  215. #ifdef MULTIPLAYERDEMO
  216. MapName.Format("C&C_Under.mix");
  217. #else
  218. MapName = rhs.MapName;
  219. ModName = rhs.ModName;
  220. #endif
  221. Owner = rhs.Owner;
  222. MaxPlayers = rhs.MaxPlayers;
  223. TimeLimitMinutes = rhs.TimeLimitMinutes;
  224. IntermissionTimeSeconds = rhs.IntermissionTimeSeconds;
  225. VersionNumber = rhs.VersionNumber;
  226. IpAddress = rhs.IpAddress;
  227. Port = rhs.Port;
  228. IniFilename = rhs.IniFilename;
  229. RadarMode = rhs.RadarMode;
  230. CurrentPlayers = rhs.CurrentPlayers;
  231. IntermissionTimeRemaining = rhs.IntermissionTimeRemaining;
  232. TimeRemainingSeconds = rhs.TimeRemainingSeconds;
  233. MaximumWorldDistance = rhs.MaximumWorldDistance;
  234. MinQualifyingTimeMinutes = rhs.MinQualifyingTimeMinutes;
  235. for (int clanSlot = 0; clanSlot < MAX_CLAN_SLOTS; ++clanSlot) {
  236. mClanSlots[clanSlot] = rhs.mClanSlots[clanSlot];
  237. }
  238. return (*this);
  239. }
  240. //-----------------------------------------------------------------------------
  241. void cGameData::Reset_Game(bool is_reloaded)
  242. {
  243. WWDEBUG_SAY(("cGameData::Reset_Game\n"));
  244. //
  245. // Game_Reset is called on both C & S at the beginning of every game.
  246. //
  247. mWinnerID = -1;
  248. IsIntermission.Set(false);
  249. //
  250. // 12/11/01
  251. // This dialog flush was added to remove the purchase screen because it persists
  252. // over reload.
  253. //
  254. if (GameModeManager::Find ("Combat")->Is_Active ()) {
  255. if (GameModeManager::Find ("Menu")->Is_Active ()) {
  256. GameModeManager::Find ("Menu")->Deactivate ();
  257. } else {
  258. DialogMgrClass::Flush_Dialogs ();
  259. }
  260. }
  261. if (Get_Text_Display()) {
  262. WWASSERT(Get_Text_Display() != NULL);
  263. Get_Text_Display()->Flush();
  264. }
  265. if (!IS_MISSION) {
  266. WWAudioClass::Get_Instance()->Create_Instant_Sound("Game_Start", Matrix3D(1));
  267. }
  268. //TSS092601 if ( !is_reloaded ) {
  269. if ( !IS_MISSION || !is_reloaded ) {
  270. cPlayerManager::Reset_Players();
  271. }
  272. //}
  273. cTeamManager::Reset_Teams();
  274. if (Is_Time_Limit()) {
  275. Reset_Time_Remaining_Seconds();
  276. if (cNetwork::I_Am_Server()) {
  277. cGameDataUpdateEvent * p_event = new cGameDataUpdateEvent();
  278. p_event->Init(-1);
  279. }
  280. }
  281. if (cNetwork::I_Am_Server())
  282. {
  283. HostedGameNumber++;
  284. }
  285. }
  286. //-----------------------------------------------------------------------------
  287. void cGameData::Swap_Team_Sides(void)
  288. {
  289. //WWASSERT(Is_Team_Game());
  290. WWASSERT(cNetwork::I_Am_Server());
  291. for (
  292. SLNode<cPlayer> * player_node = cPlayerManager::Get_Player_Object_List()->Head();
  293. player_node;
  294. player_node = player_node->Next()) {
  295. cPlayer * p_player = player_node->Data();
  296. WWASSERT(p_player != NULL);
  297. int team = p_player->Get_Player_Type();
  298. WWASSERT(team == PLAYERTYPE_NOD || team == PLAYERTYPE_GDI);
  299. int new_team = PLAYERTYPE_NOD;
  300. if (team == PLAYERTYPE_NOD)
  301. {
  302. new_team = PLAYERTYPE_GDI;
  303. }
  304. else
  305. {
  306. new_team = PLAYERTYPE_NOD;
  307. }
  308. p_player->Set_Player_Type(new_team);
  309. }
  310. //
  311. // Inform the players
  312. //
  313. //WideStringClass text;
  314. //text.Format(L"_TEAMS_SWAPPED_!_");
  315. WideStringClass text = TRANSLATE(IDS_MP_TEAMS_SWAPPED);
  316. cScTextObj * p_text_obj = new cScTextObj();
  317. p_text_obj->Init(text, TEXT_MESSAGE_PUBLIC, false, HOST_TEXT_SENDER, -1);
  318. }
  319. //-----------------------------------------------------------------------------
  320. void cGameData::Remix_Team_Sides(void)
  321. {
  322. //WWASSERT(Is_Team_Game());
  323. WWASSERT(cNetwork::I_Am_Server());
  324. WWASSERT(IsClanGame.Is_False() && "Remix teams not allowed");
  325. if (IsClanGame.Is_True()) {
  326. return;
  327. }
  328. //
  329. // Randomly choose a team for each player
  330. //
  331. for (
  332. SLNode<cPlayer> * player_node = cPlayerManager::Get_Player_Object_List()->Head();
  333. player_node;
  334. player_node = player_node->Next()) {
  335. cPlayer * p_player = player_node->Data();
  336. WWASSERT(p_player != NULL);
  337. int new_team = PLAYERTYPE_NOD;
  338. if (rand() % 2 == 0)
  339. {
  340. new_team = PLAYERTYPE_GDI;
  341. }
  342. else
  343. {
  344. new_team = PLAYERTYPE_NOD;
  345. }
  346. p_player->Set_Player_Type(new_team);
  347. }
  348. //
  349. // Inform the players
  350. //
  351. //WideStringClass text;
  352. //text.Format(L"_TEAMS_REMIXED_!_");
  353. WideStringClass text = TRANSLATE(IDS_MP_TEAMS_REMIXED);
  354. cScTextObj * p_text_obj = new cScTextObj();
  355. p_text_obj->Init(text, TEXT_MESSAGE_PUBLIC, false, HOST_TEXT_SENDER, -1);
  356. }
  357. //-----------------------------------------------------------------------------
  358. void cGameData::Rebalance_Team_Sides(void)
  359. {
  360. //WWASSERT(Is_Team_Game());
  361. WWASSERT(cNetwork::I_Am_Server());
  362. WWASSERT(IsClanGame.Is_False() && "Rebalance teams not allowed");
  363. if (IsClanGame.Is_True()) {
  364. return;
  365. }
  366. //
  367. // Rebalance teams numerically
  368. //
  369. cTeam * p_nod = cTeamManager::Find_Team(PLAYERTYPE_NOD);
  370. WWASSERT(p_nod != NULL);
  371. cTeam * p_gdi = cTeamManager::Find_Team(PLAYERTYPE_GDI);
  372. WWASSERT(p_gdi != NULL);
  373. int move_count = 0;
  374. int nod_tally = 0;
  375. int gdi_tally = 0;
  376. do
  377. {
  378. nod_tally = p_nod->Tally_Size();
  379. gdi_tally = p_gdi->Tally_Size();
  380. if (nod_tally > gdi_tally + 1)
  381. {
  382. cPlayer * p_player = cPlayerManager::Find_Team_Player(PLAYERTYPE_NOD);
  383. WWASSERT(p_player != NULL);
  384. p_player->Set_Player_Type(PLAYERTYPE_GDI);
  385. move_count++;
  386. }
  387. else if (gdi_tally > nod_tally + 1)
  388. {
  389. cPlayer * p_player = cPlayerManager::Find_Team_Player(PLAYERTYPE_GDI);
  390. WWASSERT(p_player != NULL);
  391. p_player->Set_Player_Type(PLAYERTYPE_NOD);
  392. move_count++;
  393. }
  394. } while (::abs(nod_tally - gdi_tally) > 1);
  395. if (move_count > 0) {
  396. //
  397. // Inform the players
  398. //
  399. //WideStringClass text;
  400. //text.Format(L"_TEAMS_REBALANCED_!_");
  401. WideStringClass text = TRANSLATE(IDS_MP_TEAMS_REBALANCED);
  402. cScTextObj * p_text_obj = new cScTextObj();
  403. p_text_obj->Init(text, TEXT_MESSAGE_PUBLIC, false, HOST_TEXT_SENDER, -1);
  404. }
  405. }
  406. //-----------------------------------------------------------------------------
  407. void cGameData::Set_Ip_And_Port(void)
  408. {
  409. /*
  410. SOCKADDR_IN local_address;
  411. bool retcode = cNetUtil::Get_Local_Address(&local_address);
  412. WWASSERT(retcode == true);
  413. //
  414. // hack
  415. //
  416. if (g_ip_override != INADDR_NONE) {
  417. local_address.sin_addr.s_addr = g_ip_override;
  418. }
  419. Set_Ip_Address(local_address.sin_addr.s_addr);
  420. */
  421. ULONG ip = 0;
  422. if (cGameSpyAdmin::Get_Is_Server_Gamespy_Listed()) {
  423. ip = cUserOptions::PreferredGameSpyNic.Get();
  424. } else {
  425. ip = cUserOptions::PreferredLanNic.Get();
  426. }
  427. if (g_ip_override != INADDR_NONE) {
  428. ip = g_ip_override;
  429. }
  430. //
  431. // IP is set automatically in WOL unless there is an IP override and a port overrride.
  432. //
  433. if (GameModeManager::Find("WOL")->Is_Active()) {
  434. if (g_ip_override == INADDR_NONE || WOLNATInterface.Get_Force_Port() == 0) {
  435. unsigned long temp = FirewallHelper.Get_Local_Address();
  436. if (temp) {
  437. //ip = temp;
  438. ip = ::ntohl(temp);
  439. }
  440. }
  441. }
  442. //WWASSERT(ip != 0);
  443. Set_Ip_Address(ip);
  444. }
  445. //-----------------------------------------------------------------------------
  446. //
  447. // A convenience function...
  448. //
  449. bool cGameData::Set_Generic_Num(int generic_num,
  450. int lower_bound, int upper_bound, int & set_num)
  451. {
  452. if (generic_num >= lower_bound && generic_num <= upper_bound) {
  453. set_num = generic_num;
  454. return true;
  455. } else {
  456. return false;
  457. }
  458. }
  459. //-----------------------------------------------------------------------------
  460. bool cGameData::Set_Max_Players(int max)
  461. {
  462. return Set_Generic_Num(max, 0, MAX_PLAYERS, MaxPlayers);
  463. }
  464. //-----------------------------------------------------------------------------
  465. bool cGameData::Set_Time_Limit_Minutes(int time_limit_minutes)
  466. {
  467. return Set_Generic_Num(time_limit_minutes, 0, MAX_TIME_LIMIT, TimeLimitMinutes);
  468. }
  469. //-----------------------------------------------------------------------------
  470. void cGameData::Set_Radar_Mode(RadarModeEnum mode)
  471. {
  472. RadarMode = mode;
  473. }
  474. //-----------------------------------------------------------------------------
  475. void cGameData::Set_Intermission_Time_Seconds(int time)
  476. {
  477. WWASSERT(time >= 0);
  478. IntermissionTimeSeconds = time;
  479. }
  480. //-----------------------------------------------------------------------------
  481. void cGameData::Set_Motd(const WCHAR * motd)
  482. {
  483. WWASSERT(motd != NULL);
  484. Motd = motd;
  485. }
  486. //-----------------------------------------------------------------------------
  487. void cGameData::Set_Mod_Name(const StringClass &mod_name)
  488. {
  489. ModName = mod_name;
  490. ModPackageMgrClass::Set_Current_Package (ModName);
  491. return ;
  492. }
  493. //-----------------------------------------------------------------------------
  494. void cGameData::Set_Map_Name(const StringClass & map_name)
  495. {
  496. #ifdef MULTIPLAYERDEMO
  497. MapName.Format("C&C_Under.mix");
  498. #else
  499. MapName = map_name;
  500. #endif
  501. }
  502. //-----------------------------------------------------------------------------
  503. bool cGameData::Set_Current_Players(int current)
  504. {
  505. return Set_Generic_Num(current, 0, MAX_PLAYERS, CurrentPlayers);
  506. }
  507. //-----------------------------------------------------------------------------
  508. void cGameData::Set_Owner(WideStringClass & owner)
  509. {
  510. Owner = owner;
  511. }
  512. //-----------------------------------------------------------------------------
  513. void cGameData::Set_Ip_Address(ULONG ip_address)
  514. {
  515. IpAddress = ip_address;
  516. }
  517. //-----------------------------------------------------------------------------
  518. void cGameData::Set_Port(int port)
  519. {
  520. WWASSERT(port >= MIN_SERVER_PORT && port <= MAX_SERVER_PORT);
  521. Port = port;
  522. }
  523. //-----------------------------------------------------------------------------
  524. bool cGameData::Is_Limited(void) const
  525. {
  526. return Is_Time_Limit();
  527. }
  528. //-----------------------------------------------------------------------------
  529. bool cGameData::Is_Map_Valid(char **out_filename)
  530. {
  531. bool map_exists = false;
  532. if (ModName.Is_Empty () == false) {
  533. if (out_filename) {
  534. *out_filename = ModName.Peek_Buffer();
  535. }
  536. map_exists = cMiscUtil::File_Exists (ModName);
  537. } else {
  538. if (out_filename) {
  539. *out_filename = MapName.Peek_Buffer();
  540. }
  541. map_exists = cMiscUtil::File_Exists (MapName);
  542. }
  543. return(map_exists);
  544. }
  545. #define PRINT_CONFIG_ERROR ConsoleBox.Print("File %s - Error:\r\n\t ", Get_Ini_Filename());
  546. //-----------------------------------------------------------------------------
  547. bool cGameData::Is_Valid_Settings(WideStringClass& outMsg, bool check_as_server)
  548. {
  549. if (MapName.Is_Empty()) {
  550. //cHelpText::Set(TRANSLATION(IDS_MP_NO_LEVEL_SELECTED));
  551. Debug_Say(( "cGameData::No level file selected.\n" ));
  552. PRINT_CONFIG_ERROR;
  553. ConsoleBox.Print("No initial level file selected\n\n");
  554. outMsg = TRANSLATE(IDS_HOPTERR_NO_LEVEL);
  555. return false;
  556. } else {
  557. //
  558. // Test to see whether or not the map exists
  559. //
  560. char *filename = NULL;
  561. if (!Is_Map_Valid(&filename)) {
  562. Debug_Say(("cGameData::Is_Valid_Settings: Level \"%s\" not found\n", filename));
  563. PRINT_CONFIG_ERROR;
  564. ConsoleBox.Print("Map file '%s' not found\n\n", filename);
  565. outMsg.Format(TRANSLATE(IDS_HOPTERR_MAP_NOTFOUND), filename);
  566. return(false);
  567. }
  568. }
  569. if (IsPassworded.Is_True() && Password.Get_Length () == 0) {
  570. //cHelpText::Set(TRANSLATION(IDS_MP_BLANK_PASSWORD_ILLEGAL));
  571. Debug_Say(( "cGameData::Is_Valid_Settings: You can not use a blank password.\n" ));
  572. PRINT_CONFIG_ERROR;
  573. ConsoleBox.Print("Blank passwords are not allowed\n\n");
  574. outMsg = TRANSLATE(IDS_HOPTERR_BLANK_PASS);
  575. return false;
  576. }
  577. #ifndef FREEDEDICATEDSERVER
  578. if (GameModeManager::Find("WOL")->Is_Active()) {
  579. #endif //FREEDEDICATEDSERVER
  580. if (IsPassworded.Is_True() && Is_QuickMatch_Server()) {
  581. Debug_Say(("cGameData::Is_Valid_Settings: Quickmatch can not have passwords.\n" ));
  582. PRINT_CONFIG_ERROR;
  583. ConsoleBox.Print("A password cannot be used on a Quickmatch server\n\n");
  584. outMsg = TRANSLATE(IDS_HOPTERR_QM_HASPASS);
  585. return false;
  586. }
  587. if (Is_QuickMatch_Server() && IsLaddered.Is_False()) {
  588. Debug_Say(("cGameData::Is_Valid_Settings: Quickmatch must be laddered.\n" ));
  589. PRINT_CONFIG_ERROR;
  590. ConsoleBox.Print("A Quickmatch server must also be laddered\n\n");
  591. outMsg = TRANSLATE(IDS_HOPTERR_QM_NOLADDER);
  592. return false;
  593. }
  594. if (Is_QuickMatch_Server() && IsClanGame.Is_True()) {
  595. Debug_Say(("cGameData::Is_Valid_Settings: Quickmatch cannot be clanned.\n" ));
  596. PRINT_CONFIG_ERROR;
  597. ConsoleBox.Print("Clans are not allowed in a quickmatch server\n\n");
  598. outMsg = TRANSLATE(IDS_HOPTERR_QM_NOCLANS);
  599. return false;
  600. }
  601. if (IsLaddered.Is_True() && IsTeamChangingAllowed.Is_True()) {
  602. PRINT_CONFIG_ERROR;
  603. ConsoleBox.Print("Team changing not allowed on a laddered server\n\n");
  604. outMsg = TRANSLATE(IDS_HOPTERR_NO_TEAMCHANGE);
  605. return false;
  606. }
  607. if (IsClanGame.Is_True() && (IsTeamChangingAllowed.Is_True() || RemixTeams.Is_True())) {
  608. PRINT_CONFIG_ERROR;
  609. ConsoleBox.Print("Team changing or Team Remix not allowed on a clan game server.\n");
  610. outMsg = "Team changing or Team Remix not allowed on a clan game server."; //TRANSLATE(IDS_HOPTERR_NO_TEAMCHANGE);
  611. return false;
  612. }
  613. #ifndef FREEDEDICATEDSERVER
  614. }
  615. #endif //FREEDEDICATEDSERVER
  616. #ifdef FREEDEDICATEDSERVER
  617. if (Get_Max_Players() == 0 && ServerSettingsClass::Get_Game_Mode() !=
  618. ServerSettingsClass::MODE_WOL) {
  619. #else
  620. if (Get_Max_Players() == 0) {
  621. #endif
  622. PRINT_CONFIG_ERROR;
  623. ConsoleBox.Print("Max player count must be greater than 0\n\n");
  624. outMsg = TRANSLATE(IDS_HOPTERR_MAXPLAYER_0);
  625. return(false);
  626. }
  627. // Check server only parameters
  628. if (check_as_server || ConsoleBox.Is_Exclusive()) {
  629. if (Get_Max_Players() > NetworkObjectClass::MAX_CLIENT_COUNT-1) {
  630. PRINT_CONFIG_ERROR;
  631. ConsoleBox.Print("Max player count must be less than %d\n\n", NetworkObjectClass::MAX_CLIENT_COUNT);
  632. outMsg.Format(TRANSLATE(IDS_HOPTERR_MAXPLAYER_TOOBIG), NetworkObjectClass::MAX_CLIENT_COUNT);
  633. return(false);
  634. }
  635. if (DoMapsLoop && Get_Map_Cycle(0).Get_Length() == 0) {
  636. PRINT_CONFIG_ERROR;
  637. ConsoleBox.Print("Map cycling is enabled but there are no maps in the cycle\n\n");
  638. outMsg = TRANSLATE(IDS_HOPTERR_NO_MAPCYCLE);
  639. return(false);
  640. }
  641. /*
  642. ** Make sure all the maps exist.
  643. */
  644. if (DoMapsLoop && ModName.Is_Empty ()) {
  645. for (int i=0 ; i<MAX_MAPS ; i++) {
  646. StringClass map_name = Get_Map_Cycle(i);
  647. if (map_name.Get_Length()) {
  648. char filename[_MAX_PATH];
  649. sprintf(filename, "data\\%s", map_name.Peek_Buffer());
  650. RawFileClass file(filename);
  651. if (!file.Is_Available()) {
  652. PRINT_CONFIG_ERROR;
  653. ConsoleBox.Print("Map file '%s' not found\n\n", filename);
  654. outMsg.Format(TRANSLATE(IDS_HOPTERR_MAP_NOTFOUND), filename);
  655. return(false);
  656. }
  657. }
  658. }
  659. }
  660. /*
  661. ** Check the game end conditions.
  662. */
  663. if (!Is_Limited()) {
  664. //cHelpText::Set(TRANSLATION(IDS_MP_GAMEMODE_NEEDS_LIMIT));
  665. PRINT_CONFIG_ERROR;
  666. ConsoleBox.Print("Game must end by time limit or base destruction\n\n");
  667. outMsg = TRANSLATE(IDS_HOPTERR_NO_GAMEEND);
  668. return false;
  669. }
  670. /*
  671. ** Check the Message of the day for excessive length.
  672. */
  673. if (Motd.Get_Length() > MAX_MOTD_LENGTH) {
  674. PRINT_CONFIG_ERROR;
  675. ConsoleBox.Print("Message of the day cannot exceed %d characters\n\n", MAX_MOTD_LENGTH);
  676. outMsg.Format(TRANSLATE(IDS_HOPTERR_MOTD_TOOBIG), MAX_MOTD_LENGTH);
  677. return false;
  678. }
  679. /*
  680. ** Check the game title for length. The buffers are pretty much all 256 bytes but 100 seems a more reasonable figure.
  681. */
  682. if (GameTitle.Get_Length() > 100) {
  683. PRINT_CONFIG_ERROR;
  684. ConsoleBox.Print("Game title cannot exceed %d characters\n\n", 100);
  685. outMsg.Format(TRANSLATE(IDS_HOPTERR_TITLE_TOOBIG), 100);
  686. return false;
  687. }
  688. }
  689. return true; // it's valid !
  690. }
  691. //-----------------------------------------------------------------------------
  692. //
  693. // Server options are exported in 2 tiers. Tier 1 is the basic parameters
  694. // that show up in the list of games. Tier 2 is the remainder of the full
  695. // set of server settings.
  696. //
  697. void cGameData::Export_Tier_1_Data(cPacket & packet)
  698. {
  699. packet.Add(IpAddress);
  700. packet.Add_Wide_Terminated_String(Owner);
  701. packet.Add_Wide_Terminated_String(GameTitle, true);
  702. packet.Add(Port);
  703. packet.Add(CurrentPlayers);
  704. packet.Add(MaxPlayers);
  705. packet.Add(VersionNumber);
  706. //
  707. // Send the individual CRC's (for internal use)
  708. //
  709. packet.Add(cNetwork::Get_Exe_CRC ());
  710. packet.Add(cNetwork::Get_Strings_CRC ());
  711. packet.Add(IsDedicated.Get());
  712. packet.Add(IsTeamChangingAllowed.Get());
  713. packet.Add(IsPassworded.Get());
  714. packet.Add(IsLaddered.Get());
  715. packet.Add(IsClanGame.Get());
  716. #ifndef MULTIPLAYERDEMO
  717. packet.Add(::CRC_Stringi(MapName));
  718. packet.Add(::CRC_Stringi(ModName));
  719. #endif // MULTIPLAYERDEMO
  720. }
  721. //-----------------------------------------------------------------------------
  722. void cGameData::Import_Tier_1_Data(cPacket & packet)
  723. {
  724. ULONG ip_address = packet.Get(ip_address);
  725. Set_Ip_Address(ip_address);
  726. WideStringClass owner;
  727. packet.Get_Wide_Terminated_String(owner.Get_Buffer(256), 256);
  728. Set_Owner(owner);
  729. WideStringClass title;
  730. packet.Get_Wide_Terminated_String(title.Get_Buffer(256), 256, true);
  731. Set_Game_Title(title);
  732. int i_placeholder;
  733. bool b_placeholder;
  734. Set_Port( packet.Get(i_placeholder));
  735. Set_Current_Players( packet.Get(i_placeholder));
  736. Set_Max_Players( packet.Get(i_placeholder));
  737. Set_Version_Number( packet.Get(i_placeholder));
  738. //
  739. // Compare the individual CRC's against our own
  740. //
  741. DoExeVersionsMatch = (packet.Get(i_placeholder) == cNetwork::Get_Exe_CRC ());
  742. DoStringVersionsMatch = (packet.Get(i_placeholder) == cNetwork::Get_Strings_CRC ());
  743. IsDedicated.Set( packet.Get(b_placeholder));
  744. IsTeamChangingAllowed.Set( packet.Get(b_placeholder));
  745. IsPassworded.Set( packet.Get(b_placeholder));
  746. IsLaddered.Set( packet.Get(b_placeholder));
  747. IsClanGame.Set( packet.Get(b_placeholder));
  748. #ifndef MULTIPLAYERDEMO
  749. //
  750. // Get the CRC of the map and the mod
  751. //
  752. ULONG map_name_crc = packet.Get(map_name_crc);
  753. ULONG mod_name_crc = packet.Get(mod_name_crc);
  754. //
  755. // Determine what the name of the mod and the map are from their CRC's
  756. //
  757. StringClass mod_name(0,true);
  758. StringClass map_name(0,true);
  759. if (ModPackageMgrClass::Get_Mod_Map_Name_From_CRC (mod_name_crc, map_name_crc, &mod_name, &map_name)) {
  760. Set_Mod_Name (mod_name);
  761. Set_Map_Name (map_name);
  762. } else {
  763. ModName = L"";
  764. MapName = L"";
  765. }
  766. #endif // MULTIPLAYERDEMO
  767. return ;
  768. }
  769. //-----------------------------------------------------------------------------
  770. bool cGameData::Does_Map_Exist (void)
  771. {
  772. bool retval = true;
  773. //
  774. // If the map and mod names are empty then it is due to the fact
  775. // that we couldn't find the map and/or mod when we looked
  776. //
  777. if (ModName.Is_Empty () && MapName.Is_Empty ()) {
  778. retval = false;
  779. }
  780. return retval;
  781. }
  782. //-----------------------------------------------------------------------------
  783. void cGameData::Import_Tier_1_Data(const WOLGameInfo& gameInfo)
  784. {
  785. Set_Map_Name(gameInfo.MapName());
  786. Set_Mod_Name(gameInfo.ModName());
  787. WideStringClass title(0, true);
  788. title.Convert_From(gameInfo.Title());
  789. Set_Game_Title(title);
  790. Set_Max_Players(gameInfo.MaxPlayers());
  791. Set_Current_Players(gameInfo.NumPlayers());
  792. // Set game flags
  793. IsDedicated.Set(gameInfo.IsDedicated());
  794. IsPassworded.Set(gameInfo.IsPassworded());
  795. IsLaddered.Set(gameInfo.IsLaddered());
  796. IsFriendlyFirePermitted.Set(gameInfo.IsFriendlyFire());
  797. IsFreeWeapons.Set(gameInfo.IsFreeWeapons());
  798. RemixTeams.Set(gameInfo.IsTeamRemix());
  799. IsTeamChangingAllowed.Set(gameInfo.IsTeamChange());
  800. IsClanGame.Set(gameInfo.IsClanGame());
  801. IsQuickMatchServer = gameInfo.IsQuickmatch();
  802. CanRepairBuildings.Set(gameInfo.IsRepairBuildings());
  803. DriverIsAlwaysGunner.Set(gameInfo.IsDriverGunner());
  804. SpawnWeapons.Set(gameInfo.IsSpawnWeapons());
  805. Clear_Clans();
  806. mClanSlots[0] = gameInfo.ClanID1();
  807. mClanSlots[1] = gameInfo.ClanID2();
  808. }
  809. //-----------------------------------------------------------------------------
  810. void cGameData::Export_Tier_2_Data(cPacket & packet)
  811. {
  812. packet.Add(TimeLimitMinutes);
  813. packet.Add((int) RadarMode);
  814. packet.Add(IntermissionTimeSeconds);
  815. packet.Add(MinQualifyingTimeMinutes);
  816. packet.Add(IsFriendlyFirePermitted.Get());
  817. packet.Add(IsFreeWeapons.Get());
  818. packet.Add(IsClientTrusted.Get());
  819. packet.Add(RemixTeams.Get());
  820. if (Is_Cnc()) {
  821. packet.Add(CanRepairBuildings.Get());
  822. packet.Add(DriverIsAlwaysGunner.Get());
  823. packet.Add(SpawnWeapons.Get());
  824. }
  825. packet.Add_Wide_Terminated_String(Motd, true);
  826. }
  827. //-----------------------------------------------------------------------------
  828. void cGameData::Import_Tier_2_Data(cPacket & packet)
  829. {
  830. int i_placeholder = 0;
  831. bool b_placeholder = false;
  832. Set_Time_Limit_Minutes( packet.Get(i_placeholder));
  833. Set_Radar_Mode((RadarModeEnum) packet.Get(i_placeholder));
  834. Set_Intermission_Time_Seconds( packet.Get(i_placeholder));
  835. Set_Min_Qualifying_Time_Minutes( packet.Get(i_placeholder));
  836. IsFriendlyFirePermitted.Set( packet.Get(b_placeholder));
  837. IsFreeWeapons.Set( packet.Get(b_placeholder));
  838. IsClientTrusted.Set( packet.Get(b_placeholder));
  839. RemixTeams.Set( packet.Get(b_placeholder));
  840. if (Is_Cnc()) {
  841. CanRepairBuildings.Set( packet.Get(b_placeholder));
  842. DriverIsAlwaysGunner.Set( packet.Get(b_placeholder));
  843. SpawnWeapons.Set( packet.Get(b_placeholder));
  844. }
  845. WideStringClass motd;
  846. packet.Get_Wide_Terminated_String(motd.Get_Buffer(MAX_MOTD_LENGTH), MAX_MOTD_LENGTH, true);
  847. Set_Motd(motd);
  848. }
  849. //-----------------------------------------------------------------------------
  850. void cGameData::Load_From_Server_Config(LPCSTR config_file)
  851. {
  852. WWASSERT(config_file != NULL);
  853. WWASSERT(cMiscUtil::Is_String_Different(config_file, ""));
  854. INIClass * p_ini = Get_INI(config_file);
  855. StringClass full_filename(config_file, true);
  856. if (p_ini == NULL) {
  857. full_filename.Format("data\\%s", config_file);
  858. FILE * file = fopen(full_filename, "w");
  859. fclose(file);
  860. p_ini = Get_INI(config_file);
  861. }
  862. WWASSERT(p_ini != NULL);
  863. LastServerConfigModTime = Get_Config_File_Mod_Time();
  864. char map_name[MAX_MAPNAME_SIZE];
  865. char mod_name[MAX_MAPNAME_SIZE];
  866. char string8[256];
  867. bool b;
  868. int i;
  869. //float f;
  870. //p_ini->Get_String( INI_SECTION_NAME, "Password", Get_Password(), password, sizeof(password));
  871. //Set_Password(password);
  872. p_ini->Get_String( INI_SECTION_NAME, "MapName", "", map_name, sizeof(map_name));
  873. StringClass map(map_name,true);
  874. Set_Map_Name(map);
  875. p_ini->Get_String( INI_SECTION_NAME, "ModName", "", mod_name, sizeof(mod_name));
  876. StringClass mod(mod_name,true);
  877. Set_Mod_Name(mod);
  878. i = p_ini->Get_Int( INI_SECTION_NAME, "TimeLimitMinutes", Get_Time_Limit_Minutes());
  879. Set_Time_Limit_Minutes(i);
  880. i = p_ini->Get_Int( INI_SECTION_NAME, "RadarMode", Get_Radar_Mode());
  881. Set_Radar_Mode((RadarModeEnum) i);
  882. //i = p_ini->Get_Int( INI_SECTION_NAME, "IntermissionTimeSeconds", Get_Intermission_Time_Seconds());
  883. //Set_Intermission_Time_Seconds(i);
  884. #ifndef FREEDEDICATEDSERVER
  885. i = p_ini->Get_Int( INI_SECTION_NAME, "Port", Get_Port());
  886. Set_Port(i);
  887. b = p_ini->Get_Bool( INI_SECTION_NAME, "IsDedicated", IsDedicated.Get());
  888. IsDedicated.Set(b);
  889. #else ////FREEDEDICATEDSERVER
  890. IsDedicated.Set(true);
  891. #endif //FREEDEDICATEDSERVER
  892. b = p_ini->Get_Bool( INI_SECTION_NAME, "IsAutoRestart", IsAutoRestart.Get());
  893. IsAutoRestart.Set(b);
  894. b = p_ini->Get_Bool( INI_SECTION_NAME, "IsPassworded", IsPassworded.Get());
  895. IsPassworded.Set(b);
  896. b = p_ini->Get_Bool( INI_SECTION_NAME, "IsQuickMatch", IsQuickMatchServer.Get());
  897. IsQuickMatchServer.Set(b);
  898. b = p_ini->Get_Bool( INI_SECTION_NAME, "IsLaddered", IsLaddered.Get());
  899. #ifndef FREEDEDICATEDSERVER
  900. b = ((IsQuickMatchServer.Get() == true) ? true : b);
  901. #endif //FREEDEDICATEDSERVER
  902. IsLaddered.Set(b);
  903. b = p_ini->Get_Bool( INI_SECTION_NAME, "IsClanGame", IsClanGame.Get());
  904. #ifndef FREEDEDICATEDSERVER
  905. b = ((IsQuickMatchServer.Get() == true) ? false : b);
  906. #endif /FREEDEDICATEDSERVER
  907. IsClanGame.Set(b);
  908. b = p_ini->Get_Bool( INI_SECTION_NAME, "RemixTeams", RemixTeams.Get());
  909. RemixTeams.Set(b);
  910. b = p_ini->Get_Bool( INI_SECTION_NAME, "CanRepairBuildings", CanRepairBuildings.Get());
  911. CanRepairBuildings.Set(b);
  912. b = p_ini->Get_Bool( INI_SECTION_NAME, "DriverIsAlwaysGunner", DriverIsAlwaysGunner.Get());
  913. DriverIsAlwaysGunner.Set(b);
  914. b = p_ini->Get_Bool( INI_SECTION_NAME, "SpawnWeapons", SpawnWeapons.Get());
  915. SpawnWeapons.Set(b);
  916. //
  917. // Disguise "IsClientTrusted" with something that sounds like you need it but
  918. // that doesn't scream "hack me"
  919. //
  920. //b = p_ini->Get_Bool( INI_SECTION_NAME, "IsClientTrusted", IsClientTrusted.Get());
  921. b = p_ini->Get_Bool( INI_SECTION_NAME, "UseLagReduction", IsClientTrusted.Get());
  922. IsClientTrusted.Set(b);
  923. // Read the 8 bit versions of the strings first and use those as defaults.
  924. p_ini->Get_String(INI_SECTION_NAME, "bGameTitle", "", string8, sizeof(string8));
  925. Set_Game_Title(WideStringClass(string8, true));
  926. p_ini->Get_String(INI_SECTION_NAME, "bMotd", "", string8, sizeof(string8));
  927. Set_Motd(WideStringClass(string8, true));
  928. p_ini->Get_String(INI_SECTION_NAME, "bPassword", "", string8, sizeof(string8));
  929. Set_Password(WideStringClass(string8, true));
  930. p_ini->Get_String(INI_SECTION_NAME, "bConfigName", "", string8, sizeof(string8));
  931. Set_Settings_Description(WideStringClass(string8, true));
  932. // Now read the 16 bit versions as overrides.
  933. WideStringClass wide_string(Get_Game_Title(), true);
  934. p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wGameTitle", wide_string.Peek_Buffer());
  935. Set_Game_Title(wide_string);
  936. wide_string = Get_Password();
  937. p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wPassword", wide_string.Peek_Buffer());
  938. Set_Password(wide_string);
  939. wide_string = Get_Motd();
  940. p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wMotd", wide_string.Peek_Buffer());
  941. Set_Motd(wide_string);
  942. wide_string = Get_Settings_Description();
  943. p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wConfigName", wide_string.Peek_Buffer());
  944. Set_Settings_Description(wide_string);
  945. for (int j = 0; j < MAX_MAPS; j++) {
  946. StringClass item_name(0,true);
  947. item_name.Format("MapName%02d", j);
  948. p_ini->Get_String( INI_SECTION_NAME, item_name, "", map_name, sizeof(map_name));
  949. StringClass map(map_name,true);
  950. MapCycle[j] = map;
  951. }
  952. //char motd[2 * MAX_MOTD_LENGTH];
  953. //p_ini->Get_String( INI_SECTION_NAME, "Motd", "", motd, sizeof(motd));
  954. //if (::strlen(motd) > 0) {
  955. // Motd.Convert_From(motd);
  956. //}
  957. Release_INI(p_ini);
  958. }
  959. //-----------------------------------------------------------------------------
  960. void cGameData::Save_To_Server_Config(LPCSTR config_file)
  961. {
  962. WWASSERT(config_file != NULL);
  963. WWASSERT(cMiscUtil::Is_String_Different(config_file, ""));
  964. INIClass * p_ini = Get_INI(config_file);
  965. WWASSERT(p_ini != NULL);
  966. //
  967. // We can't overwrite entries, so clear them out first.
  968. //
  969. p_ini->Clear(INI_SECTION_NAME);
  970. p_ini->Put_Wide_String( INI_SECTION_NAME, "wConfigName", Get_Settings_Description());
  971. p_ini->Put_Wide_String( INI_SECTION_NAME, "wPassword", Get_Password());
  972. p_ini->Put_String( INI_SECTION_NAME, "MapName", Get_Map_Name());
  973. p_ini->Put_String( INI_SECTION_NAME, "ModName", Get_Mod_Name());
  974. p_ini->Put_Int( INI_SECTION_NAME, "TimeLimitMinutes", Get_Time_Limit_Minutes());
  975. p_ini->Put_Int( INI_SECTION_NAME, "RadarMode", Get_Radar_Mode());
  976. //p_ini->Put_Int( INI_SECTION_NAME, "IntermissionTimeSeconds", Get_Intermission_Time_Seconds());
  977. p_ini->Put_Int( INI_SECTION_NAME, "Port", Get_Port());
  978. p_ini->Put_Bool( INI_SECTION_NAME, "IsDedicated", IsDedicated.Get());
  979. p_ini->Put_Bool( INI_SECTION_NAME, "IsAutoRestart", IsAutoRestart.Get());
  980. p_ini->Put_Bool( INI_SECTION_NAME, "IsPassworded", IsPassworded.Get());
  981. p_ini->Put_Bool( INI_SECTION_NAME, "IsQuickMatch", IsQuickMatchServer.Get());
  982. p_ini->Put_Bool( INI_SECTION_NAME, "IsLaddered", IsLaddered.Get());
  983. p_ini->Put_Bool( INI_SECTION_NAME, "IsClanGame", IsClanGame.Get());
  984. p_ini->Put_Bool( INI_SECTION_NAME, "RemixTeams", RemixTeams.Get());
  985. p_ini->Put_Bool( INI_SECTION_NAME, "CanRepairBuildings", CanRepairBuildings.Get());
  986. p_ini->Put_Bool( INI_SECTION_NAME, "DriverIsAlwaysGunner", DriverIsAlwaysGunner.Get());
  987. p_ini->Put_Bool( INI_SECTION_NAME, "SpawnWeapons", SpawnWeapons.Get());
  988. //p_ini->Put_Bool( INI_SECTION_NAME, "IsClientTrusted", IsClientTrusted.Get());
  989. p_ini->Put_Bool( INI_SECTION_NAME, "UseLagReduction", IsClientTrusted.Get());
  990. p_ini->Put_Wide_String( INI_SECTION_NAME, "wGameTitle", Get_Game_Title());
  991. p_ini->Put_Wide_String( INI_SECTION_NAME, "wMOTD", Get_Motd());
  992. #if (0)
  993. // Save out 8 bit string versions too.
  994. StringClass string8(256, true);
  995. WideStringClass(Get_Game_Title(), true).Convert_To(string8);
  996. p_ini->Put_String( INI_SECTION_NAME, "bGameTitle", string8);
  997. WideStringClass(Get_Motd(), true).Convert_To(string8);
  998. p_ini->Put_String( INI_SECTION_NAME, "bMOTD", string8);
  999. WideStringClass(Get_Password(), true).Convert_To(string8);
  1000. p_ini->Put_String( INI_SECTION_NAME, "bPassword", string8);
  1001. #endif //(0)
  1002. for (int j = 0; j < MAX_MAPS; j++) {
  1003. StringClass item_name(0,true);
  1004. item_name.Format("MapName%02d", j);
  1005. p_ini->Put_String( INI_SECTION_NAME, item_name, MapCycle[j]);
  1006. }
  1007. if (!Motd.Is_Empty()) {
  1008. StringClass motd;
  1009. Motd.Convert_To(motd);
  1010. p_ini->Put_String( INI_SECTION_NAME, "Motd", motd.Peek_Buffer());
  1011. }
  1012. Save_INI(p_ini, config_file);
  1013. Release_INI(p_ini);
  1014. }
  1015. //-----------------------------------------------------------------------------
  1016. void cGameData::Soldier_Added(SoldierGameObj * p_soldier)
  1017. {
  1018. WWASSERT(p_soldier != NULL);
  1019. if (IsFreeWeapons.Is_True() &&
  1020. p_soldier->Get_Player_Type() != PLAYERTYPE_NEUTRAL) {
  1021. p_soldier->Give_All_Weapons();
  1022. int weapon = 0;
  1023. if (p_soldier->Is_Human_Controlled()) {
  1024. weapon = 1;
  1025. } else {
  1026. weapon = 1 + rand() % 7;
  1027. }
  1028. WWASSERT(p_soldier->Get_Weapon_Bag() != NULL);
  1029. p_soldier->Get_Weapon_Bag()->Select_Key_Number(weapon);
  1030. }
  1031. }
  1032. //-----------------------------------------------------------------------------
  1033. void cGameData::Begin_Intermission(void)
  1034. {
  1035. // If we are transitioning from one game to another we must first end the
  1036. // previous game.
  1037. GameModeClass* gameMode = GameModeManager::Find("WOL");
  1038. if (gameMode && gameMode->Is_Active()) {
  1039. WolGameModeClass* wolGame = reinterpret_cast<WolGameModeClass*>(gameMode);
  1040. wolGame->End_Game();
  1041. }
  1042. IsIntermission.Set(true);
  1043. IntermissionTimeRemaining = Get_Intermission_Time_Seconds();
  1044. //
  1045. // Display a dialog with the win information on it
  1046. //
  1047. if (!ConsoleBox.Is_Exclusive()) {
  1048. START_DIALOG (CNCWinScreenMenuClass);
  1049. }
  1050. return ;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. void cGameData::Set_Maximum_World_Distance(float distance)
  1054. {
  1055. //
  1056. // You will typically get this assert if you don't have the level file.
  1057. //
  1058. WWASSERT(distance > 0);
  1059. MaximumWorldDistance = distance;
  1060. }
  1061. //-----------------------------------------------------------------------------
  1062. void cGameData::Set_Min_Qualifying_Time_Minutes(int minutes)
  1063. {
  1064. WWASSERT(minutes >= 0);
  1065. MinQualifyingTimeMinutes = minutes;
  1066. }
  1067. //-----------------------------------------------------------------------------
  1068. int cGameData::Get_Duration_Seconds(void)
  1069. {
  1070. return (int)(TimeLimitMinutes * 60 - TimeRemainingSeconds);
  1071. }
  1072. //-----------------------------------------------------------------------------
  1073. WideStringClass cGameData::Get_Team_Word(void)
  1074. {
  1075. //
  1076. // In clan games, the work "Clan" is used instead of "Team"
  1077. //
  1078. if (IsClanGame.Is_True()) {
  1079. return TRANSLATION(IDS_MP_CLAN);
  1080. } else {
  1081. return TRANSLATION(IDS_MP_TEAM);
  1082. }
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. void cGameData::Set_Time_Remaining_Seconds(float time_remaining_seconds)
  1086. {
  1087. WWASSERT(time_remaining_seconds >= 0);
  1088. TimeRemainingSeconds = time_remaining_seconds;
  1089. }
  1090. //-----------------------------------------------------------------------------
  1091. void cGameData::Reset_Time_Remaining_Seconds(void)
  1092. {
  1093. TimeRemainingSeconds = 60 * TimeLimitMinutes;
  1094. }
  1095. //-----------------------------------------------------------------------------
  1096. float cGameData::Get_Time_Remaining_Seconds(void)
  1097. {
  1098. return TimeRemainingSeconds;
  1099. }
  1100. //-----------------------------------------------------------------------------
  1101. bool cGameData::Is_Valid_Player_Type(int player_type)
  1102. {
  1103. bool is_valid = true;
  1104. if (!Is_Single_Player()) {
  1105. //if (player_type == PLAYERTYPE_RENEGADE &&
  1106. // Is_Team_Game()) {
  1107. if (player_type == PLAYERTYPE_RENEGADE) {
  1108. is_valid = false;
  1109. }
  1110. /*
  1111. if ((player_type == PLAYERTYPE_NOD || player_type == PLAYERTYPE_GDI) &&
  1112. !Is_Team_Game()) {
  1113. is_valid = false;
  1114. }
  1115. */
  1116. }
  1117. return is_valid;
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. int cGameData::Choose_Player_Type(cPlayer* player, int team_choice, bool is_grunt)
  1121. {
  1122. if (IsClanGame.Is_True() && !is_grunt) {
  1123. // Bots are assigned to the smallest team.
  1124. if (player && !player->Is_Human()) {
  1125. int team = Choose_Smallest_Team();
  1126. WWDEBUG_SAY(("CLANS: Bot '%S' assigned to smallest team (%d)\n",
  1127. (const WCHAR*)player->Get_Name(), team));
  1128. return team;
  1129. }
  1130. // If there are other players from the same clan then team up them.
  1131. // Otherwise we must be the first of our clan so select the next available team.
  1132. cPlayer* clanMate = cPlayerManager::Find_Clan_Mate(player);
  1133. if (clanMate) {
  1134. int team = clanMate->Get_Player_Type();
  1135. WWDEBUG_SAY(("CLANS: Player '%S' assigned to team with clanmates (%d)\n",
  1136. (const WCHAR*)player->Get_Name(), team));
  1137. return team;
  1138. } else {
  1139. int team = Choose_Available_Team(team_choice);
  1140. WWDEBUG_SAY(("CLANS: Player '%S' assigned to available team (%d)\n",
  1141. (const WCHAR*)player->Get_Name(), team));
  1142. return team;
  1143. }
  1144. WWDEBUG_SAY(("CLANS: ERROR - Player not assigned to team\n"));
  1145. WWASSERT("ERROR: Player not assigned to team");
  1146. } else {
  1147. if (PLAYERTYPE_RENEGADE == team_choice || IsTeamChangingAllowed.Is_False()) {
  1148. return Choose_Smallest_Team();
  1149. }
  1150. }
  1151. return team_choice;
  1152. }
  1153. int cGameData::Choose_Available_Team(int preference)
  1154. {
  1155. // If the perferred team is available then use it.
  1156. if (preference != -1) {
  1157. cTeam* team = cTeamManager::Find_Team(preference);
  1158. if (team && (team->Tally_Size() == 0)) {
  1159. return team->Get_Id();
  1160. }
  1161. }
  1162. // Find the next available team
  1163. cTeam* team = cTeamManager::Find_Empty_Team();
  1164. if (team) {
  1165. return team->Get_Id();
  1166. }
  1167. WWDEBUG_SAY(("ERROR: No available team found\n"));
  1168. WWASSERT("ERROR: No available team found");
  1169. return -1;
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. int cGameData::Choose_Smallest_Team(void)
  1173. {
  1174. //WWASSERT(Is_Team_Game());
  1175. cTeam * p_team_0 = cTeamManager::Find_Team(0);
  1176. WWASSERT(p_team_0 != NULL);
  1177. cTeam * p_team_1 = cTeamManager::Find_Team(1);
  1178. WWASSERT(p_team_1 != NULL);
  1179. int team = -999;
  1180. int size_team_0 = p_team_0->Tally_Size();
  1181. int size_team_1 = p_team_1->Tally_Size();
  1182. if (size_team_0 < size_team_1) {
  1183. team = p_team_0->Get_Id();
  1184. } else if (size_team_1 < size_team_0) {
  1185. team = p_team_1->Get_Id();
  1186. } else {
  1187. //
  1188. // Both teams are equal in size, so choose the losing team.
  1189. //
  1190. if (p_team_0->Get_Score() < p_team_1->Get_Score()) {
  1191. team = p_team_0->Get_Id();
  1192. } else if (p_team_0->Get_Score() > p_team_1->Get_Score()) {
  1193. team = p_team_1->Get_Id();
  1194. } else {
  1195. //
  1196. // Both teams have the same score. Choose Randomly.
  1197. //
  1198. if (rand() % 2 == 0) {
  1199. team = p_team_0->Get_Id();
  1200. } else {
  1201. team = p_team_1->Get_Id();
  1202. }
  1203. }
  1204. }
  1205. WWASSERT(team != -999);
  1206. return team;
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. bool cGameData::Is_Game_Over(void)
  1210. {
  1211. WWASSERT(cNetwork::I_Am_Server());
  1212. bool is_game_over = false;
  1213. //
  1214. // Games may be manually ended with the "gameover" command.
  1215. //
  1216. if (IsManualRestart) {
  1217. IsManualRestart = false;
  1218. WinType = WIN_TYPE_FORCED;
  1219. is_game_over = true;
  1220. }
  1221. //
  1222. // Games may be ended with the "quit" command.
  1223. //
  1224. if (!is_game_over && IsManualExit) {
  1225. WinType = WIN_TYPE_FORCED;
  1226. is_game_over = true;
  1227. }
  1228. //
  1229. // Time expired?
  1230. //
  1231. if (!is_game_over && Is_Time_Limit() && TimeRemainingSeconds <= WWMATH_EPSILON) {
  1232. WinType = WIN_TYPE_TIME;
  1233. is_game_over = true;
  1234. }
  1235. //
  1236. // If game time has passed but gameplay now pends, end the game
  1237. //
  1238. if (!is_game_over && Get_Game_Duration_S() > 0 && !Is_Gameplay_Permitted()) {
  1239. WinType = WIN_TYPE_FORCED;
  1240. is_game_over = true;
  1241. }
  1242. /*
  1243. //
  1244. // THIS NEEDS REFINEMENT
  1245. //
  1246. // The following test will end a non-mission game when your opponents
  1247. // abandon you. To determine whether any combat has occurred we simply
  1248. // examine the IsBloodShed flag.
  1249. //
  1250. if (!Is_Mission() && IsBloodShed.Is_True() &&
  1251. ((Is_Team_Game() && cTeamManager::Get_Living_Count() <= 1) ||
  1252. (!Is_Team_Game() && cPlayerManager::Get_Living_Count() <= 1))) {
  1253. return true;
  1254. }
  1255. */
  1256. if (is_game_over)
  1257. {
  1258. TimeRemainingSeconds = 0;
  1259. }
  1260. return is_game_over;
  1261. }
  1262. //-----------------------------------------------------------------------------
  1263. bool cGameData::Has_Config_File_Changed(void)
  1264. {
  1265. unsigned long mod_time = Get_Config_File_Mod_Time();
  1266. if (LastServerConfigModTime != mod_time) {
  1267. return(true);
  1268. }
  1269. return(false);
  1270. }
  1271. //-----------------------------------------------------------------------------
  1272. unsigned long cGameData::Get_Config_File_Mod_Time(void)
  1273. {
  1274. StringClass full_filename(IniFilename, true);
  1275. RawFileClass file(full_filename);
  1276. if (!file.Is_Available()) {
  1277. full_filename.Format("data\\%s", IniFilename);
  1278. file.Set_Name(full_filename);
  1279. }
  1280. if (file.Is_Available()) {
  1281. file.Open();
  1282. unsigned long mod_time = file.Get_Date_Time();
  1283. file.Close();
  1284. return(mod_time);
  1285. }
  1286. return(0);
  1287. }
  1288. //-----------------------------------------------------------------------------
  1289. void cGameData::Game_Over_Processing(void)
  1290. {
  1291. WWDEBUG_SAY(("cGameData::Game_Over_Processing\n"));
  1292. WWASSERT(cNetwork::I_Am_Server());
  1293. int winning_team = cTeamManager::Get_Leaders_Id();
  1294. //
  1295. // Reload the game settings if they changed on disk.
  1296. //
  1297. if (Has_Config_File_Changed()) {
  1298. //
  1299. // Verify that the new settings are good.
  1300. //
  1301. cGameDataCnc *test_game_settings = (cGameDataCnc*) Create_Game_Of_Type(cGameData::GAME_TYPE_CNC);
  1302. WWASSERT(test_game_settings != NULL);
  1303. bool ok = false;
  1304. if (test_game_settings) {
  1305. test_game_settings->Set_Ini_Filename(IniFilename);
  1306. test_game_settings->Load_From_Server_Config();
  1307. WideStringClass outMsg;
  1308. ok = test_game_settings->Is_Valid_Settings(outMsg, true);
  1309. delete test_game_settings;
  1310. }
  1311. //
  1312. // If they are good settings then reload them.
  1313. //
  1314. if (ok) {
  1315. ConsoleBox.Print("Game settings changed - realoading settings\n");
  1316. Load_From_Server_Config();
  1317. }
  1318. }
  1319. Rotate_Map();
  1320. cPlayerManager::Increment_Player_Times();
  1321. //
  1322. // Compute the game duration
  1323. //
  1324. DWORD duration_s = (int)((TIMEGETTIME() - GameStartTimeMs) / 1000.0f);
  1325. Set_Game_Duration_S(duration_s);
  1326. //
  1327. // Record the MVP name and track the number of consecutives
  1328. //
  1329. WideStringClass mvp_name = cPlayerManager::Determine_Mvp_Name();
  1330. if (mvp_name.Compare_No_Case(MvpName)) {
  1331. Set_Mvp_Count(1);
  1332. Set_Mvp_Name(cPlayerManager::Determine_Mvp_Name());
  1333. } else {
  1334. Increment_Mvp_Count();
  1335. }
  1336. mWinnerID = winning_team;
  1337. cWinEvent * p_win = new cWinEvent;
  1338. p_win->Init(mWinnerID, PLAYER_ID_UNKNOWN, IsMapCycleOver);
  1339. cPlayerManager::Compute_Ladder_Points(winning_team);
  1340. cTeamManager::Log_Team_List();
  1341. cPlayerManager::Log_Player_List();
  1342. //
  1343. // Results logs wrap back to 1 after 100, and overwrite.
  1344. //
  1345. int log_num = cUserOptions::ResultsLogNumber.Get();
  1346. log_num++;
  1347. if (log_num > 100)
  1348. {
  1349. log_num = 1;
  1350. }
  1351. cUserOptions::ResultsLogNumber.Set(log_num);
  1352. Begin_Intermission();
  1353. }
  1354. //-----------------------------------------------------------------------------
  1355. bool cGameData::Is_Gameplay_Permitted(void)
  1356. {
  1357. bool permitted = true;
  1358. if (IsIntermission.Is_True()) {
  1359. permitted = false;
  1360. }
  1361. if (!GameModeManager::Find ("Combat")->Is_Active ()) {
  1362. permitted = false;
  1363. }
  1364. return permitted;
  1365. }
  1366. void cGameData::Set_Clan(int slot, unsigned long clanID)
  1367. {
  1368. WWASSERT(slot >= 0 && slot < MAX_CLAN_SLOTS);
  1369. mClanSlots[slot] = clanID;
  1370. }
  1371. unsigned long cGameData::Get_Clan(int slot) const
  1372. {
  1373. WWASSERT(slot >= 0 && slot < MAX_CLAN_SLOTS);
  1374. return mClanSlots[slot];
  1375. }
  1376. void cGameData::Clear_Clans(void)
  1377. {
  1378. for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) {
  1379. mClanSlots[slot] = 0;
  1380. }
  1381. }
  1382. int cGameData::Find_Free_Clan_Slot(void) const
  1383. {
  1384. if (IsClanGame.Is_True()) {
  1385. for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) {
  1386. if (mClanSlots[slot] == 0) {
  1387. return slot;
  1388. }
  1389. }
  1390. }
  1391. return -1;
  1392. }
  1393. bool cGameData::Is_Clan_Competing(unsigned long clanID) const
  1394. {
  1395. if (IsClanGame.Is_True() && (clanID != 0)) {
  1396. for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) {
  1397. if (mClanSlots[slot] == clanID) {
  1398. return true;
  1399. }
  1400. }
  1401. }
  1402. return false;
  1403. }
  1404. //-----------------------------------------------------------------------------
  1405. bool cGameData::Is_Clan_Game_Open(void) const
  1406. {
  1407. if (IsClanGame.Is_True()) {
  1408. for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) {
  1409. if (mClanSlots[slot] == 0) {
  1410. return true;
  1411. }
  1412. }
  1413. }
  1414. return false;
  1415. }
  1416. //-----------------------------------------------------------------------------
  1417. cGameData * cGameData::Create_Game_Of_Type(GameTypeEnum game_type)
  1418. {
  1419. /*
  1420. cGameData * p_game_data = NULL;
  1421. switch (game_type) {
  1422. //case GAME_TYPE_DEATHMATCH: p_game_data = new cGameDataDeathMatch; break;
  1423. //case GAME_TYPE_TEAM_DEATHMATCH: p_game_data = new cGameDataTeamDeathMatch; break;
  1424. case GAME_TYPE_CNC: p_game_data = new cGameDataCnc; break;
  1425. default: DIE; break;
  1426. }
  1427. return p_game_data;
  1428. */
  1429. WWASSERT(game_type == GAME_TYPE_CNC);
  1430. return new cGameDataCnc;
  1431. }
  1432. /*
  1433. //-----------------------------------------------------------------------------
  1434. const char* cGameData::Get_Game_Type_Name(GameTypeEnum type)
  1435. {
  1436. static const char* _modeNames[] = {"SP", "SK", "CNC"};
  1437. return _modeNames[type];
  1438. }
  1439. */
  1440. //-----------------------------------------------------------------------------
  1441. const char * cGameData::Get_Game_Type_Name(void) const
  1442. {
  1443. WideStringClass wide_name;
  1444. wide_name.Format(L"%s", Get_Game_Name());
  1445. StringClass name;
  1446. wide_name.Convert_To(name);
  1447. return name.Peek_Buffer();
  1448. }
  1449. //-----------------------------------------------------------------------------
  1450. void cGameData::Add_Bottom_Text(WideStringClass & text)
  1451. {
  1452. //WWASSERT(text != NULL);
  1453. /* WWASSERT(PFont != NULL);
  1454. float x = Render2DClass::Get_Screen_Resolution().Center().X -
  1455. PFont->String_Width(text) / 2.0f;
  1456. float y = MultiHUDClass::Get_Bottom_Text_Y_Pos();
  1457. y -= 1.2 * PFont->Char_Height();
  1458. MultiHUDClass::Set_Bottom_Text_Y_Pos(y);
  1459. WWASSERT(PTextRenderer != NULL);
  1460. PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y)));
  1461. PTextRenderer->Draw_Text(text);
  1462. */
  1463. BottomText.Add(text);
  1464. }
  1465. //-----------------------------------------------------------------------------
  1466. void cGameData::Show_Game_Settings_Limits(void)
  1467. {
  1468. if (PTextRenderer == NULL) {
  1469. return;
  1470. }
  1471. bool changed=false;
  1472. WideStringClass text(0,true);
  1473. unsigned color;
  1474. Get_Time_Limit_Text(text);
  1475. if (text!=renderer_time_text) {
  1476. renderer_time_text=text;
  1477. changed=true;
  1478. }
  1479. // Dedicated server label
  1480. if (cNetwork::I_Am_Only_Server()) {
  1481. Get_Dedicated_Server_Label(text,color);
  1482. }
  1483. else {
  1484. text="";
  1485. color=0;
  1486. }
  1487. if (text!=renderer_dedicated_server_label) {
  1488. renderer_dedicated_server_label=text;
  1489. changed=true;
  1490. }
  1491. if (color!=renderer_dedicated_server_color) {
  1492. renderer_dedicated_server_color=color;
  1493. changed=true;
  1494. }
  1495. // Gameplay pending label -
  1496. bool show_gameplay_label = false;
  1497. if (!Is_Gameplay_Permitted() || (COMBAT_STAR == NULL)) {
  1498. show_gameplay_label = true;
  1499. }
  1500. //if (IsIntermission.Is_False() && (!Is_Gameplay_Permitted() || (COMBAT_STAR == NULL))) {
  1501. if (show_gameplay_label) {
  1502. Get_Gameplay_Not_Permitted_Label(text,color);
  1503. } else {
  1504. text="";
  1505. color=0;
  1506. }
  1507. if (text!=renderer_gameplay_label) {
  1508. renderer_gameplay_label=text;
  1509. changed=true;
  1510. }
  1511. if (color!=renderer_gameplay_color) {
  1512. renderer_gameplay_color=color;
  1513. changed=true;
  1514. }
  1515. if (!changed) {
  1516. if (BottomText.Count()!=OldBottomText.Count()) {
  1517. changed=true;
  1518. }
  1519. else {
  1520. for (int j=0;j<BottomText.Count();++j) {
  1521. if (BottomText[j]!=OldBottomText[j]) {
  1522. changed=true;
  1523. break;
  1524. }
  1525. }
  1526. }
  1527. }
  1528. // Render if needed -------------------------------------------------------
  1529. float charHeight = PTextRenderer->Peek_Font()->Get_Char_Height();
  1530. if (!changed) {
  1531. // Proceed the multihud by one line (as we are caching the time render which would usually do this)
  1532. float y = MultiHUDClass::Get_Bottom_Text_Y_Pos();
  1533. y -= 1.2 * charHeight;
  1534. MultiHUDClass::Set_Bottom_Text_Y_Pos(y);
  1535. BottomText.Reset_Active();
  1536. return;
  1537. }
  1538. // Re-compose the OldBottomText vector
  1539. OldBottomText.Reset_Active();
  1540. for (int j=0;j<BottomText.Count();++j) {
  1541. OldBottomText.Add(BottomText[j]);
  1542. }
  1543. BottomText.Reset_Active();
  1544. PTextRenderer->Reset();
  1545. float x,y;
  1546. // Render bottom text (start with time text, which is to be first)
  1547. Vector2 textExtent = PTextRenderer->Get_Text_Extents(text);
  1548. x = Render2DClass::Get_Screen_Resolution().Center().X - textExtent.X / 2.0f;
  1549. //Always draw on the bottom
  1550. MultiHUDClass::Set_Bottom_Text_Y_Pos( Render2DClass::Get_Screen_Resolution().Bottom - 15 );
  1551. y = MultiHUDClass::Get_Bottom_Text_Y_Pos();
  1552. y -= 1.2 * charHeight;
  1553. Vector2 loc(cMathUtil::Round(x), cMathUtil::Round(y));
  1554. PTextRenderer->Set_Location(loc);
  1555. PTextRenderer->Build_Sentence(renderer_time_text);
  1556. PTextRenderer->Draw_Sentence();
  1557. for (j=0;j<OldBottomText.Count();++j) {
  1558. y -= 1.2 * charHeight;
  1559. loc[1]=cMathUtil::Round(y);
  1560. PTextRenderer->Set_Location(loc);
  1561. PTextRenderer->Build_Sentence(OldBottomText[j]);
  1562. PTextRenderer->Draw_Sentence();
  1563. }
  1564. MultiHUDClass::Set_Bottom_Text_Y_Pos(y);
  1565. // Dedicated server label
  1566. if (cNetwork::I_Am_Only_Server()) {
  1567. Vector2 extent = PTextRenderer->Get_Text_Extents(renderer_dedicated_server_label);
  1568. x = Render2DClass::Get_Screen_Resolution().Center().X - extent.X / 2.0f;
  1569. y = Render2DClass::Get_Screen_Resolution().Center().Y;
  1570. PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y)));
  1571. PTextRenderer->Build_Sentence(renderer_dedicated_server_label);
  1572. PTextRenderer->Draw_Sentence(renderer_dedicated_server_color);
  1573. }
  1574. // Gameplay pending label
  1575. if (show_gameplay_label) {
  1576. Vector2 extent = PTextRenderer->Get_Text_Extents(renderer_gameplay_label);
  1577. x = Render2DClass::Get_Screen_Resolution().Center().X - extent.X / 2.0f;
  1578. y = Render2DClass::Get_Screen_Resolution().Center().Y + 1.2 * charHeight;
  1579. PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y)));
  1580. PTextRenderer->Build_Sentence(renderer_gameplay_label);
  1581. PTextRenderer->Draw_Sentence(color);
  1582. }
  1583. }
  1584. //-----------------------------------------------------------------------------
  1585. void cGameData::Get_Dedicated_Server_Label(WideStringClass& text, unsigned& color)
  1586. {
  1587. color = 0xFFFFFFFF; // white
  1588. if (cMathUtil::Round(TimeManager::Get_Seconds()) % 2 != 0) {
  1589. color = 0xFF00FF00; // green
  1590. }
  1591. text = TRANSLATION(IDS_MP_DEDICATED_SERVER);
  1592. }
  1593. //-----------------------------------------------------------------------------
  1594. void cGameData::Get_Gameplay_Not_Permitted_Label(WideStringClass& text, unsigned& color)
  1595. {
  1596. color = 0xFFFFFFFF; // white
  1597. if (cMathUtil::Round(TimeManager::Get_Seconds()) % 2 != 0) {
  1598. color = 0xFF00FF00; // green
  1599. }
  1600. text = TRANSLATION(IDS_MP_GAMEPLAY_PENDING);
  1601. }
  1602. //-----------------------------------------------------------------------------
  1603. void cGameData::Get_Time_Limit_Text(WideStringClass& text)
  1604. {
  1605. if (IsIntermission.Is_True()) {
  1606. text.Format(
  1607. L"%s: %d",
  1608. TRANSLATION(IDS_MP_NEXTGAME_COUNTDOWN),
  1609. cMathUtil::Round(Get_Intermission_Time_Remaining()));
  1610. } else if (Is_Time_Limit()) {
  1611. int hours = 0;
  1612. int mins = 0;
  1613. int seconds = 0;
  1614. cMiscUtil::Seconds_To_Hms(TimeRemainingSeconds, hours, mins, seconds);
  1615. WideStringClass time_string(0, true);
  1616. time_string.Format(L"%02d:%02d:%02d", hours, mins, seconds);
  1617. text.Format(L"%s: %s", TRANSLATION(IDS_MP_TIME_REMAINING), time_string);
  1618. }
  1619. }
  1620. //-----------------------------------------------------------------------------
  1621. void cGameData::Think(void)
  1622. {
  1623. if (IsIntermission.Is_True()) {
  1624. IntermissionTimeRemaining -= TimeManager::Get_Frame_Real_Seconds();
  1625. if (IntermissionTimeRemaining < 0) {
  1626. IntermissionTimeRemaining = 0;
  1627. }
  1628. } else if (Is_Gameplay_Permitted()) {
  1629. TimeRemainingSeconds -= TimeManager::Get_Frame_Real_Seconds();
  1630. if (TimeRemainingSeconds < 0) {
  1631. TimeRemainingSeconds = 0;
  1632. }
  1633. DWORD duration_s = (int)((TIMEGETTIME() - GameStartTimeMs) / 1000.0f);
  1634. Set_Game_Duration_S(duration_s);
  1635. }
  1636. if (cNetwork::I_Am_Server()) {
  1637. //
  1638. // Update CurrentPlayers
  1639. //
  1640. int max = (int) WWMath::Max(
  1641. cPlayerManager::Count(),
  1642. cNetwork::PServerConnection->Get_Num_RHosts());
  1643. Set_Current_Players(max);
  1644. }
  1645. DEMO_SECURITY_CHECK;
  1646. FrameCount++;
  1647. }
  1648. //-----------------------------------------------------------------------------
  1649. void cGameData::Render(void)
  1650. {
  1651. Show_Game_Settings_Limits();
  1652. if (PTextRenderer != NULL) {
  1653. WWPROFILE("cGameData::Render");
  1654. PTextRenderer->Render();
  1655. }
  1656. }
  1657. //-----------------------------------------------------------------------------
  1658. void cGameData::On_Game_Begin(void)
  1659. {
  1660. //
  1661. // Note, On_Game_Begin happens after load.
  1662. //
  1663. WWDEBUG_SAY(("cGameData::On_Game_Begin\n"));
  1664. GetSystemTime(&GameStartTime);
  1665. FrameCount = 0;
  1666. GameStartTimeMs = TIMEGETTIME();
  1667. //
  1668. // Clear the MVP name
  1669. // Let MVP carry over into next game.
  1670. //
  1671. //MvpName.Format(L"");
  1672. //MvpCount = 0;
  1673. //
  1674. // Reset the game duration
  1675. //
  1676. GameDurationS = 0;
  1677. //
  1678. // Notify the combat layer about various server options
  1679. //
  1680. cCsDamageEvent::Set_Are_Clients_Trusted(IsClientTrusted.Get());
  1681. BuildingGameObj::Set_Can_Repair_Buildings(CanRepairBuildings.Get());
  1682. VehicleGameObj::Set_Default_Driver_Is_Gunner(DriverIsAlwaysGunner.Get());
  1683. CombatManager::Set_Friendly_Fire_Permitted(IsFriendlyFirePermitted.Get());
  1684. CombatManager::Set_Beacon_Placement_Ends_Game(false);
  1685. //
  1686. // Filter out unwanted spawners
  1687. //
  1688. if (cNetwork::I_Am_Server()) {
  1689. Filter_Spawners();
  1690. }
  1691. //
  1692. // Adjust teaming for auto-teamed games
  1693. //
  1694. //if (!IS_MISSION && cNetwork::I_Am_Server() && Is_Team_Game() && IsTeamChangingAllowed.Is_False()) {
  1695. if (!IS_MISSION && cNetwork::I_Am_Server()) {
  1696. if (IsClanGame.Is_False() && IsTeamChangingAllowed.Is_False() && RemixTeams.Is_True()) {
  1697. //
  1698. // Remix Teams if the server option is set.
  1699. //
  1700. Remix_Team_Sides();
  1701. } else {
  1702. //
  1703. // In non-remixed C&C mode, we have a 50-50 chance of the teams being swapped. I prefer this
  1704. // to simply alternating, because if you alternate and the number of maps in the
  1705. // cycle is even, you will always play GDI on the same 50% of the maps.
  1706. //
  1707. if (Is_Skirmish() || (Is_Cnc() && (rand() % 2 == 0))) {
  1708. Swap_Team_Sides();
  1709. }
  1710. }
  1711. if (IsClanGame.Is_False() && IsTeamChangingAllowed.Is_False())
  1712. {
  1713. //
  1714. // We always rebalance the teams numerically
  1715. //
  1716. Rebalance_Team_Sides();
  1717. }
  1718. }
  1719. GameModeClass* gameMode = GameModeManager::Find("WOL");
  1720. if (gameMode && gameMode->Is_Active()) {
  1721. WolGameModeClass* wolGame = reinterpret_cast<WolGameModeClass*>(gameMode);
  1722. WWASSERT(wolGame != NULL);
  1723. wolGame->Start_Game(this);
  1724. }
  1725. }
  1726. //-----------------------------------------------------------------------------
  1727. void cGameData::On_Game_End(void)
  1728. {
  1729. WWDEBUG_SAY(("cGameData::On_Game_End\n"));
  1730. GameModeClass* gameMode = GameModeManager::Find("WOL");
  1731. if (gameMode && gameMode->Is_Active()) {
  1732. WolGameModeClass* wolGame = reinterpret_cast<WolGameModeClass*>(gameMode);
  1733. wolGame->End_Game();
  1734. }
  1735. }
  1736. //-----------------------------------------------------------------------------
  1737. int cGameData::Get_Mission_Number_From_Map_Name( const char * map_name )
  1738. {
  1739. // If tutorial, return tutorial number
  1740. if ( ::strnicmp( map_name, "M00_T", 5 ) == 0 ) {
  1741. #define TUTORIAL_LOAD_MENU_NUMBER 90
  1742. return TUTORIAL_LOAD_MENU_NUMBER;
  1743. }
  1744. // Assume the map name is in the form "mXX.mix" where xx is the level number
  1745. if ( ::strlen( map_name ) > 0 ) {
  1746. return ::atoi( ((const char *)map_name)+1 );
  1747. }
  1748. return 0;
  1749. }
  1750. //-----------------------------------------------------------------------------
  1751. const StringClass& cGameData::Get_Map_Cycle(int map)
  1752. {
  1753. WWASSERT(map >= 0 && map < MAX_MAPS);
  1754. #ifdef MULTIPLAYERDEMO
  1755. MapCycle[map].Format("C&C_Under.mix");
  1756. #endif // MULTIPLAYERDEMO
  1757. return MapCycle[map];
  1758. }
  1759. //-----------------------------------------------------------------------------
  1760. void
  1761. cGameData::Set_Map_Cycle(int map, const StringClass & map_name)
  1762. {
  1763. WWASSERT(map >= 0 && map < MAX_MAPS);
  1764. MapCycle[map] = map_name;
  1765. }
  1766. //-----------------------------------------------------------------------------
  1767. void
  1768. cGameData::Clear_Map_Cycle(void)
  1769. {
  1770. for (int i = 0; i < MAX_MAPS; i++)
  1771. {
  1772. MapCycle[i].Format("");
  1773. }
  1774. }
  1775. //-----------------------------------------------------------------------------
  1776. void
  1777. cGameData::Rotate_Map(void)
  1778. {
  1779. IsMapCycleOver = false;
  1780. //
  1781. // Determine the current map
  1782. //
  1783. int current_map = MapCycleIndex;
  1784. #if (0)
  1785. int current_map = 0;
  1786. for (int i = 0; i < MAX_MAPS; i++)
  1787. {
  1788. if (MapName == MapCycle[i]) {
  1789. current_map = i;
  1790. break;
  1791. }
  1792. }
  1793. #endif //(0)
  1794. //
  1795. // Increment it
  1796. //
  1797. current_map++;
  1798. //
  1799. // Go back to the first map if necessary
  1800. //
  1801. if (current_map >= MAX_MAPS || MapCycle[current_map].Is_Empty()) {
  1802. current_map = 0;
  1803. if (DoMapsLoop == false) {
  1804. IsMapCycleOver = true;
  1805. }
  1806. }
  1807. //
  1808. // Set the map name
  1809. //
  1810. #ifdef MULTIPLAYERDEMO
  1811. MapName.Format("C&C_Under.mix");
  1812. #else
  1813. MapName = MapCycle[current_map];
  1814. #endif
  1815. MapCycleIndex = current_map;
  1816. return ;
  1817. }
  1818. //-----------------------------------------------------------------------------
  1819. void cGameData::Set_Win_Text(WideStringClass & text)
  1820. {
  1821. WinText = text;
  1822. }
  1823. //-----------------------------------------------------------------------------
  1824. void cGameData::ReceiveSignal(MPChooseTeamSignal& choice)
  1825. {
  1826. if (choice.GetItemA() == true) {
  1827. //
  1828. // Do nothing if the player selected 'auto' rather than GDI or NOD.
  1829. //
  1830. if (choice.GetItemB() != PLAYERTYPE_RENEGADE) {
  1831. cNetwork::SwitchTeam(choice.GetItemB());
  1832. }
  1833. }
  1834. }
  1835. //-----------------------------------------------------------------------------
  1836. void cGameData::Filter_Spawners(void)
  1837. {
  1838. WWASSERT(cNetwork::I_Am_Server());
  1839. if (SpawnWeapons.Is_False()) {
  1840. //
  1841. // Disable multiplay weapons spawners
  1842. //
  1843. DynamicVectorClass<SpawnerClass*> spawner_list = SpawnManager::Get_Spawner_List();
  1844. for (int i = 0; i < spawner_list.Count(); i++) {
  1845. WWASSERT(spawner_list[i] != NULL);
  1846. if (spawner_list[i]->Get_Definition().Is_Multiplay_Weapon_Spawner()) {
  1847. spawner_list[i]->Enable(false);
  1848. }
  1849. }
  1850. }
  1851. }
  1852. //------------------------------------------------------------------------------------
  1853. void cGameData::Set_Mvp_Name(const WideStringClass name)
  1854. {
  1855. MvpName = name;
  1856. }
  1857. //------------------------------------------------------------------------------------
  1858. void cGameData::Set_Mvp_Count(int count)
  1859. {
  1860. WWASSERT(count >= 0);
  1861. MvpCount = count;
  1862. }
  1863. //------------------------------------------------------------------------------------
  1864. void cGameData::Set_Win_Type(WinTypeEnum type)
  1865. {
  1866. WinType = type;
  1867. }
  1868. //------------------------------------------------------------------------------------
  1869. void cGameData::Set_Game_Duration_S(DWORD seconds)
  1870. {
  1871. GameDurationS = seconds;
  1872. }
  1873. //-----------------------------------------------------------------------------
  1874. void cGameData::Get_Description(WideStringClass & description)
  1875. {
  1876. const WideStringClass delimiter = L"\t";
  1877. const WideStringClass newline = L"\n";
  1878. const WideStringClass yes = TRANSLATE(IDS_YES);
  1879. const WideStringClass no = TRANSLATE(IDS_NO);
  1880. WideStringClass attribute(0, true);
  1881. WideStringClass value(0, true);
  1882. //
  1883. // Host
  1884. //
  1885. attribute = TRANSLATE(IDS_MP_HOST);
  1886. value = Owner;
  1887. description += (attribute + delimiter + value + newline);
  1888. //
  1889. // Game Name
  1890. //
  1891. attribute = TRANSLATE(IDS_MENU_TEXT292);
  1892. value = GameTitle;
  1893. description += (attribute + delimiter + value + newline);
  1894. //
  1895. // Map Name
  1896. //
  1897. if (ModName.Is_Empty () == false) {
  1898. attribute = L"Mod Name:";
  1899. value = ModName;
  1900. description += (attribute + delimiter + value + newline);
  1901. }
  1902. //
  1903. // Map Name
  1904. //
  1905. attribute = TRANSLATE(IDS_MP_GAME_LIST_HEADER_GAME_MAP);
  1906. value = MapName;
  1907. description += (attribute + delimiter + value + newline);
  1908. //
  1909. // Time Limit
  1910. //
  1911. attribute = TRANSLATE(IDS_MENU_TEXT298);
  1912. if (Is_Time_Limit()) {
  1913. value.Format(L"%d %s", TimeLimitMinutes, TRANSLATE(IDS_MP_MINUTES));
  1914. } else {
  1915. value = TRANSLATE(IDS_MP_NONE);
  1916. }
  1917. description += (attribute + delimiter + value + newline);
  1918. //
  1919. // Max. Players
  1920. //
  1921. attribute = TRANSLATE(IDS_MENU_TEXT294);
  1922. value.Format(L"%d", MaxPlayers);
  1923. description += (attribute + delimiter + value + newline);
  1924. //
  1925. // Radar
  1926. //
  1927. attribute = TRANSLATE(IDS_MENU_TEXT488);
  1928. switch (RadarMode) {
  1929. case RADAR_NOBODY:
  1930. value = TRANSLATION(IDS_MP_RADAR_MODE_NOBODY);
  1931. break;
  1932. case RADAR_TEAMMATES:
  1933. value = TRANSLATION(IDS_MP_RADAR_MODE_TEAMMATES);
  1934. break;
  1935. case RADAR_ALL:
  1936. value = TRANSLATION(IDS_MP_RADAR_MODE_ALL);
  1937. break;
  1938. default:
  1939. DIE;
  1940. }
  1941. description += (attribute + delimiter + value + newline);
  1942. //
  1943. // Allow Quickmatching
  1944. //
  1945. attribute = TRANSLATE(IDS_MENU_TEXT584);
  1946. value = (IsQuickMatchServer.Get() ? yes : no);
  1947. description += (attribute + delimiter + value + newline);
  1948. //
  1949. // Dedicated
  1950. //
  1951. attribute = TRANSLATE(IDS_MENU_TEXT309);
  1952. value = (IsDedicated.Get() ? yes : no);
  1953. description += (attribute + delimiter + value + newline);
  1954. //
  1955. // Friendly Fire
  1956. //
  1957. attribute = TRANSLATE(IDS_MENU_TEXT301);
  1958. value = (IsFriendlyFirePermitted.Get() ? yes : no);
  1959. description += (attribute + delimiter + value + newline);
  1960. //
  1961. // Manual Teaming
  1962. //
  1963. attribute = TRANSLATE(IDS_MENU_TEXT490);
  1964. value = (IsTeamChangingAllowed.Get() ? yes : no);
  1965. description += (attribute + delimiter + value + newline);
  1966. //
  1967. // Passworded
  1968. //
  1969. attribute = TRANSLATE(IDS_MP_PASSWORDED);
  1970. value = (IsPassworded.Get() ? yes : no);
  1971. description += (attribute + delimiter + value + newline);
  1972. //
  1973. // Laddered
  1974. //
  1975. attribute = TRANSLATE(IDS_MENU_TEXT496);
  1976. value = (IsLaddered.Get() ? yes : no);
  1977. description += (attribute + delimiter + value + newline);
  1978. //
  1979. // Clan Game
  1980. //
  1981. attribute = TRANSLATE(IDS_MENU_TEXT497);
  1982. value = (IsClanGame.Get() ? yes : no);
  1983. description += (attribute + delimiter + value + newline);
  1984. /*
  1985. //
  1986. // Trust Clients
  1987. //
  1988. attribute = TRANSLATE(IDS_MENU_TEXT585);
  1989. value = (IsClientTrusted.Get() ? yes : no);
  1990. description += (attribute + delimiter + value + newline);
  1991. */
  1992. //
  1993. // Remix Teams
  1994. //
  1995. attribute = TRANSLATE(IDS_MENU_TEXT587);
  1996. value = (RemixTeams.Get() ? yes : no);
  1997. description += (attribute + delimiter + value + newline);
  1998. //
  1999. // Can Repair Buildings
  2000. //
  2001. attribute = TRANSLATE(IDS_MENU_TEXT590);
  2002. value = (CanRepairBuildings.Get() ? yes : no);
  2003. description += (attribute + delimiter + value + newline);
  2004. //
  2005. // Driver Is Always Gunner
  2006. //
  2007. attribute = TRANSLATE(IDS_MENU_TEXT591);
  2008. value = (DriverIsAlwaysGunner.Get() ? yes : no);
  2009. description += (attribute + delimiter + value + newline);
  2010. //
  2011. // Weapon spawning
  2012. //
  2013. attribute = TRANSLATE(IDS_MENU_TEXT592);
  2014. value = (SpawnWeapons.Get() ? yes : no);
  2015. description += (attribute + delimiter + value + newline);
  2016. }
  2017. //-----------------------------------------------------------------------------
  2018. //cGameData * The_Game(void) {WWASSERT(PTheGameData != NULL); return PTheGameData;}
  2019. cGameData * The_Game(void) {return PTheGameData;}
  2020. cGameDataSinglePlayer * The_Single_Player_Game(void) {WWASSERT(The_Game()->As_Single_Player() != NULL); return The_Game()->As_Single_Player();}
  2021. cGameDataSkirmish * The_Skirmish_Game(void) {WWASSERT(The_Game()->As_Skirmish() != NULL); return The_Game()->As_Skirmish();}
  2022. cGameDataCnc * The_Cnc_Game(void) {WWASSERT(The_Game()->As_Cnc() != NULL); return The_Game()->As_Cnc();}
  2023. /*
  2024. if (Is_Team_Game()) {
  2025. has_opponents =
  2026. cPlayerManager::Get_Count(PLAYERTYPE_NOD) > 0 &&
  2027. cPlayerManager::Get_Count(PLAYERTYPE_GDI) > 0;
  2028. } else {
  2029. has_opponents = (cPlayerManager::Get_Count(PLAYERTYPE_RENEGADE) > 1);
  2030. }
  2031. */
  2032. /*
  2033. //-----------------------------------------------------------------------------
  2034. void cGameData::Set_Min_Game_Time_Required_Mins(int mins)
  2035. {
  2036. WWASSERT(mins >= 0 );
  2037. MinGameTimeRequiredMins = mins;
  2038. }
  2039. */
  2040. /*
  2041. //-----------------------------------------------------------------------------
  2042. void cGameData::Set_Full_Score_Time_Threshold_Mins(int mins)
  2043. {
  2044. WWASSERT(mins >= 0);
  2045. FullScoreTimeThresholdMins = mins;
  2046. }
  2047. */
  2048. //#include "helptext.h"
  2049. //#include "gddeathmatch.h"
  2050. //#include "gdteamdeathmatch.h"
  2051. //MinGameTimeRequiredMins = 10;
  2052. //FullScoreTimeThresholdMins = 30;
  2053. //MinGameTimeRequiredMins = rhs.MinGameTimeRequiredMins;
  2054. //FullScoreTimeThresholdMins = rhs.FullScoreTimeThresholdMins;
  2055. //packet.Add(MinGameTimeRequiredMins);
  2056. //packet.Add(FullScoreTimeThresholdMins);
  2057. //Set_Min_Game_Time_Required_Mins( packet.Get(i_placeholder));
  2058. //Set_Full_Score_Time_Threshold_Mins( packet.Get(i_placeholder));
  2059. //cGameDataDeathMatch * The_Deathmatch_Game(void) {WWASSERT(The_Game()->As_Deathmatch() != NULL); return The_Game()->As_Deathmatch();}
  2060. //cGameDataTeamDeathMatch * The_Team_Deathmatch_Game(void) {WWASSERT(The_Game()->As_Team_Deathmatch() != NULL); return The_Game()->As_Team_Deathmatch();}
  2061. //if (Is_Team_Game()) {
  2062. /*
  2063. } else {
  2064. has_opponents = (cPlayerManager::Tally_Team_Size(PLAYERTYPE_RENEGADE) > 1);
  2065. }
  2066. */
  2067. //IsBloodShed.Set( false);
  2068. //IsBloodShed = rhs.IsBloodShed;
  2069. /*
  2070. if (cNetwork::I_Am_Server()) {
  2071. IsBloodShed.Set(false);
  2072. }
  2073. */