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

248 lines
6.9 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 ZRTools_Handled to stop the damage to client.
* ZRTools_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.
if (damagetype & DMG_CSS_BURN)
{
// 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.
//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_flLifetime\": \"%s\"", classname);
}
}
return _:ACTION_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[])
{
// 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))
{
new bool:reset = GetConVarBool(g_hCvarsList[CVAR_NAPALM_TIME_RESET]);
new flags = GetEntityFlags(client);
if (reset || !(flags & FL_ONFIRE))
{
// This stops the fire before re-ignition.
ExtinguishEntity(client);
// Ignite client.
IgniteEntity(client, napalm_time);
}
}
}
/**
* Client has been killed.
*
* @param client The client index.
*/
NapalmOnClientDeath(client)
{
// Extinguish any flames to stop burning sounds.
ExtinguishEntity(client);
}
/**
* Weapon has been fired.
*
* @param client The client index.
* @param weapon The weapon name.
*/
NapalmOnWeaponFire(client, const String:weapon[])
{
// If grenade fire is disabled, then stop.
new bool:napalmignite = GetConVarBool(g_hCvarsList[CVAR_NAPALM_IGNITE]);
if (!napalmignite)
{
return;
}
// If human class can't throw napalm grenades, then stop.
if (!ClassGetHasNapalm(client))
{
return;
}
// If weapon isn't a grenade, then stop.
if (!StrEqual(weapon, "hegrenade", false))
{
return;
}
// Wait .1 seconds.
CreateTimer(0.1, NapalmIgniteGrenade);
}
/**
* Timer callback, ignite's all hegrenade projectiles.
*
* @param timer The timer handle.
*/
public Action:NapalmIgniteGrenade(Handle:timer)
{
decl String:classname[64];
// Get max entities.
new maxentities = GetMaxEntities();
// x = entity index.
for (new x = 0; x <= maxentities; x++)
{
// If entity is invalid, then stop.
if(!IsValidEntity(x) || !IsValidEdict(x))
{
continue;
}
GetEdictClassname(x, classname, sizeof(classname));
if(StrEqual(classname, "hegrenade_projectile"))
{
IgniteEntity(x, 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);
}