mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 22:43:21 +00:00
Update things
This commit is contained in:
parent
9590ceb207
commit
d4f9241b3c
25 changed files with 650 additions and 345 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,20 +5,22 @@
|
|||
|
||||
#define PLUGIN_VERSION "1.0"
|
||||
|
||||
#define PRECACHE_SOUNDS_COUNT 5
|
||||
#define PRECACHE_SOUNDS_COUNT 6
|
||||
char PRECACHE_SOUNDS[PRECACHE_SOUNDS_COUNT][] = {
|
||||
"custom/meow1.mp3",
|
||||
"custom/xen_teleport.mp3",
|
||||
"custom/mariokartmusic.mp3",
|
||||
"custom/spookyscaryskeletons.mp3",
|
||||
"custom/wearenumberone2.mp3"
|
||||
"custom/wearenumberone2.mp3",
|
||||
"custom/quack.mp3"
|
||||
};
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdkhooks>
|
||||
#include <left4dhooks>
|
||||
#include <jutils.inc>
|
||||
#include <sceneprocessor>
|
||||
#undef REQUIRE_PLUGIN
|
||||
#tryinclude <sceneprocessor>
|
||||
#include <multicolors>
|
||||
#include "l4d_survivor_identity_fix.inc"
|
||||
|
||||
|
@ -177,7 +179,7 @@ Action Timer_CheckPlayerPings(Handle timer) {
|
|||
if(iHighPingCount[i]++ > 2) {
|
||||
PrintToChat(i, "Due to your high ping (%d ms) you have been moved to AFK.", ping);
|
||||
PrintToChat(i, "You will be automatically switched back once your ping restores");
|
||||
SDKCall(hGoAwayFromKeyboard, i);
|
||||
// SDKCall(hGoAwayFromKeyboard, i);
|
||||
//PrintToChat(i, "Type /pingignore to disable this feature.");
|
||||
// L4D_ReplaceWithBot(i);
|
||||
isHighPingIdle[i] = true;
|
||||
|
@ -462,7 +464,7 @@ void SetCharacter(int target, int survivorIndex, L4DModelId modelIndex, bool kee
|
|||
if (IsFakeClient(target)) {
|
||||
char name[32];
|
||||
GetSurvivorName(target, name, sizeof(name));
|
||||
SetClientInfo(target, "name", name);
|
||||
// SetClientInfo(target, "name", name);
|
||||
}
|
||||
UpdatePlayerIdentity(target, view_as<Character>(survivorIndex), keepModel);
|
||||
|
||||
|
@ -636,6 +638,7 @@ public void OnConfigsExecuted() {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined _sceneprocessor_included
|
||||
public void OnSceneStageChanged(int scene, SceneStages stage) {
|
||||
if(stage == SceneStage_Started) {
|
||||
int activator = GetSceneInitiator(scene);
|
||||
|
@ -650,6 +653,7 @@ public void OnSceneStageChanged(int scene, SceneStages stage) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
///AFK BOT WEAPON FIX
|
||||
public void Event_BotPlayerSwap(Event event, const char[] name, bool dontBroadcast) {
|
||||
int bot = GetClientOfUserId(event.GetInt("bot"));
|
||||
|
|
|
@ -16,3 +16,21 @@ native void ApplyTroll(int victim, const char[] name, TrollModifier modifier = T
|
|||
forward void OnTrollApplied(int victim, const char[] trollName, int flags = 0, int activator = 0);
|
||||
|
||||
forward void OnTrollMarked(int activator, int victim);
|
||||
|
||||
public SharedPlugin __pl_myfile =
|
||||
{
|
||||
name = "feedthetrolls",
|
||||
file = "feedthetrolls.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_myfile_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("ApplyTroll");
|
||||
}
|
||||
#endif
|
|
@ -4,7 +4,7 @@
|
|||
//Allow MAX_TROLLS to be defined elsewhere
|
||||
#if defined MAX_TROLLS
|
||||
#else
|
||||
#define MAX_TROLLS 56
|
||||
#define MAX_TROLLS 55
|
||||
#endif
|
||||
|
||||
Troll t_metaReverse;
|
||||
|
@ -21,13 +21,15 @@ enum TrollEffectResponse {
|
|||
TE_Error, // Error, continue menu (retry)
|
||||
TE_Menu // Switching menus / etc, don't continue menu
|
||||
}
|
||||
|
||||
typeset PromptActivateFunction {
|
||||
function TrollEffectResponse (Troll troll, int activator, int victim, any data, int flags, trollModifier mod)
|
||||
function void (Troll troll, int activator, int victim, any data, int flags, trollModifier mod)
|
||||
}
|
||||
typedef ActivateFunction = function void (Troll troll, int activator, int victim, int flags, trollModifier mod);
|
||||
typedef ResetFunction = function void (Troll troll, int activator, int victim);
|
||||
typedef PromptActivateFunction = function TrollEffectResponse (Troll troll, int activator, int victim, any data, int flags, trollModifier mod);
|
||||
// typedef PromptActivateFunction = function TrollEffectResponse (Troll troll, int activator, int victim, any data, int flags, trollModifier mod);
|
||||
|
||||
StringMap trollKV;
|
||||
char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
|
||||
char DEFAULT_FLAG_PROMPT_MULTIPLE[] = "Enable options (Multiple)";
|
||||
char DEFAULT_FLAG_PROMPT[] = "Select an option";
|
||||
bool SilentMenuSelected[MAXPLAYERS+1];
|
||||
|
@ -91,45 +93,12 @@ enum struct TrollData {
|
|||
Handle timerHandles[MAXPLAYERS+1];
|
||||
float timerInterval;
|
||||
int timerRequiredFlags;
|
||||
bool timerIsDataPack;
|
||||
|
||||
void Toggle(int client, int flags) {
|
||||
if(this.IsActive(client)) {
|
||||
this.Disable(client);
|
||||
} else {
|
||||
this.Enable(client, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void Enable(int client, int 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) {
|
||||
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];
|
||||
}
|
||||
if(this.resetFn != null) {
|
||||
Call_StartForward(this.resetFn);
|
||||
Call_PushCell(0);
|
||||
Call_PushCell(client);
|
||||
Call_PushCell(0);
|
||||
Call_Finish();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: REMOVE OLD
|
||||
bool IsActive(int client) {
|
||||
return this.activeFlagClients[client] != -1;
|
||||
if(this.id == 0 || client == 0) return false; // bug fix
|
||||
return this.activeFlagClients[client] >= 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -170,6 +139,12 @@ methodmap Troll {
|
|||
LogError("Unknown troll \"%s\"", name);
|
||||
return view_as<Troll>(i);
|
||||
}
|
||||
public static bool TryFromName(const char[] name, Troll &troll) {
|
||||
int i = GetTrollID(name);
|
||||
if(i > -1)
|
||||
troll = Troll(i);
|
||||
return i > -1;
|
||||
}
|
||||
property bool Hidden {
|
||||
public get() { return Trolls[this.Id].hidden; }
|
||||
}
|
||||
|
@ -194,8 +169,13 @@ methodmap Troll {
|
|||
public get() { return this.TotalOptionsCount > 0; }
|
||||
}
|
||||
|
||||
public bool IsActive(int client) {
|
||||
return Trolls[this.Id].activeFlagClients[client] != -1;
|
||||
/// Is troll active for client. If flags is > 0, will do bitwise and
|
||||
public bool IsActive(int client, int flags = 0) {
|
||||
if(this.Id == 0 || client == 0) return false; // bug fix
|
||||
if(flags > 0) {
|
||||
return (Trolls[this.Id].activeFlagClients[client] & flags) == flags;
|
||||
} else
|
||||
return Trolls[this.Id].activeFlagClients[client] >= 0;
|
||||
}
|
||||
|
||||
public bool HasFlag(int client, int flag) {
|
||||
|
@ -203,7 +183,7 @@ methodmap Troll {
|
|||
}
|
||||
|
||||
public int GetFlags(int client) {
|
||||
return Trolls[this.Id].activeFlagClients[client]
|
||||
return Trolls[this.Id].activeFlagClients[client];
|
||||
}
|
||||
|
||||
public bool HasMod(trollModifier mod) {
|
||||
|
@ -215,18 +195,23 @@ methodmap Troll {
|
|||
}
|
||||
|
||||
public TrollEffectResponse Activate(int activator, int victim, trollModifier modifier = TrollMod_Invalid, int flags = 0, bool silent = false) {
|
||||
PrintToServer("Activate: act:%d vic:%d", activator, victim);
|
||||
if(modifier == TrollMod_Invalid) modifier = this.GetDefaultMod();
|
||||
if(victim == 0) ThrowError("Victim is invalid");
|
||||
return ApplyTroll(victim, this, activator, modifier, flags, silent);
|
||||
}
|
||||
|
||||
public void Reset(int victim) {
|
||||
Trolls[this.Id].activeFlagClients[victim] = -1;
|
||||
// Stop any running timer:
|
||||
if(Trolls[this.Id].timerHandles[victim] != null) {
|
||||
PrintToServer("FTT Debug: Disabling timer for %N", victim);
|
||||
delete Trolls[this.Id].timerHandles[victim];
|
||||
}
|
||||
if(Trolls[this.Id].resetFn != null) {
|
||||
Call_StartForward(Trolls[this.Id].resetFn);
|
||||
Call_PushCell(this);
|
||||
Call_PushCell(Troll(this.Id));
|
||||
Call_PushCell(0);
|
||||
Call_PushCell(victim);
|
||||
Call_PushCell(0);
|
||||
Call_Finish();
|
||||
}
|
||||
}
|
||||
|
@ -310,6 +295,43 @@ methodmap Troll {
|
|||
else if(Trolls[this.Id].mods == view_as<int>(TrollMod_Constant)) return TrollMod_Constant;
|
||||
else return TrollMod_Invalid;
|
||||
}
|
||||
|
||||
public TrollEffectResponse _triggerActivateFn(int activator, int victim, int flags, trollModifier modifier) {
|
||||
if(Trolls[this.Id].activateFn == null) return;
|
||||
Call_StartForward(Trolls[this.Id].activateFn);
|
||||
Call_PushCell(this);
|
||||
Call_PushCell(activator);
|
||||
Call_PushCell(victim);
|
||||
Call_PushCell(flags);
|
||||
Call_PushCell(modifier);
|
||||
Call_Finish();
|
||||
|
||||
// TrollFlagPrompt prompt;
|
||||
// for(int i = 0; i < Trolls[trollIndex].flagPrompts.Length; i++) {
|
||||
// Trolls[trollIndex].flagPrompts.GetArray(i, prompt);
|
||||
// if(!prompt.multiselect && prompt.activateFn != null) {
|
||||
// int value;
|
||||
// instance.GetPromptDataInt(victim, i, value);
|
||||
// for(int j = 0; j < Trolls[trollIndex].promptOptions.Length; j++) {
|
||||
// int bit = 1 << j;
|
||||
// if(flags & bit && prompt.flags & bit) {
|
||||
// Call_StartForward(prompt.activateFn);
|
||||
// Call_PushCell(instance);
|
||||
// Call_PushCell(activator);
|
||||
// Call_PushCell(victim);
|
||||
// Call_PushCell(value);
|
||||
// Call_PushCell(flags);
|
||||
// Call_PushCell(modifier);
|
||||
// response = view_as<TrollEffectResponse>(Call_Finish());
|
||||
// if(response != TE_Success) return response; // Let the menu handler deal with checking
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
}
|
||||
}
|
||||
|
||||
int g_iTrollIndex;
|
||||
|
@ -349,16 +371,22 @@ methodmap TrollBuilder {
|
|||
strcopy(Trolls[this.Id].description, 128, description);
|
||||
}
|
||||
|
||||
public TrollBuilder SetTimer(float interval, Timer timer, int requiredFlags = 0) {
|
||||
public TrollBuilder SetTimer(float interval, Timer timer, int requiredFlags = 0, bool isDatapack = false) {
|
||||
Trolls[this.Id].timerInterval = interval;
|
||||
Trolls[this.Id].timerFunction = timer;
|
||||
Trolls[this.Id].timerRequiredFlags = requiredFlags;
|
||||
Trolls[this.Id].timerIsDataPack = isDatapack;
|
||||
// Don't think this is necessary but whatever
|
||||
for(int i = 0; i <= MAXPLAYERS; i++) {
|
||||
Trolls[this.Id].timerHandles[i] = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public TrollBuilder SetAutoTimer(float interval, int requiredFlags = 0) {
|
||||
this.SetTimer(interval, Timer_GenericTrollActivate, requiredFlags, true);
|
||||
}
|
||||
|
||||
public TrollBuilder AddPrompt(const char[] customPrompt = "", int requiredFlags = 0) {
|
||||
this._AddPrompt(false, requiredFlags, customPrompt);
|
||||
return this;
|
||||
|
@ -436,7 +464,7 @@ methodmap TrollBuilder {
|
|||
|
||||
}
|
||||
|
||||
public TrollBuilder SetActivationFunction(ActivateFunction fn) {
|
||||
public TrollBuilder OnActivate(ActivateFunction fn) {
|
||||
if(Trolls[this.Id].activateFn == null) {
|
||||
Trolls[this.Id].activateFn = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
}
|
||||
|
@ -444,7 +472,7 @@ methodmap TrollBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public TrollBuilder SetResetFunction(ResetFunction fn) {
|
||||
public TrollBuilder OnReset(ResetFunction fn) {
|
||||
if(Trolls[this.Id].resetFn == null) {
|
||||
Trolls[this.Id].resetFn = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
|
||||
}
|
||||
|
@ -458,6 +486,7 @@ methodmap TrollBuilder {
|
|||
|
||||
}
|
||||
|
||||
|
||||
int GetTrollID(const char[] name) {
|
||||
static int i = 0;
|
||||
char buffer[MAX_TROLL_NAME_LENGTH];
|
||||
|
@ -471,21 +500,12 @@ int GetTrollID(const char[] name) {
|
|||
}
|
||||
|
||||
bool IsAnyTrollActive(int victim) {
|
||||
for(int i = 0; i <= MAX_TROLLS; i++) {
|
||||
if(Trolls[i].activeFlagClients[victim] >= 0) return true;
|
||||
for(int i = 1; i <= MAX_TROLLS; i++) {
|
||||
if(Troll(i).IsActive(victim)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetTrollFlags(int client, const char[] name, int flags = -1) {
|
||||
int index = GetTrollID(name);
|
||||
if(flags == -1)
|
||||
Trolls[index].Disable(client);
|
||||
else
|
||||
Trolls[index].Enable(client, flags);
|
||||
}
|
||||
|
||||
|
||||
TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModifier modifier, int flags = 0, bool silent = false) {
|
||||
char name[MAX_TROLL_NAME_LENGTH];
|
||||
troll.GetName(name, sizeof(name));
|
||||
|
@ -497,7 +517,16 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
if(troll.HasTimer) {
|
||||
if(!isActive) {
|
||||
if(modifier & TrollMod_Constant && (Trolls[trollIndex].timerRequiredFlags == 0 || Trolls[trollIndex].timerRequiredFlags & flags)) {
|
||||
Trolls[trollIndex].timerHandles[victim] = CreateTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, victim, TIMER_REPEAT);
|
||||
if(Trolls[trollIndex].timerIsDataPack) {
|
||||
DataPack pack;
|
||||
Trolls[trollIndex].timerHandles[victim] = CreateDataTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, pack, TIMER_REPEAT);
|
||||
pack.WriteCell(troll);
|
||||
pack.WriteCell(activator);
|
||||
pack.WriteCell(victim);
|
||||
pack.WriteCell(flags);
|
||||
} else {
|
||||
Trolls[trollIndex].timerHandles[victim] = CreateTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, victim, TIMER_REPEAT);
|
||||
}
|
||||
}
|
||||
} else if(Trolls[trollIndex].timerHandles[victim] != null) {
|
||||
delete Trolls[trollIndex].timerHandles[victim];
|
||||
|
@ -517,7 +546,7 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
|
||||
// If victim is a survivor bot, check if has an idle player
|
||||
if(IsFakeClient(victim) && GetClientTeam(victim) == 2) {
|
||||
int player = GetSpectatorClient(victim);
|
||||
int player = GetRealClient(victim);
|
||||
if(player > 0) {
|
||||
// If there is an idle player, apply troll to them
|
||||
ApplyTroll(player, troll, activator, modifier, flags, silent);
|
||||
|
@ -530,8 +559,10 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
|
||||
|
||||
// Toggle on flags for client, if it's not a single run.
|
||||
if(modifier & TrollMod_Constant) {
|
||||
Trolls[trollIndex].activeFlagClients[victim] = isActive ? -1 : flags;
|
||||
if(isActive) {
|
||||
Trolls[trollIndex].activeFlagClients[victim] = -1;
|
||||
} else if(modifier & TrollMod_Constant) {
|
||||
Trolls[trollIndex].activeFlagClients[victim] = flags;
|
||||
}
|
||||
|
||||
// Applies any custom logic needed for a troll, mostly only used for TrollMod_Instant
|
||||
|
@ -541,15 +572,7 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
// Invoke Callbacks:
|
||||
if(!isActive) {
|
||||
Troll instance = Troll(trollIndex);
|
||||
if(Trolls[trollIndex].activateFn != null) {
|
||||
Call_StartForward(Trolls[trollIndex].activateFn);
|
||||
Call_PushCell(instance);
|
||||
Call_PushCell(activator);
|
||||
Call_PushCell(victim);
|
||||
Call_PushCell(flags);
|
||||
Call_PushCell(modifier);
|
||||
Call_Finish();
|
||||
}
|
||||
instance._triggerActivateFn(activator, victim, flags, modifier);
|
||||
|
||||
// Call the corresponding prompt callback if applicable
|
||||
TrollFlagPrompt prompt;
|
||||
|
@ -558,7 +581,7 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
if(!prompt.multiselect && prompt.activateFn != null) {
|
||||
int value;
|
||||
instance.GetPromptDataInt(victim, i, value);
|
||||
for(int j = 0; j < Trolls[trollIndex].promptOptions.Length; i++) {
|
||||
for(int j = 0; j < Trolls[trollIndex].promptOptions.Length; j++) {
|
||||
int bit = 1 << j;
|
||||
if(flags & bit && prompt.flags & bit) {
|
||||
Call_StartForward(prompt.activateFn);
|
||||
|
@ -582,7 +605,6 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
Call_PushCell(Troll(trollIndex));
|
||||
Call_PushCell(activator);
|
||||
Call_PushCell(victim);
|
||||
Call_PushCell(modifier);
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
|
@ -611,11 +633,11 @@ TrollEffectResponse ApplyTroll(int victim, Troll troll, int activator, trollModi
|
|||
|
||||
|
||||
void EnableTroll(int client, const char[] troll, int flags = 0) {
|
||||
SetTrollFlags(client, troll, flags);
|
||||
Troll.FromName(troll).Activate(0, client, TrollMod_Invalid, flags);
|
||||
}
|
||||
|
||||
void DisableTroll(int client, const char[] troll) {
|
||||
SetTrollFlags(client, troll, -1);
|
||||
Troll.FromName(troll).Reset(client);
|
||||
}
|
||||
|
||||
public void SetCategory(const char[] newCat) {
|
||||
|
@ -627,7 +649,6 @@ void GetCategory(int category, char[] buffer, int size) {
|
|||
categories.GetString(category, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
public int Native_ApplyTroll(Handle plugin, int numParams) {
|
||||
int victim = GetNativeCell(1);
|
||||
char name[MAX_TROLL_NAME_LENGTH];
|
||||
|
@ -640,7 +661,7 @@ public int Native_ApplyTroll(Handle plugin, int numParams) {
|
|||
int activator = GetNativeCell(5);
|
||||
|
||||
Troll troll = Troll.FromName(name);
|
||||
troll.Activate(victim, activator, modifier, flags, GetNativeCell(6));
|
||||
troll.Activate(activator, victim, modifier, flags, GetNativeCell(6));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6,39 +6,45 @@ enum struct SpecifiedTroll {
|
|||
trollModifier mod;
|
||||
int flags;
|
||||
}
|
||||
enum struct TrollCombo {
|
||||
enum struct TrollComboData {
|
||||
char name[32];
|
||||
ArrayList trolls;
|
||||
|
||||
void AddTroll(const char[] name, int flags = 0, trollModifier mod = TrollMod_Invalid) {
|
||||
Troll instance = Troll.FromName(name);
|
||||
bool AddTroll(const char[] name, int flags = 0, trollModifier mod = TrollMod_Invalid) {
|
||||
Troll instance;
|
||||
if(!Troll.TryFromName(name, instance)) {
|
||||
PrintToServer("[FTT] Combo \"%s\": unknown troll named \"%s\"", this.name, name);
|
||||
return false;
|
||||
}
|
||||
if(mod == TrollMod_Invalid) mod = instance.GetDefaultMod();
|
||||
SpecifiedTroll troll;
|
||||
troll.id = instance.Id;
|
||||
troll.mod = mod;
|
||||
troll.flags = flags;
|
||||
this.trolls.PushArray(troll, sizeof(troll));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Activate(int client, int target) {
|
||||
PrintToServer("Applying %d trolls for combo %s for %N", this.trolls.Length, this.name, target);
|
||||
SpecifiedTroll troll;
|
||||
for(int i = 0; i < this.trolls.Length; i++) {
|
||||
SpecifiedTroll troll;
|
||||
this.trolls.GetArray(i, troll, sizeof(troll));
|
||||
Troll(troll.id).Activate(target, client, troll.mod, troll.flags);
|
||||
Troll(troll.id).Activate(client, target, troll.mod, troll.flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetupCombo(TrollCombo combo, const char[] name) {
|
||||
void SetupCombo(TrollComboData combo, const char[] name) {
|
||||
strcopy(combo.name, sizeof(combo.name), name);
|
||||
combo.trolls = new ArrayList(sizeof(SpecifiedTroll));
|
||||
combos.PushArray(combo, sizeof(combo));
|
||||
}
|
||||
|
||||
void SetupsTrollCombos() {
|
||||
combos = new ArrayList(sizeof(TrollCombo));
|
||||
combos = new ArrayList(sizeof(TrollComboData));
|
||||
|
||||
TrollCombo combo;
|
||||
TrollComboData combo;
|
||||
SetupCombo(combo, "Magnet Galore");
|
||||
combo.AddTroll("Special Magnet");
|
||||
combo.AddTroll("Tank Magnet");
|
||||
|
@ -79,7 +85,7 @@ void SetupsTrollCombos() {
|
|||
|
||||
SetupCombo(combo, "Shut up");
|
||||
combo.AddTroll("Vocalize Gag");
|
||||
combo.AddTroll("Honk / Meow / Woof", .flags=1);
|
||||
combo.AddTroll("Honk & Animal Sounds", .flags=1);
|
||||
|
||||
SetupCombo(combo, "Weakness Compels You");
|
||||
combo.AddTroll("No Shove");
|
||||
|
|
|
@ -383,10 +383,7 @@ public Action Command_ListTheTrolls(int client, int args) {
|
|||
char buffer[50];
|
||||
for(int p = 0; p < target_count; p++) {
|
||||
int target = target_list[p];
|
||||
if(IsPlayerAlive(target))
|
||||
ReplyToCommand(client, "> Active Trolls for %N:", target);
|
||||
else
|
||||
ReplyToCommand(client, "> Active Trolls for %N: (Paused)", target);
|
||||
CReplyToCommand(client, "> Active Trolls for {olive}%N:", target);
|
||||
|
||||
if(IsFakeClient(target)) {
|
||||
int player = GetRealClient(target);
|
||||
|
@ -401,9 +398,9 @@ public Action Command_ListTheTrolls(int client, int args) {
|
|||
if(flags > 0) {
|
||||
buffer[0] = '\0';
|
||||
troll.GetFlagNames(target, flags, buffer, sizeof(buffer));
|
||||
ReplyToCommand(client, "\"%s\" Flags: %s", Trolls[troll.Id].name, buffer);
|
||||
CReplyToCommand(client, "\t{green}%s:{default} %s", Trolls[troll.Id].name, buffer);
|
||||
} else
|
||||
ReplyToCommand(client, "%s", Trolls[troll.Id].name);
|
||||
CReplyToCommand(client, "\t{green}%s", Trolls[troll.Id].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,31 +408,29 @@ public Action Command_ListTheTrolls(int client, int args) {
|
|||
}
|
||||
|
||||
int count = 0;
|
||||
char[][] modeListArr = new char[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
|
||||
static char modeList[255];
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) > 1 && IsAnyTrollActive(i)) {
|
||||
if(IsFakeClient(i)) {
|
||||
int player = GetRealClient(i);
|
||||
if(player != -1) i = player;
|
||||
char[][] bufferList = new char[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
|
||||
char buffer[255];
|
||||
for(int player = 1; player <= MaxClients; player++) {
|
||||
if(IsClientConnected(player) && IsClientInGame(player) && GetClientTeam(player) > 1 && IsAnyTrollActive(player)) {
|
||||
if(IsFakeClient(player)) {
|
||||
int realPlayer = GetRealClient(player);
|
||||
if(realPlayer != -1) player = realPlayer;
|
||||
}
|
||||
int modeCount = 0;
|
||||
for(int j = 1; j <= MAX_TROLLS; j++) {
|
||||
int trollCount = 0;
|
||||
for(int j = 1; j < MAX_TROLLS; j++) {
|
||||
Troll troll = Troll(j);
|
||||
if(troll.IsActive(i)) {
|
||||
if(troll.GetFlags(i) > 0)
|
||||
Format(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, "%s(%d)", trollIds[j], Trolls[j].activeFlagClients[i]);
|
||||
if(troll.IsActive(player)) {
|
||||
int flags = troll.GetFlags(player);
|
||||
if(flags > 0)
|
||||
Format(bufferList[trollCount], MAX_TROLL_NAME_LENGTH, "%s(%d)", Trolls[j].name, flags);
|
||||
else
|
||||
strcopy(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, trollIds[j]);
|
||||
modeCount++;
|
||||
strcopy(bufferList[trollCount], MAX_TROLL_NAME_LENGTH, Trolls[j].name);
|
||||
trollCount++;
|
||||
}
|
||||
}
|
||||
|
||||
ImplodeStrings(modeListArr, modeCount, ", ", modeList, sizeof(modeList));
|
||||
if(IsPlayerAlive(i))
|
||||
ReplyToCommand(client, "%N | %s", i, modeList);
|
||||
else
|
||||
ReplyToCommand(client, "%N (Paused) | %s", i, modeList);
|
||||
ImplodeStrings(bufferList, trollCount, ", ", buffer, sizeof(buffer));
|
||||
ReplyToCommand(client, "%N | %s", player, buffer);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast)
|
|||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
if(client > 0) {
|
||||
for(int i = 0 ; i < MAX_TROLLS; i++) {
|
||||
Trolls[i].activeFlagClients[client] = 0;
|
||||
Trolls[i].activeFlagClients[client] = -1;
|
||||
if(Trolls[i].timerHandles[client] != null) {
|
||||
delete Trolls[i].timerHandles[client];
|
||||
}
|
||||
|
@ -321,10 +321,6 @@ public Action RushPlayer(Handle h, int user) {
|
|||
return Plugin_Handled;
|
||||
}
|
||||
public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
|
||||
static int spMagnetID, tankMagnetID;
|
||||
if(spMagnetID == 0) spMagnetID = GetTrollID("Special Magnet");
|
||||
if(tankMagnetID == 0) tankMagnetID = GetTrollID("Tank Magnet");
|
||||
|
||||
L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass"));
|
||||
// Check for any existing victims
|
||||
int existingTarget = GetClientOfUserId(pdata[attacker].attackerTargetUid);
|
||||
|
@ -337,16 +333,16 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
|
|||
}
|
||||
// Stop targetting if no longer magnetted:
|
||||
if(class == L4D2Infected_Tank) {
|
||||
if(!Trolls[tankMagnetID].IsActive(existingTarget) || !WillMagnetRun(Trolls[tankMagnetID], existingTarget)) return Plugin_Continue;
|
||||
if(!t_tankMagnet.IsActive(existingTarget) || !WillMagnetRun(t_tankMagnet, existingTarget)) return Plugin_Continue;
|
||||
} else if(class != L4D2Infected_Tank) {
|
||||
if(!Trolls[spMagnetID].IsActive(existingTarget) || !WillMagnetRun(Trolls[spMagnetID], existingTarget)) return Plugin_Continue;
|
||||
if(!t_specialMagnet.IsActive(existingTarget) || !WillMagnetRun(t_specialMagnet, existingTarget)) return Plugin_Continue;
|
||||
}
|
||||
|
||||
// Only set target based on incap rules:
|
||||
if(class == L4D2Infected_Tank && (!IsPlayerIncapped(existingTarget) || hMagnetTargetMode.IntValue & 2) && WillMagnetRun(Trolls[tankMagnetID], existingTarget)) {
|
||||
if(class == L4D2Infected_Tank && (!IsPlayerIncapped(existingTarget) || hMagnetTargetMode.IntValue & 2) && WillMagnetRun(t_tankMagnet, existingTarget)) {
|
||||
curTarget = existingTarget;
|
||||
return Plugin_Changed;
|
||||
} else if(class != L4D2Infected_Tank && (!IsPlayerIncapped(existingTarget) || hMagnetTargetMode.IntValue & 1) && WillMagnetRun(Trolls[spMagnetID], existingTarget)) {
|
||||
} else if(class != L4D2Infected_Tank && (!IsPlayerIncapped(existingTarget) || hMagnetTargetMode.IntValue & 1) && WillMagnetRun(t_specialMagnet, existingTarget)) {
|
||||
curTarget = existingTarget;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
@ -367,9 +363,9 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
|
|||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
|
||||
if(class == L4D2Infected_Tank) {
|
||||
if(!Trolls[tankMagnetID].IsActive(i) || !WillMagnetRun(Trolls[tankMagnetID], i)) continue;
|
||||
if(!t_tankMagnet.IsActive(i) || !WillMagnetRun(t_tankMagnet, i)) continue;
|
||||
} else if(class != L4D2Infected_Tank) {
|
||||
if(!Trolls[spMagnetID].IsActive(i) || !WillMagnetRun(Trolls[spMagnetID], i)) continue;
|
||||
if(!t_specialMagnet.IsActive(i) || !WillMagnetRun(t_specialMagnet, i)) continue;
|
||||
}
|
||||
|
||||
if(IsPlayerIncapped(i)) {
|
||||
|
@ -395,26 +391,21 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
|
|||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
// TODO: migrate to Troll
|
||||
bool WillMagnetRun(const TrollData troll, int i) {
|
||||
bool WillMagnetRun(Troll troll, int client) {
|
||||
// In the case none of the flags are set, return true (100% chance)
|
||||
// Some systems may give magnet w/ no flags
|
||||
if(troll.activeFlagClients[i] == 0) return true;
|
||||
|
||||
float cChance = 1.0;
|
||||
//Skip first bit as it is ('Always')
|
||||
if(troll.activeFlagClients[i] & 2) // 2nd: 50%
|
||||
cChance = 0.5;
|
||||
else if(troll.activeFlagClients[i] & 4) //3rd: 10%
|
||||
cChance = 0.1;
|
||||
return GetRandomFloat() <= cChance;
|
||||
int flags = troll.GetFlags(client);
|
||||
if(flags == 0) return true;
|
||||
float chance = 1.0;
|
||||
troll.GetPromptDataFloat(client, 0, chance);
|
||||
return GetRandomFloat() <= chance;
|
||||
}
|
||||
|
||||
public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce) {
|
||||
if(client > 0 && client <= MaxClients) {
|
||||
static int noShoveIndex;
|
||||
if(noShoveIndex == 0) noShoveIndex == GetTrollID("No Shove");
|
||||
if(Trolls[noShoveIndex].IsActive(client) && GetRandomFloat() < hShoveFailChance.FloatValue) {
|
||||
static Troll t_noShove;
|
||||
if(t_noShove.Id == 0) t_noShove == Troll.FromName("No Shove");
|
||||
if(t_noShove.IsActive(client) && GetRandomFloat() < hShoveFailChance.FloatValue) {
|
||||
float shoveTime = L4D2Direct_GetNextShoveTime(client);
|
||||
L4D2Direct_SetNextShoveTime(client, shoveTime + 2.0);
|
||||
return Plugin_Handled;
|
||||
|
@ -426,14 +417,12 @@ public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecD
|
|||
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
|
||||
if(client <= 0 || sArgs[0] == '@') return Plugin_Continue; //Ignore admin chat or console
|
||||
|
||||
static int honkID;
|
||||
static int profanityID;
|
||||
static int typooId;
|
||||
if(honkID == 0) honkID = GetTrollID("Honk / Meow / Woof");
|
||||
if(profanityID == 0) profanityID = GetTrollID("No Profanity");
|
||||
if(typooId == 0) typooId = GetTrollID("Typoos");
|
||||
|
||||
if(Trolls[honkID].IsActive(client) && Trolls[honkID].activeFlagClients[client] & 1) {
|
||||
if(t_honk.IsActive(client) && t_honk.GetFlags(client) & 1) {
|
||||
// Honk Processing
|
||||
static char strings[32][8];
|
||||
int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5);
|
||||
|
@ -446,17 +435,14 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
|
|||
int length = 8 * words;
|
||||
char[] message = new char[length];
|
||||
ImplodeStrings(strings, 32, " ", message, length);
|
||||
if(Trolls[honkID].activeFlagClients[client] & 1)
|
||||
if(t_honk.HasFlag(client, 16)) {
|
||||
// Show modified to them
|
||||
CPrintToChatAll("{blue}%N {default}: %s", client, message);
|
||||
else {
|
||||
} else {
|
||||
CPrintToChat(client, "{blue}%N {default}: %s", client, message);
|
||||
bool showOriginalToOthers = Trolls[honkID].activeFlagClients[client] & 4 != 0;
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && i != client) {
|
||||
if(showOriginalToOthers)
|
||||
CPrintToChat(i, "{blue}%N {default}: %s", client, sArgs);
|
||||
else
|
||||
CPrintToChat(i, "{blue}%N {default}: %s", client, message);
|
||||
CPrintToChat(i, "{blue}%N {default}: %s", client, sArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -742,7 +728,7 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
}
|
||||
|
||||
// Inverted control code:
|
||||
if(Trolls[t_invertedTrollIndex].IsActive(client)) {
|
||||
if(t_invertedTroll.IsActive(client)) {
|
||||
if(buttons & IN_MOVELEFT || buttons & IN_MOVERIGHT) {
|
||||
vel[1] = -vel[1];
|
||||
}
|
||||
|
@ -786,7 +772,7 @@ Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage
|
|||
if(GetClientTeam(attacker) == 4 && IsFakeClient(attacker)) return Plugin_Continue;
|
||||
}
|
||||
// Boost all damage no matter what
|
||||
if(Trolls[t_damageBoostIndex].IsActive(victim)) {
|
||||
if(t_damageBoost.IsActive(victim)) {
|
||||
damage * 2;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
@ -804,29 +790,22 @@ Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage
|
|||
if(damage > 0.0 && Trolls[t_slipperyShoesIndex].IsActive(victim) && Trolls[t_slipperyShoesIndex].activeFlagClients[victim] & 16) {
|
||||
L4D_StaggerPlayer(victim, victim, NULL_VECTOR);
|
||||
}
|
||||
if(isSameTeam && Trolls[t_reverseFFIndex].IsActive(attacker)) {
|
||||
if(isSameTeam && t_reverseFF.IsActive(attacker)) {
|
||||
// Should this be applied? (as in no FF granted)
|
||||
bool disableFF = false;
|
||||
int flags = t_reverseFF.GetFlags(attacker);
|
||||
if(damagetype & DMG_BURN) {
|
||||
disableFF = Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 32 != 0;
|
||||
disableFF = flags & 64 != 0;
|
||||
} else if(damagetype & DMG_BLAST) {
|
||||
disableFF = Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 64 != 0;
|
||||
disableFF = flags & 32 != 0;
|
||||
} else {
|
||||
// Does not run if DMG_BURN or DMG_BLAST
|
||||
// Does not run if DMG_BURN or DMG_BLAST, basically any other damage was caused besides burn/blast, then allow it
|
||||
disableFF = true;
|
||||
}
|
||||
|
||||
if(disableFF) {
|
||||
float returnDmg = damage; //default is 1:1
|
||||
if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 2) {
|
||||
returnDmg *= 2.0;
|
||||
} else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 4) {
|
||||
returnDmg /= 2.0;
|
||||
} else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 8) {
|
||||
returnDmg = 0.0;
|
||||
} else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 16) {
|
||||
returnDmg *= 3.0;
|
||||
}
|
||||
t_reverseFF.GetPromptDataFloat(attacker, 0, returnDmg);
|
||||
SDKHooks_TakeDamage(attacker, attacker, attacker, returnDmg, damagetype, -1);
|
||||
damage = 0.0;
|
||||
return Plugin_Changed;
|
||||
|
@ -863,11 +842,7 @@ Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage
|
|||
}
|
||||
|
||||
public Action OnVocalizeCommand(int client, const char[] vocalize, int initiator) {
|
||||
static int vocalGagID;
|
||||
static int noRushingUsID;
|
||||
if(vocalGagID == 0) vocalGagID = GetTrollID("Vocalize Gag");
|
||||
if(noRushingUsID == 0) noRushingUsID = GetTrollID("No Rushing Us");
|
||||
if(Trolls[noRushingUsID].IsActive(client) && (StrEqual(vocalize, "PlayerHurryUp") || StrEqual(vocalize, "PlayerYellRun") || StrEqual(vocalize, "PlayerMoveOn") || StrEqual(vocalize, "PlayerLeadOn"))) {
|
||||
if(t_noRushingUs.IsActive(client) && (StrEqual(vocalize, "PlayerHurryUp") || StrEqual(vocalize, "PlayerYellRun") || StrEqual(vocalize, "PlayerMoveOn") || StrEqual(vocalize, "PlayerLeadOn"))) {
|
||||
noRushingUsSpeed[client] -= 0.01;
|
||||
if(noRushingUsSpeed[client] < 0.05) {
|
||||
noRushingUsSpeed[client] = 0.05;
|
||||
|
@ -878,7 +853,7 @@ public Action OnVocalizeCommand(int client, const char[] vocalize, int initiator
|
|||
if(Trolls[t_slotRouletteIndex].IsActive(client) && GetURandomFloat() < 0.10) {
|
||||
SetSlot(client, -1);
|
||||
}
|
||||
if(Trolls[vocalGagID].IsActive(client)) {
|
||||
if(t_vocalGag.IsActive(client) && t_vocalGag.GetFlags(client) == 0) {
|
||||
return Plugin_Handled;
|
||||
}
|
||||
return Plugin_Continue;
|
||||
|
@ -922,11 +897,6 @@ public void OnSceneStageChanged(int scene, SceneStages stage) {
|
|||
#endif
|
||||
|
||||
public Action SoundHook(int clients[MAXPLAYERS], int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char soundEntry[PLATFORM_MAX_PATH], int& seed) {
|
||||
static int honkID;
|
||||
static int vocalGagID;
|
||||
if(honkID == 0) honkID = GetTrollID("Honk / Meow / Woof");
|
||||
if(vocalGagID == 0) vocalGagID = GetTrollID("Vocalize Gag");
|
||||
|
||||
if(lastButtonUser > 0 && IsClientConnected(lastButtonUser) && !IsFakeClient(lastButtonUser) && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) {
|
||||
PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser);
|
||||
#if defined DEBUG
|
||||
|
@ -943,24 +913,37 @@ public Action SoundHook(int clients[MAXPLAYERS], int& numClients, char sample[PL
|
|||
lastButtonUser = -1;
|
||||
}else if(numClients > 0 && entity > 0 && entity <= MaxClients) {
|
||||
if(StrContains(sample, "survivor\\voice") > -1) {
|
||||
if(Trolls[honkID].IsActive(entity)) {
|
||||
if(Trolls[honkID].activeFlagClients[entity] & 1)
|
||||
if(t_honk.IsActive(entity)) {
|
||||
int trollFlags = t_honk.GetFlags(entity);
|
||||
if(trollFlags & 1) {
|
||||
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
|
||||
else if(Trolls[honkID].activeFlagClients[entity] & 2) {
|
||||
} else if(trollFlags & 2) {
|
||||
strcopy(sample, sizeof(sample), "custom/quack.mp3");
|
||||
// volume += 0.2;
|
||||
} else if(trollFlags & 4) {
|
||||
strcopy(sample, sizeof(sample), "custom/meow1.mp3");
|
||||
volume += 0.2;
|
||||
} else if(Trolls[honkID].activeFlagClients[entity] & 4) {
|
||||
} else if(trollFlags & 8) {
|
||||
strcopy(sample, sizeof(sample), "custom/woof1.mp3");
|
||||
volume += 0.6;
|
||||
} else
|
||||
return Plugin_Continue;
|
||||
return Plugin_Changed;
|
||||
} else if(Trolls[vocalGagID].IsActive(entity)) {
|
||||
if(Trolls[vocalGagID].activeFlagClients[entity] & 2) {
|
||||
clients[0] = entity;
|
||||
numClients = 1;
|
||||
} else if(t_vocalGag.IsActive(entity)) {
|
||||
int trollFlags = t_vocalGag.GetFlags(entity);
|
||||
if(trollFlags & 2) {
|
||||
SDKHooks_TakeDamage(entity, entity, entity, 1.0, DMG_GENERIC);
|
||||
}
|
||||
if(trollFlags & 1) {
|
||||
volume /= 2.0;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
||||
// if(Trolls[vocalGagID].activeFlagClients[entity] & 2) {
|
||||
// clients[0] = entity;
|
||||
// numClients = 1;
|
||||
// return Plugin_Changed;
|
||||
// }
|
||||
return Plugin_Handled;
|
||||
}
|
||||
}
|
||||
|
@ -1008,11 +991,10 @@ public void Event_WitchVictimSet(Event event, const char[] name, bool dontBroadc
|
|||
public Action L4D2_MeleeGetDamageForVictim(int client, int weapon, int victim, float &damage) {
|
||||
static int dullMeleeID;
|
||||
if(!dullMeleeID) dullMeleeID = GetTrollID("Dull Melee");
|
||||
if(Trolls[dullMeleeID].IsActive(client)) {
|
||||
float max = 1.0;
|
||||
if(Trolls[dullMeleeID].activeFlagClients[client] & 2) max = 0.5;
|
||||
else if(Trolls[dullMeleeID].activeFlagClients[client] & 4) max = 0.1;
|
||||
if(GetRandomFloat() <= max) {
|
||||
if(t_dullMelee.IsActive(client)) {
|
||||
float chance = 1.0;
|
||||
t_dullMelee.GetPromptDataFloat(client, 0, chance);
|
||||
if(GetURandomFloat() <= chance) {
|
||||
damage = 0.0;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ public int ChooseComboHandler(Menu menu, MenuAction action, int client, int para
|
|||
return 0;
|
||||
}
|
||||
|
||||
static TrollCombo combo;
|
||||
static TrollComboData combo;
|
||||
combos.GetArray(comboID, combo, sizeof(combo));
|
||||
combo.Activate(client, victim);
|
||||
} else if (action == MenuAction_End)
|
||||
|
@ -377,7 +377,7 @@ void ShowTrollCombosMenu(int client, int victimUserID) {
|
|||
Format(id, sizeof(id), "Choose troll combo");
|
||||
comboMenu.SetTitle(id);
|
||||
|
||||
static TrollCombo combo;
|
||||
static TrollComboData combo;
|
||||
|
||||
if(combos.Length == 0) {
|
||||
ReplyToCommand(client, "FTT: No troll combos available");
|
||||
|
@ -457,7 +457,8 @@ void ShowSelectFlagMenu(int activator, int victimUserID, int modifiers, Troll tr
|
|||
prompt.GetPromptText(info, sizeof(info));
|
||||
flagMenu.SetTitle("%s", info);
|
||||
|
||||
if(prevFlags == -1) prevFlags = prompt.defaults;
|
||||
if(prevFlags == -1 && prompt.multiselect) prevFlags = prompt.defaults;
|
||||
|
||||
|
||||
Format(info, sizeof(info), "%d|%d|%d|%d|%d|1", victimUserID, troll.Id, modifiers, prevFlags, promptIndex);
|
||||
|
||||
|
|
|
@ -63,18 +63,6 @@ bool ToggleMarkPlayer(int client, int target) {
|
|||
}
|
||||
}
|
||||
|
||||
// Finds the survivor bot that took over an idle player
|
||||
int GetSpectatorClient(int bot) {
|
||||
if(!IsFakeClient(bot)) return -1;
|
||||
static char netclass[16];
|
||||
GetEntityNetClass(bot, netclass, sizeof(netclass));
|
||||
if(strcmp(netclass, "SurvivorBot") == 0 ) {
|
||||
int user = GetEntProp(bot, Prop_Send, "m_humanSpectatorUserID");
|
||||
if(user > 0) return GetClientOfUserId(user);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
stock bool IsPlayerIncapped(int client) {
|
||||
return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1;
|
||||
}
|
||||
|
@ -641,13 +629,13 @@ void SetSlot(int client, int slot) {
|
|||
ClientCommand(client, slotStr);
|
||||
}
|
||||
|
||||
void RewindPlayer(int client) {
|
||||
void RewindPlayer(int client, float distance = 100.0) {
|
||||
float curFlow = L4D2Direct_GetFlowDistance(client);
|
||||
ArrayList navs = new ArrayList();
|
||||
L4D_GetAllNavAreas(navs);
|
||||
navs.Sort(Sort_Random, Sort_Integer);
|
||||
float minFlow = curFlow - 300.0;
|
||||
float maxFlow = curFlow - 150.0;
|
||||
float minFlow = curFlow - (3.0*distance);
|
||||
float maxFlow = curFlow - (1.5*distance);
|
||||
// This finds the first nav area in range, usually closer
|
||||
for(int i = 0; i < navs.Length; i++) {
|
||||
float flow = L4D2Direct_GetTerrorNavAreaFlow(navs.Get(i));
|
||||
|
|
|
@ -154,6 +154,9 @@ Action Timer_SetWitchTarget(Handle h, DataPack pack) {
|
|||
}
|
||||
|
||||
stock SpecialType GetSpecialType(const char[] input) {
|
||||
if(StrEqual(input, "random")) {
|
||||
return view_as<SpecialType>(GetRandomInt(0, 6))
|
||||
}
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if(strcmp(SPECIAL_NAMES[i], input, false) == 0) return view_as<SpecialType>(i + 1);
|
||||
}
|
||||
|
|
|
@ -481,8 +481,21 @@ Action Timer_RestoreHud(Handle h, int userid) {
|
|||
}
|
||||
Action Timer_RandomRewind(Handle h, int client) {
|
||||
if(IsClientInGame(client) && GetURandomFloat() > 0.3) {
|
||||
RewindPlayer(client);
|
||||
float distance = 100.0;
|
||||
t_rewind.GetPromptDataFloat(client, 0, distance);
|
||||
RewindPlayer(client, distance);
|
||||
}
|
||||
return Plugin_Handled;
|
||||
|
||||
}
|
||||
Action Timer_GenericTrollActivate(Handle h, DataPack pack) {
|
||||
pack.Reset();
|
||||
Troll troll = Troll(pack.ReadCell());
|
||||
int activator = pack.ReadCell();
|
||||
int victim = pack.ReadCell();
|
||||
if(IsClientInGame(victim)) {
|
||||
int flags = pack.ReadCell();
|
||||
troll._triggerActivateFn(activator, victim, flags, TrollMod_Constant);
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
|
@ -1,19 +1,26 @@
|
|||
// UP THE VALUE 'MAX_TROLLS' in base.inc before adding new ones!
|
||||
|
||||
Troll t_specialMagnet;
|
||||
Troll t_tankMagnet;
|
||||
int t_slipperyShoesIndex = 0;
|
||||
Troll t_stickyGoo;
|
||||
int t_invertedTrollIndex;
|
||||
Troll t_invertedTroll;
|
||||
int t_randomizeAnglesIndex;
|
||||
int t_randomizeVelocityIndex;
|
||||
int t_vomitPlayerIndex;
|
||||
int t_shakeyCameraIndex;
|
||||
int t_slotRouletteIndex;
|
||||
int t_damageBoostIndex;
|
||||
int t_reverseFFIndex;
|
||||
Troll t_damageBoost;
|
||||
Troll t_reverseFF;
|
||||
int t_hideHUDIndex;
|
||||
Troll t_throwItAll;
|
||||
Troll t_voiceMute;
|
||||
Troll t_gunJam;
|
||||
Troll t_honk;
|
||||
Troll t_vocalGag;
|
||||
Troll t_dullMelee;
|
||||
Troll t_rewind;
|
||||
Troll t_noRushingUs;
|
||||
|
||||
void SetupTrolls() {
|
||||
trollKV = new StringMap();
|
||||
|
@ -25,8 +32,10 @@ void SetupTrolls() {
|
|||
SetCategory("Magnets");
|
||||
troll = TrollBuilder("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant);
|
||||
AddMagnetFlags(troll);
|
||||
t_specialMagnet = troll.Build();
|
||||
troll = TrollBuilder("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant);
|
||||
AddMagnetFlags(troll);
|
||||
t_tankMagnet = troll.Build();
|
||||
#if defined _actions_included
|
||||
TrollBuilder("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant);
|
||||
#endif
|
||||
|
@ -112,14 +121,14 @@ void SetupTrolls() {
|
|||
.AddOption("UZI Only", true)
|
||||
.AddOption("AWP Only", false)
|
||||
TrollBuilder("Primary Disable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant);
|
||||
TrollBuilder("Dull Melee", "Player's melee weapon does 0 damage (based on %). Headshots still work", TrollMod_Constant)
|
||||
t_dullMelee = TrollBuilder("Dull Melee", "Player's melee weapon does 0 damage (based on %). Headshots still work", TrollMod_Constant)
|
||||
.AddPrompt()
|
||||
.AddOption("Always (100%)", false)
|
||||
.AddOption("Half Time (50%)", true)
|
||||
.AddOption("Rare (10%)", false);
|
||||
.AddOptionFloat("Always (100%)", false, 1.0)
|
||||
.AddOptionFloat("Half Time (50%)", true, 0.5)
|
||||
.AddOptionFloat("Rare (10%)", false, 0.10)
|
||||
.Build();
|
||||
TrollBuilder("Nerf Gun", "When they shoot it does no damage.", TrollMod_Constant);
|
||||
TrollBuilder("Randomize Clip Ammo", "Randomly changes their clip ammo downwards", TrollMod_Constant | TrollMod_Instant);
|
||||
TrollBuilder("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant);
|
||||
|
||||
t_slotRouletteIndex = TrollBuilder("Slot Roulette", "Randomize their slots", TrollMod_Constant)
|
||||
.SetTimer(0.2, Timer_SlotRoulette, 8)
|
||||
|
@ -146,40 +155,42 @@ void SetupTrolls() {
|
|||
.AddPrompt()
|
||||
.AddOption("Show Modified to Them", true)
|
||||
.AddOption("Show Original to Them");
|
||||
TrollBuilder("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant);
|
||||
// .AddPrompt()
|
||||
// .AddOption("Mute for All", true);
|
||||
// .AddOption("Mute For All But Them", false);
|
||||
TrollBuilder("Honk / Meow / Woof", "Custom sounds", TrollMod_Constant)
|
||||
t_vocalGag = TrollBuilder("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant)
|
||||
.AddPromptMulti()
|
||||
.AddOption("Quieter", false)
|
||||
.AddOption("Painful", false)
|
||||
.Build()
|
||||
t_honk = TrollBuilder("Honk & Animal Sounds", "Custom sounds", TrollMod_Constant)
|
||||
.AddPrompt("Choose Sound:")
|
||||
.AddOption("Honk", true)
|
||||
.AddOption("Meow", false)
|
||||
.AddOption("Woof", false)
|
||||
.AddOption("Honk", true) // 1 << 0
|
||||
.AddOption("Quack", false) // 1 << 1
|
||||
.AddOption("Meow", false) // 1 << 2
|
||||
.AddOption("Woof", false) // 1 << 3
|
||||
.AddPrompt("Choose Chat modifier:", 1)
|
||||
.AddOption("Show Modified to Them", true)
|
||||
.AddOption("Show Original to Them", false)
|
||||
.AddOption("Show Modified Only To Them", false);
|
||||
.AddOption("Show Modified To All", true) // 1 << 4
|
||||
.AddOption("Show Original To Others", false) // 1 << 5
|
||||
.Build();
|
||||
TrollBuilder("Reversed", "Reserves their message", TrollMod_Constant);
|
||||
t_voiceMute = TrollBuilder("Voice Mute", "Mutes from voice", TrollMod_Constant).Build();
|
||||
TrollBuilder("No Rushing Us", "Decreases player speed everytime they yell hurry up", TrollMod_Constant);
|
||||
t_noRushingUs = TrollBuilder("No Rushing Us", "Decreases player speed everytime they yell hurry up", TrollMod_Constant).Build();
|
||||
|
||||
/// CATEGORY: Health
|
||||
SetCategory("Health");
|
||||
t_damageBoostIndex = TrollBuilder("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant).Id;
|
||||
t_damageBoost = TrollBuilder("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant).Build();
|
||||
TrollBuilder("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant);
|
||||
TrollBuilder("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant);
|
||||
TrollBuilder("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
|
||||
t_reverseFFIndex = TrollBuilder("Reverse FF", "All damage dealt to a player is reversed", TrollMod_Constant)
|
||||
t_reverseFF = TrollBuilder("Reverse FF", "All damage dealt to a player is reversed", TrollMod_Constant)
|
||||
.AddPrompt("Choose Reverse FF", false)
|
||||
.AddOption("1:1 Ratio", true) //1
|
||||
.AddOption("2x Ratio", false) //2
|
||||
.AddOption("0.5x Ratio", false) //4
|
||||
.AddOption("0.0x Ratio (None)", false) //8
|
||||
.AddOption("3x Ratio", false) //16
|
||||
.AddOptionFloat("1:1 Ratio", true, 1.0) //1
|
||||
.AddOptionFloat("2x Ratio", false, 2.0) //2
|
||||
.AddOptionFloat("0.5x Ratio", false, 0.5) //4
|
||||
.AddOptionFloat("0.0x Ratio (None)", false, 0.0) //8
|
||||
.AddOptionFloat("3x Ratio", false, 3.0) //16
|
||||
.AddPromptMulti("Modes")
|
||||
.AddOption("Reverse Fire Damage", false) //32
|
||||
.AddOption("Reverse Explosions", false) //64
|
||||
.Id;
|
||||
.Build();
|
||||
|
||||
|
||||
TrollBuilder("Dep Bots", "Makes bots heal a player. At any cost", TrollMod_Constant)
|
||||
|
@ -202,15 +213,19 @@ void SetupTrolls() {
|
|||
/// CATEGORY: Movement
|
||||
SetCategory("Movement");
|
||||
TrollBuilder("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant)
|
||||
.OnReset(Reset_SlowSpeed)
|
||||
.AddPrompt()
|
||||
.OnPromptActivate(Activate_SlowSpeed)
|
||||
.AddOptionFloat("90% Movement Speed", true, 0.9)
|
||||
.AddOptionFloat("80% Movement Speed", false, 0.8)
|
||||
.AddOptionFloat("70% Movement Speed", false, 0.7)
|
||||
.AddOptionFloat("50% Movement Speed", false, 0.5)
|
||||
.AddOptionFloat("30% Movement Speed", false, 0.3)
|
||||
.AddOptionFloat("0% Movement Speed", false, 0.0);
|
||||
TrollBuilder("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
|
||||
t_invertedTrollIndex = TrollBuilder("Inverted Controls", "Well, aint it obvious", TrollMod_Constant).Id;
|
||||
TrollBuilder("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant)
|
||||
.OnActivate(Activate_HighGravity)
|
||||
.OnReset(Reset_HighGravity);
|
||||
t_invertedTroll = TrollBuilder("Inverted Controls", "Well, aint it obvious", TrollMod_Constant).Build();
|
||||
t_slipperyShoesIndex = TrollBuilder("Slippery Shoes", "Periodically stumbles around.", TrollMod_Constant | TrollMod_Instant)
|
||||
.AddPromptMulti()
|
||||
.AddOption("Periodically", true) // 1 << 0
|
||||
|
@ -236,8 +251,16 @@ void SetupTrolls() {
|
|||
.AddOption("Severe Earthquake", false) //8
|
||||
.AddOption("Bouncy Castle", false) //16
|
||||
.Id;
|
||||
TrollBuilder("Rewind", "Teleports player backwards", TrollMod_Instant | TrollMod_Constant)
|
||||
.SetTimer(10.0, Timer_RandomRewind);
|
||||
t_rewind = TrollBuilder("Rewind", "Teleports player backwards", TrollMod_Instant | TrollMod_Constant)
|
||||
// .SetTimer(10.0, Timer_RandomRewind)
|
||||
.SetAutoTimer(10.0)
|
||||
.OnActivate(Activate_Rewind)
|
||||
.AddPrompt("Distance")
|
||||
.AddOptionFloat("Subtle", false, 10.0)
|
||||
.AddOptionFloat("Tiny", false, 50.0)
|
||||
.AddOptionFloat("Normal", true, 100.0)
|
||||
.AddOptionFloat("Far", false, 250.0)
|
||||
.Build();
|
||||
|
||||
/// CATEGORY: MISC
|
||||
SetCategory("Misc");
|
||||
|
@ -297,8 +320,25 @@ TrollEffectResponse Activate_SmartCharge(Troll troll, int activator, int victim,
|
|||
return TE_Success;
|
||||
}
|
||||
|
||||
void Activate_Rewind(Troll troll, int activator, int victim, int flags, trollModifier mod) {
|
||||
float distance;
|
||||
troll.GetPromptDataFloat(activator, 0, distance);
|
||||
RewindPlayer(victim, distance);
|
||||
}
|
||||
void Activate_SlowSpeed(Troll troll, int activator, int victim, float movement, int flags, trollModifier mod) {
|
||||
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", movement);
|
||||
}
|
||||
void Reset_SlowSpeed(Troll troll, int activator, int victim) {
|
||||
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
|
||||
}
|
||||
void Activate_HighGravity(Troll troll, int activator, int victim, int flags, trollModifier mod) {
|
||||
SetEntityGravity(victim, 1.3);
|
||||
}
|
||||
void Reset_HighGravity(Troll troll, int activator, int victim) {
|
||||
SetEntityGravity(victim, 1.0);
|
||||
}
|
||||
|
||||
void AddMagnetFlags(TrollBuilder troll) {
|
||||
PrintToServer("adding: %d", troll.Id);
|
||||
troll.AddPrompt("Choose Magnet Chance:")
|
||||
.AddOptionFloat("Always (100%)", true, 1.0)
|
||||
.AddOptionFloat("Half Time (50%)", false, 0.5)
|
||||
|
@ -309,30 +349,12 @@ TrollEffectResponse ApplyAffect(int victim, Troll troll, int activator, trollMod
|
|||
bool toActive = troll.IsActive(victim);
|
||||
char name[MAX_TROLL_NAME_LENGTH];
|
||||
troll.GetName(name, sizeof(name));
|
||||
if(StrEqual(name, "Reset User")) {
|
||||
if(troll.Id == 0) {
|
||||
LogAction(activator, victim, "\"%L\" reset all effects for \"%L\"", activator, victim);
|
||||
ShowActivityEx(activator, "[FTT] ", "reset effects for %N. ", victim);
|
||||
// for(int i = 0; i <= MAX_TROLLS; i++) {
|
||||
// Trolls[i].activeFlagClients[victim] = -1;
|
||||
// }
|
||||
// SetEntityGravity(victim, 1.0);
|
||||
// SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
|
||||
ResetClient(victim, true);
|
||||
return TE_Error; // Not an error, but don't want to show activation
|
||||
} else if(StrEqual(name, "Slow Speed")) {
|
||||
if(toActive) {
|
||||
float movement = 0.0;
|
||||
if(flags & 1) movement = 0.9;
|
||||
else if(flags & 2) movement = 0.8;
|
||||
else if(flags & 4) movement = 0.7;
|
||||
else if(flags & 8) movement = 0.5;
|
||||
else if(flags & 16) movement = 0.3;
|
||||
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", movement);
|
||||
} else
|
||||
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
|
||||
} else if(StrEqual(name, "Higher Gravity"))
|
||||
SetEntityGravity(victim, toActive ? 1.3 : 1.0);
|
||||
else if(StrEqual(name, "UziRules / AwpSmells")) {
|
||||
} else if(StrEqual(name, "UziRules / AwpSmells")) {
|
||||
DisableTroll(victim, "No Pickup");
|
||||
DisableTroll(victim, "Primary Disable");
|
||||
} else if(StrEqual(name, "Primary Disable")) {
|
||||
|
@ -343,8 +365,6 @@ TrollEffectResponse ApplyAffect(int victim, Troll troll, int activator, trollMod
|
|||
DisableTroll(victim, "UziRules / AwpSmells");
|
||||
DisableTroll(victim, "Primary Disable");
|
||||
SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
|
||||
} else if(StrEqual(name, "CameTooEarly")) {
|
||||
ReplyToCommand(activator, "This troll mode is not implemented.");
|
||||
} else if(StrEqual(name, "KillMeSoftly")) {
|
||||
static char wpn[32];
|
||||
GetClientWeaponName(victim, 4, wpn, sizeof(wpn));
|
||||
|
|
1
scripting/include/hats.inc
Normal file
1
scripting/include/hats.inc
Normal file
|
@ -0,0 +1 @@
|
|||
native bool SpawnSchematic(const char name[32], const float pos[3], const float angles[3] = NULL_VECTOR);
|
|
@ -155,7 +155,7 @@ enum struct EditorData {
|
|||
|
||||
bool CheckEntity() {
|
||||
if(this.entity != INVALID_ENT_REFERENCE) {
|
||||
if(!IsValidEntity(this.entity)) {
|
||||
if(this.entity == -1 && !IsValidEntity(this.entity)) {
|
||||
PrintToChat(this.client, "\x04[Editor]\x01 Entity has vanished, editing cancelled.");
|
||||
this.Reset();
|
||||
return false;
|
||||
|
@ -301,7 +301,7 @@ enum struct EditorData {
|
|||
char component[16];
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if(this.colorIndex == i)
|
||||
Format(component, sizeof(component), "%s \x05 %c \x01", component, COLOR_INDEX[i]);
|
||||
Format(component, sizeof(component), "%s \x05%c\x01", component, COLOR_INDEX[i]);
|
||||
else
|
||||
Format(component, sizeof(component), "%s %c", component, COLOR_INDEX[i]);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
char g_pendingSaveName[64];
|
||||
int g_pendingSaveClient;
|
||||
ArrayList g_previewItems;
|
||||
CategoryData ROOT_CATEGORY;
|
||||
ArrayList g_spawnedItems; // ArrayList(block=2)<entRef, [creator]>
|
||||
ArrayList g_savedItems; // ArrayList<entRef>
|
||||
StringMap g_recentItems; // Key: model[128], value: RecentEntry
|
||||
|
||||
/* Wish to preface this file:
|
||||
* It's kinda messy. The main structs are:
|
||||
|
@ -12,7 +16,123 @@ The rest are kinda necessary, for sorting reasons (SearchData, RecentEntry).
|
|||
enum ChatPrompt {
|
||||
Prompt_None,
|
||||
Prompt_Search,
|
||||
Prompt_Save
|
||||
Prompt_SaveScene,
|
||||
Prompt_SaveSchematic
|
||||
}
|
||||
enum SaveType {
|
||||
Save_None,
|
||||
Save_Scene,
|
||||
Save_Schematic
|
||||
}
|
||||
|
||||
enum struct Schematic {
|
||||
char name[64];
|
||||
char creatorSteamid[32];
|
||||
char creatorName[32];
|
||||
ArrayList entities;
|
||||
|
||||
void Reset() {
|
||||
this.name[0] = '\0';
|
||||
this.creatorSteamid[0] = '\0';
|
||||
this.creatorName[0] = '\0';
|
||||
if(this.entities != null) delete this.entities;
|
||||
}
|
||||
|
||||
void AddEntity(int entity, int client) {
|
||||
SaveData save;
|
||||
save.FromEntity(entity);
|
||||
this.entities.PushArray(save);
|
||||
}
|
||||
|
||||
void New(int client, const char[] name) {
|
||||
if(client > 0) {
|
||||
GetClientName(client, this.creatorName, sizeof(this.creatorName));
|
||||
GetClientAuthId(client, AuthId_Steam2, this.creatorSteamid, sizeof(this.creatorSteamid));
|
||||
}
|
||||
strcopy(this.name, sizeof(this.name), name);
|
||||
this.entities = new ArrayList(sizeof(SaveData));
|
||||
}
|
||||
|
||||
bool Save() {
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/schematics/%s.schem", this.name);
|
||||
CreateDirectory("data/prop_spawner/schematics", 0775);
|
||||
KeyValues kv = new KeyValues(this.name);
|
||||
kv.SetString("creator_steamid", this.creatorSteamid);
|
||||
kv.SetString("creator_name", this.creatorName);
|
||||
kv.JumpToKey("entities");
|
||||
this.entities = new ArrayList(sizeof(SaveData));
|
||||
SaveData ent;
|
||||
while(kv.GotoNextKey()) {
|
||||
kv.GetVector("offset", ent.origin);
|
||||
kv.GetVector("angles", ent.angles);
|
||||
kv.GetColor4("color", ent.color);
|
||||
kv.GetString("model", ent.model, sizeof(ent.model));
|
||||
this.entities.PushArray(ent);
|
||||
}
|
||||
kv.ExportToFile(path);
|
||||
delete kv;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Import(const char[] name) {
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/schematics/%s.schem", name);
|
||||
KeyValues kv = new KeyValues("root");
|
||||
if(kv.ImportFromFile(path)) {
|
||||
delete kv;
|
||||
return false;
|
||||
}
|
||||
strcopy(this.name, sizeof(this.name), name);
|
||||
kv.GetString("creator_steamid", this.creatorSteamid, sizeof(this.creatorSteamid));
|
||||
kv.GetString("creator_name", this.creatorName, sizeof(this.creatorName));
|
||||
kv.JumpToKey("entities");
|
||||
this.entities = new ArrayList(sizeof(SaveData));
|
||||
SaveData ent;
|
||||
while(kv.GotoNextKey()) {
|
||||
kv.GetVector("offset", ent.origin);
|
||||
kv.GetVector("angles", ent.angles);
|
||||
kv.GetColor4("color", ent.color);
|
||||
kv.GetString("model", ent.model, sizeof(ent.model));
|
||||
this.entities.PushArray(ent);
|
||||
}
|
||||
delete kv;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Spawns all schematics entities, returns list of entities, first being parent.
|
||||
ArrayList SpawnEntities(const float origin[3], bool asPreview = true) {
|
||||
if(this.entities == null) return null;
|
||||
SaveData ent;
|
||||
int parent = -1;
|
||||
ArrayList spawnedEntities = new ArrayList();
|
||||
for(int i = 0; i < this.entities.Length; i++) {
|
||||
this.entities.GetArray(i, ent, sizeof(ent));
|
||||
int entity = ent.ToEntity(origin, asPreview);
|
||||
spawnedEntities.Push(EntIndexToEntRef(entity));
|
||||
if(i == 0) {
|
||||
SetParent(entity, parent)
|
||||
} else {
|
||||
parent = entity;
|
||||
}
|
||||
}
|
||||
return spawnedEntities;
|
||||
}
|
||||
}
|
||||
public any Native_SpawnSchematic(Handle plugin, int numParams) {
|
||||
char name[32];
|
||||
float pos[3];
|
||||
float ang[3];
|
||||
GetNativeString(0, name, sizeof(name));
|
||||
GetNativeArray(1, pos, 3);
|
||||
GetNativeArray(1, ang, 3);
|
||||
Schematic schem;
|
||||
if(!schem.Import(name)) {
|
||||
return false;
|
||||
}
|
||||
ArrayList list = schem.SpawnEntities(pos, false);
|
||||
delete list;
|
||||
return true;
|
||||
}
|
||||
enum struct PlayerPropData {
|
||||
ArrayList categoryStack;
|
||||
|
@ -25,6 +145,9 @@ enum struct PlayerPropData {
|
|||
char classnameOverride[64];
|
||||
ChatPrompt chatPrompt;
|
||||
ArrayList markedProps;
|
||||
SaveType pendingSaveType;
|
||||
|
||||
Schematic schematic;
|
||||
|
||||
// Called on PlayerDisconnect
|
||||
void Reset() {
|
||||
|
@ -36,6 +159,15 @@ enum struct PlayerPropData {
|
|||
this.lastActiveTime = 0;
|
||||
this.classnameOverride[0] = '\0';
|
||||
this.CleanupBuffers();
|
||||
this.pendingSaveType = Save_None;
|
||||
this.schematic.Reset();
|
||||
}
|
||||
|
||||
void StartSchematic(int client, const char[] name) {
|
||||
this.schematic.New(client, name);
|
||||
this.pendingSaveType = Save_Schematic;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Started new schematic: \x05%s", name);
|
||||
ShowCategoryList(client, ROOT_CATEGORY);
|
||||
}
|
||||
|
||||
// Sets the list buffer
|
||||
|
@ -97,6 +229,7 @@ enum struct PlayerPropData {
|
|||
}
|
||||
PlayerPropData g_PropData[MAXPLAYERS+1];
|
||||
|
||||
|
||||
enum struct CategoryData {
|
||||
// The display name of category
|
||||
char name[64];
|
||||
|
@ -124,6 +257,8 @@ enum struct SearchData {
|
|||
strcopy(this.name, sizeof(this.name), item.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum struct SaveData {
|
||||
char model[128];
|
||||
buildType type;
|
||||
|
@ -148,6 +283,43 @@ enum struct SaveData {
|
|||
GetEntityRenderColor(entity, this.color[0],this.color[1],this.color[2],this.color[3]);
|
||||
}
|
||||
|
||||
int ToEntity(const float offset[3], bool asPreview = true) {
|
||||
int entity = -1;
|
||||
if(this.type == Build_Physics)
|
||||
entity = CreateEntityByName("prop_physics");
|
||||
else
|
||||
entity = CreateEntityByName("prop_dynamic_override");
|
||||
if(entity == -1) {
|
||||
return -1;
|
||||
}
|
||||
PrecacheModel(this.model);
|
||||
DispatchKeyValue(entity, "model", this.model);
|
||||
DispatchKeyValue(entity, "targetname", "saved_prop");
|
||||
if(asPreview) {
|
||||
DispatchKeyValue(entity, "rendermode", "1");
|
||||
DispatchKeyValue(entity, "solid", "0");
|
||||
} else {
|
||||
DispatchKeyValue(entity, "solid", this.type == Build_NonSolid ? "0" : "6");
|
||||
}
|
||||
float pos[3];
|
||||
for(int i = 0; i < 3; i++)
|
||||
pos[i] = this.origin[i] + offset[i];
|
||||
|
||||
TeleportEntity(entity, pos, this.angles, NULL_VECTOR);
|
||||
if(!DispatchSpawn(entity)) {
|
||||
return -1;
|
||||
}
|
||||
int alpha = asPreview ? 200 : this.color[3];
|
||||
SetEntityRenderColor(entity, this.color[0], this.color[1], this.color[2], alpha);
|
||||
|
||||
if(asPreview)
|
||||
g_previewItems.Push(EntIndexToEntRef(entity));
|
||||
else
|
||||
AddSpawnedItem(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
void Serialize(char[] output, int maxlen) {
|
||||
Format(
|
||||
output, maxlen, "%s,%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%d,%d,%d",
|
||||
|
@ -181,10 +353,6 @@ enum struct RecentEntry {
|
|||
char name[64];
|
||||
int count;
|
||||
}
|
||||
CategoryData ROOT_CATEGORY;
|
||||
ArrayList g_spawnedItems; // ArrayList(block=2)<entRef, [creator]>
|
||||
ArrayList g_savedItems; // ArrayList<entRef>
|
||||
StringMap g_recentItems; // Key: model[128], value: RecentEntry
|
||||
|
||||
#include <hats/props/db.sp>
|
||||
#include <hats/props/methods.sp>
|
||||
|
|
|
@ -12,6 +12,27 @@ Action Command_Props(int client, int args) {
|
|||
PrintToConsole(client, "favorite - favorites active editor entity");
|
||||
PrintToConsole(client, "controls - list all the controls");
|
||||
PrintToConsole(client, "reload - reload prop list");
|
||||
PrintToConsole(client, "schem[atic] <new/save/edit/delete/load> <name>");
|
||||
} else if(StrEqual(arg, "schem") || StrEqual(arg, "schematic")) {
|
||||
char arg2[16];
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
if(StrEqual(arg2, "new")) {
|
||||
char name[32];
|
||||
GetCmdArg(3, name, sizeof(name));
|
||||
if(name[0] == '\0') {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Please enter a name");
|
||||
} else {
|
||||
g_PropData[client].StartSchematic(client, name);
|
||||
}
|
||||
} else if(StrEqual(arg2, "save")) {
|
||||
if(g_PropData[client].pendingSaveType == Save_Schematic) {
|
||||
g_PropData[client].schematic.Save();
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 No schematic to save.");
|
||||
}
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Unknown option: %s", arg2);
|
||||
}
|
||||
} else if(StrEqual(arg, "list")) {
|
||||
char arg2[16];
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
|
|
|
@ -75,44 +75,89 @@ void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject obj
|
|||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Save / Load");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
Menu menu = new Menu(SaveLoadHandler);
|
||||
menu.SetTitle("Save / Load");
|
||||
char name[64];
|
||||
// TODO: possibly let you overwrite saves?
|
||||
menu.AddItem("", "[New Save]");
|
||||
ArrayList saves = LoadSaves();
|
||||
if(saves != null) {
|
||||
for(int i = 0; i < saves.Length; i++) {
|
||||
saves.GetString(i, name, sizeof(name));
|
||||
menu.AddItem(name, name);
|
||||
}
|
||||
delete saves;
|
||||
}
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(param, MENU_TIME_FOREVER);
|
||||
Spawn_ShowSaveLoadMainMenu(param);
|
||||
}
|
||||
}
|
||||
|
||||
int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
int SaveLoadMainMenuHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[2];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
SaveType type = view_as<SaveType>(StringToInt(info));
|
||||
ShowSaves(client, type);
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveLoadSceneHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char saveName[64];
|
||||
menu.GetItem(param2, saveName, sizeof(saveName));
|
||||
if(saveName[0] == '\0') {
|
||||
// Save new
|
||||
FormatTime(saveName, sizeof(saveName), "%Y-%m-%d_%H-%I-%M");
|
||||
if(CreateSave(saveName)) {
|
||||
if(CreateSceneSave(saveName)) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Saved as \x05%s/%s.txt", g_currentMap, saveName);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Unable to save. Sorry.");
|
||||
}
|
||||
} else if(LoadSave(saveName, true)) {
|
||||
strcopy(g_pendingSaveName, sizeof(g_pendingSaveName), saveName);
|
||||
} else if(g_pendingSaveClient != 0 && g_pendingSaveClient != client) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Another user is currently loading a save.");
|
||||
} else if(g_PropData[client].pendingSaveType == Save_Schematic) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Please complete or cancel current schematic to continue.");
|
||||
} else if(LoadScene(saveName, true)) {
|
||||
ConfirmSave(client, saveName);
|
||||
g_pendingSaveClient = client;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Previewing save \x05%s", saveName);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Press \x05Shift + Middle Mouse\x01 to spawn, \x05Middle Mouse\x01 to cancel");
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Could not load save file.");
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveLoadSchematicHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char saveName[64];
|
||||
menu.GetItem(param2, saveName, sizeof(saveName));
|
||||
Schematic schem;
|
||||
if(saveName[0] == '\0') {
|
||||
if(g_PropData[client].pendingSaveType == Save_Schematic) {
|
||||
if(g_PropData[client].schematic.Save()) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Saved schematic as \x05%s", g_PropData[client].schematic.name);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Failed to save schematic.");
|
||||
}
|
||||
g_PropData[client].schematic.Reset();
|
||||
g_PropData[client].pendingSaveType = Save_None;
|
||||
} else {
|
||||
g_PropData[client].chatPrompt = Prompt_SaveSchematic;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Enter in chat a name for schematic");
|
||||
}
|
||||
} else if(schem.Import(saveName)) {
|
||||
float pos[3];
|
||||
GetCursorLocation(client, pos);
|
||||
ArrayList list = schem.SpawnEntities(pos, true);
|
||||
SaveData save;
|
||||
int parent = list.GetArray(0, save);
|
||||
delete list;
|
||||
Editor[client].Import(parent);
|
||||
if(g_pendingSaveClient != 0 && g_pendingSaveClient != client) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Another user is currently loading a save.");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Another user is currently loading a scene.");
|
||||
} else {
|
||||
g_pendingSaveClient = client;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Previewing save \x05%s", saveName);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Previewing schematic \x05%s", saveName);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Press \x05Shift + Middle Mouse\x01 to spawn, \x05Middle Mouse\x01 to cancel");
|
||||
}
|
||||
} else {
|
||||
|
@ -120,12 +165,31 @@ int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) {
|
|||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveLoadConfirmHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
ClearSavePreview();
|
||||
char info[64];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
if(info[0] != '\0') {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Loaded scene \x05%s", info);
|
||||
LoadScene(info, false);
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
Spawn_ShowSaveLoadMainMenu(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[8];
|
||||
|
|
|
@ -657,16 +657,15 @@ stock void StringToUpper(char[] str) {
|
|||
}
|
||||
}
|
||||
|
||||
stock int GetRealClient(int client) {
|
||||
if(IsFakeClient(client)) {
|
||||
char netclass[32];
|
||||
GetEntityClassname(client, netclass, sizeof(netclass));
|
||||
if(!StrEqual(netclass, "SurvivorBot", false)) return false;
|
||||
int realPlayer = GetClientOfUserId(GetEntProp(client, Prop_Send, "m_humanSpectatorUserID"));
|
||||
return realPlayer > 0 ? realPlayer : -1;
|
||||
}else{
|
||||
return client;
|
||||
stock int GetRealClient(int bot) {
|
||||
if(!IsFakeClient(bot)) return -1;
|
||||
static char netclass[16];
|
||||
GetEntityNetClass(bot, netclass, sizeof(netclass));
|
||||
if(StrEqual(netclass, "SurvivorBot")) {
|
||||
int user = GetEntProp(bot, Prop_Send, "m_humanSpectatorUserID");
|
||||
if(user > 0) return GetClientOfUserId(user);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
stock int FindIdleBot(int client) {
|
||||
|
|
|
@ -259,6 +259,7 @@ public void OnPluginStart() {
|
|||
|
||||
HookEvent("player_spawn", Event_PlayerSpawn);
|
||||
HookEvent("player_first_spawn", Event_PlayerFirstSpawn);
|
||||
HookEvent("player_left_start_area", Event_LeaveStartArea);
|
||||
//Tracking player items:
|
||||
HookEvent("item_pickup", Event_ItemPickup);
|
||||
HookEvent("weapon_drop", Event_ItemPickup);
|
||||
|
@ -939,6 +940,10 @@ void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast)
|
|||
delete g_saveTimer[client];
|
||||
}
|
||||
|
||||
void Event_LeaveStartArea(Event event, const char[] name, bool dontBroadcast) {
|
||||
PopulateItems();
|
||||
}
|
||||
|
||||
void Event_PlayerInfo(Event event, const char[] name, bool dontBroadcast) {
|
||||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
if(client && !IsFakeClient(client)) {
|
||||
|
@ -1336,7 +1341,6 @@ public void OnMapStart() {
|
|||
L4D2_RunScript(HUD_SCRIPT_CLEAR);
|
||||
Director_OnMapStart();
|
||||
g_areItemsPopulated = false;
|
||||
CreateTimer(30.0, Timer_Populate);
|
||||
|
||||
if(g_isLateLoaded) {
|
||||
UpdateSurvivorCount();
|
||||
|
@ -1486,11 +1490,6 @@ public void OnMapEnd() {
|
|||
void Event_FinaleStart(Event event, const char[] name, bool dontBroadcast) {
|
||||
g_finaleStage = Stage_Active;
|
||||
}
|
||||
Action Timer_Populate(Handle h) {
|
||||
PopulateItems();
|
||||
return Plugin_Continue;
|
||||
|
||||
}
|
||||
public void OnClientSpeaking(int client) {
|
||||
g_isSpeaking[client] = true;
|
||||
}
|
||||
|
@ -1566,7 +1565,7 @@ Action Hook_CabinetItemSpawn(int entity) {
|
|||
int cabEnt = cabinets[ci].items[block];
|
||||
PrintDebug(DEBUG_ANY, "cabinet %d spawner %d block %d: %d", cabinet, entity, block, cabEnt);
|
||||
if(cabEnt <= 0) {
|
||||
cabinets[ci].items[block] = entity;
|
||||
cabinets[ci].items[block] = EntIndexToEntRef(entity);
|
||||
PrintDebug(DEBUG_SPAWNLOGIC, "Adding spawner %d for cabinet %d block %d", entity, cabinet, block);
|
||||
break;
|
||||
}
|
||||
|
@ -1770,6 +1769,7 @@ Action Timer_UpdateHud(Handle h) {
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PopulateItems() {
|
||||
PrintToServer("[EPI:TEMP] PopulateItems hasRan=%b finale=%b", g_areItemsPopulated, L4D_IsMissionFinalMap(true));
|
||||
if(g_areItemsPopulated) return;
|
||||
UpdateSurvivorCount();
|
||||
if(!IsEPIActive()) return;
|
||||
|
@ -1831,7 +1831,8 @@ void PopulateCabinets() {
|
|||
while(extraAmount > 0) {
|
||||
//FIXME: spawner is sometimes invalid entity. Ref needed?
|
||||
for(int block = 0; block < CABINET_ITEM_BLOCKS; block++) {
|
||||
spawner = cabinets[i].items[block];
|
||||
if(cabinets[i].items[block] == 0) break;
|
||||
spawner = EntRefToEntIndex(cabinets[i].items[block]);
|
||||
if(spawner > 0) {
|
||||
if(!HasEntProp(spawner, Prop_Data, "m_itemCount")) continue;
|
||||
hasSpawner = true;
|
||||
|
|
|
@ -32,7 +32,9 @@ public Plugin myinfo =
|
|||
};
|
||||
|
||||
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) {
|
||||
|
|
|
@ -575,12 +575,8 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
// OnPlayerRunCmd :: ENTITY EDITOR
|
||||
/////////////////////////////
|
||||
if(g_pendingSaveClient == client) {
|
||||
if(buttons & IN_ZOOM) {
|
||||
ClearSavePreview();
|
||||
if(buttons & IN_SPEED) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Loaded save \x05%s", g_pendingSaveName);
|
||||
LoadSave(g_pendingSaveName, false);
|
||||
}
|
||||
if(g_PropData[client].pendingSaveType == Save_Schematic) {
|
||||
// move cursor? or should be editor anyway
|
||||
}
|
||||
} else if(g_PropData[client].markedProps != null) {
|
||||
SetWeaponDelay(client, 0.5);
|
||||
|
@ -615,10 +611,10 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
cmdThrottle[client] = tick;
|
||||
}
|
||||
} else if(Editor[client].IsActive()) {
|
||||
if(buttons & IN_USE && buttons & IN_RELOAD) {
|
||||
ClientCommand(client, "sm_wall done");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
// if(buttons & IN_USE && buttons & IN_RELOAD) {
|
||||
// ClientCommand(client, "sm_wall done");
|
||||
// return Plugin_Handled;
|
||||
// }
|
||||
bool allowMove = true;
|
||||
switch(Editor[client].mode) {
|
||||
case MOVE_ORIGIN: {
|
||||
|
@ -626,7 +622,7 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
|
||||
bool isRotate;
|
||||
int flags = GetEntityFlags(client);
|
||||
if(buttons & IN_USE && ~buttons & IN_ZOOM) {
|
||||
if(buttons & IN_RELOAD && ~buttons & IN_ZOOM) {
|
||||
if(!g_inRotate[client]) {
|
||||
g_inRotate[client] = true;
|
||||
}
|
||||
|
@ -717,22 +713,19 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
}
|
||||
}
|
||||
}
|
||||
if(tick - cmdThrottle[client] > 0.13) {
|
||||
if(buttons & IN_RELOAD)
|
||||
Editor[client].CycleMode(); // R: Cycle forward
|
||||
else if(buttons & IN_ZOOM) {
|
||||
buttons &= ~IN_ZOOM;
|
||||
|
||||
if(buttons & IN_SPEED) {
|
||||
int entity;
|
||||
Editor[client].Done(entity);
|
||||
} else if(Editor[client].flags & Edit_Preview && buttons & IN_DUCK) {
|
||||
Editor[client].CycleBuildType();
|
||||
} else if(~buttons & IN_DUCK) {
|
||||
Editor[client].Cancel();
|
||||
}
|
||||
if(!(oldButtons & IN_USE) && buttons & IN_USE) {
|
||||
if(buttons & IN_SPEED) {
|
||||
Editor[client].Cancel();
|
||||
} else if(buttons & IN_DUCK) {
|
||||
if(Editor[client].flags & Edit_Preview)
|
||||
Editor[client].CycleBuildType();
|
||||
} else {
|
||||
int entity;
|
||||
Editor[client].Done(entity);
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
|
||||
} else if(!(oldButtons & IN_ZOOM) && buttons & IN_ZOOM) {
|
||||
Editor[client].CycleMode(); // ZOOM: Cycle forward
|
||||
}
|
||||
|
||||
Editor[client].Draw(BUILDER_COLOR, 0.1, 0.1);
|
||||
|
@ -900,7 +893,7 @@ stock bool Filter_NoPlayers(int entity, int mask, int data) {
|
|||
}
|
||||
|
||||
stock bool Filter_IgnorePlayerAndWall(int entity, int mask, int data) {
|
||||
if(entity > MaxClients && entity != data && EntRefToEntIndex(Editor[data].entity) != entity) {
|
||||
if(entity > MaxClients && entity != data && EntRefToEntIndex(Editor[data].entity) != entity && EntRefToEntIndex(hatData[data].entity) != entity) {
|
||||
static char classname[16];
|
||||
GetEntityClassname(entity, classname, sizeof(classname));
|
||||
// Ignore infected
|
||||
|
@ -912,8 +905,9 @@ stock bool Filter_IgnorePlayerAndWall(int entity, int mask, int data) {
|
|||
|
||||
bool Filter_ValidHats(int entity, int mask, int data) {
|
||||
if(entity == data) return false;
|
||||
if(entity <= MaxClients) {
|
||||
if(entity <= MaxClients && entity > 0) {
|
||||
int client = GetRealClient(data);
|
||||
if(client == -1) client = data;
|
||||
return CanTarget(client); // Don't target if player targetting off
|
||||
}
|
||||
return CheckBlacklist(entity);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <jutils>
|
||||
// Addons:
|
||||
#undef REQUIRE_PLUGIN
|
||||
#tryinclude <feedthetrolls>
|
||||
#include <feedthetrolls>
|
||||
#undef REQUIRE_PLUGIN
|
||||
#tryinclude <tkstopper>
|
||||
|
||||
|
@ -504,6 +504,7 @@ bool ApplyAction(int targetUserId, const char[] action, const char[] key, const
|
|||
#if defined _ftt_included_
|
||||
if(GetFeatureStatus(FeatureType_Native, "ApplyTroll") != FeatureStatus_Available) {
|
||||
PrintToServer("[PlayerNotes] Warn: Action \"%s\" for %N has missing plugin: Feed The Trolls", action, target);
|
||||
return false;
|
||||
}
|
||||
// Replace under scores with spaces
|
||||
char newKey[32];
|
||||
|
@ -524,6 +525,7 @@ bool ApplyAction(int targetUserId, const char[] action, const char[] key, const
|
|||
#if defined _tkstopper_included_
|
||||
if(GetFeatureStatus(FeatureType_Native, "SetImmunity") != FeatureStatus_Available) {
|
||||
PrintToServer("[PlayerNotes] Warn: Action \"%s\" for %N has missing plugin: TKStopper", action, target);
|
||||
return false;
|
||||
} else if(StrEqual(key, "rff")) {
|
||||
SetImmunity(target, TKImmune_ReverseFriendlyFire, true);
|
||||
} else if(StrEqual(key, "tk")) {
|
||||
|
@ -544,6 +546,8 @@ bool ApplyAction(int targetUserId, const char[] action, const char[] key, const
|
|||
} else {
|
||||
|
||||
}
|
||||
} else if(strncmp(action, "model", 4) == 0) {
|
||||
ServerCommand("sm_model %s #%d", key, GetClientUserId(target));
|
||||
} else {
|
||||
PrintToServer("[PlayerNotes] Warn: Action (\"%s\") for %N is not valid", action, target);
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue