sharivan

l4d2_unscrambler.sp

Nov 16th, 2018
254
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <sourcemod>
  2. #include <sdktools>
  3. #include <adminmenu>
  4.  
  5. #pragma semicolon 1
  6.  
  7. #define VERSION "1.0.3"
  8. #define SIDSIZE 32
  9. #define TEAMSIZE 16
  10. #define L4D_MAXCLIENTS MaxClients
  11. #define L4D_MAXCLIENTS_PLUS1 (L4D_MAXCLIENTS + 1)
  12. #define DEBUG 1
  13. #define DEBUGTEAMS 0
  14. #define L4D_TEAM_SURVIVORS 2
  15. #define L4D_TEAM_INFECTED 3
  16. #define L4D_TEAM_SPECTATE 1
  17. #define SCORE_TEAM_A 1
  18. #define SCORE_TEAM_B 2
  19. #define SCORE_TYPE_ROUND 0
  20. #define SCORE_TYPE_CAMPAIGN 1
  21.  
  22. public Plugin:myinfo =
  23. {
  24.     name = "[L4D2] Unscrambler",
  25.     author = "modified by V10 (original by Fyren)",
  26.     description = "Keeps teams unscrambled after map change in versus\team switch, team change",
  27.     version = VERSION,
  28.     url = "http://forums.alliedmods.net/showthread.php?p=730278"
  29. };
  30.  
  31. new Handle:cvarWait = INVALID_HANDLE;
  32. new Handle:cvarHoldOn = INVALID_HANDLE;
  33. new Handle:timerWait = INVALID_HANDLE;
  34. new Handle:timerUnscramble = INVALID_HANDLE;
  35. new Handle:IsAutoBalanceOn = INVALID_HANDLE;
  36. new String:teams[2][TEAMSIZE][SIDSIZE]; //two teams, four players, 16 chars for Steam ID
  37. #if DEBUG
  38. new String:logPath[256];
  39. #endif
  40. new nTeam[2]; //number of players stored in the list
  41. //new storing; //if we're on a versus map and should be storing teams
  42. new uCount; //number of teams unscramble has repped as a failsafe
  43. new Handle:gConf = INVALID_HANDLE;
  44. new Handle:fSHS = INVALID_HANDLE;
  45. new Handle:fTOB = INVALID_HANDLE;
  46. new Handle:fGTS = INVALID_HANDLE;
  47. new bool:RoundEndDone;
  48. //new Scores[3];    
  49. new Round=0;
  50. new LastInfectedTeam;
  51. new FirstSurvivorTeam;
  52. new bool:isFirstMap=false;
  53. new Handle:h_Switch_CheckTeams;
  54. new Handle:hCVScrambleTime = INVALID_HANDLE;
  55. new bool:FirstSpawn=true;
  56. // top menu
  57. new Handle:hTopMenu = INVALID_HANDLE;
  58.  
  59. public OnPluginStart()
  60. {
  61.     #if DEBUG
  62.     BuildPath(Path_SM, logPath, sizeof(logPath), "logs/l4d2unscramber.log");
  63.     #endif
  64.     LoadTranslations("common.phrases");
  65.    
  66.     gConf = LoadGameConfigFile("l4dunscrambler");
  67.    
  68.     StartPrepSDKCall(SDKCall_Player);
  69.     PrepSDKCall_SetFromConf(gConf, SDKConf_Signature, "SetHumanSpec");
  70.     PrepSDKCall_AddParameter(SDKType_CBasePlayer, SDKPass_Pointer);
  71.     fSHS = EndPrepSDKCall();
  72.    
  73.     StartPrepSDKCall(SDKCall_Player);
  74.     PrepSDKCall_SetFromConf(gConf, SDKConf_Signature, "TakeOverBot");
  75.     PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain);
  76.     fTOB = EndPrepSDKCall();
  77.    
  78.     StartPrepSDKCall(SDKCall_GameRules);
  79.     PrepSDKCall_SetFromConf(gConf, SDKConf_Signature, "GetTeamScore");
  80.     PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
  81.     PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain);
  82.     PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
  83.     fGTS = EndPrepSDKCall();
  84.  
  85.     cvarWait = CreateConVar("l4d2u_wait", "15", "Wait this many seconds after a map starts before giving up on fixing teams");
  86.     cvarHoldOn = CreateConVar("l4d2u_holdon", "15", "If there's a connecting player when we decide to stop waiting, hold on for this many more seconds");
  87.     h_Switch_CheckTeams = CreateConVar("l4d2u_checkteams", "1", "Determines if the function should check if target team is full", ADMFLAG_KICK, true, 0.0, true, 1.0);
  88.     IsAutoBalanceOn = CreateConVar("l4d2u_allowautobalance", "0", "Should we autobalance teams on round end?");
  89.     hCVScrambleTime = CreateConVar("l4d2u_scramble_time", "60", "Scramble teams in first map of compaign in X seconds. 0 - disable");
  90.     CreateConVar("l4d2u_version", VERSION, "L4D2 Unscrambler version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_UNLOGGED|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
  91.     AutoExecConfig(true, "l4d2u");
  92.    
  93.     HookEvent("player_first_spawn", Event_FirstSpawnNotify,EventHookMode_Post);
  94.     HookEvent("round_start", Event_RoundStart,EventHookMode_Post);
  95.     HookEvent("round_end", eventRoundEnd,EventHookMode_Post);
  96. //  RegConsoleCmd("chooseteam",Command_ChooseTeam);
  97.     // First we check if menu is ready ..
  98.     if (LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
  99.     {
  100.         OnAdminMenuReady(hTopMenu);
  101.     }
  102.    
  103. }
  104.  
  105.  
  106.  
  107. #if DEBUG
  108.  
  109. dumpNames()
  110. {
  111.     decl String:name[MAX_NAME_LENGTH];
  112.     decl String:auth[SIDSIZE];
  113.     new i;
  114.     for (i = 1; i <= L4D_MAXCLIENTS; i++)
  115.         if (IsClientConnected(i))
  116.     {
  117.         if (IsClientAuthorized(i)) GetClientIP(i, auth, sizeof(auth),false);
  118.         else auth = "noauth";
  119.        
  120.         GetClientName(i, name, sizeof(name));
  121.         if (IsClientInGame(i)) LogToFileEx(logPath, "%s (%d, %s) is on team %d", name, i, auth, GetClientTeam(i));
  122.         else LogToFileEx(logPath, "%s (%d, %s) isn't in game", name, i, auth);
  123.     }
  124. }
  125. #endif
  126. #if DEBUG
  127. new String:TeamNames[3][]={"Spectators","Survivors","Infected"};
  128. debugNames(String:prefix[], i, j,needteam_index)
  129. {
  130.     decl String:name[2][MAX_NAME_LENGTH];
  131.     GetClientName(i, name[0], sizeof(name[]));
  132.     if (j){
  133.         GetClientName(j, name[1], sizeof(name[]));
  134.         LogToFileEx(logPath, "%s swapped %s and %s", prefix, name[0], name[1]);
  135.     }else{
  136.         LogToFileEx(logPath, "%s Switched %s to %s", prefix, name[0], TeamNames[needteam_index]);
  137.     }
  138. }
  139. #endif
  140.  
  141. //if the wait time has elapsed, kill the unscramble timer
  142. //if there's someone still connecting hold on a little longer,
  143. //but only hold on once
  144. //also clear the saved team list
  145. public Action:stopWait(Handle:timer, any:holdingOn)
  146. {
  147.     #if DEBUG
  148.     LogToFileEx(logPath, "Stop wait?");
  149.     #endif
  150.     if ((GetClientCount() == GetClientCount(false)) || holdingOn)
  151.     {
  152.         #if DEBUG
  153.         LogToFileEx(logPath, "Not holding on");
  154.         dumpNames();
  155.         #endif
  156.         if (timerUnscramble != INVALID_HANDLE)
  157.         {
  158.             KillTimer(timerUnscramble);
  159.             timerUnscramble = INVALID_HANDLE;
  160.         }
  161.     }
  162.     else timerWait = CreateTimer(GetConVarFloat(cvarHoldOn), stopWait, true, TIMER_FLAG_NO_MAPCHANGE);
  163. }
  164.  
  165. //swap the two given players
  166. swap(i, j)
  167. {
  168.     new inf, surv;
  169.     if (GetClientTeam(i) == L4D_TEAM_INFECTED)
  170.     {
  171.         inf = i;
  172.         surv = j;
  173.     }
  174.     else
  175.     {
  176.         inf = j;
  177.         surv = i;
  178.     }
  179.    
  180.     ChangeClientTeam(inf, L4D_TEAM_SPECTATE);
  181.     ChangeClientTeam(surv, L4D_TEAM_SPECTATE);
  182.     ChangePlayerTeam(surv, L4D_TEAM_INFECTED);
  183.     ChangePlayerTeam(inf,L4D_TEAM_SURVIVORS);
  184. }
  185.  
  186.  
  187. public Action:unscramble(Handle:timer)
  188. {
  189.     //just to be sure this timer doesn't go forever somehow
  190.     uCount++;
  191.     if (uCount > 30)
  192.     {
  193.         #if DEBUG
  194.         LogToFileEx(logPath, "Forcefully stopped unscrambling.");
  195.         #endif
  196.        
  197.         timerUnscramble = INVALID_HANDLE;
  198.         if (timerWait != INVALID_HANDLE)
  199.         {
  200.             KillTimer(timerWait);
  201.             timerWait = INVALID_HANDLE;
  202.         }
  203.        
  204.         return Plugin_Stop;
  205.     }
  206.    
  207.     new i, j, k, team;
  208.    
  209.     new String:auth[SIDSIZE];
  210.     new clStatus[L4D_MAXCLIENTS + 1];
  211.     new nIncorrect, nCorrect; //total number of correct and incorrect players (see comment below)
  212.     new curTeam[3]; //count of players currently on each team
  213.     new nICTeam[3]; //count of incorrect players currently on each team
  214.     //0 - spec, 1 - surv, 2 -inf
  215.  
  216.    
  217.     //decide if a player is
  218.     //(1) correct: he's from the previous round and on the right team
  219.     //(-2 or -3, based on current team) incorrect: he's from the previous round and on the wrong team
  220.     //(2 or 3, based on current team) someone who wasn't here before, so can be swapped freely
  221.     //(0) not connected/not authed/empty slot
  222.     //TODO make this suck less, should have used a trie
  223.     new found;
  224.     for (k = 1; k <= L4D_MAXCLIENTS; k++)
  225.     {
  226.         found = 0;
  227.         team = -1;
  228.        
  229.         //if they're not in game yet move on
  230.         if (IsClientConnected(k) && IsClientInGame(k) && !IsFakeClient(k) && IsClientAuthorized(k))
  231.         {
  232.             team = GetClientTeam(k);
  233.             if (team < 1 || team > 3) continue; //if they're not on a team yet, move on
  234.             //0-surv, 1 -inf 2-spec
  235.             curTeam[team - 1]++;
  236.         }
  237.         else continue;
  238.        
  239.         GetClientIP(k, auth, sizeof(auth),false);
  240.        
  241.         for (i = 0; i < 2; i++){
  242.             for (j = 0; j < nTeam[i]; j++){
  243.                 #if DEBUGTEAMS
  244.                 LogToFileEx(logPath, "Going to compare teams[%d][%d] = %s to clID[%d] = %s", i, j, teams[i][j], k, clID[k]);
  245.                 #endif
  246.                
  247.                 if (StrEqual(teams[i][j], auth))
  248.                     if (team == (i + 2)){                      
  249.                         nCorrect++;        
  250.                         clStatus[k] = 1;
  251.                         found = 1;
  252.                         break; //j loop
  253.                     }else{
  254.                         nIncorrect++;
  255.                         nICTeam[team - 1]++; // 0 -never
  256.                         //nICTeam - 0 spec, 1 - surv, 2-inf
  257.                         //clStatus - (-2) - survivios, (-3) - infected
  258.                         clStatus[k] = -(i + 2);
  259.                         found = 1;
  260.                         break; //j loop
  261.                     }
  262.             }
  263.            
  264.             if (found) break; //i loop
  265.         }
  266.        
  267.         //not in stored list and on a team
  268.         if (!found && ((team == 2) || (team == 3))) {
  269.             //todo: send to spectators
  270.             clStatus[k] = team;
  271.         }else if (!found) {
  272.             //todo: kick           
  273.             clStatus[k] = 1;
  274.         }
  275.     }
  276.    
  277.     #if DEBUGTEAMS
  278.     decl String:name[MAX_NAME_LENGTH];
  279.     for (i = 1; i <= L4D_MAXCLIENTS; i++)
  280.     {
  281.         if (IsClientConnected(i))
  282.         {
  283.             GetClientName(i, name, sizeof(name));
  284.             GetClientIP(i, auth, sizeof(auth),false);
  285.             if (IsClientInGame(i)) LogToFileEx(logPath, "%s: ID=%d, auth=%s, team=%d, status=%d", name, i, auth, GetClientTeam(i), clStatus[i]);
  286.             else LogToFileEx(logPath, "%s (%d, %s) isn't in game", name, i, auth);
  287.         }
  288.         //else LogToFileEx(logPath, "%d is not connected", i);
  289.     }
  290.    
  291.     #endif
  292.    
  293.     #if DEBUG
  294.     LogToFileEx(logPath, "Pass starting: nT[0] = %d, nT[1] = %d, nIC = %d, nC = %d, nIC[0] = %d, nIC[1] = %d, nIC[2] = %d", nTeam[0], nTeam[1], nIncorrect, nCorrect, nICTeam[0], nICTeam[1], nICTeam[2]);
  295.     #endif
  296.    
  297.     //for each incorrect player, swap somebody if it won't empty out the survivor team
  298.     //if the survivor team gets emptied out, the server might cycle the round
  299.     for (i = 1; i <= L4D_MAXCLIENTS; i++)
  300.     {
  301.         //if the player isn't incorrect, move on
  302.         if (clStatus[i] >= 0) continue;
  303.         new needteam=-clStatus[i];
  304.         new needteam_index=needteam - 1;
  305.         //nICTeam,curTeam - 0 spec, 1 - surv, 2-inf
  306.         //clStatus - (-2) - survivios, (-3) - infected
  307.         if (curTeam[needteam_index] < GetTeamMaxHumans(needteam))
  308.         {
  309.             #if DEBUG
  310.             debugNames("I/0", i, 0,needteam_index);
  311.             #endif
  312.            
  313.             //swap team and update status
  314.             ChangeClientTeam(i, 1);        
  315.             if (!ChangePlayerTeam(i,needteam)){
  316.                 PrintToServer("Unscramble Error: Cannot change team!");
  317.             }
  318.            
  319.             nIncorrect--;
  320.             nCorrect++;
  321.             curTeam[needteam_index]++;
  322.             nICTeam[3-needteam_index]--; // 1 => 2, 2 =>1
  323.             clStatus[i] = 1;
  324.         }
  325.         //if there's at least one player on each team that's incorrect, swap them unless
  326.         //there's only one survivor
  327.         else if (nICTeam[1]>0 && nICTeam[2]>0)
  328.         {
  329.             //start looking from after current index, since we've fixed earlier ones
  330.             for (j = i; j <= L4D_MAXCLIENTS; j++)
  331.                 //map -2 -> -3 and -3 -> -2 to see if they're on opposite teams and incorrect
  332.             if (clStatus[i] == (-clStatus[j] - 5))
  333.             {
  334.                 #if DEBUG
  335.                 debugNames("I/I", i, j,needteam_index);
  336.                 #endif
  337.                 swap(i, j);
  338.                
  339.                 //update counts/statuses
  340.                 nIncorrect -= 2;
  341.                 nCorrect += 2;
  342.                 nICTeam[1]--;
  343.                 nICTeam[2]--;
  344.                 clStatus[i] = 1;
  345.                 clStatus[j] = 1;
  346.                 break;
  347.             }
  348.         }
  349.         //if there isn't an incorrect player on the other team to swap with,
  350.         //and there isn't room on the other team,
  351.         //then find a new player on the other team and swap
  352.         else
  353.         {
  354.             new found_free=false;
  355.             for (j = 1; j <= L4D_MAXCLIENTS; j++){
  356.                 //map -2 -> 3 and -3 -> 2 to see if they're on opposite team but non-incorrect
  357.             if (needteam == clStatus[j])
  358.             {
  359.                 #if DEBUG
  360.                 debugNames("I/X", i, j,needteam_index);
  361.                 #endif
  362.                 team = GetClientTeam(i);
  363.                 if (team==L4D_TEAM_SPECTATE){
  364.                     ChangeClientTeam(j, L4D_TEAM_SPECTATE);
  365.                     ChangePlayerTeam(i,needteam);
  366.                 }else{
  367.                     swap(i,j);
  368.                 }  
  369.                 nIncorrect--;
  370.                 nICTeam[needteam_index]--;
  371.                 nCorrect++;
  372.                 clStatus[i] = 1;
  373. //              if (team==1) clStatus[j] = 1;
  374. //              else clStatus[j] = -team;
  375.                 found_free=true;
  376.                 break;
  377.             }
  378.             }
  379.             if (!found_free){
  380.                 #if DEBUG
  381.                 LogToFileEx(logPath, "ERROR: free not found");
  382.                 #endif
  383.             }
  384.         }
  385.     }  
  386.    
  387.     #if DEBUG
  388.     LogToFileEx(logPath, "Pass done: nIC = %d, nC = %d, nIC[0] = %d, nIC[1] = %d, nIC[2] = %d", nIncorrect, nCorrect, nICTeam[0], nICTeam[1], nICTeam[2]);
  389.     #endif
  390.    
  391.     //so now, everyone connected and authed is correct
  392.     //if all players from the last map are accounted for, we're done
  393.     //blank out the stored teams and stop the timers if so
  394.     if (nCorrect == (nTeam[0] + nTeam[1]))
  395.     {  
  396.         #if DEBUG
  397.         LogToFileEx(logPath, "Fixed teams, stopping stopwait");
  398.         dumpNames();
  399.         #endif
  400.        
  401.         timerUnscramble = INVALID_HANDLE;
  402.         if (timerWait != INVALID_HANDLE)
  403.         {
  404.             KillTimer(timerWait);
  405.             timerWait = INVALID_HANDLE;
  406.         }
  407.        
  408.         return Plugin_Stop;
  409.     }
  410.    
  411.     return Plugin_Continue;
  412. }
  413.  
  414. public OnMapStart()
  415. {
  416.     decl String:curMap[32];
  417.     GetCurrentMap(curMap, sizeof(curMap));
  418.     #if DEBUG  
  419.     LogToFileEx(logPath, "Got map %s", curMap);
  420.     #endif
  421.    
  422.     Round=0;
  423.    
  424.     //on non versus maps do nothing, on map 1 don't try to fix teams, on map 5 don't store teams
  425.     decl String:gamemode[64];
  426.     GetConVarString(FindConVar("mp_gamemode"), gamemode, 64);
  427.     if (StrEqual(gamemode, "versus")){
  428.         isFirstMap = GetTeamCompaignScore(SCORE_TEAM_A)==0;
  429.         if (isFirstMap) {
  430.             InitCompaign();
  431.             if (GetConVarInt(hCVScrambleTime) > 0) {
  432.                 CreateTimer(GetConVarFloat(hCVScrambleTime), ScrabmleTeams_Timer, TIMER_FLAG_NO_MAPCHANGE);
  433.             }
  434.         }else{
  435.             if(GetTeamCompaignScore(LastInfectedTeam)>GetTeamCompaignScore(OppositeLogicalTeam(LastInfectedTeam))){
  436.                 #if DEBUG
  437.                 LogToFileEx(logPath, "SWAP TEAMS! last infected swaped to surv [%d,%d - %d,%d]",LastInfectedTeam,GetTeamCompaignScore(LastInfectedTeam),OppositeLogicalTeam(LastInfectedTeam),GetTeamCompaignScore(OppositeLogicalTeam(LastInfectedTeam)));
  438.                 #endif
  439.                 FirstSurvivorTeam=LastInfectedTeam;
  440.                 new String:tmpAuth[SIDSIZE];
  441.                 new i;
  442.                 for (i = 0; i < TEAMSIZE; i++){
  443.                     strcopy(tmpAuth, SIDSIZE, teams[0][i]);
  444.                     strcopy(teams[0][i], SIDSIZE, teams[1][i]);
  445.                     strcopy(teams[1][i], SIDSIZE, tmpAuth);
  446.                 }
  447.                 i=nTeam[0];
  448.                 nTeam[0] = nTeam[1];
  449.                 nTeam[1]=i;            
  450.             }else{
  451.                 FirstSurvivorTeam=OppositeLogicalTeam(LastInfectedTeam);
  452.                 #if DEBUG
  453.                 LogToFileEx(logPath, "Last infected team loose [%d,%d - %d,%d]",LastInfectedTeam,GetTeamCompaignScore(LastInfectedTeam),OppositeLogicalTeam(LastInfectedTeam),GetTeamCompaignScore(OppositeLogicalTeam(LastInfectedTeam)));
  454.                 #endif
  455.             }
  456.         }      
  457.         if (StrContains(curMap, "c1m1") == -1){
  458.             LogToFileEx(logPath, "Map Start scores: %d %d",GetTeamCompaignScore(1),GetTeamCompaignScore(2));           
  459.             uCount = 0;
  460.         }else{
  461.             FirstSpawn=false;
  462.         }
  463.     }
  464. }
  465.  
  466. public OnMapEnd()
  467. {
  468.     FirstSpawn=true;
  469.  
  470.     #if DEBUG
  471.     new j;
  472.     for (new i = 0; i < 2; i++)
  473.         for (j = 0; j < nTeam[i]; j++)
  474.             LogToFileEx(logPath, "teams[%d][%d] = %s", i, j, teams[i][j]);
  475.     dumpNames();
  476.     LogToFileEx(logPath, "Map End scores: %d %d",GetTeamCompaignScore(1),GetTeamCompaignScore(2));
  477.     #endif
  478.     LastInfectedTeam=FirstSurvivorTeam;
  479. //  storeTeams();
  480. //  Scores[1]=GetTeamCompaignScore(1);
  481. //  Scores[2]=GetTeamCompaignScore(2);
  482. }
  483.  
  484. public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast)
  485. {
  486.     Round++;
  487.     RoundEndDone=false;
  488. /*  if (BeforeMapStart) {
  489.         #if DEBUG
  490.         LogToFileEx(logPath, "WARNING!!! RoundStart befor map start");
  491.         #endif
  492.     }
  493. */
  494. }
  495.  
  496. public Action:Event_FirstSpawnNotify(Handle:event, const String:name[], bool:dontBroadcast)
  497. {
  498.  
  499.     if (FirstSpawn){
  500.         timerUnscramble = CreateTimer(5.0, unscramble, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
  501.         timerWait = CreateTimer(GetConVarFloat(cvarWait), stopWait, false, TIMER_FLAG_NO_MAPCHANGE);
  502.     }
  503.     FirstSpawn=false;
  504. }
  505.  
  506.  
  507. public Action:eventRoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
  508. {
  509.     //for detect double round end (calc scores and team at second pass)
  510.     if(!RoundEndDone) {
  511.         RoundEndDone=true;
  512.         return Plugin_Continue;
  513.     }
  514.    
  515.     RoundEndDone = true;
  516.    
  517.     if (Round==0){
  518.         //Scores[0]=GetTeamCompaignScore(1);
  519.         //Scores[1]=GetTeamCompaignScore(2);
  520.     }else{
  521. //      Scores[0]=GetTeamCompaignScore(1);
  522. //      Scores[1]=GetTeamCompaignScore(2);
  523.     }
  524.     #if DEBUG
  525.     LogToFileEx(logPath, "Round:%d. Campagin scores: A=%d B=%d",Round,GetTeamCompaignScore(1),GetTeamCompaignScore(2));
  526.     #endif
  527.     storeTeams();
  528.     return Plugin_Continue;
  529. }
  530.  
  531. InitCompaign()
  532. {
  533.     #if DEBUG
  534.     LogToFileEx(logPath, "InitCompaign()");
  535.     #endif
  536.    
  537.    
  538.     isFirstMap=true;
  539.     FirstSurvivorTeam=SCORE_TEAM_A;
  540. }
  541.  
  542. public Action:ScrabmleTeams_Timer(Handle:timer)
  543. {
  544.     ScrambleTeams();
  545. }
  546.  
  547. public Action:ScrambleTeamsSuccess(Handle:timer)
  548. {
  549.     PrintHintTextToAll("[SM] \x3%t","TEAMS succesfully scrambled");
  550.     PrintHintTextToAll("[SM] \x4%t","TEAMS succesfully scrambled");
  551.     PrintHintTextToAll("[SM] \x5%t","TEAMS succesfully scrambled");
  552. }
  553.  
  554. public ScrambleTeams()
  555. {
  556.     for (new i = 1; i <= L4D_MAXCLIENTS; i++)
  557.         if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && IsClientAuthorized(i))
  558.         {
  559.             ChangeClientTeam(i, L4D_TEAM_SPECTATE);
  560.         }
  561.  
  562.     new curteam = 1;
  563.     new nextteam = -1;
  564.     for (new i = 1; i <= L4D_MAXCLIENTS; i++)
  565.         if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && IsClientAuthorized(i))
  566.         {
  567.             if (nextteam > 0) {
  568.                 curteam = nextteam;
  569.                 nextteam = -1;
  570.             }else{
  571.                 curteam = (GetRandomInt(0,1) == 0 ? 2 : 3);
  572.                 nextteam = ( curteam == 2 ? 3 : 2);
  573.             }
  574.             //UTIL_AllowTeamChange(i);
  575.             PerformSwitch_fast(i, curteam);
  576.         }
  577.     storeTeams();
  578.     CreateTimer(0.5,ScrambleTeamsSuccess);
  579. }
  580.  
  581.  
  582. //put everyone's SteamIDs into the array
  583. //index 0 is team 2, index 1 is team 3
  584. storeTeams()
  585. {
  586.     new i, team, String:auth[SIDSIZE];
  587.     #if DEBUGTEAMS
  588.     new String:name[MAX_NAME_LENGTH];
  589.     #endif
  590.     nTeam[0] = 0; nTeam[1] = 0;
  591.    
  592.     for (i = 1; i <= L4D_MAXCLIENTS; i++)
  593.         if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && IsClientAuthorized(i))
  594.     {
  595.         team = GetClientTeam(i);
  596.        
  597.         if ((team != 2) && (team != 3)) continue;
  598.        
  599.         if (nTeam[team - 2] > TEAMSIZE)
  600.         {
  601.             #if DEBUGTEAMS
  602.             LogToFileEx(logPath, "PRINTER IS ON FIRE");
  603.             #endif
  604.             continue;
  605.         }
  606.        
  607.         #if DEBUGTEAMS
  608.         GetClientName(i, name, sizeof(name));
  609.         LogToFileEx(logPath, "Found %s on team %d, team - 2 = %d, nT[team - 2] = %d", name, team, team - 2, nTeam[team - 2]);
  610.         #endif
  611.         GetClientIP(i, auth, sizeof(auth),false);
  612.         strcopy(teams[team - 2][nTeam[team - 2]], SIDSIZE, auth);
  613.         nTeam[team - 2]++;
  614.     }
  615.     if (GetConVarBool(IsAutoBalanceOn))
  616.     {
  617.         new balanced=RoundToNearest(FloatAbs(float(nTeam[0]-nTeam[1])));
  618.         if (balanced>=2)
  619.         {
  620.             new balanced2=balanced / 2;
  621.             PrintToChatAll("Player moved to another team due team balance.");
  622.             if (nTeam[0]>nTeam[1]){
  623.                 // survivors have disbalans
  624.                 for (i = 0; i <= balanced2; i++)
  625.                 {
  626.                     strcopy(teams[1][nTeam[1]], SIDSIZE, teams[0][nTeam[0]]);
  627.                     new client=Ip2Client(teams[1][nTeam[1]]);
  628.                     //if (GetClientFrags(client) & ADMFLAG_RESERVATION)
  629.                     //continue;
  630.                     nTeam[0]--;
  631.                     nTeam[1]++;
  632.                     if (client)
  633.                         PerformSwitch_fast(client,L4D_TEAM_INFECTED);
  634.                 }
  635.                 PrintToChatAll("Player moved to another team due team balance.(SURV->INF) (%d,%d)",balanced,balanced2);
  636.             }else
  637.             {
  638.                 // infected have disbalans
  639.                 for (i = 0; i <= balanced2; i++)
  640.                 {
  641.                     strcopy(teams[0][nTeam[0]], SIDSIZE, teams[1][nTeam[1]]);
  642.                     new client=Ip2Client(teams[1][nTeam[1]]);
  643.                     nTeam[1]--;
  644.                     nTeam[0]++;
  645.                     if (client)
  646.                         PerformSwitch_fast(client,L4D_TEAM_SURVIVORS);
  647.                 }
  648.                 PrintToChatAll("Player moved to another team due team balance.(INF->SURV) (%d,%d)",balanced,balanced2);
  649.             }
  650.         }
  651.     }
  652.    
  653.     #if DEBUG
  654.     LogToFileEx(logPath, "Stored %d, %d", nTeam[0], nTeam[1]);
  655.     #endif
  656. }
  657.  
  658. Ip2Client(const String:ip[])
  659. {
  660.     for (new i = 1; i <= L4D_MAXCLIENTS; i++)
  661.         if (IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && IsClientAuthorized(i)){
  662.             decl String:curip[32];
  663.             GetClientIP(i,curip,32,false);
  664.             if (StrEqual(curip,ip)){
  665.                 return i;
  666.             }
  667.         }
  668.     return 0;  
  669. }
  670.  
  671. /********************************************************************************/
  672. /********************** from TeamSWITCH (by SkyDavid (djromero)) ****************/
  673. /********************************************************************************/
  674.  
  675. new bool:IsSwapPlayers;
  676. new SwapPlayer1;
  677. new SwapPlayer2;
  678.  
  679. new g_SwitchTo;
  680. new g_SwitchTarget;
  681.  
  682. public OnLibraryRemoved(const String:name[])
  683. {
  684.     if (StrEqual(name, "adminmenu"))
  685.     {
  686.         hTopMenu = INVALID_HANDLE;
  687.     }
  688. }
  689.  
  690. public OnAdminMenuReady(Handle:topmenu)
  691. {
  692.     // Check ..
  693.     if (topmenu == hTopMenu) return;
  694.    
  695.     // We save the handle
  696.     hTopMenu = topmenu;
  697.    
  698.     // Find player's menu ...
  699.     new TopMenuObject:players_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_PLAYERCOMMANDS);
  700.    
  701.     // now we add the function ...
  702.     if (players_commands != INVALID_TOPMENUOBJECT)
  703.     {
  704.         AddToTopMenu (hTopMenu, "l4dteamswitch", TopMenuObject_Item, SkyAdmin_SwitchPlayer, players_commands, "l4dteamswitch", ADMFLAG_KICK);
  705.         AddToTopMenu (hTopMenu, "l4dswapplayers", TopMenuObject_Item, SkyAdmin_SwapPlayers, players_commands, "l4dswapplayers", ADMFLAG_KICK);
  706.     }
  707. }
  708.  
  709. public SkyAdmin_SwitchPlayer(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
  710. {
  711.     IsSwapPlayers = false;
  712.     SwapPlayer1 = -1;
  713.     SwapPlayer2 = -1;
  714.    
  715.     if (action == TopMenuAction_DisplayOption)
  716.     {
  717.         Format(buffer, maxlength, "Switch player", "", param);
  718.     }
  719.     else if (action == TopMenuAction_SelectOption)
  720.     {
  721.         //DisplaySwitchPlayerToMenu(param);
  722.         DisplaySwitchPlayerMenu(param);
  723.     }
  724. }
  725.  
  726. public SkyAdmin_SwapPlayers(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
  727. {
  728.     IsSwapPlayers = true;
  729.     SwapPlayer1 = -1;
  730.     SwapPlayer2 = -1;
  731.    
  732.     if (action == TopMenuAction_DisplayOption)
  733.     {
  734.         Format(buffer, maxlength, "Swap players", "", param);
  735.     }
  736.     else if (action == TopMenuAction_SelectOption)
  737.     {
  738.         //DisplaySwitchPlayerToMenu(param);
  739.         DisplaySwitchPlayerMenu(param);
  740.     }
  741. }
  742.  
  743.  
  744. DisplaySwitchPlayerMenu(client)
  745. {
  746.     new Handle:menu = CreateMenu(MenuHandler_SwitchPlayer);
  747.    
  748.     decl String:title[100];
  749.     if (!IsSwapPlayers)
  750.         Format(title, sizeof(title), "Switch player", "", client);
  751.     else
  752.     {
  753.         if (SwapPlayer1 == -1)
  754.             Format(title, sizeof(title), "Player 1", "", client);
  755.         else
  756.         Format(title, sizeof(title), "Player 2", "", client);
  757.     }
  758.     SetMenuTitle(menu, title);
  759.     SetMenuExitBackButton(menu, true);
  760.    
  761.     AddTargetsToMenu2(menu, client, COMMAND_FILTER_CONNECTED | COMMAND_FILTER_NO_BOTS);
  762.    
  763.     DisplayMenu(menu, client, MENU_TIME_FOREVER);
  764. }
  765.  
  766. public MenuHandler_SwitchPlayer(Handle:menu, MenuAction:action, param1, param2)
  767. {
  768.     if (action == MenuAction_End)
  769.     {
  770.         CloseHandle(menu);
  771.     }
  772.     else if (action == MenuAction_Cancel)
  773.     {
  774.         if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
  775.         {
  776.             DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
  777.         }
  778.     }
  779.     else if (action == MenuAction_Select)
  780.     {
  781.         decl String:info[32];
  782.         new userid, target;
  783.        
  784.         GetMenuItem(menu, param2, info, sizeof(info));
  785.         userid = StringToInt(info);
  786.        
  787.         if ((target = GetClientOfUserId(userid)) == 0)
  788.         {
  789.             PrintToChat(param1, "[SM] %t", "Player no longer available");
  790.         }
  791.         else if (!CanUserTarget(param1, target))
  792.         {
  793.             PrintToChat(param1, "[SM] %t", "Unable to target");
  794.         }
  795.        
  796.         if (IsSwapPlayers)
  797.         {
  798.             if (SwapPlayer1 == -1)
  799.                 SwapPlayer1 = target;
  800.             else
  801.             SwapPlayer2 = target;
  802.            
  803.             if ((SwapPlayer1 != -1)&&(SwapPlayer2 != -1))
  804.             {
  805.                 PerformSwap(param1);
  806.                 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
  807.             }
  808.             else
  809.             DisplaySwitchPlayerMenu(param1);
  810.            
  811.         }
  812.         else
  813.         {
  814.             g_SwitchTarget = target;
  815.             DisplaySwitchPlayerToMenu(param1);
  816.         }
  817.     }
  818. }
  819.  
  820. DisplaySwitchPlayerToMenu(client)
  821. {
  822.     new Handle:menu = CreateMenu(MenuHandler_SwitchPlayerTo);
  823.    
  824.     decl String:title[100];
  825.     Format(title, sizeof(title), "Choose team", "", client);
  826.     SetMenuTitle(menu, title);
  827.     SetMenuExitBackButton(menu, true);
  828.    
  829.     AddMenuItem(menu, "1", "Spectators");
  830.     AddMenuItem(menu, "2", "Survivors");
  831.     AddMenuItem(menu, "3", "Infected");
  832.    
  833.     DisplayMenu(menu, client, MENU_TIME_FOREVER);
  834. }
  835.  
  836. public MenuHandler_SwitchPlayerTo(Handle:menu, MenuAction:action, param1, param2)
  837. {
  838.     if (action == MenuAction_End)
  839.     {
  840.         CloseHandle(menu);
  841.     }
  842.     else if (action == MenuAction_Cancel)
  843.     {
  844.         if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
  845.         {
  846.             DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
  847.         }
  848.     }
  849.     else if (action == MenuAction_Select)
  850.     {
  851.         decl String:info[32];
  852.        
  853.         GetMenuItem(menu, param2, info, sizeof(info));
  854.         g_SwitchTo = StringToInt(info);
  855.        
  856.         PerformSwitch(param1, g_SwitchTarget, g_SwitchTo, false);
  857.        
  858.         DisplaySwitchPlayerMenu(param1);
  859.     }
  860. }
  861.  
  862. /*public Action:Command_ChooseTeam(client, args) {
  863.     if (client==0) client=1;
  864.     DisplayChooseTeamMenu(client);
  865.     return Plugin_Handled;
  866. }
  867. */
  868. DisplayChooseTeamMenu(client)
  869. {
  870.     new Handle:menu = CreateMenu(MenuHandler_ChooseTeam);
  871.     SetMenuTitle(menu, "Choose team");
  872.     SetMenuExitButton(menu, true);
  873.    
  874.     AddMenuItem(menu, "option1", "Spectators");
  875.     AddMenuItem(menu, "option2", "Survivors");
  876.     AddMenuItem(menu, "option3", "Infected");
  877.    
  878.     DisplayMenu(menu, client, MENU_TIME_FOREVER);
  879. }
  880.  
  881. public MenuHandler_ChooseTeam(Handle:menu, MenuAction:action, param1, param2)
  882. {
  883.     if (action == MenuAction_End)
  884.     {
  885.         CloseHandle(menu);
  886.     }
  887.     else if (action == MenuAction_Select)
  888.     {
  889.         param2+=1;
  890.         PerformSwitch(param1, param1, param2, true);
  891.         CloseHandle(menu);
  892.     }
  893. }
  894.  
  895.  
  896. bool:IsTeamFull (team)
  897. {
  898.     // Spectator's team is never full :P
  899.     if (team == 1)
  900.         return false;
  901.    
  902.     new max = GetTeamMaxHumans(team);
  903.     new count = GetTeamHumanCount(team);
  904.    
  905.     // If full ...
  906.     return (count >= max);
  907. }
  908.  
  909.  
  910. PerformSwap (client)
  911. {
  912.     // If client 1 and 2 are the same ...
  913.     if (SwapPlayer1 == SwapPlayer2)
  914.     {
  915.         PrintToChat(client, "[SM] Can't swap this player with himself.");
  916.         return;
  917.     }
  918.    
  919.     // Check if 1st player is still valid ...
  920.     if ((!IsClientConnected(SwapPlayer1)) || (!IsClientInGame(SwapPlayer1)))
  921.     {
  922.         PrintToChat(client, "[SM] First player is not available anymore.");
  923.         return;
  924.     }
  925.  
  926.     // Check if 2nd player is still valid ....
  927.     if ((!IsClientConnected(SwapPlayer2)) || (!IsClientInGame(SwapPlayer2)))
  928.     {
  929.         PrintToChat(client, "[SM] Second player is not available anymore.");
  930.         return;
  931.     }
  932.    
  933.     // get the teams of each player
  934.     new team1 = GetClientTeam(SwapPlayer1);
  935.     new team2 = GetClientTeam(SwapPlayer2);
  936.    
  937.     // If both players are on the same team ...
  938.     if (team1 == team2)
  939.     {
  940.         PrintToChat(client, "[SM] Can't swap players that are on the same team.");
  941.         return;
  942.     }
  943.     ChangeTeamInList(SwapPlayer1,SwapPlayer2,true);
  944.    
  945.     // first we move both clients to spectators
  946.     PerformSwitch(client, SwapPlayer1, 1, true);
  947.     PerformSwitch(client, SwapPlayer2, 1, true);
  948.    
  949.     // Now we move each client to their respective team
  950.     PerformSwitch(client, SwapPlayer1, team2, true);
  951.     PerformSwitch(client, SwapPlayer2, team1, true);
  952.    
  953.     // Print swap info ..
  954.     new String:PlayerName1[200];
  955.     new String:PlayerName2[200];
  956.     GetClientName(SwapPlayer1, PlayerName1, sizeof(PlayerName1));
  957.     GetClientName(SwapPlayer2, PlayerName2, sizeof(PlayerName2));
  958.     PrintToChatAll("\x01[SM] \x03%s \x01has been swapped with \x03%s", PlayerName1, PlayerName2);
  959. }
  960.  
  961.  
  962. PerformSwitch_fast (target, team)
  963. {
  964.     ChangePlayerTeam(target,team);
  965.     // Print switch info ..
  966.     new String:PlayerName[200];
  967.     GetClientName(target, PlayerName, sizeof(PlayerName));
  968.     if (team == 1)
  969.         PrintToChatAll("\x01[SM] \x03%s \x01has been moved to \x03Spectators", PlayerName);
  970.     else if (team == 2)
  971.         PrintToChatAll("\x01[SM] \x03%s \x01has been moved to \x03Survivors", PlayerName);
  972.     else if (team == 3)
  973.         PrintToChatAll("\x01[SM] \x03%s \x01has been moved to \x03Infected", PlayerName);
  974. }
  975.  
  976. PerformSwitch (client, target, team, bool:silent)
  977. {
  978.     if ((!IsClientConnected(target)) || (!IsClientInGame(target)))
  979.     {
  980.         PrintToChat(client, "[SM] The player is not avilable anymore.");
  981.         return;
  982.     }
  983.    
  984.     // If teams are the same ...
  985.     if (GetClientTeam(target) == team)
  986.     {
  987.         PrintToChat(client, "[SM] That player is already on that team.");
  988.         return;
  989.     }
  990.    
  991.     // If we should check if teams are full ...
  992.     if (GetConVarBool(h_Switch_CheckTeams))
  993.     {
  994.         // We check if target team is full...
  995.         if (IsTeamFull(team))
  996.         {
  997.             if (team == 2)
  998.                 PrintToChat(client, "[SM] The \x03Survivor\x01's team is already full.");
  999.             else
  1000.             PrintToChat(client, "[SM] The \x03Infected\x01's team is already full.");
  1001.             return;
  1002.         }
  1003.     }
  1004.  
  1005.     if (!silent)
  1006.         ChangeTeamInList(target,team,false);
  1007.        
  1008.    
  1009.     if (!ChangePlayerTeam(target,team)){
  1010.         PrintToChat(client, "[SM] Error due change team.");
  1011.     }
  1012.    
  1013.     // Print switch info ..
  1014.     new String:PlayerName[200];
  1015.     GetClientName(target, PlayerName, sizeof(PlayerName));
  1016.    
  1017.     if (!silent)
  1018.     {
  1019.         if (team == 1)
  1020.             PrintToChatAll("\x01[SM] \x03%s \x01has been moved to \x03Spectators", PlayerName);
  1021.         else if (team == 2)
  1022.             PrintToChatAll("\x01[SM] \x03%s \x01has been moved to \x03Survivors", PlayerName);
  1023.         else if (team == 3)
  1024.             PrintToChatAll("\x01[SM] \x03%s \x01has been moved to \x03Infected", PlayerName);
  1025.     }
  1026. }
  1027.  
  1028.  
  1029. /********************************************************************************/
  1030. /******************************** STOKS *****************************************/
  1031. /********************************************************************************/
  1032.  
  1033. ChangeTeamInList(client,param2=0,bool:goswap)
  1034. {
  1035.     decl String:ip1[SIDSIZE];
  1036.     decl String:ip2[SIDSIZE];
  1037.     new index=-1;
  1038.     new index2=-1;
  1039.     new subindex=-1;
  1040.     new subindex2=-1;
  1041.     GetClientIP(client,ip1,SIDSIZE,false);
  1042.     if (goswap)    
  1043.         GetClientIP(param2,ip2,SIDSIZE,false);
  1044.     for (new i = 0; i < 2; i++){
  1045.         for (new j = 0; j < nTeam[i]; j++){
  1046.             if (!strcmp(ip1,teams[i][j])){
  1047.                     index=i;
  1048.                     subindex=j;
  1049.                     if (!goswap) break;
  1050.             }
  1051.             if (goswap){
  1052.                 if (!strcmp(ip2,teams[i][j])){
  1053.                     index2=i;
  1054.                     subindex2=j;
  1055.                 }
  1056.                 if (subindex!=-1 && subindex2!=-1) break;
  1057.             }
  1058.         }
  1059.     }
  1060.     if (goswap){
  1061.         if (subindex!=-1)
  1062.             strcopy(teams[index][subindex],SIDSIZE,ip2);
  1063.         if (subindex2!=-1)
  1064.             strcopy(teams[index2][subindex2],SIDSIZE,ip1);
  1065.         return;
  1066.     }
  1067.     new nindex = param2 - 2;   
  1068.     if (index != -1)
  1069.         DeleteFromList(index,subindex);
  1070.     if (param2==L4D_TEAM_SPECTATE)
  1071.         return;
  1072.     strcopy(teams[nindex][nTeam[nindex]], SIDSIZE, ip1);
  1073.     nTeam[nindex]++;   
  1074. }
  1075.  
  1076. DeleteFromList(index,subindex)
  1077. {
  1078.     if (subindex!=nTeam[index]-1)
  1079.         strcopy(teams[index][subindex],SIDSIZE,teams[index][nTeam[index]-1]);
  1080.     nTeam[index]--;
  1081. }
  1082.  
  1083. stock OppositeLogicalTeam(logical_team)
  1084. {
  1085.     if(logical_team == SCORE_TEAM_A)
  1086.         return SCORE_TEAM_B;
  1087.    
  1088.     else if(logical_team == SCORE_TEAM_B)
  1089.         return SCORE_TEAM_A;
  1090.    
  1091.     else
  1092.     return -1;
  1093. }
  1094.  
  1095. stock bool:ChangePlayerTeam(client, team)
  1096. {
  1097.     if(GetClientTeam(client) == team) return true;
  1098.    
  1099.     if(team != L4D_TEAM_SURVIVORS)
  1100.     {
  1101.         //we can always swap to infected or spectator, it has no actual limit
  1102.         ChangeClientTeam(client, team);
  1103.         return true;
  1104.     }
  1105.    
  1106.     if(GetTeamHumanCount(team) == GetTeamMaxHumans(team))
  1107.     {
  1108.         LogToFileEx(logPath, "ChangePlayerTeam() : Cannot switch %N to team %d, as team is full", client, team);
  1109.         return false;
  1110.     }
  1111.    
  1112.     new bot;
  1113.     //for survivors its more tricky
  1114.     for(bot = 1;
  1115.     bot < L4D_MAXCLIENTS_PLUS1 && (!IsClientConnected(bot) || !IsFakeClient(bot) || (GetClientTeam(bot) != L4D_TEAM_SURVIVORS));
  1116.     bot++) {}
  1117.    
  1118.     if(bot == L4D_MAXCLIENTS_PLUS1)
  1119.     {
  1120.         LogToFileEx(logPath, "Could not find a survivor bot, adding a bot ourselves");
  1121.        
  1122.         new String:command[] = "sb_add";
  1123.         new flags = GetCommandFlags(command);
  1124.         SetCommandFlags(command, flags & ~FCVAR_CHEAT);
  1125.        
  1126.         ServerCommand("sb_add");
  1127.        
  1128.         SetCommandFlags(command, flags);
  1129.        
  1130.         LogToFileEx(logPath, "Added a survivor bot, trying again...");
  1131.         return false;
  1132.     }
  1133.    
  1134.     //have to do this to give control of a survivor bot
  1135.     SDKCall(fSHS, bot, client);
  1136.     SDKCall(fTOB, client, true);
  1137.    
  1138.     return true;
  1139. }
  1140.  
  1141. stock GetTeamHumanCount(team)
  1142. {
  1143.     new humans = 0;
  1144.    
  1145.     for(new i = 1; i < L4D_MAXCLIENTS_PLUS1; i++)
  1146.     {
  1147.         if(IsClientInGameHuman(i) && GetClientTeam(i) == team){
  1148.             humans++;
  1149.         }
  1150.     }
  1151.    
  1152.     return humans;
  1153. }
  1154.  
  1155. stock GetTeamMaxHumans(team)
  1156. {
  1157.     if(team == L4D_TEAM_SURVIVORS)
  1158.     {
  1159.         return GetConVarInt(FindConVar("survivor_limit"));
  1160.     }
  1161.     else if(team == L4D_TEAM_INFECTED)
  1162.     {
  1163.         return GetConVarInt(FindConVar("z_max_player_zombies"));
  1164.     }
  1165.     else if(team == L4D_TEAM_SPECTATE)
  1166.     {
  1167.         return L4D_MAXCLIENTS;
  1168.     }
  1169.    
  1170.     return -1;
  1171. }
  1172.  
  1173. stock GetTeamRoundScore(logical_team)
  1174. {
  1175.     return SDKCall(fGTS, logical_team, SCORE_TYPE_ROUND);  
  1176. }
  1177.  
  1178. stock GetTeamCompaignScore(logical_team)
  1179. {
  1180.     return SDKCall(fGTS, logical_team, SCORE_TYPE_CAMPAIGN);   
  1181. }
  1182.  
  1183.  
  1184. //client is in-game and not a bot
  1185. stock bool:IsClientInGameHuman(client)
  1186. {
  1187.     if (client > 0) return IsClientInGame(client) && !IsFakeClient(client);
  1188.     else return false;
  1189. }
RAW Paste Data