diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 7b802f7..189aa1d 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -109,7 +109,7 @@ public OnPluginStart() // ====================================================================== - market = LibraryExists("market"); + g_bMarket = LibraryExists("market"); // ====================================================================== @@ -126,7 +126,7 @@ public OnLibraryRemoved(const String:name[]) { if (StrEqual(name, "market")) { - market = false; + g_bMarket = false; } } @@ -134,7 +134,7 @@ public OnLibraryAdded(const String:name[]) { if (StrEqual(name, "market")) { - market = true; + g_bMarket = true; } } @@ -187,7 +187,7 @@ public OnConfigsExecuted() public OnClientPutInServer(client) { - gBlockMotherInfect[client] = false; + bMotherInfectImmune[client] = false; // Forward event to modules. ClassClientInit(client); @@ -198,14 +198,12 @@ public OnClientPutInServer(client) ZHPClientInit(client); ClientHookAttack(client); - FindClientDXLevel(client); + ZRFindClientDXLevel(client); for (new x = 0; x < MAXTIMERS; x++) { tHandles[client][x] = INVALID_HANDLE; } - - RefreshList(); } public OnClientDisconnect(client) @@ -227,8 +225,6 @@ public OnClientDisconnect(client) tHandles[client][x] = INVALID_HANDLE; } } - - RefreshList(); } MapChangeCleanup() diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index be00a60..d84ee42 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -101,7 +101,6 @@ CreateCvars() { gCvars[CVAR_ENABLE] = CreateConVar("zr_enable", "1", "Enable zombie gameplay (0: Disable)"); gCvars[CVAR_LOG] = CreateConVar("zr_log", "331", "Logging flags. Log messages to sourcemod logs, server console or client console. Use zr_log_flags to see a list of flags. (0: Disable)"); - gCvars[CVAR_ALLOW_PLAYER_TEAM] = CreateConVar("zr_allow_player_team", "0", "This will allow the player_team event to be fired on first team join, enable when using mani model menu (0: Disable)"); gCvars[CVAR_AMBIENTSOUNDS] = CreateConVar("zr_ambientsounds", "1", "Enable creepy ambience to be played throughout the game (0: Disable)"); gCvars[CVAR_AMBIENTSOUNDS_FILE] = CreateConVar("zr_ambientsounds_file", "ambient/zr/zr_ambience.mp3", "Path to ambient sound file that will be played throughout the game, when zr_ambience is 1"); gCvars[CVAR_AMBIENTSOUNDS_LENGTH] = CreateConVar("zr_ambientsounds_length", "60.0", "The length, in seconds, of the ambient sound file"); diff --git a/src/zr/event.inc b/src/zr/event.inc index 3305d8f..00fe2c2 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -35,7 +35,6 @@ UnhookEvents() public Action:RoundStart(Handle:event, const String:name[], bool:dontBroadcast) { ChangeLightStyle(); - RefreshList(); // Forward event to sub-modules. SEffectsOnRoundStart(); @@ -97,7 +96,7 @@ public Action:RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) tInfect = INVALID_HANDLE; } - zombieSpawned = false; + g_bZombieSpawned = false; for (new x = 1; x<= MaxClients; x++) { @@ -106,10 +105,7 @@ public Action:RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) continue; } - gZombie[x] = false; - - new bool:consecutive_infect = GetConVarBool(gCvars[CVAR_CONSECUTIVE_INFECT]); - gBlockMotherInfect[x] = consecutive_infect ? false : motherZombie[x]; + bZombie[x] = false; } BalanceTeams(); @@ -135,14 +131,7 @@ public Action:PlayerTeam(Handle:event, const String:name[], bool:dontBroadcast) if (team == CS_TEAM_SPECTATOR) { - gZombie[index] = false; - motherZombie[index] = false; - } - - new bool:allow_player_team = GetConVarBool(gCvars[CVAR_ALLOW_PLAYER_TEAM]); - if (allow_player_team && !IsPlayerInList(index)) - { - return Plugin_Continue; + bZombie[index] = false; } return Plugin_Handled; @@ -161,8 +150,7 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) } } - gZombie[index] = false; - motherZombie[index] = false; + bZombie[index] = false; // Reset FOV and overlay. SetPlayerFOV(index, 90); @@ -182,7 +170,7 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) NightVisionOn(index, false); NightVision(index, false); - if (zombieSpawned) + if (g_bZombieSpawned) { if (ZRIsClientOnTeam(index, CS_TEAM_T)) { diff --git a/src/zr/menu.inc b/src/zr/menu.inc index 70a96df..dd8d652 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -32,7 +32,7 @@ MainMenu(client) AddMenuItem(menu_main, "zadmin", zadmin, itemdraw); AddMenuItem(menu_main, "zclass", zclass); - if (market) + if (g_bMarket) { AddMenuItem(menu_main, "zmarket", zmarket); } diff --git a/src/zr/overlays.inc b/src/zr/overlays.inc index 0324c60..022d274 100644 --- a/src/zr/overlays.inc +++ b/src/zr/overlays.inc @@ -25,7 +25,7 @@ ShowOverlays(Float:time, ZTeam:winner) { if (IsClientInGame(x)) { - DisplayClientOverlay(x, overlay); + ZRDisplayClientOverlay(x, overlay); } } diff --git a/src/zr/playerclasses/classevents.inc b/src/zr/playerclasses/classevents.inc index d7a59d1..4f16795 100644 --- a/src/zr/playerclasses/classevents.inc +++ b/src/zr/playerclasses/classevents.inc @@ -56,7 +56,7 @@ ClassOnClientSpawn(client) // If the first zombie spawned, and the player is on the terrorist team, then // find a random zombie class, otherwise find a human class. - if (zombieSpawned && teamid == CS_TEAM_T) + if (g_bZombieSpawned && teamid == CS_TEAM_T) { new classindex = ClassGetRandomClass(ZR_CLASS_TEAM_ZOMBIES); ClassSelected[client][ZR_CLASS_TEAM_ZOMBIES] = classindex; diff --git a/src/zr/respawn.inc b/src/zr/respawn.inc index 46aefc4..5ef2c77 100644 --- a/src/zr/respawn.inc +++ b/src/zr/respawn.inc @@ -115,7 +115,7 @@ RespawnSpawnClient(client) CS_RespawnPlayer(client); // Stop here if the first zombie hasn't spawned yet. - if (!zombieSpawned) + if (!g_bZombieSpawned) { return; } diff --git a/src/zr/sayhooks.inc b/src/zr/sayhooks.inc index 71bb290..f315405 100644 --- a/src/zr/sayhooks.inc +++ b/src/zr/sayhooks.inc @@ -98,13 +98,6 @@ ZSpawn(client) { return; } - - if (IsPlayerInList(client)) - { - return; - } RespawnSpawnClient(client); - - AddPlayerToList(client); } \ No newline at end of file diff --git a/src/zr/spawnprotect.inc b/src/zr/spawnprotect.inc index d9c1e58..074a0fd 100644 --- a/src/zr/spawnprotect.inc +++ b/src/zr/spawnprotect.inc @@ -62,7 +62,7 @@ SpawnProtectOnClientSpawn(client) } // If zombie hasn't spawned, then stop. - if (!zombieSpawned) + if (!g_bZombieSpawned) { return; } diff --git a/src/zr/teleport.inc b/src/zr/teleport.inc index 8561ccf..a2f312c 100644 --- a/src/zr/teleport.inc +++ b/src/zr/teleport.inc @@ -386,7 +386,7 @@ bool:ZTele(client) tele_humans = true; } - if (!tele_humans && zombieSpawned) + if (!tele_humans && g_bZombieSpawned) { ZR_PrintToChat(client, "!ztele humans restricted"); return false; diff --git a/src/zr/weapons/markethandler.inc b/src/zr/weapons/markethandler.inc index f55a754..c92884b 100644 --- a/src/zr/weapons/markethandler.inc +++ b/src/zr/weapons/markethandler.inc @@ -14,7 +14,7 @@ bool:ZMarketSend(client) { // If market is disabled, then stop. - if (!market) + if (!g_bMarket) { // Tell client market is disabled. ZR_PrintToChat(client, "Feature is disabled"); diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index b431f5e..bf99c3e 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -50,7 +50,7 @@ WeaponsMenuMain(client) AddMenuItem(menu_weapons_main, "togglewgrouprestriction", togglewgrouprestriction); // Disable market option if market isn't installed. - if (market) + if (g_bMarket) { AddMenuItem(menu_weapons_main, "zmarket", zmarket); } @@ -422,7 +422,7 @@ WeaponsMenuMarket(client) decl String:togglebuyzone[64]; decl String:curSetting[8]; - BoolToConfigSetting(GetConVarBool(gCvars[CVAR_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting)); + ZRBoolToConfigSetting(GetConVarBool(gCvars[CVAR_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting)); Format(togglebuyzone, sizeof(togglebuyzone), "%t", "Weapons menu market toggle buyzone", curSetting); diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index db05086..832f1df 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -107,7 +107,7 @@ RestrictDefaultRestrictions() decl String:restrict[8]; KvGetString(kvWeapons, "restrict", restrict, sizeof(restrict), "no"); - if (ConfigSettingToBool(restrict)) + if (ZRConfigSettingToBool(restrict)) { new WpnRestrictQuery:output = RestrictRestrict(weapon, display); RestrictPrintRestrictOutput(0, output, display, true); diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index dc44866..e54426f 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -234,7 +234,7 @@ bool:WeaponsIsWeaponMenu(const String:weapon[]) KvGetString(kvWeapons, "menu", menu, sizeof(menu), "yes"); // Return weapon's setting. - return ConfigSettingToBool(menu); + return ZRConfigSettingToBool(menu); } } while (KvGotoNextKey(kvWeapons)); } diff --git a/src/zr/zombie.inc b/src/zr/zombie.inc index 36e244e..ea46094 100644 --- a/src/zr/zombie.inc +++ b/src/zr/zombie.inc @@ -96,67 +96,127 @@ public RestartGameHook(Handle:convar, const String:oldValue[], const String:newV TerminateRound(StringToFloat(newValue), Round_Draw); } +/** + * Timer callback, chooses mother zombies. + * + * @param timer The timer handle. + */ public Action:MotherZombie(Handle:timer) { - RefreshList(); + // Reset timer handle. + tInfect = INVALID_HANDLE; - new size = GetArraySize(pList); - new immune = 0; + // Create array. + new Handle:arrayEligibleClients = CreateArray(); - for (new x = 0; x < size; x++) + // Populate list with eligible clients. + // x = client index. + for (new x = 1; x <= MaxClients; x++) { - new index = GetArrayCell(pList, x); - - if (gBlockMotherInfect[index]) - { - immune++; - } - - if (!IsPlayerAlive(index) || IsPlayerZombie(index)) + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) { continue; } - CS_SwitchTeam(index, CS_TEAM_CT); + // If client is dead, then stop. + if (!IsPlayerAlive(x)) + { + continue; + } + + // If client is immune from being a mother zombie, then stop. + if (bMotherInfectImmune[x]) + { + // Take away immunity. + bMotherInfectImmune[x] = false; + + continue; + } + + // Add eligible client to array. + PushArrayCell(arrayEligibleClients, x); } - if (!(size - immune)) + // If there are no eligible client's then stop. + new eligibleclients = GetArraySize(arrayEligibleClients); + if (!eligibleclients) { - tInfect = INVALID_HANDLE; - return; } - new randclient; + // Move all clients to CT + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // If client is dead, then stop. + if (!IsPlayerAlive(x)) + { + continue; + } + + // Switch client to CT team. + CS_SwitchTeam(x, CS_TEAM_CT); + } + + // Variable to store randomly chosen array index. + new randindex; + + // Variable to store client stored in random array index. + new client; + + // Ratio of mother zombies to humans. new ratio = GetConVarInt(gCvars[CVAR_MOTHER_ZOMBIE_RATIO]); + // If ratio is 0 or lower, then pick 1 zombie. if (ratio <= 0) { - do - { - randclient = RandomPlayerFromList(); - } while (!IsPlayerAlive(randclient) || gBlockMotherInfect[randclient]); + // Get a random valid array index. + randindex = GetRandomInt(0, eligibleclients - 1); - InfectPlayer(randclient, _, true); + // Get the client stored in the random array index. + client = GetArrayCell(arrayEligibleClients, randindex); + + // Infect player. + InfectPlayer(client, _, true); } else { - new mothercount = RoundToCeil(float(size) / ratio); + // Calculate mother zombie sound. + new mothercount = RoundToCeil(float(eligibleclients) / ratio); + // x = current mother zombie count. for (new x = 0; x < mothercount; x++) { - do - { - randclient = RandomPlayerFromList(); - } while (IsPlayerZombie(randclient) || !IsPlayerAlive(randclient) || gBlockMotherInfect[randclient]); + // Recount eligible clients. + eligibleclients = GetArraySize(arrayEligibleClients); - InfectPlayer(randclient, _, true); + // If there are no more eligible clients, then break loop. + if (!eligibleclients) + { + break; + } + // Get a random valid array index. + randindex = GetRandomInt(0, eligibleclients - 1); + + // Get the client stored in the random array index. + client = GetArrayCell(arrayEligibleClients, randindex); + + // Infect player. + InfectPlayer(client, _, true); + + // Remove player from eligible zombie list. + RemoveFromArray(arrayEligibleClients, randindex); } } - tInfect = INVALID_HANDLE; - - zombieSpawned = true; + // Mother zombies have been infected. + g_bZombieSpawned = true; } /** @@ -184,8 +244,7 @@ InfectPlayer(client, attacker = -1, bool:motherinfect = false) } // Set player status. - gZombie[client] = true; - motherZombie[client] = motherinfect; + bZombie[client] = true; // Remove all weapons and give a knife. RemoveAllPlayersWeapons(client); @@ -200,6 +259,9 @@ InfectPlayer(client, attacker = -1, bool:motherinfect = false) // Switch the player to terrorists. CS_SwitchTeam(client, CS_TEAM_T); + // Flag player to be immune from being mother zombie twice. + bMotherInfectImmune[client] = motherinfect; + // Forward event to modules. ClassOnClientInfected(client, motherinfect); SEffectsOnClientInfected(client); @@ -333,7 +395,7 @@ PlayerLeft(client) for (new x = 1; x <= MaxClients; x++) { - if (!IsClientInGame(x) || !IsPlayerAlive(x) || client == x || GetClientTeam(x) != CS_TEAM_CT || gBlockMotherInfect[x]) + if (!IsClientInGame(x) || !IsPlayerAlive(x) || client == x || GetClientTeam(x) != CS_TEAM_CT || bMotherInfectImmune[x]) { continue; } @@ -405,7 +467,7 @@ ZTeam:IsRoundOver() if (humans && !zombies) { - if (zombieSpawned) + if (g_bZombieSpawned) { return Human; } @@ -486,12 +548,12 @@ public Action:RoundOver(Handle:timer) bool:IsPlayerZombie(client) { - return gZombie[client]; + return bZombie[client]; } bool:IsPlayerHuman(client) { - return !gZombie[client]; + return !bZombie[client]; } ZTeam:GetPlayerZTeam(client) diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index 3faef3b..b569c5b 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -6,13 +6,6 @@ * ==================== */ -enum ZTeam -{ - Neither, /** Round is not over */ - Zombie, /** Round is over because zombies win */ - Human, /** Round is over because humans wins */ -} - #define Target_Bombed 1 // Target Successfully Bombed! #define VIP_Escaped 2 // The VIP has escaped! #define VIP_Assassinated 3 // VIP has been assassinated! @@ -63,14 +56,52 @@ enum ZTeam * @endsection */ -new bool:market; +/** + * Lists possible returns of the game at any time. + */ +enum ZTeam +{ + Neither, /** Round is not over */ + Zombie, /** Round is over because zombies win */ + Human, /** Round is over because humans wins */ +} + +/** + * Global variable set to true if market plugin is installed + */ +new bool:g_bMarket; + +/** + * The DirectX level of a client. + */ new dxLevel[MAXPLAYERS + 1]; -new bool:zombieSpawned; -new bool:motherZombie[MAXPLAYERS + 1]; -new bool:gZombie[MAXPLAYERS + 1]; -new bool:gBlockMotherInfect[MAXPLAYERS + 1]; +/** + * Global variable set to true when the first zombie(s) is/are spawned. + */ +new bool:g_bZombieSpawned; +/** + * Array for flagging client as zombie. + */ +new bool:bZombie[MAXPLAYERS + 1]; + +/** + * Array for flagging player has immune to mother infect. + */ +new bool:bMotherInfectImmune[MAXPLAYERS + 1]; + +/** + * Global variable to store round win timer handle. + */ +new Handle:tRound = INVALID_HANDLE; + +/** + * Global variable to store the infect timer handle. + */ +new Handle:tInfect = INVALID_HANDLE; + +// TODO: MOVE TO TELEPORT MODULE. new Float:spawnLoc[MAXPLAYERS + 1][3]; new Float:bufferLoc[MAXPLAYERS + 1][3]; new bool:ztele_spawned[MAXPLAYERS + 1] = {false, ...}; @@ -82,145 +113,134 @@ new Handle:ztele_startup_timer = INVALID_HANDLE; new Handle:ztele_countdown_timer[MAXPLAYERS + 1] = {INVALID_HANDLE, ...}; new Handle:ztele_cooldown_timer[MAXPLAYERS + 1] = {INVALID_HANDLE, ...}; -new Handle:tRound = INVALID_HANDLE; -new Handle:tInfect = INVALID_HANDLE; - -new Handle:pList = INVALID_HANDLE; +// TODO: USE SEPARATE VARIABLE TO STORE TELEPORT TIMER HANDLE +// THEN WE CAN REMOVE tHandles ARRAY FOR GOOD. #define MAXTIMERS 1 #define TTELE 1 new Handle:tHandles[MAXPLAYERS + 1][MAXTIMERS]; -new QueryCookie:mat_dxlevel; - -bool:ConfigSettingToBool(const String:option[]) +/** + * Converts string of "yes" or "no" to a boolean value. + * + * @param option "yes" or "no" string to be converted. + * @return True if string is "yes", false otherwise. + */ +bool:ZRConfigSettingToBool(const String:option[]) { + // If option is equal to "yes," then return true. if (StrEqual(option, "yes", false)) { return true; } + // Option isn't "yes." return false; } -BoolToConfigSetting(bool:bOption, String:option[], maxlen) +/** + * Converts boolean value to "yes" or "no". + * + * @param bOption True/false value to be converted to "yes"/"no", respectively. + * @param option Variable to store "yes" or "no" in. + * @param maxlen Max length of return string, (can't be more than 4) + */ +ZRBoolToConfigSetting(bool:bOption, String:option[], maxlen) { + // If option is true, then copy "yes" to return string. if (bOption) { strcopy(option, maxlen, "yes"); } + // If option is false, then copy "no" to return string. else { strcopy(option, maxlen, "no"); } } -FindClientDXLevel(client) +/** + * Global variable to store a convar query cookie + */ +new QueryCookie:mat_dxlevel; + +/** + * Finds DX level of a client. + * + * @param client The client index. + */ +ZRFindClientDXLevel(client) { + // If client is fake (or bot), then stop. if (IsFakeClient(client)) { return; } - mat_dxlevel = QueryClientConVar(client, "mat_dxlevel", DXLevelClientQuery); + // Query mat_dxlevel on client. + mat_dxlevel = QueryClientConVar(client, "mat_dxlevel", ZRDXLevelClientQuery); } -public DXLevelClientQuery(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[]) +/** + * Query callback function. + * + * @param cookie Unique cookie of the query. + * @param client The client index. + * @param result The result of the query (see console.inc enum ConVarQueryResult) + * @param cvarName Name of the cvar. + * @param cvarValue Value of the cvar. + */ +public ZRDXLevelClientQuery(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[]) { + // If query cookie does not match cookie given by mat_dxlevel query, then stop, this isn't our query. if (cookie != mat_dxlevel) { return; } + // Reset dxLevel. dxLevel[client] = 0; + // If result is any other than ConVarQuery_Okay, then stop. if (result != ConVarQuery_Okay) { return; } + // Copy cvar value to dxLevel array. dxLevel[client] = StringToInt(cvarValue); } -DisplayClientOverlay(client, const String:overlay[]) +/** + * Displays overlay to client, or prints unsupported message on client's screen. + * + * @param client The client index. + * @param overlay The overlay path. + */ +ZRDisplayClientOverlay(client, const String:overlay[]) { + // If dxLevel is 0, then query on client failed, so try again, then stop. if (!dxLevel[client]) { - FindClientDXLevel(client); - + // Query dxlevel cvar. + ZRFindClientDXLevel(client); return; } + // If dxLevel is above or equal to minimum requirement, then display overlay. if (dxLevel[client] >= DXLEVEL_MIN) { ClientCommand(client, "r_screenoverlay \"%s\"", overlay); } + // If client doesn't meet minimum requirement, then print unsupported text. else { ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], DXLEVEL_MIN); } } -RefreshList() -{ - ClearList(); - - pList = CreateArray(); - - for (new x = 1; x <= MaxClients; x++) - { - if (IsClientInGame(x) && IsPlayerAlive(x)) - { - new team = GetClientTeam(x); - if (team == CS_TEAM_T || team == CS_TEAM_CT) - { - PushArrayCell(pList, x); - } - } - } -} - -AddPlayerToList(client) -{ - if (pList != INVALID_HANDLE) - { - PushArrayCell(pList, client); - } -} - -ClearList() -{ - if (pList != INVALID_HANDLE) - { - ClearArray(pList); - } -} - -RandomPlayerFromList() -{ - if (pList != INVALID_HANDLE) - { - new size = GetArraySize(pList); - new index = GetRandomInt(0, size - 1); - - return GetArrayCell(pList, index); - } - - return -1; -} - -bool:IsPlayerInList(client) -{ - if (pList != INVALID_HANDLE) - { - return (FindValueInArray(pList, client) != -1); - } - - return false; -} - /** * Check if a client index is a valid player. * @@ -266,6 +286,24 @@ bool:ZRIsClientOnTeam(client, team = -1) return (clientteam == team); } +/** + * Check if there are clients on a team. + * + * @param team (Optional) Team to check if there are clients on. + */ +ZRTeamHasClients(team = -1) +{ + // If team is + if (team == -1) + { + // Return true if both teams have at least 1 client. + return (GetTeamClientCount(CS_TEAM_T) && GetTeamClientCount(CS_TEAM_CT)); + } + + // Return true if given team has at least 1 client. + return (GetTeamClientCount(team)); +} + /** * Returns whether a player is a generic admin or not. *