csrd_jointeam_fix.sp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * [CSRD] `jointeam` Fix
  3. */
  4. #pragma semicolon 1
  5. #include <sourcemod>
  6. #include <sdktools>
  7. #pragma newdecls required
  8. #define PLUGIN_VERSION "1.1.0"
  9. public Plugin myinfo = {
  10. name = "[CSRD] `jointeam` Fix",
  11. author = "nosoop",
  12. description = "Redisplays the team selection panel if the player is on cooldown while "
  13. ... "unassigned.",
  14. version = PLUGIN_VERSION,
  15. url = "https://git.csrd.science/"
  16. }
  17. any offs_CTFPlayer_flNextTimeAllowTeamChange;
  18. ConVar tf_arena_use_queue;
  19. public void OnPluginStart() {
  20. // cross-reference against the offset assigned a few blocks above the inlined
  21. // CTFPlayer::HandleCommand_JoinTeam() call in ::ClientCommand()
  22. offs_CTFPlayer_flNextTimeAllowTeamChange = FindSendPropInfo("CTFPlayer", "m_hItem") + 0x18;
  23. tf_arena_use_queue = FindConVar("tf_arena_use_queue");
  24. AddCommandListener(OnClientJoinTeam, "jointeam");
  25. UserMsg vguiMessage = GetUserMessageId("VGUIMenu");
  26. HookUserMessage(vguiMessage, OnVGUIMenuPreSent, true);
  27. }
  28. /**
  29. * Intercepts attempts to join team; if the player is on cooldown, then wait a bit before
  30. * redisplaying the team select panel.
  31. */
  32. Action OnClientJoinTeam(int client, const char[] command, int argc) {
  33. if (!client || GetClientTeam(client)) {
  34. return Plugin_Continue;
  35. }
  36. float flNextAllowedTeamChange = GetEntDataFloat(client,
  37. offs_CTFPlayer_flNextTimeAllowTeamChange);
  38. if (flNextAllowedTeamChange > GetGameTime()) {
  39. // we're not allowed to change teams right now --
  40. // silently block the attempt then redisplay once the cooldown is over
  41. CreateTimer(0.1 + flNextAllowedTeamChange - GetGameTime(), RedisplayTeamSelectMenu,
  42. GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
  43. return Plugin_Handled;
  44. }
  45. return Plugin_Continue;
  46. }
  47. /**
  48. * Intercepts attempts to transmit the team select panel to a client, delaying transmission if
  49. * the player is unassigned and on cooldown.
  50. */
  51. Action OnVGUIMenuPreSent(UserMsg vguiMessage, BfRead buffer, const int[] players,
  52. int nPlayers, bool reliable, bool init) {
  53. // vgui usermessages are expected to only have a single recipient
  54. if (nPlayers != 1) {
  55. return Plugin_Continue;
  56. }
  57. char name[128];
  58. buffer.ReadString(name, sizeof(name));
  59. if (!StrEqual(name, "arenateampanel") && !StrEqual(name, "team")) {
  60. return Plugin_Continue;
  61. }
  62. int client = players[0];
  63. if (GetClientTeam(client)) {
  64. return Plugin_Continue;
  65. }
  66. float flNextAllowedTeamChange = GetEntDataFloat(client,
  67. offs_CTFPlayer_flNextTimeAllowTeamChange);
  68. if (flNextAllowedTeamChange > GetGameTime()) {
  69. // we're not allowed to change teams right now --
  70. // silently block the attempt then redisplay once the cooldown is over
  71. CreateTimer(0.1 + flNextAllowedTeamChange - GetGameTime(), RedisplayTeamSelectMenu,
  72. GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
  73. return Plugin_Handled;
  74. }
  75. return Plugin_Continue;
  76. }
  77. /**
  78. * Redisplay the team select panel.
  79. */
  80. Action RedisplayTeamSelectMenu(Handle timer, int clientserial) {
  81. int client = GetClientFromSerial(clientserial);
  82. if (!client) {
  83. return Plugin_Handled;
  84. }
  85. if (IsInArenaMode() && tf_arena_use_queue.BoolValue) {
  86. ShowVGUIPanel(client, "arenateampanel");
  87. } else {
  88. ShowVGUIPanel(client, "team");
  89. }
  90. return Plugin_Handled;
  91. }
  92. bool IsInArenaMode() {
  93. return GameRules_GetProp("m_nGameType") == 4;
  94. }