diff --git a/cstrike/addons/sourcemod/configs/zr/playerclasses.txt b/cstrike/addons/sourcemod/configs/zr/playerclasses.txt index b8a1339..3f8a648 100644 --- a/cstrike/addons/sourcemod/configs/zr/playerclasses.txt +++ b/cstrike/addons/sourcemod/configs/zr/playerclasses.txt @@ -34,18 +34,18 @@ // napalm_time decimal Napalm burn duration. Zombies only. // immunity_mode text Special immunity modes. Some modes only works on humans or zombies: // "none" - Instant infection. -// (Not implemented) "full" - Completely immune. Humans can't be infected, zombies don't receive damage or knock back. Careful with this, it might not be that fun. +// "full" - Completely immune. Humans can't be infected, zombies don't receive damage or knock back. Careful with this, it might not be that fun. // "infect" - Humans are immune to infections until HP go below a threshold. Threshold at zero enable stabbing to death. -// (Not implemented) "damage" - Zombies are immune to damage from humans/grenades, but still vulnerable to knock back. +// "damage" - Zombies are immune to damage from humans/grenades, but still vulnerable to knock back. // "delay" - Delay infection for a certain number of seconds. // (Not implemented) "shield" - Shield against infections (humans) or knock back (zombies) for a certain amount of seconds (similar to TF2's übercharge). // immunity_amount number Immunity data value (humans only). Depends on the immunity mode above: // "infect" - HP threshold. Infection will be allowed when HP go below this value. Zero will enable stabbing to death. -// (Not implemented) "delay" - Number of seconds the infection is delayed since first hit by a zombie. +// "delay" - Number of seconds the infection is delayed since first hit by a zombie. // (Not implemented) "shield" - Number of seconds the shield is active. // immunity_cooldown number Number of seconds of cooldown for temporary immunity effects, depending on mode. -// "shield" - Number of seconds the player has to wait before the shield can be used again. // "delay" - Number of seconds the delay is reduced every time a zombie attack, while a delayed infection is in progress. +// "shield" - Number of seconds the player has to wait before the shield can be used again. // no_fall_damage on/off Disables fall damage. // health number How many health points to give. // health_regen_interval decimal Sets the regeneration interval. 0 to disable. @@ -503,9 +503,9 @@ "napalm_time" "0.0" // Player behavior - "immunity_mode" "delay" // Delay infection - "immunity_amount" "10" // 10 seconds. - "immunity_cooldown" "2" // Reduce delay 2 seconds every subsequent attack (infect faster). + "immunity_mode" "none" + "immunity_amount" "1" + "immunity_cooldown" "60" "no_fall_damage" "0" "health" "100" @@ -548,8 +548,8 @@ "napalm_time" "0.0" // Player behavior - "immunity_mode" "infect" // Immune against infection, - "immunity_amount" "10" // when HP is above 10. + "immunity_mode" "none" + "immunity_amount" "1" "immunity_cooldown" "60" "no_fall_damage" "yes" diff --git a/src/zr/damage.inc b/src/zr/damage.inc index 51647ba..c739f68 100644 --- a/src/zr/damage.inc +++ b/src/zr/damage.inc @@ -220,7 +220,6 @@ public ZRTools_Action:DamageTraceAttack(client, inflictor, attacker, Float:damag if (ImmunityOnClientTraceAttack(client, attacker, damage, hitgroup, damagetype)) { // Block damage. - PrintToChatAll("DamageTraceAttack - Blocking damage."); return ACTION_HANDLED; } diff --git a/src/zr/immunityhandler.inc b/src/zr/immunityhandler.inc index 8c94b18..2dca868 100644 --- a/src/zr/immunityhandler.inc +++ b/src/zr/immunityhandler.inc @@ -26,9 +26,14 @@ */ /** - * Current immunity modes. + * Maximum delay of infection. */ -//new ImmunityMode:PlayerImmunityMode[MAXPLAYERS + 1] = {Immunity_None, ...}; +#define IMMUNITY_MAX_DELAY 300 + +/** + * Maximum shield duration. + */ +#define IMMUNITY_MAX_SHIELD_TIME 300 /** * Timers for handling timed immunity actions. @@ -139,7 +144,7 @@ bool:ImmunityOnClientTraceAttack(client, attacker, Float:damage, hitgroup, damag { case Immunity_Full: { - // Block damage. + // Block damage (implies blocking knock back on zombies). return true; } case Immunity_Infect: @@ -166,6 +171,7 @@ bool:ImmunityOnClientTraceAttack(client, attacker, Float:damage, hitgroup, damag // Client must be zombie. if (!InfectIsClientInfected(client)) { + // Allow damage. return false; } @@ -192,6 +198,7 @@ bool:ImmunityOnClientTraceAttack(client, attacker, Float:damage, hitgroup, damag } } + // Allow damage. return false; } @@ -364,7 +371,6 @@ public Action:ImmunityDelayTimerHandler(Handle:timer, any:client) if (!IsClientInGame(client) || !IsPlayerAlive(client)) { // Client disconnected or died. Abort immunity action. - PlayerImmunityTimer[client] = INVALID_HANDLE; ImmunityAbortHandler(client, false); return Plugin_Stop; } @@ -377,7 +383,6 @@ public Action:ImmunityDelayTimerHandler(Handle:timer, any:client) { // Time is up. Reset data. PlayerImmunityDuration[client] = 0; - //PlayerImmunityTimer[client] = INVALID_HANDLE; ImmunityAbortHandler(client); // Infect client. @@ -405,7 +410,7 @@ public Action:ImmunityDelayTimerHandler(Handle:timer, any:client) */ bool:ImmunityShieldModeHandler(client, bool:asZombie = true) { - // Check cooldown. + // Stop if cooldown is still in progress. // Deploy shield. if (asZombie) @@ -681,3 +686,137 @@ ImmunityModeToString(ImmunityMode:mode, String:buffer[], maxlen) return 0; } + +/** + * Returns whether the amount value is valid for the specified mode. + * + * @param mode Immunity mode to validate against. + * @param amount Amount value to test. + * + * @return True if valid, false otherwise. + */ +bool:ImmunityIsValidAmount(ImmunityMode:mode, amount) +{ + switch (mode) + { + case Immunity_Invalid: + { + return false; + } + case Immunity_None: + { + // Immunity mode disabled, amount ignored. + return true; + } + case Immunity_Full: + { + // Amount isn't used in this mode. + return true; + } + case Immunity_Infect: + { + // Check if HP threshold is negative. + if (amount < 0) + { + return false; + } + + // There's no upper limit. If the value is too high it will + // overflow and become negative. + } + case Immunity_Damage: + { + // Amount isn't used in this mode. + return true; + } + case Immunity_Delay: + { + if (amount <= 0 || amount > IMMUNITY_MAX_DELAY) + { + return false; + } + } + case Immunity_Shield: + { + if (amount <= 0 || amount > IMMUNITY_MAX_SHIELD_TIME) + { + return false; + } + } + default: + { + // Invalid mode. + return false; + } + } + + // Passed. + return true; +} + +/** + * Returns whether the cooldown value is valid for the specified mode. + * + * @param mode Immunity mode to validate against. + * @param cooldown Cooldown value to test. + * + * @return True if valid, false otherwise. + */ +bool:ImmunityIsValidCooldown(ImmunityMode:mode, cooldown) +{ + switch (mode) + { + case Immunity_Invalid: + { + return false; + } + case Immunity_None: + { + // Immunity mode disabled, amount ignored. + return true; + } + case Immunity_Full: + { + // Cooldown isn't used in this mode. + return true; + } + case Immunity_Infect: + { + // Cooldown isn't used in this mode. + return true; + } + case Immunity_Damage: + { + // Cooldown isn't used in this mode. + return true; + } + case Immunity_Delay: + { + if (cooldown < 0) + { + return false; + } + + // No upper limit. It may be intentional to use a high value so that + // the section attack will remove all delay and infect instantly. + } + case Immunity_Shield: + { + if (cooldown < 0) + { + return false; + } + + // No upper limit. It may be intentional to use a high value so that + // the shield can only be used once per life. + } + default: + { + // Invalid mode. + return false; + } + } + + // Passed. + return true; +} diff --git a/src/zr/playerclasses/filtertools.inc b/src/zr/playerclasses/filtertools.inc index f6637cb..d2793ea 100644 --- a/src/zr/playerclasses/filtertools.inc +++ b/src/zr/playerclasses/filtertools.inc @@ -297,7 +297,26 @@ stock ClassValidateAttributes(classindex, bool:logErrors = false) } // Immunity amount. - // TODO: Validate amount value. This depends on the immunity mode. + new immunityAmount = ClassData[classindex][Class_ImmunityAmount]; + if (!ImmunityIsValidAmount(immunityMode, immunityAmount)) + { + flags += ZR_CLASS_IMMUNITY_AMOUNT; + if (logErrors) + { + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Playerclasses, "Config Validation", "Warning: Invalid immunity_amount at index %d.", classindex); + } + } + + // Immunity cooldown. + new immunityCooldown = ClassData[classindex][Class_ImmunityCooldown]; + if (!ImmunityIsValidCooldown(immunityMode, immunityCooldown)) + { + flags += ZR_CLASS_IMMUNITY_COOLDOWN; + if (logErrors) + { + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Playerclasses, "Config Validation", "Warning: Invalid immunity_cooldown at index %d.", classindex); + } + } // Health. new health = ClassData[classindex][Class_Health];