mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 23:23:21 +00:00
255 lines
No EOL
11 KiB
SourcePawn
255 lines
No EOL
11 KiB
SourcePawn
#pragma semicolon 1
|
|
#pragma newdecls required
|
|
|
|
//#define DEBUG
|
|
|
|
#define MAIN_TIMER_INTERVAL_S 3.5
|
|
#define PLUGIN_VERSION "1.0"
|
|
#define THROWITALL_INTERVAL 30.0
|
|
|
|
#include <sourcemod>
|
|
#include <sdktools>
|
|
#include <sdkhooks>
|
|
#include <left4dhooks>
|
|
#include <jutils>
|
|
#undef REQUIRE_PLUGIN
|
|
#tryinclude <sceneprocessor>
|
|
#undef REQUIRE_PLUGIN
|
|
#tryinclude <actions>
|
|
#include <basecomm>
|
|
#include <ftt>
|
|
#include <multicolors>
|
|
#undef REQUIRE_PLUGIN
|
|
#tryinclude <l4d_anti_rush>
|
|
|
|
public Plugin myinfo =
|
|
{
|
|
name = "L4D2 Feed The Trolls",
|
|
author = "jackzmc",
|
|
description = "https://forums.alliedmods.net/showthread.php?t=325331",
|
|
version = PLUGIN_VERSION,
|
|
url = "https://github.com/Jackzmc/sourcemod-plugins"
|
|
};
|
|
|
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
|
|
// return APLRes_SilentFailure;
|
|
CreateNative("ApplyTroll", Native_ApplyTroll);
|
|
RegPluginLibrary("feedthetrolls");
|
|
return APLRes_Success;
|
|
}
|
|
public void OnLibraryAdded(const char[] name) {
|
|
if(StrEqual(name, "actionslib")) {
|
|
g_actionsAvailable = true;
|
|
}
|
|
}
|
|
public void OnLibraryRemoved(const char[] name) {
|
|
if(StrEqual(name, "actionslib")) {
|
|
g_actionsAvailable = false;
|
|
}
|
|
}
|
|
public void OnAllPluginsLoaded() {
|
|
g_actionsAvailable = LibraryExists("actionslib");
|
|
}
|
|
|
|
|
|
public void OnPluginStart() {
|
|
EngineVersion g_Game = GetEngineVersion();
|
|
if(g_Game != Engine_Left4Dead2) {
|
|
SetFailState("This plugin is for L4D2 only.");
|
|
}
|
|
LoadTranslations("common.phrases");
|
|
|
|
g_PlayerMarkedForward = new GlobalForward("OnTrollMarked", ET_Ignore, Param_Cell, Param_Cell);
|
|
g_TrollAppliedForward = new GlobalForward("OnTrollApplied", ET_Ignore, Param_Cell, Param_Cell);
|
|
|
|
|
|
// Load core things (trolls & phrases):
|
|
REPLACEMENT_PHRASES = new StringMap();
|
|
LoadPhrases();
|
|
LoadTypos();
|
|
SetupTrolls();
|
|
SetupsTrollCombos();
|
|
|
|
CreateTimer(1.0, Timer_DecreaseAntiRush, TIMER_REPEAT);
|
|
|
|
g_spSpawnQueue = new ArrayList(sizeof(SpecialSpawnRequest));
|
|
|
|
// Witch target overwrite stuff:
|
|
GameData data = new GameData("feedthetrolls");
|
|
StartPrepSDKCall(SDKCall_Raw);
|
|
PrepSDKCall_SetFromConf(data, SDKConf_Signature, "WitchAttack::WitchAttack");
|
|
PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL | VDECODE_FLAG_ALLOWWORLD);
|
|
g_hWitchAttack = EndPrepSDKCall();
|
|
delete data;
|
|
|
|
hAllowEnemyTeam = CreateConVar("sm_ftt_select_enemy", "0", "Allow applying trolls to enemy teams", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
hAutoPunish = CreateConVar("sm_ftt_autopunish_action", "0", "Setup automatic punishment of players. Add bits together\n0=Disabled, 1=Tank magnet, 2=Special magnet, 4=Swarm, 8=InstantVomit", FCVAR_NONE, true, 0.0);
|
|
hAutoPunishExpire = CreateConVar("sm_ftt_autopunish_expire", "0", "How many minutes of gametime until autopunish is turned off? 0 for never.", FCVAR_NONE, true, 0.0);
|
|
hMagnetTargetMode = CreateConVar("sm_ftt_magnet_targetting", "6", "How does the specials target players. Add bits together\n0=Incapped are ignored, 1=Specials targets incapped, 2=Tank targets incapped 4=Witch targets incapped");
|
|
hShoveFailChance = CreateConVar("sm_ftt_shove_fail_chance", "0.65", "The % chance that a shove fails", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
hBadThrowHitSelf = CreateConVar("sm_ftt_badthrow_fail_chance", "1", "The % chance that on a throw, they will instead hit themselves. 0 to disable", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
hBotReverseFFDefend = CreateConVar("sm_ftt_bot_defend", "0", "Should bots defend themselves?\n0 = OFF\n1 = Will retaliate against non-admins\n2 = Anyone", FCVAR_NONE, true, 0.0, true, 2.0);
|
|
hAntirushBaseFreq = CreateConVar("sm_ftt_antirush_freq_base", "24", "The base frequency of anti-rush", FCVAR_NONE, true, 0.0);
|
|
hAntirushIncFreq = CreateConVar("sm_ftt_antirush_freq_inc", "1", "The incremental frequency of anti-rush", FCVAR_NONE, true, 0.0);
|
|
hBotDefendChance = CreateConVar("sm_ftt_bot_defend_chance", "0.75", "% Chance bots will defend themselves.", FCVAR_NONE, true, 0.0, true, 1.0);
|
|
|
|
hSbFriendlyFire = FindConVar("sb_friendlyfire");
|
|
|
|
if(hBotReverseFFDefend.IntValue > 0) hSbFriendlyFire.BoolValue = true;
|
|
hBotReverseFFDefend.AddChangeHook(Change_BotDefend);
|
|
|
|
RegAdminCmd("sm_ftl", Command_ListTheTrolls, ADMFLAG_GENERIC, "Lists all the trolls currently ingame.");
|
|
RegAdminCmd("sm_ftm", Command_ListModes, ADMFLAG_GENERIC, "Lists all the troll modes and their description");
|
|
RegAdminCmd("sm_ftr", Command_ResetUser, ADMFLAG_GENERIC, "Resets user of any troll effects.");
|
|
RegAdminCmd("sm_fta", Command_ApplyUser, ADMFLAG_KICK, "Apply a troll mod to a player, or shows menu if no parameters.");
|
|
RegAdminCmd("sm_ftas", Command_ApplyUserSilent, ADMFLAG_ROOT, "Apply a troll mod to a player, or shows menu if no parameters.");
|
|
RegAdminCmd("sm_ftt", Command_FeedTheTrollMenu, ADMFLAG_GENERIC, "Opens a list that shows all the commands");
|
|
RegAdminCmd("sm_mark", Command_MarkPendingTroll, ADMFLAG_KICK, "Marks a player as to be banned on disconnect");
|
|
RegAdminCmd("sm_ftp", Command_FeedTheCrescendoTroll, ADMFLAG_KICK, "Applies a manual punish on the last crescendo activator");
|
|
RegAdminCmd("sm_ftc", Command_ApplyComboTrolls, ADMFLAG_KICK, "Applies predefined combinations of trolls");
|
|
#if defined _actions_included
|
|
RegAdminCmd("sm_witch_attack", Command_WitchAttack, ADMFLAG_BAN, "Makes all witches target a player");
|
|
#endif
|
|
RegAdminCmd("sm_insta", Command_InstaSpecial, ADMFLAG_KICK, "Spawns a special that targets them, close to them.");
|
|
RegAdminCmd("sm_stagger", Command_Stagger, ADMFLAG_KICK, "Stagger a player");
|
|
RegAdminCmd("sm_inface", Command_InstaSpecialFace, ADMFLAG_KICK, "Spawns a special that targets them, right in their face.");
|
|
RegAdminCmd("sm_bots_attack", Command_BotsAttack, ADMFLAG_BAN, "Instructs all bots to attack a player until they have X health.");
|
|
RegAdminCmd("sm_scharge", Command_SmartCharge, ADMFLAG_BAN, "Auto Smart charge");
|
|
RegAdminCmd("sm_healbots", Command_HealTarget, ADMFLAG_BAN, "Make bots heal a player");
|
|
RegAdminCmd("sm_rff", Command_SetReverseFF, ADMFLAG_KICK, "Set reverse FF on player");
|
|
RegAdminCmd("sm_magnet", Command_SetMagnetShortcut, ADMFLAG_KICK, "");
|
|
RegAdminCmd("sm_csplat", Command_CarSplat, ADMFLAG_KICK, "");
|
|
RegAdminCmd("sm_typo", Command_AddTypo, ADMFLAG_GENERIC);
|
|
|
|
HookEvent("player_spawn", Event_PlayerSpawn);
|
|
HookEvent("player_first_spawn", Event_PlayerFirstSpawn);
|
|
HookEvent("player_disconnect", Event_PlayerDisconnect);
|
|
HookEvent("player_death", Event_PlayerDeath);
|
|
HookEvent("triggered_car_alarm", Event_CarAlarm);
|
|
HookEvent("witch_harasser_set", Event_WitchVictimSet);
|
|
HookEvent("door_open", Event_DoorToggle);
|
|
HookEvent("door_close", Event_DoorToggle);
|
|
HookEvent("adrenaline_used", Event_SecondaryHealthUsed);
|
|
HookEvent("pills_used", Event_SecondaryHealthUsed);
|
|
HookEvent("entered_spit", Event_EnteredSpit);
|
|
HookEvent("bot_player_replace", Event_BotPlayerSwap);
|
|
HookEvent("heal_success", Event_HealSuccess);
|
|
HookEvent("player_incapacitated", Event_Incapped);
|
|
|
|
AddNormalSoundHook(SoundHook);
|
|
|
|
AutoExecConfig(true, "l4d2_feedthetrolls");
|
|
|
|
for(int i = 1; i <= MaxClients; i++) {
|
|
if(IsClientConnected(i) && IsClientInGame(i)) {
|
|
SDKHook(i, SDKHook_OnTakeDamage, Event_TakeDamage);
|
|
}
|
|
}
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CVAR CHANGES
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Turn on bot FF if bot defend enabled
|
|
void Change_BotDefend(ConVar convar, const char[] oldValue, const char[] newValue) {
|
|
hSbFriendlyFire.IntValue = convar.IntValue != 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// METHODS - Old methods, some are also in feedthetrolls/misc.inc
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ThrowAllItems(int victim) {
|
|
float vicPos[3], destPos[3];
|
|
int clients[4];
|
|
GetClientAbsOrigin(victim, vicPos);
|
|
//Find a survivor to throw to (grabs the first nearest non-self survivor)
|
|
int clientCount = GetClientsInRange(vicPos, RangeType_Visibility, clients, sizeof(clients));
|
|
for(int i = 0; i < clientCount; i++) {
|
|
if(clients[i] != victim) {
|
|
GetClientAbsOrigin(clients[i], destPos);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Loop all item slots
|
|
for(int slot = 0; slot <= 4; slot++) {
|
|
Handle pack;
|
|
CreateDataTimer(0.22 * float(slot), Timer_ThrowWeapon, pack);
|
|
|
|
WritePackFloat(pack, destPos[0]);
|
|
WritePackFloat(pack, destPos[1]);
|
|
WritePackFloat(pack, destPos[2]);
|
|
WritePackCell(pack, slot);
|
|
WritePackCell(pack, victim);
|
|
}
|
|
}
|
|
|
|
bool IsPlayerFarDistance(int client, float distance) {
|
|
int farthestClient = -1, secondClient = -1;
|
|
float highestFlow, secondHighestFlow;
|
|
for(int i = 1; i <= MaxClients; i++) {
|
|
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
|
|
float flow = L4D2Direct_GetFlowDistance(i);
|
|
if(flow > highestFlow || farthestClient == -1) {
|
|
secondHighestFlow = highestFlow;
|
|
secondClient = farthestClient;
|
|
farthestClient = i;
|
|
highestFlow = flow;
|
|
}
|
|
}
|
|
}
|
|
//Incase the first player checked is the farthest:
|
|
if(secondClient == -1) {
|
|
for(int i = 1; i <= MaxClients; i++) {
|
|
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
|
|
float flow = L4D2Direct_GetFlowDistance(i);
|
|
if(farthestClient != i && ((flow < highestFlow && flow > secondHighestFlow) || secondClient == -1)) {
|
|
secondClient = i;
|
|
secondHighestFlow = flow;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
float difference = highestFlow - secondHighestFlow;
|
|
PrintToConsoleAll("Flow Check | Player1=%N Flow1=%f Delta=%f", farthestClient, highestFlow, difference);
|
|
PrintToConsoleAll("Flow Check | Player2=%N Flow2=%f", secondClient, secondHighestFlow);
|
|
return client == farthestClient && difference > distance;
|
|
}
|
|
|
|
#if defined _actions_included
|
|
BehaviorAction CreateWitchAttackAction(int target = 0) {
|
|
BehaviorAction action = ActionsManager.Allocate(18556);
|
|
SDKCall(g_hWitchAttack, action, target);
|
|
return action;
|
|
}
|
|
|
|
Action OnWitchActionUpdate(BehaviorAction action, int actor, float interval, ActionResult result) {
|
|
/* Change to witch attack */
|
|
result.type = CHANGE_TO;
|
|
result.action = CreateWitchAttackAction(g_iWitchAttackVictim);
|
|
result.SetReason("FTT");
|
|
return Plugin_Handled;
|
|
}
|
|
#endif
|
|
|
|
void HideHUD(int victim, float timeout = 0.0) {
|
|
SetEntProp(victim, Prop_Send, "m_iHideHUD", 64);
|
|
if(timeout > 0.0)
|
|
CreateTimer(timeout, Timer_RestoreHud, GetClientUserId(victim));
|
|
}
|
|
void HideHUDRandom(int victim) {
|
|
float timeout = 0.0;
|
|
if(~Trolls[t_hideHUDIndex].activeFlagClients[victim] & 3) {
|
|
if(Trolls[t_hideHUDIndex].activeFlagClients[victim] & 1) {
|
|
if(GetURandomFloat() > 0.2)
|
|
return;
|
|
timeout = GetRandomFloat(1.0, 5.0);
|
|
} else if(Trolls[t_hideHUDIndex].activeFlagClients[victim] & 2) {
|
|
if(GetURandomFloat() < 0.5)
|
|
return;
|
|
timeout = GetRandomFloat(5.0, 10.0);
|
|
}
|
|
}
|
|
HideHUD(victim, timeout);
|
|
} |