Added sound effects module, moved all moaning, groaning, and death sounds to zombie sounds sub-module, and made a basic sound API.

This commit is contained in:
Greyscale 2009-04-16 22:21:32 +02:00
parent 39ff709d7f
commit ee9d3a9f39
12 changed files with 460 additions and 156 deletions

View File

@ -212,6 +212,13 @@
"knockback" "100.0"
}
"Knife"
{
"restrict" "no"
"menu" "no"
"knockback" "8.0"
}
"NVGs"
{
"restrict" "yes"

View File

@ -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);

View File

@ -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 <class name|\"random\">");
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.");

View File

@ -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();

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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.
*