diff --git a/BackupManagement.cs b/BackupManagement.cs index 1c0bcbe..fd36506 100644 --- a/BackupManagement.cs +++ b/BackupManagement.cs @@ -121,7 +121,7 @@ private void HandleRestoreCommand(CCSPlayerController? player, string commandArg if (!string.IsNullOrWhiteSpace(commandArg)) { if (int.TryParse(commandArg, out int roundNumber) && roundNumber >= 0) { string round = roundNumber.ToString("D2"); - string requiredBackupFileName = $"matchzy_data_backup_{liveMatchId}_{matchConfig.CurrentMapNumber}_round_{round}.json"; + string requiredBackupFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round{round}.json"; RestoreRoundBackup(player, requiredBackupFileName); } else { @@ -186,6 +186,20 @@ private void RestoreRoundBackup(CCSPlayerController? player, string fileName) { isRoundRestoring = true; + // MatchID is set first to avoid generating a new one. + if (backupData.TryGetValue("matchid", out var matchId)) + { + liveMatchId = long.Parse(matchId); + } + if (backupData.TryGetValue("match_loaded", out var matchLoaded)) + { + isMatchSetup = bool.Parse(matchLoaded); + } + if (backupData.TryGetValue("match_config", out var matchConfigValue)) + { + matchConfig = Newtonsoft.Json.JsonConvert.DeserializeObject(matchConfigValue)!; + SetupRoundBackupFile(); + } if (backupData.TryGetValue("map_name", out var map_name)) { if (map_name != Server.MapName) @@ -253,22 +267,18 @@ private void RestoreRoundBackup(CCSPlayerController? player, string fileName) { { gameRules.CTTimeOuts = int.Parse(ctTimeouts); } - if (backupData.TryGetValue("matchid", out var matchId)) - { - liveMatchId = long.Parse(matchId); - } - if (backupData.TryGetValue("match_loaded", out var matchLoaded)) - { - isMatchSetup = bool.Parse(matchLoaded); - } - if (backupData.TryGetValue("match_config", out var matchConfigValue)) - { - matchConfig = Newtonsoft.Json.JsonConvert.DeserializeObject(matchConfigValue)!; - } if (backupData.TryGetValue("valve_backup", out var valveBackup)) { - string tempFilePath = Path.Combine(Server.GameDirectory, "csgo", $"{fileName}.txt"); - File.WriteAllText(tempFilePath, valveBackup); + string tempFileName = fileName.Replace(".json", ".txt"); + if (backupData.TryGetValue("round", out var roundNumber)) + { + tempFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round{roundNumber}"; + } + string tempFilePath = Path.Combine(Server.GameDirectory, "csgo", tempFileName); + if (!File.Exists(tempFilePath)) + { + File.WriteAllText(tempFilePath, valveBackup); + } int restoreTimer = liveSetupRequired ? 2 : 0; if (liveSetupRequired) { @@ -279,7 +289,7 @@ private void RestoreRoundBackup(CCSPlayerController? player, string fileName) { Server.ExecuteCommand($"mp_backup_restore_load_file {tempFilePath}"); StartDemoRecording(); }); - AddTimer(5, () => File.Delete(tempFilePath)); + // AddTimer(5, () => File.Delete(tempFilePath)); } } catch (Exception e) { @@ -307,7 +317,7 @@ public void CreateMatchZyRoundDataBackup() (int t1score, int t2score) = GetTeamsScore(); int roundNumber = t1score + t2score; string round = roundNumber.ToString("D2"); - string matchZyBackupFileName = $"matchzy_data_backup_{liveMatchId}_{matchConfig.CurrentMapNumber}_round_{round}.json"; + string matchZyBackupFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round{round}.json"; string filePath = Server.GameDirectory + "/csgo/MatchZyDataBackup/" + matchZyBackupFileName; string? directoryPath = Path.GetDirectoryName(filePath); if (directoryPath != null && !Directory.Exists(directoryPath)) @@ -379,7 +389,7 @@ public List GetBackups(string matchID) var directoryInfo = new DirectoryInfo(backupDir); var files = directoryInfo.GetFiles(); - var pattern = $"matchzy_data_backup_{matchID}_"; + var pattern = $"matchzy_{matchID}_"; var backups = new List(); foreach (var file in files) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d3de0..75ea636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # MatchZy Changelog +# 0.8.3 + +#### August 25, 2024 + +- Fixed issues with backup restore where `.restore` command would show as round restored, but nothing happened. (Improved file naming and backup saving logic) +- Updated live.cfg as per new rules (mp_team_timeout_max 3; mp_team_timeout_ot_max 1; mp_team_timeout_ot_add_each 1) +- Added css_globalnades alias (!globalnades) for css_save_nades_as_global / .globalnades + # 0.8.2 #### August 25, 2024 diff --git a/ConsoleCommands.cs b/ConsoleCommands.cs index 22f3257..96ad012 100644 --- a/ConsoleCommands.cs +++ b/ConsoleCommands.cs @@ -35,6 +35,7 @@ public void OnWLCommand(CCSPlayerController? player, CommandInfo? command) } [ConsoleCommand("css_save_nades_as_global", "Toggles Global Lineups for players")] + [ConsoleCommand("css_globalnades", "Toggles Global Lineups for players")] public void OnSaveNadesAsGlobalCommand(CCSPlayerController? player, CommandInfo? command) { if (IsPlayerAdmin(player, "css_save_nades_as_global", "@css/config")) diff --git a/MatchZy.cs b/MatchZy.cs index b819422..d9af499 100644 --- a/MatchZy.cs +++ b/MatchZy.cs @@ -13,7 +13,7 @@ public partial class MatchZy : BasePlugin { public override string ModuleName => "MatchZy"; - public override string ModuleVersion => "0.8.2"; + public override string ModuleVersion => "0.8.3"; public override string ModuleAuthor => "WD- (https://github.com/shobhit-pathak/)"; diff --git a/PracticeMode.cs b/PracticeMode.cs index 69f5a99..a99617f 100644 --- a/PracticeMode.cs +++ b/PracticeMode.cs @@ -1245,7 +1245,7 @@ public void ExecDryRunCFG() } else { Log($"[ExecDryRunCFG] Starting Dryrun! Dryrun CFG not found in {absolutePath}, using default CFG!"); Server.ExecuteCommand("ammo_grenade_limit_default 1;ammo_grenade_limit_flashbang 2;ammo_grenade_limit_total 4;bot_quota 0;cash_player_bomb_defused 300;cash_player_bomb_planted 300;cash_player_damage_hostage -30;cash_player_interact_with_hostage 300;cash_player_killed_enemy_default 300;cash_player_killed_enemy_factor 1;cash_player_killed_hostage -1000;cash_player_killed_teammate -300;cash_player_rescued_hostage 1000;cash_team_elimination_bomb_map 3250;cash_team_elimination_hostage_map_ct 3000;cash_team_elimination_hostage_map_t 3000;cash_team_hostage_alive 0;cash_team_hostage_interaction 600;cash_team_loser_bonus 1400;cash_team_loser_bonus_consecutive_rounds 500;cash_team_planted_bomb_but_defused 600;cash_team_rescued_hostage 600;cash_team_terrorist_win_bomb 3500;cash_team_win_by_defusing_bomb 3500;"); - Server.ExecuteCommand("cash_team_win_by_hostage_rescue 2900;cash_team_win_by_time_running_out_bomb 3250;cash_team_win_by_time_running_out_hostage 3250;ff_damage_reduction_bullets 0.33;ff_damage_reduction_grenade 0.85;ff_damage_reduction_grenade_self 1;ff_damage_reduction_other 0.4;mp_afterroundmoney 0;mp_autokick 0;mp_autoteambalance 0;mp_backup_restore_load_autopause 1;mp_backup_round_auto 1;mp_buy_anywhere 0;mp_buy_during_immunity 0;mp_buytime 20;mp_c4timer 40;mp_ct_default_melee weapon_knife;mp_ct_default_primary \"\";mp_ct_default_secondary weapon_hkp2000;mp_death_drop_defuser 1;mp_death_drop_grenade 2;mp_death_drop_gun 1;mp_defuser_allocation 0;mp_display_kill_assists 1;mp_endmatch_votenextmap 0;mp_forcecamera 1;mp_free_armor 0;mp_freezetime 6;mp_friendlyfire 1;mp_give_player_c4 1;mp_halftime 1;mp_halftime_duration 15;mp_halftime_pausetimer 0;mp_ignore_round_win_conditions 0;mp_limitteams 0;mp_match_can_clinch 1;mp_match_end_restart 0;mp_maxmoney 16000;mp_maxrounds 24;mp_overtime_enable 1;mp_overtime_halftime_pausetimer 0;mp_overtime_maxrounds 6;mp_overtime_startmoney 10000;mp_playercashawards 1;mp_randomspawn 0;mp_respawn_immunitytime 0;mp_respawn_on_death_ct 0;mp_respawn_on_death_t 0;mp_round_restart_delay 5;mp_roundtime 1.92;mp_roundtime_defuse 1.92;mp_roundtime_hostage 1.92;mp_solid_teammates 1;mp_starting_losses 1;mp_startmoney 16000;mp_t_default_melee weapon_knife;mp_t_default_primary \"\";mp_t_default_secondary weapon_glock;mp_teamcashawards 1;mp_timelimit 0;mp_weapons_allow_map_placed 1;mp_weapons_allow_zeus 1;mp_win_panel_display_time 3;spec_freeze_deathanim_time 0;spec_freeze_time 2;spec_freeze_time_lock 2;spec_replay_enable 0;sv_allow_votes 1;sv_auto_full_alltalk_during_warmup_half_end 0;sv_damage_print_enable 0;sv_deadtalk 1;sv_hibernate_postgame_delay 300;sv_ignoregrenaderadio 0;sv_infinite_ammo 0;sv_talk_enemy_dead 0;sv_talk_enemy_living 0;sv_voiceenable 1;tv_relayvoice 1;mp_team_timeout_max 4;mp_team_timeout_time 30;sv_vote_command_delay 0;cash_team_bonus_shorthanded 0;mp_spectators_max 20;mp_team_intro_time 0;mp_restartgame 3;mp_warmup_end;"); + Server.ExecuteCommand("cash_team_win_by_hostage_rescue 2900;cash_team_win_by_time_running_out_bomb 3250;cash_team_win_by_time_running_out_hostage 3250;ff_damage_reduction_bullets 0.33;ff_damage_reduction_grenade 0.85;ff_damage_reduction_grenade_self 1;ff_damage_reduction_other 0.4;mp_afterroundmoney 0;mp_autokick 0;mp_autoteambalance 0;mp_backup_restore_load_autopause 1;mp_backup_round_auto 1;mp_buy_anywhere 0;mp_buy_during_immunity 0;mp_buytime 20;mp_c4timer 40;mp_ct_default_melee weapon_knife;mp_ct_default_primary \"\";mp_ct_default_secondary weapon_hkp2000;mp_death_drop_defuser 1;mp_death_drop_grenade 2;mp_death_drop_gun 1;mp_defuser_allocation 0;mp_display_kill_assists 1;mp_endmatch_votenextmap 0;mp_forcecamera 1;mp_free_armor 0;mp_freezetime 6;mp_friendlyfire 1;mp_give_player_c4 1;mp_halftime 1;mp_halftime_duration 15;mp_halftime_pausetimer 0;mp_ignore_round_win_conditions 0;mp_limitteams 0;mp_match_can_clinch 1;mp_match_end_restart 0;mp_maxmoney 16000;mp_maxrounds 24;mp_overtime_enable 1;mp_overtime_halftime_pausetimer 0;mp_overtime_maxrounds 6;mp_overtime_startmoney 10000;mp_playercashawards 1;mp_randomspawn 0;mp_respawn_immunitytime 0;mp_respawn_on_death_ct 0;mp_respawn_on_death_t 0;mp_round_restart_delay 5;mp_roundtime 1.92;mp_roundtime_defuse 1.92;mp_roundtime_hostage 1.92;mp_solid_teammates 1;mp_starting_losses 1;mp_startmoney 16000;mp_t_default_melee weapon_knife;mp_t_default_primary \"\";mp_t_default_secondary weapon_glock;mp_teamcashawards 1;mp_timelimit 0;mp_weapons_allow_map_placed 1;mp_weapons_allow_zeus 1;mp_win_panel_display_time 3;spec_freeze_deathanim_time 0;spec_freeze_time 2;spec_freeze_time_lock 2;spec_replay_enable 0;sv_allow_votes 1;sv_auto_full_alltalk_during_warmup_half_end 0;sv_damage_print_enable 0;sv_deadtalk 1;sv_hibernate_postgame_delay 300;sv_ignoregrenaderadio 0;sv_infinite_ammo 0;sv_talk_enemy_dead 0;sv_talk_enemy_living 0;sv_voiceenable 1;tv_relayvoice 1;mp_team_timeout_max 3;mp_team_timeout_ot_max 1;mp_team_timeout_ot_add_each 1;mp_team_timeout_time 30;sv_vote_command_delay 0;cash_team_bonus_shorthanded 0;mp_spectators_max 20;mp_team_intro_time 0;mp_restartgame 3;mp_warmup_end;"); } } diff --git a/Teams.cs b/Teams.cs index 7192bb3..48f6125 100644 --- a/Teams.cs +++ b/Teams.cs @@ -115,8 +115,8 @@ public void OnAddPlayerCommand(CCSPlayerController? player, CommandInfo? command command.ReplyToCommand($"Player {playerName} added to {playerTeam} successfully!"); } - [ConsoleCommand("matchzy_removeplayer", "Adds player to the provided team")] - [ConsoleCommand("get5_removeplayer", "Adds player to the provided team")] + [ConsoleCommand("matchzy_removeplayer", "Removes the player from all the teams")] + [ConsoleCommand("get5_removeplayer", "Removes the player from all the teams")] [CommandHelper(minArgs: 1, usage: "")] public void OnRemovePlayerCommand(CCSPlayerController? player, CommandInfo? command) { @@ -127,7 +127,7 @@ public void OnRemovePlayerCommand(CCSPlayerController? player, CommandInfo? comm } if (IsHalfTimePhase()) { - command.ReplyToCommand("Cannot add players during halftime. Please wait until the next round starts."); + command.ReplyToCommand("Cannot remove players during halftime. Please wait until the next round starts."); return; } diff --git a/Utility.cs b/Utility.cs index aed1e43..c04e85d 100644 --- a/Utility.cs +++ b/Utility.cs @@ -299,7 +299,7 @@ private void StartLive() // Storing 0-0 score backup file as lastBackupFileName, so that .stop functions properly in first round. lastBackupFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round00.txt"; - lastMatchZyBackupFileName = $"matchzy_data_backup_{liveMatchId}_{matchConfig.CurrentMapNumber}_round_00.json"; + lastMatchZyBackupFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round00.json"; // This is to reload the map once it is over so that all flags are reset accordingly Server.ExecuteCommand("mp_match_end_restart true"); @@ -1047,7 +1047,7 @@ private void HandlePostRoundEndEvent(EventRoundEnd @event) string round = GetRoundNumer().ToString("D2"); lastBackupFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round{round}.txt"; - lastMatchZyBackupFileName = $"matchzy_data_backup_{liveMatchId}_{matchConfig.CurrentMapNumber}_round_{round}.json"; + lastMatchZyBackupFileName = $"matchzy_{liveMatchId}_{matchConfig.CurrentMapNumber}_round{round}.json"; Log($"[HandlePostRoundEndEvent] Setting lastBackupFileName to {lastBackupFileName} and lastMatchZyBackupFileName to {lastMatchZyBackupFileName}"); // One of the team did not use .stop command hence display the proper message after the round has ended. @@ -1305,7 +1305,7 @@ private void ExecLiveCFG() else { Server.ExecuteCommand("ammo_grenade_limit_default 1;ammo_grenade_limit_flashbang 2;ammo_grenade_limit_total 4;bot_quota 0;cash_player_bomb_defused 300;cash_player_bomb_planted 300;cash_player_damage_hostage -30;cash_player_interact_with_hostage 300;cash_player_killed_enemy_default 300;cash_player_killed_enemy_factor 1;cash_player_killed_hostage -1000;cash_player_killed_teammate -300;cash_player_rescued_hostage 1000;cash_team_elimination_bomb_map 3250;cash_team_elimination_hostage_map_ct 3000;cash_team_elimination_hostage_map_t 3000;cash_team_hostage_alive 0;cash_team_hostage_interaction 600;cash_team_loser_bonus 1400;cash_team_loser_bonus_consecutive_rounds 500;cash_team_planted_bomb_but_defused 600;cash_team_rescued_hostage 600;cash_team_terrorist_win_bomb 3500;cash_team_win_by_defusing_bomb 3500;"); - Server.ExecuteCommand("cash_team_win_by_hostage_rescue 2900;cash_team_win_by_time_running_out_bomb 3250;cash_team_win_by_time_running_out_hostage 3250;ff_damage_reduction_bullets 0.33;ff_damage_reduction_grenade 0.85;ff_damage_reduction_grenade_self 1;ff_damage_reduction_other 0.4;mp_afterroundmoney 0;mp_autokick 0;mp_autoteambalance 0;mp_backup_restore_load_autopause 1;mp_backup_round_auto 1;mp_buy_anywhere 0;mp_buy_during_immunity 0;mp_buytime 20;mp_c4timer 40;mp_ct_default_melee weapon_knife;mp_ct_default_primary \"\";mp_ct_default_secondary weapon_hkp2000;mp_death_drop_defuser 1;mp_death_drop_grenade 2;mp_death_drop_gun 1;mp_defuser_allocation 0;mp_display_kill_assists 1;mp_endmatch_votenextmap 0;mp_forcecamera 1;mp_free_armor 0;mp_freezetime 18;mp_friendlyfire 1;mp_give_player_c4 1;mp_halftime 1;mp_halftime_duration 15;mp_halftime_pausetimer 0;mp_ignore_round_win_conditions 0;mp_limitteams 0;mp_match_can_clinch 1;mp_match_end_restart 0;mp_maxmoney 16000;mp_maxrounds 24;mp_overtime_enable 1;mp_overtime_halftime_pausetimer 0;mp_overtime_maxrounds 6;mp_overtime_startmoney 10000;mp_playercashawards 1;mp_randomspawn 0;mp_respawn_immunitytime 0;mp_respawn_on_death_ct 0;mp_respawn_on_death_t 0;mp_round_restart_delay 5;mp_roundtime 1.92;mp_roundtime_defuse 1.92;mp_roundtime_hostage 1.92;mp_solid_teammates 1;mp_starting_losses 1;mp_startmoney 800;mp_t_default_melee weapon_knife;mp_t_default_primary \"\";mp_t_default_secondary weapon_glock;mp_teamcashawards 1;mp_timelimit 0;mp_weapons_allow_map_placed 1;mp_weapons_allow_zeus 1;mp_win_panel_display_time 3;spec_freeze_deathanim_time 0;spec_freeze_time 2;spec_freeze_time_lock 2;spec_replay_enable 0;sv_allow_votes 1;sv_auto_full_alltalk_during_warmup_half_end 0;sv_damage_print_enable 0;sv_deadtalk 1;sv_hibernate_postgame_delay 300;sv_ignoregrenaderadio 0;sv_infinite_ammo 0;sv_talk_enemy_dead 0;sv_talk_enemy_living 0;sv_voiceenable 1;tv_relayvoice 1;mp_team_timeout_max 4;mp_team_timeout_time 30;sv_vote_command_delay 0;cash_team_bonus_shorthanded 0;mp_spectators_max 20;mp_team_intro_time 0;mp_restartgame 3;mp_warmup_end;"); + Server.ExecuteCommand("cash_team_win_by_hostage_rescue 2900;cash_team_win_by_time_running_out_bomb 3250;cash_team_win_by_time_running_out_hostage 3250;ff_damage_reduction_bullets 0.33;ff_damage_reduction_grenade 0.85;ff_damage_reduction_grenade_self 1;ff_damage_reduction_other 0.4;mp_afterroundmoney 0;mp_autokick 0;mp_autoteambalance 0;mp_backup_restore_load_autopause 1;mp_backup_round_auto 1;mp_buy_anywhere 0;mp_buy_during_immunity 0;mp_buytime 20;mp_c4timer 40;mp_ct_default_melee weapon_knife;mp_ct_default_primary \"\";mp_ct_default_secondary weapon_hkp2000;mp_death_drop_defuser 1;mp_death_drop_grenade 2;mp_death_drop_gun 1;mp_defuser_allocation 0;mp_display_kill_assists 1;mp_endmatch_votenextmap 0;mp_forcecamera 1;mp_free_armor 0;mp_freezetime 18;mp_friendlyfire 1;mp_give_player_c4 1;mp_halftime 1;mp_halftime_duration 15;mp_halftime_pausetimer 0;mp_ignore_round_win_conditions 0;mp_limitteams 0;mp_match_can_clinch 1;mp_match_end_restart 0;mp_maxmoney 16000;mp_maxrounds 24;mp_overtime_enable 1;mp_overtime_halftime_pausetimer 0;mp_overtime_maxrounds 6;mp_overtime_startmoney 10000;mp_playercashawards 1;mp_randomspawn 0;mp_respawn_immunitytime 0;mp_respawn_on_death_ct 0;mp_respawn_on_death_t 0;mp_round_restart_delay 5;mp_roundtime 1.92;mp_roundtime_defuse 1.92;mp_roundtime_hostage 1.92;mp_solid_teammates 1;mp_starting_losses 1;mp_startmoney 800;mp_t_default_melee weapon_knife;mp_t_default_primary \"\";mp_t_default_secondary weapon_glock;mp_teamcashawards 1;mp_timelimit 0;mp_weapons_allow_map_placed 1;mp_weapons_allow_zeus 1;mp_win_panel_display_time 3;spec_freeze_deathanim_time 0;spec_freeze_time 2;spec_freeze_time_lock 2;spec_replay_enable 0;sv_allow_votes 1;sv_auto_full_alltalk_during_warmup_half_end 0;sv_damage_print_enable 0;sv_deadtalk 1;sv_hibernate_postgame_delay 300;sv_ignoregrenaderadio 0;sv_infinite_ammo 0;sv_talk_enemy_dead 0;sv_talk_enemy_living 0;sv_voiceenable 1;tv_relayvoice 1;mp_team_timeout_max 3;mp_team_timeout_ot_max 1;mp_team_timeout_ot_add_each 1;mp_team_timeout_time 30;sv_vote_command_delay 0;cash_team_bonus_shorthanded 0;mp_spectators_max 20;mp_team_intro_time 0;mp_restartgame 3;mp_warmup_end;"); } } } diff --git a/cfg/MatchZy/dryrun.cfg b/cfg/MatchZy/dryrun.cfg index 97d18ac..0fc3799 100644 --- a/cfg/MatchZy/dryrun.cfg +++ b/cfg/MatchZy/dryrun.cfg @@ -100,8 +100,10 @@ sv_talk_enemy_dead 0 sv_talk_enemy_living 0 sv_voiceenable 1 tv_relayvoice 1 -mp_team_timeout_max 4 +mp_team_timeout_max 3 mp_team_timeout_time 30 +mp_team_timeout_ot_max 1 +mp_team_timeout_ot_add_each 1 sv_vote_command_delay 0 cash_team_bonus_shorthanded 0 mp_spectators_max 20 diff --git a/cfg/MatchZy/live.cfg b/cfg/MatchZy/live.cfg index e62b3e6..3569c1a 100644 --- a/cfg/MatchZy/live.cfg +++ b/cfg/MatchZy/live.cfg @@ -100,8 +100,10 @@ sv_talk_enemy_dead 0 sv_talk_enemy_living 0 sv_voiceenable 1 tv_relayvoice 1 -mp_team_timeout_max 4 +mp_team_timeout_max 3 mp_team_timeout_time 30 +mp_team_timeout_ot_max 1 +mp_team_timeout_ot_add_each 1 sv_vote_command_delay 0 cash_team_bonus_shorthanded 0 mp_spectators_max 20 diff --git a/cfg/MatchZy/sleep.cfg b/cfg/MatchZy/sleep.cfg index c1963fb..09bb63e 100644 --- a/cfg/MatchZy/sleep.cfg +++ b/cfg/MatchZy/sleep.cfg @@ -100,8 +100,10 @@ sv_talk_enemy_dead 0 sv_talk_enemy_living 0 sv_voiceenable 1 tv_relayvoice 1 -mp_team_timeout_max 4 +mp_team_timeout_max 3 mp_team_timeout_time 30 +mp_team_timeout_ot_max 1 +mp_team_timeout_ot_add_each 1 sv_vote_command_delay 0 cash_team_bonus_shorthanded 0 mp_spectators_max 20