diff --git a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt index 3c87a6e..e742e29 100644 --- a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt +++ b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt @@ -9,11 +9,6 @@ "Offsets" { - "RemoveAllItems" - { - "windows" "283" - "linux" "284" - } "EyePosition" { diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 9b3baa2..94300fb 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -41,18 +41,24 @@ // Class System (core) #include "zr/playerclasses/playerclasses" +// Weapons (core) +#include "zr/weapons/weapons" + // Round End (core) #include "zr/roundend" +// Infect (core) +#include "zr/infect" + // Damage (core) #include "zr/damage" -// Weapons (core) -#include "zr/weapons/weapons" - // Hitgroups (core) #include "zr/hitgroups" +// Account (module) +#include "zr/account" + // Sound Effects (module) #include "zr/soundeffects/soundeffects" @@ -162,15 +168,14 @@ public OnLibraryAdded(const String:name[]) public OnMapStart() { - MapChangeCleanup(); - LoadModelData(); LoadDownloadData(); // Forward event to modules. ClassLoad(); - RoundEndOnMapStart(); WeaponsLoad(); + RoundEndOnMapStart(); + InfectOnMapStart(); HitgroupsLoad(); SEffectsOnMapStart(); AntiStickOnMapStart(); @@ -211,14 +216,13 @@ public OnConfigsExecuted() public OnClientPutInServer(client) { - bMotherInfectImmune[client] = false; - // Forward event to modules. ClassClientInit(client); + WeaponsClientInit(client); RoundEndClientInit(client); + InfectClientInit(client); DamageClientInit(client); SEffectsClientInit(client); - WeaponsClientInit(client); SpawnProtectClientInit(client); RespawnClientInit(client); ZHPClientInit(client); @@ -226,44 +230,10 @@ public OnClientPutInServer(client) public OnClientDisconnect(client) { - PlayerLeft(client); - // Forward event to modules. ClassOnClientDisconnect(client); - DamageOnClientDisconnect(client); WeaponsOnClientDisconnect(client); + InfectOnClientDisconnect(client); + DamageOnClientDisconnect(client); ZTeleResetClient(client); -} - -MapChangeCleanup() -{ - tInfect = INVALID_HANDLE; -} - -/*ZREnd() -{ - TerminateRound(3.0, Game_Commencing); - - CvarsHook(); - CvarsUnhook(); - - // TODO: Disable all modules! Teleport, ambience, overlays, antistick, etc. - - new maxplayers = GetMaxClients(); - for (new x = 1; x <= maxplayers; x++) - { - if (!IsClientInGame(x)) - { - continue; - } - - for (new y = 0; y < MAXTIMERS; y++) - { - if (tHandles[x][y] != INVALID_HANDLE) - { - KillTimer(tHandles[x][y]); - tHandles[x][y] = INVALID_HANDLE; - } - } - } -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/zr/account.inc b/src/zr/account.inc new file mode 100644 index 0000000..75b2dc5 --- /dev/null +++ b/src/zr/account.inc @@ -0,0 +1,59 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: account.inc + * Description: (Module) Handles client's accounts. (cash) + * + * ============================================================================ + */ + +/** + * Maximum limit for cash in CS:S. + */ +#define ACCOUNT_CASH_MAX 16000 + +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +AccountOnClientSpawn(client) +{ + // If cashfill cvar is disabled, then stop. + new bool:accountcashfill = GetConVarBool(g_hCvarsList[CVAR_ACCOUNT_CASHFILL]); + if (!accountcashfill) + { + return; + } + + // Get cash value. + new cash = GetConVarInt(g_hCvarsList[CVAR_ACCOUNT_CASHFILL_VALUE]); + + // Set client's account. + AccountSetClientCash(client, cash); +} + +/** + * Set's a client's account value (cash) + * + * @param client The client index. + * @param value The value to set to. + */ +AccountSetClientCash(client, value) +{ + // If value if below 0, then set to 0. + if (value < 0) + { + value = 0; + } + // If value is above max, then set to max. + else if (value > ACCOUNT_CASH_MAX) + { + value = ACCOUNT_CASH_MAX; + } + + // Set client's cash. + SetEntData(client, offsAccount, value, 4); +} \ No newline at end of file diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index 8eab79e..6bcebe4 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -29,9 +29,26 @@ enum CvarsList Handle:CVAR_DAMAGE_SUICIDE_ZOMBIE, Handle:CVAR_DAMAGE_SUICIDE_HUMAN, Handle:CVAR_DAMAGE_SUICIDE_CMDS, + Handle:CVAR_INFECT_SPAWNTIME_MIN, + Handle:CVAR_INFECT_SPAWNTIME_MAX, + Handle:CVAR_INFECT_CONSECUTIVE_BLOCK, + Handle:CVAR_INFECT_MZOMBIE_RATIO, + Handle:CVAR_INFECT_MZOMBIE_RESPAWN, + Handle:CVAR_INFECT_SOUND, + Handle:CVAR_INFECT_ESPLASH, + Handle:CVAR_INFECT_FIREBALL, + Handle:CVAR_INFECT_SMOKE, + Handle:CVAR_INFECT_SPARKS, + Handle:CVAR_INFECT_SHAKE, + Handle:CVAR_INFECT_SHAKE_AMP, + Handle:CVAR_INFECT_SHAKE_FREQUENCY, + Handle:CVAR_INFECT_SHAKE_DURATION, Handle:CVAR_WEAPONS, Handle:CVAR_WEAPONS_RESTRICT, + Handle:CVAR_WEAPONS_ZMARKET_BUYZONE, Handle:CVAR_HITGROUPS, + Handle:CVAR_ACCOUNT_CASHFILL, + Handle:CVAR_ACCOUNT_CASHFILL_VALUE, Handle:CVAR_SOUNDEFFECTS_MOAN, Handle:CVAR_SOUNDEFFECTS_GROAN, Handle:CVAR_SOUNDEFFECTS_DEATH, @@ -57,13 +74,6 @@ enum CvarsList Handle:CVAR_DARK, Handle:CVAR_DARK_LEVEL, Handle:CVAR_DARK_SKY, - Handle:CVAR_MOTHER_ZOMBIE_RATIO, - Handle:CVAR_MOTHER_ZOMBIE_RESPAWN, - Handle:CVAR_SUICIDE_WORLD_DAMAGE, - Handle:CVAR_SPAWN_MIN, - Handle:CVAR_SPAWN_MAX, - Handle:CVAR_INFECT_CONSECUTIVE_BLOCK, - Handle:CVAR_ZMARKET_BUYZONE, Handle:CVAR_ZSPAWN, Handle:CVAR_ZTELE, Handle:CVAR_ZTELE_STARTUP_DELAY, @@ -73,17 +83,6 @@ enum CvarsList Handle:CVAR_ZTELE_ZOMBIE_DELAY, Handle:CVAR_ZTELE_ZOMBIE_LIMIT, Handle:CVAR_ZTELE_RESET_BUFFERS, - Handle:CVAR_CASHFILL, - Handle:CVAR_CASHAMOUNT, - Handle:CVAR_INFECT_FIREBALL, - Handle:CVAR_INFECT_SMOKE, - Handle:CVAR_INFECT_SPARKS, - Handle:CVAR_INFECT_SOUND, - Handle:CVAR_INFECT_ESPLASH, - Handle:CVAR_INFECT_SHAKE, - Handle:CVAR_INFECT_SHAKE_AMP, - Handle:CVAR_INFECT_SHAKE_FREQUENCY, - Handle:CVAR_INFECT_SHAKE_DURATION, Handle:CVAR_ANTICAMP, Handle:CVAR_ANTICAMP_UPDATE_INTERVAL, } @@ -184,6 +183,28 @@ CvarsInit() g_hCvarsList[CVAR_DAMAGE_SUICIDE_CMDS] = CreateConVar("zr_damage_suicide_cmds", "kill, spectate, jointeam", ""); // Old Desc: List of suicide commands to intercept. (Delimited by \", \" + // =========================== + // Infect (core) + // =========================== + + g_hCvarsList[CVAR_INFECT_MZOMBIE_RATIO] = CreateConVar("zr_infect_motherzombie_ratio", "5", ""); + g_hCvarsList[CVAR_INFECT_MZOMBIE_RESPAWN] = CreateConVar("zr_infect_motherzombie_respawn", "0", ""); + g_hCvarsList[CVAR_INFECT_SPAWNTIME_MIN] = CreateConVar("zr_infect_spawntime_min", "30.0", ""); + g_hCvarsList[CVAR_INFECT_SPAWNTIME_MAX] = CreateConVar("zr_infect_spawntime_max", "50.0", ""); + g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK] = CreateConVar("zr_infect_consecutive_block", "1", ""); + + // Effects + + g_hCvarsList[CVAR_INFECT_FIREBALL] = CreateConVar("zr_infect_fireball", "1", ""); + g_hCvarsList[CVAR_INFECT_SMOKE] = CreateConVar("zr_infect_smoke", "1", ""); + g_hCvarsList[CVAR_INFECT_SPARKS] = CreateConVar("zr_infect_sparks", "1", ""); + g_hCvarsList[CVAR_INFECT_SOUND] = CreateConVar("zr_infect_sound", "npc/fast_zombie/fz_scream1.wav", ""); + g_hCvarsList[CVAR_INFECT_ESPLASH] = CreateConVar("zr_infect_esplash", "1", ""); + g_hCvarsList[CVAR_INFECT_SHAKE] = CreateConVar("zr_infect_shake", "1", ""); + g_hCvarsList[CVAR_INFECT_SHAKE_AMP] = CreateConVar("zr_infect_shake_amp", "15.0", ""); + g_hCvarsList[CVAR_INFECT_SHAKE_FREQUENCY] = CreateConVar("zr_infect_shake_frequency", "1.0", ""); + g_hCvarsList[CVAR_INFECT_SHAKE_DURATION] = CreateConVar("zr_infect_shake_duration", "5.0", ""); + // =========================== // Weapons (core) // =========================== @@ -199,6 +220,11 @@ CvarsInit() g_hCvarsList[CVAR_WEAPONS_RESTRICT] = CreateConVar("zr_weapons_restrict", "1", ""); // Note make config file cvar. + // Market Handler + + g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE] = CreateConVar("zr_weapons_zmarket_buyzone", "1", ""); + // Old Desc: Must be in buyzone to access !zmarket, if Market is installed (0: Can be used anywhere) + // =========================== // Hitgroups (core) // =========================== @@ -206,6 +232,15 @@ CvarsInit() g_hCvarsList[CVAR_HITGROUPS] = CreateConVar("zr_hitgroups", "1", ""); // Note make config file cvar. + // =========================== + // Account (module) + // =========================== + + g_hCvarsList[CVAR_ACCOUNT_CASHFILL] = CreateConVar("zr_account_cashfill", "1", ""); + // Old Desc: Enable the mod to set the players cash to zr_cashamount (0: Disabled) + g_hCvarsList[CVAR_ACCOUNT_CASHFILL_VALUE] = CreateConVar("zr_account_cashfill_value", "12000", ""); + // Old Desc: How much money players will have when they spawn when zr_cashfill is 1 + // =========================== // Sound Effects (module) // =========================== @@ -294,18 +329,6 @@ CvarsInit() // Old Desc: The darkness of the map, a being the darkest, z being extremely bright when zr_dark is 1 (n: Default) g_hCvarsList[CVAR_DARK_SKY] = CreateConVar("zr_dark_sky", "sky_borealis01", ""); // Old Desc: The sky the map will have when zr_dark is 1 - g_hCvarsList[CVAR_MOTHER_ZOMBIE_RATIO] = CreateConVar("zr_mother_zombie_ratio", "5", ""); - // Old Desc: For every 'x' number of humans, there will be 1 zombie (0: Always only 1 mother zombie) - g_hCvarsList[CVAR_MOTHER_ZOMBIE_RESPAWN] = CreateConVar("zr_mother_zombie_respawn", "0", ""); - // Old Desc: First zombie(s) will be teleported back to spawn when infected (0: Disable) - g_hCvarsList[CVAR_SPAWN_MIN] = CreateConVar("zr_spawn_min", "30", ""); - // Old Desc: Minimum time a player is picked to be zombie after the round starts, in seconds - g_hCvarsList[CVAR_SPAWN_MAX] = CreateConVar("zr_spawn_max", "50", ""); - // Old Desc: Maximum time a player is picked to be zombie after the round starts, in seconds - g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK] = CreateConVar("zr_infect_consecutive_block", "1", ""); - // Old Desc: Allow player to be randomly chosen twice in a row to be a mother zombie (0: Disable) - g_hCvarsList[CVAR_ZMARKET_BUYZONE] = CreateConVar("zr_zmarket_buyzone", "1", ""); - // Old Desc: Must be in buyzone to access !zmarket, if Market is installed (0: Can be used anywhere) g_hCvarsList[CVAR_ZSPAWN] = CreateConVar("zr_zspawn", "1", ""); // Old Desc: Allow players to spawn if they just joined the game (0: Disable) g_hCvarsList[CVAR_ZTELE] = CreateConVar("zr_tele", "1", ""); @@ -324,28 +347,6 @@ CvarsInit() // Old Desc: Maximum number of teleports zombies can do. (0: Zombies can't use the teleporter. -1: Unlimited) g_hCvarsList[CVAR_ZTELE_RESET_BUFFERS] = CreateConVar("zr_tele_reset_buffers", "1", ""); // Old Desc: Reset custom saved teleport locations on each round start. (0: Disable) - g_hCvarsList[CVAR_CASHFILL] = CreateConVar("zr_cashfill", "1", ""); - // Old Desc: Enable the mod to set the players cash to zr_cashamount (0: Disabled) - g_hCvarsList[CVAR_CASHAMOUNT] = CreateConVar("zr_cashamount", "12000", ""); - // Old Desc: How much money players will have when they spawn when zr_cashfill is 1 - g_hCvarsList[CVAR_INFECT_FIREBALL] = CreateConVar("zr_infect_fireball", "1", ""); - // Old Desc: A fireball is created when a player is infected (0: Disable) - g_hCvarsList[CVAR_INFECT_SMOKE] = CreateConVar("zr_infect_smoke", "1", ""); - // Old Desc: A puff of smoke is created when a player is infected (0: Disable) - g_hCvarsList[CVAR_INFECT_SPARKS] = CreateConVar("zr_infect_sparks", "1", ""); - // Old Desc: Sparks are emitted when a player is infected (0: Disable) - g_hCvarsList[CVAR_INFECT_SOUND] = CreateConVar("zr_infect_sound", ""); - // Old Desc: npc/fast_zombie/fz_scream1.wav", "Sound played from from player on infection (Leave blank to disable) - g_hCvarsList[CVAR_INFECT_ESPLASH] = CreateConVar("zr_infect_esplash", "1", ""); - // Old Desc: An energy splash is emitted when player is infected (0: Disable) - g_hCvarsList[CVAR_INFECT_SHAKE] = CreateConVar("zr_infect_shake", "1", ""); - // Old Desc: Player's screen is shaken on infection (0: Disable) - g_hCvarsList[CVAR_INFECT_SHAKE_AMP] = CreateConVar("zr_infect_shake_amp", "15.0", ""); - // Old Desc: Amplitude of the shake, when zr_infect_shake is 1 - g_hCvarsList[CVAR_INFECT_SHAKE_FREQUENCY] = CreateConVar("zr_infect_shake_frequency", "1.0", ""); - // Old Desc: Frequency of the shake, when zr_infect_shake is 1 - g_hCvarsList[CVAR_INFECT_SHAKE_DURATION] = CreateConVar("zr_infect_shake_duration", "5.0", ""); - // Old Desc: Duration of the shake, when zr_infect_shake is 1 g_hCvarsList[CVAR_ANTICAMP] = CreateConVar("zr_anticamp", "1", ""); // Old Desc: Enables or disables hurt volumes for preventing unfair camping. (0: Disable) g_hCvarsList[CVAR_ANTICAMP_UPDATE_INTERVAL] = CreateConVar("zr_anticamp_update_interval", "1", ""); diff --git a/src/zr/damage.inc b/src/zr/damage.inc index 52dde3a..5f693ee 100644 --- a/src/zr/damage.inc +++ b/src/zr/damage.inc @@ -69,7 +69,7 @@ DamageInit() * Client is joining the server. * * @param client The client index. - */ + */ DamageClientInit(client) { // Hook damage callbacks. diff --git a/src/zr/event.inc b/src/zr/event.inc index 48e5438..6d1647f 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -36,28 +36,11 @@ public Action:RoundStart(Handle:event, const String:name[], bool:dontBroadcast) { ChangeLightStyle(); - if (tInfect != INVALID_HANDLE) - { - KillTimer(tInfect); - tInfect = INVALID_HANDLE; - } - - g_bZombieSpawned = false; - - for (new x = 1; x<= MaxClients; x++) - { - if (!IsClientInGame(x)) - { - continue; - } - - bZombie[x] = false; - } - ZR_PrintToChat(0, "Round objective"); // Forward event to sub-modules. RoundEndOnRoundStart(); + InfectOnRoundStart(); SEffectsOnRoundStart(); AntiStickOnRoundStart(); } @@ -66,68 +49,41 @@ public Action:RoundFreezeEnd(Handle:event, const String:name[], bool:dontBroadca { RemoveObjectives(); - if (tInfect != INVALID_HANDLE) - { - KillTimer(tInfect); - } - - new Float:min = GetConVarFloat(g_hCvarsList[CVAR_SPAWN_MIN]); - new Float:max = GetConVarFloat(g_hCvarsList[CVAR_SPAWN_MAX]); - new Float:randlen = GetRandomFloat(min, max); - tInfect = CreateTimer(randlen, MotherZombie, _, TIMER_FLAG_NO_MAPCHANGE); - // Forward events to modules. RoundEndOnRoundFreezeEnd(); + InfectOnRoundFreezeEnd(); ZTeleEnable(); } public Action:RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) { + // Get all required event info. new reason = GetEventInt(event, "reason"); - if (tInfect != INVALID_HANDLE) - { - KillTimer(tInfect); - tInfect = INVALID_HANDLE; - } - - g_bZombieSpawned = false; - - for (new x = 1; x<= MaxClients; x++) - { - if (!IsClientInGame(x)) - { - continue; - } - - bZombie[x] = false; - } - // Forward event to modules. RoundEndOnRoundEnd(reason); + InfectOnRoundEnd(); ZTeleReset(); } public Action:PlayerTeam(Handle:event, const String:name[], bool:dontBroadcast) { + // Get all required event info. new index = GetClientOfUserId(GetEventInt(event, "userid")); new team = GetEventInt(event, "team"); - if (team == CS_TEAM_SPECTATOR) - { - bZombie[index] = false; - } + // Forward event to modules. + InfectOnClientTeam(index, team); return Plugin_Handled; } public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) { + // Get all required event info. new index = GetClientOfUserId(GetEventInt(event, "userid")); - bZombie[index] = false; - // Reset FOV and overlay. SetPlayerFOV(index, 90); ClientCommand(index, "r_screenoverlay \"\""); @@ -135,13 +91,6 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) // Check if client is on a team. if (ZRIsClientOnTeam(index)) { - new bool:cashfill = GetConVarBool(g_hCvarsList[CVAR_CASHFILL]); - if (cashfill) - { - new cash = GetConVarInt(g_hCvarsList[CVAR_CASHAMOUNT]); - SetPlayerMoney(index, cash); - } - // Remove night vision. NightVisionOn(index, false); NightVision(index, false); @@ -162,7 +111,9 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) // Forward event to modules. ClassOnClientSpawn(index); + InfectOnClientSpawn(index); SEffectsOnClientSpawn(index); + AccountOnClientSpawn(index); SpawnProtectOnClientSpawn(index); RespawnOnClientSpawn(index); ZHPOnClientSpawn(index); @@ -173,32 +124,18 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) public Action:PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) { + // Get all required event info. new index = GetClientOfUserId(GetEventInt(event, "userid")); new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); - new hitgroup = GetEventInt(event, "hitgroup"); - new dmg_health = GetEventInt(event, "dmg_health"); decl String:weapon[32]; GetEventString(event, "weapon", weapon, sizeof(weapon)); - // Check if the attacker is a player. - if (ZRIsValidClient(attacker)) - { - // Check if a zombie attacks a human. - if (IsPlayerHuman(index) && IsPlayerZombie(attacker)) - { - // Check if spawn protection is disabled and the weapon is a knife. - if (!pSpawnProtect[index] && StrEqual(weapon, "knife")) - { - InfectPlayer(index, attacker); - } - } - } - // Forward event to modules. ClassAlphaUpdate(index); + InfectOnClientHurt(index, attacker, weapon); SEffectsOnClientHurt(index); KnockbackOnClientHurt(index, attacker, weapon, hitgroup, dmg_health); NapalmOnClientHurt(index, weapon); @@ -207,72 +144,49 @@ public Action:PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) public Action:PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) { - new index = GetClientOfUserId(GetEventInt(event, "userid")); - new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); - - // Extinguish fire. - ExtinguishEntity(index); - // Get the weapon name. decl String:weapon[32]; GetEventString(event, "weapon", weapon, sizeof(weapon)); - // Check if the player was infected. + // If client is being infected, then stop. if (StrEqual(weapon, "zombie_claws_of_death", false)) { - // Add a death count to the players score. - if (ZRIsValidClient(index)) - { - AddPlayerDeath(index, 1); - } - - // Give a point to the attacker. - if (ZRIsValidClient(attacker)) - { - AddPlayerScore(attacker, 1); - - new healthgain = ClassGetHealthInfectGain(attacker); - new health = GetClientHealth(attacker); - - SetEntityHealth(attacker, health + healthgain); - - // Forward event to modules. - ZHPOnHealthInfectGain(attacker); - } - } - else - { - // Reset field of view. - SetPlayerFOV(index, DEFAULT_FOV); - - if (IsPlayerZombie(index)) - { - // Give kill bonus. - if (ZRIsValidClient(attacker)) - { - new bonus = ClassGetKillBonus(attacker); - AddPlayerScore(attacker, bonus); - } - } - - // Forward event to modules. - ClassOnClientDeath(index); - SEffectsOnClientDeath(index); - SpawnProtectOnClientDeath(index); - RespawnOnClientDeath(index, attacker, weapon); - ZHPOnClientDeath(index); + return; } - new RoundEndOutcome:outcome; - if (RoundEndGetRoundStatus(outcome)) + // Get all required event info. + new index = GetClientOfUserId(GetEventInt(event, "userid")); + new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); + + // Extinguish any flames to stop burning sounds. + ExtinguishEntity(index); + + // If the attacker is valid, then continue. + if (ZRIsValidClient(attacker)) { - RoundEndTerminateRound(outcome); + // If the client is a zombie, then continue. + if (IsPlayerZombie(index)) + { + // Add kill bonus to attacker's score. + new bonus = ClassGetKillBonus(attacker); + AddPlayerScore(attacker, bonus); + } } + + // Forward event to modules. + ClassOnClientDeath(index); + RoundEndOnClientDeath(); + SEffectsOnClientDeath(index); + SpawnProtectOnClientDeath(index); + RespawnOnClientDeath(index, attacker, weapon); + ZHPOnClientDeath(index); } public Action:PlayerJump(Handle:event, const String:name[], bool:dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "userid")); + // Get all required event info. + new client = GetClientOfUserId(GetEventInt(event, "userid")); + new Float:distance = ClassGetJumpDistance(client); new Float:height = ClassGetJumpHeight(client); @@ -281,6 +195,7 @@ public Action:PlayerJump(Handle:event, const String:name[], bool:dontBroadcast) public Action:WeaponFire(Handle:event, const String:name[], bool:dontBroadcast) { + // Get all required event info. decl String:weapon[32]; GetEventString(event, "weapon", weapon, sizeof(weapon)); diff --git a/src/zr/infect.inc b/src/zr/infect.inc new file mode 100644 index 0000000..8eb57e8 --- /dev/null +++ b/src/zr/infect.inc @@ -0,0 +1,665 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: infect.inc + * Description: Client infection functions. + * + * ============================================================================ + */ + +/** + * @section Explosion flags. + */ +#define EXP_NODAMAGE 1 +#define EXP_REPEATABLE 2 +#define EXP_NOFIREBALL 4 +#define EXP_NOSMOKE 8 +#define EXP_NODECAL 16 +#define EXP_NOSPARKS 32 +#define EXP_NOSOUND 64 +#define EXP_RANDOMORIENTATION 128 +#define EXP_NOFIREBALLSMOKE 256 +#define EXP_NOPARTICLES 512 +#define EXP_NODLIGHTS 1024 +#define EXP_NOCLAMPMIN 2048 +#define EXP_NOCLAMPMAX 4096 +/** + * @endsection + */ + +/** + * Global variable to store infect timer handle. + */ +new Handle:tInfect = INVALID_HANDLE; + +/** + * Array for flagging client as zombie. + */ +new bool:bZombie[MAXPLAYERS + 1]; + +/** + * @section bInfectImmune indexes + */ +#define INFECT_TYPE_MOTHER 0 +#define INFECT_TYPE_NORMAL 1 +/** + * @endsection + */ + +/** + * Array for flagging client to be protected. (See defines above) + */ +new bool:bInfectImmune[MAXPLAYERS + 1][2]; + +/** + * Map is starting. + */ +InfectOnMapStart() +{ + // Reset timer handle. + tInfect = INVALID_HANDLE; + + // Get infection sound. + decl String:sound[PLATFORM_MAX_PATH]; + GetConVarString(g_hCvarsList[CVAR_INFECT_SOUND], sound, sizeof(sound)); + + // If infect sound cvar is empty, then stop. + if (!sound[0]) + { + return; + } + + // Prepend sound/ to the path. + Format(sound, sizeof(sound), "sound/%s", sound); + + // Add sound file to downloads table. + AddFileToDownloadsTable(sound); +} + +/** + * Client is joining the server. + * + * @param client The client index. + */ +InfectClientInit(client) +{ + // Reset infect immunity flags. + bInfectImmune[client][INFECT_TYPE_MOTHER] = false; + bInfectImmune[client][INFECT_TYPE_NORMAL] = false; +} + +/** + * Client is leaving the server. + * + * @param client The client index. + */ +InfectOnClientDisconnect(client) +{ + // If zombie hasn't spawned, then stop. + if (!g_bZombieSpawned) + { + return; + } + + // If client is dead, then stop. + if (!IsPlayerAlive(client)) + { + return; + } + + // Initialize count variables + new zombiecount; + new humancount; + + // Count valid clients. + ZRCountValidClients(zombiecount, humancount); + + // If client is a human. + if (IsPlayerHuman(client)) + { + // If there are other humans (ignoring this human), then stop. + if (humancount > 1) + { + return; + } + + // If there are no more clients in the server, then stop. + if (!ZRTeamHasClients(CS_TEAM_T)) + { + return; + } + + // Manually terminate round. + RoundEndTerminateRound(ZombiesWin); + + return; + } + + // We know here that player is a zombie. + + // If there is 1 or less humans, then stop. + if (humancount <= 1) + { + return; + } + + // If there are other zombies (ignoring this zombie), then stop. + if (zombiecount - 1) + { + return; + } + + // Create eligible player list. + new Handle:arrayEligibleClients = INVALID_HANDLE; + + // Create eligible client list, with no mother infect immunities + new eligibleclients = ZRCreateEligibleClientList(arrayEligibleClients, true, true, true); + + // If there are no eligible client's then stop. + if (!eligibleclients) + { + return; + } + + // Get a random valid array index. + new randindex = GetRandomInt(0, eligibleclients - 1); + + // Get the client stored in the random array index. + new randclient = GetArrayCell(arrayEligibleClients, randindex); + + // Infect player. + InfectPlayer(randclient); + + // Tell client they have been randomly been chosen to replace disconnecting zombie. + ZR_PrintToChat(randclient, "Zombie replacement"); + + // Destroy handle. + CloseHandle(arrayEligibleClients); +} + +/** + * Client is joining a team. + * + * @param client The client index. + * @param team The team index. + */ +InfectOnClientTeam(client, team) +{ + // If client isn't joining spec, then stop. + if (team != CS_TEAM_SPECTATOR) + { + return; + } + + // Disable zombie flag on client. + bZombie[client] = false; +} + +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +InfectOnClientSpawn(client) +{ + // Disable zombie flag on client. + bZombie[client] = false; +} + +/** Client has been hurt. + * + * @param client The client index. + * @param attacker The attacker index. + * @param weapon The weapon used. + */ +InfectOnClientHurt(client, attacker, const String:weapon[]) +{ + // If attacker isn't valid, then stop. + if (!ZRIsValidClient(attacker)) + { + return; + } + + // If client isn't a human, then stop. + if (!IsPlayerHuman(client)) + { + return; + } + + // Attacker isn't a zombie, then stop. + if (!IsPlayerZombie(attacker)) + { + return; + } + + // If client has infect immunity, then stop. + if (bInfectImmune[client][INFECT_TYPE_NORMAL]) + { + return; + } + + // If weapon isn't a knife, then stop. + if (!StrEqual(weapon, "knife")) + { + return; + } + + // Infect client. + InfectPlayer(client, attacker); +} + +/** + * The round is starting. + */ +InfectOnRoundStart() +{ + // If infect timer is running, then kill it. + if (tInfect != INVALID_HANDLE) + { + // Kill timer. + KillTimer(tInfect); + + // Reset timer handle. + tInfect = INVALID_HANDLE; + } + + // x = client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Disable zombie flag on client. + bZombie[x] = false; + } +} + +/** + * The freeze time is ending. + */ +InfectOnRoundFreezeEnd() +{ + // If infect timer is running, then kill it. + if (tInfect != INVALID_HANDLE) + { + // Kill timer. + KillTimer(tInfect); + } + + // Get min and max times. + new Float:infectspawntimemin = GetConVarFloat(g_hCvarsList[CVAR_INFECT_SPAWNTIME_MIN]); + new Float:infectspawntimemax = GetConVarFloat(g_hCvarsList[CVAR_INFECT_SPAWNTIME_MAX]); + + // Pick random time between min and max. + new Float:randomtime = GetRandomFloat(infectspawntimemin, infectspawntimemax); + + tInfect = CreateTimer(randomtime, InfectMotherZombie, _, TIMER_FLAG_NO_MAPCHANGE); +} + +/** + * The round is ending. + */ +InfectOnRoundEnd() +{ + // If infect timer is running, then kill it. + if (tInfect != INVALID_HANDLE) + { + // Kill timer. + KillTimer(tInfect); + + // Reset timer handle. + tInfect = INVALID_HANDLE; + } + + // x = client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Disable zombie flag on client. + bZombie[x] = false; + } +} + +/** + * Timer callback, chooses mother zombies. + * + * @param timer The timer handle. + */ +public Action:InfectMotherZombie(Handle:timer) +{ + // Reset timer handle. + tInfect = INVALID_HANDLE; + + // Create eligible player list. + new Handle:arrayEligibleClients = INVALID_HANDLE; + new eligibleclients = ZRCreateEligibleClientList(arrayEligibleClients, true, true, true); + + // If there are no eligible client's then stop. + if (!eligibleclients) + { + return; + } + + // Variable to store client stored in random array index. + new client; + + // Prune list of immune clients. + // x = array index. + // client = client index. + for (new x = 0; x < eligibleclients; x++) + { + // Get client stored in array index. + client = GetArrayCell(arrayEligibleClients, x); + + // If client is immune from being a mother zombie, then stop. + if (bInfectImmune[client][INFECT_TYPE_MOTHER]) + { + // Take away immunity. + bInfectImmune[client][INFECT_TYPE_MOTHER] = false; + + // Remove client from array. + RemoveFromArray(arrayEligibleClients, x); + + // Subtract one from count. + eligibleclients--; + + // If there are no eligible client's then stop. + if (!eligibleclients) + { + return; + } + + // Backtrack one index, because we deleted it out from under the loop. + x--; + } + } + + // 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; + + // Ratio of mother zombies to humans. + new ratio = GetConVarInt(g_hCvarsList[CVAR_INFECT_MZOMBIE_RATIO]); + + // If ratio is 0 or lower, then pick 1 zombie. + if (ratio <= 0) + { + // 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); + } + else + { + // Initialize count variables + new zombiecount; + new humancount; + + // Count valid human clients + ZRCountValidClients(zombiecount, humancount, _, true); + + // Calculate mother zombie count. + new mothercount = RoundToCeil(float(humancount) / ratio); + + // x = current mother zombie count. + for (new x = 0; x < mothercount; x++) + { + // Recount eligible clients. + eligibleclients = GetArraySize(arrayEligibleClients); + + // 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); + } + } + + // Mother zombies have been infected. + g_bZombieSpawned = true; + + // Destroy handle. + CloseHandle(arrayEligibleClients); +} + +/** + * Infects a player. Execute events, sets attributes and flags that indicate + * that the player is a zombie. + * + * @param client The player to infect. + * @param attacker (Optional) The attacker who did the infect. + * @param motherinfect (Optional) Indicates a mother zombie infect. + */ +InfectPlayer(client, attacker = -1, bool:motherinfect = false) +{ + // Mark player as zombie. + bZombie[client] = true; + + // Get a list of all client's weapon indexes. + new weapons[WeaponsType]; + WeaponsGetClientWeapons(client, weapons); + + // Loop through array slots and force drop. + // x = weapon slot. + for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + { + // If this is the knife slot, then stop. + if (WeaponsType:x == Type_Melee) + { + continue; + } + + // If weapon is invalid, then stop. + if (weapons[x] == -1) + { + continue; + } + + // Force client to drop weapon. + WeaponForceClientDrop(client, weapons[x]); + } + + // If client has no knife, give them one. + if (weapons[Type_Melee] == -1) + { + GivePlayerItem(client, "weapon_knife"); + } + + // Check if consecutive infection protection is enabled. + new bool:infectconsecutiveblock = GetConVarBool(g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK]); + + // Flag player to be immune from being mother zombie twice, if consecutive infect protection is enabled. + bInfectImmune[client][INFECT_TYPE_MOTHER] = infectconsecutiveblock ? motherinfect : false; + + // Apply effects. + InfectEffects(client); + + // Add a death to the zombie's score. + AddPlayerDeath(client, 1); + + // Fire death event and set weapon info if the attacker is specified. + if (ZRIsValidClient(attacker)) + { + // Create and send custom player_death event. + new Handle:event = CreateEvent("player_death"); + if (event != INVALID_HANDLE) + { + SetEventInt(event, "userid", GetClientUserId(client)); + SetEventInt(event, "attacker", GetClientUserId(attacker)); + SetEventString(event, "weapon", "zombie_claws_of_death"); + FireEvent(event, false); + } + + // Give client's infector a point. + AddPlayerScore(attacker, 1); + + // Apply infect HP gain. + new healthgain = ClassGetHealthInfectGain(attacker); + new health = GetClientHealth(attacker); + + // Set attacker's new health. + SetEntityHealth(attacker, health + healthgain); + + // Forward event to modules. + ZHPOnHealthInfectGain(attacker); + } + + // Switch the player to terrorists. + // TODO: A solution to stop confusing bots? Respawn and teleport? + CS_SwitchTeam(client, CS_TEAM_T); + + // Forward event to modules. + ClassOnClientInfected(client, motherinfect); + SEffectsOnClientInfected(client); + ZHPOnClientInfected(client); + TeleportOnClientInfected(client); + + // Terminate the round if the last player was infected. + new RoundEndOutcome:outcome; + if (RoundEndGetRoundStatus(outcome)) + { + RoundEndTerminateRound(outcome); + } +} + +/** + * Creates effects on a newly infected client. + * + * @param client The client index. + */ +InfectEffects(client) +{ + // Create location and direction arrays. + new Float:clientloc[3]; + new Float:direction[3] = {0.0, 0.0, 0.0}; + + // Get client's position. + GetClientAbsOrigin(client, clientloc); + clientloc[2] += 30; + + // Get infection sound. + decl String:sound[PLATFORM_MAX_PATH]; + GetConVarString(g_hCvarsList[CVAR_INFECT_SOUND], sound, sizeof(sound)); + if (sound[0]) + { + SEffectsEmitSoundFromClient(client, sound, SNDLEVEL_SCREAMING); + } + + // Create an energy splash effect. + new bool:esplash = GetConVarBool(g_hCvarsList[CVAR_INFECT_ESPLASH]); + if (esplash) + { + TE_SetupEnergySplash(clientloc, direction, true); + TE_SendToAll(); + } + + // Create an explosion entity. + new explosion = CreateEntityByName("env_explosion"); + + // If explosion entity is valid, then continue. + if (explosion != -1) + { + // Get and set flags on explosion. + new flags = GetEntProp(explosion, Prop_Data, "m_spawnflags"); + flags = flags | EXP_NODAMAGE | EXP_NODECAL; + + // Set "nofireball" flag if fireball is disabled. + new bool:fireball = GetConVarBool(g_hCvarsList[CVAR_INFECT_FIREBALL]); + if (!fireball) + { + flags = flags | EXP_NOFIREBALL; + } + + // Set "nosmoke" flag if smoke is disabled. + new bool:smoke = GetConVarBool(g_hCvarsList[CVAR_INFECT_SMOKE]); + if (!smoke) + { + flags = flags | EXP_NOSMOKE; + } + + // Set "nosparks" flag if sparks are disabled. + new bool:sparks = GetConVarBool(g_hCvarsList[CVAR_INFECT_SPARKS]); + if (!sparks) + { + flags = flags | EXP_NOSPARKS; + } + + // Set new flags on entity. + SetEntProp(explosion, Prop_Data, "m_spawnflags", flags); + + // Spawn the entity into the world. + DispatchSpawn(explosion); + + // Precache fireball model. + PrecacheModel("materials/sprites/xfireball3.vmt"); + + // Set origin and explosion key values on entity. + DispatchKeyValueVector(explosion, "origin", clientloc); + DispatchKeyValue(explosion, "fireballsprite", "materials/sprites/xfireball3.vmt"); + + // Tell the entity to explode. + AcceptEntityInput(explosion, "Explode"); + } + + // If shake effect is enabled, then continue. + new bool:shake = GetConVarBool(g_hCvarsList[CVAR_INFECT_SHAKE]); + if (shake) + { + // If shake usermsg isn't invalid, then continue. + new Handle:hShake = StartMessageOne("Shake", client); + if (hShake != INVALID_HANDLE) + { + // Write shake information to usermsg handle. + BfWriteByte(hShake, 0); + BfWriteFloat(hShake, GetConVarFloat(g_hCvarsList[CVAR_INFECT_SHAKE_AMP])); + BfWriteFloat(hShake, GetConVarFloat(g_hCvarsList[CVAR_INFECT_SHAKE_FREQUENCY])); + BfWriteFloat(hShake, GetConVarFloat(g_hCvarsList[CVAR_INFECT_SHAKE_DURATION])); + + // End usermsg and sent to client. + EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index 1eb1601..9a1004d 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -6,14 +6,14 @@ * ==================== */ -/** Player hurt event. +/** Client has been hurt. * - * @param client The victim index. (zombie) + * @param client The client index. (zombie) * @param attacker The attacker index. (human) * @param weapon The weapon used. * @param hitgroup Hitgroup attacker has damaged. * @param dmg_health Damage done. - */ + */ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_health) { // If attacker is invalid, then stop. diff --git a/src/zr/offsets.inc b/src/zr/offsets.inc index 2b7a12a..e3088d9 100644 --- a/src/zr/offsets.inc +++ b/src/zr/offsets.inc @@ -13,7 +13,7 @@ new offsSpeed; new offsNVG; new offsNVGOn; new offsCollision; -new offsMoney; +new offsAccount; new offsFOV; new offsBuyZone; new offsColor; @@ -21,7 +21,6 @@ new offsRender; new offsActiveWeapon; new Handle:g_hGameConf = INVALID_HANDLE; -new Handle:g_hRemoveAllItems = INVALID_HANDLE; new Handle:g_hEyePosition = INVALID_HANDLE; new Handle:g_hEyeAngles = INVALID_HANDLE; new Handle:g_hTerminateRound = INVALID_HANDLE; @@ -71,8 +70,8 @@ FindOffsets() SetFailState("Couldn't find \"m_CollisionGroup\"!"); } - offsMoney = FindSendPropInfo("CCSPlayer", "m_iAccount"); - if (offsMoney == -1) + offsAccount = FindSendPropInfo("CCSPlayer", "m_iAccount"); + if (offsAccount == -1) { SetFailState("Couldn't find \"m_iAccount\"!"); } @@ -113,16 +112,6 @@ SetupGameData() // Load game config file. g_hGameConf = LoadGameConfigFile("plugin.zombiereloaded"); - // - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(g_hGameConf, SDKConf_Virtual, "RemoveAllItems"); - g_hRemoveAllItems = EndPrepSDKCall(); - - if(g_hRemoveAllItems == INVALID_HANDLE) - { - SetFailState("Couldn't find offset \"RemoveAllItems\"!"); - } - StartPrepSDKCall(SDKCall_Player); PrepSDKCall_SetFromConf(g_hGameConf, SDKConf_Virtual, "EyePosition"); PrepSDKCall_SetReturnInfo(SDKType_QAngle, SDKPass_ByValue); @@ -230,11 +219,6 @@ bool:CanCollide(client) return true; } - -SetPlayerMoney(client, amount) -{ - SetEntData(client, offsMoney, amount, 4, true); -} SetPlayerFOV(client, fov) { @@ -258,11 +242,6 @@ AddPlayerDeath(client, amount) SetEntProp(client, Prop_Data, "m_iDeaths", deaths + amount); } -RemoveAllPlayersWeapons(client) -{ - SDKCall(g_hRemoveAllItems, client); -} - GetPlayerEyePosition(client, Float:vec[3]) { SDKCall(g_hEyePosition, client, vec); @@ -278,11 +257,6 @@ TerminateRound(Float:delay, reason) SDKCall(g_hTerminateRound, delay, reason); } -CSDropWeapon(client, weapon) -{ - SDKCall(g_hCSWeaponDrop, client, weapon, true, false); -} - SetPlayerAlpha(client, alpha) { SetEntData(client, offsRender, 3, 1, true); diff --git a/src/zr/playerclasses/apply.inc b/src/zr/playerclasses/apply.inc index 42540a6..c096b4d 100644 --- a/src/zr/playerclasses/apply.inc +++ b/src/zr/playerclasses/apply.inc @@ -139,9 +139,9 @@ bool:ClassApplyOverlay(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) } // If client doesn't meet minimum requirement, then print unsupported text. - if (dxLevel[client] < GENERAL_MIN_DXLEVEL) + if (dxLevel[client] < GENERAL_DXLEVEL_MIN) { - ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], GENERAL_MIN_DXLEVEL); + ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], GENERAL_DXLEVEL_MIN); return false; } diff --git a/src/zr/playerclasses/attributes.inc b/src/zr/playerclasses/attributes.inc index f0d7fe4..b9fc84f 100644 --- a/src/zr/playerclasses/attributes.inc +++ b/src/zr/playerclasses/attributes.inc @@ -9,6 +9,11 @@ * ============================================================================ */ +/** + * Default FOV attribute value. + */ +#define ATTRIBUTES_FOV_DEFAULT 90 + /* * ------------------------------------ * diff --git a/src/zr/playerclasses/classevents.inc b/src/zr/playerclasses/classevents.inc index c262365..27e50e5 100644 --- a/src/zr/playerclasses/classevents.inc +++ b/src/zr/playerclasses/classevents.inc @@ -37,6 +37,9 @@ ClassOnClientDisconnect(client) ClassOnClientSpawn(client) { + // Reset client's FOV. + SetPlayerFOV(client, ATTRIBUTES_FOV_DEFAULT); + new bool:randomclass = GetConVarBool(g_hCvarsList[CVAR_CLASSES_RANDOM]); new bool:showmenu = GetConVarBool(g_hCvarsList[CVAR_CLASSES_SPAWN]); decl String:steamid[16]; @@ -92,7 +95,6 @@ ClassOnClientInfected(client, bool:motherzombie = false) ClassOnRoundStart() { - } diff --git a/src/zr/roundend.inc b/src/zr/roundend.inc index 51b50ae..a1f9eea 100644 --- a/src/zr/roundend.inc +++ b/src/zr/roundend.inc @@ -82,6 +82,21 @@ RoundEndClientInit(client) RoundEndGetClientDXLevel(client); } +/** + * Client has been killed. + * + * @param client The client index. + */ +RoundEndOnClientDeath() +{ + // Terminate the round if the last player was infected. + new RoundEndOutcome:outcome; + if (RoundEndGetRoundStatus(outcome)) + { + RoundEndTerminateRound(outcome); + } +} + /** * The round is starting. */ @@ -97,6 +112,9 @@ RoundEndOnRoundStart() tRoundEnd = INVALID_HANDLE; } + // Tell plugin no zombies have been spawned. + g_bZombieSpawned = false; + // Balance teams, and respawn all players. RoundEndBalanceTeams(true); } @@ -134,6 +152,9 @@ RoundEndOnRoundEnd(reason) tRoundEnd = INVALID_HANDLE; } + // Tell plugin no zombies have been spawned. + g_bZombieSpawned = false; + // Get outcome of the round. new RoundEndOutcome:outcome = RoundEndReasonToOutcome(reason); @@ -319,7 +340,7 @@ RoundEndBalanceTeams(bool:spawn = false) { // Create eligible player list. new Handle:arrayEligibleClients = INVALID_HANDLE; - new eligibleclients = CreateEligibleClientList(arrayEligibleClients, true); + new eligibleclients = ZRCreateEligibleClientList(arrayEligibleClients, true); // If there are no eligible client's then stop. if (!eligibleclients) @@ -399,14 +420,14 @@ RoundEndDisplayClientOverlay(client, const String:overlay[]) } // If dxLevel is above or equal to minimum requirement, then display overlay. - if (dxLevel[client] >= GENERAL_MIN_DXLEVEL) + if (dxLevel[client] >= GENERAL_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], GENERAL_MIN_DXLEVEL); + ZR_PrintCenterText(client, "DX90 not supported", dxLevel[client], GENERAL_DXLEVEL_MIN); } } diff --git a/src/zr/spawnprotect.inc b/src/zr/spawnprotect.inc index 8b47480..042a67e 100644 --- a/src/zr/spawnprotect.inc +++ b/src/zr/spawnprotect.inc @@ -14,11 +14,6 @@ */ new Handle:tSpawnProtect[MAXPLAYERS + 1]; -/** - * Array for flagging client to be protected. - */ -new bool:pSpawnProtect[MAXPLAYERS + 1]; - /** * Array for storing time left for spawn protection per client. */ @@ -43,7 +38,7 @@ SpawnProtectClientInit(client) SpawnProtectOnClientSpawn(client) { // Disable spawn protection on client. - pSpawnProtect[client] = false; + bInfectImmune[client][INFECT_TYPE_NORMAL] = false; // If timer is currently running, kill it. if (tSpawnProtect[client] != INVALID_HANDLE) @@ -80,7 +75,7 @@ SpawnProtectOnClientSpawn(client) if (!respawn_zombie && !RespawnKilledByWorld(client)) { // Set spawn protect flag on client. - pSpawnProtect[client] = true; + bInfectImmune[client][INFECT_TYPE_NORMAL] = true; // Set improved attributes // (Move to cvar?) @@ -149,7 +144,7 @@ public Action:SpawnProtectTimer(Handle:timer, any:client) if (pSpawnProtectTime[client] <= 0) { // Remove protect flag. - pSpawnProtect[client] = false; + bInfectImmune[client][INFECT_TYPE_NORMAL] = false; // Tell client spawn protection is over. ZR_HudHint(client, "Spawn protection end"); diff --git a/src/zr/weapons/markethandler.inc b/src/zr/weapons/markethandler.inc index 6d0d01d..c6a83c7 100644 --- a/src/zr/weapons/markethandler.inc +++ b/src/zr/weapons/markethandler.inc @@ -1,11 +1,19 @@ -/** - * ==================== +/* + * ============================================================================ + * * Zombie:Reloaded - * File: markethandler.inc - * Author: Greyscale - * ==================== + * + * File: markethandler.inc + * Description: Handles market (optional plugin) API, natives, and forwards. + * + * ============================================================================ */ +/** + * Global variable set to true if market plugin is installed + */ +new bool:g_bMarket; + /** * Sends market menu to client. * @@ -30,7 +38,7 @@ bool:ZMarketSend(client) } // Check buyzone cvar to see if client has to be in a buyzone to use. - new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_ZMARKET_BUYZONE]); + new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); if (!IsClientInBuyZone(client) && buyzone) { // Tell client they must be in a buyzone. @@ -106,7 +114,7 @@ public bool:Market_OnWeaponSelected(client, String:weaponid[]) } // Check if buyzone cvar is enabled, and if the client is in a buyzone. - new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_ZMARKET_BUYZONE]); + new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); if (!IsClientInBuyZone(client) && buyzone) { ZR_PrintCenterText(client, "Market out of buyzone"); diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index ae77249..456fee8 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -422,7 +422,7 @@ WeaponsMenuMarket(client) decl String:togglebuyzone[64]; decl String:curSetting[8]; - ZRBoolToConfigSetting(GetConVarBool(g_hCvarsList[CVAR_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting)); + ZRBoolToConfigSetting(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting)); Format(togglebuyzone, sizeof(togglebuyzone), "%t", "Weapons menu market toggle buyzone", curSetting); @@ -451,13 +451,13 @@ public WeaponsMenuMarketHandle(Handle:menu_weapons_market, MenuAction:action, cl { case 0: { - if (GetConVarBool(g_hCvarsList[CVAR_ZMARKET_BUYZONE])) + if (GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE])) { - SetConVarBool(g_hCvarsList[CVAR_ZMARKET_BUYZONE], false); + SetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE], false); } else { - SetConVarBool(g_hCvarsList[CVAR_ZMARKET_BUYZONE], true); + SetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE], true); } } } diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index b7be8bd..70dcd7e 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -297,7 +297,7 @@ Float:WeaponGetWeaponKnockback(const String:weapon[]) /** * General weapon API. */ - + /** * Return an array that contains all client's weapon indexes. * @@ -358,4 +358,16 @@ WeaponsType:WeaponsGetDeployedWeaponSlot(client) } return Type_Invalid; +} + +/** + * Forces player to drop weapon index. + * + * @param client The client index. + * @param weapon The weapon index to force client to drop. + */ +WeaponForceClientDrop(client, weapon) +{ + // Force client to drop weapon. + SDKCall(g_hCSWeaponDrop, client, weapon, true, false); } \ No newline at end of file diff --git a/src/zr/zombie.inc b/src/zr/zombie.inc index 1b470b7..ec892db 100644 --- a/src/zr/zombie.inc +++ b/src/zr/zombie.inc @@ -5,20 +5,6 @@ * Author: Greyscale * ==================== */ - -#define EXP_NODAMAGE 1 -#define EXP_REPEATABLE 2 -#define EXP_NOFIREBALL 4 -#define EXP_NOSMOKE 8 -#define EXP_NODECAL 16 -#define EXP_NOSPARKS 32 -#define EXP_NOSOUND 64 -#define EXP_RANDOMORIENTATION 128 -#define EXP_NOFIREBALLSMOKE 256 -#define EXP_NOPARTICLES 512 -#define EXP_NODLIGHTS 1024 -#define EXP_NOCLAMPMIN 2048 -#define EXP_NOCLAMPMAX 4096 new String:skyname[32]; @@ -90,291 +76,6 @@ ChangeLightStyle() } } -/** - * Create an array populated with eligible clients to be zombie. - * - * @param arrayEligibleClients The handle of the array, don't forget to call CloseHandle - * on it when finished! - * @param immunity True to ignore clients immune from mother infect, false to count them. - */ -CreateEligibleClientList(&Handle:arrayEligibleClients, bool:team = false, bool:alive = false, bool:human = false, bool:immunity = false) -{ - // Create array. - arrayEligibleClients = CreateArray(); - - // Populate list with eligible clients. - // x = client index. - for (new x = 1; x <= MaxClients; x++) - { - // If client isn't in-game, then stop. - if (!IsClientInGame(x)) - { - continue; - } - - // If client isn't on a team, then stop. - if (team && !ZRIsClientOnTeam(x)) - { - continue; - } - - // If client is dead, then stop. - if (alive && !IsPlayerAlive(x)) - { - continue; - } - - // If client is already zombie (via admin), then stop. - if (human && !IsPlayerHuman(x)) - { - continue; - } - - // If client is immune from being a mother zombie, then stop. - if (immunity && bMotherInfectImmune[x]) - { - // Take away immunity. - bMotherInfectImmune[x] = false; - - continue; - } - - // Add eligible client to array. - PushArrayCell(arrayEligibleClients, x); - } - - return GetArraySize(arrayEligibleClients); -} - -/** - * Timer callback, chooses mother zombies. - * - * @param timer The timer handle. - */ -public Action:MotherZombie(Handle:timer) -{ - // Reset timer handle. - tInfect = INVALID_HANDLE; - - // Create eligible player list. - new Handle:arrayEligibleClients = INVALID_HANDLE; - new eligibleclients = CreateEligibleClientList(arrayEligibleClients, true, true, true, true); - - // If there are no eligible client's then stop. - if (!eligibleclients) - { - return; - } - - // 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(g_hCvarsList[CVAR_MOTHER_ZOMBIE_RATIO]); - - // If ratio is 0 or lower, then pick 1 zombie. - if (ratio <= 0) - { - // 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); - } - else - { - // Calculate mother zombie sound. - new mothercount = RoundToCeil(float(eligibleclients) / ratio); - - // x = current mother zombie count. - for (new x = 0; x < mothercount; x++) - { - // Recount eligible clients. - eligibleclients = GetArraySize(arrayEligibleClients); - - // 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); - } - } - - // Mother zombies have been infected. - g_bZombieSpawned = true; - - // Destroy handle. - CloseHandle(arrayEligibleClients); -} - -/** - * Zombifies a player. Execute events, sets attributes and flags that indicate - * that the player is a zombie. - * - * @param client The player to infect. - * @param attacker Optional. The attacker who did the infect. - * @param motherinfect Optional. Indicates a mother zombie infect. - */ -InfectPlayer(client, attacker = -1, bool:motherinfect = false) -{ - // Mark player as zombie. - bZombie[client] = true; - - // Remove all weapons and give a knife. - RemoveAllPlayersWeapons(client); - GivePlayerItem(client, "weapon_knife"); - - // Check if consecutive infection protection is enabled. - new bool:infectconsecutiveblock = GetConVarBool(g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK]); - - // Flag player to be immune from being mother zombie twice, if consecutive infect protection is enabled. - bMotherInfectImmune[client] = infectconsecutiveblock ? motherinfect : false; - - // Forward event to modules. - ClassOnClientInfected(client, motherinfect); - SEffectsOnClientInfected(client); - ZHPOnClientInfected(client); - TeleportOnClientInfected(client); - - // Apply effects. - InfectionEffects(client); - - // Fire death event and set weapon info if the attacker is specified. - if (ZRIsValidClient(attacker)) - { - new Handle:event = CreateEvent("player_death"); - if (event != INVALID_HANDLE) - { - SetEventInt(event, "userid", GetClientUserId(client)); - SetEventInt(event, "attacker", GetClientUserId(attacker)); - SetEventString(event, "weapon", "zombie_claws_of_death"); - FireEvent(event, false); - } - } - - // Switch the player to terrorists. - // TODO: A solution to stop confusing bots? Respawn and teleport? - CS_SwitchTeam(client, CS_TEAM_T); - - // Terminate the round if the last player was infected. - new RoundEndOutcome:outcome; - if (RoundEndGetRoundStatus(outcome)) - { - RoundEndTerminateRound(outcome); - } -} - -InfectionEffects(client) -{ - new Float:clientloc[3]; - new Float:direction[3] = {0.0, 0.0, 0.0}; - - GetClientAbsOrigin(client, clientloc); - clientloc[2] += 30; - - decl String:sound[128]; - GetConVarString(g_hCvarsList[CVAR_INFECT_SOUND], sound, sizeof(sound)); - if (sound[0]) - { - SEffectsEmitSoundFromClient(client, sound, SNDLEVEL_SCREAMING); - } - - new bool:esplash = GetConVarBool(g_hCvarsList[CVAR_INFECT_ESPLASH]); - if (esplash) - { - TE_SetupEnergySplash(clientloc, direction, true); - TE_SendToAll(); - } - - new explosion = CreateEntityByName("env_explosion"); - - if (explosion != -1) - { - new flags = GetEntProp(explosion, Prop_Data, "m_spawnflags"); - flags = flags | EXP_NODAMAGE | EXP_NODECAL; - - new bool:fireball = GetConVarBool(g_hCvarsList[CVAR_INFECT_FIREBALL]); - if (!fireball) - { - flags = flags | EXP_NOFIREBALL; - } - - new bool:smoke = GetConVarBool(g_hCvarsList[CVAR_INFECT_SMOKE]); - if (!smoke) - { - flags = flags | EXP_NOSMOKE; - } - - new bool:sparks = GetConVarBool(g_hCvarsList[CVAR_INFECT_SPARKS]); - if (!sparks) - { - flags = flags | EXP_NOSPARKS; - } - - SetEntProp(explosion, Prop_Data, "m_spawnflags", flags); - - DispatchSpawn(explosion); - - PrecacheModel("materials/sprites/xfireball3.vmt"); - - DispatchKeyValueVector(explosion, "origin", clientloc); - DispatchKeyValue(explosion, "fireballsprite", "materials/sprites/xfireball3.vmt"); - - AcceptEntityInput(explosion, "Explode"); - } - - new bool:shake = GetConVarBool(g_hCvarsList[CVAR_INFECT_SHAKE]); - if (shake) - { - new Handle:hShake = StartMessageOne("Shake", client); - if (hShake != INVALID_HANDLE) - { - BfWriteByte(hShake, 0); - BfWriteFloat(hShake, GetConVarFloat(g_hCvarsList[CVAR_INFECT_SHAKE_AMP])); - BfWriteFloat(hShake, GetConVarFloat(g_hCvarsList[CVAR_INFECT_SHAKE_FREQUENCY])); - BfWriteFloat(hShake, GetConVarFloat(g_hCvarsList[CVAR_INFECT_SHAKE_DURATION])); - - EndMessage(); - } - } -} - JumpBoost(client, Float:distance, Float:height) { new Float:vel[3]; @@ -388,86 +89,6 @@ JumpBoost(client, Float:distance, Float:height) SetPlayerVelocity(client, vel, false); } -/** - * Finds a new zombie if the last one disconnects. - * - * @param client The client index. - */ -PlayerLeft(client) -{ - // If zombie hasn't spawned, then stop. - if (!g_bZombieSpawned) - { - return; - } - - // If client is dead, then stop. - if (!IsPlayerAlive(client)) - { - return; - } - - // Get zombie flag on client. - new zombieclient = IsPlayerZombie(client); - - // Initialize count variables - new zombiecount; - new humancount; - - // Count valid clients. - ZRCountValidClients(zombiecount, humancount); - - // If client is a human, and is the last one, then terminate round. - if (IsPlayerHuman(client) && humancount <= 1) - { - // If there are no more clients in the server, then stop. - if (!ZRTeamHasClients(CS_TEAM_T)) - { - return; - } - - // Manually terminate round. - RoundEndTerminateRound(ZombiesWin); - - return; - } - - // We know here that player is a zombie. - - // If there are other zombies (ignoring this zombie), then stop. - if (zombiecount - 1) - { - return; - } - - // Create eligible player list. - new Handle:arrayEligibleClients = INVALID_HANDLE; - - // Create eligible client list, with no mother infect immunities - new eligibleclients = CreateEligibleClientList(arrayEligibleClients, true, true, true); - - // If there are no eligible client's then stop. - if (!eligibleclients) - { - return; - } - - // Get a random valid array index. - new randindex = GetRandomInt(0, eligibleclients - 1); - - // Get the client stored in the random array index. - new randclient = GetArrayCell(arrayEligibleClients, randindex); - - // Infect player. - InfectPlayer(randclient); - - // Tell client they have been randomly been chosen to replace disconnecting zombie. - ZR_PrintToChat(randclient, "Zombie replacement"); - - // Destroy handle. - CloseHandle(arrayEligibleClients); -} - RemoveObjectives() { decl String:classname[64]; diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index 6ef2719..bf04dc1 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -1,22 +1,18 @@ -/** - * ==================== +/* + * ============================================================================ + * * Zombie:Reloaded - * File: zombiereloaded.inc - * Author: Greyscale - * ==================== + * + * File: zombiereloaded.inc + * Description: General plugin functions and defines. + * + * ============================================================================ */ - -#define DEFAULT_FOV 90 /** * Minimum dx level required to see overlays. */ -#define GENERAL_MIN_DXLEVEL 90 - -/** - * Global variable set to true if market plugin is installed - */ -new bool:g_bMarket; +#define GENERAL_DXLEVEL_MIN 90 /** * The DirectX level of a client. @@ -28,22 +24,6 @@ new dxLevel[MAXPLAYERS + 1]; */ 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 the infect timer handle. - */ -new Handle:tInfect = INVALID_HANDLE; - - /** * Converts string of "yes" or "no" to a boolean value. * @@ -83,6 +63,53 @@ ZRBoolToConfigSetting(bool:bOption, String:option[], maxlen) } } +/** + * Create an array populated with eligible clients to be zombie. + * + * @param arrayEligibleClients The handle of the array, don't forget to call CloseHandle + * on it when finished! + * @param immunity True to ignore clients immune from mother infect, false to count them. + */ +ZRCreateEligibleClientList(&Handle:arrayEligibleClients, bool:team = false, bool:alive = false, bool:human = false) +{ + // Create array. + arrayEligibleClients = CreateArray(); + + // Populate list with eligible clients. + // x = client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // If client isn't on a team, then stop. + if (team && !ZRIsClientOnTeam(x)) + { + continue; + } + + // If client is dead, then stop. + if (alive && !IsPlayerAlive(x)) + { + continue; + } + + // If client is already zombie (via admin), then stop. + if (human && !IsPlayerHuman(x)) + { + continue; + } + + // Add eligible client to array. + PushArrayCell(arrayEligibleClients, x); + } + + return GetArraySize(arrayEligibleClients); +} + /** * Check if a client index is a valid player. * @@ -110,10 +137,10 @@ bool:ZRIsValidClient(client, bool:console = false) * @param alive If true it will only count live players, false will count alive and dead. * @return True if successful (zombie has spawned), false otherwise. */ -bool:ZRCountValidClients(&zombiecount = 0, &humancount = 0, bool:alive = true) +bool:ZRCountValidClients(&zombiecount = 0, &humancount = 0, bool:alive = true, bool:ignorezombiespawned = false) { - // If zombie hasn't spawned, then stop. - if (!g_bZombieSpawned) + // If zombie hasn't spawned and were not only counting humans, then stop. + if (!g_bZombieSpawned && !ignorezombiespawned) { return false; } @@ -195,7 +222,7 @@ bool:ZRTeamHasClients(team = -1) } // Return true if given team has at least 1 client. - return (GetTeamClientCount(team)); + return bool:GetTeamClientCount(team); } /**