/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando * * * * $Archive:: /Commando/Code/Commando/gamedata.cpp $* * * * $Author:: Steve_t $* * * * $Modtime:: 11/01/02 4:32p $* * * * $Revision:: 221 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "gamedata.h" #include #include #include "win.h" #include "miscutil.h" #include "cnetwork.h" #include "chatshre.h" #include "wwdebug.h" #include "netinterface.h" #include "translatedb.h" #include "playertype.h" #include "teammanager.h" #include "playermanager.h" #include "assets.h" #include "translatedb.h" #include "string_ids.h" #include "gamemode.h" #include "savegame.h" #include "bandwidth.h" #include "gametype.h" #include "systimer.h" #include "objlibrary.h" #include "scriptzone.h" #include "aabox.h" #include "rendobj.h" #include "weaponbag.h" #include "multihud.h" #include "wwaudio.h" #include "textdisplay.h" #include "render2d.h" #include "render2dsentence.h" #include "wwprofile.h" #include "winevent.h" #include "realcrc.h" #include "useroptions.h" #include "gdsingleplayer.h" #include "gdcnc.h" #include "wolgmode.h" #include "font3d.h" #include "nat.h" #include "csdamageevent.h" #include "sctextobj.h" #include "widestring.h" #include "vehicle.h" #include "wolgameinfo.h" #include "spawn.h" #include "dlgcncwinscreen.h" #include "dialogmgr.h" #include "rawfile.h" #include "consolemode.h" #include "gamedataupdateevent.h" #include "stylemgr.h" #include "modpackagemgr.h" #include "modpackage.h" #include "bandwidthcheck.h" #include "serversettings.h" #include "gamespyadmin.h" #include "specialbuilds.h" #include "demosupport.h" #include "specialbuilds.h" const int cGameData::MAX_TIME_LIMIT = 999; cGameData * PTheGameData = NULL; static WideStringClass renderer_time_text; static WideStringClass renderer_dedicated_server_label; static WideStringClass renderer_gameplay_label; static unsigned renderer_dedicated_server_color; static unsigned renderer_gameplay_color; // // Class statics // const StringClass cGameData::INI_SECTION_NAME = "Settings"; const float cGameData::LIMITS_X_POS = 0.8f; Render2DSentenceClass * cGameData::PTextRenderer = NULL; int cGameData::HostedGameNumber = 0; bool cGameData::IsManualRestart = false; bool cGameData::IsManualExit = false; WideStringClass cGameData::WinText; // // hack // ULONG g_ip_override = INADDR_NONE; //------------------------------------------------------------------------------------ void cGameData::Onetime_Init(void) { WWDEBUG_SAY(("cGameData::Onetime_Init\n")); if (!ConsoleBox.Is_Exclusive()) { PTextRenderer = new Render2DSentenceClass; StyleMgrClass::Assign_Font(PTextRenderer, StyleMgrClass::FONT_INGAME_TXT); PTextRenderer->Set_Mono_Spaced(true); PTextRenderer->Set_Clipping_Rect(Render2DClass::Get_Screen_Resolution()); } } //------------------------------------------------------------------------------------ void cGameData::Onetime_Shutdown(void) { WWDEBUG_SAY(("cGameData::Onetime_Shutdown\n")); if (!ConsoleBox.Is_Exclusive()) { WWASSERT(PTextRenderer != NULL); delete PTextRenderer; PTextRenderer = NULL; } } //----------------------------------------------------------------------------- cGameData::cGameData(void) : DoExeVersionsMatch (true), DoStringVersionsMatch (true), DoMapsLoop (true), IsMapCycleOver (false), MapCycleIndex(0) { //WWDEBUG_SAY(("cGameData::cGameData\n")); IsIntermission.Set( false); IsDedicated.Set( false); IsAutoRestart.Set( false); IsFriendlyFirePermitted.Set( false); IsTeamChangingAllowed.Set( true); IsPassworded.Set( false); IsFreeWeapons.Set( false); IsLaddered.Set( false); IsClanGame.Set( false); IsClientTrusted.Set( true); RemixTeams.Set( false); CanRepairBuildings.Set( true); DriverIsAlwaysGunner.Set( true); SpawnWeapons.Set( false); mWinnerID = -1; MaxPlayers = 16; TimeLimitMinutes = 0; RadarMode = RADAR_ALL; IniFilename = ""; Motd.Format(L""); Set_Password( L""); //Set_Owner( "UNOWNED"); Set_Owner( cNetInterface::Get_Nickname()); IntermissionTimeSeconds = 15; Set_Version_Number( cNetwork::Get_Exe_Key()); Set_Ip_Address(0); Set_Port( 4848);//TSS - hardcoded port Set_Current_Players(0); IntermissionTimeRemaining = 0; TimeRemainingSeconds = 0; MaximumWorldDistance = 0; MinQualifyingTimeMinutes = 2; IsQuickMatchServer = false; //ServerIsGameplayPermitted = false; WinType = WIN_TYPE_TIME; GameDurationS = 0; LastServerConfigModTime = 0; SettingsDescription = TRANSLATE(IDS_SERVER_SAVELOAD_CUSTOM_DEFAULT); Clear_Clans(); MvpCount = 0; #ifdef MULTIPLAYERDEMO MapName.Format("C&C_Under.mix"); #endif // MULTIPLAYERDEMO } //----------------------------------------------------------------------------- cGameData::~cGameData(void) { //WWDEBUG_SAY(("cGameData::~cGameData\n")); } //----------------------------------------------------------------------------- cGameData& cGameData::operator=(const cGameData& rhs) { IsIntermission = rhs.IsIntermission; IsDedicated = rhs.IsDedicated; IsAutoRestart = rhs.IsAutoRestart; IsFriendlyFirePermitted = rhs.IsFriendlyFirePermitted; IsTeamChangingAllowed = rhs.IsTeamChangingAllowed; IsPassworded = rhs.IsPassworded; IsFreeWeapons = rhs.IsFreeWeapons; IsLaddered = rhs.IsLaddered; IsClanGame = rhs.IsClanGame; IsClientTrusted = rhs.IsClientTrusted; RemixTeams = rhs.RemixTeams; CanRepairBuildings = rhs.CanRepairBuildings; DriverIsAlwaysGunner = rhs.DriverIsAlwaysGunner; SpawnWeapons = rhs.SpawnWeapons; Password = rhs.Password; GameTitle = rhs.GameTitle; Motd = rhs.Motd; #ifdef MULTIPLAYERDEMO MapName.Format("C&C_Under.mix"); #else MapName = rhs.MapName; ModName = rhs.ModName; #endif Owner = rhs.Owner; MaxPlayers = rhs.MaxPlayers; TimeLimitMinutes = rhs.TimeLimitMinutes; IntermissionTimeSeconds = rhs.IntermissionTimeSeconds; VersionNumber = rhs.VersionNumber; IpAddress = rhs.IpAddress; Port = rhs.Port; IniFilename = rhs.IniFilename; RadarMode = rhs.RadarMode; CurrentPlayers = rhs.CurrentPlayers; IntermissionTimeRemaining = rhs.IntermissionTimeRemaining; TimeRemainingSeconds = rhs.TimeRemainingSeconds; MaximumWorldDistance = rhs.MaximumWorldDistance; MinQualifyingTimeMinutes = rhs.MinQualifyingTimeMinutes; for (int clanSlot = 0; clanSlot < MAX_CLAN_SLOTS; ++clanSlot) { mClanSlots[clanSlot] = rhs.mClanSlots[clanSlot]; } return (*this); } //----------------------------------------------------------------------------- void cGameData::Reset_Game(bool is_reloaded) { WWDEBUG_SAY(("cGameData::Reset_Game\n")); // // Game_Reset is called on both C & S at the beginning of every game. // mWinnerID = -1; IsIntermission.Set(false); // // 12/11/01 // This dialog flush was added to remove the purchase screen because it persists // over reload. // if (GameModeManager::Find ("Combat")->Is_Active ()) { if (GameModeManager::Find ("Menu")->Is_Active ()) { GameModeManager::Find ("Menu")->Deactivate (); } else { DialogMgrClass::Flush_Dialogs (); } } if (Get_Text_Display()) { WWASSERT(Get_Text_Display() != NULL); Get_Text_Display()->Flush(); } if (!IS_MISSION) { WWAudioClass::Get_Instance()->Create_Instant_Sound("Game_Start", Matrix3D(1)); } //TSS092601 if ( !is_reloaded ) { if ( !IS_MISSION || !is_reloaded ) { cPlayerManager::Reset_Players(); } //} cTeamManager::Reset_Teams(); if (Is_Time_Limit()) { Reset_Time_Remaining_Seconds(); if (cNetwork::I_Am_Server()) { cGameDataUpdateEvent * p_event = new cGameDataUpdateEvent(); p_event->Init(-1); } } if (cNetwork::I_Am_Server()) { HostedGameNumber++; } } //----------------------------------------------------------------------------- void cGameData::Swap_Team_Sides(void) { //WWASSERT(Is_Team_Game()); WWASSERT(cNetwork::I_Am_Server()); for ( SLNode * player_node = cPlayerManager::Get_Player_Object_List()->Head(); player_node; player_node = player_node->Next()) { cPlayer * p_player = player_node->Data(); WWASSERT(p_player != NULL); int team = p_player->Get_Player_Type(); WWASSERT(team == PLAYERTYPE_NOD || team == PLAYERTYPE_GDI); int new_team = PLAYERTYPE_NOD; if (team == PLAYERTYPE_NOD) { new_team = PLAYERTYPE_GDI; } else { new_team = PLAYERTYPE_NOD; } p_player->Set_Player_Type(new_team); } // // Inform the players // //WideStringClass text; //text.Format(L"_TEAMS_SWAPPED_!_"); WideStringClass text = TRANSLATE(IDS_MP_TEAMS_SWAPPED); cScTextObj * p_text_obj = new cScTextObj(); p_text_obj->Init(text, TEXT_MESSAGE_PUBLIC, false, HOST_TEXT_SENDER, -1); } //----------------------------------------------------------------------------- void cGameData::Remix_Team_Sides(void) { //WWASSERT(Is_Team_Game()); WWASSERT(cNetwork::I_Am_Server()); WWASSERT(IsClanGame.Is_False() && "Remix teams not allowed"); if (IsClanGame.Is_True()) { return; } // // Randomly choose a team for each player // for ( SLNode * player_node = cPlayerManager::Get_Player_Object_List()->Head(); player_node; player_node = player_node->Next()) { cPlayer * p_player = player_node->Data(); WWASSERT(p_player != NULL); int new_team = PLAYERTYPE_NOD; if (rand() % 2 == 0) { new_team = PLAYERTYPE_GDI; } else { new_team = PLAYERTYPE_NOD; } p_player->Set_Player_Type(new_team); } // // Inform the players // //WideStringClass text; //text.Format(L"_TEAMS_REMIXED_!_"); WideStringClass text = TRANSLATE(IDS_MP_TEAMS_REMIXED); cScTextObj * p_text_obj = new cScTextObj(); p_text_obj->Init(text, TEXT_MESSAGE_PUBLIC, false, HOST_TEXT_SENDER, -1); } //----------------------------------------------------------------------------- void cGameData::Rebalance_Team_Sides(void) { //WWASSERT(Is_Team_Game()); WWASSERT(cNetwork::I_Am_Server()); WWASSERT(IsClanGame.Is_False() && "Rebalance teams not allowed"); if (IsClanGame.Is_True()) { return; } // // Rebalance teams numerically // cTeam * p_nod = cTeamManager::Find_Team(PLAYERTYPE_NOD); WWASSERT(p_nod != NULL); cTeam * p_gdi = cTeamManager::Find_Team(PLAYERTYPE_GDI); WWASSERT(p_gdi != NULL); int move_count = 0; int nod_tally = 0; int gdi_tally = 0; do { nod_tally = p_nod->Tally_Size(); gdi_tally = p_gdi->Tally_Size(); if (nod_tally > gdi_tally + 1) { cPlayer * p_player = cPlayerManager::Find_Team_Player(PLAYERTYPE_NOD); WWASSERT(p_player != NULL); p_player->Set_Player_Type(PLAYERTYPE_GDI); move_count++; } else if (gdi_tally > nod_tally + 1) { cPlayer * p_player = cPlayerManager::Find_Team_Player(PLAYERTYPE_GDI); WWASSERT(p_player != NULL); p_player->Set_Player_Type(PLAYERTYPE_NOD); move_count++; } } while (::abs(nod_tally - gdi_tally) > 1); if (move_count > 0) { // // Inform the players // //WideStringClass text; //text.Format(L"_TEAMS_REBALANCED_!_"); WideStringClass text = TRANSLATE(IDS_MP_TEAMS_REBALANCED); cScTextObj * p_text_obj = new cScTextObj(); p_text_obj->Init(text, TEXT_MESSAGE_PUBLIC, false, HOST_TEXT_SENDER, -1); } } //----------------------------------------------------------------------------- void cGameData::Set_Ip_And_Port(void) { /* SOCKADDR_IN local_address; bool retcode = cNetUtil::Get_Local_Address(&local_address); WWASSERT(retcode == true); // // hack // if (g_ip_override != INADDR_NONE) { local_address.sin_addr.s_addr = g_ip_override; } Set_Ip_Address(local_address.sin_addr.s_addr); */ ULONG ip = 0; if (cGameSpyAdmin::Get_Is_Server_Gamespy_Listed()) { ip = cUserOptions::PreferredGameSpyNic.Get(); } else { ip = cUserOptions::PreferredLanNic.Get(); } if (g_ip_override != INADDR_NONE) { ip = g_ip_override; } // // IP is set automatically in WOL unless there is an IP override and a port overrride. // if (GameModeManager::Find("WOL")->Is_Active()) { if (g_ip_override == INADDR_NONE || WOLNATInterface.Get_Force_Port() == 0) { unsigned long temp = FirewallHelper.Get_Local_Address(); if (temp) { //ip = temp; ip = ::ntohl(temp); } } } //WWASSERT(ip != 0); Set_Ip_Address(ip); } //----------------------------------------------------------------------------- // // A convenience function... // bool cGameData::Set_Generic_Num(int generic_num, int lower_bound, int upper_bound, int & set_num) { if (generic_num >= lower_bound && generic_num <= upper_bound) { set_num = generic_num; return true; } else { return false; } } //----------------------------------------------------------------------------- bool cGameData::Set_Max_Players(int max) { return Set_Generic_Num(max, 0, MAX_PLAYERS, MaxPlayers); } //----------------------------------------------------------------------------- bool cGameData::Set_Time_Limit_Minutes(int time_limit_minutes) { return Set_Generic_Num(time_limit_minutes, 0, MAX_TIME_LIMIT, TimeLimitMinutes); } //----------------------------------------------------------------------------- void cGameData::Set_Radar_Mode(RadarModeEnum mode) { RadarMode = mode; } //----------------------------------------------------------------------------- void cGameData::Set_Intermission_Time_Seconds(int time) { WWASSERT(time >= 0); IntermissionTimeSeconds = time; } //----------------------------------------------------------------------------- void cGameData::Set_Motd(const WCHAR * motd) { WWASSERT(motd != NULL); Motd = motd; } //----------------------------------------------------------------------------- void cGameData::Set_Mod_Name(const StringClass &mod_name) { ModName = mod_name; ModPackageMgrClass::Set_Current_Package (ModName); return ; } //----------------------------------------------------------------------------- void cGameData::Set_Map_Name(const StringClass & map_name) { #ifdef MULTIPLAYERDEMO MapName.Format("C&C_Under.mix"); #else MapName = map_name; #endif } //----------------------------------------------------------------------------- bool cGameData::Set_Current_Players(int current) { return Set_Generic_Num(current, 0, MAX_PLAYERS, CurrentPlayers); } //----------------------------------------------------------------------------- void cGameData::Set_Owner(WideStringClass & owner) { Owner = owner; } //----------------------------------------------------------------------------- void cGameData::Set_Ip_Address(ULONG ip_address) { IpAddress = ip_address; } //----------------------------------------------------------------------------- void cGameData::Set_Port(int port) { WWASSERT(port >= MIN_SERVER_PORT && port <= MAX_SERVER_PORT); Port = port; } //----------------------------------------------------------------------------- bool cGameData::Is_Limited(void) const { return Is_Time_Limit(); } //----------------------------------------------------------------------------- bool cGameData::Is_Map_Valid(char **out_filename) { bool map_exists = false; if (ModName.Is_Empty () == false) { if (out_filename) { *out_filename = ModName.Peek_Buffer(); } map_exists = cMiscUtil::File_Exists (ModName); } else { if (out_filename) { *out_filename = MapName.Peek_Buffer(); } map_exists = cMiscUtil::File_Exists (MapName); } return(map_exists); } #define PRINT_CONFIG_ERROR ConsoleBox.Print("File %s - Error:\r\n\t ", Get_Ini_Filename()); //----------------------------------------------------------------------------- bool cGameData::Is_Valid_Settings(WideStringClass& outMsg, bool check_as_server) { if (MapName.Is_Empty()) { //cHelpText::Set(TRANSLATION(IDS_MP_NO_LEVEL_SELECTED)); Debug_Say(( "cGameData::No level file selected.\n" )); PRINT_CONFIG_ERROR; ConsoleBox.Print("No initial level file selected\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_NO_LEVEL); return false; } else { // // Test to see whether or not the map exists // char *filename = NULL; if (!Is_Map_Valid(&filename)) { Debug_Say(("cGameData::Is_Valid_Settings: Level \"%s\" not found\n", filename)); PRINT_CONFIG_ERROR; ConsoleBox.Print("Map file '%s' not found\n\n", filename); outMsg.Format(TRANSLATE(IDS_HOPTERR_MAP_NOTFOUND), filename); return(false); } } if (IsPassworded.Is_True() && Password.Get_Length () == 0) { //cHelpText::Set(TRANSLATION(IDS_MP_BLANK_PASSWORD_ILLEGAL)); Debug_Say(( "cGameData::Is_Valid_Settings: You can not use a blank password.\n" )); PRINT_CONFIG_ERROR; ConsoleBox.Print("Blank passwords are not allowed\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_BLANK_PASS); return false; } #ifndef FREEDEDICATEDSERVER if (GameModeManager::Find("WOL")->Is_Active()) { #endif //FREEDEDICATEDSERVER if (IsPassworded.Is_True() && Is_QuickMatch_Server()) { Debug_Say(("cGameData::Is_Valid_Settings: Quickmatch can not have passwords.\n" )); PRINT_CONFIG_ERROR; ConsoleBox.Print("A password cannot be used on a Quickmatch server\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_QM_HASPASS); return false; } if (Is_QuickMatch_Server() && IsLaddered.Is_False()) { Debug_Say(("cGameData::Is_Valid_Settings: Quickmatch must be laddered.\n" )); PRINT_CONFIG_ERROR; ConsoleBox.Print("A Quickmatch server must also be laddered\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_QM_NOLADDER); return false; } if (Is_QuickMatch_Server() && IsClanGame.Is_True()) { Debug_Say(("cGameData::Is_Valid_Settings: Quickmatch cannot be clanned.\n" )); PRINT_CONFIG_ERROR; ConsoleBox.Print("Clans are not allowed in a quickmatch server\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_QM_NOCLANS); return false; } if (IsLaddered.Is_True() && IsTeamChangingAllowed.Is_True()) { PRINT_CONFIG_ERROR; ConsoleBox.Print("Team changing not allowed on a laddered server\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_NO_TEAMCHANGE); return false; } if (IsClanGame.Is_True() && (IsTeamChangingAllowed.Is_True() || RemixTeams.Is_True())) { PRINT_CONFIG_ERROR; ConsoleBox.Print("Team changing or Team Remix not allowed on a clan game server.\n"); outMsg = "Team changing or Team Remix not allowed on a clan game server."; //TRANSLATE(IDS_HOPTERR_NO_TEAMCHANGE); return false; } #ifndef FREEDEDICATEDSERVER } #endif //FREEDEDICATEDSERVER #ifdef FREEDEDICATEDSERVER if (Get_Max_Players() == 0 && ServerSettingsClass::Get_Game_Mode() != ServerSettingsClass::MODE_WOL) { #else if (Get_Max_Players() == 0) { #endif PRINT_CONFIG_ERROR; ConsoleBox.Print("Max player count must be greater than 0\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_MAXPLAYER_0); return(false); } // Check server only parameters if (check_as_server || ConsoleBox.Is_Exclusive()) { if (Get_Max_Players() > NetworkObjectClass::MAX_CLIENT_COUNT-1) { PRINT_CONFIG_ERROR; ConsoleBox.Print("Max player count must be less than %d\n\n", NetworkObjectClass::MAX_CLIENT_COUNT); outMsg.Format(TRANSLATE(IDS_HOPTERR_MAXPLAYER_TOOBIG), NetworkObjectClass::MAX_CLIENT_COUNT); return(false); } if (DoMapsLoop && Get_Map_Cycle(0).Get_Length() == 0) { PRINT_CONFIG_ERROR; ConsoleBox.Print("Map cycling is enabled but there are no maps in the cycle\n\n"); outMsg = TRANSLATE(IDS_HOPTERR_NO_MAPCYCLE); return(false); } /* ** Make sure all the maps exist. */ if (DoMapsLoop && ModName.Is_Empty ()) { for (int i=0 ; i MAX_MOTD_LENGTH) { PRINT_CONFIG_ERROR; ConsoleBox.Print("Message of the day cannot exceed %d characters\n\n", MAX_MOTD_LENGTH); outMsg.Format(TRANSLATE(IDS_HOPTERR_MOTD_TOOBIG), MAX_MOTD_LENGTH); return false; } /* ** Check the game title for length. The buffers are pretty much all 256 bytes but 100 seems a more reasonable figure. */ if (GameTitle.Get_Length() > 100) { PRINT_CONFIG_ERROR; ConsoleBox.Print("Game title cannot exceed %d characters\n\n", 100); outMsg.Format(TRANSLATE(IDS_HOPTERR_TITLE_TOOBIG), 100); return false; } } return true; // it's valid ! } //----------------------------------------------------------------------------- // // Server options are exported in 2 tiers. Tier 1 is the basic parameters // that show up in the list of games. Tier 2 is the remainder of the full // set of server settings. // void cGameData::Export_Tier_1_Data(cPacket & packet) { packet.Add(IpAddress); packet.Add_Wide_Terminated_String(Owner); packet.Add_Wide_Terminated_String(GameTitle, true); packet.Add(Port); packet.Add(CurrentPlayers); packet.Add(MaxPlayers); packet.Add(VersionNumber); // // Send the individual CRC's (for internal use) // packet.Add(cNetwork::Get_Exe_CRC ()); packet.Add(cNetwork::Get_Strings_CRC ()); packet.Add(IsDedicated.Get()); packet.Add(IsTeamChangingAllowed.Get()); packet.Add(IsPassworded.Get()); packet.Add(IsLaddered.Get()); packet.Add(IsClanGame.Get()); #ifndef MULTIPLAYERDEMO packet.Add(::CRC_Stringi(MapName)); packet.Add(::CRC_Stringi(ModName)); #endif // MULTIPLAYERDEMO } //----------------------------------------------------------------------------- void cGameData::Import_Tier_1_Data(cPacket & packet) { ULONG ip_address = packet.Get(ip_address); Set_Ip_Address(ip_address); WideStringClass owner; packet.Get_Wide_Terminated_String(owner.Get_Buffer(256), 256); Set_Owner(owner); WideStringClass title; packet.Get_Wide_Terminated_String(title.Get_Buffer(256), 256, true); Set_Game_Title(title); int i_placeholder; bool b_placeholder; Set_Port( packet.Get(i_placeholder)); Set_Current_Players( packet.Get(i_placeholder)); Set_Max_Players( packet.Get(i_placeholder)); Set_Version_Number( packet.Get(i_placeholder)); // // Compare the individual CRC's against our own // DoExeVersionsMatch = (packet.Get(i_placeholder) == cNetwork::Get_Exe_CRC ()); DoStringVersionsMatch = (packet.Get(i_placeholder) == cNetwork::Get_Strings_CRC ()); IsDedicated.Set( packet.Get(b_placeholder)); IsTeamChangingAllowed.Set( packet.Get(b_placeholder)); IsPassworded.Set( packet.Get(b_placeholder)); IsLaddered.Set( packet.Get(b_placeholder)); IsClanGame.Set( packet.Get(b_placeholder)); #ifndef MULTIPLAYERDEMO // // Get the CRC of the map and the mod // ULONG map_name_crc = packet.Get(map_name_crc); ULONG mod_name_crc = packet.Get(mod_name_crc); // // Determine what the name of the mod and the map are from their CRC's // StringClass mod_name(0,true); StringClass map_name(0,true); if (ModPackageMgrClass::Get_Mod_Map_Name_From_CRC (mod_name_crc, map_name_crc, &mod_name, &map_name)) { Set_Mod_Name (mod_name); Set_Map_Name (map_name); } else { ModName = L""; MapName = L""; } #endif // MULTIPLAYERDEMO return ; } //----------------------------------------------------------------------------- bool cGameData::Does_Map_Exist (void) { bool retval = true; // // If the map and mod names are empty then it is due to the fact // that we couldn't find the map and/or mod when we looked // if (ModName.Is_Empty () && MapName.Is_Empty ()) { retval = false; } return retval; } //----------------------------------------------------------------------------- void cGameData::Import_Tier_1_Data(const WOLGameInfo& gameInfo) { Set_Map_Name(gameInfo.MapName()); Set_Mod_Name(gameInfo.ModName()); WideStringClass title(0, true); title.Convert_From(gameInfo.Title()); Set_Game_Title(title); Set_Max_Players(gameInfo.MaxPlayers()); Set_Current_Players(gameInfo.NumPlayers()); // Set game flags IsDedicated.Set(gameInfo.IsDedicated()); IsPassworded.Set(gameInfo.IsPassworded()); IsLaddered.Set(gameInfo.IsLaddered()); IsFriendlyFirePermitted.Set(gameInfo.IsFriendlyFire()); IsFreeWeapons.Set(gameInfo.IsFreeWeapons()); RemixTeams.Set(gameInfo.IsTeamRemix()); IsTeamChangingAllowed.Set(gameInfo.IsTeamChange()); IsClanGame.Set(gameInfo.IsClanGame()); IsQuickMatchServer = gameInfo.IsQuickmatch(); CanRepairBuildings.Set(gameInfo.IsRepairBuildings()); DriverIsAlwaysGunner.Set(gameInfo.IsDriverGunner()); SpawnWeapons.Set(gameInfo.IsSpawnWeapons()); Clear_Clans(); mClanSlots[0] = gameInfo.ClanID1(); mClanSlots[1] = gameInfo.ClanID2(); } //----------------------------------------------------------------------------- void cGameData::Export_Tier_2_Data(cPacket & packet) { packet.Add(TimeLimitMinutes); packet.Add((int) RadarMode); packet.Add(IntermissionTimeSeconds); packet.Add(MinQualifyingTimeMinutes); packet.Add(IsFriendlyFirePermitted.Get()); packet.Add(IsFreeWeapons.Get()); packet.Add(IsClientTrusted.Get()); packet.Add(RemixTeams.Get()); if (Is_Cnc()) { packet.Add(CanRepairBuildings.Get()); packet.Add(DriverIsAlwaysGunner.Get()); packet.Add(SpawnWeapons.Get()); } packet.Add_Wide_Terminated_String(Motd, true); } //----------------------------------------------------------------------------- void cGameData::Import_Tier_2_Data(cPacket & packet) { int i_placeholder = 0; bool b_placeholder = false; Set_Time_Limit_Minutes( packet.Get(i_placeholder)); Set_Radar_Mode((RadarModeEnum) packet.Get(i_placeholder)); Set_Intermission_Time_Seconds( packet.Get(i_placeholder)); Set_Min_Qualifying_Time_Minutes( packet.Get(i_placeholder)); IsFriendlyFirePermitted.Set( packet.Get(b_placeholder)); IsFreeWeapons.Set( packet.Get(b_placeholder)); IsClientTrusted.Set( packet.Get(b_placeholder)); RemixTeams.Set( packet.Get(b_placeholder)); if (Is_Cnc()) { CanRepairBuildings.Set( packet.Get(b_placeholder)); DriverIsAlwaysGunner.Set( packet.Get(b_placeholder)); SpawnWeapons.Set( packet.Get(b_placeholder)); } WideStringClass motd; packet.Get_Wide_Terminated_String(motd.Get_Buffer(MAX_MOTD_LENGTH), MAX_MOTD_LENGTH, true); Set_Motd(motd); } //----------------------------------------------------------------------------- void cGameData::Load_From_Server_Config(LPCSTR config_file) { WWASSERT(config_file != NULL); WWASSERT(cMiscUtil::Is_String_Different(config_file, "")); INIClass * p_ini = Get_INI(config_file); StringClass full_filename(config_file, true); if (p_ini == NULL) { full_filename.Format("data\\%s", config_file); FILE * file = fopen(full_filename, "w"); fclose(file); p_ini = Get_INI(config_file); } WWASSERT(p_ini != NULL); LastServerConfigModTime = Get_Config_File_Mod_Time(); char map_name[MAX_MAPNAME_SIZE]; char mod_name[MAX_MAPNAME_SIZE]; char string8[256]; bool b; int i; //float f; //p_ini->Get_String( INI_SECTION_NAME, "Password", Get_Password(), password, sizeof(password)); //Set_Password(password); p_ini->Get_String( INI_SECTION_NAME, "MapName", "", map_name, sizeof(map_name)); StringClass map(map_name,true); Set_Map_Name(map); p_ini->Get_String( INI_SECTION_NAME, "ModName", "", mod_name, sizeof(mod_name)); StringClass mod(mod_name,true); Set_Mod_Name(mod); i = p_ini->Get_Int( INI_SECTION_NAME, "TimeLimitMinutes", Get_Time_Limit_Minutes()); Set_Time_Limit_Minutes(i); i = p_ini->Get_Int( INI_SECTION_NAME, "RadarMode", Get_Radar_Mode()); Set_Radar_Mode((RadarModeEnum) i); //i = p_ini->Get_Int( INI_SECTION_NAME, "IntermissionTimeSeconds", Get_Intermission_Time_Seconds()); //Set_Intermission_Time_Seconds(i); #ifndef FREEDEDICATEDSERVER i = p_ini->Get_Int( INI_SECTION_NAME, "Port", Get_Port()); Set_Port(i); b = p_ini->Get_Bool( INI_SECTION_NAME, "IsDedicated", IsDedicated.Get()); IsDedicated.Set(b); #else ////FREEDEDICATEDSERVER IsDedicated.Set(true); #endif //FREEDEDICATEDSERVER b = p_ini->Get_Bool( INI_SECTION_NAME, "IsAutoRestart", IsAutoRestart.Get()); IsAutoRestart.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "IsPassworded", IsPassworded.Get()); IsPassworded.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "IsQuickMatch", IsQuickMatchServer.Get()); IsQuickMatchServer.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "IsLaddered", IsLaddered.Get()); #ifndef FREEDEDICATEDSERVER b = ((IsQuickMatchServer.Get() == true) ? true : b); #endif //FREEDEDICATEDSERVER IsLaddered.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "IsClanGame", IsClanGame.Get()); #ifndef FREEDEDICATEDSERVER b = ((IsQuickMatchServer.Get() == true) ? false : b); #endif /FREEDEDICATEDSERVER IsClanGame.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "RemixTeams", RemixTeams.Get()); RemixTeams.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "CanRepairBuildings", CanRepairBuildings.Get()); CanRepairBuildings.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "DriverIsAlwaysGunner", DriverIsAlwaysGunner.Get()); DriverIsAlwaysGunner.Set(b); b = p_ini->Get_Bool( INI_SECTION_NAME, "SpawnWeapons", SpawnWeapons.Get()); SpawnWeapons.Set(b); // // Disguise "IsClientTrusted" with something that sounds like you need it but // that doesn't scream "hack me" // //b = p_ini->Get_Bool( INI_SECTION_NAME, "IsClientTrusted", IsClientTrusted.Get()); b = p_ini->Get_Bool( INI_SECTION_NAME, "UseLagReduction", IsClientTrusted.Get()); IsClientTrusted.Set(b); // Read the 8 bit versions of the strings first and use those as defaults. p_ini->Get_String(INI_SECTION_NAME, "bGameTitle", "", string8, sizeof(string8)); Set_Game_Title(WideStringClass(string8, true)); p_ini->Get_String(INI_SECTION_NAME, "bMotd", "", string8, sizeof(string8)); Set_Motd(WideStringClass(string8, true)); p_ini->Get_String(INI_SECTION_NAME, "bPassword", "", string8, sizeof(string8)); Set_Password(WideStringClass(string8, true)); p_ini->Get_String(INI_SECTION_NAME, "bConfigName", "", string8, sizeof(string8)); Set_Settings_Description(WideStringClass(string8, true)); // Now read the 16 bit versions as overrides. WideStringClass wide_string(Get_Game_Title(), true); p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wGameTitle", wide_string.Peek_Buffer()); Set_Game_Title(wide_string); wide_string = Get_Password(); p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wPassword", wide_string.Peek_Buffer()); Set_Password(wide_string); wide_string = Get_Motd(); p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wMotd", wide_string.Peek_Buffer()); Set_Motd(wide_string); wide_string = Get_Settings_Description(); p_ini->Get_Wide_String(wide_string, INI_SECTION_NAME, "wConfigName", wide_string.Peek_Buffer()); Set_Settings_Description(wide_string); for (int j = 0; j < MAX_MAPS; j++) { StringClass item_name(0,true); item_name.Format("MapName%02d", j); p_ini->Get_String( INI_SECTION_NAME, item_name, "", map_name, sizeof(map_name)); StringClass map(map_name,true); MapCycle[j] = map; } //char motd[2 * MAX_MOTD_LENGTH]; //p_ini->Get_String( INI_SECTION_NAME, "Motd", "", motd, sizeof(motd)); //if (::strlen(motd) > 0) { // Motd.Convert_From(motd); //} Release_INI(p_ini); } //----------------------------------------------------------------------------- void cGameData::Save_To_Server_Config(LPCSTR config_file) { WWASSERT(config_file != NULL); WWASSERT(cMiscUtil::Is_String_Different(config_file, "")); INIClass * p_ini = Get_INI(config_file); WWASSERT(p_ini != NULL); // // We can't overwrite entries, so clear them out first. // p_ini->Clear(INI_SECTION_NAME); p_ini->Put_Wide_String( INI_SECTION_NAME, "wConfigName", Get_Settings_Description()); p_ini->Put_Wide_String( INI_SECTION_NAME, "wPassword", Get_Password()); p_ini->Put_String( INI_SECTION_NAME, "MapName", Get_Map_Name()); p_ini->Put_String( INI_SECTION_NAME, "ModName", Get_Mod_Name()); p_ini->Put_Int( INI_SECTION_NAME, "TimeLimitMinutes", Get_Time_Limit_Minutes()); p_ini->Put_Int( INI_SECTION_NAME, "RadarMode", Get_Radar_Mode()); //p_ini->Put_Int( INI_SECTION_NAME, "IntermissionTimeSeconds", Get_Intermission_Time_Seconds()); p_ini->Put_Int( INI_SECTION_NAME, "Port", Get_Port()); p_ini->Put_Bool( INI_SECTION_NAME, "IsDedicated", IsDedicated.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "IsAutoRestart", IsAutoRestart.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "IsPassworded", IsPassworded.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "IsQuickMatch", IsQuickMatchServer.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "IsLaddered", IsLaddered.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "IsClanGame", IsClanGame.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "RemixTeams", RemixTeams.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "CanRepairBuildings", CanRepairBuildings.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "DriverIsAlwaysGunner", DriverIsAlwaysGunner.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "SpawnWeapons", SpawnWeapons.Get()); //p_ini->Put_Bool( INI_SECTION_NAME, "IsClientTrusted", IsClientTrusted.Get()); p_ini->Put_Bool( INI_SECTION_NAME, "UseLagReduction", IsClientTrusted.Get()); p_ini->Put_Wide_String( INI_SECTION_NAME, "wGameTitle", Get_Game_Title()); p_ini->Put_Wide_String( INI_SECTION_NAME, "wMOTD", Get_Motd()); #if (0) // Save out 8 bit string versions too. StringClass string8(256, true); WideStringClass(Get_Game_Title(), true).Convert_To(string8); p_ini->Put_String( INI_SECTION_NAME, "bGameTitle", string8); WideStringClass(Get_Motd(), true).Convert_To(string8); p_ini->Put_String( INI_SECTION_NAME, "bMOTD", string8); WideStringClass(Get_Password(), true).Convert_To(string8); p_ini->Put_String( INI_SECTION_NAME, "bPassword", string8); #endif //(0) for (int j = 0; j < MAX_MAPS; j++) { StringClass item_name(0,true); item_name.Format("MapName%02d", j); p_ini->Put_String( INI_SECTION_NAME, item_name, MapCycle[j]); } if (!Motd.Is_Empty()) { StringClass motd; Motd.Convert_To(motd); p_ini->Put_String( INI_SECTION_NAME, "Motd", motd.Peek_Buffer()); } Save_INI(p_ini, config_file); Release_INI(p_ini); } //----------------------------------------------------------------------------- void cGameData::Soldier_Added(SoldierGameObj * p_soldier) { WWASSERT(p_soldier != NULL); if (IsFreeWeapons.Is_True() && p_soldier->Get_Player_Type() != PLAYERTYPE_NEUTRAL) { p_soldier->Give_All_Weapons(); int weapon = 0; if (p_soldier->Is_Human_Controlled()) { weapon = 1; } else { weapon = 1 + rand() % 7; } WWASSERT(p_soldier->Get_Weapon_Bag() != NULL); p_soldier->Get_Weapon_Bag()->Select_Key_Number(weapon); } } //----------------------------------------------------------------------------- void cGameData::Begin_Intermission(void) { // If we are transitioning from one game to another we must first end the // previous game. GameModeClass* gameMode = GameModeManager::Find("WOL"); if (gameMode && gameMode->Is_Active()) { WolGameModeClass* wolGame = reinterpret_cast(gameMode); wolGame->End_Game(); } IsIntermission.Set(true); IntermissionTimeRemaining = Get_Intermission_Time_Seconds(); // // Display a dialog with the win information on it // if (!ConsoleBox.Is_Exclusive()) { START_DIALOG (CNCWinScreenMenuClass); } return ; } //----------------------------------------------------------------------------- void cGameData::Set_Maximum_World_Distance(float distance) { // // You will typically get this assert if you don't have the level file. // WWASSERT(distance > 0); MaximumWorldDistance = distance; } //----------------------------------------------------------------------------- void cGameData::Set_Min_Qualifying_Time_Minutes(int minutes) { WWASSERT(minutes >= 0); MinQualifyingTimeMinutes = minutes; } //----------------------------------------------------------------------------- int cGameData::Get_Duration_Seconds(void) { return (int)(TimeLimitMinutes * 60 - TimeRemainingSeconds); } //----------------------------------------------------------------------------- WideStringClass cGameData::Get_Team_Word(void) { // // In clan games, the work "Clan" is used instead of "Team" // if (IsClanGame.Is_True()) { return TRANSLATION(IDS_MP_CLAN); } else { return TRANSLATION(IDS_MP_TEAM); } } //----------------------------------------------------------------------------- void cGameData::Set_Time_Remaining_Seconds(float time_remaining_seconds) { WWASSERT(time_remaining_seconds >= 0); TimeRemainingSeconds = time_remaining_seconds; } //----------------------------------------------------------------------------- void cGameData::Reset_Time_Remaining_Seconds(void) { TimeRemainingSeconds = 60 * TimeLimitMinutes; } //----------------------------------------------------------------------------- float cGameData::Get_Time_Remaining_Seconds(void) { return TimeRemainingSeconds; } //----------------------------------------------------------------------------- bool cGameData::Is_Valid_Player_Type(int player_type) { bool is_valid = true; if (!Is_Single_Player()) { //if (player_type == PLAYERTYPE_RENEGADE && // Is_Team_Game()) { if (player_type == PLAYERTYPE_RENEGADE) { is_valid = false; } /* if ((player_type == PLAYERTYPE_NOD || player_type == PLAYERTYPE_GDI) && !Is_Team_Game()) { is_valid = false; } */ } return is_valid; } //----------------------------------------------------------------------------- int cGameData::Choose_Player_Type(cPlayer* player, int team_choice, bool is_grunt) { if (IsClanGame.Is_True() && !is_grunt) { // Bots are assigned to the smallest team. if (player && !player->Is_Human()) { int team = Choose_Smallest_Team(); WWDEBUG_SAY(("CLANS: Bot '%S' assigned to smallest team (%d)\n", (const WCHAR*)player->Get_Name(), team)); return team; } // If there are other players from the same clan then team up them. // Otherwise we must be the first of our clan so select the next available team. cPlayer* clanMate = cPlayerManager::Find_Clan_Mate(player); if (clanMate) { int team = clanMate->Get_Player_Type(); WWDEBUG_SAY(("CLANS: Player '%S' assigned to team with clanmates (%d)\n", (const WCHAR*)player->Get_Name(), team)); return team; } else { int team = Choose_Available_Team(team_choice); WWDEBUG_SAY(("CLANS: Player '%S' assigned to available team (%d)\n", (const WCHAR*)player->Get_Name(), team)); return team; } WWDEBUG_SAY(("CLANS: ERROR - Player not assigned to team\n")); WWASSERT("ERROR: Player not assigned to team"); } else { if (PLAYERTYPE_RENEGADE == team_choice || IsTeamChangingAllowed.Is_False()) { return Choose_Smallest_Team(); } } return team_choice; } int cGameData::Choose_Available_Team(int preference) { // If the perferred team is available then use it. if (preference != -1) { cTeam* team = cTeamManager::Find_Team(preference); if (team && (team->Tally_Size() == 0)) { return team->Get_Id(); } } // Find the next available team cTeam* team = cTeamManager::Find_Empty_Team(); if (team) { return team->Get_Id(); } WWDEBUG_SAY(("ERROR: No available team found\n")); WWASSERT("ERROR: No available team found"); return -1; } //----------------------------------------------------------------------------- int cGameData::Choose_Smallest_Team(void) { //WWASSERT(Is_Team_Game()); cTeam * p_team_0 = cTeamManager::Find_Team(0); WWASSERT(p_team_0 != NULL); cTeam * p_team_1 = cTeamManager::Find_Team(1); WWASSERT(p_team_1 != NULL); int team = -999; int size_team_0 = p_team_0->Tally_Size(); int size_team_1 = p_team_1->Tally_Size(); if (size_team_0 < size_team_1) { team = p_team_0->Get_Id(); } else if (size_team_1 < size_team_0) { team = p_team_1->Get_Id(); } else { // // Both teams are equal in size, so choose the losing team. // if (p_team_0->Get_Score() < p_team_1->Get_Score()) { team = p_team_0->Get_Id(); } else if (p_team_0->Get_Score() > p_team_1->Get_Score()) { team = p_team_1->Get_Id(); } else { // // Both teams have the same score. Choose Randomly. // if (rand() % 2 == 0) { team = p_team_0->Get_Id(); } else { team = p_team_1->Get_Id(); } } } WWASSERT(team != -999); return team; } //----------------------------------------------------------------------------- bool cGameData::Is_Game_Over(void) { WWASSERT(cNetwork::I_Am_Server()); bool is_game_over = false; // // Games may be manually ended with the "gameover" command. // if (IsManualRestart) { IsManualRestart = false; WinType = WIN_TYPE_FORCED; is_game_over = true; } // // Games may be ended with the "quit" command. // if (!is_game_over && IsManualExit) { WinType = WIN_TYPE_FORCED; is_game_over = true; } // // Time expired? // if (!is_game_over && Is_Time_Limit() && TimeRemainingSeconds <= WWMATH_EPSILON) { WinType = WIN_TYPE_TIME; is_game_over = true; } // // If game time has passed but gameplay now pends, end the game // if (!is_game_over && Get_Game_Duration_S() > 0 && !Is_Gameplay_Permitted()) { WinType = WIN_TYPE_FORCED; is_game_over = true; } /* // // THIS NEEDS REFINEMENT // // The following test will end a non-mission game when your opponents // abandon you. To determine whether any combat has occurred we simply // examine the IsBloodShed flag. // if (!Is_Mission() && IsBloodShed.Is_True() && ((Is_Team_Game() && cTeamManager::Get_Living_Count() <= 1) || (!Is_Team_Game() && cPlayerManager::Get_Living_Count() <= 1))) { return true; } */ if (is_game_over) { TimeRemainingSeconds = 0; } return is_game_over; } //----------------------------------------------------------------------------- bool cGameData::Has_Config_File_Changed(void) { unsigned long mod_time = Get_Config_File_Mod_Time(); if (LastServerConfigModTime != mod_time) { return(true); } return(false); } //----------------------------------------------------------------------------- unsigned long cGameData::Get_Config_File_Mod_Time(void) { StringClass full_filename(IniFilename, true); RawFileClass file(full_filename); if (!file.Is_Available()) { full_filename.Format("data\\%s", IniFilename); file.Set_Name(full_filename); } if (file.Is_Available()) { file.Open(); unsigned long mod_time = file.Get_Date_Time(); file.Close(); return(mod_time); } return(0); } //----------------------------------------------------------------------------- void cGameData::Game_Over_Processing(void) { WWDEBUG_SAY(("cGameData::Game_Over_Processing\n")); WWASSERT(cNetwork::I_Am_Server()); int winning_team = cTeamManager::Get_Leaders_Id(); // // Reload the game settings if they changed on disk. // if (Has_Config_File_Changed()) { // // Verify that the new settings are good. // cGameDataCnc *test_game_settings = (cGameDataCnc*) Create_Game_Of_Type(cGameData::GAME_TYPE_CNC); WWASSERT(test_game_settings != NULL); bool ok = false; if (test_game_settings) { test_game_settings->Set_Ini_Filename(IniFilename); test_game_settings->Load_From_Server_Config(); WideStringClass outMsg; ok = test_game_settings->Is_Valid_Settings(outMsg, true); delete test_game_settings; } // // If they are good settings then reload them. // if (ok) { ConsoleBox.Print("Game settings changed - realoading settings\n"); Load_From_Server_Config(); } } Rotate_Map(); cPlayerManager::Increment_Player_Times(); // // Compute the game duration // DWORD duration_s = (int)((TIMEGETTIME() - GameStartTimeMs) / 1000.0f); Set_Game_Duration_S(duration_s); // // Record the MVP name and track the number of consecutives // WideStringClass mvp_name = cPlayerManager::Determine_Mvp_Name(); if (mvp_name.Compare_No_Case(MvpName)) { Set_Mvp_Count(1); Set_Mvp_Name(cPlayerManager::Determine_Mvp_Name()); } else { Increment_Mvp_Count(); } mWinnerID = winning_team; cWinEvent * p_win = new cWinEvent; p_win->Init(mWinnerID, PLAYER_ID_UNKNOWN, IsMapCycleOver); cPlayerManager::Compute_Ladder_Points(winning_team); cTeamManager::Log_Team_List(); cPlayerManager::Log_Player_List(); // // Results logs wrap back to 1 after 100, and overwrite. // int log_num = cUserOptions::ResultsLogNumber.Get(); log_num++; if (log_num > 100) { log_num = 1; } cUserOptions::ResultsLogNumber.Set(log_num); Begin_Intermission(); } //----------------------------------------------------------------------------- bool cGameData::Is_Gameplay_Permitted(void) { bool permitted = true; if (IsIntermission.Is_True()) { permitted = false; } if (!GameModeManager::Find ("Combat")->Is_Active ()) { permitted = false; } return permitted; } void cGameData::Set_Clan(int slot, unsigned long clanID) { WWASSERT(slot >= 0 && slot < MAX_CLAN_SLOTS); mClanSlots[slot] = clanID; } unsigned long cGameData::Get_Clan(int slot) const { WWASSERT(slot >= 0 && slot < MAX_CLAN_SLOTS); return mClanSlots[slot]; } void cGameData::Clear_Clans(void) { for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) { mClanSlots[slot] = 0; } } int cGameData::Find_Free_Clan_Slot(void) const { if (IsClanGame.Is_True()) { for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) { if (mClanSlots[slot] == 0) { return slot; } } } return -1; } bool cGameData::Is_Clan_Competing(unsigned long clanID) const { if (IsClanGame.Is_True() && (clanID != 0)) { for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) { if (mClanSlots[slot] == clanID) { return true; } } } return false; } //----------------------------------------------------------------------------- bool cGameData::Is_Clan_Game_Open(void) const { if (IsClanGame.Is_True()) { for (int slot = 0; slot < MAX_CLAN_SLOTS; ++slot) { if (mClanSlots[slot] == 0) { return true; } } } return false; } //----------------------------------------------------------------------------- cGameData * cGameData::Create_Game_Of_Type(GameTypeEnum game_type) { /* cGameData * p_game_data = NULL; switch (game_type) { //case GAME_TYPE_DEATHMATCH: p_game_data = new cGameDataDeathMatch; break; //case GAME_TYPE_TEAM_DEATHMATCH: p_game_data = new cGameDataTeamDeathMatch; break; case GAME_TYPE_CNC: p_game_data = new cGameDataCnc; break; default: DIE; break; } return p_game_data; */ WWASSERT(game_type == GAME_TYPE_CNC); return new cGameDataCnc; } /* //----------------------------------------------------------------------------- const char* cGameData::Get_Game_Type_Name(GameTypeEnum type) { static const char* _modeNames[] = {"SP", "SK", "CNC"}; return _modeNames[type]; } */ //----------------------------------------------------------------------------- const char * cGameData::Get_Game_Type_Name(void) const { WideStringClass wide_name; wide_name.Format(L"%s", Get_Game_Name()); StringClass name; wide_name.Convert_To(name); return name.Peek_Buffer(); } //----------------------------------------------------------------------------- void cGameData::Add_Bottom_Text(WideStringClass & text) { //WWASSERT(text != NULL); /* WWASSERT(PFont != NULL); float x = Render2DClass::Get_Screen_Resolution().Center().X - PFont->String_Width(text) / 2.0f; float y = MultiHUDClass::Get_Bottom_Text_Y_Pos(); y -= 1.2 * PFont->Char_Height(); MultiHUDClass::Set_Bottom_Text_Y_Pos(y); WWASSERT(PTextRenderer != NULL); PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y))); PTextRenderer->Draw_Text(text); */ BottomText.Add(text); } //----------------------------------------------------------------------------- void cGameData::Show_Game_Settings_Limits(void) { if (PTextRenderer == NULL) { return; } bool changed=false; WideStringClass text(0,true); unsigned color; Get_Time_Limit_Text(text); if (text!=renderer_time_text) { renderer_time_text=text; changed=true; } // Dedicated server label if (cNetwork::I_Am_Only_Server()) { Get_Dedicated_Server_Label(text,color); } else { text=""; color=0; } if (text!=renderer_dedicated_server_label) { renderer_dedicated_server_label=text; changed=true; } if (color!=renderer_dedicated_server_color) { renderer_dedicated_server_color=color; changed=true; } // Gameplay pending label - bool show_gameplay_label = false; if (!Is_Gameplay_Permitted() || (COMBAT_STAR == NULL)) { show_gameplay_label = true; } //if (IsIntermission.Is_False() && (!Is_Gameplay_Permitted() || (COMBAT_STAR == NULL))) { if (show_gameplay_label) { Get_Gameplay_Not_Permitted_Label(text,color); } else { text=""; color=0; } if (text!=renderer_gameplay_label) { renderer_gameplay_label=text; changed=true; } if (color!=renderer_gameplay_color) { renderer_gameplay_color=color; changed=true; } if (!changed) { if (BottomText.Count()!=OldBottomText.Count()) { changed=true; } else { for (int j=0;jPeek_Font()->Get_Char_Height(); if (!changed) { // Proceed the multihud by one line (as we are caching the time render which would usually do this) float y = MultiHUDClass::Get_Bottom_Text_Y_Pos(); y -= 1.2 * charHeight; MultiHUDClass::Set_Bottom_Text_Y_Pos(y); BottomText.Reset_Active(); return; } // Re-compose the OldBottomText vector OldBottomText.Reset_Active(); for (int j=0;jReset(); float x,y; // Render bottom text (start with time text, which is to be first) Vector2 textExtent = PTextRenderer->Get_Text_Extents(text); x = Render2DClass::Get_Screen_Resolution().Center().X - textExtent.X / 2.0f; //Always draw on the bottom MultiHUDClass::Set_Bottom_Text_Y_Pos( Render2DClass::Get_Screen_Resolution().Bottom - 15 ); y = MultiHUDClass::Get_Bottom_Text_Y_Pos(); y -= 1.2 * charHeight; Vector2 loc(cMathUtil::Round(x), cMathUtil::Round(y)); PTextRenderer->Set_Location(loc); PTextRenderer->Build_Sentence(renderer_time_text); PTextRenderer->Draw_Sentence(); for (j=0;jSet_Location(loc); PTextRenderer->Build_Sentence(OldBottomText[j]); PTextRenderer->Draw_Sentence(); } MultiHUDClass::Set_Bottom_Text_Y_Pos(y); // Dedicated server label if (cNetwork::I_Am_Only_Server()) { Vector2 extent = PTextRenderer->Get_Text_Extents(renderer_dedicated_server_label); x = Render2DClass::Get_Screen_Resolution().Center().X - extent.X / 2.0f; y = Render2DClass::Get_Screen_Resolution().Center().Y; PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y))); PTextRenderer->Build_Sentence(renderer_dedicated_server_label); PTextRenderer->Draw_Sentence(renderer_dedicated_server_color); } // Gameplay pending label if (show_gameplay_label) { Vector2 extent = PTextRenderer->Get_Text_Extents(renderer_gameplay_label); x = Render2DClass::Get_Screen_Resolution().Center().X - extent.X / 2.0f; y = Render2DClass::Get_Screen_Resolution().Center().Y + 1.2 * charHeight; PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y))); PTextRenderer->Build_Sentence(renderer_gameplay_label); PTextRenderer->Draw_Sentence(color); } } //----------------------------------------------------------------------------- void cGameData::Get_Dedicated_Server_Label(WideStringClass& text, unsigned& color) { color = 0xFFFFFFFF; // white if (cMathUtil::Round(TimeManager::Get_Seconds()) % 2 != 0) { color = 0xFF00FF00; // green } text = TRANSLATION(IDS_MP_DEDICATED_SERVER); } //----------------------------------------------------------------------------- void cGameData::Get_Gameplay_Not_Permitted_Label(WideStringClass& text, unsigned& color) { color = 0xFFFFFFFF; // white if (cMathUtil::Round(TimeManager::Get_Seconds()) % 2 != 0) { color = 0xFF00FF00; // green } text = TRANSLATION(IDS_MP_GAMEPLAY_PENDING); } //----------------------------------------------------------------------------- void cGameData::Get_Time_Limit_Text(WideStringClass& text) { if (IsIntermission.Is_True()) { text.Format( L"%s: %d", TRANSLATION(IDS_MP_NEXTGAME_COUNTDOWN), cMathUtil::Round(Get_Intermission_Time_Remaining())); } else if (Is_Time_Limit()) { int hours = 0; int mins = 0; int seconds = 0; cMiscUtil::Seconds_To_Hms(TimeRemainingSeconds, hours, mins, seconds); WideStringClass time_string(0, true); time_string.Format(L"%02d:%02d:%02d", hours, mins, seconds); text.Format(L"%s: %s", TRANSLATION(IDS_MP_TIME_REMAINING), time_string); } } //----------------------------------------------------------------------------- void cGameData::Think(void) { if (IsIntermission.Is_True()) { IntermissionTimeRemaining -= TimeManager::Get_Frame_Real_Seconds(); if (IntermissionTimeRemaining < 0) { IntermissionTimeRemaining = 0; } } else if (Is_Gameplay_Permitted()) { TimeRemainingSeconds -= TimeManager::Get_Frame_Real_Seconds(); if (TimeRemainingSeconds < 0) { TimeRemainingSeconds = 0; } DWORD duration_s = (int)((TIMEGETTIME() - GameStartTimeMs) / 1000.0f); Set_Game_Duration_S(duration_s); } if (cNetwork::I_Am_Server()) { // // Update CurrentPlayers // int max = (int) WWMath::Max( cPlayerManager::Count(), cNetwork::PServerConnection->Get_Num_RHosts()); Set_Current_Players(max); } DEMO_SECURITY_CHECK; FrameCount++; } //----------------------------------------------------------------------------- void cGameData::Render(void) { Show_Game_Settings_Limits(); if (PTextRenderer != NULL) { WWPROFILE("cGameData::Render"); PTextRenderer->Render(); } } //----------------------------------------------------------------------------- void cGameData::On_Game_Begin(void) { // // Note, On_Game_Begin happens after load. // WWDEBUG_SAY(("cGameData::On_Game_Begin\n")); GetSystemTime(&GameStartTime); FrameCount = 0; GameStartTimeMs = TIMEGETTIME(); // // Clear the MVP name // Let MVP carry over into next game. // //MvpName.Format(L""); //MvpCount = 0; // // Reset the game duration // GameDurationS = 0; // // Notify the combat layer about various server options // cCsDamageEvent::Set_Are_Clients_Trusted(IsClientTrusted.Get()); BuildingGameObj::Set_Can_Repair_Buildings(CanRepairBuildings.Get()); VehicleGameObj::Set_Default_Driver_Is_Gunner(DriverIsAlwaysGunner.Get()); CombatManager::Set_Friendly_Fire_Permitted(IsFriendlyFirePermitted.Get()); CombatManager::Set_Beacon_Placement_Ends_Game(false); // // Filter out unwanted spawners // if (cNetwork::I_Am_Server()) { Filter_Spawners(); } // // Adjust teaming for auto-teamed games // //if (!IS_MISSION && cNetwork::I_Am_Server() && Is_Team_Game() && IsTeamChangingAllowed.Is_False()) { if (!IS_MISSION && cNetwork::I_Am_Server()) { if (IsClanGame.Is_False() && IsTeamChangingAllowed.Is_False() && RemixTeams.Is_True()) { // // Remix Teams if the server option is set. // Remix_Team_Sides(); } else { // // In non-remixed C&C mode, we have a 50-50 chance of the teams being swapped. I prefer this // to simply alternating, because if you alternate and the number of maps in the // cycle is even, you will always play GDI on the same 50% of the maps. // if (Is_Skirmish() || (Is_Cnc() && (rand() % 2 == 0))) { Swap_Team_Sides(); } } if (IsClanGame.Is_False() && IsTeamChangingAllowed.Is_False()) { // // We always rebalance the teams numerically // Rebalance_Team_Sides(); } } GameModeClass* gameMode = GameModeManager::Find("WOL"); if (gameMode && gameMode->Is_Active()) { WolGameModeClass* wolGame = reinterpret_cast(gameMode); WWASSERT(wolGame != NULL); wolGame->Start_Game(this); } } //----------------------------------------------------------------------------- void cGameData::On_Game_End(void) { WWDEBUG_SAY(("cGameData::On_Game_End\n")); GameModeClass* gameMode = GameModeManager::Find("WOL"); if (gameMode && gameMode->Is_Active()) { WolGameModeClass* wolGame = reinterpret_cast(gameMode); wolGame->End_Game(); } } //----------------------------------------------------------------------------- int cGameData::Get_Mission_Number_From_Map_Name( const char * map_name ) { // If tutorial, return tutorial number if ( ::strnicmp( map_name, "M00_T", 5 ) == 0 ) { #define TUTORIAL_LOAD_MENU_NUMBER 90 return TUTORIAL_LOAD_MENU_NUMBER; } // Assume the map name is in the form "mXX.mix" where xx is the level number if ( ::strlen( map_name ) > 0 ) { return ::atoi( ((const char *)map_name)+1 ); } return 0; } //----------------------------------------------------------------------------- const StringClass& cGameData::Get_Map_Cycle(int map) { WWASSERT(map >= 0 && map < MAX_MAPS); #ifdef MULTIPLAYERDEMO MapCycle[map].Format("C&C_Under.mix"); #endif // MULTIPLAYERDEMO return MapCycle[map]; } //----------------------------------------------------------------------------- void cGameData::Set_Map_Cycle(int map, const StringClass & map_name) { WWASSERT(map >= 0 && map < MAX_MAPS); MapCycle[map] = map_name; } //----------------------------------------------------------------------------- void cGameData::Clear_Map_Cycle(void) { for (int i = 0; i < MAX_MAPS; i++) { MapCycle[i].Format(""); } } //----------------------------------------------------------------------------- void cGameData::Rotate_Map(void) { IsMapCycleOver = false; // // Determine the current map // int current_map = MapCycleIndex; #if (0) int current_map = 0; for (int i = 0; i < MAX_MAPS; i++) { if (MapName == MapCycle[i]) { current_map = i; break; } } #endif //(0) // // Increment it // current_map++; // // Go back to the first map if necessary // if (current_map >= MAX_MAPS || MapCycle[current_map].Is_Empty()) { current_map = 0; if (DoMapsLoop == false) { IsMapCycleOver = true; } } // // Set the map name // #ifdef MULTIPLAYERDEMO MapName.Format("C&C_Under.mix"); #else MapName = MapCycle[current_map]; #endif MapCycleIndex = current_map; return ; } //----------------------------------------------------------------------------- void cGameData::Set_Win_Text(WideStringClass & text) { WinText = text; } //----------------------------------------------------------------------------- void cGameData::ReceiveSignal(MPChooseTeamSignal& choice) { if (choice.GetItemA() == true) { // // Do nothing if the player selected 'auto' rather than GDI or NOD. // if (choice.GetItemB() != PLAYERTYPE_RENEGADE) { cNetwork::SwitchTeam(choice.GetItemB()); } } } //----------------------------------------------------------------------------- void cGameData::Filter_Spawners(void) { WWASSERT(cNetwork::I_Am_Server()); if (SpawnWeapons.Is_False()) { // // Disable multiplay weapons spawners // DynamicVectorClass spawner_list = SpawnManager::Get_Spawner_List(); for (int i = 0; i < spawner_list.Count(); i++) { WWASSERT(spawner_list[i] != NULL); if (spawner_list[i]->Get_Definition().Is_Multiplay_Weapon_Spawner()) { spawner_list[i]->Enable(false); } } } } //------------------------------------------------------------------------------------ void cGameData::Set_Mvp_Name(const WideStringClass name) { MvpName = name; } //------------------------------------------------------------------------------------ void cGameData::Set_Mvp_Count(int count) { WWASSERT(count >= 0); MvpCount = count; } //------------------------------------------------------------------------------------ void cGameData::Set_Win_Type(WinTypeEnum type) { WinType = type; } //------------------------------------------------------------------------------------ void cGameData::Set_Game_Duration_S(DWORD seconds) { GameDurationS = seconds; } //----------------------------------------------------------------------------- void cGameData::Get_Description(WideStringClass & description) { const WideStringClass delimiter = L"\t"; const WideStringClass newline = L"\n"; const WideStringClass yes = TRANSLATE(IDS_YES); const WideStringClass no = TRANSLATE(IDS_NO); WideStringClass attribute(0, true); WideStringClass value(0, true); // // Host // attribute = TRANSLATE(IDS_MP_HOST); value = Owner; description += (attribute + delimiter + value + newline); // // Game Name // attribute = TRANSLATE(IDS_MENU_TEXT292); value = GameTitle; description += (attribute + delimiter + value + newline); // // Map Name // if (ModName.Is_Empty () == false) { attribute = L"Mod Name:"; value = ModName; description += (attribute + delimiter + value + newline); } // // Map Name // attribute = TRANSLATE(IDS_MP_GAME_LIST_HEADER_GAME_MAP); value = MapName; description += (attribute + delimiter + value + newline); // // Time Limit // attribute = TRANSLATE(IDS_MENU_TEXT298); if (Is_Time_Limit()) { value.Format(L"%d %s", TimeLimitMinutes, TRANSLATE(IDS_MP_MINUTES)); } else { value = TRANSLATE(IDS_MP_NONE); } description += (attribute + delimiter + value + newline); // // Max. Players // attribute = TRANSLATE(IDS_MENU_TEXT294); value.Format(L"%d", MaxPlayers); description += (attribute + delimiter + value + newline); // // Radar // attribute = TRANSLATE(IDS_MENU_TEXT488); switch (RadarMode) { case RADAR_NOBODY: value = TRANSLATION(IDS_MP_RADAR_MODE_NOBODY); break; case RADAR_TEAMMATES: value = TRANSLATION(IDS_MP_RADAR_MODE_TEAMMATES); break; case RADAR_ALL: value = TRANSLATION(IDS_MP_RADAR_MODE_ALL); break; default: DIE; } description += (attribute + delimiter + value + newline); // // Allow Quickmatching // attribute = TRANSLATE(IDS_MENU_TEXT584); value = (IsQuickMatchServer.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Dedicated // attribute = TRANSLATE(IDS_MENU_TEXT309); value = (IsDedicated.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Friendly Fire // attribute = TRANSLATE(IDS_MENU_TEXT301); value = (IsFriendlyFirePermitted.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Manual Teaming // attribute = TRANSLATE(IDS_MENU_TEXT490); value = (IsTeamChangingAllowed.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Passworded // attribute = TRANSLATE(IDS_MP_PASSWORDED); value = (IsPassworded.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Laddered // attribute = TRANSLATE(IDS_MENU_TEXT496); value = (IsLaddered.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Clan Game // attribute = TRANSLATE(IDS_MENU_TEXT497); value = (IsClanGame.Get() ? yes : no); description += (attribute + delimiter + value + newline); /* // // Trust Clients // attribute = TRANSLATE(IDS_MENU_TEXT585); value = (IsClientTrusted.Get() ? yes : no); description += (attribute + delimiter + value + newline); */ // // Remix Teams // attribute = TRANSLATE(IDS_MENU_TEXT587); value = (RemixTeams.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Can Repair Buildings // attribute = TRANSLATE(IDS_MENU_TEXT590); value = (CanRepairBuildings.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Driver Is Always Gunner // attribute = TRANSLATE(IDS_MENU_TEXT591); value = (DriverIsAlwaysGunner.Get() ? yes : no); description += (attribute + delimiter + value + newline); // // Weapon spawning // attribute = TRANSLATE(IDS_MENU_TEXT592); value = (SpawnWeapons.Get() ? yes : no); description += (attribute + delimiter + value + newline); } //----------------------------------------------------------------------------- //cGameData * The_Game(void) {WWASSERT(PTheGameData != NULL); return PTheGameData;} cGameData * The_Game(void) {return PTheGameData;} cGameDataSinglePlayer * The_Single_Player_Game(void) {WWASSERT(The_Game()->As_Single_Player() != NULL); return The_Game()->As_Single_Player();} cGameDataSkirmish * The_Skirmish_Game(void) {WWASSERT(The_Game()->As_Skirmish() != NULL); return The_Game()->As_Skirmish();} cGameDataCnc * The_Cnc_Game(void) {WWASSERT(The_Game()->As_Cnc() != NULL); return The_Game()->As_Cnc();} /* if (Is_Team_Game()) { has_opponents = cPlayerManager::Get_Count(PLAYERTYPE_NOD) > 0 && cPlayerManager::Get_Count(PLAYERTYPE_GDI) > 0; } else { has_opponents = (cPlayerManager::Get_Count(PLAYERTYPE_RENEGADE) > 1); } */ /* //----------------------------------------------------------------------------- void cGameData::Set_Min_Game_Time_Required_Mins(int mins) { WWASSERT(mins >= 0 ); MinGameTimeRequiredMins = mins; } */ /* //----------------------------------------------------------------------------- void cGameData::Set_Full_Score_Time_Threshold_Mins(int mins) { WWASSERT(mins >= 0); FullScoreTimeThresholdMins = mins; } */ //#include "helptext.h" //#include "gddeathmatch.h" //#include "gdteamdeathmatch.h" //MinGameTimeRequiredMins = 10; //FullScoreTimeThresholdMins = 30; //MinGameTimeRequiredMins = rhs.MinGameTimeRequiredMins; //FullScoreTimeThresholdMins = rhs.FullScoreTimeThresholdMins; //packet.Add(MinGameTimeRequiredMins); //packet.Add(FullScoreTimeThresholdMins); //Set_Min_Game_Time_Required_Mins( packet.Get(i_placeholder)); //Set_Full_Score_Time_Threshold_Mins( packet.Get(i_placeholder)); //cGameDataDeathMatch * The_Deathmatch_Game(void) {WWASSERT(The_Game()->As_Deathmatch() != NULL); return The_Game()->As_Deathmatch();} //cGameDataTeamDeathMatch * The_Team_Deathmatch_Game(void) {WWASSERT(The_Game()->As_Team_Deathmatch() != NULL); return The_Game()->As_Team_Deathmatch();} //if (Is_Team_Game()) { /* } else { has_opponents = (cPlayerManager::Tally_Team_Size(PLAYERTYPE_RENEGADE) > 1); } */ //IsBloodShed.Set( false); //IsBloodShed = rhs.IsBloodShed; /* if (cNetwork::I_Am_Server()) { IsBloodShed.Set(false); } */