Update plugins

This commit is contained in:
Jackz 2023-08-04 11:42:05 -05:00
parent 2c99586be1
commit daa3b26a4d
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
19 changed files with 611 additions and 298 deletions

BIN
plugins/adminpanel.smx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

387
scripting/adminpanel.sp Normal file
View file

@ -0,0 +1,387 @@
#pragma semicolon 1
#define DEBUG
#define PLUGIN_VERSION "0.00"
#define UPDATE_INTERVAL 6.0
#define UPDATE_INTERVAL_SLOW 15.0
#include <sourcemod>
#include <sdktools>
#include <ripext>
#include <left4dhooks>
#include <jutils>
#pragma newdecls required
public Plugin myinfo =
{
name = "Admin Panel",
author = "Jackz",
description = "",
version = PLUGIN_VERSION,
url = ""
};
ConVar cvar_debug;
ConVar cvar_postAddress; char postAddress[128];
ConVar cvar_authKey; char authKey[512];
ConVar cvar_gamemode; char gamemode[32];
char currentMap[64];
int numberOfPlayers = 0;
int lastSuccessTime;
int lastErrorCode;
int uptime;
bool fastUpdateMode = false;
Handle updateTimer = null;
char steamidCache[MAXPLAYERS+1][32];
char nameCache[MAXPLAYERS+1][MAX_NAME_LENGTH];
int g_icBeingHealed[MAXPLAYERS+1];
int playerJoinTime[MAXPLAYERS+1];
public void OnPluginStart()
{
uptime = GetTime();
cvar_debug = CreateConVar("sm_adminpanel_debug", "0", "Turn on debug mode", FCVAR_DONTRECORD, true, 0.0, true, 1.0);
cvar_postAddress = CreateConVar("sm_adminpanel_url", "", "The base address to post updates to", FCVAR_NONE);
cvar_postAddress.AddChangeHook(OnCvarChanged);
cvar_postAddress.GetString(postAddress, sizeof(postAddress));
cvar_authKey = CreateConVar("sm_adminpanel_key", "", "The authentication key", FCVAR_NONE);
cvar_authKey.AddChangeHook(OnCvarChanged);
cvar_authKey.GetString(authKey, sizeof(authKey));
cvar_gamemode = FindConVar("mp_gamemode");
cvar_gamemode.AddChangeHook(OnCvarChanged);
cvar_gamemode.GetString(gamemode, sizeof(gamemode));
HookEvent("heal_success", Event_HealStop);
HookEvent("heal_interrupted", Event_HealStop);
HookEvent("player_first_spawn", Event_PlayerFirstSpawn);
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) {
OnClientPutInServer(i);
}
}
TryStartTimer(true);
AutoExecConfig(true, "adminpanel");
RegAdminCmd("sm_panel_status", Command_PanelStatus, ADMFLAG_GENERIC);
}
#define DATE_FORMAT "%F at %I:%M %p"
Action Command_PanelStatus(int client, int args) {
ReplyToCommand(client, "Active: %b", updateTimer != null);
ReplyToCommand(client, "Last Error Code: %d", lastErrorCode);
ReplyToCommand(client, "#Players: %d", numberOfPlayers);
ReplyToCommand(client, "Update Interval: %0f s", fastUpdateMode ? UPDATE_INTERVAL : UPDATE_INTERVAL_SLOW);
char buffer[32];
if(lastSuccessTime > 0)
FormatTime(buffer, sizeof(buffer), DATE_FORMAT, lastSuccessTime);
else
Format(buffer, sizeof(buffer), "(none)");
ReplyToCommand(client, "Last Success: %s", buffer);
return Plugin_Handled;
}
void TryStartTimer(bool fast = true) {
if(numberOfPlayers > 0 && updateTimer == null && postAddress[0] != '\0' && authKey[0] != 0) {
fastUpdateMode = fast;
float interval = fast ? UPDATE_INTERVAL : UPDATE_INTERVAL_SLOW;
updateTimer = CreateTimer(interval, Timer_PostStatus, _, TIMER_REPEAT);
PrintToServer("[AdminPanel] Timer created, updating every %.1f seconds", interval);
}
}
public void Event_HealStart(Event event, const char[] name, bool dontBroadcast) {
int healing = GetClientOfUserId(event.GetInt("subject"));
g_icBeingHealed[healing] = true;
}
public void Event_HealStop(Event event, const char[] name, bool dontBroadcast) {
int healing = GetClientOfUserId(event.GetInt("subject"));
g_icBeingHealed[healing] = false;
}
public void Event_PlayerFirstSpawn(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
playerJoinTime[client] = GetTime();
}
public void OnMapStart() {
GetCurrentMap(currentMap, sizeof(currentMap));
}
// Player counts
public void OnClientPutInServer(int client) {
GetClientName(client, nameCache[client], MAX_NAME_LENGTH);
if(!IsFakeClient(client)) {
GetClientAuthId(client, AuthId_SteamID64, steamidCache[client], 32);
numberOfPlayers++;
TryStartTimer(true);
} else {
strcopy(steamidCache[client], 32, "BOT");
}
}
public void OnClientDisconnect(int client) {
steamidCache[client][0] = '\0';
nameCache[client][0] = '\0';
if(!IsFakeClient(client)) {
numberOfPlayers--;
if(numberOfPlayers == 0 && updateTimer != null) {
delete updateTimer;
}
}
}
// Cvar updates
void OnCvarChanged(ConVar convar, const char[] oldValue, const char[] newValue) {
if(cvar_postAddress == convar) {
strcopy(postAddress, sizeof(postAddress), newValue);
PrintToServer("[AdminPanel] Update Url has updated");
} else if(cvar_authKey == convar) {
strcopy(authKey, sizeof(authKey), newValue);
PrintToServer("[AdminPanel] Auth key has been updated");
} else if(cvar_gamemode == convar) {
strcopy(gamemode, sizeof(gamemode), newValue);
}
TryStartTimer(true);
}
bool isSubmitting;
Action Timer_PostStatus(Handle h) {
if(isSubmitting) return Plugin_Continue;
isSubmitting = true;
// TODO: optimize only if someone is requesting live
HTTPRequest req = new HTTPRequest(postAddress);
JSONObject obj = GetObject();
req.SetHeader("x-authtoken", authKey);
// req.AppendFormParam("playerCount", "%d", numberOfPlayers);
// req.AppendFormParam("map", currentMap);
if(cvar_debug.BoolValue) PrintToServer("[AdminPanel] Submitting");
req.Post(obj, Callback_PostStatus);
delete obj;
// req.PostForm(Callback_PostStatus);
return Plugin_Continue;
}
void Callback_PostStatus(HTTPResponse response, any value, const char[] error) {
isSubmitting = false;
if(response.Status == HTTPStatus_NoContent || response.Status == HTTPStatus_OK) {
lastErrorCode = 0;
lastSuccessTime = GetTime();
if(cvar_debug.BoolValue)
PrintToServer("[AdminPanel] Response: OK/204");
// We have subscribers, kill timer and recreate it in fast mode (if not already):
if(!fastUpdateMode) {
PrintToServer("[AdminPanel] We have subscribers, increasing interval");
if(updateTimer != null)
delete updateTimer;
TryStartTimer(true);
}
} else if(response.Status == HTTPStatus_Gone) {
lastErrorCode = 0;
// We have no subscribers, kill timer and recreate it in slow mode (if not already):
if(fastUpdateMode) {
PrintToServer("[AdminPanel] No subscribers, decreasing interval");
if(updateTimer != null)
delete updateTimer;
TryStartTimer(false);
}
} else {
lastErrorCode = view_as<int>(response.Status);
lastSuccessTime = 0;
// TODO: backoff
char buffer[64];
JSONObject json = view_as<JSONObject>(response.Data);
if(json.GetString("error", buffer, sizeof(buffer))) {
PrintToServer("[AdminPanel] Got %d response from server: \"%s\"", view_as<int>(response.Status), buffer);
json.GetString("message", buffer, sizeof(buffer));
PrintToServer("[AdminPanel] Error message: \"%s\"", buffer);
} else {
PrintToServer("[AdminPanel] Got %d response from server: <unknown json>\n%s", view_as<int>(response.Status), error);
}
if(response.Status == HTTPStatus_Unauthorized || response.Status == HTTPStatus_Forbidden) {
PrintToServer("[AdminPanel] API Key seems to be invalid, killing timer.");
if(updateTimer != null)
delete updateTimer;
}
}
}
JSONObject GetObject() {
JSONObject obj = new JSONObject();
obj.SetInt("playerCount", numberOfPlayers);
obj.SetString("map", currentMap);
obj.SetString("gamemode", gamemode);
obj.SetInt("startTime", uptime);
obj.SetInt("commonsCount", L4D_GetCommonsCount());
obj.SetFloat("fps", 1.0 / GetGameFrameTime());
AddFinaleInfo(obj);
JSONArray players = GetPlayers();
obj.Set("players", players);
delete players;
obj.SetFloat("refreshInterval", UPDATE_INTERVAL);
obj.SetInt("lastUpdateTime", GetTime());
return obj;
}
void AddFinaleInfo(JSONObject parentObj) {
if(L4D_IsMissionFinalMap()) {
JSONObject obj = new JSONObject();
obj.SetBool("escapeLeaving", L4D_IsFinaleEscapeInProgress());
obj.SetInt("finaleStage", L4D2_GetCurrentFinaleStage());
parentObj.Set("finaleInfo", obj);
delete obj;
}
}
JSONArray GetPlayers() {
JSONArray players = new JSONArray();
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) >= 2) {
JSONObject player = GetPlayer(i);
players.Push(player);
delete player;
}
}
return players;
}
enum {
Action_BeingHealed = -1,
Action_None = 0, // No use action active
Action_Healing = 1, // Includes healing yourself or a teammate.
Action_AmmoPack = 2, // When deploying the ammo pack that was never added into the game
Action_Defibing = 4, // When defib'ing a dead body.
Action_GettingDefibed = 5, // When comming back to life from a dead body.
Action_DeployIncendiary = 6, // When deploying Incendiary ammo
Action_DeployExplosive = 7, // When deploying Explosive ammo
Action_PouringGas = 8, // Pouring gas into a generator
Action_Cola = 9, // For Dead Center map 2 cola event, when handing over the cola to whitalker.
Action_Button = 10, // Such as buttons, timed buttons, generators, etc.
Action_UsePointScript = 11 // When using a "point_script_use_target" entity
}
int GetAction(int client) {
if(g_icBeingHealed[client]) return Action_BeingHealed;
return view_as<int>(L4D2_GetPlayerUseAction(client));
}
enum {
Move_UnderAttack = -3,
Move_Hanging = -2,
Move_Incapped = -1,
Move_Idle = 0,
Move_Walk = 1,
Move_Run = 2,
Move_Crouched = 3,
Move_Ladder = 4
}
stock float GetPlayerSpeed(int client) {
int iVelocity = FindSendPropInfo("CTerrorPlayer", "m_vecVelocity[0]");
float velocity[3];
GetEntDataVector(client, iVelocity, velocity);
return GetVectorLength(velocity, false);
}
int GetPlayerMovement(int client) {
MoveType moveType = GetEntityMoveType(client);
if(moveType == MOVETYPE_LADDER) return Move_Ladder;
else if(GetEntProp(client, Prop_Send, "m_bDucked", 1)) return Move_Crouched;
else if(GetEntProp(client, Prop_Send, "m_isIncapacitated", 1)) return Move_Incapped;
else if(GetEntProp(client, Prop_Send, "m_isHangingFromLedge", 1)) return Move_Hanging;
else if(L4D_GetPinnedSurvivor(client)) return Move_UnderAttack; // TODO: optimize for events
float velocity = GetPlayerSpeed(client);
if(velocity > 85.0) return Move_Run;
else if(velocity > 1.0) return Move_Walk;
return Move_Idle;
}
// TODO: pursued by witch
enum {
pState_BlackAndWhite = 1,
pState_InSaferoom = 2,
pState_IsCalm = 4,
pState_IsBoomed = 8
}
stock bool IsPlayerBoomed(int client) {
return (GetEntPropFloat(client, Prop_Send, "m_vomitStart") + 20.1) > GetGameTime();
}
int GetPlayerStates(int client) {
int state = 0;
if(L4D_IsInLastCheckpoint(client) || L4D_IsInFirstCheckpoint(client))
state |= pState_InSaferoom;
if(GetEntProp(client, Prop_Send, "m_bIsOnThirdStrike", 1)) state |= pState_BlackAndWhite;
if(GetEntProp(client, Prop_Send, "m_isCalm")) state |= pState_IsCalm;
if(IsPlayerBoomed(client)) state |= pState_IsBoomed;
return state;
}
JSONObject GetPlayer(int client) {
int team = GetClientTeam(client);
JSONObject player = new JSONObject();
player.SetString("steamid", steamidCache[client]);
player.SetString("name", nameCache[client]);
player.SetInt("team", team);
player.SetBool("isAlive", IsPlayerAlive(client));
player.SetInt("joinTime", playerJoinTime[client]);
player.SetInt("permHealth", GetEntProp(client, Prop_Send, "m_iHealth"));
if(team == 2) {
if(IsFakeClient(client)) {
int idlePlayer = L4D_GetIdlePlayerOfBot(client);
if(idlePlayer > 0) {
player.SetString("idlePlayerId", steamidCache[idlePlayer]);
if(IsClientInGame(idlePlayer)) {
JSONObject idlePlayerObj = GetPlayer(idlePlayer);
player.Set("idlePlayer", idlePlayerObj);
delete idlePlayerObj;
}
}
}
player.SetInt("action", GetAction(client));
player.SetInt("flowProgress", L4D2_GetVersusCompletionPlayer(client));
player.SetFloat("flow", L4D2Direct_GetFlowDistance(client));
player.SetBool("isPinned", L4D2_GetInfectedAttacker(client) > 0);
player.SetInt("tempHealth", L4D_GetPlayerTempHealth(client));
player.SetInt("states", GetPlayerStates(client));
player.SetInt("move", GetPlayerMovement(client));
player.SetInt("survivor", GetEntProp(client, Prop_Send, "m_survivorCharacter"));
JSONArray weapons = GetPlayerWeapons(client);
player.Set("weapons", weapons);
delete weapons;
} else if(team == 3) {
player.SetInt("class", L4D2_GetPlayerZombieClass(client));
player.SetInt("maxHealth", GetEntProp(client, Prop_Send, "m_iMaxHealth"));
int victim = L4D2_GetSurvivorVictim(client);
if(victim > 0)
player.SetString("pinnedSurvivorId", steamidCache[victim]);
}
return player;
}
JSONArray GetPlayerWeapons(int client) {
JSONArray weapons = new JSONArray();
static char buffer[64];
for(int slot = 0; slot < 6; slot++) {
if(GetClientWeaponNameSmart(client, slot, buffer, sizeof(buffer))) {
weapons.PushString(buffer);
} else {
weapons.PushNull();
}
}
return weapons;
}

