sm-zombiereloaded-3/src/zr/napalm.inc

290 lines
8.0 KiB
SourcePawn

/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: napalm.inc
* Type: Module
* Description: Grenades burn zombies when damaged by them.
*
* Copyright (C) 2009-2013 Greyscale, Richard Helgeby
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ============================================================================
*/
/**
* The fuse length of an hegrenade.
*/
#define GRENADE_FUSE_TIME 3.0
/**
* @section m_nWaterLevel defines.
*/
#define NAPALM_WLEVEL_DRY 0
#define NAPALM_WLEVEL_FEET 1
#define NAPALM_WLEVEL_HALF 2
#define NAPALM_WLEVEL_FULL 3
/**
* @endsection
*/
/**
* Variable to store water-level offset value.
*/
new g_iToolsWaterLevel;
/**
* Find napalm-specific offsets here.
*/
NapalmOnOffsetsFound()
{
// If offset "m_bInBuyZone" can't be found, then stop the plugin.
g_iToolsWaterLevel = FindSendPropInfo("CBasePlayer", "m_nWaterLevel");
if (g_iToolsWaterLevel == -1)
{
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Napalm, "Offsets", "Offset \"CBaseEntity::m_nWaterLevel\" was not found.");
}
}
/**
* Hook: OnTakeDamage
* Forwarded from the damage module to check if we should extinguish any flames.
*
* @param client The client index.
* @param damagetype The type of damage inflicted.
* @return Return Plugin_Handled to stop the damage to client.
* Plugin_Continue to allow damage to client.
* Return -1 to not return anything and let the damage module continue as usual.
*/
NapalmOnTakeDamage(client, damagetype)
{
// Client was damaged by fire.
// TODO: Is damage type different in CS:S and CS:GO (it was checking only DMG_DIRECT for some reason). Checking both.
if (damagetype & DMG_BURN || damagetype & DMG_DIRECT)
{
// Only take action if it isn't disabled, or the option is valid.
new douse = GetConVarInt(g_hCvarsList[CVAR_NAPALM_DOUSE]);
if (douse > NAPALM_WLEVEL_DRY && douse <= NAPALM_WLEVEL_FULL)
{
// If the client water-level is equal or higher than the given, then we want to extinguish the flame.
if (NapalmGetClientWaterLevel(client) >= douse)
{
// Put the fire out.
NapalmExtinguishEntity(client);
return _:Plugin_Continue;
}
}
}
// Let the damage module continue as usual.
return -1;
}
/**
* Client has been hurt.
*
* @param client The client index.
* @param attacker The attacker index.
* @param weapon The weapon name.
*/
NapalmOnClientHurt(client, attacker, const String:weapon[], dmg_health)
{
// If there's no attacker, then stop.
if (!attacker)
{
return;
}
// If player isn't a zombie, then stop.
if (!InfectIsClientInfected(client))
{
return;
}
// If napalm time is invalid or 0, then stop.
new Float:napalm_time = ClassGetNapalmTime(client);
if (napalm_time <= 0.0)
{
return;
}
// If the attacker can't throw napalm grenades, then stop.
if (!ClassGetHasNapalm(attacker))
{
return;
}
// If weapon is a grenade, then ignite player.
if (StrEqual(weapon, "hegrenade", false) || StrEqual(weapon, "inferno", false))
{
new bool:reset = GetConVarBool(g_hCvarsList[CVAR_NAPALM_TIME_RESET]);
new flags = GetEntityFlags(client);
if (reset || !(flags & FL_ONFIRE))
{
new Float:timescale = GetConVarFloat(g_hCvarsList[CVAR_NAPALM_TIME_SCALE]);
if (timescale > 0.0)
{
// Figure out our scale value.
timescale = dmg_health / timescale;
// Make sure we dont go over 100%.
if (timescale > 1.0)
timescale = 1.0;
// Make sure we dont go below 0%.
if (timescale < 0.0)
timescale = 0.0;
// Scale our class time, accordingly.
napalm_time = napalm_time * timescale;
}
// Ignite the client or extend the current flames life.
NapalmIgniteEntity(client, napalm_time);
}
}
}
/**
* Client has been killed.
*
* @param client The client index.
*/
NapalmOnClientDeath(client)
{
// Extinguish any flames to stop burning sounds.
NapalmExtinguishEntity(client);
}
/**
* When an entity is created.
*
* @param entity Entity index
* @param classname Class name
*/
NapalmOnEntityCreated(entity, const String:classname[])
{
// Not a grenade.
if (strcmp(classname, "hegrenade_projectile", false))
{
return;
}
// If grenade fire is disabled, then stop.
new bool:napalmignite = GetConVarBool(g_hCvarsList[CVAR_NAPALM_IGNITE]);
if (!napalmignite)
{
return;
}
// Hook entity spawn.
SDKHook(entity, SDKHook_SpawnPost, NapalmOnGrenadeSpawnPost);
}
/**
* Called after a grenade entity has been spawned.
*
* @param entity Entity index
*/
public NapalmOnGrenadeSpawnPost(entity)
{
// Get client who threw this grenade.
new client = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
// Invalid client.
if (client > MaxClients || client <= 0)
{
return;
}
// If human class can't throw napalm grenades, then stop.
if (!ClassGetHasNapalm(client))
{
return;
}
// Ignite the grenade.
IgniteEntity(entity, GRENADE_FUSE_TIME);
}
/**
* Checks the current water-level on a client.
*
* @param client The client index.
* @return A NAPALM_WLEVEL_ define.
*/
stock NapalmGetClientWaterLevel(client)
{
// Return client's water-level.
return GetEntData(client, g_iToolsWaterLevel);
}
/**
* Actually extinguishes an entity.
*
* @param client The client index.
*/
stock NapalmExtinguishEntity(client)
{
//ExtinguishEntity(client); <-- Don't use this. Takes off the FL_ONFIRE flag, but flame doesn't get extinguished.
// This works.
new fire = GetEntPropEnt(client, Prop_Data, "m_hEffectEntity");
if (IsValidEntity(fire))
{
// Make sure the entity is a flame, so we can extinguish it.
decl String:classname[64];
GetEdictClassname(fire, classname, sizeof(classname));
if (StrEqual(classname, "entityflame", false))
{
SetEntPropFloat(fire, Prop_Data, "m_flLifetime", 0.0);
}
// Log what entity was in that property, for future reference.
else
{
LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Napalm, "Napalm Douse", "Found unexpected entity in prop \"m_hEffectEntity\": \"%s\"", classname);
}
}
}
/**
* Ignites an entity or changes the current flames lifetime.
*
* @param client The client index.
* @param time Number of seconds to set on fire.
*/
stock NapalmIgniteEntity(client, Float:time)
{
new fire = GetEntPropEnt(client, Prop_Data, "m_hEffectEntity");
if (IsValidEntity(fire))
{
// Make sure the entity is a flame.
decl String:classname[64];
GetEdictClassname(fire, classname, sizeof(classname));
if (StrEqual(classname, "entityflame", false))
{
SetEntPropFloat(fire, Prop_Data, "m_flLifetime", GetGameTime() + time);
return;
}
}
// No flame entity found, ignite client.
IgniteEntity(client, time);
}