diff --git a/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt b/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt index c2ede4f..31ca109 100644 --- a/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt +++ b/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt @@ -212,6 +212,13 @@ "knockback" "100.0" } + "Knife" + { + "restrict" "no" + "menu" "no" + "knockback" "8.0" + } + "NVGs" { "restrict" "yes" diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 053f5bf..b800784 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -41,6 +41,9 @@ // Weapons #include "zr/weapons/weapons" +// Sound effects +#include "zr/soundeffects/soundeffects" + // Hitgroups #include "zr/hitgroups" @@ -179,10 +182,10 @@ public OnConfigsExecuted() public OnClientPutInServer(client) { gBlockMotherInfect[client] = false; - gKilledByWorld[client] = false; // Forward event to modules. ClassClientInit(client); + ZombieSoundsClientInit(client); WeaponsClientInit(client); SpawnProtectClientInit(client); RespawnClientInit(client); diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index ad44cf8..bfdfe45 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -15,11 +15,12 @@ enum ZRSettings Handle:CVAR_AMBIENCE_FILE, Handle:CVAR_AMBIENCE_LENGTH, Handle:CVAR_AMBIENCE_VOLUME, - Handle:CVAR_EMITSOUNDS, + Handle:CVAR_SOUNDEFFECTS_MOAN, + Handle:CVAR_SOUNDEFFECTS_GROAN, + Handle:CVAR_SOUNDEFFECTS_DEATH, Handle:CVAR_CLASSES, Handle:CVAR_CLASSES_SPAWN, Handle:CVAR_CLASSES_RANDOM, - //Handle:CVAR_CLASSES_DEFAULT, Handle:CVAR_CLASSES_DEFAULT_ZOMBIE, Handle:CVAR_CLASSES_DEFAULT_HUMAN, Handle:CVAR_CLASSES_DEFAULT_ADMIN, @@ -104,11 +105,12 @@ CreateCvars() gCvars[CVAR_AMBIENCE_FILE] = CreateConVar("zr_ambience_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_AMBIENCE_LENGTH] = CreateConVar("zr_ambience_length", "60.0", "The length, in seconds, of the ambient sound file"); gCvars[CVAR_AMBIENCE_VOLUME] = CreateConVar("zr_ambience_volume", "0.6", "Volume of ambient sounds when zr_ambience is 1 (0.0: Unhearable, 1.0: Max volume)"); - gCvars[CVAR_EMITSOUNDS] = CreateConVar("zr_emitsounds", "50", "How often a zombie emits a sound, in seconds (0: Disable)"); + gCvars[CVAR_SOUNDEFFECTS_MOAN] = CreateConVar("zr_soundeffects_moan", "50", "How often, in seconds, a zombie moans (0: Disable)"); + gCvars[CVAR_SOUNDEFFECTS_GROAN] = CreateConVar("zr_soundeffects_groan", "5", "Chance factor a zombie will groan when shot (Lower: More often, 0: Disable)"); + gCvars[CVAR_SOUNDEFFECTS_DEATH] = CreateConVar("zr_soundeffects_death", "1", "Zombie will emit a death sound when killed 0: Disable)"); gCvars[CVAR_CLASSES] = CreateConVar("zr_classes", "1", "Enable zombie classes"); gCvars[CVAR_CLASSES_SPAWN] = CreateConVar("zr_classes_spawn", "0", "Classmenu is re-displayed every spawn (0: Disable)"); gCvars[CVAR_CLASSES_RANDOM] = CreateConVar("zr_classes_random", "0", "A random class is assigned to each player every round. Overrides zr_classes_spawn and default classes. (0: Disable)"); - //gCvars[CVAR_CLASSES_DEFAULT] = CreateConVar("zr_classes_default", "classic", "Default class selected for all players when they connect, or \"random\" to select a random class. Usage zr_classes_default "); gCvars[CVAR_CLASSES_DEFAULT_ZOMBIE] = CreateConVar("zr_classes_default_zombie", "", "Default zombie class selected for all players when they connect. Use \"random\" to select a random class, or blank to use class config defaults."); gCvars[CVAR_CLASSES_DEFAULT_HUMAN] = CreateConVar("zr_classes_default_human", "", "Default human class selected for all players when they connect. Use \"random\" to select a random class, or blank to use class config defaults."); gCvars[CVAR_CLASSES_DEFAULT_ADMIN] = CreateConVar("zr_classes_default_admin", "", "Default admin-only class selected for admins when they connect. Use \"random\" to select a random class, or blank to use class config defaults."); diff --git a/src/zr/event.inc b/src/zr/event.inc index 6f2b97a..8c5dab3 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -163,44 +163,40 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) SetPlayerFOV(index, 90); ClientCommand(index, "r_screenoverlay \"\""); - // Forward event to modules. - SpawnProtectOnClientSpawn(index); - RespawnOnClientSpawn(index); - ZHPOnClientSpawn(index); - - // Stop here if client isn't on a team. - new team = GetClientTeam(index); - if (team != CS_TEAM_T && team != CS_TEAM_CT) + // Check if client is on a team. + if (ZRIsClientOnTeam(index)) { - return; - } - - new bool:cashfill = GetConVarBool(gCvars[CVAR_CASHFILL]); - if (cashfill) - { - new cash = GetConVarInt(gCvars[CVAR_CASHAMOUNT]); - SetPlayerMoney(index, cash); - } - - // Remove night vision. - NightVisionOn(index, false); - NightVision(index, false); - - if (zombieSpawned) - { - if (team == CS_TEAM_T) + new bool:cashfill = GetConVarBool(gCvars[CVAR_CASHFILL]); + if (cashfill) { - CS_SwitchTeam(index, CS_TEAM_CT); - CS_RespawnPlayer(index); + new cash = GetConVarInt(gCvars[CVAR_CASHAMOUNT]); + SetPlayerMoney(index, cash); + } + + // Remove night vision. + NightVisionOn(index, false); + NightVision(index, false); + + if (zombieSpawned) + { + if (ZRIsClientOnTeam(index, CS_TEAM_T)) + { + CS_SwitchTeam(index, CS_TEAM_CT); + CS_RespawnPlayer(index); + } + } + else + { + SetPlayerAlpha(index, 255); } - } - else - { - SetPlayerAlpha(index, 255); } // Forward event to modules. ClassOnClientSpawn(index); + ZombieSoundsOnClientSpawn(index); + SpawnProtectOnClientSpawn(index); + RespawnOnClientSpawn(index); + ZHPOnClientSpawn(index); ZTeleClientSpawned(index); ZR_PrintToChat(index, "!zmenu reminder"); @@ -232,35 +228,21 @@ public Action:PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) } } - // Check if the player is a human. - if (IsPlayerHuman(index)) + // Check if the player is a zombie. + if (IsPlayerZombie(index)) { - // We're done now. Nothing more to do on humans. - return; - } - - // Play a random zombie hurt sound. - if (GetRandomInt(1, 5) == 1) - { - decl String:sound[64]; - new randsound = GetRandomInt(1, 6); - - Format(sound, sizeof(sound), "npc/zombie/zombie_pain%d.wav", randsound); - - PrecacheSound(sound); - EmitSoundToAll(sound, index); - } - - // Napalm effect. - new Float:napalm_time = ClassGetNapalmTime(index); - if (StrEqual(weapon, "hegrenade", false) && napalm_time > 0.0) - { - IgniteEntity(index, napalm_time); + // Napalm effect. + new Float:napalm_time = ClassGetNapalmTime(index); + if (StrEqual(weapon, "hegrenade", false) && napalm_time > 0.0) + { + IgniteEntity(index, napalm_time); + } } // Forward event to modules. ClassAlphaUpdate(index); - KnockbackPlayerHurt(index, attacker, weapon, hitgroup, dmg_health); + ZombieSoundsOnClientHurt(index); + KnockbackOnClientHurt(index, attacker, weapon, hitgroup, dmg_health); ZHPOnPlayerHurt(index); } @@ -304,13 +286,6 @@ public Action:PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) { if (IsPlayerZombie(index)) { - decl String:sound[64]; - - new randsound = GetRandomInt(1, 3); - Format(sound, sizeof(sound), "npc/zombie/zombie_die%d.wav", randsound); - - PrecacheSound(sound); - EmitSoundToAll(sound, index); // Give kill bonus. if (ZRIsValidClient(attacker)) @@ -318,9 +293,6 @@ public Action:PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) new bonus = ClassGetKillBonus(attacker); AddPlayerScore(attacker, bonus); } - - // Set gKilledByWorld to true if attacker is not a valid client. - gKilledByWorld[index] = !ZRIsValidClient(attacker); } // Kill various timers. @@ -336,8 +308,9 @@ public Action:PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) // Forward event to modules. ClassOnClientDeath(index); + ZombieSoundsOnClientDeath(index); SpawnProtectOnClientDeath(index); - RespawnOnClientDeath(index, weapon); + RespawnOnClientDeath(index, attacker, weapon); ZHPOnClientDeath(index); new ZTeam:team = IsRoundOver(); diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index 240d296..017a3f8 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -14,7 +14,7 @@ * @param hitgroup Hitgroup attacker has damaged. * @param dmg_health Damage done. */ -KnockbackPlayerHurt(client, attacker, const String:weapon[], hitgroup, dmg_health) +KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_health) { // Check if the attacker is a player. if (attacker != 0) diff --git a/src/zr/respawn.inc b/src/zr/respawn.inc index a26d07d..46aefc4 100644 --- a/src/zr/respawn.inc +++ b/src/zr/respawn.inc @@ -14,6 +14,11 @@ */ new Handle:tRespawn[MAXPLAYERS + 1]; +/** + * Array for flagging zombies who were killed by world. + */ +new bool:pKilledByWorld[MAXPLAYERS + 1]; + /** * Client is joining the server. */ @@ -22,8 +27,8 @@ RespawnClientInit(client) // Reset timer handle. tRespawn[client] = INVALID_HANDLE; - // Init gKilledByWorld for client. - gKilledByWorld[client] = false; + // Init pKilledByWorld for client. + pKilledByWorld[client] = false; } /** @@ -48,8 +53,15 @@ RespawnOnClientSpawn(client) * * @param client The client index. */ -RespawnOnClientDeath(client, const String:weapon[]) +RespawnOnClientDeath(client, attacker, const String:weapon[]) { + // If client is a zombie, check if they were killed by world. + if (IsPlayerZombie(client)) + { + // Set pKilledByWorld to true if attacker is not a valid client. + pKilledByWorld[client] = !ZRIsValidClient(attacker); + } + // If timer is running, kill it. if (tRespawn[client] != INVALID_HANDLE) { @@ -73,7 +85,19 @@ RespawnOnClientDeath(client, const String:weapon[]) new Float:delay = GetConVarFloat(gCvars[CVAR_RESPAWN_DELAY]); tRespawn[client] = CreateTimer(delay, RespawnTimer, client, TIMER_FLAG_NO_MAPCHANGE); } - + +/** + * Returns if a player is to be respawned as a zombie, because they were killed by world. + * + * @param client The client index. + * @return True if they were killed by world, false if not or cvar is disabled. + */ +RespawnKilledByWorld(client) +{ + // Return true if both the cvar is enabled and the player was killed by world. + return (GetConVarBool(gCvars[CVAR_SUICIDE_WORLD_DAMAGE]) && pKilledByWorld[client]); +} + /** * Spawns a player into the round. * @@ -106,10 +130,10 @@ RespawnSpawnClient(client) return; } - if (GetConVarBool(gCvars[CVAR_SUICIDE_WORLD_DAMAGE]) && gKilledByWorld[client]) + if (GetConVarBool(gCvars[CVAR_SUICIDE_WORLD_DAMAGE]) && pKilledByWorld[client]) { InfectPlayer(client); - gKilledByWorld[client] = false; + pKilledByWorld[client] = false; } } diff --git a/src/zr/sayhooks.inc b/src/zr/sayhooks.inc index 71bb290..43167cf 100644 --- a/src/zr/sayhooks.inc +++ b/src/zr/sayhooks.inc @@ -75,6 +75,14 @@ public Action:SayCommand(client, argc) { ZR_PrintToChat(client, "!ztele stuck"); } + else if (StrEqual(args, "play", false)) + { + SEffectsEmitAmbientSound("ambient/machines/heli_pass_distant1.wav"); + } + else if (StrEqual(args, "stop", false)) + { + SEffectsStopAmbientSound("ambient/machines/heli_pass_distant1.wav"); + } return Plugin_Continue; } diff --git a/src/zr/soundeffects/soundeffects.inc b/src/zr/soundeffects/soundeffects.inc new file mode 100644 index 0000000..d0665f5 --- /dev/null +++ b/src/zr/soundeffects/soundeffects.inc @@ -0,0 +1,69 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: soundeffects.inc + * Description: Basic sound-management API. + * + * ============================================================================ + */ + +/** + * Maximum sound path length. + */ +#define SOUND_MAX_PATH 128 + +/** + * Ambient sound channel. + */ +#define SOUND_AMBIENT_CHANNEL 8 + +#include "zr/soundeffects/zombiesounds" + +/** + * Emits an ambient sound + */ +SEffectsEmitAmbientSound(const String:sound[], Float:soundvolume = 1.0) +{ + // Precache sound before playing. + PrecacheSound(sound); + + // Emit ambient sound. + EmitSoundToAll(sound, SOUND_FROM_PLAYER, SOUND_AMBIENT_CHANNEL, _, _, soundvolume); +} + +/** + * Stop an ambient sound + */ +SEffectsStopAmbientSound(const String:sound[]) +{ + // x = client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Stop ambient sound. + StopSound(x, SOUND_AMBIENT_CHANNEL, sound); + } +} + +/** + * Emits a sound from a client. + * + * @param client The client index. + * @param sound The sound file relative to the sound/ directory. + * @param level The attenuation of the sound. + */ +SEffectsEmitSoundFromClient(client, const String:sound[], level = SNDLEVEL_NORMAL) +{ + // Precache sound before playing. + PrecacheSound(sound); + + // Emit sound from client. + EmitSoundToAll(sound, client, _, level); +} \ No newline at end of file diff --git a/src/zr/soundeffects/zombiesounds.inc b/src/zr/soundeffects/zombiesounds.inc new file mode 100644 index 0000000..5521535 --- /dev/null +++ b/src/zr/soundeffects/zombiesounds.inc @@ -0,0 +1,265 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: zombiesounds.inc + * Description: Zombie sound effects. + * + * ============================================================================ + */ + +/** + * @section Defines for min/max moaning sound file index. + */ +#define SOUND_MOAN_PATH "npc/zombie/zombie_voice_idle%d.wav" // %d is sound file index +#define SOUND_MOAN_MIN 1 +#define SOUND_MOAN_MAX 14 +/** + * @endsection + */ + +/** + * @section Defines for min/max groan sound file index. + */ +#define SOUND_GROAN_PATH "npc/zombie/zombie_pain%d.wav" // %d is sound file index +#define SOUND_GROAN_MIN 1 +#define SOUND_GROAN_MAX 6 +/** + * @endsection + */ + +/** + * @section Defines for min/max death sound file index. + */ +#define SOUND_DEATH_PATH "npc/zombie/zombie_die%d.wav" // %d is sound file index +#define SOUND_DEATH_MIN 1 +#define SOUND_DEATH_MAX 3 +/** + * @endsection + */ + +/** + * Zombie sound types + */ +enum ZombieSounds +{ + Moan, /** Zombie's moan periodically */ + Groan, /** When zombie is hurt */ + Death, /** When a zombie is killed */ +} + +/** + * Array for storing zombie moaning timer handles per client. + */ +new Handle:tSEffectsMoan[MAXPLAYERS + 1]; + +/** + * Client is joining the server. + * + * @param client The client index. + */ +ZombieSoundsClientInit(client) +{ + // Reset timer handle. + tSEffectsMoan[client] = INVALID_HANDLE; +} + +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +ZombieSoundsOnClientSpawn(client) +{ + // If timer is running, kill it. + if (tSEffectsMoan[client] != INVALID_HANDLE) + { + KillTimer(tSEffectsMoan[client]); + } + + // Reset timer handle. + tSEffectsMoan[client] = INVALID_HANDLE; +} + +/** + * Client has been killed. + * + * @param client The client index. + */ +ZombieSoundsOnClientDeath(client) +{ + // If timer is running, kill it. + if (tSEffectsMoan[client] != INVALID_HANDLE) + { + KillTimer(tSEffectsMoan[client]); + } + + // Reset timer handle. + tSEffectsMoan[client] = INVALID_HANDLE; + + // If player isn't a zombie, then stop. + if (!IsPlayerZombie(client)) + { + return; + } + + // If death sound cvar is disabled, then stop. + new bool:death = GetConVarBool(gCvars[CVAR_SOUNDEFFECTS_DEATH]); + if (!death) + { + return; + } + + // Get random death sound. + decl String:sound[SOUND_MAX_PATH]; + ZombieSoundsGetRandomSound(sound, Death); + + SEffectsEmitSoundFromClient(client, sound); +} + +/** + * Client has been hurt. + * + * @param client The client index. + */ +ZombieSoundsOnClientHurt(client) +{ + // If player isn't a zombie, then stop. + if (!IsPlayerZombie(client)) + { + return; + } + + // Get groan factor, if 0, then stop. + new groan = GetConVarInt(gCvars[CVAR_SOUNDEFFECTS_GROAN]); + if (!groan) + { + return; + } + + // 1 in 'groan' chance of groaning. + if (GetRandomInt(1, groan) == 1) + { + // Get random groan sound. + decl String:sound[SOUND_MAX_PATH]; + ZombieSoundsGetRandomSound(sound, Groan); + + SEffectsEmitSoundFromClient(client, sound); + } +} + +/** + * Client has been infected. + * + * @param client The client index. + */ +ZombieSoundsOnClientInfected(client) +{ + // If interval is set to 0, then stop. + new Float:interval = GetConVarFloat(gCvars[CVAR_SOUNDEFFECTS_MOAN]); + if (!interval) + { + return; + } + + // If timer is currently running, kill it. + if (tSEffectsMoan[client] != INVALID_HANDLE) + { + KillTimer(tSEffectsMoan[client]); + } + + // Start repeating timer. + tSEffectsMoan[client] = CreateTimer(interval, ZombieSoundsMoanTimer, client, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); +} + +/** + * Gets a random zombie sound from hl2 folder. + * + * @param sound The randomly picked moan sound. + * @return True if sound was successfully picked, false otherwise. + */ +bool:ZombieSoundsGetRandomSound(String:sound[], ZombieSounds:soundtype) +{ + new soundmin; + new soundmax; + decl String:soundpath[SOUND_MAX_PATH]; + + switch(soundtype) + { + // Find moan sound. + case Moan: + { + // Copy min and max + soundmin = SOUND_MOAN_MIN; + soundmax = SOUND_MOAN_MAX; + + // Copy path + strcopy(soundpath, sizeof(soundpath), SOUND_MOAN_PATH); + } + // Find groan sound. (zombie shot) + case Groan: + { + // Copy min and max + soundmin = SOUND_GROAN_MIN; + soundmax = SOUND_GROAN_MAX; + + // Copy path + strcopy(soundpath, sizeof(soundpath), SOUND_GROAN_PATH); + } + // Find death sound. + case Death: + { + // Copy min and max + soundmin = SOUND_DEATH_MIN; + soundmax = SOUND_DEATH_MAX; + + // Copy path + strcopy(soundpath, sizeof(soundpath), SOUND_DEATH_PATH); + } + // Invalid case given. + default: + { + // No handled case was given. + return false; + } + } + + // Pick a random integer between min and max sound file index. + new randsound = GetRandomInt(soundmin, soundmax); + + // Format random index into sound path. + Format(sound, SOUND_MAX_PATH, soundpath, randsound); + + // Found sound. + return true; +} + +/** + * Timer callback, repeats a moaning sound on zombies. + * + * @param timer The timer handle. + * @param client The client index. + */ +public Action:ZombieSoundsMoanTimer(Handle:timer, any:client) +{ + // If client isn't in-game or client is no longer a zombie, then stop. + if (!IsClientInGame(client) || !IsPlayerZombie(client)) + { + // Reset timer handle. + tSEffectsMoan[client] = INVALID_HANDLE; + + // Stop timer. + return Plugin_Stop; + } + + // Get random moan sound. + decl String:sound[SOUND_MAX_PATH]; + ZombieSoundsGetRandomSound(sound, Moan); + + // Emit sound from client. + SEffectsEmitSoundFromClient(client, sound, SNDLEVEL_SCREAMING); + + // Allow timer to continue. + return Plugin_Continue; +} \ No newline at end of file diff --git a/src/zr/spawnprotect.inc b/src/zr/spawnprotect.inc index bcc9921..d9c1e58 100644 --- a/src/zr/spawnprotect.inc +++ b/src/zr/spawnprotect.inc @@ -77,7 +77,7 @@ SpawnProtectOnClientSpawn(client) // If player respawns as human, and either cvar zr_suicide_world_damage or the client // wasn't killed by world is false, then continue on to protect client. new bool:respawn_zombie = GetConVarBool(gCvars[CVAR_RESPAWN_ZOMBIE]); - if (!respawn_zombie && !(GetConVarBool(gCvars[CVAR_SUICIDE_WORLD_DAMAGE]) && gKilledByWorld[client])) + if (!respawn_zombie && !RespawnKilledByWorld(client)) { // Set spawn protect flag on client. pSpawnProtect[client] = true; diff --git a/src/zr/zombie.inc b/src/zr/zombie.inc index 70e163a..1b71adc 100644 --- a/src/zr/zombie.inc +++ b/src/zr/zombie.inc @@ -159,41 +159,6 @@ public Action:MotherZombie(Handle:timer) zombieSpawned = true; } -/*Zombify_Mother(client) -{ - gZombie[client] = true; - motherZombie[client] = true; - - CS_SwitchTeam(client, CS_TEAM_T); - - RemoveAllPlayersWeapons(client); - GivePlayerItem(client, "weapon_knife"); - - ClassOnClientInfected(client, true); - InfectionEffects(client); - - ztele_count[client] = 0; - AbortTeleport(client); - - ZR_PrintToChat(client, "You are a zombie"); - - new bool:mother_zombie_respawn = GetConVarBool(gCvars[CVAR_MOTHER_ZOMBIE_RESPAWN]); - if (mother_zombie_respawn) - { - TeleportEntity(client, spawnLoc[client], NULL_VECTOR, NULL_VECTOR); - } - - new Float:interval = GetConVarFloat(gCvars[CVAR_EMITSOUNDS]); - if (interval > 0.0) - { - if (tHandles[client][TMOAN] != INVALID_HANDLE) - { - KillTimer(tHandles[client][TMOAN]); - } - tHandles[client][TMOAN] = CreateTimer(interval, ZombieMoanTimer, client, TIMER_REPEAT); - } -}*/ - /** * Zombifies a player. Execute events, sets attributes and flags that indicate * that the player is a zombie. @@ -235,20 +200,9 @@ InfectPlayer(client, attacker = -1, bool:motherinfect = false) // Switch the player to terrorists. CS_SwitchTeam(client, CS_TEAM_T); - // Check if random zombie sounds are enabled. - new Float:interval = GetConVarFloat(gCvars[CVAR_EMITSOUNDS]); - if (interval > 0.0) - { - // Create timer. - if (tHandles[client][TMOAN] != INVALID_HANDLE) - { - KillTimer(tHandles[client][TMOAN]); - } - tHandles[client][TMOAN] = CreateTimer(interval, ZombieMoanTimer, client, TIMER_REPEAT); - } - // Forward event to modules. ClassOnClientInfected(client, motherinfect); + ZombieSoundsOnClientInfected(client); ZHPOnClientInfected(client); AbortTeleport(client); @@ -268,8 +222,7 @@ InfectionEffects(client) GetConVarString(gCvars[CVAR_INFECT_SOUND], sound, sizeof(sound)); if (sound[0]) { - PrecacheSound(sound); - EmitSoundToAll(sound, client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING); + SEffectsEmitSoundFromClient(client, sound, SNDLEVEL_SCREAMING); } new bool:esplash = GetConVarBool(gCvars[CVAR_INFECT_ESPLASH]); @@ -524,31 +477,6 @@ RemoveObjectives() } } -ZombieMoan(client) -{ - decl String:sound[64]; - - new randsound = GetRandomInt(1, 14); - Format(sound, sizeof(sound), "npc/zombie/zombie_voice_idle%d.wav", randsound); - - PrecacheSound(sound); - EmitSoundToAll(sound, client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING); -} - -public Action:ZombieMoanTimer(Handle:timer, any:index) -{ - if (!IsClientInGame(index) || !IsPlayerZombie(index)) - { - tHandles[index][TMOAN] = INVALID_HANDLE; - - return Plugin_Stop; - } - - ZombieMoan(index); - - return Plugin_Continue; -} - public Action:RoundOver(Handle:timer) { tRound = INVALID_HANDLE; diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index 438ecb7..84fd52e 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -70,7 +70,6 @@ new bool:zombieSpawned; new bool:motherZombie[MAXPLAYERS + 1]; new bool:gZombie[MAXPLAYERS + 1]; new bool:gBlockMotherInfect[MAXPLAYERS + 1]; -new bool:gKilledByWorld[MAXPLAYERS + 1]; new Float:spawnLoc[MAXPLAYERS + 1][3]; new Float:bufferLoc[MAXPLAYERS + 1][3]; @@ -88,9 +87,8 @@ new Handle:tInfect = INVALID_HANDLE; new Handle:pList = INVALID_HANDLE; -#define MAXTIMERS 2 +#define MAXTIMERS 1 -#define TMOAN 0 #define TTELE 1 new Handle:tHandles[MAXPLAYERS + 1][MAXTIMERS]; @@ -228,6 +226,7 @@ bool:IsPlayerInList(client) * * @param client The client index. * @param console True to include console (index 0), false if not. + * @return True if client is valid, false otherwise. */ bool:ZRIsValidClient(client, bool:console = false) { @@ -241,6 +240,32 @@ bool:ZRIsValidClient(client, bool:console = false) return console ? (client >= 0) : (client > 0); } +/** + * Check if a client index is on a team. + * + * @param client The client index. + * @param team Team to check if player is on, -1 to check both. + * @return True if client is on a team, false otherwise. + */ +bool:ZRIsClientOnTeam(client, team = -1) +{ + // If index is invalid, then stop. + if (!ZRIsValidClient(client)) + { + return false; + } + + // Get client team. + new clientteam = GetClientTeam(client); + + if (team == -1) + { + return (clientteam == CS_TEAM_T || clientteam == CS_TEAM_CT); + } + + return (clientteam == team); +} + /** * Returns whether a player is a generic admin or not. *