View file

@ -4,7 +4,7 @@
//Allow MAX_TROLLS to be defined elsewhere
#if defined MAX_TROLLS
#else
#define MAX_TROLLS 50
#define MAX_TROLLS 51
#endif
enum trollModifier {
@ -82,6 +82,18 @@ enum struct Troll {
ArrayList flagNames;
ArrayList flagPrompts;
Timer timerFunction;
Handle timerHandles[MAXPLAYERS+1];
float timerInterval;
void SetTimer(float interval, Timer timer) {
this.timerInterval = interval;
this.timerFunction = timer;
for(int i = 0; i <= MAXPLAYERS; i++) {
this.timerHandles[i] = null;
}
}
bool HasMod(trollModifier mod) {
return ((this.mods >> (view_as<int>(mod)) - 1) & 1) == 1;
}
@ -208,15 +220,32 @@ enum struct Troll {
void Toggle(int client, int flags) {
ToggleTroll(client, this.name, flags);
if(this.IsActive(client)) {
this.Disable(client);
} else {
this.Enable(client, flags);
}
}
void Enable(int client, int flags) {
EnableTroll(client, this.name, flags);
this.activeFlagClients[client] = flags;
// If a timer is assigned, start it:
if(this.timerHandles[client] != null) {
delete this.timerHandles[client];
PrintToServer("FTT Debug: Old timer for %N, killing", client);
}
if(this.timerInterval > 0.0) {
this.timerHandles[client] = CreateTimer(this.timerInterval, this.timerFunction, GetClientUserId(client), TIMER_REPEAT);
}
}
void Disable(int client) {
DisableTroll(client, this.name);
this.activeFlagClients[client] = -1;
// Stop any running timer:
if(this.timerHandles[client] != null) {
PrintToServer("FTT Debug: Disabling timer for %N", client);
delete this.timerHandles[client];
}
}
bool IsActive(int client) {
@ -244,7 +273,7 @@ void ResetClient(int victim, bool wipe = true) {
if(victim == 0 || !IsClientConnected(victim)) return;
if(wipe) {
for(int i = 0; i <= MAX_TROLLS; i++) {
Trolls[i].activeFlagClients[victim] = -1;
Trolls[i].Disable(victim);
}
}
noRushingUsSpeed[victim] = 1.0;
@ -311,18 +340,12 @@ void GetTrollByKeyIndex(int index, Troll troll) {
troll = Trolls[index];
}
void ToggleTroll(int client, const char[] name, int flags = 0) {
static Troll troll;
GetTroll(name, troll);
if(troll.IsActive(client))
troll.activeFlagClients[client] = -1;
else
troll.activeFlagClients[client] = flags;
}
void SetTrollFlags(int client, const char[] name, int flags = -1) {
int index = GetTrollID(name);
Trolls[index].activeFlagClients[client] = flags;
if(flags == -1)
Trolls[index].Disable(client);
else
Trolls[index].Enable(client, flags);
}
void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, int flags = 0, bool silent = false) {
@ -334,6 +357,10 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
return;
}
if(flags > -1 && Trolls[trollIndex].timerInterval > 0.0) {
CreateTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, victim, TIMER_REPEAT);
}
if(!silent && SilentMenuSelected[activator]) silent = true;
static int MetaInverseTrollID;

View file

@ -44,7 +44,7 @@ public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int pa
}
SpecialType special = view_as<SpecialType>(specialInt);
if(inFace) {
if(SpawnSpecialForTarget(special, target, view_as<int>(Special_OnTarget))) {
if(SpawnSpecialForTarget(special, target, view_as<int>(Special_OnTarget | Special_SpawnDirectOnFailure))) {
LogAction(client, target, "\"%L\" spawned Insta-%s™ on \"%L\"", client, SPECIAL_NAMES[specialInt-1], target);
CShowActivityEx(client, "[FTT] ", "spawned {olive}Insta-%s™{default} on {olive}%N", SPECIAL_NAMES[specialInt-1], target);
} else {
@ -396,10 +396,9 @@ void ShowTrollMenu(int client, bool isComboList) {
menu.SetTitle("Choose a player to troll");
static char userid[8], display[64];
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) {
if(IsClientConnected(i) && IsClientInGame(i) && (hAllowEnemyTeam.BoolValue || GetClientTeam(i) == GetClientTeam(client))) {
IntToString(GetClientUserId(i), userid, sizeof(userid));
int realPlayer = L4D_GetBotOfIdlePlayer(i);
PrintToServer("%d/%d", i, realPlayer);
// Incase player is idle, grab their bot instead of them
if(realPlayer > 0 && IsClientConnected(realPlayer)) {
if(IsPlayerAlive(i))

View file

@ -45,6 +45,7 @@ stock bool SpawnSpecialForTarget(SpecialType specialType, int target, int spawnF
float minDistance = GetIdealMinDistance(specialType);
GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos);
if(!FindSuitablePosition(pos, testPos, minDistance, 100)) {
PrintToServer("[FTT] Could not find suitable position, falling back");
if(spawnFlags & view_as<int>(Special_SpawnDirectOnFailure))
GetClientAbsOrigin(target, pos);
else

View file

@ -11,6 +11,25 @@ public Action Timer_ThrowTimer(Handle timer) {
}
int instantCommonRef[MAXPLAYERS+1];
Action Timer_RandomVelocity(Handle h, int client) {
if(!IsClientConnected(client)) {
Trolls[t_randomizeVelocityIndex].timerHandles[client] = null;
return Plugin_Stop;
}
float bounds = 50.0;
if(Trolls[t_randomizeAnglesIndex].activeFlagClients[client] & 2) bounds = 100.0;
else if(Trolls[t_randomizeAnglesIndex].activeFlagClients[client] & 4) bounds = 200.0;
else if(Trolls[t_randomizeAnglesIndex].activeFlagClients[client] & 8) bounds = 500.0;
else if(Trolls[t_randomizeAnglesIndex].activeFlagClients[client] & 16) bounds = 1000.0;
float vel[3];
GetEntPropVector(client, Prop_Data, "m_vecVelocity", vel);
vel[0] += GetRandomFloat(-bounds, bounds);
vel[1] += GetRandomFloat(-bounds, bounds);
vel[2] += GetRandomFloat(-100.0, 150.0);
SetAbsVelocity(client, vel);
return Plugin_Continue;
}
public Action Timer_Main(Handle timer) {
static int loopTick;
@ -40,6 +59,19 @@ public Action Timer_Main(Handle timer) {
TeleportEntity(i, NULL_VECTOR, ang, NULL_VECTOR);
}
}
if(Trolls[t_randomizeVelocityIndex].IsActive(i)) {
float bounds = 50.0;
if(Trolls[t_randomizeVelocityIndex].activeFlagClients[i] & 2) bounds = 100.0;
else if(Trolls[t_randomizeVelocityIndex].activeFlagClients[i] & 4) bounds = 200.0;
else if(Trolls[t_randomizeVelocityIndex].activeFlagClients[i] & 8) bounds = 500.0;
else if(Trolls[t_randomizeVelocityIndex].activeFlagClients[i] & 16) bounds = 1000.0;
float vel[3];
GetEntPropVector(i, Prop_Data, "m_vecVelocity", vel);
vel[0] += GetRandomFloat(-bounds, bounds);
vel[1] += GetRandomFloat(-bounds, bounds);
vel[2] += GetRandomFloat(-100.0, 150.0);
SetAbsVelocity(i, vel);
}
if(Trolls[slowDrainIndex].IsActive(i)) {
if(loopTick % 4 == 0) {
int hp = GetClientHealth(i);

View file

@ -4,6 +4,7 @@ int slipperyShoesIndex = 0;
int stickyGooIndex = 0;
int invertedTrollIndex;
int t_randomizeAnglesIndex;
int t_randomizeVelocityIndex;
// int fireSpitMagnetTrollIndex;
void SetupTrolls() {
@ -45,7 +46,7 @@ void SetupTrolls() {
Trolls[index].AddFlag("30% Movement Speed", false);
Trolls[index].AddFlag("0% Movement Speed", false);
stickyGooIndex = index;
index = SetupTroll("Vocalize Specials", "Spawn commons on special vocals", TrollMod_Constant);
index = SetupTroll("Vocalize Specials", "Spawn commons on special vocals", TrollMod_Constant)
Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("Mute Vocalization", true);
Trolls[index].AddFlag("Do not mute", false);
@ -84,6 +85,7 @@ void SetupTrolls() {
// CATEGORY: Items
SetCategory("Items");
SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant);
index = SetupTroll("Spicy Gas", "Gascans player picks up just ignite. Magic.", TrollMod_Constant);
Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("Always (100%)", false);
@ -204,6 +206,15 @@ void SetupTrolls() {
Trolls[index].AddFlag("Painful", false); //8
Trolls[index].AddFlag("Seizure", false); //16
t_randomizeAnglesIndex = index;
index = SetupTroll("Randomize Velocity", "Randomly change their velocity", TrollMod_Constant);
Trolls[index].SetTimer(0.1, Timer_RandomVelocity);
Trolls[index].AddCustomFlagPrompt("Frequency:", false);
Trolls[index].AddFlag("Loose", true); //1
Trolls[index].AddFlag("Slippery", false); //2
Trolls[index].AddFlag("Earthquake", false); //4
Trolls[index].AddFlag("Severe Earthquake", false); //8
Trolls[index].AddFlag("Bouncy Castle", false); //16
t_randomizeVelocityIndex = index;
/// CATEGORY: MISC
@ -230,6 +241,7 @@ void SetupTrolls() {
// Initialize the default flag values to -1
for(int i = 0; i <= MAX_TROLLS; i++) {
for(int j = 1; j <= MAXPLAYERS; j++) {
Trolls[i].timerHandles[j] = null;
Trolls[i].activeFlagClients[j] = -1;
}
}

View file

@ -17,6 +17,7 @@ Handle g_hWitchAttack;
int g_iWitchAttackVictim;
Handle hThrowTimer;
ConVar hAllowEnemyTeam;
ConVar hThrowItemInterval;
ConVar hAutoPunish;
ConVar hMagnetChance;

View file

@ -896,3 +896,42 @@ stock int GetSinglePlayer(int client, const char[] input, int flags = 0) {
}
return target_list[0];
}
static int _glowColor[3] = { 255, 255, 255 };
stock void GlowPoint(const float pos[3], float lifetime = 5.0) {
PrecacheModel("models/props_fortifications/orange_cone001_reference.mdl");
int entity = CreateEntityByName("prop_dynamic");
DispatchKeyValue(entity, "disableshadows", "1");
DispatchKeyValue(entity, "model", "models/props_fortifications/orange_cone001_reference.mdl");
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
DispatchSpawn(entity);
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, _glowColor, false);
CreateTimer(lifetime, Timer_KillEntity, entity);
}
stock void GlowEntity(int entity, float lifetime = 10.0) {
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, _glowColor, false);
CreateTimer(lifetime, Timer_ClearGlow, EntIndexToEntRef(entity));
}
Action Timer_ClearGlow(Handle h, int ref) {
L4D2_RemoveEntityGlow(ref);
return Plugin_Handled;
}
stock bool CompareVector(const float a[3], const float b[3], float delta) {
return a[0] < b[0] + delta && a[0] > b[0] - delta &&
a[1] < b[1] + delta && a[1] > b[1] - delta &&
a[2] < b[2] + delta && a[2] > b[2] - delta
}
stock void CalculateWorldPosition(int entity, float pos[3]) {
float mins[3], maxs[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
GetEntPropVector(entity, Prop_Send, "m_vecMins", mins);
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", maxs);
pos[0] = pos[0] + (mins[0] + maxs[0]) * 0.5;
pos[1] = pos[1] + (mins[1] + maxs[1]) * 0.5;
pos[2] = pos[2] + (mins[2] + maxs[2]) * 0.5;
}

View file

@ -12,15 +12,13 @@ enum SocketType {
SOCKET_RAW
}
enum {
EMPTY_HOST = 1,
NO_HOST,
CONNECT_ERROR,
SEND_ERROR,
BIND_ERROR,
RECV_ERROR,
LISTEN_ERROR
}
#define EMPTY_HOST 1
#define NO_HOST 2
#define CONNECT_ERROR 3
#define SEND_ERROR 4
#define BIND_ERROR 5
#define RECV_ERROR 6
#define LISTEN_ERROR 7
/*************************************************************************************************/
@ -47,7 +45,7 @@ enum SocketOption {
* @note don't forget to set your buffer sizes at least to the value passed to this function, but
* always at least to 4096
*
* @param int 0(=default) to disable or max. chunk size including \0 terminator in bytes
* @param cell_t 0(=default) to disable or max. chunk size including \0 terminator in bytes
* @return bool true on success
*/
ConcatenateCallbacks = 1,
@ -75,7 +73,7 @@ enum SocketOption {
*
* @note this option will affect all sockets from all plugins, use it with caution!
*
* @param int maximum amount of callbacks per gameframe
* @param cell_t maximum amount of callbacks per gameframe
* @return bool true on success
*/
CallbacksPerFrame,
@ -107,7 +105,7 @@ enum SocketOption {
* This option specifies how long a socket will wait if it's being closed and its send buffer is
* still filled. This is a wrapper for setting SO_LINGER.
*
* @param int 0 (=default) to disable or time in s
* @param cell_t 0 (=default) to disable or time in s
* @return bool true on success
*/
SocketLinger,
@ -123,7 +121,7 @@ enum SocketOption {
* This option specifies how large the send buffer will be. This is a wrapper for setting
* SO_SNDBUF.
*
* @param int size in bytes
* @param cell_t size in bytes
* @return bool true on success
*/
SocketSendBuffer,
@ -131,7 +129,7 @@ enum SocketOption {
* This option specifies how large the receive buffer will be. This is a wrapper for setting
* SO_RCVBUF.
*
* @param int size in bytes
* @param cell_t size in bytes
* @return bool true on success
*/
SocketReceiveBuffer,
@ -150,7 +148,7 @@ enum SocketOption {
*
* @note this can probably block the extension, use it with caution!
*
* @param int size in bytes
* @param cell_t size in bytes
* @return bool true on success
*/
SocketReceiveLowWatermark,
@ -158,7 +156,7 @@ enum SocketOption {
* This option specifies how long a socket will try to receive data before it times out and
* processes the data. This is a wrapper for setting SO_RCVTIMEO.
*
* @param int 0 (=default) to disable or time in ms
* @param cell_t 0 (=default) to disable or time in ms
* @return bool true on success
*/
SocketReceiveTimeout,
@ -168,7 +166,7 @@ enum SocketOption {
*
* @note this can probably block the extension, use it with caution!
*
* @param int size in bytes
* @param cell_t size in bytes
* @return bool true on success
*/
SocketSendLowWatermark,
@ -176,7 +174,7 @@ enum SocketOption {
* This option specifies how long a socket will try to send data before it times out and
* retries it later. This is a wrapper for setting SO_SNDTIMEO.
*
* @param int 0 (=default) to disable or time in ms
* @param cell_t 0 (=default) to disable or time in ms
* @return bool true on success
*/
SocketSendTimeout,
@ -189,173 +187,12 @@ enum SocketOption {
DebugMode
}
// Methodmap
methodmap Socket < Handle {
/**
* Creates a new socket.
*
* @note this function may be relatively expensive, reuse sockets if possible
*
* @param SocketType protocol The protocol to use, SOCKET_TCP is default
* @param SocketErrorCB efunc The error callback
* @return Handle The socket handle. Returns INVALID_HANDLE on failure
*/
public native Socket(SocketType protocol=SOCKET_TCP, SocketErrorCB efunc);
/**
* Binds the socket to a local address
*
* @param String hostname The hostname (or IP) to bind the socket to.
* @param int port The port to bind the socket to.
* @return bool true on success
*/
public native bool Bind(const char[] hostname, int port);
/**
* Connects a socket
*
* @note this native is threaded, it may be still running after it executed, use the connect callback
* @note invokes the SocketError callback with errorType = CONNECT_ERROR or EMPTY_HOST if it fails
* @note invokes the SocketConnect callback if it succeeds
*
* @param SocketConnectCB cfunc The connect callback
* @param SocketReceiveCB rfunc The receive callback
* @param SocketDisconnectCB dfunc The disconnect callback
* @param String hostname The hostname (or IP) to connect to.
* @param int port The port to connect to.
*/
public native void Connect(SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port);
/**
* Disconnects a socket
*
* @note this will not close the handle, the socket will be reset to a state similar to after SocketCreate()
* @note this won't trigger any disconnect/error callbacks
*
* @return bool true on success
*/
public native bool Disconnect();
/**
* Makes a socket listen for incoming connections
*
* @param SocketIncomingCB ifunc The callback for incoming connections
* @return bool true on success
*/
public native bool Listen(SocketIncomingCB ifunc);
/**
* Sends data through the socket.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
* @note This native is threaded, it may be still running after it executed (not atomic).
* @note Use the SendqueueEmpty callback to determine when all data has been successfully sent.
* @note The socket extension will ensure that the data will be send in the correct order and split
* the data if required.
*
* @param String data The data to send.
*/
public native void Send(const char[] data, int size = -1);
/**
* Sends UDP data through the socket to a specific destination.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
* @note This native is threaded, it may be still running after it executed (not atomic).
* @note Use the SendqueueEmpty callback to determine when all data has been successfully sent.
* @note The socket extension will ensure that the data will be send in the correct order and split
* the data if required.
*
* @param String data The data to send.
* @param String hostname The hostname (or IP) to send to.
* @param int port The port to send to.
*/
public native void SendTo(const char[] data, int size = -1, const char[] hostname, int port);
/**
* Set a socket option.
*
* @param SocketOption option The option to modify (see enum SocketOption for details).
* @param int value The value to set the option to.
* @return int 1 on success.
*/
public native int SetOption(SocketOption option, int value);
/**
* Defines the callback function for when the socket receives data
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketConnect())
*
* @param SocketReceiveCB rfunc The receive callback
*/
public native void SetReceiveCallback(SocketReceiveCB rfunc);
/**
* Defines the callback function for when the socket sent all items in its send queue
*
* @note this must be called AFTER sending (queueing) the data
* @note if no send-data is queued this will fire the callback itself
* @note the callback is guaranteed to fire
*
* @param SocketDisconnectCB dfunc The disconnect callback
*/
public native void SetSendqueueEmptyCallback(SocketSendqueueEmptyCB sfunc);
/**
* Defines the callback function for when the socket was properly disconnected by the remote side
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketConnect())
*
* @param SocketDisconnectCB dfunc The disconnect callback
*/
public native void SetDisconnectCallback(SocketDisconnectCB dfunc);
/**
* Defines the callback function for when the socket triggered an error
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketCreate())
*
* @param SocketErrorCB efunc The error callback
*/
public native void SetErrorCallback(SocketErrorCB efunc);
/**
* Sets the argument being passed to callbacks
*
* @param any arg The argument to set
*/
public native void SetArg(any arg);
/**
* Retrieve the local system's hostname as the command "hostname" does.
*
* @param dest Destination string buffer to copy to.
* @param destLen Destination buffer length (includes null terminator).
*
* @return 1 on success
*/
public static native int GetHostName(char[] dest, int destLen);
/**
* Returns whether a socket is connected or not.
*
* @return bool The connection status
*/
property bool Connected {
public native get();
}
}
/*************************************************************************************************/
/******************************************* callbacks *******************************************/
/*************************************************************************************************/
/**
* triggered if a normal sockets finished connecting and is ready to be used
*
@ -363,20 +200,26 @@ methodmap Socket < Handle {
* @param arg The argument set by SocketSetArg()
* @noreturn
*/
typedef SocketConnectCB = function void (Socket socket, any arg);
funcenum SocketConnectCB
{
public(Handle:socket, any:arg)
};
/**
* triggered if a listening socket received an incoming connection and is ready to be used
*
* @note The child-socket won't work until receive-, disconnect-, and errorcallback for it are set.
*
* @param Socket socket The socket handle pointing to the calling listen-socket
* @param Socket newSocket The socket handle to the newly spawned child socket
* @param Handle socket The socket handle pointing to the calling listen-socket
* @param Handle newSocket The socket handle to the newly spawned child socket
* @param String remoteIP The remote IP
* @param any arg The argument set by SocketSetArg() for the listen-socket
* @noreturn
*/
typedef SocketIncomingCB = function void (Socket socket, Socket newSocket, const char[] remoteIP, int remotePort, any arg);
funcenum SocketIncomingCB
{
public(Handle:socket, Handle:newSocket, const String:remoteIP[], remotePort, any:arg)
};
/**
* triggered if a socket receives data
@ -386,46 +229,59 @@ typedef SocketIncomingCB = function void (Socket socket, Socket newSocket, const
* @note if not set otherwise by SocketSetOption(..., ConcatenateCallbacks, ...) receiveData will
* never be longer than 4096 characters including \0 terminator
*
* @param Socket socket The socket handle pointing to the calling socket
* @param Handle socket The socket handle pointing to the calling socket
* @param String receiveData The data which arrived, 0-terminated at receiveData[dataSize]
* @param int dataSize The length of the arrived data excluding the 0-termination
* @param cell_t dataSize The length of the arrived data excluding the 0-termination
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typedef SocketReceiveCB = function void (Socket socket, const char[] receiveData, const int dataSize, any arg);
funcenum SocketReceiveCB
{
public(Handle:socket, const String:receiveData[], const dataSize, any:arg)
};
/**
* called after a socket sent all items in its send queue successfully
*
* @param Socket socket The socket handle pointing to the calling socket
* @param Handle socket The socket handle pointing to the calling socket
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typedef SocketSendqueueEmptyCB = function void (Socket socket, any arg);
funcenum SocketSendqueueEmptyCB
{
public(Handle:socket, any:arg)
};
/**
* called if a socket has been properly disconnected by the remote side
*
* @note You should call CloseHandle(socket) or reuse the socket before this function ends
*
* @param Socket socket The socket handle pointing to the calling socket
* @param Handle socket The socket handle pointing to the calling socket
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typedef SocketDisconnectCB = function void (Socket socket, any arg);
funcenum SocketDisconnectCB
{
public(Handle:socket, any:arg)
};
/**
* called if an unrecoverable error occured, close the socket without an additional call to a disconnect callback
*
* @note You should call CloseHandle(socket) or reuse the socket before this function ends
*
* @param Socket socket The socket handle pointing to the calling socket
* @param int errorType The error type, see defines above
* @param int errorNum The errno, see errno.h for details
* @param Handle socket The socket handle pointing to the calling socket
* @param cell_t errorType The error type, see defines above
* @param cell_t errorNum The errno, see errno.h for details
* @param any arg The argument set by SocketSetArg() for the socket
* @noreturn
*/
typedef SocketErrorCB = function void (Socket socket, const int errorType, const int errorNum, any arg);
funcenum SocketErrorCB
{
public(Handle:socket, const errorType, const errorNum, any:arg)
};
/*************************************************************************************************/
/******************************************** natives ********************************************/
@ -438,7 +294,7 @@ typedef SocketErrorCB = function void (Socket socket, const int errorType, const
* @param socket Socket handle to check
* @return bool The connection status
*/
native bool SocketIsConnected(Handle socket);
native bool:SocketIsConnected(Handle:socket);
/**
@ -448,19 +304,18 @@ native bool SocketIsConnected(Handle socket);
*
* @param SocketType protocol The protocol to use, SOCKET_TCP is default
* @param SocketErrorCB efunc The error callback
* @return Socket The socket handle. Returns INVALID_HANDLE on failure
* @return Handle The socket handle. Returns INVALID_HANDLE on failure
*/
native Socket SocketCreate(SocketType protocol=SOCKET_TCP, SocketErrorCB efunc);
native Handle:SocketCreate(SocketType:protocol=SOCKET_TCP, SocketErrorCB:efunc);
/**
* Binds the socket to a local address
*
* @param Handle socket The handle of the socket to be used.
* @param String hostname The hostname (or IP) to bind the socket to.
* @param int port The port to bind the socket to.
* @param Handle socket The handle of the socket to be used. * @param String hostname The hostname (or IP) to bind the socket to.
* @param cell_t port The port to bind the socket to.
* @return bool true on success
*/
native bool SocketBind(Handle socket, const char[] hostname, int port);
native bool:SocketBind(Handle:socket, const String:hostname[], port);
/**
* Connects a socket
@ -472,12 +327,11 @@ native bool SocketBind(Handle socket, const char[] hostname, int port);
* @param Handle socket The handle of the socket to be used.
* @param SocketConnectCB cfunc The connect callback
* @param SocketReceiveCB rfunc The receive callback
* @param SocketDisconnectCB dfunc The disconnect callback
* @param String hostname The hostname (or IP) to connect to.
* @param int port The port to connect to.
* @param SocketDisconnectCB dfunc The disconnect callback * @param String hostname The hostname (or IP) to connect to.
* @param cell_t port The port to connect to.
* @noreturn
*/
native void SocketConnect(Handle socket, SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port);
native SocketConnect(Handle:socket, SocketConnectCB:cfunc, SocketReceiveCB:rfunc, SocketDisconnectCB:dfunc, const String:hostname[], port);
/**
* Disconnects a socket
@ -487,7 +341,7 @@ native void SocketConnect(Handle socket, SocketConnectCB cfunc, SocketReceiveCB
*
* @noreturn
*/
native bool SocketDisconnect(Handle socket);
native bool:SocketDisconnect(Handle:socket);
/**
* Makes a socket listen for incoming connections
@ -496,7 +350,7 @@ native bool SocketDisconnect(Handle socket);
* @param SocketIncomingCB ifunc The callback for incoming connections
* @return bool true on success
*/
native bool SocketListen(Handle socket, SocketIncomingCB ifunc);
native bool:SocketListen(Handle:socket, SocketIncomingCB:ifunc);
/**
* Sends data through the socket.
@ -510,12 +364,10 @@ native bool SocketListen(Handle socket, SocketIncomingCB ifunc);
*
* @param Handle socket The handle of the socket to be used.
* @param String data The data to send.
* @noreturn
*/
native void SocketSend(Handle socket, const char[] data, int size=-1);
* @noreturn */
native SocketSend(Handle:socket, const String:data[], size=-1);
/**
* Sends UDP data through the socket to a specific destination.
/** * Sends UDP data through the socket to a specific destination.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
@ -527,10 +379,9 @@ native void SocketSend(Handle socket, const char[] data, int size=-1);
* @param Handle socket The handle of the socket to be used.
* @param String data The data to send.
* @param String hostname The hostname (or IP) to send to.
* @param int port The port to send to.
* @noreturn
*/
native void SocketSendTo(Handle socket, const char[] data, int size=-1, const char[] hostname, int port);
* @param cell_t port The port to send to.
* @noreturn */
native SocketSendTo(Handle:socket, const String:data[], size=-1, const String:hostname[], port);
/**
* Set a socket option.
@ -538,9 +389,8 @@ native void SocketSendTo(Handle socket, const char[] data, int size=-1, const ch
* @param Handle socket The handle of the socket to be used. May be INVALID_HANDLE if not essential.
* @param SocketOption option The option to modify (see enum SocketOption for details).
* @param cellt_ value The value to set the option to.
* @return int 1 on success.
*/
native int SocketSetOption(Handle socket, SocketOption option, int value);
* @return cell_t 1 on success. */
native SocketSetOption(Handle:socket, SocketOption:option, value);
/**
@ -553,7 +403,7 @@ native int SocketSetOption(Handle socket, SocketOption option, int value);
* @param SocketReceiveCB rfunc The receive callback
* @noreturn
*/
native void SocketSetReceiveCallback(Handle socket, SocketReceiveCB rfunc);
native SocketSetReceiveCallback(Handle:socket, SocketReceiveCB:rfunc);
/**
* Defines the callback function for when the socket sent all items in its send queue
@ -566,7 +416,7 @@ native void SocketSetReceiveCallback(Handle socket, SocketReceiveCB rfunc);
* @param SocketDisconnectCB dfunc The disconnect callback
* @noreturn
*/
native void SocketSetSendqueueEmptyCallback(Handle socket, SocketSendqueueEmptyCB sfunc);
native SocketSetSendqueueEmptyCallback(Handle:socket, SocketSendqueueEmptyCB:sfunc);
/**
* Defines the callback function for when the socket was properly disconnected by the remote side
@ -578,7 +428,7 @@ native void SocketSetSendqueueEmptyCallback(Handle socket, SocketSendqueueEmptyC
* @param SocketDisconnectCB dfunc The disconnect callback
* @noreturn
*/
native void SocketSetDisconnectCallback(Handle socket, SocketDisconnectCB dfunc);
native SocketSetDisconnectCallback(Handle:socket, SocketDisconnectCB:dfunc);
/**
* Defines the callback function for when the socket triggered an error
@ -590,7 +440,7 @@ native void SocketSetDisconnectCallback(Handle socket, SocketDisconnectCB dfunc)
* @param SocketErrorCB efunc The error callback
* @noreturn
*/
native void SocketSetErrorCallback(Handle socket, SocketErrorCB efunc);
native SocketSetErrorCallback(Handle:socket, SocketErrorCB:efunc);
/**
@ -600,7 +450,7 @@ native void SocketSetErrorCallback(Handle socket, SocketErrorCB efunc);
* @param any arg The argument to set
* @noreturn
*/
native void SocketSetArg(Handle socket, any arg);
native SocketSetArg(Handle:socket, any:arg);
/**
* Retrieve the local system's hostname as the command "hostname" does.
@ -610,12 +460,12 @@ native void SocketSetArg(Handle socket, any arg);
*
* @return 1 on success
*/
native int SocketGetHostName(char[] dest, int destLen);
native SocketGetHostName(String:dest[], destLen);
/**
* _________________Do not edit below this line!_______________________
*/
public Extension __ext_socket =
public Extension:__ext_smsock =
{
name = "Socket",
file = "socket.ext",
@ -630,39 +480,3 @@ public Extension __ext_socket =
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public void __ext_socket_SetNTVOptional()
{
MarkNativeAsOptional("Socket.Socket");
MarkNativeAsOptional("Socket.Bind");
MarkNativeAsOptional("Socket.Connect");
MarkNativeAsOptional("Socket.Disconnect");
MarkNativeAsOptional("Socket.Listen");
MarkNativeAsOptional("Socket.Send");
MarkNativeAsOptional("Socket.SendTo");
MarkNativeAsOptional("Socket.SetOption");
MarkNativeAsOptional("Socket.SetReceiveCallback");
MarkNativeAsOptional("Socket.SetSendqueueEmptyCallback");
MarkNativeAsOptional("Socket.SetDisconnectCallback");
MarkNativeAsOptional("Socket.SetErrorCallback");
MarkNativeAsOptional("Socket.SetArg");
MarkNativeAsOptional("Socket.GetHostName");
MarkNativeAsOptional("Socket.Connected.get");
MarkNativeAsOptional("SocketIsConnected");
MarkNativeAsOptional("SocketCreate");
MarkNativeAsOptional("SocketBind");
MarkNativeAsOptional("SocketConnect");
MarkNativeAsOptional("SocketDisconnect");
MarkNativeAsOptional("SocketListen");
MarkNativeAsOptional("SocketSend");
MarkNativeAsOptional("SocketSendTo");
MarkNativeAsOptional("SocketSetOption");
MarkNativeAsOptional("SocketSetReceiveCallback");
MarkNativeAsOptional("SocketSetSendqueueEmptyCallback");
MarkNativeAsOptional("SocketSetDisconnectCallback");
MarkNativeAsOptional("SocketSetErrorCallback");
MarkNativeAsOptional("SocketSetArg");
MarkNativeAsOptional("SocketGetHostName");
}
#endif

View file

@ -371,9 +371,7 @@ public void OnClientPutInServer(int client) {
}
public void OnClientDisconnect(int client) {
if(!IsFakeClient(client)) {
SaveInventory(client);
}
}
public void OnPluginEnd() {
@ -1614,7 +1612,7 @@ void SaveInventory(int client) {
PrintDebug(DEBUG_GENERIC, "Saving inventory for %N", client);
PlayerInventory inventory;
inventory.timestamp = GetTime();
inventory.isAlive = IsPlayerAlive(client);
inventory.isAlive = IsClientInGame(client) && IsPlayerAlive(client);
playerData[client].state = State_Active;
GetClientAbsOrigin(client, inventory.location);

View file

@ -3,7 +3,7 @@
//#define DEBUG
#define MAIN_TIMER_INTERVAL_S 5.0
#define MAIN_TIMER_INTERVAL_S 4.0
#define PLUGIN_VERSION "1.0"
#define ANTI_RUSH_DEFAULT_FREQUENCY 20.0
#define ANTI_RUSH_FREQ_INC 0.75
@ -20,7 +20,6 @@
#include <multicolors>
#tryinclude <l4d_anti_rush>
public Plugin myinfo =
{
name = "L4D2 Feed The Trolls",
@ -67,6 +66,7 @@ public void OnPluginStart() {
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);
hThrowItemInterval = CreateConVar("sm_ftt_throw_interval", "30", "The interval in seconds to throw items. 0 to disable", FCVAR_NONE, true, 0.0);
hThrowItemInterval.AddChangeHook(Change_ThrowInterval);
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);

View file

@ -198,6 +198,7 @@ enum struct SceneData {
ArrayList variants;
void Cleanup() {
g_MapData.activeScenes.Clear();
SceneVariantData choice;
for(int i = 0; i < this.variants.Length; i++) {
this.variants.GetArray(i, choice);

View file

@ -386,9 +386,11 @@ public void Event_FinaleStart(Event event, const char[] name, bool dontBroadcast
}
}
public void Frame_SwapSurvivor(int client) {
if(IsClientConnected(client) && IsClientInGame(client))
SwapL4D1Survivor(client, true);
}
public void Frame_RevertSwappedSurvivor(int client) {
if(IsClientConnected(client) && IsClientInGame(client))
RevertSwappedSurvivor(client);
}