/** * [CSRD] `jointeam` Fix */ #pragma semicolon 1 #include #include #pragma newdecls required #define PLUGIN_VERSION "1.1.1" public Plugin myinfo = { name = "[CSRD] `jointeam` Fix", author = "nosoop", description = "Redisplays the team selection panel if the player is on cooldown while " ... "unassigned.", version = PLUGIN_VERSION, url = "https://git.csrd.science/" } any offs_CTFPlayer_flNextTimeAllowTeamChange; ConVar tf_arena_use_queue; public void OnPluginStart() { // cross-reference against the offset assigned a few blocks above the inlined // CTFPlayer::HandleCommand_JoinTeam() call in ::ClientCommand() offs_CTFPlayer_flNextTimeAllowTeamChange = FindSendPropInfo("CTFPlayer", "m_hItem") + 0x18; tf_arena_use_queue = FindConVar("tf_arena_use_queue"); AddCommandListener(OnClientJoinTeam, "jointeam"); UserMsg vguiMessage = GetUserMessageId("VGUIMenu"); HookUserMessage(vguiMessage, OnVGUIMenuPreSent, true); } /** * Intercepts attempts to join team; if the player is on cooldown, then wait a bit before * redisplaying the team select panel. */ Action OnClientJoinTeam(int client, const char[] command, int argc) { // block the command if we're resending on a `jointeam` cooldown return client && QueueResendTeamChangePanel(client)? Plugin_Handled : Plugin_Continue; } /** * Intercepts attempts to transmit the team select panel to a client, delaying transmission if * the player is unassigned and on cooldown. */ Action OnVGUIMenuPreSent(UserMsg vguiMessage, BfRead buffer, const int[] players, int nPlayers, bool reliable, bool init) { // vgui usermessages are expected to only have a single recipient if (nPlayers != 1) { return Plugin_Continue; } char name[128]; buffer.ReadString(name, sizeof(name)); if (!StrEqual(name, "arenateampanel") && !StrEqual(name, "team")) { return Plugin_Continue; } int client = players[0]; // block the message if we're resending on a `jointeam` cooldown return QueueResendTeamChangePanel(client)? Plugin_Handled : Plugin_Continue; } bool QueueResendTeamChangePanel(int client) { // return early if client is assigned to a team if (GetClientTeam(client)) { return false; } float flNextAllowedTeamChange = GetEntDataFloat(client, offs_CTFPlayer_flNextTimeAllowTeamChange); if (flNextAllowedTeamChange > GetGameTime()) { // we're not allowed to change teams right now, so set a timer to redisplay CreateTimer(0.1 + flNextAllowedTeamChange - GetGameTime(), RedisplayTeamSelectMenu, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE); return true; } return false; } /** * Redisplay the team select panel. */ Action RedisplayTeamSelectMenu(Handle timer, int clientserial) { int client = GetClientFromSerial(clientserial); if (!client) { return Plugin_Handled; } if (IsInArenaMode() && tf_arena_use_queue.BoolValue) { ShowVGUIPanel(client, "arenateampanel"); } else { ShowVGUIPanel(client, "team"); } return Plugin_Handled; } bool IsInArenaMode() { return GameRules_GetProp("m_nGameType") == 4; }