PDA

View Full Version : TF2 Health Modding Snippet


labelmaker
05-15-2009, 08:53
#include <sourcemod>
#include <sdktools>
#include <damage>

new g_playerAttacking[MAXPLAYERS + 1];
new bool:g_alreadykilled[MAXPLAYERS + 1];

public Plugin:myinfo =
{
name = "Health Modding",
author = "LabelMaker",
description = "Double Damage and Health Modding Example",
version = "1.0",
url = "<- URL ->"
}

public OnPluginStart()
{
HookEvent("player_hurt", EventDamage, EventHookMode_Pre);
}

public OnEventShutdown()
{
UnhookEvent("player_spawn", PlayerSpawnEvent);
}

public OnGameFrame()
{
SaveAllHealth();
}

public PlayerSpawnEvent(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
if (client > 0)
{
SaveHealth(client);
g_alreadykilled[client] = false;
}
}

public EventDamage(Handle:Event, const String:Name[], bool:dontBroadcast)
{
new victim = GetClientOfUserId(GetEventInt(Event, "userid"));

if (g_alreadykilled[victim])//this will prevent players gaining multiple kills for a single kill
{
g_alreadykilled[victim] = false;
return;
}

new attacker = GetClientOfUserId(GetEventInt(Event, "attacker"));
new bool:self = false;
new v_health = GetEntProp(victim, Prop_Send, "m_iHealth");
//new a_health = GetEntProp(attacker, Prop_Send, "m_iHealth");
new damage = GetDamage(Event, victim, attacker, -1, -1);
new victimFlags = GetEntProp(victim, Prop_Data, "m_fFlags", victimFlags);

if (attacker == victim) self = true;
if (!self && attacker != 0 && IsClientConnected(attacker))
{
v_health -= damage; // this will double the damage done by subtracting again whats already been done.
}

//is victim or attacker dead?
if (v_health != GetEntProp(victim, Prop_Send, "m_iHealth"))
{
if (v_health < 1)
{
g_playerAttacking[attacker] = victim;
CreateTimer(0.1, checkDeath, victim);// wait a frame to prevent invincible exploit
}
else
{
SetEntityHealth(victim, v_health);
SaveHealth(victim);
}
}
/* this section is only needed if you apply anything health related to your attacker//
if (a_health != GetEntProp(attacker, Prop_Send, "m_iHealth"))
{
if (a_health < 1)
{
g_playerAttacking[victim] = attacker;
CreateTimer(0.01, checkDeath, attacker);
}
else
{
SetEntityHealth(attacker, a_health);
SaveHealth(attacker);
}
}
///////////////////////////////////////////////////////////////////////////////////////*/
}

public Action:checkDeath(Handle:timer, any:client)
{
new attacker;
new fFlags = GetEntProp(client, Prop_Data, "m_fFlags", fFlags);
for(new i = 1; i <= MaxClients; ++i)
{
if (IsClientConnected(i) && g_playerAttacking[i] == client)
{
g_playerAttacking[i] = 0;
attacker = i;
break;
}
}
if (IsPlayerAlive(client) && !(fFlags & FL_KILLME)) KillPlayer(client, attacker); //if the game engine hasnt assigned the player for death, kill them.
}

KillPlayer(client, attacker)
{
new ent = CreateEntityByName("env_explosion");
if (IsValidEntity(ent))
{
g_alreadykilled[client] = true;//tell the damage event to halt, and let the game engine do the work.

DispatchKeyValue(ent, "iMagnitude", "1000");
DispatchKeyValue(ent, "iRadiusOverride", "2");
SetEntPropEnt(ent, Prop_Data, "m_hInflictor", attacker);
SetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity", attacker);
DispatchKeyValue(ent, "spawnflags", "3964");
DispatchSpawn(ent);
new Float:pos[3];
GetClientAbsOrigin(client, pos);
TeleportEntity(ent, pos, NULL_VECTOR, NULL_VECTOR);
AcceptEntityInput(ent, "explode", client, client);
CreateTimer(0.2, RemoveExplosion, ent);
}
}

public Action:RemoveExplosion(Handle:timer, any:ent)
{
if (IsValidEntity(ent))
{
RemoveEdict(ent);
}
}

Source: 42267
include file used in the snippet: 42188

p3tsin
05-15-2009, 10:30
Hmm, interesting. Noticed a few oddities though

1) Theres no such forward as OnEventShutdown(), not in SourceMod at least. Also, you dont need to unhook events, SourceMod does that for you when the plugin is unloaded.

2) new bool:g_alreadykilled[MAXPLAYERS + 1];

KillPlayer(client, attacker)
{
//...
g_alreadykilled = true;//tell the damage event to halt, and let the game engine do the work.
//...
}

Variable not indexed? :o

3) if (IsPlayerAlive(client) && !(fFlags & FL_KILLME)) KillPlayer(client, attacker); //if the game engine hasnt assigned the player for death, kill them.

Are you sure thats what FL_KILLME is used for? I know its used to tell the engine to delete an entity next time it thinks, but I guess it could be used for that too. How did you come up with it?

4) CreateTimer(0.01, checkDeath, victim);// wait a frame to prevent invincible exploit

Minimum interval for timers is 0.1 seconds, everything lower than that will be clamped up to the min value.

5) if (IsClientConnected(attacker) && attacker != 0 && !self)

The conditions should probably be in the opposite order (!self && attacker != 0 && IsClientConnected(attacker)) or else IsClientConnected will spit out an error if you pass it an invalid client index, 0 in this case.

6) for(new i = 1; i <= MAXPLAYERS; ++i)
{
if (IsValidEdict(i))
{
if (IsClientConnected(i))
{
if (g_playerAttacking[i] == client)
{
g_playerAttacking[i] = 0;
attacker = i;
break;
}
}
}
}

The IsValidEdict() check isnt needed, you probably added that because IsClientConnected was complaining about invalid client indexes again. The magic MaxClients variable holds the current maxplayers limit at all times.

for(new i = 1; i <= MaxClients; ++i)
{
if (IsClientConnected(i) && g_playerAttacking[i] == client)
{
g_playerAttacking[i] = 0;
attacker = i;
break;
}
}

Sorry if this seems Im being too hard on you, but most of those mistakes are pretty common and it can be hard to tell whats the correct way to do it. I just wanted to clear them up so that others wouldnt end up with the same flaws. :grrr:

labelmaker
05-17-2009, 03:55
thanx for those helpful bits of advice. ++karma for you :) the FL_KILLME check is to prevent players from getting multiple kill points for only having a single kill. Most of my playtesters had to reset their stats (including me) because we had unrealistic results of like 100 or 200 points per life, LOL! -EDIT- What no karma anymore! well kudos man, if I could give ya karma, id give you some!