This commit is contained in:
test 2009-04-29 01:58:41 +02:00
parent abd38ee033
commit fd129e561b
28 changed files with 1065 additions and 490 deletions

View File

@ -1,9 +1,12 @@
/** /*
* ==================== * ============================================================================
*
* Zombie:Reloaded * Zombie:Reloaded
* File: zombiereloaded.sp *
* Author: Greyscale * File: (base) zombiereloaded.sp
* ==================== * Description: Plugins base file.
*
* ============================================================================
*/ */
#pragma semicolon 1 #pragma semicolon 1
@ -17,123 +20,96 @@
#define VERSION "3.0-dev" #define VERSION "3.0-dev"
// Core include // Core includes.
#include "zr/zombiereloaded" #include "zr/zombiereloaded"
// External api (not done)
//#include "zr/global"
// Log (core)
#include "zr/log" #include "zr/log"
// Cvars (core)
#include "zr/cvars" #include "zr/cvars"
// Translations (core)
#include "zr/translation" #include "zr/translation"
#include "zr/tools"
// Offsets (core)
#include "zr/offsets"
// Models (core)
#include "zr/models" #include "zr/models"
// Class System (core)
#include "zr/playerclasses/playerclasses" #include "zr/playerclasses/playerclasses"
// Weapons (core)
#include "zr/weapons/weapons" #include "zr/weapons/weapons"
// Hitgroups (core)
#include "zr/hitgroups" #include "zr/hitgroups"
// Round End (core)
#include "zr/roundend" #include "zr/roundend"
// Infect (core)
#include "zr/infect" #include "zr/infect"
// Damage (core)
#include "zr/damage" #include "zr/damage"
// Account (module)
#include "zr/account"
// Visual Effects (module)
#include "zr/visualeffects"
// Sound Effects (module)
#include "zr/soundeffects/soundeffects"
// Antistick (module)
#include "zr/antistick"
// Knockback (module)
#include "zr/knockback"
// Spawn Protect (module)
#include "zr/spawnprotect"
// Respawn (module)
#include "zr/respawn"
// Napalm (module)
#include "zr/napalm"
// ZHP (module)
#include "zr/zhp"
#include "zr/anticamp"
#include "zr/teleport"
#include "zr/zombie"
#include "zr/menu" #include "zr/menu"
#include "zr/sayhooks" #include "zr/sayhooks"
#include "zr/event"
#include "zr/zadmin" #include "zr/zadmin"
#include "zr/commands" #include "zr/commands"
//#include "zr/global"
// Event // Modules
#include "zr/event" #include "zr/account"
#include "zr/visualeffects"
#include "zr/soundeffects/soundeffects"
#include "zr/antistick"
#include "zr/knockback"
#include "zr/spawnprotect"
#include "zr/respawn"
#include "zr/napalm"
#include "zr/zspawn"
#include "zr/zhp"
#include "zr/jumpboost"
#include "zr/anticamp"
#include "zr/teleport"
// Almost replaced! :)
#include "zr/zombie"
/**
* Tell SM ZR's info.
*/
public Plugin:myinfo = public Plugin:myinfo =
{ {
name = "Zombie:Reloaded", name = "Zombie:Reloaded",
author = "Greyscale", author = "Greyscale, Rhelgeby (Richard)",
description = "Infection/survival style gameplay", description = "Infection/survival style gameplay",
version = VERSION, version = VERSION,
url = "" url = ""
}; };
/**
* Called before plugin is loaded.
*
* @param myself The plugin handle.
* @param late True if the plugin was loaded after map change, false on map start.
* @param error Error message if load failed.
* @param err_max Max length of the error message.
*/
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
{ {
// Todo: External API // TODO: EXTERNAL API
//CreateGlobals();
// Let plugin load.
return true; return true;
} }
/**
* Plugin is loading.
*/
public OnPluginStart() public OnPluginStart()
{ {
// Load translations phrases used by plugin.
LoadTranslations("common.phrases.txt"); LoadTranslations("common.phrases.txt");
LoadTranslations("zombiereloaded.phrases.txt"); LoadTranslations("zombiereloaded.phrases.txt");
// ====================================================================== // Start loading ZR init functions.
ZR_PrintToServer("Plugin loading"); ZR_PrintToServer("Plugin loading");
// ======================================================================
// Log // Log
LogInit(); LogInit();
// Cvars // Cvars
CvarsInit(); CvarsInit();
// Tools
ToolsInit();
// TODO: Be modulized/recoded. // TODO: Be modulized/recoded.
HookChatCmds();
CreateCommands(); CreateCommands();
HookCommands(); HookCommands();
FindOffsets();
SetupGameData();
// Weapons // Weapons
WeaponsInit(); WeaponsInit();
@ -141,40 +117,53 @@ public OnPluginStart()
// Damage // Damage
DamageInit(); DamageInit();
// Say Hooks
SayHooksInit();
// Event // Event
EventInit(); EventInit();
// ====================================================================== // Set market variable to true if market is installed.
g_bMarket = LibraryExists("market"); g_bMarket = LibraryExists("market");
// ====================================================================== // Create public cvar for tracking.
CreateConVar("gs_zombiereloaded_version", VERSION, "[ZR] Current version of this plugin", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_UNLOGGED|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY); CreateConVar("gs_zombiereloaded_version", VERSION, "[ZR] Current version of this plugin", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_UNLOGGED|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
CreateConVar("zombie_version", VERSION, "Zombie:Reloaded Version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_UNLOGGED|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
CreateConVar("zombie_enabled", "1", "Not synced with zr_enable", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_UNLOGGED|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
// ======================================================================
// Finish loading ZR init functions.
ZR_PrintToServer("Plugin loaded"); ZR_PrintToServer("Plugin loaded");
} }
/**
* Library is being removed.
*
* @param name The name of the library.
*/
public OnLibraryRemoved(const String:name[]) public OnLibraryRemoved(const String:name[])
{ {
if (StrEqual(name, "market")) // If market is being removed, then set variable to false.
if (StrEqual(name, "market", false))
{ {
g_bMarket = false; g_bMarket = false;
} }
} }
/**
* Library is being added.
*
* @param name The name of the library.
*/
public OnLibraryAdded(const String:name[]) public OnLibraryAdded(const String:name[])
{ {
if (StrEqual(name, "market")) // If market is being added, then set variable to true.
if (StrEqual(name, "market", false))
{ {
g_bMarket = true; g_bMarket = true;
} }
} }
/**
* The map is starting.
*/
public OnMapStart() public OnMapStart()
{ {
LoadModelData(); LoadModelData();
@ -189,14 +178,21 @@ public OnMapStart()
Anticamp_Startup(); Anticamp_Startup();
} }
/**
* The map is ending.
*/
public OnMapEnd() public OnMapEnd()
{ {
// Forward event to modules. // Forward event to modules.
Anticamp_Disable(); Anticamp_Disable();
} }
/**
* Configs just finished getting executed.
*/
public OnConfigsExecuted() public OnConfigsExecuted()
{ {
// TODO: move to config module when made.
decl String:mapconfig[PLATFORM_MAX_PATH]; decl String:mapconfig[PLATFORM_MAX_PATH];
GetCurrentMap(mapconfig, sizeof(mapconfig)); GetCurrentMap(mapconfig, sizeof(mapconfig));
@ -223,6 +219,11 @@ public OnConfigsExecuted()
SEffectsLoad(); SEffectsLoad();
} }
/**
* Client is joining the server.
*
* @param client The client index.
*/
public OnClientPutInServer(client) public OnClientPutInServer(client)
{ {
// Forward event to modules. // Forward event to modules.
@ -237,6 +238,11 @@ public OnClientPutInServer(client)
ZHPClientInit(client); ZHPClientInit(client);
} }
/**
* Client is leaving the server.
*
* @param client The client index.
*/
public OnClientDisconnect(client) public OnClientDisconnect(client)
{ {
// Forward event to modules. // Forward event to modules.
@ -244,5 +250,6 @@ public OnClientDisconnect(client)
WeaponsOnClientDisconnect(client); WeaponsOnClientDisconnect(client);
InfectOnClientDisconnect(client); InfectOnClientDisconnect(client);
DamageOnClientDisconnect(client); DamageOnClientDisconnect(client);
ZSpawnOnClientDisconnect(client);
ZTeleResetClient(client); ZTeleResetClient(client);
} }

View File

@ -55,5 +55,5 @@ AccountSetClientCash(client, value)
} }
// Set client's cash. // Set client's cash.
SetEntData(client, offsAccount, value, 4); SetEntData(client, g_iToolsAccount, value, 4);
} }

View File

@ -6,12 +6,21 @@
* ==================== * ====================
*/ */
/**
* @section Collision values.
*/
#define ANTISTICK_COLLISIONS_OFF 2
#define ANTISTICK_COLLISIONS_ON 5
/**
* @endsection
*/
/** /**
* @section Offsets relating to player hull dimensions. * @section Offsets relating to player hull dimensions.
*/ */
#define PLAYER_HULL_XY_OFFSET 32 #define ANTISTICK_PLAYER_HULL_XY_OFFSET 32
#define PLAYER_HULL_Z_OFFSET 12 #define ANTISTICK_PLAYER_HULL_Z_OFFSET 12
#define PLAYER_HULL_STACK_OFFSET 14 #define ANTISTICK_PLAYER_HULL_STACK_OFFSET 14
/** /**
* @endsection * @endsection
*/ */
@ -79,7 +88,7 @@ AntiStickIsStuck(client)
// x-y plane distance formula: sqrt((x2-x1)^2 + (y2-y1)^2) // x-y plane distance formula: sqrt((x2-x1)^2 + (y2-y1)^2)
new Float:xydistance = SquareRoot(Pow(stuckloc[0] - clientloc[0], 2.0) + Pow(stuckloc[1] - clientloc[1], 2.0)); new Float:xydistance = SquareRoot(Pow(stuckloc[0] - clientloc[0], 2.0) + Pow(stuckloc[1] - clientloc[1], 2.0));
if (xydistance < PLAYER_HULL_XY_OFFSET) if (xydistance < ANTISTICK_PLAYER_HULL_XY_OFFSET)
{ {
if (clientloc[2] <= stuckloc[2]) if (clientloc[2] <= stuckloc[2])
{ {
@ -87,10 +96,10 @@ AntiStickIsStuck(client)
GetClientEyePosition(client, eyeloc); GetClientEyePosition(client, eyeloc);
// Get the distance between the eyes and feet and subtract the stack "view crush." // Get the distance between the eyes and feet and subtract the stack "view crush."
new Float:eyedistance = FloatAbs(eyeloc[2] - clientloc[2]) - PLAYER_HULL_STACK_OFFSET; new Float:eyedistance = FloatAbs(eyeloc[2] - clientloc[2]) - ANTISTICK_PLAYER_HULL_STACK_OFFSET;
new Float:zdistance = FloatAbs(stuckloc[2] - clientloc[2]); new Float:zdistance = FloatAbs(stuckloc[2] - clientloc[2]);
if (zdistance <= eyedistance + PLAYER_HULL_Z_OFFSET) if (zdistance <= eyedistance + ANTISTICK_PLAYER_HULL_Z_OFFSET)
{ {
return x; return x;
} }
@ -122,15 +131,15 @@ public Action:AntiStickTimer(Handle:timer)
continue; continue;
} }
if (CanCollide(x)) if (AntiStickClientCollisionGroup(x, false))
{ {
NoCollide(x, true); AntiStickClientCollisionGroup(x, true, ANTISTICK_COLLISIONS_OFF);
CreateTimer(0.5, AntiStickSolidify, x, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); CreateTimer(0.5, AntiStickSolidify, x, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
} }
if (CanCollide(stuckindex)) if (AntiStickClientCollisionGroup(stuckindex, false))
{ {
NoCollide(stuckindex, true); AntiStickClientCollisionGroup(stuckindex, true, ANTISTICK_COLLISIONS_OFF);
CreateTimer(0.5, AntiStickSolidify, stuckindex, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); CreateTimer(0.5, AntiStickSolidify, stuckindex, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
} }
} }
@ -146,7 +155,7 @@ public Action:AntiStickTimer(Handle:timer)
public Action:AntiStickSolidify(Handle:timer, any:client) public Action:AntiStickSolidify(Handle:timer, any:client)
{ {
// Validate player is in-game, alive, and is being unstuck. // Validate player is in-game, alive, and is being unstuck.
if (!IsClientInGame(client) || !IsPlayerAlive(client) || CanCollide(client)) if (!IsClientInGame(client) || !IsPlayerAlive(client) || AntiStickClientCollisionGroup(client, false))
{ {
return Plugin_Stop; return Plugin_Stop;
} }
@ -157,9 +166,27 @@ public Action:AntiStickSolidify(Handle:timer, any:client)
return Plugin_Continue; return Plugin_Continue;
} }
NoCollide(client, false); AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_ON);
return Plugin_Stop; return Plugin_Stop;
} }
/**
* Set collision group flags on a client.
* @param client The client index.
* @param collisiongroup Collision group flag.
* @return The collision group on the client, -1 if applying collision group.
*/
AntiStickClientCollisionGroup(client, bool:apply = true, collisiongroup = 0)
{
if (apply)
{
SetEntData(client, g_iToolsCollisionGroup, collisiongroup, 1, true);
return -1;
}
return GetEntData(client, g_iToolsCollisionGroup, 1);
}

View File

@ -46,6 +46,7 @@ enum CvarsList
Handle:CVAR_INFECT_SPAWNTIME_MIN, Handle:CVAR_INFECT_SPAWNTIME_MIN,
Handle:CVAR_INFECT_SPAWNTIME_MAX, Handle:CVAR_INFECT_SPAWNTIME_MAX,
Handle:CVAR_INFECT_CONSECUTIVE_BLOCK, Handle:CVAR_INFECT_CONSECUTIVE_BLOCK,
Handle:CVAR_INFECT_WEAPONS_DROP,
Handle:CVAR_INFECT_MZOMBIE_RATIO, Handle:CVAR_INFECT_MZOMBIE_RATIO,
Handle:CVAR_INFECT_MZOMBIE_RESPAWN, Handle:CVAR_INFECT_MZOMBIE_RESPAWN,
Handle:CVAR_INFECT_SOUND, Handle:CVAR_INFECT_SOUND,
@ -86,6 +87,7 @@ enum CvarsList
Handle:CVAR_RESPAWN_DELAY, Handle:CVAR_RESPAWN_DELAY,
Handle:CVAR_RESPAWN_ZOMBIE, Handle:CVAR_RESPAWN_ZOMBIE,
Handle:CVAR_RESPAWN_ZOMBIE_WORLD, Handle:CVAR_RESPAWN_ZOMBIE_WORLD,
Handle:CVAR_ZSPAWN,
Handle:CVAR_ZHP, Handle:CVAR_ZHP,
Handle:CVAR_ZHP_DEFAULT, Handle:CVAR_ZHP_DEFAULT,
@ -93,7 +95,6 @@ enum CvarsList
Handle:CVAR_OVERLAY_REDISPLAY, Handle:CVAR_OVERLAY_REDISPLAY,
Handle:CVAR_ZVISION_ALLOW_DISABLE, Handle:CVAR_ZVISION_ALLOW_DISABLE,
Handle:CVAR_MENU_AUTOCLOSE, Handle:CVAR_MENU_AUTOCLOSE,
Handle:CVAR_ZSPAWN,
Handle:CVAR_ZTELE, Handle:CVAR_ZTELE,
Handle:CVAR_ZTELE_STARTUP_DELAY, Handle:CVAR_ZTELE_STARTUP_DELAY,
Handle:CVAR_ZTELE_COOLDOWN, Handle:CVAR_ZTELE_COOLDOWN,
@ -177,7 +178,7 @@ CvarsCreate()
// (None) // (None)
// =========================== // ===========================
// Offsets (core) // Tools (core)
// =========================== // ===========================
// (None) // (None)
@ -252,6 +253,7 @@ CvarsCreate()
g_hCvarsList[CVAR_INFECT_SPAWNTIME_MIN] = CreateConVar("zr_infect_spawntime_min", "30.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_SPAWNTIME_MAX] = CreateConVar("zr_infect_spawntime_max", "50.0", "");
g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK] = CreateConVar("zr_infect_consecutive_block", "1", ""); g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK] = CreateConVar("zr_infect_consecutive_block", "1", "");
g_hCvarsList[CVAR_INFECT_WEAPONS_DROP] = CreateConVar("zr_infect_weapons_drop", "1", "");
// Effects // Effects
@ -389,6 +391,13 @@ CvarsCreate()
// (None) // (None)
// ===========================
// ZSpawn (module)
// ===========================
g_hCvarsList[CVAR_ZSPAWN] = CreateConVar("zr_zspawn", "1", "");
// Old Desc: Allow players to spawn if they just joined the game (0: Disable)
// =========================== // ===========================
// ZHP (module) // ZHP (module)
// =========================== // ===========================
@ -406,8 +415,6 @@ CvarsCreate()
// Old Desc: Allow users to disable ZVision with their nightvision key (0: Disable) // Old Desc: Allow users to disable ZVision with their nightvision key (0: Disable)
g_hCvarsList[CVAR_MENU_AUTOCLOSE] = CreateConVar("zr_menu_autoclose", "0", ""); g_hCvarsList[CVAR_MENU_AUTOCLOSE] = CreateConVar("zr_menu_autoclose", "0", "");
// Old Desc: Automatically close menus on selection. If disabled the menu will remain open. // Old Desc: Automatically close menus on selection. If disabled the menu will remain open.
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", ""); g_hCvarsList[CVAR_ZTELE] = CreateConVar("zr_tele", "1", "");
// Old Desc: Allow players to use the teleporter to get to spawn. (0: Disable) // Old Desc: Allow players to use the teleporter to get to spawn. (0: Disable)
g_hCvarsList[CVAR_ZTELE_STARTUP_DELAY] = CreateConVar("zr_tele_startup_delay", "30", ""); g_hCvarsList[CVAR_ZTELE_STARTUP_DELAY] = CreateConVar("zr_tele_startup_delay", "30", "");
@ -523,7 +530,7 @@ public CvarsHookRestartGame(Handle:cvar, const String:oldvalue[], const String:n
} }
// Terminate the round with restart time as delay. // Terminate the round with restart time as delay.
RoundEndRestart(delay); RoundEndTerminateRound(delay);
// If log flag check fails, then don't log. // If log flag check fails, then don't log.
if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE))

View File

@ -39,7 +39,7 @@ enum DamageHooks
Hook_OnTakeDamage, /** OnTakeDamage HookID */ Hook_OnTakeDamage, /** OnTakeDamage HookID */
} }
new g_iDamageHooks[MAXPLAYERS + 1][DamageHooks]; new g_iDamageHookID[MAXPLAYERS + 1][DamageHooks];
/** /**
* Damage module init function. * Damage module init function.
@ -73,8 +73,8 @@ DamageInit()
DamageClientInit(client) DamageClientInit(client)
{ {
// Hook damage callbacks. // Hook damage callbacks.
g_iDamageHooks[client][Hook_TraceAttack] = Hacks_Hook(client, HACKS_HTYPE_TRACEATTACK, DamageTraceAttack); g_iDamageHookID[client][Hook_TraceAttack] = Hacks_Hook(client, HACKS_HTYPE_TRACEATTACK, DamageTraceAttack);
g_iDamageHooks[client][Hook_OnTakeDamage] = Hacks_Hook(client, HACKS_HTYPE_ONTAKEDAMAGE, DamageOnTakeDamage); g_iDamageHookID[client][Hook_OnTakeDamage] = Hacks_Hook(client, HACKS_HTYPE_ONTAKEDAMAGE, DamageOnTakeDamage);
} }
/** /**
@ -85,8 +85,8 @@ DamageClientInit(client)
DamageOnClientDisconnect(client) DamageOnClientDisconnect(client)
{ {
// Unhook damage callbacks. // Unhook damage callbacks.
Hacks_Unhook(g_iDamageHooks[client][Hook_TraceAttack]); Hacks_Unhook(g_iDamageHookID[client][Hook_TraceAttack]);
Hacks_Unhook(g_iDamageHooks[client][Hook_OnTakeDamage]); Hacks_Unhook(g_iDamageHookID[client][Hook_OnTakeDamage]);
} }
/** /**

View File

@ -73,6 +73,7 @@ public Action:EventRoundStart(Handle:event, const String:name[], bool:dontBroadc
VEffectsOnRoundStart(); VEffectsOnRoundStart();
SEffectsOnRoundStart(); SEffectsOnRoundStart();
AntiStickOnRoundStart(); AntiStickOnRoundStart();
ZSpawnOnRoundStart();
} }
/** /**
@ -148,15 +149,17 @@ public Action:EventPlayerSpawn(Handle:event, const String:name[], bool:dontBroad
new index = GetClientOfUserId(GetEventInt(event, "userid")); new index = GetClientOfUserId(GetEventInt(event, "userid"));
// Reset FOV and overlay. // Reset FOV and overlay.
SetPlayerFOV(index, 90); ToolsSetClientDefaultFOV(index, 90);
ClientCommand(index, "r_screenoverlay \"\""); ClientCommand(index, "r_screenoverlay \"\"");
// Check if client is on a team. // Check if client is on a team.
if (ZRIsClientOnTeam(index)) if (ZRIsClientOnTeam(index))
{ {
// Remove night vision. // Turn off nightvision.
NightVisionOn(index, false); ToolsClientNightVision(index, false, false);
NightVision(index, false);
// Take nightvision away.
ToolsClientNightVision(index, false);
if (g_bZombieSpawned) if (g_bZombieSpawned)
{ {
@ -166,10 +169,6 @@ public Action:EventPlayerSpawn(Handle:event, const String:name[], bool:dontBroad
CS_RespawnPlayer(index); CS_RespawnPlayer(index);
} }
} }
else
{
SetPlayerAlpha(index, 255);
}
} }
// Forward event to modules. // Forward event to modules.
@ -248,7 +247,8 @@ public Action:EventPlayerDeath(Handle:event, const String:name[], bool:dontBroad
{ {
// Add kill bonus to attacker's score. // Add kill bonus to attacker's score.
new bonus = ClassGetKillBonus(attacker); new bonus = ClassGetKillBonus(attacker);
AddPlayerScore(attacker, bonus); new score = ToolsClientScore(index, true, false);
ToolsClientScore(index, true, true, score + bonus);
} }
} }
@ -272,12 +272,10 @@ public Action:EventPlayerDeath(Handle:event, const String:name[], bool:dontBroad
public Action:EventPlayerJump(Handle:event, const String:name[], bool:dontBroadcast) public Action:EventPlayerJump(Handle:event, const String:name[], bool:dontBroadcast)
{ {
// Get all required event info. // Get all required event info.
new client = GetClientOfUserId(GetEventInt(event, "userid")); new index = GetClientOfUserId(GetEventInt(event, "userid"));
new Float:distance = ClassGetJumpDistance(client); // Forward event to modules.
new Float:height = ClassGetJumpHeight(client); JumpBoostOnClientJump(index);
JumpBoost(client, distance, height);
} }
/** /**

View File

@ -1,9 +1,12 @@
/** /*
* ==================== * ============================================================================
*
* Zombie:Reloaded * Zombie:Reloaded
* File: global.inc *
* Author: Greyscale * File: (Core) global.inc
* ==================== * Description: External API.
*
* ============================================================================
*/ */
/** /**

View File

@ -138,7 +138,7 @@ InfectOnClientDisconnect(client)
} }
// Manually terminate round. // Manually terminate round.
RoundEndTerminateRound(ZombiesWin); RoundEndTerminateRound(ROUNDEND_DELAY, ZombiesWin);
return; return;
} }
@ -351,6 +351,12 @@ public Action:InfectMotherZombie(Handle:timer)
// client = client index. // client = client index.
for (new x = 0; x < eligibleclients; x++) for (new x = 0; x < eligibleclients; x++)
{ {
// Stop pruning if there is only 1 player left.
if (eligibleclients <= 1)
{
break;
}
// Get client stored in array index. // Get client stored in array index.
client = GetArrayCell(arrayEligibleClients, x); client = GetArrayCell(arrayEligibleClients, x);
@ -366,12 +372,6 @@ public Action:InfectMotherZombie(Handle:timer)
// Subtract one from count. // Subtract one from count.
eligibleclients--; 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. // Backtrack one index, because we deleted it out from under the loop.
x--; x--;
} }
@ -426,6 +426,12 @@ public Action:InfectMotherZombie(Handle:timer)
// Calculate mother zombie count. // Calculate mother zombie count.
new mothercount = RoundToNearest(float(humancount) / ratio); new mothercount = RoundToNearest(float(humancount) / ratio);
// If mothercount is 0, then set to 1.
if (!mothercount)
{
mothercount = 1;
}
// x = current mother zombie count. // x = current mother zombie count.
for (new x = 0; x < mothercount; x++) for (new x = 0; x < mothercount; x++)
{ {
@ -437,6 +443,7 @@ public Action:InfectMotherZombie(Handle:timer)
{ {
break; break;
} }
// Get a random valid array index. // Get a random valid array index.
randindex = GetRandomInt(0, eligibleclients - 1); randindex = GetRandomInt(0, eligibleclients - 1);
@ -475,9 +482,20 @@ InfectClient(client, attacker = -1, bool:motherinfect = false)
new weapons[WeaponsType]; new weapons[WeaponsType];
WeaponsGetClientWeapons(client, weapons); WeaponsGetClientWeapons(client, weapons);
// Check if weapons drop is enabled.
new bool:weaponsdrop = GetConVarBool(g_hCvarsList[CVAR_INFECT_WEAPONS_DROP]);
// Loop through array slots and force drop. // Loop through array slots and force drop.
// x = weapon slot. // x = weapon slot.
for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) for (new x = 0; x < WEAPONS_SLOTS_MAX; x++)
{
// If weapon is invalid, then stop.
if (weapons[x] == -1)
{
continue;
}
if (weaponsdrop)
{ {
// If this is the knife slot, then stop. // If this is the knife slot, then stop.
if (WeaponsType:x == Type_Melee) if (WeaponsType:x == Type_Melee)
@ -485,18 +503,18 @@ InfectClient(client, attacker = -1, bool:motherinfect = false)
continue; continue;
} }
// If weapon is invalid, then stop.
if (weapons[x] == -1)
{
continue;
}
// Force client to drop weapon. // Force client to drop weapon.
WeaponForceClientDrop(client, weapons[x]); WeaponForceClientDrop(client, weapons[x]);
} }
else
{
// Strip weapon.
RemovePlayerItem(client, weapons[x]);
}
}
// If client has no knife, give them one. // If client has no knife, give them one.
if (weapons[Type_Melee] == -1) if (GetPlayerWeaponSlot(client, _:Type_Melee) == -1)
{ {
GivePlayerItem(client, "weapon_knife"); GivePlayerItem(client, "weapon_knife");
} }
@ -524,10 +542,12 @@ InfectClient(client, attacker = -1, bool:motherinfect = false)
} }
// Give client's infector a point. // Give client's infector a point.
AddPlayerScore(attacker, 1); new score = ToolsClientScore(attacker, true, false);
ToolsClientScore(attacker, true, true, ++score);
// Add a death to the zombie's score. // Add a death to the zombie's score.
AddPlayerDeath(client, 1); new deaths = ToolsClientScore(client, false, false);
ToolsClientScore(client, false, true, ++deaths);
// Apply infect HP gain. // Apply infect HP gain.
new healthgain = ClassGetHealthInfectGain(attacker); new healthgain = ClassGetHealthInfectGain(attacker);

44
src/zr/jumpboost.inc Normal file
View File

@ -0,0 +1,44 @@
/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: jumpboost.inc
* Description: Modified jump vector magnitudes.
*
* ============================================================================
*/
/**
* Client is jumping.
*
* @param client The client index.
*/
JumpBoostOnClientJump(client)
{
// Get class jump multipliers.
new Float:distance = ClassGetJumpDistance(client);
new Float:height = ClassGetJumpHeight(client);
// Get client's current velocity.
new Float:vecVelocity[3];
ToolsClientVelocity(client, vecVelocity, false);
// Apply jump values.
vecVelocity[0] *= distance;
vecVelocity[1] *= distance;
vecVelocity[2] = height;
JumpBoostSetClientVelocity(client, vecVelocity);
}
/**
* Apply jump boost force on client. (Special method separate from ToolsClientVelocity)
*
* @param client The client index.
* @param vecVelocity Velocity to set on client.
*/
JumpBoostSetClientVelocity(client, const Float:vecVelocity[3])
{
SetEntDataVector(client, g_iToolsBaseVelocity, vecVelocity, true);
}

View File

@ -59,7 +59,7 @@ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_hea
// Get attackers eye angles. // Get attackers eye angles.
new Float:attackerang[3]; new Float:attackerang[3];
GetPlayerEyeAngles(attacker, attackerang); KnockbackGetClientEyeAngles(attacker, attackerang);
// Calculate knockback end-vector. // Calculate knockback end-vector.
TR_TraceRayFilter(attackerloc, attackerang, MASK_ALL, RayType_Infinite, KnockbackTRFilter); TR_TraceRayFilter(attackerloc, attackerang, MASK_ALL, RayType_Infinite, KnockbackTRFilter);
@ -99,8 +99,8 @@ KnockbackSetVelocity(client, const Float:startpoint[3], const Float:endpoint[3],
// Apply the magnitude by scaling the vector (multiplying each of its components). // Apply the magnitude by scaling the vector (multiplying each of its components).
ScaleVector(vector, magnitude); ScaleVector(vector, magnitude);
// ADD the given vector to the clients current velocity. // ADD the given vector to the client's current velocity.
SetPlayerVelocity(client, vector, false); ToolsClientVelocity(client, vector);
} }
/** /**
@ -164,3 +164,14 @@ KnockbackFindExplodingGrenade(Float:heLoc[3])
// Didn't find the grenade. // Didn't find the grenade.
return -1; return -1;
} }
/**
* Get client's eye angles.
*
* @param client The client index.
* @param vecAngles The angle vector of the client's eyes.
*/
KnockbackGetClientEyeAngles(client, Float:vecAngles[3])
{
SDKCall(g_hToolsEyeAngles, client, vecAngles);
}

View File

@ -24,6 +24,7 @@
#define LOG_FORMAT_TYPE_SIMPLE 0 /** Simple log message. */ #define LOG_FORMAT_TYPE_SIMPLE 0 /** Simple log message. */
#define LOG_FORMAT_TYPE_FULL 1 /** Full log message, printed in normal log. */ #define LOG_FORMAT_TYPE_FULL 1 /** Full log message, printed in normal log. */
#define LOG_FORMAT_TYPE_ERROR 2 /** Full log message, printed in error log. */ #define LOG_FORMAT_TYPE_ERROR 2 /** Full log message, printed in error log. */
#define LOG_FORMAT_TYPE_FATALERROR 3 /** Full log message, stops the plugin and printed in error logs. */
/** /**
* @endsection * @endsection
*/ */
@ -67,6 +68,9 @@ new Handle:g_hLogFlags = INVALID_HANDLE;
* @endsection * @endsection
*/ */
/**
* Log module init function.
*/
LogInit() LogInit()
{ {
// Create modules cvars. // Create modules cvars.
@ -100,11 +104,8 @@ LogMessageFormatted(client, const String:module[], const String:block[], const S
decl String:logtext[LOG_MAX_LENGTH_FILE]; decl String:logtext[LOG_MAX_LENGTH_FILE];
// Set to true if log to console, false if client. // If client is invalid (console), and console log events are ignored, then stop.
new bool:console = !ZRIsClientValid(client); if (client == 0 && LogCheckFlag(LOG_IGNORE_CONSOLE))
// If client is invalid (console), and console is ignored, then stop.
if (console && LogCheckFlag(LOG_IGNORE_CONSOLE))
{ {
return; return;
} }
@ -132,6 +133,11 @@ LogMessageFormatted(client, const String:module[], const String:block[], const S
Format(logtext, sizeof(logtext), "\"%s\" : \"%s\" -- %s", module, block, logtext); Format(logtext, sizeof(logtext), "\"%s\" : \"%s\" -- %s", module, block, logtext);
LogError(logtext); LogError(logtext);
} }
case LOG_FORMAT_TYPE_FATALERROR:
{
Format(logtext, sizeof(logtext), "\"%s\" : \"%s\" -- %s", module, block, logtext);
SetFailState(logtext);
}
} }
// If log to admin flag is enabled, then print to admins. // If log to admin flag is enabled, then print to admins.
@ -141,8 +147,8 @@ LogMessageFormatted(client, const String:module[], const String:block[], const S
LogToAdmins(logtext); LogToAdmins(logtext);
} }
// If client isn't console, and we log to client's then continue. // If client is a valid client (but not console), and we log to client's then continue.
if (!console && LogCheckFlag(LOG_TO_CLIENT)) if (ZRIsClientValid(client) && LogCheckFlag(LOG_TO_CLIENT))
{ {
// Set client as translation target. // Set client as translation target.
SetGlobalTransTarget(client); SetGlobalTransTarget(client);

View File

@ -1,100 +1,136 @@
/** /*
* ==================== * ============================================================================
*
* Zombie:Reloaded * Zombie:Reloaded
* File: menu.sp *
* Author: Greyscale * File: menu.inc
* ==================== * Description: Base menu functions for the plugin.
*
* ============================================================================
*/ */
MainMenu(client) /**
* Show main menu to client.
*
* @param client The client index.
*/
MenuMain(client)
{ {
new Handle:menu_main = CreateMenu(MainMenuHandle); // Create menu handle.
new itemdraw = (ZRIsClientAdmin(client)) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED; new Handle:menu_main = CreateMenu(MenuMainHandle);
// Make client global translations target.
SetGlobalTransTarget(client); SetGlobalTransTarget(client);
// Set menu title.
SetMenuTitle(menu_main, "%t\n ", "!zmenu title"); SetMenuTitle(menu_main, "%t\n ", "!zmenu title");
decl String:zadmin[128]; // Initialize menu lines.
decl String:zclass[128]; decl String:zadmin[64];
decl String:zmarket[128]; decl String:zclass[64];
decl String:zspawn[128]; decl String:zspawn[64];
decl String:ztele[128]; decl String:ztele[64];
decl String:zhp[128]; decl String:zhp[64];
decl String:zmarket[64];
Format(zadmin, sizeof(zadmin), "%t", "!zmenu admin"); // Translate each line into client's language.
Format(zclass, sizeof(zclass), "%t", "!zmenu class", ITEMDRAW_DISABLED); Format(zadmin, sizeof(zadmin), "%t", "Menu main zadmin");
Format(zmarket, sizeof(zmarket), "%t", "!zmenu market"); Format(zclass, sizeof(zclass), "%t", "Menu main zclass");
Format(zspawn, sizeof(zspawn), "%t", "!zmenu spawn"); Format(zspawn, sizeof(zspawn), "%t", "Menu main zspawn");
Format(ztele, sizeof(ztele), "%t", "!zmenu tele"); Format(ztele, sizeof(ztele), "%t", "Menu main ztele");
Format(zhp, sizeof(zhp), "%t (%d HP)", "!zmenu hp", GetClientHealth(client)); Format(zhp, sizeof(zhp), "%t", "Menu main zhp");
Format(zmarket, sizeof(zmarket), "%t", "Menu main zmarket");
// Add items to menu.
// Disable option if client isn't an admin.
new bool:admin = ZRIsClientAdmin(client);
AddMenuItem(menu_main, "zadmin", zadmin, MenuGetItemDraw(admin));
AddMenuItem(menu_main, "zadmin", zadmin, itemdraw);
AddMenuItem(menu_main, "zclass", zclass); AddMenuItem(menu_main, "zclass", zclass);
if (g_bMarket)
{
AddMenuItem(menu_main, "zmarket", zmarket);
}
else
{
AddMenuItem(menu_main, "zmarket", zmarket, ITEMDRAW_DISABLED);
}
AddMenuItem(menu_main, "zspawn", zspawn); AddMenuItem(menu_main, "zspawn", zspawn);
AddMenuItem(menu_main, "ztele", ztele); AddMenuItem(menu_main, "ztele", ztele);
AddMenuItem(menu_main, "zhp", zhp); AddMenuItem(menu_main, "zhp", zhp);
AddMenuItem(menu_main, "zmarket", zmarket, MenuGetItemDraw(g_bMarket));
// Display menu to client.
DisplayMenu(menu_main, client, MENU_TIME_FOREVER); DisplayMenu(menu_main, client, MENU_TIME_FOREVER);
} }
public MainMenuHandle(Handle:menu_main, MenuAction:action, client, slot) /**
* Menu callback (main)
* Redirects client to selected option's handle code.
*
* @param menu The menu handle.
* @param action Action client is doing in menu.
* @param client The client index.
* @param slot The menu slot selected. (starting from 0)
*/
public MenuMainHandle(Handle:menu, MenuAction:action, client, slot)
{ {
// Client selected an option.
if (action == MenuAction_Select) if (action == MenuAction_Select)
{ {
// Create variable to possible resend menu later.
new bool:resend = true;
switch(slot) switch(slot)
{ {
// Selected zadmin.
case 0: case 0:
{ {
if (!ZRAdminMenu(client)) // Copy return to resend variable.
{ resend = !ZRAdminMenu(client);
MainMenu(client);
}
} }
case 1: case 1:
{ {
// Send class menu
ClassMenuMain(client); ClassMenuMain(client);
// Don't resend this menu.
resend = false;
} }
case 2: case 2:
{ {
if (!ZMarketSend(client)) // Copy return to resend variable.
{ resend = !ZMarketSend(client);
MainMenu(client);
}
} }
case 3: case 3:
{ {
ZSpawn(client); // Send zspawn command from client.
ZSpawnClient(client);
} }
case 4: case 4:
{ {
if (!ZTele(client)) // Copy return to resend variable.
{ resend = !ZTele(client);
MainMenu(client);
}
} }
case 5: case 5:
{ {
// Toggle ZHP. // Toggle ZHP.
ZHPToggle(client); ZHPToggle(client);
}
}
// Resend menu. // Resend is still true, then resend menu.
MainMenu(client); if (resend)
} {
MenuMain(client);
} }
} }
// Client exited menu.
if (action == MenuAction_End) if (action == MenuAction_End)
{ {
CloseHandle(menu_main); CloseHandle(menu);
} }
} }
/**
* Return itemdraw flag for SM menus.
*
* @param condition If this is true, item will be drawn normally.
*/
MenuGetItemDraw(bool:condition)
{
return condition ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED;
}

View File

@ -112,7 +112,7 @@ bool:ClassApplyAlpha(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER)
return false; return false;
} }
SetPlayerAlpha(client, alpha); ToolsSetClientAlpha(client, alpha);
return true; return true;
} }
@ -187,13 +187,9 @@ bool:ClassApplyNightVision(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER
nvgs = ClassGetNvgs(classindex, cachetype); nvgs = ClassGetNvgs(classindex, cachetype);
} }
NightVision(client, nvgs); ToolsClientNightVision(client, nvgs);
ToolsClientNightVision(client, nvgs, false);
// Turn on night vision if applied.
if (nvgs)
{
NightVisionOn(client, nvgs);
}
return true; return true;
} }
@ -223,7 +219,7 @@ bool:ClassApplyFOV(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER)
fov = ClassGetFOV(classindex, cachetype); fov = ClassGetFOV(classindex, cachetype);
} }
SetPlayerFOV(client, fov); ToolsSetClientDefaultFOV(client, fov);
return true; return true;
} }
@ -333,6 +329,6 @@ bool:ClassApplySpeed(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER)
speed = ClassGetSpeed(classindex, cachetype); speed = ClassGetSpeed(classindex, cachetype);
} }
SetPlayerSpeed(client, speed); ToolsSetClientLMV(client, speed);
return true; return true;
} }

View File

@ -38,7 +38,7 @@ ClassOnClientDisconnect(client)
ClassOnClientSpawn(client) ClassOnClientSpawn(client)
{ {
// Reset client's FOV. // Reset client's FOV.
SetPlayerFOV(client, ATTRIBUTES_FOV_DEFAULT); ToolsSetClientDefaultFOV(client, ATTRIBUTES_FOV_DEFAULT);
new bool:randomclass = GetConVarBool(g_hCvarsList[CVAR_CLASSES_RANDOM]); new bool:randomclass = GetConVarBool(g_hCvarsList[CVAR_CLASSES_RANDOM]);
new bool:showmenu = GetConVarBool(g_hCvarsList[CVAR_CLASSES_SPAWN]); new bool:showmenu = GetConVarBool(g_hCvarsList[CVAR_CLASSES_SPAWN]);

View File

@ -136,7 +136,7 @@ public ClassMenuMainHandle(Handle:menu, MenuAction:action, client, slot)
{ {
if (slot == MenuCancel_ExitBack) if (slot == MenuCancel_ExitBack)
{ {
MainMenu(client); MenuMain(client);
} }
} }
} }
@ -256,6 +256,9 @@ public ClassMenuSelectHandle(Handle:menu, MenuAction:action, client, slot)
case MenuAction_End: case MenuAction_End:
{ {
CloseHandle(menu); CloseHandle(menu);
// Stop so menu doesn't reopen.
return;
} }
} }

View File

@ -22,6 +22,6 @@ ClassAlphaUpdate(client)
if ((max_health - current_health) > max_damage) if ((max_health - current_health) > max_damage)
{ {
new alpha_damaged = ClassGetAlphaDamaged(client); new alpha_damaged = ClassGetAlphaDamaged(client);
SetPlayerAlpha(client, alpha_damaged); ToolsSetClientAlpha(client, alpha_damaged);
} }
} }

View File

@ -35,21 +35,17 @@
/** /**
* Delay between round ending and new round starting. (Normal) * Delay between round ending and new round starting. (Normal)
*/ */
#define ROUNDEND_DELAY_NORMAL 5.0 #define ROUNDEND_DELAY 5.0
/**
* Delay between round ending and new round starting. (Short, for ROUNDEND_GAME_COMMENCING)
*/
#define ROUNDEND_DELAY_SHORT 3.0
/** /**
* Possible round end outcomes. * Possible round end outcomes.
*/ */
enum RoundEndOutcome enum RoundEndOutcome
{ {
Restart, /** Round is restarting. */
Draw, /** Round has ended in unexpected way. */
HumansWin, /** Humans have killed all zombies. */ HumansWin, /** Humans have killed all zombies. */
ZombiesWin, /** Zombies have infected all humans. */ ZombiesWin, /** Zombies have infected all humans. */
Draw, /** Round has ended in unexpected way. */
} }
/** /**
@ -91,7 +87,7 @@ RoundEndOnClientDeath()
new RoundEndOutcome:outcome; new RoundEndOutcome:outcome;
if (RoundEndGetRoundStatus(outcome)) if (RoundEndGetRoundStatus(outcome))
{ {
RoundEndTerminateRound(outcome); RoundEndTerminateRound(ROUNDEND_DELAY, outcome);
} }
} }
@ -104,7 +100,7 @@ RoundEndOnClientInfected()
new RoundEndOutcome:outcome; new RoundEndOutcome:outcome;
if (RoundEndGetRoundStatus(outcome)) if (RoundEndGetRoundStatus(outcome))
{ {
RoundEndTerminateRound(outcome); RoundEndTerminateRound(ROUNDEND_DELAY, outcome);
} }
} }
@ -164,7 +160,7 @@ RoundEndOnRoundEnd(reason)
new RoundEndOutcome:outcome = RoundEndReasonToOutcome(reason); new RoundEndOutcome:outcome = RoundEndReasonToOutcome(reason);
// Display the overlay to all clients. // Display the overlay to all clients.
RoundEndOverlayStart(ROUNDEND_DELAY_NORMAL, outcome); RoundEndOverlayStart(ROUNDEND_DELAY, outcome);
// Balance teams. // Balance teams.
RoundEndBalanceTeams(); RoundEndBalanceTeams();
@ -255,8 +251,8 @@ RoundEndOutcome:RoundEndReasonToOutcome(reason)
*/ */
public Action:RoundEndTimer(Handle:timer) public Action:RoundEndTimer(Handle:timer)
{ {
// Terminate the round with a normal delay, and CTs as the winner. // Terminate the round with humans as the winner.
TerminateRound(ROUNDEND_DELAY_NORMAL, ROUNDEND_CTS_WIN); RoundEndTerminateRound(ROUNDEND_DELAY, HumansWin);
} }
/** /**
@ -313,40 +309,38 @@ bool:RoundEndGetRoundStatus(&RoundEndOutcome:outcome)
} }
/** /**
* Ends the round with the given outcome. * Ends the round with the given outcome and delay.
* *
* @param delay Delay before new round starts.
* @param outcome The outcome of the round. * @param outcome The outcome of the round.
*/ */
RoundEndTerminateRound(RoundEndOutcome:outcome) RoundEndTerminateRound(Float:delay, RoundEndOutcome:outcome = Restart)
{ {
switch(outcome) switch(outcome)
{ {
// Round is restarting.
case Restart:
{
SDKCall(g_hToolsTerminateRound, delay, ROUNDEND_GAME_COMMENCING);
}
// Round was a draw.
case Draw:
{
SDKCall(g_hToolsTerminateRound, delay, ROUNDEND_ROUND_DRAW);
}
// Zombies won. // Zombies won.
case ZombiesWin: case ZombiesWin:
{ {
// Terminate the round with a normal delay, and Ts as the winner. SDKCall(g_hToolsTerminateRound, delay, ROUNDEND_TERRORISTS_WIN);
TerminateRound(ROUNDEND_DELAY_NORMAL, ROUNDEND_TERRORISTS_WIN);
} }
// Humans won. // Humans won.
case HumansWin: case HumansWin:
{ {
// Terminate the round with a normal delay, and CTs as the winner. SDKCall(g_hToolsTerminateRound, delay, ROUNDEND_CTS_WIN);
TerminateRound(ROUNDEND_DELAY_NORMAL, ROUNDEND_CTS_WIN);
} }
} }
} }
/**
* Restarts the game.
*
* @param delay How long to wait between round end and new round.
*/
RoundEndRestart(Float:delay)
{
// Terminate the round.
TerminateRound(delay, ROUNDEND_GAME_COMMENCING);
}
/** /**
* Balances teams * Balances teams
* *

View File

@ -1,103 +1,104 @@
/** /*
* ==================== * ============================================================================
*
* Zombie:Reloaded * Zombie:Reloaded
*
* File: sayhooks.inc * File: sayhooks.inc
* Author: Greyscale * Description: Hook plugin say commands and redirect to their handling module.
* ==================== *
* ============================================================================
*/ */
HookChatCmds() /**
* Max number of characters in a chat text string.
*/
#define SAYHOOKS_MAX_CHAT_LENGTH 192
/**
* @section Say command key words.
*/
#define SAYHOOKS_KEYWORD_ZMENU "!zmenu"
#define SAYHOOKS_KEYWORD_ZADMIN "!zadmin"
#define SAYHOOKS_KEYWORD_ZCLASS "!zclass"
#define SAYHOOKS_KEYWORD_ZSPAWN "!zspawn"
#define SAYHOOKS_KEYWORD_ZTELE "!ztele"
#define SAYHOOKS_KEYWORD_ZHP "!zhp"
#define SAYHOOKS_KEYWORD_ZMARKET "!zmarket"
/**
* @endsection
*/
/**
* Say hooks module init function.
*/
SayHooksInit()
{ {
RegConsoleCmd("say", SayCommand); // Hook client's say commands.
RegConsoleCmd("say_team", SayCommand); RegConsoleCmd("say", SayHooksCmdSay);
RegConsoleCmd("say_team", SayHooksCmdSay);
} }
public Action:SayCommand(client, argc) /**
* Command callback. (say, say_team)
* Catches all client's say text and takes action on key words.
*
* @param client The client index.
* @param argc The number of arguments in command string.
*/
public Action:SayHooksCmdSay(client, argc)
{ {
new bool:enabled = GetConVarBool(g_hCvarsList[CVAR_ENABLE]); decl String:args[SAYHOOKS_MAX_CHAT_LENGTH];
if (!client || !enabled)
{
return Plugin_Continue;
}
decl String:args[192];
// Get client's command string (typically 'say "text"')
GetCmdArgString(args, sizeof(args)); GetCmdArgString(args, sizeof(args));
// Strip away the quotes.
ReplaceString(args, sizeof(args), "\"", ""); ReplaceString(args, sizeof(args), "\"", "");
if (StrEqual(args, "!zmenu", false)) // If client triggered the zmenu keyword, then send menu.
if (StrEqual(args, SAYHOOKS_KEYWORD_ZMENU, false))
{ {
MainMenu(client); MenuMain(client);
} }
if (StrEqual(args, "!zadmin", false)) // If client triggered the zmenu keyword, then send menu.
else if (StrEqual(args, SAYHOOKS_KEYWORD_ZADMIN, false))
{ {
ZRAdminMenu(client); ZRAdminMenu(client);
} }
else if (StrEqual(args, "!zclass", false)) // If client triggered the zmenu keyword, then send menu.
else if (StrEqual(args, SAYHOOKS_KEYWORD_ZCLASS, false))
{ {
ClassMenuMain(client); ClassMenuMain(client);
} }
else if (StrEqual(args, "!zmarket", false)) // If client triggered the zmenu keyword, then send menu.
else if (StrEqual(args, SAYHOOKS_KEYWORD_ZSPAWN, false))
{
// Spawns a late-joining client into the game.
ZSpawnClient(client);
}
// If client triggered the zmenu keyword, then send menu.
else if (StrEqual(args, SAYHOOKS_KEYWORD_ZTELE, false))
{
ZTele(client);
}
// If client triggered the zmenu keyword, then send menu.
else if (StrEqual(args, SAYHOOKS_KEYWORD_ZHP, false))
{
// Toggle ZHP.
ZHPToggle(client);
}
// If client triggered the zmenu keyword, then send menu.
else if (StrEqual(args, SAYHOOKS_KEYWORD_ZMARKET, false))
{ {
// Send market menu. // Send market menu.
ZMarketSend(client); ZMarketSend(client);
} }
else if (StrEqual(args, "!zspawn", false))
{
ZSpawn(client);
}
else if (StrEqual(args, "!tp", false) ||
StrEqual(args, "!ztele", false) ||
StrEqual(args, "!tele", false) ||
StrEqual(args, "!teleport", false))
{
ZTele(client);
}
else if (StrEqual(args, "!teleabort", false))
{
AbortTeleport(client, false);
}
else if (StrEqual(args, "!zhp", false))
{
// Toggle ZHP.
ZHPToggle(client);
}
else if (StrContains(args, "teleport", false) != -1
|| StrContains(args, "stuck", false) != -1
|| StrContains(args, "help", false) != -1)
{
ZR_PrintToChat(client, "!ztele stuck");
}
return Plugin_Continue; return Plugin_Continue;
} }
ZSpawn(client)
{
new bool:spawn = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN]);
if (!spawn)
{
ZR_PrintToChat(client, "Feature is disabled");
return;
}
new team = GetClientTeam(client);
if (team != CS_TEAM_T && team != CS_TEAM_CT)
{
return;
}
if (IsPlayerAlive(client))
{
return;
}
RespawnSpawnClient(client);
}

View File

@ -79,8 +79,8 @@ SpawnProtectOnClientSpawn(client)
// Set improved attributes // Set improved attributes
// (Move to cvar?) // (Move to cvar?)
SetPlayerAlpha(client, 0); ToolsSetClientAlpha(client, 0);
SetPlayerSpeed(client, 600.0); ToolsSetClientLMV(client, 600.0);
// Set time left to zr_protect_time's value. // Set time left to zr_protect_time's value.
new protect_time = GetConVarInt(g_hCvarsList[CVAR_SPAWNPROTECT_TIME]); new protect_time = GetConVarInt(g_hCvarsList[CVAR_SPAWNPROTECT_TIME]);
@ -151,8 +151,8 @@ public Action:SpawnProtectTimer(Handle:timer, any:client)
// Fix attributes. // Fix attributes.
// TODO: Set class attributes. // TODO: Set class attributes.
SetPlayerAlpha(client, 255); ToolsSetClientAlpha(client, 255);
SetPlayerSpeed(client, 300.0); ToolsSetClientLMV(client, 300.0);
// Clear timer handle. // Clear timer handle.
tSpawnProtect[client] = INVALID_HANDLE; tSpawnProtect[client] = INVALID_HANDLE;

199
src/zr/tools.inc Normal file
View File

@ -0,0 +1,199 @@
/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: tools.inc
* Description: Find offsets and signatures.
*
* ============================================================================
*/
/**
* Initialize global offset variables.
*/
new g_iToolsVelocity;
new g_iToolsBaseVelocity;
new g_iToolsLMV;
new g_iToolsHasNightVision;
new g_iToolsNightVisionOn;
new g_iToolsCollisionGroup;
new g_iToolsAccount;
new g_iToolsDefaultFOV;
new g_iToolsInBuyZone;
new g_iToolsRender;
new g_iToolsRenderMode;
new g_iToolsActiveWeapon;
/**
* @endsection
*/
/**
* Initialize global SDKTools handles.
*/
new Handle:g_hToolsGameConfig = INVALID_HANDLE;
new Handle:g_hToolsEyeAngles = INVALID_HANDLE;
new Handle:g_hToolsTerminateRound = INVALID_HANDLE;
new Handle:g_hToolsCSWeaponDrop = INVALID_HANDLE;
/**
* @endsection
*/
// Tools Functions (core)
#include "zr/tools_functions"
/**
* Tools module init function.
*/
ToolsInit()
{
// Find offsets.
ToolsFindOffsets();
// Setup SDKTools
ToolsSetupGameData();
}
/**
* Finds all offset values for the plugin.
*/
ToolsFindOffsets()
{
// If offset "m_vecVelocity[0]" can't be found, then stop the plugin.
g_iToolsVelocity = FindSendPropInfo("CBasePlayer", "m_vecVelocity[0]");
if (g_iToolsVelocity == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CBasePlayer::m_vecVelocity[0]\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_vecBaseVelocity" can't be found, then stop the plugin.
g_iToolsBaseVelocity = FindSendPropInfo("CBasePlayer", "m_vecBaseVelocity");
if (g_iToolsBaseVelocity == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CBasePlayer::m_vecBaseVelocity\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_flLaggedMovementValue" can't be found, then stop the plugin.
g_iToolsLMV = FindSendPropInfo("CCSPlayer", "m_flLaggedMovementValue");
if (g_iToolsLMV == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CCSPlayer::m_flLaggedMovementValue\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_bHasNightVision" can't be found, then stop the plugin.
g_iToolsHasNightVision = FindSendPropInfo("CCSPlayer", "m_bHasNightVision");
if (g_iToolsHasNightVision == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CCSPlayer::m_bHasNightVision\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_bNightVisionOn" can't be found, then stop the plugin.
g_iToolsNightVisionOn = FindSendPropInfo("CCSPlayer", "m_bNightVisionOn");
if (g_iToolsNightVisionOn == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CCSPlayer::m_bNightVisionOn\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_CollisionGroup" can't be found, then stop the plugin.
g_iToolsCollisionGroup = FindSendPropInfo("CBaseEntity", "m_CollisionGroup");
if (g_iToolsCollisionGroup == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CBaseEntity::m_CollisionGroup\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_iAccount" can't be found, then stop the plugin.
g_iToolsAccount = FindSendPropInfo("CCSPlayer", "m_iAccount");
if (g_iToolsAccount == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CCSPlayer::m_iAccount\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_iDefaultFOV" can't be found, then stop the plugin.
g_iToolsDefaultFOV = FindSendPropInfo("CBasePlayer", "m_iDefaultFOV");
if (g_iToolsDefaultFOV == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CBasePlayer::m_iDefaultFOV\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_bInBuyZone" can't be found, then stop the plugin.
g_iToolsInBuyZone = FindSendPropInfo("CCSPlayer", "m_bInBuyZone");
if (g_iToolsInBuyZone == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CCSPlayer::m_bInBuyZone\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_clrRender" can't be found, then stop the plugin.
g_iToolsRender = FindSendPropInfo("CAI_BaseNPC", "m_clrRender");
if (g_iToolsRender == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CAI_BaseNPC::m_clrRender\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_nRenderMode" can't be found, then stop the plugin.
g_iToolsRenderMode = FindSendPropInfo("CBaseAnimating", "m_nRenderMode");
if (g_iToolsRenderMode == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CBaseAnimating::m_nRenderMode\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// If offset "m_hActiveWeapon" can't be found, then stop the plugin.
g_iToolsActiveWeapon = FindSendPropInfo("CBasePlayer", "m_hActiveWeapon");
if (g_iToolsActiveWeapon == -1)
{
LogMessageFormatted(-1, "Tools", "Offsets", "Offset \"CBasePlayer::m_hActiveWeapon\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
}
/**
* Sets up gamedata for the plugin.
*/
ToolsSetupGameData()
{
// Load game config file.
g_hToolsGameConfig = LoadGameConfigFile("plugin.zombiereloaded");
// If gamedata file can't be loaded, then stop the plugin.
if (g_hToolsGameConfig == INVALID_HANDLE)
{
LogMessageFormatted(-1, "Tools", "GameData", "Can't load game config file (plugin.zombiereloaded.txt) from the gamedata directory.", LOG_FORMAT_TYPE_FATALERROR);
}
// Prep the SDKCall for "EyeAngles."
StartPrepSDKCall(SDKCall_Player);
PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Virtual, "EyeAngles");
PrepSDKCall_SetReturnInfo(SDKType_QAngle, SDKPass_ByValue);
g_hToolsEyeAngles = EndPrepSDKCall();
// If offset "EyeAngles" can't be found, then stop the plugin.
if(g_hToolsEyeAngles == INVALID_HANDLE)
{
LogMessageFormatted(-1, "Tools", "GameData", "Offset \"EyeAngles\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// Prep the SDKCall for "TerminateRound."
StartPrepSDKCall(SDKCall_GameRules);
PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Signature, "TerminateRound");
PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain);
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
g_hToolsTerminateRound = EndPrepSDKCall();
// If offset "TerminateRound" can't be found, then stop the plugin.
if(g_hToolsTerminateRound == INVALID_HANDLE)
{
LogMessageFormatted(-1, "Tools", "GameData", "Signature \"CGameRules::TerminateRound\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
// Prep the SDKCall for "CSWeaponDrop."
StartPrepSDKCall(SDKCall_Player);
PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Signature, "CSWeaponDrop");
PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer);
PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain);
PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain);
g_hToolsCSWeaponDrop = EndPrepSDKCall();
// If offset "CSWeaponDrop" can't be found, then stop the plugin.
if(g_hToolsCSWeaponDrop == INVALID_HANDLE)
{
LogMessageFormatted(-1, "Tools", "GameData", "Signature \"CBasePlaye::CSWeaponDrop\" was not found.", LOG_FORMAT_TYPE_FATALERROR);
}
}

149
src/zr/tools_functions.inc Normal file
View File

@ -0,0 +1,149 @@
/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: tools_functions.inc
* Description: API for offsets/signatures exposed in tools.inc
*
* ============================================================================
*/
/**
* Get or set a client's velocity.
* @param client The client index.
* @param vecVelocity Array to store vector in, or velocity to set on client.
* @param retrieve True to get client's velocity, false to set it.
* @param stack If modifying velocity, then true will stack new velocity onto the client's
* current velocity, false will reset it.
*/
ToolsClientVelocity(client, Float:vecVelocity[3], bool:apply = true, bool:stack = true)
{
// If retrieve if true, then get client's velocity.
if (!apply)
{
// x = vector component.
for (new x = 0; x < 3; x++)
{
vecVelocity[x] = GetEntDataFloat(client, g_iToolsVelocity + (x*4));
}
// Stop here.
return;
}
// If stack is true, then add client's velocity.
if (stack)
{
// Get client's velocity.
new Float:vecClientVelocity[3];
// x = vector component.
for (new x = 0; x < 3; x++)
{
vecClientVelocity[x] = GetEntDataFloat(client, g_iToolsVelocity + (x*4));
}
AddVectors(vecClientVelocity, vecVelocity, vecVelocity);
}
// Apply velocity on client.
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vecVelocity);
}
/**
* Set a client's lagged movement value.
* @param client The client index.
* @param value LMV value. (1.0 = default, 2.0 = double)
*/
ToolsSetClientLMV(client, Float:fLMV)
{
// Set lagged movement value of client.
SetEntDataFloat(client, g_iToolsLMV, fLMV / 300.0, true);
}
/**
* Control nightvision values on a client.
* @param client The client index.
* @param enable Enable or disable an aspect of nightvision. (see ownership parameter)
* @param ownership If true, enable will toggle the client's ownership of nightvision.
* If false, enable will toggle the client's on/off state of the nightvision.
*/
ToolsClientNightVision(client, bool:enable, bool:ownership = true)
{
// If ownership is true, then toggle the ownership of nightvision on client.
if (ownership)
{
SetEntData(client, g_iToolsHasNightVision, enable, 1, true);
// Stop here.
return;
}
SetEntData(client, g_iToolsNightVisionOn, enable, 1, true);
}
/**
* Set a client's default field of vision.
* @param client The client index.
* @param FOV The field of vision of the client.
*/
ToolsSetClientDefaultFOV(client, FOV)
{
SetEntData(client, g_iToolsDefaultFOV, FOV, 1, true);
}
/**
* Get or set a client's score or deaths.
*
* @param client The client index.
* @param score True to look at score, false to look at deaths.
* @param apply True to set scores or death, false to get.
* @param value The value of the client's score or deaths.
* @return The score or death count of the client, -1 if setting.
*/
ToolsClientScore(client, bool:score = true, bool:apply = true, value = 0)
{
if (!apply)
{
if (score)
{
// If score is true, then return client's score.
return GetEntProp(client, Prop_Data, "m_iFrags");
}
// Return client's deaths.
else
{
return GetEntProp(client, Prop_Data, "m_iDeaths");
}
}
// If score is true, then set client's score.
if (score)
{
SetEntProp(client, Prop_Data, "m_iFrags", value);
}
// Set client's deaths.
else
{
SetEntProp(client, Prop_Data, "m_iDeaths", value);
}
// We set the client's score or deaths.
return -1;
}
/**
* Set a client's alpha value.
*
* @param client The client index.
* @param alpha The alpha value to set client's alpha to. (0-255)
*/
ToolsSetClientAlpha(client, alpha)
{
// Turn rendermode on, on the client.
SetEntData(client, g_iToolsRenderMode, 3, 1, true);
// Set alpha value on the client.
SetEntData(client, g_iToolsRender + 3, alpha, 1, true);
}

View File

@ -39,7 +39,7 @@ bool:ZMarketSend(client)
// Check buyzone cvar to see if client has to be in a buyzone to use. // Check buyzone cvar to see if client has to be in a buyzone to use.
new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]);
if (!IsClientInBuyZone(client) && buyzone) if (!ZMarketIsClientInBuyZone(client) && buyzone)
{ {
// Tell client they must be in a buyzone. // Tell client they must be in a buyzone.
ZR_PrintCenterText(client, "Market out of buyzone"); ZR_PrintCenterText(client, "Market out of buyzone");
@ -63,6 +63,17 @@ bool:ZMarketSend(client)
return true; return true;
} }
/**
* Checks if a client is in a buyzone.
*
* @param client The client index.
*/
bool:ZMarketIsClientInBuyZone(client)
{
// Return if client is in buyzone.
return bool:GetEntData(client, g_iToolsInBuyZone);
}
/** /**
* (Market) Forward called when a client selects a weapon from the market. * (Market) Forward called when a client selects a weapon from the market.
* *
@ -115,7 +126,7 @@ public bool:Market_OnWeaponSelected(client, String:weaponid[])
// Check if buyzone cvar is enabled, and if the client is in a buyzone. // Check if buyzone cvar is enabled, and if the client is in a buyzone.
new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]);
if (!IsClientInBuyZone(client) && buyzone) if (!ZMarketIsClientInBuyZone(client) && buyzone)
{ {
ZR_PrintCenterText(client, "Market out of buyzone"); ZR_PrintCenterText(client, "Market out of buyzone");

View File

@ -847,30 +847,30 @@ RestrictGetGroupWeapons(const String:groupname[], String:weaponlist[], maxlen, c
*/ */
public RestrictCanUse(client, weapon, dummy1, dummy2, dummy3, dummy4) public RestrictCanUse(client, weapon, dummy1, dummy2, dummy3, dummy4)
{ {
// If plugin is disabled then stop.
new bool:enabled = GetConVarBool(g_hCvarsList[CVAR_ENABLE]);
if (!enabled)
{
return Hacks_Continue;
}
new String:weaponname[WEAPONS_MAX_LENGTH]; new String:weaponname[WEAPONS_MAX_LENGTH];
GetEdictClassname(weapon, weaponname, sizeof(weaponname)); GetEdictClassname(weapon, weaponname, sizeof(weaponname));
// Strip "weapon_" from entity name. // Strip "weapon_" from entity name.
ReplaceString(weaponname, sizeof(weaponname), "weapon_", ""); ReplaceString(weaponname, sizeof(weaponname), "weapon_", "");
// If the weapon is restricted then prevent pickup. // If weapon is a knife, then allow pickup.
if (StrEqual(weaponname, "knife"))
{
return Hacks_Continue;
}
// If the weapon is restricted, then prevent pickup.
if (RestrictIsWeaponRestricted(weaponname)) if (RestrictIsWeaponRestricted(weaponname))
{ {
return 0; return 0;
} }
// If the player is a zombie and the weapon isn't a knife then prevent pickup. // If the player is a zombie, then prevent pickup.
if (InfectIsClientInfected(client) && !StrEqual(weaponname, "knife")) if (InfectIsClientInfected(client))
{ {
return 0; return 0;
} }
// Allow pickup.
return Hacks_Continue; return Hacks_Continue;
} }

View File

@ -369,5 +369,5 @@ WeaponsType:WeaponsGetDeployedWeaponSlot(client)
WeaponForceClientDrop(client, weapon) WeaponForceClientDrop(client, weapon)
{ {
// Force client to drop weapon. // Force client to drop weapon.
SDKCall(g_hCSWeaponDrop, client, weapon, true, false); SDKCall(g_hToolsCSWeaponDrop, client, weapon, true, false);
} }

View File

@ -102,7 +102,7 @@ public ZRAdminMenuHandle(Handle:menu_admin, MenuAction:action, client, slot)
{ {
if (slot == MenuCancel_ExitBack) if (slot == MenuCancel_ExitBack)
{ {
MainMenu(client); MenuMain(client);
} }
} }
else if (action == MenuAction_End) else if (action == MenuAction_End)
@ -422,7 +422,7 @@ ZRSpawnAll(client)
{ {
if (IsClientInGame(x)) if (IsClientInGame(x))
{ {
ZSpawn(x); ZSpawnClient(x);
} }
} }
ZRAdminMenu(client); ZRAdminMenu(client);

View File

@ -48,19 +48,6 @@ public Action:Command_NightVision(client, argc)
} }
} }
JumpBoost(client, Float:distance, Float:height)
{
new Float:vel[3];
GetPlayerVelocity(client, vel);
vel[0] *= distance;
vel[1] *= distance;
vel[2] *= height;
SetPlayerVelocity(client, vel, false);
}
RemoveObjectives() RemoveObjectives()
{ {
decl String:classname[64]; decl String:classname[64];

76
src/zr/zspawn.inc Normal file
View File

@ -0,0 +1,76 @@
/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: (Module) zspawn.inc
* Description: Handles zspawn command, spawns late-joining clients into the game.
*
* ============================================================================
*/
/**
* Array to block zspawn for a unique client serial number.
*/
new bool:g_bZSpawnBlock[MAXPLAYERS + 1];
/**
* Client is leaving the server.
*
* @param client The client index.
*/
ZSpawnOnClientDisconnect(client)
{
// Get client's unique serial number.
new serial = GetClientSerial(client);
// Block zspawn.
g_bZSpawnBlock[serial] = true;
}
/**
* The round is starting.
*/
ZSpawnOnRoundStart()
{
// Disable flag that blocks zspawn for all clients.
// x = client index.
for (new x = 1; x <= MaxClients; x++)
{
// Unblock zspawn.
g_bZSpawnBlock[x] = false;
}
}
ZSpawnClient(client)
{
// If zspawn is disabled, then stop.
new bool:zspawn = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN]);
if (!zspawn)
{
ZR_PrintToChat(client, "Feature is disabled");
return;
}
// If client isn't on a team, then stop.
if (!ZRIsClientOnTeam(client))
{
return;
}
// If client is alive, then stop.
if (IsPlayerAlive(client))
{
return;
}
// Block if client has already played during this round.
new serial = GetClientSerial(client);
if (g_bZSpawnBlock[serial])
{
return;
}
// Tell respawn module to respawn client.
RespawnSpawnClient(client);
}