Advertisement
Guest User

Untitled

a guest
Dec 12th, 2019
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.33 KB | None | 0 0
  1. #include <sourcemod>
  2. #include <sdktools_sound>
  3. #include <colors>
  4.  
  5. #define MAX_STR_LEN 30
  6. #define MIN_MIX_START_COUNT 2
  7.  
  8. #define COND_HAS_ALREADY_VOTED 0
  9. #define COND_NEED_MORE_VOTES 1
  10. #define COND_START_MIX 2
  11. #define COND_START_MIX_ADMIN 3
  12.  
  13. #define STATE_FIRST_CAPT 0
  14. #define STATE_SECOND_CAPT 1
  15. #define STATE_NO_MIX 2
  16. #define STATE_PICK_TEAMS 3
  17.  
  18. enum L4D2Team                                                                  
  19. {                                                                              
  20.     L4D2Team_None = 0,                                                          
  21.     L4D2Team_Spectator,                                                        
  22.     L4D2Team_Survivor,                                                          
  23.     L4D2Team_Infected                                                          
  24. }
  25.  
  26. new currentState = STATE_NO_MIX;
  27. new Menu:mixMenu;
  28. new StringMap:hVoteResultsTrie;
  29. new StringMap:hSwapWhitelist;
  30. new mixCallsCount = 0;
  31. char currentMaxVotedCaptAuthId[MAX_STR_LEN];
  32. char survCaptainAuthId[MAX_STR_LEN];
  33. char infCaptainAuthId[MAX_STR_LEN];
  34. new maxVoteCount = 0;
  35. new pickCount = 0;
  36. new survivorsPick = 0;
  37. new bool:isMixAllowed = false;
  38. new bool:isPickingCaptain = false;
  39. new Handle:mixStartedForward;
  40. new Handle:mixStoppedForward;
  41. new Handle:captainVoteTimer;
  42.  
  43. public Plugin myinfo =
  44. {
  45.     name = "L4D2 Mix Manager",
  46.     author = "Luckylock",
  47.     description = "Provides ability to pick captains and teams through menus",
  48.     version = "3",
  49.     url = "https://github.com/LuckyServ/"
  50. };
  51.  
  52. public void OnPluginStart()
  53. {
  54.     RegConsoleCmd("sm_mix", Cmd_MixStart, "Mix command");
  55.     RegAdminCmd("sm_stopmix", Cmd_MixStop, ADMFLAG_CHANGEMAP, "Mix command");
  56.     AddCommandListener(Cmd_OnPlayerJoinTeam, "jointeam");
  57.     hVoteResultsTrie = CreateTrie();
  58.     hSwapWhitelist = CreateTrie();
  59.     mixStartedForward = CreateGlobalForward("OnMixStarted", ET_Event);
  60.     mixStoppedForward = CreateGlobalForward("OnMixStopped", ET_Event);
  61.     PrecacheSound("buttons/blip1.wav");
  62. }
  63.  
  64. public void OnMapStart()
  65. {
  66.     isMixAllowed = true;
  67.     StopMix();
  68. }
  69.  
  70. public void OnRoundIsLive() {
  71.     isMixAllowed = false;
  72.     StopMix();
  73. }
  74.  
  75. public void StartMix()
  76. {
  77.     FakeClientCommandAll("sm_hide");
  78.     Call_StartForward(mixStartedForward);
  79.     Call_Finish();
  80.     EmitSoundToAll("buttons/blip1.wav");
  81. }
  82.  
  83. public void StopMix()
  84. {
  85.     currentState = STATE_NO_MIX;
  86.     FakeClientCommandAll("sm_show");
  87.     Call_StartForward(mixStoppedForward);
  88.     Call_Finish();
  89.  
  90.     if (isPickingCaptain && captainVoteTimer != INVALID_HANDLE) {
  91.         KillTimer(captainVoteTimer);
  92.     }
  93. }
  94.  
  95. public void FakeClientCommandAll(char[] command)
  96. {
  97.     for (new client = 1; client <= MaxClients; ++client) {
  98.         if (IsClientInGame(client) && !IsFakeClient(client)) {
  99.             FakeClientCommand(client, command);
  100.         }  
  101.     }
  102. }
  103.  
  104. public Action Cmd_OnPlayerJoinTeam(int client, const char[] command, int argc)
  105. {
  106.     char authId[MAX_STR_LEN];
  107.     char cmdArgBuffer[MAX_STR_LEN];
  108.     L4D2Team allowedTeam;
  109.     L4D2Team newTeam;
  110.  
  111.     if (argc >= 1) {
  112.  
  113.         GetCmdArg(1, cmdArgBuffer, MAX_STR_LEN);
  114.         newTeam = L4D2Team:StringToInt(cmdArgBuffer);
  115.  
  116.         if (currentState != STATE_NO_MIX && newTeam != L4D2Team_Spectator && IsHuman(client)) {
  117.  
  118.             GetClientAuthId(client, AuthId_SteamID64, authId, MAX_STR_LEN);
  119.  
  120.             if (!hSwapWhitelist.GetValue(authId, allowedTeam) || allowedTeam != newTeam) {
  121.                 CPrintToChat(client, "{blue}[{default}Mix Manager{blue}]{default} You can not join a team without being picked.");
  122.                 return Plugin_Stop;
  123.             }
  124.         }
  125.        
  126.     }
  127.  
  128.     return Plugin_Continue;
  129. }
  130.  
  131. public void OnClientPutInServer(int client)
  132. {
  133.     char authId[MAX_STR_LEN];
  134.  
  135.     if (currentState != STATE_NO_MIX && IsHuman(client))
  136.     {
  137.         GetClientAuthId(client, AuthId_SteamID64, authId, MAX_STR_LEN);
  138.         ChangeClientTeamEx(client, L4D2Team_Spectator);
  139.     }
  140. }
  141.  
  142. public Action Cmd_MixStop(int client, int args) {
  143.     if (currentState != STATE_NO_MIX) {
  144.         StopMix();
  145.         CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Stopped by admin \x03%N\x01.", client);
  146.     } else {
  147.         CPrintToChat(client, "{blue}[{default}Mix Manager{blue}]{default} Not currently started.");
  148.     }
  149. }
  150.  
  151. public Action Cmd_MixStart(int client, int args)
  152. {
  153.     if (currentState != STATE_NO_MIX) {
  154.         CPrintToChat(client, "{blue}[{default}Mix Manager{blue}]{default} Already started.");
  155.         return Plugin_Handled;
  156.     } else if (!isMixAllowed) {
  157.         CPrintToChat(client, "{blue}[{default}Mix Manager{blue}]{default} Not allowed on live round.");
  158.         return Plugin_Handled;
  159.     }
  160.  
  161.     new mixConditions;
  162.     mixConditions = GetMixConditionsAfterVote(client);
  163.  
  164.     if (mixConditions == COND_START_MIX || mixConditions == COND_START_MIX_ADMIN) {
  165.         if (mixConditions == COND_START_MIX_ADMIN) {
  166.             CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Started by admin \x03%N\x01.", client);
  167.         } else {
  168.             CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} \x03%N {default}has voted to start a Mix.", client);
  169.             CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Started by vote.");
  170.         }
  171.  
  172.         currentState = STATE_FIRST_CAPT;
  173.         StartMix();
  174.         SwapAllPlayersToSpec();
  175.  
  176.         // Initialise values
  177.         mixCallsCount = 0;
  178.         hVoteResultsTrie.Clear();
  179.         hSwapWhitelist.Clear();
  180.         maxVoteCount = 0;
  181.         strcopy(currentMaxVotedCaptAuthId, MAX_STR_LEN, " ");
  182.         pickCount = 0;
  183.  
  184.         if (Menu_Initialise()) {
  185.             Menu_AddAllSpectators();
  186.             Menu_DisplayToAllSpecs();
  187.         }
  188.  
  189.         captainVoteTimer = CreateTimer(11.0, Menu_StateHandler, _, TIMER_REPEAT);
  190.         isPickingCaptain = true;
  191.  
  192.     } else if (mixConditions == COND_NEED_MORE_VOTES) {
  193.         CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default}  \x03%N {default}has voted to start a Mix. (\x05%d \x01more to start)", client, MIN_MIX_START_COUNT - mixCallsCount);
  194.  
  195.     } else if (mixConditions == COND_HAS_ALREADY_VOTED) {
  196.         CPrintToChat(client, "{blue}[{default}Mix Manager{blue}]{default} You already voted to start a Mix.");
  197.  
  198.     }
  199.  
  200.     return Plugin_Handled;
  201. }
  202.  
  203. public int GetMixConditionsAfterVote(int client)
  204. {
  205.     new bool:dummy = false;
  206.     new bool:hasVoted = false;
  207.     char clientAuthId[MAX_STR_LEN];
  208.     GetClientAuthId(client, AuthId_SteamID64, clientAuthId, MAX_STR_LEN);
  209.     hasVoted = GetTrieValue(hVoteResultsTrie, clientAuthId, dummy)
  210.  
  211.     if (GetAdminFlag(GetUserAdmin(client), Admin_Changemap)) {
  212.         return COND_START_MIX_ADMIN;
  213.  
  214.     } else if (hasVoted){
  215.         return COND_HAS_ALREADY_VOTED;
  216.  
  217.     } else if (++mixCallsCount >= MIN_MIX_START_COUNT) {
  218.         return COND_START_MIX;
  219.  
  220.     } else {
  221.         SetTrieValue(hVoteResultsTrie, clientAuthId, true);
  222.         return COND_NEED_MORE_VOTES;
  223.  
  224.     }
  225. }
  226.  
  227. public bool Menu_Initialise()
  228. {
  229.     if (currentState == STATE_NO_MIX) return false;
  230.  
  231.     mixMenu = new Menu(Menu_MixHandler, MENU_ACTIONS_ALL);
  232.     mixMenu.ExitButton = false;
  233.  
  234.     switch(currentState) {
  235.         case STATE_FIRST_CAPT: {
  236.             mixMenu.SetTitle("Mix Manager - Pick first captain");
  237.             return true;
  238.         }
  239.  
  240.         case STATE_SECOND_CAPT: {
  241.             mixMenu.SetTitle("Mix Manager - Pick second captain");
  242.             return true;
  243.         }
  244.  
  245.         case STATE_PICK_TEAMS: {
  246.             mixMenu.SetTitle("Mix Manager - Pick team member(s)");
  247.             return true;
  248.         }
  249.     }
  250.  
  251.     CloseHandle(mixMenu);
  252.     return false;
  253. }
  254.  
  255. public void Menu_AddAllSpectators()
  256. {
  257.     char clientName[MAX_STR_LEN];
  258.     char clientId[MAX_STR_LEN];
  259.  
  260.     mixMenu.RemoveAllItems();
  261.  
  262.     for (new client = 1; client <= MaxClients; ++client) {
  263.         if (IsClientSpec(client)) {
  264.             GetClientAuthId(client, AuthId_SteamID64, clientId, MAX_STR_LEN);
  265.             GetClientName(client, clientName, MAX_STR_LEN);
  266.             mixMenu.AddItem(clientId, clientName);
  267.         }  
  268.     }
  269. }
  270.  
  271. public void Menu_AddTestSubjects()
  272. {
  273.     mixMenu.AddItem("test", "test");
  274. }
  275.  
  276. public void Menu_DisplayToAllSpecs()
  277. {
  278.     for (new client = 1; client <= MaxClients; ++client) {
  279.         if (IsClientSpec(client)) {
  280.             mixMenu.Display(client, 10);
  281.         }
  282.     }
  283. }
  284.  
  285. public int Menu_MixHandler(Menu menu, MenuAction action, int param1, int param2)
  286. {
  287.     if (action == MenuAction_Select) {
  288.         if (currentState == STATE_FIRST_CAPT || currentState == STATE_SECOND_CAPT) {
  289.             char authId[MAX_STR_LEN];
  290.             menu.GetItem(param2, authId, MAX_STR_LEN);
  291.  
  292.             new voteCount = 0;
  293.  
  294.             if (!GetTrieValue(hVoteResultsTrie, authId, voteCount)) {
  295.                 voteCount = 0;
  296.             }
  297.  
  298.             SetTrieValue(hVoteResultsTrie, authId, ++voteCount, true);
  299.  
  300.             if (voteCount > maxVoteCount) {
  301.                 strcopy(currentMaxVotedCaptAuthId, MAX_STR_LEN, authId);
  302.                 maxVoteCount = voteCount;
  303.             }
  304.  
  305.         } else if (currentState == STATE_PICK_TEAMS) {
  306.             char authId[MAX_STR_LEN];
  307.             menu.GetItem(param2, authId, MAX_STR_LEN);
  308.             new L4D2Team:team = GetClientTeamEx(param1);
  309.  
  310.             if (team == L4D2Team_Spectator || (team == L4D2Team_Infected && survivorsPick == 1) || (team == L4D2Team_Survivor && survivorsPick == 0)) {
  311.                 CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Captain \x03%N {default}found in the wrong team, aborting...", param1);
  312.                 StopMix();
  313.  
  314.             } else {
  315.                
  316.                 if (SwapPlayerToTeam(authId, team, 0)) {
  317.                     pickCount++;
  318.                     if (pickCount == 4) {
  319.                         // Do not switch picks
  320.  
  321.                     } else if (pickCount > 5) {
  322.                         CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Teams are picked.");
  323.                         StopMix();
  324.                     } else {
  325.                         survivorsPick = survivorsPick == 1 ? 0 : 1;
  326.                     }
  327.                 } else {
  328.                     CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} The team member who was picked was not found, aborting...", param1);
  329.                     StopMix();
  330.                 }
  331.             }
  332.         }
  333.     }
  334.  
  335.     return 0;
  336. }
  337.  
  338. public Action Menu_StateHandler(Handle timer, Handle hndl)
  339. {
  340.     switch(currentState) {
  341.         case STATE_FIRST_CAPT: {
  342.             new numVotes = 0;
  343.             GetTrieValue(hVoteResultsTrie, currentMaxVotedCaptAuthId, numVotes);
  344.             ClearTrie(hVoteResultsTrie);
  345.            
  346.             if (SwapPlayerToTeam(currentMaxVotedCaptAuthId, L4D2Team_Survivor, numVotes)) {
  347.                 strcopy(survCaptainAuthId, MAX_STR_LEN, currentMaxVotedCaptAuthId);
  348.                 currentState = STATE_SECOND_CAPT;
  349.                 maxVoteCount = 0;
  350.  
  351.                 if (Menu_Initialise()) {
  352.                     Menu_AddAllSpectators();
  353.                     Menu_DisplayToAllSpecs();
  354.                 }
  355.             } else {
  356.                 CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Failed to find first captain with at least 1 vote from spectators, aborting...");
  357.                 StopMix();
  358.             }
  359.  
  360.             strcopy(currentMaxVotedCaptAuthId, MAX_STR_LEN, " ");
  361.         }
  362.  
  363.         case STATE_SECOND_CAPT: {
  364.             new numVotes = 0;
  365.             GetTrieValue(hVoteResultsTrie, currentMaxVotedCaptAuthId, numVotes);
  366.             ClearTrie(hVoteResultsTrie);
  367.  
  368.             if (SwapPlayerToTeam(currentMaxVotedCaptAuthId, L4D2Team_Infected, numVotes)) {
  369.                 strcopy(infCaptainAuthId, MAX_STR_LEN, currentMaxVotedCaptAuthId);
  370.                 currentState = STATE_PICK_TEAMS;
  371.                 CreateTimer(0.5, Menu_StateHandler);
  372.  
  373.             } else {
  374.                 CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Failed to find second captain with at least 1 vote from spectators, aborting...");
  375.                 StopMix();
  376.             }
  377.  
  378.             strcopy(currentMaxVotedCaptAuthId, MAX_STR_LEN, " ");
  379.         }
  380.  
  381.         case STATE_PICK_TEAMS: {
  382.             isPickingCaptain = false;
  383.             survivorsPick = GetURandomInt() & 1;            
  384.             CreateTimer(1.0, Menu_TeamPickHandler, _, TIMER_REPEAT);
  385.         }
  386.     }
  387.  
  388.     if (currentState == STATE_NO_MIX || currentState == STATE_PICK_TEAMS) {
  389.         return Plugin_Stop;
  390.     } else {
  391.         return Plugin_Handled;
  392.     }
  393. }
  394.  
  395. public Action Menu_TeamPickHandler(Handle timer)
  396. {
  397.     if (currentState == STATE_PICK_TEAMS) {
  398.  
  399.         if (Menu_Initialise()) {
  400.             Menu_AddAllSpectators();
  401.             new captain;
  402.  
  403.             if (survivorsPick == 1) {
  404.                captain = GetClientFromAuthId(survCaptainAuthId);
  405.             } else {
  406.                captain = GetClientFromAuthId(infCaptainAuthId);
  407.             }
  408.  
  409.             if (captain > 0) {
  410.                 if (GetSpectatorsCount() > 0) {
  411.                     mixMenu.Display(captain, 1);
  412.                 } else {
  413.                     CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} No more spectators to choose from, aborting...");
  414.                     StopMix();
  415.                     return Plugin_Stop;
  416.                 }
  417.             } else {
  418.                 CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Failed to find the captain, aborting...");
  419.                 StopMix();
  420.                 return Plugin_Stop;
  421.             }
  422.  
  423.             return Plugin_Continue;
  424.         }
  425.     }
  426.     return Plugin_Stop;
  427. }
  428.  
  429. public void SwapAllPlayersToSpec()
  430. {
  431.     for (new client = 1; client <= MaxClients; ++client) {
  432.         if (IsClientInGame(client) && !IsFakeClient(client)) {
  433.             ChangeClientTeamEx(client, L4D2Team_Spectator);
  434.         }
  435.     }
  436. }
  437.  
  438. public bool SwapPlayerToTeam(const char[] authId, L4D2Team:team, numVotes)
  439. {
  440.     new client = GetClientFromAuthId(authId);
  441.     new bool:foundClient = client > 0;
  442.  
  443.     if (foundClient) {
  444.         hSwapWhitelist.SetValue(authId, team);
  445.         ChangeClientTeamEx(client, team);
  446.  
  447.         switch(currentState) {
  448.             case STATE_FIRST_CAPT: {
  449.                 CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} First captain is \x03%N\x01. (\x05%d \x01votes)", client, numVotes);
  450.             }
  451.            
  452.             case STATE_SECOND_CAPT: {
  453.                 CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Second captain is \x03%N\x01. (\x05%d \x01votes)", client, numVotes);
  454.             }
  455.  
  456.             case STATE_PICK_TEAMS: {
  457.                 if (survivorsPick == 1) {
  458.                     CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} \x03%N \x01was picked (survivors).", client)
  459.                 } else {
  460.                     CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} \x03%N \x01was picked (infected).", client)
  461.                 }
  462.             }
  463.         }
  464.     }
  465.  
  466.     return foundClient;
  467. }
  468.  
  469. public void OnClientDisconnect(client)
  470. {
  471.     if (currentState != STATE_NO_MIX && IsPlayerCaptain(client))
  472.     {
  473.         CPrintToChatAll("{blue}[{default}Mix Manager{blue}]{default} Captain \x03%N \x01has left the game, aborting...", client);
  474.         StopMix();
  475.     }
  476. }
  477.  
  478. public bool IsPlayerCaptain(client)
  479. {
  480.     return GetClientFromAuthId(survCaptainAuthId) == client || GetClientFromAuthId(infCaptainAuthId) == client;
  481. }
  482.  
  483. public int GetClientFromAuthId(const char[] authId)
  484. {
  485.     char clientAuthId[MAX_STR_LEN];
  486.     new client = 0;
  487.     new i = 0;
  488.    
  489.     while (client == 0 && i < MaxClients) {
  490.         ++i;
  491.  
  492.         if (IsClientInGame(i) && !IsFakeClient(i)) {
  493.             GetClientAuthId(i, AuthId_SteamID64, clientAuthId, MAX_STR_LEN);
  494.  
  495.             if (StrEqual(authId, clientAuthId)) {
  496.                 client = i;
  497.             }
  498.         }
  499.     }
  500.  
  501.     return client;
  502. }
  503.  
  504. public bool IsClientSpec(int client) {
  505.     return IsClientInGame(client) && !IsFakeClient(client) && GetClientTeam(client) == 1;
  506. }
  507.  
  508. public int GetSpectatorsCount()
  509. {
  510.     new count = 0;
  511.  
  512.     for (new client = 1; client <= MaxClients; ++client) {
  513.         if (IsClientSpec(client)) {
  514.             ++count;
  515.         }
  516.     }
  517.  
  518.     return count;
  519. }
  520.  
  521. stock bool:ChangeClientTeamEx(client, L4D2Team:team)
  522. {
  523.     if (GetClientTeamEx(client) == team) {
  524.         return true;
  525.     }
  526.  
  527.     if (team != L4D2Team_Survivor) {
  528.         ChangeClientTeam(client, _:team);
  529.         return true;
  530.     } else {
  531.         new bot = FindSurvivorBot();
  532.  
  533.         if (bot > 0) {
  534.             new flags = GetCommandFlags("sb_takecontrol");
  535.             SetCommandFlags("sb_takecontrol", flags & ~FCVAR_CHEAT);
  536.             FakeClientCommand(client, "sb_takecontrol");
  537.             SetCommandFlags("sb_takecontrol", flags);
  538.             return true;
  539.         }
  540.     }
  541.     return false;
  542. }
  543.  
  544. stock L4D2Team:GetClientTeamEx(client)
  545. {
  546.     return L4D2Team:GetClientTeam(client);
  547. }
  548.  
  549. stock FindSurvivorBot()
  550. {
  551.     for (new client = 1; client <= MaxClients; client++)
  552.     {
  553.         if(IsClientInGame(client) && IsFakeClient(client) && GetClientTeamEx(client) == L4D2Team_Survivor)
  554.         {
  555.             return client;
  556.         }
  557.     }
  558.     return -1;
  559. }
  560.  
  561. public bool IsHuman(client)
  562. {
  563.     return IsClientInGame(client) && !IsFakeClient(client);
  564. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement