csrd_jointeam_fix.sp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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.1"
  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. // block the command if we're resending on a `jointeam` cooldown
  34. return client && QueueResendTeamChangePanel(client)? Plugin_Handled : Plugin_Continue;
  35. }
  36. /**
  37. * Intercepts attempts to transmit the team select panel to a client, delaying transmission if
  38. * the player is unassigned and on cooldown.
  39. */
  40. Action OnVGUIMenuPreSent(UserMsg vguiMessage, BfRead buffer, const int[] players,
  41. int nPlayers, bool reliable, bool init) {
  42. // vgui usermessages are expected to only have a single recipient
  43. if (nPlayers != 1) {
  44. return Plugin_Continue;
  45. }
  46. char name[128];
  47. buffer.ReadString(name, sizeof(name));
  48. if (!StrEqual(name, "arenateampanel") && !StrEqual(name, "team")) {
  49. return Plugin_Continue;
  50. }
  51. int client = players[0];
  52. // block the message if we're resending on a `jointeam` cooldown
  53. return QueueResendTeamChangePanel(client)? Plugin_Handled : Plugin_Continue;
  54. }
  55. bool QueueResendTeamChangePanel(int client) {
  56. // return early if client is assigned to a team
  57. if (GetClientTeam(client)) {
  58. return false;
  59. }
  60. float flNextAllowedTeamChange = GetEntDataFloat(client,
  61. offs_CTFPlayer_flNextTimeAllowTeamChange);
  62. if (flNextAllowedTeamChange > GetGameTime()) {
  63. // we're not allowed to change teams right now, so set a timer to redisplay
  64. CreateTimer(0.1 + flNextAllowedTeamChange - GetGameTime(), RedisplayTeamSelectMenu,
  65. GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
  66. return true;
  67. }
  68. return false;
  69. }
  70. /**
  71. * Redisplay the team select panel.
  72. */
  73. Action RedisplayTeamSelectMenu(Handle timer, int clientserial) {
  74. int client = GetClientFromSerial(clientserial);
  75. if (!client) {
  76. return Plugin_Handled;
  77. }
  78. if (IsInArenaMode() && tf_arena_use_queue.BoolValue) {
  79. ShowVGUIPanel(client, "arenateampanel");
  80. } else {
  81. ShowVGUIPanel(client, "team");
  82. }
  83. return Plugin_Handled;
  84. }
  85. bool IsInArenaMode() {
  86. return GameRules_GetProp("m_nGameType") == 4;
  87. }