Last active
June 11, 2020 15:19
-
-
Save Sam-Belliveau/66f95be73dd17047891240378fc87c29 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| "Phrases" | |
| { | |
| "JoinedQueueMessage" | |
| { | |
| "en" "You have been placed in the waiting queue." | |
| } | |
| "WaitingQueueMessage" | |
| { | |
| "#format" "{1:i}" | |
| "en" "The game is currently full with {GREEN}{1} {NORMAL}players. You are in the waiting queue." | |
| } | |
| "RetakeSiteMessage" | |
| { | |
| "#format" "{1:s},{2:d},{3:d}" | |
| "en" "Retake {GREEN}{1}: {DARK_RED}{2} Ts {NORMAL}vs {DARK_BLUE}{3} CTs" | |
| } | |
| "FailedToPlant" | |
| { | |
| "#format" "{1:N},{2:d}" | |
| "en" "{ORANGE}{1} {NORMAL}failed to plant... {LIGHT_RED}(-{2})" | |
| } | |
| "PlayerAssignedTUp" | |
| { | |
| "#format" "{1:d},{2:N},{3:d},{4:d}" | |
| "en" "{DARK_RED}Rank {1}: {ORANGE}{2} {GREEN}(Score: {3}) {LIGHT_GREEN}(Change: +{4})" | |
| } | |
| "PlayerAssignedTDown" | |
| { | |
| "#format" "{1:d},{2:N},{3:d},{4:d}" | |
| "en" "{DARK_RED}Rank {1}: {ORANGE}{2} {GREEN}(Score: {3}) {LIGHT_RED}(Change: {4})" | |
| } | |
| "PlayerAssignedCTUp" | |
| { | |
| "#format" "{1:d},{2:N},{3:d},{4:d}" | |
| "en" "{DARK_BLUE}Rank {1}: {ORANGE}{2} {GREEN}(Score: {3}) {LIGHT_GREEN}(Change: +{4})" | |
| } | |
| "PlayerAssignedCTDown" | |
| { | |
| "#format" "{1:d},{2:N},{3:d},{4:d}" | |
| "en" "{DARK_BLUE}Rank {1}: {ORANGE}{2} {GREEN}(Score: {3}) {LIGHT_RED}(Change: {4})" | |
| } | |
| "PlayerWonRound" | |
| { | |
| "#format" "{1:d}" | |
| "en" "{ORANGE}You {LIGHT_GREEN}Won {NORMAL}That Round! {LIGHT_GREEN}(+{1})" | |
| } | |
| "PlayerLostRound" | |
| { | |
| "#format" "{1:d}" | |
| "en" "{ORANGE}You {LIGHT_RED}Lost {NORMAL}That Round! {LIGHT_RED}(-{1})" | |
| } | |
| "PlayerGainedPoints" | |
| { | |
| "#format" "{1:d}" | |
| "en" "In Total, {ORANGE}You {LIGHT_GREEN}Gained Points {NORMAL}That Round! {LIGHT_GREEN}(+{1})" | |
| } | |
| "PlayerLostPoints" | |
| { | |
| "#format" "{1:d}" | |
| "en" "In Total, {ORANGE}You {LIGHT_RED}Lost Points {NORMAL}That Round! {LIGHT_RED}({1})" | |
| } | |
| "PlayerTeamKilled" | |
| { | |
| "#format" "{1:N},{2:d}" | |
| "en" "{ORANGE}You {NORMAL}Team Killed {ORANGE}{1}! {LIGHT_RED}(-{2})" | |
| } | |
| "PlayerTeamDamaged" | |
| { | |
| "#format" "{1:N},{2:d},{3:d}" | |
| "en" "{ORANGE}You {NORMAL}Team Damaged {ORANGE}{1} {NORMAL} by {LIGHT_RED}{2} {NORMAL}Points! {LIGHT_RED}(-{3})" | |
| } | |
| "PlayerKilled" | |
| { | |
| "#format" "{1:N},{2:d}" | |
| "en" "{ORANGE}You {NORMAL}Killed {ORANGE}{1}! {LIGHT_GREEN}(+{2})" | |
| } | |
| "PlayerDamaged" | |
| { | |
| "#format" "{1:N},{2:d},{3:d}" | |
| "en" "{ORANGE}You {NORMAL}Damaged {ORANGE}{1} {NORMAL} for {LIGHT_GREEN}{2} {NORMAL}Points! {LIGHT_GREEN}(+{3})" | |
| } | |
| "PlayerKilledBy" | |
| { | |
| "#format" "{1:N},{2:d}" | |
| "en" "{ORANGE}{1} {NORMAL}Killed {ORANGE}You! {LIGHT_RED}(-{2})" | |
| } | |
| "PlayerDamagedBy" | |
| { | |
| "#format" "{1:N},{2:d},{3:d}" | |
| "en" "{ORANGE}{1} {NORMAL}Damaged {ORANGE}You {NORMAL} for {LIGHT_RED}{2} {NORMAL}Points! {LIGHT_RED}(-{3})" | |
| } | |
| "BombDefused" | |
| { | |
| "#format" "{1:N},{2:d}" | |
| "en" "{ORANGE}{1} {NORMAL}Defused The Bomb! {LIGHT_GREEN}(+{2})" | |
| } | |
| "RankTagFormat" | |
| { | |
| "#format" "{1:d}" | |
| "en" "[Rank {1}]" | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <sourcemod> | |
| #include <sdktools> | |
| #include <sdkhooks> | |
| #include <cstrike> | |
| #include <smlib> | |
| #include "include/priorityqueue.inc" | |
| #include "include/queue.inc" | |
| #include "include/restorecvars.inc" | |
| #include "include/retakes.inc" | |
| #include "include/clients.inc" | |
| #undef REQUIRE_PLUGIN | |
| #tryinclude <pugsetup> | |
| #pragma semicolon 1 | |
| #pragma newdecls required | |
| /*********************** | |
| * * | |
| * Global variables * | |
| * * | |
| ***********************/ | |
| /** | |
| * The general way players are put on teams is using a system of | |
| * "round points". Actions during a round earn points, and at the end of the round, | |
| * players are put into a priority queue using their rounds as the value. | |
| */ | |
| #define POINTS_MAX 10_000_000 | |
| #define POINTS_START 5_000_000 | |
| #define POINTS_MIN 0 | |
| #define POINTS_SPREAD 5_000_000 | |
| #define POINTS_KILL 250_000 | |
| #define POINTS_DMG 10_000 | |
| #define POINTS_BOMB 750_000 | |
| #define POINTS_BOMB_FAIL 2_500_000 | |
| #define POINTS_WIN 625_000 | |
| #define POINTS_SCALE 10_000 | |
| #define SITESTRING(%1) ((%1) == BombsiteA ? "A" : "B") | |
| #define TEAMSTRING(%1) ((%1) == CS_TEAM_CT ? "CT" : "T") | |
| bool g_Enabled = true; | |
| Handle g_SavedCvars = INVALID_HANDLE; | |
| /** Client variable arrays **/ | |
| int g_SpawnIndices[MAXPLAYERS+1] = 0; | |
| int g_RoundPoints[MAXPLAYERS+1] = 0; | |
| int g_RoundPointsChange[MAXPLAYERS+1] = 0; | |
| int g_LastRoundPointsChange[MAXPLAYERS+1] = 0; | |
| bool g_PluginTeamSwitch[MAXPLAYERS+1] = false; | |
| int g_Team[MAXPLAYERS+1] = 0; | |
| /** Queue Handles **/ | |
| Handle g_hWaitingQueue = INVALID_HANDLE; | |
| Handle g_hRankingQueue = INVALID_HANDLE; | |
| /** ConVar handles **/ | |
| ConVar g_EnabledCvar; | |
| ConVar g_hAutoTeamsCvar; | |
| ConVar g_hCvarVersion; | |
| ConVar g_hEditorEnabled; | |
| ConVar g_hMaxPlayers; | |
| ConVar g_hRoundTime; | |
| ConVar g_WarmupTimeCvar; | |
| /** Editing global variables **/ | |
| bool g_EditMode = false; | |
| bool g_DirtySpawns = false; // whether the spawns have been edited since loading from the file | |
| /** Win-streak data **/ | |
| int g_RoundCount = 0; | |
| bool g_HalfTime; | |
| /** Stored info from the spawns config file **/ | |
| #define MAX_SPAWNS 256 | |
| int g_NumSpawns = 0; | |
| bool g_SpawnDeleted[MAX_SPAWNS]; | |
| float g_SpawnPoints[MAX_SPAWNS][3]; | |
| float g_SpawnAngles[MAX_SPAWNS][3]; | |
| Bombsite g_SpawnSites[MAX_SPAWNS]; | |
| int g_SpawnTeams[MAX_SPAWNS]; | |
| SpawnType g_SpawnTypes[MAX_SPAWNS]; | |
| /** Spawns being edited per-client **/ | |
| int g_EditingSpawnTeams[MAXPLAYERS+1]; | |
| SpawnType g_EditingSpawnTypes[MAXPLAYERS+1]; | |
| /** Bomb-site stuff read from the map **/ | |
| ArrayList g_SiteMins; | |
| ArrayList g_SiteMaxs; | |
| /** Data created for the current retake scenario **/ | |
| Bombsite g_Bombsite; | |
| bool g_SpawnTaken[MAX_SPAWNS]; | |
| char g_PlayerPrimary[MAXPLAYERS+1][WEAPON_STRING_LENGTH]; | |
| char g_PlayerSecondary[MAXPLAYERS+1][WEAPON_STRING_LENGTH]; | |
| char g_PlayerNades[MAXPLAYERS+1][NADE_STRING_LENGTH]; | |
| int g_PlayerHealth[MAXPLAYERS+1]; | |
| int g_PlayerArmor[MAXPLAYERS+1]; | |
| bool g_PlayerHelmet[MAXPLAYERS+1]; | |
| bool g_PlayerKit[MAXPLAYERS+1]; | |
| /** Per-round information about the player setup **/ | |
| bool g_bombPlantSignal = false; | |
| bool g_bombPlanted = false; | |
| int g_BombOwner = -1; | |
| int g_NumCT = 0; | |
| int g_NumT = 0; | |
| int g_ActivePlayers = 0; | |
| bool g_RoundSpawnsDecided = false; // spawns are lazily decided on the first player spawn event | |
| /** Forwards **/ | |
| Handle g_hOnGunsCommand = INVALID_HANDLE; | |
| Handle g_hOnPostRoundEnqueue = INVALID_HANDLE; | |
| Handle g_hOnPreRoundEnqueue = INVALID_HANDLE; | |
| Handle g_hOnTeamSizesSet = INVALID_HANDLE; | |
| Handle g_hOnTeamsSet = INVALID_HANDLE; | |
| Handle g_OnFailToPlant = INVALID_HANDLE; | |
| Handle g_OnRoundWon = INVALID_HANDLE; | |
| Handle g_OnSitePicked = INVALID_HANDLE; | |
| Handle g_OnWeaponsAllocated = INVALID_HANDLE; | |
| #include "retakes/generic.sp" | |
| #include "retakes/editor.sp" | |
| #include "retakes/editor_commands.sp" | |
| #include "retakes/editor_menus.sp" | |
| #include "retakes/natives.sp" | |
| #include "retakes/spawns.sp" | |
| /*********************** | |
| * * | |
| * Sourcemod functions * | |
| * * | |
| ***********************/ | |
| public Plugin myinfo = { | |
| name = "CS:GO Retakes [ELO]", | |
| author = "samb, splewis", | |
| description = "CS:GO Retake practice with auto team balance", | |
| version = PLUGIN_VERSION, | |
| url = "https://github.com/splewis/csgo-retakes" | |
| }; | |
| public void OnPluginStart() { | |
| LoadTranslations("common.phrases"); | |
| LoadTranslations("retakes.phrases"); | |
| /** ConVars **/ | |
| g_EnabledCvar = CreateConVar("sm_retakes_enabled", "1", "Whether the plugin is enabled"); | |
| g_hAutoTeamsCvar = CreateConVar("sm_retakes_auto_set_teams", "1", "Whether retakes is allowed to automanage team balance"); | |
| g_hEditorEnabled = CreateConVar("sm_retakes_editor_enabled", "1", "Whether the editor can be launched by admins"); | |
| g_hMaxPlayers = CreateConVar("sm_retakes_maxplayers", "9", "Maximum number of players allowed in the game at once.", _, true, 2.0); | |
| g_hRoundTime = CreateConVar("sm_retakes_round_time", "12", "Round time left in seconds."); | |
| g_WarmupTimeCvar = CreateConVar("sm_retakes_warmuptime", "25", "Warmup time on map starts"); | |
| HookConVarChange(g_EnabledCvar, EnabledChanged); | |
| /** Create/Execute retakes cvars **/ | |
| AutoExecConfig(true, "retakes", "sourcemod/retakes"); | |
| g_hCvarVersion = CreateConVar("sm_retakes_version", PLUGIN_VERSION, "Current retakes version", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_DONTRECORD); | |
| g_hCvarVersion.SetString(PLUGIN_VERSION); | |
| /** Command hooks **/ | |
| AddCommandListener(Command_JoinTeam, "jointeam"); | |
| /** Admin/editor commands **/ | |
| RegAdminCmd("sm_edit", Command_EditSpawns, ADMFLAG_CHANGEMAP, "Launches the retakes spawn editor mode"); | |
| RegAdminCmd("sm_spawns", Command_EditSpawns, ADMFLAG_CHANGEMAP, "Launches the retakes spawn editor mode"); | |
| RegAdminCmd("sm_new", Command_AddSpawn, ADMFLAG_CHANGEMAP, "Creates a new retakes spawn"); | |
| RegAdminCmd("sm_newspawn", Command_AddSpawn, ADMFLAG_CHANGEMAP, "Creates a new retakes spawn"); | |
| RegAdminCmd("sm_delete", Command_DeleteSpawn, ADMFLAG_CHANGEMAP, "Deletes the nearest retakes spawn"); | |
| RegAdminCmd("sm_deletespawn", Command_DeleteSpawn, ADMFLAG_CHANGEMAP, "Deletes the nearest retakes spawn");\ | |
| RegAdminCmd("sm_deletemapspawns", Command_DeleteMapSpawns, ADMFLAG_CHANGEMAP, "Deletes all retakes spawns for the current map"); | |
| RegAdminCmd("sm_show", Command_Show, ADMFLAG_CHANGEMAP, "Shows all retakes spawns in a bombsite"); | |
| RegAdminCmd("sm_goto", Command_GotoSpawn, ADMFLAG_CHANGEMAP, "Goes to a retakes spawn"); | |
| RegAdminCmd("sm_nearest", Command_GotoNearestSpawn, ADMFLAG_CHANGEMAP, "Goes to nearest retakes spawn"); | |
| RegAdminCmd("sm_iteratespawns", Command_IterateSpawns, ADMFLAG_CHANGEMAP); | |
| RegAdminCmd("sm_reloadspawns", Command_ReloadSpawns, ADMFLAG_CHANGEMAP, "Reloads retakes spawns for the current map, discarding changes"); | |
| RegAdminCmd("sm_savespawns", Command_SaveSpawns, ADMFLAG_CHANGEMAP, "Saves retakes spawns for the current map"); | |
| /** Player commands **/ | |
| HookEvent("player_connect_full", Event_PlayerConnectFull); | |
| HookEvent("player_team", Event_PlayerTeam, EventHookMode_Pre); | |
| HookEvent("player_spawn", Event_PlayerSpawn); | |
| HookEvent("player_hurt", Event_DamageDealt); | |
| HookEvent("player_death", Event_PlayerDeath); | |
| HookEvent("round_prestart", Event_RoundPreStart); | |
| HookEvent("round_poststart", Event_RoundPostStart); | |
| HookEvent("round_freeze_end", Event_RoundFreezeEnd); | |
| HookEvent("bomb_planted", Event_BombPlant); | |
| HookEvent("bomb_exploded", Event_BombExploded); | |
| HookEvent("bomb_defused", Event_BombDefused); | |
| HookEvent("round_end", Event_RoundEnd); | |
| HookEvent("announce_phase_end", Event_HalfTime); | |
| g_hOnGunsCommand = CreateGlobalForward("Retakes_OnGunsCommand", ET_Ignore, Param_Cell); | |
| g_hOnPostRoundEnqueue = CreateGlobalForward("Retakes_OnPostRoundEnqueue", ET_Ignore, Param_Cell, Param_Cell); | |
| g_hOnPreRoundEnqueue = CreateGlobalForward("Retakes_OnPreRoundEnqueue", ET_Ignore, Param_Cell, Param_Cell); | |
| g_hOnTeamSizesSet = CreateGlobalForward("Retakes_OnTeamSizesSet", ET_Ignore, Param_CellByRef, Param_CellByRef); | |
| g_hOnTeamsSet = CreateGlobalForward("Retakes_OnTeamsSet", ET_Ignore, Param_Cell, Param_Cell, Param_Cell); | |
| g_OnFailToPlant = CreateGlobalForward("Retakes_OnFailToPlant", ET_Ignore, Param_Cell); | |
| g_OnRoundWon = CreateGlobalForward("Retakes_OnRoundWon", ET_Ignore, Param_Cell, Param_Cell, Param_Cell); | |
| g_OnSitePicked = CreateGlobalForward("Retakes_OnSitePicked", ET_Ignore, Param_CellByRef); | |
| g_OnWeaponsAllocated = CreateGlobalForward("Retakes_OnWeaponsAllocated", ET_Ignore, Param_Cell, Param_Cell, Param_Cell); | |
| g_SiteMins = new ArrayList(3); | |
| g_SiteMaxs = new ArrayList(3); | |
| g_hWaitingQueue = Queue_Init(); | |
| g_hRankingQueue = PQ_Init(); | |
| // Set inital spawn types. | |
| for (int i = 0; i < MAX_SPAWNS; i++) { | |
| g_SpawnTypes[i] = SpawnType_Normal; | |
| } | |
| } | |
| public void OnPluginEnd() { | |
| if (g_SavedCvars != INVALID_HANDLE) { | |
| RestoreCvars(g_SavedCvars, true); | |
| } | |
| } | |
| public void OnMapStart() { | |
| PQ_Clear(g_hRankingQueue); | |
| PQ_Clear(g_hWaitingQueue); | |
| g_RoundCount = 0; | |
| g_RoundSpawnsDecided = false; | |
| g_HalfTime = false; | |
| g_bombPlanted = false; | |
| g_bombPlantSignal = false; | |
| FindSites(); | |
| g_NumSpawns = ParseSpawns(); | |
| g_EditMode = false; | |
| CreateTimer(1.0, Timer_ShowSpawns, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); | |
| if (!g_Enabled) | |
| return; | |
| ExecConfigs(); | |
| // Restart warmup for players to connect. | |
| StartTimedWarmup(g_WarmupTimeCvar.IntValue); | |
| } | |
| public void OnMapEnd() { | |
| if (!g_Enabled) { | |
| return; | |
| } | |
| if (g_DirtySpawns) { | |
| WriteSpawns(); | |
| } | |
| } | |
| public int EnabledChanged(Handle cvar, const char[] oldValue, const char[] newValue) { | |
| bool wasEnabled = !StrEqual(oldValue, "0"); | |
| g_Enabled = !StrEqual(newValue, "0"); | |
| if (wasEnabled && !g_Enabled) { | |
| if (g_SavedCvars != INVALID_HANDLE) | |
| RestoreCvars(g_SavedCvars, true); | |
| } else if (!wasEnabled && g_Enabled) { | |
| Queue_Clear(g_hWaitingQueue); | |
| ExecConfigs(); | |
| for (int i = 1; i <= MaxClients; i++) { | |
| if (IsClientConnected(i) && !IsFakeClient(i)) { | |
| OnClientConnected(i); | |
| if (IsClientInGame(i) && IsOnTeam(i)) { | |
| SwitchPlayerTeam(i, CS_TEAM_SPECTATOR); | |
| Queue_Enqueue(g_hWaitingQueue, i); | |
| FakeClientCommand(i, "jointeam 2"); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| public void ExecConfigs() { | |
| if (g_SavedCvars != INVALID_HANDLE) { | |
| CloseCvarStorage(g_SavedCvars); | |
| } | |
| g_SavedCvars = ExecuteAndSaveCvars("sourcemod/retakes/retakes_game.cfg"); | |
| } | |
| public void OnClientConnected(int client) { | |
| ResetClientVariables(client); | |
| } | |
| public void OnClientDisconnect(int client) { | |
| ResetClientVariables(client); | |
| CheckRoundDone(); | |
| } | |
| /** | |
| * Helper functions that resets client variables when they join or leave. | |
| */ | |
| public void ResetClientVariables(int client) { | |
| if (client == g_BombOwner) | |
| g_BombOwner = -1; | |
| Queue_Drop(g_hWaitingQueue, client); | |
| g_Team[client] = CS_TEAM_SPECTATOR; | |
| g_PluginTeamSwitch[client] = false; | |
| g_RoundPoints[client] = POINTS_START; | |
| } | |
| public Action Command_Guns(int client, int args) { | |
| if (g_Enabled) { | |
| Call_StartForward(g_hOnGunsCommand); | |
| Call_PushCell(client); | |
| Call_Finish(); | |
| } | |
| return Plugin_Handled; | |
| } | |
| public Action OnClientSayCommand(int client, const char[] command, const char[] args) { | |
| if (!g_Enabled) { | |
| return Plugin_Continue; | |
| } | |
| static char gunsChatCommands[][] = { "gun", "guns", ".gun", ".guns", "!gun", "gnus" }; | |
| for (int i = 0; i < sizeof(gunsChatCommands); i++) { | |
| if (strcmp(args[0], gunsChatCommands[i], false) == 0) { | |
| Call_StartForward(g_hOnGunsCommand); | |
| Call_PushCell(client); | |
| Call_Finish(); | |
| break; | |
| } | |
| } | |
| return Plugin_Continue; | |
| } | |
| /*********************** | |
| * * | |
| * Command Hooks * | |
| * * | |
| ***********************/ | |
| public Action Command_JoinTeam(int client, const char[] command, int argc) { | |
| if (!g_Enabled || g_hAutoTeamsCvar.IntValue == 0) { | |
| return Plugin_Continue; | |
| } | |
| if (!IsValidClient(client) || argc < 1) | |
| return Plugin_Handled; | |
| if (g_EditMode) { | |
| MovePlayerToEditMode(client); | |
| return Plugin_Handled; | |
| } | |
| char arg[4]; | |
| GetCmdArg(1, arg, sizeof(arg)); | |
| int team_to = StringToInt(arg); | |
| int team_from = GetClientTeam(client); | |
| // if same team, teamswitch controlled by the plugin | |
| // note if a player hits autoselect their team_from=team_to=CS_TEAM_NONE | |
| if ((team_from == team_to && team_from != CS_TEAM_NONE) || g_PluginTeamSwitch[client] || IsFakeClient(client)) { | |
| return Plugin_Continue; | |
| } else { | |
| // ignore switches between T/CT team | |
| if ( (team_from == CS_TEAM_CT && team_to == CS_TEAM_T ) | |
| || (team_from == CS_TEAM_T && team_to == CS_TEAM_CT)) { | |
| return Plugin_Handled; | |
| } else if (team_to == CS_TEAM_SPECTATOR) { | |
| // voluntarily joining spectator will not put you in the queue | |
| SwitchPlayerTeam(client, CS_TEAM_SPECTATOR); | |
| Queue_Drop(g_hWaitingQueue, client); | |
| // check if a team is now empty | |
| CheckRoundDone(); | |
| return Plugin_Handled; | |
| } else { | |
| return PlacePlayer(client); | |
| } | |
| } | |
| } | |
| /** | |
| * Generic logic for placing a player into the correct team when they join. | |
| */ | |
| public Action PlacePlayer(int client) { | |
| int tHumanCount=0, ctHumanCount=0, nPlayers=0; | |
| GetTeamsClientCounts(tHumanCount, ctHumanCount); | |
| nPlayers = tHumanCount + ctHumanCount; | |
| if (Retakes_InWarmup() && nPlayers < g_hMaxPlayers.IntValue) { | |
| return Plugin_Continue; | |
| } | |
| if (nPlayers < 2) { | |
| ChangeClientTeam(client, CS_TEAM_SPECTATOR); | |
| Queue_Enqueue(g_hWaitingQueue, client); | |
| CS_TerminateRound(0.0, CSRoundEnd_CTWin); | |
| return Plugin_Handled; | |
| } | |
| ChangeClientTeam(client, CS_TEAM_SPECTATOR); | |
| Queue_Enqueue(g_hWaitingQueue, client); | |
| Retakes_Message(client, "%t", "JoinedQueueMessage"); | |
| return Plugin_Handled; | |
| } | |
| /*********************** | |
| * * | |
| * Event Hooks * | |
| * * | |
| ***********************/ | |
| public int Helper_GetEloDisplay(int elo) { | |
| return (elo + (POINTS_SCALE / 2)) / POINTS_SCALE; | |
| } | |
| public int Helper_UpdateScoreboard(int player) { | |
| if(IsPlayer(player)) { | |
| CS_SetMVPCount(player, 0); | |
| CS_SetClientAssists(player, 0); | |
| int score = g_RoundPoints[player] + g_RoundPointsChange[player]; | |
| CS_SetClientContributionScore(player, Helper_GetEloDisplay(score)); | |
| } | |
| } | |
| public int Helper_GetEloDelta(int w_elo, int l_elo, int k) { | |
| float score_diff = float(l_elo - w_elo); | |
| float e_winner = 1.0 / (1.0 + Pow(10.0, score_diff / float(POINTS_SPREAD))); | |
| float e_loser = 1.0 - e_winner; | |
| float delta = e_loser * k; | |
| return RoundToNearest(delta); | |
| } | |
| /** | |
| * Called when a player joins a team, silences team join events | |
| */ | |
| public Action Event_PlayerTeam(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!g_Enabled) { | |
| return Plugin_Continue; | |
| } | |
| SetEventBroadcast(event, true); | |
| return Plugin_Continue; | |
| } | |
| /** | |
| * Full connect event right when a player joins. | |
| * This sets the auto-pick time to a high value because mp_forcepicktime is broken and | |
| * if a player does not select a team but leaves their mouse over one, they are | |
| * put on that team and spawned, so we can't allow that. | |
| */ | |
| public Action Event_PlayerConnectFull(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!g_Enabled) { | |
| return; | |
| } | |
| int client = GetClientOfUserId(GetEventInt(event, "userid")); | |
| SetEntPropFloat(client, Prop_Send, "m_fForceTeam", 3600.0); | |
| } | |
| /** | |
| * Called when a player spawns. | |
| * Gives default weapons. (better than mp_ct_default_primary since it gives the player the correct skin) | |
| */ | |
| public Action Event_PlayerSpawn(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!g_Enabled) { | |
| return; | |
| } | |
| int client = GetClientOfUserId(GetEventInt(event, "userid")); | |
| if (!IsValidClient(client) || !IsOnTeam(client) || g_EditMode || Retakes_InWarmup()) | |
| return; | |
| if (!g_RoundSpawnsDecided) { | |
| if (IsPlayer(g_BombOwner)) { | |
| g_SpawnIndices[g_BombOwner] = SelectSpawn(CS_TEAM_T, true); | |
| } | |
| for (int i = 1; i <= MAXPLAYERS; i++) { | |
| if (IsPlayer(i) && IsOnTeam(i) && i != g_BombOwner) { | |
| g_SpawnIndices[i] = SelectSpawn(g_Team[i], false); | |
| } | |
| } | |
| g_RoundSpawnsDecided = true; | |
| } | |
| SetupPlayer(client); | |
| } | |
| /** | |
| * Called when a player dies - gives points to killer, and does database stuff with the kill. | |
| */ | |
| public Action Event_PlayerDeath(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return; | |
| } | |
| int victim = GetClientOfUserId(GetEventInt(event, "userid")); | |
| int attacker = GetClientOfUserId(GetEventInt(event, "attacker")); | |
| bool validAttacker = IsValidClient(attacker); | |
| bool validVictim = IsValidClient(victim); | |
| if (validAttacker && validVictim) { | |
| if (HelpfulAttack(attacker, victim)) { | |
| int diff = Helper_GetEloDelta(g_RoundPoints[attacker], g_RoundPoints[victim], POINTS_KILL); | |
| g_RoundPointsChange[attacker] += diff; | |
| g_RoundPointsChange[victim] -= diff; | |
| Retakes_Message(attacker, "%t", "PlayerKilled", victim, Helper_GetEloDisplay(diff)); | |
| Retakes_Message(victim, "%t", "PlayerKilledBy", attacker, Helper_GetEloDisplay(diff)); | |
| } else { | |
| g_RoundPointsChange[attacker] -= POINTS_KILL; | |
| Retakes_Message(attacker, "%t", "PlayerTeamKilled", victim, Helper_GetEloDisplay(POINTS_KILL)); | |
| } | |
| Helper_UpdateScoreboard(attacker); | |
| Helper_UpdateScoreboard(victim); | |
| } | |
| } | |
| /** | |
| * Called when a player deals damage to another player - ads round points if needed. | |
| */ | |
| public Action Event_DamageDealt(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return Plugin_Continue; | |
| } | |
| int attacker = GetClientOfUserId(GetEventInt(event, "attacker")); | |
| int victim = GetClientOfUserId(GetEventInt(event, "userid")); | |
| bool validAttacker = IsValidClient(attacker); | |
| bool validVictim = IsValidClient(victim); | |
| if (validAttacker && validVictim) { | |
| int damage = GetEventInt(event, "dmg_health"); | |
| if(damage > 100) | |
| damage = 100; | |
| if(HelpfulAttack(attacker, victim)) { | |
| int diff = Helper_GetEloDelta(g_RoundPoints[attacker], g_RoundPoints[victim], damage * POINTS_DMG); | |
| g_RoundPointsChange[attacker] += diff; | |
| g_RoundPointsChange[victim] -= diff; | |
| Retakes_Message(attacker, "%t", "PlayerDamaged", victim, damage, Helper_GetEloDisplay(diff)); | |
| Retakes_Message(victim, "%t", "PlayerDamagedBy", attacker, damage, Helper_GetEloDisplay(diff)); | |
| } else { | |
| int diff = damage * POINTS_DMG; | |
| g_RoundPointsChange[attacker] -= diff; | |
| Retakes_Message(attacker, "%t", "PlayerTeamDamaged", victim, damage, Helper_GetEloDisplay(diff)); | |
| } | |
| } | |
| Helper_UpdateScoreboard(attacker); | |
| Helper_UpdateScoreboard(victim); | |
| return Plugin_Continue; | |
| } | |
| /** | |
| * Called when the bomb explodes or is defuser, gives ponts to the one that planted/defused it. | |
| */ | |
| public Action Event_BombPlant(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!g_Enabled) { | |
| return; | |
| } | |
| g_bombPlanted = true; | |
| g_bombPlantSignal = false; | |
| } | |
| /** | |
| * Called when the bomb explodes or is defused, gives ponts to the one that planted/defused it. | |
| */ | |
| public Action Event_BombDefused(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return; | |
| } | |
| int client = GetClientOfUserId(GetEventInt(event, "userid")); | |
| if (IsValidClient(client)) { | |
| int diff = Helper_GetEloDelta(g_RoundPointsChange[client], POINTS_START, POINTS_BOMB); | |
| g_RoundPointsChange[client] += diff; | |
| Helper_UpdateScoreboard(client); | |
| Retakes_MessageToAll("%t", "BombDefused", client, Helper_GetEloDisplay(diff)); | |
| } | |
| } | |
| /** | |
| * Called when the bomb explodes or is defused, gives ponts to the one that planted/defused it. | |
| */ | |
| public Action Event_BombExploded(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return; | |
| } | |
| } | |
| /** | |
| * Called before any other round start events. This is the best place to change teams | |
| * since it should happen before respawns. | |
| */ | |
| public Action Event_RoundPreStart(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return; | |
| } | |
| g_RoundSpawnsDecided = false; | |
| RoundEndUpdates(); | |
| UpdateTeams(); | |
| g_HalfTime = false; | |
| int best_player = 1; | |
| for (int i = 1; i < MaxClients; i++) { | |
| if (IsValidClient(i) && IsOnTeam(i)) { | |
| Client_RemoveAllWeapons(i); | |
| Helper_UpdateScoreboard(i); | |
| if (GetClientTeam(i) == CS_TEAM_T) { | |
| if(g_RoundPoints[best_player] <= g_RoundPoints[i]) { | |
| best_player = i; | |
| } | |
| } | |
| } | |
| } | |
| g_BombOwner = best_player; | |
| } | |
| public Action Event_RoundPostStart(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return; | |
| } | |
| if (!g_EditMode) { | |
| GameRules_SetProp("m_iRoundTime", g_hRoundTime.IntValue, 4, 0, true); | |
| Retakes_MessageToAll("%t", "RetakeSiteMessage", SITESTRING(g_Bombsite), g_NumT, g_NumCT); | |
| } | |
| g_bombPlanted = false; | |
| } | |
| /** | |
| * Round freezetime end, resets the round points and unfreezes the players. | |
| */ | |
| public Action Event_RoundFreezeEnd(Handle event, const char[] name, bool dontBroadcast) { | |
| for (int i = 1; i <= MaxClients; i++) { | |
| g_RoundPointsChange[i] = 0; | |
| Helper_UpdateScoreboard(i); | |
| } | |
| } | |
| /** | |
| * Round end event, calls the appropriate winner (T/CT) unction and sets the scores. | |
| */ | |
| public Action Event_RoundEnd(Handle event, const char[] name, bool dontBroadcast) { | |
| if (!Retakes_Live()) { | |
| return; | |
| } | |
| if (g_ActivePlayers >= 2) { | |
| g_RoundCount++; | |
| int winner = GetEventInt(event, "winner"); | |
| ArrayList ts = new ArrayList(); | |
| ArrayList cts = new ArrayList(); | |
| int t_points = 0; | |
| int ct_points = 0; | |
| int total_points = 0; | |
| g_ActivePlayers = 0; | |
| g_NumCT = 0; | |
| g_NumT = 0; | |
| for (int i = 1; i <= MaxClients; i++) { | |
| if (IsPlayer(i)) { | |
| if (GetClientTeam(i) == CS_TEAM_CT) { | |
| g_ActivePlayers += 1; | |
| g_NumCT += 1; | |
| total_points += g_RoundPoints[i] + g_RoundPointsChange[i]; | |
| ct_points += g_RoundPoints[i]; | |
| cts.Push(i); | |
| } | |
| else if (GetClientTeam(i) == CS_TEAM_T) { | |
| g_ActivePlayers += 1; | |
| g_NumT += 1; | |
| total_points += g_RoundPoints[i] + g_RoundPointsChange[i]; | |
| t_points += g_RoundPoints[i]; | |
| ts.Push(i); | |
| } | |
| } | |
| } | |
| Call_StartForward(g_OnRoundWon); | |
| Call_PushCell(winner); | |
| Call_PushCell(ts); | |
| Call_PushCell(cts); | |
| Call_Finish(); | |
| delete ts; | |
| delete cts; | |
| ct_points /= g_ActivePlayers; | |
| t_points /= g_ActivePlayers; | |
| total_points /= g_ActivePlayers; | |
| int adj_diff = POINTS_START - total_points; | |
| if(winner == CS_TEAM_CT) { | |
| int diff = Helper_GetEloDelta(ct_points, t_points, POINTS_WIN); | |
| diff *= g_ActivePlayers; | |
| for (int i = 1; i <= MaxClients; i++) { | |
| if (IsPlayer(i)) { | |
| if(GetClientTeam(i) == CS_TEAM_CT) { | |
| g_RoundPointsChange[i] += diff / g_NumCT; | |
| g_RoundPointsChange[i] += adj_diff; | |
| Retakes_Message(i, "%t", "PlayerWonRound", Helper_GetEloDisplay(diff)); | |
| } | |
| else if(GetClientTeam(i) == CS_TEAM_T) { | |
| g_RoundPointsChange[i] -= diff / g_NumT; | |
| g_RoundPointsChange[i] += adj_diff; | |
| Retakes_Message(i, "%t", "PlayerLostRound", Helper_GetEloDisplay(diff)); | |
| } | |
| if(0 < g_RoundPointsChange[i]) { | |
| Retakes_Message(i, "%t", "PlayerGainedPoints", Helper_GetEloDisplay(g_RoundPointsChange[i])); | |
| } else { | |
| Retakes_Message(i, "%t", "PlayerLostPoints", Helper_GetEloDisplay(g_RoundPointsChange[i])); | |
| } | |
| Helper_UpdateScoreboard(i); | |
| } | |
| } | |
| CounterTerroristsWon(); | |
| } else if (winner == CS_TEAM_T) { | |
| int diff = Helper_GetEloDelta(t_points, ct_points, POINTS_WIN); | |
| for (int i = 1; i <= MaxClients; i++) { | |
| if (IsPlayer(i)) { | |
| if(GetClientTeam(i) == CS_TEAM_T) { | |
| g_RoundPointsChange[i] += diff; | |
| Retakes_Message(i, "%t", "PlayerWonRound", Helper_GetEloDisplay(diff)); | |
| } | |
| else if(GetClientTeam(i) == CS_TEAM_CT) { | |
| g_RoundPointsChange[i] -= diff; | |
| Retakes_Message(i, "%t", "PlayerLostRound", Helper_GetEloDisplay(diff)); | |
| } | |
| if(0 < g_RoundPointsChange[i]) { | |
| Retakes_Message(i, "%t", "PlayerGainedPoints", Helper_GetEloDisplay(g_RoundPointsChange[i])); | |
| } else { | |
| Retakes_Message(i, "%t", "PlayerLostPoints", Helper_GetEloDisplay(g_RoundPointsChange[i])); | |
| } | |
| Helper_UpdateScoreboard(i); | |
| } | |
| } | |
| TerroristsWon(); | |
| } | |
| } | |
| } | |
| public Action Event_HalfTime(Handle event, const char[] name, bool dontBroadcast) | |
| { | |
| g_HalfTime = true; | |
| } | |
| /*********************** | |
| * * | |
| * Retakes logic * | |
| * * | |
| ***********************/ | |
| /** | |
| * Called at the end of the round - puts all the players into a priority queue by | |
| * their score for placing them next round. | |
| */ | |
| public void RoundEndUpdates() { | |
| PQ_Clear(g_hRankingQueue); | |
| Call_StartForward(g_hOnPreRoundEnqueue); | |
| Call_PushCell(g_hRankingQueue); | |
| Call_PushCell(g_hWaitingQueue); | |
| Call_Finish(); | |
| for (int i = 1; i <= MaxClients; i++) { | |
| if (IsPlayer(i) && IsOnTeam(i)) { | |
| Helper_UpdateScoreboard(i); | |
| g_RoundPoints[i] += g_RoundPointsChange[i]; | |
| g_LastRoundPointsChange[i] = g_RoundPointsChange[i]; | |
| g_RoundPointsChange[i] = 0; | |
| if(g_RoundPoints[i] < POINTS_MIN) { | |
| g_RoundPoints[i] = POINTS_MIN; | |
| } | |
| if(g_RoundPoints[i] > POINTS_MAX) { | |
| g_RoundPoints[i] = POINTS_MAX; | |
| } | |
| } else { | |
| g_RoundPoints[i] = POINTS_START; | |
| g_RoundPointsChange[i] = 0; | |
| g_LastRoundPointsChange[i] = 0; | |
| } | |
| } | |
| for (int client = 1; client <= MaxClients; client++) { | |
| if (IsPlayer(client) && IsOnTeam(client)) { | |
| PQ_Enqueue(g_hRankingQueue, client, g_RoundPoints[client]); | |
| } | |
| } | |
| while (!Queue_IsEmpty(g_hWaitingQueue) && PQ_GetSize(g_hRankingQueue) < g_hMaxPlayers.IntValue) { | |
| int client = Queue_Dequeue(g_hWaitingQueue); | |
| if (IsPlayer(client)) { | |
| PQ_Enqueue(g_hRankingQueue, client, 0); | |
| } else { | |
| break; | |
| } | |
| } | |
| if (g_hAutoTeamsCvar.IntValue == 0) { | |
| PQ_Clear(g_hRankingQueue); | |
| } | |
| Call_StartForward(g_hOnPostRoundEnqueue); | |
| Call_PushCell(g_hRankingQueue); | |
| Call_PushCell(g_hWaitingQueue); | |
| Call_Finish(); | |
| } | |
| /** | |
| * Places players onto the correct team. | |
| * This assumes the priority queue has already been built (e.g. by RoundEndUpdates). | |
| */ | |
| public void UpdateTeams() { | |
| for (int i = 0; i < MAX_SPAWNS; i++) { | |
| g_SpawnTaken[i] = false; | |
| } | |
| if (g_NumSpawns < g_hMaxPlayers.IntValue) { | |
| LogError("This map does not have enough spawns!"); | |
| return; | |
| } | |
| g_Bombsite = GetRandomBool() ? BombsiteA : BombsiteB; | |
| Call_StartForward(g_OnSitePicked); | |
| Call_PushCellRef(g_Bombsite); | |
| Call_Finish(); | |
| g_ActivePlayers = PQ_GetSize(g_hRankingQueue); | |
| if (g_ActivePlayers > g_hMaxPlayers.IntValue) | |
| g_ActivePlayers = g_hMaxPlayers.IntValue; | |
| Call_StartForward(g_hOnTeamSizesSet); | |
| Call_PushCellRef(g_NumT); | |
| Call_PushCellRef(g_NumCT); | |
| Call_Finish(); | |
| ArrayList ts = new ArrayList(); | |
| ArrayList cts = new ArrayList(); | |
| if (g_hAutoTeamsCvar.IntValue != 0) { | |
| int t_points = 0; | |
| int ct_points = 0; | |
| g_NumT = 0; | |
| g_NumCT = 0; | |
| for(int i = 0; i < g_ActivePlayers; i++) { | |
| int client = PQ_Dequeue(g_hRankingQueue); | |
| if (IsValidClient(client)) { | |
| Helper_UpdateScoreboard(client); | |
| char rank[32]; | |
| Format(rank, sizeof(rank), "%T", "RankTagFormat", LANG_SERVER, 1 + i); | |
| CS_SetClientClanTag(client, rank); | |
| if(t_points <= ct_points) { | |
| if(0 <= g_LastRoundPointsChange[client]) { | |
| Retakes_MessageToAll("%t", "PlayerAssignedTUp", 1 + i, client, Helper_GetEloDisplay(g_RoundPoints[client]), Helper_GetEloDisplay(g_LastRoundPointsChange[client])); | |
| } else { | |
| Retakes_MessageToAll("%t", "PlayerAssignedTDown", 1 + i, client, Helper_GetEloDisplay(g_RoundPoints[client]), Helper_GetEloDisplay(g_LastRoundPointsChange[client])); | |
| } | |
| g_NumT += 1; | |
| t_points += g_RoundPoints[client]; | |
| ts.Push(client); | |
| } else { | |
| if(0 <= g_LastRoundPointsChange[client]) { | |
| Retakes_MessageToAll("%t", "PlayerAssignedCTUp", 1 + i, client, Helper_GetEloDisplay(g_RoundPoints[client]), Helper_GetEloDisplay(g_LastRoundPointsChange[client])); | |
| } else { | |
| Retakes_MessageToAll("%t", "PlayerAssignedCTDown", 1 + i, client, Helper_GetEloDisplay(g_RoundPoints[client]), Helper_GetEloDisplay(g_LastRoundPointsChange[client])); | |
| } | |
| g_NumCT += 1; | |
| ct_points += g_RoundPoints[client]; | |
| cts.Push(client); | |
| } | |
| } | |
| } | |
| } else { | |
| // Use the already set teams | |
| for (int i = 1; i <= MaxClients; i++) { | |
| if (IsValidClient(i)) { | |
| Helper_UpdateScoreboard(i); | |
| bool ct = GetClientTeam(i) == CS_TEAM_CT; | |
| bool t = GetClientTeam(i) == CS_TEAM_T; | |
| if ((ct && !g_HalfTime) || (t && g_HalfTime)) | |
| cts.Push(i); | |
| else if ((t && !g_HalfTime) || (ct && g_HalfTime)) | |
| ts.Push(i); | |
| } | |
| } | |
| g_NumCT = cts.Length; | |
| g_NumT = ts.Length; | |
| g_ActivePlayers = g_NumCT + g_NumT; | |
| } | |
| Call_StartForward(g_hOnTeamsSet); | |
| Call_PushCell(ts); | |
| Call_PushCell(cts); | |
| Call_PushCell(g_Bombsite); | |
| Call_Finish(); | |
| for (int i = 0; i < GetArraySize(ts); i++) { | |
| int client = GetArrayCell(ts, i); | |
| if (IsValidClient(client)) { | |
| Helper_UpdateScoreboard(client); | |
| SwitchPlayerTeam(client, CS_TEAM_T); | |
| g_Team[client] = CS_TEAM_T; | |
| g_PlayerPrimary[client] = "weapon_ak47"; | |
| g_PlayerSecondary[client] = "weapon_glock"; | |
| g_PlayerNades[client] = ""; | |
| g_PlayerKit[client] = false; | |
| g_PlayerHealth[client] = 100; | |
| g_PlayerArmor[client] = 100; | |
| g_PlayerHelmet[client] = true; | |
| } | |
| } | |
| for (int i = 0; i < GetArraySize(cts); i++) { | |
| int client = GetArrayCell(cts, i); | |
| if (IsValidClient(client)) { | |
| Helper_UpdateScoreboard(client); | |
| SwitchPlayerTeam(client, CS_TEAM_CT); | |
| g_Team[client] = CS_TEAM_CT; | |
| g_PlayerPrimary[client] = "weapon_m4a1"; | |
| g_PlayerSecondary[client] = "weapon_hkp2000"; | |
| g_PlayerNades[client] = ""; | |
| g_PlayerKit[client] = true; | |
| g_PlayerHealth[client] = 100; | |
| g_PlayerArmor[client] = 100; | |
| g_PlayerHelmet[client] = true; | |
| } | |
| } | |
| // if somebody didn't get put in, put them back into the waiting queue | |
| while (!PQ_IsEmpty(g_hRankingQueue)) { | |
| int client = PQ_Dequeue(g_hRankingQueue); | |
| if (IsPlayer(client)) { | |
| Queue_EnqueueFront(g_hWaitingQueue, client); | |
| } | |
| } | |
| Call_StartForward(g_OnWeaponsAllocated); | |
| Call_PushCell(ts); | |
| Call_PushCell(cts); | |
| Call_PushCell(g_Bombsite); | |
| Call_Finish(); | |
| int length = Queue_Length(g_hWaitingQueue); | |
| for (int i = 0; i < length; i++) { | |
| int client = GetArrayCell(g_hWaitingQueue, i); | |
| if (IsValidClient(client)) { | |
| Retakes_Message(client, "%t", "WaitingQueueMessage", g_hMaxPlayers.IntValue); | |
| } | |
| } | |
| delete ts; | |
| delete cts; | |
| ServerCommand("bot_kick"); | |
| } | |
| public void TerroristsWon() { | |
| } | |
| public void CounterTerroristsWon() { | |
| if (!g_bombPlanted && IsValidClient(g_BombOwner) && g_RoundCount >= 3) { | |
| int diff = Helper_GetEloDelta(POINTS_START, g_RoundPoints[g_BombOwner], POINTS_BOMB_FAIL); | |
| g_RoundPointsChange[g_BombOwner] -= diff; | |
| Helper_UpdateScoreboard(g_BombOwner); | |
| Retakes_MessageToAll("%t", "FailedToPlant", g_BombOwner, Helper_GetEloDisplay(diff)); | |
| Call_StartForward(g_OnFailToPlant); | |
| Call_PushCell(g_BombOwner); | |
| Call_Finish(); | |
| } | |
| } | |
| void CheckRoundDone() { | |
| int tHumanCount=0, ctHumanCount=0; | |
| GetTeamsClientCounts(tHumanCount, ctHumanCount); | |
| if (tHumanCount == 0 || ctHumanCount == 0) { | |
| CS_TerminateRound(0.1, CSRoundEnd_TerroristWin); | |
| } | |
| } | |
| public int GetOtherTeam(int team) { | |
| return (team == CS_TEAM_CT) ? CS_TEAM_T : CS_TEAM_CT; | |
| } | |
| public Bombsite GetOtherSite(Bombsite site) { | |
| return (site == BombsiteA) ? BombsiteB : BombsiteA; | |
| } | |
| // pugsetup (github.com/splewis/csgo-pug-setup) integrations | |
| #if defined _pugsetup_included | |
| public Action PugSetup_OnSetupMenuOpen(int client, Menu menu, bool displayOnly) { | |
| int leader = PugSetup_GetLeader(false); | |
| if (!IsPlayer(leader)) { | |
| PugSetup_SetLeader(client); | |
| } | |
| int style = ITEMDRAW_DEFAULT; | |
| if (!PugSetup_HasPermissions(client, Permission_Leader) || displayOnly) { | |
| style = ITEMDRAW_DISABLED; | |
| } | |
| if (g_Enabled) { | |
| AddMenuItem(menu, "disable_retakes", "Disable retakes", style); | |
| } else { | |
| AddMenuItem(menu, "enable_retakes", "Enable retakes", style); | |
| } | |
| return Plugin_Continue; | |
| } | |
| public void PugSetup_OnSetupMenuSelect(Menu menu, int client, const char[] selected_info, int selected_position) { | |
| if (StrEqual(selected_info, "disable_retakes")) { | |
| SetConVarInt(g_EnabledCvar, 0); | |
| PugSetup_GiveSetupMenu(client, false, selected_position); | |
| } else if (StrEqual(selected_info, "enable_retakes")) { | |
| SetConVarInt(g_EnabledCvar, 1); | |
| PugSetup_GiveSetupMenu(client, false, selected_position); | |
| } | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment