diff --git a/cstrike/addons/sourcemod/configs/zr/hitgroups.txt b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt new file mode 100644 index 0000000..075b4cc --- /dev/null +++ b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt @@ -0,0 +1,70 @@ +// Hitgroups +// +// Format +// +// "hitgroup index" // Index of the hitgroup (listed below) +// { +// "name" "name of hitgroup" // Redundant as of now, used for readability. +// "knockback" "1.0" (default) // The knockback multiplier for the hitgroup +// } +// +// Notes: +// +// A missing config setting will be assumed to be its default value (documented above). + +"hitgroups" // Counter-Strike: Source hitgroups +{ + "0" + { + "name" "Generic" + "knockback" "1.0" + } + + "1" + { + "name" "Head" + "knockback" "2.0" + } + + "2" + { + "name" "Chest" + "knockback" "1.3" + } + + "3" + { + "name" "Stomach" + "knockback" "1.2" + } + + "4" + { + "name" "Left Arm" + "knockback" "1.0" + } + + "5" + { + "name" "Right Arm" + "knockback" "1.0" + } + + "6" + { + "name" "Left Leg" + "knockback" "0.9" + } + + "7" + { + "name" "Right Leg" + "knockback" "0.9" + } + + "10" + { + "name" "Gear" + "knockback" "1.0" + } +} diff --git a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt index 975a1f1..c642033 100644 --- a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt +++ b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt @@ -1,33 +1,48 @@ -"Games" -{ - "cstrike" - { - "Offsets" - { - "RemoveAllItems" - { - "windows" "283" - "linux" "284" - } - "EyePosition" - { - "windows" "117" - "linux" "118" - } - "EyeAngles" - { - "windows" "206" - "linux" "207" - } - } - "Signatures" - { - "TerminateRound" - { - "library" "server" - "windows" "\x83\xEC\x18\x53\x55\x8B\xD9\x8B\x4C\x24\x28\x56\x57\x33\xF6\x8D" - "linux" "@_ZN12CCSGameRules14TerminateRoundEfi" - } - } - } +"Games" +{ + "#default" + { + "#supported" + { + "game" "cstrike" + } + + "Offsets" + { + "RemoveAllItems" + { + "windows" "283" + "linux" "284" + } + + "EyePosition" + { + "windows" "117" + "linux" "118" + } + + "EyeAngles" + { + "windows" "206" + "linux" "207" + } + } + + "Signatures" + { + "TerminateRound" + { + "library" "server" + "windows" "\x83\xEC\x18\x53\x55\x8B\xD9\x8B\x4C\x24\x28\x56\x57\x33\xF6\x8D" + "linux" "@_ZN12CCSGameRules14TerminateRoundEfi" + } + + "CSWeaponDrop" + { + "library" "server" + "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x53\x55\x56\x57\x8B\xBC\x24\x40\x01\x00\x00\x32\xDB\x85\xFF\x8B\xF1\x0F" + "linux" "@_ZN9CCSPlayer12CSWeaponDropEP17CBaseCombatWeaponbb" + } + } + } } \ No newline at end of file diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index f312008..f43dd42 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -36,9 +36,15 @@ // Weapons #include "zr/weapons/weapons" +// Hitgroups +#include "zr/hitgroups" + // Knockback #include "zr/knockback" +// Spawn protect +#include "zr/spawnprotect" + #include "zr/zadmin" #include "zr/damagecontrol" #include "zr/commands" @@ -126,7 +132,8 @@ public OnMapStart() // Forward event to modules. ClassLoad(); - WeaponsOnMapStart(); + WeaponsLoad(); + HitgroupsLoad(); Anticamp_Startup(); } diff --git a/src/zr/antistick.inc b/src/zr/antistick.inc index cc45098..7071189 100644 --- a/src/zr/antistick.inc +++ b/src/zr/antistick.inc @@ -17,7 +17,7 @@ */ /** - * Handle to keep track of AntiStickTimer + * Handle to keep track of AntiStickTimer. */ new Handle:tAntiStick = INVALID_HANDLE; @@ -48,7 +48,7 @@ AntiStickReset() } /** - * Checks if a player is currently stuck within another player + * Checks if a player is currently stuck within another player. * * @param client The client index. * @return The client index of the other stuck player, -1 when @@ -61,11 +61,11 @@ AntiStickIsStuck(client) GetClientAbsOrigin(client, clientloc); - // x = client index + // x = client index. new maxplayers = GetMaxClients(); for (new x = 1; x <= maxplayers; x++) { - // Validate player is in-game, alive, and isn't the player being checked ('client') + // Validate player is in-game, alive, and isn't the player being checked. ('client') if (!IsClientInGame(x) || !IsPlayerAlive(x) || x == client) { continue; @@ -82,7 +82,7 @@ AntiStickIsStuck(client) new Float:eyeloc[3]; GetPlayerEyePosition(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:zdistance = FloatAbs(stuckloc[2] - clientloc[2]); @@ -107,13 +107,13 @@ public Action:AntiStickTimer(Handle:timer) new maxplayers = GetMaxClients(); for (new x = 1; x <= maxplayers; x++) { - // Validate player is in-game and alive + // Validate player is in-game and alive. if (!IsClientInGame(x) || !IsPlayerAlive(x)) { continue; } - // Stop if the player isn't stuck + // Stop if the player isn't stuck. new stuckindex = AntiStickIsStuck(x); if (stuckindex == -1) { @@ -138,23 +138,24 @@ public Action:AntiStickTimer(Handle:timer) * Repeated timer function. * Re-solidifies a player being unstuck. * - * @param index The client index. + * @param timer The timer handle. + * @param client The client index. */ -public Action:AntiStickSolidify(Handle:timer, any:index) +public Action:AntiStickSolidify(Handle:timer, any:client) { - // Validate player is in-game, alive, and is being unstuck - if (!IsClientInGame(index) || !IsPlayerAlive(index) || CanCollide(index)) + // Validate player is in-game, alive, and is being unstuck. + if (!IsClientInGame(client) || !IsPlayerAlive(client) || CanCollide(client)) { return Plugin_Stop; } - // Stop if the player is still stuck - if (AntiStickIsStuck(index) > -1) + // Stop if the player is still stuck. + if (AntiStickIsStuck(client) > -1) { return Plugin_Continue; } - NoCollide(index, false); + NoCollide(client, false); return Plugin_Stop; } diff --git a/src/zr/event.inc b/src/zr/event.inc index f66ae22..9936754 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -169,6 +169,7 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) SetPlayerFOV(index, 90); ClientCommand(index, "r_screenoverlay \"\""); + // Stop here if client isn't on a team. new team = GetClientTeam(index); if (team != CS_TEAM_T && team != CS_TEAM_CT) { @@ -186,7 +187,6 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) NightVisionOn(index, false); NightVision(index, false); - pProtect[index] = false; if (zombieSpawned) { if (team == CS_TEAM_T) @@ -194,34 +194,6 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) CS_SwitchTeam(index, CS_TEAM_CT); CS_RespawnPlayer(index); } - - new protect = GetConVarInt(gCvars[CVAR_PROTECT]); - if (protect > 0) - { - decl String:respawnteam[32]; - GetConVarString(gCvars[CVAR_RESPAWN_TEAM], respawnteam, sizeof(respawnteam)); - - if (!StrEqual(respawnteam, "zombie", false) && !(GetConVarBool(gCvars[CVAR_SUICIDE_WORLD_DAMAGE]) && gKilledByWorld[index])) - { - SetPlayerAlpha(index, 0); - SetPlayerSpeed(index, 600.0); - pProtect[index] = true; - - ZR_PrintToChat(index, "Spawn protection begin", protect); - ZR_PrintCenterText(index, "Spawn protection begin", protect); - - if (tHandles[index][TPROTECT] != INVALID_HANDLE) - { - KillTimer(tHandles[index][TPROTECT]); - } - - pTimeLeft[index] = protect; - - PrintHintText(index, "%d", pTimeLeft[index]); - - tHandles[index][TPROTECT] = CreateTimer(1.0, ProtectTimer, index, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); - } - } } else { @@ -230,6 +202,7 @@ public Action:PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) // Forward event to modules. ClassOnClientSpawn(index); + SpawnProtectPlayerSpawn(index); ZTeleClientSpawned(index); ZR_PrintToChat(index, "!zmenu reminder"); @@ -240,13 +213,15 @@ public Action:PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) 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)); // Forward event to modules. - KnockbackPlayerHurt(index, attacker, weapon, dmg_health); + KnockbackPlayerHurt(index, attacker, weapon, hitgroup, dmg_health); // Check if the attacker is a player. if (attacker != 0) diff --git a/src/zr/hitgroups.inc b/src/zr/hitgroups.inc new file mode 100644 index 0000000..54d1e98 --- /dev/null +++ b/src/zr/hitgroups.inc @@ -0,0 +1,118 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: hitgroup.inc + * Description: API for loading hitgroup specific settings. + * Author: Greyscale, Richard Helgeby + * + * ============================================================================ + */ + +/** + * Array to store keyvalue data. + */ +new Handle:kvHitgroups = INVALID_HANDLE; + +/** + * @section Player hitgroup values. + */ +#define HITGROUP_GENERIC 0 +#define HITGROUP_HEAD 1 +#define HITGROUP_CHEST 2 +#define HITGROUP_STOMACH 3 +#define HITGROUP_LEFTARM 4 +#define HITGROUP_RIGHTARM 5 +#define HITGROUP_LEFTLEG 6 +#define HITGROUP_RIGHTLEG 7 +#define HITGROUP_GEAR 10 +/** + * @endsection + */ + +/** + * Clears hitgroup data. + */ +HitgroupsClearData() +{ + // Load hitgroup data. + if (kvHitgroups != INVALID_HANDLE) + { + CloseHandle(kvHitgroups); + } + + kvHitgroups = CreateKeyValues("hitgroups"); +} + +/** + * Loads hitgroup data from file. + */ +HitgroupsLoad() +{ + // Clear hitgroup data + HitgroupsClearData(); + + decl String:path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "configs/zr/hitgroups.txt"); + + // If file isn't found, stop plugin. + if (!FileToKeyValues(kvHitgroups, path)) + { + if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_HITGROUPS)) + { + ZR_LogMessageFormatted(-1, "Hitgroups", "Config Validation", "Missing file hitgroups.txt, disabling hitgroup-based modules.", LOG_FORMAT_TYPE_FULL); + } + + return; + } + + // Validate hitgroups config. + HitgroupsValidateConfig(); +} + +/** + * Validate hitgroup config file and settings. + */ +HitgroupsValidateConfig() +{ + // If log flag check fails, don't log. + if (!LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_HITGROUPS)) + { + return; + } + + KvRewind(kvHitgroups); + if (!KvGotoFirstSubKey(kvHitgroups)) + { + ZR_LogMessageFormatted(-1, "Hitgroups", "Config Validation", "No hitgroups listed in hitgroups.txt, disabling hitgroup-based modules.", LOG_FORMAT_TYPE_FULL); + } +} + +/** + * Retrieve hitgroup knockback value. + * + * @param hitgroup The hitgroup index. + */ +Float:HitgroupsGetHitgroupKnockback(hitgroup) +{ + // Reset keyvalue's traversal stack. + KvRewind(kvHitgroups); + if (KvGotoFirstSubKey(kvHitgroups)) + { + decl String:sHitgroup[4]; + + do + { + KvGetSectionName(kvHitgroups, sHitgroup, sizeof(sHitgroup)); + + // If this is the right hitgroup, then return knockback for it. + if (hitgroup == StringToInt(sHitgroup)) + { + return KvGetFloat(kvHitgroups, "knockback", 1.0); + } + } while (KvGotoNextKey(kvHitgroups)); + } + + return 1.0; +} \ No newline at end of file diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index aebf089..240d296 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -5,30 +5,16 @@ * Author: Greyscale * ==================== */ - -/** - * @section Player hitgroup values. - */ -#define HITGROUP_GENERIC 0 -#define HITGROUP_HEAD 1 -#define HITGROUP_CHEST 2 -#define HITGROUP_STOMACH 3 -#define HITGROUP_LEFTARM 4 -#define HITGROUP_RIGHTARM 5 -#define HITGROUP_LEFTLEG 6 -#define HITGROUP_RIGHTLEG 7 -#define HITGROUP_GEAR 10 -/** - * @endsection - */ -/** Player hurt event +/** Player hurt event. + * * @param client The victim index. (zombie) * @param attacker The attacker index. (human) * @param weapon The weapon used. + * @param hitgroup Hitgroup attacker has damaged. * @param dmg_health Damage done. */ -KnockbackPlayerHurt(client, attacker, const String:weapon[], dmg_health) +KnockbackPlayerHurt(client, attacker, const String:weapon[], hitgroup, dmg_health) { // Check if the attacker is a player. if (attacker != 0) @@ -68,14 +54,14 @@ KnockbackPlayerHurt(client, attacker, const String:weapon[], dmg_health) TR_GetEndPosition(clientloc); } - // Apply damage knockback multiplier - knockback *= float(dmg_health); - // Retrieve weapon knockback boost. new Float:boostWeapon = WeaponGetWeaponKnockback(weapon); - // Apply weapon knockback multiplier. - knockback *= boostWeapon; + // Retrieve hitgroup knockback boost. + new Float:boostHitgroup = HitgroupsGetHitgroupKnockback(hitgroup); + + // Apply all knockback multipliers. + knockback *= float(dmg_health) * boostWeapon * boostHitgroup; // Apply knockback. KnockbackSetVelocity(client, attackerloc, clientloc, knockback); @@ -85,6 +71,7 @@ KnockbackPlayerHurt(client, attacker, const String:weapon[], dmg_health) /** * Sets velocity on a player. + * * @param client The client index. * @param startpoint The starting coordinate to push from. * @param endpoint The ending coordinate to push towards. @@ -108,6 +95,7 @@ KnockbackSetVelocity(client, const Float:startpoint[3], const Float:endpoint[3], /** * Trace Ray forward, used as a filter to continue tracing if told so. (See sdktools_trace.inc) + * * @param entity The entity index. * @param contentsMask The contents mask. * @return True to allow hit, false to continue tracing. @@ -126,6 +114,7 @@ public bool:KnockbackTRFilter(entity, contentsMask) /** * Find the location of an exploding grenade (currently inflicting damage in player_hurt). + * * @param heLoc The location of the exploding grenade. * @return The entity index of the grenade. */ diff --git a/src/zr/models.inc b/src/zr/models.inc index 26d0d58..5d06222 100644 --- a/src/zr/models.inc +++ b/src/zr/models.inc @@ -115,25 +115,3 @@ LoadDownloadData() CloseHandle(fileDownloads); CloseHandle(arrayDownloads); } - -/*ApplyZombieModel(client) -{ - decl String:modelpath[256]; - - new bool:classes = GetConVarBool(gCvars[CVAR_CLASSES]); - if (classes) - { - GetClassModel(pClass[client], modelpath, sizeof(modelpath)); - if (!StrEqual(modelpath, "default", false)) - { - SetPlayerModel(client, modelpath); - return; - } - } - - new randmodel = GetRandomInt(0, GetArraySize(arrayModels) - 1); - GetArrayString(arrayModels, randmodel, modelpath, sizeof(modelpath)); - Format(modelpath, sizeof(modelpath), "%s.mdl", modelpath); - - SetPlayerModel(client, modelpath); -}*/ diff --git a/src/zr/offsets.inc b/src/zr/offsets.inc index 7add0bb..3576d95 100644 --- a/src/zr/offsets.inc +++ b/src/zr/offsets.inc @@ -21,9 +21,10 @@ new offsRender; new Handle:g_hGameConf = INVALID_HANDLE; new Handle:g_hRemoveAllItems = INVALID_HANDLE; -new Handle:g_hTerminateRound = INVALID_HANDLE; new Handle:g_hEyePosition = INVALID_HANDLE; new Handle:g_hEyeAngles = INVALID_HANDLE; +new Handle:g_hTerminateRound = INVALID_HANDLE; +new Handle:g_hCSWeaponDrop = INVALID_HANDLE; FindOffsets() { @@ -100,27 +101,61 @@ FindOffsets() 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); g_hEyePosition = EndPrepSDKCall(); + if(g_hEyePosition == INVALID_HANDLE) + { + SetFailState("Couldn't find offset \"EyePosition\"!"); + } + StartPrepSDKCall(SDKCall_Player); PrepSDKCall_SetFromConf(g_hGameConf, SDKConf_Virtual, "EyeAngles"); PrepSDKCall_SetReturnInfo(SDKType_QAngle, SDKPass_ByValue); g_hEyeAngles = EndPrepSDKCall(); + if(g_hEyeAngles == INVALID_HANDLE) + { + SetFailState("Couldn't find offset \"EyeAngles\"!"); + } + StartPrepSDKCall(SDKCall_GameRules); PrepSDKCall_SetFromConf(g_hGameConf, SDKConf_Signature, "TerminateRound"); PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); g_hTerminateRound = EndPrepSDKCall(); + + if(g_hTerminateRound == INVALID_HANDLE) + { + SetFailState("Couldn't find signature \"CGameRules::TerminateRound\"!"); + } + + StartPrepSDKCall(SDKCall_Player); + PrepSDKCall_SetFromConf(g_hGameConf, SDKConf_Signature, "CSWeaponDrop"); + PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); + PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); + PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); + g_hCSWeaponDrop = EndPrepSDKCall(); + + if(g_hCSWeaponDrop == INVALID_HANDLE) + { + SetFailState("Couldn't find signature \"CBasePlayer::CSWeaponDrop\"!"); + } } SetPlayerVelocity(client, const Float:vec[3], bool:reset) @@ -231,13 +266,12 @@ GetPlayerEyeAngles(client, Float:ang[3]) TerminateRound(Float:delay, reason) { - if (g_hTerminateRound == INVALID_HANDLE) return; SDKCall(g_hTerminateRound, delay, reason); } -SetPlayerModel(client, const String:model[]) +CSDropWeapon(client, weapon) { - SetEntityModel(client, model); + SDKCall(g_hCSWeaponDrop, client, weapon, true, false); } SetPlayerAlpha(client, alpha) diff --git a/src/zr/playerclasses/apply.inc b/src/zr/playerclasses/apply.inc index 6a9a3b3..d4f73db 100644 --- a/src/zr/playerclasses/apply.inc +++ b/src/zr/playerclasses/apply.inc @@ -77,7 +77,7 @@ bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) // TODO: Add support for keeping the default cs model ("default"). - SetPlayerModel(client, modelpath); + SetEntityModel(client, modelpath); return true; } diff --git a/src/zr/spawnprotect.inc b/src/zr/spawnprotect.inc new file mode 100644 index 0000000..376ea88 --- /dev/null +++ b/src/zr/spawnprotect.inc @@ -0,0 +1,145 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: spawnprotect.inc + * Description: Protects late-joining players from zombies for x seconds. + * + * ============================================================================ + */ + +/** + * Array for storing spawn protect timer handles per client. + */ +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. + */ +new pSpawnProtectTime[MAXPLAYERS + 1]; + +/** + * Client is joining the server. + * + * @param client The client index. + */ +SpawnProtectClientInit(client) +{ + tSpawnProtect[client] = INVALID_HANDLE; +} + +/** + * Player is spawning into the game. + * + * @param client The client index. + */ +SpawnProtectPlayerSpawn(client) +{ + // Disable spawn protection on client. + pSpawnProtect[client] = false; + + // If zombie hasn't spawned, then stop. + if (!zombieSpawned) + { + return; + } + + // If protect cvar is invalid or 0, then stop. + new protect = GetConVarInt(gCvars[CVAR_PROTECT]); + if (protect <= 0) + { + return; + } + + // Get respawn team. + decl String:respawnteam[32]; + GetConVarString(gCvars[CVAR_RESPAWN_TEAM], respawnteam, sizeof(respawnteam)); + + // If the respawn team is not set to zombie, and either cvar zr_suicide_world_damage or the client + // wasn't killed by world is false, then continue to protect client. + if (!StrEqual(respawnteam, "zombie", false) && !(GetConVarBool(gCvars[CVAR_SUICIDE_WORLD_DAMAGE]) && gKilledByWorld[client])) + { + // Set spawn protect flag on client. + pSpawnProtect[client] = true; + + // Set improved attributes + // (Move to cvar?) + SetPlayerAlpha(client, 0); + SetPlayerSpeed(client, 600.0); + + // Set time left to zr_protect's value. + pSpawnProtectTime[client] = protect; + + // Tell client they are being protected. + ZR_PrintToChat(client, "Spawn protection begin", protect); + + // Send time left in a hud message. + ZR_HudHint(client, "Spawn Protect", pSpawnProtectTime[client]); + + // If timer is currently running, kill it. + if (tSpawnProtect[client] != INVALID_HANDLE) + { + KillTimer(tSpawnProtect[client]); + } + + // Start repeating timer. + tSpawnProtect[client] = CreateTimer(1.0, SpawnProtectTimer, client, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); + } +} + +/** + * Timer callback function, countdown for spawn protection. + * + * @param timer The timer handle. + * @param client The client index. + */ +public Action:SpawnProtectTimer(Handle:timer, any:client) +{ + // If client leaves, then stop timer. + if (!IsClientInGame(client)) + { + return Plugin_Stop; + } + + // If client has become a zombie, then stop timer. + if (!IsPlayerHuman(client)) + { + return Plugin_Stop; + } + + // Decrement time left. + pSpawnProtectTime[client]--; + + // Print time left to client. + ZR_HudHint(client, "Spawn Protect", pSpawnProtectTime[client]); + + // Time has expired. + if (pSpawnProtectTime[client] <= 0) + { + // Remove protect flag. + pSpawnProtect[client] = false; + + // Tell client spawn protection is over. + ZR_HudHint(client, "Spawn protection end"); + + // Fix attributes. + // TODO: Set class attributes. + SetPlayerAlpha(client, 255); + SetPlayerSpeed(client, 300.0); + + // Clear timer handle. + tSpawnProtect[client] = INVALID_HANDLE; + + // Stop timer. + return Plugin_Stop; + } + + // Allow timer to continue repeating. + return Plugin_Continue; +} \ No newline at end of file diff --git a/src/zr/weapons/markethandler.inc b/src/zr/weapons/markethandler.inc index 5245783..a30ec15 100644 --- a/src/zr/weapons/markethandler.inc +++ b/src/zr/weapons/markethandler.inc @@ -15,13 +15,13 @@ */ public bool:Market_OnWeaponSelected(client, String:weaponid[]) { - // If player is dead or weaponid is invalid, then stop + // If player is dead or weaponid is invalid, then stop. if (!weaponid[0] || !IsPlayerAlive(client)) { return false; } - // If player is a zombie, then stop + // If player is a zombie, then stop. if (IsPlayerZombie(client)) { ZR_PrintToChat(client, "Zombie cant use weapon"); @@ -29,7 +29,7 @@ public bool:Market_OnWeaponSelected(client, String:weaponid[]) return false; } - // If player is using the rebuy option then allow + // If player is using the rebuy option then allow. if (StrEqual(weaponid, "rebuy")) { return true; @@ -39,16 +39,16 @@ public bool:Market_OnWeaponSelected(client, String:weaponid[]) decl String:weapon[WEAPONS_MAX_LENGTH]; new price; - // If the market plugin can't find info about the weapon, then stop + // If the market plugin can't find info about the weapon, then stop. if (!Market_GetWeaponIDInfo(weaponid, display, weapon, price)) { return false; } - // Strip "weapon_" from entity name + // Strip "weapon_" from entity name. ReplaceString(weapon, sizeof(weapon), "weapon_", ""); - // If the weapon is restricted, then stop + // If the weapon is restricted, then stop. if (RestrictIsWeaponRestricted(weapon)) { ZR_PrintToChat(client, "Weapon is restricted", weapon); @@ -56,7 +56,7 @@ public bool:Market_OnWeaponSelected(client, String:weaponid[]) return false; } - // 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(gCvars[CVAR_ZMARKET_BUYZONE]); if (!IsClientInBuyZone(client) && buyzone) { @@ -76,12 +76,12 @@ public bool:Market_OnWeaponSelected(client, String:weaponid[]) */ public Market_PostOnWeaponSelected(client, &bool:allowed) { - // If the purchase wasn't allowed, then stop + // If the purchase wasn't allowed, then stop. if (!allowed) { return; } - // Resend market menu + // Resend market menu. ZMarket(client); } \ No newline at end of file diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index cf7f2ac..b431f5e 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -16,12 +16,12 @@ enum WeaponsMenu } /** - * Array to store the client's current weapon menu + * Array to store the client's current weapon menu. */ new WeaponsMenu:curMenuWeapons[MAXPLAYERS + 1]; /** - * Array to store the client's current weapon group menu + * Array to store the client's current weapon group menu. */ new String:curMenuGroup[WEAPONS_MAX_LENGTH][MAXPLAYERS + 1]; @@ -31,7 +31,7 @@ new String:curMenuGroup[WEAPONS_MAX_LENGTH][MAXPLAYERS + 1]; */ WeaponsMenuMain(client) { - // Create menu handle + // Create menu handle. new Handle:menu_weapons_main = CreateMenu(WeaponsMenuMainHandle); SetGlobalTransTarget(client); @@ -49,7 +49,7 @@ WeaponsMenuMain(client) AddMenuItem(menu_weapons_main, "toggleweaponrestriction", toggleweaponrestriction); AddMenuItem(menu_weapons_main, "togglewgrouprestriction", togglewgrouprestriction); - // Disable market option if market isn't installed + // Disable market option if market isn't installed. if (market) { AddMenuItem(menu_weapons_main, "zmarket", zmarket); @@ -59,10 +59,10 @@ WeaponsMenuMain(client) AddMenuItem(menu_weapons_main, "zmarket", zmarket, ITEMDRAW_DISABLED); } - // Create a "Back" button to the weapons main menu + // Create a "Back" button to the weapons main menu. SetMenuExitBackButton(menu_weapons_main, true); - // Send menu + // Send menu. DisplayMenu(menu_weapons_main, client, MENU_TIME_FOREVER); } @@ -75,7 +75,7 @@ WeaponsMenuMain(client) */ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client, slot) { - // Client selected an option + // Client selected an option. if (action == MenuAction_Select) { switch(slot) @@ -94,16 +94,16 @@ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client } } } - // Client closed the menu + // Client closed the menu. if (action == MenuAction_Cancel) { - // Client hit "Back" button + // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { ZRAdminMenu(client); } } - // Client hit "Exit" button + // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_weapons_main); @@ -116,15 +116,15 @@ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client */ WeaponsMenuWeapons(client, WeaponsMenu:type) { - // Set the current action client is performing on a weapon (see enum WeaponsMenu) + // Set the current action client is performing on a weapon. (see enum WeaponsMenu) curMenuWeapons[client] = type; - // Create menu handle + // Create menu handle. new Handle:menu_weapons_weapons = CreateMenu(WeaponsMenuWeaponsHandle); SetGlobalTransTarget(client); - // If client wants to perform an action on a single weapon, show weapon list + // If client wants to perform an action on a single weapon, show weapon list. switch(curMenuWeapons[client]) { case Weapon: @@ -136,7 +136,7 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) new Handle:arrayWeapons = INVALID_HANDLE; new size = WeaponsCreateWeaponArray(arrayWeapons); - // x = Array index + // x = Array index. for (new x = 0; x < size; x++) { GetArrayString(arrayWeapons, x, weapon, sizeof(weapon)); @@ -148,7 +148,7 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) Format(display, sizeof(display), "%s*", weapon); } - // If weapon restriction is blocked for the menu, disable option + // If weapon restriction is blocked for the menu, disable option. new bool:menu = WeaponsIsWeaponMenu(weapon); if (menu) @@ -161,7 +161,7 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) } } - // If there are no weapons, add an "(Empty)" line + // If there are no weapons, add an "(Empty)" line. if (size == 0) { decl String:empty[64]; @@ -170,10 +170,10 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) AddMenuItem(menu_weapons_weapons, "empty", empty, ITEMDRAW_DISABLED); } - // Kill the array handle + // Kill the array handle. CloseHandle(arrayWeapons); } - // If client wants to perform an action on a weapon group, show custom group list + // If client wants to perform an action on a weapon group, show custom group list. case WeaponGroup: { SetMenuTitle(menu_weapons_weapons, "%t\n ", "Weapons menu weapons group title"); @@ -183,7 +183,7 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) new Handle:arrayWeaponGroups = INVALID_HANDLE; new size = RestrictCreateGroupArray(arrayWeaponGroups); - // x = Array index + // x = Array index. for (new x = 0; x < size; x++) { GetArrayString(arrayWeaponGroups, x, weapongroup, sizeof(weapongroup)); @@ -202,7 +202,7 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) AddMenuItem(menu_weapons_weapons, weapongroup, display); } - // If there are no weapons, add an "(Empty)" line + // If there are no weapons, add an "(Empty)" line. if (size == 0) { decl String:empty[64]; @@ -230,7 +230,7 @@ WeaponsMenuWeapons(client, WeaponsMenu:type) */ public WeaponsMenuWeaponsHandle(Handle:menu_weapons_weapons, MenuAction:action, client, slot) { - // Client selected an option + // Client selected an option. if (action == MenuAction_Select) { decl String:weapon[WEAPONS_MAX_LENGTH]; @@ -238,7 +238,7 @@ public WeaponsMenuWeaponsHandle(Handle:menu_weapons_weapons, MenuAction:action, switch(curMenuWeapons[client]) { - // Client is restricting a single weapon + // Client is restricting a single weapon. case Weapon: { new WpnRestrictQuery:output; @@ -254,27 +254,27 @@ public WeaponsMenuWeaponsHandle(Handle:menu_weapons_weapons, MenuAction:action, RestrictPrintUnrestrictOutput(client, output, weapon, false); } - // Resend menu + // Resend menu. WeaponsMenuWeapons(client, curMenuWeapons[client]); } - // Client is accessing a weapon group + // Client is accessing a weapon group. case WeaponGroup: { - // Send weapon group menu + // Send weapon group menu. WeaponsMenuWeaponGroup(client, weapon); } } } - // Client closed the menu + // Client closed the menu. if (action == MenuAction_Cancel) { - // Client hit "Back" button + // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { WeaponsMenuMain(client); } } - // Client hit "Exit" button + // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_weapons_weapons); @@ -285,7 +285,7 @@ WeaponsMenuWeaponGroup(client, const String:weapongroup[]) { strcopy(curMenuGroup[client], WEAPONS_MAX_LENGTH, weapongroup); - // Create menu handle + // Create menu handle. new Handle:menu_weapons_groupweapon = CreateMenu(WeaponsMenuWeaponGroupHandle); SetMenuTitle(menu_weapons_groupweapon, "%t\n ", "Weapons menu weapon group title", weapongroup); @@ -319,7 +319,7 @@ WeaponsMenuWeaponGroup(client, const String:weapongroup[]) new Handle:arrayGroupWeapons = INVALID_HANDLE; new size = RestrictCreateGroupWeaponsArray(arrayGroupWeapons, weapongroup); - // x = Array index + // x = Array index. for (new x = 0; x < size; x++) { GetArrayString(arrayGroupWeapons, x, groupweapon, sizeof(groupweapon)); @@ -334,7 +334,7 @@ WeaponsMenuWeaponGroup(client, const String:weapongroup[]) AddMenuItem(menu_weapons_groupweapon, groupweapon, display); } - // Kill the array handle + // Kill the array handle. CloseHandle(arrayGroupWeapons); SetMenuExitBackButton(menu_weapons_groupweapon, true); @@ -351,7 +351,7 @@ WeaponsMenuWeaponGroup(client, const String:weapongroup[]) */ public WeaponsMenuWeaponGroupHandle(Handle:menu_weapons_groupweapon, MenuAction:action, client, slot) { - // Client selected an option + // Client selected an option. if (action == MenuAction_Select) { switch(slot) @@ -387,19 +387,19 @@ public WeaponsMenuWeaponGroupHandle(Handle:menu_weapons_groupweapon, MenuAction: } } - // Resend menu + // Resend menu. WeaponsMenuWeaponGroup(client, curMenuGroup[client]); } - // Client closed the menu + // Client closed the menu. if (action == MenuAction_Cancel) { - // Client hit "Back" button + // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { WeaponsMenuWeapons(client, curMenuWeapons[client]); } } - // Client hit "Exit" button + // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_weapons_groupweapon); @@ -412,7 +412,7 @@ public WeaponsMenuWeaponGroupHandle(Handle:menu_weapons_groupweapon, MenuAction: */ WeaponsMenuMarket(client) { - // Create menu handle + // Create menu handle. new Handle:menu_weapons_market = CreateMenu(WeaponsMenuMarketHandle); SetGlobalTransTarget(client); @@ -428,7 +428,7 @@ WeaponsMenuMarket(client) AddMenuItem(menu_weapons_market, "togglebuyzone", togglebuyzone); - // Create a "Back" button to the weapons main menu + // Create a "Back" button to the weapons main menu. SetMenuExitBackButton(menu_weapons_market, true); // Send menu @@ -444,7 +444,7 @@ WeaponsMenuMarket(client) */ public WeaponsMenuMarketHandle(Handle:menu_weapons_market, MenuAction:action, client, slot) { - // Client selected an option + // Client selected an option. if (action == MenuAction_Select) { switch(slot) @@ -462,19 +462,19 @@ public WeaponsMenuMarketHandle(Handle:menu_weapons_market, MenuAction:action, cl } } - // Resend menu + // Resend menu. WeaponsMenuMarket(client); } - // Client closed the menu + // Client closed the menu. if (action == MenuAction_Cancel) { - // Client hit "Back" button + // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { WeaponsMenuMain(client); } } - // Client hit "Exit" button + // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_weapons_market); diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index 2304120..db05086 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -38,22 +38,22 @@ enum WpnRestrictQuery */ RestrictInit() { - // Initialize weapon restrict array + // Initialize weapon restrict array. gRestrictedWeapons = CreateArray(32, 0); - // Hook buy command + // Hook buy command. RegConsoleCmd("buy", RestrictBuyHook); } /** - * Clears weapon restrict data + * Clears weapon restrict data. */ RestrictClearData() { - // Clear restricted weapons + // Clear restricted weapons. RestrictWeaponUnrestrictAll(); - // Load weapon group data + // Load weapon group data. if (kvWeaponGroups != INVALID_HANDLE) { CloseHandle(kvWeaponGroups); @@ -67,13 +67,13 @@ RestrictClearData() */ RestrictOnMapStart() { - // Restrict default restrictions (set in weapons.txt) + // Restrict default restrictions. (set in weapons.txt) RestrictDefaultRestrictions(); decl String:path[PLATFORM_MAX_PATH]; BuildPath(Path_SM, path, sizeof(path), "configs/zr/weapons/weapongroups.txt"); - // If file isn't found, stop plugin + // If file isn't found, stop plugin. if (!FileToKeyValues(kvWeaponGroups, path)) { if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) @@ -88,7 +88,7 @@ RestrictOnMapStart() } /** - * Restrict default restrictions (set in weapons.txt) + * Restrict default restrictions. (set in weapons.txt) */ RestrictDefaultRestrictions() { @@ -103,7 +103,7 @@ RestrictDefaultRestrictions() { KvGetSectionName(kvWeapons, weapon, sizeof(weapon)); - // If weapon is defaulted to restricted, then restrict weapon + // If weapon is defaulted to restricted, then restrict weapon. decl String:restrict[8]; KvGetString(kvWeapons, "restrict", restrict, sizeof(restrict), "no"); @@ -113,7 +113,7 @@ RestrictDefaultRestrictions() RestrictPrintRestrictOutput(0, output, display, true); // Function calls above screwed with the keyvalue stack, so we have to set it back - // to where it was before those calls + // to where it was before those calls. KvRewind(kvWeapons); KvJumpToKey(kvWeapons, weapon); } @@ -126,14 +126,16 @@ RestrictDefaultRestrictions() */ RestrictValidateWeaponGroups() { - // If log flag check fails, don't log + // If log flag check fails, don't log. if (!LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) { return; } + // Reset keygroup's traversal stack. KvRewind(kvWeaponGroups); + // Traverse into the keygroup. (weapon groups level) if (KvGotoFirstSubKey(kvWeaponGroups)) { decl String:weapongroup[WEAPONS_MAX_LENGTH]; @@ -143,12 +145,14 @@ RestrictValidateWeaponGroups() { KvGetSectionName(kvWeaponGroups, weapongroup, sizeof(weapongroup)); + // Traverse into the keygroup. (weapons level) if (KvGotoFirstSubKey(kvWeaponGroups)) { do { KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); + // If weapon is invalid, then log it. if (!WeaponsIsValidWeapon(groupweapon)) { ZR_LogMessageFormatted(-1, "Weapon Restrict", "Config Validation", "Invalid weapon \"%s\" in group \"%s\" configured in weapongroups.txt.", LOG_FORMAT_TYPE_ERROR, groupweapon, weapongroup); @@ -157,6 +161,7 @@ RestrictValidateWeaponGroups() KvGoBack(kvWeaponGroups); } + // If it couldn't traverse to the weapons, then log no weapons within group. else { ZR_LogMessageFormatted(-1, "Weapon Restrict", "Config Validation", "No weapons listed in weapon group \"%s\" in weapongroups.txt.", LOG_FORMAT_TYPE_ERROR, weapongroup); @@ -174,7 +179,7 @@ RestrictWeaponUnrestrictAll() } /** - * Hook Weapon_CanUse function on a client. + * Client is joining the server. * * @param client The client index. */ @@ -202,15 +207,15 @@ RestrictOnClientDisconnect(client) */ public Action:RestrictBuyHook(client, argc) { - // If plugin is disabled then stop + // If plugin is disabled then stop. new bool:enabled = GetConVarBool(gCvars[CVAR_ENABLE]); if (!enabled) { - // Allow command + // Allow command. return Plugin_Continue; } - // If player is a zombie then block command + // If player is a zombie then block command. if (IsPlayerZombie(client)) { ZR_PrintToChat(client, "Zombie cant use weapon"); @@ -224,16 +229,16 @@ public Action:RestrictBuyHook(client, argc) ReplaceString(weapon, sizeof(weapon), "weapon_", ""); - // Check if the weapon is restricted, if so then block command + // Check if the weapon is restricted, if so then block command. if (RestrictIsWeaponRestricted(weapon)) { ZR_PrintToChat(client, "Weapon is restricted", weapon); - // Block command + // Block command. return Plugin_Handled; } - // Allow command + // Allow command. return Plugin_Continue; } @@ -251,18 +256,23 @@ public Action:RestrictBuyHook(client, argc) */ WpnRestrictQuery:RestrictRestrict(const String:weapon[], String:display[] = "") { + // Check if weapon is a custom group name. if (RestrictIsWeaponGroup(weapon)) { + // Return restrict failed if group is already restricted. if (RestrictIsGroupRestricted(weapon)) { return Failed_Group; } + // Jump to weapon group key. KvRewind(kvWeaponGroups); KvJumpToKey(kvWeaponGroups, weapon); + // Get display name of the weapon group. KvGetSectionName(kvWeaponGroups, display, WEAPONS_MAX_LENGTH); + // Traverse into the group's weapons. if (KvGotoFirstSubKey(kvWeaponGroups)) { decl String:groupweapon[WEAPONS_MAX_LENGTH]; @@ -271,12 +281,13 @@ WpnRestrictQuery:RestrictRestrict(const String:weapon[], String:display[] = "") { KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); - // If weapon is invalid, then skip + // If weapon is invalid, then skip. if (!WeaponsIsValidWeapon(groupweapon)) { continue; } + // Add to restricted weapon array if not already restricted. if (!RestrictIsWeaponRestricted(groupweapon)) { PushArrayString(gRestrictedWeapons, groupweapon); @@ -284,23 +295,29 @@ WpnRestrictQuery:RestrictRestrict(const String:weapon[], String:display[] = "") } while (KvGotoNextKey(kvWeaponGroups)); } + // Successfully restricted a group return Successful_Group; } + // If weapon name is invalid then set display to invalid weapon name. if (!WeaponsIsValidWeapon(weapon)) { strcopy(display, WEAPONS_MAX_LENGTH, weapon); + // Weapon name was invalid. return Invalid; } + // Get display name of the weapon. WeaponGetDisplayName(weapon, display); + // Return restrict failed if weapon is already restricted. if (RestrictIsWeaponRestricted(weapon)) { return Failed_Weapon; } + // Add to restricted weapon array. PushArrayString(gRestrictedWeapons, display); return Successful_Weapon; @@ -310,8 +327,8 @@ WpnRestrictQuery:RestrictRestrict(const String:weapon[], String:display[] = "") * Unrestricts a weapon. * * @param weapon The weapon/group name. - * @param display String set to the name set in weapons.txt - * Set to the value of 'weapon' if invalid + * @param display String set to the name set in weapons.txt. + * Set to the value of 'weapon' if invalid. * @return Successful_Weapon: The call successfully restricted a weapon. * Successful_Group: The call successfully restricted a weapon group. * Failed_Weapon: The call failed to restrict a weapon. @@ -320,18 +337,23 @@ WpnRestrictQuery:RestrictRestrict(const String:weapon[], String:display[] = "") */ WpnRestrictQuery:RestrictUnrestrict(const String:weapon[], String:display[] = "") { + // Check if weapon is a custom group name. if (RestrictIsWeaponGroup(weapon)) { + // Return restrict failed if group isn't restricted. if (RestrictIsGroupUnrestricted(weapon)) { return Failed_Group; } + // Jump to weapon group key. KvRewind(kvWeaponGroups); KvJumpToKey(kvWeaponGroups, weapon); + // Get display name of the weapon group. KvGetSectionName(kvWeaponGroups, display, WEAPONS_MAX_LENGTH); + // Traverse into the group's weapons. if (KvGotoFirstSubKey(kvWeaponGroups)) { decl String:groupweapon[WEAPONS_MAX_LENGTH]; @@ -346,8 +368,10 @@ WpnRestrictQuery:RestrictUnrestrict(const String:weapon[], String:display[] = "" continue; } + // Remove from restricted weapon array if currently restricted. if (RestrictIsWeaponRestricted(groupweapon)) { + // Verify weapon is in the array. new weaponindex = RestrictGetIndex(groupweapon); if (weaponindex > -1) { @@ -357,9 +381,11 @@ WpnRestrictQuery:RestrictUnrestrict(const String:weapon[], String:display[] = "" } while (KvGotoNextKey(kvWeaponGroups)); } + // Successfully unrestricted a group return Successful_Group; } + // If weapon name is invalid then set display to invalid weapon name. if (!WeaponsIsValidWeapon(weapon)) { strcopy(display, WEAPONS_MAX_LENGTH, weapon); @@ -367,16 +393,20 @@ WpnRestrictQuery:RestrictUnrestrict(const String:weapon[], String:display[] = "" return Invalid; } + // Get display name of the weapon. WeaponGetDisplayName(weapon, display); + // Return unrestrict failed if weapon isn't restricted. if (!RestrictIsWeaponRestricted(weapon)) { return Failed_Weapon; } + // Verify weapon is in the array. new weaponindex = RestrictGetIndex(display); if (weaponindex > -1) { + // Remove from restricted weapon array. RemoveFromArray(gRestrictedWeapons, weaponindex); } @@ -393,7 +423,8 @@ WpnRestrictQuery:RestrictUnrestrict(const String:weapon[], String:display[] = "" RestrictPrintRestrictOutput(client, WpnRestrictQuery:output, const String:weapon[], bool:reply) { switch(output) - { + { + // Weapon was successfully restricted. case Successful_Weapon: { ZR_PrintToChat(0, "Restrict weapon", weapon); @@ -403,6 +434,7 @@ RestrictPrintRestrictOutput(client, WpnRestrictQuery:output, const String:weapon ZR_LogMessageFormatted(client, "Weapon Restrict", "Restrict", "\"%L\" restricted weapon: \"%s\".", LOG_FORMAT_TYPE_FULL, client, weapon); } } + // Weapon group was successfully restricted. case Successful_Group: { decl String:weaponlist[128]; @@ -415,6 +447,7 @@ RestrictPrintRestrictOutput(client, WpnRestrictQuery:output, const String:weapon ZR_LogMessageFormatted(client, "Weapon Restrict", "Restrict", "\"%L\" restricted weapon group: \"%s\".", LOG_FORMAT_TYPE_FULL, client, weapon); } } + // Weapon was already restricted. case Failed_Weapon: { if (reply) @@ -426,6 +459,7 @@ RestrictPrintRestrictOutput(client, WpnRestrictQuery:output, const String:weapon ZR_PrintToChat(client, "Restrict weapon failed", weapon); } } + // Weapon group was already restricted. case Failed_Group: { decl String:weaponlist[128]; @@ -440,6 +474,7 @@ RestrictPrintRestrictOutput(client, WpnRestrictQuery:output, const String:weapon ZR_PrintToChat(client, "Restrict custom weapon group failed", weapon, weaponlist); } } + // Weapon name was invalid. case Invalid: { if (reply) @@ -465,6 +500,7 @@ RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weap { switch(output) { + // Weapon was successfully unrestricted. case Successful_Weapon: { ZR_PrintToChat(0, "Unrestrict weapon", weapon); @@ -474,6 +510,7 @@ RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weap ZR_LogMessageFormatted(client, "Weapon Restrict", "Unrestrict", "\"%L\" unrestricted weapon: \"%s\".", LOG_FORMAT_TYPE_FULL, client, weapon); } } + // Weapon group was successfully unrestricted. case Successful_Group: { decl String:weaponlist[128]; @@ -486,6 +523,7 @@ RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weap ZR_LogMessageFormatted(client, "Weapon Restrict", "Unrestrict", "\"%L\" unrestricted weapon group: \"%s\".", LOG_FORMAT_TYPE_FULL, client, weapon); } } + // Weapon wasn't restricted. case Failed_Weapon: { if (reply) @@ -497,6 +535,7 @@ RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weap ZR_PrintToChat(client, "Unrestrict weapon failed", weapon); } } + // Weapon group wasn't restricted. case Failed_Group: { decl String:weaponlist[128]; @@ -511,6 +550,7 @@ RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weap ZR_PrintToChat(client, "Unrestrict custom weapon group failed", weapon, weaponlist); } } + // Weapon name was invalid. case Invalid: { if (reply) @@ -529,22 +569,28 @@ RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weap * Checks if a weapon is restricted. * * @param weapon The weapon name. + * @return True if weapon is restricted, false if not. */ bool:RestrictIsWeaponRestricted(const String:weapon[]) { decl String:restrictedweapon[WEAPONS_MAX_LENGTH]; new size = GetArraySize(gRestrictedWeapons); + + // x = restricted weapon index. for (new x = 0; x < size; x++) { GetArrayString(gRestrictedWeapons, x, restrictedweapon, sizeof(restrictedweapon)); + // Check if weapon matches any weapon names in the restricted weapon array. if (StrEqual(weapon, restrictedweapon, false)) { + // Weapon is restricted. return true; } } + // Weapon is not restricted. return false; } @@ -555,11 +601,15 @@ bool:RestrictIsWeaponRestricted(const String:weapon[]) */ bool:RestrictIsGroupRestricted(const String:weapongroup[]) { + // Reset keygroup's traversal stack. KvRewind(kvWeaponGroups); + + // Traverse in to the group names. if (KvJumpToKey(kvWeaponGroups, weapongroup)) { decl String:groupweapon[WEAPONS_MAX_LENGTH]; + // Traverse into the group's weapons. if (KvGotoFirstSubKey(kvWeaponGroups)) { do @@ -587,11 +637,15 @@ bool:RestrictIsGroupRestricted(const String:weapongroup[]) */ bool:RestrictIsGroupUnrestricted(const String:weapongroup[]) { + // Reset keygroup's traversal stack. KvRewind(kvWeaponGroups); + + // Traverse in to the group names. if (KvJumpToKey(kvWeaponGroups, weapongroup)) { decl String:groupweapon[WEAPONS_MAX_LENGTH]; + // Traverse into the group's weapons. if (KvGotoFirstSubKey(kvWeaponGroups)) { do @@ -632,16 +686,21 @@ RestrictGetIndex(const String:weapon[]) decl String:restrictedweapon[WEAPONS_MAX_LENGTH]; new size = GetArraySize(gRestrictedWeapons); + + // x = restricted weapon index. for (new x = 0; x < size; x++) { GetArrayString(gRestrictedWeapons, x, restrictedweapon, sizeof(restrictedweapon)); + // Check if weapon matches weapon in restricted weapons array. if (StrEqual(weapon, restrictedweapon, false)) { + // Return restricted weapon's index. return x; } } + // Weapon isn't restricted. return -1; } @@ -653,10 +712,10 @@ RestrictGetIndex(const String:weapon[]) */ bool:RestrictIsWeaponGroup(const String:groupname[]) { - // Reset the traversal stack + // Reset keygroup's traversal stack. KvRewind(kvWeaponGroups); - // Returns true if groupname is listed in the custom groups file + // Returns true if groupname is listed in the custom groups file. return KvJumpToKey(kvWeaponGroups, groupname); } @@ -710,7 +769,7 @@ RestrictCreateGroupWeaponsArray(&Handle:arrayGroupWeapons, const String:weapongr { KvGetSectionName(kvWeaponGroups, groupweapon, maxlen); - // If the weapon is invalid, then stop + // If the weapon is invalid, then stop. if (!WeaponsIsValidWeapon(groupweapon)) { continue; @@ -749,7 +808,7 @@ RestrictGetGroupWeapons(const String:groupname[], String:weaponlist[], maxlen, c { KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); - // If weapon is invalid, then skip + // If weapon is invalid, then skip. if (!WeaponsIsValidWeapon(groupweapon)) { continue; @@ -775,7 +834,7 @@ RestrictGetGroupWeapons(const String:groupname[], String:weaponlist[], maxlen, c */ public RestrictCanUse(client, weapon, dummy1, dummy2, dummy3, dummy4) { - // If plugin is disabled then stop + // If plugin is disabled then stop. new bool:enabled = GetConVarBool(gCvars[CVAR_ENABLE]); if (!enabled) { @@ -785,16 +844,16 @@ public RestrictCanUse(client, weapon, dummy1, dummy2, dummy3, dummy4) new String:weaponname[WEAPONS_MAX_LENGTH]; GetEdictClassname(weapon, weaponname, sizeof(weaponname)); - // Strip "weapon_" from entity name + // Strip "weapon_" from entity name. ReplaceString(weaponname, sizeof(weaponname), "weapon_", ""); - // If the weapon is restricted then prevent pickup + // If the weapon is restricted then prevent pickup. if (RestrictIsWeaponRestricted(weaponname)) { return 0; } - // If the player is a zombie and the weapon isn't a knife then prevent pickup + // If the player is a zombie and the weapon isn't a knife then prevent pickup. if (IsPlayerZombie(client) && !StrEqual(weaponname, "knife")) { return 0; diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index 9bb1a9b..340e2b8 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -25,7 +25,7 @@ new Handle:kvWeapons = INVALID_HANDLE; #include "zr/weapons/menu_weapons" /** - * Weapons module init function + * Weapons module init function. */ WeaponsInit() { @@ -34,7 +34,7 @@ WeaponsInit() } /** - * Clears weapon data + * Clears weapon data. */ WeaponsClearData() { @@ -50,18 +50,18 @@ WeaponsClearData() /** * Loads weapon data from file. */ -WeaponsOnMapStart() +WeaponsLoad() { - // Clear weapon data + // Clear weapon data. WeaponsClearData(); - // Clear weapon restrict data + // Clear weapon restrict data. RestrictClearData(); decl String:path[PLATFORM_MAX_PATH]; BuildPath(Path_SM, path, sizeof(path), "configs/zr/weapons/weapons.txt"); - // If file isn't found, stop plugin + // If file isn't found, stop plugin. if (!FileToKeyValues(kvWeapons, path)) { if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) @@ -72,16 +72,19 @@ WeaponsOnMapStart() return; } - // Validate weapons config - WeaponsValidateWeaponsConfig(); + // Validate weapons config. + WeaponsValidateConfig(); - // Forward event to sub-module + // Forward event to sub-module. RestrictOnMapStart(); } -WeaponsValidateWeaponsConfig() +/** + * Validate weapon config file and settings. + */ +WeaponsValidateConfig() { - // If log flag check fails, don't log + // If log flag check fails, don't log. if (!LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) { return; @@ -94,15 +97,25 @@ WeaponsValidateWeaponsConfig() } } +/** + * Client is joining the server. + * + * @param client The client index. + */ WeaponsClientInit(client) { - // Forward event to sub-module + // Forward event to sub-module. RestrictClientInit(client); } +/** + * Client is leaving the server. + * + * @param client The client index. + */ WeaponsOnClientDisconnect(client) { - // Forward event to sub-module + // Forward event to sub-module. RestrictOnClientDisconnect(client); } @@ -128,7 +141,7 @@ WeaponsCreateWeaponArray(&Handle:arrayWeapons, maxlen = WEAPONS_MAX_LENGTH) { KvGetSectionName(kvWeapons, weapon, maxlen); - // Push weapon name into the array + // Push weapon name into the array. PushArrayString(arrayWeapons, weapon); // Increment count. @@ -141,12 +154,13 @@ WeaponsCreateWeaponArray(&Handle:arrayWeapons, maxlen = WEAPONS_MAX_LENGTH) } /** - * Checks if a weapon is valid (aka listed in weapons.txt) + * Checks if a weapon is valid. (aka listed in weapons.txt) * @param weapon The weapon name. * @return Returns true if valid, false it not. */ bool:WeaponsIsValidWeapon(const String:weapon[]) { + // Reset keyvalue's traversal stack. KvRewind(kvWeapons); if (KvGotoFirstSubKey(kvWeapons)) { @@ -156,6 +170,7 @@ bool:WeaponsIsValidWeapon(const String:weapon[]) { KvGetSectionName(kvWeapons, validweapon, sizeof(validweapon)); + // If weaponname matches a valid weapon, then return true. if (StrEqual(validweapon, weapon, false)) { return true; @@ -164,16 +179,18 @@ bool:WeaponsIsValidWeapon(const String:weapon[]) } while (KvGotoNextKey(kvWeapons)); } + // Weapon is invalid. return false; } /** - * Looks up a weapon in weapons.txt and returns exact display name + * Looks up a weapon in weapons.txt and returns exact display name. * @param weapon The weapon name. * @param display Returns with the display name, is not changed if weapon is invalid. */ WeaponGetDisplayName(const String:weapon[], String:display[]) { + // Reset keyvalue's traversal stack. KvRewind(kvWeapons); if (KvGotoFirstSubKey(kvWeapons)) { @@ -183,6 +200,7 @@ WeaponGetDisplayName(const String:weapon[], String:display[]) { KvGetSectionName(kvWeapons, validweapon, sizeof(validweapon)); + // If weapon matches a valid weapon (case-insensitive), then return display name. if (StrEqual(validweapon, weapon, false)) { strcopy(display, WEAPONS_MAX_LENGTH, validweapon); @@ -225,7 +243,7 @@ bool:WeaponsIsWeaponMenu(const String:weapon[]) } /** - * Returns knockback multiplier of the weapon + * Returns knockback multiplier of the weapon. * @param weapon The weapon name. * @return The float value of the knockback multiplier, 1.0 if not found. */ diff --git a/src/zr/zadmin.inc b/src/zr/zadmin.inc index d9e7e11..c68697e 100644 --- a/src/zr/zadmin.inc +++ b/src/zr/zadmin.inc @@ -519,6 +519,7 @@ ZRLogFlagsMenu(client) decl String:z_log_module_teleport[64]; decl String:z_log_module_classes[64]; decl String:z_log_module_weapons[64]; + decl String:z_log_module_hitgroups[64]; decl String:z_log_module_commands[64]; decl String:z_log_module_anticamp[64]; decl String:z_log_module_damagecontrol[64]; @@ -541,6 +542,7 @@ ZRLogFlagsMenu(client) Format(z_log_module_teleport, sizeof(z_log_module_teleport), "Teleporter (%d)", LogHasFlag(LOG_MODULE_TELEPORT)); Format(z_log_module_classes, sizeof(z_log_module_classes), "Classes (%d)", LogHasFlag(LOG_MODULE_CLASSES)); Format(z_log_module_weapons, sizeof(z_log_module_weapons), "Weapons (%d)", LogHasFlag(LOG_MODULE_WEAPONS)); + Format(z_log_module_hitgroups, sizeof(z_log_module_hitgroups), "Hitgroups (%d)", LogHasFlag(LOG_MODULE_HITGROUPS)); Format(z_log_module_commands, sizeof(z_log_module_commands), "Admin commands (%d)", LogHasFlag(LOG_MODULE_COMMANDS)); Format(z_log_module_anticamp, sizeof(z_log_module_anticamp), "Anticamp (%d)", LogHasFlag(LOG_MODULE_ANTICAMP)); Format(z_log_module_damagecontrol, sizeof(z_log_module_damagecontrol), "Damage control (suicides) (%d)", LogHasFlag(LOG_MODULE_DAMAGECONTROL)); @@ -572,7 +574,7 @@ ZRLogFlagsMenu(client) DisplayMenu(menu_log_flags, client, MENU_TIME_FOREVER); } -public ZRLogFlagsMenuHandle(Handle:menu_log_flags , MenuAction:action, client, slot) +public ZRLogFlagsMenuHandle(Handle:menu_log_flags, MenuAction:action, client, slot) { if (action == MenuAction_Select) { @@ -665,20 +667,25 @@ public ZRLogFlagsMenuHandle(Handle:menu_log_flags , MenuAction:action, client, s } case 17: { - ToggleLogFlag(LOG_MODULE_COMMANDS); + ToggleLogFlag(LOG_MODULE_HITGROUPS); ZRLogFlagsMenu(client); } case 18: { - ToggleLogFlag(LOG_MODULE_ANTICAMP); + ToggleLogFlag(LOG_MODULE_COMMANDS); ZRLogFlagsMenu(client); } case 19: { - ToggleLogFlag(LOG_MODULE_DAMAGECONTROL); + ToggleLogFlag(LOG_MODULE_ANTICAMP); ZRLogFlagsMenu(client); } case 20: + { + ToggleLogFlag(LOG_MODULE_DAMAGECONTROL); + ZRLogFlagsMenu(client); + } + case 21: { ToggleLogFlag(LOG_MODULE_OFFSETS); ZRLogFlagsMenu(client); @@ -694,7 +701,7 @@ public ZRLogFlagsMenuHandle(Handle:menu_log_flags , MenuAction:action, client, s } if (action == MenuAction_End) { - CloseHandle(menu_log_flags ); + CloseHandle(menu_log_flags); } } diff --git a/src/zr/zombie.inc b/src/zr/zombie.inc index 27f5cb5..0b00983 100644 --- a/src/zr/zombie.inc +++ b/src/zr/zombie.inc @@ -194,14 +194,6 @@ Zombify_Mother(client) tHandles[client][TMOAN] = CreateTimer(interval, ZombieMoanTimer, client, TIMER_REPEAT); } - if (tHandles[client][TPROTECT] != INVALID_HANDLE) - { - pProtect[client] = false; - - KillTimer(tHandles[client][TPROTECT]); - tHandles[client][TPROTECT] = INVALID_HANDLE; - } - if (tHandles[client][TZHP] != INVALID_HANDLE) { KillTimer(tHandles[client][TZHP]); @@ -270,15 +262,6 @@ Zombify(client, attacker = -1, bool:motherinfect = false) tHandles[client][TMOAN] = CreateTimer(interval, ZombieMoanTimer, client, TIMER_REPEAT); } - // Kill spawn protection timer. - if (tHandles[client][TPROTECT] != INVALID_HANDLE) - { - pProtect[client] = false; - - KillTimer(tHandles[client][TPROTECT]); - tHandles[client][TPROTECT] = INVALID_HANDLE; - } - // Kill HP display timer. if (tHandles[client][TZHP] != INVALID_HANDLE) { @@ -635,36 +618,6 @@ public Action:ZHPTimer(Handle:timer, any:index) return Plugin_Continue; } -public Action:ProtectTimer(Handle:timer, any:index) -{ - if (!IsClientInGame(index)) - { - tHandles[index][TPROTECT] = INVALID_HANDLE; - return Plugin_Stop; - } - - pTimeLeft[index]--; - ZR_HudHint(index, "Spawn Protect", pTimeLeft[index]); - - if (pTimeLeft[index] <= 0) - { - pProtect[index] = false; - - if (IsPlayerHuman(index)) - { - ZR_HudHint(index, "Spawn protection end"); - SetPlayerAlpha(index, 255); - SetPlayerSpeed(index, 300.0); - } - - tHandles[index][TPROTECT] = INVALID_HANDLE; - - return Plugin_Stop; - } - - return Plugin_Continue; -} - RespawnPlayer(client) { if (!IsClientInGame(client)) diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index 57774ad..6896e6e 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -55,9 +55,10 @@ enum ZTeam #define LOG_MODULE_OVERLAYS 65536 /** overlays.inc */ #define LOG_MODULE_TELEPORT 131072 /** teleport.inc */ #define LOG_MODULE_WEAPONS 262144 /** Weapons module - weapons/ *.inc */ -#define LOG_MODULE_ANTICAMP 524288 /** anticamp.inc */ -#define LOG_MODULE_DAMAGECONTROL 1048576 /** damagecontrol.inc */ -#define LOG_MODULE_OFFSETS 2097152 /** offsets.inc */ +#define LOG_MODULE_HITGROUPS 524288 /** hitgroups.inc */ +#define LOG_MODULE_ANTICAMP 1048576 /** anticamp.inc */ +#define LOG_MODULE_DAMAGECONTROL 2097152 /** damagecontrol.inc */ +#define LOG_MODULE_OFFSETS 4194304 /** offsets.inc */ /* * @endsection */ @@ -76,8 +77,6 @@ new bool:dispHP[MAXPLAYERS + 1]; new bool:pProtect[MAXPLAYERS + 1]; new bool:gKilledByWorld[MAXPLAYERS + 1] = {false, ...}; -new pTimeLeft[MAXPLAYERS + 1]; - new Float:spawnLoc[MAXPLAYERS + 1][3]; new Float:bufferLoc[MAXPLAYERS + 1][3]; new bool:ztele_spawned[MAXPLAYERS + 1] = {false, ...}; @@ -96,15 +95,14 @@ new Handle:tInfect = INVALID_HANDLE; new Handle:pList = INVALID_HANDLE; -#define MAXTIMERS 7 +#define MAXTIMERS 6 #define TMOAN 0 #define TREGEN 1 #define TTELE 2 #define TZHP 3 -#define TPROTECT 4 -#define TRESPAWN 5 -#define TZVISION 6 +#define TRESPAWN 4 +#define TZVISION 5 new Handle:tHandles[MAXPLAYERS + 1][MAXTIMERS]; @@ -243,10 +241,8 @@ bool:IsClientPlayer(client) { return true; } - else - { - return false; - } + + return false; } /** @@ -261,8 +257,6 @@ bool:IsClientAdmin(client) { return true; } - else - { - return false; - } + + return false; }