mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 20:33:20 +00:00
l4d_tank_hp_sprite: Add support for all specials instead of only tanks
This commit is contained in:
parent
11d74c5382
commit
e7cc1fe2ef
2 changed files with 811 additions and 0 deletions
BIN
plugins/l4d_tank_hp_sprite.smx
Normal file
BIN
plugins/l4d_tank_hp_sprite.smx
Normal file
Binary file not shown.
811
scripting/l4d_tank_hp_sprite.sp
Normal file
811
scripting/l4d_tank_hp_sprite.sp
Normal file
|
@ -0,0 +1,811 @@
|
|||
/**
|
||||
// ====================================================================================================
|
||||
Change Log:
|
||||
|
||||
1.0.2 (08-February-2021)
|
||||
- Fixed wrong value on max health calculation.
|
||||
- Fixed sprite hiding behind tank rocks.
|
||||
- Fixed sprite hiding while tank throws rocks (ability use).
|
||||
- Moved visibility logic to timer.
|
||||
|
||||
1.0.1 (30-January-2021)
|
||||
- Public release.
|
||||
|
||||
1.0.0 (21-April-2019)
|
||||
- Private version.
|
||||
|
||||
// ====================================================================================================
|
||||
*/
|
||||
|
||||
// ====================================================================================================
|
||||
// Plugin Info - define
|
||||
// ====================================================================================================
|
||||
#define PLUGIN_NAME "[L4D1 & L4D2] Tank HP Sprite"
|
||||
#define PLUGIN_AUTHOR "Mart"
|
||||
#define PLUGIN_DESCRIPTION "Shows a sprite at the tank head that goes from green to red based on its HP"
|
||||
#define PLUGIN_VERSION "1.0.2"
|
||||
#define PLUGIN_URL "https://forums.alliedmods.net/showthread.php?t=330370"
|
||||
|
||||
// ====================================================================================================
|
||||
// Plugin Info
|
||||
// ====================================================================================================
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = PLUGIN_NAME,
|
||||
author = PLUGIN_AUTHOR,
|
||||
description = PLUGIN_DESCRIPTION,
|
||||
version = PLUGIN_VERSION,
|
||||
url = PLUGIN_URL
|
||||
}
|
||||
|
||||
// ====================================================================================================
|
||||
// Includes
|
||||
// ====================================================================================================
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <sdkhooks>
|
||||
|
||||
// ====================================================================================================
|
||||
// Pragmas
|
||||
// ====================================================================================================
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
// ====================================================================================================
|
||||
// Cvar Flags
|
||||
// ====================================================================================================
|
||||
#define CVAR_FLAGS FCVAR_NOTIFY
|
||||
#define CVAR_FLAGS_PLUGIN_VERSION FCVAR_NOTIFY|FCVAR_DONTRECORD|FCVAR_SPONLY
|
||||
|
||||
// ====================================================================================================
|
||||
// Filenames
|
||||
// ====================================================================================================
|
||||
#define CONFIG_FILENAME "l4d_tank_hp_sprite"
|
||||
|
||||
// ====================================================================================================
|
||||
// Defines
|
||||
// ====================================================================================================
|
||||
#define CLASSNAME_ENV_SPRITE "env_sprite"
|
||||
#define CLASSNAME_TANK_ROCK "tank_rock"
|
||||
|
||||
#define TEAM_SPECTATOR 1
|
||||
#define TEAM_SURVIVOR 2
|
||||
#define TEAM_INFECTED 3
|
||||
#define TEAM_HOLDOUT 4
|
||||
|
||||
#define FLAG_TEAM_NONE (0 << 0) // 0 | 0000
|
||||
#define FLAG_TEAM_SURVIVOR (1 << 0) // 1 | 0001
|
||||
#define FLAG_TEAM_INFECTED (1 << 1) // 2 | 0010
|
||||
#define FLAG_TEAM_SPECTATOR (1 << 2) // 4 | 0100
|
||||
#define FLAG_TEAM_HOLDOUT (1 << 3) // 8 | 1000
|
||||
|
||||
#define L4D1_ZOMBIECLASS_TANK 5
|
||||
#define L4D2_ZOMBIECLASS_TANK 8
|
||||
|
||||
#define MAXENTITIES 2048
|
||||
|
||||
// ====================================================================================================
|
||||
// Plugin Cvars
|
||||
// ====================================================================================================
|
||||
static ConVar g_hCvar_Enabled;
|
||||
static ConVar g_hCvar_ZAxis;
|
||||
static ConVar g_hCvar_FadeDistance;
|
||||
static ConVar g_hCvar_Sight;
|
||||
static ConVar g_hCvar_AttackDelay;
|
||||
static ConVar g_hCvar_AliveShow;
|
||||
static ConVar g_hCvar_AliveModel;
|
||||
static ConVar g_hCvar_AliveAlpha;
|
||||
static ConVar g_hCvar_AliveScale;
|
||||
static ConVar g_hCvar_DeadShow;
|
||||
static ConVar g_hCvar_DeadModel;
|
||||
static ConVar g_hCvar_DeadAlpha;
|
||||
static ConVar g_hCvar_DeadScale;
|
||||
static ConVar g_hCvar_DeadColor;
|
||||
static ConVar g_hCvar_Team;
|
||||
static ConVar g_hCvar_AllSpecials;
|
||||
|
||||
// ====================================================================================================
|
||||
// bool - Plugin Variables
|
||||
// ====================================================================================================
|
||||
static bool g_bL4D2;
|
||||
static bool g_bConfigLoaded;
|
||||
static bool g_bEventsHooked;
|
||||
static bool g_bCvar_Enabled;
|
||||
static bool g_bCvar_Sight;
|
||||
static bool g_bCvar_AttackDelay;
|
||||
static bool g_bCvar_AliveShow;
|
||||
static bool g_bCvar_DeadShow;
|
||||
|
||||
// ====================================================================================================
|
||||
// int - Plugin Variables
|
||||
// ====================================================================================================
|
||||
static int g_iTankClass;
|
||||
static int g_iCvar_AliveAlpha;
|
||||
static int g_iCvar_DeadAlpha;
|
||||
static int g_iCvar_FadeDistance;
|
||||
static int g_iCvar_Team;
|
||||
|
||||
// ====================================================================================================
|
||||
// float - Plugin Variables
|
||||
// ====================================================================================================
|
||||
static float g_fVPlayerMins[3] = {-16.0, -16.0, 0.0};
|
||||
static float g_fVPlayerMaxs[3] = { 16.0, 16.0, 71.0};
|
||||
static float g_fVPos[3];
|
||||
static float g_fCvar_ZAxis;
|
||||
static float g_fCvar_AttackDelay;
|
||||
static float g_fCvar_AliveScale;
|
||||
static float g_fCvar_DeadScale;
|
||||
|
||||
// ====================================================================================================
|
||||
// string - Plugin Variables
|
||||
// ====================================================================================================
|
||||
static char g_sCvar_AliveModel[100];
|
||||
static char g_sCvar_AliveAlpha[4];
|
||||
static char g_sCvar_AliveScale[5];
|
||||
static char g_sCvar_DeadModel[100];
|
||||
static char g_sCvar_DeadAlpha[4];
|
||||
static char g_sCvar_DeadScale[5];
|
||||
static char g_sCvar_DeadColor[12];
|
||||
static char g_sCvar_FadeDistance[5];
|
||||
|
||||
// ====================================================================================================
|
||||
// client - Plugin Variables
|
||||
// ====================================================================================================
|
||||
static int gc_iTankSpriteRef[MAXPLAYERS+1] = { INVALID_ENT_REFERENCE, ... };
|
||||
static bool gc_bVisible[MAXPLAYERS+1][MAXPLAYERS+1];
|
||||
static float gc_fLastAttack[MAXPLAYERS+1][MAXPLAYERS+1];
|
||||
|
||||
// ====================================================================================================
|
||||
// entity - Plugin Variables
|
||||
// ====================================================================================================
|
||||
static bool ge_bInvalidTrace[MAXENTITIES+1];
|
||||
static int ge_iOwner[MAXENTITIES+1];
|
||||
|
||||
// ====================================================================================================
|
||||
// Plugin Start
|
||||
// ====================================================================================================
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||
{
|
||||
EngineVersion engine = GetEngineVersion();
|
||||
|
||||
if (engine != Engine_Left4Dead && engine != Engine_Left4Dead2)
|
||||
{
|
||||
strcopy(error, err_max, "This plugin only runs in \"Left 4 Dead\" and \"Left 4 Dead 2\" game");
|
||||
return APLRes_SilentFailure;
|
||||
}
|
||||
|
||||
g_bL4D2 = (engine == Engine_Left4Dead2);
|
||||
g_iTankClass = (g_bL4D2 ? L4D2_ZOMBIECLASS_TANK : L4D1_ZOMBIECLASS_TANK);
|
||||
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
CreateConVar("l4d_tank_hp_sprite_version", PLUGIN_VERSION, PLUGIN_DESCRIPTION, CVAR_FLAGS_PLUGIN_VERSION);
|
||||
g_hCvar_Enabled = CreateConVar("l4d_tank_hp_sprite_enable", "1", "Enable/Disable the plugin.\n0 = Disable, 1 = Enable", CVAR_FLAGS, true, 0.0, true, 1.0);
|
||||
g_hCvar_ZAxis = CreateConVar("l4d_tank_hp_sprite_z_axis", "92", "Additional Z distance based on the tank position.", CVAR_FLAGS, true, 0.0);
|
||||
g_hCvar_FadeDistance = CreateConVar("l4d_tank_hp_sprite_fade_distance", "-1", "Minimum distance that a client must be from the tank to see the sprite (both alive and dead sprites).\n-1 = Always visible.", CVAR_FLAGS, true, -1.0, true, 9999.0);
|
||||
g_hCvar_Sight = CreateConVar("l4d_tank_hp_sprite_sight", "1", "Show the sprite to the survivor only if the Tank is on sight.\n0 = OFF, 1 = ON.", CVAR_FLAGS, true, 0.0, true, 1.0);
|
||||
g_hCvar_AttackDelay = CreateConVar("l4d_tank_hp_sprite_attack_delay", "0.0", "Show the sprite to the survivor attacker, by this amount of time in seconds, after hitting the Tank.\n0 = OFF.", CVAR_FLAGS, true, 0.0);
|
||||
g_hCvar_AliveShow = CreateConVar("l4d_tank_hp_sprite_alive_show", "1", "Show the alive sprite while tank is alive.\n0 = OFF, 1 = ON.", CVAR_FLAGS, true, 0.0, true, 1.0);
|
||||
g_hCvar_AliveModel = CreateConVar("l4d_tank_hp_sprite_alive_model", "materials/vgui/healthbar_white.vmt", "Model of alive tank sprite.");
|
||||
g_hCvar_AliveAlpha = CreateConVar("l4d_tank_hp_sprite_alive_alpha", "200", "Alpha of alive tank sprite.\n0 = Invisible, 255 = Fully Visible", CVAR_FLAGS, true, 0.0, true, 255.0);
|
||||
g_hCvar_AliveScale = CreateConVar("l4d_tank_hp_sprite_alive_scale", "0.25", "Scale of alive tank sprite (increases both height and width).\nNote: Some range values maintain the same size. (e.g. from 0.0 to 0.38 the size doesn't change).", CVAR_FLAGS, true, 0.0);
|
||||
g_hCvar_DeadShow = CreateConVar("l4d_tank_hp_sprite_dead_show", "1", "Show the dead sprite when a tank dies.\n0 = OFF, 1 = ON.", CVAR_FLAGS, true, 0.0, true, 1.0);
|
||||
g_hCvar_DeadModel = CreateConVar("l4d_tank_hp_sprite_dead_model", "materials/sprites/death_icon.vmt", "Model of dead tank sprite.");
|
||||
g_hCvar_DeadAlpha = CreateConVar("l4d_tank_hp_sprite_dead_alpha", "200", "Alpha of dead tank sprite.\n0 = Invisible, 255 = Fully Visible", CVAR_FLAGS, true, 0.0, true, 255.0);
|
||||
g_hCvar_DeadScale = CreateConVar("l4d_tank_hp_sprite_dead_scale", "0.25", "Scale of dead tank sprite (increases both height and width).\nSome range values maintain the size the same.", CVAR_FLAGS, true, 0.0);
|
||||
g_hCvar_DeadColor = CreateConVar("l4d_tank_hp_sprite_dead_color", "225 0 0", "Color of dead tank sprite.\nUse three values between 0-255 separated by spaces (\"<0-255> <0-255> <0-255>\").", CVAR_FLAGS);
|
||||
g_hCvar_Team = CreateConVar("l4d_tank_hp_sprite_team", "3", "Which teams should the sprite be visible.\n0 = NONE, 1 = SURVIVOR, 2 = INFECTED, 4 = SPECTATOR, 8 = HOLDOUT.\nAdd numbers greater than 0 for multiple options.\nExample: \"3\", enables for SURVIVOR and INFECTED.", CVAR_FLAGS, true, 0.0, true, 15.0);
|
||||
g_hCvar_AllSpecials = CreateConVar("l4d_tank_hp_sprite_all_specials", "1", "Should all specials have healthbar or only tanks\n0 = Tanks Only, 1 = All Specials", CVAR_FLAGS, true, 0.0, true, 1.0);
|
||||
|
||||
g_hCvar_Enabled.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_ZAxis.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_FadeDistance.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_Sight.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_AttackDelay.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_AliveShow.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_AliveModel.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_AliveAlpha.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_AliveScale.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_DeadShow.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_DeadModel.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_DeadAlpha.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_DeadScale.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_DeadColor.AddChangeHook(Event_ConVarChanged);
|
||||
g_hCvar_Team.AddChangeHook(Event_ConVarChanged);
|
||||
|
||||
// Load plugin configs from .cfg
|
||||
AutoExecConfig(true, CONFIG_FILENAME);
|
||||
|
||||
// Admin Commands
|
||||
RegAdminCmd("sm_print_cvars_l4d_tank_hp_sprite", CmdPrintCvars, ADMFLAG_ROOT, "Print the plugin related cvars and their respective values to the console.");
|
||||
|
||||
CreateTimer(0.1, TimerKill, _, TIMER_REPEAT);
|
||||
CreateTimer(0.1, TimerVisible, _, TIMER_REPEAT);
|
||||
CreateTimer(0.1, TimerRender, _, TIMER_REPEAT);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void OnPluginEnd()
|
||||
{
|
||||
int entity;
|
||||
char targetname[64];
|
||||
|
||||
entity = INVALID_ENT_REFERENCE;
|
||||
while ((entity = FindEntityByClassname(entity, CLASSNAME_ENV_SPRITE)) != INVALID_ENT_REFERENCE)
|
||||
{
|
||||
if (GetEntProp(entity, Prop_Data, "m_iHammerID") == -1)
|
||||
{
|
||||
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||
if (StrEqual(targetname, "l4d_tank_hp_sprite"))
|
||||
AcceptEntityInput(entity, "Kill");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void OnConfigsExecuted()
|
||||
{
|
||||
GetCvars();
|
||||
|
||||
g_bConfigLoaded = true;
|
||||
|
||||
LateLoad();
|
||||
|
||||
HookEvents(g_bCvar_Enabled);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void Event_ConVarChanged(Handle convar, const char[] sOldValue, const char[] sNewValue)
|
||||
{
|
||||
GetCvars();
|
||||
|
||||
HookEvents(g_bCvar_Enabled);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void GetCvars()
|
||||
{
|
||||
g_bCvar_Enabled = g_hCvar_Enabled.BoolValue;
|
||||
g_fCvar_ZAxis = g_hCvar_ZAxis.FloatValue;
|
||||
g_fVPos[2] = g_fCvar_ZAxis;
|
||||
g_iCvar_FadeDistance = g_hCvar_FadeDistance.IntValue;
|
||||
FormatEx(g_sCvar_FadeDistance, sizeof(g_sCvar_FadeDistance), "%i", g_iCvar_FadeDistance);
|
||||
g_bCvar_Sight = g_hCvar_Sight.BoolValue;
|
||||
g_fCvar_AttackDelay = g_hCvar_AttackDelay.FloatValue;
|
||||
g_bCvar_AttackDelay = (g_fCvar_AttackDelay > 0.0);
|
||||
g_bCvar_AliveShow = g_hCvar_AliveShow.BoolValue;
|
||||
g_hCvar_AliveModel.GetString(g_sCvar_AliveModel, sizeof(g_sCvar_AliveModel));
|
||||
TrimString(g_sCvar_AliveModel);
|
||||
PrecacheModel(g_sCvar_AliveModel, true);
|
||||
g_iCvar_AliveAlpha = g_hCvar_AliveAlpha.IntValue;
|
||||
FormatEx(g_sCvar_AliveAlpha, sizeof(g_sCvar_AliveAlpha), "%i", g_iCvar_AliveAlpha);
|
||||
g_fCvar_AliveScale = g_hCvar_AliveScale.FloatValue;
|
||||
FormatEx(g_sCvar_AliveScale, sizeof(g_sCvar_AliveScale), "%.2f", g_fCvar_AliveScale);
|
||||
g_bCvar_DeadShow = g_hCvar_DeadShow.BoolValue;
|
||||
g_hCvar_DeadModel.GetString(g_sCvar_DeadModel, sizeof(g_sCvar_DeadModel));
|
||||
TrimString(g_sCvar_DeadModel);
|
||||
PrecacheModel(g_sCvar_DeadModel, true);
|
||||
g_iCvar_DeadAlpha = g_hCvar_DeadAlpha.IntValue;
|
||||
FormatEx(g_sCvar_DeadAlpha, sizeof(g_sCvar_DeadAlpha), "%i", g_iCvar_DeadAlpha);
|
||||
g_fCvar_DeadScale = g_hCvar_DeadScale.FloatValue;
|
||||
FormatEx(g_sCvar_DeadScale, sizeof(g_sCvar_DeadScale), "%.2f", g_fCvar_DeadScale);
|
||||
g_hCvar_DeadColor.GetString(g_sCvar_DeadColor, sizeof(g_sCvar_DeadColor));
|
||||
TrimString(g_sCvar_DeadColor);
|
||||
g_iCvar_Team = g_hCvar_Team.IntValue;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void LateLoad()
|
||||
{
|
||||
for (int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if (IsPlayerSpecialInfected(client))
|
||||
TankSprite(client);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void OnClientDisconnect(int client)
|
||||
{
|
||||
if (!g_bConfigLoaded)
|
||||
return;
|
||||
|
||||
gc_iTankSpriteRef[client] = INVALID_ENT_REFERENCE;
|
||||
|
||||
for (int target = 1; target <= MaxClients; target++)
|
||||
{
|
||||
gc_bVisible[target][client] = false;
|
||||
gc_fLastAttack[target][client] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void OnEntityDestroyed(int entity)
|
||||
{
|
||||
if (!g_bConfigLoaded)
|
||||
return;
|
||||
|
||||
if (!IsValidEntityIndex(entity))
|
||||
return;
|
||||
|
||||
ge_bInvalidTrace[entity] = false;
|
||||
ge_iOwner[entity] = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void OnEntityCreated(int entity, const char[] classname)
|
||||
{
|
||||
if (!g_bConfigLoaded)
|
||||
return;
|
||||
|
||||
if (!IsValidEntityIndex(entity))
|
||||
return;
|
||||
|
||||
switch (classname[0])
|
||||
{
|
||||
case 't':
|
||||
{
|
||||
if (StrEqual(classname, CLASSNAME_TANK_ROCK))
|
||||
ge_bInvalidTrace[entity] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void HookEvents(bool hook)
|
||||
{
|
||||
if (hook && !g_bEventsHooked)
|
||||
{
|
||||
g_bEventsHooked = true;
|
||||
|
||||
HookEvent("player_hurt", Event_PlayerHurt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hook && g_bEventsHooked)
|
||||
{
|
||||
g_bEventsHooked = false;
|
||||
|
||||
UnhookEvent("player_hurt", Event_PlayerHurt);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
|
||||
public void OnClientPutInServer(int client) {
|
||||
if(GetClientTeam(client) == TEAM_INFECTED) {
|
||||
//If all specials turned off and not tank; ignore.
|
||||
if(!g_hCvar_AllSpecials.BoolValue && GetZombieClass(client) != g_iTankClass) return;
|
||||
TankSprite(client);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void Event_PlayerHurt(Event event, const char[] name, bool dontBroadcast) {
|
||||
int tank = GetClientOfUserId(event.GetInt("userid"));
|
||||
if (IsPlayerSpecialInfected(tank)) {
|
||||
TankSprite(tank);
|
||||
if(g_bCvar_AttackDelay) {
|
||||
int attacker = GetClientOfUserId(event.GetInt("attacker"));
|
||||
if (IsValidClient(attacker) && GetClientTeam(attacker) != TEAM_SURVIVOR)
|
||||
gc_fLastAttack[tank][attacker] = GetGameTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public Action TimerKill(Handle timer)
|
||||
{
|
||||
if (!g_bConfigLoaded)
|
||||
return Plugin_Continue;
|
||||
|
||||
for (int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if (gc_iTankSpriteRef[client] != INVALID_ENT_REFERENCE && !IsPlayerSpecialInfected(client)) {
|
||||
int entity = EntRefToEntIndex(gc_iTankSpriteRef[client]);
|
||||
|
||||
if (entity != INVALID_ENT_REFERENCE)
|
||||
AcceptEntityInput(entity, "Kill");
|
||||
|
||||
gc_iTankSpriteRef[client] = INVALID_ENT_REFERENCE;
|
||||
|
||||
for (int client2 = 1; client2 <= MaxClients; client2++)
|
||||
{
|
||||
gc_bVisible[client][client2] = false;
|
||||
gc_fLastAttack[client][client2] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public Action TimerVisible(Handle timer)
|
||||
{
|
||||
if (!g_bConfigLoaded)
|
||||
return Plugin_Continue;
|
||||
|
||||
if (!g_bCvar_Enabled)
|
||||
return Plugin_Continue;
|
||||
|
||||
for (int target = 1; target <= MaxClients; target++)
|
||||
{
|
||||
if (gc_iTankSpriteRef[target] == INVALID_ENT_REFERENCE)
|
||||
continue;
|
||||
|
||||
if (!IsClientConnected(target))
|
||||
continue;
|
||||
|
||||
for (int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if (!IsClientConnected(client))
|
||||
continue;
|
||||
|
||||
if (IsFakeClient(client))
|
||||
continue;
|
||||
|
||||
if (!(GetClientTeamFlag(client) & g_iCvar_Team))
|
||||
{
|
||||
gc_bVisible[target][client] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_bCvar_AttackDelay || g_bCvar_Sight)
|
||||
{
|
||||
if (GetClientTeam(client) == TEAM_SURVIVOR || GetClientTeam(client) == TEAM_HOLDOUT)
|
||||
{
|
||||
if (g_bCvar_AttackDelay && (GetGameTime() - gc_fLastAttack[target][client] > g_fCvar_AttackDelay))
|
||||
{
|
||||
gc_bVisible[target][client] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_bCvar_Sight && !IsVisibleTo(client, target))
|
||||
{
|
||||
gc_bVisible[target][client] = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gc_bVisible[target][client] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public Action TimerRender(Handle timer)
|
||||
{
|
||||
if (!g_bConfigLoaded)
|
||||
return Plugin_Continue;
|
||||
|
||||
if (!g_bCvar_Enabled)
|
||||
return Plugin_Continue;
|
||||
|
||||
for (int target = 1; target <= MaxClients; target++)
|
||||
{
|
||||
if (!IsPlayerSpecialInfected(target))
|
||||
continue;
|
||||
|
||||
TankSprite(target);
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public void TankSprite(int client)
|
||||
{
|
||||
int entity = INVALID_ENT_REFERENCE;
|
||||
|
||||
if (gc_iTankSpriteRef[client] != INVALID_ENT_REFERENCE)
|
||||
entity = EntRefToEntIndex(gc_iTankSpriteRef[client]);
|
||||
|
||||
if (entity == INVALID_ENT_REFERENCE)
|
||||
{
|
||||
entity = CreateEntityByName(CLASSNAME_ENV_SPRITE);
|
||||
DispatchKeyValue(entity, "targetname", "l4d_tank_hp_sprite");
|
||||
DispatchKeyValue(entity, "spawnflags", "1");
|
||||
DispatchKeyValue(entity, "fademindist", g_sCvar_FadeDistance);
|
||||
SetEntProp(entity, Prop_Data, "m_iHammerID", -1);
|
||||
SDKHook(entity, SDKHook_SetTransmit, OnSetTransmit);
|
||||
ge_iOwner[entity] = client;
|
||||
gc_iTankSpriteRef[client] = EntIndexToEntRef(entity);
|
||||
}
|
||||
|
||||
if (IsPlayerIncapacitated(client))
|
||||
{
|
||||
if (g_bCvar_DeadShow)
|
||||
{
|
||||
DispatchKeyValue(entity, "model", g_sCvar_DeadModel);
|
||||
DispatchKeyValue(entity, "rendercolor", g_sCvar_DeadColor);
|
||||
DispatchKeyValue(entity, "renderamt", g_sCvar_DeadAlpha); // If renderamt goes before rendercolor, it doesn't render
|
||||
DispatchKeyValue(entity, "scale", g_sCvar_DeadScale);
|
||||
DispatchSpawn(entity);
|
||||
SetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity", client);
|
||||
SetVariantString("!activator");
|
||||
AcceptEntityInput(entity, "SetParent", client);
|
||||
AcceptEntityInput(entity, "ShowSprite");
|
||||
TeleportEntity(entity, g_fVPos, NULL_VECTOR, NULL_VECTOR);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_bCvar_AliveShow)
|
||||
{
|
||||
AcceptEntityInput(entity, "HideSprite");
|
||||
return;
|
||||
}
|
||||
|
||||
int maxHealth = GetEntProp(client, Prop_Data, "m_iMaxHealth");
|
||||
int currentHealth = GetClientHealth(client);
|
||||
|
||||
float percentageHealth;
|
||||
if (maxHealth == 0)
|
||||
percentageHealth = 0.0;
|
||||
else
|
||||
percentageHealth = (float(currentHealth) / float(maxHealth));
|
||||
|
||||
bool halfHealth = (percentageHealth <= 0.5);
|
||||
|
||||
char sRenderColor[12];
|
||||
Format(sRenderColor, sizeof(sRenderColor), "%i %i 0", halfHealth ? 255 : RoundFloat(255.0 * ((1.0 - percentageHealth) * 2)), halfHealth ? RoundFloat(255.0 * (percentageHealth) * 2) : 255);
|
||||
|
||||
DispatchKeyValue(entity, "model", g_sCvar_AliveModel);
|
||||
DispatchKeyValue(entity, "rendercolor", sRenderColor);
|
||||
DispatchKeyValue(entity, "renderamt", g_sCvar_AliveAlpha); // If renderamt goes before rendercolor, it doesn't render
|
||||
DispatchKeyValue(entity, "scale", g_sCvar_AliveScale);
|
||||
DispatchSpawn(entity);
|
||||
SetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity", client);
|
||||
SetVariantString("!activator");
|
||||
AcceptEntityInput(entity, "SetParent", client);
|
||||
AcceptEntityInput(entity, "ShowSprite");
|
||||
TeleportEntity(entity, g_fVPos, NULL_VECTOR, NULL_VECTOR);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public Action OnSetTransmit(int entity, int client)
|
||||
{
|
||||
int owner = ge_iOwner[entity];
|
||||
|
||||
if (owner == client)
|
||||
return Plugin_Handled;
|
||||
|
||||
if (gc_bVisible[owner][client])
|
||||
return Plugin_Continue;
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
bool IsVisibleTo(int client, int target)
|
||||
{
|
||||
float vClientPos[3];
|
||||
float vEntityPos[3];
|
||||
float vLookAt[3];
|
||||
float vAngles[3];
|
||||
|
||||
GetClientEyePosition(client, vClientPos);
|
||||
GetClientEyePosition(target, vEntityPos);
|
||||
MakeVectorFromPoints(vClientPos, vEntityPos, vLookAt);
|
||||
GetVectorAngles(vLookAt, vAngles);
|
||||
|
||||
Handle trace = TR_TraceRayFilterEx(vClientPos, vAngles, MASK_PLAYERSOLID, RayType_Infinite, TraceFilter, target);
|
||||
|
||||
bool isVisible;
|
||||
|
||||
if (TR_DidHit(trace))
|
||||
{
|
||||
isVisible = (TR_GetEntityIndex(trace) == target);
|
||||
|
||||
if (!isVisible)
|
||||
{
|
||||
vEntityPos[2] -= 62.0; // results the same as GetClientAbsOrigin
|
||||
|
||||
delete trace;
|
||||
trace = TR_TraceHullFilterEx(vClientPos, vEntityPos, g_fVPlayerMins, g_fVPlayerMaxs, MASK_PLAYERSOLID, TraceFilter, target);
|
||||
|
||||
if (TR_DidHit(trace))
|
||||
isVisible = (TR_GetEntityIndex(trace) == target);
|
||||
}
|
||||
}
|
||||
|
||||
delete trace;
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public bool TraceFilter(int entity, int contentsMask, int client)
|
||||
{
|
||||
if (entity == client)
|
||||
return true;
|
||||
|
||||
if (IsValidClientIndex(entity))
|
||||
return false;
|
||||
|
||||
return ge_bInvalidTrace[entity] ? false : true;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
public Action CmdPrintCvars(int client, int args)
|
||||
{
|
||||
PrintToConsole(client, "");
|
||||
PrintToConsole(client, "======================================================================");
|
||||
PrintToConsole(client, "");
|
||||
PrintToConsole(client, "----------------- Plugin Cvars (l4d_tank_hp_sprite) ------------------");
|
||||
PrintToConsole(client, "");
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_version : %s", PLUGIN_VERSION);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_enable : %b (%s)", g_bCvar_Enabled, g_bCvar_Enabled ? "true" : "false");
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_z_axis : %.2f", g_fCvar_ZAxis);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_fade_distance : %i", g_iCvar_FadeDistance);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_sight : %b (%s)", g_bCvar_Sight, g_bCvar_Sight ? "true" : "false");
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_attack_delay : %.2f (%s)", g_fCvar_AttackDelay, g_bCvar_AttackDelay ? "true" : "false");
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_alive_show : %b (%s)", g_bCvar_AliveShow, g_bCvar_AliveShow ? "true" : "false");
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_alive_model : \"%s\"", g_sCvar_AliveModel);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_alive_alpha : %i", g_iCvar_AliveAlpha);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_alive_scale : %.2f", g_fCvar_AliveScale);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_dead_show : %b (%s)", g_bCvar_DeadShow, g_bCvar_DeadShow ? "true" : "false");
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_dead_model : \"%s\"", g_sCvar_DeadModel);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_dead_alpha : %i", g_iCvar_DeadAlpha);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_dead_scale : %.2f", g_fCvar_DeadScale);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_dead_color : \"%s\"", g_sCvar_DeadColor);
|
||||
PrintToConsole(client, "l4d_tank_hp_sprite_team : %i", g_iCvar_Team);
|
||||
PrintToConsole(client, "");
|
||||
PrintToConsole(client, "======================================================================");
|
||||
PrintToConsole(client, "");
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// ====================================================================================================
|
||||
// Helpers
|
||||
// ====================================================================================================
|
||||
/**
|
||||
* Validates if is a valid client index.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True if client index is valid, false otherwise.
|
||||
*/
|
||||
bool IsValidClientIndex(int client)
|
||||
{
|
||||
return (1 <= client <= MaxClients);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Validates if is a valid client.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True if client index is valid and client is in game, false otherwise.
|
||||
*/
|
||||
bool IsValidClient(int client)
|
||||
{
|
||||
return (IsValidClientIndex(client) && IsClientInGame(client));
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Validates if is a valid entity index (between MaxClients+1 and 2048).
|
||||
*
|
||||
* @param entity Entity index.
|
||||
* @return True if entity index is valid, false otherwise.
|
||||
*/
|
||||
bool IsValidEntityIndex(int entity)
|
||||
{
|
||||
return (MaxClients+1 <= entity <= GetMaxEntities());
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Gets the client L4D1/L4D2 zombie class id.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return L4D1 1=SMOKER, 2=BOOMER, 3=HUNTER, 4=WITCH, 5=TANK, 6=NOT INFECTED
|
||||
* @return L4D2 1=SMOKER, 2=BOOMER, 3=HUNTER, 4=SPITTER, 5=JOCKEY, 6=CHARGER, 7=WITCH, 8=TANK, 9=NOT INFECTED
|
||||
*/
|
||||
int GetZombieClass(int client)
|
||||
{
|
||||
return (GetEntProp(client, Prop_Send, "m_zombieClass"));
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Returns is a player is in ghost state.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True if client is in ghost state, false otherwise.
|
||||
*/
|
||||
bool IsPlayerGhost(int client)
|
||||
{
|
||||
return (GetEntProp(client, Prop_Send, "m_isGhost") == 1);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Validates if the client is incapacitated.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True if the client is incapacitated, false otherwise.
|
||||
*/
|
||||
bool IsPlayerIncapacitated(int client)
|
||||
{
|
||||
return (GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1);
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Returns if the client is a valid tank.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True if client is a tank, false otherwise.
|
||||
*/
|
||||
bool IsPlayerSpecialInfected(int client) {
|
||||
bool isValid = IsValidClient(client) && GetClientTeam(client) == TEAM_INFECTED && IsPlayerAlive(client) && !IsPlayerGhost(client);
|
||||
if(!g_hCvar_AllSpecials.BoolValue && GetZombieClass(client) != g_iTankClass)
|
||||
return false;
|
||||
else
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the team flag from a client.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Client team flag.
|
||||
*/
|
||||
int GetClientTeamFlag(int client)
|
||||
{
|
||||
switch (GetClientTeam(client))
|
||||
{
|
||||
case TEAM_SURVIVOR:
|
||||
return FLAG_TEAM_SURVIVOR;
|
||||
case TEAM_INFECTED:
|
||||
return FLAG_TEAM_INFECTED;
|
||||
case TEAM_SPECTATOR:
|
||||
return FLAG_TEAM_SPECTATOR;
|
||||
case TEAM_HOLDOUT:
|
||||
return FLAG_TEAM_HOLDOUT;
|
||||
default:
|
||||
return FLAG_TEAM_NONE;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue