Update updated part of README.md

This commit is contained in:
Jackzie 2021-04-20 21:44:43 -05:00
parent 73fa3ea30f
commit f1ad9f3865
No known key found for this signature in database
GPG key ID: 1E834FE36520537A
21 changed files with 4934 additions and 89 deletions

View file

@ -166,7 +166,7 @@ This really only affects wandering zombies, mobs and panic events, but it may wo
### l4d2_feedthetrolls
This plugin allows you to enact certain troll modes on any player, some are subtle some are less so. Either way, it works great to deal with a rusher, an asshole or even your friends.
Troll Modes: (updated 1/2/2021)
Troll Modes: (updated 4/20/2021)
1. **SlowSpeed** (0.8 < 1.0 base) - Slows down a user
2. **HigherGravity** (1.3 > 1.0) - Adds more gravity to a user

BIN
plugins/BumpMineGiver.smx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
plugins/left4dhooks.smx Normal file

Binary file not shown.

BIN
plugins/sceneprocessor.smx Normal file

Binary file not shown.

View file

@ -24,7 +24,7 @@ public Plugin myinfo =
url = PLUGIN_URL
};
bool g_EnteredCheckpoint = false;
ConVar g_EnteredCheckpoint;
public void OnPluginStart()
{
@ -34,28 +34,31 @@ public void OnPluginStart()
SetFailState("This plugin is for L4D/L4D2 only.");
}
HookEvent("player_entered_checkpoint", Event_PlayerEnteredCheckpoint);
HookEvent("round_start",Event_RoundStart);
HookEvent("player_left_start_area",Event_RoundStart);
g_EnteredCheckpoint = CreateConVar("awb_status", "0", "Get status of plugin", FCVAR_SPONLY | FCVAR_DONTRECORD, true, 0.0, true, 1.0);
}
public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
g_EnteredCheckpoint = false;
if(g_EnteredCheckpoint.BoolValue) g_EnteredCheckpoint.BoolValue = false;
}
public void Event_PlayerEnteredCheckpoint(Event event, const char[] name, bool dontBroadcast) {
if(!g_EnteredCheckpoint) {
PrintToChatAll("boolvalue %d | client %d", g_EnteredCheckpoint.BoolValue, GetClientOfUserId(event.GetInt("userid")));
if(!g_EnteredCheckpoint.BoolValue) {
int client = GetClientOfUserId(event.GetInt("userid"));
bool playersLeft = false;
for (int i = 1; i < MaxClients;i++) {
if (client == i)continue;
if (!IsClientConnected(i)) continue;
if (client == i) continue;
if (!IsClientInGame(i)) continue;
if (GetClientTeam(i) != 2) continue;
PrintToChatAll("playersLeft: %d . clientr %d", playersLeft, i);
if(!IsFakeClient(i)) {
playersLeft = true;
break;
}
}
if(!playersLeft) {
g_EnteredCheckpoint = true;
g_EnteredCheckpoint.BoolValue = true;
CheatCommand(client,"warp_all_survivors_to_checkpoint","","");
}
}

114
scripting/BumpMineGiver.sp Normal file
View file

@ -0,0 +1,114 @@
#pragma semicolon 1
#define DEBUG
#define PLUGIN_AUTHOR ""
#define PLUGIN_VERSION "0.00"
#include <sourcemod>
#include <sdktools>
#include <cstrike>
//#include <sdkhooks>
#pragma newdecls required
ConVar g_bmgTTeam, g_bmgEnabled, g_bmgCmdLimit;
int g_bmgBumpsGiven[MAXPLAYERS+1];
public Plugin myinfo =
{
name = "BumpMineGiver",
author = PLUGIN_AUTHOR,
description = "",
version = PLUGIN_VERSION,
url = ""
};
public void OnPluginStart()
{
EngineVersion g_Game = GetEngineVersion();
if(g_Game != Engine_CSGO && g_Game != Engine_CSS)
{
SetFailState("This plugin is for CSGO/CSS only.");
}
g_bmgEnabled = CreateConVar("bmg_enabled", "1", "Should BumpMineGiver be enabled?", FCVAR_NONE, true, 0.0, true, 1.0);
g_bmgTTeam = CreateConVar("bmg_restrict_team", "0", "Should BumpMineGiver be restricted to a team? 0 - All, 1 - Terrorists, 2 - CounterTerrorists", FCVAR_NONE, true, 0.0, true, 3.0);
g_bmgCmdLimit = CreateConVar("bmg_cmdlimit", "0", "Limit of amount of bumpmines to be given with !bmp. 0: Disabled, -1: Infinity", FCVAR_NONE);
HookEvent("round_start", Event_RoundStart);
HookEvent("player_spawn", Event_PlayerSpawn);
RegConsoleCmd("sm_bmp", Command_GiveBMP, "Give yourself a bump mine");
RegConsoleCmd("sm_bmg", Command_GiveBMP, "Give yourself a bump mine");
RegAdminCmd("sm_givebmp", Command_GiveOthersBMP, ADMFLAG_CHEATS, "Give someone x amount of bump mines. Usage: sm_givebmp <user>");
AutoExecConfig();
}
public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
for (int i = 0; i < sizeof(g_bmgBumpsGiven); i++) {
g_bmgBumpsGiven[i] = 0;
}
}
public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) {
if(g_bmgEnabled.BoolValue) {
int client = GetClientOfUserId(event.GetInt("userid"));
int wpn_id = GetPlayerWeaponSlot(client, 4);
int team = GetClientTeam(client);
if(g_bmgTTeam.IntValue > 0) { //1 or 2
if (team != g_bmgTTeam.IntValue) return;
}
if(wpn_id == -1) {
GivePlayerItem(client, "weapon_bumpmine");
}
}
}
public Action Command_GiveBMP(int client, int args) {
if(g_bmgCmdLimit.IntValue == 0) {
ReplyToCommand(client, "You have hit the limit of bumpmines");
return Plugin_Handled;
}
//limit is enabled, check
if(g_bmgCmdLimit.IntValue > 0) {
if(g_bmgBumpsGiven[client] > g_bmgCmdLimit.IntValue) {
ReplyToCommand(client, "You have hit the limit of bumpmines");
return Plugin_Handled;
}
}
GivePlayerItem(client, "weapon_bumpmine");
g_bmgBumpsGiven[client]++;
return Plugin_Handled;
}
public Action Command_GiveOthersBMP(int client, int args) {
if(args < 1) {
ReplyToCommand(client, "Usage: sm_givebmp <user>");
}else{
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
COMMAND_FILTER_ALIVE, /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0)
{
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++)
{
GivePlayerItem(target_list[i], "weapon_bumpmine");
LogAction(client, target_list[i], "\"%L\" gave \"%L\" a bumpmine", client, target_list[i]);
}
}
return Plugin_Handled;
}

View file

@ -0,0 +1,57 @@
#pragma semicolon 1
#pragma newdecls required
//#define DEBUG
#define PLUGIN_NAME "L4D2 Prevent Bot Movement"
#define PLUGIN_DESCRIPTION "Prevents bots from moving in the beginning of the round for a set period of time."
#define PLUGIN_AUTHOR "jackzmc"
#define PLUGIN_VERSION "1.0"
#define PLUGIN_URL ""
#include <sourcemod>
#include <sdktools>
//#include <sdkhooks>
public Plugin myinfo =
{
name = PLUGIN_NAME,
author = PLUGIN_AUTHOR,
description = PLUGIN_DESCRIPTION,
version = PLUGIN_VERSION,
url = PLUGIN_URL
};
static ConVar hSBStop, hStopTime;
public void OnPluginStart()
{
EngineVersion g_Game = GetEngineVersion();
if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2)
{
SetFailState("This plugin is for L4D/L4D2 only.");
}
HookEvent("round_start",Event_RoundStart);
hStopTime = CreateConVar("sm_freeze_bot_time","20.0","How long should the bots be frozen for on beginning of round? 0 to disable",FCVAR_NONE,true,0.0);
hSBStop = FindConVar("sb_stop");
}
public void OnMapStart() {
if(hStopTime.IntValue != 0) {
PrintToChatAll("round start");
hSBStop.BoolValue = true;
CreateTimer(hStopTime.FloatValue, ResumeBots);
}
}
public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
if(hStopTime.IntValue != 0) {
PrintToChatAll("round start");
hSBStop.BoolValue = true;
CreateTimer(hStopTime.FloatValue, ResumeBots);
}
}
public Action ResumeBots(Handle timer) {
PrintToChatAll("Resuming bots");
hSBStop.BoolValue = false;
}

60
scripting/csgo-misc.sp Normal file
View file

@ -0,0 +1,60 @@
#pragma semicolon 1
#define DEBUG
#define PLUGIN_AUTHOR ""
#define PLUGIN_VERSION "0.00"
#include <sourcemod>
#include <sdktools>
#include <cstrike>
//#include <sdkhooks>
#pragma newdecls required
public Plugin myinfo =
{
name = "",
author = PLUGIN_AUTHOR,
description = "",
version = PLUGIN_VERSION,
url = ""
};
public void OnPluginStart()
{
EngineVersion g_Game = GetEngineVersion();
if(g_Game != Engine_CSGO && g_Game != Engine_CSS)
{
SetFailState("This plugin is for CSGO/CSS only.");
}
RegConsoleCmd("sm_first", Command_FirstPov, "Go back to first person");
RegConsoleCmd("sm_third", Command_ThirdPov, "Go to third person");
}
public Action Command_FirstPov(int client, int args) {
if(client == 0) {
ReplyToCommand(client, "This command is for clients only");
return Plugin_Handled;
}
CheatCommand(client, "firstperson", "", "");
return Plugin_Handled;
}
public Action Command_ThirdPov(int client, int args) {
if(client == 0) {
ReplyToCommand(client, "This command is for clients only");
return Plugin_Handled;
}
CheatCommand(client, "thirdperson", "", "");
return Plugin_Handled;
}
stock void CheatCommand(int client, char[] command, char[] argument1, char[] argument2)
{
int userFlags = GetUserFlagBits(client);
SetUserFlagBits(client, ADMFLAG_ROOT);
int flags = GetCommandFlags(command);
SetCommandFlags(command, flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "%s %s %s", command, argument1, argument2);
SetCommandFlags(command, flags);
SetUserFlagBits(client, userFlags);
}

View file

@ -0,0 +1,233 @@
#pragma semicolon 1
#pragma newdecls required //強制1.7以後的新語法
#include <sourcemod>
#include <sdktools>
#define MODEL_V_FIREAXE "models/weapons/melee/v_fireaxe.mdl"
#define MODEL_V_FRYING_PAN "models/weapons/melee/v_frying_pan.mdl"
#define MODEL_V_MACHETE "models/weapons/melee/v_machete.mdl"
#define MODEL_V_BASEBALL_BAT "models/weapons/melee/v_bat.mdl"
#define MODEL_V_CROWBAR "models/weapons/melee/v_crowbar.mdl"
#define MODEL_V_CRICKET_BAT "models/weapons/melee/v_cricket_bat.mdl"
#define MODEL_V_TONFA "models/weapons/melee/v_tonfa.mdl"
#define MODEL_V_KATANA "models/weapons/melee/v_katana.mdl"
#define MODEL_V_ELECTRIC_GUITAR "models/weapons/melee/v_electric_guitar.mdl"
#define MODEL_V_GOLFCLUB "models/weapons/melee/v_golfclub.mdl"
#define MODEL_V_SHIELD "models/weapons/melee/v_riotshield.mdl"
#define MODEL_V_KNIFE "models/v_models/v_knife_t.mdl"
#define MODEL_V_SHOVEL "models/weapons/melee/v_shovel.mdl"
#define MODEL_V_PITCHFORK "models/weapons/melee/v_pitchfork.mdl"
static g_PlayerSecondaryWeapons[MAXPLAYERS + 1];
public Plugin myinfo =
{
name = "L4D2 Drop Secondary",
author = "Jahze, Visor, NoBody & HarryPotter",
version = "1.8",
description = "Survivor players will drop their secondary weapon when they die",
url = "https://github.com/Attano/Equilibrium"
};
public void OnPluginStart()
{
HookEvent("round_start", OnRoundStart, EventHookMode_PostNoCopy);
HookEvent("player_use", OnPlayerUse, EventHookMode_Post);
HookEvent("player_bot_replace", player_bot_replace);
HookEvent("bot_player_replace", bot_player_replace);
HookEvent("player_death", OnPlayerDeath, EventHookMode_Pre);
HookEvent("weapon_drop", OnWeaponDrop);
HookEvent("item_pickup", OnItemPickUp);
}
public void OnRoundStart(Event event, const char[] name, bool dontBroadcast)
{
for (int i = 0; i <= MAXPLAYERS; i++)
{
g_PlayerSecondaryWeapons[i] = -1;
}
}
public Action OnPlayerUse(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if(client == 0 || !IsClientInGame(client) || GetClientTeam(client) != 2)
{
return;
}
int weapon = GetPlayerWeaponSlot(client, 1);
g_PlayerSecondaryWeapons[client] = (weapon == -1 ? weapon : EntIndexToEntRef(weapon));
}
public Action bot_player_replace(Event event, const char[] name, bool dontBroadcast)
{
int bot = GetClientOfUserId(event.GetInt("bot"));
int client = GetClientOfUserId(event.GetInt("player"));
g_PlayerSecondaryWeapons[client] = g_PlayerSecondaryWeapons[bot];
g_PlayerSecondaryWeapons[bot] = -1;
}
public Action player_bot_replace(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("player"));
int bot = GetClientOfUserId(event.GetInt("bot"));
g_PlayerSecondaryWeapons[bot] = g_PlayerSecondaryWeapons[client];
g_PlayerSecondaryWeapons[client] = -1;
}
public Action OnItemPickUp(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if(client == 0 || !IsClientInGame(client) || GetClientTeam(client) != 2)
{
return;
}
int weapon = GetPlayerWeaponSlot(client, 1);
g_PlayerSecondaryWeapons[client] = (weapon == -1 ? weapon : EntIndexToEntRef(weapon));
}
public Action OnWeaponDrop(Event event, const char[] name, bool dontBroadcast)
{
CreateTimer(0.1, ColdDown, event.GetInt("userid"));
}
public Action ColdDown(Handle timer, int client)
{
client = GetClientOfUserId(client);
if(client && IsClientInGame(client) && GetClientTeam(client) == 2)
{
int weapon = GetPlayerWeaponSlot(client, 1);
g_PlayerSecondaryWeapons[client] = (weapon == -1 ? weapon : EntIndexToEntRef(weapon));
}
}
public Action OnPlayerDeath(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if(client == 0 || !IsClientInGame(client) || GetClientTeam(client) != 2)
{
return;
}
int weapon = EntRefToEntIndex(g_PlayerSecondaryWeapons[client]);
if(weapon == INVALID_ENT_REFERENCE)
{
return;
}
char sWeapon[32];
int clip;
GetEdictClassname(weapon, sWeapon, 32);
int index = CreateEntityByName(sWeapon);
float origin[3];
float ang[3];
if (strcmp(sWeapon, "weapon_melee") == 0)
{
char melee[150];
GetEntPropString(weapon , Prop_Data, "m_ModelName", melee, sizeof(melee));
if (strcmp(melee, MODEL_V_FIREAXE) == 0)
{
DispatchKeyValue(index, "melee_script_name", "fireaxe");
}
else if (strcmp(melee, MODEL_V_FRYING_PAN) == 0)
{
DispatchKeyValue(index, "melee_script_name", "frying_pan");
}
else if (strcmp(melee, MODEL_V_MACHETE) == 0)
{
DispatchKeyValue(index, "melee_script_name", "machete");
}
else if (strcmp(melee, MODEL_V_BASEBALL_BAT) == 0)
{
DispatchKeyValue(index, "melee_script_name", "baseball_bat");
}
else if (strcmp(melee, MODEL_V_CROWBAR) == 0)
{
DispatchKeyValue(index, "melee_script_name", "crowbar");
}
else if (strcmp(melee, MODEL_V_CRICKET_BAT) == 0)
{
DispatchKeyValue(index, "melee_script_name", "cricket_bat");
}
else if (strcmp(melee, MODEL_V_TONFA) == 0)
{
DispatchKeyValue(index, "melee_script_name", "tonfa");
}
else if (strcmp(melee, MODEL_V_KATANA) == 0)
{
DispatchKeyValue(index, "melee_script_name", "katana");
}
else if (strcmp(melee, MODEL_V_ELECTRIC_GUITAR) == 0)
{
DispatchKeyValue(index, "melee_script_name", "electric_guitar");
}
else if (strcmp(melee, MODEL_V_GOLFCLUB) == 0)
{
DispatchKeyValue(index, "melee_script_name", "golfclub");
}
else if (strcmp(melee, MODEL_V_SHIELD) == 0)
{
DispatchKeyValue(index, "melee_script_name", "riotshield");
}
else if (strcmp(melee, MODEL_V_KNIFE) == 0)
{
DispatchKeyValue(index, "melee_script_name", "knife");
}
else if (strcmp(melee, MODEL_V_SHOVEL) == 0)
{
DispatchKeyValue(index, "melee_script_name", "shovel");
}
else if (strcmp(melee, MODEL_V_PITCHFORK) == 0)
{
DispatchKeyValue(index, "melee_script_name", "pitchfork");
}
else return;
}
else if (strcmp(sWeapon, "weapon_chainsaw") == 0)
{
clip = GetEntProp(weapon, Prop_Send, "m_iClip1");
}
else if (strcmp(sWeapon, "weapon_pistol") == 0 && (GetEntProp(weapon, Prop_Send, "m_isDualWielding") > 0))
{
int indexC = CreateEntityByName(sWeapon);
GetClientEyePosition(client,origin);
GetClientEyeAngles(client, ang);
GetAngleVectors(ang, ang, NULL_VECTOR,NULL_VECTOR);
NormalizeVector(ang,ang);
ScaleVector(ang, 90.0);
DispatchSpawn(indexC);
TeleportEntity(indexC, origin, NULL_VECTOR, ang);
}
else if (strcmp(sWeapon, "weapon_pistol_magnum") == 0)
{
clip = GetEntProp(weapon, Prop_Send, "m_iClip1");
}
RemovePlayerItem(client, weapon);
RemoveEntity(weapon);
GetClientEyePosition(client,origin);
GetClientEyeAngles(client, ang);
GetAngleVectors(ang, ang, NULL_VECTOR,NULL_VECTOR);
NormalizeVector(ang,ang);
ScaleVector(ang, 90.0);
DispatchSpawn(index);
TeleportEntity(index, origin, NULL_VECTOR, ang);
if (strcmp(sWeapon, "weapon_chainsaw") == 0 || strcmp(sWeapon, "weapon_pistol") == 0 || strcmp(sWeapon, "weapon_pistol_magnum") == 0)
{
SetEntProp(index, Prop_Send, "m_iClip1", clip);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
#pragma semicolon 1
#pragma newdecls required
//#define DEBUG
#define PLUGIN_VERSION "1.0"
#define GAMEDATA "l4d_target_override"
#include <sourcemod>
#include <sdktools>
#include <left4dhooks>
enum L4D2Infected
{
L4D2Infected_None = 0,
L4D2Infected_Smoker = 1,
L4D2Infected_Boomer = 2,
L4D2Infected_Hunter = 3,
L4D2Infected_Spitter = 4,
L4D2Infected_Jockey = 5,
L4D2Infected_Charger = 6,
L4D2Infected_Witch = 7,
L4D2Infected_Tank = 8
}
public Plugin myinfo =
{
name = "L4D2 target poo",
author = "jackzmc",
description = "",
version = PLUGIN_VERSION,
url = ""
};
bool g_bIsVictim[MAXPLAYERS+1];
Handle g_hDetour;
public void OnPluginStart()
{
EngineVersion g_Game = GetEngineVersion();
if(g_Game != Engine_Left4Dead2)
{
SetFailState("This plugin is for L4D2 only.");
}
RegAdminCmd("sm_set_victim", Cmd_SetVictim, ADMFLAG_CHEATS);
HookEvent("player_death", Event_PlayerDeath);
}
public void OnPluginEnd()
{
}
public Action Cmd_SetVictim(int client, int args) {
if(args == 0) {
ReplyToCommand(client, "Please enter a player to target");
}else{
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[1], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
COMMAND_FILTER_ALIVE, /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0)
{
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for(int i = 0; i < target_count; i++) {
int victim = target_list[i];
//g_iSITargets
g_bIsVictim[victim] = !g_bIsVictim[victim];
ReplyToCommand(client, "Successfully toggled %N victim status to: %b", victim, g_bIsVictim[victim]);
ShowActivity(client, "toggled special infected victim status for %N to %b", victim, g_bIsVictim[victim]);
}
}
return Plugin_Handled;
}
static int b_attackerTarget[MAXPLAYERS+1];
public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
// =========================
// OVERRIDE VICTIM
// =========================
L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass"));
if(class != L4D2Infected_Tank) {
int existingTarget = GetClientOfUserId(b_attackerTarget[attacker]);
if(existingTarget > 0) {
curTarget = existingTarget;
return Plugin_Changed;
}
float closestDistance, survPos[3], spPos[3];
GetClientAbsOrigin(attacker, spPos);
int closestClient = -1;
for(int i = 1; i <= MaxClients; i++) {
if(g_bIsVictim[i] && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, spPos, true);
if(closestClient == -1 || dist < closestDistance) {
closestDistance = dist;
closestClient = i;
}
}
}
if(closestClient > 0) {
PrintToConsoleAll("Attacker %N new target: %N", attacker, closestClient);
b_attackerTarget[attacker] = GetClientUserId(closestClient);
curTarget = closestClient;
return Plugin_Changed;
}
}
return Plugin_Continue;
}
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
b_attackerTarget[client] = 0;
}
public void OnClientDisconnect(int client) {
b_attackerTarget[client] = 0;
}

View file

@ -2,11 +2,24 @@
// ====================================================================================================
Change Log:
1.0.6 (12-February-2021)
- Fixed custom model cvar typo. (thanks "weffer" for reporting)
1.0.5 (11-February-2021)
- Fixed a bug not rendering custom sprites right after turning it on.
- Added one more custom sprite option with an alpha background filling the bar.
1.0.4 (11-February-2021)
- Added custom sprite option.
1.0.3 (08-February-2021)
- Fixed missing client in-game in visibility check. (thanks to "Krufftys Killers" and "Striker black")
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.
- Moved visibility logic to timer handle.
1.0.1 (30-January-2021)
- Public release.
@ -23,7 +36,7 @@ Change Log:
#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_VERSION "1.0.5"
#define PLUGIN_URL "https://forums.alliedmods.net/showthread.php?t=330370"
// ====================================================================================================
@ -66,6 +79,7 @@ public Plugin myinfo =
// Defines
// ====================================================================================================
#define CLASSNAME_ENV_SPRITE "env_sprite"
#define CLASSNAME_ENV_TEXTURETOGGLE "env_texturetoggle"
#define CLASSNAME_TANK_ROCK "tank_rock"
#define TEAM_SPECTATOR 1
@ -102,6 +116,9 @@ static ConVar g_hCvar_DeadAlpha;
static ConVar g_hCvar_DeadScale;
static ConVar g_hCvar_DeadColor;
static ConVar g_hCvar_Team;
static ConVar g_hCvar_CustomModel;
static ConVar g_hCvar_CustomModelVMT;
static ConVar g_hCvar_CustomModelVTF;
static ConVar g_hCvar_AllSpecials;
// ====================================================================================================
@ -115,6 +132,7 @@ static bool g_bCvar_Sight;
static bool g_bCvar_AttackDelay;
static bool g_bCvar_AliveShow;
static bool g_bCvar_DeadShow;
static bool g_bCvar_CustomModel;
// ====================================================================================================
// int - Plugin Variables
@ -147,11 +165,14 @@ static char g_sCvar_DeadAlpha[4];
static char g_sCvar_DeadScale[5];
static char g_sCvar_DeadColor[12];
static char g_sCvar_FadeDistance[5];
static char g_sCvar_CustomModelVMT[100];
static char g_sCvar_CustomModelVTF[100];
// ====================================================================================================
// client - Plugin Variables
// ====================================================================================================
static int gc_iTankSpriteRef[MAXPLAYERS+1] = { INVALID_ENT_REFERENCE, ... };
static int gc_iTankSpriteFrameRef[MAXPLAYERS+1] = { INVALID_ENT_REFERENCE, ... };
static bool gc_bVisible[MAXPLAYERS+1][MAXPLAYERS+1];
static float gc_fLastAttack[MAXPLAYERS+1][MAXPLAYERS+1];
@ -185,21 +206,24 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
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_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_CustomModel = CreateConVar("l4d_tank_hp_sprite_custom_model", "0", "Use a custom sprite for the alive model\nNote: This requires the client downloading the custom model (.vmt and .vtf) to work.\nSearch for FastDL for more info.\n0 = OFF, 1 = ON.", CVAR_FLAGS, true, 0.0, true, 1.0);
g_hCvar_CustomModelVMT = CreateConVar("l4d_tank_hp_sprite_custom_model_vmt", "materials/mart/mart_custombar.vmt", "Custom sprite VMT path.");
g_hCvar_CustomModelVTF = CreateConVar("l4d_tank_hp_sprite_custom_model_vtf", "materials/mart/mart_custombar.vtf", "Custom sprite VTF path.");
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);
@ -217,6 +241,9 @@ public void OnPluginStart()
g_hCvar_DeadScale.AddChangeHook(Event_ConVarChanged);
g_hCvar_DeadColor.AddChangeHook(Event_ConVarChanged);
g_hCvar_Team.AddChangeHook(Event_ConVarChanged);
g_hCvar_CustomModel.AddChangeHook(Event_ConVarChanged);
g_hCvar_CustomModelVMT.AddChangeHook(Event_ConVarChanged);
g_hCvar_CustomModelVTF.AddChangeHook(Event_ConVarChanged);
// Load plugin configs from .cfg
AutoExecConfig(true, CONFIG_FILENAME);
@ -234,7 +261,7 @@ public void OnPluginStart()
public void OnPluginEnd()
{
int entity;
char targetname[64];
char targetname[19];
entity = INVALID_ENT_REFERENCE;
while ((entity = FindEntityByClassname(entity, CLASSNAME_ENV_SPRITE)) != INVALID_ENT_REFERENCE)
@ -285,7 +312,6 @@ public void GetCvars()
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;
@ -293,7 +319,6 @@ public void GetCvars()
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;
@ -301,6 +326,28 @@ public void GetCvars()
g_hCvar_DeadColor.GetString(g_sCvar_DeadColor, sizeof(g_sCvar_DeadColor));
TrimString(g_sCvar_DeadColor);
g_iCvar_Team = g_hCvar_Team.IntValue;
g_bCvar_CustomModel = g_hCvar_CustomModel.BoolValue;
g_hCvar_CustomModelVMT.GetString(g_sCvar_CustomModelVMT, sizeof(g_sCvar_CustomModelVMT));
TrimString(g_sCvar_CustomModelVMT);
g_hCvar_CustomModelVTF.GetString(g_sCvar_CustomModelVTF, sizeof(g_sCvar_CustomModelVTF));
TrimString(g_sCvar_CustomModelVTF);
if (g_bCvar_AliveShow)
{
if (g_bCvar_CustomModel)
{
AddFileToDownloadsTable(g_sCvar_CustomModelVMT);
AddFileToDownloadsTable(g_sCvar_CustomModelVTF);
PrecacheModel(g_sCvar_CustomModelVMT, true);
}
else
{
PrecacheModel(g_sCvar_AliveModel, true);
}
}
if (g_bCvar_DeadShow)
PrecacheModel(g_sCvar_DeadModel, true);
}
/****************************************************************************************************/
@ -309,8 +356,10 @@ public void LateLoad()
{
for (int client = 1; client <= MaxClients; client++)
{
if (IsPlayerSpecialInfected(client))
TankSprite(client);
if (!IsPlayerTank(client))
continue;
TankSprite(client);
}
}
@ -322,6 +371,7 @@ public void OnClientDisconnect(int client)
return;
gc_iTankSpriteRef[client] = INVALID_ENT_REFERENCE;
gc_iTankSpriteFrameRef[client] = INVALID_ENT_REFERENCE;
for (int target = 1; target <= MaxClients; target++)
{
@ -372,6 +422,7 @@ public void HookEvents(bool hook)
{
g_bEventsHooked = true;
HookEvent("tank_spawn", Event_TankSpawn);
HookEvent("player_hurt", Event_PlayerHurt);
return;
@ -381,6 +432,7 @@ public void HookEvents(bool hook)
{
g_bEventsHooked = false;
UnhookEvent("tank_spawn", Event_TankSpawn);
UnhookEvent("player_hurt", Event_PlayerHurt);
return;
@ -389,27 +441,37 @@ public void HookEvents(bool hook)
/****************************************************************************************************/
public void Event_TankSpawn(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
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);
}
if (!IsValidClient(client))
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 void Event_PlayerHurt(Event event, const char[] name, bool dontBroadcast)
{
if (!g_bCvar_AttackDelay)
return;
int target = GetClientOfUserId(event.GetInt("userid"));
if (!IsPlayerTank(target))
return;
int attacker = GetClientOfUserId(event.GetInt("attacker"));
if (!IsValidClient(attacker))
return;
if (GetClientTeam(attacker) != TEAM_SURVIVOR)
return;
gc_fLastAttack[target][attacker] = GetGameTime();
}
/****************************************************************************************************/
@ -419,21 +481,26 @@ public Action TimerKill(Handle timer)
if (!g_bConfigLoaded)
return Plugin_Continue;
for (int client = 1; client <= MaxClients; client++)
for (int target = 1; target <= MaxClients; target++)
{
if (gc_iTankSpriteRef[client] != INVALID_ENT_REFERENCE && !IsPlayerSpecialInfected(client)) {
int entity = EntRefToEntIndex(gc_iTankSpriteRef[client]);
if (gc_iTankSpriteRef[target] == INVALID_ENT_REFERENCE)
continue;
if (entity != INVALID_ENT_REFERENCE)
AcceptEntityInput(entity, "Kill");
if (g_bCvar_Enabled && IsPlayerTank(target))
continue;
gc_iTankSpriteRef[client] = INVALID_ENT_REFERENCE;
int entity = EntRefToEntIndex(gc_iTankSpriteRef[target]);
for (int client2 = 1; client2 <= MaxClients; client2++)
{
gc_bVisible[client][client2] = false;
gc_fLastAttack[client][client2] = 0.0;
}
if (entity != INVALID_ENT_REFERENCE)
AcceptEntityInput(entity, "Kill");
gc_iTankSpriteRef[target] = INVALID_ENT_REFERENCE;
gc_iTankSpriteFrameRef[target] = INVALID_ENT_REFERENCE;
for (int client = 1; client <= MaxClients; client++)
{
gc_bVisible[target][client] = false;
gc_fLastAttack[target][client] = 0.0;
}
}
@ -455,38 +522,31 @@ public Action TimerVisible(Handle timer)
if (gc_iTankSpriteRef[target] == INVALID_ENT_REFERENCE)
continue;
if (!IsClientConnected(target))
if (!IsClientInGame(target))
continue;
for (int client = 1; client <= MaxClients; client++)
{
if (!IsClientConnected(client))
gc_bVisible[target][client] = false;
if (!IsClientInGame(client))
continue;
if (IsFakeClient(client))
continue;
if (!(GetClientTeamFlag(client) & g_iCvar_Team))
{
gc_bVisible[target][client] = false;
if (!(GetTeamFlag(GetClientTeam(client)) & g_iCvar_Team))
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;
}
}
}
@ -509,7 +569,7 @@ public Action TimerRender(Handle timer)
for (int target = 1; target <= MaxClients; target++)
{
if (!IsPlayerSpecialInfected(target))
if (!IsPlayerTank(target))
continue;
TankSprite(target);
@ -529,14 +589,43 @@ public void TankSprite(int client)
if (entity == INVALID_ENT_REFERENCE)
{
char targetname[22];
FormatEx(targetname, sizeof(targetname), "%s-%i", "l4d_tank_hp_sprite", client);
entity = CreateEntityByName(CLASSNAME_ENV_SPRITE);
DispatchKeyValue(entity, "targetname", "l4d_tank_hp_sprite");
ge_iOwner[entity] = client;
gc_iTankSpriteRef[client] = EntIndexToEntRef(entity);
DispatchKeyValue(entity, "targetname", targetname);
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 (g_bCvar_CustomModel)
{
int entityFrame = INVALID_ENT_REFERENCE;
if (gc_iTankSpriteFrameRef[client] != INVALID_ENT_REFERENCE)
entityFrame = EntRefToEntIndex(gc_iTankSpriteFrameRef[client]);
if (entityFrame == INVALID_ENT_REFERENCE)
{
char targetname[22];
FormatEx(targetname, sizeof(targetname), "%s-%i", "l4d_tank_hp_sprite", client);
entityFrame = CreateEntityByName(CLASSNAME_ENV_TEXTURETOGGLE);
gc_iTankSpriteFrameRef[client] = EntIndexToEntRef(entityFrame);
DispatchKeyValue(entityFrame, "targetname", "l4d_tank_hp_sprite");
DispatchKeyValue(entityFrame, "target", targetname);
TeleportEntity(entityFrame, g_fVPos, NULL_VECTOR, NULL_VECTOR);
DispatchSpawn(entityFrame);
ActivateEntity(entityFrame);
SetVariantString("!activator");
AcceptEntityInput(entityFrame, "SetParent", entity);
}
}
if (IsPlayerIncapacitated(client))
@ -547,12 +636,15 @@ public void TankSprite(int client)
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);
TeleportEntity(entity, g_fVPos, NULL_VECTOR, NULL_VECTOR);
DispatchSpawn(entity);
ActivateEntity(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;
@ -568,9 +660,7 @@ public void TankSprite(int client)
int currentHealth = GetClientHealth(client);
float percentageHealth;
if (maxHealth == 0)
percentageHealth = 0.0;
else
if (maxHealth > 0)
percentageHealth = (float(currentHealth) / float(maxHealth));
bool halfHealth = (percentageHealth <= 0.5);
@ -578,16 +668,35 @@ public void TankSprite(int client)
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, "model", g_bCvar_CustomModel ? g_sCvar_CustomModelVMT : 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);
TeleportEntity(entity, g_fVPos, NULL_VECTOR, NULL_VECTOR);
DispatchSpawn(entity);
ActivateEntity(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);
if (!g_bCvar_CustomModel)
return;
int entityFrame = EntRefToEntIndex(gc_iTankSpriteFrameRef[client]);
if (entityFrame == INVALID_ENT_REFERENCE)
return;
int frame = RoundFloat(percentageHealth * 100);
char input[38];
FormatEx(input, sizeof(input), "OnUser1 !self:SetTextureIndex:%i:0:1", frame);
SetVariantString(input);
AcceptEntityInput(entityFrame, "AddOutput");
AcceptEntityInput(entityFrame, "FireUser1");
}
/****************************************************************************************************/
@ -612,14 +721,14 @@ bool IsVisibleTo(int client, int target)
float vClientPos[3];
float vEntityPos[3];
float vLookAt[3];
float vAngles[3];
float vAng[3];
GetClientEyePosition(client, vClientPos);
GetClientEyePosition(target, vEntityPos);
MakeVectorFromPoints(vClientPos, vEntityPos, vLookAt);
GetVectorAngles(vLookAt, vAngles);
GetVectorAngles(vLookAt, vAng);
Handle trace = TR_TraceRayFilterEx(vClientPos, vAngles, MASK_PLAYERSOLID, RayType_Infinite, TraceFilter, target);
Handle trace = TR_TraceRayFilterEx(vClientPos, vAng, MASK_PLAYERSOLID, RayType_Infinite, TraceFilter, target);
bool isVisible;
@ -682,6 +791,9 @@ public Action CmdPrintCvars(int client, int args)
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, "l4d_tank_hp_sprite_custom_model : %b (%s)", g_bCvar_CustomModel, g_bCvar_CustomModel ? "true" : "false");
PrintToConsole(client, "l4d_tank_hp_sprite_custom_model_vmt : \"%s\"", g_sCvar_CustomModelVMT);
PrintToConsole(client, "l4d_tank_hp_sprite_custom_model_vtf : \"%s\"", g_sCvar_CustomModelVTF);
PrintToConsole(client, "");
PrintToConsole(client, "======================================================================");
PrintToConsole(client, "");
@ -777,7 +889,8 @@ bool IsPlayerIncapacitated(int client)
* @param client Client index.
* @return True if client is a tank, false otherwise.
*/
bool IsPlayerSpecialInfected(int client) {
bool IsPlayerTank(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;
@ -788,14 +901,14 @@ bool IsPlayerSpecialInfected(int client) {
/****************************************************************************************************/
/**
* Returns the team flag from a client.
* Returns the team flag from a team.
*
* @param client Client index.
* @return Client team flag.
* @param team Team index.
* @return Team flag.
*/
int GetClientTeamFlag(int client)
int GetTeamFlag(int team)
{
switch (GetClientTeam(client))
switch (team)
{
case TEAM_SURVIVOR:
return FLAG_TEAM_SURVIVOR;

View file

@ -0,0 +1,149 @@
#include <sourcemod>
#include <sdktools>
#include <left4dhooks>
#define UNRESERVE_VERSION "1.1.1"
#define UNRESERVE_DEBUG 0
#define UNRESERVE_DEBUG_LOG 0
#define L4D_MAXCLIENTS MaxClients
#define L4D_MAXCLIENTS_PLUS1 (L4D_MAXCLIENTS + 1)
#define L4D_MAXHUMANS_LOBBY_VERSUS 8
#define L4D_MAXHUMANS_LOBBY_OTHER 4
new Handle:cvarGameMode = INVALID_HANDLE;
public Plugin:myinfo =
{
name = "L4D1/2 Remove Lobby Reservation",
author = "Downtown1",
description = "Removes lobby reservation when server is full",
version = UNRESERVE_VERSION,
url = "http://forums.alliedmods.net/showthread.php?t=87759"
}
new Handle:cvarUnreserve = INVALID_HANDLE;
public OnPluginStart()
{
LoadTranslations("common.phrases");
RegAdminCmd("sm_unreserve", Command_Unreserve, ADMFLAG_BAN, "sm_unreserve - manually force removes the lobby reservation");
cvarUnreserve = CreateConVar("l4d_unreserve_full", "1", "Automatically unreserve server after a full lobby joins", FCVAR_SPONLY|FCVAR_NOTIFY);
CreateConVar("l4d_unreserve_version", UNRESERVE_VERSION, "Version of the Lobby Unreserve plugin.", FCVAR_SPONLY|FCVAR_NOTIFY);
cvarGameMode = FindConVar("mp_gamemode");
}
bool:IsScavengeMode()
{
decl String:sGameMode[32];
GetConVarString(cvarGameMode, sGameMode, sizeof(sGameMode));
if (StrContains(sGameMode, "scavenge") > -1)
{
return true;
}
else
{
return false;
}
}
bool:IsVersusMode()
{
decl String:sGameMode[32];
GetConVarString(cvarGameMode, sGameMode, sizeof(sGameMode));
if (StrContains(sGameMode, "versus") > -1)
{
return true;
}
else
{
return false;
}
}
IsServerLobbyFull()
{
new humans = GetHumanCount();
DebugPrintToAll("IsServerLobbyFull : humans = %d", humans);
if(IsVersusMode() || IsScavengeMode())
{
return humans >= L4D_MAXHUMANS_LOBBY_VERSUS;
}
return humans >= L4D_MAXHUMANS_LOBBY_OTHER;
}
public OnClientPutInServer(client)
{
DebugPrintToAll("Client put in server %N", client);
if(GetConVarBool(cvarUnreserve) && /*L4D_LobbyIsReserved() &&*/ IsServerLobbyFull())
{
//PrintToChatAll("[SM] A full lobby has connected, automatically unreserving the server.");
L4D_LobbyUnreserve();
}
}
public Action:Command_Unreserve(client, args)
{
/*if(!L4D_LobbyIsReserved())
{
ReplyToCommand(client, "[SM] Server is already unreserved.");
}*/
L4D_LobbyUnreserve();
PrintToChatAll("[SM] Lobby reservation has been removed.");
return Plugin_Handled;
}
//client is in-game and not a bot
stock bool:IsClientInGameHuman(client)
{
return IsClientInGame(client) && !IsFakeClient(client);
}
stock GetHumanCount()
{
new humans = 0;
new i;
for(i = 1; i < L4D_MAXCLIENTS_PLUS1; i++)
{
if(IsClientInGameHuman(i))
{
humans++
}
}
return humans;
}
DebugPrintToAll(const String:format[], any:...)
{
#if UNRESERVE_DEBUG || UNRESERVE_DEBUG_LOG
decl String:buffer[192];
VFormat(buffer, sizeof(buffer), format, 2);
#if UNRESERVE_DEBUG
PrintToChatAll("[UNRESERVE] %s", buffer);
PrintToConsole(0, "[UNRESERVE] %s", buffer);
#endif
LogMessage("%s", buffer);
#else
//suppress "format" never used warning
if(format[0])
return;
else
return;
#endif
}

855
scripting/sceneprocessor.sp Normal file
View file

@ -0,0 +1,855 @@
#define PLUGIN_VERSION "1.33.2"
#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <sceneprocessor>
int iSkippedFrames;
char sVocalizeScene[MAXPLAYERS+1][MAX_VOCALIZE_LENGTH];
bool bSceneHasInitiator[MAXPLAYERS+1], bScenesUnprocessed, bUnvocalizedCommands, bJailbreakVocalize, bIsL4D;
float fStartTimeStamp, fVocalizePreDelay[MAXPLAYERS+1], fVocalizePitch[MAXPLAYERS+1];
Handle hSceneStageForward, hVocalizeCommandForward;
ArrayList alVocalize;
ArrayStack asScene;
enum struct SceneData
{
SceneStages ssDataBit;
bool bInFakePostSpawn;
float fTimeStampData;
int iActorData;
int iInitiatorData;
char sFileData[MAX_SCENEFILE_LENGTH];
char sVocalizeData[MAX_VOCALIZE_LENGTH];
float fPreDelayData;
float fPitchData;
}
SceneData nSceneData[2048];
int iScenePlaying[MAXPLAYERS+1], iVocalizeTick[MAXPLAYERS+1], iVocalizeInitiator[MAXPLAYERS+1];
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
EngineVersion evGame = GetEngineVersion();
if (evGame == Engine_Left4Dead)
{
bIsL4D = true;
}
else if (evGame != Engine_Left4Dead2)
{
strcopy(error, err_max, "[SP] Plugin Supports L4D And L4D2 Only!");
return APLRes_Failure;
}
CreateNative("GetSceneStage", SP_GetSceneStage);
CreateNative("GetSceneStartTimeStamp", SP_GetSceneStartTimeStamp);
CreateNative("GetActorFromScene", SP_GetSceneActor);
CreateNative("GetSceneFromActor", SP_GetActorScene);
CreateNative("GetSceneInitiator", SP_GetSceneInitiator);
CreateNative("GetSceneFile", SP_GetSceneFile);
CreateNative("GetSceneVocalize", SP_GetSceneVocalize);
CreateNative("GetScenePreDelay", SP_GetScenePreDelay);
CreateNative("SetScenePreDelay", SP_SetScenePreDelay);
CreateNative("GetScenePitch", SP_GetScenePitch);
CreateNative("SetScenePitch", SP_SetScenePitch);
CreateNative("CancelScene", SP_CancelScene);
CreateNative("PerformScene", SP_PerformScene);
CreateNative("PerformSceneEx", SP_PerformSceneEx);
RegPluginLibrary("sceneprocessor");
return APLRes_Success;
}
public any SP_GetSceneStage(Handle plugin, int numParams)
{
if (numParams == 0)
{
return SceneStage_Unknown;
}
int scene = GetNativeCell(1);
if (scene < 1 || scene > 2048 || !IsValidEntity(scene))
{
return SceneStage_Unknown;
}
return nSceneData[scene].ssDataBit;
}
public any SP_GetSceneStartTimeStamp(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0.0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0.0;
}
return nSceneData[scene].fTimeStampData;
}
public int SP_GetActorScene(Handle plugin, int numParams)
{
if (numParams == 0)
{
return INVALID_ENT_REFERENCE;
}
int iActor = GetNativeCell(1);
if (iActor < 1 || iActor > MaxClients || !IsClientInGame(iActor) || GetClientTeam(iActor) != 2 || !IsPlayerAlive(iActor))
{
return INVALID_ENT_REFERENCE;
}
return iScenePlaying[iActor];
}
public int SP_GetSceneActor(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
return nSceneData[scene].iActorData;
}
public int SP_GetSceneInitiator(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
return nSceneData[scene].iInitiatorData;
}
public int SP_GetSceneFile(Handle plugin, int numParams)
{
if (numParams != 3)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
int len = GetNativeCell(3);
int bytesWritten;
SetNativeString(2, nSceneData[scene].sFileData, len, _, bytesWritten);
return bytesWritten;
}
public int SP_GetSceneVocalize(Handle plugin, int numParams)
{
if (numParams != 3)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
int len = GetNativeCell(3);
int bytesWritten;
SetNativeString(2, nSceneData[scene].sVocalizeData, len, _, bytesWritten);
return bytesWritten;
}
public any SP_GetScenePreDelay(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0.0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0.0;
}
return nSceneData[scene].fPreDelayData;
}
public int SP_SetScenePreDelay(Handle plugin, int numParams)
{
if (numParams != 2)
{
return;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return;
}
float fPreDelay = GetNativeCell(2);
SetEntPropFloat(scene, Prop_Data, "m_flPreDelay", fPreDelay);
nSceneData[scene].fPreDelayData = fPreDelay;
}
public any SP_GetScenePitch(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0.0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0.0;
}
return nSceneData[scene].fPitchData;
}
public int SP_SetScenePitch(Handle plugin, int numParams)
{
if (numParams != 2)
{
return;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return;
}
float fPitch = GetNativeCell(2);
SetEntPropFloat(scene, Prop_Data, "m_fPitch", fPitch);
nSceneData[scene].fPitchData = fPitch;
}
public int SP_CancelScene(Handle plugin, int numParams)
{
if (numParams == 0)
{
return;
}
int scene = GetNativeCell(1);
if (scene < 1 || scene > 2048 || !IsValidEntity(scene))
{
return;
}
SceneStages ssBit = nSceneData[scene].ssDataBit;
if (ssBit == SceneStage_Unknown)
{
return;
}
else if (ssBit == SceneStage_Started || (ssBit == SceneStage_SpawnedPost && nSceneData[scene].bInFakePostSpawn))
{
AcceptEntityInput(scene, "Cancel");
}
else if (ssBit != SceneStage_Cancelled && ssBit != SceneStage_Completion && ssBit != SceneStage_Killed)
{
AcceptEntityInput(scene, "Kill");
}
}
public int SP_PerformScene(Handle plugin, int numParams)
{
if (numParams < 2)
{
return;
}
int client = GetNativeCell(1);
if (client < 1 || client > MaxClients || !IsClientInGame(client) || GetClientTeam(client) != 2 || !IsPlayerAlive(client))
{
return;
}
static char sVocalize[MAX_VOCALIZE_LENGTH], sFile[MAX_SCENEFILE_LENGTH];
float fPreDelay = DEFAULT_SCENE_PREDELAY, fPitch = DEFAULT_SCENE_PITCH;
int iInitiator = SCENE_INITIATOR_PLUGIN;
if (GetNativeString(2, sVocalize, MAX_VOCALIZE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown Vocalize Parameter!");
return;
}
if (numParams >= 3)
{
if (GetNativeString(3, sFile, MAX_SCENEFILE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown File Parameter!");
return;
}
}
if (numParams >= 4)
{
fPreDelay = GetNativeCell(4);
}
if (numParams >= 5)
{
fPitch = GetNativeCell(5);
}
if (numParams >= 6)
{
iInitiator = GetNativeCell(6);
}
Scene_Perform(client, sVocalize, sFile, fPreDelay, fPitch, iInitiator);
}
public int SP_PerformSceneEx(Handle plugin, int numParams)
{
if (numParams < 2)
{
return;
}
int client = GetNativeCell(1);
if (client < 1 || client > MaxClients || !IsClientInGame(client) || GetClientTeam(client) != 2 || !IsPlayerAlive(client))
{
return;
}
static char sVocalize[MAX_VOCALIZE_LENGTH], sFile[MAX_SCENEFILE_LENGTH];
float fPreDelay = DEFAULT_SCENE_PREDELAY, fPitch = DEFAULT_SCENE_PITCH;
int iInitiator = SCENE_INITIATOR_PLUGIN;
if (GetNativeString(2, sVocalize, MAX_VOCALIZE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown Vocalize Parameter!");
return;
}
if (numParams >= 3)
{
if (GetNativeString(3, sFile, MAX_SCENEFILE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown File Parameter!");
return;
}
}
if (numParams >= 4)
{
fPreDelay = GetNativeCell(4);
}
if (numParams >= 5)
{
fPitch = GetNativeCell(5);
}
if (numParams >= 6)
{
iInitiator = GetNativeCell(6);
}
Scene_Perform(client, sVocalize, sFile, fPreDelay, fPitch, iInitiator, true);
}
public Plugin myinfo =
{
name = "Scene Processor",
author = "Buster \"Mr. Zero\" Nielsen (Fork by cravenge & Dragokas)",
description = "Provides Forwards and Natives For Scenes' Manipulation.",
version = PLUGIN_VERSION,
url = "https://forums.alliedmods.net/showthread.php?t=241585"
};
public void OnPluginStart()
{
hSceneStageForward = CreateGlobalForward("OnSceneStageChanged", ET_Ignore, Param_Cell, Param_Cell);
hVocalizeCommandForward = CreateGlobalForward("OnVocalizeCommand", ET_Hook, Param_Cell, Param_String, Param_Cell);
CreateConVar("sceneprocessor_version", PLUGIN_VERSION, "Scene Processor Version", FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD);
if (!bIsL4D)
{
ConVar spJailbreakVocalize = CreateConVar("sceneprocessor_jailbreak_vocalize", "1", "Enable/Disable Jailbreak Vocalizations", FCVAR_SPONLY|FCVAR_NOTIFY);
spJailbreakVocalize.AddChangeHook(OnSPCVarChanged);
bJailbreakVocalize = spJailbreakVocalize.BoolValue;
}
AddCommandListener(OnVocalizeCmd, "vocalize");
asScene = new ArrayStack();
alVocalize = new ArrayList(MAX_VOCALIZE_LENGTH);
for (int i = 1; i < 2049; i++)
{
if (IsValidEntity(i) && IsValidEdict(i))
{
SceneData_SetStage(i, SceneStage_Unknown);
}
}
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
{
ResetClientVocalizeData(i);
}
}
}
public void OnSPCVarChanged(ConVar cvar, const char[] sOldValue, const char[] sNewValue)
{
bJailbreakVocalize = cvar.BoolValue;
}
public Action OnVocalizeCmd(int client, const char[] command, int args)
{
if (client == 0 || args == 0)
{
return Plugin_Continue;
}
if (!IsClientInGame(client))
{
return Plugin_Handled;
}
static char sVocalize[128];
GetCmdArg(1, sVocalize, sizeof(sVocalize));
if (!bIsL4D && args != 2)
{
if (bJailbreakVocalize)
{
JailbreakVocalize(client, sVocalize);
}
return Plugin_Handled;
}
int iTick = GetGameTickCount();
if (!bSceneHasInitiator[client] || (iVocalizeTick[client] > 0 && iVocalizeTick[client] != iTick))
{
iVocalizeInitiator[client] = client;
if (!bIsL4D && args > 1 && StrEqual(sVocalize, "smartlook", false))
{
static char sTime[32];
GetCmdArg(2, sTime, sizeof(sTime));
if (StrEqual(sTime, "auto", false))
{
iVocalizeInitiator[client] = SCENE_INITIATOR_WORLD;
}
}
}
strcopy(sVocalizeScene[client], MAX_VOCALIZE_LENGTH, sVocalize);
iVocalizeTick[client] = iTick;
Action aResult = Plugin_Continue;
Call_StartForward(hVocalizeCommandForward);
Call_PushCell(client);
Call_PushString(sVocalize);
Call_PushCell(iVocalizeInitiator[client]);
Call_Finish(aResult);
return (aResult == Plugin_Stop) ? Plugin_Handled : Plugin_Continue;
}
public void OnPluginEnd()
{
RemoveCommandListener(OnVocalizeCmd, "vocalize");
}
public void OnMapStart()
{
iSkippedFrames = 0;
fStartTimeStamp = GetGameTime();
}
public void OnEntityCreated(int entity, const char[] classname)
{
if (entity < 1 || entity > 2048)
{
return;
}
if (StrEqual(classname, "instanced_scripted_scene"))
{
SDKHook(entity, SDKHook_SpawnPost, OnSpawnPost);
SceneData_SetStage(entity, SceneStage_Created);
}
}
public void OnSpawnPost(int entity)
{
int iActor = GetEntPropEnt(entity, Prop_Data, "m_hOwner");
nSceneData[entity].iActorData = iActor;
static char sFile[MAX_SCENEFILE_LENGTH];
GetEntPropString(entity, Prop_Data, "m_iszSceneFile", sFile, MAX_SCENEFILE_LENGTH);
strcopy(nSceneData[entity].sFileData, MAX_SCENEFILE_LENGTH, sFile);
nSceneData[entity].fPitchData = GetEntPropFloat(entity, Prop_Data, "m_fPitch");
if (iActor > 0 && iActor <= MaxClients && IsClientInGame(iActor))
{
if (iVocalizeTick[iActor] == GetGameTickCount())
{
strcopy(nSceneData[entity].sVocalizeData, MAX_VOCALIZE_LENGTH, sVocalizeScene[iActor]);
nSceneData[entity].iInitiatorData = iVocalizeInitiator[iActor];
nSceneData[entity].fPreDelayData = fVocalizePreDelay[iActor];
nSceneData[entity].fPitchData = fVocalizePitch[iActor];
}
ResetClientVocalizeData(iActor);
}
SetEntPropFloat(entity, Prop_Data, "m_fPitch", nSceneData[entity].fPitchData);
SetEntPropFloat(entity, Prop_Data, "m_flPreDelay", nSceneData[entity].fPreDelayData);
asScene.Push(entity);
bScenesUnprocessed = true;
HookSingleEntityOutput(entity, "OnStart", OnSceneStart_EntOutput);
HookSingleEntityOutput(entity, "OnCanceled", OnSceneCanceled_EntOutput);
SceneData_SetStage(entity, SceneStage_Spawned);
}
public void OnSceneStart_EntOutput(const char[] output, int caller, int activator, float delay)
{
if (caller < 1 || caller > 2048 || !IsValidEntity(caller))
{
return;
}
static char sFile[MAX_SCENEFILE_LENGTH];
strcopy(sFile, MAX_SCENEFILE_LENGTH, nSceneData[caller].sFileData);
if (!sFile[0])
{
return;
}
nSceneData[caller].fTimeStampData = GetEngineTime();
if (nSceneData[caller].ssDataBit == SceneStage_Spawned)
{
nSceneData[caller].bInFakePostSpawn = true;
SceneData_SetStage(caller, SceneStage_SpawnedPost);
}
if (nSceneData[caller].ssDataBit == SceneStage_SpawnedPost)
{
int iActor = nSceneData[caller].iActorData;
if (iActor > 0 && iActor <= MaxClients && IsClientInGame(iActor))
{
iScenePlaying[iActor] = caller;
}
SceneData_SetStage(caller, SceneStage_Started);
}
}
public void OnSceneCanceled_EntOutput(const char[] output, int caller, int activator, float delay)
{
if (caller < 1 || caller > 2048 || !IsValidEntity(caller))
{
return;
}
for (int i = 1; i <= MaxClients; i++)
{
if (iScenePlaying[i] == caller)
{
iScenePlaying[i] = INVALID_ENT_REFERENCE;
break;
}
}
SceneData_SetStage(caller, SceneStage_Cancelled);
}
public void OnEntityDestroyed(int entity)
{
if (entity < 1 || entity > 2048 || !IsValidEdict(entity))
{
return;
}
static char sEntityClass[64];
GetEdictClassname(entity, sEntityClass, sizeof(sEntityClass));
if (!StrEqual(sEntityClass, "instanced_scripted_scene"))
{
return;
}
SDKUnhook(entity, SDKHook_SpawnPost, OnSpawnPost);
SceneStages ssBit = nSceneData[entity].ssDataBit;
if (ssBit != SceneStage_Unknown)
{
if (ssBit == SceneStage_Started)
{
SceneData_SetStage(entity, SceneStage_Completion);
}
SceneData_SetStage(entity, SceneStage_Killed);
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || iScenePlaying[i] != entity)
{
continue;
}
iScenePlaying[i] = INVALID_ENT_REFERENCE;
break;
}
}
SceneData_SetStage(entity, SceneStage_Unknown);
}
public void OnClientDisconnect(int client)
{
if (client == 0)
{
return;
}
iScenePlaying[client] = INVALID_ENT_REFERENCE;
}
public void OnGameFrame()
{
iSkippedFrames += 1;
if (iSkippedFrames < 3)
{
return;
}
iSkippedFrames = 1;
if (bScenesUnprocessed)
{
bScenesUnprocessed = false;
int dScene;
while (!asScene.Empty)
{
asScene.Pop(dScene);
if (dScene < 1 || dScene > 2048 || !IsValidEntity(dScene))
{
continue;
}
if (nSceneData[dScene].ssDataBit != SceneStage_Spawned)
{
continue;
}
nSceneData[dScene].fPreDelayData = GetEntPropFloat(dScene, Prop_Data, "m_flPreDelay");
nSceneData[dScene].bInFakePostSpawn = false;
SceneData_SetStage(dScene, SceneStage_SpawnedPost);
}
}
if (bUnvocalizedCommands)
{
int iArraySize = alVocalize.Length,
iCurrentTick = GetGameTickCount();
static char sVocalize[MAX_VOCALIZE_LENGTH];
float fPreDelay, fPitch;
int client, dInitiator, dTick;
for (int i = 0; i < iArraySize; i += 6)
{
dTick = alVocalize.Get(i + 5);
if (iCurrentTick != dTick)
{
continue;
}
client = alVocalize.Get(i + 0);
alVocalize.GetString(i + 1, sVocalize, MAX_VOCALIZE_LENGTH);
fPreDelay = view_as<float>(alVocalize.Get(i + 2));
fPitch = view_as<float>(alVocalize.Get(i + 3));
dInitiator = alVocalize.Get(i + 4);
Scene_Perform(client, sVocalize, _, fPreDelay, fPitch, dInitiator, true);
for (int j = 0; j < 6; j++)
{
alVocalize.Erase(i);
iArraySize -= 1;
}
}
if (iArraySize < 1)
{
alVocalize.Clear();
bUnvocalizedCommands = false;
}
}
}
public void OnMapEnd()
{
iSkippedFrames = 0;
bScenesUnprocessed = false;
bUnvocalizedCommands = false;
while (!asScene.Empty)
{
PopStack(asScene);
}
alVocalize.Clear();
for (int i = 1; i < 2049; i++)
{
if (IsValidEntity(i) && IsValidEdict(i))
{
SceneData_SetStage(i, SceneStage_Unknown);
}
}
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
{
iScenePlaying[i] = INVALID_ENT_REFERENCE;
}
}
}
void ResetClientVocalizeData(int client)
{
iVocalizeTick[client] = 0;
sVocalizeScene[client] = "\0";
bSceneHasInitiator[client] = false;
iVocalizeInitiator[client] = SCENE_INITIATOR_WORLD;
fVocalizePreDelay[client] = DEFAULT_SCENE_PREDELAY;
fVocalizePitch[client] = DEFAULT_SCENE_PITCH;
}
void SceneData_SetStage(int scene, SceneStages stage)
{
nSceneData[scene].ssDataBit = stage;
if (stage != SceneStage_Unknown)
{
Call_StartForward(hSceneStageForward);
Call_PushCell(scene);
Call_PushCell(stage);
Call_Finish();
}
else
{
nSceneData[scene].bInFakePostSpawn = false;
nSceneData[scene].fTimeStampData = 0.0;
nSceneData[scene].iActorData = 0;
nSceneData[scene].iInitiatorData = 0;
strcopy(nSceneData[scene].sFileData, MAX_SCENEFILE_LENGTH, "\0");
strcopy(nSceneData[scene].sVocalizeData, MAX_VOCALIZE_LENGTH, "\0");
nSceneData[scene].fPreDelayData = DEFAULT_SCENE_PREDELAY;
nSceneData[scene].fPitchData = DEFAULT_SCENE_PITCH;
}
}
void Scene_Perform(int client, const char[] sVocalizeParam, const char[] sFileParam = "", float fScenePreDelay = DEFAULT_SCENE_PREDELAY, float fScenePitch = DEFAULT_SCENE_PITCH, int iSceneInitiator = SCENE_INITIATOR_PLUGIN, bool bVocalizeNow = false)
{
if (sFileParam[0] && FileExists(sFileParam, true))
{
int iScene = CreateEntityByName("instanced_scripted_scene");
DispatchKeyValue(iScene, "SceneFile", sFileParam);
SetEntPropEnt(iScene, Prop_Data, "m_hOwner", client);
nSceneData[iScene].iActorData = client;
SetEntPropFloat(iScene, Prop_Data, "m_flPreDelay", fScenePreDelay);
nSceneData[iScene].fPreDelayData = fScenePreDelay;
SetEntPropFloat(iScene, Prop_Data, "m_fPitch", fScenePitch);
nSceneData[iScene].fPitchData = fScenePitch;
nSceneData[iScene].iInitiatorData = iSceneInitiator;
strcopy(nSceneData[iScene].sVocalizeData, MAX_VOCALIZE_LENGTH, sVocalizeParam);
DispatchSpawn(iScene);
ActivateEntity(iScene);
AcceptEntityInput(iScene, "Start", client, client);
}
else if (sVocalizeParam[0])
{
if (bVocalizeNow)
{
iVocalizeInitiator[client] = iSceneInitiator;
bSceneHasInitiator[client] = true;
fVocalizePreDelay[client] = fScenePreDelay;
fVocalizePitch[client] = fScenePitch;
if (bIsL4D)
{
FakeClientCommandEx(client, "vocalize %s", sVocalizeParam);
}
else
{
JailbreakVocalize(client, sVocalizeParam);
}
}
else
{
alVocalize.Push(client);
alVocalize.PushString(sVocalizeParam);
alVocalize.Push(fScenePreDelay);
alVocalize.Push(fScenePitch);
alVocalize.Push(iSceneInitiator);
alVocalize.Push(GetGameTickCount() + 10 - 1);
bUnvocalizedCommands = true;
}
}
}
void JailbreakVocalize(int client, const char[] sVocalize)
{
char sBuffer[2][32];
FloatToString((GetGameTime() - fStartTimeStamp) + 2.0, sBuffer[0], 32);
ExplodeString(sBuffer[0], ".", sBuffer, 2, 32);
Format(sBuffer[1], 2, "%s\0", sBuffer[1][0]);
FakeClientCommandEx(client, "vocalize %s #%s%s", sVocalize, sBuffer[0], sBuffer[1]);
}