Skip to content

Instantly share code, notes, and snippets.

@sigsegv-mvm
Last active March 30, 2024 04:29
Show Gist options
  • Save sigsegv-mvm/a032eaf0f95281ea847b6515388d72a2 to your computer and use it in GitHub Desktop.
Save sigsegv-mvm/a032eaf0f95281ea847b6515388d72a2 to your computer and use it in GitHub Desktop.
TF2 game mode determination logic
// Based on TF2 server_srv.so version 20161111a
// Reverse engineering by sigsegv
void CTFGameRules::Activate()
{
m_nGameType = TF_GAMETYPE_UNDEFINED;
tf_gamemode_arena .SetValue(0);
tf_gamemode_cp .SetValue(0);
tf_gamemode_ctf .SetValue(0);
tf_gamemode_sd .SetValue(0);
tf_gamemode_payload .SetValue(0);
tf_gamemode_mvm .SetValue(0);
tf_gamemode_rd .SetValue(0);
tf_gamemode_pd .SetValue(0);
tf_gamemode_tc .SetValue(0);
tf_beta_content .SetValue(0);
tf_gamemode_passtime.SetValue(0);
tf_gamemode_misc .SetValue(0);
tf_bot_count .SetValue(0);
m_bPlayingMannVsMachine = false;
m_bBountyModeEnabled = false;
m_bMannVsMachineAlarmStatus = false;
m_bPlayingKoth = false;
m_bPlayingMedieval = false;
m_bPlayingHybrid_CTF_CP = false;
m_bPlayingSpecialDeliveryMode = false;
m_bPlayingRobotDestructionMode = false;
m_bPowerupMode = false;
// dword @ +0x6F8 = 0
// dword @ +0x6FC = 0
// CHandle @ +0xC70 = nullptr
// CHandle @ +0xC74 = nullptr
// CHandle @ +0xC78 = nullptr
// CHandle @ +0xC7C = nullptr
// float @ +0xCBC = -1.0f
// dword @ +0xCC0 = 0
// dword @ +0x6E8 = 0
m_nMapHolidayType = 0;
auto logic_arena = dynamic_cast<CArenaLogic *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_arena"));
if (logic_arena != nullptr) {
// handle @ +0xC7C = logic_arena
m_nGameType = TF_GAMETYPE_ARENA;
tf_gamemode_arena.SetValue(1);
Msg("Executing server arena config file\n");
engine->ServerCommand("exec config_arena.cfg\n");
}
// SKIPPED: item schema stuff related to setting tf_beta_content
if (V_strncmp(STRING(gpGlobals->mapname), "tc_", 3) == 0) {
tf_gamemode_tc.SetValue(1);
}
// This checks for the existence of a tf_logic_robot_destruction entity
if (CTFRobotDestructionLogic::GetRobotDestructionLogic() != nullptr) {
m_bPlayingRobotDestructionMode = true;
if (CTFRobotDestructionLogic::GetRobotDestructionLogic()->GetType() != 0) {
tf_gamemode_pd.SetValue(1);
m_nGameType = TF_GAMETYPE_PD;
} else {
tf_gamemode_rd.SetValue(1);
m_nGameType = TF_GAMETYPE_RD;
tf_beta_content.SetValue(1);
}
} else if (dynamic_cast<CMannVsMachineLogic *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_mann_vs_machine")) != nullptr) {
m_bPlayingMannVsMachine = true;
tf_gamemode_mvm.SetValue(1);
m_nGameType = TF_GAMETYPE_MVM;
} else if (StringAfterPrefix(STRING(gpGlobals->mapname), "sd_")) {
m_bPlayingSpecialDeliveryMode = true;
tf_gamemode_sd.SetValue(1);
} else if (ICaptureFlagAutoList::AutoList().Count() > 0) {
m_nGameType = TF_GAMETYPE_CTF;
tf_gamemode_ctf.SetValue(1);
} else if (dynamic_cast<CTeamTrainWatcher *>(gEntList.FindEntityByClassname(nullptr, "team_train_watcher")) != nullptr) {
m_nGameType = TF_GAMETYPE_ESCORT;
tf_gamemode_payload.SetValue(1);
if (dynamic_cast<CMultipleEscort *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_multiple_escort")) != nullptr) {
m_bMultipleTrains = true;
} else {
m_bMultipleTrains = false;
}
} else if (g_hControlPointMasters.Count() != 0 && m_nGameType != TF_GAMETYPE_ARENA) {
m_nGameType = TF_GAMETYPE_CP;
tf_gamemode_cp.SetValue(1);
}
if (dynamic_cast<CTFPasstimeLogic *>(gEntList.FindEntityByClassname(nullptr, "passtime_logic")) != nullptr) {
m_nGameType = TF_GAMETYPE_PASSTIME;
tf_gamemode_passtime.SetValue(1);
}
auto logic_training = dynamic_cast<CTrainingModeLogic *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_training_mode"));
if (logic_training != nullptr) {
m_bIsInTraining = true;
m_bAllowTrainingAchievements = false;
mp_humans_must_join_team.SetValue("blue");
m_bIsTrainingHUDVisible = true;
tf_training_client_message.SetValue(0);
}
// handle @ +0x6A4 = logic_training
m_bIsInItemTestingMode = false;
if (dynamic_cast<CKothLogic *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_koth")) != nullptr) {
m_bPlayingKoth = true;
}
if (dynamic_cast<CMedievalLogic *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_medieval")) != nullptr) {
m_bPlayingMedieval = true;
}
auto logic_competitive = dynamic_cast<CCompetitiveLogic *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_competitive"));
if (logic_competitive != nullptr) {
// handle @ +0x6A0 = logic_competitive
}
if (dynamic_cast<CHybridMap_CTF_CP *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_hybrid_ctf_cp")) != nullptr) {
m_bPlayingHybrid_CTF_CP = true;
}
auto logic_holiday = dynamic_cast<CTFHolidayEntity *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_holiday"));
if (logic_holiday != nullptr) {
m_nMapHolidayType = logic_holiday->m_nHolidayType;
}
// SKIPPED: bot_roster stuff
// SKIPPED: tf_logic_cp_timer stuff
if (IsInTraining() || TheTFBots().IsInOfflinePractice() || IsInItemTestingMode()) {
hide_server.SetValue(1);
}
// byte @ +0x6D4 = 0
// byte @ +0x6D5 = 0
// dword @ +0x6D8 = 0
if (tf_powerup_mode.GetBool() && !m_bPowerupMode) {
SetPowerupMode(true);
}
if (IsInTournamentMode() && m_nGameType != TF_GAMETYPE_MVM && /* last gametype was TF_GAMETYPE_MVM */) {
mp_tournament.SetValue(0);
}
if (m_bPlayingMannVsMachine && g_pPopulationManager == nullptr) {
CreateEntityByName("info_populator");
}
if (tf_gamemode_tc.GetBool() || tf_gamemode_sd.GetBool() || tf_gamemode_pd.GetBool() || m_bPlayingMedieval) {
tf_gamemode_misc.SetValue(1);
}
if (gEntList.FindEntityByName(nullptr, "competitive_stage_logic_case") != nullptr) {
m_bPlayersAreOnMatchSummaryStage = true;
}
m_bCompetitiveMode = false;
auto match_group_desc = GetMatchGroupDescription(GetCurrentMatchGroup());
if (match_group_desc != nullptr) {
match_group_desc->InitGameRulesSettings();
}
if (dynamic_cast<CLogicMannPower *>(gEntList.FindEntityByClassname(nullptr, "tf_logic_mannpower")) != nullptr) {
tf_powerup_mode.SetValue(1);
} else {
tf_powerup_mode.SetValue(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment