From 1e2ad1ea87db771680a96ded821231ba2db3d817 Mon Sep 17 00:00:00 2001
From: Alexey <lexuzieel@gmail.com>
Date: Wed, 14 Aug 2019 00:14:17 +0300
Subject: [PATCH 1/6] Update slender fortress to the latest version

---
 addons/sourcemod/gamedata/sf2.txt             |    22 +
 addons/sourcemod/scripting/include/dhooks.inc |   152 +-
 addons/sourcemod/scripting/include/sf2.inc    |   644 +-
 addons/sourcemod/scripting/rytp_horror.sp     | 12891 ++++++++--------
 .../scripting/rytp_horror/adminmenu.sp        |  1820 +--
 .../sourcemod/scripting/rytp_horror/client.sp | 11852 +++++++-------
 .../sourcemod/scripting/rytp_horror/debug.sp  |   320 +-
 .../scripting/rytp_horror/effects.sp          |   550 +-
 .../scripting/rytp_horror/logging.sp          |    52 +-
 .../sourcemod/scripting/rytp_horror/menus.sp  |  1594 +-
 addons/sourcemod/scripting/rytp_horror/nav.sp |  1414 +-
 addons/sourcemod/scripting/rytp_horror/npc.sp |  5354 ++++---
 .../scripting/rytp_horror/npc/npc_chaser.sp   |  5028 +++---
 .../scripting/rytp_horror/playergroups.sp     |  1226 +-
 .../rytp_horror/playergroups/menus.sp         |  1238 +-
 .../scripting/rytp_horror/profiles.sp         |  2376 +--
 .../rytp_horror/profiles/profile_chaser.sp    |  1140 +-
 addons/sourcemod/scripting/rytp_horror/pvp.sp |  1162 +-
 .../scripting/rytp_horror/pvp/menus.sp        |   122 +-
 .../scripting/rytp_horror/specialround.sp     |   755 +-
 .../sourcemod/scripting/rytp_horror/stocks.sp |  1397 +-
 addons/sourcemod/scripting/spcomp.exe         |   Bin 345600 -> 403968 bytes
 .../sourcemod/translations/ru/sf2.phrases.txt |    30 +
 addons/sourcemod/translations/sf2.phrases.txt |    30 +
 24 files changed, 25574 insertions(+), 25595 deletions(-)
 create mode 100644 addons/sourcemod/gamedata/sf2.txt

diff --git a/addons/sourcemod/gamedata/sf2.txt b/addons/sourcemod/gamedata/sf2.txt
new file mode 100644
index 0000000..aa60ffc
--- /dev/null
+++ b/addons/sourcemod/gamedata/sf2.txt
@@ -0,0 +1,22 @@
+"Games"
+{
+	"tf"
+	{
+		"Offsets"
+		{
+			"CTFPlayer::WantsLagCompensationOnEntity"
+			{
+				"windows"	"323"
+				"linux"		"324"
+				"mac"		"324"
+			}
+			
+			"CBaseEntity::ShouldTransmit"
+			{
+				"windows"	"18"
+				"linux"	"19"
+				"mac"	"19"
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/include/dhooks.inc b/addons/sourcemod/scripting/include/dhooks.inc
index 5d26765..604b186 100644
--- a/addons/sourcemod/scripting/include/dhooks.inc
+++ b/addons/sourcemod/scripting/include/dhooks.inc
@@ -2,6 +2,7 @@
 #endinput
 #endif
 #define _dhooks_included
+
 enum ObjectValueType
 {
 	ObjectValueType_Int = 0,
@@ -18,11 +19,13 @@ enum ObjectValueType
 	ObjectValueType_CharPtr,
 	ObjectValueType_String
 };
+
 enum ListenType
 {
 	ListenType_Created,
 	ListenType_Deleted
 };
+
 enum ReturnType
 {
 	ReturnType_Unknown,
@@ -38,6 +41,7 @@ enum ReturnType
 	ReturnType_CBaseEntity,
 	ReturnType_Edict
 };
+
 enum HookParamType
 {
 	HookParamType_Unknown,
@@ -53,18 +57,21 @@ enum HookParamType
 	HookParamType_Edict,
 	HookParamType_Object
 };
+
 enum ThisPointerType
 {
 	ThisPointer_Ignore,
 	ThisPointer_CBaseEntity,
 	ThisPointer_Address
 };
+
 enum HookType
 {
 	HookType_Entity,
 	HookType_GameRules,
 	HookType_Raw
 };
+
 enum MRESReturn
 {
 	MRES_ChangedHandled = -2,	// Use changed values and return MRES_Handled
@@ -74,63 +81,71 @@ enum MRESReturn
 	MRES_Override,				// call real function, but use my return value
 	MRES_Supercede				// skip real function; use my return value
 };
+
 enum DHookPassFlag
 {
-	DHookPass_ByVal = (1<<0),
-	DHookPass_ByRef = (1<<1)
+	DHookPass_ByVal = 		(1<<0),		/**< Passing by value */
+	DHookPass_ByRef = 		(1<<1),		/**< Passing by reference */
+	DHookPass_ODTOR =		(1<<2),		/**< Object has a destructor */
+	DHookPass_OCTOR =		(1<<3),		/**< Object has a constructor */
+	DHookPass_OASSIGNOP	=	(1<<4),		/**< Object has an assignment operator */
 };
-funcenum ListenCB
+
+typeset ListenCB
 {
 	//Deleted
-	public (entity),
+	function void (int entity);
+	
 	//Created
-	public (entity, const String:classname[])
-}
-funcenum DHookRemovalCB
+	function void (int entity, const char[] classname);
+};
+
+typeset DHookRemovalCB
 {
-	public (hookid)
+	function void (int hookid);
 };
-funcenum DHookCallback
+typeset DHookCallback
 {
 	//Function Example: void Ham::Test() with this pointer ignore
-	MRESReturn:public(),
+	function MRESReturn ();
 	
 	//Function Example: void Ham::Test() with this pointer passed
-	MRESReturn:public(thisPointer),
+	function MRESReturn (int pThis);
 	
 	//Function Example: void Ham::Test(int cake) with this pointer ignore
-	MRESReturn:public(Handle:hParams),
+	function MRESReturn (Handle hParams);
 	
 	//Function Example: void Ham::Test(int cake) with this pointer passed
-	MRESReturn:public(thisPointer, Handle:hParams),
+	function MRESReturn (int pThis, Handle hParams);
 	
 	//Function Example: int Ham::Test() with this pointer ignore
-	MRESReturn:public(Handle:hReturn),
+	function MRESReturn (Handle hReturn);
 	
 	//Function Example: int Ham::Test() with this pointer passed
-	MRESReturn:public(thisPointer, Handle:hReturn),
+	function MRESReturn (int pThis, Handle hReturn);
 	
 	//Function Example: int Ham::Test(int cake) with this pointer ignore
-	MRESReturn:public(Handle:hReturn, Handle:hParams),
+	function MRESReturn (Handle hReturn, Handle hParams);
 	
 	//Function Example: int Ham::Test(int cake) with this pointer passed
-	MRESReturn:public(thisPointer, Handle:hReturn, Handle:hParams),
+	function MRESReturn (int pThis, Handle hReturn, Handle hParams);
 	
 	//Address NOW
 	
 	//Function Example: void Ham::Test() with this pointer passed
-	MRESReturn:public(Address:thisPointer),
+	function MRESReturn (Address pThis);
 	
 	//Function Example: void Ham::Test(int cake) with this pointer passed
-	MRESReturn:public(Address:thisPointer, Handle:hParams),
+	function MRESReturn (Address pThis, Handle hParams);
 	
 	//Function Example: int Ham::Test() with this pointer passed
-	MRESReturn:public(Address:thisPointer, Handle:hReturn),
+	function MRESReturn (Address pThis, Handle hReturn);
 	
 	//Function Example: int Ham::Test(int cake) with this pointer passed
-	MRESReturn:public(Address:thisPointer, Handle:hReturn, Handle:hParams)
+	function MRESReturn (Address pThis, Handle hReturn, Handle hParams);
 	
 };
+
 /* Adds an entity listener hook
  *
  * @param type			Type of listener to add
@@ -138,7 +153,7 @@ funcenum DHookCallback
  *
  * @noreturn
 */
-native DHookAddEntityListener(ListenType:type, ListenCB:callback);
+native void DHookAddEntityListener(ListenType type, ListenCB callback);
 
 /* Removes an entity listener hook
  *
@@ -147,7 +162,7 @@ native DHookAddEntityListener(ListenType:type, ListenCB:callback);
  *
  * @return True if one was removed false otherwise.
 */
-native bool:DHookRemoveEntityListener(ListenType:type, ListenCB:callback);
+native bool DHookRemoveEntityListener(ListenType type, ListenCB callback);
 
 /* Creates a hook
  *
@@ -155,11 +170,11 @@ native bool:DHookRemoveEntityListener(ListenType:type, ListenCB:callback);
  * @param hooktype		Type of hook
  * @param returntype	Type type of return
  * @param thistype		Type of this pointer or ignore (ignore can be used if not needed)
- * @param callback		Callback function
+ * @param callback		Optional callback function, if not set here must be set when hooking.
  * 
  * @return Returns setup handle for the hook or INVALID_HANDLE.
 */
-native Handle:DHookCreate(offset, HookType:hooktype, ReturnType:returntype, ThisPointerType:thisPointertype, DHookCallback:callback);
+native Handle DHookCreate(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback=INVALID_FUNCTION);
 
 /* Adds param to a hook setup
  *
@@ -171,8 +186,7 @@ native Handle:DHookCreate(offset, HookType:hooktype, ReturnType:returntype, This
  * @error	Invalid setup handle or too many params added (request upping the max in thread)
  * @noreturn
 */
-native DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:flag=DHookPass_ByVal);
-//native DHookAddParam(Handle:setup, HookParamType:type);
+native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal);
 
 /* Hook entity
  * 
@@ -180,22 +194,24 @@ native DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:fl
  * @param post			True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
  * @param entity		Entity index to hook on.
  * @param removalcb		Callback for when the hook is removed (Entity hooks are auto-removed on entity destroyed and will call this callback)
+ * @param callback		Optional callback function, if not set here must be set when creating the hook.
  * 
- * @error Invalid setup handle, invalid entity or invalid hook type.
+ * @error Invalid setup handle, invalid address, invalid hook type or invalid callback.
  * @return -1 on fail a hookid on success
 */
-native DHookEntity(Handle:setup, bool:post, entity, DHookRemovalCB:removalcb=DHookRemovalCB:-1);
+native int DHookEntity(Handle setup, bool post, int entity, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION);
 
 /* Hook gamerules
  * 
  * @param setup			Setup handle to use to add the hook.
  * @param post			True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
  * @param removalcb		Callback for when the hook is removed (Game rules hooks are auto-removed on map end and will call this callback)
+ * @param callback		Optional callback function, if not set here must be set when creating the hook.
  * 
- * @error Invalid setup handle, failing to get gamerules pointer or invalid hook type.
+ * @error Invalid setup handle, invalid address, invalid hook type or invalid callback.
  * @return -1 on fail a hookid on success
 */
-native DHookGamerules(Handle:setup, bool:post, DHookRemovalCB:removalcb=DHookRemovalCB:-1);
+native int DHookGamerules(Handle setup, bool post, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION);
 
 /* Hook a raw pointer
  * 
@@ -203,11 +219,12 @@ native DHookGamerules(Handle:setup, bool:post, DHookRemovalCB:removalcb=DHookRem
  * @param post			True to make the hook a post hook. (If you need to change the retunr value or need the return value use a post hook! If you need to change params and return use a pre and post hook!)
  * @param addr			This pointer address.
  * @param removalcb		Callback for when the hook is removed (Entity hooks are auto-removed on entity destroyed and will call this callback)
+ * @param callback		Optional callback function, if not set here must be set when creating the hook.
  * 
- * @error Invalid setup handle, invalid address or invalid hook type.
+ * @error Invalid setup handle, invalid address, invalid hook type or invalid callback.
  * @return -1 on fail a hookid on success
 */
-native DHookRaw(Handle:setup, bool:post, Address:addr, DHookRemovalCB:removalcb=DHookRemovalCB:-1);
+native int DHookRaw(Handle setup, bool post, Address addr, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION);
 
 /* Remove hook by hook id
  * 
@@ -216,7 +233,7 @@ native DHookRaw(Handle:setup, bool:post, Address:addr, DHookRemovalCB:removalcb=
  * @return true on success false otherwise
  * @note This will not fire the removal callback!
 */
-native bool:DHookRemoveHookID(hookid);
+native bool DHookRemoveHookID(int hookid);
 
 /* Get param value (Only use for: int, entity, bool or float param types)
  * 
@@ -226,7 +243,7 @@ native bool:DHookRemoveHookID(hookid);
  * @error Invalid handle. Invalid param number. Invalid param type.
  * @return value if num greater than 0. If 0 returns paramcount.
 */
-native any:DHookGetParam(Handle:hParams, num);
+native any DHookGetParam(Handle hParams, int num);
 
 /* Get vector param value
  * 
@@ -237,7 +254,7 @@ native any:DHookGetParam(Handle:hParams, num);
  * @error Invalid handle. Invalid param number. Invalid param type.
  * @noreturn
 */
-native DHookGetParamVector(Handle:hParams, num, Float:vec[3]);
+native void DHookGetParamVector(Handle hParams, int num, float vec[3]);
 
 /* Get string param value
  * 
@@ -247,9 +264,9 @@ native DHookGetParamVector(Handle:hParams, num, Float:vec[3]);
  * @param size			Buffer size
  * 
  * @error Invalid handle. Invalid param number. Invalid param type.
- * @return value if num greater than 0.
+ * @noreturn
 */
-native DHookGetParamString(Handle:hParams, num, String:buffer[], size);
+native void DHookGetParamString(Handle hParams, int num, char[] buffer, int size);
 
 /* Set param value (Only use for: int, entity, bool or float param types)
  * 
@@ -260,7 +277,7 @@ native DHookGetParamString(Handle:hParams, num, String:buffer[], size);
  * @error Invalid handle. Invalid param number. Invalid param type.
  * @noreturn
 */
-native DHookSetParam(Handle:hParams, num, any:value);
+native void DHookSetParam(Handle hParams, int num, any value);
 
 /* Set vector param value
  * 
@@ -271,7 +288,7 @@ native DHookSetParam(Handle:hParams, num, any:value);
  * @error Invalid handle. Invalid param number. Invalid param type.
  * @noreturn
 */
-native DHookSetParamVector(Handle:hParams, num, Float:vec[3]);
+native void DHookSetParamVector(Handle hParams, int num, float vec[3]);
 
 /* Set string param value
  * 
@@ -282,7 +299,7 @@ native DHookSetParamVector(Handle:hParams, num, Float:vec[3]);
  * @error Invalid handle. Invalid param number. Invalid param type.
  * @noreturn
 */
-native DHookSetParamString(Handle:hParams, num, String:value[]);
+native void DHookSetParamString(Handle hParams, int num, char[] value);
 
 /* Get return value (Only use for: int, entity, bool or float return types)
  * 
@@ -291,7 +308,7 @@ native DHookSetParamString(Handle:hParams, num, String:value[]);
  * @error Invalid Handle, invalid type.
  * @return Returns default value if prehook returns actual value if post hook.
 */
-native any:DHookGetReturn(Handle:hReturn);
+native any DHookGetReturn(Handle hReturn);
 
 /* Get return vector value
  * 
@@ -301,7 +318,7 @@ native any:DHookGetReturn(Handle:hReturn);
  * @error Invalid Handle, invalid type.
  * @noreturn
 */
-native DHookGetReturnVector(Handle:hReturn, Float:vec[3]);
+native void DHookGetReturnVector(Handle hReturn, float vec[3]);
 
 /* Get return string value
  * 
@@ -312,7 +329,7 @@ native DHookGetReturnVector(Handle:hReturn, Float:vec[3]);
  * @error Invalid Handle, invalid type.
  * @noreturn
 */
-native DHookGetReturnString(Handle:hReturn, String:buffer[], size);
+native void DHookGetReturnString(Handle hReturn, char[] buffer, int size);
 
 /* Set return value (Only use for: int, entity, bool or float return types)
  * 
@@ -322,7 +339,7 @@ native DHookGetReturnString(Handle:hReturn, String:buffer[], size);
  * @error Invalid Handle, invalid type.
  * @noreturn
 */
-native DHookSetReturn(Handle:hReturn, any:value);
+native void DHookSetReturn(Handle hReturn, any value);
 
 /* Set return vector value
  * 
@@ -332,7 +349,7 @@ native DHookSetReturn(Handle:hReturn, any:value);
  * @error Invalid Handle, invalid type.
  * @noreturn
 */
-native DHookSetReturnVector(Handle:hReturn, Float:vec[3]);
+native void DHookSetReturnVector(Handle hReturn, float vec[3]);
 
 /* Set return string value
  * 
@@ -342,24 +359,26 @@ native DHookSetReturnVector(Handle:hReturn, Float:vec[3]);
  * @error Invalid Handle, invalid type.
  * @noreturn
 */
-native DHookSetReturnString(Handle:hReturn, String:value[]);
+native void DHookSetReturnString(Handle hReturn, char[] value);
+
+//WE SHOULD WRAP THESE AROUND STOCKS FOR NON PTR AS WE SUPPORT BOTH WITH THESE NATIVE'S
 
 /* Gets an objects variable value
  *
  * @param hParams		Handle to params structure
- * @param num			Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1. 0 Will return the number of params stored)
+ * @param num			Param number to get.
  * @param offset		Offset within the object to the var to get.
  * @param type			Type of var it is
  *
  * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
  * @return Value of the objects var. If EHANDLE type or entity returns entity index.
 */
-native any:DHookGetParamObjectPtrVar(Handle:hParams, num, offset, ObjectValueType:type);
+native any DHookGetParamObjectPtrVar(Handle hParams, int num, int offset, ObjectValueType type);
 
 /* Sets an objects variable value
  *
  * @param hParams		Handle to params structure
- * @param num			Param number to set. (Example if the function has 2 params and you need the value of the first param num would be 1. 0 Will return the number of params stored)
+ * @param num			Param number to set.
  * @param offset		Offset within the object to the var to set.
  * @param type			Type of var it is
  * @param value			The value to set the var to.
@@ -367,25 +386,25 @@ native any:DHookGetParamObjectPtrVar(Handle:hParams, num, offset, ObjectValueTyp
  * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
  * @noreturn
 */
-native DHookSetParamObjectPtrVar(Handle:hParams, num, offset, ObjectValueType:type, any:value);
+native void DHookSetParamObjectPtrVar(Handle hParams, int num, int offset, ObjectValueType type, any value);
 
 /* Gets an objects vector variable value
  *
  * @param hParams		Handle to params structure
- * @param num			Param number to get. (Example if the function has 2 params and you need the value of the first param num would be 1. 0 Will return the number of params stored)
+ * @param num			Param number to get.
  * @param offset		Offset within the object to the var to get.
  * @param type			Type of var it is
  * @param buffer		Buffer to store the result vector
  *
  * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
- * @return Value of the objects var.
+ * @noreturn
 */
-native DHookGetParamObjectPtrVarVector(Handle:hParams, num, offset, ObjectValueType:type, Float:buffer[3]);
+native void DHookGetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float buffer[3]);
 
 /* Sets an objects vector variable value
  *
  * @param hParams		Handle to params structure
- * @param num			Param number to set. (Example if the function has 2 params and you need the value of the first param num would be 1. 0 Will return the number of params stored)
+ * @param num			Param number to set.
  * @param offset		Offset within the object to the var to set.
  * @param type			Type of var it is
  * @param value			The value to set the vector var to.
@@ -393,12 +412,21 @@ native DHookGetParamObjectPtrVarVector(Handle:hParams, num, offset, ObjectValueT
  * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
  * @noreturn
 */
-native DHookSetParamObjectPtrVarVector(Handle:hParams, num, offset, ObjectValueType:type, Float:value[3]);
+native void DHookSetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float value[3]);
 
-
-//ADD DOCS OR ELSE
-//WE SHOULD WRAP THESE AROUND STOCKS FOR NON PTR AS WE SUPPORT BOTH WITH THIS NATIVE
-native DHookGetParamObjectPtrString(Handle:hParams, num, offset, ObjectValueType:type, String:buffer[], size);
+/* Gets an objects string variable value
+ *
+ * @param hParams		Handle to params structure
+ * @param num			Param number to get.
+ * @param offset		Offset within the object to the var to get.
+ * @param type			Type of var it is
+ * @param buffer		Buffer to store the result vector
+ * @param size			Size of the buffer
+ *
+ * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type.
+ * @noreturn
+*/
+native void DHookGetParamObjectPtrString(Handle hParams, int num, int offset, ObjectValueType type, char[] buffer, int size);
 
 /* Checks if a pointer param is null
  *
@@ -408,9 +436,9 @@ native DHookGetParamObjectPtrString(Handle:hParams, num, offset, ObjectValueType
  * @error Non pointer param
  * @return True if null false otherwise.
 */
-native bool:DHookIsNullParam(Handle:hParams, num);
+native bool DHookIsNullParam(Handle hParams, int num);
 
-public Extension:__ext_dhooks =
+public Extension __ext_dhooks =
 {
 	name = "dhooks",
 	file = "dhooks.ext",
diff --git a/addons/sourcemod/scripting/include/sf2.inc b/addons/sourcemod/scripting/include/sf2.inc
index b6467ad..3dc0e20 100644
--- a/addons/sourcemod/scripting/include/sf2.inc
+++ b/addons/sourcemod/scripting/include/sf2.inc
@@ -1,321 +1,325 @@
-#if defined _sf2_included
- #endinput
-#endif
-#define _sf2_included
-
-// Some defines.
-#define SF2_MAX_PROFILE_NAME_LENGTH 64
-#define SF2_MAX_NAME_LENGTH 32
-
-#define MAX_BOSSES 32
-#define MAX_NODES -1
-
-// Difficulty modifiers.
-#define DIFFICULTY_EASY 0.75
-#define DIFFICULTY_NORMAL 1.0
-#define DIFFICULTY_HARD 2.0
-#define DIFFICULTY_INSANE 3.5
-
-// Music system flags.
-#define MUSICF_PAGES1PERCENT (1 << 0)
-#define MUSICF_PAGES25PERCENT (1 << 1)
-#define MUSICF_PAGES50PERCENT (1 << 2)
-#define MUSICF_PAGES75PERCENT (1 << 3)
-#define MUSICF_DEATH (1 << 4)
-#define MUSICF_CHASE (1 << 5)
-#define MUSICF_CHASEVISIBLE (1 << 6)
-#define MUSICF_ALERT (1 << 7)
-#define MUSICF_20DOLLARS (1 << 8)
-
-// Special round enumerations.
-enum
-{
-	SPECIALROUND_DOUBLETROUBLE = 1,
-	SPECIALROUND_INSANEDIFFICULTY,
-	SPECIALROUND_LIGHTSOUT,
-	SPECIALROUND_MAXROUNDS
-};
-
-// Boss state enumerations.
-enum
-{
-	STATE_IDLE = 0,
-	STATE_WANDER,
-	STATE_ALERT,
-	STATE_CHASE,
-	STATE_ATTACK,
-	STATE_STUN
-};
-
-enum SoundType
-{
-	SoundType_None = 0,
-	SoundType_Footstep,
-	SoundType_Voice,
-	SoundType_Weapon
-};
-
-enum
-{
-	Difficulty_Easy = 0,
-	Difficulty_Normal,
-	Difficulty_Hard,
-	Difficulty_Insane,
-	Difficulty_Max
-};
-
-enum
-{
-	Static_None = 0,
-	Static_Increase,
-	Static_Decrease
-};
-
-enum
-{
-	SF2BossType_Unknown = -1,
-	SF2BossType_Static = 0,
-	SF2BossType_Creeper,
-	SF2BossType_Chaser,
-	SF2BossType_AdvancedChaser,
-	SF2BossType_MaxTypes
-};
-
-enum SF2RoundState
-{
-	SF2RoundState_Invalid = -1,
-	SF2RoundState_Waiting = 0,		// waiting for players
-	SF2RoundState_Intro,				// if intro is enabled, intro stage for RED
-	SF2RoundState_Active,			// round is running for RED
-	SF2RoundState_Escape,			// escape stage for RED
-	SF2RoundState_Outro				// round win for a team, next round coming soon
-};
-
-// Boss flags.
-#define SFF_SPAWNONCE (1 << 0)
-#define SFF_NOTELEPORT (1 << 1)
-#define SFF_FAKE (1 << 2)
-#define SFF_MARKEDASFAKE (1 << 3)
-#define SFF_ATTACKWAITERS (1 << 4)
-#define SFF_HASSTATICSHAKE (1 << 5)
-#define SFF_STATICONLOOK (1 << 6)
-#define SFF_STATICONRADIUS (1 << 7)
-#define SFF_PROXIES (1 << 8)
-#define SFF_WANDERMOVE (1 << 9)
-#define SFF_HASJUMPSCARE (1 << 10)
-#define SFF_HASSIGHTSOUNDS (1 << 11)
-#define SFF_HASSTATICLOOPLOCALSOUND (1 << 12)
-#define SFF_HASVIEWSHAKE (1 << 13)
-#define SFF_COPIES (1 << 14)
-#define SFF_ATTACKPROPS (1 << 15)
-
-// Interrup conditions.
-#define COND_HEARDSUSPICIOUSSOUND (1 << 0)
-#define COND_HEARDFOOTSTEP (1 << 1)
-#define COND_HEARDFOOTSTEPLOUD (1 << 2)
-#define COND_HEARDWEAPON (1 << 3)
-#define COND_HEARDVOICE (1 << 4)
-#define COND_CHASETARGETINVALIDATED (1 << 5)
-#define COND_SAWENEMY (1 << 5)
-
-
-forward SF2_OnBossAdded(iBossIndex);
-
-forward SF2_OnBossSpawn(iBossIndex);
-
-forward SF2_OnBossChangeState(iBossIndex, iOldState, iNewState);
-
-forward SF2_OnBossRemoved(iBossIndex);
-
-forward SF2_OnPagesSpawned();
-
-forward SF2_OnClientBlinked(client);
-
-forward SF2_OnClientCaughtByBoss(client, iBossIndex);
-
-forward Action:SF2_OnClientGiveQueuePoints(client, &iAddAmount);
-
-forward SF2_OnClientActivateFlashlight(client);
-
-forward SF2_OnClientDeactivateFlashlight(client);
-
-forward SF2_OnClientBreakFlashlight(client);
-
-forward SF2_OnClientEscape(client);
-
-forward SF2_OnClientLooksAtBoss(client, iBossIndex);
-
-forward SF2_OnClientLooksAwayFromBoss(client, iBossIndex);
-
-forward SF2_OnClientStartDeathCam(client, iBossIndex);
-
-forward SF2_OnClientEndDeathCam(client, iBossIndex);
-
-forward Action:SF2_OnClientGetDefaultWalkSpeed(client, &Float:flDefault);
-
-forward Action:SF2_OnClientGetDefaultSprintSpeed(client, &Float:flDefault);
-
-forward Action:SF2_OnGroupGiveQueuePoints(iGroupIndex, &iAddAmount);
-
-forward SF2_OnClientDamagedByBoss(client, iBossIndex, inflictor, Float:flDamage, iDamageType);
-
-forward SF2_OnClientSpawnedAsProxy(client);
-
-
-/**
- * Returns a bool about the gamemode's state.
- *
- * @return				True if the gamemode is running, false if not.
- */
-native bool:SF2_IsRunning();
-
-/**
- * Returns the current difficulty of the round.
- *
- * @return				Integer of the difficulty.
- */
-native SF2_GetCurrentDifficulty();
-
-/**
- * Returns the current difficulty of the round.
- *
- * @param iDifficulty	Difficulty number.
- * @return				Modifier float value of the indicated difficulty number.
- */
-native Float:SF2_GetDifficultyModifier(iDifficulty);
-
-/**
- * Returns a bool indicating whether or not a special round is currently running.
- *
- * @return				True if a special round is running, false if not.
- */
-native bool:SF2_IsSpecialRoundRunning();
-
-/**
- * Returns the type of special round that is running.
- *
- * @return				Special round type.
- */
-native SF2_GetSpecialRoundType();
-
-/**
- * Returns a bool about the client's elimination state.
- *
- * @param client		Client index.
- * @return				True if the player is eliminated, false if not.
- */
-native bool:SF2_IsClientEliminated(client);
-
-/**
- * Returns a bool about the client's ghost mode state.
- *
- * @param client		Client index.
- * @return				True if the player is in Ghost Mode, false if not.
- */
-native bool:SF2_IsClientInGhostMode(client);
-
-/**
- * Returns a bool if the client is in a Player vs. Player zone or not.
- *
- * @param client		Client index.
- * @return				True if the player is in a PvP zone, false if not.
- */
-native bool:SF2_IsClientInPvP(client);
-
-/**
- * Tells whether if the client is a Proxy or not.
- *
- * @param client		Client index.
- * @return				True if the player is a Proxy, false if not.
- */
-native bool:SF2_IsClientProxy(client);
-
-/**
- * Tells whether or not the client is looking at the boss.
- *
- * @param client		Client index.
- * @param iBossIndex	Boss index.
- * @return				True if the player is a Proxy, false if not.
- */
-native bool:SF2_IsClientLookingAtBoss(client, iBossIndex);
-
-/**
- * Gives the amount of times the client has blinked in one life. This count will reset upon spawn.
- *
- * @param client		Client index.
- * @return				Number of times the client has blinked in one life.
- */
-native SF2_GetClientBlinkCount(client);
-
-/**
- * If the client is a Proxy, then this returns the boss index that the client is associated with.
- *
- * @param client		Client index.
- * @return				If the client is a proxy, then this will return a boss index, -1 if not.
- */
-native SF2_GetClientProxyMaster(client);
-
-/**
- * If the client is a Proxy, then this returns the amount of Control points the client has left.
- *
- * @param client		Client index.
- * @return				If the client is a proxy, then this will return the amount of Control Points out of 100, else 0.
- */
-native SF2_GetClientProxyControlAmount(client);
-
-/**
- * If the client is a Proxy, then this returns the rate which each Control point will drain for the client.
- *
- * @param client		Client index.
- * @return				If the client is a proxy, then this will return a boss index, -1 if not.
- */
-native Float:SF2_GetClientProxyControlRate(client);
-
-native SF2_SetClientProxyMaster(client, iBossIndex);
-
-native SF2_SetClientProxyControlAmount(client, iAmount);
-
-native SF2_SetClientProxyControlRate(client, Float:flAmount);
-
-native SF2_GetMaxBossCount();
-
-native SF2_EntIndexToBossIndex(iEntIndex);
-
-native SF2_BossIndexToEntIndex(iBossIndex);
-
-native SF2_BossIDToBossIndex(iBossID);
-
-native SF2_BossIndexToBossID(iBossID);
-
-native SF2_GetBossName(iBossIndex, String:sBuffer[], iBufferLen);
-
-native SF2_GetBossModelEntity(iBossIndex);
-
-native SF2_GetBossTarget(iBossIndex);
-
-native SF2_GetBossMaster(iBossIndex);
-
-native SF2_GetBossState(iBossIndex);
-
-native bool:SF2_IsBossProfileValid(const String:sProfile[]);
-
-native SF2_GetBossProfileNum(const String:sProfile[], const String:sKey[], iDefaultValue=0);
-
-native Float:SF2_GetBossProfileFloat(const String:sProfile[], const String:sKey[], Float:flDefaultValue=0.0);
-
-native bool:SF2_GetBossProfileString(const String:sProfile[], const String:sKey[], String:sBuffer[], iBufferLen, const String:sDefaultValue[]="");
-
-native bool:SF2_GetBossProfileVector(const String:sProfile[], const String:sKey[], Float:flBuffer[3], const Float:flDefaultValue[3]=NULL_VECTOR);
-
-native bool:SF2_GetRandomStringFromBossProfile(const String:sProfile, const String:sKey[], String:sBuffer[], iBufferLen, iIndex=-1);
-
-public SharedPlugin:__pl_sf2 = 
-{
-	name = "sf2",
-	file = "sf2.smx",
-#if defined REQUIRE_PLUGIN
-	required = 1,
-#else
-	required = 0,
-#endif
+#if defined _sf2_included
+ #endinput
+#endif
+#define _sf2_included
+
+// Some defines.
+#define SF2_MAX_PROFILE_NAME_LENGTH 64
+#define SF2_MAX_NAME_LENGTH 32
+
+#define MAX_BOSSES 32
+#define MAX_NODES -1
+
+// Difficulty modifiers.
+#define DIFFICULTY_EASY 0.75
+#define DIFFICULTY_NORMAL 1.0
+#define DIFFICULTY_HARD 2.0
+#define DIFFICULTY_INSANE 3.5
+
+// Music system flags.
+#define MUSICF_PAGES1PERCENT (1 << 0)
+#define MUSICF_PAGES25PERCENT (1 << 1)
+#define MUSICF_PAGES50PERCENT (1 << 2)
+#define MUSICF_PAGES75PERCENT (1 << 3)
+#define MUSICF_DEATH (1 << 4)
+#define MUSICF_CHASE (1 << 5)
+#define MUSICF_CHASEVISIBLE (1 << 6)
+#define MUSICF_ALERT (1 << 7)
+#define MUSICF_20DOLLARS (1 << 8)
+
+// Special round enumerations.
+enum
+{
+	SPECIALROUND_DOUBLETROUBLE = 1,
+	SPECIALROUND_INSANEDIFFICULTY,
+	SPECIALROUND_SINGLEPLAYER,
+	SPECIALROUND_DOUBLEMAXPLAYERS,
+	SPECIALROUND_LIGHTSOUT,
+	SPECIALROUND_MAXROUNDS
+};
+
+// Boss state enumerations.
+enum
+{
+	STATE_IDLE = 0,
+	STATE_WANDER,
+	STATE_ALERT,
+	STATE_CHASE,
+	STATE_ATTACK,
+	STATE_STUN
+};
+
+enum SoundType
+{
+	SoundType_None = 0,
+	SoundType_Footstep,
+	SoundType_Voice,
+	SoundType_Weapon
+};
+
+enum
+{
+	Difficulty_Easy = 0,
+	Difficulty_Normal,
+	Difficulty_Hard,
+	Difficulty_Insane,
+	Difficulty_Max
+};
+
+enum
+{
+	Static_None = 0,
+	Static_Increase,
+	Static_Decrease
+};
+
+enum
+{
+	SF2BossType_Unknown = -1,
+	SF2BossType_Static = 0,
+	SF2BossType_Creeper,
+	SF2BossType_Chaser,
+	SF2BossType_AdvancedChaser,
+	SF2BossType_MaxTypes
+};
+
+enum SF2RoundState
+{
+	SF2RoundState_Invalid = -1,
+	SF2RoundState_Waiting = 0,		// waiting for players
+	SF2RoundState_Intro,				// if intro is enabled, intro stage for RED
+	SF2RoundState_Active,			// round is running for RED
+	SF2RoundState_Escape,			// escape stage for RED
+	SF2RoundState_Outro				// round win for a team, next round coming soon
+};
+
+// Boss flags.
+#define SFF_SPAWNONCE (1 << 0)
+#define SFF_NOTELEPORT (1 << 1)
+#define SFF_FAKE (1 << 2)
+#define SFF_MARKEDASFAKE (1 << 3)
+#define SFF_ATTACKWAITERS (1 << 4)
+#define SFF_HASSTATICSHAKE (1 << 5)
+#define SFF_STATICONLOOK (1 << 6)
+#define SFF_STATICONRADIUS (1 << 7)
+#define SFF_PROXIES (1 << 8)
+#define SFF_WANDERMOVE (1 << 9)
+#define SFF_HASJUMPSCARE (1 << 10)
+#define SFF_HASSIGHTSOUNDS (1 << 11)
+#define SFF_HASSTATICLOOPLOCALSOUND (1 << 12)
+#define SFF_HASVIEWSHAKE (1 << 13)
+#define SFF_COPIES (1 << 14)
+#define SFF_ATTACKPROPS (1 << 15)
+
+// Interrup conditions.
+#define COND_HEARDSUSPICIOUSSOUND (1 << 0)
+#define COND_HEARDFOOTSTEP (1 << 1)
+#define COND_HEARDFOOTSTEPLOUD (1 << 2)
+#define COND_HEARDWEAPON (1 << 3)
+#define COND_HEARDVOICE (1 << 4)
+#define COND_CHASETARGETINVALIDATED (1 << 5)
+#define COND_SAWENEMY (1 << 5)
+
+
+forward SF2_OnBossAdded(iBossIndex);
+
+forward SF2_OnBossSpawn(iBossIndex);
+
+forward SF2_OnBossChangeState(iBossIndex, iOldState, iNewState);
+
+forward SF2_OnBossRemoved(iBossIndex);
+
+forward SF2_OnPagesSpawned();
+
+forward SF2_OnClientBlinked(client);
+
+forward SF2_OnClientCaughtByBoss(client, iBossIndex);
+
+forward Action:SF2_OnClientGiveQueuePoints(client, &iAddAmount);
+
+forward SF2_OnClientActivateFlashlight(client);
+
+forward SF2_OnClientDeactivateFlashlight(client);
+
+forward SF2_OnClientBreakFlashlight(client);
+
+forward SF2_OnClientEscape(client);
+
+forward SF2_OnClientLooksAtBoss(client, iBossIndex);
+
+forward SF2_OnClientLooksAwayFromBoss(client, iBossIndex);
+
+forward SF2_OnClientStartDeathCam(client, iBossIndex);
+
+forward SF2_OnClientEndDeathCam(client, iBossIndex);
+
+forward Action:SF2_OnClientGetDefaultWalkSpeed(client, &Float:flDefault);
+
+forward Action:SF2_OnClientGetDefaultSprintSpeed(client, &Float:flDefault);
+
+forward Action:SF2_OnGroupGiveQueuePoints(iGroupIndex, &iAddAmount);
+
+forward SF2_OnClientDamagedByBoss(client, iBossIndex, inflictor, Float:flDamage, iDamageType);
+
+forward SF2_OnClientSpawnedAsProxy(client);
+
+
+/**
+ * Returns a bool about the gamemode's state.
+ *
+ * @return				True if the gamemode is running, false if not.
+ */
+native bool:SF2_IsRunning();
+
+/**
+ * Returns the current difficulty of the round.
+ *
+ * @return				Integer of the difficulty.
+ */
+native SF2_GetCurrentDifficulty();
+
+/**
+ * Returns the current difficulty of the round.
+ *
+ * @param iDifficulty	Difficulty number.
+ * @return				Modifier float value of the indicated difficulty number.
+ */
+native Float:SF2_GetDifficultyModifier(iDifficulty);
+
+/**
+ * Returns a bool indicating whether or not a special round is currently running.
+ *
+ * @return				True if a special round is running, false if not.
+ */
+native bool:SF2_IsSpecialRoundRunning();
+
+/**
+ * Returns the type of special round that is running.
+ *
+ * @return				Special round type.
+ */
+native SF2_GetSpecialRoundType();
+
+/**
+ * Returns a bool about the client's elimination state.
+ *
+ * @param client		Client index.
+ * @return				True if the player is eliminated, false if not.
+ */
+native bool:SF2_IsClientEliminated(client);
+
+/**
+ * Returns a bool about the client's ghost mode state.
+ *
+ * @param client		Client index.
+ * @return				True if the player is in Ghost Mode, false if not.
+ */
+native bool:SF2_IsClientInGhostMode(client);
+
+/**
+ * Returns a bool if the client is in a Player vs. Player zone or not.
+ *
+ * @param client		Client index.
+ * @return				True if the player is in a PvP zone, false if not.
+ */
+native bool:SF2_IsClientInPvP(client);
+
+/**
+ * Tells whether if the client is a Proxy or not.
+ *
+ * @param client		Client index.
+ * @return				True if the player is a Proxy, false if not.
+ */
+native bool:SF2_IsClientProxy(client);
+
+/**
+ * Tells whether or not the client is looking at the boss.
+ *
+ * @param client		Client index.
+ * @param iBossIndex	Boss index.
+ * @return				True if the player is a Proxy, false if not.
+ */
+native bool:SF2_IsClientLookingAtBoss(client, iBossIndex);
+
+/**
+ * Gives the amount of times the client has blinked in one life. This count will reset upon spawn.
+ *
+ * @param client		Client index.
+ * @return				Number of times the client has blinked in one life.
+ */
+native SF2_GetClientBlinkCount(client);
+
+/**
+ * If the client is a Proxy, then this returns the boss index that the client is associated with.
+ *
+ * @param client		Client index.
+ * @return				If the client is a proxy, then this will return a boss index, -1 if not.
+ */
+native SF2_GetClientProxyMaster(client);
+
+/**
+ * If the client is a Proxy, then this returns the amount of Control points the client has left.
+ *
+ * @param client		Client index.
+ * @return				If the client is a proxy, then this will return the amount of Control Points out of 100, else 0.
+ */
+native SF2_GetClientProxyControlAmount(client);
+
+/**
+ * If the client is a Proxy, then this returns the rate which each Control point will drain for the client.
+ *
+ * @param client		Client index.
+ * @return				If the client is a proxy, then this will return a boss index, -1 if not.
+ */
+native Float:SF2_GetClientProxyControlRate(client);
+
+native SF2_SetClientProxyMaster(client, iBossIndex);
+
+native SF2_SetClientProxyControlAmount(client, iAmount);
+
+native SF2_SetClientProxyControlRate(client, Float:flAmount);
+
+native SF2_CollectAsPage(pageEnt, client);
+
+native SF2_GetMaxBossCount();
+
+native SF2_EntIndexToBossIndex(iEntIndex);
+
+native SF2_BossIndexToEntIndex(iBossIndex);
+
+native SF2_BossIDToBossIndex(iBossID);
+
+native SF2_BossIndexToBossID(iBossID);
+
+native SF2_GetBossName(iBossIndex, String:sBuffer[], iBufferLen);
+
+native SF2_GetBossModelEntity(iBossIndex);
+
+native SF2_GetBossTarget(iBossIndex);
+
+native SF2_GetBossMaster(iBossIndex);
+
+native SF2_GetBossState(iBossIndex);
+
+native bool:SF2_IsBossProfileValid(const String:sProfile[]);
+
+native SF2_GetBossProfileNum(const String:sProfile[], const String:sKey[], iDefaultValue=0);
+
+native Float:SF2_GetBossProfileFloat(const String:sProfile[], const String:sKey[], Float:flDefaultValue=0.0);
+
+native bool:SF2_GetBossProfileString(const String:sProfile[], const String:sKey[], String:sBuffer[], iBufferLen, const String:sDefaultValue[]="");
+
+native bool:SF2_GetBossProfileVector(const String:sProfile[], const String:sKey[], Float:flBuffer[3], const Float:flDefaultValue[3]=NULL_VECTOR);
+
+native bool:SF2_GetRandomStringFromBossProfile(const String:sProfile, const String:sKey[], String:sBuffer[], iBufferLen, iIndex=-1);
+
+public SharedPlugin:__pl_sf2 = 
+{
+	name = "sf2",
+	file = "sf2.smx",
+#if defined REQUIRE_PLUGIN
+	required = 1,
+#else
+	required = 0,
+#endif
 };
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror.sp b/addons/sourcemod/scripting/rytp_horror.sp
index bbadb42..b26e668 100644
--- a/addons/sourcemod/scripting/rytp_horror.sp
+++ b/addons/sourcemod/scripting/rytp_horror.sp
@@ -1,6517 +1,6376 @@
-#include <sourcemod>
-#include <sdktools>
-#include <sdkhooks>
-#include <clientprefs>
-#include <steamtools>
-#include <tf2items>
-#include <dhooks>
-#include <navmesh>
-
-#include <tf2>
-#include <tf2_stocks>
-#include <morecolors>
-#include <sf2>
-
-#undef REQUIRE_PLUGIN
-#include <adminmenu>
-#tryinclude <store/store-tf2footprints>
-#define REQUIRE_PLUGIN
-
-#define DEBUG
-
-// If compiling with SM 1.7+, uncomment to compile and use SF2 methodmaps.
-//#define METHODMAPS
-
-#define PLUGIN_VERSION "0.2.5-git132"
-#define PLUGIN_VERSION_DISPLAY "0.2.5"
-
-public Plugin:myinfo = 
-{
-    name = "RYTP Horror (Slender Fortress edit by lexuzieel special for Penek-Gaming.Ru)",
-    author	= "KitRifty",
-    description	= "Based on the game Slender: The Eight Pages.",
-    version = PLUGIN_VERSION,
-    url = "http://steamcommunity.com/groups/SlenderFortress"
-}
-
-#define FILE_RESTRICTEDWEAPONS "configs/sf2/restrictedweapons.cfg"
-
-#define BOSS_THINKRATE 0.1 // doesn't really matter much since timers go at a minimum of 0.1 seconds anyways
-
-#define CRIT_SOUND "player/crit_hit.wav"
-#define CRIT_PARTICLENAME "crit_text"
-
-#define PAGE_MODEL "models/rytp/horror/props/hint_paper.mdl"
-#define PAGE_MODELSCALE 1.1
-
-#define FLASHLIGHT_CLICKSOUND "rytp_horror/toggleflashlight.wav"
-#define FLASHLIGHT_BREAKSOUND "ambient/energy/spark6.wav"
-#define FLASHLIGHT_NOSOUND "player/suit_denydevice.wav"
-#define PAGE_GRABSOUND "rytp_horror/grabpage_sound.wav"
-
-#define MUSIC_CHAN SNDCHAN_AUTO
-
-#define MUSIC_GOTPAGES1_SOUND "rytp_horror/grabpage_music_1.wav"
-#define MUSIC_GOTPAGES2_SOUND "rytp_horror/grabpage_music_2.wav"
-#define MUSIC_GOTPAGES3_SOUND "rytp_horror/grabpage_music_3.wav"
-#define MUSIC_GOTPAGES4_SOUND "rytp_horror/grabpage_music_4.wav"
-#define MUSIC_PAGE_VOLUME 1.0
-
-#define SF2_INTRO_DEFAULT_MUSIC "rytp_horror/intro_music.mp3"
-
-#define SF2_HUD_TEXT_COLOR_R 127
-#define SF2_HUD_TEXT_COLOR_G 167
-#define SF2_HUD_TEXT_COLOR_B 141
-#define SF2_HUD_TEXT_COLOR_A 255
-
-enum MuteMode
-{
-	MuteMode_Normal = 0,
-	MuteMode_DontHearOtherTeam,
-	MuteMode_DontHearOtherTeamIfNotProxy
-};
-
-// Offsets.
-new g_offsPlayerFOV = -1;
-new g_offsPlayerDefaultFOV = -1;
-new g_offsPlayerFogCtrl = -1;
-new g_offsPlayerPunchAngle = -1;
-new g_offsPlayerPunchAngleVel = -1;
-new g_offsFogCtrlEnable = -1;
-new g_offsFogCtrlEnd = -1;
-
-new g_iParticleCriticalHit = -1;
-
-new bool:g_bEnabled;
-
-new Handle:g_hConfig;
-new Handle:g_hRestrictedWeaponsConfig;
-new Handle:g_hSpecialRoundsConfig;
-
-new Handle:g_hPageMusicRanges;
-
-new g_iSlenderModel[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-new g_iSlenderPoseEnt[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-new g_iSlenderCopyMaster[MAX_BOSSES] = { -1, ... };
-new Float:g_flSlenderEyePosOffset[MAX_BOSSES][3];
-new Float:g_flSlenderEyeAngOffset[MAX_BOSSES][3];
-new Float:g_flSlenderDetectMins[MAX_BOSSES][3];
-new Float:g_flSlenderDetectMaxs[MAX_BOSSES][3];
-new Handle:g_hSlenderThink[MAX_BOSSES];
-new Handle:g_hSlenderEntityThink[MAX_BOSSES];
-new Handle:g_hSlenderFakeTimer[MAX_BOSSES];
-new Float:g_flSlenderLastKill[MAX_BOSSES];
-new g_iSlenderState[MAX_BOSSES];
-new g_iSlenderTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-new Float:g_flSlenderAcceleration[MAX_BOSSES];
-new Float:g_flSlenderGoalPos[MAX_BOSSES][3];
-new Float:g_flSlenderStaticRadius[MAX_BOSSES];
-new Float:g_flSlenderChaseDeathPosition[MAX_BOSSES][3];
-new bool:g_bSlenderChaseDeathPosition[MAX_BOSSES];
-new Float:g_flSlenderIdleAnimationPlaybackRate[MAX_BOSSES];
-new Float:g_flSlenderWalkAnimationPlaybackRate[MAX_BOSSES];
-new Float:g_flSlenderRunAnimationPlaybackRate[MAX_BOSSES];
-new Float:g_flSlenderJumpSpeed[MAX_BOSSES];
-new Float:g_flSlenderPathNodeTolerance[MAX_BOSSES];
-new Float:g_flSlenderPathNodeLookAhead[MAX_BOSSES];
-new bool:g_bSlenderFeelerReflexAdjustment[MAX_BOSSES];
-new Float:g_flSlenderFeelerReflexAdjustmentPos[MAX_BOSSES][3];
-
-new g_iSlenderTeleportTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-
-new Float:g_flSlenderNextTeleportTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportTargetTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMinRange[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMaxRange[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMaxTargetTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMaxTargetStress[MAX_BOSSES] = { 0.0, ... };
-new Float:g_flSlenderTeleportPlayersRestTime[MAX_BOSSES][MAXPLAYERS + 1];
-
-// For boss type 2
-// General variables
-new g_iSlenderHealth[MAX_BOSSES];
-new Handle:g_hSlenderPath[MAX_BOSSES];
-new g_iSlenderCurrentPathNode[MAX_BOSSES] = { -1, ... };
-new bool:g_bSlenderAttacking[MAX_BOSSES];
-new Handle:g_hSlenderAttackTimer[MAX_BOSSES];
-new Float:g_flSlenderNextJump[MAX_BOSSES] = { -1.0, ... };
-new g_iSlenderInterruptConditions[MAX_BOSSES];
-new Float:g_flSlenderLastFoundPlayer[MAX_BOSSES][MAXPLAYERS + 1];
-new Float:g_flSlenderLastFoundPlayerPos[MAX_BOSSES][MAXPLAYERS + 1][3];
-new Float:g_flSlenderNextPathTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderCalculatedWalkSpeed[MAX_BOSSES];
-new Float:g_flSlenderCalculatedSpeed[MAX_BOSSES];
-new Float:g_flSlenderTimeUntilNoPersistence[MAX_BOSSES];
-
-new Float:g_flSlenderProxyTeleportMinRange[MAX_BOSSES];
-new Float:g_flSlenderProxyTeleportMaxRange[MAX_BOSSES];
-
-// Sound variables
-new Float:g_flSlenderTargetSoundLastTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTargetSoundMasterPos[MAX_BOSSES][3]; // to determine hearing focus
-new Float:g_flSlenderTargetSoundTempPos[MAX_BOSSES][3];
-new Float:g_flSlenderTargetSoundDiscardMasterPosTime[MAX_BOSSES];
-new bool:g_bSlenderInvestigatingSound[MAX_BOSSES];
-new SoundType:g_iSlenderTargetSoundType[MAX_BOSSES] = { SoundType_None, ... };
-new g_iSlenderTargetSoundCount[MAX_BOSSES];
-new Float:g_flSlenderLastHeardVoice[MAX_BOSSES];
-new Float:g_flSlenderLastHeardFootstep[MAX_BOSSES];
-new Float:g_flSlenderLastHeardWeapon[MAX_BOSSES];
-
-
-new Float:g_flSlenderNextJumpScare[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderNextVoiceSound[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderNextMoanSound[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderNextWanderPos[MAX_BOSSES] = { -1.0, ... };
-
-
-new Float:g_flSlenderTimeUntilRecover[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilAlert[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilIdle[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilChase[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilKill[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilNextProxy[MAX_BOSSES] = { -1.0, ... };
-
-// Page data.
-new g_iPageCount;
-new g_iPageMax;
-new Float:g_flPageFoundLastTime;
-new bool:g_bPageRef;
-new String:g_strPageRefModel[PLATFORM_MAX_PATH];
-new Float:g_flPageRefModelScale;
-
-static Handle:g_hPlayerIntroMusicTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Seeing Mr. Slendy data.
-new bool:g_bPlayerSeesSlender[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerSeesSlenderLastTime[MAXPLAYERS + 1][MAX_BOSSES];
-
-new Float:g_flPlayerSightSoundNextTime[MAXPLAYERS + 1][MAX_BOSSES];
-
-new Float:g_flPlayerScareLastTime[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerScareNextTime[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerStaticAmount[MAXPLAYERS + 1];
-
-new Float:g_flPlayerLastChaseBossEncounterTime[MAXPLAYERS + 1][MAX_BOSSES];
-
-// Player static data.
-new g_iPlayerStaticMode[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerStaticIncreaseRate[MAXPLAYERS + 1];
-new Float:g_flPlayerStaticDecreaseRate[MAXPLAYERS + 1];
-new Handle:g_hPlayerStaticTimer[MAXPLAYERS + 1];
-new g_iPlayerStaticMaster[MAXPLAYERS + 1] = { -1, ... };
-new String:g_strPlayerStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new String:g_strPlayerLastStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerLastStaticTime[MAXPLAYERS + 1];
-new Float:g_flPlayerLastStaticVolume[MAXPLAYERS + 1];
-new Handle:g_hPlayerLastStaticTimer[MAXPLAYERS + 1];
-
-// Static shake data.
-new g_iPlayerStaticShakeMaster[MAXPLAYERS + 1];
-new bool:g_bPlayerInStaticShake[MAXPLAYERS + 1];
-new String:g_strPlayerStaticShakeSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerStaticShakeMinVolume[MAXPLAYERS + 1];
-new Float:g_flPlayerStaticShakeMaxVolume[MAXPLAYERS + 1];
-
-// Fake lag compensation for FF.
-new bool:g_bPlayerLagCompensation[MAXPLAYERS + 1];
-new g_iPlayerLagCompensationTeam[MAXPLAYERS + 1];
-
-// Hint data.
-enum
-{
-	PlayerHint_Sprint = 0,
-	PlayerHint_Flashlight,
-	PlayerHint_MainMenu,
-	PlayerHint_Blink,
-	PlayerHint_MaxNum
-};
-
-enum PlayerPreferences
-{
-	bool:PlayerPreference_PvPAutoSpawn,
-	MuteMode:PlayerPreference_MuteMode,
-	bool:PlayerPreference_ShowHints,
-	bool:PlayerPreference_EnableProxySelection,
-	bool:PlayerPreference_ProjectedFlashlight
-};
-
-new bool:g_bPlayerHints[MAXPLAYERS + 1][PlayerHint_MaxNum];
-new g_iPlayerPreferences[MAXPLAYERS + 1][PlayerPreferences];
-
-// Player data.
-new g_iPlayerLastButtons[MAXPLAYERS + 1];
-new bool:g_bPlayerChoseTeam[MAXPLAYERS + 1];
-new bool:g_bPlayerEliminated[MAXPLAYERS + 1];
-new bool:g_bPlayerEscaped[MAXPLAYERS + 1];
-new g_iPlayerPageCount[MAXPLAYERS + 1];
-new g_iPlayerQueuePoints[MAXPLAYERS + 1];
-new bool:g_bPlayerPlaying[MAXPLAYERS + 1];
-new Handle:g_hPlayerOverlayCheck[MAXPLAYERS + 1];
-
-new Handle:g_hPlayerSwitchBlueTimer[MAXPLAYERS + 1];
-
-// Player stress data.
-new Float:g_flPlayerStress[MAXPLAYERS + 1];
-new Float:g_flPlayerStressNextUpdateTime[MAXPLAYERS + 1];
-
-// Proxy data.
-new bool:g_bPlayerProxy[MAXPLAYERS + 1];
-new bool:g_bPlayerProxyAvailable[MAXPLAYERS + 1];
-new Handle:g_hPlayerProxyAvailableTimer[MAXPLAYERS + 1];
-new bool:g_bPlayerProxyAvailableInForce[MAXPLAYERS + 1];
-new g_iPlayerProxyAvailableCount[MAXPLAYERS + 1];
-new g_iPlayerProxyMaster[MAXPLAYERS + 1];
-new g_iPlayerProxyControl[MAXPLAYERS + 1];
-new Handle:g_hPlayerProxyControlTimer[MAXPLAYERS + 1];
-new Float:g_flPlayerProxyControlRate[MAXPLAYERS + 1];
-new Handle:g_flPlayerProxyVoiceTimer[MAXPLAYERS + 1];
-new g_iPlayerProxyAskMaster[MAXPLAYERS + 1] = { -1, ... };
-new Float:g_iPlayerProxyAskPosition[MAXPLAYERS + 1][3];
-
-new g_iPlayerDesiredFOV[MAXPLAYERS + 1];
-
-new Handle:g_hPlayerPostWeaponsTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Music system.
-new g_iPlayerMusicFlags[MAXPLAYERS + 1];
-new String:g_strPlayerMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerMusicVolume[MAXPLAYERS + 1];
-new Float:g_flPlayerMusicTargetVolume[MAXPLAYERS + 1];
-new Handle:g_hPlayerMusicTimer[MAXPLAYERS + 1];
-new g_iPlayerPageMusicMaster[MAXPLAYERS + 1];
-
-// Chase music system, which apparently also uses the alert song system. And the idle sound system.
-new String:g_strPlayerChaseMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new String:g_strPlayerChaseMusicSee[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerChaseMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerChaseMusicSeeVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayerChaseMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayerChaseMusicSeeTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new g_iPlayerChaseMusicMaster[MAXPLAYERS + 1] = { -1, ... };
-new g_iPlayerChaseMusicSeeMaster[MAXPLAYERS + 1] = { -1, ... };
-
-new String:g_strPlayerAlertMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerAlertMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayerAlertMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new g_iPlayerAlertMusicMaster[MAXPLAYERS + 1] = { -1, ... };
-
-new String:g_strPlayer20DollarsMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayer20DollarsMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayer20DollarsMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new g_iPlayer20DollarsMusicMaster[MAXPLAYERS + 1] = { -1, ... };
-
-// Player overlay data
-new Handle:g_hOverlayUpdateTimer[MAXPLAYERS + 1];
-
-
-new SF2RoundState:g_iRoundState = SF2RoundState_Invalid;
-new bool:g_bRoundGrace = false;
-new Float:g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
-new bool:g_bRoundInfiniteFlashlight = false;
-new bool:g_bRoundInfiniteBlink = false;
-new bool:g_bRoundInfiniteSprint = false;
-
-static Handle:g_hRoundGraceTimer = INVALID_HANDLE;
-static Handle:g_hRoundTimer = INVALID_HANDLE;
-static Handle:g_hVoteTimer = INVALID_HANDLE;
-static String:g_strRoundBossProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-
-static g_iRoundCount = 0;
-static g_iRoundEndCount = 0;
-static g_iRoundActiveCount = 0;
-static g_iRoundTime = 0;
-static g_iRoundTimeLimit = 0;
-static g_iRoundEscapeTimeLimit = 0;
-static g_iRoundTimeGainFromPage = 0;
-static bool:g_bRoundHasEscapeObjective = false;
-
-static g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
-
-static g_iRoundIntroFadeColor[4] = { 255, ... };
-static Float:g_flRoundIntroFadeHoldTime;
-static Float:g_flRoundIntroFadeDuration;
-static Handle:g_hRoundIntroTimer = INVALID_HANDLE;
-static bool:g_bRoundIntroTextDefault = true;
-static Handle:g_hRoundIntroTextTimer = INVALID_HANDLE;
-static g_iRoundIntroText;
-static String:g_strRoundIntroMusic[PLATFORM_MAX_PATH] = "";
-
-static g_iRoundWarmupRoundCount = 0;
-
-static bool:g_bRoundWaitingForPlayers = false;
-
-// Special round variables.
-new bool:g_bSpecialRound = false;
-new g_iSpecialRoundType = 0;
-new bool:g_bSpecialRoundNew = false;
-new bool:g_bSpecialRoundContinuous = false;
-new g_iSpecialRoundCount = 1;
-new bool:g_bPlayerPlayedSpecialRound[MAXPLAYERS + 1] = { true, ... };
-
-// New boss round variables.
-static bool:g_bNewBossRound = false;
-static bool:g_bNewBossRoundNew = false;
-static bool:g_bNewBossRoundContinuous = false;
-static g_iNewBossRoundCount = 1;
-static bool:g_bPlayerPlayedNewBossRound[MAXPLAYERS + 1] = { true, ... };
-static String:g_strNewBossRoundProfile[64] = "";
-
-static Handle:g_hRoundMessagesTimer = INVALID_HANDLE;
-static g_iRoundMessagesNum = 0;
-
-static Handle:g_hBossCountUpdateTimer = INVALID_HANDLE;
-static Handle:g_hClientAverageUpdateTimer = INVALID_HANDLE;
-
-// Server variables.
-new Handle:g_cvVersion;
-new Handle:g_cvEnabled;
-new Handle:g_cvSlenderMapsOnly;
-new Handle:g_cvPlayerViewbobEnabled;
-new Handle:g_cvPlayerShakeEnabled;
-new Handle:g_cvPlayerShakeFrequencyMax;
-new Handle:g_cvPlayerShakeAmplitudeMax;
-new Handle:g_cvGraceTime;
-new Handle:g_cvAllChat;
-new Handle:g_cv20Dollars;
-new Handle:g_cvMaxPlayers;
-new Handle:g_cvMaxPlayersOverride;
-new Handle:g_cvCampingEnabled;
-new Handle:g_cvCampingMaxStrikes;
-new Handle:g_cvCampingStrikesWarn;
-new Handle:g_cvCampingMinDistance;
-new Handle:g_cvCampingNoStrikeSanity;
-new Handle:g_cvCampingNoStrikeBossDistance;
-new Handle:g_cvDifficulty;
-new Handle:g_cvBossMain;
-new Handle:g_cvBossProfileOverride;
-new Handle:g_cvPlayerBlinkRate;
-new Handle:g_cvPlayerBlinkHoldTime;
-new Handle:g_cvSpecialRoundBehavior;
-new Handle:g_cvSpecialRoundForce;
-new Handle:g_cvSpecialRoundOverride;
-new Handle:g_cvSpecialRoundInterval;
-new Handle:g_cvNewBossRoundBehavior;
-new Handle:g_cvNewBossRoundInterval;
-new Handle:g_cvNewBossRoundForce;
-new Handle:g_cvPlayerVoiceDistance;
-new Handle:g_cvPlayerVoiceWallScale;
-new Handle:g_cvUltravisionEnabled;
-new Handle:g_cvUltravisionRadiusRed;
-new Handle:g_cvUltravisionRadiusBlue;
-new Handle:g_cvUltravisionBrightness;
-new Handle:g_cvGhostModeConnectionCheck;
-new Handle:g_cvGhostModeConnectionTolerance;
-new Handle:g_cvIntroEnabled;
-new Handle:g_cvIntroDefaultHoldTime;
-new Handle:g_cvIntroDefaultFadeTime;
-new Handle:g_cvTimeLimit;
-new Handle:g_cvTimeLimitEscape;
-new Handle:g_cvTimeGainFromPageGrab;
-new Handle:g_cvWarmupRound;
-new Handle:g_cvWarmupRoundNum;
-new Handle:g_cvPlayerViewbobHurtEnabled;
-new Handle:g_cvPlayerViewbobSprintEnabled;
-new Handle:g_cvPlayerFakeLagCompensation;
-new Handle:g_cvPlayerProxyWaitTime;
-new Handle:g_cvPlayerProxyAsk;
-new Handle:g_cvHalfZatoichiHealthGain;
-new Handle:g_cvBlockSuicideDuringRound;
-
-new Handle:g_cvPlayerInfiniteSprintOverride;
-new Handle:g_cvPlayerInfiniteFlashlightOverride;
-new Handle:g_cvPlayerInfiniteBlinkOverride;
-
-new Handle:g_cvGravity;
-new Float:g_flGravity;
-
-new Handle:g_cvMaxRounds;
-
-new bool:g_b20Dollars;
-
-new bool:g_bPlayerShakeEnabled;
-new bool:g_bPlayerViewbobEnabled;
-new bool:g_bPlayerViewbobHurtEnabled;
-new bool:g_bPlayerViewbobSprintEnabled;
-
-new Handle:g_hHudSync;
-new Handle:g_hHudSync2;
-new Handle:g_hRoundTimerSync;
-
-new Handle:g_hCookie;
-
-// Global forwards.
-new Handle:fOnBossAdded;
-new Handle:fOnBossSpawn;
-new Handle:fOnBossChangeState;
-new Handle:fOnBossRemoved;
-new Handle:fOnPagesSpawned;
-new Handle:fOnClientBlink;
-new Handle:fOnClientCaughtByBoss;
-new Handle:fOnClientGiveQueuePoints;
-new Handle:fOnClientActivateFlashlight;
-new Handle:fOnClientDeactivateFlashlight;
-new Handle:fOnClientBreakFlashlight;
-new Handle:fOnClientEscape;
-new Handle:fOnClientLooksAtBoss;
-new Handle:fOnClientLooksAwayFromBoss;
-new Handle:fOnClientStartDeathCam;
-new Handle:fOnClientEndDeathCam;
-new Handle:fOnClientGetDefaultWalkSpeed;
-new Handle:fOnClientGetDefaultSprintSpeed;
-new Handle:fOnClientSpawnedAsProxy;
-new Handle:fOnClientDamagedByBoss;
-new Handle:fOnGroupGiveQueuePoints;
-
-new Handle:g_hSDKWeaponScattergun;
-new Handle:g_hSDKWeaponPistolScout;
-new Handle:g_hSDKWeaponBat;
-new Handle:g_hSDKWeaponSniperRifle;
-new Handle:g_hSDKWeaponSMG;
-new Handle:g_hSDKWeaponKukri;
-new Handle:g_hSDKWeaponRocketLauncher;
-new Handle:g_hSDKWeaponShotgunSoldier;
-new Handle:g_hSDKWeaponShovel;
-new Handle:g_hSDKWeaponGrenadeLauncher;
-new Handle:g_hSDKWeaponStickyLauncher;
-new Handle:g_hSDKWeaponBottle;
-new Handle:g_hSDKWeaponMinigun;
-new Handle:g_hSDKWeaponShotgunHeavy;
-new Handle:g_hSDKWeaponFists;
-new Handle:g_hSDKWeaponSyringeGun;
-new Handle:g_hSDKWeaponMedigun;
-new Handle:g_hSDKWeaponBonesaw;
-new Handle:g_hSDKWeaponFlamethrower;
-new Handle:g_hSDKWeaponShotgunPyro;
-new Handle:g_hSDKWeaponFireaxe;
-new Handle:g_hSDKWeaponRevolver;
-new Handle:g_hSDKWeaponKnife;
-new Handle:g_hSDKWeaponInvis;
-new Handle:g_hSDKWeaponShotgunPrimary;
-new Handle:g_hSDKWeaponPistol;
-new Handle:g_hSDKWeaponWrench;
-
-new Handle:g_hSDKGetMaxHealth;
-new Handle:g_hSDKWantsLagCompensationOnEntity;
-new Handle:g_hSDKShouldTransmit;
-
-#include "rytp_horror/stocks.sp"
-#include "rytp_horror/overlay.sp"
-#include "rytp_horror/logging.sp"
-#include "rytp_horror/debug.sp"
-#include "rytp_horror/profiles.sp"
-#include "rytp_horror/nav.sp"
-#include "rytp_horror/effects.sp"
-#include "rytp_horror/playergroups.sp"
-#include "rytp_horror/menus.sp"
-#include "rytp_horror/pvp.sp"
-#include "rytp_horror/client.sp"
-#include "rytp_horror/npc.sp"
-#include "rytp_horror/specialround.sp"
-#include "rytp_horror/adminmenu.sp"
-
-
-#define SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND "ui/item_acquired.wav"
-
-//	==========================================================
-//	GENERAL PLUGIN HOOK FUNCTIONS
-//	==========================================================
-
-public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
-{
-	RegPluginLibrary("sf2");
-	
-	fOnBossAdded = CreateGlobalForward("SF2_OnBossAdded", ET_Ignore, Param_Cell);
-	fOnBossSpawn = CreateGlobalForward("SF2_OnBossSpawn", ET_Ignore, Param_Cell);
-	fOnBossChangeState = CreateGlobalForward("SF2_OnBossChangeState", ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
-	fOnBossRemoved = CreateGlobalForward("SF2_OnBossRemoved", ET_Ignore, Param_Cell);
-	fOnPagesSpawned = CreateGlobalForward("SF2_OnPagesSpawned", ET_Ignore);
-	fOnClientBlink = CreateGlobalForward("SF2_OnClientBlink", ET_Ignore, Param_Cell);
-	fOnClientCaughtByBoss = CreateGlobalForward("SF2_OnClientCaughtByBoss", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientGiveQueuePoints = CreateGlobalForward("SF2_OnClientGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
-	fOnClientActivateFlashlight = CreateGlobalForward("SF2_OnClientActivateFlashlight", ET_Ignore, Param_Cell);
-	fOnClientDeactivateFlashlight = CreateGlobalForward("SF2_OnClientDeactivateFlashlight", ET_Ignore, Param_Cell);
-	fOnClientBreakFlashlight = CreateGlobalForward("SF2_OnClientBreakFlashlight", ET_Ignore, Param_Cell);
-	fOnClientEscape = CreateGlobalForward("SF2_OnClientEscape", ET_Ignore, Param_Cell);
-	fOnClientLooksAtBoss = CreateGlobalForward("SF2_OnClientLooksAtBoss", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientLooksAwayFromBoss = CreateGlobalForward("SF2_OnClientLooksAwayFromBoss", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientStartDeathCam = CreateGlobalForward("SF2_OnClientStartDeathCam", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientEndDeathCam = CreateGlobalForward("SF2_OnClientEndDeathCam", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientGetDefaultWalkSpeed = CreateGlobalForward("SF2_OnClientGetDefaultWalkSpeed", ET_Hook, Param_Cell, Param_CellByRef);
-	fOnClientGetDefaultSprintSpeed = CreateGlobalForward("SF2_OnClientGetDefaultSprintSpeed", ET_Hook, Param_Cell, Param_CellByRef);
-	fOnClientSpawnedAsProxy = CreateGlobalForward("SF2_OnClientSpawnedAsProxy", ET_Ignore, Param_Cell);
-	fOnClientDamagedByBoss = CreateGlobalForward("SF2_OnClientDamagedByBoss", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell);
-	fOnGroupGiveQueuePoints = CreateGlobalForward("SF2_OnGroupGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
-	
-	CreateNative("SF2_IsRunning", Native_IsRunning);
-	CreateNative("SF2_GetCurrentDifficulty", Native_GetCurrentDifficulty);
-	CreateNative("SF2_GetDifficultyModifier", Native_GetDifficultyModifier);
-	CreateNative("SF2_IsClientEliminated", Native_IsClientEliminated);
-	CreateNative("SF2_IsClientInGhostMode", Native_IsClientInGhostMode);
-	CreateNative("SF2_IsClientProxy", Native_IsClientProxy);
-	CreateNative("SF2_GetClientBlinkCount", Native_GetClientBlinkCount);
-	CreateNative("SF2_GetClientProxyMaster", Native_GetClientProxyMaster);
-	CreateNative("SF2_GetClientProxyControlAmount", Native_GetClientProxyControlAmount);
-	CreateNative("SF2_GetClientProxyControlRate", Native_GetClientProxyControlRate);
-	CreateNative("SF2_SetClientProxyMaster", Native_SetClientProxyMaster);
-	CreateNative("SF2_SetClientProxyControlAmount", Native_SetClientProxyControlAmount);
-	CreateNative("SF2_SetClientProxyControlRate", Native_SetClientProxyControlRate);
-	CreateNative("SF2_IsClientLookingAtBoss", Native_IsClientLookingAtBoss);
-	CreateNative("SF2_GetMaxBossCount", Native_GetMaxBosses);
-	CreateNative("SF2_EntIndexToBossIndex", Native_EntIndexToBossIndex);
-	CreateNative("SF2_BossIndexToEntIndex", Native_BossIndexToEntIndex);
-	CreateNative("SF2_BossIDToBossIndex", Native_BossIDToBossIndex);
-	CreateNative("SF2_BossIndexToBossID", Native_BossIndexToBossID);
-	CreateNative("SF2_GetBossName", Native_GetBossName);
-	CreateNative("SF2_GetBossModelEntity", Native_GetBossModelEntity);
-	CreateNative("SF2_GetBossTarget", Native_GetBossTarget);
-	CreateNative("SF2_GetBossMaster", Native_GetBossMaster);
-	CreateNative("SF2_GetBossState", Native_GetBossState);
-	CreateNative("SF2_IsBossProfileValid", Native_IsBossProfileValid);
-	CreateNative("SF2_GetBossProfileNum", Native_GetBossProfileNum);
-	CreateNative("SF2_GetBossProfileFloat", Native_GetBossProfileFloat);
-	CreateNative("SF2_GetBossProfileString", Native_GetBossProfileString);
-	CreateNative("SF2_GetBossProfileVector", Native_GetBossProfileVector);
-	CreateNative("SF2_GetRandomStringFromBossProfile", Native_GetRandomStringFromBossProfile);
-	
-	PvP_InitializeAPI();
-	
-	SpecialRoundInitializeAPI();
-	
-	return APLRes_Success;
-}
-
-public OnPluginStart()
-{
-	LoadTranslations("core.phrases");
-	LoadTranslations("common.phrases");
-	LoadTranslations("sf2.phrases");
-	
-	// Get offsets.
-	g_offsPlayerFOV = FindSendPropInfo("CBasePlayer", "m_iFOV");
-	if (g_offsPlayerFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iFOV.");
-	
-	g_offsPlayerDefaultFOV = FindSendPropInfo("CBasePlayer", "m_iDefaultFOV");
-	if (g_offsPlayerDefaultFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iDefaultFOV.");
-	
-	g_offsPlayerFogCtrl = FindSendPropInfo("CBasePlayer", "m_PlayerFog.m_hCtrl");
-	if (g_offsPlayerFogCtrl == -1) LogError("Couldn't find CBasePlayer offset for m_PlayerFog.m_hCtrl!");
-	
-	g_offsPlayerPunchAngle = FindSendPropInfo("CBasePlayer", "m_vecPunchAngle");
-	if (g_offsPlayerPunchAngle == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngle!");
-	
-	g_offsPlayerPunchAngleVel = FindSendPropInfo("CBasePlayer", "m_vecPunchAngleVel");
-	if (g_offsPlayerPunchAngleVel == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngleVel!");
-	
-	g_offsFogCtrlEnable = FindSendPropInfo("CFogController", "m_fog.enable");
-	if (g_offsFogCtrlEnable == -1) LogError("Couldn't find CFogController offset for m_fog.enable!");
-	
-	g_offsFogCtrlEnd = FindSendPropInfo("CFogController", "m_fog.end");
-	if (g_offsFogCtrlEnd == -1) LogError("Couldn't find CFogController offset for m_fog.end!");
-	
-	g_hPageMusicRanges = CreateArray(3);
-	
-	// Register console variables.
-	g_cvVersion = CreateConVar("sf2_version", PLUGIN_VERSION, "The current version of Slender Fortress. DO NOT TOUCH!", FCVAR_SPONLY | FCVAR_NOTIFY | FCVAR_DONTRECORD);
-	SetConVarString(g_cvVersion, PLUGIN_VERSION);
-	
-	g_cvEnabled = CreateConVar("sf2_enabled", "1", "Enable/Disable the Slender Fortress gamemode. This will take effect on map change.", FCVAR_NOTIFY | FCVAR_DONTRECORD);
-	g_cvSlenderMapsOnly = CreateConVar("sf2_slendermapsonly", "1", "Only enable the Slender Fortress gamemode on map names prefixed with \"slender_\" or \"sf2_\".");
-	
-	g_cvGraceTime = CreateConVar("sf2_gracetime", "30.0");
-	g_cvIntroEnabled = CreateConVar("sf2_intro_enabled", "1");
-	g_cvIntroDefaultHoldTime = CreateConVar("sf2_intro_default_hold_time", "9.0");
-	g_cvIntroDefaultFadeTime = CreateConVar("sf2_intro_default_fade_time", "1.0");
-	
-	g_cvBlockSuicideDuringRound = CreateConVar("sf2_block_suicide_during_round", "0");
-	
-	g_cvAllChat = CreateConVar("sf2_alltalk", "0");
-	HookConVarChange(g_cvAllChat, OnConVarChanged);
-	
-	g_cvPlayerVoiceDistance = CreateConVar("sf2_player_voice_distance", "800.0", "The maximum distance RED can communicate in voice chat. Set to 0 if you want them to be heard at all times.", _, true, 0.0);
-	g_cvPlayerVoiceWallScale = CreateConVar("sf2_player_voice_scale_blocked", "0.5", "The distance required to hear RED in voice chat will be multiplied by this amount if something is blocking them.");
-	
-	g_cvPlayerViewbobEnabled = CreateConVar("sf2_player_viewbob_enabled", "1", "Enable/Disable player viewbobbing.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerViewbobEnabled, OnConVarChanged);
-	g_cvPlayerViewbobHurtEnabled = CreateConVar("sf2_player_viewbob_hurt_enabled", "0", "Enable/Disable player view tilting when hurt.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerViewbobHurtEnabled, OnConVarChanged);
-	g_cvPlayerViewbobSprintEnabled = CreateConVar("sf2_player_viewbob_sprint_enabled", "0", "Enable/Disable player step viewbobbing when sprinting.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerViewbobSprintEnabled, OnConVarChanged);
-	g_cvGravity = FindConVar("sv_gravity");
-	HookConVarChange(g_cvGravity, OnConVarChanged);
-	
-	g_cvPlayerFakeLagCompensation = CreateConVar("sf2_player_fakelagcompensation", "0", "(EXPERIMENTAL) Enable/Disable fake lag compensation for some hitscan weapons such as the Sniper Rifle.", _, true, 0.0, true, 1.0);
-	
-	g_cvPlayerShakeEnabled = CreateConVar("sf2_player_shake_enabled", "1", "Enable/Disable player view shake during boss encounters.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerShakeEnabled, OnConVarChanged);
-	g_cvPlayerShakeFrequencyMax = CreateConVar("sf2_player_shake_frequency_max", "255", "Maximum frequency value of the shake. Should be a value between 1-255.", _, true, 1.0, true, 255.0);
-	g_cvPlayerShakeAmplitudeMax = CreateConVar("sf2_player_shake_amplitude_max", "5", "Maximum amplitude value of the shake. Should be a value between 1-16.", _, true, 1.0, true, 16.0);
-	
-	g_cvPlayerBlinkRate = CreateConVar("sf2_player_blink_rate", "0.33", "How long (in seconds) each bar on the player's Blink meter lasts.", _, true, 0.0);
-	g_cvPlayerBlinkHoldTime = CreateConVar("sf2_player_blink_holdtime", "0.15", "How long (in seconds) a player will stay in Blink mode when he or she blinks.", _, true, 0.0);
-	
-	g_cvUltravisionEnabled = CreateConVar("sf2_player_ultravision_enabled", "1", "Enable/Disable player Ultravision. This helps players see in the dark when their Flashlight is off or unavailable.", _, true, 0.0, true, 1.0);
-	g_cvUltravisionRadiusRed = CreateConVar("sf2_player_ultravision_radius_red", "512.0");
-	g_cvUltravisionRadiusBlue = CreateConVar("sf2_player_ultravision_radius_blue", "800.0");
-	g_cvUltravisionBrightness = CreateConVar("sf2_player_ultravision_brightness", "-4");
-	
-	g_cvGhostModeConnectionCheck = CreateConVar("sf2_ghostmode_check_connection", "1", "Checks a player's connection while in Ghost Mode. If the check fails, the client is booted out of Ghost Mode and the action and client's SteamID is logged in the main SF2 log.");
-	g_cvGhostModeConnectionTolerance = CreateConVar("sf2_ghostmode_connection_tolerance", "2.5", "If sf2_ghostmode_check_connection is set to 1 and the client has timed out for at least this amount of time, the client will be booted out of Ghost Mode.");
-	
-	g_cv20Dollars = CreateConVar("sf2_20dollarmode", "0", "Enable/Disable $20 mode.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cv20Dollars, OnConVarChanged);
-	
-	g_cvMaxPlayers = CreateConVar("sf2_maxplayers", "5", "The maximum amount of players that can be in one round.", _, true, 1.0);
-	HookConVarChange(g_cvMaxPlayers, OnConVarChanged);
-	
-	g_cvMaxPlayersOverride = CreateConVar("sf2_maxplayers_override", "-1", "Overrides the maximum amount of players that can be in one round.", _, true, -1.0);
-	HookConVarChange(g_cvMaxPlayersOverride, OnConVarChanged);
-	
-	g_cvCampingEnabled = CreateConVar("sf2_anticamping_enabled", "1", "Enable/Disable anti-camping system for RED.", _, true, 0.0, true, 1.0);
-	g_cvCampingMaxStrikes = CreateConVar("sf2_anticamping_maxstrikes", "4", "How many 5-second intervals players are allowed to stay in one spot before he/she is forced to suicide.", _, true, 0.0);
-	g_cvCampingStrikesWarn = CreateConVar("sf2_anticamping_strikeswarn", "2", "The amount of strikes left where the player will be warned of camping.");
-	g_cvCampingMinDistance = CreateConVar("sf2_anticamping_mindistance", "128.0", "Every 5 seconds the player has to be at least this far away from his last position 5 seconds ago or else he'll get a strike.");
-	g_cvCampingNoStrikeSanity = CreateConVar("sf2_anticamping_no_strike_sanity", "0.1", "The camping system will NOT give any strikes under any circumstances if the players's Sanity is missing at least this much of his maximum Sanity (max is 1.0).");
-	g_cvCampingNoStrikeBossDistance = CreateConVar("sf2_anticamping_no_strike_boss_distance", "512.0", "The camping system will NOT give any strikes under any circumstances if the player is this close to a boss (ignoring LOS).");
-	g_cvBossMain = CreateConVar("sf2_boss_main", "slenderman", "The name of the main boss (its profile name, not its display name)");
-	g_cvBossProfileOverride = CreateConVar("sf2_boss_profile_override", "", "Overrides which boss will be chosen next. Only applies to the first boss being chosen.");
-	g_cvDifficulty = CreateConVar("sf2_difficulty", "1", "Difficulty of the game. 1 = Normal, 2 = Hard, 3 = Insane.", _, true, 1.0, true, 3.0);
-	HookConVarChange(g_cvDifficulty, OnConVarChanged);
-	
-	g_cvSpecialRoundBehavior = CreateConVar("sf2_specialround_mode", "0", "0 = Special Round resets on next round, 1 = Special Round keeps going until all players have played (not counting spectators, recently joined players, and those who reset their queue points during the round)", _, true, 0.0, true, 1.0);
-	g_cvSpecialRoundForce = CreateConVar("sf2_specialround_forceenable", "-1", "Sets whether a Special Round will occur on the next round or not.", _, true, -1.0, true, 1.0);
-	g_cvSpecialRoundOverride = CreateConVar("sf2_specialround_forcetype", "-1", "Sets the type of Special Round that will be chosen on the next Special Round. Set to -1 to let the game choose.", _, true, -1.0);
-	g_cvSpecialRoundInterval = CreateConVar("sf2_specialround_interval", "5", "If this many rounds are completed, the next round will be a Special Round.", _, true, 0.0);
-	
-	g_cvNewBossRoundBehavior = CreateConVar("sf2_newbossround_mode", "0", "0 = boss selection will return to normal after the boss round, 1 = the new boss will continue being the boss until all players in the server have played against it (not counting spectators, recently joined players, and those who reset their queue points during the round).", _, true, 0.0, true, 1.0);
-	g_cvNewBossRoundInterval = CreateConVar("sf2_newbossround_interval", "3", "If this many rounds are completed, the next round's boss will be randomly chosen, but will not be the main boss.", _, true, 0.0);
-	g_cvNewBossRoundForce = CreateConVar("sf2_newbossround_forceenable", "-1", "Sets whether a new boss will be chosen on the next round or not. Set to -1 to let the game choose.", _, true, -1.0, true, 1.0);
-	
-	g_cvTimeLimit = CreateConVar("sf2_timelimit_default", "300", "The time limit of the round. Maps can change the time limit.", _, true, 0.0);
-	g_cvTimeLimitEscape = CreateConVar("sf2_timelimit_escape_default", "90", "The time limit to escape. Maps can change the time limit.", _, true, 0.0);
-	g_cvTimeGainFromPageGrab = CreateConVar("sf2_time_gain_page_grab", "12", "The time gained from grabbing a page. Maps can change the time gain amount.");
-	
-	g_cvWarmupRound = CreateConVar("sf2_warmupround", "1", "Enables/disables Warmup Rounds after the \"Waiting for Players\" phase.", _, true, 0.0, true, 1.0);
-	g_cvWarmupRoundNum = CreateConVar("sf2_warmupround_num", "1", "Sets the amount of Warmup Rounds that occur after the \"Waiting for Players\" phase.", _, true, 0.0);
-	
-	g_cvPlayerProxyWaitTime = CreateConVar("sf2_player_proxy_waittime", "35", "How long (in seconds) after a player was chosen to be a Proxy must the system wait before choosing him again.");
-	g_cvPlayerProxyAsk = CreateConVar("sf2_player_proxy_ask", "0", "Set to 1 if the player can choose before becoming a Proxy, set to 0 to force.");
-	
-	g_cvHalfZatoichiHealthGain = CreateConVar("sf2_halfzatoichi_healthgain", "20", "How much health should be gained from killing a player with the Half-Zatoichi? Set to -1 for default behavior.");
-	
-	g_cvPlayerInfiniteSprintOverride = CreateConVar("sf2_player_infinite_sprint_override", "-1", "1 = infinite sprint, 0 = never have infinite sprint, -1 = let the game choose.", _, true, -1.0, true, 1.0);
-	g_cvPlayerInfiniteFlashlightOverride = CreateConVar("sf2_player_infinite_flashlight_override", "-1", "1 = infinite flashlight, 0 = never have infinite flashlight, -1 = let the game choose.", _, true, -1.0, true, 1.0);
-	g_cvPlayerInfiniteBlinkOverride = CreateConVar("sf2_player_infinite_blink_override", "-1", "1 = infinite blink, 0 = never have infinite blink, -1 = let the game choose.", _, true, -1.0, true, 1.0);
-	
-	g_cvMaxRounds = FindConVar("mp_maxrounds");
-	
-	g_hHudSync = CreateHudSynchronizer();
-	g_hHudSync2 = CreateHudSynchronizer();
-	g_hRoundTimerSync = CreateHudSynchronizer();
-	g_hCookie = RegClientCookie("slender_cookie", "", CookieAccess_Private);
-	
-	// Register console commands.
-	RegConsoleCmd("sm_sf2", Command_MainMenu);
-	RegConsoleCmd("sm_slender", Command_MainMenu);
-	RegConsoleCmd("sm_horror", Command_MainMenu);
-	RegConsoleCmd("sm_slnext", Command_Next);
-	RegConsoleCmd("sm_slgroup", Command_Group);
-	RegConsoleCmd("sm_slgroupname", Command_GroupName);
-	RegConsoleCmd("sm_slghost", Command_GhostMode);
-	RegConsoleCmd("sm_slhelp", Command_Help);
-	RegConsoleCmd("sm_slsettings", Command_Settings);
-	RegConsoleCmd("sm_slcredits", Command_Credits);
-	RegConsoleCmd("sm_flashlight", Command_ToggleFlashlight);
-	RegConsoleCmd("+sprint", Command_SprintOn);
-	RegConsoleCmd("-sprint", Command_SprintOff);
-	
-	RegAdminCmd("sm_sf2_scare", Command_ClientPerformScare, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_spawn_boss", Command_SpawnSlender, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_add_boss", Command_AddSlender, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_add_boss_fake", Command_AddSlenderFake, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_remove_boss", Command_RemoveSlender, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_getbossindexes", Command_GetBossIndexes, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_setplaystate", Command_ForceState, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_boss_attack_waiters", Command_SlenderAttackWaiters, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_boss_no_teleport", Command_SlenderNoTeleport, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_force_proxy", Command_ForceProxy, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_force_escape", Command_ForceEscape, ADMFLAG_CHEATS);
-	
-	// Hook onto existing console commands.
-	AddCommandListener(Hook_CommandBuild, "build");
-	AddCommandListener(Hook_CommandSuicideAttempt, "kill");
-	AddCommandListener(Hook_CommandSuicideAttempt, "explode");
-	AddCommandListener(Hook_CommandSuicideAttempt, "joinclass");
-	AddCommandListener(Hook_CommandSuicideAttempt, "join_class");
-	AddCommandListener(Hook_CommandSuicideAttempt, "jointeam");
-	AddCommandListener(Hook_CommandSuicideAttempt, "spectate");
-	AddCommandListener(Hook_CommandVoiceMenu, "voicemenu");
-	AddCommandListener(Hook_CommandSay, "say");
-	
-	// Hook events.
-	HookEvent("teamplay_round_start", Event_RoundStart);
-	HookEvent("teamplay_round_win", Event_RoundEnd);
-	HookEvent("player_team", Event_DontBroadcastToClients, EventHookMode_Pre);
-	HookEvent("player_team", Event_PlayerTeam);
-	HookEvent("player_spawn", Event_PlayerSpawn);
-	HookEvent("player_hurt", Event_PlayerHurt);
-	HookEvent("post_inventory_application", Event_PostInventoryApplication);
-	HookEvent("item_found", Event_DontBroadcastToClients, EventHookMode_Pre);
-	HookEvent("teamplay_teambalanced_player", Event_DontBroadcastToClients, EventHookMode_Pre);
-	HookEvent("fish_notice", Event_PlayerDeathPre, EventHookMode_Pre);
-	HookEvent("fish_notice__arm", Event_PlayerDeathPre, EventHookMode_Pre);
-	HookEvent("player_death", Event_PlayerDeathPre, EventHookMode_Pre);
-	HookEvent("player_death", Event_PlayerDeath);
-	
-	// Hook entities.
-	HookEntityOutput("trigger_multiple", "OnStartTouch", Hook_TriggerOnStartTouch);
-	HookEntityOutput("trigger_multiple", "OnEndTouch", Hook_TriggerOnEndTouch);
-	
-	// Hook usermessages.
-	HookUserMessage(GetUserMessageId("VoiceSubtitle"), Hook_BlockUserMessage, true);
-	
-	// Hook sounds.
-	AddNormalSoundHook(Hook_NormalSound);
-	
-	AddTempEntHook("Fire Bullets", Hook_TEFireBullets);
-	
-	InitializeBossProfiles();
-	
-	NPCInitialize();
-	
-	SetupMenus();
-	
-	SetupAdminMenu();
-	
-	SetupClassDefaultWeapons();
-	
-	SetupPlayerGroups();
-	
-	PvP_Initialize();
-	
-	// @TODO: When cvars are finalized, set this to true.
-	AutoExecConfig(false);
-	
-#if defined DEBUG
-	InitializeDebug();
-#endif
-}
-
-public OnAllPluginsLoaded()
-{
-	SetupHooks();
-}
-
-public OnPluginEnd()
-{
-	for(new c = 1; c < MaxClients; c++) DestroySpriteOverlay(c);
-	StopPlugin();
-}
-
-static SetupHooks()
-{
-	// Check SDKHooks gamedata.
-	new Handle:hConfig = LoadGameConfigFile("sdkhooks.games");
-	if (hConfig == INVALID_HANDLE) SetFailState("Couldn't find SDKHooks gamedata!");
-	
-	StartPrepSDKCall(SDKCall_Entity);
-	PrepSDKCall_SetFromConf(hConfig, SDKConf_Virtual, "GetMaxHealth");
-	PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
-	if ((g_hSDKGetMaxHealth = EndPrepSDKCall()) == INVALID_HANDLE)
-	{
-		SetFailState("Failed to retrieve GetMaxHealth offset from SDKHooks gamedata!");
-	}
-	
-	CloseHandle(hConfig);
-	
-	// Check our own gamedata.
-	hConfig = LoadGameConfigFile("sf2");
-	if (hConfig == INVALID_HANDLE) SetFailState("Could not find SF2 gamedata!");
-	
-	new iOffset = GameConfGetOffset(hConfig, "CTFPlayer::WantsLagCompensationOnEntity"); 
-	g_hSDKWantsLagCompensationOnEntity = DHookCreate(iOffset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_ClientWantsLagCompensationOnEntity); 
-	if (g_hSDKWantsLagCompensationOnEntity == INVALID_HANDLE)
-	{
-		SetFailState("Failed to create hook CTFPlayer::WantsLagCompensationOnEntity offset from SF2 gamedata!");
-	}
-	
-	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_CBaseEntity);
-	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_ObjectPtr);
-	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_Unknown);
-	
-	iOffset = GameConfGetOffset(hConfig, "CBaseEntity::ShouldTransmit");
-	g_hSDKShouldTransmit = DHookCreate(iOffset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, Hook_EntityShouldTransmit);
-	if (g_hSDKShouldTransmit == INVALID_HANDLE)
-	{
-		SetFailState("Failed to create hook CBaseEntity::ShouldTransmit offset from SF2 gamedata!");
-	}
-	
-	DHookAddParam(g_hSDKShouldTransmit, HookParamType_ObjectPtr);
-	
-	CloseHandle(hConfig);
-}
-
-static SetupClassDefaultWeapons()
-{
-	// Scout
-	g_hSDKWeaponScattergun = PrepareItemHandle("tf_weapon_scattergun", 13, 0, 0, "");
-	g_hSDKWeaponPistolScout = PrepareItemHandle("tf_weapon_pistol", 23, 0, 0, "");
-	g_hSDKWeaponBat = PrepareItemHandle("tf_weapon_bat", 0, 0, 0, "");
-	
-	// Sniper
-	g_hSDKWeaponSniperRifle = PrepareItemHandle("tf_weapon_sniperrifle", 14, 0, 0, "");
-	g_hSDKWeaponSMG = PrepareItemHandle("tf_weapon_smg", 16, 0, 0, "");
-	g_hSDKWeaponKukri = PrepareItemHandle("tf_weapon_club", 3, 0, 0, "");
-	
-	// Soldier
-	g_hSDKWeaponRocketLauncher = PrepareItemHandle("tf_weapon_rocketlauncher", 18, 0, 0, "");
-	g_hSDKWeaponShotgunSoldier = PrepareItemHandle("tf_weapon_shotgun", 10, 0, 0, "");
-	g_hSDKWeaponShovel = PrepareItemHandle("tf_weapon_shovel", 6, 0, 0, "");
-	
-	// Demoman
-	g_hSDKWeaponGrenadeLauncher = PrepareItemHandle("tf_weapon_grenadelauncher", 19, 0, 0, "");
-	g_hSDKWeaponStickyLauncher = PrepareItemHandle("tf_weapon_pipebomblauncher", 20, 0, 0, "");
-	g_hSDKWeaponBottle = PrepareItemHandle("tf_weapon_bottle", 1, 0, 0, "");
-	
-	// Heavy
-	g_hSDKWeaponMinigun = PrepareItemHandle("tf_weapon_minigun", 15, 0, 0, "");
-	g_hSDKWeaponShotgunHeavy = PrepareItemHandle("tf_weapon_shotgun", 11, 0, 0, "");
-	g_hSDKWeaponFists = PrepareItemHandle("tf_weapon_fists", 5, 0, 0, "");
-	
-	// Medic
-	g_hSDKWeaponSyringeGun = PrepareItemHandle("tf_weapon_syringegun_medic", 17, 0, 0, "");
-	g_hSDKWeaponMedigun = PrepareItemHandle("tf_weapon_medigun", 29, 0, 0, "");
-	g_hSDKWeaponBonesaw = PrepareItemHandle("tf_weapon_bonesaw", 8, 0, 0, "");
-	
-	// Pyro
-	g_hSDKWeaponFlamethrower = PrepareItemHandle("tf_weapon_flamethrower", 21, 0, 0, "254 ; 4.0");
-	g_hSDKWeaponShotgunPyro = PrepareItemHandle("tf_weapon_shotgun", 12, 0, 0, "");
-	g_hSDKWeaponFireaxe = PrepareItemHandle("tf_weapon_fireaxe", 2, 0, 0, "");
-	
-	// Spy
-	g_hSDKWeaponRevolver = PrepareItemHandle("tf_weapon_revolver", 24, 0, 0, "");
-	g_hSDKWeaponKnife = PrepareItemHandle("tf_weapon_knife", 4, 0, 0, "");
-	g_hSDKWeaponInvis = PrepareItemHandle("tf_weapon_invis", 297, 0, 0, "");
-	
-	// Engineer
-	g_hSDKWeaponShotgunPrimary = PrepareItemHandle("tf_weapon_shotgun", 9, 0, 0, "");
-	g_hSDKWeaponPistol = PrepareItemHandle("tf_weapon_pistol", 22, 0, 0, "");
-	g_hSDKWeaponWrench = PrepareItemHandle("tf_weapon_wrench", 7, 0, 0, "");
-}
-
-public OnMapStart()
-{
-	PvP_OnMapStart();
-}
-
-public OnConfigsExecuted()
-{
-	if (!GetConVarBool(g_cvEnabled))
-	{
-		StopPlugin();
-	}
-	else
-	{
-		if (GetConVarBool(g_cvSlenderMapsOnly))
-		{
-			decl String:sMap[256];
-			GetCurrentMap(sMap, sizeof(sMap));
-			
-			if (!StrContains(sMap, "slender_", false) || !StrContains(sMap, "sf2_", false))
-			{
-				StartPlugin();
-			}
-			else
-			{
-				LogMessage("%s is not a Slender Fortress map. Plugin disabled!", sMap);
-				StopPlugin();
-			}
-		}
-		else
-		{
-			StartPlugin();
-		}
-	}
-}
-
-static StartPlugin()
-{
-	if (g_bEnabled) return;
-	
-	g_bEnabled = true;
-	
-	InitializeLogging();
-	
-#if defined DEBUG
-	InitializeDebugLogging();
-#endif
-	
-	// Handle ConVars.
-	new Handle:hCvar = FindConVar("mp_friendlyfire");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
-	
-	hCvar = FindConVar("mp_flashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
-	
-	hCvar = FindConVar("mat_supportflashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
-	
-	hCvar = FindConVar("mp_autoteambalance");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	g_flGravity = GetConVarFloat(g_cvGravity);
-	
-	g_b20Dollars = GetConVarBool(g_cv20Dollars);
-	
-	g_bPlayerShakeEnabled = GetConVarBool(g_cvPlayerShakeEnabled);
-	g_bPlayerViewbobEnabled = GetConVarBool(g_cvPlayerViewbobEnabled);
-	g_bPlayerViewbobHurtEnabled = GetConVarBool(g_cvPlayerViewbobHurtEnabled);
-	g_bPlayerViewbobSprintEnabled = GetConVarBool(g_cvPlayerViewbobSprintEnabled);
-	
-	decl String:sBuffer[64];
-	Format(sBuffer, sizeof(sBuffer), "RYTP Horror", PLUGIN_VERSION_DISPLAY);
-	Steam_SetGameDescription(sBuffer);
-	
-	PrecacheStuff();
-	
-	// Reset special round.
-	g_bSpecialRound = false;
-	g_bSpecialRoundNew = false;
-	g_bSpecialRoundContinuous = false;
-	g_iSpecialRoundCount = 1;
-	g_iSpecialRoundType = 0;
-	
-	SpecialRoundReset();
-	
-	// Reset boss rounds.
-	g_bNewBossRound = false;
-	g_bNewBossRoundNew = false;
-	g_bNewBossRoundContinuous = false;
-	g_iNewBossRoundCount = 1;
-	strcopy(g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile), "");
-	
-	// Reset global round vars.
-	g_iRoundCount = 0;
-	g_iRoundEndCount = 0;
-	g_iRoundActiveCount = 0;
-	g_iRoundState = SF2RoundState_Invalid;
-	g_hRoundMessagesTimer = CreateTimer(200.0, Timer_RoundMessages, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	g_iRoundMessagesNum = 0;
-	
-	g_iRoundWarmupRoundCount = 0;
-	
-	g_hClientAverageUpdateTimer = CreateTimer(0.2, Timer_ClientAverageUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	g_hBossCountUpdateTimer = CreateTimer(2.0, Timer_BossCountUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	
-	SetRoundState(SF2RoundState_Waiting);
-	
-	ReloadBossProfiles();
-	ReloadRestrictedWeapons();
-	ReloadSpecialRounds();
-	
-	NPCOnConfigsExecuted();
-	
-	InitializeBossPackVotes();
-	SetupTimeLimitTimerForBossPackVote();
-	
-	// Late load compensation.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		OnClientPutInServer(i);
-	}
-}
-
-static PrecacheStuff()
-{
-	// Initialize particles.
-	g_iParticleCriticalHit = PrecacheParticleSystem(CRIT_PARTICLENAME);
-	
-	PrecacheSound2(CRIT_SOUND);
-	
-	// simple_bot;
-	PrecacheModel("models/humans/group01/female_01.mdl", true);
-	
-	PrecacheModel(PAGE_MODEL, true);
-	PrecacheModel(GHOST_MODEL, true);
-	
-	PrecacheSound2(FLASHLIGHT_CLICKSOUND);
-	PrecacheSound2(FLASHLIGHT_BREAKSOUND);
-	PrecacheSound2(FLASHLIGHT_NOSOUND);
-	PrecacheSound2(PAGE_GRABSOUND);
-	
-	PrecacheSound2(MUSIC_GOTPAGES1_SOUND);
-	PrecacheSound2(MUSIC_GOTPAGES2_SOUND);
-	PrecacheSound2(MUSIC_GOTPAGES3_SOUND);
-	PrecacheSound2(MUSIC_GOTPAGES4_SOUND);
-	
-	PrecacheSound2(SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
-	
-	for (new i = 0; i < sizeof(g_strPlayerBreathSounds); i++)
-	{
-		PrecacheSound2(g_strPlayerBreathSounds[i]);
-	}
-	
-	for (new i = 0; i < sizeof(g_strGhostHelpPhrases); i++)
-	{
-		PrecacheSound2(g_strGhostHelpPhrases[i]);
-	}
-	
-	for (new i = 0; i < sizeof(g_sOverlayMat); i++)
-	{
-		new String:path[PLATFORM_MAX_PATH];
-		//strcopy(path, sizeof(path), g_sOverlayMat[i][10]);
-		Format(path, sizeof(path), "%s.vmt", g_sOverlayMat[i]);
-		PrecacheModel(path);
-		Format(path, sizeof(path), "%s.vtf", g_sOverlayMat[i]);
-		PrecacheModel(path);
-		//PrintToServer("PrecacheMaterial2('%s');", path);
-	}
-	PrecacheMaterial2(STATIC_OVERLAY);
-	PrecacheSound2(STATIC_SOUND);
-	
-	// Special round.
-	PrecacheSound2(SR_MUSIC);
-	PrecacheSound2(SR_SOUND_SELECT);
-	PrecacheSound2(SF2_INTRO_DEFAULT_MUSIC);
-	
-	PrecacheMaterial2(GRAIN_OVERLAY);
-	
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.mdl");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx80.vtx");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx90.vtx");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.phy");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.sw.vtx");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.vvd");
-	
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vmt");
-	
-	// pvp
-	PvP_Precache();
-}
-
-static StopPlugin()
-{
-	if (!g_bEnabled) return;
-	
-	g_bEnabled = false;
-	
-	// Reset CVars.
-	new Handle:hCvar = FindConVar("mp_friendlyfire");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	hCvar = FindConVar("mp_flashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	hCvar = FindConVar("mat_supportflashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	// Cleanup bosses.
-	NPCRemoveAll();
-	
-	// Cleanup clients.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		ClientResetFlashlight(i);
-		ClientDeactivateUltravision(i);
-		ClientDisableConstantGlow(i);
-		ClientRemoveInteractiveGlow(i);
-	}
-	
-	ForceTeamWin(_:TFTeam_Blue);
-	
-	BossProfilesOnMapEnd();
-}
-
-public OnMapEnd()
-{
-	StopPlugin();
-}
-
-public OnMapTimeLeftChanged()
-{
-	if (g_bEnabled)
-	{
-		SetupTimeLimitTimerForBossPackVote();
-	}
-}
-
-public TF2_OnConditionAdded(client, TFCond:cond)
-{
-	if (cond == TFCond_Taunting)
-	{
-		if (IsClientInGhostMode(client))
-		{
-			// Stop ghosties from taunting.
-			TF2_RemoveCondition(client, TFCond_Taunting);
-		}
-	}
-}
-
-public OnGameFrame()
-{
-	if (!g_bEnabled) return;
-
-	// Process through boss movement.
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		new iBoss = NPCGetEntIndex(i);
-		if (!iBoss || iBoss == INVALID_ENT_REFERENCE) continue;
-		
-		if (NPCGetFlags(i) & SFF_MARKEDASFAKE) continue;
-		
-		new iType = NPCGetType(i);
-		
-		switch (iType)
-		{
-			case SF2BossType_Static:
-			{
-				decl Float:myPos[3], Float:hisPos[3];
-				SlenderGetAbsOrigin(i, myPos);
-				AddVectors(myPos, g_flSlenderEyePosOffset[i], myPos);
-				
-				new iBestPlayer = -1;
-				new Float:flBestDistance = 16384.0;
-				new Float:flTempDistance;
-				
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsClientInGame(iClient) || !IsPlayerAlive(iClient) || IsClientInGhostMode(iClient) || IsClientInDeathCam(iClient)) continue;
-					if (!IsPointVisibleToPlayer(iClient, myPos, false, false)) continue;
-					
-					GetClientAbsOrigin(iClient, hisPos);
-					
-					flTempDistance = GetVectorDistance(myPos, hisPos);
-					if (flTempDistance < flBestDistance)
-					{
-						iBestPlayer = iClient;
-						flBestDistance = flTempDistance;
-					}
-				}
-				
-				if (iBestPlayer > 0)
-				{
-					SlenderGetAbsOrigin(i, myPos);
-					GetClientAbsOrigin(iBestPlayer, hisPos);
-					
-					if (!SlenderOnlyLooksIfNotSeen(i) || !IsPointVisibleToAPlayer(myPos, false, SlenderUsesBlink(i)))
-					{
-						new Float:flTurnRate = NPCGetTurnRate(i);
-					
-						if (flTurnRate > 0.0)
-						{
-							decl Float:flMyEyeAng[3], Float:ang[3];
-							GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
-							AddVectors(flMyEyeAng, g_flSlenderEyeAngOffset[i], flMyEyeAng);
-							SubtractVectors(hisPos, myPos, ang);
-							GetVectorAngles(ang, ang);
-							ang[0] = 0.0;
-							ang[1] += (AngleDiff(ang[1], flMyEyeAng[1]) >= 0.0 ? 1.0 : -1.0) * flTurnRate * GetTickInterval();
-							ang[2] = 0.0;
-							
-							// Take care of angle offsets.
-							AddVectors(ang, g_flSlenderEyePosOffset[i], ang);
-							for (new i2 = 0; i2 < 3; i2++) ang[i2] = AngleNormalize(ang[i2]);
-							
-							TeleportEntity(iBoss, NULL_VECTOR, ang, NULL_VECTOR);
-						}
-					}
-				}
-			}
-			case SF2BossType_Chaser:
-			{
-				SlenderChaseBossProcessMovement(i);
-			}
-		}
-	}
-	
-	PvP_OnGameFrame();
-}
-
-//	==========================================================
-//	COMMANDS AND COMMAND HOOK FUNCTIONS
-//	==========================================================
-
-public Action:Command_Help(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayMenu(g_hMenuHelp, client, 30);
-	return Plugin_Handled;
-}
-
-public Action:Command_Settings(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayMenu(g_hMenuSettings, client, 30);
-	return Plugin_Handled;
-}
-
-public Action:Command_Credits(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayMenu(g_hMenuCredits, client, MENU_TIME_FOREVER);
-	return Plugin_Handled;
-}
-
-public Action:Command_ToggleFlashlight(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return Plugin_Handled;
-	
-	if (!IsRoundInWarmup() && !IsRoundInIntro() && !IsRoundEnding() && !DidClientEscape(client))
-	{
-		if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
-		{
-			ClientHandleFlashlight(client);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SprintOn(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
-	{
-		ClientHandleSprint(client, true);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SprintOff(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
-	{
-		ClientHandleSprint(client, false);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_MainMenu(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	DisplayMenu(g_hMenuMain, client, 30);
-	return Plugin_Handled;
-}
-
-public Action:Command_Next(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayQueuePointsMenu(client);
-	return Plugin_Handled;
-}
-
-public Action:Command_Group(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayGroupMainMenuToClient(client);
-	return Plugin_Handled;
-}
-
-public Action:Command_GroupName(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_slgroupname <name>");
-		return Plugin_Handled;
-	}
-	
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return Plugin_Handled;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	GetCmdArg(1, sGroupName, sizeof(sGroupName));
-	if (!sGroupName[0])
-	{
-		CPrintToChat(client, "%T", "SF2 Invalid Group Name", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:sOldGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	GetPlayerGroupName(iGroupIndex, sOldGroupName, sizeof(sOldGroupName));
-	SetPlayerGroupName(iGroupIndex, sGroupName);
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		if (ClientGetPlayerGroup(i) != iGroupIndex) continue;
-		CPrintToChat(i, "%T", "SF2 Group Name Set", i, sOldGroupName, sGroupName);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_GhostMode(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	DisplayMenu(g_hMenuGhostMode, client, 15);
-	return Plugin_Handled;
-}
-
-public Action:Hook_CommandSay(client, const String:command[], argc)
-{
-	if (!g_bEnabled || GetConVarBool(g_cvAllChat)) return Plugin_Continue;
-	
-	if (!IsRoundEnding())
-	{
-		if (g_bPlayerEliminated[client])
-		{
-			decl String:sMessage[256];
-			GetCmdArgString(sMessage, sizeof(sMessage));
-			FakeClientCommand(client, "say_team %s", sMessage);
-			return Plugin_Handled;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_CommandSuicideAttempt(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsClientInGhostMode(client)) return Plugin_Handled;
-	
-	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
-	
-	if (GetConVarBool(g_cvBlockSuicideDuringRound))
-	{
-		if (!g_bRoundGrace && !g_bPlayerEliminated[client] && !DidClientEscape(client))
-		{
-			return Plugin_Handled;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_CommandBlockInGhostMode(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsClientInGhostMode(client)) return Plugin_Handled;
-	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_CommandVoiceMenu(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsClientInGhostMode(client))
-	{
-		ClientGhostModeNextTarget(client);
-		return Plugin_Handled;
-	}
-	
-	if (g_bPlayerProxy[client])
-	{
-		new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-		if (iMaster != -1)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
-		
-			if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
-			{
-				return Plugin_Handled;
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Command_ClientPerformScare(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_scare <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32], String:arg2[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			COMMAND_FILTER_ALIVE,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new target = target_list[i];
-		ClientPerformScare(target, StringToInt(arg2));
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SpawnSlender(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args == 0)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_spawn_boss <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl Float:eyePos[3], Float:eyeAng[3], Float:endPos[3];
-	GetClientEyePosition(client, eyePos);
-	GetClientEyeAngles(client, eyeAng);
-	
-	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
-	TR_GetEndPosition(endPos, hTrace);
-	CloseHandle(hTrace);
-	
-	SpawnSlender(iBossIndex, endPos);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Spawned Boss", client);
-	LogAction(client, -1, "%N spawned boss %d! (%s)", client, iBossIndex, sProfile);
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_RemoveSlender(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args == 0)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_remove_boss <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	NPCRemove(iBossIndex);
-	
-	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Removed Boss", client);
-	LogAction(client, -1, "%N removed boss %d! (%s)", client, iBossIndex, sProfile);
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_GetBossIndexes(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	decl String:sMessage[512];
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	ClientCommand(client, "echo Active Boss Indexes:");
-	ClientCommand(client, "echo ----------------------------");
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		Format(sMessage, sizeof(sMessage), "%d - %s", i, sProfile);
-		if (NPCGetFlags(i) & SFF_FAKE)
-		{
-			StrCat(sMessage, sizeof(sMessage), " (fake)");
-		}
-		
-		if (g_iSlenderCopyMaster[i] != -1)
-		{
-			decl String:sCat[64];
-			Format(sCat, sizeof(sCat), " (copy of %d)", g_iSlenderCopyMaster[i]);
-			StrCat(sMessage, sizeof(sMessage), sCat);
-		}
-		
-		ClientCommand(client, "echo %s", sMessage);
-	}
-	
-	ClientCommand(client, "echo ----------------------------");
-	
-	ReplyToCommand(client, "Printed active boss indexes to your console!");
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SlenderAttackWaiters(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_boss_attack_waiters <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iBossFlags = NPCGetFlags(iBossIndex);
-	
-	new bool:bState = bool:StringToInt(arg2);
-	new bool:bOldState = bool:(iBossFlags & SFF_ATTACKWAITERS);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (bState)
-	{
-		if (!bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags | SFF_ATTACKWAITERS);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Attack Waiters", client);
-			LogAction(client, -1, "%N forced boss %d to attack waiters! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	else
-	{
-		if (bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_ATTACKWAITERS);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Do Not Attack Waiters", client);
-			LogAction(client, -1, "%N forced boss %d to not attack waiters! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SlenderNoTeleport(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_boss_no_teleport <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iBossFlags = NPCGetFlags(iBossIndex);
-	
-	new bool:bState = bool:StringToInt(arg2);
-	new bool:bOldState = bool:(iBossFlags & SFF_NOTELEPORT);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (bState)
-	{
-		if (!bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags | SFF_NOTELEPORT);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Not Teleport", client);
-			LogAction(client, -1, "%N disabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	else
-	{
-		if (bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_NOTELEPORT);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Teleport", client);
-			LogAction(client, -1, "%N enabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_ForceProxy(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_force_proxy <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	if (IsRoundEnding() || IsRoundInWarmup())
-	{
-		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			0,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iBossIndex = StringToInt(arg2);
-	if (iBossIndex < 0 || iBossIndex >= MAX_BOSSES)
-	{
-		ReplyToCommand(client, "Boss index is out of range!");
-		return Plugin_Handled;
-	}
-	else if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		ReplyToCommand(client, "Boss index is invalid! Boss index not active!");
-		return Plugin_Handled;
-	}
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new iTarget = target_list[i];
-		
-		decl String:sName[MAX_NAME_LENGTH];
-		GetClientName(iTarget, sName, sizeof(sName));
-		
-		if (!g_bPlayerEliminated[iTarget])
-		{
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Unable To Perform Action On Player In Round", client, sName);
-			continue;
-		}
-		
-		if (g_bPlayerProxy[iTarget]) continue;
-		
-		decl Float:flNewPos[3];
-		
-		if (!SlenderCalculateNewPlace(iBossIndex, flNewPos, true, true, client)) 
-		{
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Player No Place For Proxy", client, sName);
-			continue;
-		}
-		
-		ClientEnableProxy(iTarget, iBossIndex);
-		TeleportEntity(iTarget, flNewPos, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-		
-		LogAction(client, iTarget, "%N forced %N to be a Proxy!", client, iTarget);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_ForceEscape(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_force_escape <name|#userid>");
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			COMMAND_FILTER_ALIVE,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new target = target_list[i];
-		if (!g_bPlayerEliminated[i] && !DidClientEscape(i))
-		{
-			ClientEscape(target);
-			TeleportClientToEscapePoint(target);
-			
-			LogAction(client, target, "%N forced %N to escape!", client, target);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_AddSlender(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_add_boss <name>");
-		return Plugin_Handled;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetCmdArg(1, sProfile, sizeof(sProfile));
-	
-	KvRewind(g_hConfig);
-	if (!KvJumpToKey(g_hConfig, sProfile)) 
-	{
-		ReplyToCommand(client, "That boss does not exist!");
-		return Plugin_Handled;
-	}
-	
-	new iBossIndex = AddProfile(sProfile);
-	if (iBossIndex != -1)
-	{
-		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
-		GetClientEyePosition(client, eyePos);
-		GetClientEyeAngles(client, eyeAng);
-		
-		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
-		TR_GetEndPosition(flPos, hTrace);
-		CloseHandle(hTrace);
-	
-		SpawnSlender(iBossIndex, flPos);
-		
-		LogAction(client, -1, "%N added a boss! (%s)", client, sProfile);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_AddSlenderFake(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_add_boss_fake <name>");
-		return Plugin_Handled;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetCmdArg(1, sProfile, sizeof(sProfile));
-	
-	KvRewind(g_hConfig);
-	if (!KvJumpToKey(g_hConfig, sProfile)) 
-	{
-		ReplyToCommand(client, "That boss does not exist!");
-		return Plugin_Handled;
-	}
-	
-	new iBossIndex = AddProfile(sProfile, SFF_FAKE);
-	if (iBossIndex != -1)
-	{
-		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
-		GetClientEyePosition(client, eyePos);
-		GetClientEyeAngles(client, eyeAng);
-		
-		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
-		TR_GetEndPosition(flPos, hTrace);
-		CloseHandle(hTrace);
-	
-		SpawnSlender(iBossIndex, flPos);
-		
-		LogAction(client, -1, "%N added a fake boss! (%s)", client, sProfile);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_ForceState(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_setplaystate <name|#userid> <0/1>");
-		return Plugin_Handled;
-	}
-	
-	if (IsRoundEnding() || IsRoundInWarmup())
-	{
-		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			0,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iState = StringToInt(arg2);
-	
-	decl String:sName[MAX_NAME_LENGTH];
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new target = target_list[i];
-		GetClientName(target, sName, sizeof(sName));
-		
-		if (iState && g_bPlayerEliminated[target])
-		{
-			SetClientPlayState(target, true);
-			
-			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced In Game", sName);
-			LogAction(client, target, "%N forced %N into the game.", client, target);
-		}
-		else if (!iState && !g_bPlayerEliminated[target])
-		{
-			SetClientPlayState(target, false);
-			
-			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced Out Of Game", sName);
-			LogAction(client, target, "%N took %N out of the game.", client, target);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Hook_CommandBuild(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (!IsClientInPvP(client)) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_BossCountUpdate(Handle:timer)
-{
-	if (timer != g_hBossCountUpdateTimer) return Plugin_Stop;
-	
-	if (!g_bEnabled) return Plugin_Stop;
-
-	new iBossCount = NPCGetCount();
-	new iBossPreferredCount;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1 ||
-			g_iSlenderCopyMaster[i] != -1 ||
-			(NPCGetFlags(i) & SFF_FAKE))
-		{
-			continue;
-		}
-		
-		iBossPreferredCount++;
-	}
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i) ||
-			!IsPlayerAlive(i) ||
-			g_bPlayerEliminated[i] ||
-			IsClientInGhostMode(i) ||
-			IsClientInDeathCam(i) ||
-			DidClientEscape(i)) continue;
-		
-		// Check if we're near any bosses.
-		new iClosest = -1;
-		new Float:flBestDist = SF2_BOSS_PAGE_CALCULATION;
-		
-		for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
-		{
-			if (NPCGetUniqueID(iBoss) == -1) continue;
-			if (NPCGetEntIndex(iBoss) == INVALID_ENT_REFERENCE) continue;
-			if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
-			
-			new Float:flDist = NPCGetDistanceFromEntity(iBoss, i);
-			if (flDist < flBestDist)
-			{
-				iClosest = iBoss;
-				flBestDist = flDist;
-				break;
-			}
-		}
-		
-		if (iClosest != -1) continue;
-		
-		iClosest = -1;
-		flBestDist = SF2_BOSS_PAGE_CALCULATION;
-		
-		for (new iClient = 1; iClient <= MaxClients; iClient++)
-		{
-			if (!IsValidClient(iClient) ||
-				!IsPlayerAlive(iClient) ||
-				g_bPlayerEliminated[iClient] ||
-				IsClientInGhostMode(iClient) ||
-				IsClientInDeathCam(iClient) ||
-				DidClientEscape(iClient)) 
-			{
-				continue;
-			}
-			
-			new bool:bwub = false;
-			for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
-			{
-				if (NPCGetUniqueID(iBoss) == -1) continue;
-				if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
-				
-				if (g_iSlenderTarget[iBoss] == iClient)
-				{
-					bwub = true;
-					break;
-				}
-			}
-			
-			if (!bwub) continue;
-			
-			new Float:flDist = EntityDistanceFromEntity(i, iClient);
-			if (flDist < flBestDist)
-			{
-				iClosest = iClient;
-				flBestDist = flDist;
-			}
-		}
-		
-		if (!IsValidClient(iClosest))
-		{
-			// No one's close to this dude? DUDE! WE NEED ANOTHER BOSS!
-			iBossPreferredCount++;
-		}
-	}
-	
-	new iDiff = iBossCount - iBossPreferredCount;
-	if (iDiff)
-	{	
-		if (iDiff > 0)
-		{
-			new iCount = iDiff;
-			// We need less bosses. Try and see if we can remove some.
-			for (new i = 0; i < MAX_BOSSES; i++)
-			{
-				if (g_iSlenderCopyMaster[i] == -1) continue;
-				if (PeopleCanSeeSlender(i, _, false)) continue;
-				if (NPCGetFlags(i) & SFF_FAKE) continue;
-				
-				if (SlenderCanRemove(i))
-				{
-					NPCRemove(i);
-					iCount--;
-				}
-				
-				if (iCount <= 0)
-				{
-					break;
-				}
-			}
-		}
-		else
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		
-			new iCount = RoundToFloor(FloatAbs(float(iDiff)));
-			// Add new bosses (copy of the first boss).
-			for (new i = 0; i < MAX_BOSSES && iCount > 0; i++)
-			{
-				if (NPCGetUniqueID(i) == -1) continue;
-				if (g_iSlenderCopyMaster[i] != -1) continue;
-				if (!(NPCGetFlags(i) & SFF_COPIES)) continue;
-				
-				// Get the number of copies I already have and see if I can have more copies.
-				new iCopyCount;
-				for (new i2 = 0; i2 < MAX_BOSSES; i2++)
-				{
-					if (NPCGetUniqueID(i2) == -1) continue;
-					if (g_iSlenderCopyMaster[i2] != i) continue;
-					
-					iCopyCount++;
-				}
-				
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-				
-				if (iCopyCount >= GetProfileNum(sProfile, "copy_max", 10)) 
-				{
-					continue;
-				}
-				
-				new iBossIndex = AddProfile(sProfile, _, i);
-				if (iBossIndex == -1)
-				{
-					LogError("Could not add copy for %d: No free slots!", i);
-				}
-				
-				iCount--;
-			}
-		}
-	}
-	
-	// Check if we can add some proxies.
-	if (!g_bRoundGrace)
-	{
-		if (NavMesh_Exists())
-		{
-			new Handle:hProxyCandidates = CreateArray();
-			
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			
-			for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-			{
-				if (NPCGetUniqueID(iBossIndex) == -1) continue;
-				
-				if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) continue;
-				
-				if (g_iSlenderCopyMaster[iBossIndex] != -1) continue; // Copies cannot generate proxies.
-				
-				if (GetGameTime() < g_flSlenderTimeUntilNextProxy[iBossIndex]) continue; // Proxy spawning hasn't cooled down yet.
-				
-				new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
-				if (!iTeleportTarget || iTeleportTarget == INVALID_ENT_REFERENCE) continue; // No teleport target.
-				
-				NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-				
-				new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
-				new iNumActiveProxies = 0;
-				
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-					if (!g_bPlayerProxy[iClient]) continue;
-					
-					if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) == iBossIndex)
-					{
-						iNumActiveProxies++;
-					}
-				}
-				
-				if (iNumActiveProxies >= iMaxProxies) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d has too many active proxies!", iBossIndex);
-#endif
-					continue;
-				}
-				
-				new Float:flSpawnChanceMin = GetProfileFloat(sProfile, "proxies_spawn_chance_min");
-				new Float:flSpawnChanceMax = GetProfileFloat(sProfile, "proxies_spawn_chance_max");
-				new Float:flSpawnChanceThreshold = GetProfileFloat(sProfile, "proxies_spawn_chance_threshold") * NPCGetAnger(iBossIndex);
-				
-				new Float:flChance = GetRandomFloat(flSpawnChanceMin, flSpawnChanceMax);
-				if (flChance > flSpawnChanceThreshold) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's chances weren't in his favor!", iBossIndex);
-#endif
-					continue;
-				}
-				
-				new iAvailableProxies = iMaxProxies - iNumActiveProxies;
-				
-				new iSpawnNumMin = GetProfileNum(sProfile, "proxies_spawn_num_min");
-				new iSpawnNumMax = GetProfileNum(sProfile, "proxies_spawn_num_max");
-				
-				new iSpawnNum = 0;
-				
-				// Get a list of people we can transform into a good Proxy.
-				ClearArray(hProxyCandidates);
-				
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-					if (g_bPlayerProxy[iClient]) continue;
-					
-					if (!g_iPlayerPreferences[iClient][PlayerPreference_EnableProxySelection])
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your preferences.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					if (!g_bPlayerProxyAvailable[iClient])
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your cooldown.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					if (g_bPlayerProxyAvailableInForce[iClient])
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're already being forced into a Proxy.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					if (!IsClientParticipating(iClient))
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're not participating.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					PushArrayCell(hProxyCandidates, iClient);
-					iSpawnNum++;
-				}
-				
-				if (iSpawnNum >= iSpawnNumMax)
-				{
-					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNumMax);
-				}
-				else if (iSpawnNum >= iSpawnNumMin)
-				{
-					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNum);
-				}
-				
-				if (iSpawnNum <= 0) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d had a set spawn number of 0!", iBossIndex);
-#endif
-					continue;
-				}
-				
-				decl Float:flTargetPos[3];
-				GetClientAbsOrigin(iTeleportTarget, flTargetPos);
-				
-				new iTargetAreaIndex = NavMesh_GetNearestArea(flTargetPos);
-				if (iTargetAreaIndex == -1) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's teleport target is not on the navmesh!", iBossIndex);
-#endif
-					continue; // target is not on the nav mesh.
-				}
-				
-				// Search outwards until travel distance is at maximum range.
-				new Handle:hAreaArray = CreateArray(2);
-				new Handle:hAreas = CreateStack();
-				NavMesh_CollectSurroundingAreas(hAreas, iTargetAreaIndex, g_flSlenderProxyTeleportMaxRange[iBossIndex]);
-				
-				new Float:flTeleportMinRange = CalculateTeleportMinRange(iBossIndex, g_flSlenderProxyTeleportMinRange[iBossIndex], g_flSlenderProxyTeleportMaxRange[iBossIndex]);
-				
-				{
-					new iAreaIndex = -1;
-					new iPoppedAreas = 0;
-					
-					while (!IsStackEmpty(hAreas))
-					{
-						PopStackCell(hAreas, iAreaIndex);
-						new iCostSoFar = NavMeshArea_GetCostSoFar(iAreaIndex);
-						
-						if (float(iCostSoFar) >= flTeleportMinRange)
-						{
-							new iIndex = PushArrayCell(hAreaArray, iAreaIndex);
-							SetArrayCell(hAreaArray, iIndex, float(iCostSoFar), 1);
-							iPoppedAreas++;
-						}
-					}
-					
-					CloseHandle(hAreas);
-					
-					if (iPoppedAreas == 0)
-					{
-						// no areas to use!
-						CloseHandle(hAreaArray);
-
-#if defined DEBUG
-						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any sufficient surrounding areas!", iBossIndex);
-#endif
-						
-						continue;
-					}
-#if defined DEBUG
-					else
-					{
-						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d found %d surrounding areas", iBossIndex, iPoppedAreas);
-					}
-#endif
-				}
-				
-				new Handle:hAreaArrayClose = CreateArray();
-				new Handle:hAreaArrayAverage = CreateArray();
-				new Handle:hAreaArrayFar = CreateArray();
-				
-				for (new iRangeSection = 1; iRangeSection <= 3; iRangeSection++)
-				{
-					new Float:flRangeSectionMin = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection - 1) / 3.0);
-					new Float:flRangeSectionMax = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection) / 3.0);
-					
-					for (new i = 0, iSize = GetArraySize(hAreaArray); i < iSize; i++)
-					{
-						new iAreaIndex = GetArrayCell(hAreaArray, i);
-						
-						decl Float:flAreaCenter[3];
-						NavMeshArea_GetCenter(iAreaIndex, flAreaCenter);
-						
-						decl Float:flTestPos[3];
-						decl Float:flEyeOffset[3];
-						flEyeOffset[0] = 0.0;
-						flEyeOffset[1] = 0.0;
-						flEyeOffset[2] = HalfHumanHeight * 2.0;
-						
-						// Check visibility first.
-						if (IsPointVisibleToAPlayer(flAreaCenter, false, false)) 
-						{
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (1)", iBossIndex, iAreaIndex);
-#endif
-							continue;
-						}
-						
-						AddVectors(flAreaCenter, flEyeOffset, flTestPos);
-						
-						if (IsPointVisibleToAPlayer(flTestPos, false, false)) 
-						{
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (2)", iBossIndex, iAreaIndex);
-#endif
-						
-							continue;
-						}
-						
-						new iBoss = NPCGetEntIndex(iBossIndex);
-						
-						// Check space. First raise to HalfHumanHeight * 2, then trace downwards to get ground level.
-						{
-							decl Float:flTraceStartPos[3];
-							flTraceStartPos[0] = flAreaCenter[0];
-							flTraceStartPos[1] = flAreaCenter[1];
-							flTraceStartPos[2] = flAreaCenter[2] + (HalfHumanHeight * 2.0);
-							
-							decl Float:flTraceMins[3];
-							flTraceMins[0] = -20.0;
-							flTraceMins[1] = -20.0;
-							flTraceMins[2] = 0.0;
-							
-							decl Float:flTraceMaxs[3];
-							flTraceMaxs[0] = 20.0;
-							flTraceMaxs[1] = 20.0;
-							flTraceMaxs[2] = 0.0;
-							
-							new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
-								flAreaCenter,
-								flTraceMins,
-								flTraceMaxs,
-								MASK_NPCSOLID,
-								TraceRayDontHitEntity,
-								iBoss);
-							
-							decl Float:flTraceHitPos[3];
-							TR_GetEndPosition(flTraceHitPos, hTrace);
-							flTraceHitPos[2] += 1.0;
-							CloseHandle(hTrace);
-							
-							static Float:flTraceSpaceMin[3] = { -20.0, -20.0, 0.0 };
-							static Float:flTraceSpaceMax[3] = { 20.0, 20.0, 72.0 };
-							
-							flTraceSpaceMax[2] = HalfHumanHeight * 2.0;
-							
-							if (IsSpaceOccupiedPlayer(flTraceHitPos,
-								flTraceSpaceMin,
-								flTraceSpaceMax,
-								iBoss == INVALID_ENT_REFERENCE ? -1 : iBoss))
-							{
-#if defined DEBUG
-								SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected too small area index %d! (2)", iBossIndex, iAreaIndex);
-#endif
-							
-								continue;
-							}
-						}
-						
-						new bool:bTooNear = false;
-						
-						// Check minimum range.
-						for (new iClient = 1; iClient <= MaxClients; iClient++)
-						{
-							if (!IsClientInGame(iClient) ||
-								!IsPlayerAlive(iClient) ||
-								g_bPlayerEliminated[iClient] ||
-								DidClientEscape(iClient) ||
-								g_bPlayerProxy[iClient] ||
-								IsClientInGhostMode(iClient))
-							{
-								continue;
-							}
-							
-							decl Float:flTempPos[3];
-							GetClientAbsOrigin(iClient, flTempPos);
-							
-							if (GetVectorDistance(flAreaCenter, flTempPos) <= flTeleportMinRange)
-							{
-								bTooNear = true;
-								break;
-							}
-						}
-						
-						if (bTooNear) 
-						{
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected near area index %d!", iBossIndex, iAreaIndex);
-#endif
-						
-							continue;	// This area is too close to a player.
-						}
-						
-						// Check travel distance.
-						new Float:flDist = Float:GetArrayCell(hAreaArray, i, 1);
-						if (flDist > flRangeSectionMin && flDist < flRangeSectionMax)
-						{
-							switch (iRangeSection)
-							{
-								case 1: PushArrayCell(hAreaArrayClose, iAreaIndex);
-								case 2: PushArrayCell(hAreaArrayAverage, iAreaIndex);
-								case 3: PushArrayCell(hAreaArrayFar, iAreaIndex);
-							}
-						}
-					}
-				}
-				
-				CloseHandle(hAreaArray);
-				
-				// Set the cooldown time!
-				new Float:flSpawnCooldownMin = GetProfileFloat(sProfile, "proxies_spawn_cooldown_min");
-				new Float:flSpawnCooldownMax = GetProfileFloat(sProfile, "proxies_spawn_cooldown_max");
-				
-				g_flSlenderTimeUntilNextProxy[iBossIndex] = GetGameTime() + GetRandomFloat(flSpawnCooldownMin, flSpawnCooldownMax);
-				
-				// Randomize the array.
-				SortADTArray(hProxyCandidates, Sort_Random, Sort_Integer);
-				
-				decl Float:flDestinationPos[3];
-				
-				for (new iNum = 0; iNum < iSpawnNum && iNum < iAvailableProxies; iNum++)
-				{
-					new iClient = GetArrayCell(hProxyCandidates, iNum);
-					new iBestAreaIndex = -1;
-					
-					if (GetArraySize(hAreaArrayClose) > 0)
-					{
-						iBestAreaIndex = GetArrayCell(hAreaArrayClose, GetRandomInt(0, GetArraySize(hAreaArrayClose) - 1));
-					}
-					else if (GetArraySize(hAreaArrayAverage) > 0)
-					{
-						iBestAreaIndex = GetArrayCell(hAreaArrayAverage, GetRandomInt(0, GetArraySize(hAreaArrayAverage) - 1));
-					}
-					else if (GetArraySize(hAreaArrayFar) > 0)
-					{
-						iBestAreaIndex = GetArrayCell(hAreaArrayFar, GetRandomInt(0, GetArraySize(hAreaArrayFar) - 1));
-					}
-					
-					if (iBestAreaIndex == -1) 
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any areas to place proxies (spawned %d)!", iBossIndex, iNum);
-#endif
-						break;
-					}
-					
-					NavMeshArea_GetCenter(iBestAreaIndex, flDestinationPos);
-					
-					if (!GetConVarBool(g_cvPlayerProxyAsk))
-					{
-						ClientStartProxyForce(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
-					}
-					else
-					{
-						DisplayProxyAskMenu(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
-					}
-				}
-				
-				CloseHandle(hAreaArrayClose);
-				CloseHandle(hAreaArrayAverage);
-				CloseHandle(hAreaArrayFar);
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d finished proxy process!", iBossIndex);
-#endif
-			}
-			
-			CloseHandle(hProxyCandidates);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-ReloadRestrictedWeapons()
-{
-	if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
-	{
-		CloseHandle(g_hRestrictedWeaponsConfig);
-		g_hRestrictedWeaponsConfig = INVALID_HANDLE;
-	}
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	BuildPath(Path_SM, buffer, sizeof(buffer), FILE_RESTRICTEDWEAPONS);
-	new Handle:kv = CreateKeyValues("root");
-	if (!FileToKeyValues(kv, buffer))
-	{
-		CloseHandle(kv);
-		LogError("Failed to load restricted weapons list! File not found!");
-	}
-	else
-	{
-		g_hRestrictedWeaponsConfig = kv;
-		LogSF2Message("Reloaded restricted weapons configuration file successfully");
-	}
-}
-
-public Action:Timer_RoundMessages(Handle:timer)
-{
-	if (!g_bEnabled) return Plugin_Stop;
-	
-	if (timer != g_hRoundMessagesTimer) return Plugin_Stop;
-	
-	switch (g_iRoundMessagesNum)
-	{
-		case 0: CPrintToChatAll("{lightgreen}Slender Fortress v %s{olive} by {lightgreen}Kit o' Rifty{olive}. {lightgreen}RYTP Horror {olive}edit by {lightgreen}lexuzieel", PLUGIN_VERSION_DISPLAY);
-		case 1: CPrintToChatAll("%t", "SF2 Ad Message 1");
-		case 2: CPrintToChatAll("%t", "SF2 Ad Message 2");
-		case 3: CPrintToChatAll("%t", "SF2 Ad Message 3");
-	}
-	
-	g_iRoundMessagesNum++;
-	if (g_iRoundMessagesNum > 3) g_iRoundMessagesNum = 0;
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_WelcomeMessage(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	CPrintToChat(client, "%T", "SF2 Welcome Message", client);
-}
-
-GetMaxPlayersForRound()
-{
-	new iOverride = GetConVarInt(g_cvMaxPlayersOverride);
-	if (iOverride != -1) return iOverride;
-	return GetConVarInt(g_cvMaxPlayers);
-}
-
-public OnConVarChanged(Handle:cvar, const String:oldValue[], const String:newValue[])
-{
-	if (cvar == g_cvDifficulty)
-	{
-		switch (StringToInt(newValue))
-		{
-			case Difficulty_Easy: g_flRoundDifficultyModifier = DIFFICULTY_EASY;
-			case Difficulty_Hard: g_flRoundDifficultyModifier = DIFFICULTY_HARD;
-			case Difficulty_Insane: g_flRoundDifficultyModifier = DIFFICULTY_INSANE;
-			default: g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
-		}
-	}
-	else if (cvar == g_cvMaxPlayers || cvar == g_cvMaxPlayersOverride)
-	{
-		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-		{
-			CheckPlayerGroup(i);
-		}
-	}
-	else if (cvar == g_cvPlayerShakeEnabled)
-	{
-		g_bPlayerShakeEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvPlayerViewbobEnabled)
-	{
-		g_bPlayerViewbobEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvPlayerViewbobHurtEnabled)
-	{
-		g_bPlayerViewbobHurtEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvPlayerViewbobSprintEnabled)
-	{
-		g_bPlayerViewbobSprintEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvGravity)
-	{
-		g_flGravity = StringToFloat(newValue);
-	}
-	else if (cvar == g_cv20Dollars)
-	{
-		g_b20Dollars = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvAllChat)
-	{
-		if (g_bEnabled)
-		{
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				ClientUpdateListeningFlags(i);
-			}
-		}
-	}
-}
-
-//	==========================================================
-//	IN-GAME AND ENTITY HOOK FUNCTIONS
-//	==========================================================
-
-
-public OnEntityCreated(ent, const String:classname[])
-{
-	if (!g_bEnabled) return;
-	
-	if (!IsValidEntity(ent) || ent <= 0) return;
-	
-	if (StrEqual(classname, "spotlight_end", false))
-	{
-		SDKHook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
-	}
-	else if (StrEqual(classname, "beam", false))
-	{
-		SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightBeamSetTransmit);
-	}
-	
-	PvP_OnEntityCreated(ent, classname);
-}
-
-public OnEntityDestroyed(ent)
-{
-	if (!g_bEnabled) return;
-
-	if (!IsValidEntity(ent) || ent <= 0) return;
-	
-	decl String:sClassname[64];
-	GetEntityClassname(ent, sClassname, sizeof(sClassname));
-	
-	if (StrEqual(sClassname, "light_dynamic", false))
-	{
-		AcceptEntityInput(ent, "TurnOff");
-		
-		new iEnd = INVALID_ENT_REFERENCE;
-		while ((iEnd = FindEntityByClassname(iEnd, "spotlight_end")) != -1)
-		{
-			if (GetEntPropEnt(iEnd, Prop_Data, "m_hOwnerEntity") == ent)
-			{
-				AcceptEntityInput(iEnd, "Kill");
-				break;
-			}
-		}
-	}
-	
-	PvP_OnEntityDestroyed(ent, sClassname);
-}
-
-public Action:Hook_BlockUserMessage(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init) 
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	return Plugin_Handled;
-}
-
-public Action:Hook_NormalSound(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsValidClient(entity))
-	{
-		if (IsClientInGhostMode(entity))
-		{
-			switch (channel)
-			{
-				case SNDCHAN_VOICE, SNDCHAN_WEAPON, SNDCHAN_ITEM, SNDCHAN_BODY: return Plugin_Handled;
-			}
-		}
-		else if (g_bPlayerProxy[entity])
-		{
-			new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[entity]);
-			if (iMaster != -1)
-			{
-				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-				NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
-				
-				switch (channel)
-				{
-					case SNDCHAN_VOICE:
-					{
-						if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
-						{
-							return Plugin_Handled;
-						}
-					}
-				}
-			}
-		}
-		else if (!g_bPlayerEliminated[entity])
-		{
-			switch (channel)
-			{
-				case SNDCHAN_VOICE:
-				{
-					if (IsRoundInIntro()) return Plugin_Handled;
-				
-					for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-					{
-						if (NPCGetUniqueID(iBossIndex) == -1) continue;
-						
-						if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Voice))
-						{
-							GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
-							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
-							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDVOICE;
-						}
-					}
-				}
-				case SNDCHAN_BODY:
-				{
-					if (!StrContains(sample, "player/footsteps", false) || StrContains(sample, "step", false) != -1)
-					{
-						if (GetConVarBool(g_cvPlayerViewbobSprintEnabled) && IsClientReallySprinting(entity))
-						{
-							// Viewpunch.
-							new Float:flPunchVelStep[3];
-							
-							decl Float:flVelocity[3];
-							GetEntPropVector(entity, Prop_Data, "m_vecAbsVelocity", flVelocity);
-							new Float:flSpeed = GetVectorLength(flVelocity);
-							
-							flPunchVelStep[0] = flSpeed / 300.0;
-							flPunchVelStep[1] = 0.0;
-							flPunchVelStep[2] = 0.0;
-							
-							ClientViewPunch(entity, flPunchVelStep);
-						}
-						
-						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-						{
-							if (NPCGetUniqueID(iBossIndex) == -1) continue;
-							
-							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Footstep))
-							{
-								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEP;
-								
-								if (IsClientSprinting(entity) && !(GetEntProp(entity, Prop_Send, "m_bDucking") || GetEntProp(entity, Prop_Send, "m_bDucked")))
-								{
-									g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEPLOUD;
-								}
-							}
-						}
-					}
-				}
-				case SNDCHAN_ITEM, SNDCHAN_WEAPON:
-				{
-					if (StrContains(sample, "impact", false) != -1 || StrContains(sample, "hit", false) != -1)
-					{
-						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-						{
-							if (NPCGetUniqueID(iBossIndex) == -1) continue;
-							
-							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Weapon))
-							{
-								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDWEAPON;
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	/*
-	new bool:bModified = false;
-	
-	for (new i = 0; i < numClients; i++)
-	{
-		new iClient = clients[i];
-		if (IsValidClient(iClient) && IsPlayerAlive(iClient) && !IsClientInGhostMode(iClient))
-		{
-			new bool:bCanHearSound = true;
-			
-			if (IsValidClient(entity) && entity != iClient)
-			{
-				if (!g_bPlayerEliminated[iClient])
-				{
-					if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-					{
-						if (!g_bPlayerEliminated[entity] && !DidClientEscape(entity))
-						{
-							bCanHearSound = false;
-						}
-					}
-				}
-			}
-			
-			if (!bCanHearSound)
-			{
-				bModified = true;
-				clients[i] = -1;
-			}
-		}
-	}
-	
-	if (bModified) return Plugin_Changed;
-	*/
-	return Plugin_Continue;
-}
-
-public MRESReturn:Hook_EntityShouldTransmit(thisPointer, Handle:hReturn, Handle:hParams)
-{
-	if (!g_bEnabled) return MRES_Ignored;
-	
-	if (IsValidClient(thisPointer))
-	{
-		if (DoesClientHaveConstantGlow(thisPointer))
-		{
-			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
-			return MRES_Supercede;
-		}
-	}
-	else
-	{
-		new iBossIndex = NPCGetFromEntIndex(thisPointer);
-		if (iBossIndex != -1)
-		{
-			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
-			return MRES_Supercede;
-		}
-	}
-	
-	return MRES_Ignored;
-}
-
-public Hook_TriggerOnStartTouch(const String:output[], caller, activator, Float:delay)
-{
-	if (!g_bEnabled) return;
-
-	if (!IsValidEntity(caller)) return;
-	
-	decl String:sName[64];
-	GetEntPropString(caller, Prop_Data, "m_iName", sName, sizeof(sName));
-	
-	if (StrContains(sName, "sf2_escape_trigger", false) == 0)
-	{
-		if (IsRoundInEscapeObjective())
-		{
-			if (IsValidClient(activator) && IsPlayerAlive(activator) && !IsClientInDeathCam(activator) && !g_bPlayerEliminated[activator] && !DidClientEscape(activator))
-			{
-				ClientEscape(activator);
-				TeleportClientToEscapePoint(activator);
-			}
-		}
-	}
-	
-	PvP_OnTriggerStartTouch(caller, activator);
-}
-
-public Hook_TriggerOnEndTouch(const String:sOutput[], caller, activator, Float:flDelay)
-{
-	if (!g_bEnabled) return;
-	
-	PvP_OnTriggerEndTouch(caller, activator);
-}
-
-public Action:Hook_PageOnTakeDamage(page, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsValidClient(attacker))
-	{
-		if (!g_bPlayerEliminated[attacker])
-		{
-			if (damagetype & 0x80) // 0x80 == melee damage
-			{
-				SetPageCount(g_iPageCount + 1);
-				g_iPlayerPageCount[attacker] += 1;
-				EmitSoundToAll(PAGE_GRABSOUND, attacker, SNDCHAN_ITEM, SNDLEVEL_SCREAMING);
-				
-				// Gives points. Credit to the makers of VSH/FF2.
-				new Handle:hEvent = CreateEvent("player_escort_score", true);
-				SetEventInt(hEvent, "player", attacker);
-				SetEventInt(hEvent, "points", 1);
-				FireEvent(hEvent);
-				
-				AcceptEntityInput(page, "FireUser1");
-				AcceptEntityInput(page, "Kill");
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	GENERIC CLIENT HOOKS AND FUNCTIONS
-//	==========================================================
-
-
-public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	ClientDisableFakeLagCompensation(client);
-	
-	// Check impulse (block spraying and built-in flashlight)
-	switch (impulse)
-	{
-		case 100:
-		{
-			impulse = 0;
-		}
-		case 201:
-		{
-			if (IsClientInGhostMode(client))
-			{
-				impulse = 0;
-			}
-		}
-	}
-	
-	for (new i = 0; i < MAX_BUTTONS; i++)
-	{
-		new button = (1 << i);
-		
-		if ((buttons & button))
-		{
-			if (!(g_iPlayerLastButtons[client] & button))
-			{
-				ClientOnButtonPress(client, button);
-			}
-		}
-		else if ((g_iPlayerLastButtons[client] & button))
-		{
-			ClientOnButtonRelease(client, button);
-		}
-	}
-	
-	g_iPlayerLastButtons[client] = buttons;
-	
-	return Plugin_Continue;
-}
-
-
-public OnClientCookiesCached(client)
-{
-	if (!g_bEnabled) return;
-	
-	// Load our saved settings.
-	new String:sCookie[64];
-	GetClientCookie(client, g_hCookie, sCookie, sizeof(sCookie));
-	
-	if (!sCookie[0])
-	{
-		g_iPlayerQueuePoints[client] = 0;
-		
-		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
-		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
-		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
-	}
-	else
-	{
-		new String:s2[12][32];
-		ExplodeString(sCookie, " ; ", s2, 12, 32);
-		
-		g_iPlayerQueuePoints[client] = StringToInt(s2[0]);
-		
-		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = bool:StringToInt(s2[1]);
-		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode:StringToInt(s2[2]);
-		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = bool:StringToInt(s2[4]);
-	}
-}
-
-public OnClientPutInServer(client)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientPutInServer(%d)", client);
-#endif
-	
-	ClientSetPlayerGroup(client, -1);
-	
-	g_bPlayerEscaped[client] = false;
-	g_bPlayerEliminated[client] = true;
-	g_bPlayerChoseTeam[client] = false;
-	g_bPlayerPlayedSpecialRound[client] = true;
-	g_bPlayerPlayedNewBossRound[client] = true;
-	
-	g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn] = false;
-	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
-	
-	g_iPlayerPageCount[client] = 0;
-	g_iPlayerDesiredFOV[client] = 90;
-	
-	SDKHook(client, SDKHook_PreThink, Hook_ClientPreThink);
-	SDKHook(client, SDKHook_SetTransmit, Hook_ClientSetTransmit);
-	SDKHook(client, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage);
-	
-	DHookEntity(g_hSDKWantsLagCompensationOnEntity, true, client); 
-	DHookEntity(g_hSDKShouldTransmit, true, client);
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		
-		SetPlayerGroupInvitedPlayer(i, client, false);
-		SetPlayerGroupInvitedPlayerCount(i, client, 0);
-		SetPlayerGroupInvitedPlayerTime(i, client, 0.0);
-	}
-	
-	ClientDisableFakeLagCompensation(client);
-	
-	ClientResetStatic(client);
-	ClientResetSlenderStats(client);
-	ClientResetCampingStats(client);
-	ClientResetOverlay(client);
-	ClientResetJumpScare(client);
-	ClientUpdateListeningFlags(client);
-	ClientUpdateMusicSystem(client);
-	ClientChaseMusicReset(client);
-	ClientChaseMusicSeeReset(client);
-	ClientAlertMusicReset(client);
-	Client20DollarsMusicReset(client);
-	ClientMusicReset(client);
-	ClientResetProxy(client);
-	ClientResetHints(client);
-	ClientResetScare(client);
-	
-	ClientResetDeathCam(client);
-	ClientResetFlashlight(client);
-	ClientDeactivateUltravision(client);
-	ClientResetSprint(client);
-	ClientResetBreathing(client);
-	ClientResetBlink(client);
-	ClientResetInteractiveGlow(client);
-	ClientDisableConstantGlow(client);
-	
-	ClientSetScareBoostEndTime(client, -1.0);
-	
-	ClientStartProxyAvailableTimer(client);
-	
-	if (!IsFakeClient(client))
-	{
-		// See if the player is using the projected flashlight.
-		QueryClientConVar(client, "mat_supportflashlight", OnClientGetProjectedFlashlightSetting);
-		
-		// Get desired FOV.
-		QueryClientConVar(client, "fov_desired", OnClientGetDesiredFOV);
-	}
-	
-	PvP_OnClientPutInServer(client);
-	
-#if defined DEBUG
-	g_iPlayerDebugFlags[client] = 0;
-
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientPutInServer(%d)", client);
-#endif
-}
-
-public OnClientGetProjectedFlashlightSetting(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
-{
-	if (result != ConVarQuery_Okay) 
-	{
-		LogError("Warning: Player %N failed to query for ConVar mat_supportflashlight", client);
-		return;
-	}
-	
-	if (StringToInt(cvarValue))
-	{
-		decl String:sAuth[64];
-		GetClientAuthString(client, sAuth, sizeof(sAuth));
-		
-		g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = true;
-		LogSF2Message("Player %N (%s) has mat_supportflashlight enabled, projected flashlight will be used", client, sAuth);
-	}
-}
-
-public OnClientGetDesiredFOV(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
-{
-	if (!IsValidClient(client)) return;
-	
-	g_iPlayerDesiredFOV[client] = StringToInt(cvarValue);
-}
-
-public OnClientDisconnect(client)
-{
-	DestroySpriteOverlay(client);
-	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
-	
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientDisconnect(%d)", client);
-#endif
-	
-	g_bPlayerEscaped[client] = false;
-	
-	// Save and reset settings for the next client.
-	ClientSaveCookies(client);
-	ClientSetPlayerGroup(client, -1);
-	
-	// Reset variables.
-	g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
-	g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
-	g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
-	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
-	
-	// Reset any client functions that may be still active.
-	ClientResetOverlay(client);
-	ClientResetFlashlight(client);
-	ClientDeactivateUltravision(client);
-	ClientSetGhostModeState(client, false);
-	ClientResetInteractiveGlow(client);
-	ClientDisableConstantGlow(client);
-	
-	ClientStopProxyForce(client);
-	
-	if (!IsRoundInWarmup())
-	{
-		if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
-		{
-			if (g_bRoundGrace)
-			{
-				// Force the next player in queue to take my place, if any.
-				ForceInNextPlayersInQueue(1, true);
-			}
-			else
-			{
-				if (!IsRoundEnding()) 
-				{
-					CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
-				}
-			}
-		}
-	}
-	
-	// Reset queue points global variable.
-	g_iPlayerQueuePoints[client] = 0;
-	
-	PvP_OnClientDisconnect(client);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientDisconnect(%d)", client);
-#endif
-}
-
-public OnClientDisconnect_Post(client)
-{
-    g_iPlayerLastButtons[client] = 0;
-}
-
-public TF2_OnWaitingForPlayersStart()
-{
-	g_bRoundWaitingForPlayers = true;
-}
-
-public TF2_OnWaitingForPlayersEnd()
-{
-	g_bRoundWaitingForPlayers = false;
-}
-
-SF2RoundState:GetRoundState()
-{
-	return g_iRoundState;
-}
-
-SetRoundState(SF2RoundState:iRoundState)
-{
-	if (g_iRoundState == iRoundState) return;
-	
-	PrintToServer("SetRoundState(%d)", iRoundState);
-	
-	new SF2RoundState:iOldRoundState = GetRoundState();
-	g_iRoundState = iRoundState;
-	
-	// Cleanup from old roundstate if needed.
-	switch (iOldRoundState)
-	{
-		case SF2RoundState_Waiting:
-		{
-		}
-		case SF2RoundState_Intro:
-		{
-			g_hRoundIntroTimer = INVALID_HANDLE;
-		}
-		case SF2RoundState_Active:
-		{
-			g_bRoundGrace = false;
-			g_hRoundGraceTimer = INVALID_HANDLE;
-			g_hRoundTimer = INVALID_HANDLE;
-		}
-		case SF2RoundState_Escape:
-		{
-			g_hRoundTimer = INVALID_HANDLE;
-		}
-		case SF2RoundState_Outro:
-		{
-		}
-	}
-	
-	switch (g_iRoundState)
-	{
-		case SF2RoundState_Waiting:
-		{
-		}
-		case SF2RoundState_Intro:
-		{
-			g_hRoundIntroTimer = INVALID_HANDLE;
-			g_iRoundIntroText = 0;
-			g_bRoundIntroTextDefault = false;
-			g_hRoundIntroTextTimer = CreateTimer(0.0, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
-			TriggerTimer(g_hRoundIntroTextTimer);
-			
-			// Gather data on the intro parameters set by the map.
-			new Float:flHoldTime = g_flRoundIntroFadeHoldTime;
-			g_hRoundIntroTimer = CreateTimer(flHoldTime, Timer_ActivateRoundFromIntro, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			// Trigger any intro logic entities, if any.
-			new ent = -1;
-			while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
-			{
-				decl String:sName[64];
-				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-				if (StrEqual(sName, "sf2_intro_relay", false))
-				{
-					AcceptEntityInput(ent, "Trigger");
-					break;
-				}
-			}
-		}
-		case SF2RoundState_Active:
-		{
-			// Start the grace period timer.
-			g_bRoundGrace = true;
-			g_hRoundGraceTimer = CreateTimer(GetConVarFloat(g_cvGraceTime), Timer_RoundGrace, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			CreateTimer(2.0, Timer_RoundStart, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			// Enable movement on players.
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
-				SetEntityFlags(i, GetEntityFlags(i) & ~FL_FROZEN);
-			}
-			
-			// Fade in.
-			new Float:flFadeTime = g_flRoundIntroFadeDuration;
-			new iFadeFlags = SF_FADE_IN | FFADE_PURGE;
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
-				UTIL_ScreenFade(i, FixedUnsigned16(flFadeTime, 1 << 12), 0, iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
-			}
-		}
-		case SF2RoundState_Escape:
-		{
-			// Initialize the escape timer, if needed.
-			if (g_iRoundEscapeTimeLimit > 0)
-			{
-				g_iRoundTime = g_iRoundEscapeTimeLimit;
-				g_hRoundTimer = CreateTimer(1.0, Timer_RoundTimeEscape, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			}
-			else
-			{
-				g_hRoundTimer = INVALID_HANDLE;
-			}
-		
-			decl String:sName[32];
-			new ent = -1;
-			while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-			{
-				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-				if (StrEqual(sName, "sf2_logic_escape", false))
-				{
-					AcceptEntityInput(ent, "FireUser1");
-					break;
-				}
-			}
-		}
-		case SF2RoundState_Outro:
-		{
-			if (!g_bRoundHasEscapeObjective)
-			{
-				// Teleport winning players to the escape point.
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i)) continue;
-					
-					if (!g_bPlayerEliminated[i])
-					{
-						TeleportClientToEscapePoint(i);
-					}
-				}
-			}
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i)) continue;
-				
-				if (IsClientInGhostMode(i))
-				{
-					// Take the player out of ghost mode.
-					ClientSetGhostModeState(i, false);	
-					TF2_RespawnPlayer(i);
-				}
-				else if (g_bPlayerProxy[i])
-				{
-					TF2_RespawnPlayer(i);
-				}
-				
-				if (!g_bPlayerEliminated[i])
-				{
-					// Give them back all their weapons so they can beat the crap out of the other team.
-					TF2_RegeneratePlayer(i);
-				}
-				
-				ClientUpdateListeningFlags(i);
-			}
-		}
-	}
-}
-
-bool:IsRoundInEscapeObjective()
-{
-	return bool:(GetRoundState() == SF2RoundState_Escape);
-}
-
-bool:IsRoundInWarmup()
-{
-	return bool:(GetRoundState() == SF2RoundState_Waiting);
-}
-
-bool:IsRoundInIntro()
-{
-	return bool:(GetRoundState() == SF2RoundState_Intro);
-}
-
-bool:IsRoundEnding()
-{
-	return bool:(GetRoundState() == SF2RoundState_Outro);
-}
-
-bool:IsInfiniteBlinkEnabled()
-{
-	return bool:(g_bRoundInfiniteBlink || (GetConVarInt(g_cvPlayerInfiniteBlinkOverride) == 1));
-}
-
-bool:IsInfiniteFlashlightEnabled()
-{
-	return bool:(g_bRoundInfiniteFlashlight || (GetConVarInt(g_cvPlayerInfiniteFlashlightOverride) == 1));
-}
-
-bool:IsInfiniteSprintEnabled()
-{
-	return bool:(g_bRoundInfiniteSprint || (GetConVarInt(g_cvPlayerInfiniteSprintOverride) == 1));
-}
-
-
-#define SF2_PLAYER_HUD_BLINK_SYMBOL "B"
-#define SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL "ÏŸ"
-#define SF2_PLAYER_HUD_BAR_SYMBOL "|"
-#define SF2_PLAYER_HUD_BAR_MISSING_SYMBOL ""
-#define SF2_PLAYER_HUD_INFINITY_SYMBOL "∞"
-#define SF2_PLAYER_HUD_SPRINT_SYMBOL "»"
-
-public Action:Timer_ClientAverageUpdate(Handle:timer)
-{
-	if (timer != g_hClientAverageUpdateTimer) return Plugin_Stop;
-	
-	if (!g_bEnabled) return Plugin_Stop;
-	
-	if (IsRoundInWarmup() || IsRoundEnding()) return Plugin_Continue;
-	
-	// First, process through HUD stuff.
-	decl String:buffer[256];
-	
-	static iHudColorHealthy[3] = { 150, 255, 150 };
-	static iHudColorCritical[3] = { 255, 10, 10 };
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (IsPlayerAlive(i) && !IsClientInDeathCam(i))
-		{
-			if (!g_bPlayerEliminated[i])
-			{
-				if (DidClientEscape(i)) continue;
-				
-				new iMaxBars = 12;
-				new iBars = RoundToCeil(float(iMaxBars) * ClientGetBlinkMeter(i));
-				if (iBars > iMaxBars) iBars = iMaxBars;
-				
-				Format(buffer, sizeof(buffer), "%s  ", SF2_PLAYER_HUD_BLINK_SYMBOL);
-				
-				if (IsInfiniteBlinkEnabled())
-				{
-					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
-				}
-				else
-				{
-					for (new i2 = 0; i2 < iMaxBars; i2++) 
-					{
-						if (i2 < iBars)
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-						}
-						else
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
-						}
-					}
-				}
-				
-				if (!g_bSpecialRound || g_iSpecialRoundType != SPECIALROUND_LIGHTSOUT)
-				{
-					iBars = RoundToCeil(float(iMaxBars) * ClientGetFlashlightBatteryLife(i));
-					if (iBars > iMaxBars) iBars = iMaxBars;
-					
-					decl String:sBuffer2[64];
-					Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL);
-					StrCat(buffer, sizeof(buffer), sBuffer2);
-					
-					if (IsInfiniteFlashlightEnabled())
-					{
-						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
-					}
-					else
-					{
-						for (new i2 = 0; i2 < iMaxBars; i2++) 
-						{
-							if (i2 < iBars)
-							{
-								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-							}
-							else
-							{
-								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
-							}
-						}
-					}
-				}
-				
-				iBars = RoundToCeil(float(iMaxBars) * (float(ClientGetSprintPoints(i)) / 100.0));
-				if (iBars > iMaxBars) iBars = iMaxBars;
-				
-				decl String:sBuffer2[64];
-				Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_SPRINT_SYMBOL);
-				StrCat(buffer, sizeof(buffer), sBuffer2);
-				
-				if (IsInfiniteSprintEnabled())
-				{
-					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
-				}
-				else
-				{
-					for (new i2 = 0; i2 < iMaxBars; i2++) 
-					{
-						if (i2 < iBars)
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-						}
-						else
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
-						}
-					}
-				}
-				
-				
-				new Float:flHealthRatio = float(GetEntProp(i, Prop_Send, "m_iHealth")) / float(SDKCall(g_hSDKGetMaxHealth, i));
-				
-				new iColor[3];
-				for (new i2 = 0; i2 < 3; i2++)
-				{
-					iColor[i2] = RoundFloat(float(iHudColorHealthy[i2]) + (float(iHudColorCritical[i2] - iHudColorHealthy[i2]) * (1.0 - flHealthRatio)));
-				}
-				
-				SetHudTextParams(0.035, 0.83,
-					0.3,
-					iColor[0],
-					iColor[1],
-					iColor[2],
-					40,
-					_,
-					1.0,
-					0.07,
-					0.5);
-				ShowSyncHudText(i, g_hHudSync2, buffer);
-			}
-			else
-			{
-				if (g_bPlayerProxy[i])
-				{
-					new iMaxBars = 12;
-					new iBars = RoundToCeil(float(iMaxBars) * (float(g_iPlayerProxyControl[i]) / 100.0));
-					if (iBars > iMaxBars) iBars = iMaxBars;
-					
-					strcopy(buffer, sizeof(buffer), "CONTROL\n");
-					
-					for (new i2 = 0; i2 < iBars; i2++)
-					{
-						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-					}
-					
-					SetHudTextParams(-1.0, 0.83,
-						0.3,
-						SF2_HUD_TEXT_COLOR_R,
-						SF2_HUD_TEXT_COLOR_G,
-						SF2_HUD_TEXT_COLOR_B,
-						40,
-						_,
-						1.0,
-						0.07,
-						0.5);
-					ShowSyncHudText(i, g_hHudSync2, buffer);
-				}
-			}
-		}
-		
-		ClientUpdateListeningFlags(i);
-		ClientUpdateMusicSystem(i);
-	}
-	
-	return Plugin_Continue;
-}
-
-stock bool:IsClientParticipating(client)
-{
-	if (!IsValidClient(client)) return false;
-	
-	if (bool:GetEntProp(client, Prop_Send, "m_bIsCoaching")) 
-	{
-		// Who would coach in this game?
-		return false;
-	}
-	
-	new iTeam = GetClientTeam(client);
-	
-	if (g_bPlayerLagCompensation[client]) 
-	{
-		iTeam = g_iPlayerLagCompensationTeam[client];
-	}
-	
-	switch (iTeam)
-	{
-		case TFTeam_Unassigned, TFTeam_Spectator: return false;
-	}
-	
-	if (_:TF2_GetPlayerClass(client) == 0)
-	{
-		// Player hasn't chosen a class? What.
-		return false;
-	}
-	
-	return true;
-}
-
-Handle:GetQueueList()
-{
-	new Handle:hArray = CreateArray(3);
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientParticipating(i)) continue;
-		if (IsPlayerGroupActive(ClientGetPlayerGroup(i))) continue;
-		
-		new index = PushArrayCell(hArray, i);
-		SetArrayCell(hArray, index, g_iPlayerQueuePoints[i], 1);
-		SetArrayCell(hArray, index, false, 2);
-	}
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		new index = PushArrayCell(hArray, i);
-		SetArrayCell(hArray, index, GetPlayerGroupQueuePoints(i), 1);
-		SetArrayCell(hArray, index, true, 2);
-	}
-	
-	if (GetArraySize(hArray)) SortADTArrayCustom(hArray, SortQueueList);
-	return hArray;
-}
-
-SetClientPlayState(client, bool:bState, bool:bEnablePlay=true)
-{
-	if (bState)
-	{
-		if (!g_bPlayerEliminated[client]) return;
-		
-		g_bPlayerEliminated[client] = false;
-		g_bPlayerPlaying[client] = bEnablePlay;
-		g_hPlayerSwitchBlueTimer[client] = INVALID_HANDLE;
-		
-		ClientSetGhostModeState(client, false);
-		
-		PvP_SetPlayerPvPState(client, false, false, false);
-		
-		if (g_bSpecialRound) 
-		{
-			SetClientPlaySpecialRoundState(client, true);
-		}
-		
-		if (g_bNewBossRound) 
-		{
-			SetClientPlayNewBossRoundState(client, true);
-		}
-		
-		if (TF2_GetPlayerClass(client) == TFClassType:0)
-		{
-			// Player hasn't chosen a class for some reason. Choose one for him.
-			TF2_SetPlayerClass(client, TFClassType:GetRandomInt(1, 9), true, true);
-		}
-		
-		ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
-	}
-	else
-	{
-		if (g_bPlayerEliminated[client]) return;
-		
-		g_bPlayerEliminated[client] = true;
-		g_bPlayerPlaying[client] = false;
-		
-		ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
-	}
-}
-
-SetClientPlayNewBossRoundState(client, bool:bState)
-{
-	g_bPlayerPlayedNewBossRound[client] = bState;
-}
-
-SetClientPlaySpecialRoundState(client, bool:bState)
-{
-	g_bPlayerPlayedSpecialRound[client] = bState;
-}
-
-TeleportClientToEscapePoint(client)
-{
-	if (!IsClientInGame(client)) return;
-	
-	new ent = EntRefToEntIndex(g_iRoundEscapePointEntity);
-	if (ent && ent != -1)
-	{
-		decl Float:flPos[3], Float:flAng[3];
-		GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
-		GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", flAng);
-		
-		TeleportEntity(client, flPos, flAng, Float:{ 0.0, 0.0, 0.0 });
-		AcceptEntityInput(ent, "FireUser1", client);
-	}
-}
-
-ForceInNextPlayersInQueue(iAmount, bool:bShowMessage=false)
-{
-	// Grab the next person in line, or the next group in line if space allows.
-	new iAmountLeft = iAmount;
-	new Handle:hPlayers = CreateArray();
-	new Handle:hArray = GetQueueList();
-	
-	for (new i = 0, iSize = GetArraySize(hArray); i < iSize && iAmountLeft > 0; i++)
-	{
-		if (!GetArrayCell(hArray, i, 2))
-		{
-			new iClient = GetArrayCell(hArray, i);
-			if (g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
-			
-			PushArrayCell(hPlayers, iClient);
-			iAmountLeft--;
-		}
-		else
-		{
-			new iGroupIndex = GetArrayCell(hArray, i);
-			if (!IsPlayerGroupActive(iGroupIndex)) continue;
-			
-			new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
-			if (iMemberCount <= iAmountLeft)
-			{
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsValidClient(iClient) || g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
-					if (ClientGetPlayerGroup(iClient) == iGroupIndex)
-					{
-						PushArrayCell(hPlayers, iClient);
-					}
-				}
-				
-				SetPlayerGroupPlaying(iGroupIndex, true);
-				
-				iAmountLeft -= iMemberCount;
-			}
-		}
-	}
-	
-	CloseHandle(hArray);
-	
-	for (new i = 0, iSize = GetArraySize(hPlayers); i < iSize; i++)
-	{
-		new iClient = GetArrayCell(hPlayers, i);
-		ClientSetQueuePoints(iClient, 0);
-		SetClientPlayState(iClient, true);
-		
-		if (bShowMessage) CPrintToChat(iClient, "%T", "SF2 Force Play", iClient);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public SortQueueList(index1, index2, Handle:array, Handle:hndl)
-{
-	new iQueuePoints1 = GetArrayCell(array, index1, 1);
-	new iQueuePoints2 = GetArrayCell(array, index2, 1);
-	
-	if (iQueuePoints1 > iQueuePoints2) return -1;
-	else if (iQueuePoints1 == iQueuePoints2) return 0;
-	return 1;
-}
-
-//	==========================================================
-//	GENERIC PAGE/BOSS HOOKS AND FUNCTIONS
-//	==========================================================
-
-public Action:Hook_SlenderObjectSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (!IsPlayerAlive(other) || IsClientInDeathCam(other))
-	{
-		if (!IsValidEdict(GetEntPropEnt(other, Prop_Send, "m_hObserverTarget"))) return Plugin_Handled;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_SlenderBlinkBossThink(Handle:timer, any:entref)
-{
-	new slender = EntRefToEntIndex(entref);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return Plugin_Stop;
-	
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	if (timer != g_hSlenderEntityThink[iBossIndex]) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (NPCGetType(iBossIndex) == SF2BossType_Creeper)
-	{
-		new bool:bMove = false;
-		
-		if ((GetGameTime() - g_flSlenderLastKill[iBossIndex]) >= GetProfileFloat(sProfile, "kill_cooldown"))
-		{
-			if (PeopleCanSeeSlender(iBossIndex, false, false) && !PeopleCanSeeSlender(iBossIndex, true, SlenderUsesBlink(iBossIndex)))
-			{
-				new iBestPlayer = -1;
-				new Handle:hArray = CreateArray();
-				
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientInDeathCam(i) || g_bPlayerEliminated[i] || DidClientEscape(i) || IsClientInGhostMode(i) || !PlayerCanSeeSlender(i, iBossIndex, false, false)) continue;
-					PushArrayCell(hArray, i);
-				}
-				
-				if (GetArraySize(hArray))
-				{
-					decl Float:flSlenderPos[3];
-					SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
-					
-					decl Float:flTempPos[3];
-					new iTempPlayer = -1;
-					new Float:flTempDist = 16384.0;
-					for (new i = 0; i < GetArraySize(hArray); i++)
-					{
-						new iClient = GetArrayCell(hArray, i);
-						GetClientAbsOrigin(iClient, flTempPos);
-						if (GetVectorDistance(flTempPos, flSlenderPos) < flTempDist)
-						{
-							iTempPlayer = iClient;
-							flTempDist = GetVectorDistance(flTempPos, flSlenderPos);
-						}
-					}
-					
-					iBestPlayer = iTempPlayer;
-				}
-				
-				CloseHandle(hArray);
-				
-				decl Float:buffer[3];
-				if (iBestPlayer != -1 && SlenderCalculateApproachToPlayer(iBossIndex, iBestPlayer, buffer))
-				{
-					bMove = true;
-					
-					decl Float:flAng[3], Float:flBuffer[3];
-					decl Float:flSlenderPos[3], Float:flPos[3];
-					GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flSlenderPos);
-					GetClientAbsOrigin(iBestPlayer, flPos);
-					SubtractVectors(flPos, buffer, flAng);
-					GetVectorAngles(flAng, flAng);
-					
-					// Take care of angle offsets.
-					AddVectors(flAng, g_flSlenderEyeAngOffset[iBossIndex], flAng);
-					for (new i = 0; i < 3; i++) flAng[i] = AngleNormalize(flAng[i]);
-					
-					flAng[0] = 0.0;
-					
-					// Take care of position offsets.
-					GetProfileVector(sProfile, "pos_offset", flBuffer);
-					AddVectors(buffer, flBuffer, buffer);
-					
-					TeleportEntity(slender, buffer, flAng, NULL_VECTOR);
-					
-					new Float:flMaxRange = GetProfileFloat(sProfile, "teleport_range_max");
-					new Float:flDist = GetVectorDistance(buffer, flPos);
-					
-					decl String:sBuffer[PLATFORM_MAX_PATH];
-					
-					if (flDist < (flMaxRange * 0.33)) 
-					{
-						GetProfileString(sProfile, "model_closedist", sBuffer, sizeof(sBuffer));
-					}
-					else if (flDist < (flMaxRange * 0.66)) 
-					{
-						GetProfileString(sProfile, "model_averagedist", sBuffer, sizeof(sBuffer));
-					}
-					else 
-					{
-						GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
-					}
-					
-					// Fallback if error.
-					if (!sBuffer[0]) GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
-					
-					SetEntProp(slender, Prop_Send, "m_nModelIndex", PrecacheModel(sBuffer));
-					
-					if (flDist <= NPCGetInstantKillRadius(iBossIndex))
-					{
-						if (NPCGetFlags(iBossIndex) & SFF_FAKE)
-						{
-							SlenderMarkAsFake(iBossIndex);
-							return Plugin_Stop;
-						}
-						else
-						{
-							g_flSlenderLastKill[iBossIndex] = GetGameTime();
-							ClientStartDeathCam(iBestPlayer, iBossIndex, buffer);
-						}
-					}
-				}
-			}
-		}
-		
-		if (bMove)
-		{
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_move_single", sBuffer, sizeof(sBuffer));
-			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-			
-			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
-			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, SND_CHANGEVOL);
-		}
-		else
-		{
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
-			if (sBuffer[0]) StopSound(slender, SNDCHAN_AUTO, sBuffer);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-
-SlenderOnClientStressUpdate(client)
-{
-	new Float:flStress = g_flPlayerStress[client];
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-	{	
-		if (NPCGetUniqueID(iBossIndex) == -1) continue;
-		
-		new iBossFlags = NPCGetFlags(iBossIndex);
-		if (iBossFlags & SFF_MARKEDASFAKE ||
-			iBossFlags & SFF_NOTELEPORT)
-		{
-			continue;
-		}
-		
-		NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-		
-		new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
-		if (iTeleportTarget && iTeleportTarget != INVALID_ENT_REFERENCE)
-		{
-			if (g_bPlayerEliminated[iTeleportTarget] ||
-				DidClientEscape(iTeleportTarget) ||
-				flStress >= g_flSlenderTeleportMaxTargetStress[iBossIndex] ||
-				GetGameTime() >= g_flSlenderTeleportMaxTargetTime[iBossIndex])
-			{
-				// Queue for a new target and mark the old target in the rest period.
-				new Float:flRestPeriod = GetProfileFloat(sProfile, "teleport_target_rest_period", 15.0);
-				flRestPeriod = (flRestPeriod * GetRandomFloat(0.92, 1.08)) / (NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier);
-				
-				g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-				g_flSlenderTeleportPlayersRestTime[iBossIndex][iTeleportTarget] = GetGameTime() + flRestPeriod;
-				g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
-				g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
-				g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: lost target, putting at rest period", iBossIndex);
-#endif
-			}
-		}
-		else if (!g_bRoundGrace)
-		{
-			new iPreferredTeleportTarget = INVALID_ENT_REFERENCE;
-			
-			new Float:flTargetStressMin = GetProfileFloat(sProfile, "teleport_target_stress_min", 0.2);
-			new Float:flTargetStressMax = GetProfileFloat(sProfile, "teleport_target_stress_max", 0.9);
-			
-			new Float:flTargetStress = flTargetStressMax - ((flTargetStressMax - flTargetStressMin) / (g_flRoundDifficultyModifier * NPCGetAnger(iBossIndex)));
-			
-			new Float:flPreferredTeleportTargetStress = flTargetStress;
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) ||
-					!IsPlayerAlive(i) ||
-					g_bPlayerEliminated[i] ||
-					IsClientInGhostMode(i) ||
-					DidClientEscape(i))
-				{
-					continue;
-				}
-				
-				if (g_flPlayerStress[i] < flPreferredTeleportTargetStress)
-				{
-					if (g_flSlenderTeleportPlayersRestTime[iBossIndex][i] <= GetGameTime())
-					{
-						iPreferredTeleportTarget = i;
-						flPreferredTeleportTargetStress = g_flPlayerStress[i];
-					}
-				}
-			}
-			
-			if (iPreferredTeleportTarget && iPreferredTeleportTarget != INVALID_ENT_REFERENCE)
-			{
-				// Set our preferred target to the new guy.
-				new Float:flTargetDuration = GetProfileFloat(sProfile, "teleport_target_persistency_period", 13.0);
-				new Float:flDeviation = GetRandomFloat(0.92, 1.08);
-				flTargetDuration = Pow(flDeviation * flTargetDuration, ((g_flRoundDifficultyModifier * (NPCGetAnger(iBossIndex) - 1.0)) / 2.0)) + ((flDeviation * flTargetDuration) - 1.0);
-				
-				g_iSlenderTeleportTarget[iBossIndex] = EntIndexToEntRef(iPreferredTeleportTarget);
-				g_flSlenderTeleportPlayersRestTime[iBossIndex][iPreferredTeleportTarget] = -1.0;
-				g_flSlenderTeleportMaxTargetTime[iBossIndex] = GetGameTime() + flTargetDuration;
-				g_flSlenderTeleportTargetTime[iBossIndex] = GetGameTime();
-				g_flSlenderTeleportMaxTargetStress[iBossIndex] = flTargetStress;
-				
-				iTeleportTarget = iPreferredTeleportTarget;
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: got new target %N", iBossIndex, iPreferredTeleportTarget);
-#endif
-			}
-		}
-	}
-}
-
-static GetPageMusicRanges()
-{
-	ClearArray(g_hPageMusicRanges);
-	
-	decl String:sName[64];
-	
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		
-		if (sName[0] && !StrContains(sName, "sf2_page_music_", false))
-		{
-			ReplaceString(sName, sizeof(sName), "sf2_page_music_", "", false);
-			
-			new String:sPageRanges[2][32];
-			ExplodeString(sName, "-", sPageRanges, 2, 32);
-			
-			new iIndex = PushArrayCell(g_hPageMusicRanges, EntIndexToEntRef(ent));
-			if (iIndex != -1)
-			{
-				new iMin = StringToInt(sPageRanges[0]);
-				new iMax = StringToInt(sPageRanges[0]);
-				
-#if defined DEBUG
-				DebugMessage("Page range found: entity %d, iMin = %d, iMax = %d", ent, iMin, iMax);
-#endif
-				SetArrayCell(g_hPageMusicRanges, iIndex, iMin, 1);
-				SetArrayCell(g_hPageMusicRanges, iIndex, iMax, 2);
-			}
-		}
-	}
-	
-	// precache
-	if (GetArraySize(g_hPageMusicRanges) > 0)
-	{
-		decl String:sPath[PLATFORM_MAX_PATH];
-		
-		for (new i = 0; i < GetArraySize(g_hPageMusicRanges); i++)
-		{
-			ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
-			if (!ent || ent == INVALID_ENT_REFERENCE) continue;
-			
-			GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-			if (sPath[0])
-			{
-				PrecacheSound(sPath);
-			}
-		}
-	}
-	
-	LogSF2Message("Loaded page music ranges successfully!");
-}
-
-SetPageCount(iNum)
-{
-	if (iNum > g_iPageMax) iNum = g_iPageMax;
-	
-	new iOldPageCount = g_iPageCount;
-	g_iPageCount = iNum;
-	
-	if (g_iPageCount != iOldPageCount)
-	{
-		if (g_iPageCount > iOldPageCount)
-		{
-			if (g_hRoundGraceTimer != INVALID_HANDLE) 
-			{
-				TriggerTimer(g_hRoundGraceTimer);
-			}
-			
-			g_iRoundTime += g_iRoundTimeGainFromPage;
-			if (g_iRoundTime > g_iRoundTimeLimit) g_iRoundTime = g_iRoundTimeLimit;
-			
-			// Increase anger on selected bosses.
-			for (new i = 0; i < MAX_BOSSES; i++)
-			{
-				if (NPCGetUniqueID(i) == -1) continue;
-				
-				new Float:flPageDiff = NPCGetAngerAddOnPageGrabTimeDiff(i);
-				if (flPageDiff >= 0.0)
-				{
-					new iDiff = g_iPageCount - iOldPageCount;
-					if ((GetGameTime() - g_flPageFoundLastTime) < flPageDiff)
-					{
-						NPCAddAnger(i, NPCGetAngerAddOnPageGrab(i) * float(iDiff));
-					}
-				}
-			}
-			
-			g_flPageFoundLastTime = GetGameTime();
-		}
-		
-		// Notify logic entities.
-		decl String:sTargetName[64];
-		decl String:sFindTargetName[64];
-		Format(sFindTargetName, sizeof(sFindTargetName), "sf2_onpagecount_%d", g_iPageCount);
-		
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
-		{
-			GetEntPropString(ent, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
-			if (sTargetName[0] && StrEqual(sTargetName, sFindTargetName, false))
-			{
-				AcceptEntityInput(ent, "Trigger");
-				break;
-			}
-		}
-	
-		new iClients[MAXPLAYERS + 1] = { -1, ... };
-		new iClientsNum = 0;
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i)) continue;
-			if (!g_bPlayerEliminated[i] || IsClientInGhostMode(i))
-			{
-				if (g_iPageCount)
-				{
-					iClients[iClientsNum] = i;
-					iClientsNum++;
-				}
-			}
-		}
-		
-		if (g_iPageCount > 0 && g_bRoundHasEscapeObjective && g_iPageCount == g_iPageMax)
-		{
-			// Escape initialized!
-			SetRoundState(SF2RoundState_Escape);
-			
-			if (iClientsNum)
-			{
-				new iGameTextEscape = GetTextEntity("sf2_escape_message", false);
-				if (iGameTextEscape != -1)
-				{
-					// Custom escape message.
-					decl String:sMessage[512];
-					GetEntPropString(iGameTextEscape, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextEscape, g_hHudSync, sMessage);
-				}
-				else
-				{
-					// Default escape message.
-					for (new i = 0; i < iClientsNum; i++)
-					{
-						new client = iClients[i];
-						ClientShowMainMessage(client, "%d/%d\n%T", g_iPageCount, g_iPageMax, "SF2 Default Escape Message", i);
-					}
-				}
-			}
-		}
-		else
-		{
-			if (iClientsNum)
-			{
-				new iGameTextPage = GetTextEntity("sf2_page_message", false);
-				if (iGameTextPage != -1)
-				{
-					// Custom page message.
-					decl String:sMessage[512];
-					GetEntPropString(iGameTextPage, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextPage, g_hHudSync, sMessage, g_iPageCount, g_iPageMax);
-				}
-				else
-				{
-					// Default page message.
-					for (new i = 0; i < iClientsNum; i++)
-					{
-						new client = iClients[i];
-						ClientShowMainMessage(client, "%d/%d", g_iPageCount, g_iPageMax);
-					}
-				}
-			}
-		}
-		
-		CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
-	}
-}
-
-GetTextEntity(const String:sTargetName[], bool:bCaseSensitive=true)
-{
-	// Try to see if we can use a custom message instead of the default.
-	decl String:targetName[64];
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "game_text")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
-		if (targetName[0])
-		{
-			if (StrEqual(targetName, sTargetName, bCaseSensitive))
-			{
-				return ent;
-			}
-		}
-	}
-	
-	return -1;
-}
-
-ShowHudTextUsingTextEntity(const iClients[], iClientsNum, iGameText, Handle:hHudSync, const String:sMessage[], ...)
-{
-	if (!sMessage[0]) return;
-	if (!IsValidEntity(iGameText)) return;
-	
-	decl String:sTrueMessage[512];
-	VFormat(sTrueMessage, sizeof(sTrueMessage), sMessage, 6);
-	
-	new Float:flX = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.x");
-	new Float:flY = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.y");
-	new iEffect = GetEntProp(iGameText, Prop_Data, "m_textParms.effect");
-	new Float:flFadeInTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime");
-	new Float:flFadeOutTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime");
-	new Float:flHoldTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
-	new Float:flFxTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fxTime");
-	
-	new Color1[4] = { 255, 255, 255, 255 };
-	new Color2[4] = { 255, 255, 255, 255 };
-	
-	new iParmsOffset = FindDataMapOffs(iGameText, "m_textParms");
-	if (iParmsOffset != -1)
-	{
-		// hudtextparms_s m_textParms
-		
-		Color1[0] = GetEntData(iGameText, iParmsOffset + 12, 1);
-		Color1[1] = GetEntData(iGameText, iParmsOffset + 13, 1);
-		Color1[2] = GetEntData(iGameText, iParmsOffset + 14, 1);
-		Color1[3] = GetEntData(iGameText, iParmsOffset + 15, 1);
-		
-		Color2[0] = GetEntData(iGameText, iParmsOffset + 16, 1);
-		Color2[1] = GetEntData(iGameText, iParmsOffset + 17, 1);
-		Color2[2] = GetEntData(iGameText, iParmsOffset + 18, 1);
-		Color2[3] = GetEntData(iGameText, iParmsOffset + 19, 1);
-	}
-	
-	SetHudTextParamsEx(flX, flY, flHoldTime, Color1, Color2, iEffect, flFxTime, flFadeInTime, flFadeOutTime);
-	
-	for (new i = 0; i < iClientsNum; i++)
-	{
-		new iClient = iClients[i];
-		if (!IsValidClient(iClient) || IsFakeClient(iClient)) continue;
-		
-		ShowSyncHudText(iClient, hHudSync, sTrueMessage);
-	}
-}
-
-//	==========================================================
-//	EVENT HOOKS
-//	==========================================================
-
-public Event_RoundStart(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundStart");
-#endif
-	
-	// Reset some global variables.
-	g_iRoundCount++;
-	g_hRoundTimer = INVALID_HANDLE;
-	
-	SetRoundState(SF2RoundState_Invalid);
-	
-	SetPageCount(0);
-	g_iPageMax = 0;
-	g_flPageFoundLastTime = GetGameTime();
-	
-	g_hVoteTimer = INVALID_HANDLE;
-	
-	// Remove all bosses from the game.
-	NPCRemoveAll();
-	
-	// Refresh groups.
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		SetPlayerGroupPlaying(i, false);
-		CheckPlayerGroup(i);
-	}
-	
-	// Refresh players.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		ClientSetGhostModeState(i, false);
-		
-		g_bPlayerPlaying[i] = false;
-		g_bPlayerEliminated[i] = true;
-		g_bPlayerEscaped[i] = false;
-	}
-	
-	// Calculate the new round state.
-	if (g_bRoundWaitingForPlayers)
-	{
-		SetRoundState(SF2RoundState_Waiting);
-	}
-	else if (GetConVarBool(g_cvWarmupRound) && g_iRoundWarmupRoundCount < GetConVarInt(g_cvWarmupRoundNum))
-	{
-		g_iRoundWarmupRoundCount++;
-		
-		SetRoundState(SF2RoundState_Waiting);
-		
-		ServerCommand("mp_restartgame 15");
-		PrintCenterTextAll("Round restarting in 15 seconds");
-	}
-	else
-	{
-		g_iRoundActiveCount++;
-		
-		InitializeNewGame();
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundStart");
-#endif
-}
-
-public Event_RoundEnd(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundEnd");
-#endif
-	
-	SetRoundState(SF2RoundState_Outro);
-	
-	DistributeQueuePointsToPlayers();
-	
-	g_iRoundEndCount++;	
-	CheckRoundLimitForBossPackVote(g_iRoundEndCount);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundEnd");
-#endif
-}
-
-static DistributeQueuePointsToPlayers()
-{
-	// Give away queue points.
-	new iDefaultAmount = 5;
-	new iAmount = iDefaultAmount;
-	new iAmount2 = iAmount;
-	new Action:iAction = Plugin_Continue;
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		
-		if (IsPlayerGroupPlaying(i))
-		{
-			SetPlayerGroupQueuePoints(i, 0);
-		}
-		else
-		{
-			iAmount = iDefaultAmount;
-			iAmount2 = iAmount;
-			iAction = Plugin_Continue;
-			
-			Call_StartForward(fOnGroupGiveQueuePoints);
-			Call_PushCell(i);
-			Call_PushCellRef(iAmount2);
-			Call_Finish(iAction);
-			
-			if (iAction == Plugin_Changed) iAmount = iAmount2;
-			
-			SetPlayerGroupQueuePoints(i, GetPlayerGroupQueuePoints(i) + iAmount);
-		
-			for (new iClient = 1; iClient <= MaxClients; iClient++)
-			{
-				if (!IsValidClient(iClient)) continue;
-				if (ClientGetPlayerGroup(iClient) == i)
-				{
-					CPrintToChat(iClient, "%T", "SF2 Give Group Queue Points", iClient, iAmount);
-				}
-			}
-		}
-	}
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (g_bPlayerPlaying[i]) 
-		{
-			ClientSetQueuePoints(i, 0);
-		}
-		else
-		{
-			if (!IsClientParticipating(i))
-			{
-				CPrintToChat(i, "%T", "SF2 No Queue Points To Spectator", i);
-			}
-			else
-			{
-				iAmount = iDefaultAmount;
-				iAmount2 = iAmount;
-				iAction = Plugin_Continue;
-				
-				Call_StartForward(fOnClientGiveQueuePoints);
-				Call_PushCell(i);
-				Call_PushCellRef(iAmount2);
-				Call_Finish(iAction);
-				
-				if (iAction == Plugin_Changed) iAmount = iAmount2;
-				
-				ClientSetQueuePoints(i, g_iPlayerQueuePoints[i] + iAmount);
-				CPrintToChat(i, "%T", "SF2 Give Queue Points", i, iAmount);
-			}
-		}	
-	}
-}
-
-public Action:Event_PlayerTeamPre(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerTeamPre");
-#endif
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client > 0)
-	{
-		if (GetEventInt(event, "team") > 1 || GetEventInt(event, "oldteam") > 1) SetEventBroadcast(event, true);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerTeamPre");
-#endif
-	
-	return Plugin_Continue;
-}
-
-public Event_PlayerTeam(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerTeam");
-#endif
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client > 0)
-	{
-		new iNewTeam = GetEventInt(event, "team");
-		if (iNewTeam <= _:TFTeam_Spectator)
-		{
-			if (g_bRoundGrace)
-			{
-				if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
-				{
-					ForceInNextPlayersInQueue(1, true);
-				}
-			}
-			
-			// You're not playing anymore.
-			if (g_bPlayerPlaying[client])
-			{
-				ClientSetQueuePoints(client, 0);
-			}
-			
-			g_bPlayerPlaying[client] = false;
-			g_bPlayerEliminated[client] = true;
-			g_bPlayerEscaped[client] = false;
-			
-			ClientSetGhostModeState(client, false);
-			
-			if (!bool:GetEntProp(client, Prop_Send, "m_bIsCoaching"))
-			{
-				// This is to prevent player spawn spam when someone is coaching. Who coaches in SF2, anyway?
-				TF2_RespawnPlayer(client);
-			}
-			
-			// Special round.
-			if (g_bSpecialRound) g_bPlayerPlayedSpecialRound[client] = true;
-			
-			// Boss round.
-			if (g_bNewBossRound) g_bPlayerPlayedNewBossRound[client] = true;
-		}
-		else
-		{
-			if (!g_bPlayerChoseTeam[client])
-			{
-				g_bPlayerChoseTeam[client] = true;
-				
-				if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
-				{
-					EmitSoundToClient(client, SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
-					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Projected{olive}.");
-				}
-				else
-				{
-					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Normal{olive}.");
-				}
-				
-				CreateTimer(5.0, Timer_WelcomeMessage, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-			}
-		}
-	}
-	
-	// Check groups.
-	if (!IsRoundEnding())
-	{
-		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-		{
-			if (!IsPlayerGroupActive(i)) continue;
-			CheckPlayerGroup(i);
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerTeam");
-#endif
-
-}
-
-/**
- *	Sets the player to the correct team if needed. Returns true if a change was necessary, false if no change occurred.
- */
-static bool:HandlePlayerTeam(client, bool:bRespawn=true)
-{
-	if (!IsClientInGame(client) || !IsClientParticipating(client)) return false;
-	
-	if (!g_bPlayerEliminated[client])
-	{
-		if (GetClientTeam(client) != _:TFTeam_Red)
-		{
-			if (bRespawn)
-				ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
-			else
-				ChangeClientTeam(client, _:TFTeam_Red);
-				
-			return true;
-		}
-	}
-	else
-	{
-		if (GetClientTeam(client) != _:TFTeam_Blue)
-		{
-			if (bRespawn) {
-				ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
-			}
-			else
-				ChangeClientTeam(client, _:TFTeam_Blue);
-			return true;
-		}
-	}
-	
-	return false;
-}
-
-static HandlePlayerIntroState(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client) || !IsClientParticipating(client)) return;
-	
-	if (!IsRoundInIntro()) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START HandlePlayerIntroState(%d)", client);
-#endif
-	
-	// Disable movement on player.
-	SetEntityFlags(client, GetEntityFlags(client) | FL_FROZEN);
-	
-	new Float:flDelay = 0.0;
-	if (!IsFakeClient(client))
-	{
-		flDelay = GetClientLatency(client, NetFlow_Outgoing);
-	}
-	
-	CreateTimer(flDelay * 4.0, Timer_IntroBlackOut, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END HandlePlayerIntroState(%d)", client);
-#endif
-}
-
-HandlePlayerHUD(client)
-{
-	if (IsRoundInWarmup() || IsClientInGhostMode(client))
-	{
-		SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
-	}
-	else
-	{
-		if (!g_bPlayerEliminated[client])
-		{
-			if (!DidClientEscape(client))
-			{
-				// Player is in the game; disable normal HUD.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
-			}
-			else
-			{
-				// Player isn't in the game; enable normal HUD behavior.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
-			}
-		}
-		else
-		{
-			if (g_bPlayerProxy[client])
-			{
-				// Player is in the game; disable normal HUD.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
-			}
-			else
-			{
-				// Player isn't in the game; enable normal HUD behavior.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
-			}
-		}
-	}
-}
-
-public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client <= 0) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerSpawn(%d)", client);
-#endif
-	
-	if (!IsClientParticipating(client))
-	{
-		ClientSetGhostModeState(client, false);
-	}
-	
-	g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
-	
-	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
-	g_iGhostNextHelpPhrase[client] = 0;
-	
-	if (IsPlayerAlive(client) && IsClientParticipating(client))
-	{
-		if (HandlePlayerTeam(client))
-		{
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("client->HandlePlayerTeam()");
-#endif
-		}
-		else
-		{
-			g_iPlayerPageCount[client] = 0;
-			
-			ClientDisableFakeLagCompensation(client);
-			
-			ClientResetStatic(client);
-			ClientResetSlenderStats(client);
-			ClientResetCampingStats(client);
-			ClientResetOverlay(client);
-			ClientResetJumpScare(client);
-			ClientUpdateListeningFlags(client);
-			ClientUpdateMusicSystem(client);
-			ClientChaseMusicReset(client);
-			ClientChaseMusicSeeReset(client);
-			ClientAlertMusicReset(client);
-			Client20DollarsMusicReset(client);
-			ClientMusicReset(client);
-			ClientResetProxy(client);
-			ClientResetHints(client);
-			ClientResetScare(client);
-			
-			ClientResetDeathCam(client);
-			ClientResetFlashlight(client);
-			ClientDeactivateUltravision(client);
-			ClientResetSprint(client);
-			ClientResetBreathing(client);
-			ClientResetBlink(client);
-			ClientResetInteractiveGlow(client);
-			ClientDisableConstantGlow(client);
-			
-			ClientHandleGhostMode(client);
-			
-			if (!g_bPlayerEliminated[client])
-			{
-				ClientStartDrainingBlinkMeter(client);
-				ClientSetScareBoostEndTime(client, -1.0);
-				
-				ClientStartCampingTimer(client);
-				
-				HandlePlayerIntroState(client);
-				
-				// screen overlay timer
-				g_hPlayerOverlayCheck[client] = CreateTimer(0.0, Timer_PlayerOverlayCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-				TriggerTimer(g_hPlayerOverlayCheck[client], true);
-				
-				if (DidClientEscape(client))
-				{
-					CreateTimer(0.1, Timer_TeleportPlayerToEscapePoint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-				else
-				{
-					ClientEnableConstantGlow(client, "head");
-					ClientActivateUltravision(client);
-					CreateTimer(0.1, Timer_CreateSpriteOverlay, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-			}
-			else
-			{
-				g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
-			}
-			
-			g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-			
-			HandlePlayerHUD(client);
-		}
-	}
-	
-	PvP_OnPlayerSpawn(client);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerSpawn(%d)", client);
-#endif
-}
-
-public Action:Timer_UpdateOverlayTime(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	new String:Time[64], String:DigitBuffer[2];
-	FormatTime(Time, sizeof(Time), "%d"); // Day
-	Format(DigitBuffer, 2, "%s", Time[0]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit0), StringToFloat(DigitBuffer));
-	Format(DigitBuffer, 2, "%s", Time[1]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit1), StringToFloat(DigitBuffer));
-	FormatTime(Time, sizeof(Time), "%m"); // Month
-	Format(DigitBuffer, 2, "%s", Time[0]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit3), StringToFloat(DigitBuffer));
-	Format(DigitBuffer, 2, "%s", Time[1]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit4), StringToFloat(DigitBuffer));
-	FormatTime(Time, sizeof(Time), "%H"); // Hours
-	Format(DigitBuffer, 2, "%s", Time[0]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit0), StringToFloat(DigitBuffer));
-	Format(DigitBuffer, 2, "%s", Time[1]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit1), StringToFloat(DigitBuffer));
-	FormatTime(Time, sizeof(Time), "%M"); // Minutes
-	Format(DigitBuffer, 2, "%s", Time[0]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit3), StringToFloat(DigitBuffer));
-	Format(DigitBuffer, 2, "%s", Time[1]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit4), StringToFloat(DigitBuffer));
-	if(g_hRoundTimer != INVALID_HANDLE) {
-		//g_iRoundTime
-		//g_iRoundTime = g_iRoundTimeLimit;g_iPageCount == g_iPageMax
-		new time = g_iRoundTime;
-		decl maxTime;
-		if(g_iPageCount == g_iPageMax) {
-			maxTime = g_iRoundEscapeTimeLimit;
-		} else {
-			maxTime = g_iRoundTimeLimit;
-		}
-		if(float(time) / float(maxTime) >= 0.75) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
-		else if(float(time) / float(maxTime) >= 0.5) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 1.0);
-		else if(float(time) / float(maxTime) >= 0.25) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 2.0);
-		else if(float(time) / float(maxTime) >= 0.17) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 3.0);
-		else {
-			Overlay_Color_Red(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[0]);
-			Overlay_Color_Green(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
-			Overlay_Color_Blue(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
-			if(g_bHudBatteryToggle[client]) Overlay_Hide(OverlayRef_ByLayer(client, _:HudBattery));// Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 3.0);
-			else {
-				Overlay_Show(OverlayRef_ByLayer(client, _:HudBattery));
-				Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 3.0);
-			}
-			//PrintToServer("%d", g_bHudBatteryToggle[client]);
-			g_bHudBatteryToggle[client] = !g_bHudBatteryToggle[client];
-		}
-		//Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), float(g_iRoundTime));
-		/*
-			Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
-			Overlay_Color_Red(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[0]);
-			Overlay_Color_Green(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[1]);
-			Overlay_Color_Blue(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[1]);
-		*/
-	}
-}
-
-public Action:Timer_CreateSpriteOverlay(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	/*
-	PrintToServer("Add_Sprite()");
-	Add_Sprite(client, OverlayGeneric, 14.0);
-	//Overlay_Render(client, _:OverlayGeneric, g_fOverlayMatOffset[OverlayGeneric], g_sOverlayMat[OverlayGeneric], -5.0);
-	new spr;
-	new String:cl[32];
-	PrintToServer("Overlay_Layer_Exists(client, _:OverlayGeneric): %d", Overlay_Layer_Exists(client, _:OverlayGeneric, spr));
-	Overlay_Show(spr);
-	GetEntityClassname(spr, cl, sizeof(cl));
-	PrintToServer("spr: %d (%s)", spr, cl);
-	*/
-	g_fOverlayMatRotation[OverlayGeneric][2] = GetRandomFloat(0.0, 180.0);
-	Add_Sprite(client, OverlayGeneric, 35.0);
-	Add_Sprite(client, Crosshair, 3.0);
-	
-	Add_Sprite(client, DateDigit0, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit1, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit2, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit3, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit4, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit5, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit6, g_fHudDigitScale);
-	Add_Sprite(client, DateDigit7, g_fHudDigitScale);
-	Add_Sprite(client, ClockDigit0, g_fHudDigitScale);
-	Add_Sprite(client, ClockDigit1, g_fHudDigitScale);
-	Add_Sprite(client, ClockDigit2, g_fHudDigitScale);
-	Add_Sprite(client, ClockDigit3, g_fHudDigitScale);
-	Add_Sprite(client, ClockDigit4, g_fHudDigitScale);
-	
-	Add_Sprite(client, HudRec, g_fHudDigitScale);
-	Add_Sprite(client, HudBattery, g_fHudDigitScale);
-	g_bHudBatteryToggle[client] = true;
-	//PrintToServer("%d", Overlay_Exists(OverlayRef_ByLayer(client, _:DateDigit0)));
-	for(new i = _:DateDigit0; i <= _:HudBattery; i++) {
-		Overlay_Framerate(OverlayRef_ByLayer(client, i), 0.0);
-		Overlay_Color_Red(OverlayRef_ByLayer(client, i), g_fHudDigitIntensity[0]);
-		Overlay_Color_Green(OverlayRef_ByLayer(client, i), g_fHudDigitIntensity[1]);
-		Overlay_Color_Blue(OverlayRef_ByLayer(client, i), g_fHudDigitIntensity[1]);
-	}
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit2), 10.0);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit5), 10.0);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit2), 11.0);
-	/*
-	new Float:yearDigits[2], String:buffer[16];
-	Format(buffer, 16, "0000%s", g_sCameraYear);
-	strcopy(g_sCameraYear, sizeof(g_sCameraYear), buffer);
-	Format(buffer, 1, "%s", g_sCameraYear[strlen(g_sCameraYear)-1]);
-	strcopy(g_sCameraYear, sizeof(g_sCameraYear), buffer);
-	yearDigits[0] = StringToFloat(buffer[0]);
-	Format(buffer, 1, "%s", g_sCameraYear[strlen(g_sCameraYear)-1]);
-	strcopy(g_sCameraYear, sizeof(g_sCameraYear), buffer);
-	yearDigits[1] = StringToFloat(buffer[0]);
-	*/
-	//PrintToServer("%s %d %s %s %s", g_sCameraYear, strlen(g_sCameraYear), g_sCameraYear[strlen(g_sCameraYear)-1], g_sCameraYear[strlen(g_sCameraYear)-2], g_sCameraYear[strlen(g_sCameraYear)-3]);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit6), 8.0);
-	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit7), 6.0);
-	g_hOverlayUpdateTimer[client] = CreateTimer(1.2, Timer_UpdateOverlayTime, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
-	//Hide_Weapon(client);
-}
-
-public Action:Timer_IntroBlackOut(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (!IsRoundInIntro()) return;
-	
-	if (!IsPlayerAlive(client) || g_bPlayerEliminated[client]) return;
-	
-	// Black out the player's screen.
-	new iFadeFlags = FFADE_OUT | FFADE_STAYOUT | FFADE_PURGE;
-	UTIL_ScreenFade(client, 0, FixedUnsigned16(90.0, 1 << 12), iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
-}
-
-public Event_PostInventoryApplication(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PostInventoryApplication");
-#endif
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client > 0)
-	{
-		g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PostInventoryApplication");
-#endif
-}
-
-public Action:Event_DontBroadcastToClients(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsRoundInWarmup()) return Plugin_Continue;
-	
-	SetEventBroadcast(event, true);
-	return Plugin_Continue;
-}
-
-public Action:Event_PlayerDeathPre(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerDeathPre");
-#endif
-	
-	if (!IsRoundInWarmup())
-	{
-		new client = GetClientOfUserId(GetEventInt(event, "userid"));
-		if (client > 0)
-		{
-			if (!IsRoundEnding())
-			{
-				if (g_bRoundGrace || g_bPlayerEliminated[client] || IsClientInGhostMode(client))
-				{
-					SetEventBroadcast(event, true);
-				}
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerDeathPre");
-#endif
-	
-	return Plugin_Continue;
-}
-
-public Event_PlayerHurt(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client <= 0) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerHurt");
-#endif
-	
-	ClientDisableFakeLagCompensation(client);
-	
-	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
-	if (attacker > 0)
-	{
-		if (g_bPlayerProxy[attacker])
-		{
-			g_iPlayerProxyControl[attacker] = 100;
-		}
-	}
-	
-	// Play any sounds, if any.
-	if (g_bPlayerProxy[client])
-	{
-		new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-		if (iProxyMaster != -1)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
-		
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			if (GetRandomStringFromProfile(sProfile, "sound_proxy_hurt", sBuffer, sizeof(sBuffer)) && sBuffer[0])
-			{
-				new iChannel = GetProfileNum(sProfile, "sound_proxy_hurt_channel", SNDCHAN_AUTO);
-				new iLevel = GetProfileNum(sProfile, "sound_proxy_hurt_level", SNDLEVEL_NORMAL);
-				new iFlags = GetProfileNum(sProfile, "sound_proxy_hurt_flags", SND_NOFLAGS);
-				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_hurt_volume", SNDVOL_NORMAL);
-				new iPitch = GetProfileNum(sProfile, "sound_proxy_hurt_pitch", SNDPITCH_NORMAL);
-				
-				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerHurt");
-#endif
-}
-
-public Event_PlayerDeath(Handle:event, const String:name[], bool:dB)
-{
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	
-	if (client <= 0) return;
-	
-	DestroySpriteOverlay(client);
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerDeath(%d)", client);
-#endif
-	
-	new bool:bFake = bool:(GetEventInt(event, "death_flags") & TF_DEATHFLAG_DEADRINGER);
-	new inflictor = GetEventInt(event, "inflictor_entindex");
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("inflictor = %d", inflictor);
-#endif
-	
-	if (!bFake)
-	{
-		ClientDisableFakeLagCompensation(client);
-		
-		ClientResetStatic(client);
-		ClientResetSlenderStats(client);
-		ClientResetCampingStats(client);
-		ClientResetOverlay(client);
-		ClientResetJumpScare(client);
-		ClientResetInteractiveGlow(client);
-		ClientDisableConstantGlow(client);
-		ClientChaseMusicReset(client);
-		ClientChaseMusicSeeReset(client);
-		ClientAlertMusicReset(client);
-		Client20DollarsMusicReset(client);
-		ClientMusicReset(client);
-		
-		ClientResetFlashlight(client);
-		ClientDeactivateUltravision(client);
-		ClientResetSprint(client);
-		ClientResetBreathing(client);
-		ClientResetBlink(client);
-		ClientResetDeathCam(client);
-		
-		ClientUpdateMusicSystem(client);
-		
-		PvP_SetPlayerPvPState(client, false, false, false);
-		
-		if (IsRoundInWarmup())
-		{
-			CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-		}
-		else
-		{
-			if (!g_bPlayerEliminated[client])
-			{
-				if (IsRoundInIntro() || g_bRoundGrace || DidClientEscape(client))
-				{
-					CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-				else
-				{
-					g_bPlayerEliminated[client] = true;
-					g_bPlayerEscaped[client] = false;
-					g_hPlayerSwitchBlueTimer[client] = CreateTimer(2.5, Timer_PlayerSwitchToBlue, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-					ClientCommand(client, "r_screenoverlay %s", STATIC_OVERLAY);
-					EmitSoundToClient(client, STATIC_SOUND, _, MUSIC_CHAN, SNDLEVEL_NONE);
-				}
-			}
-			else
-			{
-			}
-			
-			{
-				// If this player was killed by a boss, play a sound.
-				new npcIndex = NPCGetFromEntIndex(inflictor);
-				if (npcIndex != -1)
-				{
-					decl String:npcProfile[SF2_MAX_PROFILE_NAME_LENGTH], String:buffer[PLATFORM_MAX_PATH];
-					NPCGetProfile(npcIndex, npcProfile, sizeof(npcProfile));
-					
-					if (GetRandomStringFromProfile(npcProfile, "sound_attack_killed_all", buffer, sizeof(buffer)) && strlen(buffer) > 0)
-					{
-						if (!g_bPlayerEliminated[client])
-						{
-							EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_HELICOPTER);
-						}
-					}
-					
-					SlenderPerformVoice(npcIndex, "sound_attack_killed");
-				}
-			}
-			
-			CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			// Notify to other bosses that this player has died.
-			for (new i = 0; i < MAX_BOSSES; i++)
-			{
-				if (NPCGetUniqueID(i) == -1) continue;
-				
-				if (EntRefToEntIndex(g_iSlenderTarget[i]) == client)
-				{
-					g_iSlenderInterruptConditions[i] |= COND_CHASETARGETINVALIDATED;
-					GetClientAbsOrigin(client, g_flSlenderChaseDeathPosition[i]);
-				}
-			}
-		}
-		
-		if (g_bPlayerProxy[client])
-		{
-			// We're a proxy, so play some sounds.
-		
-			new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-			if (iProxyMaster != -1)
-			{
-				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-				NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
-				
-				decl String:sBuffer[PLATFORM_MAX_PATH];
-				if (GetRandomStringFromProfile(sProfile, "sound_proxy_death", sBuffer, sizeof(sBuffer)) && sBuffer[0])
-				{
-					new iChannel = GetProfileNum(sProfile, "sound_proxy_death_channel", SNDCHAN_AUTO);
-					new iLevel = GetProfileNum(sProfile, "sound_proxy_death_level", SNDLEVEL_NORMAL);
-					new iFlags = GetProfileNum(sProfile, "sound_proxy_death_flags", SND_NOFLAGS);
-					new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_death_volume", SNDVOL_NORMAL);
-					new iPitch = GetProfileNum(sProfile, "sound_proxy_death_pitch", SNDPITCH_NORMAL);
-					
-					EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
-				}
-			}
-		}
-		
-		ClientResetProxy(client, false);
-		ClientUpdateListeningFlags(client);
-		
-		// Half-Zatoichi nerf code.
-		new iKatanaHealthGain = GetConVarInt(g_cvHalfZatoichiHealthGain);
-		if (iKatanaHealthGain >= 0)
-		{
-			new iAttacker = GetClientOfUserId(GetEventInt(event, "attacker"));
-			if (iAttacker > 0)
-			{
-				if (!IsClientInPvP(iAttacker) && (!g_bPlayerEliminated[iAttacker] || g_bPlayerProxy[iAttacker]))
-				{
-					decl String:sWeapon[64];
-					GetEventString(event, "weapon", sWeapon, sizeof(sWeapon));
-					
-					if (StrEqual(sWeapon, "demokatana"))
-					{
-						new iAttackerPreHealth = GetEntProp(iAttacker, Prop_Send, "m_iHealth");
-						new Handle:hPack = CreateDataPack();
-						WritePackCell(hPack, GetClientUserId(iAttacker));
-						WritePackCell(hPack, iAttackerPreHealth + iKatanaHealthGain);
-						
-						CreateTimer(0.0, Timer_SetPlayerHealth, hPack, TIMER_FLAG_NO_MAPCHANGE);
-					}
-				}
-			}
-		}
-		
-		g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
-	}
-	
-	PvP_OnPlayerDeath(client, bFake);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerDeath(%d)", client);
-#endif
-}
-
-public Action:Timer_SetPlayerHealth(Handle:timer, any:data)
-{
-	new Handle:hPack = Handle:data;
-	ResetPack(hPack);
-	new iAttacker = GetClientOfUserId(ReadPackCell(hPack));
-	new iHealth = ReadPackCell(hPack);
-	CloseHandle(hPack);
-	
-	if (iAttacker <= 0) return;
-	
-	SetEntProp(iAttacker, Prop_Data, "m_iHealth", iHealth);
-	SetEntProp(iAttacker, Prop_Send, "m_iHealth", iHealth);
-}
-
-public Action:Timer_PlayerSwitchToBlue(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerSwitchBlueTimer[client]) return;
-	
-	ChangeClientTeam(client, _:TFTeam_Blue);
-}
-
-public Action:Timer_RoundStart(Handle:timer)
-{
-	if (g_iPageMax > 0)
-	{
-		new Handle:hArrayClients = CreateArray();
-		new iClients[MAXPLAYERS + 1];
-		new iClientsNum = 0;
-		
-		new iGameText = GetTextEntity("sf2_intro_message", false);
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || IsFakeClient(i) || g_bPlayerEliminated[i]) continue;
-			
-			if (iGameText == -1)
-			{
-				if (g_iPageMax > 1)
-				{
-					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Plural", i, g_iPageMax);
-				}
-				else
-				{
-					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Singular", i, g_iPageMax);
-				}
-			}
-			
-			PushArrayCell(hArrayClients, GetClientUserId(i));
-			iClients[iClientsNum] = i;
-			iClientsNum++;
-		}
-		
-		// Show difficulty menu.
-		if (iClientsNum)
-		{
-			// Automatically set it to Normal.
-			SetConVarInt(g_cvDifficulty, Difficulty_Normal);
-			
-			g_hVoteTimer = CreateTimer(1.0, Timer_VoteDifficulty, hArrayClients, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			TriggerTimer(g_hVoteTimer, true);
-			
-			if (iGameText != -1)
-			{
-				decl String:sMessage[512];
-				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-				
-				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
-			}
-		}
-		else
-		{
-			CloseHandle(hArrayClients);
-		}
-	}
-}
-
-public Action:Timer_CheckRoundWinConditions(Handle:timer)
-{
-	CheckRoundWinConditions();
-}
-
-public Action:Timer_RoundGrace(Handle:timer)
-{
-	if (timer != g_hRoundGraceTimer) return;
-	
-	g_bRoundGrace = false;
-	g_hRoundGraceTimer = INVALID_HANDLE;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientParticipating(i)) g_bPlayerEliminated[i] = true;
-	}
-	
-	// Initialize the main round timer.
-	if (g_iRoundTimeLimit > 0)
-	{
-		// Set round time.
-		g_iRoundTime = g_iRoundTimeLimit;
-		g_hRoundTimer = CreateTimer(1.0, Timer_RoundTime, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	}
-	else
-	{
-		// Infinite round time.
-		g_hRoundTimer = INVALID_HANDLE;
-	}
-	
-	CPrintToChatAll("{olive}%t", "SF2 Grace Period End");
-}
-
-public Action:Timer_RoundTime(Handle:timer)
-{
-	if (timer != g_hRoundTimer) return Plugin_Stop;
-	
-	if (g_iRoundTime <= 0)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i)) continue;
-			
-			decl Float:flBuffer[3];
-			GetClientAbsOrigin(i, flBuffer);
-			SDKHooks_TakeDamage(i, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-		}
-		
-		return Plugin_Stop;
-	}
-	
-	g_iRoundTime--;
-	
-	new hours, minutes, seconds;
-	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
-	
-	SetHudTextParams(-1.0, 0.1, 
-		1.0,
-		SF2_HUD_TEXT_COLOR_R, SF2_HUD_TEXT_COLOR_G, SF2_HUD_TEXT_COLOR_B, SF2_HUD_TEXT_COLOR_A,
-		_,
-		_,
-		1.5, 1.5);
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
-		ShowSyncHudText(i, g_hRoundTimerSync, "%d/%d\n%d:%02d", g_iPageCount, g_iPageMax, minutes, seconds);
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_RoundTimeEscape(Handle:timer)
-{
-	if (timer != g_hRoundTimer) return Plugin_Stop;
-	
-	if (g_iRoundTime <= 0)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i) || DidClientEscape(i)) continue;
-			
-			decl Float:flBuffer[3];
-			GetClientAbsOrigin(i, flBuffer);
-			ClientStartDeathCam(i, 0, flBuffer);
-		}
-		
-		return Plugin_Stop;
-	}
-	
-	new hours, minutes, seconds;
-	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
-	
-	SetHudTextParams(-1.0, 0.1, 
-		1.0,
-		SF2_HUD_TEXT_COLOR_R, 
-		SF2_HUD_TEXT_COLOR_G, 
-		SF2_HUD_TEXT_COLOR_B, 
-		SF2_HUD_TEXT_COLOR_A,
-		_,
-		_,
-		1.5, 1.5);
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
-		ShowSyncHudText(i, g_hRoundTimerSync, "%T\n%d:%02d", "SF2 Default Escape Message", i, minutes, seconds);
-	}
-	
-	g_iRoundTime--;
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_VoteDifficulty(Handle:timer, any:data)
-{
-	new Handle:hArrayClients = Handle:data;
-	
-	if (timer != g_hVoteTimer || IsRoundEnding()) 
-	{
-		CloseHandle(hArrayClients);
-		return Plugin_Stop;
-	}
-	
-	if (IsVoteInProgress()) return Plugin_Continue; // There's another vote in progess. Wait.
-	
-	new iClients[MAXPLAYERS + 1] = { -1, ... };
-	new iClientsNum;
-	for (new i = 0, iSize = GetArraySize(hArrayClients); i < iSize; i++)
-	{
-		new iClient = GetClientOfUserId(GetArrayCell(hArrayClients, i));
-		if (iClient <= 0) continue;
-		
-		iClients[iClientsNum] = iClient;
-		iClientsNum++;
-	}
-	
-	CloseHandle(hArrayClients);
-	
-	VoteMenu(g_hMenuVoteDifficulty, iClients, iClientsNum, 15);
-	
-	return Plugin_Stop;
-}
-
-static InitializeMapEntities()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeMapEntities()");
-#endif
-	
-	g_bRoundInfiniteFlashlight = false;
-	g_bRoundInfiniteBlink = false;
-	g_bRoundInfiniteSprint = false;
-	g_bRoundHasEscapeObjective = false;
-	
-	g_iRoundTimeLimit = GetConVarInt(g_cvTimeLimit);
-	g_iRoundEscapeTimeLimit = GetConVarInt(g_cvTimeLimitEscape);
-	g_iRoundTimeGainFromPage = GetConVarInt(g_cvTimeGainFromPageGrab);
-	
-	// Reset page reference.
-	g_bPageRef = false;
-	strcopy(g_strPageRefModel, sizeof(g_strPageRefModel), "");
-	g_flPageRefModelScale = 1.0;
-	
-	new Handle:hArray = CreateArray(2);
-	new Handle:hPageTrie = CreateTrie();
-	
-	decl String:targetName[64];
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
-		if (targetName[0])
-		{
-			if (!StrContains(targetName, "sf2_maxpages_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_maxpages_", "", false);
-				g_iPageMax = StringToInt(targetName);
-			}
-			else if (!StrContains(targetName, "sf2_page_spawnpoint", false))
-			{
-				if (!StrContains(targetName, "sf2_page_spawnpoint_", false))
-				{
-					ReplaceString(targetName, sizeof(targetName), "sf2_page_spawnpoint_", "", false);
-					if (targetName[0])
-					{
-						new Handle:hButtStallion = INVALID_HANDLE;
-						if (!GetTrieValue(hPageTrie, targetName, hButtStallion))
-						{
-							hButtStallion = CreateArray();
-							SetTrieValue(hPageTrie, targetName, hButtStallion);
-						}
-						
-						new iIndex = FindValueInArray(hArray, hButtStallion);
-						if (iIndex == -1)
-						{
-							iIndex = PushArrayCell(hArray, hButtStallion);
-						}
-						
-						PushArrayCell(hButtStallion, ent);
-						SetArrayCell(hArray, iIndex, true, 1);
-					}
-					else
-					{
-						new iIndex = PushArrayCell(hArray, ent);
-						SetArrayCell(hArray, iIndex, false, 1);
-					}
-				}
-				else
-				{
-					new iIndex = PushArrayCell(hArray, ent);
-					SetArrayCell(hArray, iIndex, false, 1);
-				}
-			}
-			else if (!StrContains(targetName, "sf2_logic_escape", false))
-			{
-				g_bRoundHasEscapeObjective = true;
-			}
-			else if (!StrContains(targetName, "sf2_infiniteflashlight", false))
-			{
-				g_bRoundInfiniteFlashlight = true;
-			}
-			else if (!StrContains(targetName, "sf2_infiniteblink", false))
-			{
-				g_bRoundInfiniteBlink = true;
-			}
-			else if (!StrContains(targetName, "sf2_infinitesprint", false))
-			{
-				g_bRoundInfiniteSprint = true;
-			}
-			else if (!StrContains(targetName, "sf2_time_limit_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_time_limit_", "", false);
-				g_iRoundTimeLimit = StringToInt(targetName);
-				
-				LogSF2Message("Found sf2_time_limit entity, set time limit to %d", g_iRoundTimeLimit);
-			}
-			else if (!StrContains(targetName, "sf2_escape_time_limit_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_escape_time_limit_", "", false);
-				g_iRoundEscapeTimeLimit = StringToInt(targetName);
-				
-				LogSF2Message("Found sf2_escape_time_limit entity, set escape time limit to %d", g_iRoundEscapeTimeLimit);
-			}
-			else if (!StrContains(targetName, "sf2_time_gain_from_page_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_time_gain_from_page_", "", false);
-				g_iRoundTimeGainFromPage = StringToInt(targetName);
-				
-				LogSF2Message("Found sf2_time_gain_from_page entity, set time gain to %d", g_iRoundTimeGainFromPage);
-			}
-			else if (g_iRoundActiveCount == 1 && (!StrContains(targetName, "sf2_maxplayers_", false)))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_maxplayers_", "", false);
-				SetConVarInt(g_cvMaxPlayers, StringToInt(targetName));
-				
-				LogSF2Message("Found sf2_maxplayers entity, set maxplayers to %d", StringToInt(targetName));
-			}
-			else if (!StrContains(targetName, "sf2_boss_override_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_boss_override_", "", false);
-				SetConVarString(g_cvBossProfileOverride, targetName);
-				
-				LogSF2Message("Found sf2_boss_override entity, set boss profile override to %s", targetName);
-			}
-		}
-	}
-	
-	// Get a reference entity, if any.
-	
-	ent = -1;
-	while ((ent = FindEntityByClassname(ent, "prop_dynamic")) != -1)
-	{
-		if (g_bPageRef) break;
-	
-		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
-		if (targetName[0])
-		{
-			if (StrEqual(targetName, "sf2_page_model", false))
-			{
-				g_bPageRef = true;
-				GetEntPropString(ent, Prop_Data, "m_ModelName", g_strPageRefModel, sizeof(g_strPageRefModel));
-				g_flPageRefModelScale = 1.0;
-			}
-		}
-	}
-	
-	new iPageCount = GetArraySize(hArray);
-	if (iPageCount)
-	{
-		SortADTArray(hArray, Sort_Random, Sort_Integer);
-		
-		decl Float:vecPos[3], Float:vecAng[3], Float:vecDir[3];
-		decl page;
-		ent = -1;
-		
-		for (new i = 0; i < iPageCount && (i + 1) <= g_iPageMax; i++)
-		{
-			if (bool:GetArrayCell(hArray, i, 1))
-			{
-				new Handle:hButtStallion = Handle:GetArrayCell(hArray, i);
-				ent = GetArrayCell(hButtStallion, GetRandomInt(0, GetArraySize(hButtStallion) - 1));
-			}
-			else
-			{
-				ent = GetArrayCell(hArray, i);
-			}
-			
-			GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", vecPos);
-			GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", vecAng);
-			GetAngleVectors(vecAng, vecDir, NULL_VECTOR, NULL_VECTOR);
-			NormalizeVector(vecDir, vecDir);
-			ScaleVector(vecDir, 1.0);
-			
-			page = CreateEntityByName("prop_dynamic_override");
-			if (page != -1)
-			{
-				TeleportEntity(page, vecPos, vecAng, NULL_VECTOR);
-				DispatchKeyValue(page, "targetname", "sf2_page");
-				
-				if (g_bPageRef)
-				{
-					SetEntityModel(page, g_strPageRefModel);
-				}
-				else
-				{
-					SetEntityModel(page, PAGE_MODEL);
-				}
-				
-				DispatchKeyValue(page, "solid", "2");
-				DispatchSpawn(page);
-				ActivateEntity(page);
-				SetVariantInt(i);
-				AcceptEntityInput(page, "Skin");
-				AcceptEntityInput(page, "EnableCollision");
-				
-				if (g_bPageRef)
-				{
-					SetEntPropFloat(page, Prop_Send, "m_flModelScale", g_flPageRefModelScale);
-				}
-				else
-				{
-					SetEntPropFloat(page, Prop_Send, "m_flModelScale", PAGE_MODELSCALE);
-				}
-				
-				SDKHook(page, SDKHook_OnTakeDamage, Hook_PageOnTakeDamage);
-				SDKHook(page, SDKHook_SetTransmit, Hook_SlenderObjectSetTransmit);
-			}
-		}
-		
-		// Safely remove all handles.
-		for (new i = 0, iSize = GetArraySize(hArray); i < iSize; i++)
-		{
-			if (bool:GetArrayCell(hArray, i, 1))
-			{
-				CloseHandle(Handle:GetArrayCell(hArray, i));
-			}
-		}
-	
-		Call_StartForward(fOnPagesSpawned);
-		Call_Finish();
-	}
-	
-	CloseHandle(hPageTrie);
-	CloseHandle(hArray);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeMapEntities()");
-#endif
-}
-
-static HandleSpecialRoundState()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleSpecialRoundState()");
-#endif
-	
-	new bool:bOld = g_bSpecialRound;
-	new bool:bContinuousOld = g_bSpecialRoundContinuous;
-	g_bSpecialRound = false;
-	g_bSpecialRoundNew = false;
-	g_bSpecialRoundContinuous = false;
-	
-	new bool:bForceNew = false;
-	
-	if (bOld)
-	{
-		if (bContinuousOld)
-		{
-			// Check if there are players who haven't played the special round yet.
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || !IsClientParticipating(i))
-				{
-					g_bPlayerPlayedSpecialRound[i] = true;
-					continue;
-				}
-				
-				if (!g_bPlayerPlayedSpecialRound[i])
-				{
-					// Someone didn't get to play this yet. Continue the special round.
-					g_bSpecialRound = true;
-					g_bSpecialRoundContinuous = true;
-					break;
-				}
-			}
-		}
-	}
-	
-	new iRoundInterval = GetConVarInt(g_cvSpecialRoundInterval);
-	
-	if (iRoundInterval > 0 && g_iSpecialRoundCount >= iRoundInterval)
-	{
-		g_bSpecialRound = true;
-		bForceNew = true;
-	}
-	
-	// Do special round force override and reset it.
-	if (GetConVarInt(g_cvSpecialRoundForce) >= 0)
-	{
-		g_bSpecialRound = GetConVarBool(g_cvSpecialRoundForce);
-		SetConVarInt(g_cvSpecialRoundForce, -1);
-	}
-	
-	if (g_bSpecialRound)
-	{
-		if (bForceNew || !bOld || !bContinuousOld)
-		{
-			g_bSpecialRoundNew = true;
-		}
-		
-		if (g_bSpecialRoundNew)
-		{
-			if (GetConVarInt(g_cvSpecialRoundBehavior) == 1)
-			{
-				g_bSpecialRoundContinuous = true;
-			}
-			else
-			{
-				// New special round, but it's not continuous.
-				g_bSpecialRoundContinuous = false;
-			}
-		}
-	}
-	else
-	{
-		g_bSpecialRoundContinuous = false;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleSpecialRoundState() -> g_bSpecialRound = %d (count = %d, new = %d, continuous = %d)", g_bSpecialRound, g_iSpecialRoundCount, g_bSpecialRoundNew, g_bSpecialRoundContinuous);
-#endif
-}
-
-bool:IsNewBossRoundRunning()
-{
-	return g_bNewBossRound;
-}
-
-/**
- *	Returns an array which contains all the profile names valid to be chosen for a new boss round.
- */
-static Handle:GetNewBossRoundProfileList()
-{
-	new Handle:hBossList = CloneArray(GetSelectableBossProfileList());
-	
-	if (GetArraySize(hBossList) > 0)
-	{
-		decl String:sMainBoss[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetConVarString(g_cvBossMain, sMainBoss, sizeof(sMainBoss));
-		
-		new index = FindStringInArray(hBossList, sMainBoss);
-		if (index != -1)
-		{
-			// Main boss exists; remove him from the list.
-			RemoveFromArray(hBossList, index);
-		}
-		else
-		{
-			// Main boss doesn't exist; remove the first boss from the list.
-			RemoveFromArray(hBossList, 0);
-		}
-	}
-	
-	return hBossList;
-}
-
-static HandleNewBossRoundState()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleNewBossRoundState()");
-#endif
-	
-	new bool:bOld = g_bNewBossRound;
-	new bool:bContinuousOld = g_bNewBossRoundContinuous;
-	g_bNewBossRound = false;
-	g_bNewBossRoundNew = false;
-	g_bNewBossRoundContinuous = false;
-	
-	new bool:bForceNew = false;
-	
-	if (bOld)
-	{
-		if (bContinuousOld)
-		{
-			// Check if there are players who haven't played the boss round yet.
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || !IsClientParticipating(i))
-				{
-					g_bPlayerPlayedNewBossRound[i] = true;
-					continue;
-				}
-				
-				if (!g_bPlayerPlayedNewBossRound[i])
-				{
-					// Someone didn't get to play this yet. Continue the boss round.
-					g_bNewBossRound = true;
-					g_bNewBossRoundContinuous = true;
-					break;
-				}
-			}
-		}
-	}
-	
-	// Don't force a new special round while a continuous round is going on.
-	if (!g_bNewBossRoundContinuous)
-	{
-		new iRoundInterval = GetConVarInt(g_cvNewBossRoundInterval);
-		
-		if (/*iRoundInterval > 0 &&*/ iRoundInterval <= 0 || g_iNewBossRoundCount >= iRoundInterval)
-		{
-			g_bNewBossRound = true;
-			bForceNew = true;
-		}
-	}
-	
-	// Do boss round force override and reset it.
-	if (GetConVarInt(g_cvNewBossRoundForce) >= 0)
-	{
-		g_bNewBossRound = GetConVarBool(g_cvNewBossRoundForce);
-		SetConVarInt(g_cvNewBossRoundForce, -1);
-	}
-	
-	// Check if we have enough bosses.
-	if (g_bNewBossRound)
-	{
-		new Handle:hBossList = GetNewBossRoundProfileList();
-	
-		if (GetArraySize(hBossList) < 1)
-		{
-			g_bNewBossRound = false; // Not enough bosses.
-		}
-		
-		CloseHandle(hBossList);
-	}
-	
-	if (g_bNewBossRound)
-	{
-		if (bForceNew || !bOld || !bContinuousOld)
-		{
-			g_bNewBossRoundNew = true;
-		}
-		
-		if (g_bNewBossRoundNew)
-		{
-			if (GetConVarInt(g_cvNewBossRoundBehavior) == 1)
-			{
-				g_bNewBossRoundContinuous = true;
-			}
-			else
-			{
-				// New "new boss round", but it's not continuous.
-				g_bNewBossRoundContinuous = false;
-			}
-		}
-	}
-	else
-	{
-		g_bNewBossRoundContinuous = false;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleNewBossRoundState() -> g_bNewBossRound = %d (count = %d, new = %d, continuous = %d)", g_bNewBossRound, g_iNewBossRoundCount, g_bNewBossRoundNew, g_bNewBossRoundContinuous);
-#endif
-}
-
-/**
- *	Returns the amount of players that are in game and currently not eliminated.
- */
-stock GetActivePlayerCount()
-{
-	new count = 0;
-
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || !IsClientParticipating(i)) continue;
-		
-		if (!g_bPlayerEliminated[i])
-		{
-			count++;
-		}
-	}
-	
-	return count;
-}
-
-static SelectStartingBossesForRound()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START SelectStartingBossesForRound()");
-#endif
-
-	new Handle:hSelectableBossList = GetSelectableBossProfileList();
-
-	// Select which boss profile to use.
-	decl String:sProfileOverride[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetConVarString(g_cvBossProfileOverride, sProfileOverride, sizeof(sProfileOverride));
-	
-	if (strlen(sProfileOverride) > 0 && IsProfileValid(sProfileOverride))
-	{
-		// Pick the overridden boss.
-		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfileOverride);
-		SetConVarString(g_cvBossProfileOverride, "");
-	}
-	else if (g_bNewBossRound)
-	{
-		if (g_bNewBossRoundNew)
-		{
-			new Handle:hBossList = GetNewBossRoundProfileList();
-		
-			GetArrayString(hBossList, GetRandomInt(0, GetArraySize(hBossList) - 1), g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile));
-		
-			CloseHandle(hBossList);
-		}
-		
-		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), g_strNewBossRoundProfile);
-	}
-	else
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetConVarString(g_cvBossMain, sProfile, sizeof(sProfile));
-		
-		if (strlen(sProfile) > 0 && IsProfileValid(sProfile))
-		{
-			strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfile);
-		}
-		else
-		{
-			if (GetArraySize(hSelectableBossList) > 0)
-			{
-				// Pick the first boss in our array if the main boss doesn't exist.
-				GetArrayString(hSelectableBossList, 0, g_strRoundBossProfile, sizeof(g_strRoundBossProfile));
-			}
-			else
-			{
-				// No bosses to pick. What?
-				strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), "");
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END SelectStartingBossesForRound() -> boss: %s", g_strRoundBossProfile);
-#endif
-}
-
-static GetRoundIntroParameters()
-{
-	g_iRoundIntroFadeColor[0] = 0;
-	g_iRoundIntroFadeColor[1] = 0;
-	g_iRoundIntroFadeColor[2] = 0;
-	g_iRoundIntroFadeColor[3] = 255;
-	
-	g_flRoundIntroFadeHoldTime = GetConVarFloat(g_cvIntroDefaultHoldTime);
-	g_flRoundIntroFadeDuration = GetConVarFloat(g_cvIntroDefaultFadeTime);
-	
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "env_fade")) != -1)
-	{
-		decl String:sName[32];
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		if (StrEqual(sName, "sf2_intro_fade", false))
-		{
-			new iColorOffset = FindSendPropOffs("CBaseEntity", "m_clrRender");
-			if (iColorOffset != -1)
-			{
-				g_iRoundIntroFadeColor[0] = GetEntData(ent, iColorOffset, 1);
-				g_iRoundIntroFadeColor[1] = GetEntData(ent, iColorOffset + 1, 1);
-				g_iRoundIntroFadeColor[2] = GetEntData(ent, iColorOffset + 2, 1);
-				g_iRoundIntroFadeColor[3] = GetEntData(ent, iColorOffset + 3, 1);
-			}
-			
-			g_flRoundIntroFadeHoldTime = GetEntPropFloat(ent, Prop_Data, "m_HoldTime");
-			g_flRoundIntroFadeDuration = GetEntPropFloat(ent, Prop_Data, "m_Duration");
-			
-			break;
-		}
-	}
-	
-	// Get the intro music.
-	strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), SF2_INTRO_DEFAULT_MUSIC);
-	
-	ent = -1;
-	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
-	{
-		decl String:sName[64];
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		
-		if (StrEqual(sName, "sf2_intro_music", false))
-		{
-			decl String:sSongPath[PLATFORM_MAX_PATH];
-			GetEntPropString(ent, Prop_Data, "m_iszSound", sSongPath, sizeof(sSongPath));
-			
-			if (strlen(sSongPath) == 0)
-			{
-				LogError("Found sf2_intro_music entity, but it has no sound path specified! Default intro music will be used instead.");
-			}
-			else
-			{
-				strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), sSongPath);
-			}
-			
-			break;
-		}
-	}
-}
-
-static GetRoundEscapeParameters()
-{
-	g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
-	
-	decl String:sName[64];
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		if (!StrContains(sName, "sf2_escape_spawnpoint", false))
-		{
-			g_iRoundEscapePointEntity = EntIndexToEntRef(ent);
-			break;
-		}
-	}
-}
-
-InitializeNewGame()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeNewGame()");
-#endif
-	
-	GetRoundIntroParameters();
-	GetRoundEscapeParameters();
-	
-	// Choose round state.
-	if (GetConVarBool(g_cvIntroEnabled))
-	{
-		// Set the round state to the intro stage.
-		SetRoundState(SF2RoundState_Intro);
-	}
-	else
-	{
-		SetRoundState(SF2RoundState_Active);
-	}
-	
-	if (g_iRoundActiveCount == 1)
-	{
-		SetConVarString(g_cvBossProfileOverride, "");
-	}
-	
-	HandleSpecialRoundState();
-	
-	// Was a new special round initialized?
-	if (g_bSpecialRound)
-	{
-		if (g_bSpecialRoundNew)
-		{
-			// Reset round count.
-			g_iSpecialRoundCount = 1;
-			
-			if (g_bSpecialRoundContinuous)
-			{
-				// It's the start of a continuous special round.
-			
-				// Initialize all players' values.
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || !IsClientParticipating(i))
-					{
-						g_bPlayerPlayedSpecialRound[i] = true;
-						continue;
-					}
-					
-					g_bPlayerPlayedSpecialRound[i] = false;
-				}
-			}
-			
-			SpecialRoundCycleStart();
-		}
-		else
-		{
-			SpecialRoundStart();
-			
-			if (g_bSpecialRoundContinuous)
-			{
-				// Display the current special round going on to late players.
-				CreateTimer(3.0, Timer_DisplaySpecialRound, _, TIMER_FLAG_NO_MAPCHANGE);
-			}
-		}
-	}
-	else
-	{
-		g_iSpecialRoundCount++;
-	
-		SpecialRoundReset();
-	}
-	
-	// Determine boss round state.
-	HandleNewBossRoundState();
-	
-	if (g_bNewBossRound)
-	{
-		if (g_bNewBossRoundNew)
-		{
-			// Reset round count;
-			g_iNewBossRoundCount = 1;
-			
-			if (g_bNewBossRoundContinuous)
-			{
-				// It's the start of a continuous "new boss round".
-			
-				// Initialize all players' values.
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || !IsClientParticipating(i))
-					{
-						g_bPlayerPlayedNewBossRound[i] = true;
-						continue;
-					}
-					
-					g_bPlayerPlayedNewBossRound[i] = false;
-				}
-			}
-		}
-	}
-	else
-	{
-		g_iNewBossRoundCount++;
-	}
-	
-	InitializeMapEntities();
-	
-	// Initialize pages and entities.
-	GetPageMusicRanges();
-	
-	SelectStartingBossesForRound();
-	
-	ForceInNextPlayersInQueue(GetMaxPlayersForRound());
-	
-	// Respawn all players, if needed.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if(IsValidClient(i)) {
-			if (IsClientParticipating(i))
-			{
-				if (!HandlePlayerTeam(i))
-				{
-					TF2_RespawnPlayer(i);
-				}
-				/*
-				if(g_bPlayerEliminated[i]) {
-					ClientSetGhostModeState(i, true);
-					PrintToServer("IsClientParticipating(%d): %d", i, IsClientParticipating(i));
-					PrintToServer("g_bPlayerEliminated[%d]: %d", i, g_bPlayerEliminated[i]);
-					PrintToServer("IsClientInGhostMode(%d): %d", i, IsClientInGhostMode(i));
-				}
-				*/
-			}
-			//PrintToServer("IsClientInGhostMode(i): %d", IsClientInGhostMode(i));
-			//if(IsClientInGhostMode(i)) ClientGhostModeNextTarget(i);
-		}
-	}
-	
-	if (GetRoundState() == SF2RoundState_Intro)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i)) continue;
-			
-			if (!g_bPlayerEliminated[i])
-			{
-				if (!IsFakeClient(i))
-				{
-					// Currently in intro state, play intro music.
-					g_hPlayerIntroMusicTimer[i] = CreateTimer(0.5, Timer_PlayIntroMusicToPlayer, GetClientUserId(i), TIMER_FLAG_NO_MAPCHANGE);
-				}
-				else
-				{
-					g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
-				}
-			}
-			else
-			{
-				g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
-				/*
-				PrintToServer("IsClientInGhostMode(i): %d", IsClientInGhostMode(i));
-				if(IsClientInGhostMode(i)) ClientGhostModeNextTarget(i);
-				*/
-			}
-		}
-	}
-	else
-	{
-		// Spawn the boss!
-		SelectProfile(0, g_strRoundBossProfile);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeNewGame()");
-#endif
-}
-
-public Action:Timer_PlayIntroMusicToPlayer(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerIntroMusicTimer[client]) return;
-	
-	g_hPlayerIntroMusicTimer[client] = INVALID_HANDLE;
-	
-	EmitSoundToClient(client, g_strRoundIntroMusic, _, MUSIC_CHAN, SNDLEVEL_NONE);
-}
-
-public Action:Timer_IntroTextSequence(Handle:timer)
-{
-	if (!g_bEnabled) return;
-	if (g_hRoundIntroTextTimer != timer) return;
-	
-	new Float:flDuration = 0.0;
-	
-	if (g_iRoundIntroText != 0)
-	{
-		new bool:bFoundGameText = false;
-		
-		new iClients[MAXPLAYERS + 1];
-		new iClientsNum;
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
-			
-			iClients[iClientsNum] = i;
-			iClientsNum++;
-		}
-		
-		if (!g_bRoundIntroTextDefault)
-		{
-			decl String:sTargetname[64];
-			Format(sTargetname, sizeof(sTargetname), "sf2_intro_text_%d", g_iRoundIntroText);
-		
-			new iGameText = FindEntityByTargetname(sTargetname, "game_text");
-			if (iGameText && iGameText != INVALID_ENT_REFERENCE)
-			{
-				bFoundGameText = true;
-				flDuration = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
-				
-				decl String:sMessage[512];
-				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
-			}
-		}
-		else
-		{
-			if (g_iRoundIntroText == 2)
-			{
-				bFoundGameText = false;
-				
-				decl String:sMessage[64];
-				GetCurrentMap(sMessage, sizeof(sMessage));
-				
-				for (new i = 0; i < iClientsNum; i++)
-				{
-					ClientShowMainMessage(iClients[i], sMessage, 1);
-				}
-			}
-		}
-		
-		if (g_iRoundIntroText == 1 && !bFoundGameText)
-		{
-			// Use default intro sequence. Eugh.
-			g_bRoundIntroTextDefault = true;
-			flDuration = GetConVarFloat(g_cvIntroDefaultHoldTime) / 2.0;
-			
-			for (new i = 0; i < iClientsNum; i++)
-			{
-				EmitSoundToClient(iClients[i], SF2_INTRO_DEFAULT_MUSIC, _, MUSIC_CHAN, SNDLEVEL_NONE);
-			}
-		}
-		else
-		{
-			if (!bFoundGameText) return; // done with sequence; don't check anymore.
-		}
-	}
-	
-	g_iRoundIntroText++;
-	g_hRoundIntroTextTimer = CreateTimer(flDuration, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_ActivateRoundFromIntro(Handle:timer)
-{
-	if (!g_bEnabled) return;
-	if (g_hRoundIntroTimer != timer) return;
-	
-	// Obviously we don't want to spawn the boss when g_strRoundBossProfile isn't set yet.
-	SetRoundState(SF2RoundState_Active);
-	
-	// Spawn the boss!
-	SelectProfile(0, g_strRoundBossProfile);
-}
-
-CheckRoundWinConditions()
-{
-	if (IsRoundInWarmup() || IsRoundEnding()) return;
-	
-	new iTotalCount = 0;
-	new iAliveCount = 0;
-	new iEscapedCount = 0;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		iTotalCount++;
-		if (!g_bPlayerEliminated[i] && !IsClientInDeathCam(i)) 
-		{
-			iAliveCount++;
-			if (DidClientEscape(i)) iEscapedCount++;
-		}
-	}
-	
-	if (iAliveCount == 0)
-	{
-		ForceTeamWin(_:TFTeam_Blue);
-	}
-	else
-	{
-		if (g_bRoundHasEscapeObjective)
-		{
-			if (iEscapedCount == iAliveCount)
-			{
-				ForceTeamWin(_:TFTeam_Red);
-			}
-		}
-		else
-		{
-			if (g_iPageMax > 0 && g_iPageCount == g_iPageMax)
-			{
-				ForceTeamWin(_:TFTeam_Red);
-			}
-		}
-	}
-}
-
-//	==========================================================
-//	API
-//	==========================================================
-
-public Native_IsRunning(Handle:plugin, numParams)
-{
-	return g_bEnabled;
-}
-
-public Native_GetCurrentDifficulty(Handle:plugin, numParams)
-{
-	return GetConVarInt(g_cvDifficulty);
-}
-
-public Native_GetDifficultyModifier(Handle:plugin, numParams)
-{
-	new iDifficulty = GetNativeCell(1);
-	if (iDifficulty < Difficulty_Easy || iDifficulty >= Difficulty_Max)
-	{
-		LogError("Difficulty parameter can only be from %d to %d!", Difficulty_Easy, Difficulty_Max - 1);
-		return _:1.0;
-	}
-	
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return _:DIFFICULTY_EASY;
-		case Difficulty_Hard: return _:DIFFICULTY_HARD;
-		case Difficulty_Insane: return _:DIFFICULTY_INSANE;
-	}
-	
-	return _:DIFFICULTY_NORMAL;
-}
-
-public Native_IsClientEliminated(Handle:plugin, numParams)
-{
-	return g_bPlayerEliminated[GetNativeCell(1)];
-}
-
-public Native_IsClientInGhostMode(Handle:plugin, numParams)
-{
-	return IsClientInGhostMode(GetNativeCell(1));
-}
-
-public Native_IsClientProxy(Handle:plugin, numParams)
-{
-	return g_bPlayerProxy[GetNativeCell(1)];
-}
-
-public Native_GetClientBlinkCount(Handle:plugin, numParams)
-{
-	return ClientGetBlinkCount(GetNativeCell(1));
-}
-
-public Native_GetClientProxyMaster(Handle:plugin, numParams)
-{
-	return NPCGetFromUniqueID(g_iPlayerProxyMaster[GetNativeCell(1)]);
-}
-
-public Native_GetClientProxyControlAmount(Handle:plugin, numParams)
-{
-	return g_iPlayerProxyControl[GetNativeCell(1)];
-}
-
-public Native_GetClientProxyControlRate(Handle:plugin, numParams)
-{
-	return _:g_flPlayerProxyControlRate[GetNativeCell(1)];
-}
-
-public Native_SetClientProxyMaster(Handle:plugin, numParams)
-{
-	g_iPlayerProxyMaster[GetNativeCell(1)] = NPCGetUniqueID(GetNativeCell(2));
-}
-
-public Native_SetClientProxyControlAmount(Handle:plugin, numParams)
-{
-	g_iPlayerProxyControl[GetNativeCell(1)] = GetNativeCell(2);
-}
-
-public Native_SetClientProxyControlRate(Handle:plugin, numParams)
-{
-	g_flPlayerProxyControlRate[GetNativeCell(1)] = Float:GetNativeCell(2);
-}
-
-public Native_IsClientLookingAtBoss(Handle:plugin, numParams)
-{
-	return g_bPlayerSeesSlender[GetNativeCell(1)][GetNativeCell(2)];
-}
-
-public Native_GetMaxBosses(Handle:plugin, numParams)
-{
-	return MAX_BOSSES;
-}
-
-public Native_EntIndexToBossIndex(Handle:plugin, numParams)
-{
-	return NPCGetFromEntIndex(GetNativeCell(1));
-}
-
-public Native_BossIndexToEntIndex(Handle:plugin, numParams)
-{
-	return NPCGetEntIndex(GetNativeCell(1));
-}
-
-public Native_BossIDToBossIndex(Handle:plugin, numParams)
-{
-	return NPCGetFromUniqueID(GetNativeCell(1));
-}
-
-public Native_BossIndexToBossID(Handle:plugin, numParams)
-{
-	return NPCGetUniqueID(GetNativeCell(1));
-}
-
-public Native_GetBossName(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(GetNativeCell(1), sProfile, sizeof(sProfile));
-	
-	SetNativeString(2, sProfile, GetNativeCell(3));
-}
-
-public Native_GetBossModelEntity(Handle:plugin, numParams)
-{
-	return EntRefToEntIndex(g_iSlenderModel[GetNativeCell(1)]);
-}
-
-public Native_GetBossTarget(Handle:plugin, numParams)
-{
-	return EntRefToEntIndex(g_iSlenderTarget[GetNativeCell(1)]);
-}
-
-public Native_GetBossMaster(Handle:plugin, numParams)
-{
-	return g_iSlenderCopyMaster[GetNativeCell(1)];
-}
-
-public Native_GetBossState(Handle:plugin, numParams)
-{
-	return g_iSlenderState[GetNativeCell(1)];
-}
-
-public Native_IsBossProfileValid(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-	
-	return IsProfileValid(sProfile);
-}
-
-public Native_GetBossProfileNum(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-	
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	return GetProfileNum(sProfile, sKeyValue, GetNativeCell(3));
-}
-
-public Native_GetBossProfileFloat(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	return _:GetProfileFloat(sProfile, sKeyValue, Float:GetNativeCell(3));
-}
-
-public Native_GetBossProfileString(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	new iResultLen = GetNativeCell(4);
-	decl String:sResult[iResultLen];
-	
-	decl String:sDefaultValue[512];
-	GetNativeString(5, sDefaultValue, sizeof(sDefaultValue));
-	
-	new bool:bSuccess = GetProfileString(sProfile, sKeyValue, sResult, iResultLen, sDefaultValue);
-	
-	SetNativeString(3, sResult, iResultLen);
-	return bSuccess;
-}
-
-public Native_GetBossProfileVector(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	decl Float:flResult[3];
-	decl Float:flDefaultValue[3];
-	GetNativeArray(4, flDefaultValue, 3);
-	
-	new bool:bSuccess = GetProfileVector(sProfile, sKeyValue, flResult, flDefaultValue);
-	
-	SetNativeArray(3, flResult, 3);
-	return bSuccess;
-}
-
-public Native_GetRandomStringFromBossProfile(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	new iBufferLen = GetNativeCell(4);
-	decl String:sBuffer[iBufferLen];
-	
-	new iIndex = GetNativeCell(5);
-	
-	new bool:bSuccess = GetRandomStringFromProfile(sProfile, sKeyValue, sBuffer, iBufferLen, iIndex);
-	SetNativeString(3, sBuffer, iBufferLen);
-	return bSuccess;
+#include <sourcemod>
+#include <sdktools>
+#include <sdkhooks>
+#include <clientprefs>
+#include <steamtools>
+#include <tf2items>
+#include <dhooks>
+#include <navmesh>
+
+#include <tf2>
+#include <tf2_stocks>
+#include <morecolors>
+#include <sf2>
+
+#undef REQUIRE_PLUGIN
+#include <adminmenu>
+#tryinclude <store/store-tf2footprints>
+#define REQUIRE_PLUGIN
+
+//#define DEBUG
+
+// If compiling with SM 1.7+, uncomment to compile and use SF2 methodmaps.
+//#define METHODMAPS
+
+#define PLUGIN_VERSION "0.2.6-git136"
+#define PLUGIN_VERSION_DISPLAY "0.2.6"
+
+public Plugin:myinfo = 
+{
+    name = "RYTP Horror (Slender Fortress edit by lexuzieel special for Penek-Gaming.Ru)",
+    author	= "KitRifty",
+    description	= "Based on the game Slender: The Eight Pages.",
+    version = PLUGIN_VERSION,
+    url = "http://steamcommunity.com/groups/SlenderFortress"
+}
+
+#define FILE_RESTRICTEDWEAPONS "configs/sf2/restrictedweapons.cfg"
+
+#define BOSS_THINKRATE 0.1 // doesn't really matter much since timers go at a minimum of 0.1 seconds anyways
+
+#define CRIT_SOUND "player/crit_hit.wav"
+#define CRIT_PARTICLENAME "crit_text"
+
+#define PAGE_MODEL "models/rytp/horror/props/hint_paper.mdl"
+#define PAGE_MODELSCALE 1.1
+
+#define FLASHLIGHT_CLICKSOUND "rytp_horror/toggleflashlight.wav"
+#define FLASHLIGHT_BREAKSOUND "ambient/energy/spark6.wav"
+#define FLASHLIGHT_NOSOUND "player/suit_denydevice.wav"
+#define PAGE_GRABSOUND "rytp_horror/grabpage_sound.wav"
+
+#define MUSIC_CHAN SNDCHAN_AUTO
+
+#define MUSIC_GOTPAGES1_SOUND "rytp_horror/grabpage_music_1.wav"
+#define MUSIC_GOTPAGES2_SOUND "rytp_horror/grabpage_music_2.wav"
+#define MUSIC_GOTPAGES3_SOUND "rytp_horror/grabpage_music_3.wav"
+#define MUSIC_GOTPAGES4_SOUND "rytp_horror/grabpage_music_4.wav"
+#define MUSIC_PAGE_VOLUME 1.0
+
+#define SF2_INTRO_DEFAULT_MUSIC "rytp_horror/intro_music.mp3"
+
+#define SF2_HUD_TEXT_COLOR_R 127
+#define SF2_HUD_TEXT_COLOR_G 167
+#define SF2_HUD_TEXT_COLOR_B 141
+#define SF2_HUD_TEXT_COLOR_A 255
+
+enum MuteMode
+{
+	MuteMode_Normal = 0,
+	MuteMode_DontHearOtherTeam,
+	MuteMode_DontHearOtherTeamIfNotProxy
+};
+
+// Offsets.
+new g_offsPlayerFOV = -1;
+new g_offsPlayerDefaultFOV = -1;
+new g_offsPlayerFogCtrl = -1;
+new g_offsPlayerPunchAngle = -1;
+new g_offsPlayerPunchAngleVel = -1;
+new g_offsFogCtrlEnable = -1;
+new g_offsFogCtrlEnd = -1;
+
+new g_iParticleCriticalHit = -1;
+
+new bool:g_bEnabled;
+
+new Handle:g_hConfig;
+new Handle:g_hRestrictedWeaponsConfig;
+new Handle:g_hSpecialRoundsConfig;
+
+new Handle:g_hPageMusicRanges;
+
+new g_iSlenderModel[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+new g_iSlenderPoseEnt[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+new g_iSlenderCopyMaster[MAX_BOSSES] = { -1, ... };
+new Float:g_flSlenderEyePosOffset[MAX_BOSSES][3];
+new Float:g_flSlenderEyeAngOffset[MAX_BOSSES][3];
+new Float:g_flSlenderDetectMins[MAX_BOSSES][3];
+new Float:g_flSlenderDetectMaxs[MAX_BOSSES][3];
+new Handle:g_hSlenderThink[MAX_BOSSES];
+new Handle:g_hSlenderEntityThink[MAX_BOSSES];
+new Handle:g_hSlenderFakeTimer[MAX_BOSSES];
+new Float:g_flSlenderLastKill[MAX_BOSSES];
+new g_iSlenderState[MAX_BOSSES];
+new g_iSlenderTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+new Float:g_flSlenderAcceleration[MAX_BOSSES];
+new Float:g_flSlenderGoalPos[MAX_BOSSES][3];
+new Float:g_flSlenderStaticRadius[MAX_BOSSES];
+new Float:g_flSlenderChaseDeathPosition[MAX_BOSSES][3];
+new bool:g_bSlenderChaseDeathPosition[MAX_BOSSES];
+new Float:g_flSlenderIdleAnimationPlaybackRate[MAX_BOSSES];
+new Float:g_flSlenderWalkAnimationPlaybackRate[MAX_BOSSES];
+new Float:g_flSlenderRunAnimationPlaybackRate[MAX_BOSSES];
+new Float:g_flSlenderJumpSpeed[MAX_BOSSES];
+new Float:g_flSlenderPathNodeTolerance[MAX_BOSSES];
+new Float:g_flSlenderPathNodeLookAhead[MAX_BOSSES];
+new bool:g_bSlenderFeelerReflexAdjustment[MAX_BOSSES];
+new Float:g_flSlenderFeelerReflexAdjustmentPos[MAX_BOSSES][3];
+
+new g_iSlenderTeleportTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+
+new Float:g_flSlenderNextTeleportTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportTargetTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMinRange[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMaxRange[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMaxTargetTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMaxTargetStress[MAX_BOSSES] = { 0.0, ... };
+new Float:g_flSlenderTeleportPlayersRestTime[MAX_BOSSES][MAXPLAYERS + 1];
+
+// For boss type 2
+// General variables
+new g_iSlenderHealth[MAX_BOSSES];
+new Handle:g_hSlenderPath[MAX_BOSSES];
+new g_iSlenderCurrentPathNode[MAX_BOSSES] = { -1, ... };
+new bool:g_bSlenderAttacking[MAX_BOSSES];
+new Handle:g_hSlenderAttackTimer[MAX_BOSSES];
+new Float:g_flSlenderNextJump[MAX_BOSSES] = { -1.0, ... };
+new g_iSlenderInterruptConditions[MAX_BOSSES];
+new Float:g_flSlenderLastFoundPlayer[MAX_BOSSES][MAXPLAYERS + 1];
+new Float:g_flSlenderLastFoundPlayerPos[MAX_BOSSES][MAXPLAYERS + 1][3];
+new Float:g_flSlenderNextPathTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderCalculatedWalkSpeed[MAX_BOSSES];
+new Float:g_flSlenderCalculatedSpeed[MAX_BOSSES];
+new Float:g_flSlenderTimeUntilNoPersistence[MAX_BOSSES];
+
+new Float:g_flSlenderProxyTeleportMinRange[MAX_BOSSES];
+new Float:g_flSlenderProxyTeleportMaxRange[MAX_BOSSES];
+
+// Sound variables
+new Float:g_flSlenderTargetSoundLastTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTargetSoundMasterPos[MAX_BOSSES][3]; // to determine hearing focus
+new Float:g_flSlenderTargetSoundTempPos[MAX_BOSSES][3];
+new Float:g_flSlenderTargetSoundDiscardMasterPosTime[MAX_BOSSES];
+new bool:g_bSlenderInvestigatingSound[MAX_BOSSES];
+new SoundType:g_iSlenderTargetSoundType[MAX_BOSSES] = { SoundType_None, ... };
+new g_iSlenderTargetSoundCount[MAX_BOSSES];
+new Float:g_flSlenderLastHeardVoice[MAX_BOSSES];
+new Float:g_flSlenderLastHeardFootstep[MAX_BOSSES];
+new Float:g_flSlenderLastHeardWeapon[MAX_BOSSES];
+
+
+new Float:g_flSlenderNextJumpScare[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderNextVoiceSound[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderNextMoanSound[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderNextWanderPos[MAX_BOSSES] = { -1.0, ... };
+
+
+new Float:g_flSlenderTimeUntilRecover[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilAlert[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilIdle[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilChase[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilKill[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilNextProxy[MAX_BOSSES] = { -1.0, ... };
+
+// Page data.
+new g_iPageCount;
+new g_iPageMax;
+new Float:g_flPageFoundLastTime;
+new bool:g_bPageRef;
+new String:g_strPageRefModel[PLATFORM_MAX_PATH];
+new Float:g_flPageRefModelScale;
+
+static Handle:g_hPlayerIntroMusicTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Seeing Mr. Slendy data.
+new bool:g_bPlayerSeesSlender[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerSeesSlenderLastTime[MAXPLAYERS + 1][MAX_BOSSES];
+
+new Float:g_flPlayerSightSoundNextTime[MAXPLAYERS + 1][MAX_BOSSES];
+
+new Float:g_flPlayerScareLastTime[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerScareNextTime[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerStaticAmount[MAXPLAYERS + 1];
+
+new Float:g_flPlayerLastChaseBossEncounterTime[MAXPLAYERS + 1][MAX_BOSSES];
+
+// Player static data.
+new g_iPlayerStaticMode[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerStaticIncreaseRate[MAXPLAYERS + 1];
+new Float:g_flPlayerStaticDecreaseRate[MAXPLAYERS + 1];
+new Handle:g_hPlayerStaticTimer[MAXPLAYERS + 1];
+new g_iPlayerStaticMaster[MAXPLAYERS + 1] = { -1, ... };
+new String:g_strPlayerStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new String:g_strPlayerLastStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerLastStaticTime[MAXPLAYERS + 1];
+new Float:g_flPlayerLastStaticVolume[MAXPLAYERS + 1];
+new Handle:g_hPlayerLastStaticTimer[MAXPLAYERS + 1];
+
+// Static shake data.
+new g_iPlayerStaticShakeMaster[MAXPLAYERS + 1];
+new bool:g_bPlayerInStaticShake[MAXPLAYERS + 1];
+new String:g_strPlayerStaticShakeSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerStaticShakeMinVolume[MAXPLAYERS + 1];
+new Float:g_flPlayerStaticShakeMaxVolume[MAXPLAYERS + 1];
+
+// Fake lag compensation for FF.
+new bool:g_bPlayerLagCompensation[MAXPLAYERS + 1];
+new g_iPlayerLagCompensationTeam[MAXPLAYERS + 1];
+
+// Hint data.
+enum
+{
+	PlayerHint_Sprint = 0,
+	PlayerHint_Flashlight,
+	PlayerHint_MainMenu,
+	PlayerHint_Blink,
+	PlayerHint_MaxNum
+};
+
+enum PlayerPreferences
+{
+	bool:PlayerPreference_PvPAutoSpawn,
+	MuteMode:PlayerPreference_MuteMode,
+	bool:PlayerPreference_FilmGrain,
+	bool:PlayerPreference_ShowHints,
+	bool:PlayerPreference_EnableProxySelection,
+	bool:PlayerPreference_ProjectedFlashlight,
+	bool:PlayerPreference_GhostOverlay
+};
+
+new bool:g_bPlayerHints[MAXPLAYERS + 1][PlayerHint_MaxNum];
+new g_iPlayerPreferences[MAXPLAYERS + 1][PlayerPreferences];
+
+// Player data.
+new g_iPlayerLastButtons[MAXPLAYERS + 1];
+new bool:g_bPlayerChoseTeam[MAXPLAYERS + 1];
+new bool:g_bPlayerEliminated[MAXPLAYERS + 1];
+new bool:g_bPlayerEscaped[MAXPLAYERS + 1];
+new g_iPlayerPageCount[MAXPLAYERS + 1];
+new g_iPlayerQueuePoints[MAXPLAYERS + 1];
+new bool:g_bPlayerPlaying[MAXPLAYERS + 1];
+new Handle:g_hPlayerOverlayCheck[MAXPLAYERS + 1];
+
+new Handle:g_hPlayerSwitchBlueTimer[MAXPLAYERS + 1];
+
+// Player stress data.
+new Float:g_flPlayerStress[MAXPLAYERS + 1];
+new Float:g_flPlayerStressNextUpdateTime[MAXPLAYERS + 1];
+
+// Proxy data.
+new bool:g_bPlayerProxy[MAXPLAYERS + 1];
+new bool:g_bPlayerProxyAvailable[MAXPLAYERS + 1];
+new Handle:g_hPlayerProxyAvailableTimer[MAXPLAYERS + 1];
+new bool:g_bPlayerProxyAvailableInForce[MAXPLAYERS + 1];
+new g_iPlayerProxyAvailableCount[MAXPLAYERS + 1];
+new g_iPlayerProxyMaster[MAXPLAYERS + 1];
+new g_iPlayerProxyControl[MAXPLAYERS + 1];
+new Handle:g_hPlayerProxyControlTimer[MAXPLAYERS + 1];
+new Float:g_flPlayerProxyControlRate[MAXPLAYERS + 1];
+new Handle:g_flPlayerProxyVoiceTimer[MAXPLAYERS + 1];
+new g_iPlayerProxyAskMaster[MAXPLAYERS + 1] = { -1, ... };
+new Float:g_iPlayerProxyAskPosition[MAXPLAYERS + 1][3];
+
+new g_iPlayerDesiredFOV[MAXPLAYERS + 1];
+
+new Handle:g_hPlayerPostWeaponsTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Music system.
+new g_iPlayerMusicFlags[MAXPLAYERS + 1];
+new String:g_strPlayerMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerMusicVolume[MAXPLAYERS + 1];
+new Float:g_flPlayerMusicTargetVolume[MAXPLAYERS + 1];
+new Handle:g_hPlayerMusicTimer[MAXPLAYERS + 1];
+new g_iPlayerPageMusicMaster[MAXPLAYERS + 1];
+
+// Chase music system, which apparently also uses the alert song system. And the idle sound system.
+new String:g_strPlayerChaseMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new String:g_strPlayerChaseMusicSee[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerChaseMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerChaseMusicSeeVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayerChaseMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayerChaseMusicSeeTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new g_iPlayerChaseMusicMaster[MAXPLAYERS + 1] = { -1, ... };
+new g_iPlayerChaseMusicSeeMaster[MAXPLAYERS + 1] = { -1, ... };
+
+new String:g_strPlayerAlertMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerAlertMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayerAlertMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new g_iPlayerAlertMusicMaster[MAXPLAYERS + 1] = { -1, ... };
+
+new String:g_strPlayer20DollarsMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayer20DollarsMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayer20DollarsMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new g_iPlayer20DollarsMusicMaster[MAXPLAYERS + 1] = { -1, ... };
+
+
+new SF2RoundState:g_iRoundState = SF2RoundState_Invalid;
+new bool:g_bRoundGrace = false;
+new Float:g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
+new bool:g_bRoundInfiniteFlashlight = false;
+new bool:g_bRoundInfiniteBlink = false;
+new bool:g_bRoundInfiniteSprint = false;
+
+static Handle:g_hRoundGraceTimer = INVALID_HANDLE;
+static Handle:g_hRoundTimer = INVALID_HANDLE;
+static Handle:g_hVoteTimer = INVALID_HANDLE;
+static String:g_strRoundBossProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+
+static g_iRoundCount = 0;
+static g_iRoundEndCount = 0;
+static g_iRoundActiveCount = 0;
+static g_iRoundTime = 0;
+static g_iRoundTimeLimit = 0;
+static g_iRoundEscapeTimeLimit = 0;
+static g_iRoundTimeGainFromPage = 0;
+static bool:g_bRoundHasEscapeObjective = false;
+
+static g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
+
+static g_iRoundIntroFadeColor[4] = { 255, ... };
+static Float:g_flRoundIntroFadeHoldTime;
+static Float:g_flRoundIntroFadeDuration;
+static Handle:g_hRoundIntroTimer = INVALID_HANDLE;
+static bool:g_bRoundIntroTextDefault = true;
+static Handle:g_hRoundIntroTextTimer = INVALID_HANDLE;
+static g_iRoundIntroText;
+static String:g_strRoundIntroMusic[PLATFORM_MAX_PATH] = "";
+
+static g_iRoundWarmupRoundCount = 0;
+
+static bool:g_bRoundWaitingForPlayers = false;
+
+// Special round variables.
+new bool:g_bSpecialRound = false;
+new g_iSpecialRoundType = 0;
+new bool:g_bSpecialRoundNew = false;
+new bool:g_bSpecialRoundContinuous = false;
+new g_iSpecialRoundCount = 1;
+new bool:g_bPlayerPlayedSpecialRound[MAXPLAYERS + 1] = { true, ... };
+
+// New boss round variables.
+static bool:g_bNewBossRound = false;
+static bool:g_bNewBossRoundNew = false;
+static bool:g_bNewBossRoundContinuous = false;
+static g_iNewBossRoundCount = 1;
+static bool:g_bPlayerPlayedNewBossRound[MAXPLAYERS + 1] = { true, ... };
+static String:g_strNewBossRoundProfile[64] = "";
+
+static Handle:g_hRoundMessagesTimer = INVALID_HANDLE;
+static g_iRoundMessagesNum = 0;
+
+static Handle:g_hBossCountUpdateTimer = INVALID_HANDLE;
+static Handle:g_hClientAverageUpdateTimer = INVALID_HANDLE;
+
+// Server variables.
+new Handle:g_cvVersion;
+new Handle:g_cvEnabled;
+new Handle:g_cvSlenderMapsOnly;
+new Handle:g_cvPlayerViewbobEnabled;
+new Handle:g_cvPlayerShakeEnabled;
+new Handle:g_cvPlayerShakeFrequencyMax;
+new Handle:g_cvPlayerShakeAmplitudeMax;
+new Handle:g_cvGraceTime;
+new Handle:g_cvAllChat;
+new Handle:g_cv20Dollars;
+new Handle:g_cvMaxPlayers;
+new Handle:g_cvMaxPlayersOverride;
+new Handle:g_cvCampingEnabled;
+new Handle:g_cvCampingMaxStrikes;
+new Handle:g_cvCampingStrikesWarn;
+new Handle:g_cvCampingMinDistance;
+new Handle:g_cvCampingNoStrikeSanity;
+new Handle:g_cvCampingNoStrikeBossDistance;
+new Handle:g_cvDifficulty;
+new Handle:g_cvBossMain;
+new Handle:g_cvBossProfileOverride;
+new Handle:g_cvPlayerBlinkRate;
+new Handle:g_cvPlayerBlinkHoldTime;
+new Handle:g_cvSpecialRoundBehavior;
+new Handle:g_cvSpecialRoundForce;
+new Handle:g_cvSpecialRoundOverride;
+new Handle:g_cvSpecialRoundInterval;
+new Handle:g_cvNewBossRoundBehavior;
+new Handle:g_cvNewBossRoundInterval;
+new Handle:g_cvNewBossRoundForce;
+new Handle:g_cvPlayerVoiceDistance;
+new Handle:g_cvPlayerVoiceWallScale;
+new Handle:g_cvUltravisionEnabled;
+new Handle:g_cvUltravisionRadiusRed;
+new Handle:g_cvUltravisionRadiusBlue;
+new Handle:g_cvUltravisionBrightness;
+new Handle:g_cvGhostModeConnectionCheck;
+new Handle:g_cvGhostModeConnectionTolerance;
+new Handle:g_cvIntroEnabled;
+new Handle:g_cvIntroDefaultHoldTime;
+new Handle:g_cvIntroDefaultFadeTime;
+new Handle:g_cvTimeLimit;
+new Handle:g_cvTimeLimitEscape;
+new Handle:g_cvTimeGainFromPageGrab;
+new Handle:g_cvWarmupRound;
+new Handle:g_cvWarmupRoundNum;
+new Handle:g_cvPlayerViewbobHurtEnabled;
+new Handle:g_cvPlayerViewbobSprintEnabled;
+new Handle:g_cvPlayerFakeLagCompensation;
+new Handle:g_cvPlayerProxyWaitTime;
+new Handle:g_cvPlayerProxyAsk;
+new Handle:g_cvHalfZatoichiHealthGain;
+new Handle:g_cvBlockSuicideDuringRound;
+
+new Handle:g_cvPlayerInfiniteSprintOverride;
+new Handle:g_cvPlayerInfiniteFlashlightOverride;
+new Handle:g_cvPlayerInfiniteBlinkOverride;
+
+new Handle:g_cvGravity;
+new Float:g_flGravity;
+
+new Handle:g_cvMaxRounds;
+
+new bool:g_b20Dollars;
+
+new bool:g_bPlayerShakeEnabled;
+new bool:g_bPlayerViewbobEnabled;
+new bool:g_bPlayerViewbobHurtEnabled;
+new bool:g_bPlayerViewbobSprintEnabled;
+
+new Handle:g_hHudSync;
+new Handle:g_hHudSync2;
+new Handle:g_hRoundTimerSync;
+
+new Handle:g_hCookie;
+
+// Global forwards.
+new Handle:fOnBossAdded;
+new Handle:fOnBossSpawn;
+new Handle:fOnBossChangeState;
+new Handle:fOnBossRemoved;
+new Handle:fOnPagesSpawned;
+new Handle:fOnClientBlink;
+new Handle:fOnClientCaughtByBoss;
+new Handle:fOnClientGiveQueuePoints;
+new Handle:fOnClientActivateFlashlight;
+new Handle:fOnClientDeactivateFlashlight;
+new Handle:fOnClientBreakFlashlight;
+new Handle:fOnClientEscape;
+new Handle:fOnClientLooksAtBoss;
+new Handle:fOnClientLooksAwayFromBoss;
+new Handle:fOnClientStartDeathCam;
+new Handle:fOnClientEndDeathCam;
+new Handle:fOnClientGetDefaultWalkSpeed;
+new Handle:fOnClientGetDefaultSprintSpeed;
+new Handle:fOnClientSpawnedAsProxy;
+new Handle:fOnClientDamagedByBoss;
+new Handle:fOnGroupGiveQueuePoints;
+
+new Handle:g_hSDKWeaponScattergun;
+new Handle:g_hSDKWeaponPistolScout;
+new Handle:g_hSDKWeaponBat;
+new Handle:g_hSDKWeaponSniperRifle;
+new Handle:g_hSDKWeaponSMG;
+new Handle:g_hSDKWeaponKukri;
+new Handle:g_hSDKWeaponRocketLauncher;
+new Handle:g_hSDKWeaponShotgunSoldier;
+new Handle:g_hSDKWeaponShovel;
+new Handle:g_hSDKWeaponGrenadeLauncher;
+new Handle:g_hSDKWeaponStickyLauncher;
+new Handle:g_hSDKWeaponBottle;
+new Handle:g_hSDKWeaponMinigun;
+new Handle:g_hSDKWeaponShotgunHeavy;
+new Handle:g_hSDKWeaponFists;
+new Handle:g_hSDKWeaponSyringeGun;
+new Handle:g_hSDKWeaponMedigun;
+new Handle:g_hSDKWeaponBonesaw;
+new Handle:g_hSDKWeaponFlamethrower;
+new Handle:g_hSDKWeaponShotgunPyro;
+new Handle:g_hSDKWeaponFireaxe;
+new Handle:g_hSDKWeaponRevolver;
+new Handle:g_hSDKWeaponKnife;
+new Handle:g_hSDKWeaponInvis;
+new Handle:g_hSDKWeaponShotgunPrimary;
+new Handle:g_hSDKWeaponPistol;
+new Handle:g_hSDKWeaponWrench;
+
+new Handle:g_hSDKGetMaxHealth;
+new Handle:g_hSDKWantsLagCompensationOnEntity;
+new Handle:g_hSDKShouldTransmit;
+
+#include "rytp_horror/stocks.sp"
+#include "rytp_horror/overlay.sp"
+#include "rytp_horror/logging.sp"
+#include "rytp_horror/debug.sp"
+#include "rytp_horror/profiles.sp"
+#include "rytp_horror/nav.sp"
+#include "rytp_horror/effects.sp"
+#include "rytp_horror/playergroups.sp"
+#include "rytp_horror/menus.sp"
+#include "rytp_horror/pvp.sp"
+#include "rytp_horror/client.sp"
+#include "rytp_horror/npc.sp"
+#include "rytp_horror/specialround.sp"
+#include "rytp_horror/adminmenu.sp"
+
+
+#define SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND "ui/item_acquired.wav"
+
+//	==========================================================
+//	GENERAL PLUGIN HOOK FUNCTIONS
+//	==========================================================
+
+public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
+{
+	RegPluginLibrary("sf2");
+	
+	fOnBossAdded = CreateGlobalForward("SF2_OnBossAdded", ET_Ignore, Param_Cell);
+	fOnBossSpawn = CreateGlobalForward("SF2_OnBossSpawn", ET_Ignore, Param_Cell);
+	fOnBossChangeState = CreateGlobalForward("SF2_OnBossChangeState", ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
+	fOnBossRemoved = CreateGlobalForward("SF2_OnBossRemoved", ET_Ignore, Param_Cell);
+	fOnPagesSpawned = CreateGlobalForward("SF2_OnPagesSpawned", ET_Ignore);
+	fOnClientBlink = CreateGlobalForward("SF2_OnClientBlink", ET_Ignore, Param_Cell);
+	fOnClientCaughtByBoss = CreateGlobalForward("SF2_OnClientCaughtByBoss", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientGiveQueuePoints = CreateGlobalForward("SF2_OnClientGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
+	fOnClientActivateFlashlight = CreateGlobalForward("SF2_OnClientActivateFlashlight", ET_Ignore, Param_Cell);
+	fOnClientDeactivateFlashlight = CreateGlobalForward("SF2_OnClientDeactivateFlashlight", ET_Ignore, Param_Cell);
+	fOnClientBreakFlashlight = CreateGlobalForward("SF2_OnClientBreakFlashlight", ET_Ignore, Param_Cell);
+	fOnClientEscape = CreateGlobalForward("SF2_OnClientEscape", ET_Ignore, Param_Cell);
+	fOnClientLooksAtBoss = CreateGlobalForward("SF2_OnClientLooksAtBoss", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientLooksAwayFromBoss = CreateGlobalForward("SF2_OnClientLooksAwayFromBoss", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientStartDeathCam = CreateGlobalForward("SF2_OnClientStartDeathCam", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientEndDeathCam = CreateGlobalForward("SF2_OnClientEndDeathCam", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientGetDefaultWalkSpeed = CreateGlobalForward("SF2_OnClientGetDefaultWalkSpeed", ET_Hook, Param_Cell, Param_CellByRef);
+	fOnClientGetDefaultSprintSpeed = CreateGlobalForward("SF2_OnClientGetDefaultSprintSpeed", ET_Hook, Param_Cell, Param_CellByRef);
+	fOnClientSpawnedAsProxy = CreateGlobalForward("SF2_OnClientSpawnedAsProxy", ET_Ignore, Param_Cell);
+	fOnClientDamagedByBoss = CreateGlobalForward("SF2_OnClientDamagedByBoss", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell);
+	fOnGroupGiveQueuePoints = CreateGlobalForward("SF2_OnGroupGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
+	
+	CreateNative("SF2_IsRunning", Native_IsRunning);
+	CreateNative("SF2_GetCurrentDifficulty", Native_GetCurrentDifficulty);
+	CreateNative("SF2_GetDifficultyModifier", Native_GetDifficultyModifier);
+	CreateNative("SF2_IsClientEliminated", Native_IsClientEliminated);
+	CreateNative("SF2_IsClientInGhostMode", Native_IsClientInGhostMode);
+	CreateNative("SF2_IsClientProxy", Native_IsClientProxy);
+	CreateNative("SF2_GetClientBlinkCount", Native_GetClientBlinkCount);
+	CreateNative("SF2_GetClientProxyMaster", Native_GetClientProxyMaster);
+	CreateNative("SF2_GetClientProxyControlAmount", Native_GetClientProxyControlAmount);
+	CreateNative("SF2_GetClientProxyControlRate", Native_GetClientProxyControlRate);
+	CreateNative("SF2_SetClientProxyMaster", Native_SetClientProxyMaster);
+	CreateNative("SF2_SetClientProxyControlAmount", Native_SetClientProxyControlAmount);
+	CreateNative("SF2_SetClientProxyControlRate", Native_SetClientProxyControlRate);
+	CreateNative("SF2_IsClientLookingAtBoss", Native_IsClientLookingAtBoss);
+	CreateNative("SF2_CollectAsPage", Native_CollectAsPage);
+	CreateNative("SF2_GetMaxBossCount", Native_GetMaxBosses);
+	CreateNative("SF2_EntIndexToBossIndex", Native_EntIndexToBossIndex);
+	CreateNative("SF2_BossIndexToEntIndex", Native_BossIndexToEntIndex);
+	CreateNative("SF2_BossIDToBossIndex", Native_BossIDToBossIndex);
+	CreateNative("SF2_BossIndexToBossID", Native_BossIndexToBossID);
+	CreateNative("SF2_GetBossName", Native_GetBossName);
+	CreateNative("SF2_GetBossModelEntity", Native_GetBossModelEntity);
+	CreateNative("SF2_GetBossTarget", Native_GetBossTarget);
+	CreateNative("SF2_GetBossMaster", Native_GetBossMaster);
+	CreateNative("SF2_GetBossState", Native_GetBossState);
+	CreateNative("SF2_IsBossProfileValid", Native_IsBossProfileValid);
+	CreateNative("SF2_GetBossProfileNum", Native_GetBossProfileNum);
+	CreateNative("SF2_GetBossProfileFloat", Native_GetBossProfileFloat);
+	CreateNative("SF2_GetBossProfileString", Native_GetBossProfileString);
+	CreateNative("SF2_GetBossProfileVector", Native_GetBossProfileVector);
+	CreateNative("SF2_GetRandomStringFromBossProfile", Native_GetRandomStringFromBossProfile);
+	
+	PvP_InitializeAPI();
+	
+	SpecialRoundInitializeAPI();
+	
+	return APLRes_Success;
+}
+
+public OnPluginStart()
+{
+	LoadTranslations("core.phrases");
+	LoadTranslations("common.phrases");
+	LoadTranslations("sf2.phrases");
+	
+	// Get offsets.
+	g_offsPlayerFOV = FindSendPropInfo("CBasePlayer", "m_iFOV");
+	if (g_offsPlayerFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iFOV.");
+	
+	g_offsPlayerDefaultFOV = FindSendPropInfo("CBasePlayer", "m_iDefaultFOV");
+	if (g_offsPlayerDefaultFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iDefaultFOV.");
+	
+	g_offsPlayerFogCtrl = FindSendPropInfo("CBasePlayer", "m_PlayerFog.m_hCtrl");
+	if (g_offsPlayerFogCtrl == -1) LogError("Couldn't find CBasePlayer offset for m_PlayerFog.m_hCtrl!");
+	
+	g_offsPlayerPunchAngle = FindSendPropInfo("CBasePlayer", "m_vecPunchAngle");
+	if (g_offsPlayerPunchAngle == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngle!");
+	
+	g_offsPlayerPunchAngleVel = FindSendPropInfo("CBasePlayer", "m_vecPunchAngleVel");
+	if (g_offsPlayerPunchAngleVel == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngleVel!");
+	
+	g_offsFogCtrlEnable = FindSendPropInfo("CFogController", "m_fog.enable");
+	if (g_offsFogCtrlEnable == -1) LogError("Couldn't find CFogController offset for m_fog.enable!");
+	
+	g_offsFogCtrlEnd = FindSendPropInfo("CFogController", "m_fog.end");
+	if (g_offsFogCtrlEnd == -1) LogError("Couldn't find CFogController offset for m_fog.end!");
+	
+	g_hPageMusicRanges = CreateArray(3);
+	
+	// Register console variables.
+	g_cvVersion = CreateConVar("sf2_version", PLUGIN_VERSION, "The current version of Slender Fortress. DO NOT TOUCH!", FCVAR_SPONLY | FCVAR_NOTIFY | FCVAR_DONTRECORD);
+	SetConVarString(g_cvVersion, PLUGIN_VERSION);
+	
+	g_cvEnabled = CreateConVar("sf2_enabled", "1", "Enable/Disable the Slender Fortress gamemode. This will take effect on map change.", FCVAR_NOTIFY | FCVAR_DONTRECORD);
+	g_cvSlenderMapsOnly = CreateConVar("sf2_slendermapsonly", "1", "Only enable the Slender Fortress gamemode on map names prefixed with \"slender_\" or \"sf2_\".");
+	
+	g_cvGraceTime = CreateConVar("sf2_gracetime", "30.0");
+	g_cvIntroEnabled = CreateConVar("sf2_intro_enabled", "1");
+	g_cvIntroDefaultHoldTime = CreateConVar("sf2_intro_default_hold_time", "9.0");
+	g_cvIntroDefaultFadeTime = CreateConVar("sf2_intro_default_fade_time", "1.0");
+	
+	g_cvBlockSuicideDuringRound = CreateConVar("sf2_block_suicide_during_round", "0");
+	
+	g_cvAllChat = CreateConVar("sf2_alltalk", "0");
+	HookConVarChange(g_cvAllChat, OnConVarChanged);
+	
+	g_cvPlayerVoiceDistance = CreateConVar("sf2_player_voice_distance", "800.0", "The maximum distance RED can communicate in voice chat. Set to 0 if you want them to be heard at all times.", _, true, 0.0);
+	g_cvPlayerVoiceWallScale = CreateConVar("sf2_player_voice_scale_blocked", "0.5", "The distance required to hear RED in voice chat will be multiplied by this amount if something is blocking them.");
+	
+	g_cvPlayerViewbobEnabled = CreateConVar("sf2_player_viewbob_enabled", "1", "Enable/Disable player viewbobbing.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerViewbobEnabled, OnConVarChanged);
+	g_cvPlayerViewbobHurtEnabled = CreateConVar("sf2_player_viewbob_hurt_enabled", "0", "Enable/Disable player view tilting when hurt.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerViewbobHurtEnabled, OnConVarChanged);
+	g_cvPlayerViewbobSprintEnabled = CreateConVar("sf2_player_viewbob_sprint_enabled", "0", "Enable/Disable player step viewbobbing when sprinting.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerViewbobSprintEnabled, OnConVarChanged);
+	g_cvGravity = FindConVar("sv_gravity");
+	HookConVarChange(g_cvGravity, OnConVarChanged);
+	
+	g_cvPlayerFakeLagCompensation = CreateConVar("sf2_player_fakelagcompensation", "0", "(EXPERIMENTAL) Enable/Disable fake lag compensation for some hitscan weapons such as the Sniper Rifle.", _, true, 0.0, true, 1.0);
+	
+	g_cvPlayerShakeEnabled = CreateConVar("sf2_player_shake_enabled", "1", "Enable/Disable player view shake during boss encounters.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerShakeEnabled, OnConVarChanged);
+	g_cvPlayerShakeFrequencyMax = CreateConVar("sf2_player_shake_frequency_max", "255", "Maximum frequency value of the shake. Should be a value between 1-255.", _, true, 1.0, true, 255.0);
+	g_cvPlayerShakeAmplitudeMax = CreateConVar("sf2_player_shake_amplitude_max", "5", "Maximum amplitude value of the shake. Should be a value between 1-16.", _, true, 1.0, true, 16.0);
+	
+	g_cvPlayerBlinkRate = CreateConVar("sf2_player_blink_rate", "0.33", "How long (in seconds) each bar on the player's Blink meter lasts.", _, true, 0.0);
+	g_cvPlayerBlinkHoldTime = CreateConVar("sf2_player_blink_holdtime", "0.15", "How long (in seconds) a player will stay in Blink mode when he or she blinks.", _, true, 0.0);
+	
+	g_cvUltravisionEnabled = CreateConVar("sf2_player_ultravision_enabled", "1", "Enable/Disable player Ultravision. This helps players see in the dark when their Flashlight is off or unavailable.", _, true, 0.0, true, 1.0);
+	g_cvUltravisionRadiusRed = CreateConVar("sf2_player_ultravision_radius_red", "512.0");
+	g_cvUltravisionRadiusBlue = CreateConVar("sf2_player_ultravision_radius_blue", "800.0");
+	g_cvUltravisionBrightness = CreateConVar("sf2_player_ultravision_brightness", "-4");
+	
+	g_cvGhostModeConnectionCheck = CreateConVar("sf2_ghostmode_check_connection", "1", "Checks a player's connection while in Ghost Mode. If the check fails, the client is booted out of Ghost Mode and the action and client's SteamID is logged in the main SF2 log.");
+	g_cvGhostModeConnectionTolerance = CreateConVar("sf2_ghostmode_connection_tolerance", "5.0", "If sf2_ghostmode_check_connection is set to 1 and the client has timed out for at least this amount of time, the client will be booted out of Ghost Mode.");
+	
+	g_cv20Dollars = CreateConVar("sf2_20dollarmode", "0", "Enable/Disable $20 mode.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cv20Dollars, OnConVarChanged);
+	
+	g_cvMaxPlayers = CreateConVar("sf2_maxplayers", "5", "The maximum amount of players that can be in one round.", _, true, 1.0);
+	HookConVarChange(g_cvMaxPlayers, OnConVarChanged);
+	
+	g_cvMaxPlayersOverride = CreateConVar("sf2_maxplayers_override", "-1", "Overrides the maximum amount of players that can be in one round.", _, true, -1.0);
+	HookConVarChange(g_cvMaxPlayersOverride, OnConVarChanged);
+	
+	g_cvCampingEnabled = CreateConVar("sf2_anticamping_enabled", "1", "Enable/Disable anti-camping system for RED.", _, true, 0.0, true, 1.0);
+	g_cvCampingMaxStrikes = CreateConVar("sf2_anticamping_maxstrikes", "4", "How many 5-second intervals players are allowed to stay in one spot before he/she is forced to suicide.", _, true, 0.0);
+	g_cvCampingStrikesWarn = CreateConVar("sf2_anticamping_strikeswarn", "2", "The amount of strikes left where the player will be warned of camping.");
+	g_cvCampingMinDistance = CreateConVar("sf2_anticamping_mindistance", "128.0", "Every 5 seconds the player has to be at least this far away from his last position 5 seconds ago or else he'll get a strike.");
+	g_cvCampingNoStrikeSanity = CreateConVar("sf2_anticamping_no_strike_sanity", "0.1", "The camping system will NOT give any strikes under any circumstances if the players's Sanity is missing at least this much of his maximum Sanity (max is 1.0).");
+	g_cvCampingNoStrikeBossDistance = CreateConVar("sf2_anticamping_no_strike_boss_distance", "512.0", "The camping system will NOT give any strikes under any circumstances if the player is this close to a boss (ignoring LOS).");
+	g_cvBossMain = CreateConVar("sf2_boss_main", "slenderman", "The name of the main boss (its profile name, not its display name)");
+	g_cvBossProfileOverride = CreateConVar("sf2_boss_profile_override", "", "Overrides which boss will be chosen next. Only applies to the first boss being chosen.");
+	g_cvDifficulty = CreateConVar("sf2_difficulty", "1", "Difficulty of the game. 1 = Normal, 2 = Hard, 3 = Insane.", _, true, 1.0, true, 3.0);
+	HookConVarChange(g_cvDifficulty, OnConVarChanged);
+	
+	g_cvSpecialRoundBehavior = CreateConVar("sf2_specialround_mode", "0", "0 = Special Round resets on next round, 1 = Special Round keeps going until all players have played (not counting spectators, recently joined players, and those who reset their queue points during the round)", _, true, 0.0, true, 1.0);
+	g_cvSpecialRoundForce = CreateConVar("sf2_specialround_forceenable", "-1", "Sets whether a Special Round will occur on the next round or not.", _, true, -1.0, true, 1.0);
+	g_cvSpecialRoundOverride = CreateConVar("sf2_specialround_forcetype", "-1", "Sets the type of Special Round that will be chosen on the next Special Round. Set to -1 to let the game choose.", _, true, -1.0);
+	g_cvSpecialRoundInterval = CreateConVar("sf2_specialround_interval", "5", "If this many rounds are completed, the next round will be a Special Round.", _, true, 0.0);
+	
+	g_cvNewBossRoundBehavior = CreateConVar("sf2_newbossround_mode", "0", "0 = boss selection will return to normal after the boss round, 1 = the new boss will continue being the boss until all players in the server have played against it (not counting spectators, recently joined players, and those who reset their queue points during the round).", _, true, 0.0, true, 1.0);
+	g_cvNewBossRoundInterval = CreateConVar("sf2_newbossround_interval", "3", "If this many rounds are completed, the next round's boss will be randomly chosen, but will not be the main boss.", _, true, 0.0);
+	g_cvNewBossRoundForce = CreateConVar("sf2_newbossround_forceenable", "-1", "Sets whether a new boss will be chosen on the next round or not. Set to -1 to let the game choose.", _, true, -1.0, true, 1.0);
+	
+	g_cvTimeLimit = CreateConVar("sf2_timelimit_default", "300", "The time limit of the round. Maps can change the time limit.", _, true, 0.0);
+	g_cvTimeLimitEscape = CreateConVar("sf2_timelimit_escape_default", "90", "The time limit to escape. Maps can change the time limit.", _, true, 0.0);
+	g_cvTimeGainFromPageGrab = CreateConVar("sf2_time_gain_page_grab", "12", "The time gained from grabbing a page. Maps can change the time gain amount.");
+	
+	g_cvWarmupRound = CreateConVar("sf2_warmupround", "1", "Enables/disables Warmup Rounds after the \"Waiting for Players\" phase.", _, true, 0.0, true, 1.0);
+	g_cvWarmupRoundNum = CreateConVar("sf2_warmupround_num", "1", "Sets the amount of Warmup Rounds that occur after the \"Waiting for Players\" phase.", _, true, 0.0);
+	
+	g_cvPlayerProxyWaitTime = CreateConVar("sf2_player_proxy_waittime", "35", "How long (in seconds) after a player was chosen to be a Proxy must the system wait before choosing him again.");
+	g_cvPlayerProxyAsk = CreateConVar("sf2_player_proxy_ask", "0", "Set to 1 if the player can choose before becoming a Proxy, set to 0 to force.");
+	
+	g_cvHalfZatoichiHealthGain = CreateConVar("sf2_halfzatoichi_healthgain", "20", "How much health should be gained from killing a player with the Half-Zatoichi? Set to -1 for default behavior.");
+	
+	g_cvPlayerInfiniteSprintOverride = CreateConVar("sf2_player_infinite_sprint_override", "-1", "1 = infinite sprint, 0 = never have infinite sprint, -1 = let the game choose.", _, true, -1.0, true, 1.0);
+	g_cvPlayerInfiniteFlashlightOverride = CreateConVar("sf2_player_infinite_flashlight_override", "-1", "1 = infinite flashlight, 0 = never have infinite flashlight, -1 = let the game choose.", _, true, -1.0, true, 1.0);
+	g_cvPlayerInfiniteBlinkOverride = CreateConVar("sf2_player_infinite_blink_override", "-1", "1 = infinite blink, 0 = never have infinite blink, -1 = let the game choose.", _, true, -1.0, true, 1.0);
+	
+	g_cvMaxRounds = FindConVar("mp_maxrounds");
+	
+	g_hHudSync = CreateHudSynchronizer();
+	g_hHudSync2 = CreateHudSynchronizer();
+	g_hRoundTimerSync = CreateHudSynchronizer();
+	g_hCookie = RegClientCookie("slender_cookie", "", CookieAccess_Private);
+	
+	// Register console commands.
+	RegConsoleCmd("sm_sf2", Command_MainMenu);
+	RegConsoleCmd("sm_slender", Command_MainMenu);
+	RegConsoleCmd("sm_horror", Command_MainMenu);
+	RegConsoleCmd("sm_slnext", Command_Next);
+	RegConsoleCmd("sm_slgroup", Command_Group);
+	RegConsoleCmd("sm_slgroupname", Command_GroupName);
+	RegConsoleCmd("sm_slghost", Command_GhostMode);
+	RegConsoleCmd("sm_slhelp", Command_Help);
+	RegConsoleCmd("sm_slsettings", Command_Settings);
+	RegConsoleCmd("sm_slcredits", Command_Credits);
+	RegConsoleCmd("sm_flashlight", Command_ToggleFlashlight);
+	RegConsoleCmd("+sprint", Command_SprintOn);
+	RegConsoleCmd("-sprint", Command_SprintOff);
+	
+	RegAdminCmd("sm_sf2_scare", Command_ClientPerformScare, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_spawn_boss", Command_SpawnSlender, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_add_boss", Command_AddSlender, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_add_boss_fake", Command_AddSlenderFake, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_remove_boss", Command_RemoveSlender, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_getbossindexes", Command_GetBossIndexes, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_setplaystate", Command_ForceState, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_boss_attack_waiters", Command_SlenderAttackWaiters, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_boss_no_teleport", Command_SlenderNoTeleport, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_force_proxy", Command_ForceProxy, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_force_escape", Command_ForceEscape, ADMFLAG_CHEATS);
+	
+	// Hook onto existing console commands.
+	AddCommandListener(Hook_CommandBuild, "build");
+	AddCommandListener(Hook_CommandSuicideAttempt, "kill");
+	AddCommandListener(Hook_CommandSuicideAttempt, "explode");
+	AddCommandListener(Hook_CommandSuicideAttempt, "joinclass");
+	AddCommandListener(Hook_CommandSuicideAttempt, "join_class");
+	AddCommandListener(Hook_CommandSuicideAttempt, "jointeam");
+	AddCommandListener(Hook_CommandSuicideAttempt, "spectate");
+	AddCommandListener(Hook_CommandVoiceMenu, "voicemenu");
+	AddCommandListener(Hook_CommandSay, "say");
+	
+	// Hook events.
+	HookEvent("teamplay_round_start", Event_RoundStart);
+	HookEvent("teamplay_round_win", Event_RoundEnd);
+	HookEvent("player_team", Event_DontBroadcastToClients, EventHookMode_Pre);
+	HookEvent("player_team", Event_PlayerTeam);
+	HookEvent("player_spawn", Event_PlayerSpawn);
+	HookEvent("player_hurt", Event_PlayerHurt);
+	HookEvent("post_inventory_application", Event_PostInventoryApplication);
+	HookEvent("item_found", Event_DontBroadcastToClients, EventHookMode_Pre);
+	HookEvent("teamplay_teambalanced_player", Event_DontBroadcastToClients, EventHookMode_Pre);
+	HookEvent("fish_notice", Event_PlayerDeathPre, EventHookMode_Pre);
+	HookEvent("fish_notice__arm", Event_PlayerDeathPre, EventHookMode_Pre);
+	HookEvent("player_death", Event_PlayerDeathPre, EventHookMode_Pre);
+	HookEvent("player_death", Event_PlayerDeath);
+	
+	// Hook entities.
+	HookEntityOutput("trigger_multiple", "OnStartTouch", Hook_TriggerOnStartTouch);
+	HookEntityOutput("trigger_multiple", "OnEndTouch", Hook_TriggerOnEndTouch);
+	
+	// Hook usermessages.
+	HookUserMessage(GetUserMessageId("VoiceSubtitle"), Hook_BlockUserMessage, true);
+	
+	// Hook sounds.
+	AddNormalSoundHook(Hook_NormalSound);
+	
+	AddTempEntHook("Fire Bullets", Hook_TEFireBullets);
+	
+	InitializeBossProfiles();
+	
+	NPCInitialize();
+	
+	SetupMenus();
+	
+	SetupAdminMenu();
+	
+	SetupClassDefaultWeapons();
+	
+	SetupPlayerGroups();
+	
+	PvP_Initialize();
+	
+	// @TODO: When cvars are finalized, set this to true.
+	AutoExecConfig(false);
+	
+#if defined DEBUG
+	InitializeDebug();
+#endif
+}
+
+public OnAllPluginsLoaded()
+{
+	SetupHooks();
+}
+
+public OnPluginEnd()
+{
+	StopPlugin();
+}
+
+static SetupHooks()
+{
+	// Check SDKHooks gamedata.
+	new Handle:hConfig = LoadGameConfigFile("sdkhooks.games");
+	if (hConfig == INVALID_HANDLE) SetFailState("Couldn't find SDKHooks gamedata!");
+	
+	StartPrepSDKCall(SDKCall_Entity);
+	PrepSDKCall_SetFromConf(hConfig, SDKConf_Virtual, "GetMaxHealth");
+	PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+	if ((g_hSDKGetMaxHealth = EndPrepSDKCall()) == INVALID_HANDLE)
+	{
+		SetFailState("Failed to retrieve GetMaxHealth offset from SDKHooks gamedata!");
+	}
+	
+	CloseHandle(hConfig);
+	
+	// Check our own gamedata.
+	hConfig = LoadGameConfigFile("sf2");
+	if (hConfig == INVALID_HANDLE) SetFailState("Could not find SF2 gamedata!");
+	
+	new iOffset = GameConfGetOffset(hConfig, "CTFPlayer::WantsLagCompensationOnEntity"); 
+	g_hSDKWantsLagCompensationOnEntity = DHookCreate(iOffset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_ClientWantsLagCompensationOnEntity); 
+	if (g_hSDKWantsLagCompensationOnEntity == INVALID_HANDLE)
+	{
+		SetFailState("Failed to create hook CTFPlayer::WantsLagCompensationOnEntity offset from SF2 gamedata!");
+	}
+	
+	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_CBaseEntity);
+	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_ObjectPtr);
+	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_Unknown);
+	
+	iOffset = GameConfGetOffset(hConfig, "CBaseEntity::ShouldTransmit");
+	g_hSDKShouldTransmit = DHookCreate(iOffset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, Hook_EntityShouldTransmit);
+	if (g_hSDKShouldTransmit == INVALID_HANDLE)
+	{
+		SetFailState("Failed to create hook CBaseEntity::ShouldTransmit offset from SF2 gamedata!");
+	}
+	
+	DHookAddParam(g_hSDKShouldTransmit, HookParamType_ObjectPtr);
+	
+	CloseHandle(hConfig);
+}
+
+static SetupClassDefaultWeapons()
+{
+	// Scout
+	g_hSDKWeaponScattergun = PrepareItemHandle("tf_weapon_scattergun", 13, 0, 0, "");
+	g_hSDKWeaponPistolScout = PrepareItemHandle("tf_weapon_pistol", 23, 0, 0, "");
+	g_hSDKWeaponBat = PrepareItemHandle("tf_weapon_bat", 0, 0, 0, "");
+	
+	// Sniper
+	g_hSDKWeaponSniperRifle = PrepareItemHandle("tf_weapon_sniperrifle", 14, 0, 0, "");
+	g_hSDKWeaponSMG = PrepareItemHandle("tf_weapon_smg", 16, 0, 0, "");
+	g_hSDKWeaponKukri = PrepareItemHandle("tf_weapon_club", 3, 0, 0, "");
+	
+	// Soldier
+	g_hSDKWeaponRocketLauncher = PrepareItemHandle("tf_weapon_rocketlauncher", 18, 0, 0, "");
+	g_hSDKWeaponShotgunSoldier = PrepareItemHandle("tf_weapon_shotgun", 10, 0, 0, "");
+	g_hSDKWeaponShovel = PrepareItemHandle("tf_weapon_shovel", 6, 0, 0, "");
+	
+	// Demoman
+	g_hSDKWeaponGrenadeLauncher = PrepareItemHandle("tf_weapon_grenadelauncher", 19, 0, 0, "");
+	g_hSDKWeaponStickyLauncher = PrepareItemHandle("tf_weapon_pipebomblauncher", 20, 0, 0, "");
+	g_hSDKWeaponBottle = PrepareItemHandle("tf_weapon_bottle", 1, 0, 0, "");
+	
+	// Heavy
+	g_hSDKWeaponMinigun = PrepareItemHandle("tf_weapon_minigun", 15, 0, 0, "");
+	g_hSDKWeaponShotgunHeavy = PrepareItemHandle("tf_weapon_shotgun", 11, 0, 0, "");
+	g_hSDKWeaponFists = PrepareItemHandle("tf_weapon_fists", 5, 0, 0, "");
+	
+	// Medic
+	g_hSDKWeaponSyringeGun = PrepareItemHandle("tf_weapon_syringegun_medic", 17, 0, 0, "");
+	g_hSDKWeaponMedigun = PrepareItemHandle("tf_weapon_medigun", 29, 0, 0, "");
+	g_hSDKWeaponBonesaw = PrepareItemHandle("tf_weapon_bonesaw", 8, 0, 0, "");
+	
+	// Pyro
+	g_hSDKWeaponFlamethrower = PrepareItemHandle("tf_weapon_flamethrower", 21, 0, 0, "254 ; 4.0");
+	g_hSDKWeaponShotgunPyro = PrepareItemHandle("tf_weapon_shotgun", 12, 0, 0, "");
+	g_hSDKWeaponFireaxe = PrepareItemHandle("tf_weapon_fireaxe", 2, 0, 0, "");
+	
+	// Spy
+	g_hSDKWeaponRevolver = PrepareItemHandle("tf_weapon_revolver", 24, 0, 0, "");
+	g_hSDKWeaponKnife = PrepareItemHandle("tf_weapon_knife", 4, 0, 0, "");
+	g_hSDKWeaponInvis = PrepareItemHandle("tf_weapon_invis", 297, 0, 0, "");
+	
+	// Engineer
+	g_hSDKWeaponShotgunPrimary = PrepareItemHandle("tf_weapon_shotgun", 9, 0, 0, "");
+	g_hSDKWeaponPistol = PrepareItemHandle("tf_weapon_pistol", 22, 0, 0, "");
+	g_hSDKWeaponWrench = PrepareItemHandle("tf_weapon_wrench", 7, 0, 0, "");
+}
+
+public OnMapStart()
+{
+	PvP_OnMapStart();
+}
+
+public OnConfigsExecuted()
+{
+	if (!GetConVarBool(g_cvEnabled))
+	{
+		StopPlugin();
+	}
+	else
+	{
+		if (GetConVarBool(g_cvSlenderMapsOnly))
+		{
+			decl String:sMap[256];
+			GetCurrentMap(sMap, sizeof(sMap));
+			
+			if (!StrContains(sMap, "slender_", false) || !StrContains(sMap, "sf2_", false))
+			{
+				StartPlugin();
+			}
+			else
+			{
+				LogMessage("%s is not a Slender Fortress map. Plugin disabled!", sMap);
+				StopPlugin();
+			}
+		}
+		else
+		{
+			StartPlugin();
+		}
+	}
+}
+
+static StartPlugin()
+{
+	if (g_bEnabled) return;
+	
+	g_bEnabled = true;
+	
+	InitializeLogging();
+	
+#if defined DEBUG
+	InitializeDebugLogging();
+#endif
+	
+	// Handle ConVars.
+	new Handle:hCvar = FindConVar("mp_friendlyfire");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
+	
+	hCvar = FindConVar("mp_flashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
+	
+	hCvar = FindConVar("mat_supportflashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
+	
+	hCvar = FindConVar("mp_autoteambalance");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	g_flGravity = GetConVarFloat(g_cvGravity);
+	
+	g_b20Dollars = GetConVarBool(g_cv20Dollars);
+	
+	g_bPlayerShakeEnabled = GetConVarBool(g_cvPlayerShakeEnabled);
+	g_bPlayerViewbobEnabled = GetConVarBool(g_cvPlayerViewbobEnabled);
+	g_bPlayerViewbobHurtEnabled = GetConVarBool(g_cvPlayerViewbobHurtEnabled);
+	g_bPlayerViewbobSprintEnabled = GetConVarBool(g_cvPlayerViewbobSprintEnabled);
+	
+	decl String:sBuffer[64];
+	Format(sBuffer, sizeof(sBuffer), "RYTP Horror", PLUGIN_VERSION_DISPLAY);
+	Steam_SetGameDescription(sBuffer);
+	
+	PrecacheStuff();
+	
+	// Reset special round.
+	g_bSpecialRound = false;
+	g_bSpecialRoundNew = false;
+	g_bSpecialRoundContinuous = false;
+	g_iSpecialRoundCount = 1;
+	g_iSpecialRoundType = 0;
+	
+	SpecialRoundReset();
+	
+	// Reset boss rounds.
+	g_bNewBossRound = false;
+	g_bNewBossRoundNew = false;
+	g_bNewBossRoundContinuous = false;
+	g_iNewBossRoundCount = 1;
+	strcopy(g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile), "");
+	
+	// Reset global round vars.
+	g_iRoundCount = 0;
+	g_iRoundEndCount = 0;
+	g_iRoundActiveCount = 0;
+	g_iRoundState = SF2RoundState_Invalid;
+	g_hRoundMessagesTimer = CreateTimer(200.0, Timer_RoundMessages, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	g_iRoundMessagesNum = 0;
+	
+	g_iRoundWarmupRoundCount = 0;
+	
+	g_hClientAverageUpdateTimer = CreateTimer(0.2, Timer_ClientAverageUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	g_hBossCountUpdateTimer = CreateTimer(2.0, Timer_BossCountUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	
+	SetRoundState(SF2RoundState_Waiting);
+	
+	ReloadBossProfiles();
+	ReloadRestrictedWeapons();
+	ReloadSpecialRounds();
+	
+	NPCOnConfigsExecuted();
+	
+	InitializeBossPackVotes();
+	SetupTimeLimitTimerForBossPackVote();
+	
+	// Late load compensation.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		OnClientPutInServer(i);
+	}
+}
+
+static PrecacheStuff()
+{
+	// Initialize particles.
+	g_iParticleCriticalHit = PrecacheParticleSystem(CRIT_PARTICLENAME);
+	
+	PrecacheSound2(CRIT_SOUND);
+	
+	// simple_bot;
+	PrecacheModel("models/humans/group01/female_01.mdl", true);
+	
+	PrecacheModel(PAGE_MODEL, true);
+	PrecacheModel(GHOST_MODEL, true);
+	
+	PrecacheSound2(FLASHLIGHT_CLICKSOUND);
+	PrecacheSound2(FLASHLIGHT_BREAKSOUND);
+	PrecacheSound2(FLASHLIGHT_NOSOUND);
+	PrecacheSound2(PAGE_GRABSOUND);
+	
+	PrecacheSound2(MUSIC_GOTPAGES1_SOUND);
+	PrecacheSound2(MUSIC_GOTPAGES2_SOUND);
+	PrecacheSound2(MUSIC_GOTPAGES3_SOUND);
+	PrecacheSound2(MUSIC_GOTPAGES4_SOUND);
+	
+	PrecacheSound2(SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
+	
+	for (new i = 0; i < sizeof(g_strPlayerBreathSounds); i++)
+	{
+		PrecacheSound2(g_strPlayerBreathSounds[i]);
+	}
+	
+	// Special round.
+	PrecacheSound2(SR_MUSIC);
+	PrecacheSound2(SR_SOUND_SELECT);
+	PrecacheSound2(SF2_INTRO_DEFAULT_MUSIC);
+	
+	PrecacheMaterial2(SF2_OVERLAY_DEFAULT);
+	PrecacheMaterial2(SF2_OVERLAY_DEFAULT_NO_FILMGRAIN);
+	PrecacheMaterial2(SF2_OVERLAY_GHOST);
+	
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.mdl");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx80.vtx");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx90.vtx");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.phy");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.sw.vtx");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.vvd");
+	
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vmt");
+	
+	// pvp
+	PvP_Precache();
+}
+
+static StopPlugin()
+{
+	if (!g_bEnabled) return;
+	
+	g_bEnabled = false;
+	
+	// Reset CVars.
+	new Handle:hCvar = FindConVar("mp_friendlyfire");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	hCvar = FindConVar("mp_flashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	hCvar = FindConVar("mat_supportflashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	// Cleanup bosses.
+	NPCRemoveAll();
+	
+	// Cleanup clients.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		ClientResetFlashlight(i);
+		ClientDeactivateUltravision(i);
+		ClientDisableConstantGlow(i);
+		ClientRemoveInteractiveGlow(i);
+	}
+	
+	BossProfilesOnMapEnd();
+}
+
+public OnMapEnd()
+{
+	StopPlugin();
+}
+
+public OnMapTimeLeftChanged()
+{
+	if (g_bEnabled)
+	{
+		SetupTimeLimitTimerForBossPackVote();
+	}
+}
+
+public TF2_OnConditionAdded(client, TFCond:cond)
+{
+	if (cond == TFCond_Taunting)
+	{
+		if (IsClientInGhostMode(client))
+		{
+			// Stop ghosties from taunting.
+			TF2_RemoveCondition(client, TFCond_Taunting);
+		}
+	}
+}
+
+public OnGameFrame()
+{
+	if (!g_bEnabled) return;
+
+	// Process through boss movement.
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		new iBoss = NPCGetEntIndex(i);
+		if (!iBoss || iBoss == INVALID_ENT_REFERENCE) continue;
+		
+		if (NPCGetFlags(i) & SFF_MARKEDASFAKE) continue;
+		
+		new iType = NPCGetType(i);
+		
+		switch (iType)
+		{
+			case SF2BossType_Static:
+			{
+				decl Float:myPos[3], Float:hisPos[3];
+				SlenderGetAbsOrigin(i, myPos);
+				AddVectors(myPos, g_flSlenderEyePosOffset[i], myPos);
+				
+				new iBestPlayer = -1;
+				new Float:flBestDistance = 16384.0;
+				new Float:flTempDistance;
+				
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsClientInGame(iClient) || !IsPlayerAlive(iClient) || IsClientInGhostMode(iClient) || IsClientInDeathCam(iClient)) continue;
+					if (!IsPointVisibleToPlayer(iClient, myPos, false, false)) continue;
+					
+					GetClientAbsOrigin(iClient, hisPos);
+					
+					flTempDistance = GetVectorDistance(myPos, hisPos);
+					if (flTempDistance < flBestDistance)
+					{
+						iBestPlayer = iClient;
+						flBestDistance = flTempDistance;
+					}
+				}
+				
+				if (iBestPlayer > 0)
+				{
+					SlenderGetAbsOrigin(i, myPos);
+					GetClientAbsOrigin(iBestPlayer, hisPos);
+					
+					if (!SlenderOnlyLooksIfNotSeen(i) || !IsPointVisibleToAPlayer(myPos, false, SlenderUsesBlink(i)))
+					{
+						new Float:flTurnRate = NPCGetTurnRate(i);
+					
+						if (flTurnRate > 0.0)
+						{
+							decl Float:flMyEyeAng[3], Float:ang[3];
+							GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
+							AddVectors(flMyEyeAng, g_flSlenderEyeAngOffset[i], flMyEyeAng);
+							SubtractVectors(hisPos, myPos, ang);
+							GetVectorAngles(ang, ang);
+							ang[0] = 0.0;
+							ang[1] += (AngleDiff(ang[1], flMyEyeAng[1]) >= 0.0 ? 1.0 : -1.0) * flTurnRate * GetTickInterval();
+							ang[2] = 0.0;
+							
+							// Take care of angle offsets.
+							AddVectors(ang, g_flSlenderEyePosOffset[i], ang);
+							for (new i2 = 0; i2 < 3; i2++) ang[i2] = AngleNormalize(ang[i2]);
+							
+							TeleportEntity(iBoss, NULL_VECTOR, ang, NULL_VECTOR);
+						}
+					}
+				}
+			}
+			case SF2BossType_Chaser:
+			{
+				SlenderChaseBossProcessMovement(i);
+			}
+		}
+	}
+	
+	PvP_OnGameFrame();
+}
+
+//	==========================================================
+//	COMMANDS AND COMMAND HOOK FUNCTIONS
+//	==========================================================
+
+public Action:Command_Help(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayMenu(g_hMenuHelp, client, 30);
+	return Plugin_Handled;
+}
+
+public Action:Command_Settings(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayMenu(g_hMenuSettings, client, 30);
+	return Plugin_Handled;
+}
+
+public Action:Command_Credits(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayMenu(g_hMenuCredits, client, MENU_TIME_FOREVER);
+	return Plugin_Handled;
+}
+
+public Action:Command_ToggleFlashlight(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return Plugin_Handled;
+	
+	if (!IsRoundInWarmup() && !IsRoundInIntro() && !IsRoundEnding() && !DidClientEscape(client))
+	{
+		if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
+		{
+			ClientHandleFlashlight(client);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SprintOn(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
+	{
+		ClientHandleSprint(client, true);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SprintOff(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
+	{
+		ClientHandleSprint(client, false);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_MainMenu(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	DisplayMenu(g_hMenuMain, client, 30);
+	return Plugin_Handled;
+}
+
+public Action:Command_Next(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayQueuePointsMenu(client);
+	return Plugin_Handled;
+}
+
+public Action:Command_Group(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayGroupMainMenuToClient(client);
+	return Plugin_Handled;
+}
+
+public Action:Command_GroupName(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_slgroupname <name>");
+		return Plugin_Handled;
+	}
+	
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return Plugin_Handled;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	GetCmdArg(1, sGroupName, sizeof(sGroupName));
+	if (!sGroupName[0])
+	{
+		CPrintToChat(client, "%T", "SF2 Invalid Group Name", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:sOldGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	GetPlayerGroupName(iGroupIndex, sOldGroupName, sizeof(sOldGroupName));
+	SetPlayerGroupName(iGroupIndex, sGroupName);
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		if (ClientGetPlayerGroup(i) != iGroupIndex) continue;
+		CPrintToChat(i, "%T", "SF2 Group Name Set", i, sOldGroupName, sGroupName);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_GhostMode(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	DisplayMenu(g_hMenuGhostMode, client, 15);
+	return Plugin_Handled;
+}
+
+public Action:Hook_CommandSay(client, const String:command[], argc)
+{
+	if (!g_bEnabled || GetConVarBool(g_cvAllChat)) return Plugin_Continue;
+	
+	if (!IsRoundEnding())
+	{
+		if (g_bPlayerEliminated[client])
+		{
+			decl String:sMessage[256];
+			GetCmdArgString(sMessage, sizeof(sMessage));
+			FakeClientCommand(client, "say_team %s", sMessage);
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_CommandSuicideAttempt(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsClientInGhostMode(client)) return Plugin_Handled;
+	
+	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
+	
+	if (GetConVarBool(g_cvBlockSuicideDuringRound))
+	{
+		if (!g_bRoundGrace && !g_bPlayerEliminated[client] && !DidClientEscape(client))
+		{
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_CommandBlockInGhostMode(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsClientInGhostMode(client)) return Plugin_Handled;
+	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_CommandVoiceMenu(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsClientInGhostMode(client))
+	{
+		ClientGhostModeNextTarget(client);
+		return Plugin_Handled;
+	}
+	
+	if (g_bPlayerProxy[client])
+	{
+		new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+		if (iMaster != -1)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
+		
+			if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
+			{
+				return Plugin_Handled;
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Command_ClientPerformScare(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_scare <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32], String:arg2[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			COMMAND_FILTER_ALIVE,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new target = target_list[i];
+		ClientPerformScare(target, StringToInt(arg2));
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SpawnSlender(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args == 0)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_spawn_boss <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl Float:eyePos[3], Float:eyeAng[3], Float:endPos[3];
+	GetClientEyePosition(client, eyePos);
+	GetClientEyeAngles(client, eyeAng);
+	
+	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
+	TR_GetEndPosition(endPos, hTrace);
+	CloseHandle(hTrace);
+	
+	SpawnSlender(iBossIndex, endPos);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Spawned Boss", client);
+	LogAction(client, -1, "%N spawned boss %d! (%s)", client, iBossIndex, sProfile);
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_RemoveSlender(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args == 0)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_remove_boss <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	NPCRemove(iBossIndex);
+	
+	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Removed Boss", client);
+	LogAction(client, -1, "%N removed boss %d! (%s)", client, iBossIndex, sProfile);
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_GetBossIndexes(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	decl String:sMessage[512];
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	ClientCommand(client, "echo Active Boss Indexes:");
+	ClientCommand(client, "echo ----------------------------");
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		Format(sMessage, sizeof(sMessage), "%d - %s", i, sProfile);
+		if (NPCGetFlags(i) & SFF_FAKE)
+		{
+			StrCat(sMessage, sizeof(sMessage), " (fake)");
+		}
+		
+		if (g_iSlenderCopyMaster[i] != -1)
+		{
+			decl String:sCat[64];
+			Format(sCat, sizeof(sCat), " (copy of %d)", g_iSlenderCopyMaster[i]);
+			StrCat(sMessage, sizeof(sMessage), sCat);
+		}
+		
+		ClientCommand(client, "echo %s", sMessage);
+	}
+	
+	ClientCommand(client, "echo ----------------------------");
+	
+	ReplyToCommand(client, "Printed active boss indexes to your console!");
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SlenderAttackWaiters(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_boss_attack_waiters <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iBossFlags = NPCGetFlags(iBossIndex);
+	
+	new bool:bState = bool:StringToInt(arg2);
+	new bool:bOldState = bool:(iBossFlags & SFF_ATTACKWAITERS);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (bState)
+	{
+		if (!bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags | SFF_ATTACKWAITERS);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Attack Waiters", client);
+			LogAction(client, -1, "%N forced boss %d to attack waiters! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	else
+	{
+		if (bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_ATTACKWAITERS);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Do Not Attack Waiters", client);
+			LogAction(client, -1, "%N forced boss %d to not attack waiters! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SlenderNoTeleport(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_boss_no_teleport <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iBossFlags = NPCGetFlags(iBossIndex);
+	
+	new bool:bState = bool:StringToInt(arg2);
+	new bool:bOldState = bool:(iBossFlags & SFF_NOTELEPORT);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (bState)
+	{
+		if (!bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags | SFF_NOTELEPORT);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Not Teleport", client);
+			LogAction(client, -1, "%N disabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	else
+	{
+		if (bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_NOTELEPORT);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Teleport", client);
+			LogAction(client, -1, "%N enabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_ForceProxy(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_force_proxy <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	if (IsRoundEnding() || IsRoundInWarmup())
+	{
+		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			0,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iBossIndex = StringToInt(arg2);
+	if (iBossIndex < 0 || iBossIndex >= MAX_BOSSES)
+	{
+		ReplyToCommand(client, "Boss index is out of range!");
+		return Plugin_Handled;
+	}
+	else if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		ReplyToCommand(client, "Boss index is invalid! Boss index not active!");
+		return Plugin_Handled;
+	}
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new iTarget = target_list[i];
+		
+		decl String:sName[MAX_NAME_LENGTH];
+		GetClientName(iTarget, sName, sizeof(sName));
+		
+		if (!g_bPlayerEliminated[iTarget])
+		{
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Unable To Perform Action On Player In Round", client, sName);
+			continue;
+		}
+		
+		if (g_bPlayerProxy[iTarget]) continue;
+		
+		decl Float:flNewPos[3];
+		
+		if (!SlenderCalculateNewPlace(iBossIndex, flNewPos, true, true, client)) 
+		{
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Player No Place For Proxy", client, sName);
+			continue;
+		}
+		
+		ClientEnableProxy(iTarget, iBossIndex);
+		TeleportEntity(iTarget, flNewPos, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+		
+		LogAction(client, iTarget, "%N forced %N to be a Proxy!", client, iTarget);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_ForceEscape(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_force_escape <name|#userid>");
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			COMMAND_FILTER_ALIVE,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new target = target_list[i];
+		if (!g_bPlayerEliminated[i] && !DidClientEscape(i))
+		{
+			ClientEscape(target);
+			TeleportClientToEscapePoint(target);
+			
+			LogAction(client, target, "%N forced %N to escape!", client, target);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_AddSlender(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_add_boss <name>");
+		return Plugin_Handled;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetCmdArg(1, sProfile, sizeof(sProfile));
+	
+	KvRewind(g_hConfig);
+	if (!KvJumpToKey(g_hConfig, sProfile)) 
+	{
+		ReplyToCommand(client, "That boss does not exist!");
+		return Plugin_Handled;
+	}
+	
+	new iBossIndex = AddProfile(sProfile);
+	if (iBossIndex != -1)
+	{
+		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
+		GetClientEyePosition(client, eyePos);
+		GetClientEyeAngles(client, eyeAng);
+		
+		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
+		TR_GetEndPosition(flPos, hTrace);
+		CloseHandle(hTrace);
+	
+		SpawnSlender(iBossIndex, flPos);
+		
+		LogAction(client, -1, "%N added a boss! (%s)", client, sProfile);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_AddSlenderFake(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_add_boss_fake <name>");
+		return Plugin_Handled;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetCmdArg(1, sProfile, sizeof(sProfile));
+	
+	KvRewind(g_hConfig);
+	if (!KvJumpToKey(g_hConfig, sProfile)) 
+	{
+		ReplyToCommand(client, "That boss does not exist!");
+		return Plugin_Handled;
+	}
+	
+	new iBossIndex = AddProfile(sProfile, SFF_FAKE);
+	if (iBossIndex != -1)
+	{
+		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
+		GetClientEyePosition(client, eyePos);
+		GetClientEyeAngles(client, eyeAng);
+		
+		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
+		TR_GetEndPosition(flPos, hTrace);
+		CloseHandle(hTrace);
+	
+		SpawnSlender(iBossIndex, flPos);
+		
+		LogAction(client, -1, "%N added a fake boss! (%s)", client, sProfile);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_ForceState(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_setplaystate <name|#userid> <0/1>");
+		return Plugin_Handled;
+	}
+	
+	if (IsRoundEnding() || IsRoundInWarmup())
+	{
+		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			0,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iState = StringToInt(arg2);
+	
+	decl String:sName[MAX_NAME_LENGTH];
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new target = target_list[i];
+		GetClientName(target, sName, sizeof(sName));
+		
+		if (iState && g_bPlayerEliminated[target])
+		{
+			SetClientPlayState(target, true);
+			
+			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced In Game", sName);
+			LogAction(client, target, "%N forced %N into the game.", client, target);
+		}
+		else if (!iState && !g_bPlayerEliminated[target])
+		{
+			SetClientPlayState(target, false);
+			
+			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced Out Of Game", sName);
+			LogAction(client, target, "%N took %N out of the game.", client, target);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Hook_CommandBuild(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (!IsClientInPvP(client)) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_BossCountUpdate(Handle:timer)
+{
+	if (timer != g_hBossCountUpdateTimer) return Plugin_Stop;
+	
+	if (!g_bEnabled) return Plugin_Stop;
+
+	new iBossCount = NPCGetCount();
+	new iBossPreferredCount;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1 ||
+			g_iSlenderCopyMaster[i] != -1 ||
+			(NPCGetFlags(i) & SFF_FAKE))
+		{
+			continue;
+		}
+		
+		iBossPreferredCount++;
+	}
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i) ||
+			!IsPlayerAlive(i) ||
+			g_bPlayerEliminated[i] ||
+			IsClientInGhostMode(i) ||
+			IsClientInDeathCam(i) ||
+			DidClientEscape(i)) continue;
+		
+		// Check if we're near any bosses.
+		new iClosest = -1;
+		new Float:flBestDist = SF2_BOSS_PAGE_CALCULATION;
+		
+		for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
+		{
+			if (NPCGetUniqueID(iBoss) == -1) continue;
+			if (NPCGetEntIndex(iBoss) == INVALID_ENT_REFERENCE) continue;
+			if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
+			
+			new Float:flDist = NPCGetDistanceFromEntity(iBoss, i);
+			if (flDist < flBestDist)
+			{
+				iClosest = iBoss;
+				flBestDist = flDist;
+				break;
+			}
+		}
+		
+		if (iClosest != -1) continue;
+		
+		iClosest = -1;
+		flBestDist = SF2_BOSS_PAGE_CALCULATION;
+		
+		for (new iClient = 1; iClient <= MaxClients; iClient++)
+		{
+			if (!IsValidClient(iClient) ||
+				!IsPlayerAlive(iClient) ||
+				g_bPlayerEliminated[iClient] ||
+				IsClientInGhostMode(iClient) ||
+				IsClientInDeathCam(iClient) ||
+				DidClientEscape(iClient)) 
+			{
+				continue;
+			}
+			
+			new bool:bwub = false;
+			for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
+			{
+				if (NPCGetUniqueID(iBoss) == -1) continue;
+				if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
+				
+				if (g_iSlenderTarget[iBoss] == iClient)
+				{
+					bwub = true;
+					break;
+				}
+			}
+			
+			if (!bwub) continue;
+			
+			new Float:flDist = EntityDistanceFromEntity(i, iClient);
+			if (flDist < flBestDist)
+			{
+				iClosest = iClient;
+				flBestDist = flDist;
+			}
+		}
+		
+		if (!IsValidClient(iClosest))
+		{
+			// No one's close to this dude? DUDE! WE NEED ANOTHER BOSS!
+			iBossPreferredCount++;
+		}
+	}
+	
+	new iDiff = iBossCount - iBossPreferredCount;
+	if (iDiff)
+	{	
+		if (iDiff > 0)
+		{
+			new iCount = iDiff;
+			// We need less bosses. Try and see if we can remove some.
+			for (new i = 0; i < MAX_BOSSES; i++)
+			{
+				if (g_iSlenderCopyMaster[i] == -1) continue;
+				if (PeopleCanSeeSlender(i, _, false)) continue;
+				if (NPCGetFlags(i) & SFF_FAKE) continue;
+				
+				if (SlenderCanRemove(i))
+				{
+					NPCRemove(i);
+					iCount--;
+				}
+				
+				if (iCount <= 0)
+				{
+					break;
+				}
+			}
+		}
+		else
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		
+			new iCount = RoundToFloor(FloatAbs(float(iDiff)));
+			// Add new bosses (copy of the first boss).
+			for (new i = 0; i < MAX_BOSSES && iCount > 0; i++)
+			{
+				if (NPCGetUniqueID(i) == -1) continue;
+				if (g_iSlenderCopyMaster[i] != -1) continue;
+				if (!(NPCGetFlags(i) & SFF_COPIES)) continue;
+				
+				// Get the number of copies I already have and see if I can have more copies.
+				new iCopyCount;
+				for (new i2 = 0; i2 < MAX_BOSSES; i2++)
+				{
+					if (NPCGetUniqueID(i2) == -1) continue;
+					if (g_iSlenderCopyMaster[i2] != i) continue;
+					
+					iCopyCount++;
+				}
+				
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+				
+				if (iCopyCount >= GetProfileNum(sProfile, "copy_max", 10)) 
+				{
+					continue;
+				}
+				
+				new iBossIndex = AddProfile(sProfile, _, i);
+				if (iBossIndex == -1)
+				{
+					LogError("Could not add copy for %d: No free slots!", i);
+				}
+				
+				iCount--;
+			}
+		}
+	}
+	
+	// Check if we can add some proxies.
+	if (!g_bRoundGrace)
+	{
+		if (NavMesh_Exists())
+		{
+			new Handle:hProxyCandidates = CreateArray();
+			
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			
+			for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+			{
+				if (NPCGetUniqueID(iBossIndex) == -1) continue;
+				
+				if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) continue;
+				
+				if (g_iSlenderCopyMaster[iBossIndex] != -1) continue; // Copies cannot generate proxies.
+				
+				if (GetGameTime() < g_flSlenderTimeUntilNextProxy[iBossIndex]) continue; // Proxy spawning hasn't cooled down yet.
+				
+				new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
+				if (!iTeleportTarget || iTeleportTarget == INVALID_ENT_REFERENCE) continue; // No teleport target.
+				
+				NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+				
+				new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
+				new iNumActiveProxies = 0;
+				
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+					if (!g_bPlayerProxy[iClient]) continue;
+					
+					if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) == iBossIndex)
+					{
+						iNumActiveProxies++;
+					}
+				}
+				
+				if (iNumActiveProxies >= iMaxProxies) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d has too many active proxies!", iBossIndex);
+#endif
+					continue;
+				}
+				
+				new Float:flSpawnChanceMin = GetProfileFloat(sProfile, "proxies_spawn_chance_min");
+				new Float:flSpawnChanceMax = GetProfileFloat(sProfile, "proxies_spawn_chance_max");
+				new Float:flSpawnChanceThreshold = GetProfileFloat(sProfile, "proxies_spawn_chance_threshold") * NPCGetAnger(iBossIndex);
+				
+				new Float:flChance = GetRandomFloat(flSpawnChanceMin, flSpawnChanceMax);
+				if (flChance > flSpawnChanceThreshold) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's chances weren't in his favor!", iBossIndex);
+#endif
+					continue;
+				}
+				
+				new iAvailableProxies = iMaxProxies - iNumActiveProxies;
+				
+				new iSpawnNumMin = GetProfileNum(sProfile, "proxies_spawn_num_min");
+				new iSpawnNumMax = GetProfileNum(sProfile, "proxies_spawn_num_max");
+				
+				new iSpawnNum = 0;
+				
+				// Get a list of people we can transform into a good Proxy.
+				ClearArray(hProxyCandidates);
+				
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+					if (g_bPlayerProxy[iClient]) continue;
+					
+					if (!g_iPlayerPreferences[iClient][PlayerPreference_EnableProxySelection])
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your preferences.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					if (!g_bPlayerProxyAvailable[iClient])
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your cooldown.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					if (g_bPlayerProxyAvailableInForce[iClient])
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're already being forced into a Proxy.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					if (!IsClientParticipating(iClient))
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're not participating.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					PushArrayCell(hProxyCandidates, iClient);
+					iSpawnNum++;
+				}
+				
+				if (iSpawnNum >= iSpawnNumMax)
+				{
+					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNumMax);
+				}
+				else if (iSpawnNum >= iSpawnNumMin)
+				{
+					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNum);
+				}
+				
+				if (iSpawnNum <= 0) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d had a set spawn number of 0!", iBossIndex);
+#endif
+					continue;
+				}
+				
+				decl Float:flTargetPos[3];
+				GetClientAbsOrigin(iTeleportTarget, flTargetPos);
+				
+				new iTargetAreaIndex = NavMesh_GetNearestArea(flTargetPos);
+				if (iTargetAreaIndex == -1) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's teleport target is not on the navmesh!", iBossIndex);
+#endif
+					continue; // target is not on the nav mesh.
+				}
+				
+				// Search outwards until travel distance is at maximum range.
+				new Handle:hAreaArray = CreateArray(2);
+				new Handle:hAreas = CreateStack();
+				NavMesh_CollectSurroundingAreas(hAreas, iTargetAreaIndex, g_flSlenderProxyTeleportMaxRange[iBossIndex]);
+				
+				new Float:flTeleportMinRange = CalculateTeleportMinRange(iBossIndex, g_flSlenderProxyTeleportMinRange[iBossIndex], g_flSlenderProxyTeleportMaxRange[iBossIndex]);
+				
+				{
+					new iAreaIndex = -1;
+					new iPoppedAreas = 0;
+					
+					while (!IsStackEmpty(hAreas))
+					{
+						PopStackCell(hAreas, iAreaIndex);
+						new iCostSoFar = NavMeshArea_GetCostSoFar(iAreaIndex);
+						
+						if (float(iCostSoFar) >= flTeleportMinRange)
+						{
+							new iIndex = PushArrayCell(hAreaArray, iAreaIndex);
+							SetArrayCell(hAreaArray, iIndex, float(iCostSoFar), 1);
+							iPoppedAreas++;
+						}
+					}
+					
+					CloseHandle(hAreas);
+					
+					if (iPoppedAreas == 0)
+					{
+						// no areas to use!
+						CloseHandle(hAreaArray);
+
+#if defined DEBUG
+						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any sufficient surrounding areas!", iBossIndex);
+#endif
+						
+						continue;
+					}
+#if defined DEBUG
+					else
+					{
+						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d found %d surrounding areas", iBossIndex, iPoppedAreas);
+					}
+#endif
+				}
+				
+				new Handle:hAreaArrayClose = CreateArray();
+				new Handle:hAreaArrayAverage = CreateArray();
+				new Handle:hAreaArrayFar = CreateArray();
+				
+				for (new iRangeSection = 1; iRangeSection <= 3; iRangeSection++)
+				{
+					new Float:flRangeSectionMin = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection - 1) / 3.0);
+					new Float:flRangeSectionMax = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection) / 3.0);
+					
+					for (new i = 0, iSize = GetArraySize(hAreaArray); i < iSize; i++)
+					{
+						new iAreaIndex = GetArrayCell(hAreaArray, i);
+						
+						decl Float:flAreaCenter[3];
+						NavMeshArea_GetCenter(iAreaIndex, flAreaCenter);
+						
+						decl Float:flTestPos[3];
+						decl Float:flEyeOffset[3];
+						flEyeOffset[0] = 0.0;
+						flEyeOffset[1] = 0.0;
+						flEyeOffset[2] = HalfHumanHeight * 2.0;
+						
+						// Check visibility first.
+						if (IsPointVisibleToAPlayer(flAreaCenter, false, false)) 
+						{
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (1)", iBossIndex, iAreaIndex);
+#endif
+							continue;
+						}
+						
+						AddVectors(flAreaCenter, flEyeOffset, flTestPos);
+						
+						if (IsPointVisibleToAPlayer(flTestPos, false, false)) 
+						{
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (2)", iBossIndex, iAreaIndex);
+#endif
+						
+							continue;
+						}
+						
+						new iBoss = NPCGetEntIndex(iBossIndex);
+						
+						// Check space. First raise to HalfHumanHeight * 2, then trace downwards to get ground level.
+						{
+							decl Float:flTraceStartPos[3];
+							flTraceStartPos[0] = flAreaCenter[0];
+							flTraceStartPos[1] = flAreaCenter[1];
+							flTraceStartPos[2] = flAreaCenter[2] + (HalfHumanHeight * 2.0);
+							
+							decl Float:flTraceMins[3];
+							flTraceMins[0] = -20.0;
+							flTraceMins[1] = -20.0;
+							flTraceMins[2] = 0.0;
+							
+							decl Float:flTraceMaxs[3];
+							flTraceMaxs[0] = 20.0;
+							flTraceMaxs[1] = 20.0;
+							flTraceMaxs[2] = 0.0;
+							
+							new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
+								flAreaCenter,
+								flTraceMins,
+								flTraceMaxs,
+								MASK_NPCSOLID,
+								TraceRayDontHitEntity,
+								iBoss);
+							
+							decl Float:flTraceHitPos[3];
+							TR_GetEndPosition(flTraceHitPos, hTrace);
+							flTraceHitPos[2] += 1.0;
+							CloseHandle(hTrace);
+							
+							static Float:flTraceSpaceMin[3] = { -20.0, -20.0, 0.0 };
+							static Float:flTraceSpaceMax[3] = { 20.0, 20.0, 72.0 };
+							
+							flTraceSpaceMax[2] = HalfHumanHeight * 2.0;
+							
+							if (IsSpaceOccupiedPlayer(flTraceHitPos,
+								flTraceSpaceMin,
+								flTraceSpaceMax,
+								iBoss == INVALID_ENT_REFERENCE ? -1 : iBoss))
+							{
+#if defined DEBUG
+								SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected too small area index %d! (2)", iBossIndex, iAreaIndex);
+#endif
+							
+								continue;
+							}
+						}
+						
+						new bool:bTooNear = false;
+						
+						// Check minimum range.
+						for (new iClient = 1; iClient <= MaxClients; iClient++)
+						{
+							if (!IsClientInGame(iClient) ||
+								!IsPlayerAlive(iClient) ||
+								g_bPlayerEliminated[iClient] ||
+								DidClientEscape(iClient) ||
+								g_bPlayerProxy[iClient] ||
+								IsClientInGhostMode(iClient))
+							{
+								continue;
+							}
+							
+							decl Float:flTempPos[3];
+							GetClientAbsOrigin(iClient, flTempPos);
+							
+							if (GetVectorDistance(flAreaCenter, flTempPos) <= flTeleportMinRange)
+							{
+								bTooNear = true;
+								break;
+							}
+						}
+						
+						if (bTooNear) 
+						{
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected near area index %d!", iBossIndex, iAreaIndex);
+#endif
+						
+							continue;	// This area is too close to a player.
+						}
+						
+						// Check travel distance.
+						new Float:flDist = Float:GetArrayCell(hAreaArray, i, 1);
+						if (flDist > flRangeSectionMin && flDist < flRangeSectionMax)
+						{
+							switch (iRangeSection)
+							{
+								case 1: PushArrayCell(hAreaArrayClose, iAreaIndex);
+								case 2: PushArrayCell(hAreaArrayAverage, iAreaIndex);
+								case 3: PushArrayCell(hAreaArrayFar, iAreaIndex);
+							}
+						}
+					}
+				}
+				
+				CloseHandle(hAreaArray);
+				
+				// Set the cooldown time!
+				new Float:flSpawnCooldownMin = GetProfileFloat(sProfile, "proxies_spawn_cooldown_min");
+				new Float:flSpawnCooldownMax = GetProfileFloat(sProfile, "proxies_spawn_cooldown_max");
+				
+				g_flSlenderTimeUntilNextProxy[iBossIndex] = GetGameTime() + GetRandomFloat(flSpawnCooldownMin, flSpawnCooldownMax);
+				
+				// Randomize the array.
+				SortADTArray(hProxyCandidates, Sort_Random, Sort_Integer);
+				
+				decl Float:flDestinationPos[3];
+				
+				for (new iNum = 0; iNum < iSpawnNum && iNum < iAvailableProxies; iNum++)
+				{
+					new iClient = GetArrayCell(hProxyCandidates, iNum);
+					new iBestAreaIndex = -1;
+					
+					if (GetArraySize(hAreaArrayClose) > 0)
+					{
+						iBestAreaIndex = GetArrayCell(hAreaArrayClose, GetRandomInt(0, GetArraySize(hAreaArrayClose) - 1));
+					}
+					else if (GetArraySize(hAreaArrayAverage) > 0)
+					{
+						iBestAreaIndex = GetArrayCell(hAreaArrayAverage, GetRandomInt(0, GetArraySize(hAreaArrayAverage) - 1));
+					}
+					else if (GetArraySize(hAreaArrayFar) > 0)
+					{
+						iBestAreaIndex = GetArrayCell(hAreaArrayFar, GetRandomInt(0, GetArraySize(hAreaArrayFar) - 1));
+					}
+					
+					if (iBestAreaIndex == -1) 
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any areas to place proxies (spawned %d)!", iBossIndex, iNum);
+#endif
+						break;
+					}
+					
+					NavMeshArea_GetCenter(iBestAreaIndex, flDestinationPos);
+					
+					if (!GetConVarBool(g_cvPlayerProxyAsk))
+					{
+						ClientStartProxyForce(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
+					}
+					else
+					{
+						DisplayProxyAskMenu(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
+					}
+				}
+				
+				CloseHandle(hAreaArrayClose);
+				CloseHandle(hAreaArrayAverage);
+				CloseHandle(hAreaArrayFar);
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d finished proxy process!", iBossIndex);
+#endif
+			}
+			
+			CloseHandle(hProxyCandidates);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+ReloadRestrictedWeapons()
+{
+	if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
+	{
+		CloseHandle(g_hRestrictedWeaponsConfig);
+		g_hRestrictedWeaponsConfig = INVALID_HANDLE;
+	}
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	BuildPath(Path_SM, buffer, sizeof(buffer), FILE_RESTRICTEDWEAPONS);
+	new Handle:kv = CreateKeyValues("root");
+	if (!FileToKeyValues(kv, buffer))
+	{
+		CloseHandle(kv);
+		LogError("Failed to load restricted weapons list! File not found!");
+	}
+	else
+	{
+		g_hRestrictedWeaponsConfig = kv;
+		LogSF2Message("Reloaded restricted weapons configuration file successfully");
+	}
+}
+
+public Action:Timer_RoundMessages(Handle:timer)
+{
+	if (!g_bEnabled) return Plugin_Stop;
+	
+	if (timer != g_hRoundMessagesTimer) return Plugin_Stop;
+	
+	switch (g_iRoundMessagesNum)
+	{
+		case 0: CPrintToChatAll("{olive}==== {lightgreen}Slender Fortress (%s){olive} coded by {lightgreen}Kit o' Rifty{olive} ====", PLUGIN_VERSION_DISPLAY);
+		case 1: CPrintToChatAll("%t", "SF2 Ad Message 1");
+		case 2: CPrintToChatAll("%t", "SF2 Ad Message 2");
+	}
+	
+	g_iRoundMessagesNum++;
+	if (g_iRoundMessagesNum > 2) g_iRoundMessagesNum = 0;
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_WelcomeMessage(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	CPrintToChat(client, "%T", "SF2 Welcome Message", client);
+}
+
+GetMaxPlayersForRound()
+{
+	new iOverride = GetConVarInt(g_cvMaxPlayersOverride);
+	if (iOverride != -1) return iOverride;
+	return GetConVarInt(g_cvMaxPlayers);
+}
+
+public OnConVarChanged(Handle:cvar, const String:oldValue[], const String:newValue[])
+{
+	if (cvar == g_cvDifficulty)
+	{
+		switch (StringToInt(newValue))
+		{
+			case Difficulty_Easy: g_flRoundDifficultyModifier = DIFFICULTY_EASY;
+			case Difficulty_Hard: g_flRoundDifficultyModifier = DIFFICULTY_HARD;
+			case Difficulty_Insane: g_flRoundDifficultyModifier = DIFFICULTY_INSANE;
+			default: g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
+		}
+	}
+	else if (cvar == g_cvMaxPlayers || cvar == g_cvMaxPlayersOverride)
+	{
+		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+		{
+			CheckPlayerGroup(i);
+		}
+	}
+	else if (cvar == g_cvPlayerShakeEnabled)
+	{
+		g_bPlayerShakeEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvPlayerViewbobEnabled)
+	{
+		g_bPlayerViewbobEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvPlayerViewbobHurtEnabled)
+	{
+		g_bPlayerViewbobHurtEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvPlayerViewbobSprintEnabled)
+	{
+		g_bPlayerViewbobSprintEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvGravity)
+	{
+		g_flGravity = StringToFloat(newValue);
+	}
+	else if (cvar == g_cv20Dollars)
+	{
+		g_b20Dollars = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvAllChat)
+	{
+		if (g_bEnabled)
+		{
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				ClientUpdateListeningFlags(i);
+			}
+		}
+	}
+}
+
+//	==========================================================
+//	IN-GAME AND ENTITY HOOK FUNCTIONS
+//	==========================================================
+
+
+public OnEntityCreated(ent, const String:classname[])
+{
+	if (!g_bEnabled) return;
+	
+	if (!IsValidEntity(ent) || ent <= 0) return;
+	
+	if (StrEqual(classname, "spotlight_end", false))
+	{
+		SDKHook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
+	}
+	else if (StrEqual(classname, "beam", false))
+	{
+		SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightBeamSetTransmit);
+	}
+	
+	PvP_OnEntityCreated(ent, classname);
+}
+
+public OnEntityDestroyed(ent)
+{
+	if (!g_bEnabled) return;
+
+	if (!IsValidEntity(ent) || ent <= 0) return;
+	
+	decl String:sClassname[64];
+	GetEntityClassname(ent, sClassname, sizeof(sClassname));
+	
+	if (StrEqual(sClassname, "light_dynamic", false))
+	{
+		AcceptEntityInput(ent, "TurnOff");
+		
+		new iEnd = INVALID_ENT_REFERENCE;
+		while ((iEnd = FindEntityByClassname(iEnd, "spotlight_end")) != -1)
+		{
+			if (GetEntPropEnt(iEnd, Prop_Data, "m_hOwnerEntity") == ent)
+			{
+				AcceptEntityInput(iEnd, "Kill");
+				break;
+			}
+		}
+	}
+	
+	PvP_OnEntityDestroyed(ent, sClassname);
+}
+
+public Action:Hook_BlockUserMessage(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init) 
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	return Plugin_Handled;
+}
+
+public Action:Hook_NormalSound(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsValidClient(entity))
+	{
+		if (IsClientInGhostMode(entity))
+		{
+			switch (channel)
+			{
+				case SNDCHAN_VOICE, SNDCHAN_WEAPON, SNDCHAN_ITEM, SNDCHAN_BODY: return Plugin_Handled;
+			}
+		}
+		else if (g_bPlayerProxy[entity])
+		{
+			new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[entity]);
+			if (iMaster != -1)
+			{
+				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+				NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
+				
+				switch (channel)
+				{
+					case SNDCHAN_VOICE:
+					{
+						if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
+						{
+							return Plugin_Handled;
+						}
+					}
+				}
+			}
+		}
+		else if (!g_bPlayerEliminated[entity])
+		{
+			switch (channel)
+			{
+				case SNDCHAN_VOICE:
+				{
+					if (IsRoundInIntro()) return Plugin_Handled;
+				
+					for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+					{
+						if (NPCGetUniqueID(iBossIndex) == -1) continue;
+						
+						if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Voice))
+						{
+							GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
+							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
+							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDVOICE;
+						}
+					}
+				}
+				case SNDCHAN_BODY:
+				{
+					if (!StrContains(sample, "player/footsteps", false) || StrContains(sample, "step", false) != -1)
+					{
+						if (GetConVarBool(g_cvPlayerViewbobSprintEnabled) && IsClientReallySprinting(entity))
+						{
+							// Viewpunch.
+							new Float:flPunchVelStep[3];
+							
+							decl Float:flVelocity[3];
+							GetEntPropVector(entity, Prop_Data, "m_vecAbsVelocity", flVelocity);
+							new Float:flSpeed = GetVectorLength(flVelocity);
+							
+							flPunchVelStep[0] = flSpeed / 300.0;
+							flPunchVelStep[1] = 0.0;
+							flPunchVelStep[2] = 0.0;
+							
+							ClientViewPunch(entity, flPunchVelStep);
+						}
+						
+						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+						{
+							if (NPCGetUniqueID(iBossIndex) == -1) continue;
+							
+							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Footstep))
+							{
+								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEP;
+								
+								if (IsClientSprinting(entity) && !(GetEntProp(entity, Prop_Send, "m_bDucking") || GetEntProp(entity, Prop_Send, "m_bDucked")))
+								{
+									g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEPLOUD;
+								}
+							}
+						}
+					}
+				}
+				case SNDCHAN_ITEM, SNDCHAN_WEAPON:
+				{
+					if (StrContains(sample, "impact", false) != -1 || StrContains(sample, "hit", false) != -1)
+					{
+						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+						{
+							if (NPCGetUniqueID(iBossIndex) == -1) continue;
+							
+							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Weapon))
+							{
+								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDWEAPON;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	new bool:bModified = false;
+	
+	for (new i = 0; i < numClients; i++)
+	{
+		new iClient = clients[i];
+		if (IsValidClient(iClient) && IsPlayerAlive(iClient) && !IsClientInGhostMode(iClient))
+		{
+			new bool:bCanHearSound = true;
+			
+			if (IsValidClient(entity) && entity != iClient)
+			{
+				if (!g_bPlayerEliminated[iClient])
+				{
+					if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+					{
+						if (!g_bPlayerEliminated[entity] && !DidClientEscape(entity))
+						{
+							bCanHearSound = false;
+						}
+					}
+				}
+			}
+			
+			if (!bCanHearSound)
+			{
+				bModified = true;
+				clients[i] = -1;
+			}
+		}
+	}
+	
+	if (bModified) return Plugin_Changed;
+	return Plugin_Continue;
+}
+
+public MRESReturn:Hook_EntityShouldTransmit(thisPointer, Handle:hReturn, Handle:hParams)
+{
+	if (!g_bEnabled) return MRES_Ignored;
+	
+	if (IsValidClient(thisPointer))
+	{
+		if (DoesClientHaveConstantGlow(thisPointer))
+		{
+			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
+			return MRES_Supercede;
+		}
+	}
+	else
+	{
+		new iBossIndex = NPCGetFromEntIndex(thisPointer);
+		if (iBossIndex != -1)
+		{
+			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
+			return MRES_Supercede;
+		}
+	}
+	
+	return MRES_Ignored;
+}
+
+public Hook_TriggerOnStartTouch(const String:output[], caller, activator, Float:delay)
+{
+	if (!g_bEnabled) return;
+
+	if (!IsValidEntity(caller)) return;
+	
+	decl String:sName[64];
+	GetEntPropString(caller, Prop_Data, "m_iName", sName, sizeof(sName));
+	
+	if (StrContains(sName, "sf2_escape_trigger", false) == 0)
+	{
+		if (IsRoundInEscapeObjective())
+		{
+			if (IsValidClient(activator) && IsPlayerAlive(activator) && !IsClientInDeathCam(activator) && !g_bPlayerEliminated[activator] && !DidClientEscape(activator))
+			{
+				ClientEscape(activator);
+				TeleportClientToEscapePoint(activator);
+			}
+		}
+	}
+	
+	PvP_OnTriggerStartTouch(caller, activator);
+}
+
+public Hook_TriggerOnEndTouch(const String:sOutput[], caller, activator, Float:flDelay)
+{
+	if (!g_bEnabled) return;
+	
+	PvP_OnTriggerEndTouch(caller, activator);
+}
+
+public Action:Hook_PageOnTakeDamage(page, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsValidClient(attacker))
+	{
+		if (!g_bPlayerEliminated[attacker])
+		{
+			if (damagetype & 0x80) // 0x80 == melee damage
+			{
+				CollectPage(page, attacker);
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+static CollectPage(page, activator)
+{
+	SetPageCount(g_iPageCount + 1);
+	g_iPlayerPageCount[activator] += 1;
+	EmitSoundToAll(PAGE_GRABSOUND, activator, SNDCHAN_ITEM, SNDLEVEL_SCREAMING);
+				
+	// Gives points. Credit to the makers of VSH/FF2.
+	new Handle:hEvent = CreateEvent("player_escort_score", true);
+	SetEventInt(hEvent, "player", activator);
+	SetEventInt(hEvent, "points", 1);
+	FireEvent(hEvent);
+				
+	AcceptEntityInput(page, "FireUser1");
+	AcceptEntityInput(page, "Kill");
+}
+	
+//	==========================================================
+//	GENERIC CLIENT HOOKS AND FUNCTIONS
+//	==========================================================
+
+
+public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	ClientDisableFakeLagCompensation(client);
+	
+	// Check impulse (block spraying and built-in flashlight)
+	switch (impulse)
+	{
+		case 100:
+		{
+			impulse = 0;
+		}
+		case 201:
+		{
+			if (IsClientInGhostMode(client))
+			{
+				impulse = 0;
+			}
+		}
+	}
+	
+	for (new i = 0; i < MAX_BUTTONS; i++)
+	{
+		new button = (1 << i);
+		
+		if ((buttons & button))
+		{
+			if (!(g_iPlayerLastButtons[client] & button))
+			{
+				ClientOnButtonPress(client, button);
+			}
+		}
+		else if ((g_iPlayerLastButtons[client] & button))
+		{
+			ClientOnButtonRelease(client, button);
+		}
+	}
+	
+	g_iPlayerLastButtons[client] = buttons;
+	
+	return Plugin_Continue;
+}
+
+
+public OnClientCookiesCached(client)
+{
+	if (!g_bEnabled) return;
+	
+	// Load our saved settings.
+	new String:sCookie[64];
+	GetClientCookie(client, g_hCookie, sCookie, sizeof(sCookie));
+	
+		g_iPlayerQueuePoints[client] = 0;
+		
+		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
+		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
+	g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = true;
+		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
+	g_iPlayerPreferences[client][PlayerPreference_GhostOverlay] = true;
+	
+	if (sCookie[0])
+	{
+		new String:s2[12][32];
+		new count = ExplodeString(sCookie, " ; ", s2, 12, 32);
+		
+		if (count > 0)
+		g_iPlayerQueuePoints[client] = StringToInt(s2[0]);
+		if (count > 1)
+		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = bool:StringToInt(s2[1]);
+		if (count > 2)
+		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode:StringToInt(s2[2]);
+		if (count > 3)
+			g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = bool:StringToInt(s2[3]);
+		if (count > 4)
+		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = bool:StringToInt(s2[4]);
+		if (count > 5)
+			g_iPlayerPreferences[client][PlayerPreference_GhostOverlay] = bool:StringToInt(s2[5]);
+	}
+}
+
+public OnClientPutInServer(client)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientPutInServer(%d)", client);
+#endif
+	
+	ClientSetPlayerGroup(client, -1);
+	
+	g_bPlayerEscaped[client] = false;
+	g_bPlayerEliminated[client] = true;
+	g_bPlayerChoseTeam[client] = false;
+	g_bPlayerPlayedSpecialRound[client] = true;
+	g_bPlayerPlayedNewBossRound[client] = true;
+	
+	g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn] = false;
+	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
+	
+	g_iPlayerPageCount[client] = 0;
+	g_iPlayerDesiredFOV[client] = 90;
+	
+	SDKHook(client, SDKHook_PreThink, Hook_ClientPreThink);
+	SDKHook(client, SDKHook_SetTransmit, Hook_ClientSetTransmit);
+	SDKHook(client, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage);
+	
+	DHookEntity(g_hSDKWantsLagCompensationOnEntity, true, client); 
+	DHookEntity(g_hSDKShouldTransmit, true, client);
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		
+		SetPlayerGroupInvitedPlayer(i, client, false);
+		SetPlayerGroupInvitedPlayerCount(i, client, 0);
+		SetPlayerGroupInvitedPlayerTime(i, client, 0.0);
+	}
+	
+	ClientDisableFakeLagCompensation(client);
+	
+	ClientResetStatic(client);
+	ClientResetSlenderStats(client);
+	ClientResetCampingStats(client);
+	ClientResetOverlay(client);
+	ClientResetJumpScare(client);
+	ClientUpdateListeningFlags(client);
+	ClientUpdateMusicSystem(client);
+	ClientChaseMusicReset(client);
+	ClientChaseMusicSeeReset(client);
+	ClientAlertMusicReset(client);
+	Client20DollarsMusicReset(client);
+	ClientMusicReset(client);
+	ClientResetProxy(client);
+	ClientResetHints(client);
+	ClientResetScare(client);
+	
+	ClientResetDeathCam(client);
+	ClientResetFlashlight(client);
+	ClientDeactivateUltravision(client);
+	ClientResetSprint(client);
+	ClientResetBreathing(client);
+	ClientResetBlink(client);
+	ClientResetInteractiveGlow(client);
+	ClientDisableConstantGlow(client);
+	
+	ClientSetScareBoostEndTime(client, -1.0);
+	
+	ClientStartProxyAvailableTimer(client);
+	
+	if (!IsFakeClient(client))
+	{
+		// See if the player is using the projected flashlight.
+		QueryClientConVar(client, "mat_supportflashlight", OnClientGetProjectedFlashlightSetting);
+		
+		// Get desired FOV.
+		QueryClientConVar(client, "fov_desired", OnClientGetDesiredFOV);
+	}
+	
+	PvP_OnClientPutInServer(client);
+	
+#if defined DEBUG
+	g_iPlayerDebugFlags[client] = 0;
+
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientPutInServer(%d)", client);
+#endif
+}
+
+public OnClientGetProjectedFlashlightSetting(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
+{
+	if (result != ConVarQuery_Okay) 
+	{
+		LogError("Warning: Player %N failed to query for ConVar mat_supportflashlight", client);
+		return;
+	}
+	
+	if (StringToInt(cvarValue))
+	{
+		decl String:sAuth[64];
+		GetClientAuthString(client, sAuth, sizeof(sAuth));
+		
+		g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = true;
+		LogSF2Message("Player %N (%s) has mat_supportflashlight enabled, projected flashlight will be used", client, sAuth);
+	}
+}
+
+public OnClientGetDesiredFOV(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
+{
+	if (!IsValidClient(client)) return;
+	
+	g_iPlayerDesiredFOV[client] = StringToInt(cvarValue);
+}
+
+public OnClientDisconnect(client)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientDisconnect(%d)", client);
+#endif
+	
+	g_bPlayerEscaped[client] = false;
+	
+	// Save and reset settings for the next client.
+	ClientSaveCookies(client);
+	ClientSetPlayerGroup(client, -1);
+	
+	// Reset variables.
+	g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
+	g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
+	g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = true;
+	g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
+	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
+	
+	// Reset any client functions that may be still active.
+	ClientResetOverlay(client);
+	ClientResetFlashlight(client);
+	ClientDeactivateUltravision(client);
+	ClientSetGhostModeState(client, false);
+	ClientResetInteractiveGlow(client);
+	ClientDisableConstantGlow(client);
+	
+	ClientStopProxyForce(client);
+	
+	if (!IsRoundInWarmup())
+	{
+		if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
+		{
+			if (g_bRoundGrace)
+			{
+				// Force the next player in queue to take my place, if any.
+				ForceInNextPlayersInQueue(1, true);
+			}
+			else
+			{
+				if (!IsRoundEnding()) 
+				{
+					CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
+				}
+			}
+		}
+	}
+	
+	// Reset queue points global variable.
+	g_iPlayerQueuePoints[client] = 0;
+	
+	PvP_OnClientDisconnect(client);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientDisconnect(%d)", client);
+#endif
+}
+
+public OnClientDisconnect_Post(client)
+{
+    g_iPlayerLastButtons[client] = 0;
+}
+
+public TF2_OnWaitingForPlayersStart()
+{
+	g_bRoundWaitingForPlayers = true;
+}
+
+public TF2_OnWaitingForPlayersEnd()
+{
+	g_bRoundWaitingForPlayers = false;
+}
+
+SF2RoundState:GetRoundState()
+{
+	return g_iRoundState;
+}
+
+SetRoundState(SF2RoundState:iRoundState)
+{
+	if (g_iRoundState == iRoundState) return;
+	
+	PrintToServer("SetRoundState(%d)", iRoundState);
+	
+	new SF2RoundState:iOldRoundState = GetRoundState();
+	g_iRoundState = iRoundState;
+	
+	// Cleanup from old roundstate if needed.
+	switch (iOldRoundState)
+	{
+		case SF2RoundState_Waiting:
+		{
+		}
+		case SF2RoundState_Intro:
+		{
+			g_hRoundIntroTimer = INVALID_HANDLE;
+		}
+		case SF2RoundState_Active:
+		{
+			g_bRoundGrace = false;
+			g_hRoundGraceTimer = INVALID_HANDLE;
+			g_hRoundTimer = INVALID_HANDLE;
+		}
+		case SF2RoundState_Escape:
+		{
+			g_hRoundTimer = INVALID_HANDLE;
+		}
+		case SF2RoundState_Outro:
+		{
+		}
+	}
+	
+	switch (g_iRoundState)
+	{
+		case SF2RoundState_Waiting:
+		{
+		}
+		case SF2RoundState_Intro:
+		{
+			g_hRoundIntroTimer = INVALID_HANDLE;
+			g_iRoundIntroText = 0;
+			g_bRoundIntroTextDefault = false;
+			g_hRoundIntroTextTimer = CreateTimer(0.0, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
+			TriggerTimer(g_hRoundIntroTextTimer);
+			
+			// Gather data on the intro parameters set by the map.
+			new Float:flHoldTime = g_flRoundIntroFadeHoldTime;
+			g_hRoundIntroTimer = CreateTimer(flHoldTime, Timer_ActivateRoundFromIntro, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			// Trigger any intro logic entities, if any.
+			new ent = -1;
+			while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
+			{
+				decl String:sName[64];
+				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+				if (StrEqual(sName, "sf2_intro_relay", false))
+				{
+					AcceptEntityInput(ent, "Trigger");
+					break;
+				}
+			}
+		}
+		case SF2RoundState_Active:
+		{
+			// Start the grace period timer.
+			g_bRoundGrace = true;
+			g_hRoundGraceTimer = CreateTimer(GetConVarFloat(g_cvGraceTime), Timer_RoundGrace, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			CreateTimer(2.0, Timer_RoundStart, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			// Enable movement on players.
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
+				SetEntityFlags(i, GetEntityFlags(i) & ~FL_FROZEN);
+			}
+			
+			// Fade in.
+			new Float:flFadeTime = g_flRoundIntroFadeDuration;
+			new iFadeFlags = SF_FADE_IN | FFADE_PURGE;
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
+				UTIL_ScreenFade(i, FixedUnsigned16(flFadeTime, 1 << 12), 0, iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
+			}
+		}
+		case SF2RoundState_Escape:
+		{
+			// Initialize the escape timer, if needed.
+			if (g_iRoundEscapeTimeLimit > 0)
+			{
+				g_iRoundTime = g_iRoundEscapeTimeLimit;
+				g_hRoundTimer = CreateTimer(1.0, Timer_RoundTimeEscape, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			}
+			else
+			{
+				g_hRoundTimer = INVALID_HANDLE;
+			}
+		
+			decl String:sName[32];
+			new ent = -1;
+			while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+			{
+				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+				if (StrEqual(sName, "sf2_logic_escape", false))
+				{
+					AcceptEntityInput(ent, "FireUser1");
+					break;
+				}
+			}
+		}
+		case SF2RoundState_Outro:
+		{
+			if (!g_bRoundHasEscapeObjective)
+			{
+				// Teleport winning players to the escape point.
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i)) continue;
+					
+					if (!g_bPlayerEliminated[i])
+					{
+						TeleportClientToEscapePoint(i);
+					}
+				}
+			}
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i)) continue;
+				
+				if (IsClientInGhostMode(i))
+				{
+					// Take the player out of ghost mode.
+					ClientSetGhostModeState(i, false);	
+					TF2_RespawnPlayer(i);
+				}
+				else if (g_bPlayerProxy[i])
+				{
+					TF2_RespawnPlayer(i);
+				}
+				
+				if (!g_bPlayerEliminated[i])
+				{
+					// Give them back all their weapons so they can beat the crap out of the other team.
+					TF2_RegeneratePlayer(i);
+				}
+				
+				ClientUpdateListeningFlags(i);
+			}
+		}
+	}
+}
+
+bool:IsRoundInEscapeObjective()
+{
+	return bool:(GetRoundState() == SF2RoundState_Escape);
+}
+
+bool:IsRoundInWarmup()
+{
+	return bool:(GetRoundState() == SF2RoundState_Waiting);
+}
+
+bool:IsRoundInIntro()
+{
+	return bool:(GetRoundState() == SF2RoundState_Intro);
+}
+
+bool:IsRoundEnding()
+{
+	return bool:(GetRoundState() == SF2RoundState_Outro);
+}
+
+bool:IsInfiniteBlinkEnabled()
+{
+	return bool:(g_bRoundInfiniteBlink || (GetConVarInt(g_cvPlayerInfiniteBlinkOverride) == 1));
+}
+
+bool:IsInfiniteFlashlightEnabled()
+{
+	return bool:(g_bRoundInfiniteFlashlight || (GetConVarInt(g_cvPlayerInfiniteFlashlightOverride) == 1));
+}
+
+bool:IsInfiniteSprintEnabled()
+{
+	return bool:(g_bRoundInfiniteSprint || (GetConVarInt(g_cvPlayerInfiniteSprintOverride) == 1));
+}
+
+
+#define SF2_PLAYER_HUD_BLINK_SYMBOL "B"
+#define SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL "ÏŸ"
+#define SF2_PLAYER_HUD_BAR_SYMBOL "|"
+#define SF2_PLAYER_HUD_BAR_MISSING_SYMBOL ""
+#define SF2_PLAYER_HUD_INFINITY_SYMBOL "∞"
+#define SF2_PLAYER_HUD_SPRINT_SYMBOL "»"
+
+public Action:Timer_ClientAverageUpdate(Handle:timer)
+{
+	if (timer != g_hClientAverageUpdateTimer) return Plugin_Stop;
+	
+	if (!g_bEnabled) return Plugin_Stop;
+	
+	if (IsRoundInWarmup() || IsRoundEnding()) return Plugin_Continue;
+	
+	// First, process through HUD stuff.
+	decl String:buffer[256];
+	
+	static iHudColorHealthy[3] = { 150, 255, 150 };
+	static iHudColorCritical[3] = { 255, 10, 10 };
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (IsPlayerAlive(i) && !IsClientInDeathCam(i))
+		{
+			if (!g_bPlayerEliminated[i])
+			{
+				if (DidClientEscape(i)) continue;
+				
+				new iMaxBars = 12;
+				new iBars = RoundToCeil(float(iMaxBars) * ClientGetBlinkMeter(i));
+				if (iBars > iMaxBars) iBars = iMaxBars;
+				
+				Format(buffer, sizeof(buffer), "%s  ", SF2_PLAYER_HUD_BLINK_SYMBOL);
+				
+				if (IsInfiniteBlinkEnabled())
+				{
+					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
+				}
+				else
+				{
+					for (new i2 = 0; i2 < iMaxBars; i2++) 
+					{
+						if (i2 < iBars)
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+						}
+						else
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
+						}
+					}
+				}
+				
+				if (!g_bSpecialRound || g_iSpecialRoundType != SPECIALROUND_LIGHTSOUT)
+				{
+					iBars = RoundToCeil(float(iMaxBars) * ClientGetFlashlightBatteryLife(i));
+					if (iBars > iMaxBars) iBars = iMaxBars;
+					
+					decl String:sBuffer2[64];
+					Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL);
+					StrCat(buffer, sizeof(buffer), sBuffer2);
+					
+					if (IsInfiniteFlashlightEnabled())
+					{
+						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
+					}
+					else
+					{
+						for (new i2 = 0; i2 < iMaxBars; i2++) 
+						{
+							if (i2 < iBars)
+							{
+								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+							}
+							else
+							{
+								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
+							}
+						}
+					}
+				}
+				
+				iBars = RoundToCeil(float(iMaxBars) * (float(ClientGetSprintPoints(i)) / 100.0));
+				if (iBars > iMaxBars) iBars = iMaxBars;
+				
+				decl String:sBuffer2[64];
+				Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_SPRINT_SYMBOL);
+				StrCat(buffer, sizeof(buffer), sBuffer2);
+				
+				if (IsInfiniteSprintEnabled())
+				{
+					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
+				}
+				else
+				{
+					for (new i2 = 0; i2 < iMaxBars; i2++) 
+					{
+						if (i2 < iBars)
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+						}
+						else
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
+						}
+					}
+				}
+				
+				
+				new Float:flHealthRatio = float(GetEntProp(i, Prop_Send, "m_iHealth")) / float(SDKCall(g_hSDKGetMaxHealth, i));
+				
+				new iColor[3];
+				for (new i2 = 0; i2 < 3; i2++)
+				{
+					iColor[i2] = RoundFloat(float(iHudColorHealthy[i2]) + (float(iHudColorCritical[i2] - iHudColorHealthy[i2]) * (1.0 - flHealthRatio)));
+				}
+				
+				SetHudTextParams(0.035, 0.83,
+					0.3,
+					iColor[0],
+					iColor[1],
+					iColor[2],
+					40,
+					_,
+					1.0,
+					0.07,
+					0.5);
+				ShowSyncHudText(i, g_hHudSync2, buffer);
+			}
+			else
+			{
+				if (g_bPlayerProxy[i])
+				{
+					new iMaxBars = 12;
+					new iBars = RoundToCeil(float(iMaxBars) * (float(g_iPlayerProxyControl[i]) / 100.0));
+					if (iBars > iMaxBars) iBars = iMaxBars;
+					
+					strcopy(buffer, sizeof(buffer), "CONTROL\n");
+					
+					for (new i2 = 0; i2 < iBars; i2++)
+					{
+						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+					}
+					
+					SetHudTextParams(-1.0, 0.83,
+						0.3,
+						SF2_HUD_TEXT_COLOR_R,
+						SF2_HUD_TEXT_COLOR_G,
+						SF2_HUD_TEXT_COLOR_B,
+						40,
+						_,
+						1.0,
+						0.07,
+						0.5);
+					ShowSyncHudText(i, g_hHudSync2, buffer);
+				}
+			}
+		}
+		
+		ClientUpdateListeningFlags(i);
+		ClientUpdateMusicSystem(i);
+	}
+	
+	return Plugin_Continue;
+}
+
+stock bool:IsClientParticipating(client)
+{
+	if (!IsValidClient(client)) return false;
+	
+	if (bool:GetEntProp(client, Prop_Send, "m_bIsCoaching")) 
+	{
+		// Who would coach in this game?
+		return false;
+	}
+	
+	new iTeam = GetClientTeam(client);
+	
+	if (g_bPlayerLagCompensation[client]) 
+	{
+		iTeam = g_iPlayerLagCompensationTeam[client];
+	}
+	
+	switch (iTeam)
+	{
+		case TFTeam_Unassigned, TFTeam_Spectator: return false;
+	}
+	
+	if (_:TF2_GetPlayerClass(client) == 0)
+	{
+		// Player hasn't chosen a class? What.
+		return false;
+	}
+	
+	return true;
+}
+
+Handle:GetQueueList()
+{
+	new Handle:hArray = CreateArray(3);
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientParticipating(i)) continue;
+		if (IsPlayerGroupActive(ClientGetPlayerGroup(i))) continue;
+		
+		new index = PushArrayCell(hArray, i);
+		SetArrayCell(hArray, index, g_iPlayerQueuePoints[i], 1);
+		SetArrayCell(hArray, index, false, 2);
+	}
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		new index = PushArrayCell(hArray, i);
+		SetArrayCell(hArray, index, GetPlayerGroupQueuePoints(i), 1);
+		SetArrayCell(hArray, index, true, 2);
+	}
+	
+	if (GetArraySize(hArray)) SortADTArrayCustom(hArray, SortQueueList);
+	return hArray;
+}
+
+SetClientPlayState(client, bool:bState, bool:bEnablePlay=true)
+{
+	if (bState)
+	{
+		if (!g_bPlayerEliminated[client]) return;
+		
+		g_bPlayerEliminated[client] = false;
+		g_bPlayerPlaying[client] = bEnablePlay;
+		g_hPlayerSwitchBlueTimer[client] = INVALID_HANDLE;
+		
+		ClientSetGhostModeState(client, false);
+		
+		PvP_SetPlayerPvPState(client, false, false, false);
+		
+		if (g_bSpecialRound) 
+		{
+			SetClientPlaySpecialRoundState(client, true);
+		}
+		
+		if (g_bNewBossRound) 
+		{
+			SetClientPlayNewBossRoundState(client, true);
+		}
+		
+		if (TF2_GetPlayerClass(client) == TFClassType:0)
+		{
+			// Player hasn't chosen a class for some reason. Choose one for him.
+			TF2_SetPlayerClass(client, TFClassType:GetRandomInt(1, 9), true, true);
+		}
+		
+		ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
+	}
+	else
+	{
+		if (g_bPlayerEliminated[client]) return;
+		
+		g_bPlayerEliminated[client] = true;
+		g_bPlayerPlaying[client] = false;
+		
+		ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
+	}
+}
+
+bool:DidClientPlayNewBossRound(client)
+{
+	return g_bPlayerPlayedNewBossRound[client];
+}
+
+SetClientPlayNewBossRoundState(client, bool:bState)
+{
+	g_bPlayerPlayedNewBossRound[client] = bState;
+}
+
+bool:DidClientPlaySpecialRound(client)
+{
+	return g_bPlayerPlayedNewBossRound[client];
+}
+
+SetClientPlaySpecialRoundState(client, bool:bState)
+{
+	g_bPlayerPlayedSpecialRound[client] = bState;
+}
+
+TeleportClientToEscapePoint(client)
+{
+	if (!IsClientInGame(client)) return;
+	
+	new ent = EntRefToEntIndex(g_iRoundEscapePointEntity);
+	if (ent && ent != -1)
+	{
+		decl Float:flPos[3], Float:flAng[3];
+		GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
+		GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", flAng);
+		
+		TeleportEntity(client, flPos, flAng, Float:{ 0.0, 0.0, 0.0 });
+		AcceptEntityInput(ent, "FireUser1", client);
+	}
+}
+
+ForceInNextPlayersInQueue(iAmount, bool:bShowMessage=false)
+{
+	// Grab the next person in line, or the next group in line if space allows.
+	new iAmountLeft = iAmount;
+	new Handle:hPlayers = CreateArray();
+	new Handle:hArray = GetQueueList();
+	
+	for (new i = 0, iSize = GetArraySize(hArray); i < iSize && iAmountLeft > 0; i++)
+	{
+		if (!GetArrayCell(hArray, i, 2))
+		{
+			new iClient = GetArrayCell(hArray, i);
+			if (g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
+			
+			PushArrayCell(hPlayers, iClient);
+			iAmountLeft--;
+		}
+		else
+		{
+			new iGroupIndex = GetArrayCell(hArray, i);
+			if (!IsPlayerGroupActive(iGroupIndex)) continue;
+			
+			new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
+			if (iMemberCount <= iAmountLeft)
+			{
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsValidClient(iClient) || g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
+					if (ClientGetPlayerGroup(iClient) == iGroupIndex)
+					{
+						PushArrayCell(hPlayers, iClient);
+					}
+				}
+				
+				SetPlayerGroupPlaying(iGroupIndex, true);
+				
+				iAmountLeft -= iMemberCount;
+			}
+		}
+	}
+	
+	CloseHandle(hArray);
+	
+	for (new i = 0, iSize = GetArraySize(hPlayers); i < iSize; i++)
+	{
+		new iClient = GetArrayCell(hPlayers, i);
+		ClientSetQueuePoints(iClient, 0);
+		SetClientPlayState(iClient, true);
+		
+		if (bShowMessage) CPrintToChat(iClient, "%T", "SF2 Force Play", iClient);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public SortQueueList(index1, index2, Handle:array, Handle:hndl)
+{
+	new iQueuePoints1 = GetArrayCell(array, index1, 1);
+	new iQueuePoints2 = GetArrayCell(array, index2, 1);
+	
+	if (iQueuePoints1 > iQueuePoints2) return -1;
+	else if (iQueuePoints1 == iQueuePoints2) return 0;
+	return 1;
+}
+
+//	==========================================================
+//	GENERIC PAGE/BOSS HOOKS AND FUNCTIONS
+//	==========================================================
+
+public Action:Hook_SlenderObjectSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (!IsPlayerAlive(other) || IsClientInDeathCam(other))
+	{
+		if (!IsValidEdict(GetEntPropEnt(other, Prop_Send, "m_hObserverTarget"))) return Plugin_Handled;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_SlenderBlinkBossThink(Handle:timer, any:entref)
+{
+	new slender = EntRefToEntIndex(entref);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return Plugin_Stop;
+	
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	if (timer != g_hSlenderEntityThink[iBossIndex]) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (NPCGetType(iBossIndex) == SF2BossType_Creeper)
+	{
+		new bool:bMove = false;
+		
+		if ((GetGameTime() - g_flSlenderLastKill[iBossIndex]) >= GetProfileFloat(sProfile, "kill_cooldown"))
+		{
+			if (PeopleCanSeeSlender(iBossIndex, false, false) && !PeopleCanSeeSlender(iBossIndex, true, SlenderUsesBlink(iBossIndex)))
+			{
+				new iBestPlayer = -1;
+				new Handle:hArray = CreateArray();
+				
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientInDeathCam(i) || g_bPlayerEliminated[i] || DidClientEscape(i) || IsClientInGhostMode(i) || !PlayerCanSeeSlender(i, iBossIndex, false, false)) continue;
+					PushArrayCell(hArray, i);
+				}
+				
+				if (GetArraySize(hArray))
+				{
+					decl Float:flSlenderPos[3];
+					SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
+					
+					decl Float:flTempPos[3];
+					new iTempPlayer = -1;
+					new Float:flTempDist = 16384.0;
+					for (new i = 0; i < GetArraySize(hArray); i++)
+					{
+						new iClient = GetArrayCell(hArray, i);
+						GetClientAbsOrigin(iClient, flTempPos);
+						if (GetVectorDistance(flTempPos, flSlenderPos) < flTempDist)
+						{
+							iTempPlayer = iClient;
+							flTempDist = GetVectorDistance(flTempPos, flSlenderPos);
+						}
+					}
+					
+					iBestPlayer = iTempPlayer;
+				}
+				
+				CloseHandle(hArray);
+				
+				decl Float:buffer[3];
+				if (iBestPlayer != -1 && SlenderCalculateApproachToPlayer(iBossIndex, iBestPlayer, buffer))
+				{
+					bMove = true;
+					
+					decl Float:flAng[3], Float:flBuffer[3];
+					decl Float:flSlenderPos[3], Float:flPos[3];
+					GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flSlenderPos);
+					GetClientAbsOrigin(iBestPlayer, flPos);
+					SubtractVectors(flPos, buffer, flAng);
+					GetVectorAngles(flAng, flAng);
+					
+					// Take care of angle offsets.
+					AddVectors(flAng, g_flSlenderEyeAngOffset[iBossIndex], flAng);
+					for (new i = 0; i < 3; i++) flAng[i] = AngleNormalize(flAng[i]);
+					
+					flAng[0] = 0.0;
+					
+					// Take care of position offsets.
+					GetProfileVector(sProfile, "pos_offset", flBuffer);
+					AddVectors(buffer, flBuffer, buffer);
+					
+					TeleportEntity(slender, buffer, flAng, NULL_VECTOR);
+					
+					new Float:flMaxRange = GetProfileFloat(sProfile, "teleport_range_max");
+					new Float:flDist = GetVectorDistance(buffer, flPos);
+					
+					decl String:sBuffer[PLATFORM_MAX_PATH];
+					
+					if (flDist < (flMaxRange * 0.33)) 
+					{
+						GetProfileString(sProfile, "model_closedist", sBuffer, sizeof(sBuffer));
+					}
+					else if (flDist < (flMaxRange * 0.66)) 
+					{
+						GetProfileString(sProfile, "model_averagedist", sBuffer, sizeof(sBuffer));
+					}
+					else 
+					{
+						GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
+					}
+					
+					// Fallback if error.
+					if (!sBuffer[0]) GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
+					
+					SetEntProp(slender, Prop_Send, "m_nModelIndex", PrecacheModel(sBuffer));
+					
+					if (flDist <= NPCGetInstantKillRadius(iBossIndex))
+					{
+						if (NPCGetFlags(iBossIndex) & SFF_FAKE)
+						{
+							SlenderMarkAsFake(iBossIndex);
+							return Plugin_Stop;
+						}
+						else
+						{
+							g_flSlenderLastKill[iBossIndex] = GetGameTime();
+							ClientStartDeathCam(iBestPlayer, iBossIndex, buffer);
+						}
+					}
+				}
+			}
+		}
+		
+		if (bMove)
+		{
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_move_single", sBuffer, sizeof(sBuffer));
+			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+			
+			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
+			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, SND_CHANGEVOL);
+		}
+		else
+		{
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
+			if (sBuffer[0]) StopSound(slender, SNDCHAN_AUTO, sBuffer);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+
+SlenderOnClientStressUpdate(client)
+{
+	new Float:flStress = g_flPlayerStress[client];
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+	{	
+		if (NPCGetUniqueID(iBossIndex) == -1) continue;
+		
+		new iBossFlags = NPCGetFlags(iBossIndex);
+		if (iBossFlags & SFF_MARKEDASFAKE ||
+			iBossFlags & SFF_NOTELEPORT)
+		{
+			continue;
+		}
+		
+		NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+		
+		new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
+		if (iTeleportTarget && iTeleportTarget != INVALID_ENT_REFERENCE)
+		{
+			if (g_bPlayerEliminated[iTeleportTarget] ||
+				DidClientEscape(iTeleportTarget) ||
+				flStress >= g_flSlenderTeleportMaxTargetStress[iBossIndex] ||
+				GetGameTime() >= g_flSlenderTeleportMaxTargetTime[iBossIndex])
+			{
+				// Queue for a new target and mark the old target in the rest period.
+				new Float:flRestPeriod = GetProfileFloat(sProfile, "teleport_target_rest_period", 15.0);
+				flRestPeriod = (flRestPeriod * GetRandomFloat(0.92, 1.08)) / (NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier);
+				
+				g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+				g_flSlenderTeleportPlayersRestTime[iBossIndex][iTeleportTarget] = GetGameTime() + flRestPeriod;
+				g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
+				g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
+				g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: lost target, putting at rest period", iBossIndex);
+#endif
+			}
+		}
+		else if (!g_bRoundGrace)
+		{
+			new iPreferredTeleportTarget = INVALID_ENT_REFERENCE;
+			
+			new Float:flTargetStressMin = GetProfileFloat(sProfile, "teleport_target_stress_min", 0.2);
+			new Float:flTargetStressMax = GetProfileFloat(sProfile, "teleport_target_stress_max", 0.9);
+			
+			new Float:flTargetStress = flTargetStressMax - ((flTargetStressMax - flTargetStressMin) / (g_flRoundDifficultyModifier * NPCGetAnger(iBossIndex)));
+			
+			new Float:flPreferredTeleportTargetStress = flTargetStress;
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) ||
+					!IsPlayerAlive(i) ||
+					g_bPlayerEliminated[i] ||
+					IsClientInGhostMode(i) ||
+					DidClientEscape(i))
+				{
+					continue;
+				}
+				
+				if (g_flPlayerStress[i] < flPreferredTeleportTargetStress)
+				{
+					if (g_flSlenderTeleportPlayersRestTime[iBossIndex][i] <= GetGameTime())
+					{
+						iPreferredTeleportTarget = i;
+						flPreferredTeleportTargetStress = g_flPlayerStress[i];
+					}
+				}
+			}
+			
+			if (iPreferredTeleportTarget && iPreferredTeleportTarget != INVALID_ENT_REFERENCE)
+			{
+				// Set our preferred target to the new guy.
+				new Float:flTargetDuration = GetProfileFloat(sProfile, "teleport_target_persistency_period", 13.0);
+				new Float:flDeviation = GetRandomFloat(0.92, 1.08);
+				flTargetDuration = Pow(flDeviation * flTargetDuration, ((g_flRoundDifficultyModifier * (NPCGetAnger(iBossIndex) - 1.0)) / 2.0)) + ((flDeviation * flTargetDuration) - 1.0);
+				
+				g_iSlenderTeleportTarget[iBossIndex] = EntIndexToEntRef(iPreferredTeleportTarget);
+				g_flSlenderTeleportPlayersRestTime[iBossIndex][iPreferredTeleportTarget] = -1.0;
+				g_flSlenderTeleportMaxTargetTime[iBossIndex] = GetGameTime() + flTargetDuration;
+				g_flSlenderTeleportTargetTime[iBossIndex] = GetGameTime();
+				g_flSlenderTeleportMaxTargetStress[iBossIndex] = flTargetStress;
+				
+				iTeleportTarget = iPreferredTeleportTarget;
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: got new target %N", iBossIndex, iPreferredTeleportTarget);
+#endif
+			}
+		}
+	}
+}
+
+static GetPageMusicRanges()
+{
+	ClearArray(g_hPageMusicRanges);
+	
+	decl String:sName[64];
+	
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		
+		if (sName[0] && !StrContains(sName, "sf2_page_music_", false))
+		{
+			ReplaceString(sName, sizeof(sName), "sf2_page_music_", "", false);
+			
+			new String:sPageRanges[2][32];
+			ExplodeString(sName, "-", sPageRanges, 2, 32);
+			
+			new iIndex = PushArrayCell(g_hPageMusicRanges, EntIndexToEntRef(ent));
+			if (iIndex != -1)
+			{
+				new iMin = StringToInt(sPageRanges[0]);
+				new iMax = StringToInt(sPageRanges[1]);
+				
+#if defined DEBUG
+				DebugMessage("Page range found: entity %d, iMin = %d, iMax = %d", ent, iMin, iMax);
+#endif
+				SetArrayCell(g_hPageMusicRanges, iIndex, iMin, 1);
+				SetArrayCell(g_hPageMusicRanges, iIndex, iMax, 2);
+			}
+		}
+	}
+	
+	// precache
+	if (GetArraySize(g_hPageMusicRanges) > 0)
+	{
+		decl String:sPath[PLATFORM_MAX_PATH];
+		
+		for (new i = 0; i < GetArraySize(g_hPageMusicRanges); i++)
+		{
+			ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
+			if (!ent || ent == INVALID_ENT_REFERENCE) continue;
+			
+			GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+			if (sPath[0])
+			{
+				PrecacheSound(sPath);
+			}
+		}
+	}
+	
+	LogSF2Message("Loaded page music ranges successfully!");
+}
+
+SetPageCount(iNum)
+{
+	if (iNum > g_iPageMax) iNum = g_iPageMax;
+	
+	new iOldPageCount = g_iPageCount;
+	g_iPageCount = iNum;
+	
+	if (g_iPageCount != iOldPageCount)
+	{
+		if (g_iPageCount > iOldPageCount)
+		{
+			if (g_hRoundGraceTimer != INVALID_HANDLE) 
+			{
+				TriggerTimer(g_hRoundGraceTimer);
+			}
+			
+			g_iRoundTime += g_iRoundTimeGainFromPage;
+			if (g_iRoundTime > g_iRoundTimeLimit) g_iRoundTime = g_iRoundTimeLimit;
+			
+			// Increase anger on selected bosses.
+			for (new i = 0; i < MAX_BOSSES; i++)
+			{
+				if (NPCGetUniqueID(i) == -1) continue;
+				
+				new Float:flPageDiff = NPCGetAngerAddOnPageGrabTimeDiff(i);
+				if (flPageDiff >= 0.0)
+				{
+					new iDiff = g_iPageCount - iOldPageCount;
+					if ((GetGameTime() - g_flPageFoundLastTime) < flPageDiff)
+					{
+						NPCAddAnger(i, NPCGetAngerAddOnPageGrab(i) * float(iDiff));
+					}
+				}
+			}
+			
+			g_flPageFoundLastTime = GetGameTime();
+		}
+		
+		// Notify logic entities.
+		decl String:sTargetName[64];
+		decl String:sFindTargetName[64];
+		Format(sFindTargetName, sizeof(sFindTargetName), "sf2_onpagecount_%d", g_iPageCount);
+		
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
+		{
+			GetEntPropString(ent, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
+			if (sTargetName[0] && StrEqual(sTargetName, sFindTargetName, false))
+			{
+				AcceptEntityInput(ent, "Trigger");
+				break;
+			}
+		}
+	
+		new iClients[MAXPLAYERS + 1] = { -1, ... };
+		new iClientsNum = 0;
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i)) continue;
+			if (!g_bPlayerEliminated[i] || IsClientInGhostMode(i))
+			{
+				if (g_iPageCount)
+				{
+					iClients[iClientsNum] = i;
+					iClientsNum++;
+				}
+			}
+		}
+		
+		if (g_iPageCount > 0 && g_bRoundHasEscapeObjective && g_iPageCount == g_iPageMax)
+		{
+			// Escape initialized!
+			SetRoundState(SF2RoundState_Escape);
+			
+			if (iClientsNum)
+			{
+				new iGameTextEscape = GetTextEntity("sf2_escape_message", false);
+				if (iGameTextEscape != -1)
+				{
+					// Custom escape message.
+					decl String:sMessage[512];
+					GetEntPropString(iGameTextEscape, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextEscape, g_hHudSync, sMessage);
+				}
+				else
+				{
+					// Default escape message.
+					for (new i = 0; i < iClientsNum; i++)
+					{
+						new client = iClients[i];
+						ClientShowMainMessage(client, "%d/%d\n%T", g_iPageCount, g_iPageMax, "SF2 Default Escape Message", i);
+					}
+				}
+			}
+		}
+		else
+		{
+			if (iClientsNum)
+			{
+				new iGameTextPage = GetTextEntity("sf2_page_message", false);
+				if (iGameTextPage != -1)
+				{
+					// Custom page message.
+					decl String:sMessage[512];
+					GetEntPropString(iGameTextPage, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextPage, g_hHudSync, sMessage, g_iPageCount, g_iPageMax);
+				}
+				else
+				{
+					// Default page message.
+					for (new i = 0; i < iClientsNum; i++)
+					{
+						new client = iClients[i];
+						ClientShowMainMessage(client, "%d/%d", g_iPageCount, g_iPageMax);
+					}
+				}
+			}
+		}
+		
+		CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
+	}
+}
+
+GetTextEntity(const String:sTargetName[], bool:bCaseSensitive=true)
+{
+	// Try to see if we can use a custom message instead of the default.
+	decl String:targetName[64];
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "game_text")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
+		if (targetName[0])
+		{
+			if (StrEqual(targetName, sTargetName, bCaseSensitive))
+			{
+				return ent;
+			}
+		}
+	}
+	
+	return -1;
+}
+
+ShowHudTextUsingTextEntity(const iClients[], iClientsNum, iGameText, Handle:hHudSync, const String:sMessage[], ...)
+{
+	if (!sMessage[0]) return;
+	if (!IsValidEntity(iGameText)) return;
+	
+	decl String:sTrueMessage[512];
+	VFormat(sTrueMessage, sizeof(sTrueMessage), sMessage, 6);
+	
+	new Float:flX = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.x");
+	new Float:flY = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.y");
+	new iEffect = GetEntProp(iGameText, Prop_Data, "m_textParms.effect");
+	new Float:flFadeInTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime");
+	new Float:flFadeOutTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime");
+	new Float:flHoldTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
+	new Float:flFxTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fxTime");
+	
+	new Color1[4] = { 255, 255, 255, 255 };
+	new Color2[4] = { 255, 255, 255, 255 };
+	
+	new iParmsOffset = FindDataMapOffs(iGameText, "m_textParms");
+	if (iParmsOffset != -1)
+	{
+		// hudtextparms_s m_textParms
+		
+		Color1[0] = GetEntData(iGameText, iParmsOffset + 12, 1);
+		Color1[1] = GetEntData(iGameText, iParmsOffset + 13, 1);
+		Color1[2] = GetEntData(iGameText, iParmsOffset + 14, 1);
+		Color1[3] = GetEntData(iGameText, iParmsOffset + 15, 1);
+		
+		Color2[0] = GetEntData(iGameText, iParmsOffset + 16, 1);
+		Color2[1] = GetEntData(iGameText, iParmsOffset + 17, 1);
+		Color2[2] = GetEntData(iGameText, iParmsOffset + 18, 1);
+		Color2[3] = GetEntData(iGameText, iParmsOffset + 19, 1);
+	}
+	
+	SetHudTextParamsEx(flX, flY, flHoldTime, Color1, Color2, iEffect, flFxTime, flFadeInTime, flFadeOutTime);
+	
+	for (new i = 0; i < iClientsNum; i++)
+	{
+		new iClient = iClients[i];
+		if (!IsValidClient(iClient) || IsFakeClient(iClient)) continue;
+		
+		ShowSyncHudText(iClient, hHudSync, sTrueMessage);
+	}
+}
+
+//	==========================================================
+//	EVENT HOOKS
+//	==========================================================
+
+public Event_RoundStart(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundStart");
+#endif
+	
+	// Reset some global variables.
+	g_iRoundCount++;
+	g_hRoundTimer = INVALID_HANDLE;
+	
+	SetRoundState(SF2RoundState_Invalid);
+	
+	SetPageCount(0);
+	g_iPageMax = 0;
+	g_flPageFoundLastTime = GetGameTime();
+	
+	g_hVoteTimer = INVALID_HANDLE;
+	
+	// Remove all bosses from the game.
+	NPCRemoveAll();
+	
+	// Refresh groups.
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		SetPlayerGroupPlaying(i, false);
+		CheckPlayerGroup(i);
+	}
+	
+	// Refresh players.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		ClientSetGhostModeState(i, false);
+		
+		g_bPlayerPlaying[i] = false;
+		g_bPlayerEliminated[i] = true;
+		g_bPlayerEscaped[i] = false;
+	}
+	
+	// Calculate the new round state.
+	if (g_bRoundWaitingForPlayers)
+	{
+		SetRoundState(SF2RoundState_Waiting);
+	}
+	else if (GetConVarBool(g_cvWarmupRound) && g_iRoundWarmupRoundCount < GetConVarInt(g_cvWarmupRoundNum))
+	{
+		g_iRoundWarmupRoundCount++;
+		
+		SetRoundState(SF2RoundState_Waiting);
+		
+		ServerCommand("mp_restartgame 15");
+		PrintCenterTextAll("Round restarting in 15 seconds");
+	}
+	else
+	{
+		g_iRoundActiveCount++;
+		
+		InitializeNewGame();
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundStart");
+#endif
+}
+
+public Event_RoundEnd(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundEnd");
+#endif
+	
+	SetRoundState(SF2RoundState_Outro);
+	
+	DistributeQueuePointsToPlayers();
+	
+	g_iRoundEndCount++;	
+	CheckRoundLimitForBossPackVote(g_iRoundEndCount);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundEnd");
+#endif
+}
+
+static DistributeQueuePointsToPlayers()
+{
+	// Give away queue points.
+	new iDefaultAmount = 5;
+	new iAmount = iDefaultAmount;
+	new iAmount2 = iAmount;
+	new Action:iAction = Plugin_Continue;
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		
+		if (IsPlayerGroupPlaying(i))
+		{
+			SetPlayerGroupQueuePoints(i, 0);
+		}
+		else
+		{
+			iAmount = iDefaultAmount;
+			iAmount2 = iAmount;
+			iAction = Plugin_Continue;
+			
+			Call_StartForward(fOnGroupGiveQueuePoints);
+			Call_PushCell(i);
+			Call_PushCellRef(iAmount2);
+			Call_Finish(iAction);
+			
+			if (iAction == Plugin_Changed) iAmount = iAmount2;
+			
+			SetPlayerGroupQueuePoints(i, GetPlayerGroupQueuePoints(i) + iAmount);
+		
+			for (new iClient = 1; iClient <= MaxClients; iClient++)
+			{
+				if (!IsValidClient(iClient)) continue;
+				if (ClientGetPlayerGroup(iClient) == i)
+				{
+					CPrintToChat(iClient, "%T", "SF2 Give Group Queue Points", iClient, iAmount);
+				}
+			}
+		}
+	}
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (g_bPlayerPlaying[i]) 
+		{
+			ClientSetQueuePoints(i, 0);
+		}
+		else
+		{
+			if (!IsClientParticipating(i))
+			{
+				CPrintToChat(i, "%T", "SF2 No Queue Points To Spectator", i);
+			}
+			else
+			{
+				iAmount = iDefaultAmount;
+				iAmount2 = iAmount;
+				iAction = Plugin_Continue;
+				
+				Call_StartForward(fOnClientGiveQueuePoints);
+				Call_PushCell(i);
+				Call_PushCellRef(iAmount2);
+				Call_Finish(iAction);
+				
+				if (iAction == Plugin_Changed) iAmount = iAmount2;
+				
+				ClientSetQueuePoints(i, g_iPlayerQueuePoints[i] + iAmount);
+				CPrintToChat(i, "%T", "SF2 Give Queue Points", i, iAmount);
+			}
+		}	
+	}
+}
+
+public Action:Event_PlayerTeamPre(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerTeamPre");
+#endif
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client > 0)
+	{
+		if (GetEventInt(event, "team") > 1 || GetEventInt(event, "oldteam") > 1) SetEventBroadcast(event, true);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerTeamPre");
+#endif
+	
+	return Plugin_Continue;
+}
+
+public Event_PlayerTeam(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerTeam");
+#endif
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client > 0)
+	{
+		new iNewTeam = GetEventInt(event, "team");
+		if (iNewTeam <= _:TFTeam_Spectator)
+		{
+			if (g_bRoundGrace)
+			{
+				if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
+				{
+					ForceInNextPlayersInQueue(1, true);
+				}
+			}
+			
+			// You're not playing anymore.
+			if (g_bPlayerPlaying[client])
+			{
+				ClientSetQueuePoints(client, 0);
+			}
+			
+			g_bPlayerPlaying[client] = false;
+			g_bPlayerEliminated[client] = true;
+			g_bPlayerEscaped[client] = false;
+			
+			ClientSetGhostModeState(client, false);
+			
+			if (!bool:GetEntProp(client, Prop_Send, "m_bIsCoaching"))
+			{
+				// This is to prevent player spawn spam when someone is coaching. Who coaches in SF2, anyway?
+				TF2_RespawnPlayer(client);
+			}
+			
+			// Special round.
+			if (g_bSpecialRound) g_bPlayerPlayedSpecialRound[client] = true;
+			
+			// Boss round.
+			if (g_bNewBossRound) g_bPlayerPlayedNewBossRound[client] = true;
+		}
+		else
+		{
+			if (!g_bPlayerChoseTeam[client])
+			{
+				g_bPlayerChoseTeam[client] = true;
+				
+				if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
+				{
+					EmitSoundToClient(client, SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
+					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Projected{olive}.");
+				}
+				else
+				{
+					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Normal{olive}.");
+				}
+				
+				CreateTimer(5.0, Timer_WelcomeMessage, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+			}
+		}
+	}
+	
+	// Check groups.
+	if (!IsRoundEnding())
+	{
+		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+		{
+			if (!IsPlayerGroupActive(i)) continue;
+			CheckPlayerGroup(i);
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerTeam");
+#endif
+
+}
+
+/**
+ *	Sets the player to the correct team if needed. Returns true if a change was necessary, false if no change occurred.
+ */
+static bool:HandlePlayerTeam(client, bool:bRespawn=true)
+{
+	if (!IsClientInGame(client) || !IsClientParticipating(client)) return false;
+	
+	if (!g_bPlayerEliminated[client])
+	{
+		if (GetClientTeam(client) != _:TFTeam_Red)
+		{
+			if (bRespawn)
+				ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
+			else
+				ChangeClientTeam(client, _:TFTeam_Red);
+				
+			return true;
+		}
+	}
+	else
+	{
+		if (GetClientTeam(client) != _:TFTeam_Blue)
+		{
+			if (bRespawn)
+				ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
+			else
+				ChangeClientTeam(client, _:TFTeam_Blue);
+				
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+static HandlePlayerIntroState(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client) || !IsClientParticipating(client)) return;
+	
+	if (!IsRoundInIntro()) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START HandlePlayerIntroState(%d)", client);
+#endif
+	
+	// Disable movement on player.
+	SetEntityFlags(client, GetEntityFlags(client) | FL_FROZEN);
+	
+	new Float:flDelay = 0.0;
+	if (!IsFakeClient(client))
+	{
+		flDelay = GetClientLatency(client, NetFlow_Outgoing);
+	}
+	
+	CreateTimer(flDelay * 4.0, Timer_IntroBlackOut, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END HandlePlayerIntroState(%d)", client);
+#endif
+}
+
+HandlePlayerHUD(client)
+{
+	if (IsRoundInWarmup() || IsClientInGhostMode(client))
+	{
+		SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
+	}
+	else
+	{
+		if (!g_bPlayerEliminated[client])
+		{
+			if (!DidClientEscape(client))
+			{
+				// Player is in the game; disable normal HUD.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
+			}
+			else
+			{
+				// Player isn't in the game; enable normal HUD behavior.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
+			}
+		}
+		else
+		{
+			if (g_bPlayerProxy[client])
+			{
+				// Player is in the game; disable normal HUD.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
+			}
+			else
+			{
+				// Player isn't in the game; enable normal HUD behavior.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
+			}
+		}
+	}
+}
+
+public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client <= 0) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerSpawn(%d)", client);
+#endif
+	
+	if (!IsClientParticipating(client))
+	{
+		ClientSetGhostModeState(client, false);
+	}
+	
+	g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
+	
+	if (IsPlayerAlive(client) && IsClientParticipating(client))
+	{
+		if (HandlePlayerTeam(client))
+		{
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("client->HandlePlayerTeam()");
+#endif
+		}
+		else
+		{
+			g_iPlayerPageCount[client] = 0;
+			
+			ClientDisableFakeLagCompensation(client);
+			
+			ClientResetStatic(client);
+			ClientResetSlenderStats(client);
+			ClientResetCampingStats(client);
+			ClientResetOverlay(client);
+			ClientResetJumpScare(client);
+			ClientUpdateListeningFlags(client);
+			ClientUpdateMusicSystem(client);
+			ClientChaseMusicReset(client);
+			ClientChaseMusicSeeReset(client);
+			ClientAlertMusicReset(client);
+			Client20DollarsMusicReset(client);
+			ClientMusicReset(client);
+			ClientResetProxy(client);
+			ClientResetHints(client);
+			ClientResetScare(client);
+			
+			ClientResetDeathCam(client);
+			ClientResetFlashlight(client);
+			ClientDeactivateUltravision(client);
+			ClientResetSprint(client);
+			ClientResetBreathing(client);
+			ClientResetBlink(client);
+			ClientResetInteractiveGlow(client);
+			ClientDisableConstantGlow(client);
+			
+			ClientHandleGhostMode(client);
+			
+			if (!g_bPlayerEliminated[client])
+			{
+				ClientStartDrainingBlinkMeter(client);
+				ClientSetScareBoostEndTime(client, -1.0);
+				
+				ClientStartCampingTimer(client);
+				
+				HandlePlayerIntroState(client);
+				
+				// screen overlay timer
+				g_hPlayerOverlayCheck[client] = CreateTimer(0.0, Timer_PlayerOverlayCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+				TriggerTimer(g_hPlayerOverlayCheck[client], true);
+				
+				if (DidClientEscape(client))
+				{
+					CreateTimer(0.1, Timer_TeleportPlayerToEscapePoint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+				else
+				{
+					ClientEnableConstantGlow(client, "head");
+					ClientActivateUltravision(client);
+				}
+			}
+			else
+			{
+				g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
+			}
+			
+			g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+			
+			HandlePlayerHUD(client);
+		}
+	}
+	
+	PvP_OnPlayerSpawn(client);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerSpawn(%d)", client);
+#endif
+}
+
+public Action:Timer_IntroBlackOut(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (!IsRoundInIntro()) return;
+	
+	if (!IsPlayerAlive(client) || g_bPlayerEliminated[client]) return;
+	
+	// Black out the player's screen.
+	new iFadeFlags = FFADE_OUT | FFADE_STAYOUT | FFADE_PURGE;
+	UTIL_ScreenFade(client, 0, FixedUnsigned16(90.0, 1 << 12), iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
+}
+
+public Event_PostInventoryApplication(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PostInventoryApplication");
+#endif
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client > 0)
+	{
+		g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PostInventoryApplication");
+#endif
+}
+
+public Action:Event_DontBroadcastToClients(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsRoundInWarmup()) return Plugin_Continue;
+	
+	SetEventBroadcast(event, true);
+	return Plugin_Continue;
+}
+
+public Action:Event_PlayerDeathPre(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerDeathPre");
+#endif
+	
+	if (!IsRoundInWarmup())
+	{
+		new client = GetClientOfUserId(GetEventInt(event, "userid"));
+		if (client > 0)
+		{
+			if (!IsRoundEnding())
+			{
+				if (g_bRoundGrace || g_bPlayerEliminated[client] || IsClientInGhostMode(client))
+				{
+					SetEventBroadcast(event, true);
+				}
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerDeathPre");
+#endif
+	
+	return Plugin_Continue;
+}
+
+public Event_PlayerHurt(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client <= 0) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerHurt");
+#endif
+	
+	ClientDisableFakeLagCompensation(client);
+	
+	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
+	if (attacker > 0)
+	{
+		if (g_bPlayerProxy[attacker])
+		{
+			g_iPlayerProxyControl[attacker] = 100;
+		}
+	}
+	
+	// Play any sounds, if any.
+	if (g_bPlayerProxy[client])
+	{
+		new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+		if (iProxyMaster != -1)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
+		
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			if (GetRandomStringFromProfile(sProfile, "sound_proxy_hurt", sBuffer, sizeof(sBuffer)) && sBuffer[0])
+			{
+				new iChannel = GetProfileNum(sProfile, "sound_proxy_hurt_channel", SNDCHAN_AUTO);
+				new iLevel = GetProfileNum(sProfile, "sound_proxy_hurt_level", SNDLEVEL_NORMAL);
+				new iFlags = GetProfileNum(sProfile, "sound_proxy_hurt_flags", SND_NOFLAGS);
+				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_hurt_volume", SNDVOL_NORMAL);
+				new iPitch = GetProfileNum(sProfile, "sound_proxy_hurt_pitch", SNDPITCH_NORMAL);
+				
+				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerHurt");
+#endif
+}
+
+public Event_PlayerDeath(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client <= 0) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerDeath(%d)", client);
+#endif
+	
+	new bool:bFake = bool:(GetEventInt(event, "death_flags") & TF_DEATHFLAG_DEADRINGER);
+	new inflictor = GetEventInt(event, "inflictor_entindex");
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("inflictor = %d", inflictor);
+#endif
+	
+	if (!bFake)
+	{
+		ClientDisableFakeLagCompensation(client);
+		
+		ClientResetStatic(client);
+		ClientResetSlenderStats(client);
+		ClientResetCampingStats(client);
+		ClientResetOverlay(client);
+		ClientResetJumpScare(client);
+		ClientResetInteractiveGlow(client);
+		ClientDisableConstantGlow(client);
+		ClientChaseMusicReset(client);
+		ClientChaseMusicSeeReset(client);
+		ClientAlertMusicReset(client);
+		Client20DollarsMusicReset(client);
+		ClientMusicReset(client);
+		
+		ClientResetFlashlight(client);
+		ClientDeactivateUltravision(client);
+		ClientResetSprint(client);
+		ClientResetBreathing(client);
+		ClientResetBlink(client);
+		ClientResetDeathCam(client);
+		
+		ClientUpdateMusicSystem(client);
+		
+		PvP_SetPlayerPvPState(client, false, false, false);
+		
+		if (IsRoundInWarmup())
+		{
+			CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+		}
+		else
+		{
+			if (!g_bPlayerEliminated[client])
+			{
+				if (IsRoundInIntro() || g_bRoundGrace || DidClientEscape(client))
+				{
+					CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+				else
+				{
+					g_bPlayerEliminated[client] = true;
+					g_bPlayerEscaped[client] = false;
+					g_hPlayerSwitchBlueTimer[client] = CreateTimer(0.5, Timer_PlayerSwitchToBlue, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+			}
+			else
+			{
+			}
+			
+			{
+				// If this player was killed by a boss, play a sound.
+				new npcIndex = NPCGetFromEntIndex(inflictor);
+				if (npcIndex != -1)
+				{
+					decl String:npcProfile[SF2_MAX_PROFILE_NAME_LENGTH], String:buffer[PLATFORM_MAX_PATH];
+					NPCGetProfile(npcIndex, npcProfile, sizeof(npcProfile));
+					
+					if (GetRandomStringFromProfile(npcProfile, "sound_attack_killed_all", buffer, sizeof(buffer)) && strlen(buffer) > 0)
+					{
+						if (!g_bPlayerEliminated[client])
+						{
+							EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_HELICOPTER);
+						}
+					}
+					
+					SlenderPerformVoice(npcIndex, "sound_attack_killed");
+				}
+			}
+			
+			CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			// Notify to other bosses that this player has died.
+			for (new i = 0; i < MAX_BOSSES; i++)
+			{
+				if (NPCGetUniqueID(i) == -1) continue;
+				
+				if (EntRefToEntIndex(g_iSlenderTarget[i]) == client)
+				{
+					g_iSlenderInterruptConditions[i] |= COND_CHASETARGETINVALIDATED;
+					GetClientAbsOrigin(client, g_flSlenderChaseDeathPosition[i]);
+				}
+			}
+		}
+		
+		if (g_bPlayerProxy[client])
+		{
+			// We're a proxy, so play some sounds.
+		
+			new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+			if (iProxyMaster != -1)
+			{
+				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+				NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
+				
+				decl String:sBuffer[PLATFORM_MAX_PATH];
+				if (GetRandomStringFromProfile(sProfile, "sound_proxy_death", sBuffer, sizeof(sBuffer)) && sBuffer[0])
+				{
+					new iChannel = GetProfileNum(sProfile, "sound_proxy_death_channel", SNDCHAN_AUTO);
+					new iLevel = GetProfileNum(sProfile, "sound_proxy_death_level", SNDLEVEL_NORMAL);
+					new iFlags = GetProfileNum(sProfile, "sound_proxy_death_flags", SND_NOFLAGS);
+					new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_death_volume", SNDVOL_NORMAL);
+					new iPitch = GetProfileNum(sProfile, "sound_proxy_death_pitch", SNDPITCH_NORMAL);
+					
+					EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
+				}
+			}
+		}
+		
+		ClientResetProxy(client, false);
+		ClientUpdateListeningFlags(client);
+		
+		// Half-Zatoichi nerf code.
+		new iKatanaHealthGain = GetConVarInt(g_cvHalfZatoichiHealthGain);
+		if (iKatanaHealthGain >= 0)
+		{
+			new iAttacker = GetClientOfUserId(GetEventInt(event, "attacker"));
+			if (iAttacker > 0)
+			{
+				if (!IsClientInPvP(iAttacker) && (!g_bPlayerEliminated[iAttacker] || g_bPlayerProxy[iAttacker]))
+				{
+					decl String:sWeapon[64];
+					GetEventString(event, "weapon", sWeapon, sizeof(sWeapon));
+					
+					if (StrEqual(sWeapon, "demokatana"))
+					{
+						new iAttackerPreHealth = GetEntProp(iAttacker, Prop_Send, "m_iHealth");
+						new Handle:hPack = CreateDataPack();
+						WritePackCell(hPack, GetClientUserId(iAttacker));
+						WritePackCell(hPack, iAttackerPreHealth + iKatanaHealthGain);
+						
+						CreateTimer(0.0, Timer_SetPlayerHealth, hPack, TIMER_FLAG_NO_MAPCHANGE);
+					}
+				}
+			}
+		}
+		
+		g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
+	}
+	
+	PvP_OnPlayerDeath(client, bFake);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerDeath(%d)", client);
+#endif
+}
+
+public Action:Timer_SetPlayerHealth(Handle:timer, any:data)
+{
+	new Handle:hPack = Handle:data;
+	ResetPack(hPack);
+	new iAttacker = GetClientOfUserId(ReadPackCell(hPack));
+	new iHealth = ReadPackCell(hPack);
+	CloseHandle(hPack);
+	
+	if (iAttacker <= 0) return;
+	
+	SetEntProp(iAttacker, Prop_Data, "m_iHealth", iHealth);
+	SetEntProp(iAttacker, Prop_Send, "m_iHealth", iHealth);
+}
+
+public Action:Timer_PlayerSwitchToBlue(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerSwitchBlueTimer[client]) return;
+	
+	ChangeClientTeam(client, _:TFTeam_Blue);
+}
+
+public Action:Timer_RoundStart(Handle:timer)
+{
+	if (g_iPageMax > 0)
+	{
+		new Handle:hArrayClients = CreateArray();
+		new iClients[MAXPLAYERS + 1];
+		new iClientsNum = 0;
+		
+		new iGameText = GetTextEntity("sf2_intro_message", false);
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || IsFakeClient(i) || g_bPlayerEliminated[i]) continue;
+			
+			if (iGameText == -1)
+			{
+				if (g_iPageMax > 1)
+				{
+					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Plural", i, g_iPageMax);
+				}
+				else
+				{
+					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Singular", i, g_iPageMax);
+				}
+			}
+			
+			PushArrayCell(hArrayClients, GetClientUserId(i));
+			iClients[iClientsNum] = i;
+			iClientsNum++;
+		}
+		
+		// Show difficulty menu.
+		if (iClientsNum)
+		{
+			// Automatically set it to Normal.
+			SetConVarInt(g_cvDifficulty, Difficulty_Normal);
+			
+			g_hVoteTimer = CreateTimer(1.0, Timer_VoteDifficulty, hArrayClients, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			TriggerTimer(g_hVoteTimer, true);
+			
+			if (iGameText != -1)
+			{
+				decl String:sMessage[512];
+				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+				
+				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
+			}
+		}
+		else
+		{
+			CloseHandle(hArrayClients);
+		}
+	}
+}
+
+public Action:Timer_CheckRoundWinConditions(Handle:timer)
+{
+	CheckRoundWinConditions();
+}
+
+public Action:Timer_RoundGrace(Handle:timer)
+{
+	if (timer != g_hRoundGraceTimer) return;
+	
+	g_bRoundGrace = false;
+	g_hRoundGraceTimer = INVALID_HANDLE;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientParticipating(i)) g_bPlayerEliminated[i] = true;
+	}
+	
+	// Initialize the main round timer.
+	if (g_iRoundTimeLimit > 0)
+	{
+		// Set round time.
+		g_iRoundTime = g_iRoundTimeLimit;
+		g_hRoundTimer = CreateTimer(1.0, Timer_RoundTime, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	}
+	else
+	{
+		// Infinite round time.
+		g_hRoundTimer = INVALID_HANDLE;
+	}
+	
+	CPrintToChatAll("{olive}%t", "SF2 Grace Period End");
+}
+
+public Action:Timer_RoundTime(Handle:timer)
+{
+	if (timer != g_hRoundTimer) return Plugin_Stop;
+	
+	if (g_iRoundTime <= 0)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i)) continue;
+			
+			decl Float:flBuffer[3];
+			GetClientAbsOrigin(i, flBuffer);
+			SDKHooks_TakeDamage(i, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+		}
+		
+		return Plugin_Stop;
+	}
+	
+	g_iRoundTime--;
+	
+	new hours, minutes, seconds;
+	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
+	
+	SetHudTextParams(-1.0, 0.1, 
+		1.0,
+		SF2_HUD_TEXT_COLOR_R, SF2_HUD_TEXT_COLOR_G, SF2_HUD_TEXT_COLOR_B, SF2_HUD_TEXT_COLOR_A,
+		_,
+		_,
+		1.5, 1.5);
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
+		ShowSyncHudText(i, g_hRoundTimerSync, "%d/%d\n%d:%02d", g_iPageCount, g_iPageMax, minutes, seconds);
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_RoundTimeEscape(Handle:timer)
+{
+	if (timer != g_hRoundTimer) return Plugin_Stop;
+	
+	if (g_iRoundTime <= 0)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i) || DidClientEscape(i)) continue;
+			
+			decl Float:flBuffer[3];
+			GetClientAbsOrigin(i, flBuffer);
+			ClientStartDeathCam(i, 0, flBuffer);
+		}
+		
+		return Plugin_Stop;
+	}
+	
+	new hours, minutes, seconds;
+	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
+	
+	SetHudTextParams(-1.0, 0.1, 
+		1.0,
+		SF2_HUD_TEXT_COLOR_R, 
+		SF2_HUD_TEXT_COLOR_G, 
+		SF2_HUD_TEXT_COLOR_B, 
+		SF2_HUD_TEXT_COLOR_A,
+		_,
+		_,
+		1.5, 1.5);
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
+		ShowSyncHudText(i, g_hRoundTimerSync, "%T\n%d:%02d", "SF2 Default Escape Message", i, minutes, seconds);
+	}
+	
+	g_iRoundTime--;
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_VoteDifficulty(Handle:timer, any:data)
+{
+	new Handle:hArrayClients = Handle:data;
+	
+	if (timer != g_hVoteTimer || IsRoundEnding()) 
+	{
+		CloseHandle(hArrayClients);
+		return Plugin_Stop;
+	}
+	
+	if (IsVoteInProgress()) return Plugin_Continue; // There's another vote in progess. Wait.
+	
+	new iClients[MAXPLAYERS + 1] = { -1, ... };
+	new iClientsNum;
+	for (new i = 0, iSize = GetArraySize(hArrayClients); i < iSize; i++)
+	{
+		new iClient = GetClientOfUserId(GetArrayCell(hArrayClients, i));
+		if (iClient <= 0) continue;
+		
+		iClients[iClientsNum] = iClient;
+		iClientsNum++;
+	}
+	
+	CloseHandle(hArrayClients);
+	
+	VoteMenu(g_hMenuVoteDifficulty, iClients, iClientsNum, 15);
+	
+	return Plugin_Stop;
+}
+
+static InitializeMapEntities()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeMapEntities()");
+#endif
+	
+	g_bRoundInfiniteFlashlight = false;
+	g_bRoundInfiniteBlink = false;
+	g_bRoundInfiniteSprint = false;
+	g_bRoundHasEscapeObjective = false;
+	
+	g_iRoundTimeLimit = GetConVarInt(g_cvTimeLimit);
+	g_iRoundEscapeTimeLimit = GetConVarInt(g_cvTimeLimitEscape);
+	g_iRoundTimeGainFromPage = GetConVarInt(g_cvTimeGainFromPageGrab);
+	
+	// Reset page reference.
+	g_bPageRef = false;
+	strcopy(g_strPageRefModel, sizeof(g_strPageRefModel), "");
+	g_flPageRefModelScale = 1.0;
+	
+	new Handle:hArray = CreateArray(2);
+	new Handle:hPageTrie = CreateTrie();
+	
+	decl String:targetName[64];
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
+		if (targetName[0])
+		{
+			if (!StrContains(targetName, "sf2_maxpages_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_maxpages_", "", false);
+				g_iPageMax = StringToInt(targetName);
+			}
+			else if (!StrContains(targetName, "sf2_page_spawnpoint", false))
+			{
+				if (!StrContains(targetName, "sf2_page_spawnpoint_", false))
+				{
+					ReplaceString(targetName, sizeof(targetName), "sf2_page_spawnpoint_", "", false);
+					if (targetName[0])
+					{
+						new Handle:hButtStallion = INVALID_HANDLE;
+						if (!GetTrieValue(hPageTrie, targetName, hButtStallion))
+						{
+							hButtStallion = CreateArray();
+							SetTrieValue(hPageTrie, targetName, hButtStallion);
+						}
+						
+						new iIndex = FindValueInArray(hArray, hButtStallion);
+						if (iIndex == -1)
+						{
+							iIndex = PushArrayCell(hArray, hButtStallion);
+						}
+						
+						PushArrayCell(hButtStallion, ent);
+						SetArrayCell(hArray, iIndex, true, 1);
+					}
+					else
+					{
+						new iIndex = PushArrayCell(hArray, ent);
+						SetArrayCell(hArray, iIndex, false, 1);
+					}
+				}
+				else
+				{
+					new iIndex = PushArrayCell(hArray, ent);
+					SetArrayCell(hArray, iIndex, false, 1);
+				}
+			}
+			else if (!StrContains(targetName, "sf2_logic_escape", false))
+			{
+				g_bRoundHasEscapeObjective = true;
+			}
+			else if (!StrContains(targetName, "sf2_infiniteflashlight", false))
+			{
+				g_bRoundInfiniteFlashlight = true;
+			}
+			else if (!StrContains(targetName, "sf2_infiniteblink", false))
+			{
+				g_bRoundInfiniteBlink = true;
+			}
+			else if (!StrContains(targetName, "sf2_infinitesprint", false))
+			{
+				g_bRoundInfiniteSprint = true;
+			}
+			else if (!StrContains(targetName, "sf2_time_limit_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_time_limit_", "", false);
+				g_iRoundTimeLimit = StringToInt(targetName);
+				
+				LogSF2Message("Found sf2_time_limit entity, set time limit to %d", g_iRoundTimeLimit);
+			}
+			else if (!StrContains(targetName, "sf2_escape_time_limit_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_escape_time_limit_", "", false);
+				g_iRoundEscapeTimeLimit = StringToInt(targetName);
+				
+				LogSF2Message("Found sf2_escape_time_limit entity, set escape time limit to %d", g_iRoundEscapeTimeLimit);
+			}
+			else if (!StrContains(targetName, "sf2_time_gain_from_page_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_time_gain_from_page_", "", false);
+				g_iRoundTimeGainFromPage = StringToInt(targetName);
+				
+				LogSF2Message("Found sf2_time_gain_from_page entity, set time gain to %d", g_iRoundTimeGainFromPage);
+			}
+			else if (g_iRoundActiveCount == 1 && (!StrContains(targetName, "sf2_maxplayers_", false)))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_maxplayers_", "", false);
+				SetConVarInt(g_cvMaxPlayers, StringToInt(targetName));
+				
+				LogSF2Message("Found sf2_maxplayers entity, set maxplayers to %d", StringToInt(targetName));
+			}
+			else if (!StrContains(targetName, "sf2_boss_override_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_boss_override_", "", false);
+				SetConVarString(g_cvBossProfileOverride, targetName);
+				
+				LogSF2Message("Found sf2_boss_override entity, set boss profile override to %s", targetName);
+			}
+		}
+	}
+	
+	// Get a reference entity, if any.
+	
+	ent = -1;
+	while ((ent = FindEntityByClassname(ent, "prop_dynamic")) != -1)
+	{
+		if (g_bPageRef) break;
+	
+		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
+		if (targetName[0])
+		{
+			if (StrEqual(targetName, "sf2_page_model", false))
+			{
+				g_bPageRef = true;
+				GetEntPropString(ent, Prop_Data, "m_ModelName", g_strPageRefModel, sizeof(g_strPageRefModel));
+				g_flPageRefModelScale = 1.0;
+			}
+		}
+	}
+	
+	new iPageCount = GetArraySize(hArray);
+	if (iPageCount)
+	{
+		SortADTArray(hArray, Sort_Random, Sort_Integer);
+		
+		decl Float:vecPos[3], Float:vecAng[3], Float:vecDir[3];
+		decl page;
+		ent = -1;
+		
+		for (new i = 0; i < iPageCount && (i + 1) <= g_iPageMax; i++)
+		{
+			if (bool:GetArrayCell(hArray, i, 1))
+			{
+				new Handle:hButtStallion = Handle:GetArrayCell(hArray, i);
+				ent = GetArrayCell(hButtStallion, GetRandomInt(0, GetArraySize(hButtStallion) - 1));
+			}
+			else
+			{
+				ent = GetArrayCell(hArray, i);
+			}
+			
+			GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", vecPos);
+			GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", vecAng);
+			GetAngleVectors(vecAng, vecDir, NULL_VECTOR, NULL_VECTOR);
+			NormalizeVector(vecDir, vecDir);
+			ScaleVector(vecDir, 1.0);
+			
+			page = CreateEntityByName("prop_dynamic_override");
+			if (page != -1)
+			{
+				TeleportEntity(page, vecPos, vecAng, NULL_VECTOR);
+				DispatchKeyValue(page, "targetname", "sf2_page");
+				
+				if (g_bPageRef)
+				{
+					SetEntityModel(page, g_strPageRefModel);
+				}
+				else
+				{
+					SetEntityModel(page, PAGE_MODEL);
+				}
+				
+				DispatchKeyValue(page, "solid", "2");
+				DispatchSpawn(page);
+				ActivateEntity(page);
+				SetVariantInt(i);
+				AcceptEntityInput(page, "Skin");
+				AcceptEntityInput(page, "EnableCollision");
+				
+				if (g_bPageRef)
+				{
+					SetEntPropFloat(page, Prop_Send, "m_flModelScale", g_flPageRefModelScale);
+				}
+				else
+				{
+					SetEntPropFloat(page, Prop_Send, "m_flModelScale", PAGE_MODELSCALE);
+				}
+				
+				SDKHook(page, SDKHook_OnTakeDamage, Hook_PageOnTakeDamage);
+				SDKHook(page, SDKHook_SetTransmit, Hook_SlenderObjectSetTransmit);
+			}
+		}
+		
+		// Safely remove all handles.
+		for (new i = 0, iSize = GetArraySize(hArray); i < iSize; i++)
+		{
+			if (bool:GetArrayCell(hArray, i, 1))
+			{
+				CloseHandle(Handle:GetArrayCell(hArray, i));
+			}
+		}
+	
+		Call_StartForward(fOnPagesSpawned);
+		Call_Finish();
+	}
+	
+	CloseHandle(hPageTrie);
+	CloseHandle(hArray);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeMapEntities()");
+#endif
+}
+
+static HandleSpecialRoundState()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleSpecialRoundState()");
+#endif
+	
+	new bool:bOld = g_bSpecialRound;
+	new bool:bContinuousOld = g_bSpecialRoundContinuous;
+	g_bSpecialRound = false;
+	g_bSpecialRoundNew = false;
+	g_bSpecialRoundContinuous = false;
+	
+	new bool:bForceNew = false;
+	
+	if (bOld)
+	{
+		if (bContinuousOld)
+		{
+			// Check if there are players who haven't played the special round yet.
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || !IsClientParticipating(i))
+				{
+					g_bPlayerPlayedSpecialRound[i] = true;
+					continue;
+				}
+				
+				if (!g_bPlayerPlayedSpecialRound[i])
+				{
+					// Someone didn't get to play this yet. Continue the special round.
+					g_bSpecialRound = true;
+					g_bSpecialRoundContinuous = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	new iRoundInterval = GetConVarInt(g_cvSpecialRoundInterval);
+	
+	if (iRoundInterval > 0 && g_iSpecialRoundCount >= iRoundInterval)
+	{
+		g_bSpecialRound = true;
+		bForceNew = true;
+	}
+	
+	// Do special round force override and reset it.
+	if (GetConVarInt(g_cvSpecialRoundForce) >= 0)
+	{
+		g_bSpecialRound = GetConVarBool(g_cvSpecialRoundForce);
+		SetConVarInt(g_cvSpecialRoundForce, -1);
+	}
+	
+	if (g_bSpecialRound)
+	{
+		if (bForceNew || !bOld || !bContinuousOld)
+		{
+			g_bSpecialRoundNew = true;
+		}
+		
+		if (g_bSpecialRoundNew)
+		{
+			if (GetConVarInt(g_cvSpecialRoundBehavior) == 1)
+			{
+				g_bSpecialRoundContinuous = true;
+			}
+			else
+			{
+				// New special round, but it's not continuous.
+				g_bSpecialRoundContinuous = false;
+			}
+		}
+	}
+	else
+	{
+		g_bSpecialRoundContinuous = false;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleSpecialRoundState() -> g_bSpecialRound = %d (count = %d, new = %d, continuous = %d)", g_bSpecialRound, g_iSpecialRoundCount, g_bSpecialRoundNew, g_bSpecialRoundContinuous);
+#endif
+}
+
+bool:IsNewBossRoundRunning()
+{
+	return g_bNewBossRound;
+}
+
+/**
+ *	Returns an array which contains all the profile names valid to be chosen for a new boss round.
+ */
+static Handle:GetNewBossRoundProfileList()
+{
+	new Handle:hBossList = CloneArray(GetSelectableBossProfileList());
+	
+	if (GetArraySize(hBossList) > 0)
+	{
+		decl String:sMainBoss[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetConVarString(g_cvBossMain, sMainBoss, sizeof(sMainBoss));
+		
+		new index = FindStringInArray(hBossList, sMainBoss);
+		if (index != -1)
+		{
+			// Main boss exists; remove him from the list.
+			RemoveFromArray(hBossList, index);
+		}
+		else
+		{
+			// Main boss doesn't exist; remove the first boss from the list.
+			RemoveFromArray(hBossList, 0);
+		}
+	}
+	
+	return hBossList;
+}
+
+static HandleNewBossRoundState()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleNewBossRoundState()");
+#endif
+	
+	new bool:bOld = g_bNewBossRound;
+	new bool:bContinuousOld = g_bNewBossRoundContinuous;
+	g_bNewBossRound = false;
+	g_bNewBossRoundNew = false;
+	g_bNewBossRoundContinuous = false;
+	
+	new bool:bForceNew = false;
+	
+	if (bOld)
+	{
+		if (bContinuousOld)
+		{
+			// Check if there are players who haven't played the boss round yet.
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || !IsClientParticipating(i))
+				{
+					g_bPlayerPlayedNewBossRound[i] = true;
+					continue;
+				}
+				
+				if (!g_bPlayerPlayedNewBossRound[i])
+				{
+					// Someone didn't get to play this yet. Continue the boss round.
+					g_bNewBossRound = true;
+					g_bNewBossRoundContinuous = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	// Don't force a new special round while a continuous round is going on.
+	if (!g_bNewBossRoundContinuous)
+	{
+		new iRoundInterval = GetConVarInt(g_cvNewBossRoundInterval);
+		
+		if (/*iRoundInterval > 0 &&*/ iRoundInterval <= 0 || g_iNewBossRoundCount >= iRoundInterval)
+		{
+			g_bNewBossRound = true;
+			bForceNew = true;
+		}
+	}
+	
+	// Do boss round force override and reset it.
+	if (GetConVarInt(g_cvNewBossRoundForce) >= 0)
+	{
+		g_bNewBossRound = GetConVarBool(g_cvNewBossRoundForce);
+		SetConVarInt(g_cvNewBossRoundForce, -1);
+	}
+	
+	// Check if we have enough bosses.
+	if (g_bNewBossRound)
+	{
+		new Handle:hBossList = GetNewBossRoundProfileList();
+	
+		if (GetArraySize(hBossList) < 1)
+		{
+			g_bNewBossRound = false; // Not enough bosses.
+		}
+		
+		CloseHandle(hBossList);
+	}
+	
+	if (g_bNewBossRound)
+	{
+		if (bForceNew || !bOld || !bContinuousOld)
+		{
+			g_bNewBossRoundNew = true;
+		}
+		
+		if (g_bNewBossRoundNew)
+		{
+			if (GetConVarInt(g_cvNewBossRoundBehavior) == 1)
+			{
+				g_bNewBossRoundContinuous = true;
+			}
+			else
+			{
+				// New "new boss round", but it's not continuous.
+				g_bNewBossRoundContinuous = false;
+			}
+		}
+	}
+	else
+	{
+		g_bNewBossRoundContinuous = false;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleNewBossRoundState() -> g_bNewBossRound = %d (count = %d, new = %d, continuous = %d)", g_bNewBossRound, g_iNewBossRoundCount, g_bNewBossRoundNew, g_bNewBossRoundContinuous);
+#endif
+}
+
+/**
+ *	Returns the amount of players that are in game and currently not eliminated.
+ */
+GetActivePlayerCount()
+{
+	new count = 0;
+
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || !IsClientParticipating(i)) continue;
+		
+		if (!g_bPlayerEliminated[i])
+		{
+			count++;
+		}
+	}
+	
+	return count;
+}
+
+static SelectStartingBossesForRound()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START SelectStartingBossesForRound()");
+#endif
+
+	new Handle:hSelectableBossList = GetSelectableBossProfileList();
+
+	// Select which boss profile to use.
+	decl String:sProfileOverride[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetConVarString(g_cvBossProfileOverride, sProfileOverride, sizeof(sProfileOverride));
+	
+	if (strlen(sProfileOverride) > 0 && IsProfileValid(sProfileOverride))
+	{
+		// Pick the overridden boss.
+		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfileOverride);
+		SetConVarString(g_cvBossProfileOverride, "");
+	}
+	else if (g_bNewBossRound)
+	{
+		if (g_bNewBossRoundNew)
+		{
+			new Handle:hBossList = GetNewBossRoundProfileList();
+		
+			GetArrayString(hBossList, GetRandomInt(0, GetArraySize(hBossList) - 1), g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile));
+		
+			CloseHandle(hBossList);
+		}
+		
+		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), g_strNewBossRoundProfile);
+	}
+	else
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetConVarString(g_cvBossMain, sProfile, sizeof(sProfile));
+		
+		if (strlen(sProfile) > 0 && IsProfileValid(sProfile))
+		{
+			strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfile);
+		}
+		else
+		{
+			if (GetArraySize(hSelectableBossList) > 0)
+			{
+				// Pick the first boss in our array if the main boss doesn't exist.
+				GetArrayString(hSelectableBossList, 0, g_strRoundBossProfile, sizeof(g_strRoundBossProfile));
+			}
+			else
+			{
+				// No bosses to pick. What?
+				strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), "");
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END SelectStartingBossesForRound() -> boss: %s", g_strRoundBossProfile);
+#endif
+}
+
+static GetRoundIntroParameters()
+{
+	g_iRoundIntroFadeColor[0] = 0;
+	g_iRoundIntroFadeColor[1] = 0;
+	g_iRoundIntroFadeColor[2] = 0;
+	g_iRoundIntroFadeColor[3] = 255;
+	
+	g_flRoundIntroFadeHoldTime = GetConVarFloat(g_cvIntroDefaultHoldTime);
+	g_flRoundIntroFadeDuration = GetConVarFloat(g_cvIntroDefaultFadeTime);
+	
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "env_fade")) != -1)
+	{
+		decl String:sName[32];
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		if (StrEqual(sName, "sf2_intro_fade", false))
+		{
+			new iColorOffset = FindSendPropOffs("CBaseEntity", "m_clrRender");
+			if (iColorOffset != -1)
+			{
+				g_iRoundIntroFadeColor[0] = GetEntData(ent, iColorOffset, 1);
+				g_iRoundIntroFadeColor[1] = GetEntData(ent, iColorOffset + 1, 1);
+				g_iRoundIntroFadeColor[2] = GetEntData(ent, iColorOffset + 2, 1);
+				g_iRoundIntroFadeColor[3] = GetEntData(ent, iColorOffset + 3, 1);
+			}
+			
+			g_flRoundIntroFadeHoldTime = GetEntPropFloat(ent, Prop_Data, "m_HoldTime");
+			g_flRoundIntroFadeDuration = GetEntPropFloat(ent, Prop_Data, "m_Duration");
+			
+			break;
+		}
+	}
+	
+	// Get the intro music.
+	strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), SF2_INTRO_DEFAULT_MUSIC);
+	
+	ent = -1;
+	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
+	{
+		decl String:sName[64];
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		
+		if (StrEqual(sName, "sf2_intro_music", false))
+		{
+			decl String:sSongPath[PLATFORM_MAX_PATH];
+			GetEntPropString(ent, Prop_Data, "m_iszSound", sSongPath, sizeof(sSongPath));
+			
+			if (strlen(sSongPath) == 0)
+			{
+				LogError("Found sf2_intro_music entity, but it has no sound path specified! Default intro music will be used instead.");
+			}
+			else
+			{
+				strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), sSongPath);
+			}
+			
+			break;
+		}
+	}
+}
+
+static GetRoundEscapeParameters()
+{
+	g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
+	
+	decl String:sName[64];
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		if (!StrContains(sName, "sf2_escape_spawnpoint", false))
+		{
+			g_iRoundEscapePointEntity = EntIndexToEntRef(ent);
+			break;
+		}
+	}
+}
+
+InitializeNewGame()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeNewGame()");
+#endif
+	
+	GetRoundIntroParameters();
+	GetRoundEscapeParameters();
+	
+	// Choose round state.
+	if (GetConVarBool(g_cvIntroEnabled))
+	{
+		// Set the round state to the intro stage.
+		SetRoundState(SF2RoundState_Intro);
+	}
+	else
+	{
+		SetRoundState(SF2RoundState_Active);
+	}
+	
+	if (g_iRoundActiveCount == 1)
+	{
+		SetConVarString(g_cvBossProfileOverride, "");
+	}
+	
+	HandleSpecialRoundState();
+	
+	// Was a new special round initialized?
+	if (g_bSpecialRound)
+	{
+		if (g_bSpecialRoundNew)
+		{
+			// Reset round count.
+			g_iSpecialRoundCount = 1;
+			
+			if (g_bSpecialRoundContinuous)
+			{
+				// It's the start of a continuous special round.
+			
+				// Initialize all players' values.
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || !IsClientParticipating(i))
+					{
+						g_bPlayerPlayedSpecialRound[i] = true;
+						continue;
+					}
+					
+					g_bPlayerPlayedSpecialRound[i] = false;
+				}
+			}
+			
+			SpecialRoundCycleStart();
+		}
+		else
+		{
+			SpecialRoundStart();
+			
+			if (g_bSpecialRoundContinuous)
+			{
+				// Display the current special round going on to late players.
+				CreateTimer(3.0, Timer_DisplaySpecialRound, _, TIMER_FLAG_NO_MAPCHANGE);
+			}
+		}
+	}
+	else
+	{
+		g_iSpecialRoundCount++;
+	
+		SpecialRoundReset();
+	}
+	
+	// Determine boss round state.
+	HandleNewBossRoundState();
+	
+	if (g_bNewBossRound)
+	{
+		if (g_bNewBossRoundNew)
+		{
+			// Reset round count;
+			g_iNewBossRoundCount = 1;
+			
+			if (g_bNewBossRoundContinuous)
+			{
+				// It's the start of a continuous "new boss round".
+			
+				// Initialize all players' values.
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || !IsClientParticipating(i))
+					{
+						g_bPlayerPlayedNewBossRound[i] = true;
+						continue;
+					}
+					
+					g_bPlayerPlayedNewBossRound[i] = false;
+				}
+			}
+		}
+	}
+	else
+	{
+		g_iNewBossRoundCount++;
+	}
+	
+	InitializeMapEntities();
+	
+	// Initialize pages and entities.
+	GetPageMusicRanges();
+	
+	SelectStartingBossesForRound();
+	
+	ForceInNextPlayersInQueue(GetMaxPlayersForRound());
+	
+	// Respawn all players, if needed.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+			if (IsClientParticipating(i))
+			{
+				if (!HandlePlayerTeam(i))
+				{
+				if (!g_bPlayerEliminated[i])
+				{
+					// Players currently in the "game" still have to be respawned.
+					TF2_RespawnPlayer(i);
+				}
+			}
+		}
+	}
+	
+	if (GetRoundState() == SF2RoundState_Intro)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i)) continue;
+			
+			if (!g_bPlayerEliminated[i])
+			{
+				if (!IsFakeClient(i))
+				{
+					// Currently in intro state, play intro music.
+					g_hPlayerIntroMusicTimer[i] = CreateTimer(0.5, Timer_PlayIntroMusicToPlayer, GetClientUserId(i), TIMER_FLAG_NO_MAPCHANGE);
+				}
+				else
+				{
+					g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
+				}
+			}
+			else
+			{
+				g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
+			}
+		}
+	}
+	else
+	{
+		// Spawn the boss!
+		SelectProfile(0, g_strRoundBossProfile);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeNewGame()");
+#endif
+}
+
+public Action:Timer_PlayIntroMusicToPlayer(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerIntroMusicTimer[client]) return;
+	
+	g_hPlayerIntroMusicTimer[client] = INVALID_HANDLE;
+	
+	EmitSoundToClient(client, g_strRoundIntroMusic, _, MUSIC_CHAN, SNDLEVEL_NONE);
+}
+
+public Action:Timer_IntroTextSequence(Handle:timer)
+{
+	if (!g_bEnabled) return;
+	if (g_hRoundIntroTextTimer != timer) return;
+	
+	new Float:flDuration = 0.0;
+	
+	if (g_iRoundIntroText != 0)
+	{
+		new bool:bFoundGameText = false;
+		
+		new iClients[MAXPLAYERS + 1];
+		new iClientsNum;
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
+			
+			iClients[iClientsNum] = i;
+			iClientsNum++;
+		}
+		
+		if (!g_bRoundIntroTextDefault)
+		{
+			decl String:sTargetname[64];
+			Format(sTargetname, sizeof(sTargetname), "sf2_intro_text_%d", g_iRoundIntroText);
+		
+			new iGameText = FindEntityByTargetname(sTargetname, "game_text");
+			if (iGameText && iGameText != INVALID_ENT_REFERENCE)
+			{
+				bFoundGameText = true;
+				flDuration = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
+				
+				decl String:sMessage[512];
+				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
+			}
+		}
+		else
+		{
+			if (g_iRoundIntroText == 2)
+			{
+				bFoundGameText = false;
+				
+				decl String:sMessage[64];
+				GetCurrentMap(sMessage, sizeof(sMessage));
+				
+				for (new i = 0; i < iClientsNum; i++)
+				{
+					ClientShowMainMessage(iClients[i], sMessage, 1);
+				}
+			}
+		}
+		
+		if (g_iRoundIntroText == 1 && !bFoundGameText)
+		{
+			// Use default intro sequence. Eugh.
+			g_bRoundIntroTextDefault = true;
+			flDuration = GetConVarFloat(g_cvIntroDefaultHoldTime) / 2.0;
+			
+			for (new i = 0; i < iClientsNum; i++)
+			{
+				EmitSoundToClient(iClients[i], SF2_INTRO_DEFAULT_MUSIC, _, MUSIC_CHAN, SNDLEVEL_NONE);
+			}
+		}
+		else
+		{
+			if (!bFoundGameText) return; // done with sequence; don't check anymore.
+		}
+	}
+	
+	g_iRoundIntroText++;
+	g_hRoundIntroTextTimer = CreateTimer(flDuration, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_ActivateRoundFromIntro(Handle:timer)
+{
+	if (!g_bEnabled) return;
+	if (g_hRoundIntroTimer != timer) return;
+	
+	// Obviously we don't want to spawn the boss when g_strRoundBossProfile isn't set yet.
+	SetRoundState(SF2RoundState_Active);
+	
+	// Spawn the boss!
+	SelectProfile(0, g_strRoundBossProfile);
+}
+
+CheckRoundWinConditions()
+{
+	if (IsRoundInWarmup() || IsRoundEnding()) return;
+	
+	new iTotalCount = 0;
+	new iAliveCount = 0;
+	new iEscapedCount = 0;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		iTotalCount++;
+		if (!g_bPlayerEliminated[i] && !IsClientInDeathCam(i)) 
+		{
+			iAliveCount++;
+			if (DidClientEscape(i)) iEscapedCount++;
+		}
+	}
+	
+	if (iAliveCount == 0)
+	{
+		ForceTeamWin(_:TFTeam_Blue);
+	}
+	else
+	{
+		if (g_bRoundHasEscapeObjective)
+		{
+			if (iEscapedCount == iAliveCount)
+			{
+				ForceTeamWin(_:TFTeam_Red);
+			}
+		}
+		else
+		{
+			if (g_iPageMax > 0 && g_iPageCount == g_iPageMax)
+			{
+				ForceTeamWin(_:TFTeam_Red);
+			}
+		}
+	}
+}
+
+//	==========================================================
+//	API
+//	==========================================================
+
+public Native_IsRunning(Handle:plugin, numParams)
+{
+	return g_bEnabled;
+}
+
+public Native_GetCurrentDifficulty(Handle:plugin, numParams)
+{
+	return GetConVarInt(g_cvDifficulty);
+}
+
+public Native_GetDifficultyModifier(Handle:plugin, numParams)
+{
+	new iDifficulty = GetNativeCell(1);
+	if (iDifficulty < Difficulty_Easy || iDifficulty >= Difficulty_Max)
+	{
+		LogError("Difficulty parameter can only be from %d to %d!", Difficulty_Easy, Difficulty_Max - 1);
+		return _:1.0;
+	}
+	
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return _:DIFFICULTY_EASY;
+		case Difficulty_Hard: return _:DIFFICULTY_HARD;
+		case Difficulty_Insane: return _:DIFFICULTY_INSANE;
+	}
+	
+	return _:DIFFICULTY_NORMAL;
+}
+
+public Native_IsClientEliminated(Handle:plugin, numParams)
+{
+	return g_bPlayerEliminated[GetNativeCell(1)];
+}
+
+public Native_IsClientInGhostMode(Handle:plugin, numParams)
+{
+	return IsClientInGhostMode(GetNativeCell(1));
+}
+
+public Native_IsClientProxy(Handle:plugin, numParams)
+{
+	return g_bPlayerProxy[GetNativeCell(1)];
+}
+
+public Native_GetClientBlinkCount(Handle:plugin, numParams)
+{
+	return ClientGetBlinkCount(GetNativeCell(1));
+}
+
+public Native_GetClientProxyMaster(Handle:plugin, numParams)
+{
+	return NPCGetFromUniqueID(g_iPlayerProxyMaster[GetNativeCell(1)]);
+}
+
+public Native_GetClientProxyControlAmount(Handle:plugin, numParams)
+{
+	return g_iPlayerProxyControl[GetNativeCell(1)];
+}
+
+public Native_GetClientProxyControlRate(Handle:plugin, numParams)
+{
+	return _:g_flPlayerProxyControlRate[GetNativeCell(1)];
+}
+
+public Native_SetClientProxyMaster(Handle:plugin, numParams)
+{
+	g_iPlayerProxyMaster[GetNativeCell(1)] = NPCGetUniqueID(GetNativeCell(2));
+}
+
+public Native_SetClientProxyControlAmount(Handle:plugin, numParams)
+{
+	g_iPlayerProxyControl[GetNativeCell(1)] = GetNativeCell(2);
+}
+
+public Native_SetClientProxyControlRate(Handle:plugin, numParams)
+{
+	g_flPlayerProxyControlRate[GetNativeCell(1)] = Float:GetNativeCell(2);
+}
+
+public Native_IsClientLookingAtBoss(Handle:plugin, numParams)
+{
+	return g_bPlayerSeesSlender[GetNativeCell(1)][GetNativeCell(2)];
+}
+
+public Native_CollectAsPage(Handle:plugin, numParams)
+{
+	CollectPage(GetNativeCell(1), GetNativeCell(2));
+}
+
+public Native_GetMaxBosses(Handle:plugin, numParams)
+{
+	return MAX_BOSSES;
+}
+
+public Native_EntIndexToBossIndex(Handle:plugin, numParams)
+{
+	return NPCGetFromEntIndex(GetNativeCell(1));
+}
+
+public Native_BossIndexToEntIndex(Handle:plugin, numParams)
+{
+	return NPCGetEntIndex(GetNativeCell(1));
+}
+
+public Native_BossIDToBossIndex(Handle:plugin, numParams)
+{
+	return NPCGetFromUniqueID(GetNativeCell(1));
+}
+
+public Native_BossIndexToBossID(Handle:plugin, numParams)
+{
+	return NPCGetUniqueID(GetNativeCell(1));
+}
+
+public Native_GetBossName(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(GetNativeCell(1), sProfile, sizeof(sProfile));
+	
+	SetNativeString(2, sProfile, GetNativeCell(3));
+}
+
+public Native_GetBossModelEntity(Handle:plugin, numParams)
+{
+	return EntRefToEntIndex(g_iSlenderModel[GetNativeCell(1)]);
+}
+
+public Native_GetBossTarget(Handle:plugin, numParams)
+{
+	return EntRefToEntIndex(g_iSlenderTarget[GetNativeCell(1)]);
+}
+
+public Native_GetBossMaster(Handle:plugin, numParams)
+{
+	return g_iSlenderCopyMaster[GetNativeCell(1)];
+}
+
+public Native_GetBossState(Handle:plugin, numParams)
+{
+	return g_iSlenderState[GetNativeCell(1)];
+}
+
+public Native_IsBossProfileValid(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+	
+	return IsProfileValid(sProfile);
+}
+
+public Native_GetBossProfileNum(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+	
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	return GetProfileNum(sProfile, sKeyValue, GetNativeCell(3));
+}
+
+public Native_GetBossProfileFloat(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	return _:GetProfileFloat(sProfile, sKeyValue, Float:GetNativeCell(3));
+}
+
+public Native_GetBossProfileString(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	new iResultLen = GetNativeCell(4);
+	decl String:sResult[iResultLen];
+	
+	decl String:sDefaultValue[512];
+	GetNativeString(5, sDefaultValue, sizeof(sDefaultValue));
+	
+	new bool:bSuccess = GetProfileString(sProfile, sKeyValue, sResult, iResultLen, sDefaultValue);
+	
+	SetNativeString(3, sResult, iResultLen);
+	return bSuccess;
+}
+
+public Native_GetBossProfileVector(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	decl Float:flResult[3];
+	decl Float:flDefaultValue[3];
+	GetNativeArray(4, flDefaultValue, 3);
+	
+	new bool:bSuccess = GetProfileVector(sProfile, sKeyValue, flResult, flDefaultValue);
+	
+	SetNativeArray(3, flResult, 3);
+	return bSuccess;
+}
+
+public Native_GetRandomStringFromBossProfile(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	new iBufferLen = GetNativeCell(4);
+	decl String:sBuffer[iBufferLen];
+	
+	new iIndex = GetNativeCell(5);
+	
+	new bool:bSuccess = GetRandomStringFromProfile(sProfile, sKeyValue, sBuffer, iBufferLen, iIndex);
+	SetNativeString(3, sBuffer, iBufferLen);
+	return bSuccess;
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/adminmenu.sp b/addons/sourcemod/scripting/rytp_horror/adminmenu.sp
index f40582c..3b21732 100644
--- a/addons/sourcemod/scripting/rytp_horror/adminmenu.sp
+++ b/addons/sourcemod/scripting/rytp_horror/adminmenu.sp
@@ -1,911 +1,911 @@
-#if defined _sf2_adminmenu_included
- #endinput
-#endif
-#define _sf2_adminmenu_included
-
-static Handle:g_hTopMenu = INVALID_HANDLE;
-static g_iPlayerAdminMenuTargetUserId[MAXPLAYERS + 1] = { -1, ... };
-
-SetupAdminMenu()
-{
-	/* Account for late loading */
-	new Handle:hTopMenu = INVALID_HANDLE;
-	if (LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
-	{
-		OnAdminMenuReady(hTopMenu);
-	}
-}
-
-
-public OnAdminMenuReady(Handle:hTopMenu)
-{
-	if (hTopMenu == g_hTopMenu) return;
-	
-	g_hTopMenu = hTopMenu;
-	
-	new TopMenuObject:hServerCommands = FindTopMenuCategory(hTopMenu, ADMINMENU_SERVERCOMMANDS);
-	if (hServerCommands != INVALID_TOPMENUOBJECT)
-	{
-		AddToTopMenu(hTopMenu, "sf2_boss_admin_main", TopMenuObject_Item, AdminTopMenu_BossMain, hServerCommands, "sm_sf2_add_boss", ADMFLAG_SLAY);
-	}
-	
-	new TopMenuObject:hPlayerCommands = FindTopMenuCategory(hTopMenu, ADMINMENU_PLAYERCOMMANDS);
-	if (hPlayerCommands != INVALID_TOPMENUOBJECT)
-	{
-		AddToTopMenu(hTopMenu, "sf2_player_setplaystate", TopMenuObject_Item, AdminTopMenu_PlayerSetPlayState, hPlayerCommands, "sm_sf2_setplaystate", ADMFLAG_SLAY);
-		AddToTopMenu(hTopMenu, "sf2_player_force_proxy", TopMenuObject_Item, AdminTopMenu_PlayerForceProxy, hPlayerCommands, "sm_sf2_force_proxy", ADMFLAG_SLAY);
-	}
-}
-
-static DisplayPlayerForceProxyAdminMenu(client)
-{
-	new Handle:hMenu = CreateMenu(AdminMenu_PlayerForceProxy);
-	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Force Proxy", client);
-	AddTargetsToMenu(hMenu, client);
-	SetMenuExitBackButton(hMenu, true);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public AdminTopMenu_PlayerForceProxy(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
-{
-	if (action == TopMenuAction_DisplayOption)
-	{
-		Format(buffer, maxlength, "%t%T", "SF2 Prefix", "SF2 Admin Menu Player Force Proxy", param);
-	}
-	else if (action == TopMenuAction_SelectOption)
-	{
-		DisplayPlayerForceProxyAdminMenu(param);
-	}
-}
-
-public AdminMenu_PlayerForceProxy(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE)
-		{
-			DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sUserId[64];
-		GetMenuItem(menu, param2, sUserId, sizeof(sUserId));
-		
-		new client = GetClientOfUserId(StringToInt(sUserId));
-		if (client <= 0)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
-			DisplayPlayerForceProxyAdminMenu(param1);
-		}
-		else
-		{
-			g_iPlayerAdminMenuTargetUserId[param1] = StringToInt(sUserId);
-		
-			decl String:sName[MAX_NAME_LENGTH];
-			GetClientName(client, sName, sizeof(sName));
-			
-			new Handle:hMenu = CreateMenu(AdminMenu_PlayerForceProxyBoss);
-			if (!AddBossTargetsToMenu(hMenu))
-			{
-				CloseHandle(hMenu);
-				DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
-				CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", param1);
-			}
-			else
-			{
-				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Force Proxy Boss", param1, sName);
-				SetMenuExitBackButton(hMenu, true);
-				DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
-			}
-		}
-	}
-}
-
-public AdminMenu_PlayerForceProxyBoss(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayPlayerForceProxyAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		new client = GetClientOfUserId(g_iPlayerAdminMenuTargetUserId[param1]);
-		if (client <= 0)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
-		}
-		else
-		{
-			decl String:sID[64];
-			GetMenuItem(menu, param2, sID, sizeof(sID));
-			new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-			if (iIndex == -1)
-			{
-				CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-			}
-			else
-			{
-				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-				NPCGetProfile(iIndex, sProfile, sizeof(sProfile));
-			
-				if (!bool:GetProfileNum(sProfile, "proxies", 0) ||
-					g_iSlenderCopyMaster[iIndex] != -1)
-				{
-					CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Not Allowed To Have Proxies", param1);
-				}
-				else if (!g_bPlayerEliminated[client])
-				{
-					CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player In Game", param1);
-				}
-				else if (g_bPlayerProxy[param1])
-				{
-					CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Already A Proxy", param1);
-				}
-				else
-				{
-					FakeClientCommand(param1, "sm_sf2_force_proxy #%d %d", g_iPlayerAdminMenuTargetUserId[param1], iIndex);
-				}
-			}
-		}
-		
-		DisplayPlayerForceProxyAdminMenu(param1);
-	}
-}
-
-static DisplayPlayerSetPlayStateAdminMenu(client)
-{
-	new Handle:hMenu = CreateMenu(AdminMenu_PlayerSetPlayState);
-	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Set Play State", client);
-	AddTargetsToMenu(hMenu, client);
-	SetMenuExitBackButton(hMenu, true);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public AdminTopMenu_PlayerSetPlayState(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
-{
-	if (action == TopMenuAction_DisplayOption)
-	{
-		Format(buffer, maxlength, "%t%T", "SF2 Prefix", "SF2 Admin Menu Player Set Play State", param);
-	}
-	else if (action == TopMenuAction_SelectOption)
-	{
-		DisplayPlayerSetPlayStateAdminMenu(param);
-	}
-}
-
-public AdminMenu_PlayerSetPlayState(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE)
-		{
-			DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sUserId[64];
-		GetMenuItem(menu, param2, sUserId, sizeof(sUserId));
-		new client = GetClientOfUserId(StringToInt(sUserId));
-		if (client <= 0)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
-			DisplayPlayerSetPlayStateAdminMenu(param1);
-		}
-		else
-		{
-			decl String:sName[MAX_NAME_LENGTH];
-			GetClientName(client, sName, sizeof(sName));
-			
-			new Handle:hMenu = CreateMenu(AdminMenu_PlayerSetPlayStateConfirm);
-			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Set Play State Confirm", param1, sName);
-			decl String:sBuffer[256];
-			Format(sBuffer, sizeof(sBuffer), "%T", "SF2 In", param1);
-			AddMenuItem(hMenu, sUserId, sBuffer);
-			Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Out", param1);
-			AddMenuItem(hMenu, sUserId, sBuffer);
-			SetMenuExitBackButton(hMenu, true);
-			DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
-		}
-	}
-}
-
-public AdminMenu_PlayerSetPlayStateConfirm(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayPlayerSetPlayStateAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sUserId[64];
-		GetMenuItem(menu, param2, sUserId, sizeof(sUserId));
-		new client = GetClientOfUserId(StringToInt(sUserId));
-		if (client <= 0)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
-		}
-		else
-		{
-			new iUserId = StringToInt(sUserId);
-			switch (param2)
-			{
-				case 0: FakeClientCommand(param1, "sm_sf2_setplaystate #%d 1", iUserId);
-				case 1: FakeClientCommand(param1, "sm_sf2_setplaystate #%d 0", iUserId);
-			}
-		}
-		
-		DisplayPlayerSetPlayStateAdminMenu(param1);
-	}
-}
-
-static DisplayBossMainAdminMenu(client)
-{
-	new Handle:hMenu = CreateMenu(AdminMenu_BossMain);
-	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Main", client);
-	
-	decl String:sBuffer[512];
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Add Boss", client);
-	AddMenuItem(hMenu, "add_boss", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Add Fake Boss", client);
-	AddMenuItem(hMenu, "add_boss_fake", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Remove Boss", client);
-	AddMenuItem(hMenu, "remove_boss", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Spawn Boss", client);
-	AddMenuItem(hMenu, "spawn_boss", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Boss Attack Waiters", client);
-	AddMenuItem(hMenu, "boss_attack_waiters", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Boss Teleport", client);
-	AddMenuItem(hMenu, "boss_no_teleport", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Override Boss", client);
-	AddMenuItem(hMenu, "override_boss", sBuffer);
-	
-	
-	SetMenuExitBackButton(hMenu, true);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public AdminMenu_BossMain(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE)
-		{
-			DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sInfo[64];
-		GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
-		if (StrEqual(sInfo, "add_boss"))
-		{
-			DisplayAddBossAdminMenu(param1);
-		}
-		else if (StrEqual(sInfo, "add_boss_fake"))
-		{
-			DisplayAddFakeBossAdminMenu(param1);
-		}
-		else if (StrEqual(sInfo, "remove_boss"))
-		{
-			DisplayRemoveBossAdminMenu(param1);
-		}
-		else if (StrEqual(sInfo, "spawn_boss"))
-		{
-			DisplaySpawnBossAdminMenu(param1);
-		}
-		else if (StrEqual(sInfo, "boss_attack_waiters"))
-		{
-			DisplayBossAttackWaitersAdminMenu(param1);
-		}
-		else if (StrEqual(sInfo, "boss_no_teleport"))
-		{
-			DisplayBossTeleportAdminMenu(param1);
-		}
-		else if (StrEqual(sInfo, "override_boss"))
-		{
-			DisplayOverrideBossAdminMenu(param1);
-		}
-	}
-}
-
-public AdminTopMenu_BossMain(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
-{
-	if (action == TopMenuAction_DisplayOption)
-	{
-		Format(buffer, maxlength, "%t%T", "SF2 Prefix", "SF2 Admin Menu Boss Main", param);
-	}
-	else if (action == TopMenuAction_SelectOption)
-	{
-		DisplayBossMainAdminMenu(param);
-	}
-}
-
-static bool:DisplayAddBossAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_AddBoss);
-			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Add Boss", client);
-			
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			decl String:sDisplayName[SF2_MAX_NAME_LENGTH];
-			
-			do
-			{
-				KvGetSectionName(g_hConfig, sProfile, sizeof(sProfile));
-				KvGetString(g_hConfig, "name", sDisplayName, sizeof(sDisplayName));
-				if (!sDisplayName[0]) strcopy(sDisplayName, sizeof(sDisplayName), sProfile);
-				AddMenuItem(hMenu, sProfile, sDisplayName);
-			}
-			while (KvGotoNextKey(g_hConfig));
-			
-			SetMenuExitBackButton(hMenu, true);
-			
-			DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-			
-			return true;
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_AddBoss(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetMenuItem(menu, param2, sProfile, sizeof(sProfile));
-		
-		FakeClientCommand(param1, "sm_sf2_add_boss %s", sProfile);
-		
-		DisplayAddBossAdminMenu(param1);
-	}
-}
-
-static bool:DisplayAddFakeBossAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_AddFakeBoss);
-			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Add Fake Boss", client);
-			
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			decl String:sDisplayName[SF2_MAX_NAME_LENGTH];
-			
-			do
-			{
-				KvGetSectionName(g_hConfig, sProfile, sizeof(sProfile));
-				KvGetString(g_hConfig, "name", sDisplayName, sizeof(sDisplayName));
-				if (!sDisplayName[0]) strcopy(sDisplayName, sizeof(sDisplayName), sProfile);
-				AddMenuItem(hMenu, sProfile, sDisplayName);
-			}
-			while (KvGotoNextKey(g_hConfig));
-			
-			SetMenuExitBackButton(hMenu, true);
-			
-			DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-			
-			return true;
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_AddFakeBoss(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetMenuItem(menu, param2, sProfile, sizeof(sProfile));
-		
-		FakeClientCommand(param1, "sm_sf2_add_boss_fake %s", sProfile);
-		
-		DisplayAddFakeBossAdminMenu(param1);
-	}
-}
-
-static AddBossTargetsToMenu(Handle:hMenu)
-{
-	if (g_hConfig == INVALID_HANDLE) return 0;
-	
-	KvRewind(g_hConfig);
-	if (!KvGotoFirstSubKey(g_hConfig)) return 0;
-	
-	decl String:sBuffer[512];
-	decl String:sDisplay[512], String:sInfo[64];
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	new iCount;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		new iUniqueID = NPCGetUniqueID(i);
-		if (iUniqueID == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		GetProfileString(sProfile, "name", sBuffer, sizeof(sBuffer));
-		if (strlen(sBuffer) == 0) strcopy(sBuffer, sizeof(sBuffer), sProfile);
-		
-		Format(sDisplay, sizeof(sDisplay), "%d - %s", i, sBuffer);
-		if (g_iSlenderCopyMaster[i] != -1)
-		{
-			Format(sBuffer, sizeof(sBuffer), " (copy of boss %d)", g_iSlenderCopyMaster[i]);
-			StrCat(sDisplay, sizeof(sDisplay), sBuffer);
-		}
-		
-		if (NPCGetFlags(i) & SFF_FAKE)
-		{
-			StrCat(sDisplay, sizeof(sDisplay), " (fake)");
-		}
-		
-		IntToString(iUniqueID, sInfo, sizeof(sInfo));
-		
-		AddMenuItem(hMenu, sInfo, sDisplay);
-		iCount++;
-	}
-	
-	return iCount;
-}
-
-static bool:DisplayRemoveBossAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_RemoveBoss);
-			if (!AddBossTargetsToMenu(hMenu))
-			{
-				CloseHandle(hMenu);
-				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
-			}
-			else
-			{
-				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Remove Boss", client);
-				SetMenuExitBackButton(hMenu, true);
-				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-				return true;
-			}
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_RemoveBoss(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sID[64];
-		GetMenuItem(menu, param2, sID, sizeof(sID));
-		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-		if (iIndex == -1)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-		}
-		else
-		{
-			FakeClientCommand(param1, "sm_sf2_remove_boss %d", iIndex);
-		}
-		
-		DisplayRemoveBossAdminMenu(param1);
-	}
-}
-
-static bool:DisplaySpawnBossAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_SpawnBoss);
-			if (!AddBossTargetsToMenu(hMenu))
-			{
-				CloseHandle(hMenu);
-				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
-			}
-			else
-			{
-				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Spawn Boss", client);
-				SetMenuExitBackButton(hMenu, true);
-				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-				return true;
-			}
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_SpawnBoss(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sID[64];
-		GetMenuItem(menu, param2, sID, sizeof(sID));
-		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-		if (iIndex == -1)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-		}
-		else
-		{
-			FakeClientCommand(param1, "sm_sf2_spawn_boss %d", iIndex);
-		}
-		
-		DisplaySpawnBossAdminMenu(param1);
-	}
-}
-
-static bool:DisplayBossAttackWaitersAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_BossAttackWaiters);
-			if (!AddBossTargetsToMenu(hMenu))
-			{
-				CloseHandle(hMenu);
-				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
-			}
-			else
-			{
-				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Attack Waiters", client);
-				SetMenuExitBackButton(hMenu, true);
-				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-				return true;
-			}
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_BossAttackWaiters(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sID[64];
-		GetMenuItem(menu, param2, sID, sizeof(sID));
-		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-		if (iIndex == -1)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-			DisplayBossAttackWaitersAdminMenu(param1);
-		}
-		else
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iIndex, sProfile, sizeof(sProfile));
-		
-			decl String:sName[SF2_MAX_NAME_LENGTH];
-			GetProfileString(sProfile, "name", sName, sizeof(sName));
-			if (!sName[0]) strcopy(sName, sizeof(sName), sProfile);
-			
-			new Handle:hMenu = CreateMenu(AdminMenu_BossAttackWaitersConfirm);
-			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Attack Waiters Confirm", param1, sName);
-			decl String:sBuffer[256];
-			Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
-			AddMenuItem(hMenu, sID, sBuffer);
-			Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
-			AddMenuItem(hMenu, sID, sBuffer);
-			SetMenuExitBackButton(hMenu, true);
-			DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
-		}
-	}
-}
-
-public AdminMenu_BossAttackWaitersConfirm(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossAttackWaitersAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sID[64];
-		GetMenuItem(menu, param2, sID, sizeof(sID));
-		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-		if (iIndex == -1)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-		}
-		else
-		{
-			switch (param2)
-			{
-				case 0: FakeClientCommand(param1, "sm_sf2_boss_attack_waiters %d 1", iIndex);
-				case 1: FakeClientCommand(param1, "sm_sf2_boss_attack_waiters %d 0", iIndex);
-			}
-		}
-		
-		DisplayBossAttackWaitersAdminMenu(param1);
-	}
-}
-
-static bool:DisplayBossTeleportAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_BossTeleport);
-			if (!AddBossTargetsToMenu(hMenu))
-			{
-				CloseHandle(hMenu);
-				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
-			}
-			else
-			{
-				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Teleport", client);
-				SetMenuExitBackButton(hMenu, true);
-				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-				return true;
-			}
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_BossTeleport(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sID[64];
-		GetMenuItem(menu, param2, sID, sizeof(sID));
-		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-		if (iIndex == -1)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-			DisplayBossTeleportAdminMenu(param1);
-		}
-		else
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iIndex, sProfile, sizeof(sProfile));
-		
-			decl String:sName[SF2_MAX_NAME_LENGTH];
-			GetProfileString(sProfile, "name", sName, sizeof(sName));
-			if (!sName[0]) strcopy(sName, sizeof(sName), sProfile);
-			
-			new Handle:hMenu = CreateMenu(AdminMenu_BossTeleportConfirm);
-			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Teleport Confirm", param1, sName);
-			decl String:sBuffer[256];
-			Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
-			AddMenuItem(hMenu, sID, sBuffer);
-			Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
-			AddMenuItem(hMenu, sID, sBuffer);
-			SetMenuExitBackButton(hMenu, true);
-			DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
-		}
-	}
-}
-
-public AdminMenu_BossTeleportConfirm(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossTeleportAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sID[64];
-		GetMenuItem(menu, param2, sID, sizeof(sID));
-		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
-		if (iIndex == -1)
-		{
-			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
-		}
-		else
-		{
-			switch (param2)
-			{
-				case 0: FakeClientCommand(param1, "sm_sf2_boss_no_teleport %d 0", iIndex);
-				case 1: FakeClientCommand(param1, "sm_sf2_boss_no_teleport %d 1", iIndex);
-			}
-		}
-		
-		DisplayBossTeleportAdminMenu(param1);
-	}
-}
-
-static bool:DisplayOverrideBossAdminMenu(client)
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		KvRewind(g_hConfig);
-		if (KvGotoFirstSubKey(g_hConfig))
-		{
-			new Handle:hMenu = CreateMenu(AdminMenu_OverrideBoss);
-			
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			decl String:sDisplayName[SF2_MAX_NAME_LENGTH];
-			
-			do
-			{
-				KvGetSectionName(g_hConfig, sProfile, sizeof(sProfile));
-				KvGetString(g_hConfig, "name", sDisplayName, sizeof(sDisplayName));
-				if (!sDisplayName[0]) strcopy(sDisplayName, sizeof(sDisplayName), sProfile);
-				AddMenuItem(hMenu, sProfile, sDisplayName);
-			}
-			while (KvGotoNextKey(g_hConfig));
-			
-			SetMenuExitBackButton(hMenu, true);
-			
-			new String:sProfileOverride[SF2_MAX_PROFILE_NAME_LENGTH], String:sProfileDisplayName[SF2_MAX_PROFILE_NAME_LENGTH];
-			GetConVarString(g_cvBossProfileOverride, sProfileOverride, sizeof(sProfileOverride));
-			
-			if (strlen(sProfileOverride) > 0 && IsProfileValid(sProfileOverride))
-			{
-				GetProfileString(sProfileOverride, "name", sProfileDisplayName, sizeof(sProfileDisplayName));
-				
-				if (strlen(sProfileDisplayName) == 0)
-					strcopy(sProfileDisplayName, sizeof(sProfileDisplayName), sProfileOverride)
-			}
-			else
-				strcopy(sProfileDisplayName, sizeof(sProfileDisplayName), "---");
-			
-			SetMenuTitle(hMenu, "%t%T\n%T\n \n", "SF2 Prefix", "SF2 Admin Menu Override Boss", client, "SF2 Admin Menu Current Boss Override", client, sProfileDisplayName);
-			
-			DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-			
-			return true;
-		}
-	}
-	
-	DisplayBossMainAdminMenu(client);
-	return false;
-}
-
-public AdminMenu_OverrideBoss(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayBossMainAdminMenu(param1);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetMenuItem(menu, param2, sProfile, sizeof(sProfile));
-		
-		FakeClientCommand(param1, "sm_cvar sf2_boss_profile_override %s", sProfile);
-		
-		DisplayOverrideBossAdminMenu(param1);
-	}
+#if defined _sf2_adminmenu_included
+ #endinput
+#endif
+#define _sf2_adminmenu_included
+
+static Handle:g_hTopMenu = INVALID_HANDLE;
+static g_iPlayerAdminMenuTargetUserId[MAXPLAYERS + 1] = { -1, ... };
+
+SetupAdminMenu()
+{
+	/* Account for late loading */
+	new Handle:hTopMenu = INVALID_HANDLE;
+	if (LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
+	{
+		OnAdminMenuReady(hTopMenu);
+	}
+}
+
+
+public OnAdminMenuReady(Handle:hTopMenu)
+{
+	if (hTopMenu == g_hTopMenu) return;
+	
+	g_hTopMenu = hTopMenu;
+	
+	new TopMenuObject:hServerCommands = FindTopMenuCategory(hTopMenu, ADMINMENU_SERVERCOMMANDS);
+	if (hServerCommands != INVALID_TOPMENUOBJECT)
+	{
+		AddToTopMenu(hTopMenu, "sf2_boss_admin_main", TopMenuObject_Item, AdminTopMenu_BossMain, hServerCommands, "sm_sf2_add_boss", ADMFLAG_SLAY);
+	}
+	
+	new TopMenuObject:hPlayerCommands = FindTopMenuCategory(hTopMenu, ADMINMENU_PLAYERCOMMANDS);
+	if (hPlayerCommands != INVALID_TOPMENUOBJECT)
+	{
+		AddToTopMenu(hTopMenu, "sf2_player_setplaystate", TopMenuObject_Item, AdminTopMenu_PlayerSetPlayState, hPlayerCommands, "sm_sf2_setplaystate", ADMFLAG_SLAY);
+		AddToTopMenu(hTopMenu, "sf2_player_force_proxy", TopMenuObject_Item, AdminTopMenu_PlayerForceProxy, hPlayerCommands, "sm_sf2_force_proxy", ADMFLAG_SLAY);
+	}
+}
+
+static DisplayPlayerForceProxyAdminMenu(client)
+{
+	new Handle:hMenu = CreateMenu(AdminMenu_PlayerForceProxy);
+	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Force Proxy", client);
+	AddTargetsToMenu(hMenu, client);
+	SetMenuExitBackButton(hMenu, true);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public AdminTopMenu_PlayerForceProxy(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
+{
+	if (action == TopMenuAction_DisplayOption)
+	{
+		Format(buffer, maxlength, "%t%T", "SF2 Prefix", "SF2 Admin Menu Player Force Proxy", param);
+	}
+	else if (action == TopMenuAction_SelectOption)
+	{
+		DisplayPlayerForceProxyAdminMenu(param);
+	}
+}
+
+public AdminMenu_PlayerForceProxy(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE)
+		{
+			DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sUserId[64];
+		GetMenuItem(menu, param2, sUserId, sizeof(sUserId));
+		
+		new client = GetClientOfUserId(StringToInt(sUserId));
+		if (client <= 0)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
+			DisplayPlayerForceProxyAdminMenu(param1);
+		}
+		else
+		{
+			g_iPlayerAdminMenuTargetUserId[param1] = StringToInt(sUserId);
+		
+			decl String:sName[MAX_NAME_LENGTH];
+			GetClientName(client, sName, sizeof(sName));
+			
+			new Handle:hMenu = CreateMenu(AdminMenu_PlayerForceProxyBoss);
+			if (!AddBossTargetsToMenu(hMenu))
+			{
+				CloseHandle(hMenu);
+				DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
+				CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", param1);
+			}
+			else
+			{
+				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Force Proxy Boss", param1, sName);
+				SetMenuExitBackButton(hMenu, true);
+				DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
+			}
+		}
+	}
+}
+
+public AdminMenu_PlayerForceProxyBoss(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayPlayerForceProxyAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		new client = GetClientOfUserId(g_iPlayerAdminMenuTargetUserId[param1]);
+		if (client <= 0)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
+		}
+		else
+		{
+			decl String:sID[64];
+			GetMenuItem(menu, param2, sID, sizeof(sID));
+			new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+			if (iIndex == -1)
+			{
+				CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+			}
+			else
+			{
+				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+				NPCGetProfile(iIndex, sProfile, sizeof(sProfile));
+			
+				if (!bool:GetProfileNum(sProfile, "proxies", 0) ||
+					g_iSlenderCopyMaster[iIndex] != -1)
+				{
+					CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Not Allowed To Have Proxies", param1);
+				}
+				else if (!g_bPlayerEliminated[client])
+				{
+					CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player In Game", param1);
+				}
+				else if (g_bPlayerProxy[param1])
+				{
+					CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Already A Proxy", param1);
+				}
+				else
+				{
+					FakeClientCommand(param1, "sm_sf2_force_proxy #%d %d", g_iPlayerAdminMenuTargetUserId[param1], iIndex);
+				}
+			}
+		}
+		
+		DisplayPlayerForceProxyAdminMenu(param1);
+	}
+}
+
+static DisplayPlayerSetPlayStateAdminMenu(client)
+{
+	new Handle:hMenu = CreateMenu(AdminMenu_PlayerSetPlayState);
+	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Set Play State", client);
+	AddTargetsToMenu(hMenu, client);
+	SetMenuExitBackButton(hMenu, true);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public AdminTopMenu_PlayerSetPlayState(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
+{
+	if (action == TopMenuAction_DisplayOption)
+	{
+		Format(buffer, maxlength, "%t%T", "SF2 Prefix", "SF2 Admin Menu Player Set Play State", param);
+	}
+	else if (action == TopMenuAction_SelectOption)
+	{
+		DisplayPlayerSetPlayStateAdminMenu(param);
+	}
+}
+
+public AdminMenu_PlayerSetPlayState(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE)
+		{
+			DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sUserId[64];
+		GetMenuItem(menu, param2, sUserId, sizeof(sUserId));
+		new client = GetClientOfUserId(StringToInt(sUserId));
+		if (client <= 0)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
+			DisplayPlayerSetPlayStateAdminMenu(param1);
+		}
+		else
+		{
+			decl String:sName[MAX_NAME_LENGTH];
+			GetClientName(client, sName, sizeof(sName));
+			
+			new Handle:hMenu = CreateMenu(AdminMenu_PlayerSetPlayStateConfirm);
+			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Player Set Play State Confirm", param1, sName);
+			decl String:sBuffer[256];
+			Format(sBuffer, sizeof(sBuffer), "%T", "SF2 In", param1);
+			AddMenuItem(hMenu, sUserId, sBuffer);
+			Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Out", param1);
+			AddMenuItem(hMenu, sUserId, sBuffer);
+			SetMenuExitBackButton(hMenu, true);
+			DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
+		}
+	}
+}
+
+public AdminMenu_PlayerSetPlayStateConfirm(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayPlayerSetPlayStateAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sUserId[64];
+		GetMenuItem(menu, param2, sUserId, sizeof(sUserId));
+		new client = GetClientOfUserId(StringToInt(sUserId));
+		if (client <= 0)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Player Does Not Exist", param1);
+		}
+		else
+		{
+			new iUserId = StringToInt(sUserId);
+			switch (param2)
+			{
+				case 0: FakeClientCommand(param1, "sm_sf2_setplaystate #%d 1", iUserId);
+				case 1: FakeClientCommand(param1, "sm_sf2_setplaystate #%d 0", iUserId);
+			}
+		}
+		
+		DisplayPlayerSetPlayStateAdminMenu(param1);
+	}
+}
+
+static DisplayBossMainAdminMenu(client)
+{
+	new Handle:hMenu = CreateMenu(AdminMenu_BossMain);
+	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Main", client);
+	
+	decl String:sBuffer[512];
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Add Boss", client);
+	AddMenuItem(hMenu, "add_boss", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Add Fake Boss", client);
+	AddMenuItem(hMenu, "add_boss_fake", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Remove Boss", client);
+	AddMenuItem(hMenu, "remove_boss", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Spawn Boss", client);
+	AddMenuItem(hMenu, "spawn_boss", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Boss Attack Waiters", client);
+	AddMenuItem(hMenu, "boss_attack_waiters", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Boss Teleport", client);
+	AddMenuItem(hMenu, "boss_no_teleport", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Menu Override Boss", client);
+	AddMenuItem(hMenu, "override_boss", sBuffer);
+	
+	
+	SetMenuExitBackButton(hMenu, true);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public AdminMenu_BossMain(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE)
+		{
+			DisplayTopMenu(g_hTopMenu, param1, TopMenuPosition_LastCategory);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sInfo[64];
+		GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
+		if (StrEqual(sInfo, "add_boss"))
+		{
+			DisplayAddBossAdminMenu(param1);
+		}
+		else if (StrEqual(sInfo, "add_boss_fake"))
+		{
+			DisplayAddFakeBossAdminMenu(param1);
+		}
+		else if (StrEqual(sInfo, "remove_boss"))
+		{
+			DisplayRemoveBossAdminMenu(param1);
+		}
+		else if (StrEqual(sInfo, "spawn_boss"))
+		{
+			DisplaySpawnBossAdminMenu(param1);
+		}
+		else if (StrEqual(sInfo, "boss_attack_waiters"))
+		{
+			DisplayBossAttackWaitersAdminMenu(param1);
+		}
+		else if (StrEqual(sInfo, "boss_no_teleport"))
+		{
+			DisplayBossTeleportAdminMenu(param1);
+		}
+		else if (StrEqual(sInfo, "override_boss"))
+		{
+			DisplayOverrideBossAdminMenu(param1);
+		}
+	}
+}
+
+public AdminTopMenu_BossMain(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
+{
+	if (action == TopMenuAction_DisplayOption)
+	{
+		Format(buffer, maxlength, "%t%T", "SF2 Prefix", "SF2 Admin Menu Boss Main", param);
+	}
+	else if (action == TopMenuAction_SelectOption)
+	{
+		DisplayBossMainAdminMenu(param);
+	}
+}
+
+static bool:DisplayAddBossAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_AddBoss);
+			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Add Boss", client);
+			
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			decl String:sDisplayName[SF2_MAX_NAME_LENGTH];
+			
+			do
+			{
+				KvGetSectionName(g_hConfig, sProfile, sizeof(sProfile));
+				KvGetString(g_hConfig, "name", sDisplayName, sizeof(sDisplayName));
+				if (!sDisplayName[0]) strcopy(sDisplayName, sizeof(sDisplayName), sProfile);
+				AddMenuItem(hMenu, sProfile, sDisplayName);
+			}
+			while (KvGotoNextKey(g_hConfig));
+			
+			SetMenuExitBackButton(hMenu, true);
+			
+			DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+			
+			return true;
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_AddBoss(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetMenuItem(menu, param2, sProfile, sizeof(sProfile));
+		
+		FakeClientCommand(param1, "sm_sf2_add_boss %s", sProfile);
+		
+		DisplayAddBossAdminMenu(param1);
+	}
+}
+
+static bool:DisplayAddFakeBossAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_AddFakeBoss);
+			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Add Fake Boss", client);
+			
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			decl String:sDisplayName[SF2_MAX_NAME_LENGTH];
+			
+			do
+			{
+				KvGetSectionName(g_hConfig, sProfile, sizeof(sProfile));
+				KvGetString(g_hConfig, "name", sDisplayName, sizeof(sDisplayName));
+				if (!sDisplayName[0]) strcopy(sDisplayName, sizeof(sDisplayName), sProfile);
+				AddMenuItem(hMenu, sProfile, sDisplayName);
+			}
+			while (KvGotoNextKey(g_hConfig));
+			
+			SetMenuExitBackButton(hMenu, true);
+			
+			DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+			
+			return true;
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_AddFakeBoss(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetMenuItem(menu, param2, sProfile, sizeof(sProfile));
+		
+		FakeClientCommand(param1, "sm_sf2_add_boss_fake %s", sProfile);
+		
+		DisplayAddFakeBossAdminMenu(param1);
+	}
+}
+
+static AddBossTargetsToMenu(Handle:hMenu)
+{
+	if (g_hConfig == INVALID_HANDLE) return 0;
+	
+	KvRewind(g_hConfig);
+	if (!KvGotoFirstSubKey(g_hConfig)) return 0;
+	
+	decl String:sBuffer[512];
+	decl String:sDisplay[512], String:sInfo[64];
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	new iCount;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		new iUniqueID = NPCGetUniqueID(i);
+		if (iUniqueID == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		GetProfileString(sProfile, "name", sBuffer, sizeof(sBuffer));
+		if (strlen(sBuffer) == 0) strcopy(sBuffer, sizeof(sBuffer), sProfile);
+		
+		Format(sDisplay, sizeof(sDisplay), "%d - %s", i, sBuffer);
+		if (g_iSlenderCopyMaster[i] != -1)
+		{
+			Format(sBuffer, sizeof(sBuffer), " (copy of boss %d)", g_iSlenderCopyMaster[i]);
+			StrCat(sDisplay, sizeof(sDisplay), sBuffer);
+		}
+		
+		if (NPCGetFlags(i) & SFF_FAKE)
+		{
+			StrCat(sDisplay, sizeof(sDisplay), " (fake)");
+		}
+		
+		IntToString(iUniqueID, sInfo, sizeof(sInfo));
+		
+		AddMenuItem(hMenu, sInfo, sDisplay);
+		iCount++;
+	}
+	
+	return iCount;
+}
+
+static bool:DisplayRemoveBossAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_RemoveBoss);
+			if (!AddBossTargetsToMenu(hMenu))
+			{
+				CloseHandle(hMenu);
+				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
+			}
+			else
+			{
+				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Remove Boss", client);
+				SetMenuExitBackButton(hMenu, true);
+				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+				return true;
+			}
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_RemoveBoss(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sID[64];
+		GetMenuItem(menu, param2, sID, sizeof(sID));
+		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+		if (iIndex == -1)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+		}
+		else
+		{
+			FakeClientCommand(param1, "sm_sf2_remove_boss %d", iIndex);
+		}
+		
+		DisplayRemoveBossAdminMenu(param1);
+	}
+}
+
+static bool:DisplaySpawnBossAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_SpawnBoss);
+			if (!AddBossTargetsToMenu(hMenu))
+			{
+				CloseHandle(hMenu);
+				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
+			}
+			else
+			{
+				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Spawn Boss", client);
+				SetMenuExitBackButton(hMenu, true);
+				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+				return true;
+			}
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_SpawnBoss(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sID[64];
+		GetMenuItem(menu, param2, sID, sizeof(sID));
+		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+		if (iIndex == -1)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+		}
+		else
+		{
+			FakeClientCommand(param1, "sm_sf2_spawn_boss %d", iIndex);
+		}
+		
+		DisplaySpawnBossAdminMenu(param1);
+	}
+}
+
+static bool:DisplayBossAttackWaitersAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_BossAttackWaiters);
+			if (!AddBossTargetsToMenu(hMenu))
+			{
+				CloseHandle(hMenu);
+				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
+			}
+			else
+			{
+				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Attack Waiters", client);
+				SetMenuExitBackButton(hMenu, true);
+				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+				return true;
+			}
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_BossAttackWaiters(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sID[64];
+		GetMenuItem(menu, param2, sID, sizeof(sID));
+		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+		if (iIndex == -1)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+			DisplayBossAttackWaitersAdminMenu(param1);
+		}
+		else
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iIndex, sProfile, sizeof(sProfile));
+		
+			decl String:sName[SF2_MAX_NAME_LENGTH];
+			GetProfileString(sProfile, "name", sName, sizeof(sName));
+			if (!sName[0]) strcopy(sName, sizeof(sName), sProfile);
+			
+			new Handle:hMenu = CreateMenu(AdminMenu_BossAttackWaitersConfirm);
+			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Attack Waiters Confirm", param1, sName);
+			decl String:sBuffer[256];
+			Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+			AddMenuItem(hMenu, sID, sBuffer);
+			Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+			AddMenuItem(hMenu, sID, sBuffer);
+			SetMenuExitBackButton(hMenu, true);
+			DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
+		}
+	}
+}
+
+public AdminMenu_BossAttackWaitersConfirm(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossAttackWaitersAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sID[64];
+		GetMenuItem(menu, param2, sID, sizeof(sID));
+		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+		if (iIndex == -1)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+		}
+		else
+		{
+			switch (param2)
+			{
+				case 0: FakeClientCommand(param1, "sm_sf2_boss_attack_waiters %d 1", iIndex);
+				case 1: FakeClientCommand(param1, "sm_sf2_boss_attack_waiters %d 0", iIndex);
+			}
+		}
+		
+		DisplayBossAttackWaitersAdminMenu(param1);
+	}
+}
+
+static bool:DisplayBossTeleportAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_BossTeleport);
+			if (!AddBossTargetsToMenu(hMenu))
+			{
+				CloseHandle(hMenu);
+				CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 No Active Bosses", client);
+			}
+			else
+			{
+				SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Teleport", client);
+				SetMenuExitBackButton(hMenu, true);
+				DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+				return true;
+			}
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_BossTeleport(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sID[64];
+		GetMenuItem(menu, param2, sID, sizeof(sID));
+		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+		if (iIndex == -1)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+			DisplayBossTeleportAdminMenu(param1);
+		}
+		else
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iIndex, sProfile, sizeof(sProfile));
+		
+			decl String:sName[SF2_MAX_NAME_LENGTH];
+			GetProfileString(sProfile, "name", sName, sizeof(sName));
+			if (!sName[0]) strcopy(sName, sizeof(sName), sProfile);
+			
+			new Handle:hMenu = CreateMenu(AdminMenu_BossTeleportConfirm);
+			SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Admin Menu Boss Teleport Confirm", param1, sName);
+			decl String:sBuffer[256];
+			Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+			AddMenuItem(hMenu, sID, sBuffer);
+			Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+			AddMenuItem(hMenu, sID, sBuffer);
+			SetMenuExitBackButton(hMenu, true);
+			DisplayMenu(hMenu, param1, MENU_TIME_FOREVER);
+		}
+	}
+}
+
+public AdminMenu_BossTeleportConfirm(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossTeleportAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sID[64];
+		GetMenuItem(menu, param2, sID, sizeof(sID));
+		new iIndex = NPCGetFromUniqueID(StringToInt(sID));
+		if (iIndex == -1)
+		{
+			CPrintToChat(param1, "%t%T", "SF2 Prefix", "SF2 Boss Does Not Exist", param1);
+		}
+		else
+		{
+			switch (param2)
+			{
+				case 0: FakeClientCommand(param1, "sm_sf2_boss_no_teleport %d 0", iIndex);
+				case 1: FakeClientCommand(param1, "sm_sf2_boss_no_teleport %d 1", iIndex);
+			}
+		}
+		
+		DisplayBossTeleportAdminMenu(param1);
+	}
+}
+
+static bool:DisplayOverrideBossAdminMenu(client)
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		KvRewind(g_hConfig);
+		if (KvGotoFirstSubKey(g_hConfig))
+		{
+			new Handle:hMenu = CreateMenu(AdminMenu_OverrideBoss);
+			
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			decl String:sDisplayName[SF2_MAX_NAME_LENGTH];
+			
+			do
+			{
+				KvGetSectionName(g_hConfig, sProfile, sizeof(sProfile));
+				KvGetString(g_hConfig, "name", sDisplayName, sizeof(sDisplayName));
+				if (!sDisplayName[0]) strcopy(sDisplayName, sizeof(sDisplayName), sProfile);
+				AddMenuItem(hMenu, sProfile, sDisplayName);
+			}
+			while (KvGotoNextKey(g_hConfig));
+			
+			SetMenuExitBackButton(hMenu, true);
+			
+			new String:sProfileOverride[SF2_MAX_PROFILE_NAME_LENGTH], String:sProfileDisplayName[SF2_MAX_PROFILE_NAME_LENGTH];
+			GetConVarString(g_cvBossProfileOverride, sProfileOverride, sizeof(sProfileOverride));
+			
+			if (strlen(sProfileOverride) > 0 && IsProfileValid(sProfileOverride))
+			{
+				GetProfileString(sProfileOverride, "name", sProfileDisplayName, sizeof(sProfileDisplayName));
+				
+				if (strlen(sProfileDisplayName) == 0)
+					strcopy(sProfileDisplayName, sizeof(sProfileDisplayName), sProfileOverride)
+			}
+			else
+				strcopy(sProfileDisplayName, sizeof(sProfileDisplayName), "---");
+			
+			SetMenuTitle(hMenu, "%t%T\n%T\n \n", "SF2 Prefix", "SF2 Admin Menu Override Boss", client, "SF2 Admin Menu Current Boss Override", client, sProfileDisplayName);
+			
+			DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+			
+			return true;
+		}
+	}
+	
+	DisplayBossMainAdminMenu(client);
+	return false;
+}
+
+public AdminMenu_OverrideBoss(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayBossMainAdminMenu(param1);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetMenuItem(menu, param2, sProfile, sizeof(sProfile));
+		
+		FakeClientCommand(param1, "sm_cvar sf2_boss_profile_override %s", sProfile);
+		
+		DisplayOverrideBossAdminMenu(param1);
+	}
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/client.sp b/addons/sourcemod/scripting/rytp_horror/client.sp
index 9e06990..f3626f5 100644
--- a/addons/sourcemod/scripting/rytp_horror/client.sp
+++ b/addons/sourcemod/scripting/rytp_horror/client.sp
@@ -1,5966 +1,5888 @@
-#if defined _sf2_client_included
- #endinput
-#endif
-#define _sf2_client_included
-
-#define GHOST_MODEL "models/props_halloween/ghost_no_hat.mdl"
-//#define BLACK_OVERLAY "overlays/slender/newcamerahud"
-
-#define EF_NODRAW 32
-
-#define SF2_FLASHLIGHT_WIDTH 512.0 // How wide the player's Flashlight should be in world units.
-#define SF2_FLASHLIGHT_LENGTH 1024.0 // How far the player's Flashlight can reach in world units.
-#define SF2_FLASHLIGHT_BRIGHTNESS 0 // Intensity of the players' Flashlight.
-#define SF2_FLASHLIGHT_DRAIN_RATE 0.65 // How long (in seconds) each bar on the player's Flashlight meter lasts.
-#define SF2_FLASHLIGHT_RECHARGE_RATE 0.68 // How long (in seconds) it takes each bar on the player's Flashlight meter to recharge.
-#define SF2_FLASHLIGHT_FLICKERAT 0.25 // The percentage of the Flashlight battery where the Flashlight will start to blink.
-#define SF2_FLASHLIGHT_ENABLEAT 0.3 // The percentage of the Flashlight battery where the Flashlight will be able to be used again (if the player shortens out the Flashlight from excessive use).
-#define SF2_FLASHLIGHT_COOLDOWN 0.4 // How much time players have to wait before being able to switch their flashlight on again after turning it off.
-
-#define SF2_ULTRAVISION_WIDTH 800.0
-#define SF2_ULTRAVISION_LENGTH 800.0
-#define SF2_ULTRAVISION_BRIGHTNESS -4 // Intensity of Ultravision.
-#define SF2_ULTRAVISION_CONE 180.0
-
-#define SF2_PLAYER_BREATH_COOLDOWN_MIN 0.8
-#define SF2_PLAYER_BREATH_COOLDOWN_MAX 2.0
-
-#define SF2_BREATH_VIEWBOB_SPEED 0.05
-#define SF2_BREATH_VIEWBOB_START 0.045
-#define SF2_BREATH_VIEWBOB_AMPLITUDE 0.17
-
-new String:g_strPlayerBreathSounds[][] = 
-{
-	"rytp_horror/player_breath_1.wav"
-};
-
-new String:g_strGhostHelpPhrases[][] = 
-{
-	"rytp_horror/ghost/epifancev_zdes.mp3",
-	"rytp_horror/ghost/pahom_ohh.mp3",
-	"rytp_horror/ghost/pahom_ja_nichego_net_net.mp3",
-	"rytp_horror/ghost/zs_epifan_vou.mp3",
-	"rytp_horror/ghost/zs_mmm.mp3",
-	"rytp_horror/ghost/zs_mmm2.mp3"
-};
-new g_iGhostHelpPhraseInterval = 2;
-new g_iGhostNextHelpPhrase[MAXPLAYERS + 1];
-
-static String:g_strPlayerLagCompensationWeapons[][] = 
-{
-	"tf_weapon_sniperrifle",
-	"tf_weapon_sniperrifle_decap",
-	"tf_weapon_sniperrifle_classic"
-};
-
-// Deathcam data.
-static g_iPlayerDeathCamBoss[MAXPLAYERS + 1] = { -1, ... };
-static bool:g_bPlayerDeathCam[MAXPLAYERS + 1] = { false, ... };
-static bool:g_bPlayerDeathCamShowOverlay[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerDeathCamEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static g_iPlayerDeathCamEnt2[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static Handle:g_hPlayerDeathCamTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Flashlight data.
-static bool:g_bPlayerFlashlight[MAXPLAYERS + 1] = { false, ... };
-static bool:g_bPlayerFlashlightBroken[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerFlashlightEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static g_iPlayerFlashlightEntAng[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static Float:g_flPlayerFlashlightBatteryLife[MAXPLAYERS + 1] = { 1.0, ... };
-static Handle:g_hPlayerFlashlightBatteryTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static Float:g_flPlayerFlashlightNextInputTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-// Ultravision data.
-static bool:g_bPlayerUltravision[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerUltravisionEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-
-// Sprint data.
-static bool:g_bPlayerSprint[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerSprintPoints[MAXPLAYERS + 1] = { 100, ... };
-static Handle:g_hPlayerSprintTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Blink data.
-static Handle:g_hPlayerBlinkTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static bool:g_bPlayerBlink[MAXPLAYERS + 1] = { false, ... };
-static Float:g_flPlayerBlinkMeter[MAXPLAYERS + 1] = { 0.0, ... };
-static g_iPlayerBlinkCount[MAXPLAYERS + 1] = { 0, ... };
-
-// Breathing data.
-static bool:g_bPlayerBreath[MAXPLAYERS + 1] = { false, ... };
-static Handle:g_hPlayerBreathTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-new Float:g_flPlayerBreathViewbobPhase[MAXPLAYERS + 1];
-new Float:g_flPlayerBreathViewbobXMult[MAXPLAYERS + 1] = 1.0;
-new Float:g_flPlayerBreathViewbobYMult[MAXPLAYERS + 1] = 1.0;
-
-// Interactive glow data.
-static g_iPlayerInteractiveGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static g_iPlayerInteractiveGlowTargetEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-
-// Constant glow data.
-static g_iPlayerConstantGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static bool:g_bPlayerConstantGlowEnabled[MAXPLAYERS + 1] = { false, ... };
-
-// Jumpscare data.
-static g_iPlayerJumpScareBoss[MAXPLAYERS + 1] = { -1, ... };
-static Float:g_flPlayerJumpScareLifeTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-static Float:g_flPlayerScareBoostEndTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-// Anti-camping data.
-static g_iPlayerCampingStrikes[MAXPLAYERS + 1] = { 0, ... };
-static Handle:g_hPlayerCampingTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static Float:g_flPlayerCampingLastPosition[MAXPLAYERS + 1][3];
-static bool:g_bPlayerCampingFirstTime[MAXPLAYERS + 1] = { true, ... };
-
-
-//	==========================================================
-//	GENERAL CLIENT HOOK FUNCTIONS
-//	==========================================================
-
-#define SF2_PLAYER_VIEWBOB_TIMER 10.0
-#define SF2_PLAYER_VIEWBOB_SCALE_X 0.05
-#define SF2_PLAYER_VIEWBOB_SCALE_Y 0.0
-#define SF2_PLAYER_VIEWBOB_SCALE_Z 0.0
-
-
-public MRESReturn:Hook_ClientWantsLagCompensationOnEntity(thisPointer, Handle:hReturn, Handle:hParams)
-{
-	if (!g_bEnabled || IsFakeClient(thisPointer)) return MRES_Ignored;
-	
-	DHookSetReturn(hReturn, true);
-	return MRES_Supercede;
-}
-
-Float:ClientGetScareBoostEndTime(client)
-{
-	return g_flPlayerScareBoostEndTime[client];
-}
-
-ClientSetScareBoostEndTime(client, Float:time)
-{
-	g_flPlayerScareBoostEndTime[client] = time;
-}
-
-public Hook_ClientPreThink(client)
-{
-	if (!g_bEnabled) return;
-	
-	ClientProcessViewAngles(client);
-	ClientProcessVisibility(client);
-	ClientProcessStaticShake(client);
-	ClientProcessFlashlightAngles(client);
-	ClientProcessInteractiveGlow(client);
-	
-	if (IsClientInGhostMode(client))
-	{
-		SetEntPropFloat(client, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0);
-		SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 520.0);
-	}
-	else if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
-	{
-		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
-		{
-			new iRoundState = _:GameRules_GetRoundState();
-			
-			Hide_Weapon(client);
-		
-			// No double jumping for players in play.
-			SetEntProp(client, Prop_Send, "m_iAirDash", 99999);
-		
-			if (!g_bPlayerProxy[client])
-			{
-				if (iRoundState == 4)
-				{
-					new bool:bDanger = false;
-					
-					if (!bDanger)
-					{
-						decl iState;
-						decl iBossTarget;
-						
-						for (new i = 0; i < MAX_BOSSES; i++)
-						{
-							if (NPCGetUniqueID(i) == -1) continue;
-							
-							if (NPCGetType(i) == SF2BossType_Chaser)
-							{
-								iBossTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
-								iState = g_iSlenderState[i];
-								
-								if ((iState == STATE_CHASE || iState == STATE_ATTACK || iState == STATE_STUN) &&
-									((iBossTarget && iBossTarget != INVALID_ENT_REFERENCE && (iBossTarget == client || ClientGetDistanceFromEntity(client, iBossTarget) < 512.0)) || NPCGetDistanceFromEntity(i, client) < 512.0 || PlayerCanSeeSlender(client, i, false)))
-								{
-									bDanger = true;
-									ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
-									
-									// Induce client stress levels.
-									new Float:flUnComfortZoneDist = 512.0;
-									new Float:flStressScalar = (flUnComfortZoneDist / NPCGetDistanceFromEntity(i, client));
-									ClientAddStress(client, 0.025 * flStressScalar);
-									
-									break;
-								}
-							}
-						}
-					}
-					
-					if (g_flPlayerStaticAmount[client] > 0.4) bDanger = true;
-					if (GetGameTime() < ClientGetScareBoostEndTime(client)) bDanger = true;
-					
-					if (!bDanger)
-					{
-						decl iState;
-						for (new i = 0; i < MAX_BOSSES; i++)
-						{
-							if (NPCGetUniqueID(i) == -1) continue;
-							
-							if (NPCGetType(i) == SF2BossType_Chaser)
-							{
-								if (iState == STATE_ALERT)
-								{
-									if (PlayerCanSeeSlender(client, i))
-									{
-										bDanger = true;
-										ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
-									}
-								}
-							}
-						}
-					}
-					
-					if (!bDanger)
-					{
-						new Float:flCurTime = GetGameTime();
-						new Float:flScareSprintDuration = 3.0;
-						if (TF2_GetPlayerClass(client) == TFClass_DemoMan) flScareSprintDuration *= 1.667;
-						
-						for (new i = 0; i < MAX_BOSSES; i++)
-						{
-							if (NPCGetUniqueID(i) == -1) continue;
-							
-							if ((flCurTime - g_flPlayerScareLastTime[client][i]) <= flScareSprintDuration)
-							{
-								bDanger = true;
-								break;
-							}
-						}
-					}
-					
-					new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
-					new Float:flSprintSpeed = ClientGetDefaultSprintSpeed(client);
-					
-					// Check for weapon speed changes.
-					new iWeapon = INVALID_ENT_REFERENCE;
-					
-					for (new iSlot = 0; iSlot <= 5; iSlot++)
-					{
-						iWeapon = GetPlayerWeaponSlot(client, iSlot);
-						if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
-						
-						new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-						switch (iItemDef)
-						{
-							case 239: // Gloves of Running Urgently
-							{
-								if (GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon") == iWeapon)
-								{
-									flSprintSpeed += (flSprintSpeed * 0.1);
-								}
-							}
-							case 775: // Escape Plan
-							{
-								new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
-								new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
-								new Float:flPercentage = flHealth / flMaxHealth;
-								
-								if (flPercentage < 0.805 && flPercentage >= 0.605) flSprintSpeed += (flSprintSpeed * 0.05);
-								else if (flPercentage < 0.605 && flPercentage >= 0.405) flSprintSpeed += (flSprintSpeed * 0.1);
-								else if (flPercentage < 0.405 && flPercentage >= 0.205) flSprintSpeed += (flSprintSpeed * 0.15);
-								else if (flPercentage < 0.205) flSprintSpeed += (flSprintSpeed * 0.2);
-							}
-						}
-					}
-					
-					// Speed buff?
-					if (TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly))
-					{
-						flWalkSpeed += (flWalkSpeed * 0.08);
-						flSprintSpeed += (flSprintSpeed * 0.08);
-					}
-					
-					if (bDanger)
-					{
-						flWalkSpeed *= 1.33;
-						flSprintSpeed *= 1.33;
-						
-						if (!g_bPlayerHints[client][PlayerHint_Sprint])
-						{
-							ClientShowHint(client, PlayerHint_Sprint);
-						}
-					}
-					
-					new Float:flSprintSpeedSubtract = ((flSprintSpeed - flWalkSpeed) * 0.5);
-					flSprintSpeedSubtract -= flSprintSpeedSubtract * (g_iPlayerSprintPoints[client] != 0 ? (float(g_iPlayerSprintPoints[client]) / 100.0) : 0.0);
-					flSprintSpeed -= flSprintSpeedSubtract;
-					
-					if (IsClientSprinting(client)) 
-					{
-						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flSprintSpeed);
-					}
-					else 
-					{
-						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flWalkSpeed);
-					}
-					
-					if (ClientCanBreath(client) && !g_bPlayerBreath[client])
-					{
-						ClientStartBreathing(client);
-					}
-				}
-			}
-			else
-			{
-				new TFClassType:iClass = TF2_GetPlayerClass(client);
-				new bool:bSpeedup = TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly);
-			
-				switch (iClass)
-				{
-					case TFClass_Scout:
-					{
-						if (iRoundState == 4)
-						{
-							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 405.0);
-							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
-						}
-					}
-					case TFClass_Medic:
-					{
-						if (iRoundState == 4)
-						{
-							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 385.0);
-							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	// Calculate player stress levels.
-	if (GetGameTime() >= g_flPlayerStressNextUpdateTime[client])
-	{
-		//new Float:flPagePercent = g_iPageMax != 0 ? float(g_iPageCount) / float(g_iPageMax) : 0.0;
-		//new Float:flPageCountPercent = g_iPageMax != 0? float(g_iPlayerPageCount[client]) / float(g_iPageMax) : 0.0;
-		
-		g_flPlayerStressNextUpdateTime[client] = GetGameTime() + 0.33;
-		ClientAddStress(client, -0.01);
-		
-#if defined DEBUG
-		SendDebugMessageToPlayer(client, DEBUG_PLAYER_STRESS, 1, "g_flPlayerStress[%d]: %0.1f", client, g_flPlayerStress[client]);
-#endif
-	}
-	
-	// Process screen shake, if enabled.
-	if (g_bPlayerShakeEnabled)
-	{
-		new bool:bDoShake = false;
-		
-		if (IsPlayerAlive(client))
-		{
-			new iStaticMaster = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
-			if (iStaticMaster != -1 && NPCGetFlags(iStaticMaster) & SFF_HASVIEWSHAKE)
-			{
-				bDoShake = true;
-			}
-		}
-		
-		if (bDoShake)
-		{
-			new Float:flPercent = g_flPlayerStaticAmount[client];
-			
-			new Float:flAmplitudeMax = GetConVarFloat(g_cvPlayerShakeAmplitudeMax);
-			new Float:flAmplitude = flAmplitudeMax * flPercent;
-			
-			new Float:flFrequencyMax = GetConVarFloat(g_cvPlayerShakeFrequencyMax);
-			new Float:flFrequency = flFrequencyMax * flPercent;
-			
-			UTIL_ScreenShake(client, flAmplitude, 0.5, flFrequency);
-		}
-	}
-}
-
-public Action:Hook_ClientSetTransmit(client, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (other != client)
-	{
-		if (IsClientInGhostMode(client) && !IsClientInGhostMode(other)) return Plugin_Handled;
-		
-		if (!IsRoundEnding())
-		{
-			// SPECIAL ROUND: Singleplayer
-			/*
-			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-			{
-				if (!g_bPlayerEliminated[client] && !g_bPlayerEliminated[other] && !DidClientEscape(other)) return Plugin_Handled; 
-			}
-			*/
-			// pvp
-			if (IsClientInPvP(client) && IsClientInPvP(other)) 
-			{
-				if (TF2_IsPlayerInCondition(client, TFCond_Cloaked) &&
-					!TF2_IsPlayerInCondition(client, TFCond_CloakFlicker) &&
-					!TF2_IsPlayerInCondition(client, TFCond_Jarated) &&
-					!TF2_IsPlayerInCondition(client, TFCond_Milked) &&
-					!TF2_IsPlayerInCondition(client, TFCond_OnFire) &&
-					(GetGameTime() > GetEntPropFloat(client, Prop_Send, "m_flInvisChangeCompleteTime")))
-				{
-					return Plugin_Handled;
-				}
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:TF2_CalcIsAttackCritical(client, weapon, String:sWeaponName[], &bool:result)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if ((IsRoundInWarmup() || IsClientInPvP(client)) && !IsRoundEnding())
-	{
-		if (!GetConVarBool(g_cvPlayerFakeLagCompensation))
-		{
-			new bool:bNeedsManualDamage = false;
-			
-			// Fake lag compensation isn't enabled; check to see if we need to deal damage manually.
-			for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
-			{
-				if (StrEqual(sWeaponName, g_strPlayerLagCompensationWeapons[i], false))
-				{
-					bNeedsManualDamage = true;
-					break;
-				}
-			}
-			
-			if (bNeedsManualDamage)
-			{
-				decl Float:flStartPos[3], Float:flEyeAng[3];
-				GetClientEyePosition(client, flStartPos);
-				GetClientEyeAngles(client, flEyeAng);
-				
-				new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flEyeAng, MASK_SHOT, RayType_Infinite, TraceRayDontHitEntity, client);
-				new iHitEntity = TR_GetEntityIndex(hTrace);
-				new iHitGroup = TR_GetHitGroup(hTrace);
-				CloseHandle(hTrace);
-				
-				if (IsValidClient(iHitEntity))
-				{
-					if (GetClientTeam(iHitEntity) == GetClientTeam(client))
-					{
-						if (IsRoundInWarmup() || IsClientInPvP(iHitEntity))
-						{
-							new Float:flChargedDamage = GetEntPropFloat(weapon, Prop_Send, "m_flChargedDamage");
-							if (flChargedDamage < 50.0) flChargedDamage = 50.0;
-							new iDamageType = DMG_BULLET;
-							
-							if (IsClientCritBoosted(client))
-							{
-								result = true;
-								iDamageType |= DMG_ACID;
-							}
-							else if (iHitGroup == 1)
-							{
-								if (StrEqual(sWeaponName, "tf_weapon_sniperrifle_classic", false))
-								{
-									if (flChargedDamage >= 150.0)
-									{
-										result = true;
-										iDamageType |= DMG_ACID;
-									}
-								}
-								else
-								{
-									if (TF2_IsPlayerInCondition(client, TFCond_Zoomed))
-									{
-										result = true;
-										iDamageType |= DMG_ACID;
-									}
-								}
-							}
-							
-							SDKHooks_TakeDamage(iHitEntity, client, client, flChargedDamage, iDamageType);
-							return Plugin_Changed;
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_ClientOnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsRoundInWarmup()) return Plugin_Continue;
-	
-	if (attacker != victim && IsValidClient(attacker))
-	{
-		if (!IsRoundEnding())
-		{
-			if (IsClientInPvP(victim) && IsClientInPvP(attacker))
-			{
-				if (attacker == inflictor)
-				{
-					if (IsValidEdict(weapon))
-					{
-						decl String:sWeaponClass[64];
-						GetEdictClassname(weapon, sWeaponClass, sizeof(sWeaponClass));
-						
-						// Backstab check!
-						if ((StrEqual(sWeaponClass, "tf_weapon_knife", false) || (TF2_GetPlayerClass(attacker) == TFClass_Spy && StrEqual(sWeaponClass, "saxxy", false))) &&
-							(damagecustom != TF_CUSTOM_TAUNT_FENCING))
-						{
-							decl Float:flMyPos[3], Float:flHisPos[3], Float:flMyDirection[3];
-							GetClientAbsOrigin(victim, flMyPos);
-							GetClientAbsOrigin(attacker, flHisPos);
-							GetClientEyeAngles(victim, flMyDirection);
-							GetAngleVectors(flMyDirection, flMyDirection, NULL_VECTOR, NULL_VECTOR);
-							NormalizeVector(flMyDirection, flMyDirection);
-							ScaleVector(flMyDirection, 32.0);
-							AddVectors(flMyDirection, flMyPos, flMyDirection);
-							
-							decl Float:p[3], Float:s[3];
-							MakeVectorFromPoints(flMyPos, flHisPos, p);
-							MakeVectorFromPoints(flMyPos, flMyDirection, s);
-							if (GetVectorDotProduct(p, s) <= 0.0)
-							{
-								damage = float(GetEntProp(victim, Prop_Send, "m_iHealth")) * 2.0;
-								
-								new Handle:hCvar = FindConVar("tf_weapon_criticals");
-								if (hCvar != INVALID_HANDLE && GetConVarBool(hCvar)) damagetype |= DMG_ACID;
-								return Plugin_Changed;
-							}
-						}
-					}
-				}
-			}
-			/*
-			else if (g_bPlayerProxy[victim] || g_bPlayerProxy[attacker])
-			{
-				if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
-				{
-					damage = 0.0;
-					return Plugin_Changed;
-				}
-				
-				if (g_bPlayerProxy[attacker])
-				{
-					new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, victim);
-					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[attacker]);
-					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
-					{
-						if (damagecustom == TF_CUSTOM_TAUNT_GRAND_SLAM ||
-							damagecustom == TF_CUSTOM_TAUNT_FENCING ||
-							damagecustom == TF_CUSTOM_TAUNT_ARROW_STAB ||
-							damagecustom == TF_CUSTOM_TAUNT_GRENADE ||
-							damagecustom == TF_CUSTOM_TAUNT_BARBARIAN_SWING ||
-							damagecustom == TF_CUSTOM_TAUNT_ENGINEER_ARM ||
-							damagecustom == TF_CUSTOM_TAUNT_ARMAGEDDON)
-						{
-							if (damage >= float(iMaxHealth)) damage = float(iMaxHealth) * 0.5;
-							else damage = 0.0;
-						}
-						else if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage.
-						{
-							damage = float(iMaxHealth) * GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy_backstab", 0.25);
-							if (damagetype & DMG_ACID) damage /= 3.0;
-						}
-					
-						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitenemy");
-						if (g_iPlayerProxyControl[attacker] > 100)
-						{
-							g_iPlayerProxyControl[attacker] = 100;
-						}
-						
-						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy", 1.0);
-					}
-					
-					return Plugin_Changed;
-				}
-				else if (g_bPlayerProxy[victim])
-				{
-					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[victim]);
-					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
-					{
-						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitbyenemy");
-						if (g_iPlayerProxyControl[attacker] > 100)
-						{
-							g_iPlayerProxyControl[attacker] = 100;
-						}
-						
-						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_self", 1.0);
-					}
-					
-					return Plugin_Changed;
-				}
-			}
-			*/
-			else
-			{
-				damage = 0.0;
-				return Plugin_Changed;
-			}
-		}
-		else
-		{
-			if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
-			{
-				damage = 0.0;
-				return Plugin_Changed;
-			}
-		}
-		
-		if (IsClientInGhostMode(victim))
-		{
-			damage = 0.0;
-			return Plugin_Changed;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_TEFireBullets(const String:te_name[], const Players[], numClients, Float:delay)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	new client = TE_ReadNum("m_iPlayer") + 1;
-	if (IsValidClient(client))
-	{
-		if (GetConVarBool(g_cvPlayerFakeLagCompensation))
-		{
-			if ((IsRoundInWarmup() || IsClientInPvP(client)))
-			{
-				ClientEnableFakeLagCompensation(client);
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-ClientResetStatic(client)
-{
-	g_iPlayerStaticMaster[client] = -1;
-	g_hPlayerStaticTimer[client] = INVALID_HANDLE;
-	g_flPlayerStaticIncreaseRate[client] = 0.0;
-	g_flPlayerStaticDecreaseRate[client] = 0.0;
-	g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-	g_flPlayerLastStaticTime[client] = 0.0;
-	g_flPlayerLastStaticVolume[client] = 0.0;
-	g_bPlayerInStaticShake[client] = false;
-	g_iPlayerStaticShakeMaster[client] = -1;
-	g_flPlayerStaticShakeMinVolume[client] = 0.0;
-	g_flPlayerStaticShakeMaxVolume[client] = 0.0;
-	g_flPlayerStaticAmount[client] = 0.0;
-	
-	if (IsClientInGame(client))
-	{
-		if (g_strPlayerStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticSound[client]);
-		if (g_strPlayerLastStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-		if (g_strPlayerStaticShakeSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
-	}
-	
-	strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
-	strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), "");
-	strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
-}
-
-ClientResetHints(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetHints(%d)", client);
-#endif
-
-	for (new i = 0; i < PlayerHint_MaxNum; i++)
-	{
-		g_bPlayerHints[client][i] = false;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetHints(%d)", client);
-#endif
-}
-
-ClientShowHint(client, iHint)
-{
-	g_bPlayerHints[client][iHint] = true;
-	
-	switch (iHint)
-	{
-		case PlayerHint_Sprint: PrintHintText(client, "%T", "SF2 Hint Sprint", client);
-		case PlayerHint_Flashlight: PrintHintText(client, "%T", "SF2 Hint Flashlight", client);
-		case PlayerHint_Blink: PrintHintText(client, "%T", "SF2 Hint Blink", client);
-		case PlayerHint_MainMenu: PrintHintText(client, "%T", "SF2 Hint Main Menu", client);
-	}
-}
-
-bool:DidClientEscape(client)
-{
-	return g_bPlayerEscaped[client];
-}
-
-ClientEscape(client)
-{
-	if (DidClientEscape(client)) return;
-
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("START ClientEscape(%d)", client);
-#endif
-	
-	g_bPlayerEscaped[client] = true;
-	
-	ClientResetBreathing(client);
-	ClientResetSprint(client);
-	ClientResetFlashlight(client);
-	ClientDeactivateUltravision(client);
-	ClientDisableConstantGlow(client);
-	
-	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
-	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
-	
-	HandlePlayerHUD(client);
-	
-	decl String:sName[MAX_NAME_LENGTH];
-	GetClientName(client, sName, sizeof(sName));
-	CPrintToChatAll("%t", "SF2 Player Escaped", sName);
-	
-	CheckRoundWinConditions();
-	
-	Call_StartForward(fOnClientEscape);
-	Call_PushCell(client);
-	Call_Finish();
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("END ClientEscape(%d)", client);
-#endif
-}
-
-public Action:Timer_TeleportPlayerToEscapePoint(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (!DidClientEscape(client)) return;
-	
-	if (IsPlayerAlive(client))
-	{
-		TeleportClientToEscapePoint(client);
-	}
-}
-
-stock Float:ClientGetDistanceFromEntity(client, entity)
-{
-	decl Float:flStartPos[3], Float:flEndPos[3];
-	GetClientAbsOrigin(client, flStartPos);
-	GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", flEndPos);
-	return GetVectorDistance(flStartPos, flEndPos);
-}
-
-ClientEnableFakeLagCompensation(client)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client) || g_bPlayerLagCompensation[client]) return;
-	
-	// Can only enable lag compensation if we're in either of these two teams only.
-	new iMyTeam = GetClientTeam(client);
-	if (iMyTeam != _:TFTeam_Red && iMyTeam != _:TFTeam_Blue) return;
-	
-	// Can only enable lag compensation if there are other active teammates around. This is to prevent spontaneous round restarting.
-	new iCount;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (i == client) continue;
-		
-		if (IsValidClient(i) && IsPlayerAlive(i))
-		{
-			new iTeam = GetClientTeam(i);
-			if ((iTeam == _:TFTeam_Red || iTeam == _:TFTeam_Blue) && iTeam == iMyTeam)
-			{
-				iCount++;
-			}
-		}
-	}
-	
-	if (!iCount) return;
-	
-	// Can only enable lag compensation only for specific weapons.
-	new iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
-	if (!IsValidEdict(iActiveWeapon)) return;
-	
-	decl String:sClassName[64];
-	GetEdictClassname(iActiveWeapon, sClassName, sizeof(sClassName));
-	
-	new bool:bCompensate = false;
-	for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
-	{
-		if (StrEqual(sClassName, g_strPlayerLagCompensationWeapons[i], false))
-		{
-			bCompensate = true;
-			break;
-		}
-	}
-	
-	if (!bCompensate) return;
-	
-	g_bPlayerLagCompensation[client] = true;
-	g_iPlayerLagCompensationTeam[client] = iMyTeam;
-	SetEntProp(client, Prop_Send, "m_iTeamNum", 0);
-}
-
-ClientDisableFakeLagCompensation(client)
-{
-	if (!g_bPlayerLagCompensation[client]) return;
-	
-	SetEntProp(client, Prop_Send, "m_iTeamNum", g_iPlayerLagCompensationTeam[client]);
-	g_bPlayerLagCompensation[client] = false;
-	g_iPlayerLagCompensationTeam[client] = -1;
-}
-
-//	==========================================================
-//	FLASHLIGHT / ULTRAVISION FUNCTIONS
-//	==========================================================
-
-bool:IsClientUsingFlashlight(client)
-{
-	return g_bPlayerFlashlight[client];
-}
-
-Float:ClientGetFlashlightBatteryLife(client)
-{
-	return g_flPlayerFlashlightBatteryLife[client];
-}
-
-ClientSetFlashlightBatteryLife(client, Float:flPercent)
-{
-	g_flPlayerFlashlightBatteryLife[client] = flPercent;
-}
-
-/**
- *	Called in Hook_ClientPreThink, this makes sure the flashlight is oriented correctly on the player.
- */
-static ClientProcessFlashlightAngles(client)
-{
-	if (!IsClientInGame(client)) return;
-	
-	if (IsPlayerAlive(client))
-	{
-		decl fl, Float:eyeAng[3], Float:ang2[3];
-		
-		if (IsClientUsingFlashlight(client))
-		{
-			fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
-			if (fl && fl != INVALID_ENT_REFERENCE)
-			{
-				TeleportEntity(fl, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 }, NULL_VECTOR);
-			}
-			
-			fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
-			if (fl && fl != INVALID_ENT_REFERENCE)
-			{
-				GetClientEyeAngles(client, eyeAng);
-				GetClientAbsAngles(client, ang2);
-				SubtractVectors(eyeAng, ang2, eyeAng);
-				TeleportEntity(fl, NULL_VECTOR, eyeAng, NULL_VECTOR);
-			}
-		}
-	}
-}
-
-/**
- *	Handles whether or not the player's flashlight should be "flickering", a sign of a dying flashlight battery.
- */
-static ClientHandleFlashlightFlickerState(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	if (IsClientUsingFlashlight(client))
-	{
-		new bool:bFlicker = bool:(ClientGetFlashlightBatteryLife(client) <= SF2_FLASHLIGHT_FLICKERAT);
-	
-		new fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
-		if (fl && fl != INVALID_ENT_REFERENCE)
-		{
-			if (bFlicker)
-			{
-				SetEntProp(fl, Prop_Data, "m_LightStyle", 10);
-			}
-			else
-			{
-				SetEntProp(fl, Prop_Data, "m_LightStyle", 0);
-			}
-		}
-		
-		fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
-		if (fl && fl != INVALID_ENT_REFERENCE)
-		{
-			if (bFlicker) 
-			{
-				SetEntityRenderFx(fl, RenderFx:13);
-			}
-			else 
-			{
-				SetEntityRenderFx(fl, RenderFx:0);
-			}
-		}
-	}
-}
-
-bool:IsClientFlashlightBroken(client)
-{
-	return g_bPlayerFlashlightBroken[client];
-}
-
-Float:ClientGetFlashlightNextInputTime(client)
-{
-	return g_flPlayerFlashlightNextInputTime[client];
-}
-
-/**
- *	Breaks the player's flashlight. Nothing else.
- */
-ClientBreakFlashlight(client)
-{
-	if (IsClientFlashlightBroken(client)) return;
-	
-	g_bPlayerFlashlightBroken[client] = true;
-	
-	ClientSetFlashlightBatteryLife(client, 0.0);
-	ClientTurnOffFlashlight(client);
-	
-	ClientAddStress(client, 0.2);
-	
-	EmitSoundToAll(FLASHLIGHT_BREAKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
-	
-	Call_StartForward(fOnClientBreakFlashlight);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-/**
- *	Resets everything of the player's flashlight.
- */
-ClientResetFlashlight(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetFlashlight(%d)", client);
-#endif
-	
-	ClientTurnOffFlashlight(client);
-	ClientSetFlashlightBatteryLife(client, 1.0);
-	g_bPlayerFlashlightBroken[client] = false;
-	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
-	g_flPlayerFlashlightNextInputTime[client] = -1.0;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetFlashlight(%d)", client);
-#endif
-}
-
-public Action:Hook_FlashlightSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (EntRefToEntIndex(g_iPlayerFlashlightEnt[other]) != ent) return Plugin_Handled;
-	
-	// We've already checked for flashlight ownership in the last statement. So we can do just this.
-	if (g_iPlayerPreferences[other][PlayerPreference_ProjectedFlashlight]) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_Flashlight2SetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[other]) == ent) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-public Hook_FlashlightEndSpawnPost(ent)
-{
-	if (!g_bEnabled) return;
-
-	SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightEndSetTransmit);
-	SDKUnhook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
-}
-
-public Action:Hook_FlashlightBeamSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	new iOwner = -1;
-	new iSpotlight = -1;
-	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
-	{
-		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
-		{
-			iOwner = iSpotlight;
-			break;
-		}
-	}
-	
-	if (iOwner == -1) return Plugin_Continue;
-	
-	new iClient = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
-		{
-			iClient = i;
-			break;
-		}
-	}
-	
-	if (iClient == -1) return Plugin_Continue;
-	
-	if (iClient == other)
-	{
-		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
-		{
-			return Plugin_Handled;
-		}
-	}
-	/*
-	else
-	{
-		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-		{
-			return Plugin_Handled;
-		}
-	}
-	*/
-	return Plugin_Continue;
-}
-
-public Action:Hook_FlashlightEndSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	new iOwner = -1;
-	new iSpotlight = -1;
-	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
-	{
-		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
-		{
-			iOwner = iSpotlight;
-			break;
-		}
-	}
-	
-	if (iOwner == -1) return Plugin_Continue;
-	
-	new iClient = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
-		{
-			iClient = i;
-			break;
-		}
-	}
-	
-	if (iClient == -1) return Plugin_Continue;
-	
-	if (iClient == other)
-	{
-		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
-		{
-			return Plugin_Handled;
-		}
-	}
-	/*
-	else
-	{
-		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-		{
-			return Plugin_Handled;
-		}
-	}
-	*/
-	return Plugin_Continue;
-}
-
-public Action:Timer_DrainFlashlight(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
-	
-	new iOverride = GetConVarInt(g_cvPlayerInfiniteFlashlightOverride);
-	if ((!g_bRoundInfiniteFlashlight && iOverride != 1) || iOverride == 0)
-	{
-		ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) - 0.01);
-	}
-	
-	if (ClientGetFlashlightBatteryLife(client) <= 0.0)
-	{
-		// Break the player's flashlight, but also start recharging.
-		ClientBreakFlashlight(client);
-		ClientStartRechargingFlashlightBattery(client);
-		ClientActivateUltravision(client);
-		return Plugin_Stop;
-	}
-	else
-	{
-		ClientHandleFlashlightFlickerState(client);
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_RechargeFlashlight(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
-	
-	ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) + 0.01);
-	
-	if (IsClientFlashlightBroken(client) && ClientGetFlashlightBatteryLife(client) >= SF2_FLASHLIGHT_ENABLEAT)
-	{
-		// Repair the flashlight.
-		g_bPlayerFlashlightBroken[client] = false;
-	}
-	
-	if (ClientGetFlashlightBatteryLife(client) >= 1.0)
-	{
-		// I am fully charged!
-		ClientSetFlashlightBatteryLife(client, 1.0);
-		g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
-		
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-/**
- *	Turns on the player's flashlight. Nothing else.
- */
-ClientTurnOnFlashlight(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	if (IsClientUsingFlashlight(client)) return;
-	
-	g_bPlayerFlashlight[client] = true;
-	
-	decl Float:flEyePos[3];
-	GetClientEyePosition(client, flEyePos);
-	
-	if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
-	{
-		// If the player is using the projected flashlight, just set effect flags.
-		new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-		if (!(iEffects & (1 << 2)))
-		{
-			SetEntProp(client, Prop_Send, "m_fEffects", iEffects | (1 << 2));
-		}
-	}
-	else
-	{
-		// Spawn the light which only the user will see.
-		new ent = CreateEntityByName("light_dynamic");
-		if (ent != -1)
-		{
-			TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
-			DispatchKeyValue(ent, "targetname", "WUBADUBDUBMOTHERBUCKERS");
-			DispatchKeyValue(ent, "rendercolor", "255 255 255");
-			SetVariantFloat(SF2_FLASHLIGHT_WIDTH);
-			AcceptEntityInput(ent, "spotlight_radius");
-			SetVariantFloat(SF2_FLASHLIGHT_LENGTH);
-			AcceptEntityInput(ent, "distance");
-			SetVariantInt(SF2_FLASHLIGHT_BRIGHTNESS);
-			AcceptEntityInput(ent, "brightness");
-			
-			// Convert WU to inches.
-			new Float:cone = 55.0;
-			cone *= 0.75;
-			
-			SetVariantInt(RoundToFloor(cone));
-			AcceptEntityInput(ent, "_inner_cone");
-			SetVariantInt(RoundToFloor(cone));
-			AcceptEntityInput(ent, "_cone");
-			DispatchSpawn(ent);
-			ActivateEntity(ent);
-			SetVariantString("!activator");
-			AcceptEntityInput(ent, "SetParent", client);
-			AcceptEntityInput(ent, "TurnOn");
-			
-			g_iPlayerFlashlightEnt[client] = EntIndexToEntRef(ent);
-			
-			SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightSetTransmit);
-		}
-	}
-	
-	// Spawn the light that only everyone else will see.
-	new ent = CreateEntityByName("point_spotlight");
-	if (ent != -1)
-	{
-		TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
-		
-		decl String:sBuffer[256];
-		FloatToString(SF2_FLASHLIGHT_LENGTH, sBuffer, sizeof(sBuffer));
-		DispatchKeyValue(ent, "spotlightlength", sBuffer);
-		FloatToString(SF2_FLASHLIGHT_WIDTH, sBuffer, sizeof(sBuffer));
-		DispatchKeyValue(ent, "spotlightwidth", sBuffer);
-		DispatchKeyValue(ent, "rendercolor", "255 255 255");
-		DispatchSpawn(ent);
-		ActivateEntity(ent);
-		SetVariantString("!activator");
-		AcceptEntityInput(ent, "SetParent", client);
-		AcceptEntityInput(ent, "LightOn");
-		
-		g_iPlayerFlashlightEntAng[client] = EntIndexToEntRef(ent);
-	}
-	
-	Call_StartForward(fOnClientActivateFlashlight);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-/**
- *	Turns off the player's flashlight. Nothing else.
- */
-ClientTurnOffFlashlight(client)
-{
-	if (!IsClientUsingFlashlight(client)) return;
-	
-	g_bPlayerFlashlight[client] = false;
-	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
-	
-	// Remove user-only light.
-	new ent = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE) 
-	{
-		AcceptEntityInput(ent, "TurnOff");
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	// Remove everyone-else-only light.
-	ent = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE) 
-	{
-		AcceptEntityInput(ent, "LightOff");
-		CreateTimer(0.1, Timer_KillEntity, g_iPlayerFlashlightEntAng[client], TIMER_FLAG_NO_MAPCHANGE);
-	}
-	
-	g_iPlayerFlashlightEnt[client] = INVALID_ENT_REFERENCE;
-	g_iPlayerFlashlightEntAng[client] = INVALID_ENT_REFERENCE;
-	
-	if (IsClientInGame(client))
-	{
-		if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
-		{
-			new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-			if (iEffects & (1 << 2))
-			{
-				SetEntProp(client, Prop_Send, "m_fEffects", iEffects &= ~(1 << 2));
-			}
-		}
-	}
-	
-	Call_StartForward(fOnClientDeactivateFlashlight);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-ClientStartRechargingFlashlightBattery(client)
-{
-	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(SF2_FLASHLIGHT_RECHARGE_RATE, Timer_RechargeFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStartDrainingFlashlightBattery(client)
-{
-	new Float:flDrainRate = SF2_FLASHLIGHT_DRAIN_RATE;
-	if (TF2_GetPlayerClass(client) == TFClass_Engineer) 
-	{
-		// Engineers have a 33% longer battery life, basically.
-		// TODO: Make this value customizable via cvar.
-		flDrainRate *= 1.33;
-	}
-	
-	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(flDrainRate, Timer_DrainFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientHandleFlashlight(client)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client)) return;
-	
-	if (IsClientUsingFlashlight(client)) 
-	{
-		ClientTurnOffFlashlight(client);
-		ClientStartRechargingFlashlightBattery(client);
-		ClientActivateUltravision(client);
-		
-		g_flPlayerFlashlightNextInputTime[client] = GetGameTime() + SF2_FLASHLIGHT_COOLDOWN;
-		
-		EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
-	}
-	else
-	{
-		// Only players in the "game" can use the flashlight.
-		if (!g_bPlayerEliminated[client])
-		{
-			new bool:bCanUseFlashlight = true;
-			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_LIGHTSOUT) 
-			{
-				// Unequip the flashlight please.
-				bCanUseFlashlight = false;
-			}
-			
-			if (!IsClientFlashlightBroken(client) && bCanUseFlashlight)
-			{
-				ClientTurnOnFlashlight(client);
-				ClientStartDrainingFlashlightBattery(client);
-				ClientDeactivateUltravision(client);
-				
-				g_flPlayerFlashlightNextInputTime[client] = GetGameTime();
-				
-				EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
-			}
-			else
-			{
-				EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
-			}
-		}
-	}
-}
-
-bool:IsClientUsingUltravision(client)
-{
-	return g_bPlayerUltravision[client];
-}
-
-ClientActivateUltravision(client)
-{
-	if (!IsClientInGame(client) || IsClientUsingUltravision(client)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientActivateUltravision(%d)", client);
-#endif
-	
-	g_bPlayerUltravision[client] = true;
-	
-	new ent = CreateEntityByName("light_dynamic");
-	if (ent != -1)
-	{
-		decl Float:flEyePos[3];
-		GetClientEyePosition(client, flEyePos);
-		
-		TeleportEntity(ent, flEyePos, Float:{ 90.0, 0.0, 0.0 }, NULL_VECTOR);
-		DispatchKeyValue(ent, "rendercolor", "0 200 255");
-		
-		new Float:flRadius = 0.0;
-		if (g_bPlayerEliminated[client])
-		{
-			flRadius = GetConVarFloat(g_cvUltravisionRadiusBlue);
-		}
-		else
-		{
-			flRadius = GetConVarFloat(g_cvUltravisionRadiusRed);
-		}
-		
-		SetVariantFloat(flRadius);
-		AcceptEntityInput(ent, "spotlight_radius");
-		SetVariantFloat(flRadius);
-		AcceptEntityInput(ent, "distance");
-		
-		SetVariantInt(-15); // Start dark, then fade in via the Timer_UltravisionFadeInEffect timer func.
-		AcceptEntityInput(ent, "brightness");
-		
-		// Convert WU to inches.
-		new Float:cone = SF2_ULTRAVISION_CONE;
-		cone *= 0.75;
-		
-		SetVariantInt(RoundToFloor(cone));
-		AcceptEntityInput(ent, "_inner_cone");
-		SetVariantInt(0);
-		AcceptEntityInput(ent, "_cone");
-		DispatchSpawn(ent);
-		ActivateEntity(ent);
-		SetVariantString("!activator");
-		AcceptEntityInput(ent, "SetParent", client);
-		AcceptEntityInput(ent, "TurnOn");
-		SetEntityRenderFx(ent, RENDERFX_SOLID_SLOW);
-		SetEntityRenderColor(ent, 100, 200, 255, 255);
-		
-		g_iPlayerUltravisionEnt[client] = EntIndexToEntRef(ent);
-		
-		SDKHook(ent, SDKHook_SetTransmit, Hook_UltravisionSetTransmit);
-		
-		// Fade in effect.
-		CreateTimer(0.0, Timer_UltravisionFadeInEffect, g_iPlayerUltravisionEnt[client], TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	}
-
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientActivateUltravision(%d)", client);
-#endif
-}
-
-public Action:Timer_UltravisionFadeInEffect(Handle:timer, any:entref)
-{
-	new ent = EntRefToEntIndex(entref);
-	if (!ent || ent == INVALID_ENT_REFERENCE) return Plugin_Stop;
-	
-	new iBrightness = GetEntProp(ent, Prop_Send, "m_Exponent");
-	if (iBrightness >= GetConVarInt(g_cvUltravisionBrightness)) return Plugin_Stop;
-	
-	iBrightness++;
-	SetVariantInt(iBrightness);
-	AcceptEntityInput(ent, "brightness");
-	
-	return Plugin_Continue;
-}
-
-ClientDeactivateUltravision(client)
-{
-	if (!IsClientUsingUltravision(client)) return;
-	
-	g_bPlayerUltravision[client] = false;
-	
-	new ent = EntRefToEntIndex(g_iPlayerUltravisionEnt[client]);
-	if (ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "TurnOff");
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	g_iPlayerUltravisionEnt[client] = INVALID_ENT_REFERENCE;
-}
-
-public Action:Hook_UltravisionSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (!GetConVarBool(g_cvUltravisionEnabled) || EntRefToEntIndex(g_iPlayerUltravisionEnt[other]) != ent || !IsPlayerAlive(other)) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-static Float:ClientGetDefaultWalkSpeed(client)
-{
-	new Float:flReturn = 190.0;
-	new Float:flReturn2 = flReturn;
-	new Action:iAction = Plugin_Continue;
-	new TFClassType:iClass = TF2_GetPlayerClass(client);
-	
-	switch (iClass)
-	{
-		case TFClass_Scout: flReturn = 190.0;
-		case TFClass_Sniper: flReturn = 190.0;
-		case TFClass_Soldier: flReturn = 190.0;
-		case TFClass_DemoMan: flReturn = 190.0;
-		case TFClass_Heavy: flReturn = 190.0;
-		case TFClass_Medic: flReturn = 190.0;
-		case TFClass_Pyro: flReturn = 190.0;
-		case TFClass_Spy: flReturn = 190.0;
-		case TFClass_Engineer: flReturn = 190.0;
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnClientGetDefaultWalkSpeed);
-	Call_PushCell(client);
-	Call_PushCellRef(flReturn2);
-	Call_Finish(iAction);
-	
-	if (iAction == Plugin_Changed) flReturn = flReturn2;
-	
-	return flReturn;
-}
-
-static Float:ClientGetDefaultSprintSpeed(client)
-{
-	new Float:flReturn = 300.0;
-	new Float:flReturn2 = flReturn;
-	new Action:iAction = Plugin_Continue;
-	new TFClassType:iClass = TF2_GetPlayerClass(client);
-	
-	switch (iClass)
-	{
-		case TFClass_Scout: flReturn = 300.0;
-		case TFClass_Sniper: flReturn = 300.0;
-		case TFClass_Soldier: flReturn = 275.0;
-		case TFClass_DemoMan: flReturn = 285.0;
-		case TFClass_Heavy: flReturn = 270.0;
-		case TFClass_Medic: flReturn = 300.0;
-		case TFClass_Pyro: flReturn = 300.0;
-		case TFClass_Spy: flReturn = 300.0;
-		case TFClass_Engineer: flReturn = 300.0;
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnClientGetDefaultSprintSpeed);
-	Call_PushCell(client);
-	Call_PushCellRef(flReturn2);
-	Call_Finish(iAction);
-	
-	if (iAction == Plugin_Changed) flReturn = flReturn2;
-	
-	return flReturn;
-}
-
-// Static shaking should only affect the x, y portion of the player's view, not roll.
-// This is purely for cosmetic effect.
-
-ClientProcessStaticShake(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	new bool:bOldStaticShake = g_bPlayerInStaticShake[client];
-	new iOldStaticShakeMaster = NPCGetFromUniqueID(g_iPlayerStaticShakeMaster[client]);
-	new iNewStaticShakeMaster = -1;
-	new Float:flNewStaticShakeMasterAnger = -1.0;
-	
-	new Float:flOldPunchAng[3], Float:flOldPunchAngVel[3];
-	GetEntDataVector(client, g_offsPlayerPunchAngle, flOldPunchAng);
-	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flOldPunchAngVel);
-	
-	new Float:flNewPunchAng[3], Float:flNewPunchAngVel[3];
-	
-	for (new i = 0; i < 3; i++)
-	{
-		flNewPunchAng[i] = flOldPunchAng[i];
-		flNewPunchAngVel[i] = flOldPunchAngVel[i];
-	}
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		if (g_iPlayerStaticMode[client][i] != Static_Increase) continue;
-		if (!(NPCGetFlags(i) & SFF_HASSTATICSHAKE)) continue;
-		
-		if (NPCGetAnger(i) > flNewStaticShakeMasterAnger)
-		{
-			new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
-			if (iMaster == -1) iMaster = i;
-			
-			iNewStaticShakeMaster = iMaster;
-			flNewStaticShakeMasterAnger = NPCGetAnger(iMaster);
-		}
-	}
-	
-	if (iNewStaticShakeMaster != -1)
-	{
-		g_iPlayerStaticShakeMaster[client] = NPCGetUniqueID(iNewStaticShakeMaster);
-		
-		if (iNewStaticShakeMaster != iOldStaticShakeMaster)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iNewStaticShakeMaster, sProfile, sizeof(sProfile));
-		
-			if (g_strPlayerStaticShakeSound[client][0])
-			{
-				StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
-			}
-			
-			g_flPlayerStaticShakeMinVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_min", 0.0);
-			g_flPlayerStaticShakeMaxVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_max", 1.0);
-			
-			decl String:sStaticSound[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_static_shake_local", sStaticSound, sizeof(sStaticSound));
-			if (sStaticSound[0])
-			{
-				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), sStaticSound);
-			}
-			else
-			{
-				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
-			}
-		}
-	}
-	
-	if (g_bPlayerInStaticShake[client])
-	{
-		if (g_flPlayerStaticAmount[client] <= 0.0)
-		{
-			g_bPlayerInStaticShake[client] = false;
-		}
-	}
-	else
-	{
-		if (iNewStaticShakeMaster != -1)
-		{
-			g_bPlayerInStaticShake[client] = true;
-		}
-	}
-	
-	if (g_bPlayerInStaticShake[client] && !bOldStaticShake)
-	{	
-		for (new i = 0; i < 2; i++)
-		{
-			flNewPunchAng[i] = 0.0;
-			flNewPunchAngVel[i] = 0.0;
-		}
-		
-		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
-		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
-	}
-	else if (!g_bPlayerInStaticShake[client] && bOldStaticShake)
-	{
-		for (new i = 0; i < 2; i++)
-		{
-			flNewPunchAng[i] = 0.0;
-			flNewPunchAngVel[i] = 0.0;
-		}
-	
-		g_iPlayerStaticShakeMaster[client] = -1;
-		
-		if (g_strPlayerStaticShakeSound[client][0])
-		{
-			StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
-		}
-		
-		strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
-		
-		g_flPlayerStaticShakeMinVolume[client] = 0.0;
-		g_flPlayerStaticShakeMaxVolume[client] = 0.0;
-		
-		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
-		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
-	}
-	
-	if (g_bPlayerInStaticShake[client])
-	{
-		if (g_strPlayerStaticShakeSound[client][0])
-		{
-			new Float:flVolume = g_flPlayerStaticAmount[client];
-			if (GetRandomFloat(0.0, 1.0) <= 0.35)
-			{
-				flVolume = 0.0;
-			}
-			else
-			{
-				if (flVolume < g_flPlayerStaticShakeMinVolume[client])
-				{
-					flVolume = g_flPlayerStaticShakeMinVolume[client];
-				}
-				
-				if (flVolume > g_flPlayerStaticShakeMaxVolume[client])
-				{
-					flVolume = g_flPlayerStaticShakeMaxVolume[client];
-				}
-			}
-			
-			EmitSoundToClient(client, g_strPlayerStaticShakeSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL | SND_STOP, flVolume);
-		}
-		
-		// Spazz our view all over the place.
-		for (new i = 0; i < 2; i++) flNewPunchAng[i] = AngleNormalize(GetRandomFloat(0.0, 360.0));
-		NormalizeVector(flNewPunchAng, flNewPunchAng);
-		
-		new Float:flAngVelocityScalar = 5.0 * g_flPlayerStaticAmount[client];
-		if (flAngVelocityScalar < 1.0) flAngVelocityScalar = 1.0;
-		ScaleVector(flNewPunchAng, flAngVelocityScalar);
-		
-		for (new i = 0; i < 2; i++) flNewPunchAngVel[i] = 0.0;
-		
-		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
-		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
-	}
-}
-
-ClientProcessVisibility(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	new String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	new bool:bWasSeeingSlender[MAX_BOSSES];
-	new iOldStaticMode[MAX_BOSSES];
-	
-	decl Float:flSlenderPos[3];
-	decl Float:flSlenderEyePos[3];
-	decl Float:flSlenderOBBCenterPos[3];
-	
-	decl Float:flMyPos[3];
-	GetClientAbsOrigin(client, flMyPos);
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		bWasSeeingSlender[i] = g_bPlayerSeesSlender[client][i];
-		iOldStaticMode[i] = g_iPlayerStaticMode[client][i];
-		g_bPlayerSeesSlender[client][i] = false;
-		g_iPlayerStaticMode[client][i] = Static_None;
-		
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		new iBoss = NPCGetEntIndex(i);
-		
-		if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-		{
-			SlenderGetAbsOrigin(i, flSlenderPos);
-			NPCGetEyePosition(i, flSlenderEyePos);
-			
-			decl Float:flSlenderMins[3], Float:flSlenderMaxs[3];
-			GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flSlenderMins);
-			GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flSlenderMaxs);
-			
-			for (new i2 = 0; i2 < 3; i2++) flSlenderOBBCenterPos[i2] = flSlenderPos[i2] + ((flSlenderMins[i2] + flSlenderMaxs[i2]) / 2.0);
-		}
-		
-		if (IsClientInGhostMode(client))
-		{
-		}
-		else if (!IsClientInDeathCam(client))
-		{
-			if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-			{
-				new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
-				
-				if (!IsPointVisibleToPlayer(client, flSlenderEyePos, true, SlenderUsesBlink(i)))
-				{
-					g_bPlayerSeesSlender[client][i] = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, true, SlenderUsesBlink(i));
-				}
-				else
-				{
-					g_bPlayerSeesSlender[client][i] = true;
-				}
-				
-				if ((GetGameTime() - g_flPlayerSeesSlenderLastTime[client][i]) > GetProfileFloat(sProfile, "static_on_look_gracetime", 1.0) ||
-					(iOldStaticMode[i] == Static_Increase && g_flPlayerStaticAmount[client] > 0.1))
-				{
-					if ((NPCGetFlags(i) & SFF_STATICONLOOK) && 
-						g_bPlayerSeesSlender[client][i])
-					{
-						if (iCopyMaster != -1)
-						{
-							g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
-						}
-						else
-						{
-							g_iPlayerStaticMode[client][i] = Static_Increase;
-						}
-					}
-					else if ((NPCGetFlags(i) & SFF_STATICONRADIUS) && 
-						GetVectorDistance(flMyPos, flSlenderPos) <= g_flSlenderStaticRadius[i])
-					{
-						new bool:bNoObstacles = IsPointVisibleToPlayer(client, flSlenderEyePos, false, false);
-						if (!bNoObstacles) bNoObstacles = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, false);
-						
-						if (bNoObstacles)
-						{
-							if (iCopyMaster != -1)
-							{
-								g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
-							}
-							else
-							{
-								g_iPlayerStaticMode[client][i] = Static_Increase;
-							}
-						}
-					}
-				}
-				
-				// Process death cam sequence conditions
-				if (SlenderKillsOnNear(i))
-				{
-					if (g_flPlayerStaticAmount[client] >= 1.0 ||
-						GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetInstantKillRadius(i))
-					{
-						new bool:bKillPlayer = true;
-						if (g_flPlayerStaticAmount[client] < 1.0)
-						{
-							bKillPlayer = IsPointVisibleToPlayer(client, flSlenderEyePos, false, SlenderUsesBlink(i));
-						}
-						
-						if (!bKillPlayer) bKillPlayer = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, SlenderUsesBlink(i));
-						
-						if (bKillPlayer)
-						{
-							g_flSlenderLastKill[i] = GetGameTime();
-							
-							if (g_flPlayerStaticAmount[client] >= 1.0)
-							{
-								ClientStartDeathCam(client, NPCGetFromUniqueID(g_iPlayerStaticMaster[client]), flSlenderPos);
-							}
-							else
-							{
-								ClientStartDeathCam(client, i, flSlenderPos);
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
-		if (iMaster == -1) iMaster = i;
-		
-		// Boss visiblity.
-		if (g_bPlayerSeesSlender[client][i] && !bWasSeeingSlender[i])
-		{
-			g_flPlayerSeesSlenderLastTime[client][iMaster] = GetGameTime();
-			
-			if (GetGameTime() >= g_flPlayerScareNextTime[client][iMaster])
-			{
-				if (GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetScareRadius(i))
-				{
-					ClientPerformScare(client, iMaster);
-					
-					if (NPCHasAttribute(iMaster, "ignite player on scare"))
-					{
-						new Float:flValue = NPCGetAttributeValue(iMaster, "ignite player on scare");
-						if (flValue > 0.0) TF2_IgnitePlayer(client, client);
-					}
-				}
-				else
-				{
-					g_flPlayerScareNextTime[client][iMaster] = GetGameTime() + GetProfileFloat(sProfile, "scare_cooldown");
-				}
-			}
-			
-			if (NPCGetType(i) == SF2BossType_Static)
-			{
-				if (NPCGetFlags(i) & SFF_FAKE)
-				{
-					SlenderMarkAsFake(i);
-					return;
-				}
-			}
-			
-			Call_StartForward(fOnClientLooksAtBoss);
-			Call_PushCell(client);
-			Call_PushCell(i);
-			Call_Finish();
-		}
-		else if (!g_bPlayerSeesSlender[client][i] && bWasSeeingSlender[i])
-		{
-			g_flPlayerScareLastTime[client][iMaster] = GetGameTime();
-			
-			Call_StartForward(fOnClientLooksAwayFromBoss);
-			Call_PushCell(client);
-			Call_PushCell(i);
-			Call_Finish();
-		}
-		
-		if (g_bPlayerSeesSlender[client][i])
-		{
-			if (GetGameTime() >= g_flPlayerSightSoundNextTime[client][iMaster])
-			{
-				ClientPerformSightSound(client, i);
-			}
-		}
-		
-		if (g_iPlayerStaticMode[client][i] == Static_Increase &&
-			iOldStaticMode[i] != Static_Increase)
-		{
-			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
-			{
-				decl String:sLoopSound[PLATFORM_MAX_PATH];
-				GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
-				
-				if (sLoopSound[0])
-				{
-					EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, GetProfileNum(sProfile, "sound_static_loop_local_level", SNDLEVEL_NORMAL), SND_CHANGEVOL, 1.0);
-					ClientAddStress(client, 0.03);
-				}
-				else
-				{
-					LogError("Warning! Boss %s supports static loop local sounds, but was given a blank sound path!", sProfile);
-				}
-			}
-		}
-		else if (g_iPlayerStaticMode[client][i] != Static_Increase &&
-			iOldStaticMode[i] == Static_Increase)
-		{
-			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
-			{
-				if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-				{
-					decl String:sLoopSound[PLATFORM_MAX_PATH];
-					GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
-					
-					if (sLoopSound[0])
-					{
-						EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, _, SND_CHANGEVOL | SND_STOP, 0.0);
-					}
-				}
-			}
-		}
-	}
-	
-	// Initialize static timers.
-	new iBossLastStatic = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
-	new iBossNewStatic = -1;
-	if (iBossLastStatic != -1 && g_iPlayerStaticMode[client][iBossLastStatic] == Static_Increase)
-	{
-		iBossNewStatic = iBossLastStatic;
-	}
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		new iStaticMode = g_iPlayerStaticMode[client][i];
-		
-		// Determine new static rates.
-		if (iStaticMode != Static_Increase) continue;
-		
-		if (iBossLastStatic == -1 || 
-			g_iPlayerStaticMode[client][iBossLastStatic] != Static_Increase || 
-			NPCGetAnger(i) > NPCGetAnger(iBossLastStatic))
-		{
-			iBossNewStatic = i;
-		}
-	}
-	
-	if (iBossNewStatic != -1)
-	{
-		new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossNewStatic]);
-		if (iCopyMaster != -1)
-		{
-			iBossNewStatic = iCopyMaster;
-			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iCopyMaster);
-		}
-		else
-		{
-			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iBossNewStatic);
-		}
-	}
-	else
-	{
-		g_iPlayerStaticMaster[client] = -1;
-	}
-	
-	if (iBossNewStatic != iBossLastStatic)
-	{
-		if (!StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false))
-		{
-			// Stop last-last static sound entirely.
-			if (g_strPlayerLastStaticSound[client][0])
-			{
-				StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-			}
-		}
-		
-		// Move everything down towards the last arrays.
-		if (g_strPlayerStaticSound[client][0])
-		{
-			strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), g_strPlayerStaticSound[client]);
-		}
-		
-		if (iBossNewStatic == -1)
-		{
-			// No one is the static master.
-			g_hPlayerStaticTimer[client] = CreateTimer(g_flPlayerStaticDecreaseRate[client], 
-				Timer_ClientDecreaseStatic, 
-				GetClientUserId(client), 
-				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-				
-			TriggerTimer(g_hPlayerStaticTimer[client], true);
-		}
-		else
-		{
-			NPCGetProfile(iBossNewStatic, sProfile, sizeof(sProfile));
-		
-			strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
-			
-			new String:sStaticSound[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_static", sStaticSound, sizeof(sStaticSound), 1);
-			
-			if (sStaticSound[0]) 
-			{
-				strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), sStaticSound);
-			}
-			
-			// Cross-fade out the static sounds.
-			g_flPlayerLastStaticVolume[client] = g_flPlayerStaticAmount[client];
-			g_flPlayerLastStaticTime[client] = GetGameTime();
-			
-			g_hPlayerLastStaticTimer[client] = CreateTimer(0.0, 
-				Timer_ClientFadeOutLastStaticSound, 
-				GetClientUserId(client), 
-				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			
-			TriggerTimer(g_hPlayerLastStaticTimer[client], true);
-			
-			// Start up our own static timer.
-			new Float:flStaticIncreaseRate = GetProfileFloat(sProfile, "static_rate") / g_flRoundDifficultyModifier;
-			new Float:flStaticDecreaseRate = GetProfileFloat(sProfile, "static_rate_decay");
-			
-			g_flPlayerStaticIncreaseRate[client] = flStaticIncreaseRate;
-			g_flPlayerStaticDecreaseRate[client] = flStaticDecreaseRate;
-			
-			g_hPlayerStaticTimer[client] = CreateTimer(flStaticIncreaseRate, 
-				Timer_ClientIncreaseStatic, 
-				GetClientUserId(client), 
-				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			
-			TriggerTimer(g_hPlayerStaticTimer[client], true);
-		}
-	}
-}
-
-ClientProcessViewAngles(client)
-{
-	if ((!g_bPlayerEliminated[client] || g_bPlayerProxy[client]) && 
-		!DidClientEscape(client))
-	{
-		// Process view bobbing, if enabled.
-		// This code is based on the code in this page: https://developer.valvesoftware.com/wiki/Camera_Bob
-		// Many thanks to whomever created it in the first place.
-		
-		if (IsPlayerAlive(client))
-		{
-			if (g_bPlayerViewbobEnabled)
-			{
-				new Float:flPunchVel[3];
-			
-				if (!g_bPlayerViewbobSprintEnabled || !IsClientReallySprinting(client))
-				{
-					if (GetEntityFlags(client) & FL_ONGROUND)
-					{
-						decl Float:flVelocity[3];
-						GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
-						new Float:flSpeed = GetVectorLength(flVelocity);
-						
-						new Float:flPunchIdle[3];
-						
-						if (flSpeed > 0.0)
-						{
-							if (flSpeed >= 60.0)
-							{
-								flPunchIdle[0] = Sine(GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_X / 400.0;
-								flPunchIdle[1] = Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Y / 400.0;
-								flPunchIdle[2] = Sine(1.6 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Z / 400.0;
-								
-								AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-							}
-							
-							// Calculate roll.
-							decl Float:flForward[3], Float:flVelocityDirection[3];
-							GetClientEyeAngles(client, flForward);
-							GetVectorAngles(flVelocity, flVelocityDirection);
-							
-							new Float:flYawDiff = AngleDiff(flForward[1], flVelocityDirection[1]);
-							if (FloatAbs(flYawDiff) > 90.0) flYawDiff = AngleDiff(flForward[1] + 180.0, flVelocityDirection[1]) * -1.0;
-							
-							new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
-							new Float:flRollScalar = flSpeed / flWalkSpeed;
-							if (flRollScalar > 1.0) flRollScalar = 1.0;
-							
-							new Float:flRollScale = (flYawDiff / 90.0) * 0.25 * flRollScalar;
-							flPunchIdle[0] = 0.0;
-							flPunchIdle[1] = 0.0;
-							flPunchIdle[2] = flRollScale * -1.0;
-							
-							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-						}
-						
-						g_flPlayerBreathViewbobPhase[client] += SF2_BREATH_VIEWBOB_SPEED;
-						if(g_flPlayerBreathViewbobPhase[client] > 3.14159265355) {
-							g_flPlayerBreathViewbobPhase[client] = 0.0; // Sine cycle
-							g_flPlayerBreathViewbobXMult[client] = GetRandomFloat(-1.0, 1.0);
-							g_flPlayerBreathViewbobYMult[client] = GetRandomFloat(-1.0, 1.0);
-						}
-						new Float:sine = Sine(g_flPlayerBreathViewbobPhase[client]);
-						flPunchIdle[0] = SF2_BREATH_VIEWBOB_START * sine * g_flPlayerBreathViewbobXMult[client] + SF2_BREATH_VIEWBOB_AMPLITUDE * sine * g_flPlayerBreathViewbobXMult[client] *  float(100 - g_iPlayerSprintPoints[client]) / 100.0;
-						flPunchIdle[1] = SF2_BREATH_VIEWBOB_START / 2.0 * sine * g_flPlayerBreathViewbobYMult[client] + SF2_BREATH_VIEWBOB_AMPLITUDE / 2.0 * sine * g_flPlayerBreathViewbobYMult[client] * float(100 - g_iPlayerSprintPoints[client]) / 100.0;
-						flPunchIdle[2] = 0.0;//Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) ;//Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Z / 400.0;
-						
-						AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-						/*
-						if (flSpeed < 60.0) 
-						{
-							flPunchIdle[0] = FloatAbs(Cosine(GetGameTime() * 1.25) * 0.047);
-							flPunchIdle[1] = Sine(GetGameTime() * 1.25) * 0.075;
-							flPunchIdle[2] = 0.0;
-							
-							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-						}
-						*/
-					}
-				}
-				
-				if (g_bPlayerViewbobHurtEnabled)
-				{
-					// Shake screen the more the player is hurt.
-					new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
-					new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
-					
-					decl Float:flPunchVelHurt[3];
-					flPunchVelHurt[0] = Sine(1.22 * GetGameTime()) * 48.5 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
-					flPunchVelHurt[1] = Sine(2.12 * GetGameTime()) * 80.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
-					flPunchVelHurt[2] = Sine(0.5 * GetGameTime()) * 36.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
-					
-					AddVectors(flPunchVel, flPunchVelHurt, flPunchVel);
-				}
-				
-				ClientViewPunch(client, flPunchVel);
-			}
-		}
-	}
-}
-
-public Action:Timer_ClientIncreaseStatic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
-	
-	g_flPlayerStaticAmount[client] += 0.05;
-	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
-	
-	if (g_strPlayerStaticSound[client][0])
-	{
-		EmitSoundToClient(client, g_strPlayerStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerStaticAmount[client]);
-		
-		if (g_flPlayerStaticAmount[client] >= 0.5) ClientAddStress(client, 0.03);
-		else
-		{
-			ClientAddStress(client, 0.02);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_ClientDecreaseStatic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
-	
-	g_flPlayerStaticAmount[client] -= 0.05;
-	if (g_flPlayerStaticAmount[client] < 0.0) g_flPlayerStaticAmount[client] = 0.0;
-	
-	if (g_strPlayerLastStaticSound[client][0])
-	{
-		new Float:flVolume = g_flPlayerStaticAmount[client];
-		if (flVolume > 0.0)
-		{
-			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
-		}
-	}
-	
-	if (g_flPlayerStaticAmount[client] <= 0.0 && g_strPlayerLastStaticSound[client][0])
-	{
-		// I've done my job; no point to keep on doing it.
-		StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-		g_hPlayerStaticTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_ClientFadeOutLastStaticSound(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerLastStaticTimer[client]) return Plugin_Stop;
-	
-	if (StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false)) 
-	{
-		// Wait, the player's current static sound is the same one we're stopping. Abort!
-		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	if (g_strPlayerLastStaticSound[client][0])
-	{
-		new Float:flDiff = (GetGameTime() - g_flPlayerLastStaticTime[client]) / 1.0;
-		if (flDiff > 1.0) flDiff = 1.0;
-		
-		new Float:flVolume = g_flPlayerLastStaticVolume[client] - flDiff;
-		if (flVolume < 0.0) flVolume = 0.0;
-		
-		if (flVolume <= 0.0)
-		{
-			// I've done my job; no point to keep on doing it.
-			StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-			g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-			return Plugin_Stop;
-		}
-		else
-		{
-			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
-		}
-	}
-	else
-	{
-		// I've done my job; no point to keep on doing it.
-		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	INTERACTIVE GLOW FUNCTIONS
-//	==========================================================
-
-static ClientProcessInteractiveGlow(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client) || (g_bPlayerEliminated[client] && !g_bPlayerProxy[client]) || IsClientInGhostMode(client)) return;
-	
-	new iOldLookEntity = EntRefToEntIndex(g_iPlayerInteractiveGlowTargetEntity[client]);
-	
-	decl Float:flStartPos[3], Float:flMyEyeAng[3];
-	GetClientEyePosition(client, flStartPos);
-	GetClientEyeAngles(client, flMyEyeAng);
-	
-	new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flMyEyeAng, MASK_VISIBLE, RayType_Infinite, TraceRayDontHitPlayers, -1);
-	new iEnt = TR_GetEntityIndex(hTrace);
-	CloseHandle(hTrace);
-	
-	if (IsValidEntity(iEnt))
-	{
-		g_iPlayerInteractiveGlowTargetEntity[client] = EntRefToEntIndex(iEnt);
-	}
-	else
-	{
-		g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
-	}
-	
-	if (iEnt != iOldLookEntity)
-	{
-		ClientRemoveInteractiveGlow(client);
-		
-		if (IsEntityClassname(iEnt, "prop_dynamic", false))
-		{
-			decl String:sTargetName[64];
-			GetEntPropString(iEnt, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
-			
-			if (StrContains(sTargetName, "sf2_page", false) == 0 || StrContains(sTargetName, "sf2_interact", false) == 0)
-			{
-				ClientCreateInteractiveGlow(client, iEnt);
-			}
-		}
-	}
-}
-
-ClientResetInteractiveGlow(client)
-{
-	ClientRemoveInteractiveGlow(client);
-	g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
-}
-
-/**
- *	Removes the player's current interactive glow entity.
- */
-ClientRemoveInteractiveGlow(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientRemoveInteractiveGlow(%d)", client);
-#endif
-
-	new ent = EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	g_iPlayerInteractiveGlowEntity[client] = INVALID_ENT_REFERENCE;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientRemoveInteractiveGlow(%d)", client);
-#endif
-}
-
-/**
- *	Creates an interactive glow for an entity to show to a player.
- */
-bool:ClientCreateInteractiveGlow(client, iEnt, const String:sAttachment[]="")
-{
-	ClientRemoveInteractiveGlow(client);
-	
-	if (!IsClientInGame(client)) return false;
-	
-	if (!iEnt || !IsValidEdict(iEnt)) return false;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientCreateInteractiveGlow(%d)", client);
-#endif
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetEntPropString(iEnt, Prop_Data, "m_ModelName", sBuffer, sizeof(sBuffer));
-	
-	if (strlen(sBuffer) == 0) 
-	{
-		return false;
-	}
-	
-	new ent = CreateEntityByName("tf_taunt_prop");
-	if (ent != -1)
-	{
-		g_iPlayerInteractiveGlowEntity[client] = EntIndexToEntRef(ent);
-		
-		new Float:flModelScale = GetEntPropFloat(iEnt, Prop_Send, "m_flModelScale");
-		
-		SetEntityModel(ent, sBuffer);
-		DispatchSpawn(ent);
-		ActivateEntity(ent);
-		SetEntityRenderMode(ent, RENDER_TRANSCOLOR);
-		SetEntityRenderColor(ent, 0, 0, 0, 0);
-		SetEntProp(ent, Prop_Send, "m_bGlowEnabled", 1);
-		SetEntPropFloat(ent, Prop_Send, "m_flModelScale", flModelScale);
-		
-		new iFlags = GetEntProp(ent, Prop_Send, "m_fEffects");
-		SetEntProp(ent, Prop_Send, "m_fEffects", iFlags | (1 << 0));
-		
-		SetVariantString("!activator");
-		AcceptEntityInput(ent, "SetParent", iEnt);
-		
-		if (sAttachment[0])
-		{
-			SetVariantString(sAttachment);
-			AcceptEntityInput(ent, "SetParentAttachment");
-		}
-		
-		SDKHook(ent, SDKHook_SetTransmit, Hook_InterativeGlowSetTransmit);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> true", client);
-#endif
-		
-		return true;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> false", client);
-#endif
-	
-	return false;
-}
-
-public Action:Hook_InterativeGlowSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[other]) != ent) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	BREATHING FUNCTIONS
-//	==========================================================
-
-ClientResetBreathing(client)
-{
-	g_bPlayerBreath[client] = false;
-	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
-}
-
-Float:ClientCalculateBreathingCooldown(client)
-{
-	new Float:flAverage = 0.0;
-	new iAverageNum = 0;
-	
-	// Sprinting only, for now.
-	flAverage += (SF2_PLAYER_BREATH_COOLDOWN_MAX * 6.7765 * Pow((float(g_iPlayerSprintPoints[client]) / 100.0), 1.65));
-	iAverageNum++;
-	
-	flAverage /= float(iAverageNum)
-	
-	if (flAverage < SF2_PLAYER_BREATH_COOLDOWN_MIN) flAverage = SF2_PLAYER_BREATH_COOLDOWN_MIN;
-	
-	return flAverage;
-}
-
-ClientStartBreathing(client)
-{
-	g_bPlayerBreath[client] = true;
-	g_hPlayerBreathTimer[client] = CreateTimer(ClientCalculateBreathingCooldown(client), Timer_ClientBreath, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStopBreathing(client)
-{
-	g_bPlayerBreath[client] = false;
-	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
-}
-
-bool:ClientCanBreath(client)
-{
-	return bool:(ClientCalculateBreathingCooldown(client) < SF2_PLAYER_BREATH_COOLDOWN_MAX);
-}
-
-public Action:Timer_ClientBreath(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerBreathTimer[client]) return;
-	
-	if (!g_bPlayerBreath[client]) return;
-	
-	if (ClientCanBreath(client))
-	{
-		EmitSoundToAll(g_strPlayerBreathSounds[GetRandomInt(0, sizeof(g_strPlayerBreathSounds) - 1)], client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-		
-		ClientStartBreathing(client);
-		return;
-	}
-	
-	ClientStopBreathing(client);
-}
-
-//	==========================================================
-//	SPRINTING FUNCTIONS
-//	==========================================================
-
-bool:IsClientSprinting(client)
-{
-	return g_bPlayerSprint[client];
-}
-
-ClientGetSprintPoints(client)
-{
-	return g_iPlayerSprintPoints[client];
-}
-
-ClientResetSprint(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSprint(%d)", client);
-#endif
-
-	g_bPlayerSprint[client] = false;
-	g_iPlayerSprintPoints[client] = 100;
-	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-	
-	if (IsValidClient(client))
-	{
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-		
-		ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSprint(%d)", client);
-#endif
-}
-
-ClientStartSprint(client)
-{
-	if (IsClientSprinting(client)) return;
-	
-	g_bPlayerSprint[client] = true;
-	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-	ClientSprintTimer(client);
-	TriggerTimer(g_hPlayerSprintTimer[client], true);
-	
-	SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-	SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-}
-
-static ClientSprintTimer(client, bool:bRecharge=false)
-{
-	new Float:flRate = 0.28;
-	if (bRecharge) flRate = 0.8;
-	
-	decl Float:flVelocity[3];
-	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
-	
-	if (bRecharge)
-	{
-		if (!(GetEntityFlags(client) & FL_ONGROUND)) flRate *= 0.75;
-		else if (GetVectorLength(flVelocity) == 0.0)
-		{
-			if (GetEntProp(client, Prop_Send, "m_bDucked")) flRate *= 0.66;
-			else flRate *= 0.75;
-		}
-	}
-	else
-	{
-		if (TF2_GetPlayerClass(client) == TFClass_Scout) flRate *= 1.15;
-	}
-	
-	if (bRecharge) g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientRechargeSprint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	else g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientSprinting, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStopSprint(client)
-{
-	if (!IsClientSprinting(client)) return;
-	
-	g_bPlayerSprint[client] = false;
-	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-	ClientSprintTimer(client, true);
-	
-	SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-	SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-}
-
-bool:IsClientReallySprinting(client)
-{
-	if (!IsClientSprinting(client)) return false;
-	if (!(GetEntityFlags(client) & FL_ONGROUND)) return false;
-	
-	decl Float:flVelocity[3];
-	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
-	if (GetVectorLength(flVelocity) < 30.0) return false;
-	
-	return true;
-}
-
-public Action:Timer_ClientSprinting(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerSprintTimer[client]) return;
-	
-	if (!IsClientSprinting(client)) return;
-	
-	if (g_iPlayerSprintPoints[client] <= 0)
-	{
-		ClientStopSprint(client);
-		g_iPlayerSprintPoints[client] = 0;
-		return;
-	}
-	
-	if (IsClientReallySprinting(client)) 
-	{
-		new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
-		if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
-		{
-			g_iPlayerSprintPoints[client]--;
-		}
-	}
-	
-	ClientSprintTimer(client);
-}
-
-public Hook_ClientSprintingPreThink(client)
-{
-	if (!IsClientReallySprinting(client))
-	{
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-		SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-		return;
-	}
-	/*
-	new iFOV = GetEntData(client, g_offsPlayerDefaultFOV);
-	
-	new iTargetFOV = g_iPlayerDesiredFOV[client] + 10;
-	
-	if (iFOV < iTargetFOV)
-	{
-		new iDiff = RoundFloat(FloatAbs(float(iFOV - iTargetFOV)));
-		if (iDiff >= 1)
-		{
-			ClientSetFOV(client, iFOV + 1);
-		}
-		else
-		{
-			ClientSetFOV(client, iTargetFOV);
-		}
-	}
-	else if (iFOV >= iTargetFOV)
-	{
-		ClientSetFOV(client, iTargetFOV);
-		//SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-	}
-	*/
-}
-
-public Hook_ClientRechargeSprintPreThink(client)
-{
-	if (IsClientReallySprinting(client))
-	{
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-		SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-		return;
-	}
-	
-	new iFOV = GetEntData(client, g_offsPlayerDefaultFOV);
-	if (iFOV > g_iPlayerDesiredFOV[client])
-	{
-		new iDiff = RoundFloat(FloatAbs(float(iFOV - g_iPlayerDesiredFOV[client])));
-		if (iDiff >= 1)
-		{
-			ClientSetFOV(client, iFOV - 1);
-		}
-		else
-		{
-			ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
-		}
-	}
-	else if (iFOV <= g_iPlayerDesiredFOV[client])
-	{
-		ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
-	}
-}
-
-public Action:Timer_ClientRechargeSprint(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerSprintTimer[client]) return;
-	
-	if (IsClientSprinting(client)) 
-	{
-		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-		return;
-	}
-	
-	if (g_iPlayerSprintPoints[client] >= 100)
-	{
-		g_iPlayerSprintPoints[client] = 100;
-		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-		return;
-	}
-	
-	g_iPlayerSprintPoints[client]++;
-	ClientSprintTimer(client, true);
-}
-
-//	==========================================================
-//	PROXY / GHOST AND GLOW FUNCTIONS
-//	==========================================================
-
-ClientResetProxy(client, bool:bResetFull=true)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetProxy(%d)", client);
-#endif
-
-	new iOldMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-	new String:sOldProfileName[SF2_MAX_PROFILE_NAME_LENGTH];
-	if (iOldMaster >= 0)
-	{
-		NPCGetProfile(iOldMaster, sOldProfileName, sizeof(sOldProfileName));
-	}
-	
-	new bool:bOldProxy = g_bPlayerProxy[client];
-	if (bResetFull) 
-	{
-		g_bPlayerProxy[client] = false;
-		g_iPlayerProxyMaster[client] = -1;
-	}
-	
-	g_iPlayerProxyControl[client] = 0;
-	g_hPlayerProxyControlTimer[client] = INVALID_HANDLE;
-	g_flPlayerProxyControlRate[client] = 0.0;
-	g_flPlayerProxyVoiceTimer[client] = INVALID_HANDLE;
-	
-	if (IsClientInGame(client))
-	{
-		if (bOldProxy)
-		{
-			ClientStartProxyAvailableTimer(client);
-		
-			if (bResetFull)
-			{
-				SetVariantString("");
-				AcceptEntityInput(client, "SetCustomModel");
-			}
-			
-			if (sOldProfileName[0])
-			{
-				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_spawn", GetProfileNum(sOldProfileName, "sound_proxy_spawn_channel", SNDCHAN_AUTO));
-				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_hurt", GetProfileNum(sOldProfileName, "sound_proxy_hurt_channel", SNDCHAN_AUTO));
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetProxy(%d)", client);
-#endif
-}
-
-ClientStartProxyAvailableTimer(client)
-{
-	g_bPlayerProxyAvailable[client] = false;
-	g_hPlayerProxyAvailableTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerProxyWaitTime), Timer_ClientProxyAvailable, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStartProxyForce(client, iSlenderID, const Float:flPos[3])
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
-#endif
-
-	g_iPlayerProxyAskMaster[client] = iSlenderID;
-	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
-
-	g_iPlayerProxyAvailableCount[client] = 0;
-	g_bPlayerProxyAvailableInForce[client] = true;
-	g_hPlayerProxyAvailableTimer[client] = CreateTimer(1.0, Timer_ClientForceProxy, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerProxyAvailableTimer[client], true);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
-#endif
-}
-
-ClientStopProxyForce(client)
-{
-	g_iPlayerProxyAvailableCount[client] = 0;
-	g_bPlayerProxyAvailableInForce[client] = false;
-	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
-}
-
-public Action:Timer_ClientForceProxy(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerProxyAvailableTimer[client]) return Plugin_Stop;
-	
-	if (!IsRoundEnding())
-	{
-		new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[client]);
-		if (iBossIndex != -1)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-		
-			new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
-			new iNumProxies = 0;
-			
-			for (new iClient = 1; iClient <= MaxClients; iClient++)
-			{
-				if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-				if (!g_bPlayerProxy[iClient]) continue;
-				if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
-				
-				iNumProxies++;
-			}
-			
-			if (iNumProxies < iMaxProxies)
-			{
-				if (g_iPlayerProxyAvailableCount[client] > 0)
-				{
-					g_iPlayerProxyAvailableCount[client]--;
-					
-					SetHudTextParams(-1.0, 0.25, 
-						1.0,
-						255, 255, 255, 255,
-						_,
-						_,
-						0.25, 1.25);
-					
-					ShowSyncHudText(client, g_hHudSync, "%T", "SF2 Proxy Force Message", client, g_iPlayerProxyAvailableCount[client]);
-					
-					return Plugin_Continue;
-				}
-				else
-				{
-					ClientEnableProxy(client, iBossIndex);
-					TeleportEntity(client, g_iPlayerProxyAskPosition[client], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-				}
-			}
-			else
-			{
-				PrintToChat(client, "%T", "SF2 Too Many Proxies", client);
-			}
-		}
-	}
-	
-	ClientStopProxyForce(client);
-	return Plugin_Stop;
-}
-
-DisplayProxyAskMenu(client, iAskMaster, const Float:flPos[3])
-{
-	decl String:sBuffer[512];
-	new Handle:hMenu = CreateMenu(Menu_ProxyAsk);
-	SetMenuTitle(hMenu, "%T\n \n%T\n \n", "SF2 Proxy Ask Menu Title", client, "SF2 Proxy Ask Menu Description", client);
-	
-	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
-	AddMenuItem(hMenu, "1", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	
-	g_iPlayerProxyAskMaster[client] = iAskMaster;
-	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
-	DisplayMenu(hMenu, client, 15);
-}
-
-public Menu_ProxyAsk(Handle:menu, MenuAction:action, param1, param2)
-{
-	switch (action)
-	{
-		case MenuAction_End: CloseHandle(menu);
-		case MenuAction_Select:
-		{
-			if (!IsRoundEnding())
-			{
-				new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[param1]);
-				if (iBossIndex != -1)
-				{
-					decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-					NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-				
-					new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
-					new iNumProxies;
-				
-					for (new iClient = 1; iClient <= MaxClients; iClient++)
-					{
-						if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-						if (!g_bPlayerProxy[iClient]) continue;
-						if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
-						
-						iNumProxies++;
-					}
-					
-					if (iNumProxies < iMaxProxies)
-					{
-						if (param2 == 0)
-						{
-							ClientEnableProxy(param1, iBossIndex);
-							TeleportEntity(param1, g_iPlayerProxyAskPosition[param1], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-						}
-						else
-						{
-							ClientStartProxyAvailableTimer(param1);
-						}
-					}
-					else
-					{
-						PrintToChat(param1, "%T", "SF2 Too Many Proxies", param1);
-					}
-				}
-			}
-		}
-	}
-}
-
-public Action:Timer_ClientProxyAvailable(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerProxyAvailableTimer[client]) return;
-	
-	g_bPlayerProxyAvailable[client] = true;
-	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
-}
-
-ClientEnableProxy(client, iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1) return;
-	if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) return;
-	if (g_bPlayerProxy[client]) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	PvP_SetPlayerPvPState(client, false, false, false);
-	
-	ClientSetGhostModeState(client, false);
-	
-	ClientStopProxyForce(client);
-	
-	ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
-	if (!IsPlayerAlive(client)) TF2_RespawnPlayer(client);
-	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
-	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
-	
-	g_bPlayerProxy[client] = true;
-	g_iPlayerProxyMaster[client] = NPCGetUniqueID(iBossIndex);
-	g_iPlayerProxyControl[client] = 100;
-	g_flPlayerProxyControlRate[client] = GetProfileFloat(sProfile, "proxies_controldrainrate");
-	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	g_bPlayerProxyAvailable[client] = false;
-	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
-	
-	decl String:sAllowedClasses[512];
-	GetProfileString(sProfile, "proxies_classes", sAllowedClasses, sizeof(sAllowedClasses));
-	
-	decl String:sClassName[64];
-	TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
-	if (sAllowedClasses[0] && sClassName[0] && StrContains(sAllowedClasses, sClassName, false) == -1)
-	{
-		// Pick the first class that's allowed.
-		new String:sAllowedClassesList[32][32];
-		new iClassCount = ExplodeString(sAllowedClasses, " ", sAllowedClassesList, 32, 32);
-		if (iClassCount)
-		{
-			TF2_SetPlayerClass(client, TF2_GetClass(sAllowedClassesList[0]), _, false);
-			
-			new iMaxHealth = GetEntProp(client, Prop_Send, "m_iHealth");
-			TF2_RegeneratePlayer(client);
-			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
-			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
-		}
-	}
-	
-	UTIL_ScreenFade(client, 200, 1, FFADE_IN, 255, 255, 255, 100);
-	PrecacheSound("weapons/teleporter_send.wav");
-	EmitSoundToClient(client, "weapons/teleporter_send.wav", _, SNDCHAN_STATIC);
-	
-	ClientActivateUltravision(client);
-	
-	CreateTimer(0.33, Timer_ApplyCustomModel, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	
-	Call_StartForward(fOnClientSpawnedAsProxy);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-public Action:Timer_ClientProxyControl(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerProxyControlTimer[client]) return;
-	
-	g_iPlayerProxyControl[client]--;
-	if (g_iPlayerProxyControl[client] <= 0)
-	{
-		// ForcePlayerSuicide isn't really dependable, since the player doesn't suicide until several seconds after spawning has passed.
-		SDKHooks_TakeDamage(client, client, client, 9001.0, DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-		return;
-	}
-	
-	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, userid, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-bool:DoesClientHaveConstantGlow(client)
-{
-	return g_bPlayerConstantGlowEnabled[client];
-}
-
-ClientDisableConstantGlow(client)
-{
-	if (!DoesClientHaveConstantGlow(client)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientDisableConstantGlow(%d)", client);
-#endif
-	
-	g_bPlayerConstantGlowEnabled[client] = false;
-	
-	new iGlow = EntRefToEntIndex(g_iPlayerConstantGlowEntity[client]);
-	if (iGlow && iGlow != INVALID_ENT_REFERENCE) AcceptEntityInput(iGlow, "Kill");
-	
-	g_iPlayerConstantGlowEntity[client] = INVALID_ENT_REFERENCE;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientDisableConstantGlow(%d)", client);
-#endif
-}
-
-bool:ClientEnableConstantGlow(client, const String:sAttachment[]="")
-{
-	if (DoesClientHaveConstantGlow(client)) return true;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientEnableConstantGlow(%d)", client);
-#endif
-	
-	decl String:sModel[PLATFORM_MAX_PATH];
-	GetClientModel(client, sModel, sizeof(sModel));
-	
-	if (strlen(sModel) == 0) 
-	{
-		// For some reason the model couldn't be found, so no.
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false (no model specified)", client);
-#endif
-		
-		return false;
-	}
-	
-	new iGlow = CreateEntityByName("tf_taunt_prop");
-	if (iGlow != -1)
-	{
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> created");
-#endif
-	
-		g_bPlayerConstantGlowEnabled[client] = true;
-		g_iPlayerConstantGlowEntity[client] = EntIndexToEntRef(iGlow);
-		
-		new Float:flModelScale = GetEntPropFloat(client, Prop_Send, "m_flModelScale");
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) 
-		{
-			DebugMessage("tf_taunt_prop -> get model and model scale (%s, %f, player class: %d)", sModel, flModelScale, TF2_GetPlayerClass(client));
-		}
-#endif
-		
-		SetEntityModel(iGlow, sModel);
-		DispatchSpawn(iGlow);
-		ActivateEntity(iGlow);
-		SetEntityRenderMode(iGlow, RENDER_TRANSCOLOR);
-		SetEntityRenderColor(iGlow, 0, 0, 0, 0);
-		SetEntProp(iGlow, Prop_Send, "m_bGlowEnabled", 1);
-		SetEntPropFloat(iGlow, Prop_Send, "m_flModelScale", flModelScale);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set model and model scale");
-#endif
-		
-		// Set effect flags.
-		new iFlags = GetEntProp(iGlow, Prop_Send, "m_fEffects");
-		SetEntProp(iGlow, Prop_Send, "m_fEffects", iFlags | (1 << 0)); // EF_BONEMERGE
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set bonemerge flags");
-#endif
-		
-		SetVariantString("!activator");
-		AcceptEntityInput(iGlow, "SetParent", client);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent to client");
-#endif
-		
-		if (sAttachment[0])
-		{
-			SetVariantString(sAttachment);
-			AcceptEntityInput(iGlow, "SetParentAttachment");
-		}
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent attachment to %s", sAttachment);
-#endif
-		
-		SDKHook(iGlow, SDKHook_SetTransmit, Hook_ConstantGlowSetTransmit);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> true", client);
-#endif
-		
-		return true;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false", client);
-#endif
-	
-	return false;
-}
-
-ClientResetJumpScare(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetJumpScare(%d)", client);
-#endif
-
-	g_iPlayerJumpScareBoss[client] = -1;
-	g_flPlayerJumpScareLifeTime[client] = -1.0;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetJumpScare(%d)", client);
-#endif
-}
-
-ClientDoJumpScare(client, iBossIndex, Float:flLifeTime)
-{
-	g_iPlayerJumpScareBoss[client] = NPCGetUniqueID(iBossIndex);
-	g_flPlayerJumpScareLifeTime[client] = GetGameTime() + flLifeTime;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_jumpscare", sBuffer, sizeof(sBuffer), 1);
-	
-	if (strlen(sBuffer) > 0)
-	{
-		EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN);
-	}
-}
-
- /**
-  *	Handles sprinting upon player input.
-  */
-ClientHandleSprint(client, bool:bSprint)
-{
-	if (!IsPlayerAlive(client) || 
-		g_bPlayerEliminated[client] || 
-		DidClientEscape(client) || 
-		g_bPlayerProxy[client] || 
-		IsClientInGhostMode(client)) return;
-	
-	if (bSprint)
-	{
-		if (g_iPlayerSprintPoints[client] > 0)
-		{
-			ClientStartSprint(client);
-		}
-		else
-		{
-			EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
-		}
-	}
-	else
-	{
-		if (IsClientSprinting(client))
-		{
-			ClientStopSprint(client);
-		}
-	}
-}
-
-ClientOnButtonPress(client, button)
-{
-	switch (button)
-	{
-		case IN_ATTACK2:
-		{
-			if (IsPlayerAlive(client))
-			{
-				if (!IsRoundInWarmup() &&
-					!IsRoundInIntro() &&
-					!IsRoundEnding() && 
-					!DidClientEscape(client))
-				{
-					if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
-					{
-						ClientHandleFlashlight(client);
-					}
-				}
-			}
-		}
-		case IN_ATTACK3:
-		{
-			ClientHandleSprint(client, true);
-			if(IsClientInGhostMode(client) && g_iGhostNextHelpPhrase[client] < GetTime()) {
-				EmitSoundToAll(g_strGhostHelpPhrases[GetRandomInt(0, sizeof(g_strGhostHelpPhrases) - 1)], client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-				g_iGhostNextHelpPhrase[client] = GetTime() + g_iGhostHelpPhraseInterval;
-			}
-		}
-		case IN_RELOAD:
-		{
-			if (IsPlayerAlive(client))
-			{
-				if (!g_bPlayerEliminated[client])
-				{
-					if (!IsRoundEnding() && 
-						!IsRoundInWarmup() &&
-						!IsRoundInIntro() &&
-						!DidClientEscape(client))
-					{
-						ClientBlink(client);
-					}
-				}
-			}
-		}
-		case IN_JUMP:
-		{
-			if (IsPlayerAlive(client))
-			{
-				if (!bool:GetEntProp(client, Prop_Send, "m_bDucked") && 
-					(GetEntityFlags(client) & FL_ONGROUND) &&
-					GetEntProp(client, Prop_Send, "m_nWaterLevel") < 2)
-				{
-					ClientOnJump(client);
-				}
-			}
-		}
-	}
-}
-
-ClientOnButtonRelease(client, button)
-{
-	switch (button)
-	{
-		case IN_ATTACK3:
-		{
-			ClientHandleSprint(client, false);
-		}
-	}
-}
-
-ClientOnJump(client)
-{
-	if (!g_bPlayerEliminated[client])
-	{
-		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
-		{
-			new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
-			if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
-			{
-				g_iPlayerSprintPoints[client] -= 7;
-				if (g_iPlayerSprintPoints[client] < 0) g_iPlayerSprintPoints[client] = 0;
-			}
-			
-			if (!IsClientSprinting(client))
-			{
-				if (g_hPlayerSprintTimer[client] == INVALID_HANDLE)
-				{
-					// If the player hasn't sprinted recently, force us to regenerate the stamina.
-					ClientSprintTimer(client, true);
-				}
-			}
-		}
-	}
-}
-
-//	==========================================================
-//	DEATH CAM FUNCTIONS
-//	==========================================================
-
-bool:IsClientInDeathCam(client)
-{
-	return g_bPlayerDeathCam[client];
-}
-
-public Action:Hook_DeathCamSetTransmit(slender, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (EntRefToEntIndex(g_iPlayerDeathCamEnt2[other]) != slender) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-ClientResetDeathCam(client)
-{
-	if (!IsClientInDeathCam(client)) return; // no really need to reset if it wasn't set.
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetDeathCam(%d)", client);
-#endif
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	
-	g_iPlayerDeathCamBoss[client] = -1;
-	g_bPlayerDeathCam[client] = false;
-	g_bPlayerDeathCamShowOverlay[client] = false;
-	g_hPlayerDeathCamTimer[client] = INVALID_HANDLE;
-	
-	new ent = EntRefToEntIndex(g_iPlayerDeathCamEnt[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "Disable");
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	ent = EntRefToEntIndex(g_iPlayerDeathCamEnt2[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	g_iPlayerDeathCamEnt[client] = INVALID_ENT_REFERENCE;
-	g_iPlayerDeathCamEnt2[client] = INVALID_ENT_REFERENCE;
-	
-	if (IsClientInGame(client))
-	{
-		SetClientViewEntity(client, client);
-	}
-	
-	Call_StartForward(fOnClientEndDeathCam);
-	Call_PushCell(client);
-	Call_PushCell(iDeathCamBoss);
-	Call_Finish();
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetDeathCam(%d)", client);
-#endif
-}
-
-ClientStartDeathCam(client, iBossIndex, const Float:vecLookPos[3])
-{
-	if (IsClientInDeathCam(client)) return;
-	if (!NPCIsValid(iBossIndex)) return;
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (GetProfileNum(sProfile, "death_cam_play_scare_sound"))
-	{
-		GetRandomStringFromProfile(sProfile, "sound_scare_player", buffer, sizeof(buffer));
-		if (buffer[0]) EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-	}
-	
-	GetRandomStringFromProfile(sProfile, "sound_player_deathcam", buffer, sizeof(buffer));
-	if (strlen(buffer) > 0) 
-	{
-		EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-	}
-	else
-	{
-		// Legacy support for "sound_player_death"
-		GetRandomStringFromProfile(sProfile, "sound_player_death", buffer, sizeof(buffer));
-		if (strlen(buffer) > 0)
-		{
-			EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		}
-	}
-	
-	GetRandomStringFromProfile(sProfile, "sound_player_deathcam_all", buffer, sizeof(buffer));
-	if (strlen(buffer) > 0) 
-	{
-		EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-	}
-	else
-	{
-		// Legacy support for "sound_player_death_all"
-		GetRandomStringFromProfile(sProfile, "sound_player_death_all", buffer, sizeof(buffer));
-		if (strlen(buffer) > 0) 
-		{
-			EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		}
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnClientCaughtByBoss);
-	Call_PushCell(client);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-	
-	if (!NPCHasDeathCamEnabled(iBossIndex))
-	{
-		SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol changes our lifestate.
-		
-		// TODO: Add more attributes!
-		if (NPCHasAttribute(iBossIndex, "ignite player on death"))
-		{
-			new Float:flValue = NPCGetAttributeValue(iBossIndex, "ignite player on death");
-			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
-		}
-		
-		SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-		return;
-	}
-	
-	g_iPlayerDeathCamBoss[client] = NPCGetUniqueID(iBossIndex);
-	g_bPlayerDeathCam[client] = true;
-	g_bPlayerDeathCamShowOverlay[client] = false;
-	
-	decl Float:eyePos[3], Float:eyeAng[3], Float:vecAng[3];
-	GetClientEyePosition(client, eyePos);
-	GetClientEyeAngles(client, eyeAng);
-	SubtractVectors(eyePos, vecLookPos, vecAng);
-	GetVectorAngles(vecAng, vecAng);
-	vecAng[0] = 0.0;
-	vecAng[2] = 0.0;
-	
-	// Create fake model.
-	new slender = SpawnSlenderModel(iBossIndex, vecLookPos);
-	TeleportEntity(slender, vecLookPos, vecAng, NULL_VECTOR);
-	g_iPlayerDeathCamEnt2[client] = EntIndexToEntRef(slender);
-	SDKHook(slender, SDKHook_SetTransmit, Hook_DeathCamSetTransmit);
-	
-	// Create camera look point.
-	decl String:sName[64];
-	Format(sName, sizeof(sName), "sf2_boss_%d", EntIndexToEntRef(slender));
-	
-	decl Float:flOffsetPos[3];
-	new target = CreateEntityByName("info_target");
-	GetProfileVector(sProfile, "death_cam_pos", flOffsetPos);
-	AddVectors(vecLookPos, flOffsetPos, flOffsetPos);
-	TeleportEntity(target, flOffsetPos, NULL_VECTOR, NULL_VECTOR);
-	DispatchKeyValue(target, "targetname", sName);
-	SetVariantString("!activator");
-	AcceptEntityInput(target, "SetParent", slender);
-	
-	// Create the camera itself.
-	new camera = CreateEntityByName("point_viewcontrol");
-	TeleportEntity(camera, eyePos, eyeAng, NULL_VECTOR);
-	DispatchKeyValue(camera, "spawnflags", "12");
-	DispatchKeyValue(camera, "target", sName);
-	DispatchSpawn(camera);
-	AcceptEntityInput(camera, "Enable", client);
-	g_iPlayerDeathCamEnt[client] = EntIndexToEntRef(camera);
-	
-	if (GetProfileNum(sProfile, "death_cam_overlay") && GetProfileFloat(sProfile, "death_cam_time_overlay_start") >= 0.0)
-	{
-		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_overlay_start"), Timer_ClientResetDeathCam1, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	}
-	else
-	{
-		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	}
-	
-	TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-	
-	Call_StartForward(fOnClientStartDeathCam);
-	Call_PushCell(client);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-}
-
-public Action:Timer_ClientResetDeathCam1(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerDeathCamTimer[client]) return;
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
-	
-	g_bPlayerDeathCamShowOverlay[client] = true;
-	g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, userid, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_ClientResetDeathCamEnd(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerDeathCamTimer[client]) return;
-	
-	SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol entity changes our damage state.
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	if (iDeathCamBoss != -1)
-	{
-		if (NPCHasAttribute(iDeathCamBoss, "ignite player on death"))
-		{
-			new Float:flValue = NPCGetAttributeValue(iDeathCamBoss, "ignite player on death");
-			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
-		}
-	}
-	
-	SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-	ClientResetDeathCam(client);
-}
-
-//	==========================================================
-//	GHOST MODE FUNCTIONS
-//	==========================================================
-
-static bool:g_bPlayerGhostMode[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerGhostModeTarget[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static Handle:g_hPlayerGhostModeConnectionCheckTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static Float:g_flPlayerGhostModeConnectionTimeOutTime[MAXPLAYERS + 1] = { -1.0, ... };
-static Float:g_flPlayerGhostModeConnectionBootTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-/**
- *	Enables/Disables ghost mode on the player.
- */
-ClientSetGhostModeState(client, bool:bState)
-{
-	if (bState == g_bPlayerGhostMode[client]) return;
-	
-	if (bState && !IsClientInGame(client)) return;
-	
-	g_bPlayerGhostMode[client] = bState;
-	g_iPlayerGhostModeTarget[client] = INVALID_ENT_REFERENCE;
-	
-	if (bState)
-	{
-		ClientHandleGhostMode(client, true);
-		
-		if (GetConVarBool(g_cvGhostModeConnectionCheck))
-		{
-			g_hPlayerGhostModeConnectionCheckTimer[client] = CreateTimer(0.0, Timer_GhostModeConnectionCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
-			g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
-		}
-		
-		PvP_OnClientGhostModeEnable(client);
-	}
-	else
-	{
-		DestroySpriteOverlay(client);
-		g_hPlayerGhostModeConnectionCheckTimer[client] = INVALID_HANDLE;
-		g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
-		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
-	
-		if (IsClientInGame(client))
-		{
-			TF2_RemoveCondition(client, TFCond_HalloweenGhostMode);
-			SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_PLAYER);
-		}
-	}
-}
-
-public Action:Timer_GhostModeConnectionCheck(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerGhostModeConnectionCheckTimer[client]) return Plugin_Stop;
-	
-	if (!IsFakeClient(client) && IsClientTimingOut(client))
-	{
-		new Float:bootTime = g_flPlayerGhostModeConnectionBootTime[client];
-		if (bootTime < 0.0)
-		{
-			bootTime = GetGameTime() + GetConVarFloat(g_cvGhostModeConnectionTolerance);
-			g_flPlayerGhostModeConnectionBootTime[client] = bootTime;
-			g_flPlayerGhostModeConnectionTimeOutTime[client] = GetGameTime();
-		}
-		
-		if (GetGameTime() >= bootTime)
-		{
-			ChangeClientTeamNoSuicide(client, _:TFTeam_Spectator);
-			/*
-			ClientSetGhostModeState(client, false);
-			TF2_RespawnPlayer(client);
-			*/
-			decl String:authString[128];
-			GetClientAuthString(client, authString, sizeof(authString));
-			
-			LogSF2Message("Removed %N (%s) from ghost mode due to timing out for %f seconds", client, authString, GetConVarFloat(g_cvGhostModeConnectionTolerance));
-			
-			new Float:timeOutTime = g_flPlayerGhostModeConnectionTimeOutTime[client];
-			CPrintToChat(client, "%T", "SF2 Ghost Mode Bad Connection", client, RoundFloat(bootTime - timeOutTime));
-			
-			return Plugin_Stop;
-		}
-	}
-	else
-	{
-		// Player regained connection; reset.
-		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
-	}
-	
-	return Plugin_Continue;
-}
-
-/**
- *	Makes sure that the player is a ghost when ghost mode is activated.
- */
-ClientHandleGhostMode(client, bool:bForceSpawn=false)
-{
-	if (!IsClientInGhostMode(client)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
-#endif
-	
-	if (!TF2_IsPlayerInCondition(client, TFCond_HalloweenGhostMode) || bForceSpawn)
-	{
-		TF2_AddCondition(client, TFCond_HalloweenGhostMode, -1.0);
-		SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_DEBRIS);
-		
-		// Set first observer target.
-		ClientGhostModeNextTarget(client);
-		ClientActivateUltravision(client);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
-#endif
-}
-
-ClientGhostModeNextTarget(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientGhostModeNextTarget(%d)", client);
-#endif
-	if(GetActivePlayerCount() < 1) return;
-	
-	new iLastTarget = EntRefToEntIndex(g_iPlayerGhostModeTarget[client]);
-	new iNextTarget = -1;
-	new iFirstTarget = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (IsClientInGame(i) && (!g_bPlayerEliminated[i] || g_bPlayerProxy[i]) && !IsClientInGhostMode(i) && !DidClientEscape(i) && IsPlayerAlive(i))
-		{
-			if (iFirstTarget == -1) iFirstTarget = i;
-			if (i > iLastTarget) 
-			{
-				iNextTarget = i;
-				break;
-			}
-		}
-	}
-	
-	new iTarget = -1;
-	if (IsValidClient(iNextTarget)) iTarget = iNextTarget;
-	else iTarget = iFirstTarget;
-	
-	if (IsValidClient(iTarget))
-	{
-		g_iPlayerGhostModeTarget[client] = EntIndexToEntRef(iTarget);
-		
-		decl Float:flPos[3], Float:flAng[3], Float:flVelocity[3];
-		GetClientAbsOrigin(iTarget, flPos);
-		GetClientEyeAngles(iTarget, flAng);
-		GetEntPropVector(iTarget, Prop_Data, "m_vecAbsVelocity", flVelocity);
-		TeleportEntity(client, flPos, flAng, flVelocity);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientGhostModeNextTarget(%d)", client);
-#endif
-}
-
-bool:IsClientInGhostMode(client)
-{
-	return g_bPlayerGhostMode[client];
-}
-
-//	==========================================================
-//	SCARE FUNCTIONS
-//	==========================================================
-
-ClientPerformScare(client, iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		LogError("Could not perform scare on client %d: boss does not exist!", client);
-		return;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	g_flPlayerScareLastTime[client][iBossIndex] = GetGameTime();
-	g_flPlayerScareNextTime[client][iBossIndex] = GetGameTime() + NPCGetScareCooldown(iBossIndex);
-	
-	// See how much Sanity should be drained from a scare.
-	new Float:flStaticAmount = GetProfileFloat(sProfile, "scare_static_amount", 0.0);
-	g_flPlayerStaticAmount[client] += flStaticAmount;
-	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
-	
-	decl String:sScareSound[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_scare_player", sScareSound, sizeof(sScareSound));
-	
-	if (sScareSound[0])
-	{
-		EmitSoundToClient(client, sScareSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		
-		if (NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)
-		{
-			new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
-			new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
-			
-			g_flPlayerSightSoundNextTime[client][iBossIndex] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
-		}
-		
-		if (g_flPlayerStress[client] > 0.4)
-		{
-			ClientAddStress(client, 0.4);
-		}
-		else
-		{
-			ClientAddStress(client, 0.66);
-		}
-	}
-	else
-	{
-		if (g_flPlayerStress[client] > 0.4)
-		{
-			ClientAddStress(client, 0.3);
-		}
-		else
-		{
-			ClientAddStress(client, 0.45);
-		}
-	}
-}
-
-ClientPerformSightSound(client, iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		LogError("Could not perform sight sound on client %d: boss does not exist!", client);
-		return;
-	}
-	
-	if (!(NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)) return;
-	
-	new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]);
-	if (iMaster == -1) iMaster = iBossIndex;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sSightSound[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_sight", sSightSound, sizeof(sSightSound));
-	
-	if (sSightSound[0])
-	{
-		EmitSoundToClient(client, sSightSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		
-		new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
-		new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
-		
-		g_flPlayerSightSoundNextTime[client][iMaster] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
-		
-		decl Float:flBossPos[3], Float:flMyPos[3];
-		new iBoss = NPCGetEntIndex(iBossIndex);
-		GetClientAbsOrigin(client, flMyPos);
-		GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flBossPos);
-		new Float:flDistUnComfortZone = 400.0;
-		new Float:flBossDist = GetVectorDistance(flMyPos, flBossPos);
-		
-		new Float:flStressScalar = 1.0 + (flDistUnComfortZone / flBossDist);
-		
-		ClientAddStress(client, 0.1 * flStressScalar);
-	}
-	else
-	{
-		LogError("Warning! %s supports sight sounds, but was given a blank sound!", sProfile);
-	}
-}
-
-ClientResetScare(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetScare(%d)", client);
-#endif
-
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_flPlayerScareNextTime[client][i] = -1.0;
-		g_flPlayerScareLastTime[client][i] = -1.0;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetScare(%d)", client);
-#endif
-}
-
-//	==========================================================
-//	ANTI-CAMPING FUNCTIONS
-//	==========================================================
-
-stock ClientResetCampingStats(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetCampingStats(%d)", client);
-#endif
-
-	g_iPlayerCampingStrikes[client] = 0;
-	g_hPlayerCampingTimer[client] = INVALID_HANDLE;
-	g_bPlayerCampingFirstTime[client] = true;
-	g_flPlayerCampingLastPosition[client][0] = 0.0;
-	g_flPlayerCampingLastPosition[client][1] = 0.0;
-	g_flPlayerCampingLastPosition[client][2] = 0.0;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetCampingStats(%d)", client);
-#endif
-}
-
-ClientStartCampingTimer(client)
-{
-	g_hPlayerCampingTimer[client] = CreateTimer(5.0, Timer_ClientCheckCamp, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_ClientCheckCamp(Handle:timer, any:userid)
-{
-	if (IsRoundInWarmup()) return Plugin_Stop;
-
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerCampingTimer[client]) return Plugin_Stop;
-	
-	if (IsRoundEnding() || !IsPlayerAlive(client) || g_bPlayerEliminated[client] || DidClientEscape(client)) return Plugin_Stop;
-	
-	if (!g_bPlayerCampingFirstTime[client])
-	{
-		decl Float:flPos[3], Float:flMaxs[3], Float:flMins[3];
-		GetClientAbsOrigin(client, flPos);
-		GetEntPropVector(client, Prop_Send, "m_vecMins", flMins);
-		GetEntPropVector(client, Prop_Send, "m_vecMaxs", flMaxs);
-		
-		// Only do something if the player is NOT stuck.
-		new Float:flDistFromLastPosition = GetVectorDistance(g_flPlayerCampingLastPosition[client], flPos);
-		new Float:flDistFromClosestBoss = 9999999.0;
-		new iClosestBoss = -1;
-		
-		for (new i = 0; i < MAX_BOSSES; i++)
-		{
-			if (NPCGetUniqueID(i) == -1) continue;
-			
-			new iSlender = NPCGetEntIndex(i);
-			if (!iSlender || iSlender == INVALID_ENT_REFERENCE) continue;
-			
-			decl Float:flSlenderPos[3];
-			SlenderGetAbsOrigin(i, flSlenderPos);
-			
-			new Float:flDist = GetVectorDistance(flSlenderPos, flPos);
-			if (flDist < flDistFromClosestBoss)
-			{
-				iClosestBoss = i;
-				flDistFromClosestBoss = flDist;
-			}
-		}
-		
-		if (GetConVarBool(g_cvCampingEnabled) && 
-			!g_bRoundGrace && 
-			!IsSpaceOccupiedIgnorePlayers(flPos, flMins, flMaxs, client) && 
-			g_flPlayerStaticAmount[client] <= GetConVarFloat(g_cvCampingNoStrikeSanity) && 
-			(iClosestBoss == -1 || flDistFromClosestBoss >= GetConVarFloat(g_cvCampingNoStrikeBossDistance)) &&
-			flDistFromLastPosition <= GetConVarFloat(g_cvCampingMinDistance))
-		{
-			g_iPlayerCampingStrikes[client]++;
-			if (g_iPlayerCampingStrikes[client] < GetConVarInt(g_cvCampingMaxStrikes))
-			{
-				if (g_iPlayerCampingStrikes[client] >= GetConVarInt(g_cvCampingStrikesWarn))
-				{
-					CPrintToChat(client, "{red}%T", "SF2 Camping System Warning", client, (GetConVarInt(g_cvCampingMaxStrikes) - g_iPlayerCampingStrikes[client]) * 5);
-				}
-			}
-			else
-			{
-				g_iPlayerCampingStrikes[client] = 0;
-				ClientStartDeathCam(client, 0, flPos);
-			}
-		}
-		else
-		{
-			// Forgiveness.
-			if (g_iPlayerCampingStrikes[client] > 0) g_iPlayerCampingStrikes[client]--;
-		}
-		
-		g_flPlayerCampingLastPosition[client][0] = flPos[0];
-		g_flPlayerCampingLastPosition[client][1] = flPos[1];
-		g_flPlayerCampingLastPosition[client][2] = flPos[2];
-	}
-	else
-	{
-		g_bPlayerCampingFirstTime[client] = false;
-	}
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	BLINK FUNCTIONS
-//	==========================================================
-
-bool:IsClientBlinking(client)
-{
-	return g_bPlayerBlink[client];
-}
-
-Float:ClientGetBlinkMeter(client)
-{
-	return g_flPlayerBlinkMeter[client];
-}
-
-ClientGetBlinkCount(client)
-{
-	return g_iPlayerBlinkCount[client];
-}
-
-/**
- *	Resets all data on blinking.
- */
-ClientResetBlink(client)
-{
-	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
-	g_bPlayerBlink[client] = false;
-	g_flPlayerBlinkMeter[client] = 1.0;
-	g_iPlayerBlinkCount[client] = 0;
-}
-
-/**
- *	Sets the player into a blinking state and blinds the player
- */
-ClientBlink(client)
-{
-	if (IsRoundInWarmup() || DidClientEscape(client)) return;
-	
-	if (IsClientBlinking(client)) return;
-	
-	g_bPlayerBlink[client] = true;
-	g_iPlayerBlinkCount[client]++;
-	g_flPlayerBlinkMeter[client] = 0.0;
-	g_hPlayerBlinkTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerBlinkHoldTime), Timer_BlinkTimer2, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	
-	UTIL_ScreenFade(client, 100, RoundToFloor(GetConVarFloat(g_cvPlayerBlinkHoldTime) * 1000.0), FFADE_IN, 0, 0, 0, 255);
-	
-	Call_StartForward(fOnClientBlink);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-/**
- *	Unsets the player from the blinking state.
- */
-ClientUnblink(client)
-{
-	if (!IsClientBlinking(client)) return;
-	
-	g_bPlayerBlink[client] = false;
-	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
-	g_flPlayerBlinkMeter[client] = 1.0;
-}
-
-ClientStartDrainingBlinkMeter(client)
-{
-	g_hPlayerBlinkTimer[client] = CreateTimer(ClientGetBlinkRate(client), Timer_BlinkTimer, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_BlinkTimer(Handle:timer, any:userid)
-{
-	if (IsRoundInWarmup()) return Plugin_Stop;
-
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerBlinkTimer[client]) return Plugin_Stop;
-	
-	if (IsPlayerAlive(client) && !IsClientInDeathCam(client) && !g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !IsRoundEnding())
-	{
-		new iOverride = GetConVarInt(g_cvPlayerInfiniteBlinkOverride);
-		if ((!g_bRoundInfiniteBlink && iOverride != 1) || iOverride == 0)
-		{
-			g_flPlayerBlinkMeter[client] -= 0.05;
-		}
-		
-		if (g_flPlayerBlinkMeter[client] <= 0.0)
-		{
-			ClientBlink(client);
-			return Plugin_Stop;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_BlinkTimer2(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerBlinkTimer[client]) return;
-	
-	ClientUnblink(client);
-	ClientStartDrainingBlinkMeter(client);
-}
-
-Float:ClientGetBlinkRate(client)
-{
-	new Float:flValue = GetConVarFloat(g_cvPlayerBlinkRate);
-	if (GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 3) 
-	{
-		// Being underwater makes you blink faster, obviously.
-		flValue *= 0.75;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		if (g_bPlayerSeesSlender[client][i]) 
-		{
-			flValue *= GetProfileFloat(sProfile, "blink_look_rate_multiply", 1.0);
-		}
-		
-		else if (g_iPlayerStaticMode[client][i] == Static_Increase)
-		{
-			flValue *= GetProfileFloat(sProfile, "blink_static_rate_multiply", 1.0);
-		}
-	}
-	
-	if (TF2_GetPlayerClass(client) == TFClass_Sniper) flValue *= 1.4;
-	
-	if (IsClientUsingFlashlight(client))
-	{
-		decl Float:startPos[3], Float:endPos[3], Float:flDirection[3];
-		new Float:flLength = SF2_FLASHLIGHT_LENGTH;
-		GetClientEyePosition(client, startPos);
-		GetClientEyePosition(client, endPos);
-		GetClientEyeAngles(client, flDirection);
-		GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
-		NormalizeVector(flDirection, flDirection);
-		ScaleVector(flDirection, flLength);
-		AddVectors(endPos, flDirection, endPos);
-		new Handle:hTrace = TR_TraceRayFilterEx(startPos, endPos, MASK_VISIBLE, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
-		TR_GetEndPosition(endPos, hTrace);
-		new bool:bHit = TR_DidHit(hTrace);
-		CloseHandle(hTrace);
-		
-		if (bHit)
-		{
-			new Float:flPercent = (GetVectorDistance(startPos, endPos) / flLength);
-			flPercent *= 3.5;
-			if (flPercent > 1.0) flPercent = 1.0;
-			flValue *= flPercent;
-		}
-	}
-	
-	return flValue;
-}
-
-//	==========================================================
-//	SCREEN OVERLAY FUNCTIONS
-//	==========================================================
-
-ClientAddStress(client, Float:flStressAmount)
-{
-	g_flPlayerStress[client] += flStressAmount;
-	if (g_flPlayerStress[client] < 0.0) g_flPlayerStress[client] = 0.0;
-	if (g_flPlayerStress[client] > 1.0) g_flPlayerStress[client] = 1.0;
-	
-	//PrintCenterText(client, "g_flPlayerStress[%d] = %f", client, g_flPlayerStress[client]);
-	
-	SlenderOnClientStressUpdate(client);
-}
-
-stock ClientResetOverlay(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetOverlay(%d)", client);
-#endif
-	
-	g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
-	
-	if (IsClientInGame(client))
-	{
-		ClientCommand(client, "r_screenoverlay \"\"");
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetOverlay(%d)", client);
-#endif
-}
-
-public DestroySpriteOverlay(client)
-{
-	if(IsValidClient(client) && client > 0) {
-		for(new i = 0; i < sizeof(g_iOverlayRef[]); i++) {
-			Overlay_Render_Clear_Layer(client, i);
-		}
-		g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
-		//Show_Weapon(client);
-	}
-}
-
-public Action:Timer_PlayerOverlayCheck(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerOverlayCheck[client]) return Plugin_Stop;
-	
-	if (IsRoundInWarmup()) return Plugin_Continue;
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	new iJumpScareBoss = NPCGetFromUniqueID(g_iPlayerJumpScareBoss[client]);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	decl String:sMaterial[PLATFORM_MAX_PATH];
-	
-	if (IsClientInDeathCam(client) && iDeathCamBoss != -1 && g_bPlayerDeathCamShowOverlay[client])
-	{
-		DestroySpriteOverlay(client);
-		NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
-		GetRandomStringFromProfile(sProfile, "overlay_player_death", sMaterial, sizeof(sMaterial), 1);
-	}
-	else if (iJumpScareBoss != -1 && GetGameTime() <= g_flPlayerJumpScareLifeTime[client])
-	{
-		DestroySpriteOverlay(client);
-		NPCGetProfile(iJumpScareBoss, sProfile, sizeof(sProfile));
-		GetRandomStringFromProfile(sProfile, "overlay_jumpscare", sMaterial, sizeof(sMaterial), 1);
-	}
-	else if (IsRoundInWarmup() || g_bPlayerEliminated[client] || DidClientEscape(client) && !IsClientInGhostMode(client))
-	{
-		DestroySpriteOverlay(client);
-		return Plugin_Continue;
-	}
-	else
-	{
-		strcopy(sMaterial, sizeof(sMaterial), GRAIN_OVERLAY);
-	}
-	
-	ClientCommand(client, "r_screenoverlay %s", sMaterial);
-	return Plugin_Continue;
-}
-
-public Hide_Weapon(client) {
-	if(!IsValidClient(client) || client < 1) return;
-	new v_model = GetEntPropEnt(client, Prop_Send, "m_hViewModel");
-	if(v_model < 1) return;
-	//SetEntProp(v_model, Prop_Send, "m_nModelIndex", -1);
-	new EntEffects = GetEntProp(v_model, Prop_Send, "m_fEffects");
-	EntEffects |= EF_NODRAW;
-	SetEntProp(v_model, Prop_Send, "m_fEffects", EntEffects);
-}
-
-public Show_Weapon(client) {
-	if(!IsValidClient(client) || client < 1) return;
-	new v_model = GetEntPropEnt(client, Prop_Send, "m_hViewModel");
-	if(v_model < 1) return;
-	//SetEntProp(v_model, Prop_Send, "m_nModelIndex", -1);
-	new EntEffects = GetEntProp(v_model, Prop_Send, "m_fEffects");
-	EntEffects &= ~EF_NODRAW;
-	SetEntProp(v_model, Prop_Send, "m_fEffects", EntEffects);
-}
-
-//	==========================================================
-//	MUSIC SYSTEM FUNCTIONS
-//	==========================================================
-
-stock ClientUpdateMusicSystem(client, bool:bInitialize=false)
-{
-	new iOldPageMusicMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
-	new iOldMusicFlags = g_iPlayerMusicFlags[client];
-	new iChasingBoss = -1;
-	new iChasingSeeBoss = -1;
-	new iAlertBoss = -1;
-	new i20DollarsBoss = -1;
-	
-	if (IsRoundEnding() || !IsClientInGame(client) || IsFakeClient(client) || DidClientEscape(client) || (g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !g_bPlayerProxy[client])) 
-	{
-		g_iPlayerMusicFlags[client] = 0;
-		g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-	}
-	else
-	{
-		new bool:bPlayMusicOnEscape = true;
-		decl String:sName[64];
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-		{
-			GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-			if (StrEqual(sName, "sf2_escape_custommusic", false))
-			{
-				bPlayMusicOnEscape = false;
-				break;
-			}
-		}
-		
-		// Page music first.
-		new iPageRange = 0;
-		
-		if (GetArraySize(g_hPageMusicRanges) > 0) // Map has its own defined page music?
-		{
-			for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
-			{
-				ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
-				if (!ent || ent == INVALID_ENT_REFERENCE) continue;
-				
-				new iMin = GetArrayCell(g_hPageMusicRanges, i, 1);
-				new iMax = GetArrayCell(g_hPageMusicRanges, i, 2);
-				
-				if (g_iPageCount >= iMin && g_iPageCount <= iMax)
-				{
-					g_iPlayerPageMusicMaster[client] = GetArrayCell(g_hPageMusicRanges, i);
-					break;
-				}
-			}
-		}
-		else // Nope. Use old system instead.
-		{
-			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-		
-			new Float:flPercent = g_iPageMax > 0 ? (float(g_iPageCount) / float(g_iPageMax)) : 0.0;
-			if (flPercent > 0.0 && flPercent <= 0.25) iPageRange = 1;
-			else if (flPercent > 0.25 && flPercent <= 0.5) iPageRange = 2;
-			else if (flPercent > 0.5 && flPercent <= 0.75) iPageRange = 3;
-			else if (flPercent > 0.75) iPageRange = 4;
-			
-			if (iPageRange == 1) ClientAddMusicFlag(client, MUSICF_PAGES1PERCENT);
-			else if (iPageRange == 2) ClientAddMusicFlag(client, MUSICF_PAGES25PERCENT);
-			else if (iPageRange == 3) ClientAddMusicFlag(client, MUSICF_PAGES50PERCENT);
-			else if (iPageRange == 4) ClientAddMusicFlag(client, MUSICF_PAGES75PERCENT);
-		}
-		
-		if (iPageRange != 1) ClientRemoveMusicFlag(client, MUSICF_PAGES1PERCENT);
-		if (iPageRange != 2) ClientRemoveMusicFlag(client, MUSICF_PAGES25PERCENT);
-		if (iPageRange != 3) ClientRemoveMusicFlag(client, MUSICF_PAGES50PERCENT);
-		if (iPageRange != 4) ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
-		
-		if (IsRoundInEscapeObjective() && !bPlayMusicOnEscape) 
-		{
-			ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
-			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-		}
-		
-		new iOldChasingBoss = g_iPlayerChaseMusicMaster[client];
-		new iOldChasingSeeBoss = g_iPlayerChaseMusicSeeMaster[client];
-		new iOldAlertBoss = g_iPlayerAlertMusicMaster[client];
-		new iOld20DollarsBoss = g_iPlayer20DollarsMusicMaster[client];
-		
-		new Float:flAnger = -1.0;
-		new Float:flSeeAnger = -1.0;
-		new Float:flAlertAnger = -1.0;
-		new Float:fl20DollarsAnger = -1.0;
-		
-		decl Float:flBuffer[3], Float:flBuffer2[3], Float:flBuffer3[3];
-		
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		
-		for (new i = 0; i < MAX_BOSSES; i++)
-		{
-			if (NPCGetUniqueID(i) == -1) continue;
-			
-			if (NPCGetEntIndex(i) == INVALID_ENT_REFERENCE) continue;
-			
-			NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-			new iBossType = NPCGetType(i);
-			
-			switch (iBossType)
-			{
-				case SF2BossType_Chaser:
-				{
-					GetClientAbsOrigin(client, flBuffer);
-					SlenderGetAbsOrigin(i, flBuffer3);
-					
-					new iTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
-					if (iTarget != -1)
-					{
-						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flBuffer2);
-						
-						if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK || g_iSlenderState[i] == STATE_STUN) &&
-							!(NPCGetFlags(i) & SFF_MARKEDASFAKE) && 
-							(iTarget == client || GetVectorDistance(flBuffer, flBuffer2) <= 850.0 || GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0))
-						{
-							decl String:sPath[PLATFORM_MAX_PATH];
-							GetRandomStringFromProfile(sProfile, "sound_chase_music", sPath, sizeof(sPath), 1);
-							if (sPath[0])
-							{
-								if (NPCGetAnger(i) > flAnger)
-								{
-									flAnger = NPCGetAnger(i);
-									iChasingBoss = i;
-								}
-							}
-							
-							if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK) &&
-								PlayerCanSeeSlender(client, i, false))
-							{
-								if (iOldChasingSeeBoss == -1 || !PlayerCanSeeSlender(client, iOldChasingSeeBoss, false) || (NPCGetAnger(i) > flSeeAnger))
-								{
-									GetRandomStringFromProfile(sProfile, "sound_chase_visible", sPath, sizeof(sPath), 1);
-									
-									if (sPath[0])
-									{
-										flSeeAnger = NPCGetAnger(i);
-										iChasingSeeBoss = i;
-									}
-								}
-								
-								if (g_b20Dollars)
-								{
-									if (iOld20DollarsBoss == -1 || !PlayerCanSeeSlender(client, iOld20DollarsBoss, false) || (NPCGetAnger(i) > fl20DollarsAnger))
-									{
-										GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sPath, sizeof(sPath), 1);
-										
-										if (sPath[0])
-										{
-											fl20DollarsAnger = NPCGetAnger(i);
-											i20DollarsBoss = i;
-										}
-									}
-								}
-							}
-						}
-					}
-					
-					if (g_iSlenderState[i] == STATE_ALERT)
-					{
-						decl String:sPath[PLATFORM_MAX_PATH];
-						GetRandomStringFromProfile(sProfile, "sound_alert_music", sPath, sizeof(sPath), 1);
-						if (!sPath[0]) continue;
-					
-						if (!(NPCGetFlags(i) & SFF_MARKEDASFAKE))
-						{
-							if (GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0)
-							{
-								if (NPCGetAnger(i) > flAlertAnger)
-								{
-									flAlertAnger = NPCGetAnger(i);
-									iAlertBoss = i;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		if (iChasingBoss != iOldChasingBoss)
-		{
-			if (iChasingBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_CHASE);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_CHASE);
-			}
-		}
-		
-		if (iChasingSeeBoss != iOldChasingSeeBoss)
-		{
-			if (iChasingSeeBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_CHASEVISIBLE);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_CHASEVISIBLE);
-			}
-		}
-		
-		if (iAlertBoss != iOldAlertBoss)
-		{
-			if (iAlertBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_ALERT);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_ALERT);
-			}
-		}
-		
-		if (i20DollarsBoss != iOld20DollarsBoss)
-		{
-			if (i20DollarsBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_20DOLLARS);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_20DOLLARS);
-			}
-		}
-	}
-	
-	if (IsValidClient(client))
-	{
-		new bool:bWasChase = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASE);
-		new bool:bChase = ClientHasMusicFlag(client, MUSICF_CHASE);
-		new bool:bWasChaseSee = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASEVISIBLE);
-		new bool:bChaseSee = ClientHasMusicFlag(client, MUSICF_CHASEVISIBLE);
-		new bool:bAlert = ClientHasMusicFlag(client, MUSICF_ALERT);
-		new bool:bWasAlert = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_ALERT);
-		new bool:b20Dollars = ClientHasMusicFlag(client, MUSICF_20DOLLARS);
-		new bool:bWas20Dollars = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_20DOLLARS);
-		
-		// Custom system.
-		if (GetArraySize(g_hPageMusicRanges) > 0) 
-		{
-			decl String:sPath[PLATFORM_MAX_PATH];
-		
-			new iMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
-			if (iMaster != INVALID_ENT_REFERENCE)
-			{
-				for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
-				{
-					new ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
-					if (!ent || ent == INVALID_ENT_REFERENCE) continue;
-					
-					GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-					
-					if (ent == iMaster && 
-						(iOldPageMusicMaster != iMaster || iOldPageMusicMaster == INVALID_ENT_REFERENCE))
-					{
-						if (!sPath[0])
-						{
-							LogError("Could not play music of page range %d-%d: no sound path specified!", GetArrayCell(g_hPageMusicRanges, i, 1), GetArrayCell(g_hPageMusicRanges, i, 2));
-						}
-						else
-						{
-							ClientMusicStart(client, sPath, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-						}
-						
-						if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
-						{
-							GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-							if (sPath[0])
-							{
-								StopSound(client, MUSIC_CHAN, sPath);
-							}
-						}
-					}
-				}
-			}
-			else
-			{
-				if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
-				{
-					GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-					if (sPath[0])
-					{
-						StopSound(client, MUSIC_CHAN, sPath);
-					}
-				}
-			}
-		}
-		
-		// Old system.
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES1_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES1_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES2_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES2_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES3_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES3_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES4_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES4_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		new iMainMusicState = 0;
-		
-		if (bAlert != bWasAlert || iAlertBoss != g_iPlayerAlertMusicMaster[client])
-		{
-			if (bAlert && !bChase)
-			{
-				ClientAlertMusicStart(client, iAlertBoss);
-				if (!bWasAlert) iMainMusicState = -1;
-			}
-			else
-			{
-				ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
-				if (!bChase && bWasAlert) iMainMusicState = 1;
-			}
-		}
-		
-		if (bChase != bWasChase || iChasingBoss != g_iPlayerChaseMusicMaster[client])
-		{
-			if (bChase)
-			{
-				ClientMusicChaseStart(client, iChasingBoss);
-				
-				if (!bWasChase)
-				{
-					iMainMusicState = -1;
-					
-					if (bAlert)
-					{
-						ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
-					}
-				}
-			}
-			else
-			{
-				ClientMusicChaseStop(client, g_iPlayerChaseMusicMaster[client]);
-				if (bWasChase)
-				{
-					if (bAlert)
-					{
-						ClientAlertMusicStart(client, iAlertBoss);
-					}
-					else
-					{
-						iMainMusicState = 1;
-					}
-				}
-			}
-		}
-		
-		if (bChaseSee != bWasChaseSee || iChasingSeeBoss != g_iPlayerChaseMusicSeeMaster[client])
-		{
-			if (bChaseSee)
-			{
-				ClientMusicChaseSeeStart(client, iChasingSeeBoss);
-			}
-			else
-			{
-				ClientMusicChaseSeeStop(client, g_iPlayerChaseMusicSeeMaster[client]);
-			}
-		}
-		
-		if (b20Dollars != bWas20Dollars || i20DollarsBoss != g_iPlayer20DollarsMusicMaster[client])
-		{
-			if (b20Dollars)
-			{
-				Client20DollarsMusicStart(client, i20DollarsBoss);
-			}
-			else
-			{
-				Client20DollarsMusicStop(client, g_iPlayer20DollarsMusicMaster[client]);
-			}
-		}
-		
-		if (iMainMusicState == 1)
-		{
-			ClientMusicStart(client, g_strPlayerMusic[client], _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		else if (iMainMusicState == -1)
-		{
-			ClientMusicStop(client);
-		}
-		
-		if (bChase || bAlert)
-		{
-			new iBossToUse = -1;
-			if (bChase)
-			{
-				iBossToUse = iChasingBoss;
-			}
-			else
-			{
-				iBossToUse = iAlertBoss;
-			}
-			
-			if (iBossToUse != -1)
-			{
-				// We got some alert/chase music going on! The player's excitement will no doubt go up!
-				// Excitement, though, really depends on how close the boss is in relation to the
-				// player.
-				
-				new Float:flBossDist = NPCGetDistanceFromEntity(iBossToUse, client);
-				new Float:flScalar = flBossDist / 700.0
-				if (flScalar > 1.0) flScalar = 1.0;
-				new Float:flStressAdd = 0.1 * (1.0 - flScalar);
-				
-				ClientAddStress(client, flStressAdd);
-			}
-		}
-	}
-}
-
-stock ClientMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
-	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerMusicFlags[client] = 0;
-	g_flPlayerMusicVolume[client] = 0.0;
-	g_flPlayerMusicTargetVolume[client] = 0.0;
-	g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-	g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-}
-
-stock ClientMusicStart(client, const String:sNewMusic[], Float:flVolume=-1.0, Float:flTargetVolume=-1.0, bool:bCopyOnly=false)
-{
-	if (!IsValidClient(client)) return;
-	if (!sNewMusic[0]) return;
-	
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
-	
-	if (!StrEqual(sOldMusic, sNewMusic, false))
-	{
-		if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	}
-	
-	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), sNewMusic);
-	if (flVolume >= 0.0) g_flPlayerMusicVolume[client] = flVolume;
-	if (flTargetVolume >= 0.0) g_flPlayerMusicTargetVolume[client] = flTargetVolume;
-	
-	if (!bCopyOnly)
-	{
-		g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeInMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-		TriggerTimer(g_hPlayerMusicTimer[client], true);
-	}
-	else
-	{
-		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-	}
-}
-
-stock ClientMusicStop(client)
-{
-	g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeOutMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerMusicTimer[client], true);
-}
-
-stock Client20DollarsMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayer20DollarsMusic[client]);
-	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayer20DollarsMusicMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayer20DollarsMusicTimer[client][i] = INVALID_HANDLE;
-		g_flPlayer20DollarsMusicVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsValidClient(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-				GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock Client20DollarsMusicStart(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iOldMaster = g_iPlayer20DollarsMusicMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (!sBuffer[0]) return;
-	
-	g_iPlayer20DollarsMusicMaster[client] = iBossIndex;
-	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), sBuffer);
-	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeIn20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientAlertMusicStop(client, iOldMaster);
-	}
-}
-
-stock Client20DollarsMusicStop(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayer20DollarsMusicMaster[client])
-	{
-		g_iPlayer20DollarsMusicMaster[client] = -1;
-		strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
-	}
-	
-	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOut20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
-}
-
-stock ClientAlertMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerAlertMusic[client]);
-	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerAlertMusicMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayerAlertMusicTimer[client][i] = INVALID_HANDLE;
-		g_flPlayerAlertMusicVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsValidClient(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-				GetRandomStringFromProfile(sProfile, "sound_alert_music", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock ClientAlertMusicStart(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iOldMaster = g_iPlayerAlertMusicMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (!sBuffer[0]) return;
-	
-	g_iPlayerAlertMusicMaster[client] = iBossIndex;
-	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), sBuffer);
-	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientAlertMusicStop(client, iOldMaster);
-	}
-}
-
-stock ClientAlertMusicStop(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayerAlertMusicMaster[client])
-	{
-		g_iPlayerAlertMusicMaster[client] = -1;
-		strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
-	}
-	
-	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
-}
-
-stock ClientChaseMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusic[client]);
-	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerChaseMusicMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayerChaseMusicTimer[client][i] = INVALID_HANDLE;
-		g_flPlayerChaseMusicVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsValidClient(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-				
-				GetRandomStringFromProfile(sProfile, "sound_chase_music", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock ClientMusicChaseStart(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iOldMaster = g_iPlayerChaseMusicMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (!sBuffer[0]) return;
-	
-	g_iPlayerChaseMusicMaster[client] = iBossIndex;
-	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), sBuffer);
-	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientMusicChaseStop(client, iOldMaster);
-	}
-}
-
-stock ClientMusicChaseStop(client, iBossIndex)
-{
-	if (!IsClientInGame(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayerChaseMusicMaster[client])
-	{
-		g_iPlayerChaseMusicMaster[client] = -1;
-		strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
-	}
-	
-	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
-}
-
-stock ClientChaseMusicSeeReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusicSee[client]);
-	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
-	if (IsClientInGame(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerChaseMusicSeeMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayerChaseMusicSeeTimer[client][i] = INVALID_HANDLE;
-		g_flPlayerChaseMusicSeeVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsClientInGame(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-				GetRandomStringFromProfile(sProfile, "sound_chase_visible", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock ClientMusicChaseSeeStart(client, iBossIndex)
-{
-	if (!IsClientInGame(client)) return;
-	
-	new iOldMaster = g_iPlayerChaseMusicSeeMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
-	if (!sBuffer[0]) return;
-	
-	g_iPlayerChaseMusicSeeMaster[client] = iBossIndex;
-	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), sBuffer);
-	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientMusicChaseSeeStop(client, iOldMaster);
-	}
-}
-
-stock ClientMusicChaseSeeStop(client, iBossIndex)
-{
-	if (!IsClientInGame(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayerChaseMusicSeeMaster[client])
-	{
-		g_iPlayerChaseMusicSeeMaster[client] = -1;
-		strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
-	}
-	
-	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
-}
-
-public Action:Timer_PlayerFadeInMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
-	
-	g_flPlayerMusicVolume[client] += 0.07;
-	if (g_flPlayerMusicVolume[client] > g_flPlayerMusicTargetVolume[client]) g_flPlayerMusicVolume[client] = g_flPlayerMusicTargetVolume[client];
-	
-	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
-
-	if (g_flPlayerMusicVolume[client] >= g_flPlayerMusicTargetVolume[client])
-	{
-		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
-
-	g_flPlayerMusicVolume[client] -= 0.07;
-	if (g_flPlayerMusicVolume[client] < 0.0) g_flPlayerMusicVolume[client] = 0.0;
-
-	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
-
-	if (g_flPlayerMusicVolume[client] <= 0.0)
-	{
-		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeIn20DollarsMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] > 1.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayer20DollarsMusic[client][0]) EmitSoundToClient(client, g_strPlayer20DollarsMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOut20DollarsMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (StrEqual(sBuffer, g_strPlayer20DollarsMusic[client], false))
-	{
-		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] < 0.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeInAlertMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerAlertMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayerAlertMusicVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayerAlertMusic[client][0]) EmitSoundToClient(client, g_strPlayerAlertMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutAlertMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerAlertMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
-
-	if (StrEqual(sBuffer, g_strPlayerAlertMusic[client], false))
-	{
-		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayerAlertMusicVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeInChaseMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayerChaseMusicVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayerChaseMusic[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeInChaseMusicSee(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayerChaseMusicSee[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusicSee[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutChaseMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
-
-	if (StrEqual(sBuffer, g_strPlayerChaseMusic[client], false))
-	{
-		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayerChaseMusicVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutChaseMusicSee(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
-
-	if (StrEqual(sBuffer, g_strPlayerChaseMusicSee[client], false))
-	{
-		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-stock bool:ClientHasMusicFlag(client, iFlag)
-{
-	return bool:(g_iPlayerMusicFlags[client] & iFlag);
-}
-
-stock bool:ClientHasMusicFlag2(iValue, iFlag)
-{
-	return bool:(iValue & iFlag);
-}
-
-stock ClientAddMusicFlag(client, iFlag)
-{
-	if (!ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] |= iFlag;
-}
-
-stock ClientRemoveMusicFlag(client, iFlag)
-{
-	if (ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] &= ~iFlag;
-}
-
-//	==========================================================
-//	MISC FUNCTIONS
-//	==========================================================
-
-// This could be used for entities as well.
-stock ClientStopAllSlenderSounds(client, const String:profileName[], const String:sectionName[], iChannel)
-{
-	if (!client || !IsValidEntity(client)) return;
-	
-	if (!IsProfileValid(profileName)) return;
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	
-	KvRewind(g_hConfig);
-	if (KvJumpToKey(g_hConfig, profileName))
-	{
-		decl String:s[32];
-		
-		if (KvJumpToKey(g_hConfig, sectionName))
-		{
-			for (new i2 = 1;; i2++)
-			{
-				IntToString(i2, s, sizeof(s));
-				KvGetString(g_hConfig, s, buffer, sizeof(buffer));
-				if (!buffer[0]) break;
-				
-				StopSound(client, iChannel, buffer);
-			}
-		}
-	}
-}
-
-stock ClientUpdateListeningFlags(client, bool:bReset=false)
-{
-	if (!IsClientInGame(client)) return;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (i == client || !IsClientInGame(i)) continue;
-		
-		if (bReset || IsRoundEnding() || GetConVarBool(g_cvAllChat))
-		{
-			SetListenOverride(client, i, Listen_Default);
-			continue;
-		}
-		
-		new MuteMode:iMuteMode = g_iPlayerPreferences[client][PlayerPreference_MuteMode];
-		
-		if (g_bPlayerEliminated[client])
-		{
-			if (!g_bPlayerEliminated[i])
-			{
-				if (iMuteMode == MuteMode_DontHearOtherTeam)
-				{
-					SetListenOverride(client, i, Listen_No);
-				}
-				else if (iMuteMode == MuteMode_DontHearOtherTeamIfNotProxy && !g_bPlayerProxy[client])
-				{
-					SetListenOverride(client, i, Listen_No);
-				}
-				else
-				{
-					SetListenOverride(client, i, Listen_Default);
-				}
-			}
-			else
-			{
-				SetListenOverride(client, i, Listen_Default);
-			}
-		}
-		else
-		{
-			if (!g_bPlayerEliminated[i])
-			{/*
-				if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-				{
-					if (DidClientEscape(i))
-					{
-						if (!DidClientEscape(client))
-						{
-							SetListenOverride(client, i, Listen_No);
-						}
-						else
-						{
-							SetListenOverride(client, i, Listen_Default);
-						}
-					}
-					else
-					{
-						if (!DidClientEscape(client))
-						{
-							SetListenOverride(client, i, Listen_No);
-						}
-						else
-						{
-							SetListenOverride(client, i, Listen_Default);
-						}
-					}
-				}
-				else
-				{*/
-				new bool:bCanHear = false;
-				if (GetConVarFloat(g_cvPlayerVoiceDistance) <= 0.0) bCanHear = true;
-				
-				if (!bCanHear)
-				{
-					decl Float:flMyPos[3], Float:flHisPos[3];
-					GetClientEyePosition(client, flMyPos);
-					GetClientEyePosition(i, flHisPos);
-					
-					new Float:flDist = GetVectorDistance(flMyPos, flHisPos);
-					
-					if (GetConVarFloat(g_cvPlayerVoiceWallScale) > 0.0)
-					{
-						new Handle:hTrace = TR_TraceRayFilterEx(flMyPos, flHisPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, TraceRayDontHitCharacters);
-						new bool:bDidHit = TR_DidHit(hTrace);
-						CloseHandle(hTrace);
-						
-						if (bDidHit)
-						{
-							flDist *= GetConVarFloat(g_cvPlayerVoiceWallScale);
-						}
-					}
-					
-					if (flDist <= GetConVarFloat(g_cvPlayerVoiceDistance))
-					{
-						bCanHear = true;
-					}
-				}
-				
-				if (bCanHear)
-				{
-					if (IsClientInGhostMode(i) != IsClientInGhostMode(client) &&
-						DidClientEscape(i) != DidClientEscape(client))
-					{
-						bCanHear = false;
-					}
-				}
-				
-				if (bCanHear)
-				{
-					SetListenOverride(client, i, Listen_Default);
-				}
-				else
-				{
-					SetListenOverride(client, i, Listen_No);
-				}
-				//}
-			}
-			else
-			{
-				SetListenOverride(client, i, Listen_No);
-			}
-		}
-	}
-}
-
-stock ClientShowMainMessage(client, const String:sMessage[], any:...)
-{
-	decl String:message[512];
-	VFormat(message, sizeof(message), sMessage, 3);
-	
-	SetHudTextParams(-1.0, 0.4,
-		5.0,
-		255,
-		255,
-		255,
-		200,
-		2,
-		1.0,
-		0.07,
-		2.0);
-	ShowSyncHudText(client, g_hHudSync, message);
-}
-
-stock ClientResetSlenderStats(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSlenderStats(%d)", client);
-#endif
-	
-	g_flPlayerStress[client] = 0.0;
-	g_flPlayerStressNextUpdateTime[client] = -1.0;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_bPlayerSeesSlender[client][i] = false;
-		g_flPlayerSeesSlenderLastTime[client][i] = -1.0;
-		g_flPlayerSightSoundNextTime[client][i] = -1.0;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSlenderStats(%d)", client);
-#endif
-}
-
-bool:ClientSetQueuePoints(client, iAmount)
-{
-	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return false;
-	g_iPlayerQueuePoints[client] = iAmount;
-	ClientSaveCookies(client);
-	return true;
-}
-
-ClientSaveCookies(client)
-{
-	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return;
-	
-	// Save and reset our queue points.
-	decl String:s[64];
-	Format(s, sizeof(s), "%d ; %d ; %d ; 0 ; %d", g_iPlayerQueuePoints[client], 
-		g_iPlayerPreferences[client][PlayerPreference_ShowHints], 
-		g_iPlayerPreferences[client][PlayerPreference_MuteMode], 
-		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection]);
-		
-	SetClientCookie(client, g_hCookie, s);
-}
-
-stock ClientViewPunch(client, const Float:angleOffset[3])
-{
-	if (g_offsPlayerPunchAngleVel == -1) return;
-	
-	decl Float:flOffset[3];
-	for (new i = 0; i < 3; i++) flOffset[i] = angleOffset[i];
-	ScaleVector(flOffset, 20.0);
-	
-	/*
-	if (!IsFakeClient(client))
-	{
-		// Latency compensation.
-		new Float:flLatency = GetClientLatency(client, NetFlow_Outgoing);
-		new Float:flLatencyCalcDiff = 60.0 * Pow(flLatency, 2.0);
-		
-		for (new i = 0; i < 3; i++) flOffset[i] += (flOffset[i] * flLatencyCalcDiff);
-	}
-	*/
-	
-	decl Float:flAngleVel[3];
-	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flAngleVel);
-	AddVectors(flAngleVel, flOffset, flOffset);
-	SetEntDataVector(client, g_offsPlayerPunchAngleVel, flOffset, true);
-}
-
-public Action:Hook_ConstantGlowSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	new iOwner = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		if (EntRefToEntIndex(g_iPlayerConstantGlowEntity[i]) == ent)
-		{
-			iOwner = i;
-			break;
-		}
-	}
-	
-	if (iOwner != -1)
-	{
-		if (!IsPlayerAlive(iOwner) || g_bPlayerEliminated[iOwner]) return Plugin_Handled;
-		if (!IsPlayerAlive(other) || (!g_bPlayerProxy[other] && !IsClientInGhostMode(other))) return Plugin_Handled;
-	}
-	
-	return Plugin_Continue;
-}
-
-stock ClientSetFOV(client, iFOV)
-{
-	SetEntData(client, g_offsPlayerFOV, iFOV);
-	SetEntData(client, g_offsPlayerDefaultFOV, iFOV);
-}
-
-stock TF2_GetClassName(TFClassType:iClass, String:sBuffer[], sBufferLen)
-{
-	switch (iClass)
-	{
-		case TFClass_Scout: strcopy(sBuffer, sBufferLen, "scout");
-		case TFClass_Sniper: strcopy(sBuffer, sBufferLen, "sniper");
-		case TFClass_Soldier: strcopy(sBuffer, sBufferLen, "soldier");
-		case TFClass_DemoMan: strcopy(sBuffer, sBufferLen, "demoman");
-		case TFClass_Heavy: strcopy(sBuffer, sBufferLen, "heavyweapons");
-		case TFClass_Medic: strcopy(sBuffer, sBufferLen, "medic");
-		case TFClass_Pyro: strcopy(sBuffer, sBufferLen, "pyro");
-		case TFClass_Spy: strcopy(sBuffer, sBufferLen, "spy");
-		case TFClass_Engineer: strcopy(sBuffer, sBufferLen, "engineer");
-		default: strcopy(sBuffer, sBufferLen, "");
-	}
-}
-
-#define EF_DIMLIGHT (1 << 2)
-
-stock ClientSDKFlashlightTurnOn(client)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-	if (iEffects & EF_DIMLIGHT) return;
-
-	iEffects |= EF_DIMLIGHT;
-	
-	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
-}
-
-stock ClientSDKFlashlightTurnOff(client)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-	if (!(iEffects & EF_DIMLIGHT)) return;
-
-	iEffects &= ~EF_DIMLIGHT;
-	
-	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
-}
-
-stock bool:IsPointVisibleToAPlayer(const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false)
-{
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		if (IsPointVisibleToPlayer(i, pos, bCheckFOV, bCheckBlink)) return true;
-	}
-	
-	return false;
-}
-
-stock bool:IsPointVisibleToPlayer(client, const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client) || IsClientInGhostMode(client)) return false;
-	
-	if (bCheckEliminated && g_bPlayerEliminated[client]) return false;
-	
-	if (bCheckBlink && IsClientBlinking(client)) return false;
-	
-	decl Float:eyePos[3];
-	GetClientEyePosition(client, eyePos);
-	
-	// Check fog, if we can.
-	if (g_offsPlayerFogCtrl != -1 && g_offsFogCtrlEnable != -1 && g_offsFogCtrlEnd != -1)
-	{
-		new iFogEntity = GetEntDataEnt2(client, g_offsPlayerFogCtrl);
-		if (IsValidEdict(iFogEntity))
-		{
-			if (GetEntData(iFogEntity, g_offsFogCtrlEnable) &&
-				GetVectorDistance(eyePos, pos) >= GetEntDataFloat(iFogEntity, g_offsFogCtrlEnd)) 
-			{
-				return false;
-			}
-		}
-	}
-	
-	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, pos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
-	new bool:bHit = TR_DidHit(hTrace);
-	CloseHandle(hTrace);
-	
-	if (bHit) return false;
-	
-	if (bCheckFOV)
-	{
-		decl Float:eyeAng[3], Float:reqVisibleAng[3];
-		GetClientEyeAngles(client, eyeAng);
-		
-		new Float:flFOV = float(g_iPlayerDesiredFOV[client]);
-		SubtractVectors(pos, eyePos, reqVisibleAng);
-		GetVectorAngles(reqVisibleAng, reqVisibleAng);
-		
-		new Float:difference = FloatAbs(AngleDiff(eyeAng[0], reqVisibleAng[0])) + FloatAbs(AngleDiff(eyeAng[1], reqVisibleAng[1]));
-		if (difference > ((flFOV * 0.5) + 10.0)) return false;
-	}
-	
-	return true;
-}
-
-public Action:Timer_ClientPostWeapons(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (!IsPlayerAlive(client)) return;
-	
-	if (timer != g_hPlayerPostWeaponsTimer[client]) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) 
-	{
-		DebugMessage("START Timer_ClientPostWeapons(%d)", client);
-	}
-	
-	new iOldWeaponItemIndexes[6] = { -1, ... };
-	new iNewWeaponItemIndexes[6] = { -1, ... };
-	
-	for (new i = 0; i <= 5; i++)
-	{
-		new iWeapon = GetPlayerWeaponSlot(client, i);
-		if (!IsValidEdict(iWeapon)) continue;
-		
-		iOldWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-	}
-	
-#endif
-	
-	new bool:bRemoveWeapons = true;
-	new bool:bRestrictWeapons = true;
-	
-	if (IsRoundEnding())
-	{
-		if (!g_bPlayerEliminated[client]) 
-		{
-			bRemoveWeapons = false;
-			bRestrictWeapons = false;
-		}
-	}
-	
-	// pvp
-	if (IsClientInPvP(client)) 
-	{
-		bRemoveWeapons = false;
-		bRestrictWeapons = false;
-	}
-	
-	if (IsRoundInWarmup()) 
-	{
-		bRemoveWeapons = false;
-		bRestrictWeapons = false;
-	}
-	
-	if (IsClientInGhostMode(client)) 
-	{
-		bRemoveWeapons = true;
-	}
-	
-	if (bRemoveWeapons)
-	{
-		if(!IsClientInGhostMode(client)) {
-		for (new i = 0; i <= 5; i++)
-		{
-			TF2_RemoveWeaponSlotAndWearables(client, i);
-				if (i == TFWeaponSlot_Melee)
-				{
-					// Give scout bat to every player to fix camera displacement.
-					new iNewWeapon = TF2Items_GiveNamedItem(client, g_hSDKWeaponBat);
-					EquipPlayerWeapon(client, iNewWeapon);
-				}
-			}
-		}
-		
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "tf_weapon_builder")) != -1)
-		{
-			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
-			{
-				AcceptEntityInput(ent, "Kill");
-			}
-		}
-		
-		ent = -1;
-		while ((ent = FindEntityByClassname(ent, "tf_wearable_demoshield")) != -1)
-		{
-			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
-			{
-				AcceptEntityInput(ent, "Kill");
-			}
-		}
-		
-		ClientSwitchToWeaponSlot(client, TFWeaponSlot_Melee);
-	}
-	
-	if (bRestrictWeapons)
-	{
-		new iHealth = GetEntProp(client, Prop_Send, "m_iHealth");
-		
-		if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
-		{
-			new TFClassType:iPlayerClass = TF2_GetPlayerClass(client);
-			new Handle:hItem = INVALID_HANDLE;
-			
-			new iWeapon = INVALID_ENT_REFERENCE;
-			for (new iSlot = 0; iSlot <= 5; iSlot++)
-			{
-				iWeapon = GetPlayerWeaponSlot(client, iSlot);
-				
-				if (IsValidEdict(iWeapon))
-				{
-					if (IsWeaponRestricted(iPlayerClass, GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex")))
-					{
-						hItem = INVALID_HANDLE;
-						TF2_RemoveWeaponSlotAndWearables(client, iSlot);
-						
-						switch (iSlot)
-						{
-							case TFWeaponSlot_Primary:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Scout: hItem = g_hSDKWeaponScattergun;
-									case TFClass_Sniper: hItem = g_hSDKWeaponSniperRifle;
-									case TFClass_Soldier: hItem = g_hSDKWeaponRocketLauncher;
-									case TFClass_DemoMan: hItem = g_hSDKWeaponGrenadeLauncher;
-									case TFClass_Heavy: hItem = g_hSDKWeaponMinigun;
-									case TFClass_Medic: hItem = g_hSDKWeaponSyringeGun;
-									case TFClass_Pyro: hItem = g_hSDKWeaponFlamethrower;
-									case TFClass_Spy: hItem = g_hSDKWeaponRevolver;
-									case TFClass_Engineer: hItem = g_hSDKWeaponShotgunPrimary;
-								}
-							}
-							case TFWeaponSlot_Secondary:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Scout: hItem = g_hSDKWeaponPistolScout;
-									case TFClass_Sniper: hItem = g_hSDKWeaponSMG;
-									case TFClass_Soldier: hItem = g_hSDKWeaponShotgunSoldier;
-									case TFClass_DemoMan: hItem = g_hSDKWeaponStickyLauncher;
-									case TFClass_Heavy: hItem = g_hSDKWeaponShotgunHeavy;
-									case TFClass_Medic: hItem = g_hSDKWeaponMedigun;
-									case TFClass_Pyro: hItem = g_hSDKWeaponShotgunPyro;
-									case TFClass_Engineer: hItem = g_hSDKWeaponPistol;
-								}
-							}
-							case TFWeaponSlot_Melee:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Scout: hItem = g_hSDKWeaponBat;
-									case TFClass_Sniper: hItem = g_hSDKWeaponKukri;
-									case TFClass_Soldier: hItem = g_hSDKWeaponShovel;
-									case TFClass_DemoMan: hItem = g_hSDKWeaponBottle;
-									case TFClass_Heavy: hItem = g_hSDKWeaponFists;
-									case TFClass_Medic: hItem = g_hSDKWeaponBonesaw;
-									case TFClass_Pyro: hItem = g_hSDKWeaponFireaxe;
-									case TFClass_Spy: hItem = g_hSDKWeaponKnife;
-									case TFClass_Engineer: hItem = g_hSDKWeaponWrench;
-								}
-							}
-							case 4:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Spy: hItem = g_hSDKWeaponInvis;
-								}
-							}
-						}
-						
-						if (hItem != INVALID_HANDLE)
-						{
-							new iNewWeapon = TF2Items_GiveNamedItem(client, hItem);
-							if (IsValidEntity(iNewWeapon)) 
-							{
-								EquipPlayerWeapon(client, iNewWeapon);
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		// Fixes the Pretty Boy's Pocket Pistol glitch.
-		new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, client);
-		if (iHealth > iMaxHealth)
-		{
-			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
-			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
-		}
-	}
-	
-	// Change stats on some weapons.
-	if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
-	{
-		new iWeapon = INVALID_ENT_REFERENCE;
-		decl Handle:hWeapon;
-		for (new iSlot = 0; iSlot <= 5; iSlot++)
-		{
-			iWeapon = GetPlayerWeaponSlot(client, iSlot);
-			if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
-			
-			new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-			switch (iItemDef)
-			{
-				case 214: // Powerjack
-				{
-					TF2_RemoveWeaponSlot(client, iSlot);
-					
-					hWeapon = PrepareItemHandle("tf_weapon_fireaxe", 214, 0, 0, "180 ; 20.0 ; 206 ; 1.33");
-					new iEnt = TF2Items_GiveNamedItem(client, hWeapon);
-					CloseHandle(hWeapon);
-					EquipPlayerWeapon(client, iEnt);
-				}
-			}
-		}
-	}
-	
-	// Remove all hats.
-	if (IsClientInGhostMode(client))
-	{
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "tf_wearable")) != -1)
-		{
-			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
-			{
-				AcceptEntityInput(ent, "Kill");
-			}
-		}
-	}
-	
-#if defined DEBUG
-	for (new i = 0; i <= 5; i++)
-	{
-		new iWeapon = GetPlayerWeaponSlot(client, i);
-		if (!IsValidEdict(iWeapon)) continue;
-		
-		iNewWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-	}
-
-	if (GetConVarInt(g_cvDebugDetail) > 0) 
-	{
-		for (new i = 0; i <= 5; i++)
-		{
-			DebugMessage("-> slot %d: %d (old: %d)", i, iNewWeaponItemIndexes[i], iOldWeaponItemIndexes[i]);
-		}
-	
-		DebugMessage("END Timer_ClientPostWeapons(%d) -> remove = %d, restrict = %d", client, bRemoveWeapons, bRestrictWeapons);
-	}
-#endif
-}
-
-public Action:Timer_ApplyCustomModel(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-	
-	if (g_bPlayerProxy[client] && iMaster != -1)
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
-		
-		// Set custom model, if any.
-		decl String:sBuffer[PLATFORM_MAX_PATH];
-		decl String:sSectionName[64];
-		
-		decl String:sClassName[64];
-		TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
-		
-		Format(sSectionName, sizeof(sSectionName), "mod_proxy_%s", sClassName);
-		if ((GetRandomStringFromProfile(sProfile, sSectionName, sBuffer, sizeof(sBuffer)) && sBuffer[0]) ||
-			(GetRandomStringFromProfile(sProfile, "mod_proxy_all", sBuffer, sizeof(sBuffer)) && sBuffer[0]))
-		{
-			SetVariantString(sBuffer);
-			AcceptEntityInput(client, "SetCustomModel");
-			SetEntProp(client, Prop_Send, "m_bUseClassAnimations", true);
-		}
-		
-		if (IsPlayerAlive(client))
-		{
-			// Play any sounds, if any.
-			if (GetRandomStringFromProfile(sProfile, "sound_proxy_spawn", sBuffer, sizeof(sBuffer)) && sBuffer[0])
-			{
-				new iChannel = GetProfileNum(sProfile, "sound_proxy_spawn_channel", SNDCHAN_AUTO);
-				new iLevel = GetProfileNum(sProfile, "sound_proxy_spawn_level", SNDLEVEL_NORMAL);
-				new iFlags = GetProfileNum(sProfile, "sound_proxy_spawn_flags", SND_NOFLAGS);
-				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_spawn_volume", SNDVOL_NORMAL);
-				new iPitch = GetProfileNum(sProfile, "sound_proxy_spawn_pitch", SNDPITCH_NORMAL);
-				
-				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
-			}
-		}
-	}
-}
-
-bool:IsWeaponRestricted(TFClassType:iClass, iItemDef)
-{
-	if (g_hRestrictedWeaponsConfig == INVALID_HANDLE) return false;
-	
-	new bool:bReturn = false;
-	
-	decl String:sItemDef[32];
-	IntToString(iItemDef, sItemDef, sizeof(sItemDef));
-	
-	KvRewind(g_hRestrictedWeaponsConfig);
-	if (KvJumpToKey(g_hRestrictedWeaponsConfig, "all"))
-	{
-		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef);
-	}
-	
-	new bool:bFoundSection = false;
-	KvRewind(g_hRestrictedWeaponsConfig);
-	
-	switch (iClass)
-	{
-		case TFClass_Scout: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "scout");
-		case TFClass_Soldier: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "soldier");
-		case TFClass_Sniper: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "sniper");
-		case TFClass_DemoMan: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "demoman");
-		case TFClass_Heavy: 
-		{
-			bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavy");
-		
-			if (!bFoundSection)
-			{
-				KvRewind(g_hRestrictedWeaponsConfig);
-				bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavyweapons");
-			}
-		}
-		case TFClass_Medic: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "medic");
-		case TFClass_Spy: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "spy");
-		case TFClass_Pyro: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "pyro");
-		case TFClass_Engineer: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "engineer");
-	}
-	
-	if (bFoundSection)
-	{
-		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef, bReturn);
-	}
-	
-	return bReturn;
-}
-
-public Action:Timer_RespawnPlayer(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (IsPlayerAlive(client)) return;
-	
-	TF2_RespawnPlayer(client);
+#if defined _sf2_client_included
+ #endinput
+#endif
+#define _sf2_client_included
+
+#define GHOST_MODEL "models/props_halloween/ghost_no_hat.mdl"
+#define SF2_OVERLAY_DEFAULT "overlays/rytp_horror/grain"
+#define SF2_OVERLAY_DEFAULT_NO_FILMGRAIN "overlays/rytp_horror/grain" // TODO: Update material?
+#define SF2_OVERLAY_GHOST "overlays/rytp_horror/grain"
+
+#define SF2_FLASHLIGHT_WIDTH 512.0 // How wide the player's Flashlight should be in world units.
+#define SF2_FLASHLIGHT_LENGTH 1024.0 // How far the player's Flashlight can reach in world units.
+#define SF2_FLASHLIGHT_BRIGHTNESS 0 // Intensity of the players' Flashlight.
+#define SF2_FLASHLIGHT_DRAIN_RATE 0.65 // How long (in seconds) each bar on the player's Flashlight meter lasts.
+#define SF2_FLASHLIGHT_RECHARGE_RATE 0.68 // How long (in seconds) it takes each bar on the player's Flashlight meter to recharge.
+#define SF2_FLASHLIGHT_FLICKERAT 0.25 // The percentage of the Flashlight battery where the Flashlight will start to blink.
+#define SF2_FLASHLIGHT_ENABLEAT 0.3 // The percentage of the Flashlight battery where the Flashlight will be able to be used again (if the player shortens out the Flashlight from excessive use).
+#define SF2_FLASHLIGHT_COOLDOWN 0.4 // How much time players have to wait before being able to switch their flashlight on again after turning it off.
+
+#define SF2_ULTRAVISION_WIDTH 800.0
+#define SF2_ULTRAVISION_LENGTH 800.0
+#define SF2_ULTRAVISION_BRIGHTNESS -4 // Intensity of Ultravision.
+#define SF2_ULTRAVISION_CONE 180.0
+
+#define SF2_PLAYER_BREATH_COOLDOWN_MIN 0.8
+#define SF2_PLAYER_BREATH_COOLDOWN_MAX 2.0
+
+new String:g_strPlayerBreathSounds[][] = 
+{
+	"rytp_horror/player_breath_1.wav"
+};
+
+static String:g_strPlayerLagCompensationWeapons[][] = 
+{
+	"tf_weapon_sniperrifle",
+	"tf_weapon_sniperrifle_decap",
+	"tf_weapon_sniperrifle_classic"
+};
+
+// Deathcam data.
+static g_iPlayerDeathCamBoss[MAXPLAYERS + 1] = { -1, ... };
+static bool:g_bPlayerDeathCam[MAXPLAYERS + 1] = { false, ... };
+static bool:g_bPlayerDeathCamShowOverlay[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerDeathCamEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static g_iPlayerDeathCamEnt2[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static Handle:g_hPlayerDeathCamTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Flashlight data.
+static bool:g_bPlayerFlashlight[MAXPLAYERS + 1] = { false, ... };
+static bool:g_bPlayerFlashlightBroken[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerFlashlightEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static g_iPlayerFlashlightEntAng[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static Float:g_flPlayerFlashlightBatteryLife[MAXPLAYERS + 1] = { 1.0, ... };
+static Handle:g_hPlayerFlashlightBatteryTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static Float:g_flPlayerFlashlightNextInputTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+// Ultravision data.
+static bool:g_bPlayerUltravision[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerUltravisionEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+
+// Sprint data.
+static bool:g_bPlayerSprint[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerSprintPoints[MAXPLAYERS + 1] = { 100, ... };
+static Handle:g_hPlayerSprintTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Blink data.
+static Handle:g_hPlayerBlinkTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static bool:g_bPlayerBlink[MAXPLAYERS + 1] = { false, ... };
+static Float:g_flPlayerBlinkMeter[MAXPLAYERS + 1] = { 0.0, ... };
+static g_iPlayerBlinkCount[MAXPLAYERS + 1] = { 0, ... };
+
+// Breathing data.
+static bool:g_bPlayerBreath[MAXPLAYERS + 1] = { false, ... };
+static Handle:g_hPlayerBreathTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Interactive glow data.
+static g_iPlayerInteractiveGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static g_iPlayerInteractiveGlowTargetEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+
+// Constant glow data.
+static g_iPlayerConstantGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static bool:g_bPlayerConstantGlowEnabled[MAXPLAYERS + 1] = { false, ... };
+
+// Jumpscare data.
+static g_iPlayerJumpScareBoss[MAXPLAYERS + 1] = { -1, ... };
+static Float:g_flPlayerJumpScareLifeTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+static Float:g_flPlayerScareBoostEndTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+// Anti-camping data.
+static g_iPlayerCampingStrikes[MAXPLAYERS + 1] = { 0, ... };
+static Handle:g_hPlayerCampingTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static Float:g_flPlayerCampingLastPosition[MAXPLAYERS + 1][3];
+static bool:g_bPlayerCampingFirstTime[MAXPLAYERS + 1] = { true, ... };
+
+
+//	==========================================================
+//	GENERAL CLIENT HOOK FUNCTIONS
+//	==========================================================
+
+#define SF2_PLAYER_VIEWBOB_TIMER 10.0
+#define SF2_PLAYER_VIEWBOB_SCALE_X 0.05
+#define SF2_PLAYER_VIEWBOB_SCALE_Y 0.0
+#define SF2_PLAYER_VIEWBOB_SCALE_Z 0.0
+
+
+public MRESReturn:Hook_ClientWantsLagCompensationOnEntity(thisPointer, Handle:hReturn, Handle:hParams)
+{
+	if (!g_bEnabled || IsFakeClient(thisPointer)) return MRES_Ignored;
+	
+	DHookSetReturn(hReturn, true);
+	return MRES_Supercede;
+}
+
+Float:ClientGetScareBoostEndTime(client)
+{
+	return g_flPlayerScareBoostEndTime[client];
+}
+
+ClientSetScareBoostEndTime(client, Float:time)
+{
+	g_flPlayerScareBoostEndTime[client] = time;
+}
+
+public Hook_ClientPreThink(client)
+{
+	if (!g_bEnabled) return;
+	
+	ClientProcessViewAngles(client);
+	ClientProcessVisibility(client);
+	ClientProcessStaticShake(client);
+	ClientProcessFlashlightAngles(client);
+	ClientProcessInteractiveGlow(client);
+	
+	if (IsClientInGhostMode(client))
+	{
+		SetEntPropFloat(client, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0);
+		SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 520.0);
+	}
+	else if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
+	{
+		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
+		{
+			new iRoundState = _:GameRules_GetRoundState();
+			
+			// No double jumping for players in play.
+			SetEntProp(client, Prop_Send, "m_iAirDash", 99999);
+		
+			if (!g_bPlayerProxy[client])
+			{
+				if (iRoundState == 4)
+				{
+					new bool:bDanger = false;
+					
+					if (!bDanger)
+					{
+						decl iState;
+						decl iBossTarget;
+						
+						for (new i = 0; i < MAX_BOSSES; i++)
+						{
+							if (NPCGetUniqueID(i) == -1) continue;
+							
+							if (NPCGetType(i) == SF2BossType_Chaser)
+							{
+								iBossTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
+								iState = g_iSlenderState[i];
+								
+								if ((iState == STATE_CHASE || iState == STATE_ATTACK || iState == STATE_STUN) &&
+									((iBossTarget && iBossTarget != INVALID_ENT_REFERENCE && (iBossTarget == client || ClientGetDistanceFromEntity(client, iBossTarget) < 512.0)) || NPCGetDistanceFromEntity(i, client) < 512.0 || PlayerCanSeeSlender(client, i, false)))
+								{
+									bDanger = true;
+									ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
+									
+									// Induce client stress levels.
+									new Float:flUnComfortZoneDist = 512.0;
+									new Float:flStressScalar = (flUnComfortZoneDist / NPCGetDistanceFromEntity(i, client));
+									ClientAddStress(client, 0.025 * flStressScalar);
+									
+									break;
+								}
+							}
+						}
+					}
+					
+					if (g_flPlayerStaticAmount[client] > 0.4) bDanger = true;
+					if (GetGameTime() < ClientGetScareBoostEndTime(client)) bDanger = true;
+					
+					if (!bDanger)
+					{
+						decl iState;
+						for (new i = 0; i < MAX_BOSSES; i++)
+						{
+							if (NPCGetUniqueID(i) == -1) continue;
+							
+							if (NPCGetType(i) == SF2BossType_Chaser)
+							{
+								if (iState == STATE_ALERT)
+								{
+									if (PlayerCanSeeSlender(client, i))
+									{
+										bDanger = true;
+										ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
+									}
+								}
+							}
+						}
+					}
+					
+					if (!bDanger)
+					{
+						new Float:flCurTime = GetGameTime();
+						new Float:flScareSprintDuration = 3.0;
+						if (TF2_GetPlayerClass(client) == TFClass_DemoMan) flScareSprintDuration *= 1.667;
+						
+						for (new i = 0; i < MAX_BOSSES; i++)
+						{
+							if (NPCGetUniqueID(i) == -1) continue;
+							
+							if ((flCurTime - g_flPlayerScareLastTime[client][i]) <= flScareSprintDuration)
+							{
+								bDanger = true;
+								break;
+							}
+						}
+					}
+					
+					new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
+					new Float:flSprintSpeed = ClientGetDefaultSprintSpeed(client);
+					
+					// Check for weapon speed changes.
+					new iWeapon = INVALID_ENT_REFERENCE;
+					
+					for (new iSlot = 0; iSlot <= 5; iSlot++)
+					{
+						iWeapon = GetPlayerWeaponSlot(client, iSlot);
+						if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
+						
+						new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+						switch (iItemDef)
+						{
+							case 239: // Gloves of Running Urgently
+							{
+								if (GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon") == iWeapon)
+								{
+									flSprintSpeed += (flSprintSpeed * 0.1);
+								}
+							}
+							case 775: // Escape Plan
+							{
+								new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
+								new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
+								new Float:flPercentage = flHealth / flMaxHealth;
+								
+								if (flPercentage < 0.805 && flPercentage >= 0.605) flSprintSpeed += (flSprintSpeed * 0.05);
+								else if (flPercentage < 0.605 && flPercentage >= 0.405) flSprintSpeed += (flSprintSpeed * 0.1);
+								else if (flPercentage < 0.405 && flPercentage >= 0.205) flSprintSpeed += (flSprintSpeed * 0.15);
+								else if (flPercentage < 0.205) flSprintSpeed += (flSprintSpeed * 0.2);
+							}
+						}
+					}
+					
+					// Speed buff?
+					if (TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly))
+					{
+						flWalkSpeed += (flWalkSpeed * 0.08);
+						flSprintSpeed += (flSprintSpeed * 0.08);
+					}
+					
+					if (bDanger)
+					{
+						flWalkSpeed *= 1.33;
+						flSprintSpeed *= 1.33;
+						
+						if (!g_bPlayerHints[client][PlayerHint_Sprint])
+						{
+							ClientShowHint(client, PlayerHint_Sprint);
+						}
+					}
+					
+					new Float:flSprintSpeedSubtract = ((flSprintSpeed - flWalkSpeed) * 0.5);
+					flSprintSpeedSubtract -= flSprintSpeedSubtract * (g_iPlayerSprintPoints[client] != 0 ? (float(g_iPlayerSprintPoints[client]) / 100.0) : 0.0);
+					flSprintSpeed -= flSprintSpeedSubtract;
+					
+					if (IsClientSprinting(client)) 
+					{
+						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flSprintSpeed);
+					}
+					else 
+					{
+						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flWalkSpeed);
+					}
+					
+					if (ClientCanBreath(client) && !g_bPlayerBreath[client])
+					{
+						ClientStartBreathing(client);
+					}
+				}
+			}
+			else
+			{
+				new TFClassType:iClass = TF2_GetPlayerClass(client);
+				new bool:bSpeedup = TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly);
+			
+				switch (iClass)
+				{
+					case TFClass_Scout:
+					{
+						if (iRoundState == 4)
+						{
+							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 405.0);
+							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
+						}
+					}
+					case TFClass_Medic:
+					{
+						if (iRoundState == 4)
+						{
+							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 385.0);
+							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	// Calculate player stress levels.
+	if (GetGameTime() >= g_flPlayerStressNextUpdateTime[client])
+	{
+		//new Float:flPagePercent = g_iPageMax != 0 ? float(g_iPageCount) / float(g_iPageMax) : 0.0;
+		//new Float:flPageCountPercent = g_iPageMax != 0? float(g_iPlayerPageCount[client]) / float(g_iPageMax) : 0.0;
+		
+		g_flPlayerStressNextUpdateTime[client] = GetGameTime() + 0.33;
+		ClientAddStress(client, -0.01);
+		
+#if defined DEBUG
+		SendDebugMessageToPlayer(client, DEBUG_PLAYER_STRESS, 1, "g_flPlayerStress[%d]: %0.1f", client, g_flPlayerStress[client]);
+#endif
+	}
+	
+	// Process screen shake, if enabled.
+	if (g_bPlayerShakeEnabled)
+	{
+		new bool:bDoShake = false;
+		
+		if (IsPlayerAlive(client))
+		{
+			new iStaticMaster = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
+			if (iStaticMaster != -1 && NPCGetFlags(iStaticMaster) & SFF_HASVIEWSHAKE)
+			{
+				bDoShake = true;
+			}
+		}
+		
+		if (bDoShake)
+		{
+			new Float:flPercent = g_flPlayerStaticAmount[client];
+			
+			new Float:flAmplitudeMax = GetConVarFloat(g_cvPlayerShakeAmplitudeMax);
+			new Float:flAmplitude = flAmplitudeMax * flPercent;
+			
+			new Float:flFrequencyMax = GetConVarFloat(g_cvPlayerShakeFrequencyMax);
+			new Float:flFrequency = flFrequencyMax * flPercent;
+			
+			UTIL_ScreenShake(client, flAmplitude, 0.5, flFrequency);
+		}
+	}
+}
+
+public Action:Hook_ClientSetTransmit(client, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (other != client)
+	{
+		if (IsClientInGhostMode(client) && !IsClientInGhostMode(other)) return Plugin_Handled;
+		
+		if (!IsRoundEnding())
+		{
+			// SPECIAL ROUND: Singleplayer
+			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+			{
+				if (!g_bPlayerEliminated[client] && !g_bPlayerEliminated[other] && !DidClientEscape(other)) return Plugin_Handled; 
+			}
+			
+			// pvp
+			if (IsClientInPvP(client) && IsClientInPvP(other)) 
+			{
+				if (TF2_IsPlayerInCondition(client, TFCond_Cloaked) &&
+					!TF2_IsPlayerInCondition(client, TFCond_CloakFlicker) &&
+					!TF2_IsPlayerInCondition(client, TFCond_Jarated) &&
+					!TF2_IsPlayerInCondition(client, TFCond_Milked) &&
+					!TF2_IsPlayerInCondition(client, TFCond_OnFire) &&
+					(GetGameTime() > GetEntPropFloat(client, Prop_Send, "m_flInvisChangeCompleteTime")))
+				{
+					return Plugin_Handled;
+				}
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:TF2_CalcIsAttackCritical(client, weapon, String:sWeaponName[], &bool:result)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if ((IsRoundInWarmup() || IsClientInPvP(client)) && !IsRoundEnding())
+	{
+		if (!GetConVarBool(g_cvPlayerFakeLagCompensation))
+		{
+			new bool:bNeedsManualDamage = false;
+			
+			// Fake lag compensation isn't enabled; check to see if we need to deal damage manually.
+			for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
+			{
+				if (StrEqual(sWeaponName, g_strPlayerLagCompensationWeapons[i], false))
+				{
+					bNeedsManualDamage = true;
+					break;
+				}
+			}
+			
+			if (bNeedsManualDamage)
+			{
+				decl Float:flStartPos[3], Float:flEyeAng[3];
+				GetClientEyePosition(client, flStartPos);
+				GetClientEyeAngles(client, flEyeAng);
+				
+				new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flEyeAng, MASK_SHOT, RayType_Infinite, TraceRayDontHitEntity, client);
+				new iHitEntity = TR_GetEntityIndex(hTrace);
+				new iHitGroup = TR_GetHitGroup(hTrace);
+				CloseHandle(hTrace);
+				
+				if (IsValidClient(iHitEntity))
+				{
+					if (GetClientTeam(iHitEntity) == GetClientTeam(client))
+					{
+						if (IsRoundInWarmup() || IsClientInPvP(iHitEntity))
+						{
+							new Float:flChargedDamage = GetEntPropFloat(weapon, Prop_Send, "m_flChargedDamage");
+							if (flChargedDamage < 50.0) flChargedDamage = 50.0;
+							new iDamageType = DMG_BULLET;
+							
+							if (IsClientCritBoosted(client))
+							{
+								result = true;
+								iDamageType |= DMG_ACID;
+							}
+							else if (iHitGroup == 1)
+							{
+								if (StrEqual(sWeaponName, "tf_weapon_sniperrifle_classic", false))
+								{
+									if (flChargedDamage >= 150.0)
+									{
+										result = true;
+										iDamageType |= DMG_ACID;
+									}
+								}
+								else
+								{
+									if (TF2_IsPlayerInCondition(client, TFCond_Zoomed))
+									{
+										result = true;
+										iDamageType |= DMG_ACID;
+									}
+								}
+							}
+							
+							SDKHooks_TakeDamage(iHitEntity, client, client, flChargedDamage, iDamageType);
+							return Plugin_Changed;
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_ClientOnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsRoundInWarmup()) return Plugin_Continue;
+	
+	if (attacker != victim && IsValidClient(attacker))
+	{
+		if (!IsRoundEnding())
+		{
+			if (IsClientInPvP(victim) && IsClientInPvP(attacker))
+			{
+				if (attacker == inflictor)
+				{
+					if (IsValidEdict(weapon))
+					{
+						decl String:sWeaponClass[64];
+						GetEdictClassname(weapon, sWeaponClass, sizeof(sWeaponClass));
+						
+						// Backstab check!
+						if ((StrEqual(sWeaponClass, "tf_weapon_knife", false) || (TF2_GetPlayerClass(attacker) == TFClass_Spy && StrEqual(sWeaponClass, "saxxy", false))) &&
+							(damagecustom != TF_CUSTOM_TAUNT_FENCING))
+						{
+							decl Float:flMyPos[3], Float:flHisPos[3], Float:flMyDirection[3];
+							GetClientAbsOrigin(victim, flMyPos);
+							GetClientAbsOrigin(attacker, flHisPos);
+							GetClientEyeAngles(victim, flMyDirection);
+							GetAngleVectors(flMyDirection, flMyDirection, NULL_VECTOR, NULL_VECTOR);
+							NormalizeVector(flMyDirection, flMyDirection);
+							ScaleVector(flMyDirection, 32.0);
+							AddVectors(flMyDirection, flMyPos, flMyDirection);
+							
+							decl Float:p[3], Float:s[3];
+							MakeVectorFromPoints(flMyPos, flHisPos, p);
+							MakeVectorFromPoints(flMyPos, flMyDirection, s);
+							if (GetVectorDotProduct(p, s) <= 0.0)
+							{
+								damage = float(GetEntProp(victim, Prop_Send, "m_iHealth")) * 2.0;
+								
+								new Handle:hCvar = FindConVar("tf_weapon_criticals");
+								if (hCvar != INVALID_HANDLE && GetConVarBool(hCvar)) damagetype |= DMG_ACID;
+								return Plugin_Changed;
+							}
+						}
+					}
+				}
+			}
+			/*
+			else if (g_bPlayerProxy[victim] || g_bPlayerProxy[attacker])
+			{
+				if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
+				{
+					damage = 0.0;
+					return Plugin_Changed;
+				}
+				
+				if (g_bPlayerProxy[attacker])
+				{
+					new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, victim);
+					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[attacker]);
+					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
+					{
+						if (damagecustom == TF_CUSTOM_TAUNT_GRAND_SLAM ||
+							damagecustom == TF_CUSTOM_TAUNT_FENCING ||
+							damagecustom == TF_CUSTOM_TAUNT_ARROW_STAB ||
+							damagecustom == TF_CUSTOM_TAUNT_GRENADE ||
+							damagecustom == TF_CUSTOM_TAUNT_BARBARIAN_SWING ||
+							damagecustom == TF_CUSTOM_TAUNT_ENGINEER_ARM ||
+							damagecustom == TF_CUSTOM_TAUNT_ARMAGEDDON)
+						{
+							if (damage >= float(iMaxHealth)) damage = float(iMaxHealth) * 0.5;
+							else damage = 0.0;
+						}
+						else if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage.
+						{
+							damage = float(iMaxHealth) * GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy_backstab", 0.25);
+							if (damagetype & DMG_ACID) damage /= 3.0;
+						}
+					
+						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitenemy");
+						if (g_iPlayerProxyControl[attacker] > 100)
+						{
+							g_iPlayerProxyControl[attacker] = 100;
+						}
+						
+						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy", 1.0);
+					}
+					
+					return Plugin_Changed;
+				}
+				else if (g_bPlayerProxy[victim])
+				{
+					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[victim]);
+					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
+					{
+						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitbyenemy");
+						if (g_iPlayerProxyControl[attacker] > 100)
+						{
+							g_iPlayerProxyControl[attacker] = 100;
+						}
+						
+						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_self", 1.0);
+					}
+					
+					return Plugin_Changed;
+				}
+			}
+			*/
+			else
+			{
+				damage = 0.0;
+				return Plugin_Changed;
+			}
+		}
+		else
+		{
+			if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
+			{
+				damage = 0.0;
+				return Plugin_Changed;
+			}
+		}
+		
+		if (IsClientInGhostMode(victim))
+		{
+			damage = 0.0;
+			return Plugin_Changed;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_TEFireBullets(const String:te_name[], const Players[], numClients, Float:delay)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	new client = TE_ReadNum("m_iPlayer") + 1;
+	if (IsValidClient(client))
+	{
+		if (GetConVarBool(g_cvPlayerFakeLagCompensation))
+		{
+			if ((IsRoundInWarmup() || IsClientInPvP(client)))
+			{
+				ClientEnableFakeLagCompensation(client);
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+ClientResetStatic(client)
+{
+	g_iPlayerStaticMaster[client] = -1;
+	g_hPlayerStaticTimer[client] = INVALID_HANDLE;
+	g_flPlayerStaticIncreaseRate[client] = 0.0;
+	g_flPlayerStaticDecreaseRate[client] = 0.0;
+	g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+	g_flPlayerLastStaticTime[client] = 0.0;
+	g_flPlayerLastStaticVolume[client] = 0.0;
+	g_bPlayerInStaticShake[client] = false;
+	g_iPlayerStaticShakeMaster[client] = -1;
+	g_flPlayerStaticShakeMinVolume[client] = 0.0;
+	g_flPlayerStaticShakeMaxVolume[client] = 0.0;
+	g_flPlayerStaticAmount[client] = 0.0;
+	
+	if (IsClientInGame(client))
+	{
+		if (g_strPlayerStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticSound[client]);
+		if (g_strPlayerLastStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+		if (g_strPlayerStaticShakeSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
+	}
+	
+	strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
+	strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), "");
+	strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
+}
+
+ClientResetHints(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetHints(%d)", client);
+#endif
+
+	for (new i = 0; i < PlayerHint_MaxNum; i++)
+	{
+		g_bPlayerHints[client][i] = false;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetHints(%d)", client);
+#endif
+}
+
+ClientShowHint(client, iHint)
+{
+	g_bPlayerHints[client][iHint] = true;
+	
+	switch (iHint)
+	{
+		case PlayerHint_Sprint: PrintHintText(client, "%T", "SF2 Hint Sprint", client);
+		case PlayerHint_Flashlight: PrintHintText(client, "%T", "SF2 Hint Flashlight", client);
+		case PlayerHint_Blink: PrintHintText(client, "%T", "SF2 Hint Blink", client);
+		case PlayerHint_MainMenu: PrintHintText(client, "%T", "SF2 Hint Main Menu", client);
+	}
+}
+
+bool:DidClientEscape(client)
+{
+	return g_bPlayerEscaped[client];
+}
+
+ClientEscape(client)
+{
+	if (DidClientEscape(client)) return;
+
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("START ClientEscape(%d)", client);
+#endif
+	
+	g_bPlayerEscaped[client] = true;
+	
+	ClientResetBreathing(client);
+	ClientResetSprint(client);
+	ClientResetFlashlight(client);
+	ClientDeactivateUltravision(client);
+	ClientDisableConstantGlow(client);
+	
+	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
+	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
+	
+	HandlePlayerHUD(client);
+	
+	decl String:sName[MAX_NAME_LENGTH];
+	GetClientName(client, sName, sizeof(sName));
+	CPrintToChatAll("%t", "SF2 Player Escaped", sName);
+	
+	CheckRoundWinConditions();
+	
+	Call_StartForward(fOnClientEscape);
+	Call_PushCell(client);
+	Call_Finish();
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("END ClientEscape(%d)", client);
+#endif
+}
+
+public Action:Timer_TeleportPlayerToEscapePoint(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (!DidClientEscape(client)) return;
+	
+	if (IsPlayerAlive(client))
+	{
+		TeleportClientToEscapePoint(client);
+	}
+}
+
+stock Float:ClientGetDistanceFromEntity(client, entity)
+{
+	decl Float:flStartPos[3], Float:flEndPos[3];
+	GetClientAbsOrigin(client, flStartPos);
+	GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", flEndPos);
+	return GetVectorDistance(flStartPos, flEndPos);
+}
+
+ClientEnableFakeLagCompensation(client)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client) || g_bPlayerLagCompensation[client]) return;
+	
+	// Can only enable lag compensation if we're in either of these two teams only.
+	new iMyTeam = GetClientTeam(client);
+	if (iMyTeam != _:TFTeam_Red && iMyTeam != _:TFTeam_Blue) return;
+	
+	// Can only enable lag compensation if there are other active teammates around. This is to prevent spontaneous round restarting.
+	new iCount;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (i == client) continue;
+		
+		if (IsValidClient(i) && IsPlayerAlive(i))
+		{
+			new iTeam = GetClientTeam(i);
+			if ((iTeam == _:TFTeam_Red || iTeam == _:TFTeam_Blue) && iTeam == iMyTeam)
+			{
+				iCount++;
+			}
+		}
+	}
+	
+	if (!iCount) return;
+	
+	// Can only enable lag compensation only for specific weapons.
+	new iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
+	if (!IsValidEdict(iActiveWeapon)) return;
+	
+	decl String:sClassName[64];
+	GetEdictClassname(iActiveWeapon, sClassName, sizeof(sClassName));
+	
+	new bool:bCompensate = false;
+	for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
+	{
+		if (StrEqual(sClassName, g_strPlayerLagCompensationWeapons[i], false))
+		{
+			bCompensate = true;
+			break;
+		}
+	}
+	
+	if (!bCompensate) return;
+	
+	g_bPlayerLagCompensation[client] = true;
+	g_iPlayerLagCompensationTeam[client] = iMyTeam;
+	SetEntProp(client, Prop_Send, "m_iTeamNum", 0);
+}
+
+ClientDisableFakeLagCompensation(client)
+{
+	if (!g_bPlayerLagCompensation[client]) return;
+	
+	SetEntProp(client, Prop_Send, "m_iTeamNum", g_iPlayerLagCompensationTeam[client]);
+	g_bPlayerLagCompensation[client] = false;
+	g_iPlayerLagCompensationTeam[client] = -1;
+}
+
+//	==========================================================
+//	FLASHLIGHT / ULTRAVISION FUNCTIONS
+//	==========================================================
+
+bool:IsClientUsingFlashlight(client)
+{
+	return g_bPlayerFlashlight[client];
+}
+
+Float:ClientGetFlashlightBatteryLife(client)
+{
+	return g_flPlayerFlashlightBatteryLife[client];
+}
+
+ClientSetFlashlightBatteryLife(client, Float:flPercent)
+{
+	g_flPlayerFlashlightBatteryLife[client] = flPercent;
+}
+
+/**
+ *	Called in Hook_ClientPreThink, this makes sure the flashlight is oriented correctly on the player.
+ */
+static ClientProcessFlashlightAngles(client)
+{
+	if (!IsClientInGame(client)) return;
+	
+	if (IsPlayerAlive(client))
+	{
+		decl fl, Float:eyeAng[3], Float:ang2[3];
+		
+		if (IsClientUsingFlashlight(client))
+		{
+			fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
+			if (fl && fl != INVALID_ENT_REFERENCE)
+			{
+				TeleportEntity(fl, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 }, NULL_VECTOR);
+			}
+			
+			fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
+			if (fl && fl != INVALID_ENT_REFERENCE)
+			{
+				GetClientEyeAngles(client, eyeAng);
+				GetClientAbsAngles(client, ang2);
+				SubtractVectors(eyeAng, ang2, eyeAng);
+				TeleportEntity(fl, NULL_VECTOR, eyeAng, NULL_VECTOR);
+			}
+		}
+	}
+}
+
+/**
+ *	Handles whether or not the player's flashlight should be "flickering", a sign of a dying flashlight battery.
+ */
+static ClientHandleFlashlightFlickerState(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	if (IsClientUsingFlashlight(client))
+	{
+		new bool:bFlicker = bool:(ClientGetFlashlightBatteryLife(client) <= SF2_FLASHLIGHT_FLICKERAT);
+	
+		new fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
+		if (fl && fl != INVALID_ENT_REFERENCE)
+		{
+			if (bFlicker)
+			{
+				SetEntProp(fl, Prop_Data, "m_LightStyle", 10);
+			}
+			else
+			{
+				SetEntProp(fl, Prop_Data, "m_LightStyle", 0);
+			}
+		}
+		
+		fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
+		if (fl && fl != INVALID_ENT_REFERENCE)
+		{
+			if (bFlicker) 
+			{
+				SetEntityRenderFx(fl, RenderFx:13);
+			}
+			else 
+			{
+				SetEntityRenderFx(fl, RenderFx:0);
+			}
+		}
+	}
+}
+
+bool:IsClientFlashlightBroken(client)
+{
+	return g_bPlayerFlashlightBroken[client];
+}
+
+Float:ClientGetFlashlightNextInputTime(client)
+{
+	return g_flPlayerFlashlightNextInputTime[client];
+}
+
+/**
+ *	Breaks the player's flashlight. Nothing else.
+ */
+ClientBreakFlashlight(client)
+{
+	if (IsClientFlashlightBroken(client)) return;
+	
+	g_bPlayerFlashlightBroken[client] = true;
+	
+	ClientSetFlashlightBatteryLife(client, 0.0);
+	ClientTurnOffFlashlight(client);
+	
+	ClientAddStress(client, 0.2);
+	
+	EmitSoundToAll(FLASHLIGHT_BREAKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
+	
+	Call_StartForward(fOnClientBreakFlashlight);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+/**
+ *	Resets everything of the player's flashlight.
+ */
+ClientResetFlashlight(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetFlashlight(%d)", client);
+#endif
+	
+	ClientTurnOffFlashlight(client);
+	ClientSetFlashlightBatteryLife(client, 1.0);
+	g_bPlayerFlashlightBroken[client] = false;
+	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
+	g_flPlayerFlashlightNextInputTime[client] = -1.0;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetFlashlight(%d)", client);
+#endif
+}
+
+public Action:Hook_FlashlightSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (EntRefToEntIndex(g_iPlayerFlashlightEnt[other]) != ent) return Plugin_Handled;
+	
+	// We've already checked for flashlight ownership in the last statement. So we can do just this.
+	if (g_iPlayerPreferences[other][PlayerPreference_ProjectedFlashlight]) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_Flashlight2SetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[other]) == ent) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+public Hook_FlashlightEndSpawnPost(ent)
+{
+	if (!g_bEnabled) return;
+
+	SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightEndSetTransmit);
+	SDKUnhook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
+}
+
+public Action:Hook_FlashlightBeamSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	new iOwner = -1;
+	new iSpotlight = -1;
+	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
+	{
+		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
+		{
+			iOwner = iSpotlight;
+			break;
+		}
+	}
+	
+	if (iOwner == -1) return Plugin_Continue;
+	
+	new iClient = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
+		{
+			iClient = i;
+			break;
+		}
+	}
+	
+	if (iClient == -1) return Plugin_Continue;
+	
+	if (iClient == other)
+	{
+		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
+		{
+			return Plugin_Handled;
+		}
+	}
+	else
+	{
+		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+		{
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_FlashlightEndSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	new iOwner = -1;
+	new iSpotlight = -1;
+	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
+	{
+		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
+		{
+			iOwner = iSpotlight;
+			break;
+		}
+	}
+	
+	if (iOwner == -1) return Plugin_Continue;
+	
+	new iClient = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
+		{
+			iClient = i;
+			break;
+		}
+	}
+	
+	if (iClient == -1) return Plugin_Continue;
+	
+	if (iClient == other)
+	{
+		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
+		{
+			return Plugin_Handled;
+		}
+	}
+	else
+	{
+		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+		{
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_DrainFlashlight(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
+	
+	new iOverride = GetConVarInt(g_cvPlayerInfiniteFlashlightOverride);
+	if ((!g_bRoundInfiniteFlashlight && iOverride != 1) || iOverride == 0)
+	{
+		ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) - 0.01);
+	}
+	
+	if (ClientGetFlashlightBatteryLife(client) <= 0.0)
+	{
+		// Break the player's flashlight, but also start recharging.
+		ClientBreakFlashlight(client);
+		ClientStartRechargingFlashlightBattery(client);
+		ClientActivateUltravision(client);
+		return Plugin_Stop;
+	}
+	else
+	{
+		ClientHandleFlashlightFlickerState(client);
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_RechargeFlashlight(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
+	
+	ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) + 0.01);
+	
+	if (IsClientFlashlightBroken(client) && ClientGetFlashlightBatteryLife(client) >= SF2_FLASHLIGHT_ENABLEAT)
+	{
+		// Repair the flashlight.
+		g_bPlayerFlashlightBroken[client] = false;
+	}
+	
+	if (ClientGetFlashlightBatteryLife(client) >= 1.0)
+	{
+		// I am fully charged!
+		ClientSetFlashlightBatteryLife(client, 1.0);
+		g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
+		
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+/**
+ *	Turns on the player's flashlight. Nothing else.
+ */
+ClientTurnOnFlashlight(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	if (IsClientUsingFlashlight(client)) return;
+	
+	g_bPlayerFlashlight[client] = true;
+	
+	decl Float:flEyePos[3];
+	GetClientEyePosition(client, flEyePos);
+	
+	if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
+	{
+		// If the player is using the projected flashlight, just set effect flags.
+		new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+		if (!(iEffects & (1 << 2)))
+		{
+			SetEntProp(client, Prop_Send, "m_fEffects", iEffects | (1 << 2));
+		}
+	}
+	else
+	{
+		// Spawn the light which only the user will see.
+		new ent = CreateEntityByName("light_dynamic");
+		if (ent != -1)
+		{
+			TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
+			DispatchKeyValue(ent, "targetname", "WUBADUBDUBMOTHERBUCKERS");
+			DispatchKeyValue(ent, "rendercolor", "255 255 255");
+			SetVariantFloat(SF2_FLASHLIGHT_WIDTH);
+			AcceptEntityInput(ent, "spotlight_radius");
+			SetVariantFloat(SF2_FLASHLIGHT_LENGTH);
+			AcceptEntityInput(ent, "distance");
+			SetVariantInt(SF2_FLASHLIGHT_BRIGHTNESS);
+			AcceptEntityInput(ent, "brightness");
+			
+			// Convert WU to inches.
+			new Float:cone = 55.0;
+			cone *= 0.75;
+			
+			SetVariantInt(RoundToFloor(cone));
+			AcceptEntityInput(ent, "_inner_cone");
+			SetVariantInt(RoundToFloor(cone));
+			AcceptEntityInput(ent, "_cone");
+			DispatchSpawn(ent);
+			ActivateEntity(ent);
+			SetVariantString("!activator");
+			AcceptEntityInput(ent, "SetParent", client);
+			AcceptEntityInput(ent, "TurnOn");
+			
+			g_iPlayerFlashlightEnt[client] = EntIndexToEntRef(ent);
+			
+			SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightSetTransmit);
+		}
+	}
+	
+	// Spawn the light that only everyone else will see.
+	new ent = CreateEntityByName("point_spotlight");
+	if (ent != -1)
+	{
+		TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
+		
+		decl String:sBuffer[256];
+		FloatToString(SF2_FLASHLIGHT_LENGTH, sBuffer, sizeof(sBuffer));
+		DispatchKeyValue(ent, "spotlightlength", sBuffer);
+		FloatToString(SF2_FLASHLIGHT_WIDTH, sBuffer, sizeof(sBuffer));
+		DispatchKeyValue(ent, "spotlightwidth", sBuffer);
+		DispatchKeyValue(ent, "rendercolor", "255 255 255");
+		DispatchSpawn(ent);
+		ActivateEntity(ent);
+		SetVariantString("!activator");
+		AcceptEntityInput(ent, "SetParent", client);
+		AcceptEntityInput(ent, "LightOn");
+		
+		g_iPlayerFlashlightEntAng[client] = EntIndexToEntRef(ent);
+	}
+	
+	Call_StartForward(fOnClientActivateFlashlight);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+/**
+ *	Turns off the player's flashlight. Nothing else.
+ */
+ClientTurnOffFlashlight(client)
+{
+	if (!IsClientUsingFlashlight(client)) return;
+	
+	g_bPlayerFlashlight[client] = false;
+	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
+	
+	// Remove user-only light.
+	new ent = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE) 
+	{
+		AcceptEntityInput(ent, "TurnOff");
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	// Remove everyone-else-only light.
+	ent = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE) 
+	{
+		AcceptEntityInput(ent, "LightOff");
+		CreateTimer(0.1, Timer_KillEntity, g_iPlayerFlashlightEntAng[client], TIMER_FLAG_NO_MAPCHANGE);
+	}
+	
+	g_iPlayerFlashlightEnt[client] = INVALID_ENT_REFERENCE;
+	g_iPlayerFlashlightEntAng[client] = INVALID_ENT_REFERENCE;
+	
+	if (IsClientInGame(client))
+	{
+		if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
+		{
+			new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+			if (iEffects & (1 << 2))
+			{
+				SetEntProp(client, Prop_Send, "m_fEffects", iEffects &= ~(1 << 2));
+			}
+		}
+	}
+	
+	Call_StartForward(fOnClientDeactivateFlashlight);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+ClientStartRechargingFlashlightBattery(client)
+{
+	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(SF2_FLASHLIGHT_RECHARGE_RATE, Timer_RechargeFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStartDrainingFlashlightBattery(client)
+{
+	new Float:flDrainRate = SF2_FLASHLIGHT_DRAIN_RATE;
+	if (TF2_GetPlayerClass(client) == TFClass_Engineer) 
+	{
+		// Engineers have a 33% longer battery life, basically.
+		// TODO: Make this value customizable via cvar.
+		flDrainRate *= 1.33;
+	}
+	
+	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(flDrainRate, Timer_DrainFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientHandleFlashlight(client)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client)) return;
+	
+	if (IsClientUsingFlashlight(client)) 
+	{
+		ClientTurnOffFlashlight(client);
+		ClientStartRechargingFlashlightBattery(client);
+		ClientActivateUltravision(client);
+		
+		g_flPlayerFlashlightNextInputTime[client] = GetGameTime() + SF2_FLASHLIGHT_COOLDOWN;
+		
+		EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
+	}
+	else
+	{
+		// Only players in the "game" can use the flashlight.
+		if (!g_bPlayerEliminated[client])
+		{
+			new bool:bCanUseFlashlight = true;
+			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_LIGHTSOUT) 
+			{
+				// Unequip the flashlight please.
+				bCanUseFlashlight = false;
+			}
+			
+			if (!IsClientFlashlightBroken(client) && bCanUseFlashlight)
+			{
+				ClientTurnOnFlashlight(client);
+				ClientStartDrainingFlashlightBattery(client);
+				ClientDeactivateUltravision(client);
+				
+				g_flPlayerFlashlightNextInputTime[client] = GetGameTime();
+				
+				EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
+			}
+			else
+			{
+				EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
+			}
+		}
+	}
+}
+
+bool:IsClientUsingUltravision(client)
+{
+	return g_bPlayerUltravision[client];
+}
+
+ClientActivateUltravision(client)
+{
+	if (!IsClientInGame(client) || IsClientUsingUltravision(client)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientActivateUltravision(%d)", client);
+#endif
+	
+	g_bPlayerUltravision[client] = true;
+	
+	new ent = CreateEntityByName("light_dynamic");
+	if (ent != -1)
+	{
+		decl Float:flEyePos[3];
+		GetClientEyePosition(client, flEyePos);
+		
+		TeleportEntity(ent, flEyePos, Float:{ 90.0, 0.0, 0.0 }, NULL_VECTOR);
+		DispatchKeyValue(ent, "rendercolor", "0 200 255");
+		
+		new Float:flRadius = 0.0;
+		if (g_bPlayerEliminated[client])
+		{
+			flRadius = GetConVarFloat(g_cvUltravisionRadiusBlue);
+		}
+		else
+		{
+			flRadius = GetConVarFloat(g_cvUltravisionRadiusRed);
+		}
+		
+		SetVariantFloat(flRadius);
+		AcceptEntityInput(ent, "spotlight_radius");
+		SetVariantFloat(flRadius);
+		AcceptEntityInput(ent, "distance");
+		
+		SetVariantInt(-15); // Start dark, then fade in via the Timer_UltravisionFadeInEffect timer func.
+		AcceptEntityInput(ent, "brightness");
+		
+		// Convert WU to inches.
+		new Float:cone = SF2_ULTRAVISION_CONE;
+		cone *= 0.75;
+		
+		SetVariantInt(RoundToFloor(cone));
+		AcceptEntityInput(ent, "_inner_cone");
+		SetVariantInt(0);
+		AcceptEntityInput(ent, "_cone");
+		DispatchSpawn(ent);
+		ActivateEntity(ent);
+		SetVariantString("!activator");
+		AcceptEntityInput(ent, "SetParent", client);
+		AcceptEntityInput(ent, "TurnOn");
+		SetEntityRenderFx(ent, RENDERFX_SOLID_SLOW);
+		SetEntityRenderColor(ent, 100, 200, 255, 255);
+		
+		g_iPlayerUltravisionEnt[client] = EntIndexToEntRef(ent);
+		
+		SDKHook(ent, SDKHook_SetTransmit, Hook_UltravisionSetTransmit);
+		
+		// Fade in effect.
+		CreateTimer(0.0, Timer_UltravisionFadeInEffect, g_iPlayerUltravisionEnt[client], TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	}
+
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientActivateUltravision(%d)", client);
+#endif
+}
+
+public Action:Timer_UltravisionFadeInEffect(Handle:timer, any:entref)
+{
+	new ent = EntRefToEntIndex(entref);
+	if (!ent || ent == INVALID_ENT_REFERENCE) return Plugin_Stop;
+	
+	new iBrightness = GetEntProp(ent, Prop_Send, "m_Exponent");
+	if (iBrightness >= GetConVarInt(g_cvUltravisionBrightness)) return Plugin_Stop;
+	
+	iBrightness++;
+	SetVariantInt(iBrightness);
+	AcceptEntityInput(ent, "brightness");
+	
+	return Plugin_Continue;
+}
+
+ClientDeactivateUltravision(client)
+{
+	if (!IsClientUsingUltravision(client)) return;
+	
+	g_bPlayerUltravision[client] = false;
+	
+	new ent = EntRefToEntIndex(g_iPlayerUltravisionEnt[client]);
+	if (ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "TurnOff");
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	g_iPlayerUltravisionEnt[client] = INVALID_ENT_REFERENCE;
+}
+
+public Action:Hook_UltravisionSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (!GetConVarBool(g_cvUltravisionEnabled) || EntRefToEntIndex(g_iPlayerUltravisionEnt[other]) != ent || !IsPlayerAlive(other)) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+static Float:ClientGetDefaultWalkSpeed(client)
+{
+	new Float:flReturn = 190.0;
+	new Float:flReturn2 = flReturn;
+	new Action:iAction = Plugin_Continue;
+	new TFClassType:iClass = TF2_GetPlayerClass(client);
+	
+	switch (iClass)
+	{
+		case TFClass_Scout: flReturn = 190.0;
+		case TFClass_Sniper: flReturn = 190.0;
+		case TFClass_Soldier: flReturn = 190.0;
+		case TFClass_DemoMan: flReturn = 190.0;
+		case TFClass_Heavy: flReturn = 190.0;
+		case TFClass_Medic: flReturn = 190.0;
+		case TFClass_Pyro: flReturn = 190.0;
+		case TFClass_Spy: flReturn = 190.0;
+		case TFClass_Engineer: flReturn = 190.0;
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnClientGetDefaultWalkSpeed);
+	Call_PushCell(client);
+	Call_PushCellRef(flReturn2);
+	Call_Finish(iAction);
+	
+	if (iAction == Plugin_Changed) flReturn = flReturn2;
+	
+	return flReturn;
+}
+
+static Float:ClientGetDefaultSprintSpeed(client)
+{
+	new Float:flReturn = 300.0;
+	new Float:flReturn2 = flReturn;
+	new Action:iAction = Plugin_Continue;
+	new TFClassType:iClass = TF2_GetPlayerClass(client);
+	
+	switch (iClass)
+	{
+		case TFClass_Scout: flReturn = 300.0;
+		case TFClass_Sniper: flReturn = 300.0;
+		case TFClass_Soldier: flReturn = 275.0;
+		case TFClass_DemoMan: flReturn = 285.0;
+		case TFClass_Heavy: flReturn = 270.0;
+		case TFClass_Medic: flReturn = 300.0;
+		case TFClass_Pyro: flReturn = 300.0;
+		case TFClass_Spy: flReturn = 300.0;
+		case TFClass_Engineer: flReturn = 300.0;
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnClientGetDefaultSprintSpeed);
+	Call_PushCell(client);
+	Call_PushCellRef(flReturn2);
+	Call_Finish(iAction);
+	
+	if (iAction == Plugin_Changed) flReturn = flReturn2;
+	
+	return flReturn;
+}
+
+// Static shaking should only affect the x, y portion of the player's view, not roll.
+// This is purely for cosmetic effect.
+
+ClientProcessStaticShake(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	new bool:bOldStaticShake = g_bPlayerInStaticShake[client];
+	new iOldStaticShakeMaster = NPCGetFromUniqueID(g_iPlayerStaticShakeMaster[client]);
+	new iNewStaticShakeMaster = -1;
+	new Float:flNewStaticShakeMasterAnger = -1.0;
+	
+	new Float:flOldPunchAng[3], Float:flOldPunchAngVel[3];
+	GetEntDataVector(client, g_offsPlayerPunchAngle, flOldPunchAng);
+	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flOldPunchAngVel);
+	
+	new Float:flNewPunchAng[3], Float:flNewPunchAngVel[3];
+	
+	for (new i = 0; i < 3; i++)
+	{
+		flNewPunchAng[i] = flOldPunchAng[i];
+		flNewPunchAngVel[i] = flOldPunchAngVel[i];
+	}
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		if (g_iPlayerStaticMode[client][i] != Static_Increase) continue;
+		if (!(NPCGetFlags(i) & SFF_HASSTATICSHAKE)) continue;
+		
+		if (NPCGetAnger(i) > flNewStaticShakeMasterAnger)
+		{
+			new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
+			if (iMaster == -1) iMaster = i;
+			
+			iNewStaticShakeMaster = iMaster;
+			flNewStaticShakeMasterAnger = NPCGetAnger(iMaster);
+		}
+	}
+	
+	if (iNewStaticShakeMaster != -1)
+	{
+		g_iPlayerStaticShakeMaster[client] = NPCGetUniqueID(iNewStaticShakeMaster);
+		
+		if (iNewStaticShakeMaster != iOldStaticShakeMaster)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iNewStaticShakeMaster, sProfile, sizeof(sProfile));
+		
+			if (g_strPlayerStaticShakeSound[client][0])
+			{
+				StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
+			}
+			
+			g_flPlayerStaticShakeMinVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_min", 0.0);
+			g_flPlayerStaticShakeMaxVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_max", 1.0);
+			
+			decl String:sStaticSound[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_static_shake_local", sStaticSound, sizeof(sStaticSound));
+			if (sStaticSound[0])
+			{
+				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), sStaticSound);
+			}
+			else
+			{
+				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
+			}
+		}
+	}
+	
+	if (g_bPlayerInStaticShake[client])
+	{
+		if (g_flPlayerStaticAmount[client] <= 0.0)
+		{
+			g_bPlayerInStaticShake[client] = false;
+		}
+	}
+	else
+	{
+		if (iNewStaticShakeMaster != -1)
+		{
+			g_bPlayerInStaticShake[client] = true;
+		}
+	}
+	
+	if (g_bPlayerInStaticShake[client] && !bOldStaticShake)
+	{	
+		for (new i = 0; i < 2; i++)
+		{
+			flNewPunchAng[i] = 0.0;
+			flNewPunchAngVel[i] = 0.0;
+		}
+		
+		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
+		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
+	}
+	else if (!g_bPlayerInStaticShake[client] && bOldStaticShake)
+	{
+		for (new i = 0; i < 2; i++)
+		{
+			flNewPunchAng[i] = 0.0;
+			flNewPunchAngVel[i] = 0.0;
+		}
+	
+		g_iPlayerStaticShakeMaster[client] = -1;
+		
+		if (g_strPlayerStaticShakeSound[client][0])
+		{
+			StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
+		}
+		
+		strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
+		
+		g_flPlayerStaticShakeMinVolume[client] = 0.0;
+		g_flPlayerStaticShakeMaxVolume[client] = 0.0;
+		
+		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
+		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
+	}
+	
+	if (g_bPlayerInStaticShake[client])
+	{
+		if (g_strPlayerStaticShakeSound[client][0])
+		{
+			new Float:flVolume = g_flPlayerStaticAmount[client];
+			if (GetRandomFloat(0.0, 1.0) <= 0.35)
+			{
+				flVolume = 0.0;
+			}
+			else
+			{
+				if (flVolume < g_flPlayerStaticShakeMinVolume[client])
+				{
+					flVolume = g_flPlayerStaticShakeMinVolume[client];
+				}
+				
+				if (flVolume > g_flPlayerStaticShakeMaxVolume[client])
+				{
+					flVolume = g_flPlayerStaticShakeMaxVolume[client];
+				}
+			}
+			
+			EmitSoundToClient(client, g_strPlayerStaticShakeSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL | SND_STOP, flVolume);
+		}
+		
+		// Spazz our view all over the place.
+		for (new i = 0; i < 2; i++) flNewPunchAng[i] = AngleNormalize(GetRandomFloat(0.0, 360.0));
+		NormalizeVector(flNewPunchAng, flNewPunchAng);
+		
+		new Float:flAngVelocityScalar = 5.0 * g_flPlayerStaticAmount[client];
+		if (flAngVelocityScalar < 1.0) flAngVelocityScalar = 1.0;
+		ScaleVector(flNewPunchAng, flAngVelocityScalar);
+		
+		for (new i = 0; i < 2; i++) flNewPunchAngVel[i] = 0.0;
+		
+		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
+		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
+	}
+}
+
+ClientProcessVisibility(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	new String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	new bool:bWasSeeingSlender[MAX_BOSSES];
+	new iOldStaticMode[MAX_BOSSES];
+	
+	decl Float:flSlenderPos[3];
+	decl Float:flSlenderEyePos[3];
+	decl Float:flSlenderOBBCenterPos[3];
+	
+	decl Float:flMyPos[3];
+	GetClientAbsOrigin(client, flMyPos);
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		bWasSeeingSlender[i] = g_bPlayerSeesSlender[client][i];
+		iOldStaticMode[i] = g_iPlayerStaticMode[client][i];
+		g_bPlayerSeesSlender[client][i] = false;
+		g_iPlayerStaticMode[client][i] = Static_None;
+		
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		new iBoss = NPCGetEntIndex(i);
+		
+		if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+		{
+			SlenderGetAbsOrigin(i, flSlenderPos);
+			NPCGetEyePosition(i, flSlenderEyePos);
+			
+			decl Float:flSlenderMins[3], Float:flSlenderMaxs[3];
+			GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flSlenderMins);
+			GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flSlenderMaxs);
+			
+			for (new i2 = 0; i2 < 3; i2++) flSlenderOBBCenterPos[i2] = flSlenderPos[i2] + ((flSlenderMins[i2] + flSlenderMaxs[i2]) / 2.0);
+		}
+		
+		if (IsClientInGhostMode(client))
+		{
+		}
+		else if (!IsClientInDeathCam(client))
+		{
+			if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+			{
+				new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
+				
+				if (!IsPointVisibleToPlayer(client, flSlenderEyePos, true, SlenderUsesBlink(i)))
+				{
+					g_bPlayerSeesSlender[client][i] = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, true, SlenderUsesBlink(i));
+				}
+				else
+				{
+					g_bPlayerSeesSlender[client][i] = true;
+				}
+				
+				if ((GetGameTime() - g_flPlayerSeesSlenderLastTime[client][i]) > GetProfileFloat(sProfile, "static_on_look_gracetime", 1.0) ||
+					(iOldStaticMode[i] == Static_Increase && g_flPlayerStaticAmount[client] > 0.1))
+				{
+					if ((NPCGetFlags(i) & SFF_STATICONLOOK) && 
+						g_bPlayerSeesSlender[client][i])
+					{
+						if (iCopyMaster != -1)
+						{
+							g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
+						}
+						else
+						{
+							g_iPlayerStaticMode[client][i] = Static_Increase;
+						}
+					}
+					else if ((NPCGetFlags(i) & SFF_STATICONRADIUS) && 
+						GetVectorDistance(flMyPos, flSlenderPos) <= g_flSlenderStaticRadius[i])
+					{
+						new bool:bNoObstacles = IsPointVisibleToPlayer(client, flSlenderEyePos, false, false);
+						if (!bNoObstacles) bNoObstacles = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, false);
+						
+						if (bNoObstacles)
+						{
+							if (iCopyMaster != -1)
+							{
+								g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
+							}
+							else
+							{
+								g_iPlayerStaticMode[client][i] = Static_Increase;
+							}
+						}
+					}
+				}
+				
+				// Process death cam sequence conditions
+				if (SlenderKillsOnNear(i))
+				{
+					if (g_flPlayerStaticAmount[client] >= 1.0 ||
+						GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetInstantKillRadius(i))
+					{
+						new bool:bKillPlayer = true;
+						if (g_flPlayerStaticAmount[client] < 1.0)
+						{
+							bKillPlayer = IsPointVisibleToPlayer(client, flSlenderEyePos, false, SlenderUsesBlink(i));
+						}
+						
+						if (!bKillPlayer) bKillPlayer = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, SlenderUsesBlink(i));
+						
+						if (bKillPlayer)
+						{
+							g_flSlenderLastKill[i] = GetGameTime();
+							
+							if (g_flPlayerStaticAmount[client] >= 1.0)
+							{
+								ClientStartDeathCam(client, NPCGetFromUniqueID(g_iPlayerStaticMaster[client]), flSlenderPos);
+							}
+							else
+							{
+								ClientStartDeathCam(client, i, flSlenderPos);
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
+		if (iMaster == -1) iMaster = i;
+		
+		// Boss visiblity.
+		if (g_bPlayerSeesSlender[client][i] && !bWasSeeingSlender[i])
+		{
+			g_flPlayerSeesSlenderLastTime[client][iMaster] = GetGameTime();
+			
+			if (GetGameTime() >= g_flPlayerScareNextTime[client][iMaster])
+			{
+				if (GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetScareRadius(i))
+				{
+					ClientPerformScare(client, iMaster);
+					
+					if (NPCHasAttribute(iMaster, "ignite player on scare"))
+					{
+						new Float:flValue = NPCGetAttributeValue(iMaster, "ignite player on scare");
+						if (flValue > 0.0) TF2_IgnitePlayer(client, client);
+					}
+				}
+				else
+				{
+					g_flPlayerScareNextTime[client][iMaster] = GetGameTime() + GetProfileFloat(sProfile, "scare_cooldown");
+				}
+			}
+			
+			if (NPCGetType(i) == SF2BossType_Static)
+			{
+				if (NPCGetFlags(i) & SFF_FAKE)
+				{
+					SlenderMarkAsFake(i);
+					return;
+				}
+			}
+			
+			Call_StartForward(fOnClientLooksAtBoss);
+			Call_PushCell(client);
+			Call_PushCell(i);
+			Call_Finish();
+		}
+		else if (!g_bPlayerSeesSlender[client][i] && bWasSeeingSlender[i])
+		{
+			g_flPlayerScareLastTime[client][iMaster] = GetGameTime();
+			
+			Call_StartForward(fOnClientLooksAwayFromBoss);
+			Call_PushCell(client);
+			Call_PushCell(i);
+			Call_Finish();
+		}
+		
+		if (g_bPlayerSeesSlender[client][i])
+		{
+			if (GetGameTime() >= g_flPlayerSightSoundNextTime[client][iMaster])
+			{
+				ClientPerformSightSound(client, i);
+			}
+		}
+		
+		if (g_iPlayerStaticMode[client][i] == Static_Increase &&
+			iOldStaticMode[i] != Static_Increase)
+		{
+			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
+			{
+				decl String:sLoopSound[PLATFORM_MAX_PATH];
+				GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
+				
+				if (sLoopSound[0])
+				{
+					EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, GetProfileNum(sProfile, "sound_static_loop_local_level", SNDLEVEL_NORMAL), SND_CHANGEVOL, 1.0);
+					ClientAddStress(client, 0.03);
+				}
+				else
+				{
+					LogError("Warning! Boss %s supports static loop local sounds, but was given a blank sound path!", sProfile);
+				}
+			}
+		}
+		else if (g_iPlayerStaticMode[client][i] != Static_Increase &&
+			iOldStaticMode[i] == Static_Increase)
+		{
+			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
+			{
+				if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+				{
+					decl String:sLoopSound[PLATFORM_MAX_PATH];
+					GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
+					
+					if (sLoopSound[0])
+					{
+						EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, _, SND_CHANGEVOL | SND_STOP, 0.0);
+					}
+				}
+			}
+		}
+	}
+	
+	// Initialize static timers.
+	new iBossLastStatic = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
+	new iBossNewStatic = -1;
+	if (iBossLastStatic != -1 && g_iPlayerStaticMode[client][iBossLastStatic] == Static_Increase)
+	{
+		iBossNewStatic = iBossLastStatic;
+	}
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		new iStaticMode = g_iPlayerStaticMode[client][i];
+		
+		// Determine new static rates.
+		if (iStaticMode != Static_Increase) continue;
+		
+		if (iBossLastStatic == -1 || 
+			g_iPlayerStaticMode[client][iBossLastStatic] != Static_Increase || 
+			NPCGetAnger(i) > NPCGetAnger(iBossLastStatic))
+		{
+			iBossNewStatic = i;
+		}
+	}
+	
+	if (iBossNewStatic != -1)
+	{
+		new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossNewStatic]);
+		if (iCopyMaster != -1)
+		{
+			iBossNewStatic = iCopyMaster;
+			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iCopyMaster);
+		}
+		else
+		{
+			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iBossNewStatic);
+		}
+	}
+	else
+	{
+		g_iPlayerStaticMaster[client] = -1;
+	}
+	
+	if (iBossNewStatic != iBossLastStatic)
+	{
+		if (!StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false))
+		{
+			// Stop last-last static sound entirely.
+			if (g_strPlayerLastStaticSound[client][0])
+			{
+				StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+			}
+		}
+		
+		// Move everything down towards the last arrays.
+		if (g_strPlayerStaticSound[client][0])
+		{
+			strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), g_strPlayerStaticSound[client]);
+		}
+		
+		if (iBossNewStatic == -1)
+		{
+			// No one is the static master.
+			g_hPlayerStaticTimer[client] = CreateTimer(g_flPlayerStaticDecreaseRate[client], 
+				Timer_ClientDecreaseStatic, 
+				GetClientUserId(client), 
+				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+				
+			TriggerTimer(g_hPlayerStaticTimer[client], true);
+		}
+		else
+		{
+			NPCGetProfile(iBossNewStatic, sProfile, sizeof(sProfile));
+		
+			strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
+			
+			new String:sStaticSound[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_static", sStaticSound, sizeof(sStaticSound), 1);
+			
+			if (sStaticSound[0]) 
+			{
+				strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), sStaticSound);
+			}
+			
+			// Cross-fade out the static sounds.
+			g_flPlayerLastStaticVolume[client] = g_flPlayerStaticAmount[client];
+			g_flPlayerLastStaticTime[client] = GetGameTime();
+			
+			g_hPlayerLastStaticTimer[client] = CreateTimer(0.0, 
+				Timer_ClientFadeOutLastStaticSound, 
+				GetClientUserId(client), 
+				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			
+			TriggerTimer(g_hPlayerLastStaticTimer[client], true);
+			
+			// Start up our own static timer.
+			new Float:flStaticIncreaseRate = GetProfileFloat(sProfile, "static_rate") / g_flRoundDifficultyModifier;
+			new Float:flStaticDecreaseRate = GetProfileFloat(sProfile, "static_rate_decay");
+			
+			g_flPlayerStaticIncreaseRate[client] = flStaticIncreaseRate;
+			g_flPlayerStaticDecreaseRate[client] = flStaticDecreaseRate;
+			
+			g_hPlayerStaticTimer[client] = CreateTimer(flStaticIncreaseRate, 
+				Timer_ClientIncreaseStatic, 
+				GetClientUserId(client), 
+				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			
+			TriggerTimer(g_hPlayerStaticTimer[client], true);
+		}
+	}
+}
+
+ClientProcessViewAngles(client)
+{
+	if ((!g_bPlayerEliminated[client] || g_bPlayerProxy[client]) && 
+		!DidClientEscape(client))
+	{
+		// Process view bobbing, if enabled.
+		// This code is based on the code in this page: https://developer.valvesoftware.com/wiki/Camera_Bob
+		// Many thanks to whomever created it in the first place.
+		
+		if (IsPlayerAlive(client))
+		{
+			if (g_bPlayerViewbobEnabled)
+			{
+				new Float:flPunchVel[3];
+			
+				if (!g_bPlayerViewbobSprintEnabled || !IsClientReallySprinting(client))
+				{
+					if (GetEntityFlags(client) & FL_ONGROUND)
+					{
+						decl Float:flVelocity[3];
+						GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
+						new Float:flSpeed = GetVectorLength(flVelocity);
+						
+						new Float:flPunchIdle[3];
+						
+						if (flSpeed > 0.0)
+						{
+							if (flSpeed >= 60.0)
+							{
+								flPunchIdle[0] = Sine(GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_X / 400.0;
+								flPunchIdle[1] = Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Y / 400.0;
+								flPunchIdle[2] = Sine(1.6 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Z / 400.0;
+								
+								AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+							}
+							
+							// Calculate roll.
+							decl Float:flForward[3], Float:flVelocityDirection[3];
+							GetClientEyeAngles(client, flForward);
+							GetVectorAngles(flVelocity, flVelocityDirection);
+							
+							new Float:flYawDiff = AngleDiff(flForward[1], flVelocityDirection[1]);
+							if (FloatAbs(flYawDiff) > 90.0) flYawDiff = AngleDiff(flForward[1] + 180.0, flVelocityDirection[1]) * -1.0;
+							
+							new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
+							new Float:flRollScalar = flSpeed / flWalkSpeed;
+							if (flRollScalar > 1.0) flRollScalar = 1.0;
+							
+							new Float:flRollScale = (flYawDiff / 90.0) * 0.25 * flRollScalar;
+							flPunchIdle[0] = 0.0;
+							flPunchIdle[1] = 0.0;
+							flPunchIdle[2] = flRollScale * -1.0;
+							
+							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+						}
+						
+						/*
+						if (flSpeed < 60.0) 
+						{
+							flPunchIdle[0] = FloatAbs(Cosine(GetGameTime() * 1.25) * 0.047);
+							flPunchIdle[1] = Sine(GetGameTime() * 1.25) * 0.075;
+							flPunchIdle[2] = 0.0;
+							
+							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+						}
+						*/
+					}
+				}
+				
+				if (g_bPlayerViewbobHurtEnabled)
+				{
+					// Shake screen the more the player is hurt.
+					new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
+					new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
+					
+					decl Float:flPunchVelHurt[3];
+					flPunchVelHurt[0] = Sine(1.22 * GetGameTime()) * 48.5 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
+					flPunchVelHurt[1] = Sine(2.12 * GetGameTime()) * 80.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
+					flPunchVelHurt[2] = Sine(0.5 * GetGameTime()) * 36.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
+					
+					AddVectors(flPunchVel, flPunchVelHurt, flPunchVel);
+				}
+				
+				ClientViewPunch(client, flPunchVel);
+			}
+		}
+	}
+}
+
+public Action:Timer_ClientIncreaseStatic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
+	
+	g_flPlayerStaticAmount[client] += 0.05;
+	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
+	
+	if (g_strPlayerStaticSound[client][0])
+	{
+		EmitSoundToClient(client, g_strPlayerStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerStaticAmount[client]);
+		
+		if (g_flPlayerStaticAmount[client] >= 0.5) ClientAddStress(client, 0.03);
+		else
+		{
+			ClientAddStress(client, 0.02);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_ClientDecreaseStatic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
+	
+	g_flPlayerStaticAmount[client] -= 0.05;
+	if (g_flPlayerStaticAmount[client] < 0.0) g_flPlayerStaticAmount[client] = 0.0;
+	
+	if (g_strPlayerLastStaticSound[client][0])
+	{
+		new Float:flVolume = g_flPlayerStaticAmount[client];
+		if (flVolume > 0.0)
+		{
+			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
+		}
+	}
+	
+	if (g_flPlayerStaticAmount[client] <= 0.0)
+	{
+		// I've done my job; no point to keep on doing it.
+		StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+		g_hPlayerStaticTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_ClientFadeOutLastStaticSound(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerLastStaticTimer[client]) return Plugin_Stop;
+	
+	if (StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false)) 
+	{
+		// Wait, the player's current static sound is the same one we're stopping. Abort!
+		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	if (g_strPlayerLastStaticSound[client][0])
+	{
+		new Float:flDiff = (GetGameTime() - g_flPlayerLastStaticTime[client]) / 1.0;
+		if (flDiff > 1.0) flDiff = 1.0;
+		
+		new Float:flVolume = g_flPlayerLastStaticVolume[client] - flDiff;
+		if (flVolume < 0.0) flVolume = 0.0;
+		
+		if (flVolume <= 0.0)
+		{
+			// I've done my job; no point to keep on doing it.
+			StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+			g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+			return Plugin_Stop;
+		}
+		else
+		{
+			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
+		}
+	}
+	else
+	{
+		// I've done my job; no point to keep on doing it.
+		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	INTERACTIVE GLOW FUNCTIONS
+//	==========================================================
+
+static ClientProcessInteractiveGlow(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client) || (g_bPlayerEliminated[client] && !g_bPlayerProxy[client]) || IsClientInGhostMode(client)) return;
+	
+	new iOldLookEntity = EntRefToEntIndex(g_iPlayerInteractiveGlowTargetEntity[client]);
+	
+	decl Float:flStartPos[3], Float:flMyEyeAng[3];
+	GetClientEyePosition(client, flStartPos);
+	GetClientEyeAngles(client, flMyEyeAng);
+	
+	new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flMyEyeAng, MASK_VISIBLE, RayType_Infinite, TraceRayDontHitPlayers, -1);
+	new iEnt = TR_GetEntityIndex(hTrace);
+	CloseHandle(hTrace);
+	
+	if (IsValidEntity(iEnt))
+	{
+		g_iPlayerInteractiveGlowTargetEntity[client] = EntRefToEntIndex(iEnt);
+	}
+	else
+	{
+		g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
+	}
+	
+	if (iEnt != iOldLookEntity)
+	{
+		ClientRemoveInteractiveGlow(client);
+		
+		if (IsEntityClassname(iEnt, "prop_dynamic", false))
+		{
+			decl String:sTargetName[64];
+			GetEntPropString(iEnt, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
+			
+			if (StrContains(sTargetName, "sf2_page", false) == 0 || StrContains(sTargetName, "sf2_interact", false) == 0)
+			{
+				ClientCreateInteractiveGlow(client, iEnt);
+			}
+		}
+	}
+}
+
+ClientResetInteractiveGlow(client)
+{
+	ClientRemoveInteractiveGlow(client);
+	g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
+}
+
+/**
+ *	Removes the player's current interactive glow entity.
+ */
+ClientRemoveInteractiveGlow(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientRemoveInteractiveGlow(%d)", client);
+#endif
+
+	new ent = EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	g_iPlayerInteractiveGlowEntity[client] = INVALID_ENT_REFERENCE;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientRemoveInteractiveGlow(%d)", client);
+#endif
+}
+
+/**
+ *	Creates an interactive glow for an entity to show to a player.
+ */
+bool:ClientCreateInteractiveGlow(client, iEnt, const String:sAttachment[]="")
+{
+	ClientRemoveInteractiveGlow(client);
+	
+	if (!IsClientInGame(client)) return false;
+	
+	if (!iEnt || !IsValidEdict(iEnt)) return false;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientCreateInteractiveGlow(%d)", client);
+#endif
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetEntPropString(iEnt, Prop_Data, "m_ModelName", sBuffer, sizeof(sBuffer));
+	
+	if (strlen(sBuffer) == 0) 
+	{
+		return false;
+	}
+	
+	new ent = CreateEntityByName("tf_taunt_prop");
+	if (ent != -1)
+	{
+		g_iPlayerInteractiveGlowEntity[client] = EntIndexToEntRef(ent);
+		
+		new Float:flModelScale = GetEntPropFloat(iEnt, Prop_Send, "m_flModelScale");
+		
+		SetEntityModel(ent, sBuffer);
+		DispatchSpawn(ent);
+		ActivateEntity(ent);
+		SetEntityRenderMode(ent, RENDER_TRANSCOLOR);
+		SetEntityRenderColor(ent, 0, 0, 0, 0);
+		SetEntProp(ent, Prop_Send, "m_bGlowEnabled", 1);
+		SetEntPropFloat(ent, Prop_Send, "m_flModelScale", flModelScale);
+		
+		new iFlags = GetEntProp(ent, Prop_Send, "m_fEffects");
+		SetEntProp(ent, Prop_Send, "m_fEffects", iFlags | (1 << 0));
+		
+		SetVariantString("!activator");
+		AcceptEntityInput(ent, "SetParent", iEnt);
+		
+		if (sAttachment[0])
+		{
+			SetVariantString(sAttachment);
+			AcceptEntityInput(ent, "SetParentAttachment");
+		}
+		
+		SDKHook(ent, SDKHook_SetTransmit, Hook_InterativeGlowSetTransmit);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> true", client);
+#endif
+		
+		return true;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> false", client);
+#endif
+	
+	return false;
+}
+
+public Action:Hook_InterativeGlowSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[other]) != ent) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	BREATHING FUNCTIONS
+//	==========================================================
+
+ClientResetBreathing(client)
+{
+	g_bPlayerBreath[client] = false;
+	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
+}
+
+Float:ClientCalculateBreathingCooldown(client)
+{
+	new Float:flAverage = 0.0;
+	new iAverageNum = 0;
+	
+	// Sprinting only, for now.
+	flAverage += (SF2_PLAYER_BREATH_COOLDOWN_MAX * 6.7765 * Pow((float(g_iPlayerSprintPoints[client]) / 100.0), 1.65));
+	iAverageNum++;
+	
+	flAverage /= float(iAverageNum)
+	
+	if (flAverage < SF2_PLAYER_BREATH_COOLDOWN_MIN) flAverage = SF2_PLAYER_BREATH_COOLDOWN_MIN;
+	
+	return flAverage;
+}
+
+ClientStartBreathing(client)
+{
+	g_bPlayerBreath[client] = true;
+	g_hPlayerBreathTimer[client] = CreateTimer(ClientCalculateBreathingCooldown(client), Timer_ClientBreath, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStopBreathing(client)
+{
+	g_bPlayerBreath[client] = false;
+	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
+}
+
+bool:ClientCanBreath(client)
+{
+	return bool:(ClientCalculateBreathingCooldown(client) < SF2_PLAYER_BREATH_COOLDOWN_MAX);
+}
+
+public Action:Timer_ClientBreath(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerBreathTimer[client]) return;
+	
+	if (!g_bPlayerBreath[client]) return;
+	
+	if (ClientCanBreath(client))
+	{
+		EmitSoundToAll(g_strPlayerBreathSounds[GetRandomInt(0, sizeof(g_strPlayerBreathSounds) - 1)], client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+		
+		ClientStartBreathing(client);
+		return;
+	}
+	
+	ClientStopBreathing(client);
+}
+
+//	==========================================================
+//	SPRINTING FUNCTIONS
+//	==========================================================
+
+bool:IsClientSprinting(client)
+{
+	return g_bPlayerSprint[client];
+}
+
+ClientGetSprintPoints(client)
+{
+	return g_iPlayerSprintPoints[client];
+}
+
+ClientResetSprint(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSprint(%d)", client);
+#endif
+
+	g_bPlayerSprint[client] = false;
+	g_iPlayerSprintPoints[client] = 100;
+	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+	
+	if (IsValidClient(client))
+	{
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+		
+		ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSprint(%d)", client);
+#endif
+}
+
+ClientStartSprint(client)
+{
+	if (IsClientSprinting(client)) return;
+	
+	g_bPlayerSprint[client] = true;
+	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+	ClientSprintTimer(client);
+	TriggerTimer(g_hPlayerSprintTimer[client], true);
+	
+	SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+	SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+}
+
+static ClientSprintTimer(client, bool:bRecharge=false)
+{
+	new Float:flRate = 0.28;
+	if (bRecharge) flRate = 0.8;
+	
+	decl Float:flVelocity[3];
+	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
+	
+	if (bRecharge)
+	{
+		if (!(GetEntityFlags(client) & FL_ONGROUND)) flRate *= 0.75;
+		else if (GetVectorLength(flVelocity) == 0.0)
+		{
+			if (GetEntProp(client, Prop_Send, "m_bDucked")) flRate *= 0.66;
+			else flRate *= 0.75;
+		}
+	}
+	else
+	{
+		if (TF2_GetPlayerClass(client) == TFClass_Scout) flRate *= 1.15;
+	}
+	
+	if (bRecharge) g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientRechargeSprint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	else g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientSprinting, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStopSprint(client)
+{
+	if (!IsClientSprinting(client)) return;
+	
+	g_bPlayerSprint[client] = false;
+	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+	ClientSprintTimer(client, true);
+	
+	SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+	SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+}
+
+bool:IsClientReallySprinting(client)
+{
+	if (!IsClientSprinting(client)) return false;
+	if (!(GetEntityFlags(client) & FL_ONGROUND)) return false;
+	
+	decl Float:flVelocity[3];
+	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
+	if (GetVectorLength(flVelocity) < 30.0) return false;
+	
+	return true;
+}
+
+public Action:Timer_ClientSprinting(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerSprintTimer[client]) return;
+	
+	if (!IsClientSprinting(client)) return;
+	
+	if (g_iPlayerSprintPoints[client] <= 0)
+	{
+		ClientStopSprint(client);
+		g_iPlayerSprintPoints[client] = 0;
+		return;
+	}
+	
+	if (IsClientReallySprinting(client)) 
+	{
+		new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
+		if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
+		{
+			g_iPlayerSprintPoints[client]--;
+		}
+	}
+	
+	ClientSprintTimer(client);
+}
+
+public Hook_ClientSprintingPreThink(client)
+{
+	if (!IsClientReallySprinting(client))
+	{
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+		SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+		return;
+	}
+	
+	new iFOV = GetEntData(client, g_offsPlayerDefaultFOV);
+	
+	new iTargetFOV = g_iPlayerDesiredFOV[client] + 10;
+	
+	if (iFOV < iTargetFOV)
+	{
+		new iDiff = RoundFloat(FloatAbs(float(iFOV - iTargetFOV)));
+		if (iDiff >= 1)
+		{
+			ClientSetFOV(client, iFOV + 1);
+		}
+		else
+		{
+			ClientSetFOV(client, iTargetFOV);
+		}
+	}
+	else if (iFOV >= iTargetFOV)
+	{
+		ClientSetFOV(client, iTargetFOV);
+		//SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+	}
+}
+
+public Hook_ClientRechargeSprintPreThink(client)
+{
+	if (IsClientReallySprinting(client))
+	{
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+		SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+		return;
+	}
+	
+	new iFOV = GetEntData(client, g_offsPlayerDefaultFOV);
+	if (iFOV > g_iPlayerDesiredFOV[client])
+	{
+		new iDiff = RoundFloat(FloatAbs(float(iFOV - g_iPlayerDesiredFOV[client])));
+		if (iDiff >= 1)
+		{
+			ClientSetFOV(client, iFOV - 1);
+		}
+		else
+		{
+			ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
+		}
+	}
+	else if (iFOV <= g_iPlayerDesiredFOV[client])
+	{
+		ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
+	}
+}
+
+public Action:Timer_ClientRechargeSprint(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerSprintTimer[client]) return;
+	
+	if (IsClientSprinting(client)) 
+	{
+		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+		return;
+	}
+	
+	if (g_iPlayerSprintPoints[client] >= 100)
+	{
+		g_iPlayerSprintPoints[client] = 100;
+		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+		return;
+	}
+	
+	g_iPlayerSprintPoints[client]++;
+	ClientSprintTimer(client, true);
+}
+
+//	==========================================================
+//	PROXY / GHOST AND GLOW FUNCTIONS
+//	==========================================================
+
+ClientResetProxy(client, bool:bResetFull=true)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetProxy(%d)", client);
+#endif
+
+	new iOldMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+	new String:sOldProfileName[SF2_MAX_PROFILE_NAME_LENGTH];
+	if (iOldMaster >= 0)
+	{
+		NPCGetProfile(iOldMaster, sOldProfileName, sizeof(sOldProfileName));
+	}
+	
+	new bool:bOldProxy = g_bPlayerProxy[client];
+	if (bResetFull) 
+	{
+		g_bPlayerProxy[client] = false;
+		g_iPlayerProxyMaster[client] = -1;
+	}
+	
+	g_iPlayerProxyControl[client] = 0;
+	g_hPlayerProxyControlTimer[client] = INVALID_HANDLE;
+	g_flPlayerProxyControlRate[client] = 0.0;
+	g_flPlayerProxyVoiceTimer[client] = INVALID_HANDLE;
+	
+	if (IsClientInGame(client))
+	{
+		if (bOldProxy)
+		{
+			ClientStartProxyAvailableTimer(client);
+		
+			if (bResetFull)
+			{
+				SetVariantString("");
+				AcceptEntityInput(client, "SetCustomModel");
+			}
+			
+			if (sOldProfileName[0])
+			{
+				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_spawn", GetProfileNum(sOldProfileName, "sound_proxy_spawn_channel", SNDCHAN_AUTO));
+				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_hurt", GetProfileNum(sOldProfileName, "sound_proxy_hurt_channel", SNDCHAN_AUTO));
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetProxy(%d)", client);
+#endif
+}
+
+ClientStartProxyAvailableTimer(client)
+{
+	g_bPlayerProxyAvailable[client] = false;
+	g_hPlayerProxyAvailableTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerProxyWaitTime), Timer_ClientProxyAvailable, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStartProxyForce(client, iSlenderID, const Float:flPos[3])
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
+#endif
+
+	g_iPlayerProxyAskMaster[client] = iSlenderID;
+	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
+
+	g_iPlayerProxyAvailableCount[client] = 0;
+	g_bPlayerProxyAvailableInForce[client] = true;
+	g_hPlayerProxyAvailableTimer[client] = CreateTimer(1.0, Timer_ClientForceProxy, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerProxyAvailableTimer[client], true);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
+#endif
+}
+
+ClientStopProxyForce(client)
+{
+	g_iPlayerProxyAvailableCount[client] = 0;
+	g_bPlayerProxyAvailableInForce[client] = false;
+	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
+}
+
+public Action:Timer_ClientForceProxy(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerProxyAvailableTimer[client]) return Plugin_Stop;
+	
+	if (!IsRoundEnding())
+	{
+		new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[client]);
+		if (iBossIndex != -1)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+		
+			new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
+			new iNumProxies = 0;
+			
+			for (new iClient = 1; iClient <= MaxClients; iClient++)
+			{
+				if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+				if (!g_bPlayerProxy[iClient]) continue;
+				if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
+				
+				iNumProxies++;
+			}
+			
+			if (iNumProxies < iMaxProxies)
+			{
+				if (g_iPlayerProxyAvailableCount[client] > 0)
+				{
+					g_iPlayerProxyAvailableCount[client]--;
+					
+					SetHudTextParams(-1.0, 0.25, 
+						1.0,
+						255, 255, 255, 255,
+						_,
+						_,
+						0.25, 1.25);
+					
+					ShowSyncHudText(client, g_hHudSync, "%T", "SF2 Proxy Force Message", client, g_iPlayerProxyAvailableCount[client]);
+					
+					return Plugin_Continue;
+				}
+				else
+				{
+					ClientEnableProxy(client, iBossIndex);
+					TeleportEntity(client, g_iPlayerProxyAskPosition[client], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+				}
+			}
+			else
+			{
+				PrintToChat(client, "%T", "SF2 Too Many Proxies", client);
+			}
+		}
+	}
+	
+	ClientStopProxyForce(client);
+	return Plugin_Stop;
+}
+
+DisplayProxyAskMenu(client, iAskMaster, const Float:flPos[3])
+{
+	decl String:sBuffer[512];
+	new Handle:hMenu = CreateMenu(Menu_ProxyAsk);
+	SetMenuTitle(hMenu, "%T\n \n%T\n \n", "SF2 Proxy Ask Menu Title", client, "SF2 Proxy Ask Menu Description", client);
+	
+	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
+	AddMenuItem(hMenu, "1", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	
+	g_iPlayerProxyAskMaster[client] = iAskMaster;
+	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
+	DisplayMenu(hMenu, client, 15);
+}
+
+public Menu_ProxyAsk(Handle:menu, MenuAction:action, param1, param2)
+{
+	switch (action)
+	{
+		case MenuAction_End: CloseHandle(menu);
+		case MenuAction_Select:
+		{
+			if (!IsRoundEnding())
+			{
+				new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[param1]);
+				if (iBossIndex != -1)
+				{
+					decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+					NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+				
+					new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
+					new iNumProxies;
+				
+					for (new iClient = 1; iClient <= MaxClients; iClient++)
+					{
+						if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+						if (!g_bPlayerProxy[iClient]) continue;
+						if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
+						
+						iNumProxies++;
+					}
+					
+					if (iNumProxies < iMaxProxies)
+					{
+						if (param2 == 0)
+						{
+							ClientEnableProxy(param1, iBossIndex);
+							TeleportEntity(param1, g_iPlayerProxyAskPosition[param1], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+						}
+						else
+						{
+							ClientStartProxyAvailableTimer(param1);
+						}
+					}
+					else
+					{
+						PrintToChat(param1, "%T", "SF2 Too Many Proxies", param1);
+					}
+				}
+			}
+		}
+	}
+}
+
+public Action:Timer_ClientProxyAvailable(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerProxyAvailableTimer[client]) return;
+	
+	g_bPlayerProxyAvailable[client] = true;
+	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
+}
+
+ClientEnableProxy(client, iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1) return;
+	if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) return;
+	if (g_bPlayerProxy[client]) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	PvP_SetPlayerPvPState(client, false, false, false);
+	
+	ClientSetGhostModeState(client, false);
+	
+	ClientStopProxyForce(client);
+	
+	ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
+	if (!IsPlayerAlive(client)) TF2_RespawnPlayer(client);
+	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
+	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
+	
+	g_bPlayerProxy[client] = true;
+	g_iPlayerProxyMaster[client] = NPCGetUniqueID(iBossIndex);
+	g_iPlayerProxyControl[client] = 100;
+	g_flPlayerProxyControlRate[client] = GetProfileFloat(sProfile, "proxies_controldrainrate");
+	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	g_bPlayerProxyAvailable[client] = false;
+	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
+	
+	decl String:sAllowedClasses[512];
+	GetProfileString(sProfile, "proxies_classes", sAllowedClasses, sizeof(sAllowedClasses));
+	
+	decl String:sClassName[64];
+	TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
+	if (sAllowedClasses[0] && sClassName[0] && StrContains(sAllowedClasses, sClassName, false) == -1)
+	{
+		// Pick the first class that's allowed.
+		new String:sAllowedClassesList[32][32];
+		new iClassCount = ExplodeString(sAllowedClasses, " ", sAllowedClassesList, 32, 32);
+		if (iClassCount)
+		{
+			TF2_SetPlayerClass(client, TF2_GetClass(sAllowedClassesList[0]), _, false);
+			
+			new iMaxHealth = GetEntProp(client, Prop_Send, "m_iHealth");
+			TF2_RegeneratePlayer(client);
+			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
+			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
+		}
+	}
+	
+	UTIL_ScreenFade(client, 200, 1, FFADE_IN, 255, 255, 255, 100);
+	PrecacheSound("weapons/teleporter_send.wav");
+	EmitSoundToClient(client, "weapons/teleporter_send.wav", _, SNDCHAN_STATIC);
+	
+	ClientActivateUltravision(client);
+	
+	CreateTimer(0.33, Timer_ApplyCustomModel, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	
+	Call_StartForward(fOnClientSpawnedAsProxy);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+public Action:Timer_ClientProxyControl(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerProxyControlTimer[client]) return;
+	
+	g_iPlayerProxyControl[client]--;
+	if (g_iPlayerProxyControl[client] <= 0)
+	{
+		// ForcePlayerSuicide isn't really dependable, since the player doesn't suicide until several seconds after spawning has passed.
+		SDKHooks_TakeDamage(client, client, client, 9001.0, DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+		return;
+	}
+	
+	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, userid, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+bool:DoesClientHaveConstantGlow(client)
+{
+	return g_bPlayerConstantGlowEnabled[client];
+}
+
+ClientDisableConstantGlow(client)
+{
+	if (!DoesClientHaveConstantGlow(client)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientDisableConstantGlow(%d)", client);
+#endif
+	
+	g_bPlayerConstantGlowEnabled[client] = false;
+	
+	new iGlow = EntRefToEntIndex(g_iPlayerConstantGlowEntity[client]);
+	if (iGlow && iGlow != INVALID_ENT_REFERENCE) AcceptEntityInput(iGlow, "Kill");
+	
+	g_iPlayerConstantGlowEntity[client] = INVALID_ENT_REFERENCE;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientDisableConstantGlow(%d)", client);
+#endif
+}
+
+bool:ClientEnableConstantGlow(client, const String:sAttachment[]="")
+{
+	if (DoesClientHaveConstantGlow(client)) return true;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientEnableConstantGlow(%d)", client);
+#endif
+	
+	decl String:sModel[PLATFORM_MAX_PATH];
+	GetClientModel(client, sModel, sizeof(sModel));
+	
+	if (strlen(sModel) == 0) 
+	{
+		// For some reason the model couldn't be found, so no.
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false (no model specified)", client);
+#endif
+		
+		return false;
+	}
+	
+	new iGlow = CreateEntityByName("tf_taunt_prop");
+	if (iGlow != -1)
+	{
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> created");
+#endif
+	
+		g_bPlayerConstantGlowEnabled[client] = true;
+		g_iPlayerConstantGlowEntity[client] = EntIndexToEntRef(iGlow);
+		
+		new Float:flModelScale = GetEntPropFloat(client, Prop_Send, "m_flModelScale");
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) 
+		{
+			DebugMessage("tf_taunt_prop -> get model and model scale (%s, %f, player class: %d)", sModel, flModelScale, TF2_GetPlayerClass(client));
+		}
+#endif
+		
+		SetEntityModel(iGlow, sModel);
+		DispatchSpawn(iGlow);
+		ActivateEntity(iGlow);
+		SetEntityRenderMode(iGlow, RENDER_TRANSCOLOR);
+		SetEntityRenderColor(iGlow, 0, 0, 0, 0);
+		SetEntProp(iGlow, Prop_Send, "m_bGlowEnabled", 1);
+		SetEntPropFloat(iGlow, Prop_Send, "m_flModelScale", flModelScale);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set model and model scale");
+#endif
+		
+		// Set effect flags.
+		new iFlags = GetEntProp(iGlow, Prop_Send, "m_fEffects");
+		SetEntProp(iGlow, Prop_Send, "m_fEffects", iFlags | (1 << 0)); // EF_BONEMERGE
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set bonemerge flags");
+#endif
+		
+		SetVariantString("!activator");
+		AcceptEntityInput(iGlow, "SetParent", client);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent to client");
+#endif
+		
+		if (sAttachment[0])
+		{
+			SetVariantString(sAttachment);
+			AcceptEntityInput(iGlow, "SetParentAttachment");
+		}
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent attachment to %s", sAttachment);
+#endif
+		
+		SDKHook(iGlow, SDKHook_SetTransmit, Hook_ConstantGlowSetTransmit);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> true", client);
+#endif
+		
+		return true;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false", client);
+#endif
+	
+	return false;
+}
+
+ClientResetJumpScare(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetJumpScare(%d)", client);
+#endif
+
+	g_iPlayerJumpScareBoss[client] = -1;
+	g_flPlayerJumpScareLifeTime[client] = -1.0;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetJumpScare(%d)", client);
+#endif
+}
+
+ClientDoJumpScare(client, iBossIndex, Float:flLifeTime)
+{
+	g_iPlayerJumpScareBoss[client] = NPCGetUniqueID(iBossIndex);
+	g_flPlayerJumpScareLifeTime[client] = GetGameTime() + flLifeTime;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_jumpscare", sBuffer, sizeof(sBuffer), 1);
+	
+	if (strlen(sBuffer) > 0)
+	{
+		EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN);
+	}
+}
+
+ /**
+  *	Handles sprinting upon player input.
+  */
+ClientHandleSprint(client, bool:bSprint)
+{
+	if (!IsPlayerAlive(client) || 
+		g_bPlayerEliminated[client] || 
+		DidClientEscape(client) || 
+		g_bPlayerProxy[client] || 
+		IsClientInGhostMode(client)) return;
+	
+	if (bSprint)
+	{
+		if (g_iPlayerSprintPoints[client] > 0)
+		{
+			ClientStartSprint(client);
+		}
+		else
+		{
+			EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
+		}
+	}
+	else
+	{
+		if (IsClientSprinting(client))
+		{
+			ClientStopSprint(client);
+		}
+	}
+}
+
+ClientOnButtonPress(client, button)
+{
+	switch (button)
+	{
+		case IN_ATTACK2:
+		{
+			if (IsPlayerAlive(client))
+			{
+				if (!IsRoundInWarmup() &&
+					!IsRoundInIntro() &&
+					!IsRoundEnding() && 
+					!DidClientEscape(client))
+				{
+					if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
+					{
+						ClientHandleFlashlight(client);
+					}
+				}
+			}
+		}
+		case IN_ATTACK3:
+		{
+			ClientHandleSprint(client, true);
+			}
+		case IN_RELOAD:
+		{
+			if (IsPlayerAlive(client))
+			{
+				if (!g_bPlayerEliminated[client])
+				{
+					if (!IsRoundEnding() && 
+						!IsRoundInWarmup() &&
+						!IsRoundInIntro() &&
+						!DidClientEscape(client))
+					{
+						ClientBlink(client);
+					}
+				}
+			}
+		}
+		case IN_JUMP:
+		{
+			if (IsPlayerAlive(client) && !(GetEntityFlags(client) & FL_FROZEN))
+			{
+				if (!bool:GetEntProp(client, Prop_Send, "m_bDucked") && 
+					(GetEntityFlags(client) & FL_ONGROUND) &&
+					GetEntProp(client, Prop_Send, "m_nWaterLevel") < 2)
+				{
+					ClientOnJump(client);
+				}
+			}
+		}
+	}
+}
+
+ClientOnButtonRelease(client, button)
+{
+	switch (button)
+	{
+		case IN_ATTACK3:
+		{
+			ClientHandleSprint(client, false);
+		}
+	}
+}
+
+ClientOnJump(client)
+{
+	if (!g_bPlayerEliminated[client])
+	{
+		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
+		{
+			new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
+			if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
+			{
+				g_iPlayerSprintPoints[client] -= 7;
+				if (g_iPlayerSprintPoints[client] < 0) g_iPlayerSprintPoints[client] = 0;
+			}
+			
+			if (!IsClientSprinting(client))
+			{
+				if (g_hPlayerSprintTimer[client] == INVALID_HANDLE)
+				{
+					// If the player hasn't sprinted recently, force us to regenerate the stamina.
+					ClientSprintTimer(client, true);
+				}
+			}
+		}
+	}
+}
+
+//	==========================================================
+//	DEATH CAM FUNCTIONS
+//	==========================================================
+
+bool:IsClientInDeathCam(client)
+{
+	return g_bPlayerDeathCam[client];
+}
+
+public Action:Hook_DeathCamSetTransmit(slender, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (EntRefToEntIndex(g_iPlayerDeathCamEnt2[other]) != slender) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+ClientResetDeathCam(client)
+{
+	if (!IsClientInDeathCam(client)) return; // no really need to reset if it wasn't set.
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetDeathCam(%d)", client);
+#endif
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	
+	g_iPlayerDeathCamBoss[client] = -1;
+	g_bPlayerDeathCam[client] = false;
+	g_bPlayerDeathCamShowOverlay[client] = false;
+	g_hPlayerDeathCamTimer[client] = INVALID_HANDLE;
+	
+	new ent = EntRefToEntIndex(g_iPlayerDeathCamEnt[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "Disable");
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	ent = EntRefToEntIndex(g_iPlayerDeathCamEnt2[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	g_iPlayerDeathCamEnt[client] = INVALID_ENT_REFERENCE;
+	g_iPlayerDeathCamEnt2[client] = INVALID_ENT_REFERENCE;
+	
+	if (IsClientInGame(client))
+	{
+		SetClientViewEntity(client, client);
+	}
+	
+	Call_StartForward(fOnClientEndDeathCam);
+	Call_PushCell(client);
+	Call_PushCell(iDeathCamBoss);
+	Call_Finish();
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetDeathCam(%d)", client);
+#endif
+}
+
+ClientStartDeathCam(client, iBossIndex, const Float:vecLookPos[3])
+{
+	if (IsClientInDeathCam(client)) return;
+	if (!NPCIsValid(iBossIndex)) return;
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (GetProfileNum(sProfile, "death_cam_play_scare_sound"))
+	{
+		GetRandomStringFromProfile(sProfile, "sound_scare_player", buffer, sizeof(buffer));
+		if (buffer[0]) EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+	}
+	
+	GetRandomStringFromProfile(sProfile, "sound_player_deathcam", buffer, sizeof(buffer));
+	if (strlen(buffer) > 0) 
+	{
+		EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+	}
+	else
+	{
+		// Legacy support for "sound_player_death"
+		GetRandomStringFromProfile(sProfile, "sound_player_death", buffer, sizeof(buffer));
+		if (strlen(buffer) > 0)
+		{
+			EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		}
+	}
+	
+	GetRandomStringFromProfile(sProfile, "sound_player_deathcam_all", buffer, sizeof(buffer));
+	if (strlen(buffer) > 0) 
+	{
+		EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+	}
+	else
+	{
+		// Legacy support for "sound_player_death_all"
+		GetRandomStringFromProfile(sProfile, "sound_player_death_all", buffer, sizeof(buffer));
+		if (strlen(buffer) > 0) 
+		{
+			EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		}
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnClientCaughtByBoss);
+	Call_PushCell(client);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+	
+	if (!NPCHasDeathCamEnabled(iBossIndex))
+	{
+		SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol changes our lifestate.
+		
+		// TODO: Add more attributes!
+		if (NPCHasAttribute(iBossIndex, "ignite player on death"))
+		{
+			new Float:flValue = NPCGetAttributeValue(iBossIndex, "ignite player on death");
+			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
+		}
+		
+		SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+		return;
+	}
+	
+	g_iPlayerDeathCamBoss[client] = NPCGetUniqueID(iBossIndex);
+	g_bPlayerDeathCam[client] = true;
+	g_bPlayerDeathCamShowOverlay[client] = false;
+	
+	decl Float:eyePos[3], Float:eyeAng[3], Float:vecAng[3];
+	GetClientEyePosition(client, eyePos);
+	GetClientEyeAngles(client, eyeAng);
+	SubtractVectors(eyePos, vecLookPos, vecAng);
+	GetVectorAngles(vecAng, vecAng);
+	vecAng[0] = 0.0;
+	vecAng[2] = 0.0;
+	
+	// Create fake model.
+	new slender = SpawnSlenderModel(iBossIndex, vecLookPos);
+	TeleportEntity(slender, vecLookPos, vecAng, NULL_VECTOR);
+	g_iPlayerDeathCamEnt2[client] = EntIndexToEntRef(slender);
+	SDKHook(slender, SDKHook_SetTransmit, Hook_DeathCamSetTransmit);
+	
+	// Create camera look point.
+	decl String:sName[64];
+	Format(sName, sizeof(sName), "sf2_boss_%d", EntIndexToEntRef(slender));
+	
+	decl Float:flOffsetPos[3];
+	new target = CreateEntityByName("info_target");
+	GetProfileVector(sProfile, "death_cam_pos", flOffsetPos);
+	AddVectors(vecLookPos, flOffsetPos, flOffsetPos);
+	TeleportEntity(target, flOffsetPos, NULL_VECTOR, NULL_VECTOR);
+	DispatchKeyValue(target, "targetname", sName);
+	SetVariantString("!activator");
+	AcceptEntityInput(target, "SetParent", slender);
+	
+	// Create the camera itself.
+	new camera = CreateEntityByName("point_viewcontrol");
+	TeleportEntity(camera, eyePos, eyeAng, NULL_VECTOR);
+	DispatchKeyValue(camera, "spawnflags", "12");
+	DispatchKeyValue(camera, "target", sName);
+	DispatchSpawn(camera);
+	AcceptEntityInput(camera, "Enable", client);
+	g_iPlayerDeathCamEnt[client] = EntIndexToEntRef(camera);
+	
+	if (GetProfileNum(sProfile, "death_cam_overlay") && GetProfileFloat(sProfile, "death_cam_time_overlay_start") >= 0.0)
+	{
+		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_overlay_start"), Timer_ClientResetDeathCam1, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	}
+	else
+	{
+		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	}
+	
+	TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+	
+	Call_StartForward(fOnClientStartDeathCam);
+	Call_PushCell(client);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+}
+
+public Action:Timer_ClientResetDeathCam1(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerDeathCamTimer[client]) return;
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
+	
+	g_bPlayerDeathCamShowOverlay[client] = true;
+	g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, userid, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_ClientResetDeathCamEnd(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerDeathCamTimer[client]) return;
+	
+	SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol entity changes our damage state.
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	if (iDeathCamBoss != -1)
+	{
+		if (NPCHasAttribute(iDeathCamBoss, "ignite player on death"))
+		{
+			new Float:flValue = NPCGetAttributeValue(iDeathCamBoss, "ignite player on death");
+			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
+		}
+	}
+	
+	SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+	ClientResetDeathCam(client);
+}
+
+//	==========================================================
+//	GHOST MODE FUNCTIONS
+//	==========================================================
+
+static bool:g_bPlayerGhostMode[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerGhostModeTarget[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static Handle:g_hPlayerGhostModeConnectionCheckTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static Float:g_flPlayerGhostModeConnectionTimeOutTime[MAXPLAYERS + 1] = { -1.0, ... };
+static Float:g_flPlayerGhostModeConnectionBootTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+/**
+ *	Enables/Disables ghost mode on the player.
+ */
+ClientSetGhostModeState(client, bool:bState)
+{
+	if (bState == g_bPlayerGhostMode[client]) return;
+	
+	if (bState && !IsClientInGame(client)) return;
+	
+	g_bPlayerGhostMode[client] = bState;
+	g_iPlayerGhostModeTarget[client] = INVALID_ENT_REFERENCE;
+	
+	if (bState)
+	{
+		ClientHandleGhostMode(client, true);
+		
+		if (GetConVarBool(g_cvGhostModeConnectionCheck))
+		{
+			g_hPlayerGhostModeConnectionCheckTimer[client] = CreateTimer(0.0, Timer_GhostModeConnectionCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
+			g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
+		}
+		
+		PvP_OnClientGhostModeEnable(client);
+	}
+	else
+	{
+		g_hPlayerGhostModeConnectionCheckTimer[client] = INVALID_HANDLE;
+		g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
+		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
+	
+		if (IsClientInGame(client))
+		{
+			TF2_RemoveCondition(client, TFCond_HalloweenGhostMode);
+			SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_PLAYER);
+		}
+	}
+}
+
+public Action:Timer_GhostModeConnectionCheck(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerGhostModeConnectionCheckTimer[client]) return Plugin_Stop;
+	
+	if (!IsFakeClient(client) && IsClientTimingOut(client))
+	{
+		new Float:bootTime = g_flPlayerGhostModeConnectionBootTime[client];
+		if (bootTime < 0.0)
+		{
+			bootTime = GetGameTime() + GetConVarFloat(g_cvGhostModeConnectionTolerance);
+			g_flPlayerGhostModeConnectionBootTime[client] = bootTime;
+			g_flPlayerGhostModeConnectionTimeOutTime[client] = GetGameTime();
+		}
+		
+		if (GetGameTime() >= bootTime)
+		{
+			ClientSetGhostModeState(client, false);
+			TF2_RespawnPlayer(client);
+			
+			decl String:authString[128];
+			GetClientAuthString(client, authString, sizeof(authString));
+			
+			LogSF2Message("Removed %N (%s) from ghost mode due to timing out for %f seconds", client, authString, GetConVarFloat(g_cvGhostModeConnectionTolerance));
+			
+			new Float:timeOutTime = g_flPlayerGhostModeConnectionTimeOutTime[client];
+			CPrintToChat(client, "%T", "SF2 Ghost Mode Bad Connection", client, RoundFloat(bootTime - timeOutTime));
+			
+			return Plugin_Stop;
+		}
+	}
+	else
+	{
+		// Player regained connection; reset.
+		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
+	}
+	
+	return Plugin_Continue;
+}
+
+/**
+ *	Makes sure that the player is a ghost when ghost mode is activated.
+ */
+ClientHandleGhostMode(client, bool:bForceSpawn=false)
+{
+	if (!IsClientInGhostMode(client)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
+#endif
+	
+	if (!TF2_IsPlayerInCondition(client, TFCond_HalloweenGhostMode) || bForceSpawn)
+	{
+		TF2_AddCondition(client, TFCond_HalloweenGhostMode, -1.0);
+		SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_DEBRIS);
+		
+		// Set first observer target.
+		ClientGhostModeNextTarget(client);
+		ClientActivateUltravision(client);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
+#endif
+}
+
+ClientGhostModeNextTarget(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientGhostModeNextTarget(%d)", client);
+#endif
+	
+	new iLastTarget = EntRefToEntIndex(g_iPlayerGhostModeTarget[client]);
+	new iNextTarget = -1;
+	new iFirstTarget = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (IsClientInGame(i) && (!g_bPlayerEliminated[i] || g_bPlayerProxy[i]) && !IsClientInGhostMode(i) && !DidClientEscape(i) && IsPlayerAlive(i))
+		{
+			if (iFirstTarget == -1) iFirstTarget = i;
+			if (i > iLastTarget) 
+			{
+				iNextTarget = i;
+				break;
+			}
+		}
+	}
+	
+	new iTarget = -1;
+	if (IsValidClient(iNextTarget)) iTarget = iNextTarget;
+	else iTarget = iFirstTarget;
+	
+	if (IsValidClient(iTarget))
+	{
+		g_iPlayerGhostModeTarget[client] = EntIndexToEntRef(iTarget);
+		
+		decl Float:flPos[3], Float:flAng[3], Float:flVelocity[3];
+		GetClientAbsOrigin(iTarget, flPos);
+		GetClientEyeAngles(iTarget, flAng);
+		GetEntPropVector(iTarget, Prop_Data, "m_vecAbsVelocity", flVelocity);
+		TeleportEntity(client, flPos, flAng, flVelocity);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientGhostModeNextTarget(%d)", client);
+#endif
+}
+
+bool:IsClientInGhostMode(client)
+{
+	return g_bPlayerGhostMode[client];
+}
+
+//	==========================================================
+//	SCARE FUNCTIONS
+//	==========================================================
+
+ClientPerformScare(client, iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		LogError("Could not perform scare on client %d: boss does not exist!", client);
+		return;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	g_flPlayerScareLastTime[client][iBossIndex] = GetGameTime();
+	g_flPlayerScareNextTime[client][iBossIndex] = GetGameTime() + NPCGetScareCooldown(iBossIndex);
+	
+	// See how much Sanity should be drained from a scare.
+	new Float:flStaticAmount = GetProfileFloat(sProfile, "scare_static_amount", 0.0);
+	g_flPlayerStaticAmount[client] += flStaticAmount;
+	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
+	
+	decl String:sScareSound[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_scare_player", sScareSound, sizeof(sScareSound));
+	
+	if (sScareSound[0])
+	{
+		EmitSoundToClient(client, sScareSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		
+		if (NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)
+		{
+			new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
+			new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
+			
+			g_flPlayerSightSoundNextTime[client][iBossIndex] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
+		}
+		
+		if (g_flPlayerStress[client] > 0.4)
+		{
+			ClientAddStress(client, 0.4);
+		}
+		else
+		{
+			ClientAddStress(client, 0.66);
+		}
+	}
+	else
+	{
+		if (g_flPlayerStress[client] > 0.4)
+		{
+			ClientAddStress(client, 0.3);
+		}
+		else
+		{
+			ClientAddStress(client, 0.45);
+		}
+	}
+}
+
+ClientPerformSightSound(client, iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		LogError("Could not perform sight sound on client %d: boss does not exist!", client);
+		return;
+	}
+	
+	if (!(NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)) return;
+	
+	new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]);
+	if (iMaster == -1) iMaster = iBossIndex;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sSightSound[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_sight", sSightSound, sizeof(sSightSound));
+	
+	if (sSightSound[0])
+	{
+		EmitSoundToClient(client, sSightSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		
+		new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
+		new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
+		
+		g_flPlayerSightSoundNextTime[client][iMaster] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
+		
+		decl Float:flBossPos[3], Float:flMyPos[3];
+		new iBoss = NPCGetEntIndex(iBossIndex);
+		GetClientAbsOrigin(client, flMyPos);
+		GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flBossPos);
+		new Float:flDistUnComfortZone = 400.0;
+		new Float:flBossDist = GetVectorDistance(flMyPos, flBossPos);
+		
+		new Float:flStressScalar = 1.0 + (flDistUnComfortZone / flBossDist);
+		
+		ClientAddStress(client, 0.1 * flStressScalar);
+	}
+	else
+	{
+		LogError("Warning! %s supports sight sounds, but was given a blank sound!", sProfile);
+	}
+}
+
+ClientResetScare(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetScare(%d)", client);
+#endif
+
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_flPlayerScareNextTime[client][i] = -1.0;
+		g_flPlayerScareLastTime[client][i] = -1.0;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetScare(%d)", client);
+#endif
+}
+
+//	==========================================================
+//	ANTI-CAMPING FUNCTIONS
+//	==========================================================
+
+stock ClientResetCampingStats(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetCampingStats(%d)", client);
+#endif
+
+	g_iPlayerCampingStrikes[client] = 0;
+	g_hPlayerCampingTimer[client] = INVALID_HANDLE;
+	g_bPlayerCampingFirstTime[client] = true;
+	g_flPlayerCampingLastPosition[client][0] = 0.0;
+	g_flPlayerCampingLastPosition[client][1] = 0.0;
+	g_flPlayerCampingLastPosition[client][2] = 0.0;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetCampingStats(%d)", client);
+#endif
+}
+
+ClientStartCampingTimer(client)
+{
+	g_hPlayerCampingTimer[client] = CreateTimer(5.0, Timer_ClientCheckCamp, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_ClientCheckCamp(Handle:timer, any:userid)
+{
+	if (IsRoundInWarmup()) return Plugin_Stop;
+
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerCampingTimer[client]) return Plugin_Stop;
+	
+	if (IsRoundEnding() || !IsPlayerAlive(client) || g_bPlayerEliminated[client] || DidClientEscape(client)) return Plugin_Stop;
+	
+	if (!g_bPlayerCampingFirstTime[client])
+	{
+		decl Float:flPos[3], Float:flMaxs[3], Float:flMins[3];
+		GetClientAbsOrigin(client, flPos);
+		GetEntPropVector(client, Prop_Send, "m_vecMins", flMins);
+		GetEntPropVector(client, Prop_Send, "m_vecMaxs", flMaxs);
+		
+		// Only do something if the player is NOT stuck.
+		new Float:flDistFromLastPosition = GetVectorDistance(g_flPlayerCampingLastPosition[client], flPos);
+		new Float:flDistFromClosestBoss = 9999999.0;
+		new iClosestBoss = -1;
+		
+		for (new i = 0; i < MAX_BOSSES; i++)
+		{
+			if (NPCGetUniqueID(i) == -1) continue;
+			
+			new iSlender = NPCGetEntIndex(i);
+			if (!iSlender || iSlender == INVALID_ENT_REFERENCE) continue;
+			
+			decl Float:flSlenderPos[3];
+			SlenderGetAbsOrigin(i, flSlenderPos);
+			
+			new Float:flDist = GetVectorDistance(flSlenderPos, flPos);
+			if (flDist < flDistFromClosestBoss)
+			{
+				iClosestBoss = i;
+				flDistFromClosestBoss = flDist;
+			}
+		}
+		
+		if (GetConVarBool(g_cvCampingEnabled) && 
+			!g_bRoundGrace && 
+			!IsSpaceOccupiedIgnorePlayers(flPos, flMins, flMaxs, client) && 
+			g_flPlayerStaticAmount[client] <= GetConVarFloat(g_cvCampingNoStrikeSanity) && 
+			(iClosestBoss == -1 || flDistFromClosestBoss >= GetConVarFloat(g_cvCampingNoStrikeBossDistance)) &&
+			flDistFromLastPosition <= GetConVarFloat(g_cvCampingMinDistance))
+		{
+			g_iPlayerCampingStrikes[client]++;
+			if (g_iPlayerCampingStrikes[client] < GetConVarInt(g_cvCampingMaxStrikes))
+			{
+				if (g_iPlayerCampingStrikes[client] >= GetConVarInt(g_cvCampingStrikesWarn))
+				{
+					CPrintToChat(client, "{red}%T", "SF2 Camping System Warning", client, (GetConVarInt(g_cvCampingMaxStrikes) - g_iPlayerCampingStrikes[client]) * 5);
+				}
+			}
+			else
+			{
+				g_iPlayerCampingStrikes[client] = 0;
+				ClientStartDeathCam(client, 0, flPos);
+			}
+		}
+		else
+		{
+			// Forgiveness.
+			if (g_iPlayerCampingStrikes[client] > 0) g_iPlayerCampingStrikes[client]--;
+		}
+		
+		g_flPlayerCampingLastPosition[client][0] = flPos[0];
+		g_flPlayerCampingLastPosition[client][1] = flPos[1];
+		g_flPlayerCampingLastPosition[client][2] = flPos[2];
+	}
+	else
+	{
+		g_bPlayerCampingFirstTime[client] = false;
+	}
+	
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	BLINK FUNCTIONS
+//	==========================================================
+
+bool:IsClientBlinking(client)
+{
+	return g_bPlayerBlink[client];
+}
+
+Float:ClientGetBlinkMeter(client)
+{
+	return g_flPlayerBlinkMeter[client];
+}
+
+ClientGetBlinkCount(client)
+{
+	return g_iPlayerBlinkCount[client];
+}
+
+/**
+ *	Resets all data on blinking.
+ */
+ClientResetBlink(client)
+{
+	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
+	g_bPlayerBlink[client] = false;
+	g_flPlayerBlinkMeter[client] = 1.0;
+	g_iPlayerBlinkCount[client] = 0;
+}
+
+/**
+ *	Sets the player into a blinking state and blinds the player
+ */
+ClientBlink(client)
+{
+	if (IsRoundInWarmup() || DidClientEscape(client)) return;
+	
+	if (IsClientBlinking(client)) return;
+	
+	g_bPlayerBlink[client] = true;
+	g_iPlayerBlinkCount[client]++;
+	g_flPlayerBlinkMeter[client] = 0.0;
+	g_hPlayerBlinkTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerBlinkHoldTime), Timer_BlinkTimer2, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	
+	UTIL_ScreenFade(client, 100, RoundToFloor(GetConVarFloat(g_cvPlayerBlinkHoldTime) * 1000.0), FFADE_IN, 0, 0, 0, 255);
+	
+	Call_StartForward(fOnClientBlink);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+/**
+ *	Unsets the player from the blinking state.
+ */
+ClientUnblink(client)
+{
+	if (!IsClientBlinking(client)) return;
+	
+	g_bPlayerBlink[client] = false;
+	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
+	g_flPlayerBlinkMeter[client] = 1.0;
+}
+
+ClientStartDrainingBlinkMeter(client)
+{
+	g_hPlayerBlinkTimer[client] = CreateTimer(ClientGetBlinkRate(client), Timer_BlinkTimer, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_BlinkTimer(Handle:timer, any:userid)
+{
+	if (IsRoundInWarmup()) return Plugin_Stop;
+
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerBlinkTimer[client]) return Plugin_Stop;
+	
+	if (IsPlayerAlive(client) && !IsClientInDeathCam(client) && !g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !IsRoundEnding())
+	{
+		new iOverride = GetConVarInt(g_cvPlayerInfiniteBlinkOverride);
+		if ((!g_bRoundInfiniteBlink && iOverride != 1) || iOverride == 0)
+		{
+			g_flPlayerBlinkMeter[client] -= 0.05;
+		}
+		
+		if (g_flPlayerBlinkMeter[client] <= 0.0)
+		{
+			ClientBlink(client);
+			return Plugin_Stop;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_BlinkTimer2(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerBlinkTimer[client]) return;
+	
+	ClientUnblink(client);
+	ClientStartDrainingBlinkMeter(client);
+}
+
+Float:ClientGetBlinkRate(client)
+{
+	new Float:flValue = GetConVarFloat(g_cvPlayerBlinkRate);
+	if (GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 3) 
+	{
+		// Being underwater makes you blink faster, obviously.
+		flValue *= 0.75;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		if (g_bPlayerSeesSlender[client][i]) 
+		{
+			flValue *= GetProfileFloat(sProfile, "blink_look_rate_multiply", 1.0);
+		}
+		
+		else if (g_iPlayerStaticMode[client][i] == Static_Increase)
+		{
+			flValue *= GetProfileFloat(sProfile, "blink_static_rate_multiply", 1.0);
+		}
+	}
+	
+	if (TF2_GetPlayerClass(client) == TFClass_Sniper) flValue *= 1.4;
+	
+	if (IsClientUsingFlashlight(client))
+	{
+		decl Float:startPos[3], Float:endPos[3], Float:flDirection[3];
+		new Float:flLength = SF2_FLASHLIGHT_LENGTH;
+		GetClientEyePosition(client, startPos);
+		GetClientEyePosition(client, endPos);
+		GetClientEyeAngles(client, flDirection);
+		GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
+		NormalizeVector(flDirection, flDirection);
+		ScaleVector(flDirection, flLength);
+		AddVectors(endPos, flDirection, endPos);
+		new Handle:hTrace = TR_TraceRayFilterEx(startPos, endPos, MASK_VISIBLE, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
+		TR_GetEndPosition(endPos, hTrace);
+		new bool:bHit = TR_DidHit(hTrace);
+		CloseHandle(hTrace);
+		
+		if (bHit)
+		{
+			new Float:flPercent = (GetVectorDistance(startPos, endPos) / flLength);
+			flPercent *= 3.5;
+			if (flPercent > 1.0) flPercent = 1.0;
+			flValue *= flPercent;
+		}
+	}
+	
+	return flValue;
+}
+
+//	==========================================================
+//	SCREEN OVERLAY FUNCTIONS
+//	==========================================================
+
+ClientAddStress(client, Float:flStressAmount)
+{
+	g_flPlayerStress[client] += flStressAmount;
+	if (g_flPlayerStress[client] < 0.0) g_flPlayerStress[client] = 0.0;
+	if (g_flPlayerStress[client] > 1.0) g_flPlayerStress[client] = 1.0;
+	
+	//PrintCenterText(client, "g_flPlayerStress[%d] = %f", client, g_flPlayerStress[client]);
+	
+	SlenderOnClientStressUpdate(client);
+}
+
+stock ClientResetOverlay(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetOverlay(%d)", client);
+#endif
+	
+	g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
+	
+	if (IsClientInGame(client))
+	{
+		ClientCommand(client, "r_screenoverlay \"\"");
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetOverlay(%d)", client);
+#endif
+}
+
+public Action:Timer_PlayerOverlayCheck(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerOverlayCheck[client]) return Plugin_Stop;
+	
+	if (IsRoundInWarmup()) return Plugin_Continue;
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	new iJumpScareBoss = NPCGetFromUniqueID(g_iPlayerJumpScareBoss[client]);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	decl String:sMaterial[PLATFORM_MAX_PATH];
+	
+	if (IsClientInDeathCam(client) && iDeathCamBoss != -1 && g_bPlayerDeathCamShowOverlay[client])
+	{
+		NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
+		GetRandomStringFromProfile(sProfile, "overlay_player_death", sMaterial, sizeof(sMaterial), 1);
+	}
+	else if (iJumpScareBoss != -1 && GetGameTime() <= g_flPlayerJumpScareLifeTime[client])
+	{
+		NPCGetProfile(iJumpScareBoss, sProfile, sizeof(sProfile));
+		GetRandomStringFromProfile(sProfile, "overlay_jumpscare", sMaterial, sizeof(sMaterial), 1);
+	}
+	else if (IsClientInGhostMode(client))
+	{
+		strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_GHOST);
+	}
+	else if (IsRoundInWarmup() || g_bPlayerEliminated[client] || DidClientEscape(client) && !IsClientInGhostMode(client))
+	{
+		return Plugin_Continue;
+	}
+	else
+	{
+		if (!g_iPlayerPreferences[client][PlayerPreference_FilmGrain])
+			strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_DEFAULT_NO_FILMGRAIN);
+		else
+			strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_DEFAULT);
+	}
+	
+	ClientCommand(client, "r_screenoverlay %s", sMaterial);
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	MUSIC SYSTEM FUNCTIONS
+//	==========================================================
+
+stock ClientUpdateMusicSystem(client, bool:bInitialize=false)
+{
+	new iOldPageMusicMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
+	new iOldMusicFlags = g_iPlayerMusicFlags[client];
+	new iChasingBoss = -1;
+	new iChasingSeeBoss = -1;
+	new iAlertBoss = -1;
+	new i20DollarsBoss = -1;
+	
+	if (IsRoundEnding() || !IsClientInGame(client) || IsFakeClient(client) || DidClientEscape(client) || (g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !g_bPlayerProxy[client])) 
+	{
+		g_iPlayerMusicFlags[client] = 0;
+		g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+	}
+	else
+	{
+		new bool:bPlayMusicOnEscape = true;
+		decl String:sName[64];
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+		{
+			GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+			if (StrEqual(sName, "sf2_escape_custommusic", false))
+			{
+				bPlayMusicOnEscape = false;
+				break;
+			}
+		}
+		
+		// Page music first.
+		new iPageRange = 0;
+		
+		if (GetArraySize(g_hPageMusicRanges) > 0) // Map has its own defined page music?
+		{
+			for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
+			{
+				ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
+				if (!ent || ent == INVALID_ENT_REFERENCE) continue;
+				
+				new iMin = GetArrayCell(g_hPageMusicRanges, i, 1);
+				new iMax = GetArrayCell(g_hPageMusicRanges, i, 2);
+				
+				if (g_iPageCount >= iMin && g_iPageCount <= iMax)
+				{
+					g_iPlayerPageMusicMaster[client] = GetArrayCell(g_hPageMusicRanges, i);
+					break;
+				}
+			}
+		}
+		else // Nope. Use old system instead.
+		{
+			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+		
+			new Float:flPercent = g_iPageMax > 0 ? (float(g_iPageCount) / float(g_iPageMax)) : 0.0;
+			if (flPercent > 0.0 && flPercent <= 0.25) iPageRange = 1;
+			else if (flPercent > 0.25 && flPercent <= 0.5) iPageRange = 2;
+			else if (flPercent > 0.5 && flPercent <= 0.75) iPageRange = 3;
+			else if (flPercent > 0.75) iPageRange = 4;
+			
+			if (iPageRange == 1) ClientAddMusicFlag(client, MUSICF_PAGES1PERCENT);
+			else if (iPageRange == 2) ClientAddMusicFlag(client, MUSICF_PAGES25PERCENT);
+			else if (iPageRange == 3) ClientAddMusicFlag(client, MUSICF_PAGES50PERCENT);
+			else if (iPageRange == 4) ClientAddMusicFlag(client, MUSICF_PAGES75PERCENT);
+		}
+		
+		if (iPageRange != 1) ClientRemoveMusicFlag(client, MUSICF_PAGES1PERCENT);
+		if (iPageRange != 2) ClientRemoveMusicFlag(client, MUSICF_PAGES25PERCENT);
+		if (iPageRange != 3) ClientRemoveMusicFlag(client, MUSICF_PAGES50PERCENT);
+		if (iPageRange != 4) ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
+		
+		if (IsRoundInEscapeObjective() && !bPlayMusicOnEscape) 
+		{
+			ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
+			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+		}
+		
+		new iOldChasingBoss = g_iPlayerChaseMusicMaster[client];
+		new iOldChasingSeeBoss = g_iPlayerChaseMusicSeeMaster[client];
+		new iOldAlertBoss = g_iPlayerAlertMusicMaster[client];
+		new iOld20DollarsBoss = g_iPlayer20DollarsMusicMaster[client];
+		
+		new Float:flAnger = -1.0;
+		new Float:flSeeAnger = -1.0;
+		new Float:flAlertAnger = -1.0;
+		new Float:fl20DollarsAnger = -1.0;
+		
+		decl Float:flBuffer[3], Float:flBuffer2[3], Float:flBuffer3[3];
+		
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		
+		for (new i = 0; i < MAX_BOSSES; i++)
+		{
+			if (NPCGetUniqueID(i) == -1) continue;
+			
+			if (NPCGetEntIndex(i) == INVALID_ENT_REFERENCE) continue;
+			
+			NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+			new iBossType = NPCGetType(i);
+			
+			switch (iBossType)
+			{
+				case SF2BossType_Chaser:
+				{
+					GetClientAbsOrigin(client, flBuffer);
+					SlenderGetAbsOrigin(i, flBuffer3);
+					
+					new iTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
+					if (iTarget != -1)
+					{
+						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flBuffer2);
+						
+						if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK || g_iSlenderState[i] == STATE_STUN) &&
+							!(NPCGetFlags(i) & SFF_MARKEDASFAKE) && 
+							(iTarget == client || GetVectorDistance(flBuffer, flBuffer2) <= 850.0 || GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0))
+						{
+							decl String:sPath[PLATFORM_MAX_PATH];
+							GetRandomStringFromProfile(sProfile, "sound_chase_music", sPath, sizeof(sPath), 1);
+							if (sPath[0])
+							{
+								if (NPCGetAnger(i) > flAnger)
+								{
+									flAnger = NPCGetAnger(i);
+									iChasingBoss = i;
+								}
+							}
+							
+							if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK) &&
+								PlayerCanSeeSlender(client, i, false))
+							{
+								if (iOldChasingSeeBoss == -1 || !PlayerCanSeeSlender(client, iOldChasingSeeBoss, false) || (NPCGetAnger(i) > flSeeAnger))
+								{
+									GetRandomStringFromProfile(sProfile, "sound_chase_visible", sPath, sizeof(sPath), 1);
+									
+									if (sPath[0])
+									{
+										flSeeAnger = NPCGetAnger(i);
+										iChasingSeeBoss = i;
+									}
+								}
+								
+								if (g_b20Dollars)
+								{
+									if (iOld20DollarsBoss == -1 || !PlayerCanSeeSlender(client, iOld20DollarsBoss, false) || (NPCGetAnger(i) > fl20DollarsAnger))
+									{
+										GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sPath, sizeof(sPath), 1);
+										
+										if (sPath[0])
+										{
+											fl20DollarsAnger = NPCGetAnger(i);
+											i20DollarsBoss = i;
+										}
+									}
+								}
+							}
+						}
+					}
+					
+					if (g_iSlenderState[i] == STATE_ALERT)
+					{
+						decl String:sPath[PLATFORM_MAX_PATH];
+						GetRandomStringFromProfile(sProfile, "sound_alert_music", sPath, sizeof(sPath), 1);
+						if (!sPath[0]) continue;
+					
+						if (!(NPCGetFlags(i) & SFF_MARKEDASFAKE))
+						{
+							if (GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0)
+							{
+								if (NPCGetAnger(i) > flAlertAnger)
+								{
+									flAlertAnger = NPCGetAnger(i);
+									iAlertBoss = i;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		if (iChasingBoss != iOldChasingBoss)
+		{
+			if (iChasingBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_CHASE);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_CHASE);
+			}
+		}
+		
+		if (iChasingSeeBoss != iOldChasingSeeBoss)
+		{
+			if (iChasingSeeBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_CHASEVISIBLE);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_CHASEVISIBLE);
+			}
+		}
+		
+		if (iAlertBoss != iOldAlertBoss)
+		{
+			if (iAlertBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_ALERT);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_ALERT);
+			}
+		}
+		
+		if (i20DollarsBoss != iOld20DollarsBoss)
+		{
+			if (i20DollarsBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_20DOLLARS);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_20DOLLARS);
+			}
+		}
+	}
+	
+	if (IsValidClient(client))
+	{
+		new bool:bWasChase = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASE);
+		new bool:bChase = ClientHasMusicFlag(client, MUSICF_CHASE);
+		new bool:bWasChaseSee = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASEVISIBLE);
+		new bool:bChaseSee = ClientHasMusicFlag(client, MUSICF_CHASEVISIBLE);
+		new bool:bAlert = ClientHasMusicFlag(client, MUSICF_ALERT);
+		new bool:bWasAlert = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_ALERT);
+		new bool:b20Dollars = ClientHasMusicFlag(client, MUSICF_20DOLLARS);
+		new bool:bWas20Dollars = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_20DOLLARS);
+		
+		// Custom system.
+		if (GetArraySize(g_hPageMusicRanges) > 0) 
+		{
+			decl String:sPath[PLATFORM_MAX_PATH];
+		
+			new iMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
+			if (iMaster != INVALID_ENT_REFERENCE)
+			{
+				for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
+				{
+					new ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
+					if (!ent || ent == INVALID_ENT_REFERENCE) continue;
+					
+					GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+					
+					if (ent == iMaster && 
+						(iOldPageMusicMaster != iMaster || iOldPageMusicMaster == INVALID_ENT_REFERENCE))
+					{
+						if (!sPath[0])
+						{
+							LogError("Could not play music of page range %d-%d: no sound path specified!", GetArrayCell(g_hPageMusicRanges, i, 1), GetArrayCell(g_hPageMusicRanges, i, 2));
+						}
+						else
+						{
+							ClientMusicStart(client, sPath, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+						}
+						
+						if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
+						{
+							GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+							if (sPath[0])
+							{
+								StopSound(client, MUSIC_CHAN, sPath);
+							}
+						}
+					}
+				}
+			}
+			else
+			{
+				if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
+				{
+					GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+					if (sPath[0])
+					{
+						StopSound(client, MUSIC_CHAN, sPath);
+					}
+				}
+			}
+		}
+		
+		// Old system.
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES1_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES1_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES2_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES2_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES3_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES3_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES4_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES4_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		new iMainMusicState = 0;
+		
+		if (bAlert != bWasAlert || iAlertBoss != g_iPlayerAlertMusicMaster[client])
+		{
+			if (bAlert && !bChase)
+			{
+				ClientAlertMusicStart(client, iAlertBoss);
+				if (!bWasAlert) iMainMusicState = -1;
+			}
+			else
+			{
+				ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
+				if (!bChase && bWasAlert) iMainMusicState = 1;
+			}
+		}
+		
+		if (bChase != bWasChase || iChasingBoss != g_iPlayerChaseMusicMaster[client])
+		{
+			if (bChase)
+			{
+				ClientMusicChaseStart(client, iChasingBoss);
+				
+				if (!bWasChase)
+				{
+					iMainMusicState = -1;
+					
+					if (bAlert)
+					{
+						ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
+					}
+				}
+			}
+			else
+			{
+				ClientMusicChaseStop(client, g_iPlayerChaseMusicMaster[client]);
+				if (bWasChase)
+				{
+					if (bAlert)
+					{
+						ClientAlertMusicStart(client, iAlertBoss);
+					}
+					else
+					{
+						iMainMusicState = 1;
+					}
+				}
+			}
+		}
+		
+		if (bChaseSee != bWasChaseSee || iChasingSeeBoss != g_iPlayerChaseMusicSeeMaster[client])
+		{
+			if (bChaseSee)
+			{
+				ClientMusicChaseSeeStart(client, iChasingSeeBoss);
+			}
+			else
+			{
+				ClientMusicChaseSeeStop(client, g_iPlayerChaseMusicSeeMaster[client]);
+			}
+		}
+		
+		if (b20Dollars != bWas20Dollars || i20DollarsBoss != g_iPlayer20DollarsMusicMaster[client])
+		{
+			if (b20Dollars)
+			{
+				Client20DollarsMusicStart(client, i20DollarsBoss);
+			}
+			else
+			{
+				Client20DollarsMusicStop(client, g_iPlayer20DollarsMusicMaster[client]);
+			}
+		}
+		
+		if (iMainMusicState == 1)
+		{
+			ClientMusicStart(client, g_strPlayerMusic[client], _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		else if (iMainMusicState == -1)
+		{
+			ClientMusicStop(client);
+		}
+		
+		if (bChase || bAlert)
+		{
+			new iBossToUse = -1;
+			if (bChase)
+			{
+				iBossToUse = iChasingBoss;
+			}
+			else
+			{
+				iBossToUse = iAlertBoss;
+			}
+			
+			if (iBossToUse != -1)
+			{
+				// We got some alert/chase music going on! The player's excitement will no doubt go up!
+				// Excitement, though, really depends on how close the boss is in relation to the
+				// player.
+				
+				new Float:flBossDist = NPCGetDistanceFromEntity(iBossToUse, client);
+				new Float:flScalar = flBossDist / 700.0
+				if (flScalar > 1.0) flScalar = 1.0;
+				new Float:flStressAdd = 0.1 * (1.0 - flScalar);
+				
+				ClientAddStress(client, flStressAdd);
+			}
+		}
+	}
+}
+
+stock ClientMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
+	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerMusicFlags[client] = 0;
+	g_flPlayerMusicVolume[client] = 0.0;
+	g_flPlayerMusicTargetVolume[client] = 0.0;
+	g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+	g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+}
+
+stock ClientMusicStart(client, const String:sNewMusic[], Float:flVolume=-1.0, Float:flTargetVolume=-1.0, bool:bCopyOnly=false)
+{
+	if (!IsValidClient(client)) return;
+	if (!sNewMusic[0]) return;
+	
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
+	
+	if (!StrEqual(sOldMusic, sNewMusic, false))
+	{
+		if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	}
+	
+	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), sNewMusic);
+	if (flVolume >= 0.0) g_flPlayerMusicVolume[client] = flVolume;
+	if (flTargetVolume >= 0.0) g_flPlayerMusicTargetVolume[client] = flTargetVolume;
+	
+	if (!bCopyOnly)
+	{
+		g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeInMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+		TriggerTimer(g_hPlayerMusicTimer[client], true);
+	}
+	else
+	{
+		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+	}
+}
+
+stock ClientMusicStop(client)
+{
+	g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeOutMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerMusicTimer[client], true);
+}
+
+stock Client20DollarsMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayer20DollarsMusic[client]);
+	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayer20DollarsMusicMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayer20DollarsMusicTimer[client][i] = INVALID_HANDLE;
+		g_flPlayer20DollarsMusicVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsValidClient(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+				GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock Client20DollarsMusicStart(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iOldMaster = g_iPlayer20DollarsMusicMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (!sBuffer[0]) return;
+	
+	g_iPlayer20DollarsMusicMaster[client] = iBossIndex;
+	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), sBuffer);
+	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeIn20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientAlertMusicStop(client, iOldMaster);
+	}
+}
+
+stock Client20DollarsMusicStop(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayer20DollarsMusicMaster[client])
+	{
+		g_iPlayer20DollarsMusicMaster[client] = -1;
+		strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
+	}
+	
+	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOut20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
+}
+
+stock ClientAlertMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerAlertMusic[client]);
+	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerAlertMusicMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayerAlertMusicTimer[client][i] = INVALID_HANDLE;
+		g_flPlayerAlertMusicVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsValidClient(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+				GetRandomStringFromProfile(sProfile, "sound_alert_music", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock ClientAlertMusicStart(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iOldMaster = g_iPlayerAlertMusicMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (!sBuffer[0]) return;
+	
+	g_iPlayerAlertMusicMaster[client] = iBossIndex;
+	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), sBuffer);
+	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientAlertMusicStop(client, iOldMaster);
+	}
+}
+
+stock ClientAlertMusicStop(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayerAlertMusicMaster[client])
+	{
+		g_iPlayerAlertMusicMaster[client] = -1;
+		strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
+	}
+	
+	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
+}
+
+stock ClientChaseMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusic[client]);
+	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerChaseMusicMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayerChaseMusicTimer[client][i] = INVALID_HANDLE;
+		g_flPlayerChaseMusicVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsValidClient(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+				
+				GetRandomStringFromProfile(sProfile, "sound_chase_music", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock ClientMusicChaseStart(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iOldMaster = g_iPlayerChaseMusicMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (!sBuffer[0]) return;
+	
+	g_iPlayerChaseMusicMaster[client] = iBossIndex;
+	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), sBuffer);
+	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientMusicChaseStop(client, iOldMaster);
+	}
+}
+
+stock ClientMusicChaseStop(client, iBossIndex)
+{
+	if (!IsClientInGame(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayerChaseMusicMaster[client])
+	{
+		g_iPlayerChaseMusicMaster[client] = -1;
+		strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
+	}
+	
+	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
+}
+
+stock ClientChaseMusicSeeReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusicSee[client]);
+	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
+	if (IsClientInGame(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerChaseMusicSeeMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayerChaseMusicSeeTimer[client][i] = INVALID_HANDLE;
+		g_flPlayerChaseMusicSeeVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsClientInGame(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+				GetRandomStringFromProfile(sProfile, "sound_chase_visible", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock ClientMusicChaseSeeStart(client, iBossIndex)
+{
+	if (!IsClientInGame(client)) return;
+	
+	new iOldMaster = g_iPlayerChaseMusicSeeMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
+	if (!sBuffer[0]) return;
+	
+	g_iPlayerChaseMusicSeeMaster[client] = iBossIndex;
+	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), sBuffer);
+	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientMusicChaseSeeStop(client, iOldMaster);
+	}
+}
+
+stock ClientMusicChaseSeeStop(client, iBossIndex)
+{
+	if (!IsClientInGame(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayerChaseMusicSeeMaster[client])
+	{
+		g_iPlayerChaseMusicSeeMaster[client] = -1;
+		strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
+	}
+	
+	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
+}
+
+public Action:Timer_PlayerFadeInMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
+	
+	g_flPlayerMusicVolume[client] += 0.07;
+	if (g_flPlayerMusicVolume[client] > g_flPlayerMusicTargetVolume[client]) g_flPlayerMusicVolume[client] = g_flPlayerMusicTargetVolume[client];
+	
+	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
+
+	if (g_flPlayerMusicVolume[client] >= g_flPlayerMusicTargetVolume[client])
+	{
+		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
+
+	g_flPlayerMusicVolume[client] -= 0.07;
+	if (g_flPlayerMusicVolume[client] < 0.0) g_flPlayerMusicVolume[client] = 0.0;
+
+	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
+
+	if (g_flPlayerMusicVolume[client] <= 0.0)
+	{
+		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeIn20DollarsMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] > 1.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayer20DollarsMusic[client][0]) EmitSoundToClient(client, g_strPlayer20DollarsMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOut20DollarsMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (StrEqual(sBuffer, g_strPlayer20DollarsMusic[client], false))
+	{
+		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] < 0.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeInAlertMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerAlertMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayerAlertMusicVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayerAlertMusic[client][0]) EmitSoundToClient(client, g_strPlayerAlertMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutAlertMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerAlertMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
+
+	if (StrEqual(sBuffer, g_strPlayerAlertMusic[client], false))
+	{
+		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayerAlertMusicVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeInChaseMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayerChaseMusicVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayerChaseMusic[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeInChaseMusicSee(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayerChaseMusicSee[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusicSee[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutChaseMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
+
+	if (StrEqual(sBuffer, g_strPlayerChaseMusic[client], false))
+	{
+		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayerChaseMusicVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutChaseMusicSee(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
+
+	if (StrEqual(sBuffer, g_strPlayerChaseMusicSee[client], false))
+	{
+		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+stock bool:ClientHasMusicFlag(client, iFlag)
+{
+	return bool:(g_iPlayerMusicFlags[client] & iFlag);
+}
+
+stock bool:ClientHasMusicFlag2(iValue, iFlag)
+{
+	return bool:(iValue & iFlag);
+}
+
+stock ClientAddMusicFlag(client, iFlag)
+{
+	if (!ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] |= iFlag;
+}
+
+stock ClientRemoveMusicFlag(client, iFlag)
+{
+	if (ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] &= ~iFlag;
+}
+
+//	==========================================================
+//	MISC FUNCTIONS
+//	==========================================================
+
+// This could be used for entities as well.
+stock ClientStopAllSlenderSounds(client, const String:profileName[], const String:sectionName[], iChannel)
+{
+	if (!client || !IsValidEntity(client)) return;
+	
+	if (!IsProfileValid(profileName)) return;
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	
+	KvRewind(g_hConfig);
+	if (KvJumpToKey(g_hConfig, profileName))
+	{
+		decl String:s[32];
+		
+		if (KvJumpToKey(g_hConfig, sectionName))
+		{
+			for (new i2 = 1;; i2++)
+			{
+				IntToString(i2, s, sizeof(s));
+				KvGetString(g_hConfig, s, buffer, sizeof(buffer));
+				if (!buffer[0]) break;
+				
+				StopSound(client, iChannel, buffer);
+			}
+		}
+	}
+}
+
+stock ClientUpdateListeningFlags(client, bool:bReset=false)
+{
+	if (!IsClientInGame(client)) return;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (i == client || !IsClientInGame(i)) continue;
+		
+		if (bReset || IsRoundEnding() || GetConVarBool(g_cvAllChat))
+		{
+			SetListenOverride(client, i, Listen_Default);
+			continue;
+		}
+		
+		new MuteMode:iMuteMode = g_iPlayerPreferences[client][PlayerPreference_MuteMode];
+		
+		if (g_bPlayerEliminated[client])
+		{
+			if (!g_bPlayerEliminated[i])
+			{
+				if (iMuteMode == MuteMode_DontHearOtherTeam)
+				{
+					SetListenOverride(client, i, Listen_No);
+				}
+				else if (iMuteMode == MuteMode_DontHearOtherTeamIfNotProxy && !g_bPlayerProxy[client])
+				{
+					SetListenOverride(client, i, Listen_No);
+				}
+				else
+				{
+					SetListenOverride(client, i, Listen_Default);
+				}
+			}
+			else
+			{
+				SetListenOverride(client, i, Listen_Default);
+			}
+		}
+		else
+		{
+			if (!g_bPlayerEliminated[i])
+			{
+				if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+				{
+					if (DidClientEscape(i))
+					{
+						if (!DidClientEscape(client))
+						{
+							SetListenOverride(client, i, Listen_No);
+						}
+						else
+						{
+							SetListenOverride(client, i, Listen_Default);
+						}
+					}
+					else
+					{
+						if (!DidClientEscape(client))
+						{
+							SetListenOverride(client, i, Listen_No);
+						}
+						else
+						{
+							SetListenOverride(client, i, Listen_Default);
+						}
+					}
+				}
+				else
+				{
+					new bool:bCanHear = false;
+					if (GetConVarFloat(g_cvPlayerVoiceDistance) <= 0.0) bCanHear = true;
+					
+					if (!bCanHear)
+					{
+						decl Float:flMyPos[3], Float:flHisPos[3];
+						GetClientEyePosition(client, flMyPos);
+						GetClientEyePosition(i, flHisPos);
+						
+						new Float:flDist = GetVectorDistance(flMyPos, flHisPos);
+						
+						if (GetConVarFloat(g_cvPlayerVoiceWallScale) > 0.0)
+						{
+							new Handle:hTrace = TR_TraceRayFilterEx(flMyPos, flHisPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, TraceRayDontHitCharacters);
+							new bool:bDidHit = TR_DidHit(hTrace);
+							CloseHandle(hTrace);
+							
+							if (bDidHit)
+							{
+								flDist *= GetConVarFloat(g_cvPlayerVoiceWallScale);
+							}
+						}
+						
+						if (flDist <= GetConVarFloat(g_cvPlayerVoiceDistance))
+						{
+							bCanHear = true;
+						}
+					}
+					
+					if (bCanHear)
+					{
+						if (IsClientInGhostMode(i) != IsClientInGhostMode(client) &&
+							DidClientEscape(i) != DidClientEscape(client))
+						{
+							bCanHear = false;
+						}
+					}
+					
+					if (bCanHear)
+					{
+						SetListenOverride(client, i, Listen_Default);
+					}
+					else
+					{
+						SetListenOverride(client, i, Listen_No);
+					}
+				}
+			}
+			else
+			{
+				SetListenOverride(client, i, Listen_No);
+			}
+		}
+	}
+}
+
+stock ClientShowMainMessage(client, const String:sMessage[], any:...)
+{
+	decl String:message[512];
+	VFormat(message, sizeof(message), sMessage, 3);
+	
+	SetHudTextParams(-1.0, 0.4,
+		5.0,
+		255,
+		255,
+		255,
+		200,
+		2,
+		1.0,
+		0.07,
+		2.0);
+	ShowSyncHudText(client, g_hHudSync, message);
+}
+
+stock ClientResetSlenderStats(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSlenderStats(%d)", client);
+#endif
+	
+	g_flPlayerStress[client] = 0.0;
+	g_flPlayerStressNextUpdateTime[client] = -1.0;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_bPlayerSeesSlender[client][i] = false;
+		g_flPlayerSeesSlenderLastTime[client][i] = -1.0;
+		g_flPlayerSightSoundNextTime[client][i] = -1.0;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSlenderStats(%d)", client);
+#endif
+}
+
+bool:ClientSetQueuePoints(client, iAmount)
+{
+	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return false;
+	g_iPlayerQueuePoints[client] = iAmount;
+	ClientSaveCookies(client);
+	return true;
+}
+
+ClientSaveCookies(client)
+{
+	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return;
+	
+	// Save and reset our queue points.
+	decl String:s[64];
+	Format(s, sizeof(s), "%d ; %d ; %d ; %d ; %d ; %d", g_iPlayerQueuePoints[client], 
+		g_iPlayerPreferences[client][PlayerPreference_ShowHints], 
+		g_iPlayerPreferences[client][PlayerPreference_MuteMode], 
+		g_iPlayerPreferences[client][PlayerPreference_FilmGrain],
+		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection],
+		g_iPlayerPreferences[client][PlayerPreference_GhostOverlay]);
+		
+	SetClientCookie(client, g_hCookie, s);
+}
+
+stock ClientViewPunch(client, const Float:angleOffset[3])
+{
+	if (g_offsPlayerPunchAngleVel == -1) return;
+	
+	decl Float:flOffset[3];
+	for (new i = 0; i < 3; i++) flOffset[i] = angleOffset[i];
+	ScaleVector(flOffset, 20.0);
+	
+	/*
+	if (!IsFakeClient(client))
+	{
+		// Latency compensation.
+		new Float:flLatency = GetClientLatency(client, NetFlow_Outgoing);
+		new Float:flLatencyCalcDiff = 60.0 * Pow(flLatency, 2.0);
+		
+		for (new i = 0; i < 3; i++) flOffset[i] += (flOffset[i] * flLatencyCalcDiff);
+	}
+	*/
+	
+	decl Float:flAngleVel[3];
+	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flAngleVel);
+	AddVectors(flAngleVel, flOffset, flOffset);
+	SetEntDataVector(client, g_offsPlayerPunchAngleVel, flOffset, true);
+}
+
+public Action:Hook_ConstantGlowSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	new iOwner = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		if (EntRefToEntIndex(g_iPlayerConstantGlowEntity[i]) == ent)
+		{
+			iOwner = i;
+			break;
+		}
+	}
+	
+	if (iOwner != -1)
+	{
+		if (!IsPlayerAlive(iOwner) || g_bPlayerEliminated[iOwner]) return Plugin_Handled;
+		if (!IsPlayerAlive(other) || (!g_bPlayerProxy[other] && !IsClientInGhostMode(other))) return Plugin_Handled;
+	}
+	
+	return Plugin_Continue;
+}
+
+stock ClientSetFOV(client, iFOV)
+{
+	SetEntData(client, g_offsPlayerFOV, iFOV);
+	SetEntData(client, g_offsPlayerDefaultFOV, iFOV);
+}
+
+stock TF2_GetClassName(TFClassType:iClass, String:sBuffer[], sBufferLen)
+{
+	switch (iClass)
+	{
+		case TFClass_Scout: strcopy(sBuffer, sBufferLen, "scout");
+		case TFClass_Sniper: strcopy(sBuffer, sBufferLen, "sniper");
+		case TFClass_Soldier: strcopy(sBuffer, sBufferLen, "soldier");
+		case TFClass_DemoMan: strcopy(sBuffer, sBufferLen, "demoman");
+		case TFClass_Heavy: strcopy(sBuffer, sBufferLen, "heavyweapons");
+		case TFClass_Medic: strcopy(sBuffer, sBufferLen, "medic");
+		case TFClass_Pyro: strcopy(sBuffer, sBufferLen, "pyro");
+		case TFClass_Spy: strcopy(sBuffer, sBufferLen, "spy");
+		case TFClass_Engineer: strcopy(sBuffer, sBufferLen, "engineer");
+		default: strcopy(sBuffer, sBufferLen, "");
+	}
+}
+
+#define EF_DIMLIGHT (1 << 2)
+
+stock ClientSDKFlashlightTurnOn(client)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+	if (iEffects & EF_DIMLIGHT) return;
+
+	iEffects |= EF_DIMLIGHT;
+	
+	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
+}
+
+stock ClientSDKFlashlightTurnOff(client)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+	if (!(iEffects & EF_DIMLIGHT)) return;
+
+	iEffects &= ~EF_DIMLIGHT;
+	
+	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
+}
+
+stock bool:IsPointVisibleToAPlayer(const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false)
+{
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		if (IsPointVisibleToPlayer(i, pos, bCheckFOV, bCheckBlink)) return true;
+	}
+	
+	return false;
+}
+
+stock bool:IsPointVisibleToPlayer(client, const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client) || IsClientInGhostMode(client)) return false;
+	
+	if (bCheckEliminated && g_bPlayerEliminated[client]) return false;
+	
+	if (bCheckBlink && IsClientBlinking(client)) return false;
+	
+	decl Float:eyePos[3];
+	GetClientEyePosition(client, eyePos);
+	
+	// Check fog, if we can.
+	if (g_offsPlayerFogCtrl != -1 && g_offsFogCtrlEnable != -1 && g_offsFogCtrlEnd != -1)
+	{
+		new iFogEntity = GetEntDataEnt2(client, g_offsPlayerFogCtrl);
+		if (IsValidEdict(iFogEntity))
+		{
+			if (GetEntData(iFogEntity, g_offsFogCtrlEnable) &&
+				GetVectorDistance(eyePos, pos) >= GetEntDataFloat(iFogEntity, g_offsFogCtrlEnd)) 
+			{
+				return false;
+			}
+		}
+	}
+	
+	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, pos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
+	new bool:bHit = TR_DidHit(hTrace);
+	CloseHandle(hTrace);
+	
+	if (bHit) return false;
+	
+	if (bCheckFOV)
+	{
+		decl Float:eyeAng[3], Float:reqVisibleAng[3];
+		GetClientEyeAngles(client, eyeAng);
+		
+		new Float:flFOV = float(g_iPlayerDesiredFOV[client]);
+		SubtractVectors(pos, eyePos, reqVisibleAng);
+		GetVectorAngles(reqVisibleAng, reqVisibleAng);
+		
+		new Float:difference = FloatAbs(AngleDiff(eyeAng[0], reqVisibleAng[0])) + FloatAbs(AngleDiff(eyeAng[1], reqVisibleAng[1]));
+		if (difference > ((flFOV * 0.5) + 10.0)) return false;
+	}
+	
+	return true;
+}
+
+public Action:Timer_ClientPostWeapons(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (!IsPlayerAlive(client)) return;
+	
+	if (timer != g_hPlayerPostWeaponsTimer[client]) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) 
+	{
+		DebugMessage("START Timer_ClientPostWeapons(%d)", client);
+	}
+	
+	new iOldWeaponItemIndexes[6] = { -1, ... };
+	new iNewWeaponItemIndexes[6] = { -1, ... };
+	
+	for (new i = 0; i <= 5; i++)
+	{
+		new iWeapon = GetPlayerWeaponSlot(client, i);
+		if (!IsValidEdict(iWeapon)) continue;
+		
+		iOldWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+	}
+	
+#endif
+	
+	new bool:bRemoveWeapons = true;
+	new bool:bRestrictWeapons = true;
+	
+	if (IsRoundEnding())
+	{
+		if (!g_bPlayerEliminated[client]) 
+		{
+			bRemoveWeapons = false;
+			bRestrictWeapons = false;
+		}
+	}
+	
+	// pvp
+	if (IsClientInPvP(client)) 
+	{
+		bRemoveWeapons = false;
+		bRestrictWeapons = false;
+	}
+	
+	if (IsRoundInWarmup()) 
+	{
+		bRemoveWeapons = false;
+		bRestrictWeapons = false;
+	}
+	
+	if (IsClientInGhostMode(client)) 
+	{
+		bRemoveWeapons = true;
+	}
+	
+	if (bRemoveWeapons)
+	{
+		for (new i = 0; i <= 5; i++)
+		{
+			if (i == TFWeaponSlot_Melee && !IsClientInGhostMode(client)) continue;
+			TF2_RemoveWeaponSlotAndWearables(client, i);
+		}
+		
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "tf_weapon_builder")) != -1)
+		{
+			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
+			{
+				AcceptEntityInput(ent, "Kill");
+			}
+		}
+		
+		ent = -1;
+		while ((ent = FindEntityByClassname(ent, "tf_wearable_demoshield")) != -1)
+		{
+			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
+			{
+				AcceptEntityInput(ent, "Kill");
+			}
+		}
+		
+		ClientSwitchToWeaponSlot(client, TFWeaponSlot_Melee);
+	}
+	
+	if (bRestrictWeapons)
+	{
+		new iHealth = GetEntProp(client, Prop_Send, "m_iHealth");
+		
+		if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
+		{
+			new TFClassType:iPlayerClass = TF2_GetPlayerClass(client);
+			new Handle:hItem = INVALID_HANDLE;
+			
+			new iWeapon = INVALID_ENT_REFERENCE;
+			for (new iSlot = 0; iSlot <= 5; iSlot++)
+			{
+				iWeapon = GetPlayerWeaponSlot(client, iSlot);
+				
+				if (IsValidEdict(iWeapon))
+				{
+					if (IsWeaponRestricted(iPlayerClass, GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex")))
+					{
+						hItem = INVALID_HANDLE;
+						TF2_RemoveWeaponSlotAndWearables(client, iSlot);
+						
+						switch (iSlot)
+						{
+							case TFWeaponSlot_Primary:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Scout: hItem = g_hSDKWeaponScattergun;
+									case TFClass_Sniper: hItem = g_hSDKWeaponSniperRifle;
+									case TFClass_Soldier: hItem = g_hSDKWeaponRocketLauncher;
+									case TFClass_DemoMan: hItem = g_hSDKWeaponGrenadeLauncher;
+									case TFClass_Heavy: hItem = g_hSDKWeaponMinigun;
+									case TFClass_Medic: hItem = g_hSDKWeaponSyringeGun;
+									case TFClass_Pyro: hItem = g_hSDKWeaponFlamethrower;
+									case TFClass_Spy: hItem = g_hSDKWeaponRevolver;
+									case TFClass_Engineer: hItem = g_hSDKWeaponShotgunPrimary;
+								}
+							}
+							case TFWeaponSlot_Secondary:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Scout: hItem = g_hSDKWeaponPistolScout;
+									case TFClass_Sniper: hItem = g_hSDKWeaponSMG;
+									case TFClass_Soldier: hItem = g_hSDKWeaponShotgunSoldier;
+									case TFClass_DemoMan: hItem = g_hSDKWeaponStickyLauncher;
+									case TFClass_Heavy: hItem = g_hSDKWeaponShotgunHeavy;
+									case TFClass_Medic: hItem = g_hSDKWeaponMedigun;
+									case TFClass_Pyro: hItem = g_hSDKWeaponShotgunPyro;
+									case TFClass_Engineer: hItem = g_hSDKWeaponPistol;
+								}
+							}
+							case TFWeaponSlot_Melee:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Scout: hItem = g_hSDKWeaponBat;
+									case TFClass_Sniper: hItem = g_hSDKWeaponKukri;
+									case TFClass_Soldier: hItem = g_hSDKWeaponShovel;
+									case TFClass_DemoMan: hItem = g_hSDKWeaponBottle;
+									case TFClass_Heavy: hItem = g_hSDKWeaponFists;
+									case TFClass_Medic: hItem = g_hSDKWeaponBonesaw;
+									case TFClass_Pyro: hItem = g_hSDKWeaponFireaxe;
+									case TFClass_Spy: hItem = g_hSDKWeaponKnife;
+									case TFClass_Engineer: hItem = g_hSDKWeaponWrench;
+								}
+							}
+							case 4:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Spy: hItem = g_hSDKWeaponInvis;
+								}
+							}
+						}
+						
+						if (hItem != INVALID_HANDLE)
+						{
+							new iNewWeapon = TF2Items_GiveNamedItem(client, hItem);
+							if (IsValidEntity(iNewWeapon)) 
+							{
+								EquipPlayerWeapon(client, iNewWeapon);
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		// Fixes the Pretty Boy's Pocket Pistol glitch.
+		new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, client);
+		if (iHealth > iMaxHealth)
+		{
+			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
+			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
+		}
+	}
+	
+	// Change stats on some weapons.
+	if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
+	{
+		new iWeapon = INVALID_ENT_REFERENCE;
+		decl Handle:hWeapon;
+		for (new iSlot = 0; iSlot <= 5; iSlot++)
+		{
+			iWeapon = GetPlayerWeaponSlot(client, iSlot);
+			if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
+			
+			new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+			switch (iItemDef)
+			{
+				case 214: // Powerjack
+				{
+					TF2_RemoveWeaponSlot(client, iSlot);
+					
+					hWeapon = PrepareItemHandle("tf_weapon_fireaxe", 214, 0, 0, "180 ; 20.0 ; 206 ; 1.33");
+					new iEnt = TF2Items_GiveNamedItem(client, hWeapon);
+					CloseHandle(hWeapon);
+					EquipPlayerWeapon(client, iEnt);
+				}
+			}
+		}
+	}
+	
+	// Remove all hats.
+	if (IsClientInGhostMode(client))
+	{
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "tf_wearable")) != -1)
+		{
+			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
+			{
+				AcceptEntityInput(ent, "Kill");
+			}
+		}
+	}
+	
+#if defined DEBUG
+	for (new i = 0; i <= 5; i++)
+	{
+		new iWeapon = GetPlayerWeaponSlot(client, i);
+		if (!IsValidEdict(iWeapon)) continue;
+		
+		iNewWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+	}
+
+	if (GetConVarInt(g_cvDebugDetail) > 0) 
+	{
+		for (new i = 0; i <= 5; i++)
+		{
+			DebugMessage("-> slot %d: %d (old: %d)", i, iNewWeaponItemIndexes[i], iOldWeaponItemIndexes[i]);
+		}
+	
+		DebugMessage("END Timer_ClientPostWeapons(%d) -> remove = %d, restrict = %d", client, bRemoveWeapons, bRestrictWeapons);
+	}
+#endif
+}
+
+public Action:Timer_ApplyCustomModel(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+	
+	if (g_bPlayerProxy[client] && iMaster != -1)
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
+		
+		// Set custom model, if any.
+		decl String:sBuffer[PLATFORM_MAX_PATH];
+		decl String:sSectionName[64];
+		
+		decl String:sClassName[64];
+		TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
+		
+		Format(sSectionName, sizeof(sSectionName), "mod_proxy_%s", sClassName);
+		if ((GetRandomStringFromProfile(sProfile, sSectionName, sBuffer, sizeof(sBuffer)) && sBuffer[0]) ||
+			(GetRandomStringFromProfile(sProfile, "mod_proxy_all", sBuffer, sizeof(sBuffer)) && sBuffer[0]))
+		{
+			SetVariantString(sBuffer);
+			AcceptEntityInput(client, "SetCustomModel");
+			SetEntProp(client, Prop_Send, "m_bUseClassAnimations", true);
+		}
+		
+		if (IsPlayerAlive(client))
+		{
+			// Play any sounds, if any.
+			if (GetRandomStringFromProfile(sProfile, "sound_proxy_spawn", sBuffer, sizeof(sBuffer)) && sBuffer[0])
+			{
+				new iChannel = GetProfileNum(sProfile, "sound_proxy_spawn_channel", SNDCHAN_AUTO);
+				new iLevel = GetProfileNum(sProfile, "sound_proxy_spawn_level", SNDLEVEL_NORMAL);
+				new iFlags = GetProfileNum(sProfile, "sound_proxy_spawn_flags", SND_NOFLAGS);
+				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_spawn_volume", SNDVOL_NORMAL);
+				new iPitch = GetProfileNum(sProfile, "sound_proxy_spawn_pitch", SNDPITCH_NORMAL);
+				
+				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
+			}
+		}
+	}
+}
+
+bool:IsWeaponRestricted(TFClassType:iClass, iItemDef)
+{
+	if (g_hRestrictedWeaponsConfig == INVALID_HANDLE) return false;
+	
+	new bool:bReturn = false;
+	
+	decl String:sItemDef[32];
+	IntToString(iItemDef, sItemDef, sizeof(sItemDef));
+	
+	KvRewind(g_hRestrictedWeaponsConfig);
+	if (KvJumpToKey(g_hRestrictedWeaponsConfig, "all"))
+	{
+		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef);
+	}
+	
+	new bool:bFoundSection = false;
+	KvRewind(g_hRestrictedWeaponsConfig);
+	
+	switch (iClass)
+	{
+		case TFClass_Scout: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "scout");
+		case TFClass_Soldier: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "soldier");
+		case TFClass_Sniper: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "sniper");
+		case TFClass_DemoMan: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "demoman");
+		case TFClass_Heavy: 
+		{
+			bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavy");
+		
+			if (!bFoundSection)
+			{
+				KvRewind(g_hRestrictedWeaponsConfig);
+				bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavyweapons");
+			}
+		}
+		case TFClass_Medic: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "medic");
+		case TFClass_Spy: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "spy");
+		case TFClass_Pyro: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "pyro");
+		case TFClass_Engineer: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "engineer");
+	}
+	
+	if (bFoundSection)
+	{
+		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef, bReturn);
+	}
+	
+	return bReturn;
+}
+
+public Action:Timer_RespawnPlayer(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (IsPlayerAlive(client)) return;
+	
+	TF2_RespawnPlayer(client);
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/debug.sp b/addons/sourcemod/scripting/rytp_horror/debug.sp
index 9e05614..8b48236 100644
--- a/addons/sourcemod/scripting/rytp_horror/debug.sp
+++ b/addons/sourcemod/scripting/rytp_horror/debug.sp
@@ -1,161 +1,161 @@
-#if defined _sf2_debug_included
- #endinput
-#endif
-#define _sf2_debug_included
-
-#if !defined DEBUG
- #endinput
-#endif
-
-#define DEBUG_BOSS_TELEPORTATION (1 << 0)
-#define DEBUG_BOSS_CHASE (1 << 1)
-#define DEBUG_PLAYER_STRESS (1 << 2)
-#define DEBUG_PLAYER_ACTION_SLOT (1 << 3)
-#define DEBUG_BOSS_PROXIES (1 << 4)
-
-new g_iPlayerDebugFlags[MAXPLAYERS + 1] = { 0, ... };
-
-static String:g_strDebugLogFilePath[512] = "";
-
-new Handle:g_cvDebugDetail = INVALID_HANDLE;
-new Handle:g_cvDebugBosses = INVALID_HANDLE;
-
-InitializeDebug()
-{
-	g_cvDebugDetail = CreateConVar("sf2_debug_detail", "0", "0 = off, 1 = debug only large, expensive functions, 2 = debug more events, 3 = debug client functions");
-	g_cvDebugBosses = CreateConVar("sf2_debug_bosses", "0");
-	
-	RegAdminCmd("sm_sf2_debug_boss_teleport", Command_DebugBossTeleport, ADMFLAG_CHEATS);
-	RegAdminCmd("sm_sf2_debug_boss_chase", Command_DebugBossChase, ADMFLAG_CHEATS);
-	RegAdminCmd("sm_sf2_debug_player_stress", Command_DebugPlayerStress, ADMFLAG_CHEATS);
-	RegAdminCmd("sm_sf2_debug_boss_proxies", Command_DebugBossProxies, ADMFLAG_CHEATS);
-}
-
-InitializeDebugLogging()
-{
-	decl String:sDateSuffix[256];
-	FormatTime(sDateSuffix, sizeof(sDateSuffix), "sf2-debug-%Y-%m-%d.log", GetTime());
-	
-	BuildPath(Path_SM, g_strDebugLogFilePath, sizeof(g_strDebugLogFilePath), "logs/%s", sDateSuffix);
-	
-	decl String:sMap[64];
-	GetCurrentMap(sMap, sizeof(sMap));
-	
-	DebugMessage("-------- Mapchange to %s -------", sMap);
-}
-
-stock DebugMessage(const String:sMessage[], any:...)
-{
-	decl String:sDebugMessage[1024], String:sTemp[1024];
-	VFormat(sTemp, sizeof(sTemp), sMessage, 2);
-	Format(sDebugMessage, sizeof(sDebugMessage), "%s", sTemp);
-	//LogMessage(sDebugMessage);
-	LogToFile(g_strDebugLogFilePath, sDebugMessage);
-}
-
-stock SendDebugMessageToPlayer(client, iDebugFlags, iType, const String:sMessage[], any:...)
-{
-	if (!IsClientInGame(client) || IsFakeClient(client)) return;
-
-	decl String:sMsg[1024];
-	VFormat(sMsg, sizeof(sMsg), sMessage, 5);
-	
-	if (g_iPlayerDebugFlags[client] & iDebugFlags)
-	{
-		switch (iType)
-		{
-			case 0: CPrintToChat(client, sMsg);
-			case 1: PrintCenterText(client, sMsg);
-			case 2: PrintHintText(client, sMsg);
-		}
-	}
-}
-
-stock SendDebugMessageToPlayers(iDebugFlags, iType, const String:sMessage[], any:...)
-{
-	decl String:sMsg[1024];
-	VFormat(sMsg, sizeof(sMsg), sMessage, 4);
-
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || IsFakeClient(i)) continue;
-		
-		if (g_iPlayerDebugFlags[i] & iDebugFlags)
-		{
-			switch (iType)
-			{
-				case 0: CPrintToChat(i, sMsg);
-				case 1: PrintCenterText(i, sMsg);
-				case 2: PrintHintText(i, sMsg);
-			}
-		}
-	}
-}
-
-public Action:Command_DebugBossTeleport(client, args)
-{
-	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_BOSS_TELEPORTATION);
-	if (!bInMode)
-	{
-		g_iPlayerDebugFlags[client] |= DEBUG_BOSS_TELEPORTATION;
-		PrintToChat(client, "Enabled debugging boss teleportation.");
-	}
-	else
-	{
-		g_iPlayerDebugFlags[client] &= ~DEBUG_BOSS_TELEPORTATION;
-		PrintToChat(client, "Disabled debugging boss teleportation.");
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_DebugBossChase(client, args)
-{
-	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_BOSS_CHASE);
-	if (!bInMode)
-	{
-		g_iPlayerDebugFlags[client] |= DEBUG_BOSS_CHASE;
-		PrintToChat(client, "Enabled debugging boss chasing.");
-	}
-	else
-	{
-		g_iPlayerDebugFlags[client] &= ~DEBUG_BOSS_CHASE;
-		PrintToChat(client, "Disabled debugging boss chasing.");
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_DebugPlayerStress(client, args)
-{
-	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_PLAYER_STRESS);
-	if (!bInMode)
-	{
-		g_iPlayerDebugFlags[client] |= DEBUG_PLAYER_STRESS;
-		PrintToChat(client, "Enabled debugging player stress.");
-	}
-	else
-	{
-		g_iPlayerDebugFlags[client] &= ~DEBUG_PLAYER_STRESS;
-		PrintToChat(client, "Disabled debugging player stress.");
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_DebugBossProxies(client, args)
-{
-	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_BOSS_PROXIES);
-	if (!bInMode)
-	{
-		g_iPlayerDebugFlags[client] |= DEBUG_BOSS_PROXIES;
-		PrintToChat(client, "Enabled debugging boss proxies.");
-	}
-	else
-	{
-		g_iPlayerDebugFlags[client] &= ~DEBUG_BOSS_PROXIES;
-		PrintToChat(client, "Disabled debugging boss proxies.");
-	}
-	
-	return Plugin_Handled;
+#if defined _sf2_debug_included
+ #endinput
+#endif
+#define _sf2_debug_included
+
+#if !defined DEBUG
+ #endinput
+#endif
+
+#define DEBUG_BOSS_TELEPORTATION (1 << 0)
+#define DEBUG_BOSS_CHASE (1 << 1)
+#define DEBUG_PLAYER_STRESS (1 << 2)
+#define DEBUG_PLAYER_ACTION_SLOT (1 << 3)
+#define DEBUG_BOSS_PROXIES (1 << 4)
+
+new g_iPlayerDebugFlags[MAXPLAYERS + 1] = { 0, ... };
+
+static String:g_strDebugLogFilePath[512] = "";
+
+new Handle:g_cvDebugDetail = INVALID_HANDLE;
+new Handle:g_cvDebugBosses = INVALID_HANDLE;
+
+InitializeDebug()
+{
+	g_cvDebugDetail = CreateConVar("sf2_debug_detail", "0", "0 = off, 1 = debug only large, expensive functions, 2 = debug more events, 3 = debug client functions");
+	g_cvDebugBosses = CreateConVar("sf2_debug_bosses", "0");
+	
+	RegAdminCmd("sm_sf2_debug_boss_teleport", Command_DebugBossTeleport, ADMFLAG_CHEATS);
+	RegAdminCmd("sm_sf2_debug_boss_chase", Command_DebugBossChase, ADMFLAG_CHEATS);
+	RegAdminCmd("sm_sf2_debug_player_stress", Command_DebugPlayerStress, ADMFLAG_CHEATS);
+	RegAdminCmd("sm_sf2_debug_boss_proxies", Command_DebugBossProxies, ADMFLAG_CHEATS);
+}
+
+InitializeDebugLogging()
+{
+	decl String:sDateSuffix[256];
+	FormatTime(sDateSuffix, sizeof(sDateSuffix), "sf2-debug-%Y-%m-%d.log", GetTime());
+	
+	BuildPath(Path_SM, g_strDebugLogFilePath, sizeof(g_strDebugLogFilePath), "logs/%s", sDateSuffix);
+	
+	decl String:sMap[64];
+	GetCurrentMap(sMap, sizeof(sMap));
+	
+	DebugMessage("-------- Mapchange to %s -------", sMap);
+}
+
+stock DebugMessage(const String:sMessage[], any:...)
+{
+	decl String:sDebugMessage[1024], String:sTemp[1024];
+	VFormat(sTemp, sizeof(sTemp), sMessage, 2);
+	Format(sDebugMessage, sizeof(sDebugMessage), "%s", sTemp);
+	//LogMessage(sDebugMessage);
+	LogToFile(g_strDebugLogFilePath, sDebugMessage);
+}
+
+stock SendDebugMessageToPlayer(client, iDebugFlags, iType, const String:sMessage[], any:...)
+{
+	if (!IsClientInGame(client) || IsFakeClient(client)) return;
+
+	decl String:sMsg[1024];
+	VFormat(sMsg, sizeof(sMsg), sMessage, 5);
+	
+	if (g_iPlayerDebugFlags[client] & iDebugFlags)
+	{
+		switch (iType)
+		{
+			case 0: CPrintToChat(client, sMsg);
+			case 1: PrintCenterText(client, sMsg);
+			case 2: PrintHintText(client, sMsg);
+		}
+	}
+}
+
+stock SendDebugMessageToPlayers(iDebugFlags, iType, const String:sMessage[], any:...)
+{
+	decl String:sMsg[1024];
+	VFormat(sMsg, sizeof(sMsg), sMessage, 4);
+
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || IsFakeClient(i)) continue;
+		
+		if (g_iPlayerDebugFlags[i] & iDebugFlags)
+		{
+			switch (iType)
+			{
+				case 0: CPrintToChat(i, sMsg);
+				case 1: PrintCenterText(i, sMsg);
+				case 2: PrintHintText(i, sMsg);
+			}
+		}
+	}
+}
+
+public Action:Command_DebugBossTeleport(client, args)
+{
+	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_BOSS_TELEPORTATION);
+	if (!bInMode)
+	{
+		g_iPlayerDebugFlags[client] |= DEBUG_BOSS_TELEPORTATION;
+		PrintToChat(client, "Enabled debugging boss teleportation.");
+	}
+	else
+	{
+		g_iPlayerDebugFlags[client] &= ~DEBUG_BOSS_TELEPORTATION;
+		PrintToChat(client, "Disabled debugging boss teleportation.");
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_DebugBossChase(client, args)
+{
+	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_BOSS_CHASE);
+	if (!bInMode)
+	{
+		g_iPlayerDebugFlags[client] |= DEBUG_BOSS_CHASE;
+		PrintToChat(client, "Enabled debugging boss chasing.");
+	}
+	else
+	{
+		g_iPlayerDebugFlags[client] &= ~DEBUG_BOSS_CHASE;
+		PrintToChat(client, "Disabled debugging boss chasing.");
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_DebugPlayerStress(client, args)
+{
+	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_PLAYER_STRESS);
+	if (!bInMode)
+	{
+		g_iPlayerDebugFlags[client] |= DEBUG_PLAYER_STRESS;
+		PrintToChat(client, "Enabled debugging player stress.");
+	}
+	else
+	{
+		g_iPlayerDebugFlags[client] &= ~DEBUG_PLAYER_STRESS;
+		PrintToChat(client, "Disabled debugging player stress.");
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_DebugBossProxies(client, args)
+{
+	new bool:bInMode = bool:(g_iPlayerDebugFlags[client] & DEBUG_BOSS_PROXIES);
+	if (!bInMode)
+	{
+		g_iPlayerDebugFlags[client] |= DEBUG_BOSS_PROXIES;
+		PrintToChat(client, "Enabled debugging boss proxies.");
+	}
+	else
+	{
+		g_iPlayerDebugFlags[client] &= ~DEBUG_BOSS_PROXIES;
+		PrintToChat(client, "Disabled debugging boss proxies.");
+	}
+	
+	return Plugin_Handled;
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/effects.sp b/addons/sourcemod/scripting/rytp_horror/effects.sp
index 4a8ab94..2acc0c6 100644
--- a/addons/sourcemod/scripting/rytp_horror/effects.sp
+++ b/addons/sourcemod/scripting/rytp_horror/effects.sp
@@ -1,275 +1,275 @@
-#if defined _sf2_effects_included
- #endinput
-#endif
-#define _sf2_effects_included
-
-enum EffectEvent
-{
-	EffectEvent_Invalid = -1,
-	EffectEvent_Constant = 0,
-	EffectEvent_HitPlayer,
-	EffectEvent_PlayerSeesBoss
-};
-
-enum EffectType
-{
-	EffectType_Invalid = -1,
-	EffectType_Steam = 0,
-	EffectType_DynamicLight
-};
-
-SlenderSpawnEffects(iBossIndex, EffectEvent:iEvent)
-{
-	if (iBossIndex < 0 || iBossIndex >= MAX_BOSSES) return;
-	
-	new iBossID = NPCGetUniqueID(iBossIndex);
-	if (iBossID == -1) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	KvRewind(g_hConfig);
-	if (!KvJumpToKey(g_hConfig, sProfile) || !KvJumpToKey(g_hConfig, "effects") || !KvGotoFirstSubKey(g_hConfig)) return;
-	
-	new Handle:hArray = CreateArray(64);
-	decl String:sSectionName[64];
-	
-	do
-	{
-		KvGetSectionName(g_hConfig, sSectionName, sizeof(sSectionName));
-		PushArrayString(hArray, sSectionName);
-	}
-	while (KvGotoNextKey(g_hConfig));
-	
-	if (GetArraySize(hArray) == 0)
-	{
-		CloseHandle(hArray);
-		return;
-	}
-	
-	decl String:sEvent[64];
-	GetEffectEventString(iEvent, sEvent, sizeof(sEvent));
-	if (!sEvent[0]) 
-	{
-		LogError("Could not spawn effects for boss %d: invalid event string!", iBossIndex);
-		CloseHandle(hArray);
-		return;
-	}
-	
-	new iSlender = NPCGetEntIndex(iBossIndex);
-	decl Float:flBasePos[3], Float:flBaseAng[3];
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	KvJumpToKey(g_hConfig, "effects");
-	
-	for (new i = 0, iSize = GetArraySize(hArray); i < iSize; i++)
-	{
-		GetArrayString(hArray, i, sSectionName, sizeof(sSectionName));
-		KvJumpToKey(g_hConfig, sSectionName);
-		
-		// Validate effect event. Check to see if it matches with ours.
-		decl String:sEffectEvent[64];
-		KvGetString(g_hConfig, "event", sEffectEvent, sizeof(sEffectEvent));
-		if (StrEqual(sEffectEvent, sEvent, false)) 
-		{
-			// Validate effect type.
-			decl String:sEffectType[64];
-			KvGetString(g_hConfig, "type", sEffectType, sizeof(sEffectType));
-			new EffectType:iEffectType = GetEffectTypeFromString(sEffectType);
-			
-			if (iEffectType != EffectType_Invalid)
-			{
-				// Check base position behavior.
-				decl String:sBasePosCustom[64];
-				KvGetString(g_hConfig, "origin_custom", sBasePosCustom, sizeof(sBasePosCustom));
-				if (StrEqual(sBasePosCustom, "&CURRENTTARGET&", false))
-				{
-					new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
-					if (!iTarget || iTarget == INVALID_ENT_REFERENCE)
-					{
-						LogError("Could not spawn effect %s for boss %d: unable to read position of target due to no target!");
-						KvGoBack(g_hConfig);
-						continue;
-					}
-					
-					GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flBasePos);
-				}
-				else
-				{
-					if (!iSlender || iSlender == INVALID_ENT_REFERENCE)
-					{
-						LogError("Could not spawn effect %s for boss %d: unable to read position due to boss entity not in game!");
-						KvGoBack(g_hConfig);
-						continue;
-					}
-					
-					GetEntPropVector(iSlender, Prop_Data, "m_vecAbsOrigin", flBasePos);
-				}
-				
-				decl String:sBaseAngCustom[64];
-				KvGetString(g_hConfig, "angles_custom", sBaseAngCustom, sizeof(sBaseAngCustom));
-				if (StrEqual(sBaseAngCustom, "&CURRENTTARGET&", false))
-				{
-					new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
-					if (!iTarget || iTarget == INVALID_ENT_REFERENCE)
-					{
-						LogError("Could not spawn effect %s for boss %d: unable to read angles of target due to no target!");
-						KvGoBack(g_hConfig);
-						continue;
-					}
-					
-					GetEntPropVector(iTarget, Prop_Data, "m_angAbsRotation", flBaseAng);
-				}
-				else
-				{
-					if (!iSlender || iSlender == INVALID_ENT_REFERENCE)
-					{
-						LogError("Could not spawn effect %s for boss %d: unable to read angles due to boss entity not in game!");
-						KvGoBack(g_hConfig);
-						continue;
-					}
-					
-					GetEntPropVector(iSlender, Prop_Data, "m_angAbsRotation", flBaseAng);
-				}
-				
-				new iEnt = -1;
-				
-				switch (iEffectType)
-				{
-					case EffectType_Steam: iEnt = CreateEntityByName("env_steam");
-					case EffectType_DynamicLight: iEnt = CreateEntityByName("light_dynamic");
-				}
-				
-				if (iEnt != -1)
-				{
-					decl String:sValue[PLATFORM_MAX_PATH];
-					KvGetString(g_hConfig, "renderamt", sValue, sizeof(sValue), "255");
-					DispatchKeyValue(iEnt, "renderamt", sValue);
-					KvGetString(g_hConfig, "rendermode", sValue, sizeof(sValue));
-					DispatchKeyValue(iEnt, "rendermode", sValue);
-					KvGetString(g_hConfig, "renderfx", sValue, sizeof(sValue), "0");
-					DispatchKeyValue(iEnt, "renderfx", sValue);
-					KvGetString(g_hConfig, "spawnflags", sValue, sizeof(sValue));
-					DispatchKeyValue(iEnt, "spawnflags", sValue);
-					
-					switch  (iEffectType)
-					{
-						case EffectType_Steam:
-						{
-							KvGetString(g_hConfig, "spreadspeed", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "SpreadSpeed", sValue);
-							KvGetString(g_hConfig, "speed", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "Speed", sValue);
-							KvGetString(g_hConfig, "startsize", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "StartSize", sValue);
-							KvGetString(g_hConfig, "endsize", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "EndSize", sValue);
-							KvGetString(g_hConfig, "rate", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "Rate", sValue);
-							KvGetString(g_hConfig, "jetlength", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "Jetlength", sValue);
-							KvGetString(g_hConfig, "rollspeed", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "RollSpeed", sValue);
-							KvGetString(g_hConfig, "particletype", sValue, sizeof(sValue));
-							DispatchKeyValue(iEnt, "type", sValue);
-							DispatchSpawn(iEnt);
-							ActivateEntity(iEnt);
-						}
-						case EffectType_DynamicLight:
-						{
-							SetVariantInt(KvGetNum(g_hConfig, "brightness"));
-							AcceptEntityInput(iEnt, "Brightness");
-							SetVariantFloat(KvGetFloat(g_hConfig, "distance"));
-							AcceptEntityInput(iEnt, "Distance");
-							SetVariantFloat(KvGetFloat(g_hConfig, "distance"));
-							AcceptEntityInput(iEnt, "spotlight_radius");
-							SetVariantInt(KvGetNum(g_hConfig, "cone"));
-							AcceptEntityInput(iEnt, "cone");
-							DispatchSpawn(iEnt);
-							ActivateEntity(iEnt);
-							
-							new r, g, b, a;
-							KvGetColor(g_hConfig, "rendercolor", r, g, b, a);
-							SetEntityRenderColor(iEnt, r, g, b, a);
-						}
-					}
-					
-					decl Float:flEffectPos[3], Float:flEffectAng[3];
-					
-					KvGetVector(g_hConfig, "origin", flEffectPos);
-					KvGetVector(g_hConfig, "angles", flEffectAng);
-					VectorTransform(flEffectPos, flBasePos, flBaseAng, flEffectPos);
-					AddVectors(flEffectAng, flBaseAng, flEffectAng);
-					TeleportEntity(iEnt, flEffectPos, flEffectAng, NULL_VECTOR);
-					
-					new Float:flLifeTime = KvGetFloat(g_hConfig, "lifetime");
-					if (flLifeTime > 0.0) CreateTimer(flLifeTime, Timer_KillEntity, EntIndexToEntRef(iEnt), TIMER_FLAG_NO_MAPCHANGE);
-					
-					decl String:sParentCustom[64];
-					KvGetString(g_hConfig, "parent_custom", sParentCustom, sizeof(sParentCustom));
-					if (StrEqual(sParentCustom, "&CURRENTTARGET&", false))
-					{
-						new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
-						if (!iTarget || iTarget == INVALID_ENT_REFERENCE)
-						{
-							LogError("Could not parent effect %s of boss %d to current target: target does not exist!", sSectionName, iBossIndex);
-							KvGoBack(g_hConfig);
-							continue;
-						}
-					
-						SetVariantString("!activator");
-						AcceptEntityInput(iEnt, "SetParent", iTarget);
-					}
-					else
-					{
-						if (!iSlender || iSlender == INVALID_ENT_REFERENCE)
-						{
-							LogError("Could not parent effect %s of boss %d to itself: boss entity does not exist!", sSectionName, iBossIndex);
-							KvGoBack(g_hConfig);
-							continue;
-						}
-						
-						SetVariantString("!activator");
-						AcceptEntityInput(iEnt, "SetParent", iSlender);
-					}
-					
-					switch (iEffectType)
-					{
-						case EffectType_Steam,
-							EffectType_DynamicLight: 
-						{
-							AcceptEntityInput(iEnt, "TurnOn");
-						}
-					}
-				}
-			}
-			else
-			{
-				LogError("Could not spawn effect %s for boss %d: invalid type!", sSectionName, iBossIndex);
-			}
-		}
-		
-		KvGoBack(g_hConfig);
-	}
-	
-	CloseHandle(hArray);
-}
-
-stock GetEffectEventString(EffectEvent:iEvent, String:sBuffer[], iBufferLen)
-{
-	switch (iEvent)
-	{
-		case EffectEvent_Constant: strcopy(sBuffer, iBufferLen, "constant");
-		case EffectEvent_HitPlayer: strcopy(sBuffer, iBufferLen, "boss_hitplayer");
-		case EffectEvent_PlayerSeesBoss: strcopy(sBuffer, iBufferLen, "boss_seenbyplayer");
-		default: strcopy(sBuffer, iBufferLen, "");
-	}
-}
-
-stock EffectType:GetEffectTypeFromString(const String:sType[])
-{
-	if (StrEqual(sType, "steam", false)) return EffectType_Steam;
-	if (StrEqual(sType, "dynamiclight", false)) return EffectType_DynamicLight;
-	return EffectType_Invalid;
-}
+#if defined _sf2_effects_included
+ #endinput
+#endif
+#define _sf2_effects_included
+
+enum EffectEvent
+{
+	EffectEvent_Invalid = -1,
+	EffectEvent_Constant = 0,
+	EffectEvent_HitPlayer,
+	EffectEvent_PlayerSeesBoss
+};
+
+enum EffectType
+{
+	EffectType_Invalid = -1,
+	EffectType_Steam = 0,
+	EffectType_DynamicLight
+};
+
+SlenderSpawnEffects(iBossIndex, EffectEvent:iEvent)
+{
+	if (iBossIndex < 0 || iBossIndex >= MAX_BOSSES) return;
+	
+	new iBossID = NPCGetUniqueID(iBossIndex);
+	if (iBossID == -1) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	KvRewind(g_hConfig);
+	if (!KvJumpToKey(g_hConfig, sProfile) || !KvJumpToKey(g_hConfig, "effects") || !KvGotoFirstSubKey(g_hConfig)) return;
+	
+	new Handle:hArray = CreateArray(64);
+	decl String:sSectionName[64];
+	
+	do
+	{
+		KvGetSectionName(g_hConfig, sSectionName, sizeof(sSectionName));
+		PushArrayString(hArray, sSectionName);
+	}
+	while (KvGotoNextKey(g_hConfig));
+	
+	if (GetArraySize(hArray) == 0)
+	{
+		CloseHandle(hArray);
+		return;
+	}
+	
+	decl String:sEvent[64];
+	GetEffectEventString(iEvent, sEvent, sizeof(sEvent));
+	if (!sEvent[0]) 
+	{
+		LogError("Could not spawn effects for boss %d: invalid event string!", iBossIndex);
+		CloseHandle(hArray);
+		return;
+	}
+	
+	new iSlender = NPCGetEntIndex(iBossIndex);
+	decl Float:flBasePos[3], Float:flBaseAng[3];
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	KvJumpToKey(g_hConfig, "effects");
+	
+	for (new i = 0, iSize = GetArraySize(hArray); i < iSize; i++)
+	{
+		GetArrayString(hArray, i, sSectionName, sizeof(sSectionName));
+		KvJumpToKey(g_hConfig, sSectionName);
+		
+		// Validate effect event. Check to see if it matches with ours.
+		decl String:sEffectEvent[64];
+		KvGetString(g_hConfig, "event", sEffectEvent, sizeof(sEffectEvent));
+		if (StrEqual(sEffectEvent, sEvent, false)) 
+		{
+			// Validate effect type.
+			decl String:sEffectType[64];
+			KvGetString(g_hConfig, "type", sEffectType, sizeof(sEffectType));
+			new EffectType:iEffectType = GetEffectTypeFromString(sEffectType);
+			
+			if (iEffectType != EffectType_Invalid)
+			{
+				// Check base position behavior.
+				decl String:sBasePosCustom[64];
+				KvGetString(g_hConfig, "origin_custom", sBasePosCustom, sizeof(sBasePosCustom));
+				if (StrEqual(sBasePosCustom, "&CURRENTTARGET&", false))
+				{
+					new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
+					if (!iTarget || iTarget == INVALID_ENT_REFERENCE)
+					{
+						LogError("Could not spawn effect %s for boss %d: unable to read position of target due to no target!");
+						KvGoBack(g_hConfig);
+						continue;
+					}
+					
+					GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flBasePos);
+				}
+				else
+				{
+					if (!iSlender || iSlender == INVALID_ENT_REFERENCE)
+					{
+						LogError("Could not spawn effect %s for boss %d: unable to read position due to boss entity not in game!");
+						KvGoBack(g_hConfig);
+						continue;
+					}
+					
+					GetEntPropVector(iSlender, Prop_Data, "m_vecAbsOrigin", flBasePos);
+				}
+				
+				decl String:sBaseAngCustom[64];
+				KvGetString(g_hConfig, "angles_custom", sBaseAngCustom, sizeof(sBaseAngCustom));
+				if (StrEqual(sBaseAngCustom, "&CURRENTTARGET&", false))
+				{
+					new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
+					if (!iTarget || iTarget == INVALID_ENT_REFERENCE)
+					{
+						LogError("Could not spawn effect %s for boss %d: unable to read angles of target due to no target!");
+						KvGoBack(g_hConfig);
+						continue;
+					}
+					
+					GetEntPropVector(iTarget, Prop_Data, "m_angAbsRotation", flBaseAng);
+				}
+				else
+				{
+					if (!iSlender || iSlender == INVALID_ENT_REFERENCE)
+					{
+						LogError("Could not spawn effect %s for boss %d: unable to read angles due to boss entity not in game!");
+						KvGoBack(g_hConfig);
+						continue;
+					}
+					
+					GetEntPropVector(iSlender, Prop_Data, "m_angAbsRotation", flBaseAng);
+				}
+				
+				new iEnt = -1;
+				
+				switch (iEffectType)
+				{
+					case EffectType_Steam: iEnt = CreateEntityByName("env_steam");
+					case EffectType_DynamicLight: iEnt = CreateEntityByName("light_dynamic");
+				}
+				
+				if (iEnt != -1)
+				{
+					decl String:sValue[PLATFORM_MAX_PATH];
+					KvGetString(g_hConfig, "renderamt", sValue, sizeof(sValue), "255");
+					DispatchKeyValue(iEnt, "renderamt", sValue);
+					KvGetString(g_hConfig, "rendermode", sValue, sizeof(sValue));
+					DispatchKeyValue(iEnt, "rendermode", sValue);
+					KvGetString(g_hConfig, "renderfx", sValue, sizeof(sValue), "0");
+					DispatchKeyValue(iEnt, "renderfx", sValue);
+					KvGetString(g_hConfig, "spawnflags", sValue, sizeof(sValue));
+					DispatchKeyValue(iEnt, "spawnflags", sValue);
+					
+					switch  (iEffectType)
+					{
+						case EffectType_Steam:
+						{
+							KvGetString(g_hConfig, "spreadspeed", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "SpreadSpeed", sValue);
+							KvGetString(g_hConfig, "speed", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "Speed", sValue);
+							KvGetString(g_hConfig, "startsize", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "StartSize", sValue);
+							KvGetString(g_hConfig, "endsize", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "EndSize", sValue);
+							KvGetString(g_hConfig, "rate", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "Rate", sValue);
+							KvGetString(g_hConfig, "jetlength", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "Jetlength", sValue);
+							KvGetString(g_hConfig, "rollspeed", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "RollSpeed", sValue);
+							KvGetString(g_hConfig, "particletype", sValue, sizeof(sValue));
+							DispatchKeyValue(iEnt, "type", sValue);
+							DispatchSpawn(iEnt);
+							ActivateEntity(iEnt);
+						}
+						case EffectType_DynamicLight:
+						{
+							SetVariantInt(KvGetNum(g_hConfig, "brightness"));
+							AcceptEntityInput(iEnt, "Brightness");
+							SetVariantFloat(KvGetFloat(g_hConfig, "distance"));
+							AcceptEntityInput(iEnt, "Distance");
+							SetVariantFloat(KvGetFloat(g_hConfig, "distance"));
+							AcceptEntityInput(iEnt, "spotlight_radius");
+							SetVariantInt(KvGetNum(g_hConfig, "cone"));
+							AcceptEntityInput(iEnt, "cone");
+							DispatchSpawn(iEnt);
+							ActivateEntity(iEnt);
+							
+							new r, g, b, a;
+							KvGetColor(g_hConfig, "rendercolor", r, g, b, a);
+							SetEntityRenderColor(iEnt, r, g, b, a);
+						}
+					}
+					
+					decl Float:flEffectPos[3], Float:flEffectAng[3];
+					
+					KvGetVector(g_hConfig, "origin", flEffectPos);
+					KvGetVector(g_hConfig, "angles", flEffectAng);
+					VectorTransform(flEffectPos, flBasePos, flBaseAng, flEffectPos);
+					AddVectors(flEffectAng, flBaseAng, flEffectAng);
+					TeleportEntity(iEnt, flEffectPos, flEffectAng, NULL_VECTOR);
+					
+					new Float:flLifeTime = KvGetFloat(g_hConfig, "lifetime");
+					if (flLifeTime > 0.0) CreateTimer(flLifeTime, Timer_KillEntity, EntIndexToEntRef(iEnt), TIMER_FLAG_NO_MAPCHANGE);
+					
+					decl String:sParentCustom[64];
+					KvGetString(g_hConfig, "parent_custom", sParentCustom, sizeof(sParentCustom));
+					if (StrEqual(sParentCustom, "&CURRENTTARGET&", false))
+					{
+						new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
+						if (!iTarget || iTarget == INVALID_ENT_REFERENCE)
+						{
+							LogError("Could not parent effect %s of boss %d to current target: target does not exist!", sSectionName, iBossIndex);
+							KvGoBack(g_hConfig);
+							continue;
+						}
+					
+						SetVariantString("!activator");
+						AcceptEntityInput(iEnt, "SetParent", iTarget);
+					}
+					else
+					{
+						if (!iSlender || iSlender == INVALID_ENT_REFERENCE)
+						{
+							LogError("Could not parent effect %s of boss %d to itself: boss entity does not exist!", sSectionName, iBossIndex);
+							KvGoBack(g_hConfig);
+							continue;
+						}
+						
+						SetVariantString("!activator");
+						AcceptEntityInput(iEnt, "SetParent", iSlender);
+					}
+					
+					switch (iEffectType)
+					{
+						case EffectType_Steam,
+							EffectType_DynamicLight: 
+						{
+							AcceptEntityInput(iEnt, "TurnOn");
+						}
+					}
+				}
+			}
+			else
+			{
+				LogError("Could not spawn effect %s for boss %d: invalid type!", sSectionName, iBossIndex);
+			}
+		}
+		
+		KvGoBack(g_hConfig);
+	}
+	
+	CloseHandle(hArray);
+}
+
+stock GetEffectEventString(EffectEvent:iEvent, String:sBuffer[], iBufferLen)
+{
+	switch (iEvent)
+	{
+		case EffectEvent_Constant: strcopy(sBuffer, iBufferLen, "constant");
+		case EffectEvent_HitPlayer: strcopy(sBuffer, iBufferLen, "boss_hitplayer");
+		case EffectEvent_PlayerSeesBoss: strcopy(sBuffer, iBufferLen, "boss_seenbyplayer");
+		default: strcopy(sBuffer, iBufferLen, "");
+	}
+}
+
+stock EffectType:GetEffectTypeFromString(const String:sType[])
+{
+	if (StrEqual(sType, "steam", false)) return EffectType_Steam;
+	if (StrEqual(sType, "dynamiclight", false)) return EffectType_DynamicLight;
+	return EffectType_Invalid;
+}
diff --git a/addons/sourcemod/scripting/rytp_horror/logging.sp b/addons/sourcemod/scripting/rytp_horror/logging.sp
index 3ba4d29..af3223b 100644
--- a/addons/sourcemod/scripting/rytp_horror/logging.sp
+++ b/addons/sourcemod/scripting/rytp_horror/logging.sp
@@ -1,27 +1,27 @@
-#if defined _sf2_logging_included
- #endinput
-#endif
-#define _sf2_logging_included
-
-static String:g_strLogFilePath[512] = "";
-
-InitializeLogging()
-{
-	decl String:sDateSuffix[256];
-	FormatTime(sDateSuffix, sizeof(sDateSuffix), "sf2-%Y-%m-%d.log", GetTime());
-	
-	BuildPath(Path_SM, g_strLogFilePath, sizeof(g_strLogFilePath), "logs/%s", sDateSuffix);
-	
-	decl String:sMap[64];
-	GetCurrentMap(sMap, sizeof(sMap));
-	
-	LogSF2Message("-------- Mapchange to %s -------", sMap);
-}
-
-stock LogSF2Message(const String:sMessage[], any:...)
-{
-	decl String:sLogMessage[1024], String:sTemp[1024];
-	VFormat(sTemp, sizeof(sTemp), sMessage, 2);
-	Format(sLogMessage, sizeof(sLogMessage), "%s", sTemp);
-	LogToFile(g_strLogFilePath, sLogMessage);
+#if defined _sf2_logging_included
+ #endinput
+#endif
+#define _sf2_logging_included
+
+static String:g_strLogFilePath[512] = "";
+
+InitializeLogging()
+{
+	decl String:sDateSuffix[256];
+	FormatTime(sDateSuffix, sizeof(sDateSuffix), "sf2-%Y-%m-%d.log", GetTime());
+	
+	BuildPath(Path_SM, g_strLogFilePath, sizeof(g_strLogFilePath), "logs/%s", sDateSuffix);
+	
+	decl String:sMap[64];
+	GetCurrentMap(sMap, sizeof(sMap));
+	
+	LogSF2Message("-------- Mapchange to %s -------", sMap);
+}
+
+stock LogSF2Message(const String:sMessage[], any:...)
+{
+	decl String:sLogMessage[1024], String:sTemp[1024];
+	VFormat(sTemp, sizeof(sTemp), sMessage, 2);
+	Format(sLogMessage, sizeof(sLogMessage), "%s", sTemp);
+	LogToFile(g_strLogFilePath, sLogMessage);
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/menus.sp b/addons/sourcemod/scripting/rytp_horror/menus.sp
index 94ecb5a..0416661 100644
--- a/addons/sourcemod/scripting/rytp_horror/menus.sp
+++ b/addons/sourcemod/scripting/rytp_horror/menus.sp
@@ -1,756 +1,840 @@
-#if defined _sf2_menus
- #endinput
-#endif
-
-#define _sf2_menus
-
-new Handle:g_hMenuMain;
-new Handle:g_hMenuVoteDifficulty;
-new Handle:g_hMenuGhostMode;
-new Handle:g_hMenuHelp;
-new Handle:g_hMenuHelpObjective;
-new Handle:g_hMenuHelpObjective2;
-new Handle:g_hMenuHelpCommands;
-new Handle:g_hMenuHelpGhostMode;
-new Handle:g_hMenuHelpSprinting;
-new Handle:g_hMenuHelpControls;
-new Handle:g_hMenuHelpClassInfo;
-new Handle:g_hMenuSettings;
-new Handle:g_hMenuCredits;
-new Handle:g_hMenuCredits2;
-
-#include "rytp_horror/playergroups/menus.sp"
-#include "rytp_horror/pvp/menus.sp"
-
-SetupMenus()
-{
-	decl String:buffer[512];
-	
-	// Create menus.
-	g_hMenuMain = CreateMenu(Menu_Main);
-	SetMenuTitle(g_hMenuMain, "%t%t\n \n", "SF2 Prefix", "SF2 Main Menu Title");
-	Format(buffer, sizeof(buffer), "%t (!slhelp)", "SF2 Help Menu Title");
-	AddMenuItem(g_hMenuMain, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t (!slnext)", "SF2 Queue Menu Title");
-	AddMenuItem(g_hMenuMain, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t (!slgroup)", "SF2 Group Main Menu Title");
-	AddMenuItem(g_hMenuMain, "0", buffer);
-	//Format(buffer, sizeof(buffer), "%t (!slghost)", "SF2 Ghost Mode Menu Title");
-	//AddMenuItem(g_hMenuMain, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t (!slsettings)", "SF2 Settings Menu Title");
-	AddMenuItem(g_hMenuMain, "0", buffer);
-	strcopy(buffer, sizeof(buffer), "Credits (!slcredits)");
-	AddMenuItem(g_hMenuMain, "0", buffer);
-	
-	g_hMenuVoteDifficulty = CreateMenu(Menu_VoteDifficulty);
-	SetMenuTitle(g_hMenuVoteDifficulty, "%t%t\n \n", "SF2 Prefix", "SF2 Difficulty Vote Menu Title");
-	Format(buffer, sizeof(buffer), "%t", "SF2 Normal Difficulty");
-	AddMenuItem(g_hMenuVoteDifficulty, "1", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Hard Difficulty");
-	AddMenuItem(g_hMenuVoteDifficulty, "2", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Insane Difficulty");
-	AddMenuItem(g_hMenuVoteDifficulty, "3", buffer);
-	
-	g_hMenuGhostMode = CreateMenu(Menu_GhostMode);
-	SetMenuTitle(g_hMenuGhostMode, "%t%t\n \n", "SF2 Prefix", "SF2 Ghost Mode Menu Title");
-	Format(buffer, sizeof(buffer), "Enable");
-	AddMenuItem(g_hMenuGhostMode, "0", buffer);
-	Format(buffer, sizeof(buffer), "Disable");
-	AddMenuItem(g_hMenuGhostMode, "1", buffer);
-	
-	g_hMenuHelp = CreateMenu(Menu_Help);
-	SetMenuTitle(g_hMenuHelp, "%t%t\n \n", "SF2 Prefix", "SF2 Help Menu Title");
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Objective Menu Title");
-	AddMenuItem(g_hMenuHelp, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Commands Menu Title");
-	AddMenuItem(g_hMenuHelp, "1", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Class Info Menu Title");
-	AddMenuItem(g_hMenuHelp, "2", buffer);
-	//Format(buffer, sizeof(buffer), "%t", "SF2 Help Ghost Mode Menu Title");
-	//AddMenuItem(g_hMenuHelp, "3", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Sprinting And Stamina Menu Title");
-	AddMenuItem(g_hMenuHelp, "3", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Controls Menu Title");
-	AddMenuItem(g_hMenuHelp, "4", buffer);
-	SetMenuExitBackButton(g_hMenuHelp, true);
-	
-	g_hMenuHelpObjective = CreateMenu(Menu_HelpObjective);
-	SetMenuTitle(g_hMenuHelpObjective, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Objective Menu Title", "SF2 Help Objective Description");
-	AddMenuItem(g_hMenuHelpObjective, "0", "Next");
-	AddMenuItem(g_hMenuHelpObjective, "1", "Back");
-	
-	g_hMenuHelpObjective2 = CreateMenu(Menu_HelpObjective2);
-	SetMenuTitle(g_hMenuHelpObjective2, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Objective Menu Title", "SF2 Help Objective Description 2");
-	AddMenuItem(g_hMenuHelpObjective2, "0", "Back");
-	
-	g_hMenuHelpCommands = CreateMenu(Menu_BackButtonOnly);
-	SetMenuTitle(g_hMenuHelpCommands, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Commands Menu Title", "SF2 Help Commands Description");
-	AddMenuItem(g_hMenuHelpCommands, "0", "Back");
-	
-	g_hMenuHelpGhostMode = CreateMenu(Menu_BackButtonOnly);
-	SetMenuTitle(g_hMenuHelpGhostMode, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Ghost Mode Menu Title", "SF2 Help Ghost Mode Description");
-	AddMenuItem(g_hMenuHelpGhostMode, "0", "Back");
-	
-	g_hMenuHelpSprinting = CreateMenu(Menu_BackButtonOnly);
-	SetMenuTitle(g_hMenuHelpSprinting, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Sprinting And Stamina Menu Title", "SF2 Help Sprinting And Stamina Description");
-	AddMenuItem(g_hMenuHelpSprinting, "0", "Back");
-	
-	g_hMenuHelpControls = CreateMenu(Menu_BackButtonOnly);
-	SetMenuTitle(g_hMenuHelpControls, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Controls Menu Title", "SF2 Help Controls Description");
-	AddMenuItem(g_hMenuHelpControls, "0", "Back");
-	
-	g_hMenuHelpClassInfo = CreateMenu(Menu_ClassInfo);
-	SetMenuTitle(g_hMenuHelpClassInfo, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Class Info Menu Title", "SF2 Help Class Info Description");
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Scout Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Scout", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Sniper Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Sniper", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Soldier Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Soldier", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Demoman Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Demoman", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Heavy Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Heavy", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Medic Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Medic", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Pyro Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Pyro", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Spy Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Spy", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Help Engineer Class Info Menu Title");
-	AddMenuItem(g_hMenuHelpClassInfo, "Engineer", buffer);
-	SetMenuExitBackButton(g_hMenuHelpClassInfo, true);
-	
-	g_hMenuSettings = CreateMenu(Menu_Settings);
-	SetMenuTitle(g_hMenuSettings, "%t%t\n \n", "SF2 Prefix", "SF2 Settings Menu Title");
-	//Format(buffer, sizeof(buffer), "%t", "SF2 Settings PvP Menu Title");
-	//AddMenuItem(g_hMenuSettings, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Hints Menu Title");
-	AddMenuItem(g_hMenuSettings, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Mute Mode Menu Title");
-	AddMenuItem(g_hMenuSettings, "0", buffer);
-	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Proxy Menu Title");
-	AddMenuItem(g_hMenuSettings, "0", buffer);
-	SetMenuExitBackButton(g_hMenuSettings, true);
-	
-	g_hMenuCredits = CreateMenu(Menu_Credits);
-	
-	Format(buffer, sizeof(buffer), "%tCredits\n \n", "SF2 Prefix");
-	StrCat(buffer, sizeof(buffer), "Coder: Kit o' Rifty\n");
-	StrCat(buffer, sizeof(buffer), "Version: ");
-	StrCat(buffer, sizeof(buffer), PLUGIN_VERSION);
-	StrCat(buffer, sizeof(buffer), "\n \n");
-	StrCat(buffer, sizeof(buffer), "Mark J. Hadley (AgentParsec) - The creator of the Slender game!\n");
-	StrCat(buffer, sizeof(buffer), "Mark Steen - Composing the intro music");
-	StrCat(buffer, sizeof(buffer), "Mammoth Mogul - for being a GREAT test subject\n");
-	StrCat(buffer, sizeof(buffer), "Egosins - for offering to host this publicly\n");
-	StrCat(buffer, sizeof(buffer), "Somberguy - suggestions and support\n");
-	StrCat(buffer, sizeof(buffer), "Omi-Box - materials, maps, current Slender Man model, and more!\n");
-	StrCat(buffer, sizeof(buffer), "Narry Gewman - imported first Slender Man model\n");
-	StrCat(buffer, sizeof(buffer), "Simply Delicious - for the awesome camera overlay!\n");
-	StrCat(buffer, sizeof(buffer), "Jason278 - Page models");
-	StrCat(buffer, sizeof(buffer), "\n \n");
-	
-	SetMenuTitle(g_hMenuCredits, buffer);
-	AddMenuItem(g_hMenuCredits, "0", "Next");
-	AddMenuItem(g_hMenuCredits, "1", "Back");
-	
-	g_hMenuCredits2 = CreateMenu(Menu_Credits2);
-	
-	Format(buffer, sizeof(buffer), "%tCredits\n \n", "SF2 Prefix");
-	StrCat(buffer, sizeof(buffer), "And to all the peeps who alpha-tested this thing!\n \n");
-	StrCat(buffer, sizeof(buffer), "Tofu\n");
-	StrCat(buffer, sizeof(buffer), "Ace-Dashie\n");
-	StrCat(buffer, sizeof(buffer), "Hobbes\n");
-	StrCat(buffer, sizeof(buffer), "Diskein\n");
-	StrCat(buffer, sizeof(buffer), "111112oo\n");
-	StrCat(buffer, sizeof(buffer), "Incoheriant Chipmunk\n");
-	StrCat(buffer, sizeof(buffer), "Shrow\n");
-	StrCat(buffer, sizeof(buffer), "Liquid Vita\n");
-	StrCat(buffer, sizeof(buffer), "Pinkle D Lies\n");
-	StrCat(buffer, sizeof(buffer), "Ultimatefry\n \n");
-	
-	SetMenuTitle(g_hMenuCredits2, buffer);
-	AddMenuItem(g_hMenuCredits2, "0", "Back");
-	
-	PvP_SetupMenus();
-}
-
-public Menu_Main(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuHelp, param1, 30);
-			case 1: DisplayQueuePointsMenu(param1);
-			case 2:	DisplayGroupMainMenuToClient(param1);
-			//case 3: DisplayMenu(g_hMenuGhostMode, param1, 30);
-			case 3: DisplayMenu(g_hMenuSettings, param1, 30);
-			case 4: DisplayMenu(g_hMenuCredits, param1, MENU_TIME_FOREVER);
-		}
-	}
-}
-
-public Menu_VoteDifficulty(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_VoteEnd)
-	{
-		decl String:sInfo[64], String:sDisplay[256], String:sColor[32];
-		GetMenuItem(menu, param1, sInfo, sizeof(sInfo), _, sDisplay, sizeof(sDisplay));
-		
-		if (IsSpecialRoundRunning() && 
-			(g_iSpecialRoundType == SPECIALROUND_INSANEDIFFICULTY/* || g_iSpecialRoundType == SPECIALROUND_DOUBLEMAXPLAYERS*/))
-		{
-			SetConVarInt(g_cvDifficulty, Difficulty_Insane);
-		}
-		else
-		{
-			SetConVarString(g_cvDifficulty, sInfo);
-		}
-		
-		new iDifficulty = GetConVarInt(g_cvDifficulty);
-		switch (iDifficulty)
-		{
-			case Difficulty_Easy:
-			{
-				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Easy Difficulty");
-				strcopy(sColor, sizeof(sColor), "{green}");
-			}
-			case Difficulty_Hard:
-			{
-				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Hard Difficulty");
-				strcopy(sColor, sizeof(sColor), "{orange}");
-			}
-			case Difficulty_Insane:
-			{
-				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Insane Difficulty");
-				strcopy(sColor, sizeof(sColor), "{red}");
-			}
-			default:
-			{
-				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Normal Difficulty");
-				strcopy(sColor, sizeof(sColor), "{yellow}");
-			}
-		}
-		
-		CPrintToChatAll("%t %s%s", "SF2 Difficulty Vote Finished", sColor, sDisplay);
-	}
-}
-
-public Menu_GhostMode(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		if (IsRoundEnding() ||
-			IsRoundInWarmup() ||
-			!g_bPlayerEliminated[param1] ||
-			!IsClientParticipating(param1) ||
-			g_bPlayerProxy[param1])
-		{
-			CPrintToChat(param1, "{red}%T", "SF2 Ghost Mode Not Allowed", param1);
-		}
-		else
-		{
-			switch (param2)
-			{
-				case 0:
-				{
-					if (IsClientInGhostMode(param1)) CPrintToChat(param1, "{red}%T", "SF2 Ghost Mode Enabled Already", param1);
-					else
-					{
-						TF2_RespawnPlayer(param1);
-						ClientSetGhostModeState(param1, true);
-						HandlePlayerHUD(param1);
-						
-						CPrintToChat(param1, "{olive}%T", "SF2 Ghost Mode Enabled", param1);
-					}
-				}
-				case 1:
-				{
-					if (!IsClientInGhostMode(param1)) CPrintToChat(param1, "{red}%T", "SF2 Ghost Mode Disabled Already", param1);
-					else
-					{
-						ClientSetGhostModeState(param1, false);
-						TF2_RespawnPlayer(param1);
-						
-						CPrintToChat(param1, "{olive}%T", "SF2 Ghost Mode Disabled", param1);
-					}
-				}
-			}
-		}
-	}
-}
-
-public Menu_Help(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuHelpObjective, param1, 30);
-			case 1: DisplayMenu(g_hMenuHelpCommands, param1, 30);
-			case 2: DisplayMenu(g_hMenuHelpClassInfo, param1, 30);
-			//case 3: DisplayMenu(g_hMenuHelpGhostMode, param1, 30);
-			case 3: DisplayMenu(g_hMenuHelpSprinting, param1, 30);
-			case 4: DisplayMenu(g_hMenuHelpControls, param1, 30);
-		}
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayMenu(g_hMenuMain, param1, 30);
-		}
-	}
-}
-
-public Menu_HelpObjective(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuHelpObjective2, param1, 30);
-			case 1: DisplayMenu(g_hMenuHelp, param1, 30);
-		}
-	}
-}
-
-public Menu_HelpObjective2(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuHelpObjective, param1, 30);
-		}
-	}
-}
-
-public Menu_BackButtonOnly(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuHelp, param1, 30);
-		}
-	}
-}
-
-public Menu_Credits(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuCredits2, param1, MENU_TIME_FOREVER);
-			case 1: DisplayMenu(g_hMenuMain, param1, 30);
-		}
-	}
-}
-
-public Menu_ClassInfo(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayMenu(g_hMenuMain, param1, 30);
-		}
-	}
-	else if (action == MenuAction_Select)
-	{
-		decl String:sInfo[64];
-		GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
-		
-		new Handle:hMenu = CreateMenu(Menu_ClassInfoBackOnly);
-		
-		decl String:sTitle[64], String:sDescription[64];
-		Format(sTitle, sizeof(sTitle), "SF2 Help %s Class Info Menu Title", sInfo);
-		Format(sDescription, sizeof(sDescription), "SF2 Help %s Class Info Description", sInfo);
-		
-		SetMenuTitle(hMenu, "%t%t\n \n%t\n \n", "SF2 Prefix", sTitle, sDescription);
-		AddMenuItem(hMenu, "0", "Back");
-		DisplayMenu(hMenu, param1, 30);
-	}
-}
-
-public Menu_ClassInfoBackOnly(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End)
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Select)
-	{
-		DisplayMenu(g_hMenuHelpClassInfo, param1, 30);
-	}
-}
-
-public Menu_Settings(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			//case 0: DisplayMenu(g_hMenuSettingsPvP, param1, 30);
-			case 0:
-			{
-				decl String:sBuffer[512];
-				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Hints Menu Title", param1);
-				
-				new Handle:hPanel = CreatePanel();
-				SetPanelTitle(hPanel, sBuffer);
-				
-				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
-				DrawPanelItem(hPanel, sBuffer);
-				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
-				DrawPanelItem(hPanel, sBuffer);
-				
-				SendPanelToClient(hPanel, param1, Panel_SettingsHints, 30);
-				CloseHandle(hPanel);
-			}
-			case 1:
-			{
-				decl String:sBuffer[512];
-				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Mute Mode Menu Title", param1);
-				
-				new Handle:hPanel = CreatePanel();
-				SetPanelTitle(hPanel, sBuffer);
-				
-				DrawPanelItem(hPanel, "Normal");
-				DrawPanelItem(hPanel, "Mute opposing team");
-				DrawPanelItem(hPanel, "Mute opposing team except when I'm a proxy");
-				
-				SendPanelToClient(hPanel, param1, Panel_SettingsMuteMode, 30);
-				CloseHandle(hPanel);
-			}
-			case 2:
-			{
-				decl String:sBuffer[512];
-				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Proxy Menu Title", param1);
-				
-				new Handle:hPanel = CreatePanel();
-				SetPanelTitle(hPanel, sBuffer);
-				
-				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
-				DrawPanelItem(hPanel, sBuffer);
-				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
-				DrawPanelItem(hPanel, sBuffer);
-				
-				SendPanelToClient(hPanel, param1, Panel_SettingsProxy, 30);
-				CloseHandle(hPanel);
-			}
-		}
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayMenu(g_hMenuMain, param1, 30);
-		}
-	}
-}
-
-public Panel_SettingsHints(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 1:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_ShowHints] = true;
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "%T", "SF2 Enabled Hints", param1);
-			}
-			case 2:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_ShowHints] = false;
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "%T", "SF2 Disabled Hints", param1);
-			}
-		}
-		
-		DisplayMenu(g_hMenuSettings, param1, 30);
-	}
-}
-
-public Panel_SettingsProxy(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 1:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_EnableProxySelection] = true;
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "%T", "SF2 Enabled Proxy", param1);
-			}
-			case 2:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_EnableProxySelection] = false;
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "%T", "SF2 Disabled Proxy", param1);
-			}
-		}
-		
-		DisplayMenu(g_hMenuSettings, param1, 30);
-	}
-}
-
-public Panel_SettingsMuteMode(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 1:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_MuteMode] = MuteMode_Normal;
-				ClientUpdateListeningFlags(param1);
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "{lightgreen}Mute mode set to normal.");
-			}
-			case 2:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_MuteMode] = MuteMode_DontHearOtherTeam;
-				ClientUpdateListeningFlags(param1);
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "{lightgreen}Muted opposing team.");
-			}
-			case 3:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_MuteMode] = MuteMode_DontHearOtherTeamIfNotProxy;
-				ClientUpdateListeningFlags(param1);
-				ClientSaveCookies(param1);
-				CPrintToChat(param1, "{lightgreen}Muted opposing team, but settings will be automatically set to normal if you're a proxy.");
-			}
-		}
-		
-		DisplayMenu(g_hMenuSettings, param1, 30);
-	}
-}
-
-public Menu_Credits2(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayMenu(g_hMenuCredits, param1, MENU_TIME_FOREVER);
-		}
-	}
-}
-
-DisplayQueuePointsMenu(client)
-{
-	new Handle:menu = CreateMenu(Menu_QueuePoints);
-	new Handle:hQueueList = GetQueueList();
-	
-	decl String:sBuffer[256];
-	
-	if (GetArraySize(hQueueList))
-	{
-		Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Reset Queue Points Option", client, g_iPlayerQueuePoints[client]);
-		AddMenuItem(menu, "ponyponypony", sBuffer);
-		
-		decl iIndex, String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-		decl String:sInfo[256];
-		
-		for (new i = 0, iSize = GetArraySize(hQueueList); i < iSize; i++)
-		{
-			if (!GetArrayCell(hQueueList, i, 2))
-			{
-				iIndex = GetArrayCell(hQueueList, i);
-				
-				Format(sBuffer, sizeof(sBuffer), "%N - %d", iIndex, g_iPlayerQueuePoints[iIndex]);
-				Format(sInfo, sizeof(sInfo), "player_%d", GetClientUserId(iIndex));
-				AddMenuItem(menu, sInfo, sBuffer, g_bPlayerPlaying[iIndex] ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
-			}
-			else
-			{
-				iIndex = GetArrayCell(hQueueList, i);
-				if (GetPlayerGroupMemberCount(iIndex) > 1)
-				{
-					GetPlayerGroupName(iIndex, sGroupName, sizeof(sGroupName));
-					
-					Format(sBuffer, sizeof(sBuffer), "[GROUP] %s - %d", sGroupName, GetPlayerGroupQueuePoints(iIndex));
-					Format(sInfo, sizeof(sInfo), "group_%d", iIndex);
-					AddMenuItem(menu, sInfo, sBuffer, IsPlayerGroupPlaying(iIndex) ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
-				}
-				else
-				{
-					for (new iClient = 1; iClient <= MaxClients; iClient++)
-					{
-						if (!IsValidClient(iClient)) continue;
-						if (ClientGetPlayerGroup(iClient) == iIndex)
-						{
-							Format(sBuffer, sizeof(sBuffer), "%N - %d", iClient, g_iPlayerQueuePoints[iClient]);
-							Format(sInfo, sizeof(sInfo), "player_%d", GetClientUserId(iClient));
-							AddMenuItem(menu, "player", sBuffer, g_bPlayerPlaying[iClient] ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
-							break;
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	CloseHandle(hQueueList);
-	
-	SetMenuTitle(menu, "%t%T\n \n", "SF2 Prefix", "SF2 Queue Menu Title", client);
-	SetMenuExitBackButton(menu, true);
-	DisplayMenu(menu, client, MENU_TIME_FOREVER);
-}
-
-DisplayViewGroupMembersQueueMenu(client, iGroupIndex)
-{
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// The group isn't valid anymore. Take him back to the main menu.
-		DisplayQueuePointsMenu(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	new Handle:hPlayers = CreateArray();
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		
-		new iTempGroup = ClientGetPlayerGroup(i);
-		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
-		
-		PushArrayCell(hPlayers, i);
-	}
-	
-	new iPlayerCount = GetArraySize(hPlayers);
-	if (iPlayerCount)
-	{
-		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-		GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-		
-		new Handle:hMenu = CreateMenu(Menu_ViewGroupMembersQueue);
-		SetMenuTitle(hMenu, "%t%T (%s)\n \n", "SF2 Prefix", "SF2 View Group Members Menu Title", client, sGroupName);
-		
-		decl String:sUserId[32];
-		decl String:sName[MAX_NAME_LENGTH * 2];
-		
-		for (new i = 0; i < iPlayerCount; i++)
-		{
-			new iClient = GetArrayCell(hPlayers, i);
-			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
-			GetClientName(iClient, sName, sizeof(sName));
-			if (GetPlayerGroupLeader(iGroupIndex) == iClient) StrCat(sName, sizeof(sName), " (LEADER)");
-			
-			AddMenuItem(hMenu, sUserId, sName);
-		}
-		
-		SetMenuExitBackButton(hMenu, true);
-		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-	}
-	else
-	{
-		// No players!
-		DisplayQueuePointsMenu(client);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public Menu_ViewGroupMembersQueue(Handle:menu, MenuAction:action, param1, param2)
-{
-	switch (action)
-	{
-		case MenuAction_End: CloseHandle(menu);
-		case MenuAction_Select: DisplayQueuePointsMenu(param1);
-		case MenuAction_Cancel:
-		{
-			if (param2 == MenuCancel_ExitBack) DisplayQueuePointsMenu(param1);
-		}
-	}
-}
-
-DisplayResetQueuePointsMenu(client)
-{
-	decl String:buffer[256];
-
-	new Handle:menu = CreateMenu(Menu_ResetQueuePoints);
-	Format(buffer, sizeof(buffer), "%T", "Yes", client);
-	AddMenuItem(menu, "0", buffer);
-	Format(buffer, sizeof(buffer), "%T", "No", client);
-	AddMenuItem(menu, "1", buffer);
-	SetMenuTitle(menu, "%T\n \n", "SF2 Should Reset Queue Points", client);
-	DisplayMenu(menu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_QueuePoints(Handle:menu, MenuAction:action, param1, param2)
-{
-	switch (action)
-	{
-		case MenuAction_Select:
-		{
-			new String:sInfo[64];
-			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
-			
-			if (StrEqual(sInfo, "ponyponypony")) DisplayResetQueuePointsMenu(param1);
-			else if (!StrContains(sInfo, "player_"))
-			{
-			}
-			else if (!StrContains(sInfo, "group_"))
-			{
-				decl String:sIndex[64];
-				strcopy(sIndex, sizeof(sIndex), sInfo);
-				ReplaceString(sIndex, sizeof(sIndex), "group_", "");
-				DisplayViewGroupMembersQueueMenu(param1, StringToInt(sIndex));
-			}
-		}
-		case MenuAction_Cancel:
-		{
-			if (param2 == MenuCancel_ExitBack)
-			{
-				DisplayMenu(g_hMenuMain, param1, 30);
-			}
-		}
-		case MenuAction_End: CloseHandle(menu);
-	}
-}
-
-public Menu_ResetQueuePoints(Handle:menu, MenuAction:action, param1, param2)
-{
-	switch (action)
-	{
-		case MenuAction_Select:
-		{
-			switch (param2)
-			{
-				case 0:
-				{
-					ClientSetQueuePoints(param1, 0);
-					CPrintToChat(param1, "{olive}%T", "SF2 Queue Points Reset", param1);
-					
-					// Special round.
-					if (IsSpecialRoundRunning()) 
-					{
-						SetClientPlaySpecialRoundState(param1, true);
-					}
-					
-					// new boss round
-					if (IsNewBossRoundRunning()) 
-					{
-						// If the player resets the queue points ignore them when checking for players that haven't played the new boss yet, if applicable.
-						SetClientPlayNewBossRoundState(param1, true);
-					}
-				}
-			}
-			
-			DisplayQueuePointsMenu(param1);
-		}
-		
-		case MenuAction_End: CloseHandle(menu);
-	}
+#if defined _sf2_menus
+ #endinput
+#endif
+
+#define _sf2_menus
+
+new Handle:g_hMenuMain;
+new Handle:g_hMenuVoteDifficulty;
+new Handle:g_hMenuGhostMode;
+new Handle:g_hMenuHelp;
+new Handle:g_hMenuHelpObjective;
+new Handle:g_hMenuHelpObjective2;
+new Handle:g_hMenuHelpCommands;
+new Handle:g_hMenuHelpGhostMode;
+new Handle:g_hMenuHelpSprinting;
+new Handle:g_hMenuHelpControls;
+new Handle:g_hMenuHelpClassInfo;
+new Handle:g_hMenuSettings;
+new Handle:g_hMenuCredits;
+new Handle:g_hMenuCredits2;
+
+#include "rytp_horror/playergroups/menus.sp"
+#include "rytp_horror/pvp/menus.sp"
+
+SetupMenus()
+{
+	decl String:buffer[512];
+	
+	// Create menus.
+	g_hMenuMain = CreateMenu(Menu_Main);
+	SetMenuTitle(g_hMenuMain, "%t%t\n \n", "SF2 Prefix", "SF2 Main Menu Title");
+	Format(buffer, sizeof(buffer), "%t (!slhelp)", "SF2 Help Menu Title");
+	AddMenuItem(g_hMenuMain, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t (!slnext)", "SF2 Queue Menu Title");
+	AddMenuItem(g_hMenuMain, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t (!slgroup)", "SF2 Group Main Menu Title");
+	AddMenuItem(g_hMenuMain, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t (!slghost)", "SF2 Ghost Mode Menu Title");
+	AddMenuItem(g_hMenuMain, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t (!slsettings)", "SF2 Settings Menu Title");
+	AddMenuItem(g_hMenuMain, "0", buffer);
+	strcopy(buffer, sizeof(buffer), "Credits (!slcredits)");
+	AddMenuItem(g_hMenuMain, "0", buffer);
+	
+	g_hMenuVoteDifficulty = CreateMenu(Menu_VoteDifficulty);
+	SetMenuTitle(g_hMenuVoteDifficulty, "%t%t\n \n", "SF2 Prefix", "SF2 Difficulty Vote Menu Title");
+	Format(buffer, sizeof(buffer), "%t", "SF2 Normal Difficulty");
+	AddMenuItem(g_hMenuVoteDifficulty, "1", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Hard Difficulty");
+	AddMenuItem(g_hMenuVoteDifficulty, "2", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Insane Difficulty");
+	AddMenuItem(g_hMenuVoteDifficulty, "3", buffer);
+	
+	g_hMenuGhostMode = CreateMenu(Menu_GhostMode);
+	SetMenuTitle(g_hMenuGhostMode, "%t%t\n \n", "SF2 Prefix", "SF2 Ghost Mode Menu Title");
+	Format(buffer, sizeof(buffer), "Enable");
+	AddMenuItem(g_hMenuGhostMode, "0", buffer);
+	Format(buffer, sizeof(buffer), "Disable");
+	AddMenuItem(g_hMenuGhostMode, "1", buffer);
+	
+	g_hMenuHelp = CreateMenu(Menu_Help);
+	SetMenuTitle(g_hMenuHelp, "%t%t\n \n", "SF2 Prefix", "SF2 Help Menu Title");
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Objective Menu Title");
+	AddMenuItem(g_hMenuHelp, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Commands Menu Title");
+	AddMenuItem(g_hMenuHelp, "1", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Class Info Menu Title");
+	AddMenuItem(g_hMenuHelp, "2", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Ghost Mode Menu Title");
+	AddMenuItem(g_hMenuHelp, "3", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Sprinting And Stamina Menu Title");
+	AddMenuItem(g_hMenuHelp, "4", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Controls Menu Title");
+	AddMenuItem(g_hMenuHelp, "5", buffer);
+	SetMenuExitBackButton(g_hMenuHelp, true);
+	
+	g_hMenuHelpObjective = CreateMenu(Menu_HelpObjective);
+	SetMenuTitle(g_hMenuHelpObjective, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Objective Menu Title", "SF2 Help Objective Description");
+	AddMenuItem(g_hMenuHelpObjective, "0", "Next");
+	AddMenuItem(g_hMenuHelpObjective, "1", "Back");
+	
+	g_hMenuHelpObjective2 = CreateMenu(Menu_HelpObjective2);
+	SetMenuTitle(g_hMenuHelpObjective2, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Objective Menu Title", "SF2 Help Objective Description 2");
+	AddMenuItem(g_hMenuHelpObjective2, "0", "Back");
+	
+	g_hMenuHelpCommands = CreateMenu(Menu_BackButtonOnly);
+	SetMenuTitle(g_hMenuHelpCommands, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Commands Menu Title", "SF2 Help Commands Description");
+	AddMenuItem(g_hMenuHelpCommands, "0", "Back");
+	
+	g_hMenuHelpGhostMode = CreateMenu(Menu_BackButtonOnly);
+	SetMenuTitle(g_hMenuHelpGhostMode, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Ghost Mode Menu Title", "SF2 Help Ghost Mode Description");
+	AddMenuItem(g_hMenuHelpGhostMode, "0", "Back");
+	
+	g_hMenuHelpSprinting = CreateMenu(Menu_BackButtonOnly);
+	SetMenuTitle(g_hMenuHelpSprinting, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Sprinting And Stamina Menu Title", "SF2 Help Sprinting And Stamina Description");
+	AddMenuItem(g_hMenuHelpSprinting, "0", "Back");
+	
+	g_hMenuHelpControls = CreateMenu(Menu_BackButtonOnly);
+	SetMenuTitle(g_hMenuHelpControls, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Controls Menu Title", "SF2 Help Controls Description");
+	AddMenuItem(g_hMenuHelpControls, "0", "Back");
+	
+	g_hMenuHelpClassInfo = CreateMenu(Menu_ClassInfo);
+	SetMenuTitle(g_hMenuHelpClassInfo, "%t%t\n \n%t\n \n", "SF2 Prefix", "SF2 Help Class Info Menu Title", "SF2 Help Class Info Description");
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Scout Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Scout", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Sniper Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Sniper", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Soldier Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Soldier", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Demoman Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Demoman", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Heavy Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Heavy", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Medic Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Medic", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Pyro Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Pyro", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Spy Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Spy", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Help Engineer Class Info Menu Title");
+	AddMenuItem(g_hMenuHelpClassInfo, "Engineer", buffer);
+	SetMenuExitBackButton(g_hMenuHelpClassInfo, true);
+	
+	g_hMenuSettings = CreateMenu(Menu_Settings);
+	SetMenuTitle(g_hMenuSettings, "%t%t\n \n", "SF2 Prefix", "SF2 Settings Menu Title");
+	Format(buffer, sizeof(buffer), "%t", "SF2 Settings PvP Menu Title");
+	AddMenuItem(g_hMenuSettings, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Hints Menu Title");
+	AddMenuItem(g_hMenuSettings, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Mute Mode Menu Title");
+	AddMenuItem(g_hMenuSettings, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Film Grain Menu Title");
+	AddMenuItem(g_hMenuSettings, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Proxy Menu Title");
+	AddMenuItem(g_hMenuSettings, "0", buffer);
+	Format(buffer, sizeof(buffer), "%t", "SF2 Settings Ghost Overlay Menu Title");
+	AddMenuItem(g_hMenuSettings, "0", buffer);
+	SetMenuExitBackButton(g_hMenuSettings, true);
+	
+	g_hMenuCredits = CreateMenu(Menu_Credits);
+	
+	Format(buffer, sizeof(buffer), "%tCredits\n \n", "SF2 Prefix");
+	StrCat(buffer, sizeof(buffer), "Coder: Kit o' Rifty\n");
+	StrCat(buffer, sizeof(buffer), "Version: ");
+	StrCat(buffer, sizeof(buffer), PLUGIN_VERSION);
+	StrCat(buffer, sizeof(buffer), "\n \n");
+	StrCat(buffer, sizeof(buffer), "Mark J. Hadley (AgentParsec) - The creator of the Slender game!\n");
+	StrCat(buffer, sizeof(buffer), "Mark Steen - Composing the intro music");
+	StrCat(buffer, sizeof(buffer), "Mammoth Mogul - for being a GREAT test subject\n");
+	StrCat(buffer, sizeof(buffer), "Egosins - for offering to host this publicly\n");
+	StrCat(buffer, sizeof(buffer), "Somberguy - suggestions and support\n");
+	StrCat(buffer, sizeof(buffer), "Omi-Box - materials, maps, current Slender Man model, and more!\n");
+	StrCat(buffer, sizeof(buffer), "Narry Gewman - imported first Slender Man model\n");
+	StrCat(buffer, sizeof(buffer), "Simply Delicious - for the awesome camera overlay!\n");
+	StrCat(buffer, sizeof(buffer), "Jason278 - Page models");
+	StrCat(buffer, sizeof(buffer), "\n \n");
+	
+	SetMenuTitle(g_hMenuCredits, buffer);
+	AddMenuItem(g_hMenuCredits, "0", "Next");
+	AddMenuItem(g_hMenuCredits, "1", "Back");
+	
+	g_hMenuCredits2 = CreateMenu(Menu_Credits2);
+	
+	Format(buffer, sizeof(buffer), "%tCredits\n \n", "SF2 Prefix");
+	StrCat(buffer, sizeof(buffer), "And to all the peeps who alpha-tested this thing!\n \n");
+	StrCat(buffer, sizeof(buffer), "Tofu\n");
+	StrCat(buffer, sizeof(buffer), "Ace-Dashie\n");
+	StrCat(buffer, sizeof(buffer), "Hobbes\n");
+	StrCat(buffer, sizeof(buffer), "Diskein\n");
+	StrCat(buffer, sizeof(buffer), "111112oo\n");
+	StrCat(buffer, sizeof(buffer), "Incoheriant Chipmunk\n");
+	StrCat(buffer, sizeof(buffer), "Shrow\n");
+	StrCat(buffer, sizeof(buffer), "Liquid Vita\n");
+	StrCat(buffer, sizeof(buffer), "Pinkle D Lies\n");
+	StrCat(buffer, sizeof(buffer), "Ultimatefry\n \n");
+	
+	SetMenuTitle(g_hMenuCredits2, buffer);
+	AddMenuItem(g_hMenuCredits2, "0", "Back");
+	
+	PvP_SetupMenus();
+}
+
+public Menu_Main(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuHelp, param1, 30);
+			case 1: DisplayQueuePointsMenu(param1);
+			case 2:	DisplayGroupMainMenuToClient(param1);
+			case 3: DisplayMenu(g_hMenuGhostMode, param1, 30);
+			case 4: DisplayMenu(g_hMenuSettings, param1, 30);
+			case 5: DisplayMenu(g_hMenuCredits, param1, MENU_TIME_FOREVER);
+		}
+	}
+}
+
+public Menu_VoteDifficulty(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_VoteEnd)
+	{
+		decl String:sInfo[64], String:sDisplay[256], String:sColor[32];
+		GetMenuItem(menu, param1, sInfo, sizeof(sInfo), _, sDisplay, sizeof(sDisplay));
+		
+		if (IsSpecialRoundRunning() && 
+			(g_iSpecialRoundType == SPECIALROUND_INSANEDIFFICULTY || g_iSpecialRoundType == SPECIALROUND_DOUBLEMAXPLAYERS))
+		{
+			SetConVarInt(g_cvDifficulty, Difficulty_Insane);
+		}
+		else
+		{
+			SetConVarString(g_cvDifficulty, sInfo);
+		}
+		
+		new iDifficulty = GetConVarInt(g_cvDifficulty);
+		switch (iDifficulty)
+		{
+			case Difficulty_Easy:
+			{
+				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Easy Difficulty");
+				strcopy(sColor, sizeof(sColor), "{green}");
+			}
+			case Difficulty_Hard:
+			{
+				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Hard Difficulty");
+				strcopy(sColor, sizeof(sColor), "{orange}");
+			}
+			case Difficulty_Insane:
+			{
+				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Insane Difficulty");
+				strcopy(sColor, sizeof(sColor), "{red}");
+			}
+			default:
+			{
+				Format(sDisplay, sizeof(sDisplay), "%t", "SF2 Normal Difficulty");
+				strcopy(sColor, sizeof(sColor), "{yellow}");
+			}
+		}
+		
+		CPrintToChatAll("%t %s%s", "SF2 Difficulty Vote Finished", sColor, sDisplay);
+	}
+}
+
+public Menu_GhostMode(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		if (IsRoundEnding() ||
+			IsRoundInWarmup() ||
+			!g_bPlayerEliminated[param1] ||
+			!IsClientParticipating(param1) ||
+			g_bPlayerProxy[param1])
+		{
+			CPrintToChat(param1, "{red}%T", "SF2 Ghost Mode Not Allowed", param1);
+		}
+		else
+		{
+			switch (param2)
+			{
+				case 0:
+				{
+					if (IsClientInGhostMode(param1)) CPrintToChat(param1, "{red}%T", "SF2 Ghost Mode Enabled Already", param1);
+					else
+					{
+						TF2_RespawnPlayer(param1);
+						ClientSetGhostModeState(param1, true);
+						HandlePlayerHUD(param1);
+						
+						CPrintToChat(param1, "{olive}%T", "SF2 Ghost Mode Enabled", param1);
+					}
+				}
+				case 1:
+				{
+					if (!IsClientInGhostMode(param1)) CPrintToChat(param1, "{red}%T", "SF2 Ghost Mode Disabled Already", param1);
+					else
+					{
+						ClientSetGhostModeState(param1, false);
+						TF2_RespawnPlayer(param1);
+						
+						CPrintToChat(param1, "{olive}%T", "SF2 Ghost Mode Disabled", param1);
+					}
+				}
+			}
+		}
+	}
+}
+
+public Menu_Help(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuHelpObjective, param1, 30);
+			case 1: DisplayMenu(g_hMenuHelpCommands, param1, 30);
+			case 2: DisplayMenu(g_hMenuHelpClassInfo, param1, 30);
+			case 3: DisplayMenu(g_hMenuHelpGhostMode, param1, 30);
+			case 4: DisplayMenu(g_hMenuHelpSprinting, param1, 30);
+			case 5: DisplayMenu(g_hMenuHelpControls, param1, 30);
+		}
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayMenu(g_hMenuMain, param1, 30);
+		}
+	}
+}
+
+public Menu_HelpObjective(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuHelpObjective2, param1, 30);
+			case 1: DisplayMenu(g_hMenuHelp, param1, 30);
+		}
+	}
+}
+
+public Menu_HelpObjective2(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuHelpObjective, param1, 30);
+		}
+	}
+}
+
+public Menu_BackButtonOnly(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuHelp, param1, 30);
+		}
+	}
+}
+
+public Menu_Credits(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuCredits2, param1, MENU_TIME_FOREVER);
+			case 1: DisplayMenu(g_hMenuMain, param1, 30);
+		}
+	}
+}
+
+public Menu_ClassInfo(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayMenu(g_hMenuMain, param1, 30);
+		}
+	}
+	else if (action == MenuAction_Select)
+	{
+		decl String:sInfo[64];
+		GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
+		
+		new Handle:hMenu = CreateMenu(Menu_ClassInfoBackOnly);
+		
+		decl String:sTitle[64], String:sDescription[64];
+		Format(sTitle, sizeof(sTitle), "SF2 Help %s Class Info Menu Title", sInfo);
+		Format(sDescription, sizeof(sDescription), "SF2 Help %s Class Info Description", sInfo);
+		
+		SetMenuTitle(hMenu, "%t%t\n \n%t\n \n", "SF2 Prefix", sTitle, sDescription);
+		AddMenuItem(hMenu, "0", "Back");
+		DisplayMenu(hMenu, param1, 30);
+	}
+}
+
+public Menu_ClassInfoBackOnly(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End)
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Select)
+	{
+		DisplayMenu(g_hMenuHelpClassInfo, param1, 30);
+	}
+}
+
+public Menu_Settings(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuSettingsPvP, param1, 30);
+			case 1:
+			{
+				decl String:sBuffer[512];
+				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Hints Menu Title", param1);
+				
+				new Handle:hPanel = CreatePanel();
+				SetPanelTitle(hPanel, sBuffer);
+				
+				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				
+				SendPanelToClient(hPanel, param1, Panel_SettingsHints, 30);
+				CloseHandle(hPanel);
+			}
+			case 2:
+			{
+				decl String:sBuffer[512];
+				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Mute Mode Menu Title", param1);
+				
+				new Handle:hPanel = CreatePanel();
+				SetPanelTitle(hPanel, sBuffer);
+				
+				DrawPanelItem(hPanel, "Normal");
+				DrawPanelItem(hPanel, "Mute opposing team");
+				DrawPanelItem(hPanel, "Mute opposing team except when I'm a proxy");
+				
+				SendPanelToClient(hPanel, param1, Panel_SettingsMuteMode, 30);
+				CloseHandle(hPanel);
+			}
+			case 3:
+			{
+				decl String:sBuffer[512];
+				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Film Grain Menu Title", param1);
+				
+				new Handle:hPanel = CreatePanel();
+				SetPanelTitle(hPanel, sBuffer);
+				
+				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				
+				SendPanelToClient(hPanel, param1, Panel_SettingsFilmGrain, 30);
+				CloseHandle(hPanel);
+			}
+			case 4:
+			{
+				decl String:sBuffer[512];
+				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Proxy Menu Title", param1);
+				
+				new Handle:hPanel = CreatePanel();
+				SetPanelTitle(hPanel, sBuffer);
+				
+				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				
+				SendPanelToClient(hPanel, param1, Panel_SettingsProxy, 30);
+				CloseHandle(hPanel);
+			}
+			case 5:
+			{
+				decl String:sBuffer[512];
+				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings Ghost Overlay Menu Title", param1);
+				
+				new Handle:hPanel = CreatePanel();
+				SetPanelTitle(hPanel, sBuffer);
+				
+				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				
+				SendPanelToClient(hPanel, param1, Panel_SettingsGhostOverlay, 30);
+				CloseHandle(hPanel);
+			}
+		}
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayMenu(g_hMenuMain, param1, 30);
+		}
+	}
+}
+
+public Panel_SettingsFilmGrain(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 1:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_FilmGrain] = true;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Enabled Film Grain", param1);
+			}
+			case 2:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_FilmGrain] = false;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Disabled Film Grain", param1);
+			}
+		}
+		
+		DisplayMenu(g_hMenuSettings, param1, 30);
+	}
+}
+
+public Panel_SettingsHints(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 1:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_ShowHints] = true;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Enabled Hints", param1);
+			}
+			case 2:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_ShowHints] = false;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Disabled Hints", param1);
+			}
+		}
+		
+		DisplayMenu(g_hMenuSettings, param1, 30);
+	}
+}
+
+public Panel_SettingsProxy(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 1:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_EnableProxySelection] = true;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Enabled Proxy", param1);
+			}
+			case 2:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_EnableProxySelection] = false;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Disabled Proxy", param1);
+			}
+		}
+		
+		DisplayMenu(g_hMenuSettings, param1, 30);
+	}
+}
+
+public Panel_SettingsGhostOverlay(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 1:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_GhostOverlay] = true;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Enabled Ghost Overlay", param1);
+			}
+			case 2:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_GhostOverlay] = false;
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "%T", "SF2 Disabled Ghost Overlay", param1);
+			}
+		}
+		
+		DisplayMenu(g_hMenuSettings, param1, 30);
+	}
+}
+
+public Panel_SettingsMuteMode(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 1:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_MuteMode] = MuteMode_Normal;
+				ClientUpdateListeningFlags(param1);
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "{lightgreen}Mute mode set to normal.");
+			}
+			case 2:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_MuteMode] = MuteMode_DontHearOtherTeam;
+				ClientUpdateListeningFlags(param1);
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "{lightgreen}Muted opposing team.");
+			}
+			case 3:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_MuteMode] = MuteMode_DontHearOtherTeamIfNotProxy;
+				ClientUpdateListeningFlags(param1);
+				ClientSaveCookies(param1);
+				CPrintToChat(param1, "{lightgreen}Muted opposing team, but settings will be automatically set to normal if you're a proxy.");
+			}
+		}
+		
+		DisplayMenu(g_hMenuSettings, param1, 30);
+	}
+}
+
+public Menu_Credits2(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayMenu(g_hMenuCredits, param1, MENU_TIME_FOREVER);
+		}
+	}
+}
+
+DisplayQueuePointsMenu(client)
+{
+	new Handle:menu = CreateMenu(Menu_QueuePoints);
+	new Handle:hQueueList = GetQueueList();
+	
+	decl String:sBuffer[256];
+	
+	if (GetArraySize(hQueueList))
+	{
+		Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Reset Queue Points Option", client, g_iPlayerQueuePoints[client]);
+		AddMenuItem(menu, "ponyponypony", sBuffer);
+		
+		decl iIndex, String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+		decl String:sInfo[256];
+		
+		for (new i = 0, iSize = GetArraySize(hQueueList); i < iSize; i++)
+		{
+			if (!GetArrayCell(hQueueList, i, 2))
+			{
+				iIndex = GetArrayCell(hQueueList, i);
+				
+				Format(sBuffer, sizeof(sBuffer), "%N - %d", iIndex, g_iPlayerQueuePoints[iIndex]);
+				Format(sInfo, sizeof(sInfo), "player_%d", GetClientUserId(iIndex));
+				AddMenuItem(menu, sInfo, sBuffer, g_bPlayerPlaying[iIndex] ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
+			}
+			else
+			{
+				iIndex = GetArrayCell(hQueueList, i);
+				if (GetPlayerGroupMemberCount(iIndex) > 1)
+				{
+					GetPlayerGroupName(iIndex, sGroupName, sizeof(sGroupName));
+					
+					Format(sBuffer, sizeof(sBuffer), "[GROUP] %s - %d", sGroupName, GetPlayerGroupQueuePoints(iIndex));
+					Format(sInfo, sizeof(sInfo), "group_%d", iIndex);
+					AddMenuItem(menu, sInfo, sBuffer, IsPlayerGroupPlaying(iIndex) ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
+				}
+				else
+				{
+					for (new iClient = 1; iClient <= MaxClients; iClient++)
+					{
+						if (!IsValidClient(iClient)) continue;
+						if (ClientGetPlayerGroup(iClient) == iIndex)
+						{
+							Format(sBuffer, sizeof(sBuffer), "%N - %d", iClient, g_iPlayerQueuePoints[iClient]);
+							Format(sInfo, sizeof(sInfo), "player_%d", GetClientUserId(iClient));
+							AddMenuItem(menu, "player", sBuffer, g_bPlayerPlaying[iClient] ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
+							break;
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	CloseHandle(hQueueList);
+	
+	SetMenuTitle(menu, "%t%T\n \n", "SF2 Prefix", "SF2 Queue Menu Title", client);
+	SetMenuExitBackButton(menu, true);
+	DisplayMenu(menu, client, MENU_TIME_FOREVER);
+}
+
+DisplayViewGroupMembersQueueMenu(client, iGroupIndex)
+{
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// The group isn't valid anymore. Take him back to the main menu.
+		DisplayQueuePointsMenu(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	new Handle:hPlayers = CreateArray();
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		
+		new iTempGroup = ClientGetPlayerGroup(i);
+		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
+		
+		PushArrayCell(hPlayers, i);
+	}
+	
+	new iPlayerCount = GetArraySize(hPlayers);
+	if (iPlayerCount)
+	{
+		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+		GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+		
+		new Handle:hMenu = CreateMenu(Menu_ViewGroupMembersQueue);
+		SetMenuTitle(hMenu, "%t%T (%s)\n \n", "SF2 Prefix", "SF2 View Group Members Menu Title", client, sGroupName);
+		
+		decl String:sUserId[32];
+		decl String:sName[MAX_NAME_LENGTH * 2];
+		
+		for (new i = 0; i < iPlayerCount; i++)
+		{
+			new iClient = GetArrayCell(hPlayers, i);
+			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
+			GetClientName(iClient, sName, sizeof(sName));
+			if (GetPlayerGroupLeader(iGroupIndex) == iClient) StrCat(sName, sizeof(sName), " (LEADER)");
+			
+			AddMenuItem(hMenu, sUserId, sName);
+		}
+		
+		SetMenuExitBackButton(hMenu, true);
+		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+	}
+	else
+	{
+		// No players!
+		DisplayQueuePointsMenu(client);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public Menu_ViewGroupMembersQueue(Handle:menu, MenuAction:action, param1, param2)
+{
+	switch (action)
+	{
+		case MenuAction_End: CloseHandle(menu);
+		case MenuAction_Select: DisplayQueuePointsMenu(param1);
+		case MenuAction_Cancel:
+		{
+			if (param2 == MenuCancel_ExitBack) DisplayQueuePointsMenu(param1);
+		}
+	}
+}
+
+DisplayResetQueuePointsMenu(client)
+{
+	decl String:buffer[256];
+
+	new Handle:menu = CreateMenu(Menu_ResetQueuePoints);
+	Format(buffer, sizeof(buffer), "%T", "Yes", client);
+	AddMenuItem(menu, "0", buffer);
+	Format(buffer, sizeof(buffer), "%T", "No", client);
+	AddMenuItem(menu, "1", buffer);
+	SetMenuTitle(menu, "%T\n \n", "SF2 Should Reset Queue Points", client);
+	DisplayMenu(menu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_QueuePoints(Handle:menu, MenuAction:action, param1, param2)
+{
+	switch (action)
+	{
+		case MenuAction_Select:
+		{
+			new String:sInfo[64];
+			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
+			
+			if (StrEqual(sInfo, "ponyponypony")) DisplayResetQueuePointsMenu(param1);
+			else if (!StrContains(sInfo, "player_"))
+			{
+			}
+			else if (!StrContains(sInfo, "group_"))
+			{
+				decl String:sIndex[64];
+				strcopy(sIndex, sizeof(sIndex), sInfo);
+				ReplaceString(sIndex, sizeof(sIndex), "group_", "");
+				DisplayViewGroupMembersQueueMenu(param1, StringToInt(sIndex));
+			}
+		}
+		case MenuAction_Cancel:
+		{
+			if (param2 == MenuCancel_ExitBack)
+			{
+				DisplayMenu(g_hMenuMain, param1, 30);
+			}
+		}
+		case MenuAction_End: CloseHandle(menu);
+	}
+}
+
+public Menu_ResetQueuePoints(Handle:menu, MenuAction:action, param1, param2)
+{
+	switch (action)
+	{
+		case MenuAction_Select:
+		{
+			switch (param2)
+			{
+				case 0:
+				{
+					ClientSetQueuePoints(param1, 0);
+					CPrintToChat(param1, "{olive}%T", "SF2 Queue Points Reset", param1);
+					
+					// Special round.
+					if (IsSpecialRoundRunning()) 
+					{
+						SetClientPlaySpecialRoundState(param1, true);
+					}
+					
+					// new boss round
+					if (IsNewBossRoundRunning()) 
+					{
+						// If the player resets the queue points ignore them when checking for players that haven't played the new boss yet, if applicable.
+						SetClientPlayNewBossRoundState(param1, true);
+					}
+				}
+			}
+			
+			DisplayQueuePointsMenu(param1);
+		}
+		
+		case MenuAction_End: CloseHandle(menu);
+	}
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/nav.sp b/addons/sourcemod/scripting/rytp_horror/nav.sp
index 3263ad9..609fc28 100644
--- a/addons/sourcemod/scripting/rytp_horror/nav.sp
+++ b/addons/sourcemod/scripting/rytp_horror/nav.sp
@@ -1,708 +1,708 @@
-#if defined _sf2_nav_included
- #endinput
-#endif
-#define _sf2_nav_included
-
-#define JumpCrouchHeight 58.0
-
-#if defined METHODMAPS
-
-methodmap NavPath < Handle
-{
-	public NavPath()
-	{
-		return NavPath:CreateNavPath();
-	}
-
-	public int AddNodeToHead(float nodePos[3])
-	{
-		return NavPathAddNodeToHead(this, nodePos);
-	}
-	
-	public int AddNodeToTail(float nodePos[3])
-	{
-		return NavPathAddNodeToTail(this, nodePos);
-	}
-	
-	public void GetNodePosition(int nodeIndex, float buffer[3])
-	{
-		NavPathGetNodePosition(this, nodeIndex, buffer);
-	}
-	
-	public int GetNodeAreaIndex(int nodeIndex)
-	{
-		return NavPathGetNodeAreaIndex(this, nodeIndex);
-	}
-	
-	public int GetNodeLadderIndex(int nodeIndex)
-	{
-		return NavPathGetNodeLadderIndex(this, nodeIndex);
-	}
-	
-	public bool ConstructPathFromPoints(float startPos[3], float endPos[3], float nearestAreaRadius, Function costFunction, any costData, bool populateIfIncomplete = true, int &closestAreaIndex = -1)
-	{
-		return NavPathConstructPathFromPoints(this, startPos, endPos, nearestAreaRadius, costFunction, costData, populateIfIncomplete, closestAreaIndex);
-	}
-}
-
-#endif
-
-stock Handle:CreateNavPath()
-{
-	return CreateArray(5);
-}
-
-stock NavPathGetNodePosition(Handle:hNavPath, iNodeIndex, Float:buffer[3])
-{
-	buffer[0] = Float:GetArrayCell(hNavPath, iNodeIndex, 0);
-	buffer[1] = Float:GetArrayCell(hNavPath, iNodeIndex, 1);
-	buffer[2] = Float:GetArrayCell(hNavPath, iNodeIndex, 2);
-}
-
-stock NavPathGetNodeAreaIndex(Handle:hNavPath, iNodeIndex)
-{
-	return GetArrayCell(hNavPath, iNodeIndex, 3);
-}
-
-stock NavPathGetNodeLadderIndex(Handle:hNavPath, iNodeIndex)
-{
-	return GetArrayCell(hNavPath, iNodeIndex, 4);
-}
-
-stock NavPathAddNodeToHead(Handle:hNavPath, const Float:flNodePos[3], iNodeAreaIndex, iLadderIndex=-1)
-{
-	new iIndex = -1;
-
-	if (GetArraySize(hNavPath) == 0)
-	{
-		iIndex = PushArrayArray(hNavPath, flNodePos, 3);
-		
-	}
-	else
-	{
-		iIndex = 0;
-		ShiftArrayUp(hNavPath, 0);
-		SetArrayArray(hNavPath, iIndex, flNodePos, 3);
-	}
-	
-	SetArrayCell(hNavPath, iIndex, iNodeAreaIndex, 3);
-	SetArrayCell(hNavPath, iIndex, iLadderIndex, 4);
-	
-	return iIndex;
-}
-
-stock NavPathAddNodeToTail(Handle:hNavPath, const Float:flNodePos[3], iNodeAreaIndex, iLadderIndex=-1)
-{
-	new iIndex = PushArrayArray(hNavPath, flNodePos, 3);
-	SetArrayCell(hNavPath, iIndex, iNodeAreaIndex, 3);
-	SetArrayCell(hNavPath, iIndex, iLadderIndex, 4);
-	
-	return iIndex;
-}
-
-/**
- *	Constructs a straight path leading from flStartPos to flEndPos. Useful if both points are within the same area, so pathing around is unnecessary.
- */
-stock bool:NavPathConstructTrivialPath(Handle:hNavPath, const Float:flStartPos[3], const Float:flEndPos[3], Float:flNearestAreaRadius)
-{
-	ClearArray(hNavPath);
-
-	new iStartAreaIndex = NavMesh_GetNearestArea(flStartPos, _, flNearestAreaRadius);
-	if (iStartAreaIndex == -1) return false;
-	
-	new iEndAreaIndex = NavMesh_GetNearestArea(flEndPos, _, flNearestAreaRadius);
-	if (iEndAreaIndex == -1) return false;
-
-	// Build a trivial path instead.
-	decl Float:flStartPosOnNavMesh[3];
-	flStartPosOnNavMesh[0] = flStartPos[0];
-	flStartPosOnNavMesh[1] = flStartPos[1];
-	flStartPosOnNavMesh[2] = NavMeshArea_GetZ(iStartAreaIndex, flStartPos);
-	
-	NavPathAddNodeToTail(hNavPath, flStartPosOnNavMesh, iStartAreaIndex);
-	
-	decl Float:flEndPosOnNavMesh[3];
-	flEndPosOnNavMesh[0] = flEndPos[0];
-	flEndPosOnNavMesh[1] = flEndPos[1];
-	flEndPosOnNavMesh[2] = NavMeshArea_GetZ(iEndAreaIndex, flEndPos);
-	
-	NavPathAddNodeToTail(hNavPath, flEndPosOnNavMesh, iEndAreaIndex);
-
-	return true;
-}
-
-/**
- *	Constructs a path leading from flStartPos to flEndPos. First node index (0) is the start of the path, last node index is the end.
- */
-stock bool:NavPathConstructPathFromPoints(Handle:hNavPath, const Float:flStartPos[3], const Float:flEndPos[3], Float:flNearestAreaRadius, Function:fCostFunction, any:iCostData=-1, bool:bPopulateIfIncomplete=false, &iClosestAreaIndex=0)
-{
-	ClearArray(hNavPath);
-	
-	new iStartAreaIndex = NavMesh_GetNearestArea(flStartPos, _, flNearestAreaRadius);
-	if (iStartAreaIndex == -1) return false;
-	
-	new iEndAreaIndex = NavMesh_GetNearestArea(flEndPos, _, flNearestAreaRadius);
-	if (iEndAreaIndex == -1) return false;
-	
-	if (iStartAreaIndex == iEndAreaIndex)
-	{
-		return NavPathConstructTrivialPath(hNavPath, flStartPos, flEndPos, flNearestAreaRadius);
-	}
-	
-	iClosestAreaIndex = 0;
-	
-	new bool:bResult = NavMesh_BuildPath(iStartAreaIndex,
-		iEndAreaIndex,
-		flEndPos,
-		fCostFunction,
-		iCostData,
-		iClosestAreaIndex);
-		
-	if (!bResult && bPopulateIfIncomplete) return false;
-	
-	if (bResult)
-	{
-		// Because we were able to get to the goal position successfully, add the goal position itself.
-		decl Float:flEndPosOnNavMesh[3];
-		flEndPosOnNavMesh[0] = flEndPos[0];
-		flEndPosOnNavMesh[1] = flEndPos[1];
-		flEndPosOnNavMesh[2] = NavMeshArea_GetZ(iEndAreaIndex, flEndPos);
-		
-		NavPathAddNodeToHead(hNavPath, flEndPosOnNavMesh, iEndAreaIndex);
-	}
-	
-	decl Float:flCenter[3], Float:flCenterPortal[3], Float:flClosestPoint[3];
-	
-	new iTempAreaIndex = iClosestAreaIndex;
-	new iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
-	new iNavDirection;
-	new Float:flHalfWidth;
-	
-	while (iTempParentAreaIndex != -1)
-	{
-		// Build a path of waypoints along the nav mesh for our AI to follow.
-		
-		NavMeshArea_GetCenter(iTempParentAreaIndex, flCenter);
-		iNavDirection = NavMeshArea_ComputeDirection(iTempAreaIndex, flCenter);
-		NavMeshArea_ComputePortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flHalfWidth);
-		NavMeshArea_ComputeClosestPointInPortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flClosestPoint);
-		
-		flClosestPoint[2] = NavMeshArea_GetZ(iTempAreaIndex, flClosestPoint);
-		
-		NavPathAddNodeToHead(hNavPath, flClosestPoint, iTempAreaIndex);
-		
-		iTempAreaIndex = iTempParentAreaIndex;
-		iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
-	}
-	
-	decl Float:flStartPosOnNavMesh[3];
-	flStartPosOnNavMesh[0] = flStartPos[0];
-	flStartPosOnNavMesh[1] = flStartPos[1];
-	flStartPosOnNavMesh[2] = NavMeshArea_GetZ(iStartAreaIndex, flStartPos);
-	
-	NavPathAddNodeToHead(hNavPath, flStartPosOnNavMesh, iStartAreaIndex);
-	
-	return bResult;
-}
-
-/**
- *	Return the closest point to our current position on our current path
- *	If "local" is true, only check the portion of the path surrounding iPathNodeIndex.
- *	(function imported from HL SDK)
- */
-stock FindClosestPositionOnPath(Handle:hNavPath, const Float:flFeetPos[3], const Float:flCentroidPos[3], const Float:flEyePos[3], Float:flBuffer[3]=NULL_VECTOR, bool:bLocal=false, iPathNodeIndex=-1)
-{
-	if (hNavPath == INVALID_HANDLE) return -1;
-	
-	new iNodeCount = GetArraySize(hNavPath);
-	if (iNodeCount == 0) return -1;
-	
-	new iStartNode = -1;
-	new iEndNode = -1;
-	
-	if (bLocal)
-	{
-		// Clamp nodes to stay within path segment.
-		iStartNode = iPathNodeIndex - 3;
-		if (iStartNode < 1) iStartNode = 1;
-		
-		iEndNode = iPathNodeIndex + 3;
-		if (iEndNode > iNodeCount) iEndNode = iNodeCount;
-	}
-	else
-	{
-		iStartNode = 1;
-		iEndNode = iNodeCount;
-	}
-	
-	decl Float:flFrom[3], Float:flTo[3];
-	decl Float:flAlong[3], Float:flToFeetPos[3];
-	
-	decl Float:flLength, Float:flCloseLength, Float:flDistSq;
-	
-	decl Float:flPos[3], Float:flSub[3], Float:flProbe[3];
-	
-	new Float:flCloseDistSq = 9999999999.9;
-	new iCloseIndex = -1;
-	
-	new Float:flMidHeight = flCentroidPos[2] - flFeetPos[2];
-	
-	for (new i = iStartNode; i < iEndNode; i++)
-	{
-		NavPathGetNodePosition(hNavPath, i - 1, flFrom);
-		NavPathGetNodePosition(hNavPath, i, flTo);
-		
-		// Convert flAlong to unit vector.
-		SubtractVectors(flTo, flFrom, flAlong);
-		flLength = GetVectorLength(flAlong);
-		NormalizeVector(flAlong, flAlong);
-		
-		SubtractVectors(flFeetPos, flFrom, flToFeetPos);
-		
-		// Clamp point onto current path segment.
-		flCloseLength = GetVectorDotProduct(flToFeetPos, flAlong);
-		if (flCloseLength <= 0.0)
-		{
-			flPos[0] = flFrom[0];
-			flPos[1] = flFrom[1];
-			flPos[2] = flFrom[2];
-		}
-		else if (flCloseLength >= flLength)
-		{
-			flPos[0] = flTo[0];
-			flPos[1] = flTo[1];
-			flPos[2] = flTo[2];
-		}
-		else
-		{
-			flPos[0] = flFrom[0] + (flCloseLength * flAlong[0]);
-			flPos[1] = flFrom[1] + (flCloseLength * flAlong[1]);
-			flPos[2] = flFrom[2] + (flCloseLength * flAlong[2]);
-		}
-		
-		SubtractVectors(flPos, flFeetPos, flSub);
-		flDistSq = GetVectorLength(flSub, true);
-		
-		if (flDistSq < flCloseDistSq)
-		{
-			flProbe[0] = flPos[0];
-			flProbe[1] = flPos[1];
-			flProbe[2] = flPos[2] + flMidHeight;
-			
-			if (!IsWalkableTraceLineClear(flEyePos, flProbe, WALK_THRU_DOORS | WALK_THRU_BREAKABLES)) continue;
-			
-			flCloseDistSq = flDistSq;
-			CopyVector(flPos, flBuffer);
-			
-			iCloseIndex = i - 1;
-		}
-	}
-	
-	return iCloseIndex;
-}
-
-/**
- *	Computes a point a fixed distance ahead of our path.
- *	Returns path index just after point.
- *	(function imported from HL SDK)
- */
-stock FindAheadPathPoint(Handle:hNavPath, Float:flAheadRange, iPathNodeIndex, const Float:flFeetPos[3], const Float:flCentroidPos[3], const Float:flEyePos[3], Float:flPoint[3], &iPrevPathNodeIndex)
-{
-	if (hNavPath == INVALID_HANDLE) return -1;
-	
-	new iAfterPathNodeIndex;
-	
-	decl Float:flClosestPos[3];
-	
-	new iStartPathNodeIndex = FindClosestPositionOnPath(hNavPath, flFeetPos, flCentroidPos, flEyePos, flClosestPos, true, iPathNodeIndex);
-	iPrevPathNodeIndex = iStartPathNodeIndex;
-	
-	if (iStartPathNodeIndex <= 0)
-	{
-		// Went off the end of the path or next point in path is unwalkable (ie: jump-down). Keep same point
-		return iPathNodeIndex;
-	}
-	
-	decl Float:flFeetPos2D[3], Float:flPathNodePos2D[3];
-	CopyVector(flFeetPos, flFeetPos2D);
-	flFeetPos2D[2] = 0.0;
-	
-	while (iStartPathNodeIndex < (GetArraySize(hNavPath) - 1))
-	{
-		decl Float:flPathNodePos[3];
-		NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPathNodePos);
-		flPathNodePos2D[2] = 0.0;
-		
-		static Float:closeEpsilon = 20.0;
-		
-		if (GetVectorDistance(flFeetPos2D, flPathNodePos2D) < closeEpsilon)
-		{
-			iStartPathNodeIndex++;
-		}
-		else
-		{
-			break;
-		}
-	}
-	
-	// Approaching jump area? Look no further, we must stop here.
-	if (iStartPathNodeIndex > iPathNodeIndex && iStartPathNodeIndex < GetArraySize(hNavPath) &&
-		NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, iStartPathNodeIndex)) & NAV_MESH_JUMP)
-	{
-		NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPoint);
-		return iStartPathNodeIndex;
-	}
-	
-	iStartPathNodeIndex++;
-	
-	// Approaching jump area? Look no further, we must stop here.
-	if (iStartPathNodeIndex < GetArraySize(hNavPath) &&
-		NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, iStartPathNodeIndex)) & NAV_MESH_JUMP)
-	{
-		NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPoint);
-		return iStartPathNodeIndex;
-	}
-	
-	// Get the direction of the path segment we're currently on.
-	decl Float:flStartPathNodePos[3], Float:flPrevStartPathNodePos[3];
-	NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flStartPathNodePos);
-	NavPathGetNodePosition(hNavPath, iStartPathNodeIndex - 1, flPrevStartPathNodePos);
-	
-	decl Float:flInitDir[3];
-	SubtractVectors(flStartPathNodePos, flPrevStartPathNodePos, flInitDir);
-	NormalizeVector(flInitDir, flInitDir);
-	
-	new Float:flRangeSoFar = 0.0;
-	
-	// bVisible is true if our ahead point is visible.
-	new bool:bVisible = true;
-	
-	decl Float:flPrevDir[3];
-	CopyVector(flInitDir, flPrevDir);
-	
-	new bool:bIsCorner = false;
-	new i = 0;
-	
-	new Float:flMidHeight = flCentroidPos[2] - flFeetPos[2];
-	
-	// Step along the path until we pass flAheadRange.
-	for (i = iStartPathNodeIndex; i < GetArraySize(hNavPath); i++)
-	{
-		decl Float:flPathNodePos[3], Float:flTo[3], Float:flDir[3];
-		NavPathGetNodePosition(hNavPath, i, flPathNodePos);
-		NavPathGetNodePosition(hNavPath, i - 1, flTo);
-		NegateVector(flTo);
-		AddVectors(flPathNodePos, flTo, flTo);
-		
-		NormalizeVector(flTo, flDir);
-		
-		if (GetVectorDotProduct(flDir, flInitDir) < 0.0)
-		{
-			// Don't double back.
-			i--;
-			break;
-		}
-		
-		if (GetVectorDotProduct(flDir, flPrevDir) < 0.0)
-		{
-			// Don't cut corners.
-			bIsCorner = true;
-			i--;
-			break;
-		}
-		
-		CopyVector(flDir, flPrevDir);
-		
-		decl Float:flProbe[3];
-		CopyVector(flPathNodePos, flProbe);
-		flProbe[2] += flMidHeight;
-		
-		if (!IsWalkableTraceLineClear( flEyePos, flProbe, WALK_THRU_BREAKABLES ))
-		{
-			// Points aren't visible ahead; stick to the last visible point ahead.
-			bVisible = false;
-			break;
-		}
-		
-		if (NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, i)) & NAV_MESH_JUMP)
-		{
-			// Jump area here; stop.
-			break;
-		}
-		
-		if (i == iStartPathNodeIndex)
-		{
-			decl Float:flAlong[3];
-			SubtractVectors(flPathNodePos, flFeetPos, flAlong);
-			flAlong[2] = 0.0;
-			flRangeSoFar += GetVectorLength(flAlong);
-		}
-		else
-		{
-			flRangeSoFar += GetVectorLength(flTo);
-		}
-		
-		if (flRangeSoFar >= flAheadRange)
-		{
-			// Went ahead of flAheadRange; stop.
-			break;
-		}
-	}
-	
-	// clamp iAfterPathNodeIndex between starting path node and the end
-	if (i < iStartPathNodeIndex)
-	{
-		iAfterPathNodeIndex = iStartPathNodeIndex;
-	}
-	else if (i < GetArraySize(hNavPath))
-	{
-		iAfterPathNodeIndex = i;
-	}
-	else
-	{
-		iAfterPathNodeIndex = GetArraySize(hNavPath) - 1;
-	}
-	
-	if (iAfterPathNodeIndex == 0)
-	{
-		NavPathGetNodePosition(hNavPath, 0, flPoint);
-	}
-	else
-	{
-		// Interpolate point along path segment to get exact distance.
-		decl Float:flBeforePointPos[3], Float:flAfterPointPos[3];
-		NavPathGetNodePosition(hNavPath, iAfterPathNodeIndex, flAfterPointPos);
-		NavPathGetNodePosition(hNavPath, iAfterPathNodeIndex - 1, flBeforePointPos);
-		
-		decl Float:flTo[3], Float:flTo2D[3];
-		SubtractVectors(flAfterPointPos, flBeforePointPos, flTo);
-		CopyVector(flTo, flTo2D);
-		flTo2D[2] = 0.0;
-		
-		new Float:flLength = GetVectorLength(flTo2D);
-		new Float:t = 1.0 - ((flRangeSoFar - flAheadRange) / flLength);
-		
-		if (t < 0.0) t = 0.0;
-		else if (t > 1.0) t = 1.0;
-		
-		for (new i2 = 0; i2 < 3; i2++)
-		{
-			flPoint[i2] = flBeforePointPos[i2] + (t * flTo[i2]);
-		}
-		
-		if (!bVisible)
-		{
-			// iAfterPathNodeIndex isn't visible, so slide back towards previous node until it is. 
-		
-			static const Float:flSightStepSize = 25.0;
-			new Float:dt = flSightStepSize / flLength;
-			
-			decl Float:flProbe[3];
-			CopyVector(flPoint, flProbe);
-			flProbe[2] += flMidHeight;
-			
-			while (t > 0.0 && !IsWalkableTraceLineClear(flEyePos,  flProbe, WALK_THRU_BREAKABLES))
-			{
-				t -= dt;
-				
-				for (new i2 = 0; i2 < 3; i2++)
-				{
-					flPoint[i2] = flBeforePointPos[i2] + (t * flTo[i2]);
-				}
-			}
-			
-			if (t <= 0.0)
-			{
-				CopyVector(flBeforePointPos, flPoint);
-			}
-		}
-	}
-	
-	// Is there a corner ahead?
-	if (!bIsCorner)
-	{
-		// If position found is behind us or it's too close to us, force it farther down the path so we don't stop and wiggle.
-	
-		static const Float:epsilon = 50.0;
-		
-		decl Float:flCentroid2D[3];
-		CopyVector(flCentroidPos, flCentroid2D);
-		flCentroid2D[2] = 0.0;
-		
-		decl Float:flTo2D[3];
-		flTo2D[0] = flPoint[0] - flCentroid2D[0];
-		flTo2D[1] = flPoint[1] - flCentroid2D[1];
-		flTo2D[2] = 0.0;
-		
-		decl Float:flInitDir2D[3];
-		CopyVector(flInitDir, flInitDir2D);
-		flInitDir2D[2] = 0.0;
-		
-		if (GetVectorDotProduct(flTo2D, flInitDir2D) < 0.0 || GetVectorLength(flTo2D) < epsilon)
-		{
-			// Check points ahead.
-			for (i = iStartPathNodeIndex; i < GetArraySize(hNavPath); i++)
-			{
-				decl Float:flPathNodePos[3];
-				NavPathGetNodePosition(hNavPath, i, flPathNodePos);
-			
-				flTo2D[0] = flPathNodePos[0] - flCentroid2D[0];
-				flTo2D[1] = flPathNodePos[1] - flCentroid2D[1];
-				
-				// Check if the point ahead is either a jump/ladder area or is far enough.
-				if (NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, i)) & NAV_MESH_JUMP || GetVectorLength(flTo2D) > epsilon)
-				{
-					CopyVector(flPathNodePos, flPoint);
-					iStartPathNodeIndex = i;
-					break;
-				}
-			}
-			
-			if (i == GetArraySize(hNavPath))
-			{
-				iStartPathNodeIndex = GetArraySize(hNavPath) - 1;
-				NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPoint);
-			}
-		}
-	}
-	
-	if (iStartPathNodeIndex < GetArraySize(hNavPath))
-	{
-		return iStartPathNodeIndex;
-	}
-	
-	return GetArraySize(hNavPath) - 1;
-}
-
-
-stock CalculateFeelerReflexAdjustment(const Float:flOriginalMovePos[3], 
-	const Float:flOriginalFeetPos[3], 
-	const Float:flFloorNormalDir[3],
-	Float:flFeelerHeight, 
-	Float:flFeelerOffset, 
-	Float:flFeelerLength, 
-	Float:flAvoidRange, 
-	Float:flBuffer[3], 
-	iTraceMask=MASK_PLAYERSOLID,
-	Function:fTraceFilterFunction=INVALID_FUNCTION, 
-	any:iTraceFilterFunctionData=-1)
-{
-	// Forward direction vector.
-	decl Float:flOriginalMoveDir[3], Float:flLateralDir[3];
-	SubtractVectors(flOriginalMovePos, flOriginalFeetPos, flOriginalMoveDir);
-	flOriginalMoveDir[2] = 0.0;
-	
-	GetVectorAngles(flOriginalMoveDir, flOriginalMoveDir);
-	GetAngleVectors(flOriginalMoveDir, flOriginalMoveDir, flLateralDir, NULL_VECTOR);
-	NormalizeVector(flOriginalMoveDir, flOriginalMoveDir);
-	NormalizeVector(flLateralDir, flLateralDir);
-	NegateVector(flLateralDir);
-	
-	// Correct move direction vector along floor.
-	decl Float:flDir[3];
-	GetVectorCrossProduct(flLateralDir, flFloorNormalDir, flDir);
-	NormalizeVector(flDir, flDir);
-	
-	// Correct lateral direction vector along floor.
-	GetVectorCrossProduct(flDir, flFloorNormalDir, flLateralDir);
-	NormalizeVector(flLateralDir, flLateralDir);
-	
-	if (flFeelerHeight <= 0.0)
-	{
-		flFeelerHeight = StepHeight + 0.1;
-	}
-	
-	decl Float:flFeetPos[3];
-	CopyVector(flOriginalFeetPos, flFeetPos);
-	flFeetPos[2] += flFeelerHeight;
-	
-	decl Float:flFromPos[3];
-	decl Float:flToPos[3];
-	
-	// Check the left.
-	for (new i = 0; i < 3; i++)
-	{
-		flFromPos[i] = flFeetPos[i] + (flFeelerOffset * flLateralDir[i]);
-		flToPos[i] = flFromPos[i] + (flFeelerLength * flDir[i]);
-	}
-	
-	new Handle:hTrace = INVALID_HANDLE;
-	if (fTraceFilterFunction != INVALID_FUNCTION)
-	{
-		hTrace = TR_TraceRayFilterEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint, fTraceFilterFunction, iTraceFilterFunctionData);
-	}
-	else
-	{
-		hTrace = TR_TraceRayEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint);
-	}
-	
-	new bool:bLeftClear = !TR_DidHit(hTrace);
-	CloseHandle(hTrace);
-	
-#if defined DEBUG
-	
-	if (bLeftClear)
-	{
-		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 0, 255, 0, 255 }, 30);
-	}
-	else
-	{
-		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 255, 0, 0, 255 }, 30);
-	}
-	
-	TE_SendToAll();
-	
-#endif
-	
-	// Check the right.
-	for (new i = 0; i < 3; i++)
-	{
-		flFromPos[i] = flFeetPos[i] - (flFeelerOffset * flLateralDir[i]);
-		flToPos[i] = flFromPos[i] + (flFeelerLength * flDir[i]);
-	}
-	
-	if (fTraceFilterFunction != INVALID_FUNCTION)
-	{
-		hTrace = TR_TraceRayFilterEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint, fTraceFilterFunction, iTraceFilterFunctionData);
-	}
-	else
-	{
-		hTrace = TR_TraceRayEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint);
-	}
-	
-	new bool:bRightClear = !TR_DidHit(hTrace);
-	CloseHandle(hTrace);
-	
-#if defined DEBUG
-	
-	if (bRightClear)
-	{
-		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 0, 255, 0, 255 }, 30);
-	}
-	else
-	{
-		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 255, 0, 0, 255 }, 30);
-	}
-	
-	TE_SendToAll();
-	
-#endif
-	
-	if (!bRightClear)
-	{
-		if (bLeftClear)
-		{
-			for (new i = 0; i < 3; i++)
-			{
-				flBuffer[i] = flOriginalMovePos[i] + (flAvoidRange * flLateralDir[i]);
-			}
-		}
-	}
-	else if (!bLeftClear)
-	{
-		for (new i = 0; i < 3; i++)
-		{
-			flBuffer[i] = flOriginalMovePos[i] - (flAvoidRange * flLateralDir[i]);
-		}
-	}
+#if defined _sf2_nav_included
+ #endinput
+#endif
+#define _sf2_nav_included
+
+#define JumpCrouchHeight 58.0
+
+#if defined METHODMAPS
+
+methodmap NavPath < Handle
+{
+	public NavPath()
+	{
+		return NavPath:CreateNavPath();
+	}
+
+	public int AddNodeToHead(float nodePos[3])
+	{
+		return NavPathAddNodeToHead(this, nodePos);
+	}
+	
+	public int AddNodeToTail(float nodePos[3])
+	{
+		return NavPathAddNodeToTail(this, nodePos);
+	}
+	
+	public void GetNodePosition(int nodeIndex, float buffer[3])
+	{
+		NavPathGetNodePosition(this, nodeIndex, buffer);
+	}
+	
+	public int GetNodeAreaIndex(int nodeIndex)
+	{
+		return NavPathGetNodeAreaIndex(this, nodeIndex);
+	}
+	
+	public int GetNodeLadderIndex(int nodeIndex)
+	{
+		return NavPathGetNodeLadderIndex(this, nodeIndex);
+	}
+	
+	public bool ConstructPathFromPoints(float startPos[3], float endPos[3], float nearestAreaRadius, Function costFunction, any costData, bool populateIfIncomplete = true, int &closestAreaIndex = -1)
+	{
+		return NavPathConstructPathFromPoints(this, startPos, endPos, nearestAreaRadius, costFunction, costData, populateIfIncomplete, closestAreaIndex);
+	}
+}
+
+#endif
+
+stock Handle:CreateNavPath()
+{
+	return CreateArray(5);
+}
+
+stock NavPathGetNodePosition(Handle:hNavPath, iNodeIndex, Float:buffer[3])
+{
+	buffer[0] = Float:GetArrayCell(hNavPath, iNodeIndex, 0);
+	buffer[1] = Float:GetArrayCell(hNavPath, iNodeIndex, 1);
+	buffer[2] = Float:GetArrayCell(hNavPath, iNodeIndex, 2);
+}
+
+stock NavPathGetNodeAreaIndex(Handle:hNavPath, iNodeIndex)
+{
+	return GetArrayCell(hNavPath, iNodeIndex, 3);
+}
+
+stock NavPathGetNodeLadderIndex(Handle:hNavPath, iNodeIndex)
+{
+	return GetArrayCell(hNavPath, iNodeIndex, 4);
+}
+
+stock NavPathAddNodeToHead(Handle:hNavPath, const Float:flNodePos[3], iNodeAreaIndex, iLadderIndex=-1)
+{
+	new iIndex = -1;
+
+	if (GetArraySize(hNavPath) == 0)
+	{
+		iIndex = PushArrayArray(hNavPath, flNodePos, 3);
+		
+	}
+	else
+	{
+		iIndex = 0;
+		ShiftArrayUp(hNavPath, 0);
+		SetArrayArray(hNavPath, iIndex, flNodePos, 3);
+	}
+	
+	SetArrayCell(hNavPath, iIndex, iNodeAreaIndex, 3);
+	SetArrayCell(hNavPath, iIndex, iLadderIndex, 4);
+	
+	return iIndex;
+}
+
+stock NavPathAddNodeToTail(Handle:hNavPath, const Float:flNodePos[3], iNodeAreaIndex, iLadderIndex=-1)
+{
+	new iIndex = PushArrayArray(hNavPath, flNodePos, 3);
+	SetArrayCell(hNavPath, iIndex, iNodeAreaIndex, 3);
+	SetArrayCell(hNavPath, iIndex, iLadderIndex, 4);
+	
+	return iIndex;
+}
+
+/**
+ *	Constructs a straight path leading from flStartPos to flEndPos. Useful if both points are within the same area, so pathing around is unnecessary.
+ */
+stock bool:NavPathConstructTrivialPath(Handle:hNavPath, const Float:flStartPos[3], const Float:flEndPos[3], Float:flNearestAreaRadius)
+{
+	ClearArray(hNavPath);
+
+	new iStartAreaIndex = NavMesh_GetNearestArea(flStartPos, _, flNearestAreaRadius);
+	if (iStartAreaIndex == -1) return false;
+	
+	new iEndAreaIndex = NavMesh_GetNearestArea(flEndPos, _, flNearestAreaRadius);
+	if (iEndAreaIndex == -1) return false;
+
+	// Build a trivial path instead.
+	decl Float:flStartPosOnNavMesh[3];
+	flStartPosOnNavMesh[0] = flStartPos[0];
+	flStartPosOnNavMesh[1] = flStartPos[1];
+	flStartPosOnNavMesh[2] = NavMeshArea_GetZ(iStartAreaIndex, flStartPos);
+	
+	NavPathAddNodeToTail(hNavPath, flStartPosOnNavMesh, iStartAreaIndex);
+	
+	decl Float:flEndPosOnNavMesh[3];
+	flEndPosOnNavMesh[0] = flEndPos[0];
+	flEndPosOnNavMesh[1] = flEndPos[1];
+	flEndPosOnNavMesh[2] = NavMeshArea_GetZ(iEndAreaIndex, flEndPos);
+	
+	NavPathAddNodeToTail(hNavPath, flEndPosOnNavMesh, iEndAreaIndex);
+
+	return true;
+}
+
+/**
+ *	Constructs a path leading from flStartPos to flEndPos. First node index (0) is the start of the path, last node index is the end.
+ */
+stock bool:NavPathConstructPathFromPoints(Handle:hNavPath, const Float:flStartPos[3], const Float:flEndPos[3], Float:flNearestAreaRadius, Function:fCostFunction, any:iCostData=-1, bool:bPopulateIfIncomplete=false, &iClosestAreaIndex=0)
+{
+	ClearArray(hNavPath);
+	
+	new iStartAreaIndex = NavMesh_GetNearestArea(flStartPos, _, flNearestAreaRadius);
+	if (iStartAreaIndex == -1) return false;
+	
+	new iEndAreaIndex = NavMesh_GetNearestArea(flEndPos, _, flNearestAreaRadius);
+	if (iEndAreaIndex == -1) return false;
+	
+	if (iStartAreaIndex == iEndAreaIndex)
+	{
+		return NavPathConstructTrivialPath(hNavPath, flStartPos, flEndPos, flNearestAreaRadius);
+	}
+	
+	iClosestAreaIndex = 0;
+	
+	new bool:bResult = NavMesh_BuildPath(iStartAreaIndex,
+		iEndAreaIndex,
+		flEndPos,
+		fCostFunction,
+		iCostData,
+		iClosestAreaIndex);
+		
+	if (!bResult && bPopulateIfIncomplete) return false;
+	
+	if (bResult)
+	{
+		// Because we were able to get to the goal position successfully, add the goal position itself.
+		decl Float:flEndPosOnNavMesh[3];
+		flEndPosOnNavMesh[0] = flEndPos[0];
+		flEndPosOnNavMesh[1] = flEndPos[1];
+		flEndPosOnNavMesh[2] = NavMeshArea_GetZ(iEndAreaIndex, flEndPos);
+		
+		NavPathAddNodeToHead(hNavPath, flEndPosOnNavMesh, iEndAreaIndex);
+	}
+	
+	decl Float:flCenter[3], Float:flCenterPortal[3], Float:flClosestPoint[3];
+	
+	new iTempAreaIndex = iClosestAreaIndex;
+	new iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
+	new iNavDirection;
+	new Float:flHalfWidth;
+	
+	while (iTempParentAreaIndex != -1)
+	{
+		// Build a path of waypoints along the nav mesh for our AI to follow.
+		
+		NavMeshArea_GetCenter(iTempParentAreaIndex, flCenter);
+		iNavDirection = NavMeshArea_ComputeDirection(iTempAreaIndex, flCenter);
+		NavMeshArea_ComputePortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flHalfWidth);
+		NavMeshArea_ComputeClosestPointInPortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flClosestPoint);
+		
+		flClosestPoint[2] = NavMeshArea_GetZ(iTempAreaIndex, flClosestPoint);
+		
+		NavPathAddNodeToHead(hNavPath, flClosestPoint, iTempAreaIndex);
+		
+		iTempAreaIndex = iTempParentAreaIndex;
+		iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
+	}
+	
+	decl Float:flStartPosOnNavMesh[3];
+	flStartPosOnNavMesh[0] = flStartPos[0];
+	flStartPosOnNavMesh[1] = flStartPos[1];
+	flStartPosOnNavMesh[2] = NavMeshArea_GetZ(iStartAreaIndex, flStartPos);
+	
+	NavPathAddNodeToHead(hNavPath, flStartPosOnNavMesh, iStartAreaIndex);
+	
+	return bResult;
+}
+
+/**
+ *	Return the closest point to our current position on our current path
+ *	If "local" is true, only check the portion of the path surrounding iPathNodeIndex.
+ *	(function imported from HL SDK)
+ */
+stock FindClosestPositionOnPath(Handle:hNavPath, const Float:flFeetPos[3], const Float:flCentroidPos[3], const Float:flEyePos[3], Float:flBuffer[3]=NULL_VECTOR, bool:bLocal=false, iPathNodeIndex=-1)
+{
+	if (hNavPath == INVALID_HANDLE) return -1;
+	
+	new iNodeCount = GetArraySize(hNavPath);
+	if (iNodeCount == 0) return -1;
+	
+	new iStartNode = -1;
+	new iEndNode = -1;
+	
+	if (bLocal)
+	{
+		// Clamp nodes to stay within path segment.
+		iStartNode = iPathNodeIndex - 3;
+		if (iStartNode < 1) iStartNode = 1;
+		
+		iEndNode = iPathNodeIndex + 3;
+		if (iEndNode > iNodeCount) iEndNode = iNodeCount;
+	}
+	else
+	{
+		iStartNode = 1;
+		iEndNode = iNodeCount;
+	}
+	
+	decl Float:flFrom[3], Float:flTo[3];
+	decl Float:flAlong[3], Float:flToFeetPos[3];
+	
+	decl Float:flLength, Float:flCloseLength, Float:flDistSq;
+	
+	decl Float:flPos[3], Float:flSub[3], Float:flProbe[3];
+	
+	new Float:flCloseDistSq = 9999999999.9;
+	new iCloseIndex = -1;
+	
+	new Float:flMidHeight = flCentroidPos[2] - flFeetPos[2];
+	
+	for (new i = iStartNode; i < iEndNode; i++)
+	{
+		NavPathGetNodePosition(hNavPath, i - 1, flFrom);
+		NavPathGetNodePosition(hNavPath, i, flTo);
+		
+		// Convert flAlong to unit vector.
+		SubtractVectors(flTo, flFrom, flAlong);
+		flLength = GetVectorLength(flAlong);
+		NormalizeVector(flAlong, flAlong);
+		
+		SubtractVectors(flFeetPos, flFrom, flToFeetPos);
+		
+		// Clamp point onto current path segment.
+		flCloseLength = GetVectorDotProduct(flToFeetPos, flAlong);
+		if (flCloseLength <= 0.0)
+		{
+			flPos[0] = flFrom[0];
+			flPos[1] = flFrom[1];
+			flPos[2] = flFrom[2];
+		}
+		else if (flCloseLength >= flLength)
+		{
+			flPos[0] = flTo[0];
+			flPos[1] = flTo[1];
+			flPos[2] = flTo[2];
+		}
+		else
+		{
+			flPos[0] = flFrom[0] + (flCloseLength * flAlong[0]);
+			flPos[1] = flFrom[1] + (flCloseLength * flAlong[1]);
+			flPos[2] = flFrom[2] + (flCloseLength * flAlong[2]);
+		}
+		
+		SubtractVectors(flPos, flFeetPos, flSub);
+		flDistSq = GetVectorLength(flSub, true);
+		
+		if (flDistSq < flCloseDistSq)
+		{
+			flProbe[0] = flPos[0];
+			flProbe[1] = flPos[1];
+			flProbe[2] = flPos[2] + flMidHeight;
+			
+			if (!IsWalkableTraceLineClear(flEyePos, flProbe, WALK_THRU_DOORS | WALK_THRU_BREAKABLES)) continue;
+			
+			flCloseDistSq = flDistSq;
+			CopyVector(flPos, flBuffer);
+			
+			iCloseIndex = i - 1;
+		}
+	}
+	
+	return iCloseIndex;
+}
+
+/**
+ *	Computes a point a fixed distance ahead of our path.
+ *	Returns path index just after point.
+ *	(function imported from HL SDK)
+ */
+stock FindAheadPathPoint(Handle:hNavPath, Float:flAheadRange, iPathNodeIndex, const Float:flFeetPos[3], const Float:flCentroidPos[3], const Float:flEyePos[3], Float:flPoint[3], &iPrevPathNodeIndex)
+{
+	if (hNavPath == INVALID_HANDLE) return -1;
+	
+	new iAfterPathNodeIndex;
+	
+	decl Float:flClosestPos[3];
+	
+	new iStartPathNodeIndex = FindClosestPositionOnPath(hNavPath, flFeetPos, flCentroidPos, flEyePos, flClosestPos, true, iPathNodeIndex);
+	iPrevPathNodeIndex = iStartPathNodeIndex;
+	
+	if (iStartPathNodeIndex <= 0)
+	{
+		// Went off the end of the path or next point in path is unwalkable (ie: jump-down). Keep same point
+		return iPathNodeIndex;
+	}
+	
+	decl Float:flFeetPos2D[3], Float:flPathNodePos2D[3];
+	CopyVector(flFeetPos, flFeetPos2D);
+	flFeetPos2D[2] = 0.0;
+	
+	while (iStartPathNodeIndex < (GetArraySize(hNavPath) - 1))
+	{
+		decl Float:flPathNodePos[3];
+		NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPathNodePos);
+		flPathNodePos2D[2] = 0.0;
+		
+		static Float:closeEpsilon = 20.0;
+		
+		if (GetVectorDistance(flFeetPos2D, flPathNodePos2D) < closeEpsilon)
+		{
+			iStartPathNodeIndex++;
+		}
+		else
+		{
+			break;
+		}
+	}
+	
+	// Approaching jump area? Look no further, we must stop here.
+	if (iStartPathNodeIndex > iPathNodeIndex && iStartPathNodeIndex < GetArraySize(hNavPath) &&
+		NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, iStartPathNodeIndex)) & NAV_MESH_JUMP)
+	{
+		NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPoint);
+		return iStartPathNodeIndex;
+	}
+	
+	iStartPathNodeIndex++;
+	
+	// Approaching jump area? Look no further, we must stop here.
+	if (iStartPathNodeIndex < GetArraySize(hNavPath) &&
+		NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, iStartPathNodeIndex)) & NAV_MESH_JUMP)
+	{
+		NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPoint);
+		return iStartPathNodeIndex;
+	}
+	
+	// Get the direction of the path segment we're currently on.
+	decl Float:flStartPathNodePos[3], Float:flPrevStartPathNodePos[3];
+	NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flStartPathNodePos);
+	NavPathGetNodePosition(hNavPath, iStartPathNodeIndex - 1, flPrevStartPathNodePos);
+	
+	decl Float:flInitDir[3];
+	SubtractVectors(flStartPathNodePos, flPrevStartPathNodePos, flInitDir);
+	NormalizeVector(flInitDir, flInitDir);
+	
+	new Float:flRangeSoFar = 0.0;
+	
+	// bVisible is true if our ahead point is visible.
+	new bool:bVisible = true;
+	
+	decl Float:flPrevDir[3];
+	CopyVector(flInitDir, flPrevDir);
+	
+	new bool:bIsCorner = false;
+	new i = 0;
+	
+	new Float:flMidHeight = flCentroidPos[2] - flFeetPos[2];
+	
+	// Step along the path until we pass flAheadRange.
+	for (i = iStartPathNodeIndex; i < GetArraySize(hNavPath); i++)
+	{
+		decl Float:flPathNodePos[3], Float:flTo[3], Float:flDir[3];
+		NavPathGetNodePosition(hNavPath, i, flPathNodePos);
+		NavPathGetNodePosition(hNavPath, i - 1, flTo);
+		NegateVector(flTo);
+		AddVectors(flPathNodePos, flTo, flTo);
+		
+		NormalizeVector(flTo, flDir);
+		
+		if (GetVectorDotProduct(flDir, flInitDir) < 0.0)
+		{
+			// Don't double back.
+			i--;
+			break;
+		}
+		
+		if (GetVectorDotProduct(flDir, flPrevDir) < 0.0)
+		{
+			// Don't cut corners.
+			bIsCorner = true;
+			i--;
+			break;
+		}
+		
+		CopyVector(flDir, flPrevDir);
+		
+		decl Float:flProbe[3];
+		CopyVector(flPathNodePos, flProbe);
+		flProbe[2] += flMidHeight;
+		
+		if (!IsWalkableTraceLineClear( flEyePos, flProbe, WALK_THRU_BREAKABLES ))
+		{
+			// Points aren't visible ahead; stick to the last visible point ahead.
+			bVisible = false;
+			break;
+		}
+		
+		if (NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, i)) & NAV_MESH_JUMP)
+		{
+			// Jump area here; stop.
+			break;
+		}
+		
+		if (i == iStartPathNodeIndex)
+		{
+			decl Float:flAlong[3];
+			SubtractVectors(flPathNodePos, flFeetPos, flAlong);
+			flAlong[2] = 0.0;
+			flRangeSoFar += GetVectorLength(flAlong);
+		}
+		else
+		{
+			flRangeSoFar += GetVectorLength(flTo);
+		}
+		
+		if (flRangeSoFar >= flAheadRange)
+		{
+			// Went ahead of flAheadRange; stop.
+			break;
+		}
+	}
+	
+	// clamp iAfterPathNodeIndex between starting path node and the end
+	if (i < iStartPathNodeIndex)
+	{
+		iAfterPathNodeIndex = iStartPathNodeIndex;
+	}
+	else if (i < GetArraySize(hNavPath))
+	{
+		iAfterPathNodeIndex = i;
+	}
+	else
+	{
+		iAfterPathNodeIndex = GetArraySize(hNavPath) - 1;
+	}
+	
+	if (iAfterPathNodeIndex == 0)
+	{
+		NavPathGetNodePosition(hNavPath, 0, flPoint);
+	}
+	else
+	{
+		// Interpolate point along path segment to get exact distance.
+		decl Float:flBeforePointPos[3], Float:flAfterPointPos[3];
+		NavPathGetNodePosition(hNavPath, iAfterPathNodeIndex, flAfterPointPos);
+		NavPathGetNodePosition(hNavPath, iAfterPathNodeIndex - 1, flBeforePointPos);
+		
+		decl Float:flTo[3], Float:flTo2D[3];
+		SubtractVectors(flAfterPointPos, flBeforePointPos, flTo);
+		CopyVector(flTo, flTo2D);
+		flTo2D[2] = 0.0;
+		
+		new Float:flLength = GetVectorLength(flTo2D);
+		new Float:t = 1.0 - ((flRangeSoFar - flAheadRange) / flLength);
+		
+		if (t < 0.0) t = 0.0;
+		else if (t > 1.0) t = 1.0;
+		
+		for (new i2 = 0; i2 < 3; i2++)
+		{
+			flPoint[i2] = flBeforePointPos[i2] + (t * flTo[i2]);
+		}
+		
+		if (!bVisible)
+		{
+			// iAfterPathNodeIndex isn't visible, so slide back towards previous node until it is. 
+		
+			static const Float:flSightStepSize = 25.0;
+			new Float:dt = flSightStepSize / flLength;
+			
+			decl Float:flProbe[3];
+			CopyVector(flPoint, flProbe);
+			flProbe[2] += flMidHeight;
+			
+			while (t > 0.0 && !IsWalkableTraceLineClear(flEyePos,  flProbe, WALK_THRU_BREAKABLES))
+			{
+				t -= dt;
+				
+				for (new i2 = 0; i2 < 3; i2++)
+				{
+					flPoint[i2] = flBeforePointPos[i2] + (t * flTo[i2]);
+				}
+			}
+			
+			if (t <= 0.0)
+			{
+				CopyVector(flBeforePointPos, flPoint);
+			}
+		}
+	}
+	
+	// Is there a corner ahead?
+	if (!bIsCorner)
+	{
+		// If position found is behind us or it's too close to us, force it farther down the path so we don't stop and wiggle.
+	
+		static const Float:epsilon = 50.0;
+		
+		decl Float:flCentroid2D[3];
+		CopyVector(flCentroidPos, flCentroid2D);
+		flCentroid2D[2] = 0.0;
+		
+		decl Float:flTo2D[3];
+		flTo2D[0] = flPoint[0] - flCentroid2D[0];
+		flTo2D[1] = flPoint[1] - flCentroid2D[1];
+		flTo2D[2] = 0.0;
+		
+		decl Float:flInitDir2D[3];
+		CopyVector(flInitDir, flInitDir2D);
+		flInitDir2D[2] = 0.0;
+		
+		if (GetVectorDotProduct(flTo2D, flInitDir2D) < 0.0 || GetVectorLength(flTo2D) < epsilon)
+		{
+			// Check points ahead.
+			for (i = iStartPathNodeIndex; i < GetArraySize(hNavPath); i++)
+			{
+				decl Float:flPathNodePos[3];
+				NavPathGetNodePosition(hNavPath, i, flPathNodePos);
+			
+				flTo2D[0] = flPathNodePos[0] - flCentroid2D[0];
+				flTo2D[1] = flPathNodePos[1] - flCentroid2D[1];
+				
+				// Check if the point ahead is either a jump/ladder area or is far enough.
+				if (NavMeshArea_GetFlags(NavPathGetNodeAreaIndex(hNavPath, i)) & NAV_MESH_JUMP || GetVectorLength(flTo2D) > epsilon)
+				{
+					CopyVector(flPathNodePos, flPoint);
+					iStartPathNodeIndex = i;
+					break;
+				}
+			}
+			
+			if (i == GetArraySize(hNavPath))
+			{
+				iStartPathNodeIndex = GetArraySize(hNavPath) - 1;
+				NavPathGetNodePosition(hNavPath, iStartPathNodeIndex, flPoint);
+			}
+		}
+	}
+	
+	if (iStartPathNodeIndex < GetArraySize(hNavPath))
+	{
+		return iStartPathNodeIndex;
+	}
+	
+	return GetArraySize(hNavPath) - 1;
+}
+
+
+stock CalculateFeelerReflexAdjustment(const Float:flOriginalMovePos[3], 
+	const Float:flOriginalFeetPos[3], 
+	const Float:flFloorNormalDir[3],
+	Float:flFeelerHeight, 
+	Float:flFeelerOffset, 
+	Float:flFeelerLength, 
+	Float:flAvoidRange, 
+	Float:flBuffer[3], 
+	iTraceMask=MASK_PLAYERSOLID,
+	Function:fTraceFilterFunction=INVALID_FUNCTION, 
+	any:iTraceFilterFunctionData=-1)
+{
+	// Forward direction vector.
+	decl Float:flOriginalMoveDir[3], Float:flLateralDir[3];
+	SubtractVectors(flOriginalMovePos, flOriginalFeetPos, flOriginalMoveDir);
+	flOriginalMoveDir[2] = 0.0;
+	
+	GetVectorAngles(flOriginalMoveDir, flOriginalMoveDir);
+	GetAngleVectors(flOriginalMoveDir, flOriginalMoveDir, flLateralDir, NULL_VECTOR);
+	NormalizeVector(flOriginalMoveDir, flOriginalMoveDir);
+	NormalizeVector(flLateralDir, flLateralDir);
+	NegateVector(flLateralDir);
+	
+	// Correct move direction vector along floor.
+	decl Float:flDir[3];
+	GetVectorCrossProduct(flLateralDir, flFloorNormalDir, flDir);
+	NormalizeVector(flDir, flDir);
+	
+	// Correct lateral direction vector along floor.
+	GetVectorCrossProduct(flDir, flFloorNormalDir, flLateralDir);
+	NormalizeVector(flLateralDir, flLateralDir);
+	
+	if (flFeelerHeight <= 0.0)
+	{
+		flFeelerHeight = StepHeight + 0.1;
+	}
+	
+	decl Float:flFeetPos[3];
+	CopyVector(flOriginalFeetPos, flFeetPos);
+	flFeetPos[2] += flFeelerHeight;
+	
+	decl Float:flFromPos[3];
+	decl Float:flToPos[3];
+	
+	// Check the left.
+	for (new i = 0; i < 3; i++)
+	{
+		flFromPos[i] = flFeetPos[i] + (flFeelerOffset * flLateralDir[i]);
+		flToPos[i] = flFromPos[i] + (flFeelerLength * flDir[i]);
+	}
+	
+	new Handle:hTrace = INVALID_HANDLE;
+	if (fTraceFilterFunction != INVALID_FUNCTION)
+	{
+		hTrace = TR_TraceRayFilterEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint, fTraceFilterFunction, iTraceFilterFunctionData);
+	}
+	else
+	{
+		hTrace = TR_TraceRayEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint);
+	}
+	
+	new bool:bLeftClear = !TR_DidHit(hTrace);
+	CloseHandle(hTrace);
+	
+#if defined DEBUG
+	
+	if (bLeftClear)
+	{
+		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 0, 255, 0, 255 }, 30);
+	}
+	else
+	{
+		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 255, 0, 0, 255 }, 30);
+	}
+	
+	TE_SendToAll();
+	
+#endif
+	
+	// Check the right.
+	for (new i = 0; i < 3; i++)
+	{
+		flFromPos[i] = flFeetPos[i] - (flFeelerOffset * flLateralDir[i]);
+		flToPos[i] = flFromPos[i] + (flFeelerLength * flDir[i]);
+	}
+	
+	if (fTraceFilterFunction != INVALID_FUNCTION)
+	{
+		hTrace = TR_TraceRayFilterEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint, fTraceFilterFunction, iTraceFilterFunctionData);
+	}
+	else
+	{
+		hTrace = TR_TraceRayEx(flFromPos, flToPos, iTraceMask, RayType_EndPoint);
+	}
+	
+	new bool:bRightClear = !TR_DidHit(hTrace);
+	CloseHandle(hTrace);
+	
+#if defined DEBUG
+	
+	if (bRightClear)
+	{
+		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 0, 255, 0, 255 }, 30);
+	}
+	else
+	{
+		TE_SetupBeamPoints(flFromPos, flToPos, PrecacheModel("sprites/laser.vmt"), PrecacheModel("sprites/laser.vmt"), 0, 30, 0.1, 5.0, 5.0, 1, 0.0, { 255, 0, 0, 255 }, 30);
+	}
+	
+	TE_SendToAll();
+	
+#endif
+	
+	if (!bRightClear)
+	{
+		if (bLeftClear)
+		{
+			for (new i = 0; i < 3; i++)
+			{
+				flBuffer[i] = flOriginalMovePos[i] + (flAvoidRange * flLateralDir[i]);
+			}
+		}
+	}
+	else if (!bLeftClear)
+	{
+		for (new i = 0; i < 3; i++)
+		{
+			flBuffer[i] = flOriginalMovePos[i] - (flAvoidRange * flLateralDir[i]);
+		}
+	}
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/npc.sp b/addons/sourcemod/scripting/rytp_horror/npc.sp
index 06b0cde..e916e36 100644
--- a/addons/sourcemod/scripting/rytp_horror/npc.sp
+++ b/addons/sourcemod/scripting/rytp_horror/npc.sp
@@ -1,2679 +1,2675 @@
-#if defined _sf2_npc_included
- #endinput
-#endif
-#define _sf2_npc_included
-
-#define SF2_BOSS_PAGE_CALCULATION 0.3
-#define SF2_BOSS_COPY_SPAWN_MIN_DISTANCE 1850.0 // The default minimum distance boss copies can spawn from each other.
-
-#define SF2_BOSS_ATTACK_MELEE 0
-
-static g_iNPCGlobalUniqueID = 0;
-
-static g_iNPCUniqueID[MAX_BOSSES] = { -1, ... };
-static String:g_strSlenderProfile[MAX_BOSSES][SF2_MAX_PROFILE_NAME_LENGTH];
-static g_iNPCProfileIndex[MAX_BOSSES] = { -1, ... };
-static g_iNPCUniqueProfileIndex[MAX_BOSSES] = { -1, ... };
-static g_iNPCType[MAX_BOSSES] = { SF2BossType_Unknown, ... };
-static g_iNPCFlags[MAX_BOSSES] = { 0, ... };
-static Float:g_flNPCModelScale[MAX_BOSSES] = { 1.0, ... };
-
-static Float:g_flNPCFieldOfView[MAX_BOSSES] = { 0.0, ... };
-static Float:g_flNPCTurnRate[MAX_BOSSES] = { 0.0, ... };
-
-static g_iSlender[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-
-static Float:g_flNPCSpeed[MAX_BOSSES][Difficulty_Max];
-static Float:g_flNPCMaxSpeed[MAX_BOSSES][Difficulty_Max];
-
-static Float:g_flNPCScareRadius[MAX_BOSSES];
-static Float:g_flNPCScareCooldown[MAX_BOSSES];
-
-static g_iNPCTeleportType[MAX_BOSSES] = { -1, ... };
-
-static Float:g_flNPCAnger[MAX_BOSSES] = { 1.0, ... };
-static Float:g_flNPCAngerAddOnPageGrab[MAX_BOSSES] = { 0.0, ... };
-static Float:g_flNPCAngerAddOnPageGrabTimeDiff[MAX_BOSSES] = { 0.0, ... };
-
-static Float:g_flNPCSearchRadius[MAX_BOSSES] = { 0.0, ... };
-static Float:g_flNPCInstantKillRadius[MAX_BOSSES] = { 0.0, ... };
-
-static bool:g_bNPCDeathCamEnabled[MAX_BOSSES] = { false, ... };
-
-static g_iNPCEnemy[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-
-#if defined METHODMAPS
-
-const SF2NPC_BaseNPC SF2_INVALID_NPC = SF2NPC_BaseNPC:-1;
-
-methodmap SF2NPC_BaseNPC
-{
-	property int Index
-	{
-		public get() { return _:this; }
-	}
-	
-	property int Type
-	{
-		public get() { return NPCGetType(this.Index); }
-	}
-	
-	property int ProfileIndex
-	{
-		public get() { return NPCGetProfileIndex(this.Index); }
-	}
-	
-	property int UniqueProfileIndex
-	{
-		public get() { return NPCGetUniqueProfileIndex(this.Index); }
-	}
-	
-	property int EntRef
-	{
-		public get() { return NPCGetEntRef(this.Index); }
-	}
-	
-	property int EntIndex
-	{
-		public get() { return NPCGetEntIndex(this.Index); }
-	}
-	
-	property int Flags
-	{
-		public get() { return NPCGetFlags(this.Index); }
-		public set(int flags) { NPCSetFlags(this.Index); }
-	}
-	
-	property float ModelScale
-	{
-		public get() { return NPCGetModelScale(this.Index) };
-	}
-	
-	property float TurnRate
-	{
-		public get() { return NPCGetTurnRate(this.Index) };
-	}
-	
-	property float FOV
-	{
-		public get() { return NPCGetFOV(this.Index); }
-	}
-	
-	property float Anger
-	{
-		public get() { return NPCGetAnger(this.Index); }
-		public set(float amount) { NPCSetAnger(this.Index, amount); }
-	}
-	
-	property float AngerAddOnPageGrab
-	{
-		public get() { return NPCGetAngerAddOnPageGrab(this.Index); }
-	}
-	
-	property float AngerAddOnPageGrabTimeDiff
-	{
-		public get() { return NPCGetAngerAddOnPageGrabTimeDiff(this.Index); }
-	}
-	
-	property float SearchRadius
-	{
-		public get() { return NPCGetSearchRadius(this.Index); }
-	}
-	
-	property float ScareRadius
-	{
-		public get() { return NPCGetScareRadius(this.Index); }
-	}
-	
-	property float ScareCooldown
-	{
-		public get() { return NPCGetScareCooldown(this.Index); }
-	}
-	
-	property float InstantKillRadius
-	{
-		public get() { return NPCGetInstantKillRadius(this.Index); }
-	}
-	
-	property int TeleportType
-	{
-		public get() { return NPCGetTeleportType(this.Index); }
-	}
-	
-	property int Enemy
-	{
-		public get() { return NPCGetEnemy(this.Index); }
-		public set(int entIndex) { NPCSetEnemy(this.Index, entIndex); }
-	}
-	
-	property bool DeathCamEnabled
-	{
-		public get() { return NPCHasDeathCamEnabled(this.Index); }
-		public set(bool state) { NPCSetDeathCamEnabled(this.Index, state); }
-	}
-	
-	public SF2NPC_BaseNPC(int index)
-	{
-		return SF2NPC_BaseNPC:index;
-	}
-	
-	public ~SF2NPC_BaseNPC()
-	{
-		NPCRemove(this.Index);
-	}
-	
-	public bool IsValid()
-	{
-		return NPCIsValid(this.Index);
-	}
-	
-	public void GetProfile(char[] buffer, int bufferlen) 
-	{
-		NPCGetProfile(this.Index, buffer, bufferlen);
-	}
-	
-	public void SetProfile(const char[] profileName)
-	{
-		NPCSetProfile(this.Index, profileName);
-	}
-	
-	public float GetSpeed(int difficulty)
-	{
-		return NPCGetSpeed(this.Index, difficulty);
-	}
-	
-	public float GetMaxSpeed(int difficulty)
-	{
-		return NPCGetMaxSpeed(this.Index, difficulty);
-	}
-	
-	public void GetEyePosition(float buffer[3], const float defaultValue[3] = { 0.0, 0.0, 0.0 })
-	{
-		NPCGetEyePosition(this.Index, buffer, defaultValue);
-	}
-	
-	public void GetEyePositionOffset(float buffer[3])
-	{
-		NPCGetEyePositionOffset(this.Index, buffer);
-	}
-	
-	public void AddAnger(float amount)
-	{
-		NPCAddAnger(this.Index, amount);
-	}
-	
-	public bool HasAttribute(const char[] attributeName)
-	{
-		return NPCHasAttribute(this.Index, attributeName);
-	}
-	
-	public float GetAttributeValue(const char[] attributeName, float defaultValue = 0.0)
-	{
-		return NPCGetAttributeValue(this.Index, attributeName, defaultValue);
-	}
-}
-
-#endif
-
-bool:NPCHasDeathCamEnabled(iNPCIndex)
-{
-	return g_bNPCDeathCamEnabled[iNPCIndex];
-}
-
-NPCSetDeathCamEnabled(iNPCIndex, bool:state)
-{
-	g_bNPCDeathCamEnabled[iNPCIndex] = state;
-}
-
-public NPCInitialize()
-{
-	NPCChaserInitialize();
-}
-
-public NPCOnConfigsExecuted()
-{
-	g_iNPCGlobalUniqueID = 0;
-}
-
-bool:NPCIsValid(iNPCIndex)
-{
-	return bool:(iNPCIndex >= 0 && iNPCIndex < MAX_BOSSES && NPCGetUniqueID(iNPCIndex) != -1);
-}
-
-NPCGetUniqueID(iNPCIndex)
-{
-	return g_iNPCUniqueID[iNPCIndex];
-}
-
-NPCGetFromUniqueID(iNPCUniqueID)
-{
-	if (iNPCUniqueID == -1) return -1;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == iNPCUniqueID)
-		{
-			return i;
-		}
-	}
-	
-	return -1;
-}
-
-NPCGetEntRef(iNPCIndex)
-{
-	return g_iSlender[iNPCIndex];
-}
-
-NPCGetEntIndex(iNPCIndex)
-{
-	return EntRefToEntIndex(NPCGetEntRef(iNPCIndex));
-}
-
-NPCGetFromEntIndex(entity)
-{
-	if (!entity || !IsValidEntity(entity)) return -1;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetEntIndex(i) == entity)
-		{
-			return i;
-		}
-	}
-	
-	return -1;
-}
-
-NPCGetCount()
-{
-	new iCount;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		if (NPCGetFlags(i) & SFF_FAKE) continue;
-		
-		iCount++;
-	}
-	
-	return iCount;
-}
-
-NPCGetProfileIndex(iNPCIndex)
-{
-	return g_iNPCProfileIndex[iNPCIndex];
-}
-
-NPCGetUniqueProfileIndex(iNPCIndex)
-{
-	return g_iNPCUniqueProfileIndex[iNPCIndex];
-}
-
-bool:NPCGetProfile(iNPCIndex, String:buffer[], bufferlen)
-{
-	if(iNPCIndex < 0 || iNPCIndex >= sizeof(g_strSlenderProfile)) {
-		return false;
-	}
-	
-	strcopy(buffer, bufferlen, g_strSlenderProfile[iNPCIndex]);
-	return true;
-}
-
-NPCSetProfile(iNPCIndex, const String:sProfile[])
-{
-	strcopy(g_strSlenderProfile[iNPCIndex], sizeof(g_strSlenderProfile[]), sProfile);
-}
-
-NPCRemove(iNPCIndex)
-{
-	if (!NPCIsValid(iNPCIndex)) return;
-	
-	RemoveProfile(iNPCIndex);
-}
-
-NPCRemoveAll()
-{
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		NPCRemove(i);
-	}
-}
-
-NPCGetType(iNPCIndex)
-{
-	return g_iNPCType[iNPCIndex];
-}
-
-NPCGetFlags(iNPCIndex)
-{
-	return g_iNPCFlags[iNPCIndex];
-}
-
-NPCSetFlags(iNPCIndex, iFlags)
-{
-	g_iNPCFlags[iNPCIndex] = iFlags;
-}
-
-Float:NPCGetModelScale(iNPCIndex)
-{
-	return g_flNPCModelScale[iNPCIndex];
-}
-
-Float:NPCGetSpeed(iNPCIndex, iDifficulty)
-{
-	return g_flNPCSpeed[iNPCIndex][iDifficulty];
-}
-
-Float:NPCGetMaxSpeed(iNPCIndex, iDifficulty)
-{
-	return g_flNPCMaxSpeed[iNPCIndex][iDifficulty];
-}
-
-Float:NPCGetTurnRate(iNPCIndex)
-{
-	return g_flNPCTurnRate[iNPCIndex];
-}
-
-Float:NPCGetFOV(iNPCIndex)
-{
-	return g_flNPCFieldOfView[iNPCIndex];
-}
-
-Float:NPCGetAnger(iNPCIndex)
-{
-	return g_flNPCAnger[iNPCIndex];
-}
-
-NPCSetAnger(iNPCIndex, Float:flAnger)
-{
-	g_flNPCAnger[iNPCIndex] = flAnger;
-}
-
-NPCAddAnger(iNPCIndex, Float:flAmount)
-{
-	g_flNPCAnger[iNPCIndex] += flAmount;
-}
-
-Float:NPCGetAngerAddOnPageGrab(iNPCIndex)
-{
-	return g_flNPCAngerAddOnPageGrab[iNPCIndex];
-}
-
-Float:NPCGetAngerAddOnPageGrabTimeDiff(iNPCIndex)
-{
-	return g_flNPCAngerAddOnPageGrabTimeDiff[iNPCIndex];
-}
-
-NPCGetEyePositionOffset(iNPCIndex, Float:buffer[3])
-{
-	buffer[0] = g_flSlenderEyePosOffset[iNPCIndex][0];
-	buffer[1] = g_flSlenderEyePosOffset[iNPCIndex][1];
-	buffer[2] = g_flSlenderEyePosOffset[iNPCIndex][2];
-}
-
-Float:NPCGetSearchRadius(iNPCIndex)
-{
-	return g_flNPCSearchRadius[iNPCIndex];
-}
-
-Float:NPCGetScareRadius(iNPCIndex)
-{
-	return g_flNPCScareRadius[iNPCIndex];
-}
-
-Float:NPCGetScareCooldown(iNPCIndex)
-{
-	return g_flNPCScareCooldown[iNPCIndex];
-}
-
-Float:NPCGetInstantKillRadius(iNPCIndex)
-{
-	return g_flNPCInstantKillRadius[iNPCIndex];
-}
-
-NPCGetTeleportType(iNPCIndex)
-{
-	return g_iNPCTeleportType[iNPCIndex];
-}
-
-stock NPCGetEnemy(iNPCIndex)
-{
-	return g_iNPCEnemy[iNPCIndex];
-}
-
-stock NPCSetEnemy(iNPCIndex, ent)
-{
-	g_iNPCEnemy[iNPCIndex] = IsValidEntity(ent) ? EntIndexToEntRef(ent) : INVALID_ENT_REFERENCE;
-}
-
-/**
- *	Returns the boss's eye position (eye pos offset + absorigin).
- */
-bool:NPCGetEyePosition(iNPCIndex, Float:buffer[3], const Float:flDefaultValue[3]={ 0.0, 0.0, 0.0 })
-{
-	buffer[0] = flDefaultValue[0];
-	buffer[1] = flDefaultValue[1];
-	buffer[2] = flDefaultValue[2];
-	
-	if (!NPCIsValid(iNPCIndex)) return false;
-	
-	new iNPC = NPCGetEntIndex(iNPCIndex);
-	if (!iNPC || iNPC == INVALID_ENT_REFERENCE) return false;
-	
-	// @TODO: Replace SlenderGetAbsOrigin with GetEntPropVector
-	decl Float:flPos[3], Float:flEyePosOffset[3];
-	SlenderGetAbsOrigin(iNPCIndex, flPos);
-	NPCGetEyePositionOffset(iNPCIndex, flEyePosOffset);
-	
-	AddVectors(flPos, flEyePosOffset, buffer);
-	return true;
-}
-
-bool:NPCHasAttribute(iNPCIndex, const String:sAttribute[])
-{
-	if (NPCGetUniqueID(iNPCIndex) == -1) return false;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iNPCIndex, sProfile, sizeof(sProfile));
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	if (!KvJumpToKey(g_hConfig, "attributes")) return false;
-	
-	return KvJumpToKey(g_hConfig, sAttribute);
-}
-
-Float:NPCGetAttributeValue(iNPCIndex, const String:sAttribute[], Float:flDefaultValue=0.0)
-{
-	if (!NPCHasAttribute(iNPCIndex, sAttribute)) return flDefaultValue;
-	return KvGetFloat(g_hConfig, "value", flDefaultValue);
-}
-
-bool:SlenderCanRemove(iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1) return false;
-	
-	if (PeopleCanSeeSlender(iBossIndex, _, false)) return false;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new iTeleportType = GetProfileNum(sProfile, "teleport_type");
-	
-	switch (iTeleportType)
-	{
-		case 0:
-		{
-			if (GetProfileNum(sProfile, "static_on_radius"))
-			{
-				decl Float:flSlenderPos[3], Float:flBuffer[3];
-				SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
-			
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || 
-						!IsPlayerAlive(i) || 
-						g_bPlayerEliminated[i] || 
-						IsClientInGhostMode(i) || 
-						IsClientInDeathCam(i)) continue;
-					
-					if (!IsPointVisibleToPlayer(i, flSlenderPos, false, false)) continue;
-					
-					GetClientAbsOrigin(i, flBuffer);
-					if (GetVectorDistance(flBuffer, flSlenderPos) <= GetProfileFloat(sProfile, "static_radius"))
-					{
-						return false;
-					}
-				}
-			}
-		}
-		case 1:
-		{
-			if (PeopleCanSeeSlender(iBossIndex, _, SlenderUsesBlink(iBossIndex)) || PeopleCanSeeSlender(iBossIndex, false, false))
-			{
-				return false;
-			}
-		}
-		case 2:
-		{
-			new iState = g_iSlenderState[iBossIndex];
-			if (iState == STATE_IDLE || iState == STATE_WANDER)
-			{
-				if (GetGameTime() < g_flSlenderTimeUntilKill[iBossIndex])
-				{
-					return false;
-				}
-			}
-			else
-			{
-				return false;
-			}
-		}
-	}
-	
-	return true;
-}
-
-bool:SlenderGetAbsOrigin(iBossIndex, Float:buffer[3], const Float:flDefaultValue[3]={ 0.0, 0.0, 0.0 })
-{
-	for (new i = 0; i < 3; i++) buffer[i] = flDefaultValue[i];
-	
-	if (iBossIndex < 0 || NPCGetUniqueID(iBossIndex) == -1) return false;
-	
-	new slender = NPCGetEntIndex(iBossIndex);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return false;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl Float:flPos[3], Float:flOffset[3];
-	GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flPos);
-	GetProfileVector(sProfile, "pos_offset", flOffset, flDefaultValue);
-	SubtractVectors(flPos, flOffset, buffer);
-	
-	return true;
-}
-
-bool:SlenderGetEyePosition(iBossIndex, Float:buffer[3], const Float:flDefaultValue[3]={ 0.0, 0.0, 0.0 })
-{
-	return NPCGetEyePosition(iBossIndex, buffer, flDefaultValue);
-}
-
-bool:SelectProfile(iBossIndex, const String:sProfile[], iAdditionalBossFlags=0, iCopyMaster=-1, bool:bSpawnCompanions=true, bool:bPlaySpawnSound=true)
-{
-	if (!IsProfileValid(sProfile))
-	{
-		LogSF2Message("Could not select profile for boss %d: profile %s is invalid!", iBossIndex, sProfile);
-		return false;
-	}
-	
-	NPCRemove(iBossIndex);
-	
-	new iProfileIndex = GetBossProfileIndexFromName(sProfile);
-	new iUniqueProfileIndex = GetBossProfileUniqueProfileIndex(iProfileIndex);
-	
-	NPCSetProfile(iBossIndex, sProfile);
-	
-	new iBossType = GetBossProfileType(iProfileIndex);
-	
-	g_iNPCProfileIndex[iBossIndex] = iProfileIndex;
-	g_iNPCUniqueProfileIndex[iBossIndex] = iUniqueProfileIndex;
-	g_iNPCUniqueID[iBossIndex] = g_iNPCGlobalUniqueID++;
-	g_iNPCType[iBossIndex] = iBossType;
-	
-	g_flNPCModelScale[iBossIndex] = GetBossProfileModelScale(iProfileIndex);
-	
-	NPCSetFlags(iBossIndex, GetBossProfileFlags(iProfileIndex) | iAdditionalBossFlags);
-	
-	GetBossProfileEyePositionOffset(iProfileIndex, g_flSlenderEyePosOffset[iBossIndex]);
-	GetBossProfileEyeAngleOffset(iProfileIndex, g_flSlenderEyeAngOffset[iBossIndex]);
-	
-	GetProfileVector(sProfile, "mins", g_flSlenderDetectMins[iBossIndex]);
-	GetProfileVector(sProfile, "maxs", g_flSlenderDetectMaxs[iBossIndex]);
-	
-	NPCSetAnger(iBossIndex, GetBossProfileAngerStart(iProfileIndex));
-	g_flNPCAngerAddOnPageGrab[iBossIndex] = GetBossProfileAngerAddOnPageGrab(iProfileIndex);
-	g_flNPCAngerAddOnPageGrabTimeDiff[iBossIndex] = GetBossProfileAngerPageGrabTimeDiff(iProfileIndex);
-	
-	g_iSlenderCopyMaster[iBossIndex] = -1;
-	g_iSlenderHealth[iBossIndex] = GetProfileNum(sProfile, "health", 900);
-	
-	for (new iDifficulty = 0; iDifficulty < Difficulty_Max; iDifficulty++)
-	{
-		g_flNPCSpeed[iBossIndex][iDifficulty] = GetBossProfileSpeed(iProfileIndex, iDifficulty);
-		g_flNPCMaxSpeed[iBossIndex][iDifficulty] = GetBossProfileMaxSpeed(iProfileIndex, iDifficulty);
-	}
-	
-	g_flNPCTurnRate[iBossIndex] = GetBossProfileTurnRate(iProfileIndex);
-	g_flNPCFieldOfView[iBossIndex] = GetBossProfileFOV(iProfileIndex);
-	
-	g_flNPCSearchRadius[iBossIndex] = GetBossProfileSearchRadius(iProfileIndex);
-	
-	g_flNPCScareRadius[iBossIndex] = GetBossProfileScareRadius(iProfileIndex);
-	g_flNPCScareCooldown[iBossIndex] = GetBossProfileScareCooldown(iProfileIndex);
-	
-	g_flNPCInstantKillRadius[iBossIndex] = GetBossProfileInstantKillRadius(iProfileIndex);
-	
-	g_iNPCTeleportType[iBossIndex] = GetBossProfileTeleportType(iProfileIndex);
-	
-	g_iNPCEnemy[iBossIndex] = INVALID_ENT_REFERENCE;
-	
-	// Deathcam values.
-	NPCSetDeathCamEnabled(iBossIndex, bool:GetProfileNum(sProfile, "death_cam"));
-	
-	g_flSlenderAcceleration[iBossIndex] = GetProfileFloat(sProfile, "acceleration", 150.0);
-	g_hSlenderFakeTimer[iBossIndex] = INVALID_HANDLE;
-	g_hSlenderEntityThink[iBossIndex] = INVALID_HANDLE;
-	g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
-	g_flSlenderNextTeleportTime[iBossIndex] = GetGameTime();
-	g_flSlenderLastKill[iBossIndex] = GetGameTime();
-	g_flSlenderTimeUntilKill[iBossIndex] = -1.0;
-	g_flSlenderNextJumpScare[iBossIndex] = -1.0;
-	g_flSlenderTimeUntilNextProxy[iBossIndex] = -1.0;
-	g_flSlenderTeleportMinRange[iBossIndex] = GetProfileFloat(sProfile, "teleport_range_min", 325.0);
-	g_flSlenderTeleportMaxRange[iBossIndex] = GetProfileFloat(sProfile, "teleport_range_max", 1024.0);
-	g_flSlenderStaticRadius[iBossIndex] = GetProfileFloat(sProfile, "static_radius");
-	g_flSlenderIdleAnimationPlaybackRate[iBossIndex] = GetProfileFloat(sProfile, "animation_idle_playbackrate", 1.0);
-	g_flSlenderWalkAnimationPlaybackRate[iBossIndex] = GetProfileFloat(sProfile, "animation_walk_playbackrate", 1.0);
-	g_flSlenderRunAnimationPlaybackRate[iBossIndex] = GetProfileFloat(sProfile, "animation_run_playbackrate", 1.0);
-	g_flSlenderJumpSpeed[iBossIndex] = GetProfileFloat(sProfile, "jump_speed", 512.0);
-	g_flSlenderPathNodeTolerance[iBossIndex] = GetProfileFloat(sProfile, "search_node_dist_tolerance", 32.0);
-	g_flSlenderPathNodeLookAhead[iBossIndex] = GetProfileFloat(sProfile, "search_node_dist_lookahead", 512.0);
-	g_flSlenderProxyTeleportMinRange[iBossIndex] = GetProfileFloat(sProfile, "proxies_teleport_range_min");
-	g_flSlenderProxyTeleportMaxRange[iBossIndex] = GetProfileFloat(sProfile, "proxies_teleport_range_max");
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		g_flPlayerLastChaseBossEncounterTime[i][iBossIndex] = -1.0;
-		g_flSlenderTeleportPlayersRestTime[iBossIndex][i] = -1.0;
-	}
-	
-	g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-	g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
-	g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
-	g_flSlenderNextTeleportTime[iBossIndex] = -1.0;
-	g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
-	
-	g_hSlenderThink[iBossIndex] = CreateTimer(0.1, Timer_SlenderTeleportThink, iBossIndex, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	
-	SlenderRemoveTargetMemory(iBossIndex);
-	
-	switch (iBossType)
-	{
-		case SF2BossType_Chaser:
-		{
-			NPCChaserOnSelectProfile(iBossIndex);
-			
-			SlenderCreateTargetMemory(iBossIndex);
-		}
-	}
-	
-	if (iCopyMaster >= 0 && iCopyMaster < MAX_BOSSES && NPCGetUniqueID(iCopyMaster) != -1)
-	{
-		g_iSlenderCopyMaster[iBossIndex] = iCopyMaster;
-		g_flSlenderNextJumpScare[iBossIndex] = g_flSlenderNextJumpScare[iCopyMaster];
-		
-		NPCSetAnger(iBossIndex, NPCGetAnger(iCopyMaster));
-	}
-	else
-	{
-		if (bPlaySpawnSound)
-		{
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_spawn_all", sBuffer, sizeof(sBuffer));
-			if (sBuffer[0]) EmitSoundToAll(sBuffer, _, SNDCHAN_STATIC, SNDLEVEL_HELICOPTER);
-		}
-		
-		if (bSpawnCompanions)
-		{
-			KvRewind(g_hConfig);
-			KvJumpToKey(g_hConfig, sProfile);
-			
-			decl String:sCompProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			new Handle:hCompanions = CreateArray(SF2_MAX_PROFILE_NAME_LENGTH);
-			
-			if (KvJumpToKey(g_hConfig, "companions"))
-			{
-				decl String:sNum[32];
-				
-				for (new i = 1;;i++)
-				{
-					IntToString(i, sNum, sizeof(sNum));
-					KvGetString(g_hConfig, sNum, sCompProfile, sizeof(sCompProfile));
-					if (!sCompProfile[0]) break;
-					
-					PushArrayString(hCompanions, sCompProfile);
-				}
-			}
-			
-			for (new i = 0, iSize = GetArraySize(hCompanions); i < iSize; i++)
-			{
-				GetArrayString(hCompanions, i, sCompProfile, sizeof(sCompProfile));
-				AddProfile(sCompProfile, _, _, false, false);
-			}
-			
-			CloseHandle(hCompanions);
-		}
-	}
-	
-	Call_StartForward(fOnBossAdded);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-	
-	return true;
-}
-
-AddProfile(const String:strName[], iAdditionalBossFlags=0, iCopyMaster=-1, bool:bSpawnCompanions=true, bool:bPlaySpawnSound=true)
-{
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1)
-		{
-			if (SelectProfile(i, strName, iAdditionalBossFlags, iCopyMaster, bSpawnCompanions, bPlaySpawnSound))
-			{
-				return i;
-			}
-			
-			break;
-		}
-	}
-	
-	return -1;
-}
-
-RemoveProfile(iBossIndex)
-{
-	RemoveSlender(iBossIndex);
-	
-	// Call our forward.
-	Call_StartForward(fOnBossRemoved);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	NPCChaserOnRemoveProfile(iBossIndex);
-	
-	// Remove all possible sounds, for emergencies.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		// Remove chase music.
-		if (g_iPlayerChaseMusicMaster[i] == iBossIndex)
-		{
-			ClientStopAllSlenderSounds(i, sProfile, "sound_chase", SNDCHAN_AUTO);
-		}
-	}
-	
-	// Clean up on the clients.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		g_flSlenderLastFoundPlayer[iBossIndex][i] = -1.0;
-		g_flPlayerLastChaseBossEncounterTime[i][iBossIndex] = -1.0;
-		g_flSlenderTeleportPlayersRestTime[iBossIndex][i] = -1.0;
-		
-		for (new i2 = 0; i2 < 3; i2++)
-		{
-			g_flSlenderLastFoundPlayerPos[iBossIndex][i][i2] = 0.0;
-		}
-		
-		if (IsClientInGame(i))
-		{
-			if (NPCGetUniqueID(iBossIndex) == g_iPlayerStaticMaster[i])
-			{
-				g_iPlayerStaticMaster[i] = -1;
-				
-				// No one is the static master.
-				g_hPlayerStaticTimer[i] = CreateTimer(g_flPlayerStaticDecreaseRate[i], 
-					Timer_ClientDecreaseStatic, 
-					GetClientUserId(i), 
-					TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-					
-				TriggerTimer(g_hPlayerStaticTimer[i], true);
-			}
-		}
-	}
-	
-	g_iNPCTeleportType[iBossIndex] = -1;
-	g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-	g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
-	g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
-	g_flSlenderNextTeleportTime[iBossIndex] = -1.0;
-	g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
-	g_flSlenderTimeUntilKill[iBossIndex] = -1.0;
-	
-	// Remove all copies associated with me.
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (i == iBossIndex || NPCGetUniqueID(i) == -1) continue;
-		
-		if (g_iSlenderCopyMaster[i] == iBossIndex)
-		{
-			LogMessage("Removed boss index %d because it is a copy of boss index %d", i, iBossIndex);
-			NPCRemove(i);
-		}
-	}
-	
-	NPCSetProfile(iBossIndex, "");
-	g_iNPCType[iBossIndex] = -1;
-	g_iNPCProfileIndex[iBossIndex] = -1;
-	g_iNPCUniqueProfileIndex[iBossIndex] = -1;
-	
-	NPCSetFlags(iBossIndex, 0);
-	
-	NPCSetAnger(iBossIndex, 1.0);
-	
-	g_flNPCFieldOfView[iBossIndex] = 0.0;
-	
-	g_iNPCEnemy[iBossIndex] = INVALID_ENT_REFERENCE;
-	
-	NPCSetDeathCamEnabled(iBossIndex, false);
-	
-	g_iSlenderCopyMaster[iBossIndex] = -1;
-	g_iNPCUniqueID[iBossIndex] = -1;
-	g_iSlender[iBossIndex] = INVALID_ENT_REFERENCE;
-	g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
-	g_hSlenderThink[iBossIndex] = INVALID_HANDLE;
-	g_hSlenderEntityThink[iBossIndex] = INVALID_HANDLE;
-	
-	g_hSlenderFakeTimer[iBossIndex] = INVALID_HANDLE;
-	g_flSlenderLastKill[iBossIndex] = -1.0;
-	g_iSlenderState[iBossIndex] = STATE_IDLE;
-	g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-	g_iSlenderModel[iBossIndex] = INVALID_ENT_REFERENCE;
-	g_flSlenderAcceleration[iBossIndex] = 0.0;
-	g_flSlenderTimeUntilNextProxy[iBossIndex] = -1.0;
-	g_flNPCSearchRadius[iBossIndex] = 0.0;
-	g_flNPCInstantKillRadius[iBossIndex] = 0.0;
-	g_flNPCScareRadius[iBossIndex] = 0.0;
-	g_flSlenderProxyTeleportMinRange[iBossIndex] = 0.0;
-	g_flSlenderProxyTeleportMaxRange[iBossIndex] = 0.0;
-	
-	for (new i = 0; i < 3; i++)
-	{
-		g_flSlenderDetectMins[iBossIndex][i] = 0.0;
-		g_flSlenderDetectMaxs[iBossIndex][i] = 0.0;
-		g_flSlenderEyePosOffset[iBossIndex][i] = 0.0;
-	}
-	
-	SlenderRemoveTargetMemory(iBossIndex);
-}
-
-SpawnSlender(iBossIndex, const Float:pos[3])
-{
-	RemoveSlender(iBossIndex);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl Float:flTruePos[3];
-	GetProfileVector(sProfile, "pos_offset", flTruePos);
-	AddVectors(flTruePos, pos, flTruePos);
-	
-	new iSlenderModel = SpawnSlenderModel(iBossIndex, flTruePos);
-	if (iSlenderModel == -1) 
-	{
-		LogError("Could not spawn boss: model failed to spawn!");
-		return;
-	}
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	
-	g_iSlenderModel[iBossIndex] = EntIndexToEntRef(iSlenderModel);
-	
-	switch (NPCGetType(iBossIndex))
-	{
-		case SF2BossType_Creeper:
-		{
-			g_iSlender[iBossIndex] = g_iSlenderModel[iBossIndex];
-			g_hSlenderEntityThink[iBossIndex] = CreateTimer(BOSS_THINKRATE, Timer_SlenderBlinkBossThink, g_iSlender[iBossIndex], TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-		}
-		case SF2BossType_Chaser:
-		{
-			GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
-			
-			new iBoss = CreateEntityByName("monster_generic");
-			SetEntityModel(iBoss, sBuffer);
-			TeleportEntity(iBoss, flTruePos, NULL_VECTOR, NULL_VECTOR);
-			DispatchSpawn(iBoss);
-			ActivateEntity(iBoss);
-			SetEntityRenderMode(iBoss, RENDER_TRANSCOLOR);
-			SetEntityRenderColor(iBoss, 0, 0, 0, 1);
-			SetVariantString("!activator");
-			AcceptEntityInput(iSlenderModel, "SetParent", iBoss);
-			AcceptEntityInput(iSlenderModel, "EnableShadow");
-			SetEntProp(iSlenderModel, Prop_Send, "m_usSolidFlags", FSOLID_NOT_SOLID | FSOLID_TRIGGER);
-			AcceptEntityInput(iBoss, "DisableShadow");
-			SetEntPropFloat(iBoss, Prop_Data, "m_flFriction", 0.0);
-			
-			NPCChaserSetStunHealth(iBossIndex, NPCChaserGetStunInitialHealth(iBossIndex));
-			
-			// Reset stats.
-			g_iSlender[iBossIndex] = EntIndexToEntRef(iBoss);
-			g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-			g_iSlenderState[iBossIndex] = STATE_IDLE;
-			g_bSlenderAttacking[iBossIndex] = false;
-			g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
-			g_flSlenderTargetSoundLastTime[iBossIndex] = -1.0;
-			g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = -1.0;
-			g_iSlenderTargetSoundType[iBossIndex] = SoundType_None;
-			g_bSlenderInvestigatingSound[iBossIndex] = false;
-			g_flSlenderLastHeardFootstep[iBossIndex] = GetGameTime();
-			g_flSlenderLastHeardVoice[iBossIndex] = GetGameTime();
-			g_flSlenderLastHeardWeapon[iBossIndex] = GetGameTime();
-			g_flSlenderNextVoiceSound[iBossIndex] = GetGameTime();
-			g_flSlenderNextMoanSound[iBossIndex] = GetGameTime();
-			g_flSlenderNextWanderPos[iBossIndex] = GetGameTime() + 3.0;
-			g_flSlenderTimeUntilKill[iBossIndex] = GetGameTime() + GetProfileFloat(sProfile, "idle_lifetime", 10.0);
-			g_flSlenderTimeUntilRecover[iBossIndex] = -1.0;
-			g_flSlenderTimeUntilAlert[iBossIndex] = -1.0;
-			g_flSlenderTimeUntilIdle[iBossIndex] = -1.0;
-			g_flSlenderTimeUntilChase[iBossIndex] = -1.0;
-			g_flSlenderTimeUntilNoPersistence[iBossIndex] = -1.0;
-			g_flSlenderNextJump[iBossIndex] = GetGameTime() + GetProfileFloat(sProfile, "jump_cooldown", 2.0);
-			g_flSlenderNextPathTime[iBossIndex] = GetGameTime();
-			g_hSlenderEntityThink[iBossIndex] = CreateTimer(BOSS_THINKRATE, Timer_SlenderChaseBossThink, EntIndexToEntRef(iBoss), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			g_iSlenderInterruptConditions[iBossIndex] = 0;
-			g_bSlenderChaseDeathPosition[iBossIndex] = false;
-			
-			for (new i = 0; i < 3; i++)
-			{
-				g_flSlenderGoalPos[iBossIndex][i] = 0.0;
-				g_flSlenderTargetSoundTempPos[iBossIndex][i] = 0.0;
-				g_flSlenderTargetSoundMasterPos[iBossIndex][i] = 0.0;
-				g_flSlenderChaseDeathPosition[iBossIndex][i] = 0.0;
-			}
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				g_flSlenderLastFoundPlayer[iBossIndex][i] = -1.0;
-				
-				for (new i2 = 0; i2 < 3; i2++)
-				{
-					g_flSlenderLastFoundPlayerPos[iBossIndex][i][i2] = 0.0;
-				}
-			}
-			
-			SlenderClearTargetMemory(iBossIndex);
-			
-			if (GetProfileNum(sProfile, "stun_enabled"))
-			{
-				SetEntProp(iBoss, Prop_Data, "m_takedamage", 1);
-			}
-			
-			SDKHook(iBoss, SDKHook_OnTakeDamage, Hook_SlenderOnTakeDamage);
-			SDKHook(iBoss, SDKHook_OnTakeDamagePost, Hook_SlenderOnTakeDamagePost);
-			DHookEntity(g_hSDKShouldTransmit, true, iBoss);
-		}
-		/*
-		default:
-		{
-			g_iSlender[iBossIndex] = g_iSlenderModel[iBossIndex];
-			SDKHook(iSlenderModel, SDKHook_SetTransmit, Hook_SlenderSetTransmit);
-		}
-		*/
-	}
-	
-	SDKHook(iSlenderModel, SDKHook_SetTransmit, Hook_SlenderModelSetTransmit);
-	
-	SlenderSpawnEffects(iBossIndex, EffectEvent_Constant);
-	
-	// Initialize our pose parameters, if needed.
-	new iPose = EntRefToEntIndex(g_iSlenderPoseEnt[iBossIndex]);
-	g_iSlenderPoseEnt[iBossIndex] = INVALID_ENT_REFERENCE;
-	if (iPose && iPose != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(iPose, "Kill");
-	}
-	
-	decl String:sPoseParameter[64];
-	GetProfileString(sProfile, "pose_parameter", sPoseParameter, sizeof(sPoseParameter));
-	if (sPoseParameter[0])
-	{
-		iPose = CreateEntityByName("point_posecontroller");
-		if (iPose != -1)
-		{
-			// We got a pose parameter! We need a name!
-			Format(sBuffer, sizeof(sBuffer), "s%dposepls", g_iSlenderModel[iBossIndex]);
-			DispatchKeyValue(iSlenderModel, "targetname", sBuffer);
-			
-			DispatchKeyValue(iPose, "PropName", sBuffer);
-			DispatchKeyValue(iPose, "PoseParameterName", sPoseParameter);
-			DispatchKeyValueFloat(iPose, "PoseValue", GetProfileFloat(sProfile, "pose_parameter_max"));
-			DispatchSpawn(iPose);
-			SetVariantString(sPoseParameter);
-			AcceptEntityInput(iPose, "SetPoseParameterName");
-			SetVariantString("!activator");
-			AcceptEntityInput(iPose, "SetParent", iSlenderModel);
-			
-			g_iSlenderPoseEnt[iBossIndex] = EntIndexToEntRef(iPose);
-		}
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnBossSpawn);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-}
-
-RemoveSlender(iBossIndex)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-
-	new iBoss = NPCGetEntIndex(iBossIndex);
-	g_iSlender[iBossIndex] = INVALID_ENT_REFERENCE;
-	
-	if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-	{
-		// Stop all possible looping sounds.
-		ClientStopAllSlenderSounds(iBoss, sProfile, "sound_move", SNDCHAN_AUTO);
-		
-		if (NPCGetFlags(iBossIndex) & SFF_HASSTATICLOOPLOCALSOUND)
-		{
-			decl String:sLoopSound[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
-			
-			if (sLoopSound[0])
-			{
-				StopSound(iBoss, SNDCHAN_STATIC, sLoopSound);
-			}
-		}
-		
-		AcceptEntityInput(iBoss, "Kill");
-	}
-}
-
-public Action:Hook_SlenderOnTakeDamage(slender, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return Plugin_Continue;
-	
-	if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-		
-		if (NPCChaserIsStunEnabled(iBossIndex))
-		{
-			if (damagetype & DMG_ACID) damage *= 2.0; // 2x damage for critical hits.
-			
-			NPCChaserAddStunHealth(iBossIndex, -damage);
-		}
-	}
-	
-	damage = 0.0;
-	return Plugin_Changed;
-}
-
-public Hook_SlenderOnTakeDamagePost(slender, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3])
-{
-	if (!g_bEnabled) return;
-
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return;
-	
-	if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
-	{
-		if (damagetype & DMG_ACID)
-		{
-			decl Float:flMyEyePos[3];
-			SlenderGetEyePosition(iBossIndex, flMyEyePos);
-			
-			TE_SetupTFParticleEffect(g_iParticleCriticalHit, flMyEyePos, flMyEyePos);
-			TE_SendToAll();
-			
-			EmitSoundToAll(CRIT_SOUND, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-		}
-	}
-}
-
-public Action:Hook_SlenderModelSetTransmit(entity, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	new iBossIndex = -1;
-	
-	new entref = EntIndexToEntRef(entity);
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		if (g_iSlenderModel[i] != entref) continue;
-		
-		iBossIndex = i;
-		break;
-	}
-	
-	if (iBossIndex == -1) return Plugin_Continue;
-	
-	if (!IsPlayerAlive(other) || IsClientInDeathCam(other)) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-stock bool:SlenderCanHearPlayer(iBossIndex, client, SoundType:iSoundType)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client)) return false;
-	
-	new iSlender = NPCGetEntIndex(iBossIndex);
-	if (!iSlender || iSlender == INVALID_ENT_REFERENCE) return false;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl Float:flHisPos[3], Float:flMyPos[3];
-	GetClientAbsOrigin(client, flHisPos);
-	SlenderGetAbsOrigin(iBossIndex, flMyPos);
-	
-	new Float:flHearRadius = GetProfileFloat(sProfile, "search_sound_range", 1024.0);
-	if (flHearRadius <= 0.0) return false;
-	
-	new Float:flDistance = GetVectorDistance(flHisPos, flMyPos);
-	
-	// Trace check.
-	new Handle:hTrace = INVALID_HANDLE;
-	new bool:bTraceHit = false;
-	
-	decl Float:flMyEyePos[3];
-	SlenderGetEyePosition(iBossIndex, flMyEyePos);
-	
-	if (iSoundType == SoundType_Footstep)
-	{
-		if (!(GetEntityFlags(client) & FL_ONGROUND)) return false;
-		
-		if (GetEntProp(client, Prop_Send, "m_bDucking") || GetEntProp(client, Prop_Send, "m_bDucked")) flDistance *= 1.85;
-		if (IsClientReallySprinting(client)) flDistance *= 0.66;
-		
-		hTrace = TR_TraceRayFilterEx(flMyPos, flHisPos, MASK_NPCSOLID, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, iSlender);
-		bTraceHit = TR_DidHit(hTrace);
-		CloseHandle(hTrace);
-	}
-	else if (iSoundType == SoundType_Voice)
-	{
-		decl Float:flHisEyePos[3];
-		GetClientEyePosition(client, flHisEyePos);
-		
-		hTrace = TR_TraceRayFilterEx(flMyEyePos, flHisEyePos, MASK_NPCSOLID, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, iSlender);
-		bTraceHit = TR_DidHit(hTrace);
-		CloseHandle(hTrace);
-		
-		flDistance *= 0.5;
-	}
-	else if (iSoundType == SoundType_Weapon)
-	{
-		decl Float:flHisMins[3], Float:flHisMaxs[3];
-		GetEntPropVector(client, Prop_Send, "m_vecMins", flHisMins);
-		GetEntPropVector(client, Prop_Send, "m_vecMaxs", flHisMaxs);
-		
-		new Float:flMiddle[3];
-		for (new i = 0; i < 2; i++) flMiddle[i] = (flHisMins[i] + flHisMaxs[i]) / 2.0;
-		
-		decl Float:flEndPos[3];
-		GetClientAbsOrigin(client, flEndPos);
-		AddVectors(flHisPos, flMiddle, flEndPos);
-		
-		hTrace = TR_TraceRayFilterEx(flMyEyePos, flEndPos, MASK_NPCSOLID, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, iSlender);
-		bTraceHit = TR_DidHit(hTrace);
-		CloseHandle(hTrace);
-		
-		flDistance *= 0.66;
-	}
-	
-	if (bTraceHit) flDistance *= 1.66;
-	
-	if (TF2_GetPlayerClass(client) == TFClass_Spy) flDistance *= 1.35;
-	
-	if (flDistance > flHearRadius) return false;
-	
-	return true;
-}
-
-stock SlenderArrayIndexToEntIndex(iBossIndex)
-{
-	return NPCGetEntIndex(iBossIndex);
-}
-
-stock bool:SlenderOnlyLooksIfNotSeen(iBossIndex)
-{
-	if (NPCGetType(iBossIndex) == SF2BossType_Creeper) return true;
-	return false;
-}
-
-stock bool:SlenderUsesBlink(iBossIndex)
-{
-	if (NPCGetType(iBossIndex) == SF2BossType_Creeper) return true;
-	return false;
-}
-
-stock bool:SlenderKillsOnNear(iBossIndex)
-{
-	if (NPCGetType(iBossIndex) == SF2BossType_Creeper) return false;
-	return true;
-}
-
-stock SlenderClearTargetMemory(iBossIndex)
-{
-	if (iBossIndex == -1) return;
-	
-	g_iSlenderCurrentPathNode[iBossIndex] = -1;
-	if (g_hSlenderPath[iBossIndex] == INVALID_HANDLE) return;
-	
-	ClearArray(g_hSlenderPath[iBossIndex]);
-}
-
-stock bool:SlenderCreateTargetMemory(iBossIndex)
-{
-	if (iBossIndex == -1) return false;
-	
-	g_iSlenderCurrentPathNode[iBossIndex] = -1;
-	if (g_hSlenderPath[iBossIndex] != INVALID_HANDLE) return true;
-	
-	g_hSlenderPath[iBossIndex] = CreateArray(3);
-	return true;
-}
-
-stock SlenderRemoveTargetMemory(iBossIndex)
-{
-	if (iBossIndex == -1) return;
-	
-	g_iSlenderCurrentPathNode[iBossIndex] = -1;
-	
-	if (g_hSlenderPath[iBossIndex] == INVALID_HANDLE) return;
-	
-	new Handle:hLocs = g_hSlenderPath[iBossIndex];
-	g_hSlenderPath[iBossIndex] = INVALID_HANDLE;
-	CloseHandle(hLocs);
-}
-
-SlenderPerformVoice(iBossIndex, const String:sSectionName[], iIndex=-1)
-{
-	if (iBossIndex == -1) return;
-
-	new slender = NPCGetEntIndex(iBossIndex);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sPath[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, sSectionName, sPath, sizeof(sPath), iIndex);
-	if (sPath[0])
-	{
-		decl String:sBuffer[512];
-		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
-		StrCat(sBuffer, sizeof(sBuffer), "_cooldown_min");
-		new Float:flCooldownMin = GetProfileFloat(sProfile, sBuffer, 1.5);
-		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
-		StrCat(sBuffer, sizeof(sBuffer), "_cooldown_max");
-		new Float:flCooldownMax = GetProfileFloat(sProfile, sBuffer, 1.5);
-		new Float:flCooldown = GetRandomFloat(flCooldownMin, flCooldownMax);
-		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
-		StrCat(sBuffer, sizeof(sBuffer), "_volume");
-		new Float:flVolume = GetProfileFloat(sProfile, sBuffer, 1.0);
-		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
-		StrCat(sBuffer, sizeof(sBuffer), "_channel");
-		new iChannel = GetProfileNum(sProfile, sBuffer, SNDCHAN_AUTO);
-		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
-		StrCat(sBuffer, sizeof(sBuffer), "_level");
-		new iLevel = GetProfileNum(sProfile, sBuffer, SNDLEVEL_SCREAMING);
-		
-		g_flSlenderNextVoiceSound[iBossIndex] = GetGameTime() + flCooldown;
-		EmitSoundToAll(sPath, slender, iChannel, iLevel, _, flVolume);
-	}
-}
-
-bool:SlenderCalculateApproachToPlayer(iBossIndex, iBestPlayer, Float:buffer[3])
-{
-	if (!IsValidClient(iBestPlayer)) return false;
-	
-	new slender = NPCGetEntIndex(iBossIndex);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return false;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl Float:flSlenderPos[3], Float:flPos[3], Float:flReferenceAng[3], Float:hisEyeAng[3], Float:tempDir[3], Float:tempPos[3];
-	GetClientEyePosition(iBestPlayer, flPos);
-	
-	GetEntPropVector(slender, Prop_Data, "m_angAbsRotation", hisEyeAng);
-	AddVectors(hisEyeAng, g_flSlenderEyeAngOffset[iBossIndex], hisEyeAng);
-	for (new i = 0; i < 3; i++) hisEyeAng[i] = AngleNormalize(hisEyeAng[i]);
-	
-	SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
-	
-	SubtractVectors(flPos, flSlenderPos, flReferenceAng);
-	GetVectorAngles(flReferenceAng, flReferenceAng);
-	for (new i = 0; i < 3; i++) flReferenceAng[i] = AngleNormalize(flReferenceAng[i]);
-	new Float:flDist = GetProfileFloat(sProfile, "speed") * g_flRoundDifficultyModifier;
-	if (flDist < GetProfileFloat(sProfile, "kill_radius")) flDist = GetProfileFloat(sProfile, "kill_radius") / 2.0;
-	new Float:flWithinFOV = 45.0;
-	new Float:flWithinFOVSide = 90.0;
-	
-	decl Handle:hTrace, index, Float:flHitNormal[3], Float:tempPos2[3], Float:flBuffer[3], Float:flBuffer2[3];
-	new Handle:hArray = CreateArray(6);
-	
-	decl Float:flCheckAng[3];
-	
-	new iRange = 0;
-	new iID = 1;
-	
-	for (new Float:addAng = 0.0; addAng < 360.0; addAng += 7.5)
-	{
-		tempDir[0] = 0.0;
-		tempDir[1] = AngleNormalize(hisEyeAng[1] + addAng);
-		tempDir[2] = 0.0;
-		
-		GetAngleVectors(tempDir, tempDir, NULL_VECTOR, NULL_VECTOR);
-		NormalizeVector(tempDir, tempDir);
-		ScaleVector(tempDir, flDist);
-		AddVectors(tempDir, flSlenderPos, tempPos);
-		AddVectors(tempPos, g_flSlenderEyePosOffset[iBossIndex], tempPos);
-		AddVectors(flSlenderPos, g_flSlenderEyePosOffset[iBossIndex], tempPos2);
-		
-		flBuffer[0] = g_flSlenderDetectMins[iBossIndex][0];
-		flBuffer[1] = g_flSlenderDetectMins[iBossIndex][1];
-		flBuffer[2] = 0.0;
-		flBuffer2[0] = g_flSlenderDetectMaxs[iBossIndex][0];
-		flBuffer2[1] = g_flSlenderDetectMaxs[iBossIndex][1];
-		flBuffer2[2] = 0.0;
-		
-		// Get a good move position.
-		hTrace = TR_TraceHullFilterEx(tempPos2, tempPos, flBuffer, flBuffer2, MASK_PLAYERSOLID_BRUSHONLY, TraceRayDontHitCharactersOrEntity, slender);
-		TR_GetEndPosition(tempPos, hTrace);
-		CloseHandle(hTrace);
-		
-		// Drop to the ground if we're above ground.
-		hTrace = TR_TraceRayFilterEx(tempPos, Float:{ 90.0, 0.0, 0.0 }, MASK_PLAYERSOLID_BRUSHONLY, RayType_Infinite, TraceRayDontHitCharactersOrEntity, slender);
-		new bool:bHit = TR_DidHit(hTrace);
-		TR_GetEndPosition(tempPos2, hTrace);
-		CloseHandle(hTrace);
-		
-		// Then calculate from there.
-		hTrace = TR_TraceHullFilterEx(tempPos, tempPos2, g_flSlenderDetectMins[iBossIndex], g_flSlenderDetectMaxs[iBossIndex], MASK_PLAYERSOLID_BRUSHONLY, TraceRayDontHitCharactersOrEntity, slender);
-		TR_GetEndPosition(tempPos, hTrace);
-		TR_GetPlaneNormal(hTrace, flHitNormal);
-		CloseHandle(hTrace);
-		SubtractVectors(tempPos, flSlenderPos, flCheckAng);
-		GetVectorAngles(flCheckAng, flCheckAng);
-		GetVectorAngles(flHitNormal, flHitNormal);
-		for (new i = 0; i < 3; i++) 
-		{
-			flHitNormal[i] = AngleNormalize(flHitNormal[i]);
-			flCheckAng[i] = AngleNormalize(flCheckAng[i]);
-		}
-		
-		new Float:diff = AngleDiff(flCheckAng[1], flReferenceAng[1]);
-		
-		new bool:bBackup = false;
-		
-		if (FloatAbs(diff) > flWithinFOV) bBackup = true;
-		
-		if (diff >= 0.0 && diff <= flWithinFOVSide) iRange = 1;
-		else if (diff < 0.0 && diff >= -flWithinFOVSide) iRange = 2;
-		else continue;
-		
-		if ((flHitNormal[0] >= 0.0 && flHitNormal[0] < 45.0)
-			|| (flHitNormal[0] < 0.0 && flHitNormal[0] > -45.0)
-			|| !bHit
-			|| TR_PointOutsideWorld(tempPos)
-			|| IsSpaceOccupiedNPC(tempPos, g_flSlenderDetectMins[iBossIndex], g_flSlenderDetectMaxs[iBossIndex], iBestPlayer))
-		{
-			continue;
-		}
-		
-		// Check from top to bottom of me.
-		
-		if (!IsPointVisibleToPlayer(iBestPlayer, tempPos, false, false)) continue;
-		
-		AddVectors(tempPos, g_flSlenderEyePosOffset[iBossIndex], tempPos);
-		
-		if (!IsPointVisibleToPlayer(iBestPlayer, tempPos, false, false)) continue;
-		
-		SubtractVectors(tempPos, g_flSlenderEyePosOffset[iBossIndex], tempPos);
-		
-		//	Insert the vector into our array.
-		index = PushArrayCell(hArray, iID);
-		SetArrayCell(hArray, index, tempPos[0], 1);
-		SetArrayCell(hArray, index, tempPos[1], 2);
-		SetArrayCell(hArray, index, tempPos[2], 3);
-		SetArrayCell(hArray, index, iRange, 4);
-		SetArrayCell(hArray, index, bBackup, 5);
-		
-		iID++;
-	}
-	
-	new size;
-	if ((size = GetArraySize(hArray)) > 0)
-	{
-		new Float:diff = AngleDiff(hisEyeAng[1], flReferenceAng[1]);
-		if (diff >= 0.0) iRange = 1;
-		else iRange = 2;
-		
-		new bool:bBackup = false;
-		
-		// Clean up any vectors that we don't need.
-		new Handle:hArray2 = CloneArray(hArray);
-		for (new i = 0; i < size; i++)
-		{
-			if (GetArrayCell(hArray2, i, 4) != iRange || bool:GetArrayCell(hArray2, i, 5) != bBackup)
-			{
-				new iIndex = FindValueInArray(hArray, GetArrayCell(hArray2, i));
-				if (iIndex != -1) RemoveFromArray(hArray, iIndex);
-			}
-		}
-		
-		CloseHandle(hArray2);
-		
-		size = GetArraySize(hArray);
-		if (size)
-		{
-			index = GetRandomInt(0, size - 1);
-			buffer[0] = Float:GetArrayCell(hArray, index, 1);
-			buffer[1] = Float:GetArrayCell(hArray, index, 2);
-			buffer[2] = Float:GetArrayCell(hArray, index, 3);
-		}
-		else
-		{
-			CloseHandle(hArray);
-			return false;
-		}
-	}
-	else
-	{
-		CloseHandle(hArray);
-		return false;
-	}
-	
-	CloseHandle(hArray);
-	return true;
-}
-
-// This functor ensures that the proposed boss position is not too
-// close to other players that are within the distance defined by
-// flMinSearchDist.
-
-// Returning false on the functor will immediately discard the proposed position.
-
-public bool:SlenderChaseBossPlaceFunctor(iBossIndex, const Float:flActiveAreaCenterPos[3], const Float:flAreaPos[3], Float:flMinSearchDist, Float:flMaxSearchDist, bool:bOriginalResult)
-{
-	if (FloatAbs(flActiveAreaCenterPos[2] - flAreaPos[2]) > 320.0)
-	{
-		return false;
-	}
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) ||
-			!IsPlayerAlive(i) ||
-			g_bPlayerEliminated[i] ||
-			g_bPlayerEscaped[i]) continue;
-		
-		decl Float:flClientPos[3];
-		GetClientAbsOrigin(i, flClientPos);
-		
-		if (GetVectorDistance(flClientPos, flAreaPos) < flMinSearchDist)
-		{
-			return false;
-		}
-	}
-	
-	return bOriginalResult;
-}
-
-// As time passes on, we have to get more aggressive in order to successfully peak the target's
-// stress level in the allotted duration we're given. Otherwise we'll be forced to place him
-// in a rest period.
-
-// Teleport progressively closer as time passes in attempt to increase the target's stress level.
-// Maximum minimum range is capped by the boss's anger level.
-
-stock Float:CalculateTeleportMinRange(iBossIndex, Float:flInitialMinRange, Float:flTeleportMaxRange)
-{
-	new Float:flTeleportTargetTimeLeft = g_flSlenderTeleportMaxTargetTime[iBossIndex] - GetGameTime();
-	new Float:flTeleportTargetTimeInitial = g_flSlenderTeleportMaxTargetTime[iBossIndex] - g_flSlenderTeleportTargetTime[iBossIndex];
-	new Float:flTeleportMinRange = flTeleportMaxRange - (1.0 - (flTeleportTargetTimeLeft / flTeleportTargetTimeInitial)) * (flTeleportMaxRange - flInitialMinRange);
-	
-	if (NPCGetAnger(iBossIndex) <= 1.0)
-	{
-		flTeleportMinRange += (g_flSlenderTeleportMinRange[iBossIndex] - flTeleportMaxRange) * Pow(NPCGetAnger(iBossIndex) - 1.0, 2.0 / g_flRoundDifficultyModifier);
-	}
-	
-	if (flTeleportMinRange < flInitialMinRange) flTeleportMinRange = flInitialMinRange;
-	if (flTeleportMinRange > flTeleportMaxRange) flTeleportMinRange = flTeleportMaxRange;
-	
-	return flTeleportMinRange;
-}
-
-public Action:Timer_SlenderTeleportThink(Handle:timer, any:iBossIndex)
-{
-	if (iBossIndex == -1) return Plugin_Stop;
-	if (timer != g_hSlenderThink[iBossIndex]) return Plugin_Stop;
-	
-	if (NPCGetFlags(iBossIndex) & SFF_NOTELEPORT) return Plugin_Continue;
-	
-	// Check to see if anyone's looking at me before doing anything.
-	if (PeopleCanSeeSlender(iBossIndex, _, false))
-	{
-		return Plugin_Continue;
-	}
-	
-	if (NPCGetTeleportType(iBossIndex) == 2)
-	{
-		new iBoss = NPCGetEntIndex(iBossIndex);
-		if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-		{
-			if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
-			{
-				// Check to see if it's a good time to teleport away.
-				new iState = g_iSlenderState[iBossIndex];
-				if (iState == STATE_IDLE || iState == STATE_WANDER)
-				{
-					if (GetGameTime() < g_flSlenderTimeUntilKill[iBossIndex])
-					{
-						return Plugin_Continue;
-					}
-				}
-			}
-		}
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (!g_bRoundGrace)
-	{
-		if (GetGameTime() >= g_flSlenderNextTeleportTime[iBossIndex])
-		{
-			new Float:flTeleportTime = GetRandomFloat(GetProfileFloat(sProfile, "teleport_time_min", 5.0), GetProfileFloat(sProfile, "teleport_time_max", 9.0));
-			g_flSlenderNextTeleportTime[iBossIndex] = GetGameTime() + flTeleportTime;
-			
-			new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
-			
-			if (!iTeleportTarget || iTeleportTarget == INVALID_ENT_REFERENCE)
-			{
-				// We don't have any good targets. Remove myself for now.
-				if (SlenderCanRemove(iBossIndex)) RemoveSlender(iBossIndex);
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: no good target, removing...", iBossIndex);
-#endif
-			}
-			else
-			{
-				new Float:flTeleportMinRange = CalculateTeleportMinRange(iBossIndex, g_flSlenderTeleportMinRange[iBossIndex], g_flSlenderTeleportMaxRange[iBossIndex]);
-				
-				new iTeleportAreaIndex = -1;
-				decl Float:flTeleportPos[3];
-				
-				// Search surrounding nav areas around target.
-				if (NavMesh_Exists())
-				{
-					decl Float:flTargetPos[3];
-					GetClientAbsOrigin(iTeleportTarget, flTargetPos);
-					
-					new iTargetAreaIndex = NavMesh_GetNearestArea(flTargetPos);
-					if (iTargetAreaIndex != -1)
-					{
-						new bool:bShouldBeBehindObstruction = false;
-						if (NPCGetTeleportType(iBossIndex) == 2)
-						{
-							bShouldBeBehindObstruction = true;
-						}
-						
-						// Search outwards until travel distance is at maximum range.
-						new Handle:hAreaArray = CreateArray(2);
-						new Handle:hAreas = CreateStack();
-						NavMesh_CollectSurroundingAreas(hAreas, iTargetAreaIndex, g_flSlenderTeleportMaxRange[iBossIndex]);
-						
-						{
-							new iPoppedAreas;
-						
-							while (!IsStackEmpty(hAreas))
-							{
-								new iAreaIndex = -1;
-								PopStackCell(hAreas, iAreaIndex);
-								
-								// Check flags.
-								if (NavMeshArea_GetFlags(iAreaIndex) & NAV_MESH_NO_HOSTAGES)
-								{
-									// Don't spawn/teleport at areas marked with the "NO HOSTAGES" flag.
-									continue;
-								}
-								
-								new iIndex = PushArrayCell(hAreaArray, iAreaIndex);
-								SetArrayCell(hAreaArray, iIndex, float(NavMeshArea_GetCostSoFar(iAreaIndex)), 1);
-								iPoppedAreas++;
-							}
-							
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: collected %d areas", iBossIndex, iPoppedAreas);
-#endif
-							
-							CloseHandle(hAreas);
-						}
-						
-						new Handle:hAreaArrayClose = CreateArray(4);
-						new Handle:hAreaArrayAverage = CreateArray(4);
-						new Handle:hAreaArrayFar = CreateArray(4);
-						
-						for (new i = 1; i <= 3; i++)
-						{
-							new Float:flRangeSectionMin = flTeleportMinRange + (g_flSlenderTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(i - 1) / 3.0);
-							new Float:flRangeSectionMax = flTeleportMinRange + (g_flSlenderTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(i) / 3.0);
-							
-							for (new i2 = 0, iSize = GetArraySize(hAreaArray); i2 < iSize; i2++)
-							{
-								new iAreaIndex = GetArrayCell(hAreaArray, i2);
-								
-								decl Float:flAreaSpawnPoint[3];
-								NavMeshArea_GetCenter(iAreaIndex, flAreaSpawnPoint);
-								
-								new iBoss = NPCGetEntIndex(iBossIndex);
-								
-								// Check space. First raise to HalfHumanHeight * 2, then trace downwards to get ground level.
-								{
-									decl Float:flTraceStartPos[3];
-									flTraceStartPos[0] = flAreaSpawnPoint[0];
-									flTraceStartPos[1] = flAreaSpawnPoint[1];
-									flTraceStartPos[2] = flAreaSpawnPoint[2] + (HalfHumanHeight * 2.0);
-									
-									decl Float:flTraceMins[3];
-									flTraceMins[0] = g_flSlenderDetectMins[iBossIndex][0];
-									flTraceMins[1] = g_flSlenderDetectMins[iBossIndex][1];
-									flTraceMins[2] = 0.0;
-									
-									
-									decl Float:flTraceMaxs[3];
-									flTraceMaxs[0] = g_flSlenderDetectMaxs[iBossIndex][0];
-									flTraceMaxs[1] = g_flSlenderDetectMaxs[iBossIndex][1];
-									flTraceMaxs[2] = 0.0;
-									
-									new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
-										flAreaSpawnPoint,
-										flTraceMins,
-										flTraceMaxs,
-										MASK_NPCSOLID,
-										TraceRayDontHitEntity,
-										iBoss);
-									
-									decl Float:flTraceHitPos[3];
-									TR_GetEndPosition(flTraceHitPos, hTrace);
-									flTraceHitPos[2] += 1.0;
-									CloseHandle(hTrace);
-									
-									if (IsSpaceOccupiedNPC(flTraceHitPos,
-										g_flSlenderDetectMins[iBossIndex],
-										g_flSlenderDetectMaxs[iBossIndex],
-										iBoss))
-									{
-										continue;
-									}
-									
-									if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
-									{
-										if (IsSpaceOccupiedNPC(flTraceHitPos,
-											HULL_HUMAN_MINS,
-											HULL_HUMAN_MAXS,
-											iBoss))
-										{
-											// Can't let an NPC spawn here; too little space. If we let it spawn here it will be non solid!
-											continue;
-										}
-									}
-									
-									flAreaSpawnPoint[0] = flTraceHitPos[0];
-									flAreaSpawnPoint[1] = flTraceHitPos[1];
-									flAreaSpawnPoint[2] = flTraceHitPos[2];
-								}
-								
-								// Check visibility.
-								if (IsPointVisibleToAPlayer(flAreaSpawnPoint, !bShouldBeBehindObstruction, false)) continue;
-								
-								AddVectors(flAreaSpawnPoint, g_flSlenderEyePosOffset[iBossIndex], flAreaSpawnPoint);
-								
-								if (IsPointVisibleToAPlayer(flAreaSpawnPoint, !bShouldBeBehindObstruction, false)) continue;
-								
-								SubtractVectors(flAreaSpawnPoint, g_flSlenderEyePosOffset[iBossIndex], flAreaSpawnPoint);
-								
-								new bool:bTooNear = false;
-								
-								// Check minimum range with players.
-								for (new iClient = 1; iClient <= MaxClients; iClient++)
-								{
-									if (!IsClientInGame(iClient) ||
-										!IsPlayerAlive(iClient) ||
-										g_bPlayerEliminated[iClient] ||
-										IsClientInGhostMode(iClient) || 
-										DidClientEscape(iClient))
-									{
-										continue;
-									}
-									
-									decl Float:flTempPos[3];
-									GetClientAbsOrigin(iClient, flTempPos);
-									
-									if (GetVectorDistance(flAreaSpawnPoint, flTempPos) <= g_flSlenderTeleportMinRange[iBossIndex])
-									{
-										bTooNear = true;
-										break;
-									}
-								}
-								
-								if (bTooNear) continue;	// This area is not compatible.
-								
-								// Check minimum range with boss copies (if supported).
-								if (NPCGetFlags(iBossIndex) & SFF_COPIES)
-								{
-									new Float:flMinDistBetweenBosses = GetProfileFloat(sProfile, "copy_teleport_dist_from_others", 800.0);
-									
-									for (new iBossCheck = 0; iBossCheck < MAX_BOSSES; iBossCheck++)
-									{
-										if (iBossCheck == iBossIndex ||
-											NPCGetUniqueID(iBossCheck) == -1 ||
-											(g_iSlenderCopyMaster[iBossIndex] != iBossCheck && g_iSlenderCopyMaster[iBossIndex] != g_iSlenderCopyMaster[iBossCheck]))
-										{
-											continue;
-										}
-										
-										new iBossEnt = NPCGetEntIndex(iBossCheck);
-										if (!iBossEnt || iBossEnt == INVALID_ENT_REFERENCE) continue;
-										
-										decl Float:flTempPos[3];
-										SlenderGetAbsOrigin(iBossCheck, flTempPos);
-										
-										if (GetVectorDistance(flAreaSpawnPoint, flTempPos) <= flMinDistBetweenBosses)
-										{
-											bTooNear = true;
-											break;
-										}
-									}
-								}
-								
-								if (bTooNear) continue;	// This area is not compatible.
-								
-								// Check travel distance and put in the appropriate arrays.
-								new Float:flDist = Float:GetArrayCell(hAreaArray, i2, 1);
-								if (flDist > flRangeSectionMin && flDist < flRangeSectionMax)
-								{
-									new iIndex = -1;
-									new Handle:hTargetAreaArray = INVALID_HANDLE;
-									
-									switch (i)
-									{
-										case 1: 
-										{
-											iIndex = PushArrayCell(hAreaArrayClose, iAreaIndex);
-											hTargetAreaArray = hAreaArrayClose;
-										}
-										case 2: 
-										{
-											iIndex = PushArrayCell(hAreaArrayAverage, iAreaIndex);
-											hTargetAreaArray = hAreaArrayAverage;
-										}
-										case 3: 
-										{
-											iIndex = PushArrayCell(hAreaArrayFar, iAreaIndex);
-											hTargetAreaArray = hAreaArrayFar;
-										}
-									}
-									
-									if (hTargetAreaArray != INVALID_HANDLE && iIndex != -1)
-									{
-										SetArrayCell(hTargetAreaArray, iIndex, flAreaSpawnPoint[0], 1);
-										SetArrayCell(hTargetAreaArray, iIndex, flAreaSpawnPoint[1], 2);
-										SetArrayCell(hTargetAreaArray, iIndex, flAreaSpawnPoint[2], 3);
-									}
-								}
-							}
-						}
-						
-						CloseHandle(hAreaArray);
-						
-#if defined DEBUG
-						SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: collected %d close areas, %d average areas, %d far areas", iBossIndex, GetArraySize(hAreaArrayClose),
-							GetArraySize(hAreaArrayAverage),
-							GetArraySize(hAreaArrayFar));
-#endif
-						
-						new iArrayIndex = -1;
-						
-						if (GetArraySize(hAreaArrayClose))
-						{
-							iArrayIndex = GetRandomInt(0, GetArraySize(hAreaArrayClose) - 1);
-							iTeleportAreaIndex = GetArrayCell(hAreaArrayClose, iArrayIndex);
-							flTeleportPos[0] = Float:GetArrayCell(hAreaArrayClose, iArrayIndex, 1);
-							flTeleportPos[1] = Float:GetArrayCell(hAreaArrayClose, iArrayIndex, 2);
-							flTeleportPos[2] = Float:GetArrayCell(hAreaArrayClose, iArrayIndex, 3);
-						}
-						else if (GetArraySize(hAreaArrayAverage))
-						{
-							iArrayIndex = GetRandomInt(0, GetArraySize(hAreaArrayAverage) - 1);
-							iTeleportAreaIndex = GetArrayCell(hAreaArrayAverage, iArrayIndex);
-							flTeleportPos[0] = Float:GetArrayCell(hAreaArrayAverage, iArrayIndex, 1);
-							flTeleportPos[1] = Float:GetArrayCell(hAreaArrayAverage, iArrayIndex, 2);
-							flTeleportPos[2] = Float:GetArrayCell(hAreaArrayAverage, iArrayIndex, 3);
-						}
-						else if (GetArraySize(hAreaArrayFar))
-						{
-							iArrayIndex = GetRandomInt(0, GetArraySize(hAreaArrayFar) - 1);
-							iTeleportAreaIndex = GetArrayCell(hAreaArrayFar, iArrayIndex);
-							flTeleportPos[0] = Float:GetArrayCell(hAreaArrayFar, iArrayIndex, 1);
-							flTeleportPos[1] = Float:GetArrayCell(hAreaArrayFar, iArrayIndex, 2);
-							flTeleportPos[2] = Float:GetArrayCell(hAreaArrayFar, iArrayIndex, 3);
-						}
-						
-						CloseHandle(hAreaArrayClose);
-						CloseHandle(hAreaArrayAverage);
-						CloseHandle(hAreaArrayFar);
-					}
-					else
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: failed because target is not on nav mesh!", iBossIndex);
-#endif
-					}
-				}
-				else
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: failed because of lack of nav mesh!", iBossIndex);
-#endif
-				}
-				
-				if (iTeleportAreaIndex == -1)
-				{
-					// We don't have any good areas. Remove myself for now.
-					if (SlenderCanRemove(iBossIndex)) RemoveSlender(iBossIndex);
-				}
-				else
-				{
-					SpawnSlender(iBossIndex, flTeleportPos);
-					
-					if (NPCGetFlags(iBossIndex) & SFF_HASJUMPSCARE)
-					{
-						new bool:bDidJumpScare = false;
-						
-						for (new i = 1; i <= MaxClients; i++)
-						{
-							if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i)) continue;
-							
-							if (PlayerCanSeeSlender(i, iBossIndex, false))
-							{
-								if ((NPCGetDistanceFromEntity(iBossIndex, i) <= GetProfileFloat(sProfile, "jumpscare_distance") &&
-									GetGameTime() >= g_flSlenderNextJumpScare[iBossIndex]) ||
-									PlayerCanSeeSlender(i, iBossIndex))
-								{
-									bDidJumpScare = true;
-								
-									new Float:flJumpScareDuration = GetProfileFloat(sProfile, "jumpscare_duration");
-									ClientDoJumpScare(i, iBossIndex, flJumpScareDuration);
-								}
-							}
-						}
-						
-						if (bDidJumpScare)
-						{
-							g_flSlenderNextJumpScare[iBossIndex] = GetGameTime() + GetProfileFloat(sProfile, "jumpscare_cooldown");
-						}
-					}
-				}
-			}
-		}
-		else
-		{
-#if defined DEBUG
-			SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: failed because of teleport time (curtime: %f, teletime: %f)", iBossIndex, GetGameTime(), g_flSlenderNextTeleportTime[iBossIndex]);
-#endif
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-/*
-// Deprecated.
-
-// This is just to calculate the new place, not do time checks.
-// Distance will be determined by the progression of the game and the
-// manually set values determined by flMinSearchDist and flMaxSearchDist,
-// which are float values that are (or should be) defined in the boss's
-// config file.
-
-// The place chosen should be out of (possible) sight of the players,
-// but should be within the AAS radius, the center being flActiveAreaCenterPos.
-// The game will try to find a place that is of flMinSearchDist first, but
-// if it can't, then it will try to find places that are a bit farther.
-
-// If the whole function fails, no place is given and the boss will not
-// be able to spawn.
-
-bool:SlenderChaseBossCalculateNewPlace(iBossIndex, const Float:flActiveAreaCenterPos[3], Float:flMinSearchDist, Float:flMaxSearchDist, Function:iFunctor, Float:flBuffer[3])
-{
-	new Handle:hAreas = NavMesh_GetAreas();
-	if (hAreas == INVALID_HANDLE) return false;
-	
-	new iBestAreaIndex = -1;
-	new Float:flBestAreaDist = -1.0;
-	
-	decl Float:flAreaCenterPos[3];
-	for (new i = 0, iSize = GetArraySize(hAreas); i < iSize; i++)
-	{
-		NavMeshArea_GetCenter(i, flAreaCenterPos);
-		
-		new Float:flDist = GetVectorDistance(flActiveAreaCenterPos, flAreaCenterPos);
-		if (flDist < flMinSearchDist || flDist > flMaxSearchDist) continue;
-		
-		if (IsPointVisibleToAPlayer(flAreaCenterPos, false, false)) continue;
-		
-		decl Float:flTestPos[3];
-		for (new i2 = 0; i2 < 3; i2++) flTestPos[i2] = flAreaCenterPos[i2] + g_flSlenderEyePosOffset[iBossIndex][i2];
-		
-		if (IsPointVisibleToAPlayer(flTestPos, false, false)) continue;
-		
-		if (iFunctor != INVALID_FUNCTION)
-		{
-			new bool:bResult = true;
-			
-			Call_StartFunction(INVALID_HANDLE, iFunctor);
-			Call_PushCell(iBossIndex);
-			Call_PushArray(flActiveAreaCenterPos, 3);
-			Call_PushArray(flAreaCenterPos, 3);
-			Call_PushFloat(flMinSearchDist);
-			Call_PushFloat(flMaxSearchDist);
-			Call_PushCell(bResult);
-			Call_Finish(bResult);
-			
-			if (!bResult) continue;
-		}
-		
-		if (flBestAreaDist < 0.0 || flDist < flBestAreaDist)
-		{
-			iBestAreaIndex = i;
-			flBestAreaDist = flDist;
-		}
-	}
-	
-	if (iBestAreaIndex == -1) return false;
-	
-	NavMeshArea_GetCenter(iBestAreaIndex, flBuffer);
-	return true;
-}
-*/
-
-bool:SlenderCalculateNewPlace(iBossIndex, Float:buffer[3], bool:bIgnoreCopies=false, bool:bProxy=false, iProxyPlayer=-1, &iBestPlayer=-1)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-
-	new Float:flPercent = 0.0;
-	if (g_iPageMax > 0)
-	{
-		flPercent = (float(g_iPageCount) / float(g_iPageMax)) * g_flRoundDifficultyModifier * NPCGetAnger(iBossIndex);
-	}
-	
-#if defined DEBUG
-	new iArraySize, iArraySize2;
-#endif
-	
-	if (!IsValidClient(iBestPlayer))
-	{
-		// 	Pick a player to appear to.
-		new Handle:hArray = CreateArray();
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || 
-				!IsPlayerAlive(i) || 
-				IsClientInDeathCam(i) || 
-				g_bPlayerEliminated[i] || 
-				g_bPlayerEscaped[i]) continue;
-			
-			if (NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]) != -1 && !bIgnoreCopies)
-			{
-				new bool:bwub = false;
-			
-				// No? Then check if players around him are targeted by a boss already (not me).
-				for (new iBossPlayer = 1; iBossPlayer <= MaxClients; iBossPlayer++)
-				{
-					if (i == iBossPlayer) continue;
-				
-					if (!IsClientInGame(iBossPlayer) || 
-						!IsPlayerAlive(iBossPlayer) || 
-						IsClientInDeathCam(iBossPlayer) || 
-						g_bPlayerEliminated[iBossPlayer] || 
-						g_bPlayerEscaped[iBossPlayer]) continue;
-					
-					// Get the boss that's targeting this player, if any.
-					for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
-					{
-						if (iBossIndex == iBoss || NPCGetUniqueID(iBoss) == -1) continue;
-						
-						if (EntRefToEntIndex(g_iSlenderTarget[iBoss]) == iBossPlayer)
-						{
-							// Are we near this player?
-							if (EntityDistanceFromEntity(iBossPlayer, i) < SF2_BOSS_COPY_SPAWN_MIN_DISTANCE)
-							{
-								bwub = true;
-								break;
-							}
-						}
-					}
-				}
-				
-				if (bwub) continue;
-			}
-			
-			PushArrayCell(hArray, i);
-		}
-		
-#if defined DEBUG
-		iArraySize = GetArraySize(hArray);
-		iArraySize2 = iArraySize;
-#endif
-		
-		if (GetArraySize(hArray))
-		{
-			if (g_iSlenderCopyMaster[iBossIndex] == -1 ||
-				GetProfileNum(sProfile, "copy_calculatepagecount", 0))
-			{
-				new tempBestPageCount = -1;
-				
-				new Handle:hTempArray = CloneArray(hArray);
-				for (new i = 0; i < GetArraySize(hTempArray); i++)
-				{
-					new iClient = GetArrayCell(hTempArray, i);
-					if (g_iPlayerPageCount[iClient] > tempBestPageCount)
-					{
-						tempBestPageCount = g_iPlayerPageCount[iClient];
-					}
-				}
-				
-				for (new i = 0; i < GetArraySize(hTempArray); i++)
-				{
-					new iClient = GetArrayCell(hTempArray, i);
-					if ((float(g_iPlayerPageCount[iClient]) / float(tempBestPageCount)) < SF2_BOSS_PAGE_CALCULATION)
-					{
-						new index = FindValueInArray(hArray, iClient);
-						if (index != -1) RemoveFromArray(hArray, index);
-					}
-				}
-				
-				CloseHandle(hTempArray);
-			}
-			
-#if defined DEBUG
-			iArraySize2 = GetArraySize(hArray);
-#endif
-		}
-		
-		if (GetArraySize(hArray))
-		{
-			iBestPlayer = GetArrayCell(hArray, GetRandomInt(0, GetArraySize(hArray) - 1));
-		}
-	
-		CloseHandle(hArray);
-	}
-	
-#if defined DEBUG
-	if (GetConVarBool(g_cvDebugBosses)) PrintToChatAll("SlenderCalculateNewPlace(%d): array size 1 = %d, array size 2 = %d", iBossIndex, iArraySize, iArraySize2);
-#endif
-	
-	if (iBestPlayer <= 0) 
-	{
-#if defined DEBUG
-		if (GetConVarBool(g_cvDebugBosses)) PrintToChatAll("SlenderCalculateNewPlace(%d) failed: no ibestPlayer!", iBossIndex);
-#endif
-		return false;
-	}
-	
-	//	Determine the distance we can appear from the player.
-	new Float:flPercentFar = 0.75 * (1.0 - flPercent);
-	new Float:flPercentAverage = 0.6 * (1.0 - flPercent);
-	//new Float:flPercentClose = 1.0 - flPercentFar - flPercentAverage;
-	
-	new Float:flUpperBoundFar = flPercentFar;
-	new Float:flUpperBoundAverage = flPercentFar + flPercentAverage;
-	//new Float:flUpperBoundClose = 1.0;
-	
-	new iRange = 1;
-	new Float:flChance = GetRandomFloat(0.0, 1.0);
-	new Float:flMaxRangeN = GetProfileFloat(sProfile, "teleport_range_max");
-	new Float:flMinRangeN = GetProfileFloat(sProfile, "teleport_range_min");
-	
-	new bool:bVisiblePls = false;
-	new bool:bBeCreepy = false;
-	
-	if (!bProxy)
-	{
-		// Are we gonna teleport in front of a player this time?
-		if (GetProfileNum(sProfile, "teleport_ignorevis_enable"))
-		{
-			if (GetRandomFloat(0.0, 1.0) < GetProfileFloat(sProfile, "teleport_ignorevis_chance") * NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier)
-			{
-				bVisiblePls = true;
-			}
-			
-			if (GetRandomFloat(0.0, 1.0) < GetProfileFloat(sProfile, "teleport_creepy_chance", 0.33))
-			{
-				bBeCreepy = true;
-			}
-		}
-	}
-	
-	new Float:flMaxRange = flMaxRangeN;
-	new Float:flMinRange = flMinRangeN;
-	
-	if (bVisiblePls)
-	{
-		flMaxRange = GetProfileFloat(sProfile, "teleport_ignorevis_range_max", flMaxRangeN);
-		flMinRange = GetProfileFloat(sProfile, "teleport_ignorevis_range_min", flMinRangeN);
-	}
-	
-	// Get distances.
-	new Float:flDistanceFar = GetRandomFloat(flMaxRange * 0.75, flMaxRange);
-	if (flDistanceFar < flMinRange) flDistanceFar = flMinRange;
-	new Float:flDistanceAverage = GetRandomFloat(flMaxRange * 0.33, flMaxRange * 0.75);
-	if (flDistanceAverage < flMinRange) flDistanceAverage = flMinRange;
-	new Float:flDistanceClose = GetRandomFloat(0.0, flMaxRange * 0.33);
-	if (flDistanceClose < flMinRange) flDistanceClose = flMinRange;
-	
-	if (flChance >= 0.0 && flChance < flUpperBoundFar) iRange = 1;
-	else if (flChance >= flUpperBoundFar && flChance < flUpperBoundAverage) iRange = 2;
-	else if (flChance >= flUpperBoundAverage) iRange = 3;
-	
-	// 	Get a circle of positions around the player that we can appear in.
-	
-	// Create arrays first.
-	new Handle:hArrayFar = CreateArray(3);
-	new Handle:hArrayAverage = CreateArray(3);
-	new Handle:hArrayClose = CreateArray(3);
-	
-	// Set up our distances array.
-	decl Float:flDistances[3];
-	flDistances[0] = flDistanceFar;
-	flDistances[1] = flDistanceAverage;
-	flDistances[2] = flDistanceClose;
-	
-	decl Float:hisEyePos[3], Float:hisEyeAng[3], Float:tempPos[3], Float:tempDir[3], Float:flBuffer[3], Float:flBuffer2[3], Float:flBuffer3[3];
-	GetClientEyePosition(iBestPlayer, hisEyePos);
-	GetClientEyeAngles(iBestPlayer, hisEyeAng);
-	
-	decl Handle:hTrace, index, Float:flHitNormal[3];
-	decl Handle:hArray;
-	
-	decl Float:flTargetMins[3], Float:flTargetMaxs[3];
-	if (!bProxy)
-	{
-		for (new i = 0; i < 3; i++)
-		{
-			flTargetMins[i] = g_flSlenderDetectMins[iBossIndex][i];
-			flTargetMaxs[i] = g_flSlenderDetectMaxs[iBossIndex][i];
-		}
-	}
-	else
-	{
-		GetEntPropVector(iProxyPlayer, Prop_Send, "m_vecMins", flTargetMins);
-		GetEntPropVector(iProxyPlayer, Prop_Send, "m_vecMaxs", flTargetMaxs);
-	}
-	
-	for (new i = 0; i < iRange; i++)
-	{
-		for (new Float:addAng = 0.0; addAng < 360.0; addAng += 7.5)
-		{
-			tempDir[0] = 0.0;
-			tempDir[1] = hisEyeAng[1] + addAng;
-			tempDir[2] = 0.0;
-			
-			GetAngleVectors(tempDir, tempDir, NULL_VECTOR, NULL_VECTOR);
-			NormalizeVector(tempDir, tempDir);
-			ScaleVector(tempDir, flDistances[i]);
-			AddVectors(tempDir, hisEyePos, tempPos);
-			
-			// Drop to the ground if we're above ground using a TraceHull so IsSpaceOccupiedNPC can return true on something.
-			hTrace = TR_TraceRayFilterEx(tempPos, Float:{ 90.0, 0.0, 0.0 }, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitCharactersOrEntity, iBestPlayer);
-			TR_GetEndPosition(flBuffer, hTrace);
-			CloseHandle(hTrace);
-			
-			flBuffer2[0] = flTargetMins[0];
-			flBuffer2[1] = flTargetMins[1];
-			flBuffer2[2] = -flTargetMaxs[2];
-			flBuffer3[0] = flTargetMaxs[0];
-			flBuffer3[1] = flTargetMaxs[1];
-			flBuffer3[2] = -flTargetMins[0];
-			
-			if (GetVectorDistance(tempPos, flBuffer) >= 300.0) continue;
-			
-			// Drop dowwwwwn.
-			hTrace = TR_TraceHullFilterEx(tempPos, flBuffer, flBuffer2, flBuffer3, MASK_NPCSOLID, TraceRayDontHitCharactersOrEntity, iBestPlayer);
-			TR_GetEndPosition(tempPos, hTrace);
-			TR_GetPlaneNormal(hTrace, flHitNormal);
-			CloseHandle(hTrace);
-			
-			GetVectorAngles(flHitNormal, flHitNormal);
-			for (new i2 = 0; i2 < 3; i2++) flHitNormal[i2] = AngleNormalize(flHitNormal[i2]);
-			
-			tempPos[2] -= g_flSlenderDetectMaxs[iBossIndex][2];
-			
-			if (TR_PointOutsideWorld(tempPos)
-				|| (IsSpaceOccupiedNPC(tempPos, flTargetMins, flTargetMaxs, NPCGetEntIndex(iBossIndex)))
-				|| (bProxy && IsSpaceOccupiedPlayer(tempPos, flTargetMins, flTargetMaxs, iProxyPlayer))
-				|| (flHitNormal[0] >= 0.0 && flHitNormal[0] < 45.0)
-				|| (flHitNormal[0] < 0.0 && flHitNormal[0] > -45.0))
-			{
-				continue;
-			}
-			
-			// Check if this position isn't too close to anyone else.
-			new bool:bTooClose = false;
-			
-			for (new i2 = 1; i2 <= MaxClients; i2++)
-			{
-				if (!IsClientInGame(i2) || !IsPlayerAlive(i2) || g_bPlayerEliminated[i2] || IsClientInGhostMode(i2)) continue;
-				GetClientAbsOrigin(i2, flBuffer);
-				if (GetVectorDistance(flBuffer, tempPos) < flMinRange)
-				{
-					bTooClose = true;
-					break;
-				}
-			}
-			
-			// Check if this position is too close to a boss.
-			if (!bTooClose)
-			{
-				decl iSlender;
-				for (new i2 = 0; i2 < MAX_BOSSES; i2++)
-				{
-					if (i2 == iBossIndex) continue;
-					if (NPCGetUniqueID(i2) == -1) continue;
-					
-					// If I'm a main boss, only check the distance between my copies and me.
-					if (g_iSlenderCopyMaster[iBossIndex] == -1)
-					{
-						if (g_iSlenderCopyMaster[i2] != iBossIndex) continue;
-					}
-					// If I'm a copy, just check with my other copy friends and my main boss.
-					else
-					{
-						new iMyMaster = g_iSlenderCopyMaster[iBossIndex];
-						if (g_iSlenderCopyMaster[i2] != iMyMaster || i2 != iMyMaster) continue;
-					}
-					
-					iSlender = NPCGetEntIndex(i2);
-					if (!iSlender || iSlender == INVALID_ENT_REFERENCE) continue;
-					
-					SlenderGetAbsOrigin(i2, flBuffer);
-					if (GetVectorDistance(flBuffer, tempPos) < GetProfileFloat(sProfile, "teleport_dist_from_other_copies", 800.0))
-					{
-						bTooClose = true;
-						break;
-					}
-				}
-			}
-			
-			if (bTooClose) continue;
-			
-			// Check from top to bottom of me.
-			
-			new bool:bCheckBlink = bool:GetProfileNum(sProfile, "teleport_use_blink");
-			
-			// Check if my copy master or my fellow copies could see this position.
-			new bool:bDontAddPosition = false;
-			new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]);
-			
-			decl Float:flCopyCheckPositions[6];
-			for (new i2 = 0; i2 < 3; i2++) flCopyCheckPositions[i2] = tempPos[i2];
-			for (new i2 = 3; i2 < 6; i2++) flCopyCheckPositions[i2] = tempPos[i2 - 3] + g_flSlenderEyePosOffset[iBossIndex][i2 - 3];
-			
-			for (new i2 = 0; i2 < 2; i2++)
-			{
-				decl Float:flCopyCheckPos[3];
-				for (new i3 = 0; i3 < 3; i3++) flCopyCheckPos[i3] = flCopyCheckPositions[i3 + (3 * i2)];
-				
-				// Check the conditions first.
-				if (bVisiblePls)
-				{
-					if (!IsPointVisibleToAPlayer(flCopyCheckPos, _, bCheckBlink) &&
-						!IsPointVisibleToPlayer(iBestPlayer, flCopyCheckPos, _, bCheckBlink))
-					{
-						bDontAddPosition = true;
-						break;
-					}
-				}
-				else if (bBeCreepy)
-				{
-					if (!IsPointVisibleToAPlayer(flCopyCheckPos, _, bCheckBlink) &&
-						IsPointVisibleToAPlayer(flCopyCheckPos, false, bCheckBlink) &&
-						IsPointVisibleToPlayer(iBestPlayer, flCopyCheckPos, false, bCheckBlink))
-					{
-						// Do nothing.
-					}
-					else
-					{
-						continue;
-					}
-				}
-				else
-				{
-					if (IsPointVisibleToAPlayer(flCopyCheckPos, _, bCheckBlink))
-					{
-						bDontAddPosition = true;
-						break;
-					}
-				}
-				
-				for (new i3 = 0; i3 < MAX_BOSSES; i3++)
-				{
-					if (i3 == iBossIndex) continue;
-					if (NPCGetUniqueID(i3) == -1) continue;
-					
-					new iBoss = NPCGetEntIndex(i3);
-					if (!iBoss || iBoss == INVALID_ENT_REFERENCE) continue;
-					
-					if (i3 == iCopyMaster || 
-						(iCopyMaster != -1 && NPCGetFromUniqueID(g_iSlenderCopyMaster[i3]) == iCopyMaster))
-					{
-					}
-					else continue;
-					
-					decl Float:flCopyPos[3];
-					SlenderGetEyePosition(i3, flCopyPos);
-					hTrace = TR_TraceRayFilterEx(flCopyPos,
-						flCopyCheckPos,
-						CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST,
-						RayType_EndPoint,
-						TraceRayBossVisibility,
-						iBoss);
-					
-					bDontAddPosition = !TR_DidHit(hTrace);
-					CloseHandle(hTrace);
-					
-					if (!bDontAddPosition)
-					{
-						decl Float:flCopyMins[3], Float:flCopyMaxs[3];
-						GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flCopyPos);
-						GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flCopyMins);
-						GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flCopyMaxs);
-						
-						for (new i4 = 0; i4 < 3; i4++) flCopyPos[i4] += ((flCopyMins[i4] + flCopyMaxs[i4]) / 2.0);
-						
-						hTrace = TR_TraceRayFilterEx(flCopyPos,
-							flCopyCheckPos,
-							CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST,
-							RayType_EndPoint,
-							TraceRayBossVisibility,
-							iBoss);
-						
-						bDontAddPosition = !TR_DidHit(hTrace);
-						CloseHandle(hTrace);
-					}
-					
-					if (bDontAddPosition) break;
-				}
-				
-				if (bDontAddPosition) break;
-			}
-			
-			if (bDontAddPosition) continue;
-			
-			// Insert the vector into our array. Choose which one, first.
-			// We're just using hArray as a variable to store the correct array, not the array itself. All arrays will be closed at the end.
-			if (i == 0) hArray = hArrayFar;
-			else if (i == 1) hArray = hArrayAverage;
-			else if (i == 2) hArray = hArrayClose;
-			
-			index = PushArrayCell(hArray, tempPos[0]);
-			SetArrayCell(hArray, index, tempPos[1], 1);
-			SetArrayCell(hArray, index, tempPos[2], 2);
-		}
-	}
-	
-	new size;
-	if ((size = GetArraySize(hArrayClose)) > 0)
-	{
-		index = GetRandomInt(0, size - 1);
-		buffer[0] = Float:GetArrayCell(hArrayClose, index);
-		buffer[1] = Float:GetArrayCell(hArrayClose, index, 1);
-		buffer[2] = Float:GetArrayCell(hArrayClose, index, 2);
-	}
-	else if ((size = GetArraySize(hArrayAverage)) > 0)
-	{
-		index = GetRandomInt(0, size - 1);
-		buffer[0] = Float:GetArrayCell(hArrayAverage, index);
-		buffer[1] = Float:GetArrayCell(hArrayAverage, index, 1);
-		buffer[2] = Float:GetArrayCell(hArrayAverage, index, 2);
-	}
-	else if ((size = GetArraySize(hArrayFar)) > 0)
-	{
-		index = GetRandomInt(0, size - 1);
-		buffer[0] = Float:GetArrayCell(hArrayFar, index);
-		buffer[1] = Float:GetArrayCell(hArrayFar, index, 1);
-		buffer[2] = Float:GetArrayCell(hArrayFar, index, 2);
-	}
-	else
-	{
-		CloseHandle(hArrayClose);
-		CloseHandle(hArrayAverage);
-		CloseHandle(hArrayFar);
-		
-#if defined DEBUG
-		if (GetConVarBool(g_cvDebugBosses)) PrintToChatAll("SlenderCalculateNewPlace(%d) failed: no locations available", iBossIndex);
-#endif
-		
-		return false;
-	}
-	
-	CloseHandle(hArrayClose);
-	CloseHandle(hArrayAverage);
-	CloseHandle(hArrayFar);
-	return true;
-}
-
-bool:SlenderMarkAsFake(iBossIndex)
-{
-	new iBossFlags = NPCGetFlags(iBossIndex);
-	if (iBossFlags & SFF_MARKEDASFAKE) return false;
-	
-	new slender = NPCGetEntIndex(iBossIndex);
-	new iSlenderModel = EntRefToEntIndex(g_iSlenderModel[iBossIndex]);
-	g_iSlender[iBossIndex] = INVALID_ENT_REFERENCE;
-	g_iSlenderModel[iBossIndex] = INVALID_ENT_REFERENCE;
-	
-	NPCSetFlags(iBossIndex, iBossFlags | SFF_MARKEDASFAKE);
-	
-	g_hSlenderFakeTimer[iBossIndex] = CreateTimer(3.0, Timer_SlenderMarkedAsFake, iBossIndex, TIMER_FLAG_NO_MAPCHANGE);
-	
-	if (slender && slender != INVALID_ENT_REFERENCE)
-	{
-		CreateTimer(2.0, Timer_KillEntity, EntIndexToEntRef(slender), TIMER_FLAG_NO_MAPCHANGE);
-	
-		new iFlags = GetEntProp(slender, Prop_Send, "m_usSolidFlags");
-		if (!(iFlags & 0x0004)) iFlags |= 0x0004; // 	FSOLID_NOT_SOLID
-		if (!(iFlags & 0x0008)) iFlags |= 0x0008; // 	FSOLID_TRIGGER
-		SetEntProp(slender, Prop_Send, "m_usSolidFlags", iFlags);
-	}
-	
-	if (iSlenderModel && iSlenderModel != INVALID_ENT_REFERENCE)
-	{
-		SetVariantFloat(0.0);
-		AcceptEntityInput(iSlenderModel, "SetPlaybackRate");
-		SetEntityRenderFx(iSlenderModel, RENDERFX_FADE_FAST);
-	}
-	
-	return true;
-}
-
-public Action:Timer_SlenderMarkedAsFake(Handle:timer, any:data)
-{
-	if (timer != g_hSlenderFakeTimer[data]) return;
-	
-	NPCRemove(data);
-}
-
-stock SpawnSlenderModel(iBossIndex, const Float:pos[3])
-{
-	if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		LogError("Could not spawn boss model: boss does not exist!");
-		return -1;
-	}
-	
-	new iProfileIndex = NPCGetProfileIndex(iBossIndex);
-	
-	decl String:buffer[PLATFORM_MAX_PATH], String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	GetProfileString(sProfile, "model", buffer, sizeof(buffer));
-	if (!buffer[0])
-	{
-		LogError("Could not spawn boss model: model is invalid!");
-		return -1;
-	}
-	
-	new Float:flModelScale = NPCGetModelScale(iBossIndex);
-	if (flModelScale <= 0.0)
-	{
-		LogError("Could not spawn boss model: model scale is less than or equal to 0.0!");
-		return -1;
-	}
-	
-	new iSlenderModel = CreateEntityByName("prop_dynamic_override");
-	if (iSlenderModel != -1)
-	{
-		SetEntityModel(iSlenderModel, buffer);
-		
-		TeleportEntity(iSlenderModel, pos, NULL_VECTOR, NULL_VECTOR);
-		DispatchSpawn(iSlenderModel);
-		ActivateEntity(iSlenderModel);
-		
-		SetEntProp(iSlenderModel, Prop_Send, "m_nSkin", GetBossProfileSkin(iProfileIndex));
-		SetEntProp(iSlenderModel, Prop_Send, "m_nBody", GetBossProfileBodyGroups(iProfileIndex));
-		
-		GetProfileString(sProfile, "animation_idle", buffer, sizeof(buffer));
-		if (buffer[0])
-		{
-			SetVariantString(buffer);
-			AcceptEntityInput(iSlenderModel, "SetDefaultAnimation");
-			SetVariantString(buffer);
-			AcceptEntityInput(iSlenderModel, "SetAnimation");
-			AcceptEntityInput(iSlenderModel, "DisableCollision");
-		}
-		
-		SetVariantFloat(GetProfileFloat(sProfile, "animation_idle_playbackrate", 1.0));
-		AcceptEntityInput(iSlenderModel, "SetPlaybackRate");
-		
-		SetEntPropFloat(iSlenderModel, Prop_Send, "m_flModelScale", flModelScale);
-		
-		// Create special effects.
-		SetEntityRenderMode(iSlenderModel, RenderMode:GetProfileNum(sProfile, "effect_rendermode", _:RENDER_NORMAL));
-		SetEntityRenderFx(iSlenderModel, RenderFx:GetProfileNum(sProfile, "effect_renderfx", _:RENDERFX_NONE));
-		
-		decl iColor[4];
-		GetProfileColor(sProfile, "effect_rendercolor", iColor[0], iColor[1], iColor[2], iColor[3]);
-		SetEntityRenderColor(iSlenderModel, iColor[0], iColor[1], iColor[2], iColor[3]);
-		
-		KvRewind(g_hConfig);
-		if (KvJumpToKey(g_hConfig, sProfile) && 
-			KvJumpToKey(g_hConfig, "effects") &&
-			KvGotoFirstSubKey(g_hConfig))
-		{
-			do
-			{
-				
-			}
-			while KvGotoNextKey(g_hConfig);
-		}
-	}
-	
-	return iSlenderModel;
-}
-
-stock bool:PlayerCanSeeSlender(client, iBossIndex, bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
-{
-	return IsNPCVisibleToPlayer(iBossIndex, client, bCheckFOV, bCheckBlink, bCheckEliminated);
-}
-
-stock bool:PeopleCanSeeSlender(iBossIndex, bool:bCheckFOV=true, bool:bCheckBlink=false)
-{
-	return IsNPCVisibleToAPlayer(iBossIndex, bCheckFOV, bCheckBlink);
-}
-
-// TODO: bCheckBlink and bCheckEliminated should NOT be function arguments!
-bool:IsNPCVisibleToPlayer(iNPCIndex, client, bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
-{
-	if (!NPCIsValid(iNPCIndex)) return false;
-	
-	new iNPC = NPCGetEntIndex(iNPCIndex);
-	if (iNPC && iNPC != INVALID_ENT_REFERENCE)
-	{
-		decl Float:flEyePos[3];
-		NPCGetEyePosition(iNPCIndex, flEyePos);
-		return IsPointVisibleToPlayer(client, flEyePos, bCheckFOV, bCheckBlink, bCheckEliminated);
-	}
-	
-	return false;
-}
-
-// TODO: bCheckBlink and bCheckEliminated should NOT be function arguments!
-bool:IsNPCVisibleToAPlayer(iNPCIndex, bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
-{
-	for (new client = 1; client <= MaxClients; client++)
-	{
-		if (IsNPCVisibleToPlayer(iNPCIndex, client, bCheckFOV, bCheckBlink, bCheckEliminated))
-		{
-			return true;
-		}
-	}
-	
-	return false;
-}
-
-Float:NPCGetDistanceFromPoint(iNPCIndex, const Float:flPoint[3], bool:bSquared=false)
-{
-	new iNPC = NPCGetEntIndex(iNPCIndex);
-	if (iNPC && iNPC != INVALID_ENT_REFERENCE)
-	{
-		decl Float:flPos[3];
-		SlenderGetAbsOrigin(iNPCIndex, flPos);
-		
-		return GetVectorDistance(flPos, flPoint, bSquared);
-	}
-	
-	return -1.0;
-}
-
-Float:NPCGetDistanceFromEntity(iNPCIndex, ent, bool:bSquared=false)
-{
-	if (!IsValidEntity(ent)) return -1.0;
-	
-	decl Float:flPos[3];
-	GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
-	
-	return NPCGetDistanceFromPoint(iNPCIndex, flPos, bSquared);
-}
-
-public bool:TraceRayBossVisibility(entity, mask, any:data)
-{
-	if (entity == data || IsValidClient(entity)) return false;
-	
-	new iBossIndex = NPCGetFromEntIndex(entity);
-	if (iBossIndex != -1) return false;
-	
-	if (IsValidEdict(entity))
-	{
-		decl String:sClass[64];
-		GetEntityNetClass(entity, sClass, sizeof(sClass));
-		
-		if (StrEqual(sClass, "CTFAmmoPack")) return false;
-	}
-	
-	return true;
-}
-
-public bool:TraceRayDontHitCharacters(entity, mask, any:data)
-{
-	if (entity > 0 && entity <= MaxClients) return false;
-	
-	new iBossIndex = NPCGetFromEntIndex(entity);
-	if (iBossIndex != -1) return false;
-	
-	return true;
-}
-
-public bool:TraceRayDontHitCharactersOrEntity(entity, mask, any:data)
-{
-	if (entity == data) return false;
-
-	if (entity > 0 && entity <= MaxClients) return false;
-	
-	new iBossIndex = NPCGetFromEntIndex(entity);
-	if (iBossIndex != -1) return false;
-	
-	return true;
-}
-
-#include "rytp_horror/npc/npc_chaser.sp"
+#if defined _sf2_npc_included
+ #endinput
+#endif
+#define _sf2_npc_included
+
+#define SF2_BOSS_PAGE_CALCULATION 0.3
+#define SF2_BOSS_COPY_SPAWN_MIN_DISTANCE 1850.0 // The default minimum distance boss copies can spawn from each other.
+
+#define SF2_BOSS_ATTACK_MELEE 0
+
+static g_iNPCGlobalUniqueID = 0;
+
+static g_iNPCUniqueID[MAX_BOSSES] = { -1, ... };
+static String:g_strSlenderProfile[MAX_BOSSES][SF2_MAX_PROFILE_NAME_LENGTH];
+static g_iNPCProfileIndex[MAX_BOSSES] = { -1, ... };
+static g_iNPCUniqueProfileIndex[MAX_BOSSES] = { -1, ... };
+static g_iNPCType[MAX_BOSSES] = { SF2BossType_Unknown, ... };
+static g_iNPCFlags[MAX_BOSSES] = { 0, ... };
+static Float:g_flNPCModelScale[MAX_BOSSES] = { 1.0, ... };
+
+static Float:g_flNPCFieldOfView[MAX_BOSSES] = { 0.0, ... };
+static Float:g_flNPCTurnRate[MAX_BOSSES] = { 0.0, ... };
+
+static g_iSlender[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+
+static Float:g_flNPCSpeed[MAX_BOSSES][Difficulty_Max];
+static Float:g_flNPCMaxSpeed[MAX_BOSSES][Difficulty_Max];
+
+static Float:g_flNPCScareRadius[MAX_BOSSES];
+static Float:g_flNPCScareCooldown[MAX_BOSSES];
+
+static g_iNPCTeleportType[MAX_BOSSES] = { -1, ... };
+
+static Float:g_flNPCAnger[MAX_BOSSES] = { 1.0, ... };
+static Float:g_flNPCAngerAddOnPageGrab[MAX_BOSSES] = { 0.0, ... };
+static Float:g_flNPCAngerAddOnPageGrabTimeDiff[MAX_BOSSES] = { 0.0, ... };
+
+static Float:g_flNPCSearchRadius[MAX_BOSSES] = { 0.0, ... };
+static Float:g_flNPCInstantKillRadius[MAX_BOSSES] = { 0.0, ... };
+
+static bool:g_bNPCDeathCamEnabled[MAX_BOSSES] = { false, ... };
+
+static g_iNPCEnemy[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+
+#if defined METHODMAPS
+
+const SF2NPC_BaseNPC SF2_INVALID_NPC = SF2NPC_BaseNPC:-1;
+
+methodmap SF2NPC_BaseNPC
+{
+	property int Index
+	{
+		public get() { return _:this; }
+	}
+	
+	property int Type
+	{
+		public get() { return NPCGetType(this.Index); }
+	}
+	
+	property int ProfileIndex
+	{
+		public get() { return NPCGetProfileIndex(this.Index); }
+	}
+	
+	property int UniqueProfileIndex
+	{
+		public get() { return NPCGetUniqueProfileIndex(this.Index); }
+	}
+	
+	property int EntRef
+	{
+		public get() { return NPCGetEntRef(this.Index); }
+	}
+	
+	property int EntIndex
+	{
+		public get() { return NPCGetEntIndex(this.Index); }
+	}
+	
+	property int Flags
+	{
+		public get() { return NPCGetFlags(this.Index); }
+		public set(int flags) { NPCSetFlags(this.Index); }
+	}
+	
+	property float ModelScale
+	{
+		public get() { return NPCGetModelScale(this.Index) };
+	}
+	
+	property float TurnRate
+	{
+		public get() { return NPCGetTurnRate(this.Index) };
+	}
+	
+	property float FOV
+	{
+		public get() { return NPCGetFOV(this.Index); }
+	}
+	
+	property float Anger
+	{
+		public get() { return NPCGetAnger(this.Index); }
+		public set(float amount) { NPCSetAnger(this.Index, amount); }
+	}
+	
+	property float AngerAddOnPageGrab
+	{
+		public get() { return NPCGetAngerAddOnPageGrab(this.Index); }
+	}
+	
+	property float AngerAddOnPageGrabTimeDiff
+	{
+		public get() { return NPCGetAngerAddOnPageGrabTimeDiff(this.Index); }
+	}
+	
+	property float SearchRadius
+	{
+		public get() { return NPCGetSearchRadius(this.Index); }
+	}
+	
+	property float ScareRadius
+	{
+		public get() { return NPCGetScareRadius(this.Index); }
+	}
+	
+	property float ScareCooldown
+	{
+		public get() { return NPCGetScareCooldown(this.Index); }
+	}
+	
+	property float InstantKillRadius
+	{
+		public get() { return NPCGetInstantKillRadius(this.Index); }
+	}
+	
+	property int TeleportType
+	{
+		public get() { return NPCGetTeleportType(this.Index); }
+	}
+	
+	property int Enemy
+	{
+		public get() { return NPCGetEnemy(this.Index); }
+		public set(int entIndex) { NPCSetEnemy(this.Index, entIndex); }
+	}
+	
+	property bool DeathCamEnabled
+	{
+		public get() { return NPCHasDeathCamEnabled(this.Index); }
+		public set(bool state) { NPCSetDeathCamEnabled(this.Index, state); }
+	}
+	
+	public SF2NPC_BaseNPC(int index)
+	{
+		return SF2NPC_BaseNPC:index;
+	}
+	
+	public ~SF2NPC_BaseNPC()
+	{
+		NPCRemove(this.Index);
+	}
+	
+	public bool IsValid()
+	{
+		return NPCIsValid(this.Index);
+	}
+	
+	public void GetProfile(char[] buffer, int bufferlen) 
+	{
+		NPCGetProfile(this.Index, buffer, bufferlen);
+	}
+	
+	public void SetProfile(const char[] profileName)
+	{
+		NPCSetProfile(this.Index, profileName);
+	}
+	
+	public float GetSpeed(int difficulty)
+	{
+		return NPCGetSpeed(this.Index, difficulty);
+	}
+	
+	public float GetMaxSpeed(int difficulty)
+	{
+		return NPCGetMaxSpeed(this.Index, difficulty);
+	}
+	
+	public void GetEyePosition(float buffer[3], const float defaultValue[3] = { 0.0, 0.0, 0.0 })
+	{
+		NPCGetEyePosition(this.Index, buffer, defaultValue);
+	}
+	
+	public void GetEyePositionOffset(float buffer[3])
+	{
+		NPCGetEyePositionOffset(this.Index, buffer);
+	}
+	
+	public void AddAnger(float amount)
+	{
+		NPCAddAnger(this.Index, amount);
+	}
+	
+	public bool HasAttribute(const char[] attributeName)
+	{
+		return NPCHasAttribute(this.Index, attributeName);
+	}
+	
+	public float GetAttributeValue(const char[] attributeName, float defaultValue = 0.0)
+	{
+		return NPCGetAttributeValue(this.Index, attributeName, defaultValue);
+	}
+}
+
+#endif
+
+bool:NPCHasDeathCamEnabled(iNPCIndex)
+{
+	return g_bNPCDeathCamEnabled[iNPCIndex];
+}
+
+NPCSetDeathCamEnabled(iNPCIndex, bool:state)
+{
+	g_bNPCDeathCamEnabled[iNPCIndex] = state;
+}
+
+public NPCInitialize()
+{
+	NPCChaserInitialize();
+}
+
+public NPCOnConfigsExecuted()
+{
+	g_iNPCGlobalUniqueID = 0;
+}
+
+bool:NPCIsValid(iNPCIndex)
+{
+	return bool:(iNPCIndex >= 0 && iNPCIndex < MAX_BOSSES && NPCGetUniqueID(iNPCIndex) != -1);
+}
+
+NPCGetUniqueID(iNPCIndex)
+{
+	return g_iNPCUniqueID[iNPCIndex];
+}
+
+NPCGetFromUniqueID(iNPCUniqueID)
+{
+	if (iNPCUniqueID == -1) return -1;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == iNPCUniqueID)
+		{
+			return i;
+		}
+	}
+	
+	return -1;
+}
+
+NPCGetEntRef(iNPCIndex)
+{
+	return g_iSlender[iNPCIndex];
+}
+
+NPCGetEntIndex(iNPCIndex)
+{
+	return EntRefToEntIndex(NPCGetEntRef(iNPCIndex));
+}
+
+NPCGetFromEntIndex(entity)
+{
+	if (!entity || !IsValidEntity(entity)) return -1;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetEntIndex(i) == entity)
+		{
+			return i;
+		}
+	}
+	
+	return -1;
+}
+
+NPCGetCount()
+{
+	new iCount;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		if (NPCGetFlags(i) & SFF_FAKE) continue;
+		
+		iCount++;
+	}
+	
+	return iCount;
+}
+
+NPCGetProfileIndex(iNPCIndex)
+{
+	return g_iNPCProfileIndex[iNPCIndex];
+}
+
+NPCGetUniqueProfileIndex(iNPCIndex)
+{
+	return g_iNPCUniqueProfileIndex[iNPCIndex];
+}
+
+bool:NPCGetProfile(iNPCIndex, String:buffer[], bufferlen)
+{
+	strcopy(buffer, bufferlen, g_strSlenderProfile[iNPCIndex]);
+	return true;
+}
+
+NPCSetProfile(iNPCIndex, const String:sProfile[])
+{
+	strcopy(g_strSlenderProfile[iNPCIndex], sizeof(g_strSlenderProfile[]), sProfile);
+}
+
+NPCRemove(iNPCIndex)
+{
+	if (!NPCIsValid(iNPCIndex)) return;
+	
+	RemoveProfile(iNPCIndex);
+}
+
+NPCRemoveAll()
+{
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		NPCRemove(i);
+	}
+}
+
+NPCGetType(iNPCIndex)
+{
+	return g_iNPCType[iNPCIndex];
+}
+
+NPCGetFlags(iNPCIndex)
+{
+	return g_iNPCFlags[iNPCIndex];
+}
+
+NPCSetFlags(iNPCIndex, iFlags)
+{
+	g_iNPCFlags[iNPCIndex] = iFlags;
+}
+
+Float:NPCGetModelScale(iNPCIndex)
+{
+	return g_flNPCModelScale[iNPCIndex];
+}
+
+Float:NPCGetSpeed(iNPCIndex, iDifficulty)
+{
+	return g_flNPCSpeed[iNPCIndex][iDifficulty];
+}
+
+Float:NPCGetMaxSpeed(iNPCIndex, iDifficulty)
+{
+	return g_flNPCMaxSpeed[iNPCIndex][iDifficulty];
+}
+
+Float:NPCGetTurnRate(iNPCIndex)
+{
+	return g_flNPCTurnRate[iNPCIndex];
+}
+
+Float:NPCGetFOV(iNPCIndex)
+{
+	return g_flNPCFieldOfView[iNPCIndex];
+}
+
+Float:NPCGetAnger(iNPCIndex)
+{
+	return g_flNPCAnger[iNPCIndex];
+}
+
+NPCSetAnger(iNPCIndex, Float:flAnger)
+{
+	g_flNPCAnger[iNPCIndex] = flAnger;
+}
+
+NPCAddAnger(iNPCIndex, Float:flAmount)
+{
+	g_flNPCAnger[iNPCIndex] += flAmount;
+}
+
+Float:NPCGetAngerAddOnPageGrab(iNPCIndex)
+{
+	return g_flNPCAngerAddOnPageGrab[iNPCIndex];
+}
+
+Float:NPCGetAngerAddOnPageGrabTimeDiff(iNPCIndex)
+{
+	return g_flNPCAngerAddOnPageGrabTimeDiff[iNPCIndex];
+}
+
+NPCGetEyePositionOffset(iNPCIndex, Float:buffer[3])
+{
+	buffer[0] = g_flSlenderEyePosOffset[iNPCIndex][0];
+	buffer[1] = g_flSlenderEyePosOffset[iNPCIndex][1];
+	buffer[2] = g_flSlenderEyePosOffset[iNPCIndex][2];
+}
+
+Float:NPCGetSearchRadius(iNPCIndex)
+{
+	return g_flNPCSearchRadius[iNPCIndex];
+}
+
+Float:NPCGetScareRadius(iNPCIndex)
+{
+	return g_flNPCScareRadius[iNPCIndex];
+}
+
+Float:NPCGetScareCooldown(iNPCIndex)
+{
+	return g_flNPCScareCooldown[iNPCIndex];
+}
+
+Float:NPCGetInstantKillRadius(iNPCIndex)
+{
+	return g_flNPCInstantKillRadius[iNPCIndex];
+}
+
+NPCGetTeleportType(iNPCIndex)
+{
+	return g_iNPCTeleportType[iNPCIndex];
+}
+
+NPCGetEnemy(iNPCIndex)
+{
+	return g_iNPCEnemy[iNPCIndex];
+}
+
+NPCSetEnemy(iNPCIndex, ent)
+{
+	g_iNPCEnemy[iNPCIndex] = IsValidEntity(ent) ? EntIndexToEntRef(ent) : INVALID_ENT_REFERENCE;
+}
+
+/**
+ *	Returns the boss's eye position (eye pos offset + absorigin).
+ */
+bool:NPCGetEyePosition(iNPCIndex, Float:buffer[3], const Float:flDefaultValue[3]={ 0.0, 0.0, 0.0 })
+{
+	buffer[0] = flDefaultValue[0];
+	buffer[1] = flDefaultValue[1];
+	buffer[2] = flDefaultValue[2];
+	
+	if (!NPCIsValid(iNPCIndex)) return false;
+	
+	new iNPC = NPCGetEntIndex(iNPCIndex);
+	if (!iNPC || iNPC == INVALID_ENT_REFERENCE) return false;
+	
+	// @TODO: Replace SlenderGetAbsOrigin with GetEntPropVector
+	decl Float:flPos[3], Float:flEyePosOffset[3];
+	SlenderGetAbsOrigin(iNPCIndex, flPos);
+	NPCGetEyePositionOffset(iNPCIndex, flEyePosOffset);
+	
+	AddVectors(flPos, flEyePosOffset, buffer);
+	return true;
+}
+
+bool:NPCHasAttribute(iNPCIndex, const String:sAttribute[])
+{
+	if (NPCGetUniqueID(iNPCIndex) == -1) return false;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iNPCIndex, sProfile, sizeof(sProfile));
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	if (!KvJumpToKey(g_hConfig, "attributes")) return false;
+	
+	return KvJumpToKey(g_hConfig, sAttribute);
+}
+
+Float:NPCGetAttributeValue(iNPCIndex, const String:sAttribute[], Float:flDefaultValue=0.0)
+{
+	if (!NPCHasAttribute(iNPCIndex, sAttribute)) return flDefaultValue;
+	return KvGetFloat(g_hConfig, "value", flDefaultValue);
+}
+
+bool:SlenderCanRemove(iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1) return false;
+	
+	if (PeopleCanSeeSlender(iBossIndex, _, false)) return false;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new iTeleportType = GetProfileNum(sProfile, "teleport_type");
+	
+	switch (iTeleportType)
+	{
+		case 0:
+		{
+			if (GetProfileNum(sProfile, "static_on_radius"))
+			{
+				decl Float:flSlenderPos[3], Float:flBuffer[3];
+				SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
+			
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || 
+						!IsPlayerAlive(i) || 
+						g_bPlayerEliminated[i] || 
+						IsClientInGhostMode(i) || 
+						IsClientInDeathCam(i)) continue;
+					
+					if (!IsPointVisibleToPlayer(i, flSlenderPos, false, false)) continue;
+					
+					GetClientAbsOrigin(i, flBuffer);
+					if (GetVectorDistance(flBuffer, flSlenderPos) <= GetProfileFloat(sProfile, "static_radius"))
+					{
+						return false;
+					}
+				}
+			}
+		}
+		case 1:
+		{
+			if (PeopleCanSeeSlender(iBossIndex, _, SlenderUsesBlink(iBossIndex)) || PeopleCanSeeSlender(iBossIndex, false, false))
+			{
+				return false;
+			}
+		}
+		case 2:
+		{
+			new iState = g_iSlenderState[iBossIndex];
+			if (iState == STATE_IDLE || iState == STATE_WANDER)
+			{
+				if (GetGameTime() < g_flSlenderTimeUntilKill[iBossIndex])
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+	}
+	
+	return true;
+}
+
+bool:SlenderGetAbsOrigin(iBossIndex, Float:buffer[3], const Float:flDefaultValue[3]={ 0.0, 0.0, 0.0 })
+{
+	for (new i = 0; i < 3; i++) buffer[i] = flDefaultValue[i];
+	
+	if (iBossIndex < 0 || NPCGetUniqueID(iBossIndex) == -1) return false;
+	
+	new slender = NPCGetEntIndex(iBossIndex);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return false;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl Float:flPos[3], Float:flOffset[3];
+	GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flPos);
+	GetProfileVector(sProfile, "pos_offset", flOffset, flDefaultValue);
+	SubtractVectors(flPos, flOffset, buffer);
+	
+	return true;
+}
+
+bool:SlenderGetEyePosition(iBossIndex, Float:buffer[3], const Float:flDefaultValue[3]={ 0.0, 0.0, 0.0 })
+{
+	return NPCGetEyePosition(iBossIndex, buffer, flDefaultValue);
+}
+
+bool:SelectProfile(iBossIndex, const String:sProfile[], iAdditionalBossFlags=0, iCopyMaster=-1, bool:bSpawnCompanions=true, bool:bPlaySpawnSound=true)
+{
+	if (!IsProfileValid(sProfile))
+	{
+		LogSF2Message("Could not select profile for boss %d: profile %s is invalid!", iBossIndex, sProfile);
+		return false;
+	}
+	
+	NPCRemove(iBossIndex);
+	
+	new iProfileIndex = GetBossProfileIndexFromName(sProfile);
+	new iUniqueProfileIndex = GetBossProfileUniqueProfileIndex(iProfileIndex);
+	
+	NPCSetProfile(iBossIndex, sProfile);
+	
+	new iBossType = GetBossProfileType(iProfileIndex);
+	
+	g_iNPCProfileIndex[iBossIndex] = iProfileIndex;
+	g_iNPCUniqueProfileIndex[iBossIndex] = iUniqueProfileIndex;
+	g_iNPCUniqueID[iBossIndex] = g_iNPCGlobalUniqueID++;
+	g_iNPCType[iBossIndex] = iBossType;
+	
+	g_flNPCModelScale[iBossIndex] = GetBossProfileModelScale(iProfileIndex);
+	
+	NPCSetFlags(iBossIndex, GetBossProfileFlags(iProfileIndex) | iAdditionalBossFlags);
+	
+	GetBossProfileEyePositionOffset(iProfileIndex, g_flSlenderEyePosOffset[iBossIndex]);
+	GetBossProfileEyeAngleOffset(iProfileIndex, g_flSlenderEyeAngOffset[iBossIndex]);
+	
+	GetProfileVector(sProfile, "mins", g_flSlenderDetectMins[iBossIndex]);
+	GetProfileVector(sProfile, "maxs", g_flSlenderDetectMaxs[iBossIndex]);
+	
+	NPCSetAnger(iBossIndex, GetBossProfileAngerStart(iProfileIndex));
+	g_flNPCAngerAddOnPageGrab[iBossIndex] = GetBossProfileAngerAddOnPageGrab(iProfileIndex);
+	g_flNPCAngerAddOnPageGrabTimeDiff[iBossIndex] = GetBossProfileAngerPageGrabTimeDiff(iProfileIndex);
+	
+	g_iSlenderCopyMaster[iBossIndex] = -1;
+	g_iSlenderHealth[iBossIndex] = GetProfileNum(sProfile, "health", 900);
+	
+	for (new iDifficulty = 0; iDifficulty < Difficulty_Max; iDifficulty++)
+	{
+		g_flNPCSpeed[iBossIndex][iDifficulty] = GetBossProfileSpeed(iProfileIndex, iDifficulty);
+		g_flNPCMaxSpeed[iBossIndex][iDifficulty] = GetBossProfileMaxSpeed(iProfileIndex, iDifficulty);
+	}
+	
+	g_flNPCTurnRate[iBossIndex] = GetBossProfileTurnRate(iProfileIndex);
+	g_flNPCFieldOfView[iBossIndex] = GetBossProfileFOV(iProfileIndex);
+	
+	g_flNPCSearchRadius[iBossIndex] = GetBossProfileSearchRadius(iProfileIndex);
+	
+	g_flNPCScareRadius[iBossIndex] = GetBossProfileScareRadius(iProfileIndex);
+	g_flNPCScareCooldown[iBossIndex] = GetBossProfileScareCooldown(iProfileIndex);
+	
+	g_flNPCInstantKillRadius[iBossIndex] = GetBossProfileInstantKillRadius(iProfileIndex);
+	
+	g_iNPCTeleportType[iBossIndex] = GetBossProfileTeleportType(iProfileIndex);
+	
+	g_iNPCEnemy[iBossIndex] = INVALID_ENT_REFERENCE;
+	
+	// Deathcam values.
+	NPCSetDeathCamEnabled(iBossIndex, bool:GetProfileNum(sProfile, "death_cam"));
+	
+	g_flSlenderAcceleration[iBossIndex] = GetProfileFloat(sProfile, "acceleration", 150.0);
+	g_hSlenderFakeTimer[iBossIndex] = INVALID_HANDLE;
+	g_hSlenderEntityThink[iBossIndex] = INVALID_HANDLE;
+	g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
+	g_flSlenderNextTeleportTime[iBossIndex] = GetGameTime();
+	g_flSlenderLastKill[iBossIndex] = GetGameTime();
+	g_flSlenderTimeUntilKill[iBossIndex] = -1.0;
+	g_flSlenderNextJumpScare[iBossIndex] = -1.0;
+	g_flSlenderTimeUntilNextProxy[iBossIndex] = -1.0;
+	g_flSlenderTeleportMinRange[iBossIndex] = GetProfileFloat(sProfile, "teleport_range_min", 325.0);
+	g_flSlenderTeleportMaxRange[iBossIndex] = GetProfileFloat(sProfile, "teleport_range_max", 1024.0);
+	g_flSlenderStaticRadius[iBossIndex] = GetProfileFloat(sProfile, "static_radius");
+	g_flSlenderIdleAnimationPlaybackRate[iBossIndex] = GetProfileFloat(sProfile, "animation_idle_playbackrate", 1.0);
+	g_flSlenderWalkAnimationPlaybackRate[iBossIndex] = GetProfileFloat(sProfile, "animation_walk_playbackrate", 1.0);
+	g_flSlenderRunAnimationPlaybackRate[iBossIndex] = GetProfileFloat(sProfile, "animation_run_playbackrate", 1.0);
+	g_flSlenderJumpSpeed[iBossIndex] = GetProfileFloat(sProfile, "jump_speed", 512.0);
+	g_flSlenderPathNodeTolerance[iBossIndex] = GetProfileFloat(sProfile, "search_node_dist_tolerance", 32.0);
+	g_flSlenderPathNodeLookAhead[iBossIndex] = GetProfileFloat(sProfile, "search_node_dist_lookahead", 512.0);
+	g_flSlenderProxyTeleportMinRange[iBossIndex] = GetProfileFloat(sProfile, "proxies_teleport_range_min");
+	g_flSlenderProxyTeleportMaxRange[iBossIndex] = GetProfileFloat(sProfile, "proxies_teleport_range_max");
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		g_flPlayerLastChaseBossEncounterTime[i][iBossIndex] = -1.0;
+		g_flSlenderTeleportPlayersRestTime[iBossIndex][i] = -1.0;
+	}
+	
+	g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+	g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
+	g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
+	g_flSlenderNextTeleportTime[iBossIndex] = -1.0;
+	g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
+	
+	g_hSlenderThink[iBossIndex] = CreateTimer(0.1, Timer_SlenderTeleportThink, iBossIndex, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	
+	SlenderRemoveTargetMemory(iBossIndex);
+	
+	switch (iBossType)
+	{
+		case SF2BossType_Chaser:
+		{
+			NPCChaserOnSelectProfile(iBossIndex);
+			
+			SlenderCreateTargetMemory(iBossIndex);
+		}
+	}
+	
+	if (iCopyMaster >= 0 && iCopyMaster < MAX_BOSSES && NPCGetUniqueID(iCopyMaster) != -1)
+	{
+		g_iSlenderCopyMaster[iBossIndex] = iCopyMaster;
+		g_flSlenderNextJumpScare[iBossIndex] = g_flSlenderNextJumpScare[iCopyMaster];
+		
+		NPCSetAnger(iBossIndex, NPCGetAnger(iCopyMaster));
+	}
+	else
+	{
+		if (bPlaySpawnSound)
+		{
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_spawn_all", sBuffer, sizeof(sBuffer));
+			if (sBuffer[0]) EmitSoundToAll(sBuffer, _, SNDCHAN_STATIC, SNDLEVEL_HELICOPTER);
+		}
+		
+		if (bSpawnCompanions)
+		{
+			KvRewind(g_hConfig);
+			KvJumpToKey(g_hConfig, sProfile);
+			
+			decl String:sCompProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			new Handle:hCompanions = CreateArray(SF2_MAX_PROFILE_NAME_LENGTH);
+			
+			if (KvJumpToKey(g_hConfig, "companions"))
+			{
+				decl String:sNum[32];
+				
+				for (new i = 1;;i++)
+				{
+					IntToString(i, sNum, sizeof(sNum));
+					KvGetString(g_hConfig, sNum, sCompProfile, sizeof(sCompProfile));
+					if (!sCompProfile[0]) break;
+					
+					PushArrayString(hCompanions, sCompProfile);
+				}
+			}
+			
+			for (new i = 0, iSize = GetArraySize(hCompanions); i < iSize; i++)
+			{
+				GetArrayString(hCompanions, i, sCompProfile, sizeof(sCompProfile));
+				AddProfile(sCompProfile, _, _, false, false);
+			}
+			
+			CloseHandle(hCompanions);
+		}
+	}
+	
+	Call_StartForward(fOnBossAdded);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+	
+	return true;
+}
+
+AddProfile(const String:strName[], iAdditionalBossFlags=0, iCopyMaster=-1, bool:bSpawnCompanions=true, bool:bPlaySpawnSound=true)
+{
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1)
+		{
+			if (SelectProfile(i, strName, iAdditionalBossFlags, iCopyMaster, bSpawnCompanions, bPlaySpawnSound))
+			{
+				return i;
+			}
+			
+			break;
+		}
+	}
+	
+	return -1;
+}
+
+RemoveProfile(iBossIndex)
+{
+	RemoveSlender(iBossIndex);
+	
+	// Call our forward.
+	Call_StartForward(fOnBossRemoved);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	NPCChaserOnRemoveProfile(iBossIndex);
+	
+	// Remove all possible sounds, for emergencies.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		// Remove chase music.
+		if (g_iPlayerChaseMusicMaster[i] == iBossIndex)
+		{
+			ClientStopAllSlenderSounds(i, sProfile, "sound_chase", SNDCHAN_AUTO);
+		}
+	}
+	
+	// Clean up on the clients.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		g_flSlenderLastFoundPlayer[iBossIndex][i] = -1.0;
+		g_flPlayerLastChaseBossEncounterTime[i][iBossIndex] = -1.0;
+		g_flSlenderTeleportPlayersRestTime[iBossIndex][i] = -1.0;
+		
+		for (new i2 = 0; i2 < 3; i2++)
+		{
+			g_flSlenderLastFoundPlayerPos[iBossIndex][i][i2] = 0.0;
+		}
+		
+		if (IsClientInGame(i))
+		{
+			if (NPCGetUniqueID(iBossIndex) == g_iPlayerStaticMaster[i])
+			{
+				g_iPlayerStaticMaster[i] = -1;
+				
+				// No one is the static master.
+				g_hPlayerStaticTimer[i] = CreateTimer(g_flPlayerStaticDecreaseRate[i], 
+					Timer_ClientDecreaseStatic, 
+					GetClientUserId(i), 
+					TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+					
+				TriggerTimer(g_hPlayerStaticTimer[i], true);
+			}
+		}
+	}
+	
+	g_iNPCTeleportType[iBossIndex] = -1;
+	g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+	g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
+	g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
+	g_flSlenderNextTeleportTime[iBossIndex] = -1.0;
+	g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
+	g_flSlenderTimeUntilKill[iBossIndex] = -1.0;
+	
+	// Remove all copies associated with me.
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (i == iBossIndex || NPCGetUniqueID(i) == -1) continue;
+		
+		if (g_iSlenderCopyMaster[i] == iBossIndex)
+		{
+			LogMessage("Removed boss index %d because it is a copy of boss index %d", i, iBossIndex);
+			NPCRemove(i);
+		}
+	}
+	
+	NPCSetProfile(iBossIndex, "");
+	g_iNPCType[iBossIndex] = -1;
+	g_iNPCProfileIndex[iBossIndex] = -1;
+	g_iNPCUniqueProfileIndex[iBossIndex] = -1;
+	
+	NPCSetFlags(iBossIndex, 0);
+	
+	NPCSetAnger(iBossIndex, 1.0);
+	
+	g_flNPCFieldOfView[iBossIndex] = 0.0;
+	
+	g_iNPCEnemy[iBossIndex] = INVALID_ENT_REFERENCE;
+	
+	NPCSetDeathCamEnabled(iBossIndex, false);
+	
+	g_iSlenderCopyMaster[iBossIndex] = -1;
+	g_iNPCUniqueID[iBossIndex] = -1;
+	g_iSlender[iBossIndex] = INVALID_ENT_REFERENCE;
+	g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
+	g_hSlenderThink[iBossIndex] = INVALID_HANDLE;
+	g_hSlenderEntityThink[iBossIndex] = INVALID_HANDLE;
+	
+	g_hSlenderFakeTimer[iBossIndex] = INVALID_HANDLE;
+	g_flSlenderLastKill[iBossIndex] = -1.0;
+	g_iSlenderState[iBossIndex] = STATE_IDLE;
+	g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+	g_iSlenderModel[iBossIndex] = INVALID_ENT_REFERENCE;
+	g_flSlenderAcceleration[iBossIndex] = 0.0;
+	g_flSlenderTimeUntilNextProxy[iBossIndex] = -1.0;
+	g_flNPCSearchRadius[iBossIndex] = 0.0;
+	g_flNPCInstantKillRadius[iBossIndex] = 0.0;
+	g_flNPCScareRadius[iBossIndex] = 0.0;
+	g_flSlenderProxyTeleportMinRange[iBossIndex] = 0.0;
+	g_flSlenderProxyTeleportMaxRange[iBossIndex] = 0.0;
+	
+	for (new i = 0; i < 3; i++)
+	{
+		g_flSlenderDetectMins[iBossIndex][i] = 0.0;
+		g_flSlenderDetectMaxs[iBossIndex][i] = 0.0;
+		g_flSlenderEyePosOffset[iBossIndex][i] = 0.0;
+	}
+	
+	SlenderRemoveTargetMemory(iBossIndex);
+}
+
+SpawnSlender(iBossIndex, const Float:pos[3])
+{
+	RemoveSlender(iBossIndex);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl Float:flTruePos[3];
+	GetProfileVector(sProfile, "pos_offset", flTruePos);
+	AddVectors(flTruePos, pos, flTruePos);
+	
+	new iSlenderModel = SpawnSlenderModel(iBossIndex, flTruePos);
+	if (iSlenderModel == -1) 
+	{
+		LogError("Could not spawn boss: model failed to spawn!");
+		return;
+	}
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	
+	g_iSlenderModel[iBossIndex] = EntIndexToEntRef(iSlenderModel);
+	
+	switch (NPCGetType(iBossIndex))
+	{
+		case SF2BossType_Creeper:
+		{
+			g_iSlender[iBossIndex] = g_iSlenderModel[iBossIndex];
+			g_hSlenderEntityThink[iBossIndex] = CreateTimer(BOSS_THINKRATE, Timer_SlenderBlinkBossThink, g_iSlender[iBossIndex], TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+		}
+		case SF2BossType_Chaser:
+		{
+			GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
+			
+			new iBoss = CreateEntityByName("monster_generic");
+			SetEntityModel(iBoss, sBuffer);
+			TeleportEntity(iBoss, flTruePos, NULL_VECTOR, NULL_VECTOR);
+			DispatchSpawn(iBoss);
+			ActivateEntity(iBoss);
+			SetEntityRenderMode(iBoss, RENDER_TRANSCOLOR);
+			SetEntityRenderColor(iBoss, 0, 0, 0, 1);
+			SetVariantString("!activator");
+			AcceptEntityInput(iSlenderModel, "SetParent", iBoss);
+			AcceptEntityInput(iSlenderModel, "EnableShadow");
+			SetEntProp(iSlenderModel, Prop_Send, "m_usSolidFlags", FSOLID_NOT_SOLID | FSOLID_TRIGGER);
+			AcceptEntityInput(iBoss, "DisableShadow");
+			SetEntPropFloat(iBoss, Prop_Data, "m_flFriction", 0.0);
+			
+			NPCChaserSetStunHealth(iBossIndex, NPCChaserGetStunInitialHealth(iBossIndex));
+			
+			// Reset stats.
+			g_iSlender[iBossIndex] = EntIndexToEntRef(iBoss);
+			g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+			g_iSlenderState[iBossIndex] = STATE_IDLE;
+			g_bSlenderAttacking[iBossIndex] = false;
+			g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
+			g_flSlenderTargetSoundLastTime[iBossIndex] = -1.0;
+			g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = -1.0;
+			g_iSlenderTargetSoundType[iBossIndex] = SoundType_None;
+			g_bSlenderInvestigatingSound[iBossIndex] = false;
+			g_flSlenderLastHeardFootstep[iBossIndex] = GetGameTime();
+			g_flSlenderLastHeardVoice[iBossIndex] = GetGameTime();
+			g_flSlenderLastHeardWeapon[iBossIndex] = GetGameTime();
+			g_flSlenderNextVoiceSound[iBossIndex] = GetGameTime();
+			g_flSlenderNextMoanSound[iBossIndex] = GetGameTime();
+			g_flSlenderNextWanderPos[iBossIndex] = GetGameTime() + 3.0;
+			g_flSlenderTimeUntilKill[iBossIndex] = GetGameTime() + GetProfileFloat(sProfile, "idle_lifetime", 10.0);
+			g_flSlenderTimeUntilRecover[iBossIndex] = -1.0;
+			g_flSlenderTimeUntilAlert[iBossIndex] = -1.0;
+			g_flSlenderTimeUntilIdle[iBossIndex] = -1.0;
+			g_flSlenderTimeUntilChase[iBossIndex] = -1.0;
+			g_flSlenderTimeUntilNoPersistence[iBossIndex] = -1.0;
+			g_flSlenderNextJump[iBossIndex] = GetGameTime() + GetProfileFloat(sProfile, "jump_cooldown", 2.0);
+			g_flSlenderNextPathTime[iBossIndex] = GetGameTime();
+			g_hSlenderEntityThink[iBossIndex] = CreateTimer(BOSS_THINKRATE, Timer_SlenderChaseBossThink, EntIndexToEntRef(iBoss), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			g_iSlenderInterruptConditions[iBossIndex] = 0;
+			g_bSlenderChaseDeathPosition[iBossIndex] = false;
+			
+			for (new i = 0; i < 3; i++)
+			{
+				g_flSlenderGoalPos[iBossIndex][i] = 0.0;
+				g_flSlenderTargetSoundTempPos[iBossIndex][i] = 0.0;
+				g_flSlenderTargetSoundMasterPos[iBossIndex][i] = 0.0;
+				g_flSlenderChaseDeathPosition[iBossIndex][i] = 0.0;
+			}
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				g_flSlenderLastFoundPlayer[iBossIndex][i] = -1.0;
+				
+				for (new i2 = 0; i2 < 3; i2++)
+				{
+					g_flSlenderLastFoundPlayerPos[iBossIndex][i][i2] = 0.0;
+				}
+			}
+			
+			SlenderClearTargetMemory(iBossIndex);
+			
+			if (GetProfileNum(sProfile, "stun_enabled"))
+			{
+				SetEntProp(iBoss, Prop_Data, "m_takedamage", 1);
+			}
+			
+			SDKHook(iBoss, SDKHook_OnTakeDamage, Hook_SlenderOnTakeDamage);
+			SDKHook(iBoss, SDKHook_OnTakeDamagePost, Hook_SlenderOnTakeDamagePost);
+			DHookEntity(g_hSDKShouldTransmit, true, iBoss);
+		}
+		/*
+		default:
+		{
+			g_iSlender[iBossIndex] = g_iSlenderModel[iBossIndex];
+			SDKHook(iSlenderModel, SDKHook_SetTransmit, Hook_SlenderSetTransmit);
+		}
+		*/
+	}
+	
+	SDKHook(iSlenderModel, SDKHook_SetTransmit, Hook_SlenderModelSetTransmit);
+	
+	SlenderSpawnEffects(iBossIndex, EffectEvent_Constant);
+	
+	// Initialize our pose parameters, if needed.
+	new iPose = EntRefToEntIndex(g_iSlenderPoseEnt[iBossIndex]);
+	g_iSlenderPoseEnt[iBossIndex] = INVALID_ENT_REFERENCE;
+	if (iPose && iPose != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(iPose, "Kill");
+	}
+	
+	decl String:sPoseParameter[64];
+	GetProfileString(sProfile, "pose_parameter", sPoseParameter, sizeof(sPoseParameter));
+	if (sPoseParameter[0])
+	{
+		iPose = CreateEntityByName("point_posecontroller");
+		if (iPose != -1)
+		{
+			// We got a pose parameter! We need a name!
+			Format(sBuffer, sizeof(sBuffer), "s%dposepls", g_iSlenderModel[iBossIndex]);
+			DispatchKeyValue(iSlenderModel, "targetname", sBuffer);
+			
+			DispatchKeyValue(iPose, "PropName", sBuffer);
+			DispatchKeyValue(iPose, "PoseParameterName", sPoseParameter);
+			DispatchKeyValueFloat(iPose, "PoseValue", GetProfileFloat(sProfile, "pose_parameter_max"));
+			DispatchSpawn(iPose);
+			SetVariantString(sPoseParameter);
+			AcceptEntityInput(iPose, "SetPoseParameterName");
+			SetVariantString("!activator");
+			AcceptEntityInput(iPose, "SetParent", iSlenderModel);
+			
+			g_iSlenderPoseEnt[iBossIndex] = EntIndexToEntRef(iPose);
+		}
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnBossSpawn);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+}
+
+RemoveSlender(iBossIndex)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+
+	new iBoss = NPCGetEntIndex(iBossIndex);
+	g_iSlender[iBossIndex] = INVALID_ENT_REFERENCE;
+	
+	if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+	{
+		// Stop all possible looping sounds.
+		ClientStopAllSlenderSounds(iBoss, sProfile, "sound_move", SNDCHAN_AUTO);
+		
+		if (NPCGetFlags(iBossIndex) & SFF_HASSTATICLOOPLOCALSOUND)
+		{
+			decl String:sLoopSound[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
+			
+			if (sLoopSound[0])
+			{
+				StopSound(iBoss, SNDCHAN_STATIC, sLoopSound);
+			}
+		}
+		
+		AcceptEntityInput(iBoss, "Kill");
+	}
+}
+
+public Action:Hook_SlenderOnTakeDamage(slender, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return Plugin_Continue;
+	
+	if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+		
+		if (NPCChaserIsStunEnabled(iBossIndex))
+		{
+			if (damagetype & DMG_ACID) damage *= 2.0; // 2x damage for critical hits.
+			
+			NPCChaserAddStunHealth(iBossIndex, -damage);
+		}
+	}
+	
+	damage = 0.0;
+	return Plugin_Changed;
+}
+
+public Hook_SlenderOnTakeDamagePost(slender, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3])
+{
+	if (!g_bEnabled) return;
+
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return;
+	
+	if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
+	{
+		if (damagetype & DMG_ACID)
+		{
+			decl Float:flMyEyePos[3];
+			SlenderGetEyePosition(iBossIndex, flMyEyePos);
+			
+			TE_SetupTFParticleEffect(g_iParticleCriticalHit, flMyEyePos, flMyEyePos);
+			TE_SendToAll();
+			
+			EmitSoundToAll(CRIT_SOUND, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+		}
+	}
+}
+
+public Action:Hook_SlenderModelSetTransmit(entity, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	new iBossIndex = -1;
+	
+	new entref = EntIndexToEntRef(entity);
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		if (g_iSlenderModel[i] != entref) continue;
+		
+		iBossIndex = i;
+		break;
+	}
+	
+	if (iBossIndex == -1) return Plugin_Continue;
+	
+	if (!IsPlayerAlive(other) || IsClientInDeathCam(other)) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+stock bool:SlenderCanHearPlayer(iBossIndex, client, SoundType:iSoundType)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client)) return false;
+	
+	new iSlender = NPCGetEntIndex(iBossIndex);
+	if (!iSlender || iSlender == INVALID_ENT_REFERENCE) return false;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl Float:flHisPos[3], Float:flMyPos[3];
+	GetClientAbsOrigin(client, flHisPos);
+	SlenderGetAbsOrigin(iBossIndex, flMyPos);
+	
+	new Float:flHearRadius = GetProfileFloat(sProfile, "search_sound_range", 1024.0);
+	if (flHearRadius <= 0.0) return false;
+	
+	new Float:flDistance = GetVectorDistance(flHisPos, flMyPos);
+	
+	// Trace check.
+	new Handle:hTrace = INVALID_HANDLE;
+	new bool:bTraceHit = false;
+	
+	decl Float:flMyEyePos[3];
+	SlenderGetEyePosition(iBossIndex, flMyEyePos);
+	
+	if (iSoundType == SoundType_Footstep)
+	{
+		if (!(GetEntityFlags(client) & FL_ONGROUND)) return false;
+		
+		if (GetEntProp(client, Prop_Send, "m_bDucking") || GetEntProp(client, Prop_Send, "m_bDucked")) flDistance *= 1.85;
+		if (IsClientReallySprinting(client)) flDistance *= 0.66;
+		
+		hTrace = TR_TraceRayFilterEx(flMyPos, flHisPos, MASK_NPCSOLID, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, iSlender);
+		bTraceHit = TR_DidHit(hTrace);
+		CloseHandle(hTrace);
+	}
+	else if (iSoundType == SoundType_Voice)
+	{
+		decl Float:flHisEyePos[3];
+		GetClientEyePosition(client, flHisEyePos);
+		
+		hTrace = TR_TraceRayFilterEx(flMyEyePos, flHisEyePos, MASK_NPCSOLID, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, iSlender);
+		bTraceHit = TR_DidHit(hTrace);
+		CloseHandle(hTrace);
+		
+		flDistance *= 0.5;
+	}
+	else if (iSoundType == SoundType_Weapon)
+	{
+		decl Float:flHisMins[3], Float:flHisMaxs[3];
+		GetEntPropVector(client, Prop_Send, "m_vecMins", flHisMins);
+		GetEntPropVector(client, Prop_Send, "m_vecMaxs", flHisMaxs);
+		
+		new Float:flMiddle[3];
+		for (new i = 0; i < 2; i++) flMiddle[i] = (flHisMins[i] + flHisMaxs[i]) / 2.0;
+		
+		decl Float:flEndPos[3];
+		GetClientAbsOrigin(client, flEndPos);
+		AddVectors(flHisPos, flMiddle, flEndPos);
+		
+		hTrace = TR_TraceRayFilterEx(flMyEyePos, flEndPos, MASK_NPCSOLID, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, iSlender);
+		bTraceHit = TR_DidHit(hTrace);
+		CloseHandle(hTrace);
+		
+		flDistance *= 0.66;
+	}
+	
+	if (bTraceHit) flDistance *= 1.66;
+	
+	if (TF2_GetPlayerClass(client) == TFClass_Spy) flDistance *= 1.35;
+	
+	if (flDistance > flHearRadius) return false;
+	
+	return true;
+}
+
+stock SlenderArrayIndexToEntIndex(iBossIndex)
+{
+	return NPCGetEntIndex(iBossIndex);
+}
+
+stock bool:SlenderOnlyLooksIfNotSeen(iBossIndex)
+{
+	if (NPCGetType(iBossIndex) == SF2BossType_Creeper) return true;
+	return false;
+}
+
+stock bool:SlenderUsesBlink(iBossIndex)
+{
+	if (NPCGetType(iBossIndex) == SF2BossType_Creeper) return true;
+	return false;
+}
+
+stock bool:SlenderKillsOnNear(iBossIndex)
+{
+	if (NPCGetType(iBossIndex) == SF2BossType_Creeper) return false;
+	return true;
+}
+
+stock SlenderClearTargetMemory(iBossIndex)
+{
+	if (iBossIndex == -1) return;
+	
+	g_iSlenderCurrentPathNode[iBossIndex] = -1;
+	if (g_hSlenderPath[iBossIndex] == INVALID_HANDLE) return;
+	
+	ClearArray(g_hSlenderPath[iBossIndex]);
+}
+
+stock bool:SlenderCreateTargetMemory(iBossIndex)
+{
+	if (iBossIndex == -1) return false;
+	
+	g_iSlenderCurrentPathNode[iBossIndex] = -1;
+	if (g_hSlenderPath[iBossIndex] != INVALID_HANDLE) return true;
+	
+	g_hSlenderPath[iBossIndex] = CreateArray(3);
+	return true;
+}
+
+stock SlenderRemoveTargetMemory(iBossIndex)
+{
+	if (iBossIndex == -1) return;
+	
+	g_iSlenderCurrentPathNode[iBossIndex] = -1;
+	
+	if (g_hSlenderPath[iBossIndex] == INVALID_HANDLE) return;
+	
+	new Handle:hLocs = g_hSlenderPath[iBossIndex];
+	g_hSlenderPath[iBossIndex] = INVALID_HANDLE;
+	CloseHandle(hLocs);
+}
+
+SlenderPerformVoice(iBossIndex, const String:sSectionName[], iIndex=-1)
+{
+	if (iBossIndex == -1) return;
+
+	new slender = NPCGetEntIndex(iBossIndex);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sPath[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, sSectionName, sPath, sizeof(sPath), iIndex);
+	if (sPath[0])
+	{
+		decl String:sBuffer[512];
+		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
+		StrCat(sBuffer, sizeof(sBuffer), "_cooldown_min");
+		new Float:flCooldownMin = GetProfileFloat(sProfile, sBuffer, 1.5);
+		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
+		StrCat(sBuffer, sizeof(sBuffer), "_cooldown_max");
+		new Float:flCooldownMax = GetProfileFloat(sProfile, sBuffer, 1.5);
+		new Float:flCooldown = GetRandomFloat(flCooldownMin, flCooldownMax);
+		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
+		StrCat(sBuffer, sizeof(sBuffer), "_volume");
+		new Float:flVolume = GetProfileFloat(sProfile, sBuffer, 1.0);
+		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
+		StrCat(sBuffer, sizeof(sBuffer), "_channel");
+		new iChannel = GetProfileNum(sProfile, sBuffer, SNDCHAN_AUTO);
+		strcopy(sBuffer, sizeof(sBuffer), sSectionName);
+		StrCat(sBuffer, sizeof(sBuffer), "_level");
+		new iLevel = GetProfileNum(sProfile, sBuffer, SNDLEVEL_SCREAMING);
+		
+		g_flSlenderNextVoiceSound[iBossIndex] = GetGameTime() + flCooldown;
+		EmitSoundToAll(sPath, slender, iChannel, iLevel, _, flVolume);
+	}
+}
+
+bool:SlenderCalculateApproachToPlayer(iBossIndex, iBestPlayer, Float:buffer[3])
+{
+	if (!IsValidClient(iBestPlayer)) return false;
+	
+	new slender = NPCGetEntIndex(iBossIndex);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return false;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl Float:flSlenderPos[3], Float:flPos[3], Float:flReferenceAng[3], Float:hisEyeAng[3], Float:tempDir[3], Float:tempPos[3];
+	GetClientEyePosition(iBestPlayer, flPos);
+	
+	GetEntPropVector(slender, Prop_Data, "m_angAbsRotation", hisEyeAng);
+	AddVectors(hisEyeAng, g_flSlenderEyeAngOffset[iBossIndex], hisEyeAng);
+	for (new i = 0; i < 3; i++) hisEyeAng[i] = AngleNormalize(hisEyeAng[i]);
+	
+	SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
+	
+	SubtractVectors(flPos, flSlenderPos, flReferenceAng);
+	GetVectorAngles(flReferenceAng, flReferenceAng);
+	for (new i = 0; i < 3; i++) flReferenceAng[i] = AngleNormalize(flReferenceAng[i]);
+	new Float:flDist = GetProfileFloat(sProfile, "speed") * g_flRoundDifficultyModifier;
+	if (flDist < GetProfileFloat(sProfile, "kill_radius")) flDist = GetProfileFloat(sProfile, "kill_radius") / 2.0;
+	new Float:flWithinFOV = 45.0;
+	new Float:flWithinFOVSide = 90.0;
+	
+	decl Handle:hTrace, index, Float:flHitNormal[3], Float:tempPos2[3], Float:flBuffer[3], Float:flBuffer2[3];
+	new Handle:hArray = CreateArray(6);
+	
+	decl Float:flCheckAng[3];
+	
+	new iRange = 0;
+	new iID = 1;
+	
+	for (new Float:addAng = 0.0; addAng < 360.0; addAng += 7.5)
+	{
+		tempDir[0] = 0.0;
+		tempDir[1] = AngleNormalize(hisEyeAng[1] + addAng);
+		tempDir[2] = 0.0;
+		
+		GetAngleVectors(tempDir, tempDir, NULL_VECTOR, NULL_VECTOR);
+		NormalizeVector(tempDir, tempDir);
+		ScaleVector(tempDir, flDist);
+		AddVectors(tempDir, flSlenderPos, tempPos);
+		AddVectors(tempPos, g_flSlenderEyePosOffset[iBossIndex], tempPos);
+		AddVectors(flSlenderPos, g_flSlenderEyePosOffset[iBossIndex], tempPos2);
+		
+		flBuffer[0] = g_flSlenderDetectMins[iBossIndex][0];
+		flBuffer[1] = g_flSlenderDetectMins[iBossIndex][1];
+		flBuffer[2] = 0.0;
+		flBuffer2[0] = g_flSlenderDetectMaxs[iBossIndex][0];
+		flBuffer2[1] = g_flSlenderDetectMaxs[iBossIndex][1];
+		flBuffer2[2] = 0.0;
+		
+		// Get a good move position.
+		hTrace = TR_TraceHullFilterEx(tempPos2, tempPos, flBuffer, flBuffer2, MASK_PLAYERSOLID_BRUSHONLY, TraceRayDontHitCharactersOrEntity, slender);
+		TR_GetEndPosition(tempPos, hTrace);
+		CloseHandle(hTrace);
+		
+		// Drop to the ground if we're above ground.
+		hTrace = TR_TraceRayFilterEx(tempPos, Float:{ 90.0, 0.0, 0.0 }, MASK_PLAYERSOLID_BRUSHONLY, RayType_Infinite, TraceRayDontHitCharactersOrEntity, slender);
+		new bool:bHit = TR_DidHit(hTrace);
+		TR_GetEndPosition(tempPos2, hTrace);
+		CloseHandle(hTrace);
+		
+		// Then calculate from there.
+		hTrace = TR_TraceHullFilterEx(tempPos, tempPos2, g_flSlenderDetectMins[iBossIndex], g_flSlenderDetectMaxs[iBossIndex], MASK_PLAYERSOLID_BRUSHONLY, TraceRayDontHitCharactersOrEntity, slender);
+		TR_GetEndPosition(tempPos, hTrace);
+		TR_GetPlaneNormal(hTrace, flHitNormal);
+		CloseHandle(hTrace);
+		SubtractVectors(tempPos, flSlenderPos, flCheckAng);
+		GetVectorAngles(flCheckAng, flCheckAng);
+		GetVectorAngles(flHitNormal, flHitNormal);
+		for (new i = 0; i < 3; i++) 
+		{
+			flHitNormal[i] = AngleNormalize(flHitNormal[i]);
+			flCheckAng[i] = AngleNormalize(flCheckAng[i]);
+		}
+		
+		new Float:diff = AngleDiff(flCheckAng[1], flReferenceAng[1]);
+		
+		new bool:bBackup = false;
+		
+		if (FloatAbs(diff) > flWithinFOV) bBackup = true;
+		
+		if (diff >= 0.0 && diff <= flWithinFOVSide) iRange = 1;
+		else if (diff < 0.0 && diff >= -flWithinFOVSide) iRange = 2;
+		else continue;
+		
+		if ((flHitNormal[0] >= 0.0 && flHitNormal[0] < 45.0)
+			|| (flHitNormal[0] < 0.0 && flHitNormal[0] > -45.0)
+			|| !bHit
+			|| TR_PointOutsideWorld(tempPos)
+			|| IsSpaceOccupiedNPC(tempPos, g_flSlenderDetectMins[iBossIndex], g_flSlenderDetectMaxs[iBossIndex], iBestPlayer))
+		{
+			continue;
+		}
+		
+		// Check from top to bottom of me.
+		
+		if (!IsPointVisibleToPlayer(iBestPlayer, tempPos, false, false)) continue;
+		
+		AddVectors(tempPos, g_flSlenderEyePosOffset[iBossIndex], tempPos);
+		
+		if (!IsPointVisibleToPlayer(iBestPlayer, tempPos, false, false)) continue;
+		
+		SubtractVectors(tempPos, g_flSlenderEyePosOffset[iBossIndex], tempPos);
+		
+		//	Insert the vector into our array.
+		index = PushArrayCell(hArray, iID);
+		SetArrayCell(hArray, index, tempPos[0], 1);
+		SetArrayCell(hArray, index, tempPos[1], 2);
+		SetArrayCell(hArray, index, tempPos[2], 3);
+		SetArrayCell(hArray, index, iRange, 4);
+		SetArrayCell(hArray, index, bBackup, 5);
+		
+		iID++;
+	}
+	
+	new size;
+	if ((size = GetArraySize(hArray)) > 0)
+	{
+		new Float:diff = AngleDiff(hisEyeAng[1], flReferenceAng[1]);
+		if (diff >= 0.0) iRange = 1;
+		else iRange = 2;
+		
+		new bool:bBackup = false;
+		
+		// Clean up any vectors that we don't need.
+		new Handle:hArray2 = CloneArray(hArray);
+		for (new i = 0; i < size; i++)
+		{
+			if (GetArrayCell(hArray2, i, 4) != iRange || bool:GetArrayCell(hArray2, i, 5) != bBackup)
+			{
+				new iIndex = FindValueInArray(hArray, GetArrayCell(hArray2, i));
+				if (iIndex != -1) RemoveFromArray(hArray, iIndex);
+			}
+		}
+		
+		CloseHandle(hArray2);
+		
+		size = GetArraySize(hArray);
+		if (size)
+		{
+			index = GetRandomInt(0, size - 1);
+			buffer[0] = Float:GetArrayCell(hArray, index, 1);
+			buffer[1] = Float:GetArrayCell(hArray, index, 2);
+			buffer[2] = Float:GetArrayCell(hArray, index, 3);
+		}
+		else
+		{
+			CloseHandle(hArray);
+			return false;
+		}
+	}
+	else
+	{
+		CloseHandle(hArray);
+		return false;
+	}
+	
+	CloseHandle(hArray);
+	return true;
+}
+
+// This functor ensures that the proposed boss position is not too
+// close to other players that are within the distance defined by
+// flMinSearchDist.
+
+// Returning false on the functor will immediately discard the proposed position.
+
+public bool:SlenderChaseBossPlaceFunctor(iBossIndex, const Float:flActiveAreaCenterPos[3], const Float:flAreaPos[3], Float:flMinSearchDist, Float:flMaxSearchDist, bool:bOriginalResult)
+{
+	if (FloatAbs(flActiveAreaCenterPos[2] - flAreaPos[2]) > 320.0)
+	{
+		return false;
+	}
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) ||
+			!IsPlayerAlive(i) ||
+			g_bPlayerEliminated[i] ||
+			g_bPlayerEscaped[i]) continue;
+		
+		decl Float:flClientPos[3];
+		GetClientAbsOrigin(i, flClientPos);
+		
+		if (GetVectorDistance(flClientPos, flAreaPos) < flMinSearchDist)
+		{
+			return false;
+		}
+	}
+	
+	return bOriginalResult;
+}
+
+// As time passes on, we have to get more aggressive in order to successfully peak the target's
+// stress level in the allotted duration we're given. Otherwise we'll be forced to place him
+// in a rest period.
+
+// Teleport progressively closer as time passes in attempt to increase the target's stress level.
+// Maximum minimum range is capped by the boss's anger level.
+
+stock Float:CalculateTeleportMinRange(iBossIndex, Float:flInitialMinRange, Float:flTeleportMaxRange)
+{
+	new Float:flTeleportTargetTimeLeft = g_flSlenderTeleportMaxTargetTime[iBossIndex] - GetGameTime();
+	new Float:flTeleportTargetTimeInitial = g_flSlenderTeleportMaxTargetTime[iBossIndex] - g_flSlenderTeleportTargetTime[iBossIndex];
+	new Float:flTeleportMinRange = flTeleportMaxRange - (1.0 - (flTeleportTargetTimeLeft / flTeleportTargetTimeInitial)) * (flTeleportMaxRange - flInitialMinRange);
+	
+	if (NPCGetAnger(iBossIndex) <= 1.0)
+	{
+		flTeleportMinRange += (g_flSlenderTeleportMinRange[iBossIndex] - flTeleportMaxRange) * Pow(NPCGetAnger(iBossIndex) - 1.0, 2.0 / g_flRoundDifficultyModifier);
+	}
+	
+	if (flTeleportMinRange < flInitialMinRange) flTeleportMinRange = flInitialMinRange;
+	if (flTeleportMinRange > flTeleportMaxRange) flTeleportMinRange = flTeleportMaxRange;
+	
+	return flTeleportMinRange;
+}
+
+public Action:Timer_SlenderTeleportThink(Handle:timer, any:iBossIndex)
+{
+	if (iBossIndex == -1) return Plugin_Stop;
+	if (timer != g_hSlenderThink[iBossIndex]) return Plugin_Stop;
+	
+	if (NPCGetFlags(iBossIndex) & SFF_NOTELEPORT) return Plugin_Continue;
+	
+	// Check to see if anyone's looking at me before doing anything.
+	if (PeopleCanSeeSlender(iBossIndex, _, false))
+	{
+		return Plugin_Continue;
+	}
+	
+	if (NPCGetTeleportType(iBossIndex) == 2)
+	{
+		new iBoss = NPCGetEntIndex(iBossIndex);
+		if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+		{
+			if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
+			{
+				// Check to see if it's a good time to teleport away.
+				new iState = g_iSlenderState[iBossIndex];
+				if (iState == STATE_IDLE || iState == STATE_WANDER)
+				{
+					if (GetGameTime() < g_flSlenderTimeUntilKill[iBossIndex])
+					{
+						return Plugin_Continue;
+					}
+				}
+			}
+		}
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (!g_bRoundGrace)
+	{
+		if (GetGameTime() >= g_flSlenderNextTeleportTime[iBossIndex])
+		{
+			new Float:flTeleportTime = GetRandomFloat(GetProfileFloat(sProfile, "teleport_time_min", 5.0), GetProfileFloat(sProfile, "teleport_time_max", 9.0));
+			g_flSlenderNextTeleportTime[iBossIndex] = GetGameTime() + flTeleportTime;
+			
+			new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
+			
+			if (!iTeleportTarget || iTeleportTarget == INVALID_ENT_REFERENCE)
+			{
+				// We don't have any good targets. Remove myself for now.
+				if (SlenderCanRemove(iBossIndex)) RemoveSlender(iBossIndex);
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: no good target, removing...", iBossIndex);
+#endif
+			}
+			else
+			{
+				new Float:flTeleportMinRange = CalculateTeleportMinRange(iBossIndex, g_flSlenderTeleportMinRange[iBossIndex], g_flSlenderTeleportMaxRange[iBossIndex]);
+				
+				new iTeleportAreaIndex = -1;
+				decl Float:flTeleportPos[3];
+				
+				// Search surrounding nav areas around target.
+				if (NavMesh_Exists())
+				{
+					decl Float:flTargetPos[3];
+					GetClientAbsOrigin(iTeleportTarget, flTargetPos);
+					
+					new iTargetAreaIndex = NavMesh_GetNearestArea(flTargetPos);
+					if (iTargetAreaIndex != -1)
+					{
+						new bool:bShouldBeBehindObstruction = false;
+						if (NPCGetTeleportType(iBossIndex) == 2)
+						{
+							bShouldBeBehindObstruction = true;
+						}
+						
+						// Search outwards until travel distance is at maximum range.
+						new Handle:hAreaArray = CreateArray(2);
+						new Handle:hAreas = CreateStack();
+						NavMesh_CollectSurroundingAreas(hAreas, iTargetAreaIndex, g_flSlenderTeleportMaxRange[iBossIndex]);
+						
+						{
+							new iPoppedAreas;
+						
+							while (!IsStackEmpty(hAreas))
+							{
+								new iAreaIndex = -1;
+								PopStackCell(hAreas, iAreaIndex);
+								
+								// Check flags.
+								if (NavMeshArea_GetFlags(iAreaIndex) & NAV_MESH_NO_HOSTAGES)
+								{
+									// Don't spawn/teleport at areas marked with the "NO HOSTAGES" flag.
+									continue;
+								}
+								
+								new iIndex = PushArrayCell(hAreaArray, iAreaIndex);
+								SetArrayCell(hAreaArray, iIndex, float(NavMeshArea_GetCostSoFar(iAreaIndex)), 1);
+								iPoppedAreas++;
+							}
+							
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: collected %d areas", iBossIndex, iPoppedAreas);
+#endif
+							
+							CloseHandle(hAreas);
+						}
+						
+						new Handle:hAreaArrayClose = CreateArray(4);
+						new Handle:hAreaArrayAverage = CreateArray(4);
+						new Handle:hAreaArrayFar = CreateArray(4);
+						
+						for (new i = 1; i <= 3; i++)
+						{
+							new Float:flRangeSectionMin = flTeleportMinRange + (g_flSlenderTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(i - 1) / 3.0);
+							new Float:flRangeSectionMax = flTeleportMinRange + (g_flSlenderTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(i) / 3.0);
+							
+							for (new i2 = 0, iSize = GetArraySize(hAreaArray); i2 < iSize; i2++)
+							{
+								new iAreaIndex = GetArrayCell(hAreaArray, i2);
+								
+								decl Float:flAreaSpawnPoint[3];
+								NavMeshArea_GetCenter(iAreaIndex, flAreaSpawnPoint);
+								
+								new iBoss = NPCGetEntIndex(iBossIndex);
+								
+								// Check space. First raise to HalfHumanHeight * 2, then trace downwards to get ground level.
+								{
+									decl Float:flTraceStartPos[3];
+									flTraceStartPos[0] = flAreaSpawnPoint[0];
+									flTraceStartPos[1] = flAreaSpawnPoint[1];
+									flTraceStartPos[2] = flAreaSpawnPoint[2] + (HalfHumanHeight * 2.0);
+									
+									decl Float:flTraceMins[3];
+									flTraceMins[0] = g_flSlenderDetectMins[iBossIndex][0];
+									flTraceMins[1] = g_flSlenderDetectMins[iBossIndex][1];
+									flTraceMins[2] = 0.0;
+									
+									
+									decl Float:flTraceMaxs[3];
+									flTraceMaxs[0] = g_flSlenderDetectMaxs[iBossIndex][0];
+									flTraceMaxs[1] = g_flSlenderDetectMaxs[iBossIndex][1];
+									flTraceMaxs[2] = 0.0;
+									
+									new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
+										flAreaSpawnPoint,
+										flTraceMins,
+										flTraceMaxs,
+										MASK_NPCSOLID,
+										TraceRayDontHitEntity,
+										iBoss);
+									
+									decl Float:flTraceHitPos[3];
+									TR_GetEndPosition(flTraceHitPos, hTrace);
+									flTraceHitPos[2] += 1.0;
+									CloseHandle(hTrace);
+									
+									if (IsSpaceOccupiedNPC(flTraceHitPos,
+										g_flSlenderDetectMins[iBossIndex],
+										g_flSlenderDetectMaxs[iBossIndex],
+										iBoss))
+									{
+										continue;
+									}
+									
+									if (NPCGetType(iBossIndex) == SF2BossType_Chaser)
+									{
+										if (IsSpaceOccupiedNPC(flTraceHitPos,
+											HULL_HUMAN_MINS,
+											HULL_HUMAN_MAXS,
+											iBoss))
+										{
+											// Can't let an NPC spawn here; too little space. If we let it spawn here it will be non solid!
+											continue;
+										}
+									}
+									
+									flAreaSpawnPoint[0] = flTraceHitPos[0];
+									flAreaSpawnPoint[1] = flTraceHitPos[1];
+									flAreaSpawnPoint[2] = flTraceHitPos[2];
+								}
+								
+								// Check visibility.
+								if (IsPointVisibleToAPlayer(flAreaSpawnPoint, !bShouldBeBehindObstruction, false)) continue;
+								
+								AddVectors(flAreaSpawnPoint, g_flSlenderEyePosOffset[iBossIndex], flAreaSpawnPoint);
+								
+								if (IsPointVisibleToAPlayer(flAreaSpawnPoint, !bShouldBeBehindObstruction, false)) continue;
+								
+								SubtractVectors(flAreaSpawnPoint, g_flSlenderEyePosOffset[iBossIndex], flAreaSpawnPoint);
+								
+								new bool:bTooNear = false;
+								
+								// Check minimum range with players.
+								for (new iClient = 1; iClient <= MaxClients; iClient++)
+								{
+									if (!IsClientInGame(iClient) ||
+										!IsPlayerAlive(iClient) ||
+										g_bPlayerEliminated[iClient] ||
+										IsClientInGhostMode(iClient) || 
+										DidClientEscape(iClient))
+									{
+										continue;
+									}
+									
+									decl Float:flTempPos[3];
+									GetClientAbsOrigin(iClient, flTempPos);
+									
+									if (GetVectorDistance(flAreaSpawnPoint, flTempPos) <= g_flSlenderTeleportMinRange[iBossIndex])
+									{
+										bTooNear = true;
+										break;
+									}
+								}
+								
+								if (bTooNear) continue;	// This area is not compatible.
+								
+								// Check minimum range with boss copies (if supported).
+								if (NPCGetFlags(iBossIndex) & SFF_COPIES)
+								{
+									new Float:flMinDistBetweenBosses = GetProfileFloat(sProfile, "copy_teleport_dist_from_others", 800.0);
+									
+									for (new iBossCheck = 0; iBossCheck < MAX_BOSSES; iBossCheck++)
+									{
+										if (iBossCheck == iBossIndex ||
+											NPCGetUniqueID(iBossCheck) == -1 ||
+											(g_iSlenderCopyMaster[iBossIndex] != iBossCheck && g_iSlenderCopyMaster[iBossIndex] != g_iSlenderCopyMaster[iBossCheck]))
+										{
+											continue;
+										}
+										
+										new iBossEnt = NPCGetEntIndex(iBossCheck);
+										if (!iBossEnt || iBossEnt == INVALID_ENT_REFERENCE) continue;
+										
+										decl Float:flTempPos[3];
+										SlenderGetAbsOrigin(iBossCheck, flTempPos);
+										
+										if (GetVectorDistance(flAreaSpawnPoint, flTempPos) <= flMinDistBetweenBosses)
+										{
+											bTooNear = true;
+											break;
+										}
+									}
+								}
+								
+								if (bTooNear) continue;	// This area is not compatible.
+								
+								// Check travel distance and put in the appropriate arrays.
+								new Float:flDist = Float:GetArrayCell(hAreaArray, i2, 1);
+								if (flDist > flRangeSectionMin && flDist < flRangeSectionMax)
+								{
+									new iIndex = -1;
+									new Handle:hTargetAreaArray = INVALID_HANDLE;
+									
+									switch (i)
+									{
+										case 1: 
+										{
+											iIndex = PushArrayCell(hAreaArrayClose, iAreaIndex);
+											hTargetAreaArray = hAreaArrayClose;
+										}
+										case 2: 
+										{
+											iIndex = PushArrayCell(hAreaArrayAverage, iAreaIndex);
+											hTargetAreaArray = hAreaArrayAverage;
+										}
+										case 3: 
+										{
+											iIndex = PushArrayCell(hAreaArrayFar, iAreaIndex);
+											hTargetAreaArray = hAreaArrayFar;
+										}
+									}
+									
+									if (hTargetAreaArray != INVALID_HANDLE && iIndex != -1)
+									{
+										SetArrayCell(hTargetAreaArray, iIndex, flAreaSpawnPoint[0], 1);
+										SetArrayCell(hTargetAreaArray, iIndex, flAreaSpawnPoint[1], 2);
+										SetArrayCell(hTargetAreaArray, iIndex, flAreaSpawnPoint[2], 3);
+									}
+								}
+							}
+						}
+						
+						CloseHandle(hAreaArray);
+						
+#if defined DEBUG
+						SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: collected %d close areas, %d average areas, %d far areas", iBossIndex, GetArraySize(hAreaArrayClose),
+							GetArraySize(hAreaArrayAverage),
+							GetArraySize(hAreaArrayFar));
+#endif
+						
+						new iArrayIndex = -1;
+						
+						if (GetArraySize(hAreaArrayClose))
+						{
+							iArrayIndex = GetRandomInt(0, GetArraySize(hAreaArrayClose) - 1);
+							iTeleportAreaIndex = GetArrayCell(hAreaArrayClose, iArrayIndex);
+							flTeleportPos[0] = Float:GetArrayCell(hAreaArrayClose, iArrayIndex, 1);
+							flTeleportPos[1] = Float:GetArrayCell(hAreaArrayClose, iArrayIndex, 2);
+							flTeleportPos[2] = Float:GetArrayCell(hAreaArrayClose, iArrayIndex, 3);
+						}
+						else if (GetArraySize(hAreaArrayAverage))
+						{
+							iArrayIndex = GetRandomInt(0, GetArraySize(hAreaArrayAverage) - 1);
+							iTeleportAreaIndex = GetArrayCell(hAreaArrayAverage, iArrayIndex);
+							flTeleportPos[0] = Float:GetArrayCell(hAreaArrayAverage, iArrayIndex, 1);
+							flTeleportPos[1] = Float:GetArrayCell(hAreaArrayAverage, iArrayIndex, 2);
+							flTeleportPos[2] = Float:GetArrayCell(hAreaArrayAverage, iArrayIndex, 3);
+						}
+						else if (GetArraySize(hAreaArrayFar))
+						{
+							iArrayIndex = GetRandomInt(0, GetArraySize(hAreaArrayFar) - 1);
+							iTeleportAreaIndex = GetArrayCell(hAreaArrayFar, iArrayIndex);
+							flTeleportPos[0] = Float:GetArrayCell(hAreaArrayFar, iArrayIndex, 1);
+							flTeleportPos[1] = Float:GetArrayCell(hAreaArrayFar, iArrayIndex, 2);
+							flTeleportPos[2] = Float:GetArrayCell(hAreaArrayFar, iArrayIndex, 3);
+						}
+						
+						CloseHandle(hAreaArrayClose);
+						CloseHandle(hAreaArrayAverage);
+						CloseHandle(hAreaArrayFar);
+					}
+					else
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: failed because target is not on nav mesh!", iBossIndex);
+#endif
+					}
+				}
+				else
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: failed because of lack of nav mesh!", iBossIndex);
+#endif
+				}
+				
+				if (iTeleportAreaIndex == -1)
+				{
+					// We don't have any good areas. Remove myself for now.
+					if (SlenderCanRemove(iBossIndex)) RemoveSlender(iBossIndex);
+				}
+				else
+				{
+					SpawnSlender(iBossIndex, flTeleportPos);
+					
+					if (NPCGetFlags(iBossIndex) & SFF_HASJUMPSCARE)
+					{
+						new bool:bDidJumpScare = false;
+						
+						for (new i = 1; i <= MaxClients; i++)
+						{
+							if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i)) continue;
+							
+							if (PlayerCanSeeSlender(i, iBossIndex, false))
+							{
+								if ((NPCGetDistanceFromEntity(iBossIndex, i) <= GetProfileFloat(sProfile, "jumpscare_distance") &&
+									GetGameTime() >= g_flSlenderNextJumpScare[iBossIndex]) ||
+									PlayerCanSeeSlender(i, iBossIndex))
+								{
+									bDidJumpScare = true;
+								
+									new Float:flJumpScareDuration = GetProfileFloat(sProfile, "jumpscare_duration");
+									ClientDoJumpScare(i, iBossIndex, flJumpScareDuration);
+								}
+							}
+						}
+						
+						if (bDidJumpScare)
+						{
+							g_flSlenderNextJumpScare[iBossIndex] = GetGameTime() + GetProfileFloat(sProfile, "jumpscare_cooldown");
+						}
+					}
+				}
+			}
+		}
+		else
+		{
+#if defined DEBUG
+			SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: failed because of teleport time (curtime: %f, teletime: %f)", iBossIndex, GetGameTime(), g_flSlenderNextTeleportTime[iBossIndex]);
+#endif
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+/*
+// Deprecated.
+
+// This is just to calculate the new place, not do time checks.
+// Distance will be determined by the progression of the game and the
+// manually set values determined by flMinSearchDist and flMaxSearchDist,
+// which are float values that are (or should be) defined in the boss's
+// config file.
+
+// The place chosen should be out of (possible) sight of the players,
+// but should be within the AAS radius, the center being flActiveAreaCenterPos.
+// The game will try to find a place that is of flMinSearchDist first, but
+// if it can't, then it will try to find places that are a bit farther.
+
+// If the whole function fails, no place is given and the boss will not
+// be able to spawn.
+
+bool:SlenderChaseBossCalculateNewPlace(iBossIndex, const Float:flActiveAreaCenterPos[3], Float:flMinSearchDist, Float:flMaxSearchDist, Function:iFunctor, Float:flBuffer[3])
+{
+	new Handle:hAreas = NavMesh_GetAreas();
+	if (hAreas == INVALID_HANDLE) return false;
+	
+	new iBestAreaIndex = -1;
+	new Float:flBestAreaDist = -1.0;
+	
+	decl Float:flAreaCenterPos[3];
+	for (new i = 0, iSize = GetArraySize(hAreas); i < iSize; i++)
+	{
+		NavMeshArea_GetCenter(i, flAreaCenterPos);
+		
+		new Float:flDist = GetVectorDistance(flActiveAreaCenterPos, flAreaCenterPos);
+		if (flDist < flMinSearchDist || flDist > flMaxSearchDist) continue;
+		
+		if (IsPointVisibleToAPlayer(flAreaCenterPos, false, false)) continue;
+		
+		decl Float:flTestPos[3];
+		for (new i2 = 0; i2 < 3; i2++) flTestPos[i2] = flAreaCenterPos[i2] + g_flSlenderEyePosOffset[iBossIndex][i2];
+		
+		if (IsPointVisibleToAPlayer(flTestPos, false, false)) continue;
+		
+		if (iFunctor != INVALID_FUNCTION)
+		{
+			new bool:bResult = true;
+			
+			Call_StartFunction(INVALID_HANDLE, iFunctor);
+			Call_PushCell(iBossIndex);
+			Call_PushArray(flActiveAreaCenterPos, 3);
+			Call_PushArray(flAreaCenterPos, 3);
+			Call_PushFloat(flMinSearchDist);
+			Call_PushFloat(flMaxSearchDist);
+			Call_PushCell(bResult);
+			Call_Finish(bResult);
+			
+			if (!bResult) continue;
+		}
+		
+		if (flBestAreaDist < 0.0 || flDist < flBestAreaDist)
+		{
+			iBestAreaIndex = i;
+			flBestAreaDist = flDist;
+		}
+	}
+	
+	if (iBestAreaIndex == -1) return false;
+	
+	NavMeshArea_GetCenter(iBestAreaIndex, flBuffer);
+	return true;
+}
+*/
+
+bool:SlenderCalculateNewPlace(iBossIndex, Float:buffer[3], bool:bIgnoreCopies=false, bool:bProxy=false, iProxyPlayer=-1, &iBestPlayer=-1)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+
+	new Float:flPercent = 0.0;
+	if (g_iPageMax > 0)
+	{
+		flPercent = (float(g_iPageCount) / float(g_iPageMax)) * g_flRoundDifficultyModifier * NPCGetAnger(iBossIndex);
+	}
+	
+#if defined DEBUG
+	new iArraySize, iArraySize2;
+#endif
+	
+	if (!IsValidClient(iBestPlayer))
+	{
+		// 	Pick a player to appear to.
+		new Handle:hArray = CreateArray();
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || 
+				!IsPlayerAlive(i) || 
+				IsClientInDeathCam(i) || 
+				g_bPlayerEliminated[i] || 
+				g_bPlayerEscaped[i]) continue;
+			
+			if (NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]) != -1 && !bIgnoreCopies)
+			{
+				new bool:bwub = false;
+			
+				// No? Then check if players around him are targeted by a boss already (not me).
+				for (new iBossPlayer = 1; iBossPlayer <= MaxClients; iBossPlayer++)
+				{
+					if (i == iBossPlayer) continue;
+				
+					if (!IsClientInGame(iBossPlayer) || 
+						!IsPlayerAlive(iBossPlayer) || 
+						IsClientInDeathCam(iBossPlayer) || 
+						g_bPlayerEliminated[iBossPlayer] || 
+						g_bPlayerEscaped[iBossPlayer]) continue;
+					
+					// Get the boss that's targeting this player, if any.
+					for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
+					{
+						if (iBossIndex == iBoss || NPCGetUniqueID(iBoss) == -1) continue;
+						
+						if (EntRefToEntIndex(g_iSlenderTarget[iBoss]) == iBossPlayer)
+						{
+							// Are we near this player?
+							if (EntityDistanceFromEntity(iBossPlayer, i) < SF2_BOSS_COPY_SPAWN_MIN_DISTANCE)
+							{
+								bwub = true;
+								break;
+							}
+						}
+					}
+				}
+				
+				if (bwub) continue;
+			}
+			
+			PushArrayCell(hArray, i);
+		}
+		
+#if defined DEBUG
+		iArraySize = GetArraySize(hArray);
+		iArraySize2 = iArraySize;
+#endif
+		
+		if (GetArraySize(hArray))
+		{
+			if (g_iSlenderCopyMaster[iBossIndex] == -1 ||
+				GetProfileNum(sProfile, "copy_calculatepagecount", 0))
+			{
+				new tempBestPageCount = -1;
+				
+				new Handle:hTempArray = CloneArray(hArray);
+				for (new i = 0; i < GetArraySize(hTempArray); i++)
+				{
+					new iClient = GetArrayCell(hTempArray, i);
+					if (g_iPlayerPageCount[iClient] > tempBestPageCount)
+					{
+						tempBestPageCount = g_iPlayerPageCount[iClient];
+					}
+				}
+				
+				for (new i = 0; i < GetArraySize(hTempArray); i++)
+				{
+					new iClient = GetArrayCell(hTempArray, i);
+					if ((float(g_iPlayerPageCount[iClient]) / float(tempBestPageCount)) < SF2_BOSS_PAGE_CALCULATION)
+					{
+						new index = FindValueInArray(hArray, iClient);
+						if (index != -1) RemoveFromArray(hArray, index);
+					}
+				}
+				
+				CloseHandle(hTempArray);
+			}
+			
+#if defined DEBUG
+			iArraySize2 = GetArraySize(hArray);
+#endif
+		}
+		
+		if (GetArraySize(hArray))
+		{
+			iBestPlayer = GetArrayCell(hArray, GetRandomInt(0, GetArraySize(hArray) - 1));
+		}
+	
+		CloseHandle(hArray);
+	}
+	
+#if defined DEBUG
+	if (GetConVarBool(g_cvDebugBosses)) PrintToChatAll("SlenderCalculateNewPlace(%d): array size 1 = %d, array size 2 = %d", iBossIndex, iArraySize, iArraySize2);
+#endif
+	
+	if (iBestPlayer <= 0) 
+	{
+#if defined DEBUG
+		if (GetConVarBool(g_cvDebugBosses)) PrintToChatAll("SlenderCalculateNewPlace(%d) failed: no ibestPlayer!", iBossIndex);
+#endif
+		return false;
+	}
+	
+	//	Determine the distance we can appear from the player.
+	new Float:flPercentFar = 0.75 * (1.0 - flPercent);
+	new Float:flPercentAverage = 0.6 * (1.0 - flPercent);
+	//new Float:flPercentClose = 1.0 - flPercentFar - flPercentAverage;
+	
+	new Float:flUpperBoundFar = flPercentFar;
+	new Float:flUpperBoundAverage = flPercentFar + flPercentAverage;
+	//new Float:flUpperBoundClose = 1.0;
+	
+	new iRange = 1;
+	new Float:flChance = GetRandomFloat(0.0, 1.0);
+	new Float:flMaxRangeN = GetProfileFloat(sProfile, "teleport_range_max");
+	new Float:flMinRangeN = GetProfileFloat(sProfile, "teleport_range_min");
+	
+	new bool:bVisiblePls = false;
+	new bool:bBeCreepy = false;
+	
+	if (!bProxy)
+	{
+		// Are we gonna teleport in front of a player this time?
+		if (GetProfileNum(sProfile, "teleport_ignorevis_enable"))
+		{
+			if (GetRandomFloat(0.0, 1.0) < GetProfileFloat(sProfile, "teleport_ignorevis_chance") * NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier)
+			{
+				bVisiblePls = true;
+			}
+			
+			if (GetRandomFloat(0.0, 1.0) < GetProfileFloat(sProfile, "teleport_creepy_chance", 0.33))
+			{
+				bBeCreepy = true;
+			}
+		}
+	}
+	
+	new Float:flMaxRange = flMaxRangeN;
+	new Float:flMinRange = flMinRangeN;
+	
+	if (bVisiblePls)
+	{
+		flMaxRange = GetProfileFloat(sProfile, "teleport_ignorevis_range_max", flMaxRangeN);
+		flMinRange = GetProfileFloat(sProfile, "teleport_ignorevis_range_min", flMinRangeN);
+	}
+	
+	// Get distances.
+	new Float:flDistanceFar = GetRandomFloat(flMaxRange * 0.75, flMaxRange);
+	if (flDistanceFar < flMinRange) flDistanceFar = flMinRange;
+	new Float:flDistanceAverage = GetRandomFloat(flMaxRange * 0.33, flMaxRange * 0.75);
+	if (flDistanceAverage < flMinRange) flDistanceAverage = flMinRange;
+	new Float:flDistanceClose = GetRandomFloat(0.0, flMaxRange * 0.33);
+	if (flDistanceClose < flMinRange) flDistanceClose = flMinRange;
+	
+	if (flChance >= 0.0 && flChance < flUpperBoundFar) iRange = 1;
+	else if (flChance >= flUpperBoundFar && flChance < flUpperBoundAverage) iRange = 2;
+	else if (flChance >= flUpperBoundAverage) iRange = 3;
+	
+	// 	Get a circle of positions around the player that we can appear in.
+	
+	// Create arrays first.
+	new Handle:hArrayFar = CreateArray(3);
+	new Handle:hArrayAverage = CreateArray(3);
+	new Handle:hArrayClose = CreateArray(3);
+	
+	// Set up our distances array.
+	decl Float:flDistances[3];
+	flDistances[0] = flDistanceFar;
+	flDistances[1] = flDistanceAverage;
+	flDistances[2] = flDistanceClose;
+	
+	decl Float:hisEyePos[3], Float:hisEyeAng[3], Float:tempPos[3], Float:tempDir[3], Float:flBuffer[3], Float:flBuffer2[3], Float:flBuffer3[3];
+	GetClientEyePosition(iBestPlayer, hisEyePos);
+	GetClientEyeAngles(iBestPlayer, hisEyeAng);
+	
+	decl Handle:hTrace, index, Float:flHitNormal[3];
+	decl Handle:hArray;
+	
+	decl Float:flTargetMins[3], Float:flTargetMaxs[3];
+	if (!bProxy)
+	{
+		for (new i = 0; i < 3; i++)
+		{
+			flTargetMins[i] = g_flSlenderDetectMins[iBossIndex][i];
+			flTargetMaxs[i] = g_flSlenderDetectMaxs[iBossIndex][i];
+		}
+	}
+	else
+	{
+		GetEntPropVector(iProxyPlayer, Prop_Send, "m_vecMins", flTargetMins);
+		GetEntPropVector(iProxyPlayer, Prop_Send, "m_vecMaxs", flTargetMaxs);
+	}
+	
+	for (new i = 0; i < iRange; i++)
+	{
+		for (new Float:addAng = 0.0; addAng < 360.0; addAng += 7.5)
+		{
+			tempDir[0] = 0.0;
+			tempDir[1] = hisEyeAng[1] + addAng;
+			tempDir[2] = 0.0;
+			
+			GetAngleVectors(tempDir, tempDir, NULL_VECTOR, NULL_VECTOR);
+			NormalizeVector(tempDir, tempDir);
+			ScaleVector(tempDir, flDistances[i]);
+			AddVectors(tempDir, hisEyePos, tempPos);
+			
+			// Drop to the ground if we're above ground using a TraceHull so IsSpaceOccupiedNPC can return true on something.
+			hTrace = TR_TraceRayFilterEx(tempPos, Float:{ 90.0, 0.0, 0.0 }, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitCharactersOrEntity, iBestPlayer);
+			TR_GetEndPosition(flBuffer, hTrace);
+			CloseHandle(hTrace);
+			
+			flBuffer2[0] = flTargetMins[0];
+			flBuffer2[1] = flTargetMins[1];
+			flBuffer2[2] = -flTargetMaxs[2];
+			flBuffer3[0] = flTargetMaxs[0];
+			flBuffer3[1] = flTargetMaxs[1];
+			flBuffer3[2] = -flTargetMins[0];
+			
+			if (GetVectorDistance(tempPos, flBuffer) >= 300.0) continue;
+			
+			// Drop dowwwwwn.
+			hTrace = TR_TraceHullFilterEx(tempPos, flBuffer, flBuffer2, flBuffer3, MASK_NPCSOLID, TraceRayDontHitCharactersOrEntity, iBestPlayer);
+			TR_GetEndPosition(tempPos, hTrace);
+			TR_GetPlaneNormal(hTrace, flHitNormal);
+			CloseHandle(hTrace);
+			
+			GetVectorAngles(flHitNormal, flHitNormal);
+			for (new i2 = 0; i2 < 3; i2++) flHitNormal[i2] = AngleNormalize(flHitNormal[i2]);
+			
+			tempPos[2] -= g_flSlenderDetectMaxs[iBossIndex][2];
+			
+			if (TR_PointOutsideWorld(tempPos)
+				|| (IsSpaceOccupiedNPC(tempPos, flTargetMins, flTargetMaxs, NPCGetEntIndex(iBossIndex)))
+				|| (bProxy && IsSpaceOccupiedPlayer(tempPos, flTargetMins, flTargetMaxs, iProxyPlayer))
+				|| (flHitNormal[0] >= 0.0 && flHitNormal[0] < 45.0)
+				|| (flHitNormal[0] < 0.0 && flHitNormal[0] > -45.0))
+			{
+				continue;
+			}
+			
+			// Check if this position isn't too close to anyone else.
+			new bool:bTooClose = false;
+			
+			for (new i2 = 1; i2 <= MaxClients; i2++)
+			{
+				if (!IsClientInGame(i2) || !IsPlayerAlive(i2) || g_bPlayerEliminated[i2] || IsClientInGhostMode(i2)) continue;
+				GetClientAbsOrigin(i2, flBuffer);
+				if (GetVectorDistance(flBuffer, tempPos) < flMinRange)
+				{
+					bTooClose = true;
+					break;
+				}
+			}
+			
+			// Check if this position is too close to a boss.
+			if (!bTooClose)
+			{
+				decl iSlender;
+				for (new i2 = 0; i2 < MAX_BOSSES; i2++)
+				{
+					if (i2 == iBossIndex) continue;
+					if (NPCGetUniqueID(i2) == -1) continue;
+					
+					// If I'm a main boss, only check the distance between my copies and me.
+					if (g_iSlenderCopyMaster[iBossIndex] == -1)
+					{
+						if (g_iSlenderCopyMaster[i2] != iBossIndex) continue;
+					}
+					// If I'm a copy, just check with my other copy friends and my main boss.
+					else
+					{
+						new iMyMaster = g_iSlenderCopyMaster[iBossIndex];
+						if (g_iSlenderCopyMaster[i2] != iMyMaster || i2 != iMyMaster) continue;
+					}
+					
+					iSlender = NPCGetEntIndex(i2);
+					if (!iSlender || iSlender == INVALID_ENT_REFERENCE) continue;
+					
+					SlenderGetAbsOrigin(i2, flBuffer);
+					if (GetVectorDistance(flBuffer, tempPos) < GetProfileFloat(sProfile, "teleport_dist_from_other_copies", 800.0))
+					{
+						bTooClose = true;
+						break;
+					}
+				}
+			}
+			
+			if (bTooClose) continue;
+			
+			// Check from top to bottom of me.
+			
+			new bool:bCheckBlink = bool:GetProfileNum(sProfile, "teleport_use_blink");
+			
+			// Check if my copy master or my fellow copies could see this position.
+			new bool:bDontAddPosition = false;
+			new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]);
+			
+			decl Float:flCopyCheckPositions[6];
+			for (new i2 = 0; i2 < 3; i2++) flCopyCheckPositions[i2] = tempPos[i2];
+			for (new i2 = 3; i2 < 6; i2++) flCopyCheckPositions[i2] = tempPos[i2 - 3] + g_flSlenderEyePosOffset[iBossIndex][i2 - 3];
+			
+			for (new i2 = 0; i2 < 2; i2++)
+			{
+				decl Float:flCopyCheckPos[3];
+				for (new i3 = 0; i3 < 3; i3++) flCopyCheckPos[i3] = flCopyCheckPositions[i3 + (3 * i2)];
+				
+				// Check the conditions first.
+				if (bVisiblePls)
+				{
+					if (!IsPointVisibleToAPlayer(flCopyCheckPos, _, bCheckBlink) &&
+						!IsPointVisibleToPlayer(iBestPlayer, flCopyCheckPos, _, bCheckBlink))
+					{
+						bDontAddPosition = true;
+						break;
+					}
+				}
+				else if (bBeCreepy)
+				{
+					if (!IsPointVisibleToAPlayer(flCopyCheckPos, _, bCheckBlink) &&
+						IsPointVisibleToAPlayer(flCopyCheckPos, false, bCheckBlink) &&
+						IsPointVisibleToPlayer(iBestPlayer, flCopyCheckPos, false, bCheckBlink))
+					{
+						// Do nothing.
+					}
+					else
+					{
+						continue;
+					}
+				}
+				else
+				{
+					if (IsPointVisibleToAPlayer(flCopyCheckPos, _, bCheckBlink))
+					{
+						bDontAddPosition = true;
+						break;
+					}
+				}
+				
+				for (new i3 = 0; i3 < MAX_BOSSES; i3++)
+				{
+					if (i3 == iBossIndex) continue;
+					if (NPCGetUniqueID(i3) == -1) continue;
+					
+					new iBoss = NPCGetEntIndex(i3);
+					if (!iBoss || iBoss == INVALID_ENT_REFERENCE) continue;
+					
+					if (i3 == iCopyMaster || 
+						(iCopyMaster != -1 && NPCGetFromUniqueID(g_iSlenderCopyMaster[i3]) == iCopyMaster))
+					{
+					}
+					else continue;
+					
+					decl Float:flCopyPos[3];
+					SlenderGetEyePosition(i3, flCopyPos);
+					hTrace = TR_TraceRayFilterEx(flCopyPos,
+						flCopyCheckPos,
+						CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST,
+						RayType_EndPoint,
+						TraceRayBossVisibility,
+						iBoss);
+					
+					bDontAddPosition = !TR_DidHit(hTrace);
+					CloseHandle(hTrace);
+					
+					if (!bDontAddPosition)
+					{
+						decl Float:flCopyMins[3], Float:flCopyMaxs[3];
+						GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flCopyPos);
+						GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flCopyMins);
+						GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flCopyMaxs);
+						
+						for (new i4 = 0; i4 < 3; i4++) flCopyPos[i4] += ((flCopyMins[i4] + flCopyMaxs[i4]) / 2.0);
+						
+						hTrace = TR_TraceRayFilterEx(flCopyPos,
+							flCopyCheckPos,
+							CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST,
+							RayType_EndPoint,
+							TraceRayBossVisibility,
+							iBoss);
+						
+						bDontAddPosition = !TR_DidHit(hTrace);
+						CloseHandle(hTrace);
+					}
+					
+					if (bDontAddPosition) break;
+				}
+				
+				if (bDontAddPosition) break;
+			}
+			
+			if (bDontAddPosition) continue;
+			
+			// Insert the vector into our array. Choose which one, first.
+			// We're just using hArray as a variable to store the correct array, not the array itself. All arrays will be closed at the end.
+			if (i == 0) hArray = hArrayFar;
+			else if (i == 1) hArray = hArrayAverage;
+			else if (i == 2) hArray = hArrayClose;
+			
+			index = PushArrayCell(hArray, tempPos[0]);
+			SetArrayCell(hArray, index, tempPos[1], 1);
+			SetArrayCell(hArray, index, tempPos[2], 2);
+		}
+	}
+	
+	new size;
+	if ((size = GetArraySize(hArrayClose)) > 0)
+	{
+		index = GetRandomInt(0, size - 1);
+		buffer[0] = Float:GetArrayCell(hArrayClose, index);
+		buffer[1] = Float:GetArrayCell(hArrayClose, index, 1);
+		buffer[2] = Float:GetArrayCell(hArrayClose, index, 2);
+	}
+	else if ((size = GetArraySize(hArrayAverage)) > 0)
+	{
+		index = GetRandomInt(0, size - 1);
+		buffer[0] = Float:GetArrayCell(hArrayAverage, index);
+		buffer[1] = Float:GetArrayCell(hArrayAverage, index, 1);
+		buffer[2] = Float:GetArrayCell(hArrayAverage, index, 2);
+	}
+	else if ((size = GetArraySize(hArrayFar)) > 0)
+	{
+		index = GetRandomInt(0, size - 1);
+		buffer[0] = Float:GetArrayCell(hArrayFar, index);
+		buffer[1] = Float:GetArrayCell(hArrayFar, index, 1);
+		buffer[2] = Float:GetArrayCell(hArrayFar, index, 2);
+	}
+	else
+	{
+		CloseHandle(hArrayClose);
+		CloseHandle(hArrayAverage);
+		CloseHandle(hArrayFar);
+		
+#if defined DEBUG
+		if (GetConVarBool(g_cvDebugBosses)) PrintToChatAll("SlenderCalculateNewPlace(%d) failed: no locations available", iBossIndex);
+#endif
+		
+		return false;
+	}
+	
+	CloseHandle(hArrayClose);
+	CloseHandle(hArrayAverage);
+	CloseHandle(hArrayFar);
+	return true;
+}
+
+bool:SlenderMarkAsFake(iBossIndex)
+{
+	new iBossFlags = NPCGetFlags(iBossIndex);
+	if (iBossFlags & SFF_MARKEDASFAKE) return false;
+	
+	new slender = NPCGetEntIndex(iBossIndex);
+	new iSlenderModel = EntRefToEntIndex(g_iSlenderModel[iBossIndex]);
+	g_iSlender[iBossIndex] = INVALID_ENT_REFERENCE;
+	g_iSlenderModel[iBossIndex] = INVALID_ENT_REFERENCE;
+	
+	NPCSetFlags(iBossIndex, iBossFlags | SFF_MARKEDASFAKE);
+	
+	g_hSlenderFakeTimer[iBossIndex] = CreateTimer(3.0, Timer_SlenderMarkedAsFake, iBossIndex, TIMER_FLAG_NO_MAPCHANGE);
+	
+	if (slender && slender != INVALID_ENT_REFERENCE)
+	{
+		CreateTimer(2.0, Timer_KillEntity, EntIndexToEntRef(slender), TIMER_FLAG_NO_MAPCHANGE);
+	
+		new iFlags = GetEntProp(slender, Prop_Send, "m_usSolidFlags");
+		if (!(iFlags & 0x0004)) iFlags |= 0x0004; // 	FSOLID_NOT_SOLID
+		if (!(iFlags & 0x0008)) iFlags |= 0x0008; // 	FSOLID_TRIGGER
+		SetEntProp(slender, Prop_Send, "m_usSolidFlags", iFlags);
+	}
+	
+	if (iSlenderModel && iSlenderModel != INVALID_ENT_REFERENCE)
+	{
+		SetVariantFloat(0.0);
+		AcceptEntityInput(iSlenderModel, "SetPlaybackRate");
+		SetEntityRenderFx(iSlenderModel, RENDERFX_FADE_FAST);
+	}
+	
+	return true;
+}
+
+public Action:Timer_SlenderMarkedAsFake(Handle:timer, any:data)
+{
+	if (timer != g_hSlenderFakeTimer[data]) return;
+	
+	NPCRemove(data);
+}
+
+stock SpawnSlenderModel(iBossIndex, const Float:pos[3])
+{
+	if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		LogError("Could not spawn boss model: boss does not exist!");
+		return -1;
+	}
+	
+	new iProfileIndex = NPCGetProfileIndex(iBossIndex);
+	
+	decl String:buffer[PLATFORM_MAX_PATH], String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	GetProfileString(sProfile, "model", buffer, sizeof(buffer));
+	if (!buffer[0])
+	{
+		LogError("Could not spawn boss model: model is invalid!");
+		return -1;
+	}
+	
+	new Float:flModelScale = NPCGetModelScale(iBossIndex);
+	if (flModelScale <= 0.0)
+	{
+		LogError("Could not spawn boss model: model scale is less than or equal to 0.0!");
+		return -1;
+	}
+	
+	new iSlenderModel = CreateEntityByName("prop_dynamic_override");
+	if (iSlenderModel != -1)
+	{
+		SetEntityModel(iSlenderModel, buffer);
+		
+		TeleportEntity(iSlenderModel, pos, NULL_VECTOR, NULL_VECTOR);
+		DispatchSpawn(iSlenderModel);
+		ActivateEntity(iSlenderModel);
+		
+		SetEntProp(iSlenderModel, Prop_Send, "m_nSkin", GetBossProfileSkin(iProfileIndex));
+		SetEntProp(iSlenderModel, Prop_Send, "m_nBody", GetBossProfileBodyGroups(iProfileIndex));
+		
+		GetProfileString(sProfile, "animation_idle", buffer, sizeof(buffer));
+		if (buffer[0])
+		{
+			SetVariantString(buffer);
+			AcceptEntityInput(iSlenderModel, "SetDefaultAnimation");
+			SetVariantString(buffer);
+			AcceptEntityInput(iSlenderModel, "SetAnimation");
+			AcceptEntityInput(iSlenderModel, "DisableCollision");
+		}
+		
+		SetVariantFloat(GetProfileFloat(sProfile, "animation_idle_playbackrate", 1.0));
+		AcceptEntityInput(iSlenderModel, "SetPlaybackRate");
+		
+		SetEntPropFloat(iSlenderModel, Prop_Send, "m_flModelScale", flModelScale);
+		
+		// Create special effects.
+		SetEntityRenderMode(iSlenderModel, RenderMode:GetProfileNum(sProfile, "effect_rendermode", _:RENDER_NORMAL));
+		SetEntityRenderFx(iSlenderModel, RenderFx:GetProfileNum(sProfile, "effect_renderfx", _:RENDERFX_NONE));
+		
+		decl iColor[4];
+		GetProfileColor(sProfile, "effect_rendercolor", iColor[0], iColor[1], iColor[2], iColor[3]);
+		SetEntityRenderColor(iSlenderModel, iColor[0], iColor[1], iColor[2], iColor[3]);
+		
+		KvRewind(g_hConfig);
+		if (KvJumpToKey(g_hConfig, sProfile) && 
+			KvJumpToKey(g_hConfig, "effects") &&
+			KvGotoFirstSubKey(g_hConfig))
+		{
+			do
+			{
+				
+			}
+			while KvGotoNextKey(g_hConfig);
+		}
+	}
+	
+	return iSlenderModel;
+}
+
+stock bool:PlayerCanSeeSlender(client, iBossIndex, bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
+{
+	return IsNPCVisibleToPlayer(iBossIndex, client, bCheckFOV, bCheckBlink, bCheckEliminated);
+}
+
+stock bool:PeopleCanSeeSlender(iBossIndex, bool:bCheckFOV=true, bool:bCheckBlink=false)
+{
+	return IsNPCVisibleToAPlayer(iBossIndex, bCheckFOV, bCheckBlink);
+}
+
+// TODO: bCheckBlink and bCheckEliminated should NOT be function arguments!
+bool:IsNPCVisibleToPlayer(iNPCIndex, client, bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
+{
+	if (!NPCIsValid(iNPCIndex)) return false;
+	
+	new iNPC = NPCGetEntIndex(iNPCIndex);
+	if (iNPC && iNPC != INVALID_ENT_REFERENCE)
+	{
+		decl Float:flEyePos[3];
+		NPCGetEyePosition(iNPCIndex, flEyePos);
+		return IsPointVisibleToPlayer(client, flEyePos, bCheckFOV, bCheckBlink, bCheckEliminated);
+	}
+	
+	return false;
+}
+
+// TODO: bCheckBlink and bCheckEliminated should NOT be function arguments!
+bool:IsNPCVisibleToAPlayer(iNPCIndex, bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
+{
+	for (new client = 1; client <= MaxClients; client++)
+	{
+		if (IsNPCVisibleToPlayer(iNPCIndex, client, bCheckFOV, bCheckBlink, bCheckEliminated))
+		{
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+Float:NPCGetDistanceFromPoint(iNPCIndex, const Float:flPoint[3], bool:bSquared=false)
+{
+	new iNPC = NPCGetEntIndex(iNPCIndex);
+	if (iNPC && iNPC != INVALID_ENT_REFERENCE)
+	{
+		decl Float:flPos[3];
+		SlenderGetAbsOrigin(iNPCIndex, flPos);
+		
+		return GetVectorDistance(flPos, flPoint, bSquared);
+	}
+	
+	return -1.0;
+}
+
+Float:NPCGetDistanceFromEntity(iNPCIndex, ent, bool:bSquared=false)
+{
+	if (!IsValidEntity(ent)) return -1.0;
+	
+	decl Float:flPos[3];
+	GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
+	
+	return NPCGetDistanceFromPoint(iNPCIndex, flPos, bSquared);
+}
+
+public bool:TraceRayBossVisibility(entity, mask, any:data)
+{
+	if (entity == data || IsValidClient(entity)) return false;
+	
+	new iBossIndex = NPCGetFromEntIndex(entity);
+	if (iBossIndex != -1) return false;
+	
+	if (IsValidEdict(entity))
+	{
+		decl String:sClass[64];
+		GetEntityNetClass(entity, sClass, sizeof(sClass));
+		
+		if (StrEqual(sClass, "CTFAmmoPack")) return false;
+	}
+	
+	return true;
+}
+
+public bool:TraceRayDontHitCharacters(entity, mask, any:data)
+{
+	if (entity > 0 && entity <= MaxClients) return false;
+	
+	new iBossIndex = NPCGetFromEntIndex(entity);
+	if (iBossIndex != -1) return false;
+	
+	return true;
+}
+
+public bool:TraceRayDontHitCharactersOrEntity(entity, mask, any:data)
+{
+	if (entity == data) return false;
+
+	if (entity > 0 && entity <= MaxClients) return false;
+	
+	new iBossIndex = NPCGetFromEntIndex(entity);
+	if (iBossIndex != -1) return false;
+	
+	return true;
+}
+
+#include "rytp_horror/npc/npc_chaser.sp"
diff --git a/addons/sourcemod/scripting/rytp_horror/npc/npc_chaser.sp b/addons/sourcemod/scripting/rytp_horror/npc/npc_chaser.sp
index e4b9b49..b1f5c67 100644
--- a/addons/sourcemod/scripting/rytp_horror/npc/npc_chaser.sp
+++ b/addons/sourcemod/scripting/rytp_horror/npc/npc_chaser.sp
@@ -1,2515 +1,2515 @@
-#if defined _sf2_npc_chaser_included
- #endinput
-#endif
-#define _sf2_npc_chaser_included
-
-static Float:g_flNPCStepSize[MAX_BOSSES];
-
-static Float:g_flNPCWalkSpeed[MAX_BOSSES][Difficulty_Max];
-static Float:g_flNPCAirSpeed[MAX_BOSSES][Difficulty_Max];
-
-static Float:g_flNPCMaxWalkSpeed[MAX_BOSSES][Difficulty_Max];
-static Float:g_flNPCMaxAirSpeed[MAX_BOSSES][Difficulty_Max];
-
-static Float:g_flNPCWakeRadius[MAX_BOSSES];
-
-static bool:g_bNPCStunEnabled[MAX_BOSSES];
-static Float:g_flNPCStunDuration[MAX_BOSSES];
-static bool:g_bNPCStunFlashlightEnabled[MAX_BOSSES];
-static Float:g_flNPCStunFlashlightDamage[MAX_BOSSES];
-static Float:g_flNPCStunInitialHealth[MAX_BOSSES];
-static Float:g_flNPCStunHealth[MAX_BOSSES];
-
-static g_iNPCState[MAX_BOSSES] = { -1, ... };
-static g_iNPCMovementActivity[MAX_BOSSES] = { -1, ... };
-
-enum SF2NPCChaser_BaseAttackStructure
-{
-	SF2NPCChaser_BaseAttackType,
-	Float:SF2NPCChaser_BaseAttackDamage,
-	Float:SF2NPCChaser_BaseAttackDamageVsProps,
-	Float:SF2NPCChaser_BaseAttackDamageForce,
-	SF2NPCChaser_BaseAttackDamageType,
-	Float:SF2NPCChaser_BaseAttackDamageDelay,
-	Float:SF2NPCChaser_BaseAttackRange,
-	Float:SF2NPCChaser_BaseAttackDuration,
-	Float:SF2NPCChaser_BaseAttackSpread,
-	Float:SF2NPCChaser_BaseAttackBeginRange,
-	Float:SF2NPCChaser_BaseAttackBeginFOV,
-	Float:SF2NPCChaser_BaseAttackCooldown,
-	Float:SF2NPCChaser_BaseAttackNextAttackTime
-};
-
-static g_NPCBaseAttacks[MAX_BOSSES][SF2_CHASER_BOSS_MAX_ATTACKS][SF2NPCChaser_BaseAttackStructure];
-
-#if defined METHODMAPS
-
-const SF2NPC_Chaser SF2_INVALID_NPC_CHASER = SF2NPC_Chaser:-1;
-
-
-methodmap SF2NPC_Chaser < SF2NPC_BaseNPC
-{
-	property float WakeRadius
-	{
-		public get() { return NPCChaserGetWakeRadius(this.Index); }
-	}
-	
-	property float StepSize
-	{
-		public get() { return NPCChaserGetStepSize(this.Index); }
-	}
-	
-	property bool StunEnabled
-	{
-		public get() { return NPCChaserIsStunEnabled(this.Index); }
-	}
-	
-	property bool StunByFlashlightEnabled
-	{
-		public get() { return NPCChaserIsStunByFlashlightEnabled(this.Index); }
-	}
-	
-	property float StunFlashlightDamage
-	{
-		public get() { return NPCChaserGetStunFlashlightDamage(this.Index); }
-	}
-	
-	property float StunDuration
-	{
-		public get() { return NPCChaserGetStunDuration(this.Index); }
-	}
-	
-	property float StunHealth
-	{
-		public get() { return NPCChaserGetStunHealth(this.Index); }
-		public set(float amount) { NPCChaserSetStunHealth(this.Index, amount); }
-	}
-	
-	property float StunInitialHealth
-	{
-		public get() { return NPCChaserGetStunInitialHealth(this.Index); }
-	}
-	
-	property int State
-	{
-		public get() { return NPCChaserGetState(this.Index); }
-		public set(int state) { NPCChaserSetState(this.Index, state); }
-	}
-	
-	property int MovementActivity
-	{
-		public get() { return NPCChaserGetMovementActivity(this.Index); }
-		public set(int movementActivity) { NPCChaserSetMovementActivity(this.Index, movementActivity); }
-	}
-	
-	public SF2NPC_Chaser(int index)
-	{
-		return SF2NPC_Chaser:SF2NPC_BaseNPC(index);
-	}
-	
-	public float GetWalkSpeed(int difficulty)
-	{
-		return NPCChaserGetWalkSpeed(this.Index, difficulty);
-	}
-	
-	public void SetWalkSpeed(int difficulty, float amount)
-	{
-		NPCChaserSetWalkSpeed(this.Index, difficulty, amount);
-	}
-	
-	public float GetAirSpeed(int difficulty)
-	{
-		return NPCChaserGetAirSpeed(this.Index, difficulty);
-	}
-	
-	public void SetAirSpeed(int difficulty, float amount)
-	{
-		NPCChaserSetAirSpeed(this.Index, difficulty, amount);
-	}
-	
-	public float GetMaxWalkSpeed(int difficulty)
-	{
-		return NPCChaserGetMaxWalkSpeed(this.Index, difficulty);
-	}
-	
-	public void SetMaxWalkSpeed(int difficulty, float amount)
-	{
-		NPCChaserSetMaxWalkSpeed(this.Index, difficulty, amount);
-	}
-	
-	public float GetMaxAirSpeed(int difficulty)
-	{
-		return NPCChaserGetMaxAirSpeed(this.Index, difficulty);
-	}
-	
-	public void SetMaxAirSpeed(int difficulty, float amount)
-	{
-		NPCChaserSetMaxAirSpeed(this.Index, difficulty, amount);
-	}
-	
-	public void AddStunHealth(float amount)
-	{
-		NPCChaserAddStunHealth(this.Index, amount);
-	}
-}
-
-#endif
-
-public NPCChaserInitialize()
-{
-	for (new iNPCIndex = 0; iNPCIndex < MAX_BOSSES; iNPCIndex++)
-	{
-		NPCChaserResetValues(iNPCIndex);
-	}
-}
-
-stock Float:NPCChaserGetWalkSpeed(iNPCIndex, iDifficulty)
-{
-	return g_flNPCWalkSpeed[iNPCIndex][iDifficulty];
-}
-
-stock NPCChaserSetWalkSpeed(iNPCIndex, iDifficulty, Float:flAmount)
-{
-	g_flNPCWalkSpeed[iNPCIndex][iDifficulty] = flAmount;
-}
-
-stock Float:NPCChaserGetAirSpeed(iNPCIndex, iDifficulty)
-{
-	return g_flNPCAirSpeed[iNPCIndex][iDifficulty];
-}
-
-stock NPCChaserSetAirSpeed(iNPCIndex, iDifficulty, Float:flAmount)
-{
-	g_flNPCAirSpeed[iNPCIndex][iDifficulty] = flAmount;
-}
-
-stock Float:NPCChaserGetMaxWalkSpeed(iNPCIndex, iDifficulty)
-{
-	return g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty];
-}
-
-stock NPCChaserSetMaxWalkSpeed(iNPCIndex, iDifficulty, Float:flAmount)
-{
-	g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty] = flAmount;
-}
-
-stock Float:NPCChaserGetMaxAirSpeed(iNPCIndex, iDifficulty)
-{
-	return g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty];
-}
-
-stock NPCChaserSetMaxAirSpeed(iNPCIndex, iDifficulty, Float:flAmount)
-{
-	g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty] = flAmount;
-}
-
-stock Float:NPCChaserGetWakeRadius(iNPCIndex)
-{
-	return g_flNPCWakeRadius[iNPCIndex];
-}
-
-stock Float:NPCChaserGetStepSize(iNPCIndex)
-{
-	return g_flNPCStepSize[iNPCIndex];
-}
-
-stock NPCChaserGetAttackType(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackType];
-}
-
-stock Float:NPCChaserGetAttackDamage(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamage];
-}
-
-stock Float:NPCChaserGetAttackDamageVsProps(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageVsProps];
-}
-
-stock Float:NPCChaserGetAttackDamageForce(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageForce];
-}
-
-stock NPCChaserGetAttackDamageType(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageType];
-}
-
-stock Float:NPCChaserGetAttackDamageDelay(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageDelay];
-}
-
-stock Float:NPCChaserGetAttackRange(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackRange];
-}
-
-stock Float:NPCChaserGetAttackDuration(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDuration];
-}
-
-stock Float:NPCChaserGetAttackSpread(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackSpread];
-}
-
-stock Float:NPCChaserGetAttackBeginRange(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackBeginRange];
-}
-
-stock Float:NPCChaserGetAttackBeginFOV(iNPCIndex, iAttackIndex)
-{
-	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackBeginFOV];
-}
-
-stock bool:NPCChaserIsStunEnabled(iNPCIndex)
-{
-	return g_bNPCStunEnabled[iNPCIndex];
-}
-
-stock bool:NPCChaserIsStunByFlashlightEnabled(iNPCIndex)
-{
-	return g_bNPCStunFlashlightEnabled[iNPCIndex];
-}
-
-stock Float:NPCChaserGetStunFlashlightDamage(iNPCIndex)
-{
-	return g_flNPCStunFlashlightDamage[iNPCIndex];
-}
-
-stock Float:NPCChaserGetStunDuration(iNPCIndex)
-{
-	return g_flNPCStunDuration[iNPCIndex];
-}
-
-stock Float:NPCChaserGetStunHealth(iNPCIndex)
-{
-	return g_flNPCStunHealth[iNPCIndex];
-}
-
-stock NPCChaserSetStunHealth(iNPCIndex, Float:flAmount)
-{
-	g_flNPCStunHealth[iNPCIndex] = flAmount;
-}
-
-stock NPCChaserAddStunHealth(iNPCIndex, Float:flAmount)
-{
-	NPCChaserSetStunHealth(iNPCIndex, NPCChaserGetStunHealth(iNPCIndex) + flAmount);
-}
-
-stock Float:NPCChaserGetStunInitialHealth(iNPCIndex)
-{
-	return g_flNPCStunInitialHealth[iNPCIndex];
-}
-
-stock NPCChaserGetState(iNPCIndex)
-{
-	return g_iNPCState[iNPCIndex];
-}
-
-stock NPCChaserSetState(iNPCIndex, iState)
-{
-	g_iNPCState[iNPCIndex] = iState;
-}
-
-stock NPCChaserGetMovementActivity(iNPCIndex)
-{
-	return g_iNPCMovementActivity[iNPCIndex];
-}
-
-stock NPCChaserSetMovementActivity(iNPCIndex, iMovementActivity)
-{
-	g_iNPCMovementActivity[iNPCIndex] = iMovementActivity;
-}
-
-stock NPCChaserOnSelectProfile(iNPCIndex)
-{
-	new iUniqueProfileIndex = NPCGetUniqueProfileIndex(iNPCIndex);
-
-	g_flNPCWakeRadius[iNPCIndex] = GetChaserProfileWakeRadius(iUniqueProfileIndex);
-	g_flNPCStepSize[iNPCIndex] = GetChaserProfileStepSize(iUniqueProfileIndex);
-	
-	for (new iDifficulty = 0; iDifficulty < Difficulty_Max; iDifficulty++)
-	{
-		g_flNPCWalkSpeed[iNPCIndex][iDifficulty] = GetChaserProfileWalkSpeed(iUniqueProfileIndex, iDifficulty);
-		g_flNPCAirSpeed[iNPCIndex][iDifficulty] = GetChaserProfileAirSpeed(iUniqueProfileIndex, iDifficulty);
-		
-		g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty] = GetChaserProfileMaxWalkSpeed(iUniqueProfileIndex, iDifficulty);
-		g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty] = GetChaserProfileMaxAirSpeed(iUniqueProfileIndex, iDifficulty);
-	}
-	
-	// Get attack data.
-	for (new i = 0; i < GetChaserProfileAttackCount(iUniqueProfileIndex); i++)
-	{
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackType] = GetChaserProfileAttackType(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamage] = GetChaserProfileAttackDamage(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageVsProps] = GetChaserProfileAttackDamageVsProps(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageForce] = GetChaserProfileAttackDamageForce(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageType] = GetChaserProfileAttackDamageType(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageDelay] = GetChaserProfileAttackDamageDelay(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackRange] = GetChaserProfileAttackRange(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDuration] = GetChaserProfileAttackDuration(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackSpread] = GetChaserProfileAttackSpread(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginRange] = GetChaserProfileAttackBeginRange(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginFOV] = GetChaserProfileAttackBeginFOV(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackCooldown] = GetChaserProfileAttackCooldown(iUniqueProfileIndex, i);
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackNextAttackTime] = -1.0;
-	}
-	
-	// Get stun data.
-	g_bNPCStunEnabled[iNPCIndex] = GetChaserProfileStunState(iUniqueProfileIndex);
-	g_flNPCStunDuration[iNPCIndex] = GetChaserProfileStunDuration(iUniqueProfileIndex);
-	g_bNPCStunFlashlightEnabled[iNPCIndex] = GetChaserProfileStunFlashlightState(iUniqueProfileIndex);
-	g_flNPCStunFlashlightDamage[iNPCIndex] = GetChaserProfileStunFlashlightDamage(iUniqueProfileIndex);
-	g_flNPCStunInitialHealth[iNPCIndex] = GetChaserProfileStunHealth(iUniqueProfileIndex);
-	
-	NPCChaserSetStunHealth(iNPCIndex, NPCChaserGetStunInitialHealth(iNPCIndex));
-}
-
-NPCChaserOnRemoveProfile(iNPCIndex)
-{
-	NPCChaserResetValues(iNPCIndex);
-}
-
-/**
- *	Resets all global variables on a specified NPC. Usually this should be done last upon removing a boss from the game.
- */
-static NPCChaserResetValues(iNPCIndex)
-{
-	g_flNPCWakeRadius[iNPCIndex] = 0.0;
-	g_flNPCStepSize[iNPCIndex] = 0.0;
-	
-	for (new iDifficulty = 0; iDifficulty < Difficulty_Max; iDifficulty++)
-	{
-		g_flNPCWalkSpeed[iNPCIndex][iDifficulty] = 0.0;
-		g_flNPCAirSpeed[iNPCIndex][iDifficulty] = 0.0;
-		
-		g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty] = 0.0;
-		g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty] = 0.0;
-	}
-	
-	// Clear attack data.
-	for (new i = 0; i < SF2_CHASER_BOSS_MAX_ATTACKS; i++)
-	{
-		// Base attack data.
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackType] = SF2BossAttackType_Invalid;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamage] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageVsProps] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageForce] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageType] = 0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageDelay] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackRange] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDuration] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackSpread] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginRange] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginFOV] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackCooldown] = 0.0;
-		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackNextAttackTime] = -1.0;
-	}
-	
-	g_bNPCStunEnabled[iNPCIndex] = false;
-	g_flNPCStunDuration[iNPCIndex] = 0.0;
-	g_bNPCStunFlashlightEnabled[iNPCIndex] = false;
-	g_flNPCStunInitialHealth[iNPCIndex] = 0.0;
-	
-	NPCChaserSetStunHealth(iNPCIndex, 0.0);
-	
-	g_iNPCState[iNPCIndex] = -1;
-	g_iNPCMovementActivity[iNPCIndex] = -1;
-}
-
-//	So this is how the thought process of the bosses should go.
-//	1. Search for enemy; either by sight or by sound.
-//		- Any noticeable sounds should be investigated.
-//		- Too many sounds will put me in alert mode.
-//	2. Alert of an enemy; I saw something or I heard something unusual
-//		- Go to the position where I last heard the sound.
-//		- Keep on searching until I give up. Then drop back to idle mode.
-//	3. Found an enemy! Give chase!
-//		- Keep on chasing until enemy is killed or I give up.
-//			- Keep a path in memory as long as I still have him in my sights.
-//			- If I lose sight or I'm unable to traverse safely, find paths around obstacles and follow memorized path.
-//			- If I reach the end of my path and I still don't see him and I still want to pursue him, keep on going in the direction I'm going.
-
-stock bool:IsTargetValidForSlender(iTarget, bool:bIncludeEliminated=false)
-{
-	if (!iTarget || !IsValidEntity(iTarget)) return false;
-	
-	if (IsValidClient(iTarget))
-	{
-		if (!IsClientInGame(iTarget) || 
-			!IsPlayerAlive(iTarget) || 
-			IsClientInDeathCam(iTarget) || 
-			(!bIncludeEliminated && g_bPlayerEliminated[iTarget]) ||
-			IsClientInGhostMode(iTarget) || 
-			DidClientEscape(iTarget)) return false;
-	}
-	
-	return true;
-}
-
-public Action:Timer_SlenderChaseBossThink(Handle:timer, any:entref)
-{
-	if (!g_bEnabled) return Plugin_Stop;
-
-	new slender = EntRefToEntIndex(entref);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return Plugin_Stop;
-	
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	if (timer != g_hSlenderEntityThink[iBossIndex]) return Plugin_Stop;
-	
-	if (NPCGetFlags(iBossIndex) & SFF_MARKEDASFAKE) return Plugin_Stop;
-	
-	decl Float:flSlenderVelocity[3], Float:flMyPos[3], Float:flMyEyeAng[3];
-	new Float:flBuffer[3];
-	
-	decl String:sSlenderProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sSlenderProfile, sizeof(sSlenderProfile));
-	
-	GetEntPropVector(slender, Prop_Data, "m_vecAbsVelocity", flSlenderVelocity);
-	GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flMyPos);
-	GetEntPropVector(slender, Prop_Data, "m_angAbsRotation", flMyEyeAng);
-	AddVectors(flMyEyeAng, g_flSlenderEyeAngOffset[iBossIndex], flMyEyeAng);
-	for (new i = 0; i < 3; i++) flMyEyeAng[i] = AngleNormalize(flMyEyeAng[i]);
-	
-	new iDifficulty = GetConVarInt(g_cvDifficulty);
-	
-	new Float:flVelocityRatio;
-	new Float:flVelocityRatioWalk;
-	
-	new Float:flOriginalSpeed = NPCGetSpeed(iBossIndex, iDifficulty);
-	new Float:flOriginalWalkSpeed = NPCChaserGetWalkSpeed(iBossIndex, iDifficulty);
-	new Float:flMaxSpeed = NPCGetMaxSpeed(iBossIndex, iDifficulty);
-	new Float:flMaxWalkSpeed = NPCChaserGetMaxWalkSpeed(iBossIndex, iDifficulty);
-	
-	new Float:flSpeed = flOriginalSpeed * NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier;
-	if (flSpeed < flOriginalSpeed) flSpeed = flOriginalSpeed;
-	if (flSpeed > flMaxSpeed) flSpeed = flMaxSpeed;
-	
-	new Float:flWalkSpeed = flOriginalWalkSpeed * NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier;
-	if (flWalkSpeed < flOriginalWalkSpeed) flWalkSpeed = flOriginalWalkSpeed;
-	if (flWalkSpeed > flMaxWalkSpeed) flWalkSpeed = flMaxWalkSpeed;
-	
-	if (PeopleCanSeeSlender(iBossIndex, _, false))
-	{
-		if (NPCHasAttribute(iBossIndex, "reduced speed on look"))
-		{
-			flSpeed *= NPCGetAttributeValue(iBossIndex, "reduced speed on look");
-		}
-		
-		if (NPCHasAttribute(iBossIndex, "reduced walk speed on look"))
-		{
-			flWalkSpeed *= NPCGetAttributeValue(iBossIndex, "reduced walk speed on look");
-		}
-	}
-	
-	g_flSlenderCalculatedWalkSpeed[iBossIndex] = flWalkSpeed;
-	g_flSlenderCalculatedSpeed[iBossIndex] = flSpeed;
-	
-	if (flOriginalSpeed <= 0.0) flVelocityRatio = 0.0;
-	else flVelocityRatio = GetVectorLength(flSlenderVelocity) / flOriginalSpeed;
-	
-	if (flOriginalWalkSpeed <= 0.0) flVelocityRatioWalk = 0.0;
-	else flVelocityRatioWalk = GetVectorLength(flSlenderVelocity) / flOriginalWalkSpeed;
-	
-	new Float:flAttackRange = NPCChaserGetAttackRange(iBossIndex, 0);
-	new Float:flAttackFOV = NPCChaserGetAttackSpread(iBossIndex, 0);
-	new Float:flAttackBeginRange = NPCChaserGetAttackBeginRange(iBossIndex, 0);
-	new Float:flAttackBeginFOV = NPCChaserGetAttackBeginFOV(iBossIndex, 0);
-	
-	
-	new iOldState = g_iSlenderState[iBossIndex];
-	new iOldTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
-	
-	new iBestNewTarget = INVALID_ENT_REFERENCE;
-	new Float:flSearchRange = NPCGetSearchRadius(iBossIndex);
-	new Float:flBestNewTargetDist = flSearchRange;
-	new iState = iOldState;
-	
-	new bool:bPlayerInFOV[MAXPLAYERS + 1];
-	new bool:bPlayerNear[MAXPLAYERS + 1];
-	new Float:flPlayerDists[MAXPLAYERS + 1];
-	new bool:bPlayerVisible[MAXPLAYERS + 1];
-	
-	new bool:bAttackEliminated = bool:(NPCGetFlags(iBossIndex) & SFF_ATTACKWAITERS);
-	new bool:bStunEnabled = NPCChaserIsStunEnabled(iBossIndex);
-	
-	decl Float:flSlenderMins[3], Float:flSlenderMaxs[3];
-	GetEntPropVector(slender, Prop_Send, "m_vecMins", flSlenderMins);
-	GetEntPropVector(slender, Prop_Send, "m_vecMaxs", flSlenderMaxs);
-	
-	decl Float:flTraceMins[3], Float:flTraceMaxs[3];
-	flTraceMins[0] = flSlenderMins[0];
-	flTraceMins[1] = flSlenderMins[1];
-	flTraceMins[2] = 0.0;
-	flTraceMaxs[0] = flSlenderMaxs[0];
-	flTraceMaxs[1] = flSlenderMaxs[1];
-	flTraceMaxs[2] = 0.0;
-	
-	// Gather data about the players around me and get the best new target, in case my old target is invalidated.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsTargetValidForSlender(i, bAttackEliminated)) continue;
-		
-		decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
-		NPCGetEyePosition(iBossIndex, flTraceStartPos);
-		GetClientEyePosition(i, flTraceEndPos);
-		
-		new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
-			flTraceEndPos,
-			flTraceMins,
-			flTraceMaxs,
-			MASK_NPCSOLID,
-			TraceRayBossVisibility,
-			slender);
-		
-		new bool:bIsVisible = !TR_DidHit(hTrace);
-		new iTraceHitEntity = TR_GetEntityIndex(hTrace);
-		CloseHandle(hTrace);
-		
-		if (!bIsVisible && iTraceHitEntity == i) bIsVisible = true;
-		
-		bPlayerVisible[i] = bIsVisible;
-		
-		// Near radius check.
-		if (bIsVisible &&
-			GetVectorDistance(flTraceStartPos, flTraceEndPos) <= NPCChaserGetWakeRadius(iBossIndex))
-		{
-			bPlayerNear[i] = true;
-		}
-		
-		// FOV check.
-		SubtractVectors(flTraceEndPos, flTraceStartPos, flBuffer);
-		GetVectorAngles(flBuffer, flBuffer);
-		
-		if (FloatAbs(AngleDiff(flMyEyeAng[1], flBuffer[1])) <= (NPCGetFOV(iBossIndex) * 0.5))
-		{
-			bPlayerInFOV[i] = true;
-		}
-		
-		new Float:flDist;
-		new Float:flPriorityValue = g_iPageMax > 0 ? (float(g_iPlayerPageCount[i]) / float(g_iPageMax)) : 0.0;
-		
-		if (TF2_GetPlayerClass(i) == TFClass_Medic) flPriorityValue += 0.72;
-		
-		flDist = GetVectorDistance(flTraceStartPos, flTraceEndPos);
-		flPlayerDists[i] = flDist;
-		
-		if ((bPlayerNear[i] && iState != STATE_CHASE && iState != STATE_ALERT) || (bIsVisible && bPlayerInFOV[i]))
-		{
-			decl Float:flTargetPos[3];
-			GetClientAbsOrigin(i, flTargetPos);
-			
-			if (flDist <= flSearchRange)
-			{
-				// Subtract distance to increase priority.
-				flDist -= (flDist * flPriorityValue);
-				
-				if (flDist < flBestNewTargetDist)
-				{
-					iBestNewTarget = i;
-					flBestNewTargetDist = flDist;
-					g_iSlenderInterruptConditions[iBossIndex] |= COND_SAWENEMY;
-				}
-				
-				g_flSlenderLastFoundPlayer[iBossIndex][i] = GetGameTime();
-				g_flSlenderLastFoundPlayerPos[iBossIndex][i][0] = flTargetPos[0];
-				g_flSlenderLastFoundPlayerPos[iBossIndex][i][1] = flTargetPos[1];
-				g_flSlenderLastFoundPlayerPos[iBossIndex][i][2] = flTargetPos[2];
-			}
-		}
-	}
-	
-	new bool:bInFlashlight = false;
-	
-	// Check to see if someone is facing at us with flashlight on. Only if I'm facing them too. BLINDNESS!
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsTargetValidForSlender(i, bAttackEliminated)) continue;
-	
-		if (!IsClientUsingFlashlight(i) || !bPlayerInFOV[i]) continue;
-		
-		decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
-		GetClientEyePosition(i, flTraceStartPos);
-		NPCGetEyePosition(iBossIndex, flTraceEndPos);
-		
-		if (GetVectorDistance(flTraceStartPos, flTraceEndPos) <= SF2_FLASHLIGHT_LENGTH)
-		{
-			decl Float:flEyeAng[3], Float:flRequiredAng[3];
-			GetClientEyeAngles(i, flEyeAng);
-			SubtractVectors(flTraceEndPos, flTraceStartPos, flRequiredAng);
-			GetVectorAngles(flRequiredAng, flRequiredAng);
-			
-			if ((FloatAbs(AngleDiff(flEyeAng[0], flRequiredAng[0])) + FloatAbs(AngleDiff(flEyeAng[1], flRequiredAng[1]))) <= 45.0)
-			{
-				new Handle:hTrace = TR_TraceRayFilterEx(flTraceStartPos,
-					flTraceEndPos,
-					MASK_PLAYERSOLID,
-					RayType_EndPoint,
-					TraceRayBossVisibility,
-					slender);
-					
-				new bool:bDidHit = TR_DidHit(hTrace);
-				CloseHandle(hTrace);
-				
-				if (!bDidHit)
-				{
-					bInFlashlight = true;
-					break;
-				}
-			}
-		}
-	}
-	
-	// Damage us if we're in a flashlight.
-	if (bInFlashlight)
-	{
-		if (bStunEnabled)
-		{
-			if (NPCChaserIsStunByFlashlightEnabled(iBossIndex))
-			{
-				if (NPCChaserGetStunHealth(iBossIndex) > 0)
-				{
-					NPCChaserAddStunHealth(iBossIndex, -NPCChaserGetStunFlashlightDamage(iBossIndex));
-				}
-			}
-		}
-	}
-	
-	// Process the target that we should have.
-	new iTarget = iOldTarget;
-	
-	/*
-	if (IsValidEdict(iBestNewTarget))
-	{
-		iTarget = iBestNewTarget;
-		g_iSlenderTarget[iBossIndex] = EntIndexToEntRef(iBestNewTarget);
-	}
-	*/
-	
-	if (iTarget && iTarget != INVALID_ENT_REFERENCE)
-	{
-		if (!IsTargetValidForSlender(iTarget, bAttackEliminated))
-		{
-			// Clear our target; he's not valid anymore.
-			iOldTarget = iTarget;
-			iTarget = INVALID_ENT_REFERENCE;
-			g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-		}
-	}
-	else
-	{
-		// Clear our target; he's not valid anymore.
-		iOldTarget = iTarget;
-		iTarget = INVALID_ENT_REFERENCE;
-		g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-	}
-	
-	new iInterruptConditions = g_iSlenderInterruptConditions[iBossIndex];
-	new bool:bQueueForNewPath = false;
-	
-	// Process which state we should be in.
-	switch (iState)
-	{
-		case STATE_IDLE, STATE_WANDER:
-		{
-			if (iState == STATE_WANDER)
-			{
-				if (GetArraySize(g_hSlenderPath[iBossIndex]) <= 0)
-				{
-					iState = STATE_IDLE;
-				}
-			}
-			else
-			{
-				if (GetGameTime() >= g_flSlenderNextWanderPos[iBossIndex] && GetRandomFloat(0.0, 1.0) <= 0.25)
-				{
-					iState = STATE_WANDER;
-				}
-			}
-			
-			if (iInterruptConditions & COND_SAWENEMY)
-			{
-				// I saw someone over here. Automatically put me into alert mode.
-				iState = STATE_ALERT;
-			}
-			else if (iInterruptConditions & COND_HEARDSUSPICIOUSSOUND)
-			{
-				// Sound counts:
-				// +1 will be added if it hears a footstep.
-				// +2 will be added if the footstep is someone sprinting.
-				// +5 will be added if the sound is from a player's weapon hitting an object.
-				// +10 will be added if a voice command is heard.
-				//
-				// Sound counts will be reset after the boss hears a sound after a certain amount of time.
-				// The purpose of sound counts is to induce boss focusing on sounds suspicious entities are making.
-				
-				new iCount = 0;
-				if (iInterruptConditions & COND_HEARDFOOTSTEP) iCount += 1;
-				if (iInterruptConditions & COND_HEARDFOOTSTEPLOUD) iCount += 2;
-				if (iInterruptConditions & COND_HEARDWEAPON) iCount += 5;
-				if (iInterruptConditions & COND_HEARDVOICE) iCount += 10;
-				
-				new bool:bDiscardMasterPos = bool:(GetGameTime() >= g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex]);
-				
-				if (GetVectorDistance(g_flSlenderTargetSoundTempPos[iBossIndex], g_flSlenderTargetSoundMasterPos[iBossIndex]) <= GetProfileFloat(sSlenderProfile, "search_sound_pos_dist_tolerance", 512.0) ||
-					bDiscardMasterPos)
-				{
-					if (bDiscardMasterPos) g_iSlenderTargetSoundCount[iBossIndex] = 0;
-					
-					g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_sound_pos_discard_time", 2.0);
-					g_flSlenderTargetSoundMasterPos[iBossIndex][0] = g_flSlenderTargetSoundTempPos[iBossIndex][0];
-					g_flSlenderTargetSoundMasterPos[iBossIndex][1] = g_flSlenderTargetSoundTempPos[iBossIndex][1];
-					g_flSlenderTargetSoundMasterPos[iBossIndex][2] = g_flSlenderTargetSoundTempPos[iBossIndex][2];
-					g_iSlenderTargetSoundCount[iBossIndex] += iCount;
-				}
-				
-				if (g_iSlenderTargetSoundCount[iBossIndex] >= GetProfileNum(sSlenderProfile, "search_sound_count_until_alert", 4))
-				{
-					// Someone's making some noise over there! Time to investigate.
-					g_bSlenderInvestigatingSound[iBossIndex] = true; // This is just so that our sound position would be the goal position.
-					iState = STATE_ALERT;
-				}
-			}
-		}
-		case STATE_ALERT:
-		{
-			if (GetArraySize(g_hSlenderPath[iBossIndex]) <= 0)
-			{
-				// Fully navigated through our path.
-				iState = STATE_IDLE;
-			}
-			else if (GetGameTime() >= g_flSlenderTimeUntilIdle[iBossIndex])
-			{
-				iState = STATE_IDLE;
-			}
-			else if (IsValidClient(iBestNewTarget))
-			{
-				if (GetGameTime() >= g_flSlenderTimeUntilChase[iBossIndex] || bPlayerNear[iBestNewTarget])
-				{
-					decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
-					NPCGetEyePosition(iBossIndex, flTraceStartPos);
-					
-					if (IsValidClient(iBestNewTarget)) GetClientEyePosition(iBestNewTarget, flTraceEndPos);
-					else
-					{
-						decl Float:flTargetMins[3], Float:flTargetMaxs[3];
-						GetEntPropVector(iBestNewTarget, Prop_Send, "m_vecMins", flTargetMins);
-						GetEntPropVector(iBestNewTarget, Prop_Send, "m_vecMaxs", flTargetMaxs);
-						GetEntPropVector(iBestNewTarget, Prop_Data, "m_vecAbsOrigin", flTraceEndPos);
-						for (new i = 0; i < 3; i++) flTraceEndPos[i] += ((flTargetMins[i] + flTargetMaxs[i]) / 2.0);
-					}
-					
-					new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
-						flTraceEndPos,
-						flTraceMins,
-						flTraceMaxs,
-						MASK_NPCSOLID,
-						TraceRayBossVisibility,
-						slender);
-						
-					new bool:bIsVisible = !TR_DidHit(hTrace);
-					new iTraceHitEntity = TR_GetEntityIndex(hTrace);
-					CloseHandle(hTrace);
-					
-					if (!bIsVisible && iTraceHitEntity == iBestNewTarget) bIsVisible = true;
-					
-					if ((bPlayerNear[iBestNewTarget] || bPlayerInFOV[iBestNewTarget]) && bPlayerVisible[iBestNewTarget])
-					{
-						// AHAHAHAH! I GOT YOU NOW!
-						iTarget = iBestNewTarget;
-						g_iSlenderTarget[iBossIndex] = EntIndexToEntRef(iBestNewTarget);
-						iState = STATE_CHASE;
-					}
-				}
-			}
-			else
-			{
-				if (iInterruptConditions & COND_SAWENEMY)
-				{
-					if (IsValidClient(iBestNewTarget))
-					{
-						g_flSlenderGoalPos[iBossIndex][0] = g_flSlenderLastFoundPlayerPos[iBossIndex][iBestNewTarget][0];
-						g_flSlenderGoalPos[iBossIndex][1] = g_flSlenderLastFoundPlayerPos[iBossIndex][iBestNewTarget][1];
-						g_flSlenderGoalPos[iBossIndex][2] = g_flSlenderLastFoundPlayerPos[iBossIndex][iBestNewTarget][2];
-						
-						bQueueForNewPath = true;
-					}
-				}
-				else if (iInterruptConditions & COND_HEARDSUSPICIOUSSOUND)
-				{
-					new bool:bDiscardMasterPos = bool:(GetGameTime() >= g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex]);
-					
-					if (GetVectorDistance(g_flSlenderTargetSoundTempPos[iBossIndex], g_flSlenderTargetSoundMasterPos[iBossIndex]) <= GetProfileFloat(sSlenderProfile, "search_sound_pos_dist_tolerance", 512.0) ||
-						bDiscardMasterPos)
-					{
-						g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_sound_pos_discard_time", 2.0);
-						g_flSlenderTargetSoundMasterPos[iBossIndex][0] = g_flSlenderTargetSoundTempPos[iBossIndex][0];
-						g_flSlenderTargetSoundMasterPos[iBossIndex][1] = g_flSlenderTargetSoundTempPos[iBossIndex][1];
-						g_flSlenderTargetSoundMasterPos[iBossIndex][2] = g_flSlenderTargetSoundTempPos[iBossIndex][2];
-						
-						// We have to manually set the goal position here because the goal position will not be changed due to no change in state.
-						g_flSlenderGoalPos[iBossIndex][0] = g_flSlenderTargetSoundMasterPos[iBossIndex][0];
-						g_flSlenderGoalPos[iBossIndex][1] = g_flSlenderTargetSoundMasterPos[iBossIndex][1];
-						g_flSlenderGoalPos[iBossIndex][2] = g_flSlenderTargetSoundMasterPos[iBossIndex][2];
-						
-						g_bSlenderInvestigatingSound[iBossIndex] = true;
-						
-						bQueueForNewPath = true;
-					}
-				}
-				
-				new bool:bBlockingProp = false;
-				
-				if (NPCGetFlags(iBossIndex) & SFF_ATTACKPROPS)
-				{
-					new prop = -1;
-					while ((prop = FindEntityByClassname(prop, "prop_physics")) != -1)
-					{
-						if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
-						{
-							bBlockingProp = true;
-							break;
-						}
-					}
-					
-					if (!bBlockingProp)
-					{
-						prop = -1;
-						while ((prop = FindEntityByClassname(prop, "prop_dynamic")) != -1)
-						{
-							if (GetEntProp(prop, Prop_Data, "m_iHealth") > 0)
-							{
-								if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
-								{
-									bBlockingProp = true;
-									break;
-								}
-							}
-						}
-					}
-				}
-				
-				if (bBlockingProp)
-				{
-					iState = STATE_ATTACK;
-				}
-			}
-		}
-		case STATE_CHASE, STATE_ATTACK, STATE_STUN:
-		{
-			if (iState == STATE_CHASE)
-			{
-				if (IsValidEdict(iTarget))
-				{
-					decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
-					NPCGetEyePosition(iBossIndex, flTraceStartPos);
-					
-					if (IsValidClient(iTarget))
-					{
-						GetClientEyePosition(iTarget, flTraceEndPos);
-					}
-					else
-					{
-						decl Float:flTargetMins[3], Float:flTargetMaxs[3];
-						GetEntPropVector(iTarget, Prop_Send, "m_vecMins", flTargetMins);
-						GetEntPropVector(iTarget, Prop_Send, "m_vecMaxs", flTargetMaxs);
-						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flTraceEndPos);
-						for (new i = 0; i < 3; i++) flTraceEndPos[i] += ((flTargetMins[i] + flTargetMaxs[i]) / 2.0);
-					}
-					
-					new bool:bIsDeathPosVisible = false;
-					
-					if (g_bSlenderChaseDeathPosition[iBossIndex])
-					{
-						new Handle:hTrace = TR_TraceRayFilterEx(flTraceStartPos,
-							g_flSlenderChaseDeathPosition[iBossIndex],
-							MASK_NPCSOLID,
-							RayType_EndPoint,
-							TraceRayBossVisibility,
-							slender);
-						bIsDeathPosVisible = !TR_DidHit(hTrace);
-						CloseHandle(hTrace);
-					}
-					
-					if (!bPlayerVisible[iTarget])
-					{
-						if (GetArraySize(g_hSlenderPath[iBossIndex]) == 0)
-						{
-							iState = STATE_IDLE;
-						}
-						else if (GetGameTime() >= g_flSlenderTimeUntilAlert[iBossIndex])
-						{
-							iState = STATE_ALERT;
-						}
-						else if (bIsDeathPosVisible)
-						{
-							iState = STATE_IDLE;
-						}
-						else if (iInterruptConditions & COND_CHASETARGETINVALIDATED)
-						{
-							if (!g_bSlenderChaseDeathPosition[iBossIndex])
-							{
-								g_bSlenderChaseDeathPosition[iBossIndex] = true;
-							}
-						}
-					}
-					else
-					{
-						g_bSlenderChaseDeathPosition[iBossIndex] = false;	// We're not chasing a dead player after all! Reset.
-					
-						decl Float:flAttackDirection[3];
-						GetClientAbsOrigin(iTarget, g_flSlenderGoalPos[iBossIndex]);
-						SubtractVectors(g_flSlenderGoalPos[iBossIndex], flMyPos, flAttackDirection);
-						GetVectorAngles(flAttackDirection, flAttackDirection);
-						
-						if (GetVectorDistance(g_flSlenderGoalPos[iBossIndex], flMyPos) <= flAttackBeginRange &&
-							(FloatAbs(AngleDiff(flAttackDirection[0], flMyEyeAng[0])) + FloatAbs(AngleDiff(flAttackDirection[1], flMyEyeAng[1]))) <= flAttackBeginFOV / 2.0)
-						{
-							// ENOUGH TALK! HAVE AT YOU!
-							iState = STATE_ATTACK;
-						}
-						else
-						{
-							new bool:bBlockingProp = false;
-							
-							if (NPCGetFlags(iBossIndex) & SFF_ATTACKPROPS)
-							{
-								new prop = -1;
-								while ((prop = FindEntityByClassname(prop, "prop_physics")) != -1)
-								{
-									if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
-									{
-										bBlockingProp = true;
-										break;
-									}
-								}
-								
-								if (!bBlockingProp)
-								{
-									prop = -1;
-									while ((prop = FindEntityByClassname(prop, "prop_dynamic")) != -1)
-									{
-										if (GetEntProp(prop, Prop_Data, "m_iHealth") > 0)
-										{
-											if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
-											{
-												bBlockingProp = true;
-												break;
-											}
-										}
-									}
-								}
-							}
-							
-							if (bBlockingProp)
-							{
-								iState = STATE_ATTACK;
-							}
-							else if (GetGameTime() >= g_flSlenderNextPathTime[iBossIndex])
-							{
-								g_flSlenderNextPathTime[iBossIndex] = GetGameTime() + 0.33;
-								bQueueForNewPath = true;
-							}
-						}
-					}
-				}
-				else
-				{
-					// Even if the target isn't valid anymore, see if I still have some ways to go on my current path,
-					// because I shouldn't actually know that the target has died until I see it.
-					if (GetArraySize(g_hSlenderPath[iBossIndex]) == 0)
-					{
-						iState = STATE_IDLE;
-					}
-				}
-			}
-			else if (iState == STATE_ATTACK)
-			{
-				if (!g_bSlenderAttacking[iBossIndex])
-				{
-					if (IsValidClient(iTarget))
-					{
-						g_bSlenderChaseDeathPosition[iBossIndex] = false;
-						
-						// Chase him again!
-						iState = STATE_CHASE;
-					}
-					else
-					{
-						// Target isn't valid anymore. We killed him, Mac!
-						iState = STATE_ALERT;
-					}
-				}
-			}
-			else if (iState == STATE_STUN)
-			{
-				if (GetGameTime() >= g_flSlenderTimeUntilRecover[iBossIndex])
-				{
-					NPCChaserSetStunHealth(iBossIndex, NPCChaserGetStunInitialHealth(iBossIndex));
-					
-					if (IsValidClient(iTarget))
-					{
-						// Chase him again!
-						iState = STATE_CHASE;
-					}
-					else
-					{
-						// WHAT DA FUUUUUUUUUUUQ. TARGET ISN'T VALID. AUSDHASUIHD
-						iState = STATE_ALERT;
-					}
-				}
-			}
-		}
-	}
-	
-	new bool:bDoChasePersistencyInit = false;
-	
-	if (iState != STATE_STUN)
-	{
-		if (bStunEnabled)
-		{
-			if (NPCChaserGetStunHealth(iBossIndex) <= 0)
-			{
-				if (iState != STATE_CHASE && iState != STATE_ATTACK)
-				{
-					// Sometimes players can stun the boss while it's not in chase mode. If that happens, we
-					// need to set the persistency value to the chase initial value.
-					bDoChasePersistencyInit = true;
-				}
-				
-				iState = STATE_STUN;
-			}
-		}
-	}
-	
-	// Finally, set our new state.
-	g_iSlenderState[iBossIndex] = iState;
-	
-	decl String:sAnimation[64];
-	new iModel = EntRefToEntIndex(g_iSlenderModel[iBossIndex]);
-	
-	new Float:flPlaybackRateWalk = g_flSlenderWalkAnimationPlaybackRate[iBossIndex];
-	new Float:flPlaybackRateRun = g_flSlenderRunAnimationPlaybackRate[iBossIndex];
-	new Float:flPlaybackRateIdle = g_flSlenderIdleAnimationPlaybackRate[iBossIndex];
-	
-	if (iOldState != iState)
-	{
-		switch (iState)
-		{
-			case STATE_IDLE, STATE_WANDER:
-			{
-				g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-				g_flSlenderTimeUntilIdle[iBossIndex] = -1.0;
-				g_flSlenderTimeUntilAlert[iBossIndex] = -1.0;
-				g_flSlenderTimeUntilChase[iBossIndex] = -1.0;
-				g_bSlenderChaseDeathPosition[iBossIndex] = false;
-				
-				if (iOldState != STATE_IDLE && iOldState != STATE_WANDER)
-				{
-					g_iSlenderTargetSoundCount[iBossIndex] = 0;
-					g_bSlenderInvestigatingSound[iBossIndex] = false;
-					g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = -1.0;
-					
-					g_flSlenderTimeUntilKill[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "idle_lifetime", 10.0);
-				}
-				
-				if (iState == STATE_WANDER)
-				{
-					// Force new wander position.
-					g_flSlenderNextWanderPos[iBossIndex] = -1.0;
-				}
-				
-				// Animation handling.
-				if (iModel && iModel != INVALID_ENT_REFERENCE)
-				{
-					if (iState == STATE_WANDER && (NPCGetFlags(iBossIndex) & SFF_WANDERMOVE))
-					{
-						if (GetProfileString(sSlenderProfile, "animation_walk", sAnimation, sizeof(sAnimation)))
-						{
-							EntitySetAnimation(iModel, sAnimation, _, flVelocityRatio * flPlaybackRateWalk);
-						}
-					}
-					else
-					{
-						if (GetProfileString(sSlenderProfile, "animation_idle", sAnimation, sizeof(sAnimation)))
-						{
-							EntitySetAnimation(iModel, sAnimation, _, flPlaybackRateIdle);
-						}
-					}
-				}
-			}
-			
-			case STATE_ALERT:
-			{
-				g_bSlenderChaseDeathPosition[iBossIndex] = false;
-				
-				// Set our goal position.
-				if (g_bSlenderInvestigatingSound[iBossIndex])
-				{
-					g_flSlenderGoalPos[iBossIndex][0] = g_flSlenderTargetSoundMasterPos[iBossIndex][0];
-					g_flSlenderGoalPos[iBossIndex][1] = g_flSlenderTargetSoundMasterPos[iBossIndex][1];
-					g_flSlenderGoalPos[iBossIndex][2] = g_flSlenderTargetSoundMasterPos[iBossIndex][2];
-				}
-				
-				g_flSlenderTimeUntilIdle[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_alert_duration", 5.0);
-				g_flSlenderTimeUntilAlert[iBossIndex] = -1.0;
-				g_flSlenderTimeUntilChase[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_alert_gracetime", 0.5);
-				
-				bQueueForNewPath = true;
-				
-				// Animation handling.
-				if (iModel && iModel != INVALID_ENT_REFERENCE)
-				{
-					if (GetProfileString(sSlenderProfile, "animation_walk", sAnimation, sizeof(sAnimation)))
-					{
-						EntitySetAnimation(iModel, sAnimation, _, flVelocityRatio * flPlaybackRateWalk);
-					}
-				}
-			}
-			case STATE_CHASE, STATE_ATTACK, STATE_STUN:
-			{
-				g_bSlenderInvestigatingSound[iBossIndex] = false;
-				g_iSlenderTargetSoundCount[iBossIndex] = 0;
-				
-				if (iOldState != STATE_ATTACK && iOldState != STATE_CHASE && iOldState != STATE_STUN)
-				{
-					g_flSlenderTimeUntilIdle[iBossIndex] = -1.0;
-					g_flSlenderTimeUntilAlert[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration", 10.0);
-					g_flSlenderTimeUntilChase[iBossIndex] = -1.0;
-					
-					new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init", 5.0);
-					if (flPersistencyTime >= 0.0)
-					{
-						g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
-					}
-				}
-				
-				if (iState == STATE_ATTACK)
-				{
-					g_bSlenderAttacking[iBossIndex] = true;
-					g_hSlenderAttackTimer[iBossIndex] = CreateTimer(NPCChaserGetAttackDamageDelay(iBossIndex, 0), Timer_SlenderChaseBossAttack, EntIndexToEntRef(slender), TIMER_FLAG_NO_MAPCHANGE);
-					
-					new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init_attack", -1.0);
-					if (flPersistencyTime >= 0.0)
-					{
-						g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
-					}
-					
-					flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_attack", 2.0);
-					if (flPersistencyTime >= 0.0)
-					{
-						if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
-						g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTime;
-					}
-					
-					SlenderPerformVoice(iBossIndex, "sound_attackenemy");
-				}
-				else if (iState == STATE_STUN)
-				{
-					if (g_bSlenderAttacking[iBossIndex])
-					{
-						// Cancel attacking.
-						g_bSlenderAttacking[iBossIndex] = false;
-						g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
-					}
-					
-					if (!bDoChasePersistencyInit)
-					{
-						new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init_stun", -1.0);
-						if (flPersistencyTime >= 0.0)
-						{
-							g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
-						}
-						
-						flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_stun", 2.0);
-						if (flPersistencyTime >= 0.0)
-						{
-							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
-							g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTime;
-						}
-					}
-					else
-					{
-						new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init", 5.0);
-						if (flPersistencyTime >= 0.0)
-						{
-							g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
-						}
-					}
-					
-					g_flSlenderTimeUntilRecover[iBossIndex] = GetGameTime() + NPCChaserGetStunDuration(iBossIndex);
-					
-					// Sound handling. Ignore time check.
-					SlenderPerformVoice(iBossIndex, "sound_stun");
-				}
-				else
-				{
-					if (iOldState != STATE_ATTACK)
-					{
-						// Sound handling.
-						SlenderPerformVoice(iBossIndex, "sound_chaseenemyinitial");
-					}
-				}
-				
-				// Animation handling.
-				if (iModel && iModel != INVALID_ENT_REFERENCE)
-				{
-					if (iState == STATE_CHASE)
-					{
-						if (GetProfileString(sSlenderProfile, "animation_run", sAnimation, sizeof(sAnimation)))
-						{
-							EntitySetAnimation(iModel, sAnimation, _, flVelocityRatio * flPlaybackRateRun);
-						}
-					}
-					else if (iState == STATE_ATTACK)
-					{
-						if (GetProfileString(sSlenderProfile, "animation_attack", sAnimation, sizeof(sAnimation)))
-						{
-							EntitySetAnimation(iModel, sAnimation, _, GetProfileFloat(sSlenderProfile, "animation_attack_playbackrate", 1.0));
-						}
-					}
-					else if (iState == STATE_STUN)
-					{
-						if (GetProfileString(sSlenderProfile, "animation_stun", sAnimation, sizeof(sAnimation)))
-						{
-							EntitySetAnimation(iModel, sAnimation, _, GetProfileFloat(sSlenderProfile, "animation_stun_playbackrate", 1.0));
-						}
-					}
-				}
-			}
-		}
-		
-		// Call our forward.
-		Call_StartForward(fOnBossChangeState);
-		Call_PushCell(iBossIndex);
-		Call_PushCell(iOldState);
-		Call_PushCell(iState);
-		Call_Finish();
-	}
-	
-	switch (iState)
-	{
-		case STATE_IDLE:
-		{
-			// Animation playback speed handling.
-			if (iModel && iModel != INVALID_ENT_REFERENCE)
-			{
-				SetVariantFloat(flPlaybackRateIdle);
-				AcceptEntityInput(iModel, "SetPlaybackRate");
-			}
-		}
-		case STATE_WANDER, STATE_ALERT, STATE_CHASE, STATE_ATTACK:
-		{
-			// These deal with movement, therefore we need to set our 
-			// destination first. That is, if we don't have one. (nav mesh only)
-			
-			if (iState == STATE_WANDER)
-			{
-				if (GetGameTime() >= g_flSlenderNextWanderPos[iBossIndex])
-				{
-					new Float:flMin = GetProfileFloat(sSlenderProfile, "search_wander_time_min", 4.0);
-					new Float:flMax = GetProfileFloat(sSlenderProfile, "search_wander_time_max", 6.5);
-					g_flSlenderNextWanderPos[iBossIndex] = GetGameTime() + GetRandomFloat(flMin, flMax);
-					
-					if (NPCGetFlags(iBossIndex) & SFF_WANDERMOVE)
-					{
-						// We're allowed to move in wander mode. Get a new wandering position and create a path to follow.
-						// If the position can't be reached, then just get to the closest area that we can get.
-						new Float:flWanderRangeMin = GetProfileFloat(sSlenderProfile, "search_wander_range_min", 400.0);
-						new Float:flWanderRangeMax = GetProfileFloat(sSlenderProfile, "search_wander_range_max", 1024.0);
-						new Float:flWanderRange = GetRandomFloat(flWanderRangeMin, flWanderRangeMax);
-						
-						decl Float:flWanderPos[3];
-						flWanderPos[0] = 0.0;
-						flWanderPos[1] = GetRandomFloat(0.0, 360.0);
-						flWanderPos[2] = 0.0;
-						
-						GetAngleVectors(flWanderPos, flWanderPos, NULL_VECTOR, NULL_VECTOR);
-						NormalizeVector(flWanderPos, flWanderPos);
-						ScaleVector(flWanderPos, flWanderRange);
-						AddVectors(flWanderPos, flMyPos, flWanderPos);
-						
-						g_flSlenderGoalPos[iBossIndex][0] = flWanderPos[0];
-						g_flSlenderGoalPos[iBossIndex][1] = flWanderPos[1];
-						g_flSlenderGoalPos[iBossIndex][2] = flWanderPos[2];
-						
-						bQueueForNewPath = true;
-						g_flSlenderNextPathTime[iBossIndex] = -1.0; // We're not going to wander around too much, so no need for a time constraint.
-					}
-				}
-			}
-			else if (iState == STATE_ALERT)
-			{
-				if (iInterruptConditions & COND_SAWENEMY)
-				{
-					if (IsValidEntity(iBestNewTarget))
-					{
-						if ((bPlayerInFOV[iBestNewTarget] || bPlayerNear[iBestNewTarget]) && bPlayerVisible[iBestNewTarget])
-						{
-							// Constantly update my path if I see him.
-							if (GetGameTime() >= g_flSlenderNextPathTime[iBossIndex])
-							{
-								GetEntPropVector(iBestNewTarget, Prop_Data, "m_vecAbsOrigin", g_flSlenderGoalPos[iBossIndex]);
-								bQueueForNewPath = true;
-								g_flSlenderNextPathTime[iBossIndex] = GetGameTime() + 0.33;
-							}
-						}
-					}
-				}
-			}
-			else if (iState == STATE_CHASE || iState == STATE_ATTACK)
-			{
-				if (IsValidEntity(iBestNewTarget))
-				{
-					iOldTarget = iTarget;
-					iTarget = iBestNewTarget;
-					g_iSlenderTarget[iBossIndex] = EntIndexToEntRef(iBestNewTarget);
-				}
-				
-				if (iTarget != INVALID_ENT_REFERENCE)
-				{
-					if (iOldTarget != iTarget)
-					{
-						// Brand new target! We need a path, and we need to reset our persistency, if needed.
-						new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init_newtarget", -1.0);
-						if (flPersistencyTime >= 0.0)
-						{
-							g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
-						}
-						
-						flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_newtarget", 2.0);
-						if (flPersistencyTime >= 0.0)
-						{
-							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
-							g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTime;
-						}
-					
-						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", g_flSlenderGoalPos[iBossIndex]);
-						bQueueForNewPath = true; // Brand new target! We need a new path!
-					}
-					else if ((bPlayerInFOV[iTarget] && bPlayerVisible[iTarget]) || GetGameTime() < g_flSlenderTimeUntilNoPersistence[iBossIndex])
-					{
-						// Constantly update my path if I see him or if I'm still being persistent.
-						if (GetGameTime() >= g_flSlenderNextPathTime[iBossIndex])
-						{
-							GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", g_flSlenderGoalPos[iBossIndex]);
-							bQueueForNewPath = true;
-							g_flSlenderNextPathTime[iBossIndex] = GetGameTime() + 0.33;
-						}
-					}
-				}
-			}
-			
-			if (NavMesh_Exists())
-			{
-				// So by now we should have calculated our master goal position.
-				// Now we use that to create a path.
-				
-				if (bQueueForNewPath)
-				{
-					ClearArray(g_hSlenderPath[iBossIndex]);
-					
-					new iCurrentAreaIndex = NavMesh_GetNearestArea(flMyPos);
-					if (iCurrentAreaIndex != -1)
-					{
-						new iGoalAreaIndex = NavMesh_GetNearestArea(g_flSlenderGoalPos[iBossIndex]);
-						if (iGoalAreaIndex != -1)
-						{
-							decl Float:flCenter[3], Float:flCenterPortal[3], Float:flClosestPoint[3];
-							new iClosestAreaIndex = 0;
-							
-							new bool:bPathSuccess = NavMesh_BuildPath(iCurrentAreaIndex,
-								iGoalAreaIndex,
-								g_flSlenderGoalPos[iBossIndex],
-								SlenderChaseBossShortestPathCost,
-								RoundToFloor(NPCChaserGetStepSize(iBossIndex)),
-								iClosestAreaIndex);
-								
-							new iTempAreaIndex = iClosestAreaIndex;
-							new iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
-							new iNavDirection;
-							new Float:flHalfWidth;
-							
-							if (bPathSuccess)
-							{
-								// Path successful? Insert the goal position into our list.
-								new iIndex = PushArrayCell(g_hSlenderPath[iBossIndex], g_flSlenderGoalPos[iBossIndex][0]);
-								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, g_flSlenderGoalPos[iBossIndex][1], 1);
-								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, g_flSlenderGoalPos[iBossIndex][2], 2);
-							}
-							
-							while (iTempParentAreaIndex != -1)
-							{
-								// Build a path of waypoints along the nav mesh for our AI to follow.
-								// Path order is first come, first served, so when we got our waypoint list,
-								// we have to reverse it so that the starting waypoint would be in front.
-								
-								NavMeshArea_GetCenter(iTempParentAreaIndex, flCenter);
-								iNavDirection = NavMeshArea_ComputeDirection(iTempAreaIndex, flCenter);
-								NavMeshArea_ComputePortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flHalfWidth);
-								NavMeshArea_ComputeClosestPointInPortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flClosestPoint);
-								
-								flClosestPoint[2] = NavMeshArea_GetZ(iTempAreaIndex, flClosestPoint);
-								
-								new iIndex = PushArrayCell(g_hSlenderPath[iBossIndex], flClosestPoint[0]);
-								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, flClosestPoint[1], 1);
-								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, flClosestPoint[2], 2);
-								
-								iTempAreaIndex = iTempParentAreaIndex;
-								iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
-							}
-							
-							// Set our goal position to the start node (hopefully there's something in the array).
-							if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
-							{
-								new iPosIndex = GetArraySize(g_hSlenderPath[iBossIndex]) - 1;
-								
-								g_flSlenderGoalPos[iBossIndex][0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 0);
-								g_flSlenderGoalPos[iBossIndex][1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 1);
-								g_flSlenderGoalPos[iBossIndex][2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 2);
-							}
-						}
-						else
-						{
-							PrintToServer("SF2: Failed to create new path for boss %d: destination is not on nav mesh!", iBossIndex);
-						}
-					}
-					else
-					{
-						PrintToServer("SF2: Failed to create new path for boss %d: boss is not on nav mesh!", iBossIndex);
-					}
-				}
-			}
-			else
-			{
-				// The nav mesh doesn't exist? Well, that sucks.
-				ClearArray(g_hSlenderPath[iBossIndex]);
-			}
-			
-			if (iState == STATE_CHASE || iState == STATE_ATTACK)
-			{
-				if (IsValidClient(iTarget))
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayer(iTarget, DEBUG_BOSS_CHASE, 1, "g_flSlenderTimeUntilAlert[%d]: %f\ng_flSlenderTimeUntilNoPersistence[%d]: %f", iBossIndex, g_flSlenderTimeUntilAlert[iBossIndex] - GetGameTime(), iBossIndex, g_flSlenderTimeUntilNoPersistence[iBossIndex] - GetGameTime());
-#endif
-				
-					if (bPlayerInFOV[iTarget] && bPlayerVisible[iTarget])
-					{
-						new Float:flDistRatio = flPlayerDists[iTarget] / NPCGetSearchRadius(iBossIndex);
-						
-						new Float:flChaseDurationTimeAddMin = GetProfileFloat(sSlenderProfile, "search_chase_duration_add_visible_min", 0.025);
-						new Float:flChaseDurationTimeAddMax = GetProfileFloat(sSlenderProfile, "search_chase_duration_add_visible_max", 0.2);
-						
-						new Float:flChaseDurationAdd = flChaseDurationTimeAddMax - ((flChaseDurationTimeAddMax - flChaseDurationTimeAddMin) * flDistRatio);
-						
-						if (flChaseDurationAdd > 0.0)
-						{
-							g_flSlenderTimeUntilAlert[iBossIndex] += flChaseDurationAdd;
-							if (g_flSlenderTimeUntilAlert[iBossIndex] > (GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration")))
-							{
-								g_flSlenderTimeUntilAlert[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration");
-							}
-						}
-						
-						new Float:flPersistencyTimeAddMin = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_visible_min", 0.05);
-						new Float:flPersistencyTimeAddMax = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_visible_max", 0.15);
-						
-						new Float:flPersistencyTimeAdd = flPersistencyTimeAddMax - ((flPersistencyTimeAddMax - flPersistencyTimeAddMin) * flDistRatio);
-						
-						if (flPersistencyTimeAdd > 0.0)
-						{
-							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
-						
-							g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTimeAdd;
-							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] > (GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration")))
-							{
-								g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration");
-							}
-						}
-					}
-				}
-			}
-			
-			// Process through our path waypoints.
-			if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
-			{
-				decl Float:flHitNormal[3];
-				decl Float:flNodePos[3];
-				
-				new Float:flNodeToleranceDist = g_flSlenderPathNodeTolerance[iBossIndex];
-				new bool:bGotNewPoint = false;
-				
-				for (new iNodeIndex = 0, iNodeCount = GetArraySize(g_hSlenderPath[iBossIndex]); iNodeIndex < iNodeCount; iNodeIndex++)
-				{
-					flNodePos[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeIndex, 0);
-					flNodePos[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeIndex, 1);
-					flNodePos[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeIndex, 2);
-					
-					new Handle:hTrace = TR_TraceHullFilterEx(flMyPos,
-						flNodePos, 
-						flSlenderMins, 
-						flSlenderMaxs, 
-						MASK_NPCSOLID, 
-						TraceRayDontHitCharactersOrEntity, 
-						slender);
-						
-					new bool:bDidHit = TR_DidHit(hTrace);
-					TR_GetPlaneNormal(hTrace, flHitNormal);
-					CloseHandle(hTrace);
-					GetVectorAngles(flHitNormal, flHitNormal);
-					for (new i = 0; i < 3; i++) flHitNormal[i] = AngleNormalize(flHitNormal[i]);
-					
-					// First check if we can see the point.
-					if (!bDidHit || ((flHitNormal[0] >= 0.0 && flHitNormal[0] > 45.0) || (flHitNormal[0] < 0.0 && flHitNormal[0] < -45.0)))
-					{
-						new bool:bNearNode = false;
-						
-						// See if we're already near enough.
-						new Float:flDist = GetVectorDistance(flNodePos, flMyPos);
-						if (flDist < flNodeToleranceDist) bNearNode = true;
-						
-						if (!bNearNode)
-						{
-							new bool:bOutside = false;
-						
-							// Then, predict if we're going to pass over the point on the next think.
-							decl Float:flTestPos[3];
-							NormalizeVector(flSlenderVelocity, flTestPos);
-							ScaleVector(flTestPos, GetVectorLength(flSlenderVelocity) * BOSS_THINKRATE);
-							AddVectors(flMyPos, flTestPos, flTestPos);
-							
-							decl Float:flP[3], Float:flS[3];
-							SubtractVectors(flNodePos, flMyPos, flP);
-							SubtractVectors(flTestPos, flMyPos, flS);
-							
-							new Float:flSP = GetVectorDotProduct(flP, flS);
-							if (flSP <= 0.0) bOutside = true;
-							
-							new Float:flPP = GetVectorDotProduct(flS, flS);
-							
-							if (!bOutside)
-							{
-								if (flPP <= flSP) bOutside = true;
-							}
-							
-							if (!bOutside)
-							{
-								decl Float:flD[3];
-								ScaleVector(flS, (flSP / flPP));
-								SubtractVectors(flP, flS, flD);
-							
-								flDist = GetVectorLength(flD);
-								if (flDist < flNodeToleranceDist)
-								{
-									bNearNode = true;
-								}
-							}
-						}
-						
-						if (bNearNode)
-						{
-							// Shave off this node and set our goal position to the next one.
-						
-							ResizeArray(g_hSlenderPath[iBossIndex], iNodeIndex);
-							
-							if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
-							{
-								new iPosIndex = GetArraySize(g_hSlenderPath[iBossIndex]) - 1;
-								
-								g_flSlenderGoalPos[iBossIndex][0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 0);
-								g_flSlenderGoalPos[iBossIndex][1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 1);
-								g_flSlenderGoalPos[iBossIndex][2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 2);
-							}
-							
-							bGotNewPoint = true;
-							break;
-						}
-					}
-				}
-				
-				if (!bGotNewPoint)
-				{
-					// Try to see if we can look ahead.
-					
-					decl Float:flMyEyePos[3];
-					NPCGetEyePosition(iBossIndex, flMyEyePos);
-					
-					new Float:flNodeLookAheadDist = g_flSlenderPathNodeLookAhead[iBossIndex];
-					if (flNodeLookAheadDist > 0.0)
-					{
-						new iNodeCount = GetArraySize(g_hSlenderPath[iBossIndex]);
-						if (iNodeCount)
-						{
-							decl Float:flInitDir[3];
-							flInitDir[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeCount - 1, 0);
-							flInitDir[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeCount - 1, 1);
-							flInitDir[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeCount - 1, 2);
-							
-							SubtractVectors(flInitDir, flMyPos, flInitDir);
-							NormalizeVector(flInitDir, flInitDir);
-							
-							decl Float:flPrevDir[3];
-							flPrevDir[0] = flInitDir[0];
-							flPrevDir[1] = flInitDir[1];
-							flPrevDir[2] = flInitDir[2];
-							
-							NormalizeVector(flPrevDir, flPrevDir);
-							
-							decl Float:flPrevNodePos[3];
-							
-							new iStartPointIndex = iNodeCount - 1;
-							new Float:flRangeSoFar = 0.0;
-							
-							new iLookAheadPointIndex;
-							for (iLookAheadPointIndex = iStartPointIndex; iLookAheadPointIndex >= 0; iLookAheadPointIndex--)
-							{
-								flNodePos[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex, 0);
-								flNodePos[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex, 1);
-								flNodePos[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex, 2);
-							
-								decl Float:flDir[3];
-								if (iLookAheadPointIndex == iStartPointIndex)
-								{
-									SubtractVectors(flNodePos, flMyPos, flDir);
-									NormalizeVector(flDir, flDir);
-								}
-								else
-								{
-									flPrevNodePos[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1, 0);
-									flPrevNodePos[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1, 1);
-									flPrevNodePos[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1, 2);
-								
-									SubtractVectors(flNodePos, flPrevNodePos, flDir);
-									NormalizeVector(flDir, flDir);
-								}
-								
-								if (GetVectorDotProduct(flDir, flInitDir) < 0.0)
-								{
-									break;
-								}
-								
-								if (GetVectorDotProduct(flDir, flPrevDir) < 0.5)
-								{
-									break;
-								}
-								
-								flPrevDir[0] = flDir[0];
-								flPrevDir[1] = flDir[1];
-								flPrevDir[2] = flDir[2];
-								
-								decl Float:flProbe[3];
-								flProbe[0] = flNodePos[0];
-								flProbe[1] = flNodePos[1];
-								flProbe[2] = flNodePos[2] + HalfHumanHeight;
-								
-								if (!IsWalkableTraceLineClear(flMyEyePos, flProbe, WALK_THRU_BREAKABLES))
-								{
-									break;
-								}
-								
-								if (iLookAheadPointIndex == iStartPointIndex)
-								{
-									flRangeSoFar += GetVectorDistance(flMyPos, flNodePos);
-								}
-								else
-								{
-									flRangeSoFar += GetVectorDistance(flNodePos, flPrevNodePos);
-								}
-								
-								if (flRangeSoFar >= flNodeLookAheadDist)
-								{
-									break;
-								}
-							}
-							
-							// Shave off all unnecessary nodes and keep the one that is within
-							// our viewsight.
-							
-							ResizeArray(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1);
-							
-							if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
-							{
-								new iPosIndex = GetArraySize(g_hSlenderPath[iBossIndex]) - 1;
-								
-								g_flSlenderGoalPos[iBossIndex][0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 0);
-								g_flSlenderGoalPos[iBossIndex][1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 1);
-								g_flSlenderGoalPos[iBossIndex][2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 2);
-							}
-							
-							bGotNewPoint = true;
-						}
-					}
-				}
-			}
-			
-			if (iState != STATE_ATTACK && iState != STATE_STUN)
-			{
-				// Animation playback speed handling.
-				if (iModel && iModel != INVALID_ENT_REFERENCE)
-				{
-					if (iState == STATE_WANDER && !(NPCGetFlags(iBossIndex) & SFF_WANDERMOVE))
-					{
-						SetVariantFloat(flPlaybackRateIdle);
-						AcceptEntityInput(iModel, "SetPlaybackRate");
-					}
-					else
-					{
-						SetVariantFloat(iState == STATE_CHASE ? (flVelocityRatio * flPlaybackRateRun) : (flVelocityRatioWalk * flPlaybackRateWalk));
-						AcceptEntityInput(iModel, "SetPlaybackRate");
-					}
-				}
-			}
-		}
-	}
-	
-	// Sound handling.
-	if (GetGameTime() >= g_flSlenderNextVoiceSound[iBossIndex])
-	{
-		if (iState == STATE_IDLE || iState == STATE_WANDER)
-		{
-			SlenderPerformVoice(iBossIndex, "sound_idle");
-		}
-		else if (iState == STATE_ALERT)
-		{
-			SlenderPerformVoice(iBossIndex, "sound_alertofenemy");
-		}
-		else if (iState == STATE_CHASE || iState == STATE_ATTACK)
-		{
-			SlenderPerformVoice(iBossIndex, "sound_chasingenemy");
-		}
-	}
-	
-	// Reset our interrupt conditions.
-	g_iSlenderInterruptConditions[iBossIndex] = 0;
-	
-	return Plugin_Continue;
-}
-
-SlenderChaseBossProcessMovement(iBossIndex)
-{
-	new iBoss = NPCGetEntIndex(iBossIndex);
-	new iState = g_iSlenderState[iBossIndex];
-	
-	// Constantly set the monster_generic's NPC state to idle to prevent
-	// velocity confliction.
-	
-	SetEntProp(iBoss, Prop_Data, "m_NPCState", 0);
-	
-	new Float:flWalkSpeed = g_flSlenderCalculatedWalkSpeed[iBossIndex];
-	new Float:flSpeed = g_flSlenderCalculatedSpeed[iBossIndex];
-	
-	new Float:flMyPos[3], Float:flMyEyeAng[3], Float:flMyVelocity[3];
-	
-	decl String:sSlenderProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sSlenderProfile, sizeof(sSlenderProfile));
-	
-	GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flMyPos);
-	GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
-	GetEntPropVector(iBoss, Prop_Data, "m_vecAbsVelocity", flMyVelocity);
-	
-	decl Float:flBossMins[3], Float:flBossMaxs[3];
-	GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flBossMins);
-	GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flBossMaxs);
-	
-	decl Float:flTraceMins[3], Float:flTraceMaxs[3];
-	flTraceMins[0] = flBossMins[0];
-	flTraceMins[1] = flBossMins[1];
-	flTraceMins[2] = 0.0;
-	flTraceMaxs[0] = flBossMaxs[0];
-	flTraceMaxs[1] = flBossMaxs[1];
-	flTraceMaxs[2] = 0.0;
-	
-	// By now we should have our preferable goal position. Initiate
-	// reflex adjustments.
-	
-	g_bSlenderFeelerReflexAdjustment[iBossIndex] = false;
-	
-	{
-		decl Float:flMoveDir[3];
-		NormalizeVector(flMyVelocity, flMoveDir);
-		flMoveDir[2] = 0.0;
-		
-		decl Float:flLat[3];
-		flLat[0] = -flMoveDir[1];
-		flLat[1] = flMoveDir[0];
-		flLat[2] = 0.0;
-	
-		new Float:flFeelerOffset = 25.0;
-		new Float:flFeelerLengthRun = 50.0;
-		new Float:flFeelerLengthWalk = 30.0;
-		new Float:flFeelerHeight = StepHeight + 0.1;
-		
-		new Float:flFeelerLength = iState == STATE_CHASE ? flFeelerLengthRun : flFeelerLengthWalk;
-		
-		// Get the ground height and normal.
-		new Handle:hTrace = TR_TraceRayFilterEx(flMyPos, Float:{ 0.0, 0.0, 90.0 }, MASK_NPCSOLID, RayType_Infinite, TraceFilterWalkableEntities);
-		decl Float:flTraceEndPos[3];
-		decl Float:flTraceNormal[3];
-		TR_GetEndPosition(flTraceEndPos, hTrace);
-		TR_GetPlaneNormal(hTrace, flTraceNormal);
-		new bool:bTraceHit = TR_DidHit(hTrace);
-		CloseHandle(hTrace);
-		
-		if (bTraceHit)
-		{
-			//new Float:flGroundHeight = GetVectorDistance(flMyPos, flTraceEndPos);
-			NormalizeVector(flTraceNormal, flTraceNormal);
-			GetVectorCrossProduct(flLat, flTraceNormal, flMoveDir);
-			GetVectorCrossProduct(flMoveDir, flTraceNormal, flLat);
-			
-			decl Float:flFeet[3];
-			flFeet[0] = flMyPos[0];
-			flFeet[1] = flMyPos[1];
-			flFeet[2] = flMyPos[2] + flFeelerHeight;
-			
-			decl Float:flTo[3];
-			decl Float:flFrom[3];
-			for (new i = 0; i < 3; i++)
-			{
-				flFrom[i] = flFeet[i] + (flFeelerOffset * flLat[i]);
-				flTo[i] = flFrom[i] + (flFeelerLength * flMoveDir[i]);
-			}
-			
-			new bool:bLeftClear = IsWalkableTraceLineClear(flFrom, flTo, WALK_THRU_DOORS | WALK_THRU_BREAKABLES);
-			
-			for (new i = 0; i < 3; i++)
-			{
-				flFrom[i] = flFeet[i] - (flFeelerOffset * flLat[i]);
-				flTo[i] = flFrom[i] + (flFeelerLength * flMoveDir[i]);
-			}
-			
-			new bool:bRightClear = IsWalkableTraceLineClear(flFrom, flTo, WALK_THRU_DOORS | WALK_THRU_BREAKABLES);
-			
-			new Float:flAvoidRange = 300.0;
-			
-			if (!bRightClear)
-			{
-				if (bLeftClear)
-				{
-					g_bSlenderFeelerReflexAdjustment[iBossIndex] = true;
-					
-					for (new i = 0; i < 3; i++)
-					{
-						g_flSlenderFeelerReflexAdjustmentPos[iBossIndex][i] = g_flSlenderGoalPos[iBossIndex][i] + (flAvoidRange * flLat[i]);
-					}
-				}
-			}
-			else if (!bLeftClear)
-			{
-				g_bSlenderFeelerReflexAdjustment[iBossIndex] = true;
-				
-				for (new i = 0; i < 3; i++)
-				{
-					g_flSlenderFeelerReflexAdjustmentPos[iBossIndex][i] = g_flSlenderGoalPos[iBossIndex][i] - (flAvoidRange * flLat[i]);
-				}
-			}
-		}
-	}
-	
-	new Float:flGoalPosition[3];
-	if (g_bSlenderFeelerReflexAdjustment[iBossIndex])
-	{
-		for (new i = 0; i < 3; i++)
-		{
-			flGoalPosition[i] = g_flSlenderFeelerReflexAdjustmentPos[iBossIndex][i];
-		}
-	}
-	else
-	{
-		for (new i = 0; i < 3; i++)
-		{
-			flGoalPosition[i] = g_flSlenderGoalPos[iBossIndex][i];
-		}
-	}
-	
-	// Process our desired velocity.
-	new Float:flDesiredVelocity[3];
-	switch (iState)
-	{
-		case STATE_WANDER:
-		{
-			if (NPCGetFlags(iBossIndex) & SFF_WANDERMOVE)
-			{
-				SubtractVectors(flGoalPosition, flMyPos, flDesiredVelocity);
-				flDesiredVelocity[2] = 0.0;
-				NormalizeVector(flDesiredVelocity, flDesiredVelocity);
-				ScaleVector(flDesiredVelocity, flWalkSpeed);
-			}
-		}
-		case STATE_ALERT:
-		{
-			SubtractVectors(flGoalPosition, flMyPos, flDesiredVelocity);
-			flDesiredVelocity[2] = 0.0;
-			NormalizeVector(flDesiredVelocity, flDesiredVelocity);
-			ScaleVector(flDesiredVelocity, flWalkSpeed);
-		}
-		case STATE_CHASE:
-		{
-			SubtractVectors(flGoalPosition, flMyPos, flDesiredVelocity);
-			flDesiredVelocity[2] = 0.0;
-			NormalizeVector(flDesiredVelocity, flDesiredVelocity);
-			ScaleVector(flDesiredVelocity, flSpeed);
-		}
-	}
-	
-	// Check if we're on the ground.
-	new bool:bSlenderOnGround = bool:(GetEntityFlags(iBoss) & FL_ONGROUND);
-	
-	decl Float:flTraceEndPos[3];
-	new Handle:hTrace;
-	
-	// Determine speed behavior.
-	if (bSlenderOnGround)
-	{
-		// Don't change the speed behavior.
-	}
-	else
-	{
-		flDesiredVelocity[2] = 0.0;
-		NormalizeVector(flDesiredVelocity, flDesiredVelocity);
-		ScaleVector(flDesiredVelocity, NPCChaserGetAirSpeed(iBossIndex, GetConVarInt(g_cvDifficulty)));
-	}
-	
-	new bool:bSlenderTeleportedOnStep = false;
-	new Float:flSlenderStepSize = NPCChaserGetStepSize(iBossIndex);
-	
-	// Check our stepsize in case we need to elevate ourselves a step.
-	if (bSlenderOnGround && GetVectorLength(flDesiredVelocity) > 0.0)
-	{
-		if (flSlenderStepSize > 0.0)
-		{
-			decl Float:flTraceDirection[3], Float:flObstaclePos[3], Float:flObstacleNormal[3];
-			NormalizeVector(flDesiredVelocity, flTraceDirection);
-			AddVectors(flMyPos, flTraceDirection, flTraceEndPos);
-			
-			// Tracehull in front of us to check if there's a very small obstacle blocking our way.
-			hTrace = TR_TraceHullFilterEx(flMyPos, 
-				flTraceEndPos,
-				flBossMins,
-				flBossMaxs,
-				MASK_NPCSOLID,
-				TraceRayDontHitEntity,
-				iBoss);
-				
-			new bool:bSlenderHitObstacle = TR_DidHit(hTrace);
-			TR_GetEndPosition(flObstaclePos, hTrace);
-			TR_GetPlaneNormal(hTrace, flObstacleNormal);
-			CloseHandle(hTrace);
-			
-			if (bSlenderHitObstacle &&
-				FloatAbs(flObstacleNormal[2]) == 0.0)
-			{
-				decl Float:flTraceStartPos[3];
-				flTraceStartPos[0] = flObstaclePos[0];
-				flTraceStartPos[1] = flObstaclePos[1];
-				
-				decl Float:flTraceFreePos[3];
-				
-				new Float:flTraceCheckZ = 0.0;
-				
-				// This does a crapload of traces along the wall. Very nasty and expensive to do...
-				while (flTraceCheckZ <= flSlenderStepSize)
-				{
-					flTraceCheckZ += 1.0;
-					flTraceStartPos[2] = flObstaclePos[2] + flTraceCheckZ;
-					
-					AddVectors(flTraceStartPos, flTraceDirection, flTraceEndPos);
-					
-					hTrace = TR_TraceHullFilterEx(flTraceStartPos, 
-						flTraceEndPos,
-						flTraceMins,
-						flTraceMaxs,
-						MASK_NPCSOLID,
-						TraceRayDontHitEntity,
-						iBoss);
-						
-					bSlenderHitObstacle = TR_DidHit(hTrace);
-					TR_GetEndPosition(flTraceFreePos, hTrace);
-					CloseHandle(hTrace);
-					
-					if (!bSlenderHitObstacle)
-					{
-						// Potential space to step on? See if we can fit!
-						if (!IsSpaceOccupiedNPC(flTraceFreePos,
-							flBossMins,
-							flBossMaxs,
-							iBoss))
-						{
-							// Yes we can! Break the loop and teleport to this pos.
-							bSlenderTeleportedOnStep = true;
-							TeleportEntity(iBoss, flTraceFreePos, NULL_VECTOR, NULL_VECTOR);
-							break;
-						}
-					}
-				}
-			}
-			/*
-			else if (!bSlenderHitObstacle)
-			{
-				decl Float:flTraceStartPos[3];
-				flTraceStartPos[0] = flObstaclePos[0];
-				flTraceStartPos[1] = flObstaclePos[1];
-				
-				decl Float:flTraceFreePos[3];
-				
-				new Float:flTraceCheckZ = 0.0;
-				
-				// This does a crapload of traces along the wall. Very nasty and expensive to do...
-				while (flTraceCheckZ <= flSlenderStepSize)
-				{
-					flTraceCheckZ += 1.0;
-					flTraceStartPos[2] = flObstaclePos[2] - flTraceCheckZ;
-					
-					AddVectors(flTraceStartPos, flTraceDirection, flTraceEndPos);
-					
-					hTrace = TR_TraceHullFilterEx(flTraceStartPos, 
-						flTraceEndPos,
-						flTraceMins,
-						flTraceMaxs,
-						MASK_NPCSOLID,
-						TraceRayDontHitEntity,
-						iBoss);
-						
-					bSlenderHitObstacle = TR_DidHit(hTrace);
-					TR_GetEndPosition(flTraceFreePos, hTrace);
-					CloseHandle(hTrace);
-					
-					if (bSlenderHitObstacle)
-					{
-						// Potential space to step on? See if we can fit!
-						if (!IsSpaceOccupiedNPC(flTraceFreePos,
-							flBossMins,
-							flBossMaxs,
-							iBoss))
-						{
-							// Yes we can! Break the loop and teleport to this pos.
-							bSlenderTeleportedOnStep = true;
-							TeleportEntity(iBoss, flTraceFreePos, NULL_VECTOR, NULL_VECTOR);
-							break;
-						}
-					}
-				}
-			}
-			*/
-		}
-	}
-	
-	// Apply acceleration vectors.
-	new Float:flMoveVelocity[3];
-	new Float:flFrameTime = GetTickInterval();
-	decl Float:flAcceleration[3];
-	SubtractVectors(flDesiredVelocity, flMyVelocity, flAcceleration);
-	NormalizeVector(flAcceleration, flAcceleration);
-	ScaleVector(flAcceleration, g_flSlenderAcceleration[iBossIndex] * flFrameTime);
-	
-	AddVectors(flMyVelocity, flAcceleration, flMoveVelocity);
-	
-	new Float:flSlenderJumpSpeed = g_flSlenderJumpSpeed[iBossIndex];
-	new bool:bSlenderShouldJump = false;
-	
-	decl Float:angJumpReach[3]; 
-	
-	// Check if we need to jump over a wall or something.
-	if (!bSlenderShouldJump && bSlenderOnGround && !bSlenderTeleportedOnStep && flSlenderJumpSpeed > 0.0 && GetVectorLength(flDesiredVelocity) > 0.0 &&
-		GetGameTime() >= g_flSlenderNextJump[iBossIndex])
-	{
-		new Float:flZDiff = (flGoalPosition[2] - flMyPos[2]);
-		
-		if (flZDiff > flSlenderStepSize)
-		{
-			// Our path has a jump thingy to it. Calculate the jump height needed to reach it and how far away we should start
-			// checking on when to jump.
-			
-			decl Float:vecDir[3], Float:vecDesiredDir[3];
-			GetVectorAngles(flMyVelocity, vecDir);
-			SubtractVectors(flGoalPosition, flMyPos, vecDesiredDir);
-			GetVectorAngles(vecDesiredDir, vecDesiredDir);
-			
-			if ((FloatAbs(AngleDiff(vecDir[0], vecDesiredDir[0])) + FloatAbs(AngleDiff(vecDir[1], vecDesiredDir[1]))) >= 45.0)
-			{
-				// Assuming we are actually capable of making the jump, find out WHEN we have to jump,
-				// based on 2D distance between our position and the target point, and our current horizontal 
-				// velocity.
-				
-				decl Float:vecMyPos2D[3], Float:vecGoalPos2D[3];
-				vecMyPos2D[0] = flMyPos[0];
-				vecMyPos2D[1] = flMyPos[1];
-				vecMyPos2D[2] = 0.0;
-				vecGoalPos2D[0] = flGoalPosition[0];
-				vecGoalPos2D[1] = flGoalPosition[1];
-				vecGoalPos2D[2] = 0.0;
-				
-				new Float:fl2DDist = GetVectorDistance(vecMyPos2D, vecGoalPos2D);
-				
-				new Float:flNotImaginary = Pow(flSlenderJumpSpeed, 4.0) - (g_flGravity * (g_flGravity * Pow(fl2DDist, 2.0)) + (2.0 * flZDiff * Pow(flSlenderJumpSpeed, 2.0)));
-				if (flNotImaginary >= 0.0)
-				{
-					// We can reach it.
-					new Float:flNotInfinite = g_flGravity * fl2DDist;
-					if (flNotInfinite > 0.0)
-					{
-						SubtractVectors(vecGoalPos2D, vecMyPos2D, angJumpReach);
-						GetVectorAngles(angJumpReach, angJumpReach);
-						angJumpReach[0] = -RadToDeg(ArcTangent((Pow(flSlenderJumpSpeed, 2.0) + SquareRoot(flNotImaginary)) / flNotInfinite));
-						bSlenderShouldJump = true;
-					}
-				}
-			}
-		}
-	}
-	
-	if (bSlenderOnGround && bSlenderShouldJump)
-	{
-		g_flSlenderNextJump[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "jump_cooldown", 2.0);
-		
-		decl Float:vecJump[3];
-		GetAngleVectors(angJumpReach, vecJump, NULL_VECTOR, NULL_VECTOR);
-		NormalizeVector(vecJump, vecJump);
-		ScaleVector(vecJump, flSlenderJumpSpeed);
-		AddVectors(flMoveVelocity, vecJump, flMoveVelocity);
-	}
-	else 
-	{
-		// We are in no position to defy gravity.
-		flMoveVelocity[2] = flMyVelocity[2];
-	}
-	
-	decl Float:flMoveAng[3];
-	new bool:bChangeAngles = false;
-	
-	// Process angles.
-	if (iState != STATE_ATTACK && iState != STATE_STUN)
-	{
-		if (NPCHasAttribute(iBossIndex, "always look at target"))
-		{
-			new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
-			
-			if (iTarget && iTarget != INVALID_ENT_REFERENCE)
-			{
-				decl Float:flTargetPos[3];
-				GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flTargetPos);
-				SubtractVectors(flTargetPos, flMyPos, flMoveAng);
-				GetVectorAngles(flMoveAng, flMoveAng);
-			}
-			else
-			{
-				SubtractVectors(flGoalPosition, flMyPos, flMoveAng);
-				GetVectorAngles(flMoveAng, flMoveAng);
-			}
-		}
-		else
-		{
-			SubtractVectors(flGoalPosition, flMyPos, flMoveAng);
-			GetVectorAngles(flMoveAng, flMoveAng);
-		}
-		
-		new Float:flTurnRate = NPCGetTurnRate(iBossIndex);
-		if (iState == STATE_CHASE) flTurnRate *= 2.0;
-		
-		flMoveAng[0] = 0.0;
-		flMoveAng[2] = 0.0;
-		flMoveAng[1] = ApproachAngle(flMoveAng[1], flMyEyeAng[1], flTurnRate * flFrameTime);
-		
-		bChangeAngles = true;
-	}
-	
-	TeleportEntity(iBoss, NULL_VECTOR, bChangeAngles ? flMoveAng : NULL_VECTOR, flMoveVelocity);
-}
-
-// Shortest-path cost function for NavMesh_BuildPath.
-public SlenderChaseBossShortestPathCost(iAreaIndex, iFromAreaIndex, iLadderIndex, any:iStepSize)
-{
-	if (iFromAreaIndex == -1)
-	{
-		return 0;
-	}
-	else
-	{
-		new iDist;
-		decl Float:flAreaCenter[3], Float:flFromAreaCenter[3];
-		NavMeshArea_GetCenter(iAreaIndex, flAreaCenter);
-		NavMeshArea_GetCenter(iFromAreaIndex, flFromAreaCenter);
-		
-		if (iLadderIndex != -1)
-		{
-			iDist = RoundFloat(NavMeshLadder_GetLength(iLadderIndex));
-		}
-		else
-		{
-			iDist = RoundFloat(GetVectorDistance(flAreaCenter, flFromAreaCenter));
-		}
-		
-		new iCost = iDist + NavMeshArea_GetCostSoFar(iFromAreaIndex);
-		
-		new iAreaFlags = NavMeshArea_GetFlags(iAreaIndex);
-		if (iAreaFlags & NAV_MESH_CROUCH) iCost += 20;
-		if (iAreaFlags & NAV_MESH_JUMP) iCost += (5 * iDist);
-		
-		if ((flAreaCenter[2] - flFromAreaCenter[2]) > iStepSize) iCost += iStepSize;
-		
-		return iCost;
-	}
-}
-
-public Action:Timer_SlenderChaseBossAttack(Handle:timer, any:entref)
-{
-	if (!g_bEnabled) return;
-
-	new slender = EntRefToEntIndex(entref);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return;
-	
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return;
-	
-	if (timer != g_hSlenderAttackTimer[iBossIndex]) return;
-	
-	if (NPCGetFlags(iBossIndex) & SFF_FAKE)
-	{
-		SlenderMarkAsFake(iBossIndex);
-		return;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new bool:bAttackEliminated = bool:(NPCGetFlags(iBossIndex) & SFF_ATTACKWAITERS);
-	
-	new Float:flDamage = NPCChaserGetAttackDamage(iBossIndex, 0);
-	new Float:flDamageVsProps = NPCChaserGetAttackDamageVsProps(iBossIndex, 0);
-	new iDamageType = NPCChaserGetAttackDamageType(iBossIndex, 0);
-	
-	// Damage all players within range.
-	decl Float:flMyEyePos[3], Float:flMyEyeAng[3];
-	NPCGetEyePosition(iBossIndex, flMyEyePos);
-	GetEntPropVector(slender, Prop_Data, "m_angAbsRotation", flMyEyeAng);
-	AddVectors(g_flSlenderEyePosOffset[iBossIndex], flMyEyeAng, flMyEyeAng);
-	for (new i = 0; i < 3; i++) flMyEyeAng[i] = AngleNormalize(flMyEyeAng[i]);
-	
-	decl Float:flViewPunch[3];
-	GetProfileVector(sProfile, "attack_punchvel", flViewPunch);
-	
-	decl Float:flTargetDist;
-	decl Handle:hTrace;
-	
-	new Float:flAttackRange = NPCChaserGetAttackRange(iBossIndex, 0);
-	new Float:flAttackFOV = NPCChaserGetAttackSpread(iBossIndex, 0);
-	new Float:flAttackDamageForce = NPCChaserGetAttackDamageForce(iBossIndex, 0);
-	
-	new bool:bHit = false;
-	
-	{
-		new prop = -1;
-		while ((prop = FindEntityByClassname(prop, "prop_physics")) != -1)
-		{
-			if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
-			{
-				bHit = true;
-				SDKHooks_TakeDamage(prop, slender, slender, flDamageVsProps, iDamageType, _, _, flMyEyePos);
-			}
-		}
-		
-		prop = -1;
-		while ((prop = FindEntityByClassname(prop, "prop_dynamic")) != -1)
-		{
-			if (GetEntProp(prop, Prop_Data, "m_iHealth") > 0)
-			{
-				if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
-				{
-					bHit = true;
-					SDKHooks_TakeDamage(prop, slender, slender, flDamageVsProps, iDamageType, _, _, flMyEyePos);
-				}
-			}
-		}
-	}
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientInGhostMode(i)) continue;
-		
-		if (!bAttackEliminated && g_bPlayerEliminated[i]) continue;
-		
-		decl Float:flTargetPos[3];
-		GetClientEyePosition(i, flTargetPos);
-		
-		hTrace = TR_TraceRayFilterEx(flMyEyePos,
-			flTargetPos,
-			MASK_NPCSOLID,
-			RayType_EndPoint,
-			TraceRayDontHitEntity,
-			slender);
-		
-		new bool:bTraceDidHit = TR_DidHit(hTrace);
-		new iTraceHitEntity = TR_GetEntityIndex(hTrace);
-		CloseHandle(hTrace);
-		
-		if (bTraceDidHit && iTraceHitEntity != i)
-		{
-			decl Float:flTargetMins[3], Float:flTargetMaxs[3];
-			GetEntPropVector(i, Prop_Send, "m_vecMins", flTargetMins);
-			GetEntPropVector(i, Prop_Send, "m_vecMaxs", flTargetMaxs);
-			GetClientAbsOrigin(i, flTargetPos);
-			for (new i2 = 0; i2 < 3; i2++) flTargetPos[i2] += ((flTargetMins[i2] + flTargetMaxs[i2]) / 2.0);
-			
-			hTrace = TR_TraceRayFilterEx(flMyEyePos,
-				flTargetPos,
-				MASK_NPCSOLID,
-				RayType_EndPoint,
-				TraceRayDontHitEntity,
-				slender);
-				
-			bTraceDidHit = TR_DidHit(hTrace);
-			iTraceHitEntity = TR_GetEntityIndex(hTrace);
-			CloseHandle(hTrace);
-		}
-		
-		if (!bTraceDidHit || iTraceHitEntity == i)
-		{
-			flTargetDist = GetVectorDistance(flTargetPos, flMyEyePos);
-			
-			if (flTargetDist <= flAttackRange)
-			{
-				decl Float:flDirection[3];
-				SubtractVectors(flTargetPos, flMyEyePos, flDirection);
-				GetVectorAngles(flDirection, flDirection);
-				
-				if (FloatAbs(AngleDiff(flDirection[1], flMyEyeAng[1])) <= flAttackFOV)
-				{
-					bHit = true;
-					GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
-					NormalizeVector(flDirection, flDirection);
-					ScaleVector(flDirection, flAttackDamageForce);
-					
-					Call_StartForward(fOnClientDamagedByBoss);
-					Call_PushCell(i);
-					Call_PushCell(iBossIndex);
-					Call_PushCell(slender);
-					Call_PushFloat(flDamage);
-					Call_PushCell(iDamageType);
-					Call_Finish();
-					
-					SDKHooks_TakeDamage(i, slender, slender, flDamage, iDamageType, _, flDirection, flMyEyePos);
-					ClientViewPunch(i, flViewPunch);
-					
-					if (NPCHasAttribute(iBossIndex, "bleed player on hit"))
-					{
-						new Float:flDuration = NPCGetAttributeValue(iBossIndex, "bleed player on hit");
-						if (flDuration > 0.0)
-						{
-							TF2_MakeBleed(i, slender, flDuration);
-						}
-					}
-					
-					// Add stress
-					new Float:flStressScalar = flDamage / 125.0;
-					if (flStressScalar > 1.0) flStressScalar = 1.0;
-					ClientAddStress(i, 0.33 * flStressScalar);
-				}
-			}
-		}
-	}
-	
-	decl String:sSoundPath[PLATFORM_MAX_PATH];
-	
-	if (bHit)
-	{
-		// Fling it.
-		new phys = CreateEntityByName("env_physexplosion");
-		if (phys != -1)
-		{
-			TeleportEntity(phys, flMyEyePos, NULL_VECTOR, NULL_VECTOR);
-			DispatchKeyValue(phys, "spawnflags", "1");
-			DispatchKeyValueFloat(phys, "radius", flAttackRange);
-			DispatchKeyValueFloat(phys, "magnitude", flAttackDamageForce);
-			DispatchSpawn(phys);
-			ActivateEntity(phys);
-			AcceptEntityInput(phys, "Explode");
-			AcceptEntityInput(phys, "Kill");
-		}
-		
-		GetRandomStringFromProfile(sProfile, "sound_hitenemy", sSoundPath, sizeof(sSoundPath));
-		if (sSoundPath[0]) EmitSoundToAll(sSoundPath, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-	}
-	else
-	{
-		GetRandomStringFromProfile(sProfile, "sound_missenemy", sSoundPath, sizeof(sSoundPath));
-		if (sSoundPath[0]) EmitSoundToAll(sSoundPath, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-	}
-	
-	g_hSlenderAttackTimer[iBossIndex] = CreateTimer(GetProfileFloat(sProfile, "attack_endafter"), Timer_SlenderChaseBossAttackEnd, entref, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-static NPCAttackValidateTarget(iBossIndex, iTarget, Float:flAttackRange, Float:flAttackFOV)
-{
-	new iBoss = NPCGetEntIndex(iBossIndex);
-	
-	decl Float:flMyEyePos[3], Float:flMyEyeAng[3];
-	NPCGetEyePosition(iBossIndex, flMyEyePos);
-	GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
-	AddVectors(g_flSlenderEyeAngOffset[iBossIndex], flMyEyeAng, flMyEyeAng);
-	for (new i = 0; i < 3; i++) flMyEyeAng[i] = AngleNormalize(flMyEyeAng[i]);
-	
-	decl Float:flTargetPos[3], Float:flTargetMins[3], Float:flTargetMaxs[3];
-	GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flTargetPos);
-	GetEntPropVector(iTarget, Prop_Send, "m_vecMins", flTargetMins);
-	GetEntPropVector(iTarget, Prop_Send, "m_vecMaxs", flTargetMaxs);
-	
-	for (new i = 0; i < 3; i++)
-	{
-		flTargetPos[i] += (flTargetMins[i] + flTargetMaxs[i]) / 2.0;
-	}
-	
-	new Float:flTargetDist = GetVectorDistance(flTargetPos, flMyEyePos);
-	if (flTargetDist <= flAttackRange)
-	{
-		decl Float:flDirection[3];
-		SubtractVectors(g_flSlenderGoalPos[iBossIndex], flMyEyePos, flDirection);
-		GetVectorAngles(flDirection, flDirection);
-		
-		if (FloatAbs(AngleDiff(flDirection[1], flMyEyeAng[1])) <= flAttackFOV / 2.0)
-		{
-			new Handle:hTrace = TR_TraceRayFilterEx(flMyEyePos,
-				flTargetPos,
-				MASK_NPCSOLID,
-				RayType_EndPoint,
-				TraceRayDontHitEntity,
-				iBoss);
-				
-			new bool:bTraceDidHit = TR_DidHit(hTrace);
-			new iTraceHitEntity = TR_GetEntityIndex(hTrace);
-			CloseHandle(hTrace);
-			
-			if (!bTraceDidHit || iTraceHitEntity == iTarget)
-			{
-				return true;
-			}
-		}
-	}
-	
-	return false;
-}
-
-public Action:Timer_SlenderChaseBossAttackEnd(Handle:timer, any:entref)
-{
-	if (!g_bEnabled) return;
-
-	new slender = EntRefToEntIndex(entref);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return;
-	
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return;
-	
-	if (timer != g_hSlenderAttackTimer[iBossIndex]) return;
-	
-	g_bSlenderAttacking[iBossIndex] = false;
-	g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
+#if defined _sf2_npc_chaser_included
+ #endinput
+#endif
+#define _sf2_npc_chaser_included
+
+static Float:g_flNPCStepSize[MAX_BOSSES];
+
+static Float:g_flNPCWalkSpeed[MAX_BOSSES][Difficulty_Max];
+static Float:g_flNPCAirSpeed[MAX_BOSSES][Difficulty_Max];
+
+static Float:g_flNPCMaxWalkSpeed[MAX_BOSSES][Difficulty_Max];
+static Float:g_flNPCMaxAirSpeed[MAX_BOSSES][Difficulty_Max];
+
+static Float:g_flNPCWakeRadius[MAX_BOSSES];
+
+static bool:g_bNPCStunEnabled[MAX_BOSSES];
+static Float:g_flNPCStunDuration[MAX_BOSSES];
+static bool:g_bNPCStunFlashlightEnabled[MAX_BOSSES];
+static Float:g_flNPCStunFlashlightDamage[MAX_BOSSES];
+static Float:g_flNPCStunInitialHealth[MAX_BOSSES];
+static Float:g_flNPCStunHealth[MAX_BOSSES];
+
+static g_iNPCState[MAX_BOSSES] = { -1, ... };
+static g_iNPCMovementActivity[MAX_BOSSES] = { -1, ... };
+
+enum SF2NPCChaser_BaseAttackStructure
+{
+	SF2NPCChaser_BaseAttackType,
+	Float:SF2NPCChaser_BaseAttackDamage,
+	Float:SF2NPCChaser_BaseAttackDamageVsProps,
+	Float:SF2NPCChaser_BaseAttackDamageForce,
+	SF2NPCChaser_BaseAttackDamageType,
+	Float:SF2NPCChaser_BaseAttackDamageDelay,
+	Float:SF2NPCChaser_BaseAttackRange,
+	Float:SF2NPCChaser_BaseAttackDuration,
+	Float:SF2NPCChaser_BaseAttackSpread,
+	Float:SF2NPCChaser_BaseAttackBeginRange,
+	Float:SF2NPCChaser_BaseAttackBeginFOV,
+	Float:SF2NPCChaser_BaseAttackCooldown,
+	Float:SF2NPCChaser_BaseAttackNextAttackTime
+};
+
+static g_NPCBaseAttacks[MAX_BOSSES][SF2_CHASER_BOSS_MAX_ATTACKS][SF2NPCChaser_BaseAttackStructure];
+
+#if defined METHODMAPS
+
+const SF2NPC_Chaser SF2_INVALID_NPC_CHASER = SF2NPC_Chaser:-1;
+
+
+methodmap SF2NPC_Chaser < SF2NPC_BaseNPC
+{
+	property float WakeRadius
+	{
+		public get() { return NPCChaserGetWakeRadius(this.Index); }
+	}
+	
+	property float StepSize
+	{
+		public get() { return NPCChaserGetStepSize(this.Index); }
+	}
+	
+	property bool StunEnabled
+	{
+		public get() { return NPCChaserIsStunEnabled(this.Index); }
+	}
+	
+	property bool StunByFlashlightEnabled
+	{
+		public get() { return NPCChaserIsStunByFlashlightEnabled(this.Index); }
+	}
+	
+	property float StunFlashlightDamage
+	{
+		public get() { return NPCChaserGetStunFlashlightDamage(this.Index); }
+	}
+	
+	property float StunDuration
+	{
+		public get() { return NPCChaserGetStunDuration(this.Index); }
+	}
+	
+	property float StunHealth
+	{
+		public get() { return NPCChaserGetStunHealth(this.Index); }
+		public set(float amount) { NPCChaserSetStunHealth(this.Index, amount); }
+	}
+	
+	property float StunInitialHealth
+	{
+		public get() { return NPCChaserGetStunInitialHealth(this.Index); }
+	}
+	
+	property int State
+	{
+		public get() { return NPCChaserGetState(this.Index); }
+		public set(int state) { NPCChaserSetState(this.Index, state); }
+	}
+	
+	property int MovementActivity
+	{
+		public get() { return NPCChaserGetMovementActivity(this.Index); }
+		public set(int movementActivity) { NPCChaserSetMovementActivity(this.Index, movementActivity); }
+	}
+	
+	public SF2NPC_Chaser(int index)
+	{
+		return SF2NPC_Chaser:SF2NPC_BaseNPC(index);
+	}
+	
+	public float GetWalkSpeed(int difficulty)
+	{
+		return NPCChaserGetWalkSpeed(this.Index, difficulty);
+	}
+	
+	public void SetWalkSpeed(int difficulty, float amount)
+	{
+		NPCChaserSetWalkSpeed(this.Index, difficulty, amount);
+	}
+	
+	public float GetAirSpeed(int difficulty)
+	{
+		return NPCChaserGetAirSpeed(this.Index, difficulty);
+	}
+	
+	public void SetAirSpeed(int difficulty, float amount)
+	{
+		NPCChaserSetAirSpeed(this.Index, difficulty, amount);
+	}
+	
+	public float GetMaxWalkSpeed(int difficulty)
+	{
+		return NPCChaserGetMaxWalkSpeed(this.Index, difficulty);
+	}
+	
+	public void SetMaxWalkSpeed(int difficulty, float amount)
+	{
+		NPCChaserSetMaxWalkSpeed(this.Index, difficulty, amount);
+	}
+	
+	public float GetMaxAirSpeed(int difficulty)
+	{
+		return NPCChaserGetMaxAirSpeed(this.Index, difficulty);
+	}
+	
+	public void SetMaxAirSpeed(int difficulty, float amount)
+	{
+		NPCChaserSetMaxAirSpeed(this.Index, difficulty, amount);
+	}
+	
+	public void AddStunHealth(float amount)
+	{
+		NPCChaserAddStunHealth(this.Index, amount);
+	}
+}
+
+#endif
+
+public NPCChaserInitialize()
+{
+	for (new iNPCIndex = 0; iNPCIndex < MAX_BOSSES; iNPCIndex++)
+	{
+		NPCChaserResetValues(iNPCIndex);
+	}
+}
+
+Float:NPCChaserGetWalkSpeed(iNPCIndex, iDifficulty)
+{
+	return g_flNPCWalkSpeed[iNPCIndex][iDifficulty];
+}
+
+NPCChaserSetWalkSpeed(iNPCIndex, iDifficulty, Float:flAmount)
+{
+	g_flNPCWalkSpeed[iNPCIndex][iDifficulty] = flAmount;
+}
+
+Float:NPCChaserGetAirSpeed(iNPCIndex, iDifficulty)
+{
+	return g_flNPCAirSpeed[iNPCIndex][iDifficulty];
+}
+
+NPCChaserSetAirSpeed(iNPCIndex, iDifficulty, Float:flAmount)
+{
+	g_flNPCAirSpeed[iNPCIndex][iDifficulty] = flAmount;
+}
+
+Float:NPCChaserGetMaxWalkSpeed(iNPCIndex, iDifficulty)
+{
+	return g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty];
+}
+
+NPCChaserSetMaxWalkSpeed(iNPCIndex, iDifficulty, Float:flAmount)
+{
+	g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty] = flAmount;
+}
+
+Float:NPCChaserGetMaxAirSpeed(iNPCIndex, iDifficulty)
+{
+	return g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty];
+}
+
+NPCChaserSetMaxAirSpeed(iNPCIndex, iDifficulty, Float:flAmount)
+{
+	g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty] = flAmount;
+}
+
+Float:NPCChaserGetWakeRadius(iNPCIndex)
+{
+	return g_flNPCWakeRadius[iNPCIndex];
+}
+
+Float:NPCChaserGetStepSize(iNPCIndex)
+{
+	return g_flNPCStepSize[iNPCIndex];
+}
+
+NPCChaserGetAttackType(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackType];
+}
+
+Float:NPCChaserGetAttackDamage(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamage];
+}
+
+Float:NPCChaserGetAttackDamageVsProps(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageVsProps];
+}
+
+Float:NPCChaserGetAttackDamageForce(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageForce];
+}
+
+NPCChaserGetAttackDamageType(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageType];
+}
+
+Float:NPCChaserGetAttackDamageDelay(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDamageDelay];
+}
+
+Float:NPCChaserGetAttackRange(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackRange];
+}
+
+Float:NPCChaserGetAttackDuration(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackDuration];
+}
+
+Float:NPCChaserGetAttackSpread(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackSpread];
+}
+
+Float:NPCChaserGetAttackBeginRange(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackBeginRange];
+}
+
+Float:NPCChaserGetAttackBeginFOV(iNPCIndex, iAttackIndex)
+{
+	return g_NPCBaseAttacks[iNPCIndex][iAttackIndex][SF2NPCChaser_BaseAttackBeginFOV];
+}
+
+bool:NPCChaserIsStunEnabled(iNPCIndex)
+{
+	return g_bNPCStunEnabled[iNPCIndex];
+}
+
+bool:NPCChaserIsStunByFlashlightEnabled(iNPCIndex)
+{
+	return g_bNPCStunFlashlightEnabled[iNPCIndex];
+}
+
+Float:NPCChaserGetStunFlashlightDamage(iNPCIndex)
+{
+	return g_flNPCStunFlashlightDamage[iNPCIndex];
+}
+
+Float:NPCChaserGetStunDuration(iNPCIndex)
+{
+	return g_flNPCStunDuration[iNPCIndex];
+}
+
+Float:NPCChaserGetStunHealth(iNPCIndex)
+{
+	return g_flNPCStunHealth[iNPCIndex];
+}
+
+NPCChaserSetStunHealth(iNPCIndex, Float:flAmount)
+{
+	g_flNPCStunHealth[iNPCIndex] = flAmount;
+}
+
+NPCChaserAddStunHealth(iNPCIndex, Float:flAmount)
+{
+	NPCChaserSetStunHealth(iNPCIndex, NPCChaserGetStunHealth(iNPCIndex) + flAmount);
+}
+
+Float:NPCChaserGetStunInitialHealth(iNPCIndex)
+{
+	return g_flNPCStunInitialHealth[iNPCIndex];
+}
+
+NPCChaserGetState(iNPCIndex)
+{
+	return g_iNPCState[iNPCIndex];
+}
+
+NPCChaserSetState(iNPCIndex, iState)
+{
+	g_iNPCState[iNPCIndex] = iState;
+}
+
+NPCChaserGetMovementActivity(iNPCIndex)
+{
+	return g_iNPCMovementActivity[iNPCIndex];
+}
+
+NPCChaserSetMovementActivity(iNPCIndex, iMovementActivity)
+{
+	g_iNPCMovementActivity[iNPCIndex] = iMovementActivity;
+}
+
+NPCChaserOnSelectProfile(iNPCIndex)
+{
+	new iUniqueProfileIndex = NPCGetUniqueProfileIndex(iNPCIndex);
+
+	g_flNPCWakeRadius[iNPCIndex] = GetChaserProfileWakeRadius(iUniqueProfileIndex);
+	g_flNPCStepSize[iNPCIndex] = GetChaserProfileStepSize(iUniqueProfileIndex);
+	
+	for (new iDifficulty = 0; iDifficulty < Difficulty_Max; iDifficulty++)
+	{
+		g_flNPCWalkSpeed[iNPCIndex][iDifficulty] = GetChaserProfileWalkSpeed(iUniqueProfileIndex, iDifficulty);
+		g_flNPCAirSpeed[iNPCIndex][iDifficulty] = GetChaserProfileAirSpeed(iUniqueProfileIndex, iDifficulty);
+		
+		g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty] = GetChaserProfileMaxWalkSpeed(iUniqueProfileIndex, iDifficulty);
+		g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty] = GetChaserProfileMaxAirSpeed(iUniqueProfileIndex, iDifficulty);
+	}
+	
+	// Get attack data.
+	for (new i = 0; i < GetChaserProfileAttackCount(iUniqueProfileIndex); i++)
+	{
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackType] = GetChaserProfileAttackType(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamage] = GetChaserProfileAttackDamage(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageVsProps] = GetChaserProfileAttackDamageVsProps(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageForce] = GetChaserProfileAttackDamageForce(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageType] = GetChaserProfileAttackDamageType(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageDelay] = GetChaserProfileAttackDamageDelay(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackRange] = GetChaserProfileAttackRange(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDuration] = GetChaserProfileAttackDuration(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackSpread] = GetChaserProfileAttackSpread(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginRange] = GetChaserProfileAttackBeginRange(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginFOV] = GetChaserProfileAttackBeginFOV(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackCooldown] = GetChaserProfileAttackCooldown(iUniqueProfileIndex, i);
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackNextAttackTime] = -1.0;
+	}
+	
+	// Get stun data.
+	g_bNPCStunEnabled[iNPCIndex] = GetChaserProfileStunState(iUniqueProfileIndex);
+	g_flNPCStunDuration[iNPCIndex] = GetChaserProfileStunDuration(iUniqueProfileIndex);
+	g_bNPCStunFlashlightEnabled[iNPCIndex] = GetChaserProfileStunFlashlightState(iUniqueProfileIndex);
+	g_flNPCStunFlashlightDamage[iNPCIndex] = GetChaserProfileStunFlashlightDamage(iUniqueProfileIndex);
+	g_flNPCStunInitialHealth[iNPCIndex] = GetChaserProfileStunHealth(iUniqueProfileIndex);
+	
+	NPCChaserSetStunHealth(iNPCIndex, NPCChaserGetStunInitialHealth(iNPCIndex));
+}
+
+NPCChaserOnRemoveProfile(iNPCIndex)
+{
+	NPCChaserResetValues(iNPCIndex);
+}
+
+/**
+ *	Resets all global variables on a specified NPC. Usually this should be done last upon removing a boss from the game.
+ */
+static NPCChaserResetValues(iNPCIndex)
+{
+	g_flNPCWakeRadius[iNPCIndex] = 0.0;
+	g_flNPCStepSize[iNPCIndex] = 0.0;
+	
+	for (new iDifficulty = 0; iDifficulty < Difficulty_Max; iDifficulty++)
+	{
+		g_flNPCWalkSpeed[iNPCIndex][iDifficulty] = 0.0;
+		g_flNPCAirSpeed[iNPCIndex][iDifficulty] = 0.0;
+		
+		g_flNPCMaxWalkSpeed[iNPCIndex][iDifficulty] = 0.0;
+		g_flNPCMaxAirSpeed[iNPCIndex][iDifficulty] = 0.0;
+	}
+	
+	// Clear attack data.
+	for (new i = 0; i < SF2_CHASER_BOSS_MAX_ATTACKS; i++)
+	{
+		// Base attack data.
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackType] = SF2BossAttackType_Invalid;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamage] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageVsProps] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageForce] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageType] = 0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDamageDelay] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackRange] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackDuration] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackSpread] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginRange] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackBeginFOV] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackCooldown] = 0.0;
+		g_NPCBaseAttacks[iNPCIndex][i][SF2NPCChaser_BaseAttackNextAttackTime] = -1.0;
+	}
+	
+	g_bNPCStunEnabled[iNPCIndex] = false;
+	g_flNPCStunDuration[iNPCIndex] = 0.0;
+	g_bNPCStunFlashlightEnabled[iNPCIndex] = false;
+	g_flNPCStunInitialHealth[iNPCIndex] = 0.0;
+	
+	NPCChaserSetStunHealth(iNPCIndex, 0.0);
+	
+	g_iNPCState[iNPCIndex] = -1;
+	g_iNPCMovementActivity[iNPCIndex] = -1;
+}
+
+//	So this is how the thought process of the bosses should go.
+//	1. Search for enemy; either by sight or by sound.
+//		- Any noticeable sounds should be investigated.
+//		- Too many sounds will put me in alert mode.
+//	2. Alert of an enemy; I saw something or I heard something unusual
+//		- Go to the position where I last heard the sound.
+//		- Keep on searching until I give up. Then drop back to idle mode.
+//	3. Found an enemy! Give chase!
+//		- Keep on chasing until enemy is killed or I give up.
+//			- Keep a path in memory as long as I still have him in my sights.
+//			- If I lose sight or I'm unable to traverse safely, find paths around obstacles and follow memorized path.
+//			- If I reach the end of my path and I still don't see him and I still want to pursue him, keep on going in the direction I'm going.
+
+stock bool:IsTargetValidForSlender(iTarget, bool:bIncludeEliminated=false)
+{
+	if (!iTarget || !IsValidEntity(iTarget)) return false;
+	
+	if (IsValidClient(iTarget))
+	{
+		if (!IsClientInGame(iTarget) || 
+			!IsPlayerAlive(iTarget) || 
+			IsClientInDeathCam(iTarget) || 
+			(!bIncludeEliminated && g_bPlayerEliminated[iTarget]) ||
+			IsClientInGhostMode(iTarget) || 
+			DidClientEscape(iTarget)) return false;
+	}
+	
+	return true;
+}
+
+public Action:Timer_SlenderChaseBossThink(Handle:timer, any:entref)
+{
+	if (!g_bEnabled) return Plugin_Stop;
+
+	new slender = EntRefToEntIndex(entref);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return Plugin_Stop;
+	
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	if (timer != g_hSlenderEntityThink[iBossIndex]) return Plugin_Stop;
+	
+	if (NPCGetFlags(iBossIndex) & SFF_MARKEDASFAKE) return Plugin_Stop;
+	
+	decl Float:flSlenderVelocity[3], Float:flMyPos[3], Float:flMyEyeAng[3];
+	new Float:flBuffer[3];
+	
+	decl String:sSlenderProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sSlenderProfile, sizeof(sSlenderProfile));
+	
+	GetEntPropVector(slender, Prop_Data, "m_vecAbsVelocity", flSlenderVelocity);
+	GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flMyPos);
+	GetEntPropVector(slender, Prop_Data, "m_angAbsRotation", flMyEyeAng);
+	AddVectors(flMyEyeAng, g_flSlenderEyeAngOffset[iBossIndex], flMyEyeAng);
+	for (new i = 0; i < 3; i++) flMyEyeAng[i] = AngleNormalize(flMyEyeAng[i]);
+	
+	new iDifficulty = GetConVarInt(g_cvDifficulty);
+	
+	new Float:flVelocityRatio;
+	new Float:flVelocityRatioWalk;
+	
+	new Float:flOriginalSpeed = NPCGetSpeed(iBossIndex, iDifficulty);
+	new Float:flOriginalWalkSpeed = NPCChaserGetWalkSpeed(iBossIndex, iDifficulty);
+	new Float:flMaxSpeed = NPCGetMaxSpeed(iBossIndex, iDifficulty);
+	new Float:flMaxWalkSpeed = NPCChaserGetMaxWalkSpeed(iBossIndex, iDifficulty);
+	
+	new Float:flSpeed = flOriginalSpeed * NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier;
+	if (flSpeed < flOriginalSpeed) flSpeed = flOriginalSpeed;
+	if (flSpeed > flMaxSpeed) flSpeed = flMaxSpeed;
+	
+	new Float:flWalkSpeed = flOriginalWalkSpeed * NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier;
+	if (flWalkSpeed < flOriginalWalkSpeed) flWalkSpeed = flOriginalWalkSpeed;
+	if (flWalkSpeed > flMaxWalkSpeed) flWalkSpeed = flMaxWalkSpeed;
+	
+	if (PeopleCanSeeSlender(iBossIndex, _, false))
+	{
+		if (NPCHasAttribute(iBossIndex, "reduced speed on look"))
+		{
+			flSpeed *= NPCGetAttributeValue(iBossIndex, "reduced speed on look");
+		}
+		
+		if (NPCHasAttribute(iBossIndex, "reduced walk speed on look"))
+		{
+			flWalkSpeed *= NPCGetAttributeValue(iBossIndex, "reduced walk speed on look");
+		}
+	}
+	
+	g_flSlenderCalculatedWalkSpeed[iBossIndex] = flWalkSpeed;
+	g_flSlenderCalculatedSpeed[iBossIndex] = flSpeed;
+	
+	if (flOriginalSpeed <= 0.0) flVelocityRatio = 0.0;
+	else flVelocityRatio = GetVectorLength(flSlenderVelocity) / flOriginalSpeed;
+	
+	if (flOriginalWalkSpeed <= 0.0) flVelocityRatioWalk = 0.0;
+	else flVelocityRatioWalk = GetVectorLength(flSlenderVelocity) / flOriginalWalkSpeed;
+	
+	new Float:flAttackRange = NPCChaserGetAttackRange(iBossIndex, 0);
+	new Float:flAttackFOV = NPCChaserGetAttackSpread(iBossIndex, 0);
+	new Float:flAttackBeginRange = NPCChaserGetAttackBeginRange(iBossIndex, 0);
+	new Float:flAttackBeginFOV = NPCChaserGetAttackBeginFOV(iBossIndex, 0);
+	
+	
+	new iOldState = g_iSlenderState[iBossIndex];
+	new iOldTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
+	
+	new iBestNewTarget = INVALID_ENT_REFERENCE;
+	new Float:flSearchRange = NPCGetSearchRadius(iBossIndex);
+	new Float:flBestNewTargetDist = flSearchRange;
+	new iState = iOldState;
+	
+	new bool:bPlayerInFOV[MAXPLAYERS + 1];
+	new bool:bPlayerNear[MAXPLAYERS + 1];
+	new Float:flPlayerDists[MAXPLAYERS + 1];
+	new bool:bPlayerVisible[MAXPLAYERS + 1];
+	
+	new bool:bAttackEliminated = bool:(NPCGetFlags(iBossIndex) & SFF_ATTACKWAITERS);
+	new bool:bStunEnabled = NPCChaserIsStunEnabled(iBossIndex);
+	
+	decl Float:flSlenderMins[3], Float:flSlenderMaxs[3];
+	GetEntPropVector(slender, Prop_Send, "m_vecMins", flSlenderMins);
+	GetEntPropVector(slender, Prop_Send, "m_vecMaxs", flSlenderMaxs);
+	
+	decl Float:flTraceMins[3], Float:flTraceMaxs[3];
+	flTraceMins[0] = flSlenderMins[0];
+	flTraceMins[1] = flSlenderMins[1];
+	flTraceMins[2] = 0.0;
+	flTraceMaxs[0] = flSlenderMaxs[0];
+	flTraceMaxs[1] = flSlenderMaxs[1];
+	flTraceMaxs[2] = 0.0;
+	
+	// Gather data about the players around me and get the best new target, in case my old target is invalidated.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsTargetValidForSlender(i, bAttackEliminated)) continue;
+		
+		decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
+		NPCGetEyePosition(iBossIndex, flTraceStartPos);
+		GetClientEyePosition(i, flTraceEndPos);
+		
+		new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
+			flTraceEndPos,
+			flTraceMins,
+			flTraceMaxs,
+			MASK_NPCSOLID,
+			TraceRayBossVisibility,
+			slender);
+		
+		new bool:bIsVisible = !TR_DidHit(hTrace);
+		new iTraceHitEntity = TR_GetEntityIndex(hTrace);
+		CloseHandle(hTrace);
+		
+		if (!bIsVisible && iTraceHitEntity == i) bIsVisible = true;
+		
+		bPlayerVisible[i] = bIsVisible;
+		
+		// Near radius check.
+		if (bIsVisible &&
+			GetVectorDistance(flTraceStartPos, flTraceEndPos) <= NPCChaserGetWakeRadius(iBossIndex))
+		{
+			bPlayerNear[i] = true;
+		}
+		
+		// FOV check.
+		SubtractVectors(flTraceEndPos, flTraceStartPos, flBuffer);
+		GetVectorAngles(flBuffer, flBuffer);
+		
+		if (FloatAbs(AngleDiff(flMyEyeAng[1], flBuffer[1])) <= (NPCGetFOV(iBossIndex) * 0.5))
+		{
+			bPlayerInFOV[i] = true;
+		}
+		
+		new Float:flDist;
+		new Float:flPriorityValue = g_iPageMax > 0 ? (float(g_iPlayerPageCount[i]) / float(g_iPageMax)) : 0.0;
+		
+		if (TF2_GetPlayerClass(i) == TFClass_Medic) flPriorityValue += 0.72;
+		
+		flDist = GetVectorDistance(flTraceStartPos, flTraceEndPos);
+		flPlayerDists[i] = flDist;
+		
+		if ((bPlayerNear[i] && iState != STATE_CHASE && iState != STATE_ALERT) || (bIsVisible && bPlayerInFOV[i]))
+		{
+			decl Float:flTargetPos[3];
+			GetClientAbsOrigin(i, flTargetPos);
+			
+			if (flDist <= flSearchRange)
+			{
+				// Subtract distance to increase priority.
+				flDist -= (flDist * flPriorityValue);
+				
+				if (flDist < flBestNewTargetDist)
+				{
+					iBestNewTarget = i;
+					flBestNewTargetDist = flDist;
+					g_iSlenderInterruptConditions[iBossIndex] |= COND_SAWENEMY;
+				}
+				
+				g_flSlenderLastFoundPlayer[iBossIndex][i] = GetGameTime();
+				g_flSlenderLastFoundPlayerPos[iBossIndex][i][0] = flTargetPos[0];
+				g_flSlenderLastFoundPlayerPos[iBossIndex][i][1] = flTargetPos[1];
+				g_flSlenderLastFoundPlayerPos[iBossIndex][i][2] = flTargetPos[2];
+			}
+		}
+	}
+	
+	new bool:bInFlashlight = false;
+	
+	// Check to see if someone is facing at us with flashlight on. Only if I'm facing them too. BLINDNESS!
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsTargetValidForSlender(i, bAttackEliminated)) continue;
+	
+		if (!IsClientUsingFlashlight(i) || !bPlayerInFOV[i]) continue;
+		
+		decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
+		GetClientEyePosition(i, flTraceStartPos);
+		NPCGetEyePosition(iBossIndex, flTraceEndPos);
+		
+		if (GetVectorDistance(flTraceStartPos, flTraceEndPos) <= SF2_FLASHLIGHT_LENGTH)
+		{
+			decl Float:flEyeAng[3], Float:flRequiredAng[3];
+			GetClientEyeAngles(i, flEyeAng);
+			SubtractVectors(flTraceEndPos, flTraceStartPos, flRequiredAng);
+			GetVectorAngles(flRequiredAng, flRequiredAng);
+			
+			if ((FloatAbs(AngleDiff(flEyeAng[0], flRequiredAng[0])) + FloatAbs(AngleDiff(flEyeAng[1], flRequiredAng[1]))) <= 45.0)
+			{
+				new Handle:hTrace = TR_TraceRayFilterEx(flTraceStartPos,
+					flTraceEndPos,
+					MASK_PLAYERSOLID,
+					RayType_EndPoint,
+					TraceRayBossVisibility,
+					slender);
+					
+				new bool:bDidHit = TR_DidHit(hTrace);
+				CloseHandle(hTrace);
+				
+				if (!bDidHit)
+				{
+					bInFlashlight = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	// Damage us if we're in a flashlight.
+	if (bInFlashlight)
+	{
+		if (bStunEnabled)
+		{
+			if (NPCChaserIsStunByFlashlightEnabled(iBossIndex))
+			{
+				if (NPCChaserGetStunHealth(iBossIndex) > 0)
+				{
+					NPCChaserAddStunHealth(iBossIndex, -NPCChaserGetStunFlashlightDamage(iBossIndex));
+				}
+			}
+		}
+	}
+	
+	// Process the target that we should have.
+	new iTarget = iOldTarget;
+	
+	/*
+	if (IsValidEdict(iBestNewTarget))
+	{
+		iTarget = iBestNewTarget;
+		g_iSlenderTarget[iBossIndex] = EntIndexToEntRef(iBestNewTarget);
+	}
+	*/
+	
+	if (iTarget && iTarget != INVALID_ENT_REFERENCE)
+	{
+		if (!IsTargetValidForSlender(iTarget, bAttackEliminated))
+		{
+			// Clear our target; he's not valid anymore.
+			iOldTarget = iTarget;
+			iTarget = INVALID_ENT_REFERENCE;
+			g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+		}
+	}
+	else
+	{
+		// Clear our target; he's not valid anymore.
+		iOldTarget = iTarget;
+		iTarget = INVALID_ENT_REFERENCE;
+		g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+	}
+	
+	new iInterruptConditions = g_iSlenderInterruptConditions[iBossIndex];
+	new bool:bQueueForNewPath = false;
+	
+	// Process which state we should be in.
+	switch (iState)
+	{
+		case STATE_IDLE, STATE_WANDER:
+		{
+			if (iState == STATE_WANDER)
+			{
+				if (GetArraySize(g_hSlenderPath[iBossIndex]) <= 0)
+				{
+					iState = STATE_IDLE;
+				}
+			}
+			else
+			{
+				if (GetGameTime() >= g_flSlenderNextWanderPos[iBossIndex] && GetRandomFloat(0.0, 1.0) <= 0.25)
+				{
+					iState = STATE_WANDER;
+				}
+			}
+			
+			if (iInterruptConditions & COND_SAWENEMY)
+			{
+				// I saw someone over here. Automatically put me into alert mode.
+				iState = STATE_ALERT;
+			}
+			else if (iInterruptConditions & COND_HEARDSUSPICIOUSSOUND)
+			{
+				// Sound counts:
+				// +1 will be added if it hears a footstep.
+				// +2 will be added if the footstep is someone sprinting.
+				// +5 will be added if the sound is from a player's weapon hitting an object.
+				// +10 will be added if a voice command is heard.
+				//
+				// Sound counts will be reset after the boss hears a sound after a certain amount of time.
+				// The purpose of sound counts is to induce boss focusing on sounds suspicious entities are making.
+				
+				new iCount = 0;
+				if (iInterruptConditions & COND_HEARDFOOTSTEP) iCount += 1;
+				if (iInterruptConditions & COND_HEARDFOOTSTEPLOUD) iCount += 2;
+				if (iInterruptConditions & COND_HEARDWEAPON) iCount += 5;
+				if (iInterruptConditions & COND_HEARDVOICE) iCount += 10;
+				
+				new bool:bDiscardMasterPos = bool:(GetGameTime() >= g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex]);
+				
+				if (GetVectorDistance(g_flSlenderTargetSoundTempPos[iBossIndex], g_flSlenderTargetSoundMasterPos[iBossIndex]) <= GetProfileFloat(sSlenderProfile, "search_sound_pos_dist_tolerance", 512.0) ||
+					bDiscardMasterPos)
+				{
+					if (bDiscardMasterPos) g_iSlenderTargetSoundCount[iBossIndex] = 0;
+					
+					g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_sound_pos_discard_time", 2.0);
+					g_flSlenderTargetSoundMasterPos[iBossIndex][0] = g_flSlenderTargetSoundTempPos[iBossIndex][0];
+					g_flSlenderTargetSoundMasterPos[iBossIndex][1] = g_flSlenderTargetSoundTempPos[iBossIndex][1];
+					g_flSlenderTargetSoundMasterPos[iBossIndex][2] = g_flSlenderTargetSoundTempPos[iBossIndex][2];
+					g_iSlenderTargetSoundCount[iBossIndex] += iCount;
+				}
+				
+				if (g_iSlenderTargetSoundCount[iBossIndex] >= GetProfileNum(sSlenderProfile, "search_sound_count_until_alert", 4))
+				{
+					// Someone's making some noise over there! Time to investigate.
+					g_bSlenderInvestigatingSound[iBossIndex] = true; // This is just so that our sound position would be the goal position.
+					iState = STATE_ALERT;
+				}
+			}
+		}
+		case STATE_ALERT:
+		{
+			if (GetArraySize(g_hSlenderPath[iBossIndex]) <= 0)
+			{
+				// Fully navigated through our path.
+				iState = STATE_IDLE;
+			}
+			else if (GetGameTime() >= g_flSlenderTimeUntilIdle[iBossIndex])
+			{
+				iState = STATE_IDLE;
+			}
+			else if (IsValidClient(iBestNewTarget))
+			{
+				if (GetGameTime() >= g_flSlenderTimeUntilChase[iBossIndex] || bPlayerNear[iBestNewTarget])
+				{
+					decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
+					NPCGetEyePosition(iBossIndex, flTraceStartPos);
+					
+					if (IsValidClient(iBestNewTarget)) GetClientEyePosition(iBestNewTarget, flTraceEndPos);
+					else
+					{
+						decl Float:flTargetMins[3], Float:flTargetMaxs[3];
+						GetEntPropVector(iBestNewTarget, Prop_Send, "m_vecMins", flTargetMins);
+						GetEntPropVector(iBestNewTarget, Prop_Send, "m_vecMaxs", flTargetMaxs);
+						GetEntPropVector(iBestNewTarget, Prop_Data, "m_vecAbsOrigin", flTraceEndPos);
+						for (new i = 0; i < 3; i++) flTraceEndPos[i] += ((flTargetMins[i] + flTargetMaxs[i]) / 2.0);
+					}
+					
+					new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
+						flTraceEndPos,
+						flTraceMins,
+						flTraceMaxs,
+						MASK_NPCSOLID,
+						TraceRayBossVisibility,
+						slender);
+						
+					new bool:bIsVisible = !TR_DidHit(hTrace);
+					new iTraceHitEntity = TR_GetEntityIndex(hTrace);
+					CloseHandle(hTrace);
+					
+					if (!bIsVisible && iTraceHitEntity == iBestNewTarget) bIsVisible = true;
+					
+					if ((bPlayerNear[iBestNewTarget] || bPlayerInFOV[iBestNewTarget]) && bPlayerVisible[iBestNewTarget])
+					{
+						// AHAHAHAH! I GOT YOU NOW!
+						iTarget = iBestNewTarget;
+						g_iSlenderTarget[iBossIndex] = EntIndexToEntRef(iBestNewTarget);
+						iState = STATE_CHASE;
+					}
+				}
+			}
+			else
+			{
+				if (iInterruptConditions & COND_SAWENEMY)
+				{
+					if (IsValidClient(iBestNewTarget))
+					{
+						g_flSlenderGoalPos[iBossIndex][0] = g_flSlenderLastFoundPlayerPos[iBossIndex][iBestNewTarget][0];
+						g_flSlenderGoalPos[iBossIndex][1] = g_flSlenderLastFoundPlayerPos[iBossIndex][iBestNewTarget][1];
+						g_flSlenderGoalPos[iBossIndex][2] = g_flSlenderLastFoundPlayerPos[iBossIndex][iBestNewTarget][2];
+						
+						bQueueForNewPath = true;
+					}
+				}
+				else if (iInterruptConditions & COND_HEARDSUSPICIOUSSOUND)
+				{
+					new bool:bDiscardMasterPos = bool:(GetGameTime() >= g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex]);
+					
+					if (GetVectorDistance(g_flSlenderTargetSoundTempPos[iBossIndex], g_flSlenderTargetSoundMasterPos[iBossIndex]) <= GetProfileFloat(sSlenderProfile, "search_sound_pos_dist_tolerance", 512.0) ||
+						bDiscardMasterPos)
+					{
+						g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_sound_pos_discard_time", 2.0);
+						g_flSlenderTargetSoundMasterPos[iBossIndex][0] = g_flSlenderTargetSoundTempPos[iBossIndex][0];
+						g_flSlenderTargetSoundMasterPos[iBossIndex][1] = g_flSlenderTargetSoundTempPos[iBossIndex][1];
+						g_flSlenderTargetSoundMasterPos[iBossIndex][2] = g_flSlenderTargetSoundTempPos[iBossIndex][2];
+						
+						// We have to manually set the goal position here because the goal position will not be changed due to no change in state.
+						g_flSlenderGoalPos[iBossIndex][0] = g_flSlenderTargetSoundMasterPos[iBossIndex][0];
+						g_flSlenderGoalPos[iBossIndex][1] = g_flSlenderTargetSoundMasterPos[iBossIndex][1];
+						g_flSlenderGoalPos[iBossIndex][2] = g_flSlenderTargetSoundMasterPos[iBossIndex][2];
+						
+						g_bSlenderInvestigatingSound[iBossIndex] = true;
+						
+						bQueueForNewPath = true;
+					}
+				}
+				
+				new bool:bBlockingProp = false;
+				
+				if (NPCGetFlags(iBossIndex) & SFF_ATTACKPROPS)
+				{
+					new prop = -1;
+					while ((prop = FindEntityByClassname(prop, "prop_physics")) != -1)
+					{
+						if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
+						{
+							bBlockingProp = true;
+							break;
+						}
+					}
+					
+					if (!bBlockingProp)
+					{
+						prop = -1;
+						while ((prop = FindEntityByClassname(prop, "prop_dynamic")) != -1)
+						{
+							if (GetEntProp(prop, Prop_Data, "m_iHealth") > 0)
+							{
+								if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
+								{
+									bBlockingProp = true;
+									break;
+								}
+							}
+						}
+					}
+				}
+				
+				if (bBlockingProp)
+				{
+					iState = STATE_ATTACK;
+				}
+			}
+		}
+		case STATE_CHASE, STATE_ATTACK, STATE_STUN:
+		{
+			if (iState == STATE_CHASE)
+			{
+				if (IsValidEdict(iTarget))
+				{
+					decl Float:flTraceStartPos[3], Float:flTraceEndPos[3];
+					NPCGetEyePosition(iBossIndex, flTraceStartPos);
+					
+					if (IsValidClient(iTarget))
+					{
+						GetClientEyePosition(iTarget, flTraceEndPos);
+					}
+					else
+					{
+						decl Float:flTargetMins[3], Float:flTargetMaxs[3];
+						GetEntPropVector(iTarget, Prop_Send, "m_vecMins", flTargetMins);
+						GetEntPropVector(iTarget, Prop_Send, "m_vecMaxs", flTargetMaxs);
+						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flTraceEndPos);
+						for (new i = 0; i < 3; i++) flTraceEndPos[i] += ((flTargetMins[i] + flTargetMaxs[i]) / 2.0);
+					}
+					
+					new bool:bIsDeathPosVisible = false;
+					
+					if (g_bSlenderChaseDeathPosition[iBossIndex])
+					{
+						new Handle:hTrace = TR_TraceRayFilterEx(flTraceStartPos,
+							g_flSlenderChaseDeathPosition[iBossIndex],
+							MASK_NPCSOLID,
+							RayType_EndPoint,
+							TraceRayBossVisibility,
+							slender);
+						bIsDeathPosVisible = !TR_DidHit(hTrace);
+						CloseHandle(hTrace);
+					}
+					
+					if (!bPlayerVisible[iTarget])
+					{
+						if (GetArraySize(g_hSlenderPath[iBossIndex]) == 0)
+						{
+							iState = STATE_IDLE;
+						}
+						else if (GetGameTime() >= g_flSlenderTimeUntilAlert[iBossIndex])
+						{
+							iState = STATE_ALERT;
+						}
+						else if (bIsDeathPosVisible)
+						{
+							iState = STATE_IDLE;
+						}
+						else if (iInterruptConditions & COND_CHASETARGETINVALIDATED)
+						{
+							if (!g_bSlenderChaseDeathPosition[iBossIndex])
+							{
+								g_bSlenderChaseDeathPosition[iBossIndex] = true;
+							}
+						}
+					}
+					else
+					{
+						g_bSlenderChaseDeathPosition[iBossIndex] = false;	// We're not chasing a dead player after all! Reset.
+					
+						decl Float:flAttackDirection[3];
+						GetClientAbsOrigin(iTarget, g_flSlenderGoalPos[iBossIndex]);
+						SubtractVectors(g_flSlenderGoalPos[iBossIndex], flMyPos, flAttackDirection);
+						GetVectorAngles(flAttackDirection, flAttackDirection);
+						
+						if (GetVectorDistance(g_flSlenderGoalPos[iBossIndex], flMyPos) <= flAttackBeginRange &&
+							(FloatAbs(AngleDiff(flAttackDirection[0], flMyEyeAng[0])) + FloatAbs(AngleDiff(flAttackDirection[1], flMyEyeAng[1]))) <= flAttackBeginFOV / 2.0)
+						{
+							// ENOUGH TALK! HAVE AT YOU!
+							iState = STATE_ATTACK;
+						}
+						else
+						{
+							new bool:bBlockingProp = false;
+							
+							if (NPCGetFlags(iBossIndex) & SFF_ATTACKPROPS)
+							{
+								new prop = -1;
+								while ((prop = FindEntityByClassname(prop, "prop_physics")) != -1)
+								{
+									if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
+									{
+										bBlockingProp = true;
+										break;
+									}
+								}
+								
+								if (!bBlockingProp)
+								{
+									prop = -1;
+									while ((prop = FindEntityByClassname(prop, "prop_dynamic")) != -1)
+									{
+										if (GetEntProp(prop, Prop_Data, "m_iHealth") > 0)
+										{
+											if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
+											{
+												bBlockingProp = true;
+												break;
+											}
+										}
+									}
+								}
+							}
+							
+							if (bBlockingProp)
+							{
+								iState = STATE_ATTACK;
+							}
+							else if (GetGameTime() >= g_flSlenderNextPathTime[iBossIndex])
+							{
+								g_flSlenderNextPathTime[iBossIndex] = GetGameTime() + 0.33;
+								bQueueForNewPath = true;
+							}
+						}
+					}
+				}
+				else
+				{
+					// Even if the target isn't valid anymore, see if I still have some ways to go on my current path,
+					// because I shouldn't actually know that the target has died until I see it.
+					if (GetArraySize(g_hSlenderPath[iBossIndex]) == 0)
+					{
+						iState = STATE_IDLE;
+					}
+				}
+			}
+			else if (iState == STATE_ATTACK)
+			{
+				if (!g_bSlenderAttacking[iBossIndex])
+				{
+					if (IsValidClient(iTarget))
+					{
+						g_bSlenderChaseDeathPosition[iBossIndex] = false;
+						
+						// Chase him again!
+						iState = STATE_CHASE;
+					}
+					else
+					{
+						// Target isn't valid anymore. We killed him, Mac!
+						iState = STATE_ALERT;
+					}
+				}
+			}
+			else if (iState == STATE_STUN)
+			{
+				if (GetGameTime() >= g_flSlenderTimeUntilRecover[iBossIndex])
+				{
+					NPCChaserSetStunHealth(iBossIndex, NPCChaserGetStunInitialHealth(iBossIndex));
+					
+					if (IsValidClient(iTarget))
+					{
+						// Chase him again!
+						iState = STATE_CHASE;
+					}
+					else
+					{
+						// WHAT DA FUUUUUUUUUUUQ. TARGET ISN'T VALID. AUSDHASUIHD
+						iState = STATE_ALERT;
+					}
+				}
+			}
+		}
+	}
+	
+	new bool:bDoChasePersistencyInit = false;
+	
+	if (iState != STATE_STUN)
+	{
+		if (bStunEnabled)
+		{
+			if (NPCChaserGetStunHealth(iBossIndex) <= 0)
+			{
+				if (iState != STATE_CHASE && iState != STATE_ATTACK)
+				{
+					// Sometimes players can stun the boss while it's not in chase mode. If that happens, we
+					// need to set the persistency value to the chase initial value.
+					bDoChasePersistencyInit = true;
+				}
+				
+				iState = STATE_STUN;
+			}
+		}
+	}
+	
+	// Finally, set our new state.
+	g_iSlenderState[iBossIndex] = iState;
+	
+	decl String:sAnimation[64];
+	new iModel = EntRefToEntIndex(g_iSlenderModel[iBossIndex]);
+	
+	new Float:flPlaybackRateWalk = g_flSlenderWalkAnimationPlaybackRate[iBossIndex];
+	new Float:flPlaybackRateRun = g_flSlenderRunAnimationPlaybackRate[iBossIndex];
+	new Float:flPlaybackRateIdle = g_flSlenderIdleAnimationPlaybackRate[iBossIndex];
+	
+	if (iOldState != iState)
+	{
+		switch (iState)
+		{
+			case STATE_IDLE, STATE_WANDER:
+			{
+				g_iSlenderTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+				g_flSlenderTimeUntilIdle[iBossIndex] = -1.0;
+				g_flSlenderTimeUntilAlert[iBossIndex] = -1.0;
+				g_flSlenderTimeUntilChase[iBossIndex] = -1.0;
+				g_bSlenderChaseDeathPosition[iBossIndex] = false;
+				
+				if (iOldState != STATE_IDLE && iOldState != STATE_WANDER)
+				{
+					g_iSlenderTargetSoundCount[iBossIndex] = 0;
+					g_bSlenderInvestigatingSound[iBossIndex] = false;
+					g_flSlenderTargetSoundDiscardMasterPosTime[iBossIndex] = -1.0;
+					
+					g_flSlenderTimeUntilKill[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "idle_lifetime", 10.0);
+				}
+				
+				if (iState == STATE_WANDER)
+				{
+					// Force new wander position.
+					g_flSlenderNextWanderPos[iBossIndex] = -1.0;
+				}
+				
+				// Animation handling.
+				if (iModel && iModel != INVALID_ENT_REFERENCE)
+				{
+					if (iState == STATE_WANDER && (NPCGetFlags(iBossIndex) & SFF_WANDERMOVE))
+					{
+						if (GetProfileString(sSlenderProfile, "animation_walk", sAnimation, sizeof(sAnimation)))
+						{
+							EntitySetAnimation(iModel, sAnimation, _, flVelocityRatio * flPlaybackRateWalk);
+						}
+					}
+					else
+					{
+						if (GetProfileString(sSlenderProfile, "animation_idle", sAnimation, sizeof(sAnimation)))
+						{
+							EntitySetAnimation(iModel, sAnimation, _, flPlaybackRateIdle);
+						}
+					}
+				}
+			}
+			
+			case STATE_ALERT:
+			{
+				g_bSlenderChaseDeathPosition[iBossIndex] = false;
+				
+				// Set our goal position.
+				if (g_bSlenderInvestigatingSound[iBossIndex])
+				{
+					g_flSlenderGoalPos[iBossIndex][0] = g_flSlenderTargetSoundMasterPos[iBossIndex][0];
+					g_flSlenderGoalPos[iBossIndex][1] = g_flSlenderTargetSoundMasterPos[iBossIndex][1];
+					g_flSlenderGoalPos[iBossIndex][2] = g_flSlenderTargetSoundMasterPos[iBossIndex][2];
+				}
+				
+				g_flSlenderTimeUntilIdle[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_alert_duration", 5.0);
+				g_flSlenderTimeUntilAlert[iBossIndex] = -1.0;
+				g_flSlenderTimeUntilChase[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_alert_gracetime", 0.5);
+				
+				bQueueForNewPath = true;
+				
+				// Animation handling.
+				if (iModel && iModel != INVALID_ENT_REFERENCE)
+				{
+					if (GetProfileString(sSlenderProfile, "animation_walk", sAnimation, sizeof(sAnimation)))
+					{
+						EntitySetAnimation(iModel, sAnimation, _, flVelocityRatio * flPlaybackRateWalk);
+					}
+				}
+			}
+			case STATE_CHASE, STATE_ATTACK, STATE_STUN:
+			{
+				g_bSlenderInvestigatingSound[iBossIndex] = false;
+				g_iSlenderTargetSoundCount[iBossIndex] = 0;
+				
+				if (iOldState != STATE_ATTACK && iOldState != STATE_CHASE && iOldState != STATE_STUN)
+				{
+					g_flSlenderTimeUntilIdle[iBossIndex] = -1.0;
+					g_flSlenderTimeUntilAlert[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration", 10.0);
+					g_flSlenderTimeUntilChase[iBossIndex] = -1.0;
+					
+					new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init", 5.0);
+					if (flPersistencyTime >= 0.0)
+					{
+						g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
+					}
+				}
+				
+				if (iState == STATE_ATTACK)
+				{
+					g_bSlenderAttacking[iBossIndex] = true;
+					g_hSlenderAttackTimer[iBossIndex] = CreateTimer(NPCChaserGetAttackDamageDelay(iBossIndex, 0), Timer_SlenderChaseBossAttack, EntIndexToEntRef(slender), TIMER_FLAG_NO_MAPCHANGE);
+					
+					new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init_attack", -1.0);
+					if (flPersistencyTime >= 0.0)
+					{
+						g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
+					}
+					
+					flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_attack", 2.0);
+					if (flPersistencyTime >= 0.0)
+					{
+						if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
+						g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTime;
+					}
+					
+					SlenderPerformVoice(iBossIndex, "sound_attackenemy");
+				}
+				else if (iState == STATE_STUN)
+				{
+					if (g_bSlenderAttacking[iBossIndex])
+					{
+						// Cancel attacking.
+						g_bSlenderAttacking[iBossIndex] = false;
+						g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
+					}
+					
+					if (!bDoChasePersistencyInit)
+					{
+						new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init_stun", -1.0);
+						if (flPersistencyTime >= 0.0)
+						{
+							g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
+						}
+						
+						flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_stun", 2.0);
+						if (flPersistencyTime >= 0.0)
+						{
+							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
+							g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTime;
+						}
+					}
+					else
+					{
+						new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init", 5.0);
+						if (flPersistencyTime >= 0.0)
+						{
+							g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
+						}
+					}
+					
+					g_flSlenderTimeUntilRecover[iBossIndex] = GetGameTime() + NPCChaserGetStunDuration(iBossIndex);
+					
+					// Sound handling. Ignore time check.
+					SlenderPerformVoice(iBossIndex, "sound_stun");
+				}
+				else
+				{
+					if (iOldState != STATE_ATTACK)
+					{
+						// Sound handling.
+						SlenderPerformVoice(iBossIndex, "sound_chaseenemyinitial");
+					}
+				}
+				
+				// Animation handling.
+				if (iModel && iModel != INVALID_ENT_REFERENCE)
+				{
+					if (iState == STATE_CHASE)
+					{
+						if (GetProfileString(sSlenderProfile, "animation_run", sAnimation, sizeof(sAnimation)))
+						{
+							EntitySetAnimation(iModel, sAnimation, _, flVelocityRatio * flPlaybackRateRun);
+						}
+					}
+					else if (iState == STATE_ATTACK)
+					{
+						if (GetProfileString(sSlenderProfile, "animation_attack", sAnimation, sizeof(sAnimation)))
+						{
+							EntitySetAnimation(iModel, sAnimation, _, GetProfileFloat(sSlenderProfile, "animation_attack_playbackrate", 1.0));
+						}
+					}
+					else if (iState == STATE_STUN)
+					{
+						if (GetProfileString(sSlenderProfile, "animation_stun", sAnimation, sizeof(sAnimation)))
+						{
+							EntitySetAnimation(iModel, sAnimation, _, GetProfileFloat(sSlenderProfile, "animation_stun_playbackrate", 1.0));
+						}
+					}
+				}
+			}
+		}
+		
+		// Call our forward.
+		Call_StartForward(fOnBossChangeState);
+		Call_PushCell(iBossIndex);
+		Call_PushCell(iOldState);
+		Call_PushCell(iState);
+		Call_Finish();
+	}
+	
+	switch (iState)
+	{
+		case STATE_IDLE:
+		{
+			// Animation playback speed handling.
+			if (iModel && iModel != INVALID_ENT_REFERENCE)
+			{
+				SetVariantFloat(flPlaybackRateIdle);
+				AcceptEntityInput(iModel, "SetPlaybackRate");
+			}
+		}
+		case STATE_WANDER, STATE_ALERT, STATE_CHASE, STATE_ATTACK:
+		{
+			// These deal with movement, therefore we need to set our 
+			// destination first. That is, if we don't have one. (nav mesh only)
+			
+			if (iState == STATE_WANDER)
+			{
+				if (GetGameTime() >= g_flSlenderNextWanderPos[iBossIndex])
+				{
+					new Float:flMin = GetProfileFloat(sSlenderProfile, "search_wander_time_min", 4.0);
+					new Float:flMax = GetProfileFloat(sSlenderProfile, "search_wander_time_max", 6.5);
+					g_flSlenderNextWanderPos[iBossIndex] = GetGameTime() + GetRandomFloat(flMin, flMax);
+					
+					if (NPCGetFlags(iBossIndex) & SFF_WANDERMOVE)
+					{
+						// We're allowed to move in wander mode. Get a new wandering position and create a path to follow.
+						// If the position can't be reached, then just get to the closest area that we can get.
+						new Float:flWanderRangeMin = GetProfileFloat(sSlenderProfile, "search_wander_range_min", 400.0);
+						new Float:flWanderRangeMax = GetProfileFloat(sSlenderProfile, "search_wander_range_max", 1024.0);
+						new Float:flWanderRange = GetRandomFloat(flWanderRangeMin, flWanderRangeMax);
+						
+						decl Float:flWanderPos[3];
+						flWanderPos[0] = 0.0;
+						flWanderPos[1] = GetRandomFloat(0.0, 360.0);
+						flWanderPos[2] = 0.0;
+						
+						GetAngleVectors(flWanderPos, flWanderPos, NULL_VECTOR, NULL_VECTOR);
+						NormalizeVector(flWanderPos, flWanderPos);
+						ScaleVector(flWanderPos, flWanderRange);
+						AddVectors(flWanderPos, flMyPos, flWanderPos);
+						
+						g_flSlenderGoalPos[iBossIndex][0] = flWanderPos[0];
+						g_flSlenderGoalPos[iBossIndex][1] = flWanderPos[1];
+						g_flSlenderGoalPos[iBossIndex][2] = flWanderPos[2];
+						
+						bQueueForNewPath = true;
+						g_flSlenderNextPathTime[iBossIndex] = -1.0; // We're not going to wander around too much, so no need for a time constraint.
+					}
+				}
+			}
+			else if (iState == STATE_ALERT)
+			{
+				if (iInterruptConditions & COND_SAWENEMY)
+				{
+					if (IsValidEntity(iBestNewTarget))
+					{
+						if ((bPlayerInFOV[iBestNewTarget] || bPlayerNear[iBestNewTarget]) && bPlayerVisible[iBestNewTarget])
+						{
+							// Constantly update my path if I see him.
+							if (GetGameTime() >= g_flSlenderNextPathTime[iBossIndex])
+							{
+								GetEntPropVector(iBestNewTarget, Prop_Data, "m_vecAbsOrigin", g_flSlenderGoalPos[iBossIndex]);
+								bQueueForNewPath = true;
+								g_flSlenderNextPathTime[iBossIndex] = GetGameTime() + 0.33;
+							}
+						}
+					}
+				}
+			}
+			else if (iState == STATE_CHASE || iState == STATE_ATTACK)
+			{
+				if (IsValidEntity(iBestNewTarget))
+				{
+					iOldTarget = iTarget;
+					iTarget = iBestNewTarget;
+					g_iSlenderTarget[iBossIndex] = EntIndexToEntRef(iBestNewTarget);
+				}
+				
+				if (iTarget != INVALID_ENT_REFERENCE)
+				{
+					if (iOldTarget != iTarget)
+					{
+						// Brand new target! We need a path, and we need to reset our persistency, if needed.
+						new Float:flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_init_newtarget", -1.0);
+						if (flPersistencyTime >= 0.0)
+						{
+							g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + flPersistencyTime;
+						}
+						
+						flPersistencyTime = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_newtarget", 2.0);
+						if (flPersistencyTime >= 0.0)
+						{
+							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
+							g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTime;
+						}
+					
+						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", g_flSlenderGoalPos[iBossIndex]);
+						bQueueForNewPath = true; // Brand new target! We need a new path!
+					}
+					else if ((bPlayerInFOV[iTarget] && bPlayerVisible[iTarget]) || GetGameTime() < g_flSlenderTimeUntilNoPersistence[iBossIndex])
+					{
+						// Constantly update my path if I see him or if I'm still being persistent.
+						if (GetGameTime() >= g_flSlenderNextPathTime[iBossIndex])
+						{
+							GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", g_flSlenderGoalPos[iBossIndex]);
+							bQueueForNewPath = true;
+							g_flSlenderNextPathTime[iBossIndex] = GetGameTime() + 0.33;
+						}
+					}
+				}
+			}
+			
+			if (NavMesh_Exists())
+			{
+				// So by now we should have calculated our master goal position.
+				// Now we use that to create a path.
+				
+				if (bQueueForNewPath)
+				{
+					ClearArray(g_hSlenderPath[iBossIndex]);
+					
+					new iCurrentAreaIndex = NavMesh_GetNearestArea(flMyPos);
+					if (iCurrentAreaIndex != -1)
+					{
+						new iGoalAreaIndex = NavMesh_GetNearestArea(g_flSlenderGoalPos[iBossIndex]);
+						if (iGoalAreaIndex != -1)
+						{
+							decl Float:flCenter[3], Float:flCenterPortal[3], Float:flClosestPoint[3];
+							new iClosestAreaIndex = 0;
+							
+							new bool:bPathSuccess = NavMesh_BuildPath(iCurrentAreaIndex,
+								iGoalAreaIndex,
+								g_flSlenderGoalPos[iBossIndex],
+								SlenderChaseBossShortestPathCost,
+								RoundToFloor(NPCChaserGetStepSize(iBossIndex)),
+								iClosestAreaIndex);
+								
+							new iTempAreaIndex = iClosestAreaIndex;
+							new iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
+							new iNavDirection;
+							new Float:flHalfWidth;
+							
+							if (bPathSuccess)
+							{
+								// Path successful? Insert the goal position into our list.
+								new iIndex = PushArrayCell(g_hSlenderPath[iBossIndex], g_flSlenderGoalPos[iBossIndex][0]);
+								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, g_flSlenderGoalPos[iBossIndex][1], 1);
+								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, g_flSlenderGoalPos[iBossIndex][2], 2);
+							}
+							
+							while (iTempParentAreaIndex != -1)
+							{
+								// Build a path of waypoints along the nav mesh for our AI to follow.
+								// Path order is first come, first served, so when we got our waypoint list,
+								// we have to reverse it so that the starting waypoint would be in front.
+								
+								NavMeshArea_GetCenter(iTempParentAreaIndex, flCenter);
+								iNavDirection = NavMeshArea_ComputeDirection(iTempAreaIndex, flCenter);
+								NavMeshArea_ComputePortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flHalfWidth);
+								NavMeshArea_ComputeClosestPointInPortal(iTempAreaIndex, iTempParentAreaIndex, iNavDirection, flCenterPortal, flClosestPoint);
+								
+								flClosestPoint[2] = NavMeshArea_GetZ(iTempAreaIndex, flClosestPoint);
+								
+								new iIndex = PushArrayCell(g_hSlenderPath[iBossIndex], flClosestPoint[0]);
+								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, flClosestPoint[1], 1);
+								SetArrayCell(g_hSlenderPath[iBossIndex], iIndex, flClosestPoint[2], 2);
+								
+								iTempAreaIndex = iTempParentAreaIndex;
+								iTempParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex);
+							}
+							
+							// Set our goal position to the start node (hopefully there's something in the array).
+							if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
+							{
+								new iPosIndex = GetArraySize(g_hSlenderPath[iBossIndex]) - 1;
+								
+								g_flSlenderGoalPos[iBossIndex][0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 0);
+								g_flSlenderGoalPos[iBossIndex][1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 1);
+								g_flSlenderGoalPos[iBossIndex][2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 2);
+							}
+						}
+						else
+						{
+							PrintToServer("SF2: Failed to create new path for boss %d: destination is not on nav mesh!", iBossIndex);
+						}
+					}
+					else
+					{
+						PrintToServer("SF2: Failed to create new path for boss %d: boss is not on nav mesh!", iBossIndex);
+					}
+				}
+			}
+			else
+			{
+				// The nav mesh doesn't exist? Well, that sucks.
+				ClearArray(g_hSlenderPath[iBossIndex]);
+			}
+			
+			if (iState == STATE_CHASE || iState == STATE_ATTACK)
+			{
+				if (IsValidClient(iTarget))
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayer(iTarget, DEBUG_BOSS_CHASE, 1, "g_flSlenderTimeUntilAlert[%d]: %f\ng_flSlenderTimeUntilNoPersistence[%d]: %f", iBossIndex, g_flSlenderTimeUntilAlert[iBossIndex] - GetGameTime(), iBossIndex, g_flSlenderTimeUntilNoPersistence[iBossIndex] - GetGameTime());
+#endif
+				
+					if (bPlayerInFOV[iTarget] && bPlayerVisible[iTarget])
+					{
+						new Float:flDistRatio = flPlayerDists[iTarget] / NPCGetSearchRadius(iBossIndex);
+						
+						new Float:flChaseDurationTimeAddMin = GetProfileFloat(sSlenderProfile, "search_chase_duration_add_visible_min", 0.025);
+						new Float:flChaseDurationTimeAddMax = GetProfileFloat(sSlenderProfile, "search_chase_duration_add_visible_max", 0.2);
+						
+						new Float:flChaseDurationAdd = flChaseDurationTimeAddMax - ((flChaseDurationTimeAddMax - flChaseDurationTimeAddMin) * flDistRatio);
+						
+						if (flChaseDurationAdd > 0.0)
+						{
+							g_flSlenderTimeUntilAlert[iBossIndex] += flChaseDurationAdd;
+							if (g_flSlenderTimeUntilAlert[iBossIndex] > (GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration")))
+							{
+								g_flSlenderTimeUntilAlert[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration");
+							}
+						}
+						
+						new Float:flPersistencyTimeAddMin = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_visible_min", 0.05);
+						new Float:flPersistencyTimeAddMax = GetProfileFloat(sSlenderProfile, "search_chase_persistency_time_add_visible_max", 0.15);
+						
+						new Float:flPersistencyTimeAdd = flPersistencyTimeAddMax - ((flPersistencyTimeAddMax - flPersistencyTimeAddMin) * flDistRatio);
+						
+						if (flPersistencyTimeAdd > 0.0)
+						{
+							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] < GetGameTime()) g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime();
+						
+							g_flSlenderTimeUntilNoPersistence[iBossIndex] += flPersistencyTimeAdd;
+							if (g_flSlenderTimeUntilNoPersistence[iBossIndex] > (GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration")))
+							{
+								g_flSlenderTimeUntilNoPersistence[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "search_chase_duration");
+							}
+						}
+					}
+				}
+			}
+			
+			// Process through our path waypoints.
+			if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
+			{
+				decl Float:flHitNormal[3];
+				decl Float:flNodePos[3];
+				
+				new Float:flNodeToleranceDist = g_flSlenderPathNodeTolerance[iBossIndex];
+				new bool:bGotNewPoint = false;
+				
+				for (new iNodeIndex = 0, iNodeCount = GetArraySize(g_hSlenderPath[iBossIndex]); iNodeIndex < iNodeCount; iNodeIndex++)
+				{
+					flNodePos[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeIndex, 0);
+					flNodePos[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeIndex, 1);
+					flNodePos[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeIndex, 2);
+					
+					new Handle:hTrace = TR_TraceHullFilterEx(flMyPos,
+						flNodePos, 
+						flSlenderMins, 
+						flSlenderMaxs, 
+						MASK_NPCSOLID, 
+						TraceRayDontHitCharactersOrEntity, 
+						slender);
+						
+					new bool:bDidHit = TR_DidHit(hTrace);
+					TR_GetPlaneNormal(hTrace, flHitNormal);
+					CloseHandle(hTrace);
+					GetVectorAngles(flHitNormal, flHitNormal);
+					for (new i = 0; i < 3; i++) flHitNormal[i] = AngleNormalize(flHitNormal[i]);
+					
+					// First check if we can see the point.
+					if (!bDidHit || ((flHitNormal[0] >= 0.0 && flHitNormal[0] > 45.0) || (flHitNormal[0] < 0.0 && flHitNormal[0] < -45.0)))
+					{
+						new bool:bNearNode = false;
+						
+						// See if we're already near enough.
+						new Float:flDist = GetVectorDistance(flNodePos, flMyPos);
+						if (flDist < flNodeToleranceDist) bNearNode = true;
+						
+						if (!bNearNode)
+						{
+							new bool:bOutside = false;
+						
+							// Then, predict if we're going to pass over the point on the next think.
+							decl Float:flTestPos[3];
+							NormalizeVector(flSlenderVelocity, flTestPos);
+							ScaleVector(flTestPos, GetVectorLength(flSlenderVelocity) * BOSS_THINKRATE);
+							AddVectors(flMyPos, flTestPos, flTestPos);
+							
+							decl Float:flP[3], Float:flS[3];
+							SubtractVectors(flNodePos, flMyPos, flP);
+							SubtractVectors(flTestPos, flMyPos, flS);
+							
+							new Float:flSP = GetVectorDotProduct(flP, flS);
+							if (flSP <= 0.0) bOutside = true;
+							
+							new Float:flPP = GetVectorDotProduct(flS, flS);
+							
+							if (!bOutside)
+							{
+								if (flPP <= flSP) bOutside = true;
+							}
+							
+							if (!bOutside)
+							{
+								decl Float:flD[3];
+								ScaleVector(flS, (flSP / flPP));
+								SubtractVectors(flP, flS, flD);
+							
+								flDist = GetVectorLength(flD);
+								if (flDist < flNodeToleranceDist)
+								{
+									bNearNode = true;
+								}
+							}
+						}
+						
+						if (bNearNode)
+						{
+							// Shave off this node and set our goal position to the next one.
+						
+							ResizeArray(g_hSlenderPath[iBossIndex], iNodeIndex);
+							
+							if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
+							{
+								new iPosIndex = GetArraySize(g_hSlenderPath[iBossIndex]) - 1;
+								
+								g_flSlenderGoalPos[iBossIndex][0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 0);
+								g_flSlenderGoalPos[iBossIndex][1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 1);
+								g_flSlenderGoalPos[iBossIndex][2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 2);
+							}
+							
+							bGotNewPoint = true;
+							break;
+						}
+					}
+				}
+				
+				if (!bGotNewPoint)
+				{
+					// Try to see if we can look ahead.
+					
+					decl Float:flMyEyePos[3];
+					NPCGetEyePosition(iBossIndex, flMyEyePos);
+					
+					new Float:flNodeLookAheadDist = g_flSlenderPathNodeLookAhead[iBossIndex];
+					if (flNodeLookAheadDist > 0.0)
+					{
+						new iNodeCount = GetArraySize(g_hSlenderPath[iBossIndex]);
+						if (iNodeCount)
+						{
+							decl Float:flInitDir[3];
+							flInitDir[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeCount - 1, 0);
+							flInitDir[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeCount - 1, 1);
+							flInitDir[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iNodeCount - 1, 2);
+							
+							SubtractVectors(flInitDir, flMyPos, flInitDir);
+							NormalizeVector(flInitDir, flInitDir);
+							
+							decl Float:flPrevDir[3];
+							flPrevDir[0] = flInitDir[0];
+							flPrevDir[1] = flInitDir[1];
+							flPrevDir[2] = flInitDir[2];
+							
+							NormalizeVector(flPrevDir, flPrevDir);
+							
+							decl Float:flPrevNodePos[3];
+							
+							new iStartPointIndex = iNodeCount - 1;
+							new Float:flRangeSoFar = 0.0;
+							
+							new iLookAheadPointIndex;
+							for (iLookAheadPointIndex = iStartPointIndex; iLookAheadPointIndex >= 0; iLookAheadPointIndex--)
+							{
+								flNodePos[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex, 0);
+								flNodePos[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex, 1);
+								flNodePos[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex, 2);
+							
+								decl Float:flDir[3];
+								if (iLookAheadPointIndex == iStartPointIndex)
+								{
+									SubtractVectors(flNodePos, flMyPos, flDir);
+									NormalizeVector(flDir, flDir);
+								}
+								else
+								{
+									flPrevNodePos[0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1, 0);
+									flPrevNodePos[1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1, 1);
+									flPrevNodePos[2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1, 2);
+								
+									SubtractVectors(flNodePos, flPrevNodePos, flDir);
+									NormalizeVector(flDir, flDir);
+								}
+								
+								if (GetVectorDotProduct(flDir, flInitDir) < 0.0)
+								{
+									break;
+								}
+								
+								if (GetVectorDotProduct(flDir, flPrevDir) < 0.5)
+								{
+									break;
+								}
+								
+								flPrevDir[0] = flDir[0];
+								flPrevDir[1] = flDir[1];
+								flPrevDir[2] = flDir[2];
+								
+								decl Float:flProbe[3];
+								flProbe[0] = flNodePos[0];
+								flProbe[1] = flNodePos[1];
+								flProbe[2] = flNodePos[2] + HalfHumanHeight;
+								
+								if (!IsWalkableTraceLineClear(flMyEyePos, flProbe, WALK_THRU_BREAKABLES))
+								{
+									break;
+								}
+								
+								if (iLookAheadPointIndex == iStartPointIndex)
+								{
+									flRangeSoFar += GetVectorDistance(flMyPos, flNodePos);
+								}
+								else
+								{
+									flRangeSoFar += GetVectorDistance(flNodePos, flPrevNodePos);
+								}
+								
+								if (flRangeSoFar >= flNodeLookAheadDist)
+								{
+									break;
+								}
+							}
+							
+							// Shave off all unnecessary nodes and keep the one that is within
+							// our viewsight.
+							
+							ResizeArray(g_hSlenderPath[iBossIndex], iLookAheadPointIndex + 1);
+							
+							if (GetArraySize(g_hSlenderPath[iBossIndex]) > 0)
+							{
+								new iPosIndex = GetArraySize(g_hSlenderPath[iBossIndex]) - 1;
+								
+								g_flSlenderGoalPos[iBossIndex][0] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 0);
+								g_flSlenderGoalPos[iBossIndex][1] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 1);
+								g_flSlenderGoalPos[iBossIndex][2] = Float:GetArrayCell(g_hSlenderPath[iBossIndex], iPosIndex, 2);
+							}
+							
+							bGotNewPoint = true;
+						}
+					}
+				}
+			}
+			
+			if (iState != STATE_ATTACK && iState != STATE_STUN)
+			{
+				// Animation playback speed handling.
+				if (iModel && iModel != INVALID_ENT_REFERENCE)
+				{
+					if (iState == STATE_WANDER && !(NPCGetFlags(iBossIndex) & SFF_WANDERMOVE))
+					{
+						SetVariantFloat(flPlaybackRateIdle);
+						AcceptEntityInput(iModel, "SetPlaybackRate");
+					}
+					else
+					{
+						SetVariantFloat(iState == STATE_CHASE ? (flVelocityRatio * flPlaybackRateRun) : (flVelocityRatioWalk * flPlaybackRateWalk));
+						AcceptEntityInput(iModel, "SetPlaybackRate");
+					}
+				}
+			}
+		}
+	}
+	
+	// Sound handling.
+	if (GetGameTime() >= g_flSlenderNextVoiceSound[iBossIndex])
+	{
+		if (iState == STATE_IDLE || iState == STATE_WANDER)
+		{
+			SlenderPerformVoice(iBossIndex, "sound_idle");
+		}
+		else if (iState == STATE_ALERT)
+		{
+			SlenderPerformVoice(iBossIndex, "sound_alertofenemy");
+		}
+		else if (iState == STATE_CHASE || iState == STATE_ATTACK)
+		{
+			SlenderPerformVoice(iBossIndex, "sound_chasingenemy");
+		}
+	}
+	
+	// Reset our interrupt conditions.
+	g_iSlenderInterruptConditions[iBossIndex] = 0;
+	
+	return Plugin_Continue;
+}
+
+SlenderChaseBossProcessMovement(iBossIndex)
+{
+	new iBoss = NPCGetEntIndex(iBossIndex);
+	new iState = g_iSlenderState[iBossIndex];
+	
+	// Constantly set the monster_generic's NPC state to idle to prevent
+	// velocity confliction.
+	
+	SetEntProp(iBoss, Prop_Data, "m_NPCState", 0);
+	
+	new Float:flWalkSpeed = g_flSlenderCalculatedWalkSpeed[iBossIndex];
+	new Float:flSpeed = g_flSlenderCalculatedSpeed[iBossIndex];
+	
+	new Float:flMyPos[3], Float:flMyEyeAng[3], Float:flMyVelocity[3];
+	
+	decl String:sSlenderProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sSlenderProfile, sizeof(sSlenderProfile));
+	
+	GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flMyPos);
+	GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
+	GetEntPropVector(iBoss, Prop_Data, "m_vecAbsVelocity", flMyVelocity);
+	
+	decl Float:flBossMins[3], Float:flBossMaxs[3];
+	GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flBossMins);
+	GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flBossMaxs);
+	
+	decl Float:flTraceMins[3], Float:flTraceMaxs[3];
+	flTraceMins[0] = flBossMins[0];
+	flTraceMins[1] = flBossMins[1];
+	flTraceMins[2] = 0.0;
+	flTraceMaxs[0] = flBossMaxs[0];
+	flTraceMaxs[1] = flBossMaxs[1];
+	flTraceMaxs[2] = 0.0;
+	
+	// By now we should have our preferable goal position. Initiate
+	// reflex adjustments.
+	
+	g_bSlenderFeelerReflexAdjustment[iBossIndex] = false;
+	
+	{
+		decl Float:flMoveDir[3];
+		NormalizeVector(flMyVelocity, flMoveDir);
+		flMoveDir[2] = 0.0;
+		
+		decl Float:flLat[3];
+		flLat[0] = -flMoveDir[1];
+		flLat[1] = flMoveDir[0];
+		flLat[2] = 0.0;
+	
+		new Float:flFeelerOffset = 25.0;
+		new Float:flFeelerLengthRun = 50.0;
+		new Float:flFeelerLengthWalk = 30.0;
+		new Float:flFeelerHeight = StepHeight + 0.1;
+		
+		new Float:flFeelerLength = iState == STATE_CHASE ? flFeelerLengthRun : flFeelerLengthWalk;
+		
+		// Get the ground height and normal.
+		new Handle:hTrace = TR_TraceRayFilterEx(flMyPos, Float:{ 0.0, 0.0, 90.0 }, MASK_NPCSOLID, RayType_Infinite, TraceFilterWalkableEntities);
+		decl Float:flTraceEndPos[3];
+		decl Float:flTraceNormal[3];
+		TR_GetEndPosition(flTraceEndPos, hTrace);
+		TR_GetPlaneNormal(hTrace, flTraceNormal);
+		new bool:bTraceHit = TR_DidHit(hTrace);
+		CloseHandle(hTrace);
+		
+		if (bTraceHit)
+		{
+			//new Float:flGroundHeight = GetVectorDistance(flMyPos, flTraceEndPos);
+			NormalizeVector(flTraceNormal, flTraceNormal);
+			GetVectorCrossProduct(flLat, flTraceNormal, flMoveDir);
+			GetVectorCrossProduct(flMoveDir, flTraceNormal, flLat);
+			
+			decl Float:flFeet[3];
+			flFeet[0] = flMyPos[0];
+			flFeet[1] = flMyPos[1];
+			flFeet[2] = flMyPos[2] + flFeelerHeight;
+			
+			decl Float:flTo[3];
+			decl Float:flFrom[3];
+			for (new i = 0; i < 3; i++)
+			{
+				flFrom[i] = flFeet[i] + (flFeelerOffset * flLat[i]);
+				flTo[i] = flFrom[i] + (flFeelerLength * flMoveDir[i]);
+			}
+			
+			new bool:bLeftClear = IsWalkableTraceLineClear(flFrom, flTo, WALK_THRU_DOORS | WALK_THRU_BREAKABLES);
+			
+			for (new i = 0; i < 3; i++)
+			{
+				flFrom[i] = flFeet[i] - (flFeelerOffset * flLat[i]);
+				flTo[i] = flFrom[i] + (flFeelerLength * flMoveDir[i]);
+			}
+			
+			new bool:bRightClear = IsWalkableTraceLineClear(flFrom, flTo, WALK_THRU_DOORS | WALK_THRU_BREAKABLES);
+			
+			new Float:flAvoidRange = 300.0;
+			
+			if (!bRightClear)
+			{
+				if (bLeftClear)
+				{
+					g_bSlenderFeelerReflexAdjustment[iBossIndex] = true;
+					
+					for (new i = 0; i < 3; i++)
+					{
+						g_flSlenderFeelerReflexAdjustmentPos[iBossIndex][i] = g_flSlenderGoalPos[iBossIndex][i] + (flAvoidRange * flLat[i]);
+					}
+				}
+			}
+			else if (!bLeftClear)
+			{
+				g_bSlenderFeelerReflexAdjustment[iBossIndex] = true;
+				
+				for (new i = 0; i < 3; i++)
+				{
+					g_flSlenderFeelerReflexAdjustmentPos[iBossIndex][i] = g_flSlenderGoalPos[iBossIndex][i] - (flAvoidRange * flLat[i]);
+				}
+			}
+		}
+	}
+	
+	new Float:flGoalPosition[3];
+	if (g_bSlenderFeelerReflexAdjustment[iBossIndex])
+	{
+		for (new i = 0; i < 3; i++)
+		{
+			flGoalPosition[i] = g_flSlenderFeelerReflexAdjustmentPos[iBossIndex][i];
+		}
+	}
+	else
+	{
+		for (new i = 0; i < 3; i++)
+		{
+			flGoalPosition[i] = g_flSlenderGoalPos[iBossIndex][i];
+		}
+	}
+	
+	// Process our desired velocity.
+	new Float:flDesiredVelocity[3];
+	switch (iState)
+	{
+		case STATE_WANDER:
+		{
+			if (NPCGetFlags(iBossIndex) & SFF_WANDERMOVE)
+			{
+				SubtractVectors(flGoalPosition, flMyPos, flDesiredVelocity);
+				flDesiredVelocity[2] = 0.0;
+				NormalizeVector(flDesiredVelocity, flDesiredVelocity);
+				ScaleVector(flDesiredVelocity, flWalkSpeed);
+			}
+		}
+		case STATE_ALERT:
+		{
+			SubtractVectors(flGoalPosition, flMyPos, flDesiredVelocity);
+			flDesiredVelocity[2] = 0.0;
+			NormalizeVector(flDesiredVelocity, flDesiredVelocity);
+			ScaleVector(flDesiredVelocity, flWalkSpeed);
+		}
+		case STATE_CHASE:
+		{
+			SubtractVectors(flGoalPosition, flMyPos, flDesiredVelocity);
+			flDesiredVelocity[2] = 0.0;
+			NormalizeVector(flDesiredVelocity, flDesiredVelocity);
+			ScaleVector(flDesiredVelocity, flSpeed);
+		}
+	}
+	
+	// Check if we're on the ground.
+	new bool:bSlenderOnGround = bool:(GetEntityFlags(iBoss) & FL_ONGROUND);
+	
+	decl Float:flTraceEndPos[3];
+	new Handle:hTrace;
+	
+	// Determine speed behavior.
+	if (bSlenderOnGround)
+	{
+		// Don't change the speed behavior.
+	}
+	else
+	{
+		flDesiredVelocity[2] = 0.0;
+		NormalizeVector(flDesiredVelocity, flDesiredVelocity);
+		ScaleVector(flDesiredVelocity, NPCChaserGetAirSpeed(iBossIndex, GetConVarInt(g_cvDifficulty)));
+	}
+	
+	new bool:bSlenderTeleportedOnStep = false;
+	new Float:flSlenderStepSize = NPCChaserGetStepSize(iBossIndex);
+	
+	// Check our stepsize in case we need to elevate ourselves a step.
+	if (bSlenderOnGround && GetVectorLength(flDesiredVelocity) > 0.0)
+	{
+		if (flSlenderStepSize > 0.0)
+		{
+			decl Float:flTraceDirection[3], Float:flObstaclePos[3], Float:flObstacleNormal[3];
+			NormalizeVector(flDesiredVelocity, flTraceDirection);
+			AddVectors(flMyPos, flTraceDirection, flTraceEndPos);
+			
+			// Tracehull in front of us to check if there's a very small obstacle blocking our way.
+			hTrace = TR_TraceHullFilterEx(flMyPos, 
+				flTraceEndPos,
+				flBossMins,
+				flBossMaxs,
+				MASK_NPCSOLID,
+				TraceRayDontHitEntity,
+				iBoss);
+				
+			new bool:bSlenderHitObstacle = TR_DidHit(hTrace);
+			TR_GetEndPosition(flObstaclePos, hTrace);
+			TR_GetPlaneNormal(hTrace, flObstacleNormal);
+			CloseHandle(hTrace);
+			
+			if (bSlenderHitObstacle &&
+				FloatAbs(flObstacleNormal[2]) == 0.0)
+			{
+				decl Float:flTraceStartPos[3];
+				flTraceStartPos[0] = flObstaclePos[0];
+				flTraceStartPos[1] = flObstaclePos[1];
+				
+				decl Float:flTraceFreePos[3];
+				
+				new Float:flTraceCheckZ = 0.0;
+				
+				// This does a crapload of traces along the wall. Very nasty and expensive to do...
+				while (flTraceCheckZ <= flSlenderStepSize)
+				{
+					flTraceCheckZ += 1.0;
+					flTraceStartPos[2] = flObstaclePos[2] + flTraceCheckZ;
+					
+					AddVectors(flTraceStartPos, flTraceDirection, flTraceEndPos);
+					
+					hTrace = TR_TraceHullFilterEx(flTraceStartPos, 
+						flTraceEndPos,
+						flTraceMins,
+						flTraceMaxs,
+						MASK_NPCSOLID,
+						TraceRayDontHitEntity,
+						iBoss);
+						
+					bSlenderHitObstacle = TR_DidHit(hTrace);
+					TR_GetEndPosition(flTraceFreePos, hTrace);
+					CloseHandle(hTrace);
+					
+					if (!bSlenderHitObstacle)
+					{
+						// Potential space to step on? See if we can fit!
+						if (!IsSpaceOccupiedNPC(flTraceFreePos,
+							flBossMins,
+							flBossMaxs,
+							iBoss))
+						{
+							// Yes we can! Break the loop and teleport to this pos.
+							bSlenderTeleportedOnStep = true;
+							TeleportEntity(iBoss, flTraceFreePos, NULL_VECTOR, NULL_VECTOR);
+							break;
+						}
+					}
+				}
+			}
+			/*
+			else if (!bSlenderHitObstacle)
+			{
+				decl Float:flTraceStartPos[3];
+				flTraceStartPos[0] = flObstaclePos[0];
+				flTraceStartPos[1] = flObstaclePos[1];
+				
+				decl Float:flTraceFreePos[3];
+				
+				new Float:flTraceCheckZ = 0.0;
+				
+				// This does a crapload of traces along the wall. Very nasty and expensive to do...
+				while (flTraceCheckZ <= flSlenderStepSize)
+				{
+					flTraceCheckZ += 1.0;
+					flTraceStartPos[2] = flObstaclePos[2] - flTraceCheckZ;
+					
+					AddVectors(flTraceStartPos, flTraceDirection, flTraceEndPos);
+					
+					hTrace = TR_TraceHullFilterEx(flTraceStartPos, 
+						flTraceEndPos,
+						flTraceMins,
+						flTraceMaxs,
+						MASK_NPCSOLID,
+						TraceRayDontHitEntity,
+						iBoss);
+						
+					bSlenderHitObstacle = TR_DidHit(hTrace);
+					TR_GetEndPosition(flTraceFreePos, hTrace);
+					CloseHandle(hTrace);
+					
+					if (bSlenderHitObstacle)
+					{
+						// Potential space to step on? See if we can fit!
+						if (!IsSpaceOccupiedNPC(flTraceFreePos,
+							flBossMins,
+							flBossMaxs,
+							iBoss))
+						{
+							// Yes we can! Break the loop and teleport to this pos.
+							bSlenderTeleportedOnStep = true;
+							TeleportEntity(iBoss, flTraceFreePos, NULL_VECTOR, NULL_VECTOR);
+							break;
+						}
+					}
+				}
+			}
+			*/
+		}
+	}
+	
+	// Apply acceleration vectors.
+	new Float:flMoveVelocity[3];
+	new Float:flFrameTime = GetTickInterval();
+	decl Float:flAcceleration[3];
+	SubtractVectors(flDesiredVelocity, flMyVelocity, flAcceleration);
+	NormalizeVector(flAcceleration, flAcceleration);
+	ScaleVector(flAcceleration, g_flSlenderAcceleration[iBossIndex] * flFrameTime);
+	
+	AddVectors(flMyVelocity, flAcceleration, flMoveVelocity);
+	
+	new Float:flSlenderJumpSpeed = g_flSlenderJumpSpeed[iBossIndex];
+	new bool:bSlenderShouldJump = false;
+	
+	decl Float:angJumpReach[3]; 
+	
+	// Check if we need to jump over a wall or something.
+	if (!bSlenderShouldJump && bSlenderOnGround && !bSlenderTeleportedOnStep && flSlenderJumpSpeed > 0.0 && GetVectorLength(flDesiredVelocity) > 0.0 &&
+		GetGameTime() >= g_flSlenderNextJump[iBossIndex])
+	{
+		new Float:flZDiff = (flGoalPosition[2] - flMyPos[2]);
+		
+		if (flZDiff > flSlenderStepSize)
+		{
+			// Our path has a jump thingy to it. Calculate the jump height needed to reach it and how far away we should start
+			// checking on when to jump.
+			
+			decl Float:vecDir[3], Float:vecDesiredDir[3];
+			GetVectorAngles(flMyVelocity, vecDir);
+			SubtractVectors(flGoalPosition, flMyPos, vecDesiredDir);
+			GetVectorAngles(vecDesiredDir, vecDesiredDir);
+			
+			if ((FloatAbs(AngleDiff(vecDir[0], vecDesiredDir[0])) + FloatAbs(AngleDiff(vecDir[1], vecDesiredDir[1]))) >= 45.0)
+			{
+				// Assuming we are actually capable of making the jump, find out WHEN we have to jump,
+				// based on 2D distance between our position and the target point, and our current horizontal 
+				// velocity.
+				
+				decl Float:vecMyPos2D[3], Float:vecGoalPos2D[3];
+				vecMyPos2D[0] = flMyPos[0];
+				vecMyPos2D[1] = flMyPos[1];
+				vecMyPos2D[2] = 0.0;
+				vecGoalPos2D[0] = flGoalPosition[0];
+				vecGoalPos2D[1] = flGoalPosition[1];
+				vecGoalPos2D[2] = 0.0;
+				
+				new Float:fl2DDist = GetVectorDistance(vecMyPos2D, vecGoalPos2D);
+				
+				new Float:flNotImaginary = Pow(flSlenderJumpSpeed, 4.0) - (g_flGravity * (g_flGravity * Pow(fl2DDist, 2.0)) + (2.0 * flZDiff * Pow(flSlenderJumpSpeed, 2.0)));
+				if (flNotImaginary >= 0.0)
+				{
+					// We can reach it.
+					new Float:flNotInfinite = g_flGravity * fl2DDist;
+					if (flNotInfinite > 0.0)
+					{
+						SubtractVectors(vecGoalPos2D, vecMyPos2D, angJumpReach);
+						GetVectorAngles(angJumpReach, angJumpReach);
+						angJumpReach[0] = -RadToDeg(ArcTangent((Pow(flSlenderJumpSpeed, 2.0) + SquareRoot(flNotImaginary)) / flNotInfinite));
+						bSlenderShouldJump = true;
+					}
+				}
+			}
+		}
+	}
+	
+	if (bSlenderOnGround && bSlenderShouldJump)
+	{
+		g_flSlenderNextJump[iBossIndex] = GetGameTime() + GetProfileFloat(sSlenderProfile, "jump_cooldown", 2.0);
+		
+		decl Float:vecJump[3];
+		GetAngleVectors(angJumpReach, vecJump, NULL_VECTOR, NULL_VECTOR);
+		NormalizeVector(vecJump, vecJump);
+		ScaleVector(vecJump, flSlenderJumpSpeed);
+		AddVectors(flMoveVelocity, vecJump, flMoveVelocity);
+	}
+	else 
+	{
+		// We are in no position to defy gravity.
+		flMoveVelocity[2] = flMyVelocity[2];
+	}
+	
+	decl Float:flMoveAng[3];
+	new bool:bChangeAngles = false;
+	
+	// Process angles.
+	if (iState != STATE_ATTACK && iState != STATE_STUN)
+	{
+		if (NPCHasAttribute(iBossIndex, "always look at target"))
+		{
+			new iTarget = EntRefToEntIndex(g_iSlenderTarget[iBossIndex]);
+			
+			if (iTarget && iTarget != INVALID_ENT_REFERENCE)
+			{
+				decl Float:flTargetPos[3];
+				GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flTargetPos);
+				SubtractVectors(flTargetPos, flMyPos, flMoveAng);
+				GetVectorAngles(flMoveAng, flMoveAng);
+			}
+			else
+			{
+				SubtractVectors(flGoalPosition, flMyPos, flMoveAng);
+				GetVectorAngles(flMoveAng, flMoveAng);
+			}
+		}
+		else
+		{
+			SubtractVectors(flGoalPosition, flMyPos, flMoveAng);
+			GetVectorAngles(flMoveAng, flMoveAng);
+		}
+		
+		new Float:flTurnRate = NPCGetTurnRate(iBossIndex);
+		if (iState == STATE_CHASE) flTurnRate *= 2.0;
+		
+		flMoveAng[0] = 0.0;
+		flMoveAng[2] = 0.0;
+		flMoveAng[1] = ApproachAngle(flMoveAng[1], flMyEyeAng[1], flTurnRate * flFrameTime);
+		
+		bChangeAngles = true;
+	}
+	
+	TeleportEntity(iBoss, NULL_VECTOR, bChangeAngles ? flMoveAng : NULL_VECTOR, flMoveVelocity);
+}
+
+// Shortest-path cost function for NavMesh_BuildPath.
+public SlenderChaseBossShortestPathCost(iAreaIndex, iFromAreaIndex, iLadderIndex, any:iStepSize)
+{
+	if (iFromAreaIndex == -1)
+	{
+		return 0;
+	}
+	else
+	{
+		new iDist;
+		decl Float:flAreaCenter[3], Float:flFromAreaCenter[3];
+		NavMeshArea_GetCenter(iAreaIndex, flAreaCenter);
+		NavMeshArea_GetCenter(iFromAreaIndex, flFromAreaCenter);
+		
+		if (iLadderIndex != -1)
+		{
+			iDist = RoundFloat(NavMeshLadder_GetLength(iLadderIndex));
+		}
+		else
+		{
+			iDist = RoundFloat(GetVectorDistance(flAreaCenter, flFromAreaCenter));
+		}
+		
+		new iCost = iDist + NavMeshArea_GetCostSoFar(iFromAreaIndex);
+		
+		new iAreaFlags = NavMeshArea_GetFlags(iAreaIndex);
+		if (iAreaFlags & NAV_MESH_CROUCH) iCost += 20;
+		if (iAreaFlags & NAV_MESH_JUMP) iCost += (5 * iDist);
+		
+		if ((flAreaCenter[2] - flFromAreaCenter[2]) > iStepSize) iCost += iStepSize;
+		
+		return iCost;
+	}
+}
+
+public Action:Timer_SlenderChaseBossAttack(Handle:timer, any:entref)
+{
+	if (!g_bEnabled) return;
+
+	new slender = EntRefToEntIndex(entref);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return;
+	
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return;
+	
+	if (timer != g_hSlenderAttackTimer[iBossIndex]) return;
+	
+	if (NPCGetFlags(iBossIndex) & SFF_FAKE)
+	{
+		SlenderMarkAsFake(iBossIndex);
+		return;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new bool:bAttackEliminated = bool:(NPCGetFlags(iBossIndex) & SFF_ATTACKWAITERS);
+	
+	new Float:flDamage = NPCChaserGetAttackDamage(iBossIndex, 0);
+	new Float:flDamageVsProps = NPCChaserGetAttackDamageVsProps(iBossIndex, 0);
+	new iDamageType = NPCChaserGetAttackDamageType(iBossIndex, 0);
+	
+	// Damage all players within range.
+	decl Float:flMyEyePos[3], Float:flMyEyeAng[3];
+	NPCGetEyePosition(iBossIndex, flMyEyePos);
+	GetEntPropVector(slender, Prop_Data, "m_angAbsRotation", flMyEyeAng);
+	AddVectors(g_flSlenderEyePosOffset[iBossIndex], flMyEyeAng, flMyEyeAng);
+	for (new i = 0; i < 3; i++) flMyEyeAng[i] = AngleNormalize(flMyEyeAng[i]);
+	
+	decl Float:flViewPunch[3];
+	GetProfileVector(sProfile, "attack_punchvel", flViewPunch);
+	
+	decl Float:flTargetDist;
+	decl Handle:hTrace;
+	
+	new Float:flAttackRange = NPCChaserGetAttackRange(iBossIndex, 0);
+	new Float:flAttackFOV = NPCChaserGetAttackSpread(iBossIndex, 0);
+	new Float:flAttackDamageForce = NPCChaserGetAttackDamageForce(iBossIndex, 0);
+	
+	new bool:bHit = false;
+	
+	{
+		new prop = -1;
+		while ((prop = FindEntityByClassname(prop, "prop_physics")) != -1)
+		{
+			if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
+			{
+				bHit = true;
+				SDKHooks_TakeDamage(prop, slender, slender, flDamageVsProps, iDamageType, _, _, flMyEyePos);
+			}
+		}
+		
+		prop = -1;
+		while ((prop = FindEntityByClassname(prop, "prop_dynamic")) != -1)
+		{
+			if (GetEntProp(prop, Prop_Data, "m_iHealth") > 0)
+			{
+				if (NPCAttackValidateTarget(iBossIndex, prop, flAttackRange, flAttackFOV))
+				{
+					bHit = true;
+					SDKHooks_TakeDamage(prop, slender, slender, flDamageVsProps, iDamageType, _, _, flMyEyePos);
+				}
+			}
+		}
+	}
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientInGhostMode(i)) continue;
+		
+		if (!bAttackEliminated && g_bPlayerEliminated[i]) continue;
+		
+		decl Float:flTargetPos[3];
+		GetClientEyePosition(i, flTargetPos);
+		
+		hTrace = TR_TraceRayFilterEx(flMyEyePos,
+			flTargetPos,
+			MASK_NPCSOLID,
+			RayType_EndPoint,
+			TraceRayDontHitEntity,
+			slender);
+		
+		new bool:bTraceDidHit = TR_DidHit(hTrace);
+		new iTraceHitEntity = TR_GetEntityIndex(hTrace);
+		CloseHandle(hTrace);
+		
+		if (bTraceDidHit && iTraceHitEntity != i)
+		{
+			decl Float:flTargetMins[3], Float:flTargetMaxs[3];
+			GetEntPropVector(i, Prop_Send, "m_vecMins", flTargetMins);
+			GetEntPropVector(i, Prop_Send, "m_vecMaxs", flTargetMaxs);
+			GetClientAbsOrigin(i, flTargetPos);
+			for (new i2 = 0; i2 < 3; i2++) flTargetPos[i2] += ((flTargetMins[i2] + flTargetMaxs[i2]) / 2.0);
+			
+			hTrace = TR_TraceRayFilterEx(flMyEyePos,
+				flTargetPos,
+				MASK_NPCSOLID,
+				RayType_EndPoint,
+				TraceRayDontHitEntity,
+				slender);
+				
+			bTraceDidHit = TR_DidHit(hTrace);
+			iTraceHitEntity = TR_GetEntityIndex(hTrace);
+			CloseHandle(hTrace);
+		}
+		
+		if (!bTraceDidHit || iTraceHitEntity == i)
+		{
+			flTargetDist = GetVectorDistance(flTargetPos, flMyEyePos);
+			
+			if (flTargetDist <= flAttackRange)
+			{
+				decl Float:flDirection[3];
+				SubtractVectors(flTargetPos, flMyEyePos, flDirection);
+				GetVectorAngles(flDirection, flDirection);
+				
+				if (FloatAbs(AngleDiff(flDirection[1], flMyEyeAng[1])) <= flAttackFOV)
+				{
+					bHit = true;
+					GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
+					NormalizeVector(flDirection, flDirection);
+					ScaleVector(flDirection, flAttackDamageForce);
+					
+					Call_StartForward(fOnClientDamagedByBoss);
+					Call_PushCell(i);
+					Call_PushCell(iBossIndex);
+					Call_PushCell(slender);
+					Call_PushFloat(flDamage);
+					Call_PushCell(iDamageType);
+					Call_Finish();
+					
+					SDKHooks_TakeDamage(i, slender, slender, flDamage, iDamageType, _, flDirection, flMyEyePos);
+					ClientViewPunch(i, flViewPunch);
+					
+					if (NPCHasAttribute(iBossIndex, "bleed player on hit"))
+					{
+						new Float:flDuration = NPCGetAttributeValue(iBossIndex, "bleed player on hit");
+						if (flDuration > 0.0)
+						{
+							TF2_MakeBleed(i, slender, flDuration);
+						}
+					}
+					
+					// Add stress
+					new Float:flStressScalar = flDamage / 125.0;
+					if (flStressScalar > 1.0) flStressScalar = 1.0;
+					ClientAddStress(i, 0.33 * flStressScalar);
+				}
+			}
+		}
+	}
+	
+	decl String:sSoundPath[PLATFORM_MAX_PATH];
+	
+	if (bHit)
+	{
+		// Fling it.
+		new phys = CreateEntityByName("env_physexplosion");
+		if (phys != -1)
+		{
+			TeleportEntity(phys, flMyEyePos, NULL_VECTOR, NULL_VECTOR);
+			DispatchKeyValue(phys, "spawnflags", "1");
+			DispatchKeyValueFloat(phys, "radius", flAttackRange);
+			DispatchKeyValueFloat(phys, "magnitude", flAttackDamageForce);
+			DispatchSpawn(phys);
+			ActivateEntity(phys);
+			AcceptEntityInput(phys, "Explode");
+			AcceptEntityInput(phys, "Kill");
+		}
+		
+		GetRandomStringFromProfile(sProfile, "sound_hitenemy", sSoundPath, sizeof(sSoundPath));
+		if (sSoundPath[0]) EmitSoundToAll(sSoundPath, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+	}
+	else
+	{
+		GetRandomStringFromProfile(sProfile, "sound_missenemy", sSoundPath, sizeof(sSoundPath));
+		if (sSoundPath[0]) EmitSoundToAll(sSoundPath, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+	}
+	
+	g_hSlenderAttackTimer[iBossIndex] = CreateTimer(GetProfileFloat(sProfile, "attack_endafter"), Timer_SlenderChaseBossAttackEnd, entref, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+static NPCAttackValidateTarget(iBossIndex, iTarget, Float:flAttackRange, Float:flAttackFOV)
+{
+	new iBoss = NPCGetEntIndex(iBossIndex);
+	
+	decl Float:flMyEyePos[3], Float:flMyEyeAng[3];
+	NPCGetEyePosition(iBossIndex, flMyEyePos);
+	GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
+	AddVectors(g_flSlenderEyeAngOffset[iBossIndex], flMyEyeAng, flMyEyeAng);
+	for (new i = 0; i < 3; i++) flMyEyeAng[i] = AngleNormalize(flMyEyeAng[i]);
+	
+	decl Float:flTargetPos[3], Float:flTargetMins[3], Float:flTargetMaxs[3];
+	GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flTargetPos);
+	GetEntPropVector(iTarget, Prop_Send, "m_vecMins", flTargetMins);
+	GetEntPropVector(iTarget, Prop_Send, "m_vecMaxs", flTargetMaxs);
+	
+	for (new i = 0; i < 3; i++)
+	{
+		flTargetPos[i] += (flTargetMins[i] + flTargetMaxs[i]) / 2.0;
+	}
+	
+	new Float:flTargetDist = GetVectorDistance(flTargetPos, flMyEyePos);
+	if (flTargetDist <= flAttackRange)
+	{
+		decl Float:flDirection[3];
+		SubtractVectors(g_flSlenderGoalPos[iBossIndex], flMyEyePos, flDirection);
+		GetVectorAngles(flDirection, flDirection);
+		
+		if (FloatAbs(AngleDiff(flDirection[1], flMyEyeAng[1])) <= flAttackFOV / 2.0)
+		{
+			new Handle:hTrace = TR_TraceRayFilterEx(flMyEyePos,
+				flTargetPos,
+				MASK_NPCSOLID,
+				RayType_EndPoint,
+				TraceRayDontHitEntity,
+				iBoss);
+				
+			new bool:bTraceDidHit = TR_DidHit(hTrace);
+			new iTraceHitEntity = TR_GetEntityIndex(hTrace);
+			CloseHandle(hTrace);
+			
+			if (!bTraceDidHit || iTraceHitEntity == iTarget)
+			{
+				return true;
+			}
+		}
+	}
+	
+	return false;
+}
+
+public Action:Timer_SlenderChaseBossAttackEnd(Handle:timer, any:entref)
+{
+	if (!g_bEnabled) return;
+
+	new slender = EntRefToEntIndex(entref);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return;
+	
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return;
+	
+	if (timer != g_hSlenderAttackTimer[iBossIndex]) return;
+	
+	g_bSlenderAttacking[iBossIndex] = false;
+	g_hSlenderAttackTimer[iBossIndex] = INVALID_HANDLE;
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/playergroups.sp b/addons/sourcemod/scripting/rytp_horror/playergroups.sp
index 8a6ea0e..27b65d5 100644
--- a/addons/sourcemod/scripting/rytp_horror/playergroups.sp
+++ b/addons/sourcemod/scripting/rytp_horror/playergroups.sp
@@ -1,614 +1,614 @@
-#if defined _sf2_playergroups_included
- #endinput
-#endif
-#define _sf2_playergroups_included
-
-#define SF2_MAX_PLAYER_GROUPS MAXPLAYERS
-#define SF2_MAX_PLAYER_GROUP_NAME_LENGTH 32
-
-static g_iPlayerGroupGlobalID = -1;
-static g_iPlayerCurrentGroup[MAXPLAYERS + 1] = { -1, ... };
-static bool:g_bPlayerGroupActive[SF2_MAX_PLAYER_GROUPS] = { false, ... };
-static g_iPlayerGroupLeader[SF2_MAX_PLAYER_GROUPS] = { -1, ... };
-static g_iPlayerGroupID[SF2_MAX_PLAYER_GROUPS] = { -1, ... };
-static g_iPlayerGroupQueuePoints[SF2_MAX_PLAYER_GROUPS];
-static g_bPlayerGroupPlaying[SF2_MAX_PLAYER_GROUPS] = { false, ... };
-static Handle:g_hPlayerGroupNames;
-static bool:g_bPlayerGroupInvitedPlayer[SF2_MAX_PLAYER_GROUPS][MAXPLAYERS + 1];
-static g_iPlayerGroupInvitedPlayerCount[SF2_MAX_PLAYER_GROUPS][MAXPLAYERS + 1];
-static Float:g_flPlayerGroupInvitedPlayerTime[SF2_MAX_PLAYER_GROUPS][MAXPLAYERS + 1];
-
-SetupPlayerGroups()
-{
-	g_iPlayerGroupGlobalID = -1;
-	g_hPlayerGroupNames = CreateTrie();
-}
-
-stock GetPlayerGroupFromID(iGroupID)
-{
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		if (GetPlayerGroupID(i) == iGroupID) return i;
-	}
-	
-	return -1;
-}
-
-SendPlayerGroupInvitation(client, iGroupID, iInviter=-1)
-{
-	if (!IsValidClient(client) || !IsClientParticipating(client))
-	{
-		if (IsValidClient(iInviter))
-		{
-			// TODO: Send message to the inviter that the client is invalid!
-		}
-		
-		return;
-	}
-	
-	if (!g_bPlayerEliminated[client])
-	{
-		if (IsValidClient(iInviter))
-		{
-			// TODO: Send message to the inviter that the client is currently in-game.
-		}
-		
-		return;
-	}
-	
-	new iGroupIndex = GetPlayerGroupFromID(iGroupID);
-	if (iGroupIndex == -1) return;
-	
-	new iMyGroupIndex = ClientGetPlayerGroup(client);
-	if (IsPlayerGroupActive(iMyGroupIndex))
-	{
-		if (IsValidClient(iInviter))
-		{
-			if (iMyGroupIndex == iGroupIndex)
-			{
-				CPrintToChat(iInviter, "%T", "SF2 Player In Group", iInviter);
-			}
-			else
-			{
-				CPrintToChat(iInviter, "%T", "SF2 Player In Another Group", iInviter);
-			}
-		}
-		
-		return;
-	}
-	
-	if (GetPlayerGroupMemberCount(iGroupIndex) >= GetMaxPlayersForRound())
-	{
-		if (IsValidClient(iInviter))
-		{
-			CPrintToChat(iInviter, "%T", "SF2 Group Is Full", iInviter);
-		}
-		
-		return;
-	}
-	
-	if (IsFakeClient(client))
-	{
-		ClientSetPlayerGroup(client, iGroupIndex);
-		return;
-	}
-	
-	// Anti-spam.
-	decl String:sName[MAX_NAME_LENGTH];
-	GetClientName(client, sName, sizeof(sName));
-	
-	if (IsValidClient(iInviter))
-	{
-		new Float:flNextInviteTime = GetPlayerGroupInvitedPlayerTime(iGroupIndex, client) + (20.0 * GetPlayerGroupInvitedPlayerCount(iGroupIndex, client));
-		if (GetGameTime() < flNextInviteTime)
-		{
-			CPrintToChat(iInviter, "%T", "SF2 No Group Invite Spam", iInviter, RoundFloat(flNextInviteTime - GetGameTime()), sName);
-			return;
-		}
-	}
-	
-	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	decl String:sLeaderName[64];
-	GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-	
-	new iGroupLeader = GetPlayerGroupLeader(iGroupIndex);
-	if (IsValidClient(iGroupLeader)) GetClientName(iGroupLeader, sLeaderName, sizeof(sLeaderName));
-	else strcopy(sLeaderName, sizeof(sLeaderName), "nobody");
-	
-	new Handle:hMenu = CreateMenu(Menu_GroupInvite);
-	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Group Invite Menu Description", client, sLeaderName, sGroupName);
-	
-	decl String:sGroupID[64];
-	IntToString(iGroupID, sGroupID, sizeof(sGroupID));
-	
-	decl String:sBuffer[256];
-	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
-	AddMenuItem(hMenu, sGroupID, sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	DisplayMenu(hMenu, client, 10);
-	
-	SetPlayerGroupInvitedPlayer(iGroupIndex, client, true);
-	SetPlayerGroupInvitedPlayerCount(iGroupIndex, client, GetPlayerGroupInvitedPlayerCount(iGroupIndex, client) + 1);
-	SetPlayerGroupInvitedPlayerTime(iGroupIndex, client, GetGameTime());
-	
-	if (IsValidClient(iInviter))
-	{
-		CPrintToChat(iInviter, "%T", "SF2 Group Invitation Sent", iInviter, sName);
-	}
-}
-
-public Menu_GroupInvite(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) 
-	{
-		CloseHandle(menu);
-	}
-	else if (action == MenuAction_Select)
-	{
-		if (param2 == 0)
-		{
-			decl String:sGroupID[64];
-			GetMenuItem(menu, param2, sGroupID, sizeof(sGroupID));
-			new iGroupIndex = GetPlayerGroupFromID(StringToInt(sGroupID));
-			if (IsPlayerGroupActive(iGroupIndex))
-			{
-				new iMyGroupIndex = ClientGetPlayerGroup(param1);
-				if (IsPlayerGroupActive(iMyGroupIndex))
-				{
-					if (iMyGroupIndex == iGroupIndex)
-					{
-						CPrintToChat(param1, "%T", "SF2 In Group", param1);
-					}
-					else
-					{
-						CPrintToChat(param1, "%T", "SF2 In Another Group", param1);
-					}
-				}
-				else if (GetPlayerGroupMemberCount(iGroupIndex) >= GetMaxPlayersForRound())
-				{
-					CPrintToChat(param1, "%T", "SF2 Group Is Full", param1);
-				}
-				else
-				{
-					ClientSetPlayerGroup(param1, iGroupIndex);
-				}
-			}
-			else
-			{
-				CPrintToChat(param1, "%T", "SF2 Group Does Not Exist", param1);
-			}
-		}
-	}
-}
-
-DisplayResetGroupQueuePointsMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayGroupMainMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return;
-	}
-	
-	new Handle:hMenu = CreateMenu(Menu_ResetGroupQueuePoints);
-	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Reset Group Queue Points Menu Title", client, "SF2 Reset Group Queue Points Menu Description", client);
-	
-	decl String:sBuffer[256];
-	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	
-	SetMenuExitBackButton(hMenu, true);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_ResetGroupQueuePoints(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select)
-	{
-		if (param2 == 0)
-		{
-			new iGroupIndex = ClientGetPlayerGroup(param1);
-			if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
-			{
-				SetPlayerGroupQueuePoints(iGroupIndex, 0);
-				
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsValidClient(i)) continue;
-					if (ClientGetPlayerGroup(i) == iGroupIndex)
-					{
-						CPrintToChat(i, "%T", "SF2 Group Queue Points Reset", i);
-					}
-				}
-			}
-			else
-			{
-				CPrintToChat(param1, "%T", "SF2 Not Group Leader", param1);
-			}
-		}
-		
-		DisplayAdminGroupMenuToClient(param1);
-	}
-}
-
-CheckPlayerGroup(iGroupIndex)
-{
-	if (!IsPlayerGroupActive(iGroupIndex)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START CheckPlayerGroup(%d)", iGroupIndex);
-#endif
-	
-	new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
-	if (iMemberCount <= 0)
-	{
-		RemovePlayerGroup(iGroupIndex);
-	}
-	else
-	{
-		// Remove any person that isn't participating.
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (ClientGetPlayerGroup(i) == iGroupIndex)
-			{
-				if (!IsValidClient(i) || !IsClientParticipating(i))
-				{
-#if defined DEBUG
-					if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("CheckPlayerGroup(%d): Invalid client detected (%d), removing from group", iGroupIndex, i);
-#endif
-					
-					ClientSetPlayerGroup(i, -1);
-				}
-			}
-		}
-		
-		iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
-		new iMaxPlayers = GetMaxPlayersForRound();
-		new iExcessMemberCount = (iMemberCount - iMaxPlayers);
-		
-		if (iExcessMemberCount > 0)
-		{
-#if defined DEBUG
-			if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("CheckPlayerGroup(%d): Excess members detected", iGroupIndex);
-#endif
-
-			new iGroupLeader = GetPlayerGroupLeader(iGroupIndex);
-			if (IsValidClient(iGroupLeader))
-			{
-				CPrintToChat(iGroupLeader, "%T", "SF2 Group Has Too Many Members", iGroupLeader);
-			}
-			
-			for (new i = 1, iCount; i <= MaxClients && iCount < iExcessMemberCount; i++)
-			{
-				if (!IsValidClient(i)) continue;
-				
-				if (ClientGetPlayerGroup(i) == iGroupIndex)
-				{
-					if (i == iGroupLeader) continue; // Don't kick off the group leader.
-					
-					ClientSetPlayerGroup(i, -1);
-					iCount++;
-				}
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END CheckPlayerGroup(%d)", iGroupIndex);
-#endif
-}
-
-stock GetPlayerGroupCount()
-{
-	new iCount;
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (IsPlayerGroupActive(i)) iCount++;
-	}
-	
-	return iCount;
-}
-
-stock CreatePlayerGroup()
-{
-	// Get an inactive group.
-	new iIndex = -1;
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i))
-		{
-			iIndex = i;
-			break;
-		}
-	}
-	
-	if (iIndex != -1)
-	{
-		g_bPlayerGroupActive[iIndex] = true;
-		g_iPlayerGroupGlobalID++;
-		SetPlayerGroupID(iIndex, g_iPlayerGroupGlobalID);
-		ClearPlayerGroupMembers(iIndex);
-		SetPlayerGroupQueuePoints(iIndex, 0);
-		SetPlayerGroupLeader(iIndex, -1);
-		SetPlayerGroupName(iIndex, "");
-		SetPlayerGroupPlaying(iIndex, false);
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			SetPlayerGroupInvitedPlayer(iIndex, i, false);
-			SetPlayerGroupInvitedPlayerCount(iIndex, i, 0);
-			SetPlayerGroupInvitedPlayerTime(iIndex, i, 0.0);
-		}
-	}
-	
-	return iIndex;
-}
-
-stock RemovePlayerGroup(iGroupIndex)
-{
-	if (!IsPlayerGroupActive(iGroupIndex)) return;
-	
-	ClearPlayerGroupMembers(iGroupIndex);
-	SetPlayerGroupQueuePoints(iGroupIndex, 0);
-	SetPlayerGroupPlaying(iGroupIndex, false);
-	SetPlayerGroupLeader(iGroupIndex, -1);
-	g_bPlayerGroupActive[iGroupIndex] = false;
-	SetPlayerGroupID(iGroupIndex, -1);
-}
-
-stock ClearPlayerGroupMembers(iGroupIndex)
-{
-	if (!IsPlayerGroupValid(iGroupIndex)) return;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (ClientGetPlayerGroup(i) == iGroupIndex)
-		{
-			ClientSetPlayerGroup(i, -1);
-		}
-	}
-}
-
-stock bool:GetPlayerGroupName(iGroupIndex, String:sBuffer[], iBufferLen)
-{
-	decl String:sGroupIndex[32];
-	IntToString(iGroupIndex, sGroupIndex, sizeof(sGroupIndex)); 
-	return GetTrieString(g_hPlayerGroupNames, sGroupIndex, sBuffer, iBufferLen);
-}
-
-stock SetPlayerGroupName(iGroupIndex, const String:sGroupName[])
-{
-	decl String:sGroupIndex[32];
-	IntToString(iGroupIndex, sGroupIndex, sizeof(sGroupIndex)); 
-	SetTrieString(g_hPlayerGroupNames, sGroupIndex, sGroupName);
-}
-
-stock GetPlayerGroupID(iGroupIndex)
-{
-	return g_iPlayerGroupID[iGroupIndex];
-}
-
-stock SetPlayerGroupID(iGroupIndex, iID)
-{
-	g_iPlayerGroupID[iGroupIndex] = iID;
-}
-
-stock bool:IsPlayerGroupActive(iGroupIndex)
-{
-	return IsPlayerGroupValid(iGroupIndex) && g_bPlayerGroupActive[iGroupIndex];
-}
-
-stock bool:IsPlayerGroupValid(iGroupIndex)
-{
-	return (iGroupIndex >= 0 && iGroupIndex < SF2_MAX_PLAYER_GROUPS);
-}
-
-stock GetPlayerGroupMemberCount(iGroupIndex)
-{
-	new iCount;
-
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-	
-		if (ClientGetPlayerGroup(i) == iGroupIndex)
-		{
-			iCount++;
-		}
-	}
-	
-	return iCount;
-}
-
-stock bool:IsPlayerGroupPlaying(iGroupIndex)
-{
-	return (IsPlayerGroupActive(iGroupIndex) && g_bPlayerGroupPlaying[iGroupIndex]);
-}
-
-stock SetPlayerGroupPlaying(iGroupIndex, bool:bToggle)
-{
-	g_bPlayerGroupPlaying[iGroupIndex] = bToggle;
-}
-
-stock GetPlayerGroupLeader(iGroupIndex)
-{
-	return g_iPlayerGroupLeader[iGroupIndex];
-}
-
-stock SetPlayerGroupLeader(iGroupIndex, iGroupLeader)
-{
-	g_iPlayerGroupLeader[iGroupIndex] = iGroupLeader;
-	
-	if (IsValidClient(iGroupLeader))
-	{
-		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-		GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-		CPrintToChat(iGroupLeader, "%T", "SF2 New Group Leader", iGroupLeader, sGroupName);
-		
-		decl String:sName[MAX_NAME_LENGTH];
-		GetClientName(iGroupLeader, sName, sizeof(sName));
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (iGroupLeader == i || !IsValidClient(i)) continue;
-			if (ClientGetPlayerGroup(i) == iGroupIndex)
-			{
-				CPrintToChat(i, "%T", "SF2 Player New Group Leader", i, sName);
-			}
-		}
-	}
-}
-
-PlayerGroupFindNewLeader(iGroupIndex)
-{
-	if (!IsPlayerGroupActive(iGroupIndex)) return -1;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		
-		if (ClientGetPlayerGroup(i) == iGroupIndex)
-		{
-			SetPlayerGroupLeader(iGroupIndex, i);
-			return i;
-		}
-	}
-	
-	return -1;
-}
-
-stock GetPlayerGroupQueuePoints(iGroupIndex)
-{
-	return g_iPlayerGroupQueuePoints[iGroupIndex];
-}
-
-stock SetPlayerGroupQueuePoints(iGroupIndex, iAmount)
-{
-	g_iPlayerGroupQueuePoints[iGroupIndex] = iAmount;
-}
-
-stock HasPlayerGroupInvitedPlayer(iGroupIndex, client)
-{
-	return g_bPlayerGroupInvitedPlayer[iGroupIndex][client];
-}
-
-stock SetPlayerGroupInvitedPlayer(iGroupIndex, client, bool:bToggle)
-{
-	g_bPlayerGroupInvitedPlayer[iGroupIndex][client] = bToggle;
-}
-
-stock GetPlayerGroupInvitedPlayerCount(iGroupIndex, client)
-{
-	return g_iPlayerGroupInvitedPlayerCount[iGroupIndex][client];
-}
-
-stock SetPlayerGroupInvitedPlayerCount(iGroupIndex, client, iAmount)
-{
-	g_iPlayerGroupInvitedPlayerCount[iGroupIndex][client] = iAmount;
-}
-
-stock Float:GetPlayerGroupInvitedPlayerTime(iGroupIndex, client)
-{
-	return g_flPlayerGroupInvitedPlayerTime[iGroupIndex][client];
-}
-
-stock SetPlayerGroupInvitedPlayerTime(iGroupIndex, client, Float:flTime)
-{
-	g_flPlayerGroupInvitedPlayerTime[iGroupIndex][client] = flTime;
-}
-
-stock ClientGetPlayerGroup(client)
-{
-	return g_iPlayerCurrentGroup[client];
-}
-
-stock ClientSetPlayerGroup(client, iGroupIndex)
-{
-	new iOldPlayerGroup = ClientGetPlayerGroup(client);
-	if (iOldPlayerGroup == iGroupIndex) return; // No change.
-	
-	g_iPlayerCurrentGroup[client] = iGroupIndex;
-	
-	decl String:sName[MAX_NAME_LENGTH];
-	GetClientName(client, sName, sizeof(sName));
-	
-	if (IsPlayerGroupActive(iOldPlayerGroup))
-	{
-		SetPlayerGroupInvitedPlayer(iOldPlayerGroup, client, false);
-		SetPlayerGroupInvitedPlayerCount(iOldPlayerGroup, client, 0);
-		SetPlayerGroupInvitedPlayerTime(iOldPlayerGroup, client, 0.0);
-		
-		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-		GetPlayerGroupName(iOldPlayerGroup, sGroupName, sizeof(sGroupName));
-		CPrintToChat(client, "%T", "SF2 Left Group", client, sGroupName);
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (i == client || !IsValidClient(i)) continue;
-			if (ClientGetPlayerGroup(i) == iOldPlayerGroup)
-			{
-				CPrintToChat(i, "%T", "SF2 Player Left Group", i, sName);
-			}
-		}
-	
-		new iOldGroupLeader = GetPlayerGroupLeader(iOldPlayerGroup);
-		if (iOldGroupLeader == client)
-		{
-			new iOldGroupNewLeader = PlayerGroupFindNewLeader(iOldPlayerGroup);
-			if (iOldGroupNewLeader == -1)
-			{
-				// Couldn't find a new leader. This group has no leader!
-				SetPlayerGroupLeader(iOldPlayerGroup, -1);
-			}
-		}
-		
-		CheckPlayerGroup(iOldPlayerGroup);
-	}
-	
-	if (IsPlayerGroupPlaying(iGroupIndex))
-	{
-		ClientSetQueuePoints(client, 0);
-	}
-	
-	if (IsPlayerGroupActive(iGroupIndex))
-	{
-		SetPlayerGroupInvitedPlayer(iGroupIndex, client, false);
-		SetPlayerGroupInvitedPlayerCount(iGroupIndex, client, 0);
-		SetPlayerGroupInvitedPlayerTime(iGroupIndex, client, 0.0);
-		
-		// Set the player's personal queue points to 0.
-		//ClientSetQueuePoints(client, 0);
-		
-		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-		GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-		CPrintToChat(client, "%T", "SF2 Joined Group", client, sGroupName);
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (i == client || !IsValidClient(i)) continue;
-			if (ClientGetPlayerGroup(i) == iGroupIndex)
-			{
-				CPrintToChat(i, "%T", "SF2 Player Joined Group", i, sName);
-			}
-		}
-	}
+#if defined _sf2_playergroups_included
+ #endinput
+#endif
+#define _sf2_playergroups_included
+
+#define SF2_MAX_PLAYER_GROUPS MAXPLAYERS
+#define SF2_MAX_PLAYER_GROUP_NAME_LENGTH 32
+
+static g_iPlayerGroupGlobalID = -1;
+static g_iPlayerCurrentGroup[MAXPLAYERS + 1] = { -1, ... };
+static bool:g_bPlayerGroupActive[SF2_MAX_PLAYER_GROUPS] = { false, ... };
+static g_iPlayerGroupLeader[SF2_MAX_PLAYER_GROUPS] = { -1, ... };
+static g_iPlayerGroupID[SF2_MAX_PLAYER_GROUPS] = { -1, ... };
+static g_iPlayerGroupQueuePoints[SF2_MAX_PLAYER_GROUPS];
+static g_bPlayerGroupPlaying[SF2_MAX_PLAYER_GROUPS] = { false, ... };
+static Handle:g_hPlayerGroupNames;
+static bool:g_bPlayerGroupInvitedPlayer[SF2_MAX_PLAYER_GROUPS][MAXPLAYERS + 1];
+static g_iPlayerGroupInvitedPlayerCount[SF2_MAX_PLAYER_GROUPS][MAXPLAYERS + 1];
+static Float:g_flPlayerGroupInvitedPlayerTime[SF2_MAX_PLAYER_GROUPS][MAXPLAYERS + 1];
+
+SetupPlayerGroups()
+{
+	g_iPlayerGroupGlobalID = -1;
+	g_hPlayerGroupNames = CreateTrie();
+}
+
+stock GetPlayerGroupFromID(iGroupID)
+{
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		if (GetPlayerGroupID(i) == iGroupID) return i;
+	}
+	
+	return -1;
+}
+
+SendPlayerGroupInvitation(client, iGroupID, iInviter=-1)
+{
+	if (!IsValidClient(client) || !IsClientParticipating(client))
+	{
+		if (IsValidClient(iInviter))
+		{
+			// TODO: Send message to the inviter that the client is invalid!
+		}
+		
+		return;
+	}
+	
+	if (!g_bPlayerEliminated[client])
+	{
+		if (IsValidClient(iInviter))
+		{
+			// TODO: Send message to the inviter that the client is currently in-game.
+		}
+		
+		return;
+	}
+	
+	new iGroupIndex = GetPlayerGroupFromID(iGroupID);
+	if (iGroupIndex == -1) return;
+	
+	new iMyGroupIndex = ClientGetPlayerGroup(client);
+	if (IsPlayerGroupActive(iMyGroupIndex))
+	{
+		if (IsValidClient(iInviter))
+		{
+			if (iMyGroupIndex == iGroupIndex)
+			{
+				CPrintToChat(iInviter, "%T", "SF2 Player In Group", iInviter);
+			}
+			else
+			{
+				CPrintToChat(iInviter, "%T", "SF2 Player In Another Group", iInviter);
+			}
+		}
+		
+		return;
+	}
+	
+	if (GetPlayerGroupMemberCount(iGroupIndex) >= GetMaxPlayersForRound())
+	{
+		if (IsValidClient(iInviter))
+		{
+			CPrintToChat(iInviter, "%T", "SF2 Group Is Full", iInviter);
+		}
+		
+		return;
+	}
+	
+	if (IsFakeClient(client))
+	{
+		ClientSetPlayerGroup(client, iGroupIndex);
+		return;
+	}
+	
+	// Anti-spam.
+	decl String:sName[MAX_NAME_LENGTH];
+	GetClientName(client, sName, sizeof(sName));
+	
+	if (IsValidClient(iInviter))
+	{
+		new Float:flNextInviteTime = GetPlayerGroupInvitedPlayerTime(iGroupIndex, client) + (20.0 * GetPlayerGroupInvitedPlayerCount(iGroupIndex, client));
+		if (GetGameTime() < flNextInviteTime)
+		{
+			CPrintToChat(iInviter, "%T", "SF2 No Group Invite Spam", iInviter, RoundFloat(flNextInviteTime - GetGameTime()), sName);
+			return;
+		}
+	}
+	
+	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	decl String:sLeaderName[64];
+	GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+	
+	new iGroupLeader = GetPlayerGroupLeader(iGroupIndex);
+	if (IsValidClient(iGroupLeader)) GetClientName(iGroupLeader, sLeaderName, sizeof(sLeaderName));
+	else strcopy(sLeaderName, sizeof(sLeaderName), "nobody");
+	
+	new Handle:hMenu = CreateMenu(Menu_GroupInvite);
+	SetMenuTitle(hMenu, "%t%T\n \n", "SF2 Prefix", "SF2 Group Invite Menu Description", client, sLeaderName, sGroupName);
+	
+	decl String:sGroupID[64];
+	IntToString(iGroupID, sGroupID, sizeof(sGroupID));
+	
+	decl String:sBuffer[256];
+	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
+	AddMenuItem(hMenu, sGroupID, sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	DisplayMenu(hMenu, client, 10);
+	
+	SetPlayerGroupInvitedPlayer(iGroupIndex, client, true);
+	SetPlayerGroupInvitedPlayerCount(iGroupIndex, client, GetPlayerGroupInvitedPlayerCount(iGroupIndex, client) + 1);
+	SetPlayerGroupInvitedPlayerTime(iGroupIndex, client, GetGameTime());
+	
+	if (IsValidClient(iInviter))
+	{
+		CPrintToChat(iInviter, "%T", "SF2 Group Invitation Sent", iInviter, sName);
+	}
+}
+
+public Menu_GroupInvite(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) 
+	{
+		CloseHandle(menu);
+	}
+	else if (action == MenuAction_Select)
+	{
+		if (param2 == 0)
+		{
+			decl String:sGroupID[64];
+			GetMenuItem(menu, param2, sGroupID, sizeof(sGroupID));
+			new iGroupIndex = GetPlayerGroupFromID(StringToInt(sGroupID));
+			if (IsPlayerGroupActive(iGroupIndex))
+			{
+				new iMyGroupIndex = ClientGetPlayerGroup(param1);
+				if (IsPlayerGroupActive(iMyGroupIndex))
+				{
+					if (iMyGroupIndex == iGroupIndex)
+					{
+						CPrintToChat(param1, "%T", "SF2 In Group", param1);
+					}
+					else
+					{
+						CPrintToChat(param1, "%T", "SF2 In Another Group", param1);
+					}
+				}
+				else if (GetPlayerGroupMemberCount(iGroupIndex) >= GetMaxPlayersForRound())
+				{
+					CPrintToChat(param1, "%T", "SF2 Group Is Full", param1);
+				}
+				else
+				{
+					ClientSetPlayerGroup(param1, iGroupIndex);
+				}
+			}
+			else
+			{
+				CPrintToChat(param1, "%T", "SF2 Group Does Not Exist", param1);
+			}
+		}
+	}
+}
+
+DisplayResetGroupQueuePointsMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayGroupMainMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return;
+	}
+	
+	new Handle:hMenu = CreateMenu(Menu_ResetGroupQueuePoints);
+	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Reset Group Queue Points Menu Title", client, "SF2 Reset Group Queue Points Menu Description", client);
+	
+	decl String:sBuffer[256];
+	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	
+	SetMenuExitBackButton(hMenu, true);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_ResetGroupQueuePoints(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select)
+	{
+		if (param2 == 0)
+		{
+			new iGroupIndex = ClientGetPlayerGroup(param1);
+			if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
+			{
+				SetPlayerGroupQueuePoints(iGroupIndex, 0);
+				
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsValidClient(i)) continue;
+					if (ClientGetPlayerGroup(i) == iGroupIndex)
+					{
+						CPrintToChat(i, "%T", "SF2 Group Queue Points Reset", i);
+					}
+				}
+			}
+			else
+			{
+				CPrintToChat(param1, "%T", "SF2 Not Group Leader", param1);
+			}
+		}
+		
+		DisplayAdminGroupMenuToClient(param1);
+	}
+}
+
+CheckPlayerGroup(iGroupIndex)
+{
+	if (!IsPlayerGroupActive(iGroupIndex)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START CheckPlayerGroup(%d)", iGroupIndex);
+#endif
+	
+	new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
+	if (iMemberCount <= 0)
+	{
+		RemovePlayerGroup(iGroupIndex);
+	}
+	else
+	{
+		// Remove any person that isn't participating.
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (ClientGetPlayerGroup(i) == iGroupIndex)
+			{
+				if (!IsValidClient(i) || !IsClientParticipating(i))
+				{
+#if defined DEBUG
+					if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("CheckPlayerGroup(%d): Invalid client detected (%d), removing from group", iGroupIndex, i);
+#endif
+					
+					ClientSetPlayerGroup(i, -1);
+				}
+			}
+		}
+		
+		iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
+		new iMaxPlayers = GetMaxPlayersForRound();
+		new iExcessMemberCount = (iMemberCount - iMaxPlayers);
+		
+		if (iExcessMemberCount > 0)
+		{
+#if defined DEBUG
+			if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("CheckPlayerGroup(%d): Excess members detected", iGroupIndex);
+#endif
+
+			new iGroupLeader = GetPlayerGroupLeader(iGroupIndex);
+			if (IsValidClient(iGroupLeader))
+			{
+				CPrintToChat(iGroupLeader, "%T", "SF2 Group Has Too Many Members", iGroupLeader);
+			}
+			
+			for (new i = 1, iCount; i <= MaxClients && iCount < iExcessMemberCount; i++)
+			{
+				if (!IsValidClient(i)) continue;
+				
+				if (ClientGetPlayerGroup(i) == iGroupIndex)
+				{
+					if (i == iGroupLeader) continue; // Don't kick off the group leader.
+					
+					ClientSetPlayerGroup(i, -1);
+					iCount++;
+				}
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END CheckPlayerGroup(%d)", iGroupIndex);
+#endif
+}
+
+stock GetPlayerGroupCount()
+{
+	new iCount;
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (IsPlayerGroupActive(i)) iCount++;
+	}
+	
+	return iCount;
+}
+
+stock CreatePlayerGroup()
+{
+	// Get an inactive group.
+	new iIndex = -1;
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i))
+		{
+			iIndex = i;
+			break;
+		}
+	}
+	
+	if (iIndex != -1)
+	{
+		g_bPlayerGroupActive[iIndex] = true;
+		g_iPlayerGroupGlobalID++;
+		SetPlayerGroupID(iIndex, g_iPlayerGroupGlobalID);
+		ClearPlayerGroupMembers(iIndex);
+		SetPlayerGroupQueuePoints(iIndex, 0);
+		SetPlayerGroupLeader(iIndex, -1);
+		SetPlayerGroupName(iIndex, "");
+		SetPlayerGroupPlaying(iIndex, false);
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			SetPlayerGroupInvitedPlayer(iIndex, i, false);
+			SetPlayerGroupInvitedPlayerCount(iIndex, i, 0);
+			SetPlayerGroupInvitedPlayerTime(iIndex, i, 0.0);
+		}
+	}
+	
+	return iIndex;
+}
+
+stock RemovePlayerGroup(iGroupIndex)
+{
+	if (!IsPlayerGroupActive(iGroupIndex)) return;
+	
+	ClearPlayerGroupMembers(iGroupIndex);
+	SetPlayerGroupQueuePoints(iGroupIndex, 0);
+	SetPlayerGroupPlaying(iGroupIndex, false);
+	SetPlayerGroupLeader(iGroupIndex, -1);
+	g_bPlayerGroupActive[iGroupIndex] = false;
+	SetPlayerGroupID(iGroupIndex, -1);
+}
+
+stock ClearPlayerGroupMembers(iGroupIndex)
+{
+	if (!IsPlayerGroupValid(iGroupIndex)) return;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (ClientGetPlayerGroup(i) == iGroupIndex)
+		{
+			ClientSetPlayerGroup(i, -1);
+		}
+	}
+}
+
+stock bool:GetPlayerGroupName(iGroupIndex, String:sBuffer[], iBufferLen)
+{
+	decl String:sGroupIndex[32];
+	IntToString(iGroupIndex, sGroupIndex, sizeof(sGroupIndex)); 
+	return GetTrieString(g_hPlayerGroupNames, sGroupIndex, sBuffer, iBufferLen);
+}
+
+stock SetPlayerGroupName(iGroupIndex, const String:sGroupName[])
+{
+	decl String:sGroupIndex[32];
+	IntToString(iGroupIndex, sGroupIndex, sizeof(sGroupIndex)); 
+	SetTrieString(g_hPlayerGroupNames, sGroupIndex, sGroupName);
+}
+
+stock GetPlayerGroupID(iGroupIndex)
+{
+	return g_iPlayerGroupID[iGroupIndex];
+}
+
+stock SetPlayerGroupID(iGroupIndex, iID)
+{
+	g_iPlayerGroupID[iGroupIndex] = iID;
+}
+
+stock bool:IsPlayerGroupActive(iGroupIndex)
+{
+	return IsPlayerGroupValid(iGroupIndex) && g_bPlayerGroupActive[iGroupIndex];
+}
+
+stock bool:IsPlayerGroupValid(iGroupIndex)
+{
+	return (iGroupIndex >= 0 && iGroupIndex < SF2_MAX_PLAYER_GROUPS);
+}
+
+stock GetPlayerGroupMemberCount(iGroupIndex)
+{
+	new iCount;
+
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+	
+		if (ClientGetPlayerGroup(i) == iGroupIndex)
+		{
+			iCount++;
+		}
+	}
+	
+	return iCount;
+}
+
+stock bool:IsPlayerGroupPlaying(iGroupIndex)
+{
+	return (IsPlayerGroupActive(iGroupIndex) && g_bPlayerGroupPlaying[iGroupIndex]);
+}
+
+stock SetPlayerGroupPlaying(iGroupIndex, bool:bToggle)
+{
+	g_bPlayerGroupPlaying[iGroupIndex] = bToggle;
+}
+
+stock GetPlayerGroupLeader(iGroupIndex)
+{
+	return g_iPlayerGroupLeader[iGroupIndex];
+}
+
+stock SetPlayerGroupLeader(iGroupIndex, iGroupLeader)
+{
+	g_iPlayerGroupLeader[iGroupIndex] = iGroupLeader;
+	
+	if (IsValidClient(iGroupLeader))
+	{
+		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+		GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+		CPrintToChat(iGroupLeader, "%T", "SF2 New Group Leader", iGroupLeader, sGroupName);
+		
+		decl String:sName[MAX_NAME_LENGTH];
+		GetClientName(iGroupLeader, sName, sizeof(sName));
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (iGroupLeader == i || !IsValidClient(i)) continue;
+			if (ClientGetPlayerGroup(i) == iGroupIndex)
+			{
+				CPrintToChat(i, "%T", "SF2 Player New Group Leader", i, sName);
+			}
+		}
+	}
+}
+
+PlayerGroupFindNewLeader(iGroupIndex)
+{
+	if (!IsPlayerGroupActive(iGroupIndex)) return -1;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		
+		if (ClientGetPlayerGroup(i) == iGroupIndex)
+		{
+			SetPlayerGroupLeader(iGroupIndex, i);
+			return i;
+		}
+	}
+	
+	return -1;
+}
+
+stock GetPlayerGroupQueuePoints(iGroupIndex)
+{
+	return g_iPlayerGroupQueuePoints[iGroupIndex];
+}
+
+stock SetPlayerGroupQueuePoints(iGroupIndex, iAmount)
+{
+	g_iPlayerGroupQueuePoints[iGroupIndex] = iAmount;
+}
+
+stock HasPlayerGroupInvitedPlayer(iGroupIndex, client)
+{
+	return g_bPlayerGroupInvitedPlayer[iGroupIndex][client];
+}
+
+stock SetPlayerGroupInvitedPlayer(iGroupIndex, client, bool:bToggle)
+{
+	g_bPlayerGroupInvitedPlayer[iGroupIndex][client] = bToggle;
+}
+
+stock GetPlayerGroupInvitedPlayerCount(iGroupIndex, client)
+{
+	return g_iPlayerGroupInvitedPlayerCount[iGroupIndex][client];
+}
+
+stock SetPlayerGroupInvitedPlayerCount(iGroupIndex, client, iAmount)
+{
+	g_iPlayerGroupInvitedPlayerCount[iGroupIndex][client] = iAmount;
+}
+
+stock Float:GetPlayerGroupInvitedPlayerTime(iGroupIndex, client)
+{
+	return g_flPlayerGroupInvitedPlayerTime[iGroupIndex][client];
+}
+
+stock SetPlayerGroupInvitedPlayerTime(iGroupIndex, client, Float:flTime)
+{
+	g_flPlayerGroupInvitedPlayerTime[iGroupIndex][client] = flTime;
+}
+
+stock ClientGetPlayerGroup(client)
+{
+	return g_iPlayerCurrentGroup[client];
+}
+
+stock ClientSetPlayerGroup(client, iGroupIndex)
+{
+	new iOldPlayerGroup = ClientGetPlayerGroup(client);
+	if (iOldPlayerGroup == iGroupIndex) return; // No change.
+	
+	g_iPlayerCurrentGroup[client] = iGroupIndex;
+	
+	decl String:sName[MAX_NAME_LENGTH];
+	GetClientName(client, sName, sizeof(sName));
+	
+	if (IsPlayerGroupActive(iOldPlayerGroup))
+	{
+		SetPlayerGroupInvitedPlayer(iOldPlayerGroup, client, false);
+		SetPlayerGroupInvitedPlayerCount(iOldPlayerGroup, client, 0);
+		SetPlayerGroupInvitedPlayerTime(iOldPlayerGroup, client, 0.0);
+		
+		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+		GetPlayerGroupName(iOldPlayerGroup, sGroupName, sizeof(sGroupName));
+		CPrintToChat(client, "%T", "SF2 Left Group", client, sGroupName);
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (i == client || !IsValidClient(i)) continue;
+			if (ClientGetPlayerGroup(i) == iOldPlayerGroup)
+			{
+				CPrintToChat(i, "%T", "SF2 Player Left Group", i, sName);
+			}
+		}
+	
+		new iOldGroupLeader = GetPlayerGroupLeader(iOldPlayerGroup);
+		if (iOldGroupLeader == client)
+		{
+			new iOldGroupNewLeader = PlayerGroupFindNewLeader(iOldPlayerGroup);
+			if (iOldGroupNewLeader == -1)
+			{
+				// Couldn't find a new leader. This group has no leader!
+				SetPlayerGroupLeader(iOldPlayerGroup, -1);
+			}
+		}
+		
+		CheckPlayerGroup(iOldPlayerGroup);
+	}
+	
+	if (IsPlayerGroupPlaying(iGroupIndex))
+	{
+		ClientSetQueuePoints(client, 0);
+	}
+	
+	if (IsPlayerGroupActive(iGroupIndex))
+	{
+		SetPlayerGroupInvitedPlayer(iGroupIndex, client, false);
+		SetPlayerGroupInvitedPlayerCount(iGroupIndex, client, 0);
+		SetPlayerGroupInvitedPlayerTime(iGroupIndex, client, 0.0);
+		
+		// Set the player's personal queue points to 0.
+		//ClientSetQueuePoints(client, 0);
+		
+		decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+		GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+		CPrintToChat(client, "%T", "SF2 Joined Group", client, sGroupName);
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (i == client || !IsValidClient(i)) continue;
+			if (ClientGetPlayerGroup(i) == iGroupIndex)
+			{
+				CPrintToChat(i, "%T", "SF2 Player Joined Group", i, sName);
+			}
+		}
+	}
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/playergroups/menus.sp b/addons/sourcemod/scripting/rytp_horror/playergroups/menus.sp
index 9cdecb7..633b512 100644
--- a/addons/sourcemod/scripting/rytp_horror/playergroups/menus.sp
+++ b/addons/sourcemod/scripting/rytp_horror/playergroups/menus.sp
@@ -1,620 +1,620 @@
-#if defined _sf2_playergroups_menus
- #endinput
-#endif
-
-#define _sf2_playergroups_menus
-
-DisplayGroupMainMenuToClient(client)
-{
-	new Handle:hMenu = CreateMenu(Menu_GroupMain);
-	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Group Main Menu Title", client, "SF2 Group Main Menu Description", client);
-	
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	new bool:bGroupIsActive = IsPlayerGroupActive(iGroupIndex);
-	
-	decl String:sBuffer[256];
-	if (bGroupIsActive && GetPlayerGroupLeader(iGroupIndex) == client)
-	{
-		Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Group Menu Title", client);
-	}
-	else
-	{
-		Format(sBuffer, sizeof(sBuffer), "%T", "SF2 View Current Group Info Menu Title", client);
-	}
-	
-	AddMenuItem(hMenu, "0", sBuffer, bGroupIsActive ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Create Group Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, bGroupIsActive ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Leave Group Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, bGroupIsActive ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	
-	SetMenuExitBackButton(hMenu, true);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_GroupMain(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayMenu(g_hMenuMain, param1, 30);
-	}
-	else if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0: DisplayAdminGroupMenuToClient(param1);
-			case 1: DisplayCreateGroupMenuToClient(param1);
-			case 2: DisplayLeaveGroupMenuToClient(param1);
-		}
-	}
-}
-
-DisplayCreateGroupMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (IsPlayerGroupActive(iGroupIndex))
-	{
-		// He's already in a group. Take him back to the main menu.
-		DisplayGroupMainMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 In Group", client);
-		return;
-	}
-	
-	new Handle:hMenu = CreateMenu(Menu_CreateGroup);
-	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Create Group Menu Title", client, "SF2 Create Group Menu Description", client, GetConVarInt(g_cvMaxPlayers), g_iPlayerQueuePoints[client]);
-	
-	decl String:sBuffer[256];
-	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_CreateGroup(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Select)
-	{
-		if (param2 == 0)
-		{
-			new iGroupIndex = ClientGetPlayerGroup(param1);
-			if (IsPlayerGroupActive(iGroupIndex))
-			{
-				CPrintToChat(param1, "%T", "SF2 In Group", param1);
-			}
-			else
-			{
-				iGroupIndex = CreatePlayerGroup();
-				if (iGroupIndex != -1)
-				{
-					new iQueuePoints = g_iPlayerQueuePoints[param1];
-				
-					decl String:sGroupName[64];
-					Format(sGroupName, sizeof(sGroupName), "Group %d", iGroupIndex);
-					SetPlayerGroupName(iGroupIndex, sGroupName);
-					ClientSetPlayerGroup(param1, iGroupIndex);
-					SetPlayerGroupLeader(iGroupIndex, param1);
-					SetPlayerGroupQueuePoints(iGroupIndex, iQueuePoints);
-					
-					CPrintToChat(param1, "%T", "SF2 Created Group", param1, sGroupName);
-				}
-				else
-				{
-					CPrintToChat(param1, "%T", "SF2 Max Groups Reached", param1);
-				}
-			}
-		}
-		
-		DisplayGroupMainMenuToClient(param1);
-	}
-}
-
-DisplayLeaveGroupMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayGroupMainMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-	
-	new Handle:hMenu = CreateMenu(Menu_LeaveGroup);
-	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Leave Group Menu Title", client, "SF2 Leave Group Menu Description", client, sGroupName);
-	
-	decl String:sBuffer[256];
-	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_LeaveGroup(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Select)
-	{
-		if (param2 == 0)
-		{
-			new iGroupIndex = ClientGetPlayerGroup(param1);
-			if (!IsPlayerGroupActive(iGroupIndex))
-			{
-				CPrintToChat(param1, "%T", "SF2 Group Does Not Exist", param1);
-			}
-			else
-			{
-				ClientSetPlayerGroup(param1, -1);
-			}
-		}
-		
-		DisplayGroupMainMenuToClient(param1);
-	}
-}
-
-DisplayAdminGroupMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayGroupMainMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-	
-	decl String:sLeaderName[MAX_NAME_LENGTH];
-	new iGroupLeader = GetPlayerGroupLeader(iGroupIndex);
-	if (IsValidClient(iGroupLeader)) GetClientName(iGroupLeader, sLeaderName, sizeof(sLeaderName));
-	else strcopy(sLeaderName, sizeof(sLeaderName), "---");
-	
-	new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
-	new iMaxPlayers = GetConVarInt(g_cvMaxPlayers);
-	new iQueuePoints = GetPlayerGroupQueuePoints(iGroupIndex);
-	
-	new Handle:hMenu = CreateMenu(Menu_AdminGroup);
-	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Admin Group Menu Title", client, "SF2 Admin Group Menu Description", client, sGroupName, sLeaderName, iMemberCount, iMaxPlayers, iQueuePoints);
-	
-	decl String:sBuffer[256];
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 View Group Members Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Set Group Name Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Set Group Leader Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Invite To Group Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client && iMemberCount < iMaxPlayers ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Kick From Group Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client && iMemberCount > 1 ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Reset Group Queue Points Menu Title", client);
-	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
-	
-	SetMenuExitBackButton(hMenu, true);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_AdminGroup(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayGroupMainMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select)
-	{
-		new iGroupIndex = ClientGetPlayerGroup(param1);
-		if (IsPlayerGroupActive(iGroupIndex))
-		{
-			switch (param2)
-			{
-				case 0: DisplayViewGroupMembersMenuToClient(param1);
-				case 1: DisplaySetGroupNameMenuToClient(param1);
-				case 2: DisplaySetGroupLeaderMenuToClient(param1);
-				case 3: DisplayInviteToGroupMenuToClient(param1);
-				case 4: DisplayKickFromGroupMenuToClient(param1);
-				case 5: DisplayResetGroupQueuePointsMenuToClient(param1);
-			}
-		}
-		else
-		{
-			DisplayGroupMainMenuToClient(param1);
-			CPrintToChat(param1, "%T", "SF2 Group Does Not Exist", param1);
-		}
-	}
-}
-
-DisplayViewGroupMembersMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	new Handle:hPlayers = CreateArray();
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		
-		new iTempGroup = ClientGetPlayerGroup(i);
-		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
-		
-		PushArrayCell(hPlayers, i);
-	}
-	
-	new iPlayerCount = GetArraySize(hPlayers);
-	if (iPlayerCount)
-	{
-		new Handle:hMenu = CreateMenu(Menu_ViewGroupMembers);
-		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 View Group Members Menu Title", client, "SF2 View Group Members Menu Description", client);
-		
-		decl String:sUserId[32];
-		decl String:sName[MAX_NAME_LENGTH];
-		
-		for (new i = 0; i < iPlayerCount; i++)
-		{
-			new iClient = GetArrayCell(hPlayers, i);
-			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
-			GetClientName(iClient, sName, sizeof(sName));
-			AddMenuItem(hMenu, sUserId, sName);
-		}
-		
-		SetMenuExitBackButton(hMenu, true);
-		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-	}
-	else
-	{
-		// No players left for the taking!
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 No Players Available", client);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public Menu_ViewGroupMembers(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select) DisplayAdminGroupMenuToClient(param1);
-}
-
-DisplaySetGroupLeaderMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return;
-	}
-	
-	new Handle:hPlayers = CreateArray();
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		
-		new iTempGroup = ClientGetPlayerGroup(i);
-		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
-		if (i == client) continue;
-		
-		PushArrayCell(hPlayers, i);
-	}
-	
-	new iPlayerCount = GetArraySize(hPlayers);
-	if (iPlayerCount)
-	{
-		new Handle:hMenu = CreateMenu(Menu_SetGroupLeader);
-		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Set Group Leader Menu Title", client, "SF2 Set Group Leader Menu Description", client);
-		
-		decl String:sUserId[32];
-		decl String:sName[MAX_NAME_LENGTH];
-		
-		for (new i = 0; i < iPlayerCount; i++)
-		{
-			new iClient = GetArrayCell(hPlayers, i);
-			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
-			GetClientName(iClient, sName, sizeof(sName));
-			AddMenuItem(hMenu, sUserId, sName);
-		}
-		
-		SetMenuExitBackButton(hMenu, true);
-		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-	}
-	else
-	{
-		// No players left for the taking!
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 No Players Available", client);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public Menu_SetGroupLeader(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select)
-	{
-		new iGroupIndex = ClientGetPlayerGroup(param1);
-		if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
-		{
-			decl String:sInfo[64];
-			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
-			new userid = StringToInt(sInfo);
-			new iPlayer = GetClientOfUserId(userid);
-			
-			if (ClientGetPlayerGroup(iPlayer) == iGroupIndex && IsValidClient(iPlayer))
-			{
-				decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-				decl String:sName[MAX_NAME_LENGTH];
-				GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-				GetClientName(iPlayer, sName, sizeof(sName));
-				
-				SetPlayerGroupLeader(iGroupIndex, iPlayer);
-			}
-			else
-			{
-				CPrintToChat(param1, "%T", "SF2 Player Not In Group", param1);
-			}
-		}
-		
-		DisplayAdminGroupMenuToClient(param1);
-	}
-}
-
-DisplayKickFromGroupMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return;
-	}
-	
-	new Handle:hPlayers = CreateArray();
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		
-		new iTempGroup = ClientGetPlayerGroup(i);
-		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
-		if (i == client) continue;
-		
-		PushArrayCell(hPlayers, i);
-	}
-	
-	new iPlayerCount = GetArraySize(hPlayers);
-	if (iPlayerCount)
-	{
-		new Handle:hMenu = CreateMenu(Menu_KickFromGroup);
-		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Kick From Group Menu Title", client, "SF2 Kick From Group Menu Description", client);
-		
-		decl String:sUserId[32];
-		decl String:sName[MAX_NAME_LENGTH];
-		
-		for (new i = 0; i < iPlayerCount; i++)
-		{
-			new iClient = GetArrayCell(hPlayers, i);
-			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
-			GetClientName(iClient, sName, sizeof(sName));
-			AddMenuItem(hMenu, sUserId, sName);
-		}
-		
-		SetMenuExitBackButton(hMenu, true);
-		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-	}
-	else
-	{
-		// No players left for the taking!
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 No Players Available", client);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public Menu_KickFromGroup(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select)
-	{
-		new iGroupIndex = ClientGetPlayerGroup(param1);
-		if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
-		{
-			decl String:sInfo[64];
-			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
-			new userid = StringToInt(sInfo);
-			new iPlayer = GetClientOfUserId(userid);
-			
-			if (ClientGetPlayerGroup(iPlayer) == iGroupIndex)
-			{
-				decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-				decl String:sName[MAX_NAME_LENGTH];
-				GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
-				GetClientName(iPlayer, sName, sizeof(sName));
-				
-				CPrintToChat(iPlayer, "%T", "SF2 Kicked From Group", iPlayer, sGroupName);
-				ClientSetPlayerGroup(iPlayer, -1);
-				CPrintToChat(param1, "%T", "SF2 Player Kicked From Group", param1, sName);
-			}
-			else
-			{
-				CPrintToChat(param1, "%T", "SF2 Player Not In Group", param1);
-			}
-		}
-		
-		DisplayKickFromGroupMenuToClient(param1);
-	}
-}
-
-DisplaySetGroupNameMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayGroupMainMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return;
-	}
-	
-	new Handle:hMenu = CreateMenu(Menu_SetGroupName);
-	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Set Group Name Menu Title", client, "SF2 Set Group Name Menu Description", client);
-	
-	decl String:sBuffer[256];
-	Format(sBuffer, sizeof(sBuffer), "%T", "Back", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-}
-
-public Menu_SetGroupName(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select) DisplayAdminGroupMenuToClient(param1);
-}
-
-DisplayInviteToGroupMenuToClient(client)
-{
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		// His group isn't valid anymore. Take him back to the main menu.
-		DisplayGroupMainMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return;
-	}
-	
-	if (GetPlayerGroupMemberCount(iGroupIndex) >= GetConVarInt(g_cvMaxPlayers))
-	{
-		// His group is full!
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 Group Is Full", client);
-		return;
-	}
-	
-	new Handle:hPlayers = CreateArray();
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i) || !IsClientParticipating(i)) continue;
-		
-		new iTempGroup = ClientGetPlayerGroup(i);
-		if (IsPlayerGroupActive(iTempGroup)) continue;
-		if (!g_bPlayerEliminated[i]) continue;
-		
-		PushArrayCell(hPlayers, i);
-	}
-	
-	new iPlayerCount = GetArraySize(hPlayers);
-	if (iPlayerCount)
-	{
-		new Handle:hMenu = CreateMenu(Menu_InviteToGroup);
-		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Invite To Group Menu Title", client, "SF2 Invite To Group Menu Description", client);
-		
-		decl String:sUserId[32];
-		decl String:sName[MAX_NAME_LENGTH];
-		
-		for (new i = 0; i < iPlayerCount; i++)
-		{
-			new iClient = GetArrayCell(hPlayers, i);
-			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
-			GetClientName(iClient, sName, sizeof(sName));
-			AddMenuItem(hMenu, sUserId, sName);
-		}
-		
-		SetMenuExitBackButton(hMenu, true);
-		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
-	}
-	else
-	{
-		// No players left for the taking!
-		DisplayAdminGroupMenuToClient(client);
-		CPrintToChat(client, "%T", "SF2 No Players Available", client);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public Menu_InviteToGroup(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_End) CloseHandle(menu);
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
-	}
-	else if (action == MenuAction_Select)
-	{
-		new iGroupIndex = ClientGetPlayerGroup(param1);
-		if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
-		{
-			decl String:sInfo[64];
-			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
-			new userid = StringToInt(sInfo);
-			new iInvitedPlayer = GetClientOfUserId(userid);
-			SendPlayerGroupInvitation(iInvitedPlayer, GetPlayerGroupID(iGroupIndex), param1);
-		}
-		
-		DisplayInviteToGroupMenuToClient(param1);
-	}
+#if defined _sf2_playergroups_menus
+ #endinput
+#endif
+
+#define _sf2_playergroups_menus
+
+DisplayGroupMainMenuToClient(client)
+{
+	new Handle:hMenu = CreateMenu(Menu_GroupMain);
+	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Group Main Menu Title", client, "SF2 Group Main Menu Description", client);
+	
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	new bool:bGroupIsActive = IsPlayerGroupActive(iGroupIndex);
+	
+	decl String:sBuffer[256];
+	if (bGroupIsActive && GetPlayerGroupLeader(iGroupIndex) == client)
+	{
+		Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Admin Group Menu Title", client);
+	}
+	else
+	{
+		Format(sBuffer, sizeof(sBuffer), "%T", "SF2 View Current Group Info Menu Title", client);
+	}
+	
+	AddMenuItem(hMenu, "0", sBuffer, bGroupIsActive ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Create Group Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, bGroupIsActive ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Leave Group Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, bGroupIsActive ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	
+	SetMenuExitBackButton(hMenu, true);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_GroupMain(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayMenu(g_hMenuMain, param1, 30);
+	}
+	else if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0: DisplayAdminGroupMenuToClient(param1);
+			case 1: DisplayCreateGroupMenuToClient(param1);
+			case 2: DisplayLeaveGroupMenuToClient(param1);
+		}
+	}
+}
+
+DisplayCreateGroupMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (IsPlayerGroupActive(iGroupIndex))
+	{
+		// He's already in a group. Take him back to the main menu.
+		DisplayGroupMainMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 In Group", client);
+		return;
+	}
+	
+	new Handle:hMenu = CreateMenu(Menu_CreateGroup);
+	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Create Group Menu Title", client, "SF2 Create Group Menu Description", client, GetMaxPlayersForRound(), g_iPlayerQueuePoints[client]);
+	
+	decl String:sBuffer[256];
+	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_CreateGroup(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Select)
+	{
+		if (param2 == 0)
+		{
+			new iGroupIndex = ClientGetPlayerGroup(param1);
+			if (IsPlayerGroupActive(iGroupIndex))
+			{
+				CPrintToChat(param1, "%T", "SF2 In Group", param1);
+			}
+			else
+			{
+				iGroupIndex = CreatePlayerGroup();
+				if (iGroupIndex != -1)
+				{
+					new iQueuePoints = g_iPlayerQueuePoints[param1];
+				
+					decl String:sGroupName[64];
+					Format(sGroupName, sizeof(sGroupName), "Group %d", iGroupIndex);
+					SetPlayerGroupName(iGroupIndex, sGroupName);
+					ClientSetPlayerGroup(param1, iGroupIndex);
+					SetPlayerGroupLeader(iGroupIndex, param1);
+					SetPlayerGroupQueuePoints(iGroupIndex, iQueuePoints);
+					
+					CPrintToChat(param1, "%T", "SF2 Created Group", param1, sGroupName);
+				}
+				else
+				{
+					CPrintToChat(param1, "%T", "SF2 Max Groups Reached", param1);
+				}
+			}
+		}
+		
+		DisplayGroupMainMenuToClient(param1);
+	}
+}
+
+DisplayLeaveGroupMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayGroupMainMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+	
+	new Handle:hMenu = CreateMenu(Menu_LeaveGroup);
+	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Leave Group Menu Title", client, "SF2 Leave Group Menu Description", client, sGroupName);
+	
+	decl String:sBuffer[256];
+	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_LeaveGroup(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Select)
+	{
+		if (param2 == 0)
+		{
+			new iGroupIndex = ClientGetPlayerGroup(param1);
+			if (!IsPlayerGroupActive(iGroupIndex))
+			{
+				CPrintToChat(param1, "%T", "SF2 Group Does Not Exist", param1);
+			}
+			else
+			{
+				ClientSetPlayerGroup(param1, -1);
+			}
+		}
+		
+		DisplayGroupMainMenuToClient(param1);
+	}
+}
+
+DisplayAdminGroupMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayGroupMainMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+	
+	decl String:sLeaderName[MAX_NAME_LENGTH];
+	new iGroupLeader = GetPlayerGroupLeader(iGroupIndex);
+	if (IsValidClient(iGroupLeader)) GetClientName(iGroupLeader, sLeaderName, sizeof(sLeaderName));
+	else strcopy(sLeaderName, sizeof(sLeaderName), "---");
+	
+	new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
+	new iMaxPlayers = GetMaxPlayersForRound();
+	new iQueuePoints = GetPlayerGroupQueuePoints(iGroupIndex);
+	
+	new Handle:hMenu = CreateMenu(Menu_AdminGroup);
+	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Admin Group Menu Title", client, "SF2 Admin Group Menu Description", client, sGroupName, sLeaderName, iMemberCount, iMaxPlayers, iQueuePoints);
+	
+	decl String:sBuffer[256];
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 View Group Members Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Set Group Name Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Set Group Leader Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Invite To Group Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client && iMemberCount < iMaxPlayers ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Kick From Group Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client && iMemberCount > 1 ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	Format(sBuffer, sizeof(sBuffer), "%T", "SF2 Reset Group Queue Points Menu Title", client);
+	AddMenuItem(hMenu, "0", sBuffer, iGroupLeader == client ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
+	
+	SetMenuExitBackButton(hMenu, true);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_AdminGroup(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayGroupMainMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select)
+	{
+		new iGroupIndex = ClientGetPlayerGroup(param1);
+		if (IsPlayerGroupActive(iGroupIndex))
+		{
+			switch (param2)
+			{
+				case 0: DisplayViewGroupMembersMenuToClient(param1);
+				case 1: DisplaySetGroupNameMenuToClient(param1);
+				case 2: DisplaySetGroupLeaderMenuToClient(param1);
+				case 3: DisplayInviteToGroupMenuToClient(param1);
+				case 4: DisplayKickFromGroupMenuToClient(param1);
+				case 5: DisplayResetGroupQueuePointsMenuToClient(param1);
+			}
+		}
+		else
+		{
+			DisplayGroupMainMenuToClient(param1);
+			CPrintToChat(param1, "%T", "SF2 Group Does Not Exist", param1);
+		}
+	}
+}
+
+DisplayViewGroupMembersMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	new Handle:hPlayers = CreateArray();
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		
+		new iTempGroup = ClientGetPlayerGroup(i);
+		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
+		
+		PushArrayCell(hPlayers, i);
+	}
+	
+	new iPlayerCount = GetArraySize(hPlayers);
+	if (iPlayerCount)
+	{
+		new Handle:hMenu = CreateMenu(Menu_ViewGroupMembers);
+		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 View Group Members Menu Title", client, "SF2 View Group Members Menu Description", client);
+		
+		decl String:sUserId[32];
+		decl String:sName[MAX_NAME_LENGTH];
+		
+		for (new i = 0; i < iPlayerCount; i++)
+		{
+			new iClient = GetArrayCell(hPlayers, i);
+			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
+			GetClientName(iClient, sName, sizeof(sName));
+			AddMenuItem(hMenu, sUserId, sName);
+		}
+		
+		SetMenuExitBackButton(hMenu, true);
+		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+	}
+	else
+	{
+		// No players left for the taking!
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 No Players Available", client);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public Menu_ViewGroupMembers(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select) DisplayAdminGroupMenuToClient(param1);
+}
+
+DisplaySetGroupLeaderMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return;
+	}
+	
+	new Handle:hPlayers = CreateArray();
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		
+		new iTempGroup = ClientGetPlayerGroup(i);
+		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
+		if (i == client) continue;
+		
+		PushArrayCell(hPlayers, i);
+	}
+	
+	new iPlayerCount = GetArraySize(hPlayers);
+	if (iPlayerCount)
+	{
+		new Handle:hMenu = CreateMenu(Menu_SetGroupLeader);
+		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Set Group Leader Menu Title", client, "SF2 Set Group Leader Menu Description", client);
+		
+		decl String:sUserId[32];
+		decl String:sName[MAX_NAME_LENGTH];
+		
+		for (new i = 0; i < iPlayerCount; i++)
+		{
+			new iClient = GetArrayCell(hPlayers, i);
+			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
+			GetClientName(iClient, sName, sizeof(sName));
+			AddMenuItem(hMenu, sUserId, sName);
+		}
+		
+		SetMenuExitBackButton(hMenu, true);
+		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+	}
+	else
+	{
+		// No players left for the taking!
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 No Players Available", client);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public Menu_SetGroupLeader(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select)
+	{
+		new iGroupIndex = ClientGetPlayerGroup(param1);
+		if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
+		{
+			decl String:sInfo[64];
+			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
+			new userid = StringToInt(sInfo);
+			new iPlayer = GetClientOfUserId(userid);
+			
+			if (ClientGetPlayerGroup(iPlayer) == iGroupIndex && IsValidClient(iPlayer))
+			{
+				decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+				decl String:sName[MAX_NAME_LENGTH];
+				GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+				GetClientName(iPlayer, sName, sizeof(sName));
+				
+				SetPlayerGroupLeader(iGroupIndex, iPlayer);
+			}
+			else
+			{
+				CPrintToChat(param1, "%T", "SF2 Player Not In Group", param1);
+			}
+		}
+		
+		DisplayAdminGroupMenuToClient(param1);
+	}
+}
+
+DisplayKickFromGroupMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return;
+	}
+	
+	new Handle:hPlayers = CreateArray();
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		
+		new iTempGroup = ClientGetPlayerGroup(i);
+		if (!IsPlayerGroupActive(iTempGroup) || iTempGroup != iGroupIndex) continue;
+		if (i == client) continue;
+		
+		PushArrayCell(hPlayers, i);
+	}
+	
+	new iPlayerCount = GetArraySize(hPlayers);
+	if (iPlayerCount)
+	{
+		new Handle:hMenu = CreateMenu(Menu_KickFromGroup);
+		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Kick From Group Menu Title", client, "SF2 Kick From Group Menu Description", client);
+		
+		decl String:sUserId[32];
+		decl String:sName[MAX_NAME_LENGTH];
+		
+		for (new i = 0; i < iPlayerCount; i++)
+		{
+			new iClient = GetArrayCell(hPlayers, i);
+			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
+			GetClientName(iClient, sName, sizeof(sName));
+			AddMenuItem(hMenu, sUserId, sName);
+		}
+		
+		SetMenuExitBackButton(hMenu, true);
+		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+	}
+	else
+	{
+		// No players left for the taking!
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 No Players Available", client);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public Menu_KickFromGroup(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select)
+	{
+		new iGroupIndex = ClientGetPlayerGroup(param1);
+		if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
+		{
+			decl String:sInfo[64];
+			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
+			new userid = StringToInt(sInfo);
+			new iPlayer = GetClientOfUserId(userid);
+			
+			if (ClientGetPlayerGroup(iPlayer) == iGroupIndex)
+			{
+				decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+				decl String:sName[MAX_NAME_LENGTH];
+				GetPlayerGroupName(iGroupIndex, sGroupName, sizeof(sGroupName));
+				GetClientName(iPlayer, sName, sizeof(sName));
+				
+				CPrintToChat(iPlayer, "%T", "SF2 Kicked From Group", iPlayer, sGroupName);
+				ClientSetPlayerGroup(iPlayer, -1);
+				CPrintToChat(param1, "%T", "SF2 Player Kicked From Group", param1, sName);
+			}
+			else
+			{
+				CPrintToChat(param1, "%T", "SF2 Player Not In Group", param1);
+			}
+		}
+		
+		DisplayKickFromGroupMenuToClient(param1);
+	}
+}
+
+DisplaySetGroupNameMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayGroupMainMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return;
+	}
+	
+	new Handle:hMenu = CreateMenu(Menu_SetGroupName);
+	SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Set Group Name Menu Title", client, "SF2 Set Group Name Menu Description", client);
+	
+	decl String:sBuffer[256];
+	Format(sBuffer, sizeof(sBuffer), "%T", "Back", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+}
+
+public Menu_SetGroupName(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select) DisplayAdminGroupMenuToClient(param1);
+}
+
+DisplayInviteToGroupMenuToClient(client)
+{
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		// His group isn't valid anymore. Take him back to the main menu.
+		DisplayGroupMainMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return;
+	}
+	
+	if (GetPlayerGroupMemberCount(iGroupIndex) >= GetMaxPlayersForRound())
+	{
+		// His group is full!
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 Group Is Full", client);
+		return;
+	}
+	
+	new Handle:hPlayers = CreateArray();
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i) || !IsClientParticipating(i)) continue;
+		
+		new iTempGroup = ClientGetPlayerGroup(i);
+		if (IsPlayerGroupActive(iTempGroup)) continue;
+		if (!g_bPlayerEliminated[i]) continue;
+		
+		PushArrayCell(hPlayers, i);
+	}
+	
+	new iPlayerCount = GetArraySize(hPlayers);
+	if (iPlayerCount)
+	{
+		new Handle:hMenu = CreateMenu(Menu_InviteToGroup);
+		SetMenuTitle(hMenu, "%t%T\n \n%T\n \n", "SF2 Prefix", "SF2 Invite To Group Menu Title", client, "SF2 Invite To Group Menu Description", client);
+		
+		decl String:sUserId[32];
+		decl String:sName[MAX_NAME_LENGTH];
+		
+		for (new i = 0; i < iPlayerCount; i++)
+		{
+			new iClient = GetArrayCell(hPlayers, i);
+			IntToString(GetClientUserId(iClient), sUserId, sizeof(sUserId));
+			GetClientName(iClient, sName, sizeof(sName));
+			AddMenuItem(hMenu, sUserId, sName);
+		}
+		
+		SetMenuExitBackButton(hMenu, true);
+		DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
+	}
+	else
+	{
+		// No players left for the taking!
+		DisplayAdminGroupMenuToClient(client);
+		CPrintToChat(client, "%T", "SF2 No Players Available", client);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public Menu_InviteToGroup(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_End) CloseHandle(menu);
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack) DisplayAdminGroupMenuToClient(param1);
+	}
+	else if (action == MenuAction_Select)
+	{
+		new iGroupIndex = ClientGetPlayerGroup(param1);
+		if (IsPlayerGroupActive(iGroupIndex) && GetPlayerGroupLeader(iGroupIndex) == param1)
+		{
+			decl String:sInfo[64];
+			GetMenuItem(menu, param2, sInfo, sizeof(sInfo));
+			new userid = StringToInt(sInfo);
+			new iInvitedPlayer = GetClientOfUserId(userid);
+			SendPlayerGroupInvitation(iInvitedPlayer, GetPlayerGroupID(iGroupIndex), param1);
+		}
+		
+		DisplayInviteToGroupMenuToClient(param1);
+	}
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/profiles.sp b/addons/sourcemod/scripting/rytp_horror/profiles.sp
index 7ebe648..54ca036 100644
--- a/addons/sourcemod/scripting/rytp_horror/profiles.sp
+++ b/addons/sourcemod/scripting/rytp_horror/profiles.sp
@@ -1,1189 +1,1189 @@
-#if defined _sf2_profiles_included
- #endinput
-#endif
-#define _sf2_profiles_included
-
-#define FILE_PROFILES "configs/sf2/profiles.cfg"
-#define FILE_PROFILES_PACKS "configs/sf2/profiles_packs.cfg"
-#define FILE_PROFILES_PACKS_DIR "configs/sf2/profiles/packs"
-
-static Handle:g_hBossProfileList = INVALID_HANDLE;
-static Handle:g_hSelectableBossProfileList = INVALID_HANDLE;
-
-static Handle:g_hBossProfileNames = INVALID_HANDLE;
-static Handle:g_hBossProfileData = INVALID_HANDLE;
-
-new Handle:g_cvBossProfilePack = INVALID_HANDLE;
-new Handle:g_cvBossProfilePackDefault = INVALID_HANDLE;
-
-new Handle:g_hBossPackConfig = INVALID_HANDLE;
-
-new Handle:g_cvBossPackEndOfMapVote;
-new Handle:g_cvBossPackVoteStartTime;
-new Handle:g_cvBossPackVoteStartRound;
-new Handle:g_cvBossPackVoteShuffle;
-
-static bool:g_bBossPackVoteEnabled = false;
-
-#if defined METHODMAPS
-
-methodmap SF2BossProfile
-{
-	property int Index
-	{
-		public get() { return _:this; }
-	}
-	
-	property int UniqueProfileIndex
-	{
-		public get() { return GetBossProfileUniqueProfileIndex(this.Index); }
-	}
-	
-	property int Skin
-	{
-		public get() { return GetBossProfileSkin(this.Index); }
-	}
-	
-	property int BodyGroups
-	{
-		public get() { return GetBossProfileBodyGroups(this.Index); }
-	}
-	
-	property float ModelScale
-	{
-		public get() { return GetBossProfileModelScale(this.Index); }
-	}
-	
-	property int Type
-	{
-		public get() { return GetBossProfileType(this.Index); }
-	}
-	
-	property int Flags
-	{
-		public get() { return GetBossProfileFlags(this.Index); }
-	}
-	
-	property float SearchRadius
-	{
-		public get() { return GetBossProfileSearchRadius(this.Index); }
-	}
-	
-	property float FOV
-	{
-		public get() { return GetBossProfileFOV(this.Index); }
-	}
-	
-	property float TurnRate
-	{
-		public get() { return GetBossProfileTurnRate(this.Index); }
-	}
-	
-	property float AngerStart
-	{
-		public get() { return GetBossProfileAngerStart(this.Index); }
-	}
-	
-	property float AngerAddOnPageGrab
-	{
-		public get() { return GetBossProfileAngerAddOnPageGrab(this.Index); }
-	}
-	
-	property float AngerAddOnPageGrabTimeDiff
-	{
-		public get() { return GetBossProfileAngerPageGrabTimeDiff(this.Index); }
-	}
-	
-	property float InstantKillRadius
-	{
-		public get() { return GetBossProfileInstantKillRadius(this.Index); }
-	}
-	
-	property float ScareRadius
-	{
-		public get() { return GetBossProfileScareRadius(this.Index); }
-	}
-	
-	property float ScareCooldown
-	{
-		public get() { return GetBossProfileScareCooldown(this.Index); }
-	}
-	
-	property int TeleportType
-	{
-		public get() { return GetBossProfileTeleportType(this.Index); }
-	}
-	
-	public float GetSpeed(int difficulty)
-	{
-		return GetBossProfileSpeed(this.Index, difficulty);
-	}
-	
-	public float GetMaxSpeed(int difficulty)
-	{
-		return GetBossProfileMaxSpeed(this.Index, difficulty);
-	}
-	
-	public void GetEyePositionOffset(float buffer[3])
-	{
-		GetBossProfileEyePositionOffset(this.Index, buffer);
-	}
-	
-	public void GetEyeAngleOffset(float buffer[3])
-	{
-		GetBossProfileEyeAngleOffset(this.Index, buffer);
-	}
-}
-
-#endif
-
-#include "rytp_horror/profiles/profile_chaser.sp"
-
-enum
-{
-	BossProfileData_UniqueProfileIndex,
-	BossProfileData_Type,
-	BossProfileData_ModelScale,
-	BossProfileData_Skin,
-	BossProfileData_Body,
-	BossProfileData_Flags,
-	
-	BossProfileData_SpeedEasy,
-	BossProfileData_SpeedNormal,
-	BossProfileData_SpeedHard,
-	BossProfileData_SpeedInsane,
-	
-	BossProfileData_WalkSpeedEasy,
-	BossProfileData_WalkSpeedNormal,
-	BossProfileData_WalkSpeedHard,
-	BossProfileData_WalkSpeedInsane,
-	
-	BossProfileData_AirSpeedEasy,
-	BossProfileData_AirSpeedNormal,
-	BossProfileData_AirSpeedHard,
-	BossProfileData_AirSpeedInsane,
-	
-	BossProfileData_MaxSpeedEasy,
-	BossProfileData_MaxSpeedNormal,
-	BossProfileData_MaxSpeedHard,
-	BossProfileData_MaxSpeedInsane,
-	
-	BossProfileData_MaxWalkSpeedEasy,
-	BossProfileData_MaxWalkSpeedNormal,
-	BossProfileData_MaxWalkSpeedHard,
-	BossProfileData_MaxWalkSpeedInsane,
-	
-	BossProfileData_MaxAirSpeedEasy,
-	BossProfileData_MaxAirSpeedNormal,
-	BossProfileData_MaxAirSpeedHard,
-	BossProfileData_MaxAirSpeedInsane,
-	
-	BossProfileData_SearchRange,
-	BossProfileData_FieldOfView,
-	BossProfileData_TurnRate,
-	BossProfileData_EyePosOffsetX,
-	BossProfileData_EyePosOffsetY,
-	BossProfileData_EyePosOffsetZ,
-	BossProfileData_EyeAngOffsetX,
-	BossProfileData_EyeAngOffsetY,
-	BossProfileData_EyeAngOffsetZ,
-	BossProfileData_AngerStart,
-	BossProfileData_AngerAddOnPageGrab,
-	BossProfileData_AngerPageGrabTimeDiffReq,
-	BossProfileData_InstantKillRadius,
-	
-	BossProfileData_ScareRadius,
-	BossProfileData_ScareCooldown,
-	
-	BossProfileData_TeleportType,
-	BossProfileData_MaxStats
-};
-
-InitializeBossProfiles()
-{
-	g_hBossProfileNames = CreateTrie();
-	g_hBossProfileData = CreateArray(BossProfileData_MaxStats);
-	
-	g_cvBossProfilePack = CreateConVar("sf2_boss_profile_pack", "", "The boss pack referenced in profiles_packs.cfg that should be loaded.", FCVAR_NOTIFY | FCVAR_DONTRECORD);
-	g_cvBossProfilePackDefault = CreateConVar("sf2_boss_profile_pack_default", "", "If the boss pack defined in sf2_boss_profile_pack is blank or could not be loaded, this pack will be used instead.", FCVAR_NOTIFY);
-	g_cvBossPackEndOfMapVote = CreateConVar("sf2_boss_profile_pack_endvote", "0", "Enables/Disables a boss pack vote at the end of the map.");
-	g_cvBossPackVoteStartTime = CreateConVar("sf2_boss_profile_pack_endvote_start", "4", "Specifies when to start the vote based on time remaining on the map, in minutes.", FCVAR_NOTIFY);
-	g_cvBossPackVoteStartRound = CreateConVar("sf2_boss_profile_pack_endvote_startround", "2", "Specifies when to start the vote based on rounds remaining on the map.", FCVAR_NOTIFY);
-	g_cvBossPackVoteShuffle = CreateConVar("sf2_boss_profile_pack_endvote_shuffle", "0", "Shuffles the menu options of boss pack endvotes if enabled.");
-	
-	InitializeChaserProfiles();
-}
-
-BossProfilesOnMapEnd()
-{
-	ClearBossProfiles();
-}
-
-/**
- *	Clears all data and memory currently in use by all boss profiles.
- */
-ClearBossProfiles()
-{
-	if (g_hBossProfileList != INVALID_HANDLE)
-	{
-		CloseHandle(g_hBossProfileList);
-		g_hBossProfileList = INVALID_HANDLE;
-	}
-	
-	if (g_hSelectableBossProfileList != INVALID_HANDLE)
-	{
-		CloseHandle(g_hSelectableBossProfileList);
-		g_hSelectableBossProfileList = INVALID_HANDLE;
-	}
-	
-	ClearTrie(g_hBossProfileNames);
-	ClearArray(g_hBossProfileData);
-	
-	ClearChaserProfiles();
-}
-
-ReloadBossProfiles()
-{
-	if (g_hConfig != INVALID_HANDLE)
-	{
-		CloseHandle(g_hConfig);
-		g_hConfig = INVALID_HANDLE;
-	}
-	
-	if (g_hBossPackConfig != INVALID_HANDLE)
-	{
-		CloseHandle(g_hBossPackConfig);
-		g_hBossPackConfig = INVALID_HANDLE;
-	}
-	
-	// Clear and reload the lists.
-	ClearBossProfiles();
-	
-	g_hConfig = CreateKeyValues("root");
-	g_hBossPackConfig = CreateKeyValues("root");
-	
-	if (g_hBossProfileList == INVALID_HANDLE)
-	{
-		g_hBossProfileList = CreateArray(SF2_MAX_PROFILE_NAME_LENGTH);
-	}
-	
-	if (g_hSelectableBossProfileList == INVALID_HANDLE)
-	{
-		g_hSelectableBossProfileList = CreateArray(SF2_MAX_PROFILE_NAME_LENGTH);
-	}
-	
-	decl String:configPath[PLATFORM_MAX_PATH];
-	
-	// First load from configs/sf2/profiles.cfg
-	BuildPath(Path_SM, configPath, sizeof(configPath), FILE_PROFILES);
-	LoadProfilesFromFile(configPath);
-	
-	BuildPath(Path_SM, configPath, sizeof(configPath), FILE_PROFILES_PACKS);
-	FileToKeyValues(g_hBossPackConfig, configPath);
-	
-	g_bBossPackVoteEnabled = true;
-	
-	// Try loading boss packs, if they're set to load.
-	KvRewind(g_hBossPackConfig);
-	if (KvJumpToKey(g_hBossPackConfig, "packs"))
-	{
-		if (KvGotoFirstSubKey(g_hBossPackConfig))
-		{
-			new endVoteItemCount = 0;
-		
-			decl String:forceLoadBossPackName[128];
-			GetConVarString(g_cvBossProfilePack, forceLoadBossPackName, sizeof(forceLoadBossPackName));
-			
-			new bool:voteBossPackLoaded = false;
-			
-			do
-			{
-				decl String:bossPackName[128];
-				KvGetSectionName(g_hBossPackConfig, bossPackName, sizeof(bossPackName));
-				
-				new bool:autoLoad = bool:KvGetNum(g_hBossPackConfig, "autoload");
-				
-				if (autoLoad || (strlen(forceLoadBossPackName) > 0 && StrEqual(forceLoadBossPackName, bossPackName)))
-				{
-					decl String:packConfigFile[PLATFORM_MAX_PATH];
-					KvGetString(g_hBossPackConfig, "file", packConfigFile, sizeof(packConfigFile));
-					
-					decl String:packConfigFilePath[PLATFORM_MAX_PATH];
-					Format(packConfigFilePath, sizeof(packConfigFilePath), "%s/%s", FILE_PROFILES_PACKS_DIR, packConfigFile);
-					
-					BuildPath(Path_SM, configPath, sizeof(configPath), packConfigFilePath);
-					LoadProfilesFromFile(configPath);
-					
-					if (!voteBossPackLoaded)
-					{
-						if (StrEqual(forceLoadBossPackName, bossPackName))
-						{
-							voteBossPackLoaded = true;
-						}
-					}
-				}
-				
-				if (!autoLoad)
-				{
-					endVoteItemCount++; 
-				}
-			}
-			while (KvGotoNextKey(g_hBossPackConfig));
-			
-			KvGoBack(g_hBossPackConfig);
-			
-			if (!voteBossPackLoaded)
-			{
-				GetConVarString(g_cvBossProfilePackDefault, forceLoadBossPackName, sizeof(forceLoadBossPackName));
-				if (strlen(forceLoadBossPackName) > 0)
-				{
-					if (KvJumpToKey(g_hBossPackConfig, forceLoadBossPackName))
-					{
-						decl String:packConfigFile[PLATFORM_MAX_PATH];
-						KvGetString(g_hBossPackConfig, "file", packConfigFile, sizeof(packConfigFile));
-						
-						decl String:packConfigFilePath[PLATFORM_MAX_PATH];
-						Format(packConfigFilePath, sizeof(packConfigFilePath), "%s/%s", FILE_PROFILES_PACKS_DIR, packConfigFile);
-						
-						BuildPath(Path_SM, configPath, sizeof(configPath), packConfigFilePath);
-						LoadProfilesFromFile(configPath);
-					}
-				}
-			}
-			
-			if (endVoteItemCount <= 0)
-			{
-				g_bBossPackVoteEnabled = false;
-			}
-		}
-		else
-		{
-			g_bBossPackVoteEnabled = false;
-		}
-	}
-	else
-	{
-		g_bBossPackVoteEnabled = false;
-	}
-}
-
-static LoadProfilesFromFile(const String:configPath[])
-{
-	LogSF2Message("Loading boss profiles from file %s...", configPath);
-	
-	if (!FileExists(configPath))
-	{
-		LogSF2Message("File not found! Skipping...");
-		return;
-	}
-	
-	new Handle:kv = CreateKeyValues("root");
-	if (!FileToKeyValues(kv, configPath))
-	{
-		CloseHandle(kv);
-		LogSF2Message("Unexpected error while reading file! Skipping...");
-		return;
-	}
-	else
-	{
-		if (KvGotoFirstSubKey(kv))
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			decl String:sProfileLoadFailReason[512];
-			
-			new iLoadedCount = 0;
-			
-			do
-			{
-				KvGetSectionName(kv, sProfile, sizeof(sProfile));
-				if (LoadBossProfile(kv, sProfile, sProfileLoadFailReason, sizeof(sProfileLoadFailReason)))
-				{
-					iLoadedCount++;
-					LogSF2Message("%s...", sProfile);
-				}
-				else
-				{
-					LogSF2Message("%s...FAILED (reason: %s)", sProfile, sProfileLoadFailReason);
-				}
-			}
-			while (KvGotoNextKey(kv));
-			
-			LogSF2Message("Loaded %d boss profile(s) from file!", iLoadedCount);
-		}
-		else
-		{
-			LogSF2Message("No boss profiles loaded from file!");
-		}
-		
-		CloseHandle(kv);
-	}
-}
-
-/**
- *	Loads a profile in the current KeyValues position in kv.
- */
-static bool:LoadBossProfile(Handle:kv, const String:sProfile[], String:sLoadFailReasonBuffer[], iLoadFailReasonBufferLen)
-{
-	new iBossType = KvGetNum(kv, "type", SF2BossType_Unknown);
-	if (iBossType == SF2BossType_Unknown || iBossType >= SF2BossType_MaxTypes) 
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "boss type is unknown!");
-		return false;
-	}
-	
-	new Float:flBossModelScale = KvGetFloat(kv, "model_scale", 1.0);
-	if (flBossModelScale <= 0.0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "model_scale must be a value greater than 0!");
-		return false;
-	}
-	
-	new iBossSkin = KvGetNum(kv, "skin");
-	if (iBossSkin < 0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "skin must be a value that is at least 0!");
-		return false;
-	}
-	
-	new iBossBodyGroups = KvGetNum(kv, "body");
-	if (iBossBodyGroups < 0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "body must be a value that is at least 0!");
-		return false;
-	}
-	
-	new Float:flBossAngerStart = KvGetFloat(kv, "anger_start", 1.0);
-	if (flBossAngerStart < 0.0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "anger_start must be a value that is at least 0!");
-		return false;
-	}
-	
-	new Float:flBossInstantKillRadius = KvGetFloat(kv, "kill_radius");
-	if (flBossInstantKillRadius < 0.0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "kill_radius must be a value that is at least 0!");
-		return false;
-	}
-	
-	new Float:flBossScareRadius = KvGetFloat(kv, "scare_radius");
-	if (flBossScareRadius < 0.0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "scare_radius must be a value that is at least 0!");
-		return false;
-	}
-	
-	new iBossTeleportType = KvGetNum(kv, "teleport_type");
-	if (iBossTeleportType < 0)
-	{
-		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "unknown teleport type!");
-		return false;
-	}
-	
-	new Float:flBossFOV = KvGetFloat(kv, "fov", 90.0);
-	if (flBossFOV < 0.0)
-	{
-		flBossFOV = 0.0;
-	}
-	else if (flBossFOV > 360.0)
-	{
-		flBossFOV = 360.0;
-	}
-	
-	new Float:flBossMaxTurnRate = KvGetFloat(kv, "turnrate", 90.0);
-	if (flBossMaxTurnRate < 0.0)
-	{
-		flBossMaxTurnRate = 0.0;
-	}
-	
-	new Float:flBossScareCooldown = KvGetFloat(kv, "scare_cooldown");
-	if (flBossScareCooldown < 0.0)
-	{
-		// clamp value 
-		flBossScareCooldown = 0.0;
-	}
-	
-	new Float:flBossAngerAddOnPageGrab = KvGetFloat(kv, "anger_add_on_page_grab", -1.0);
-	if (flBossAngerAddOnPageGrab < 0.0)
-	{
-		flBossAngerAddOnPageGrab = KvGetFloat(kv, "anger_page_add", -1.0);		// backwards compatibility
-		if (flBossAngerAddOnPageGrab < 0.0)
-		{
-			flBossAngerAddOnPageGrab = 0.0;
-		}
-	}
-	
-	new Float:flBossAngerPageGrabTimeDiffReq = KvGetFloat(kv, "anger_req_page_grab_time_diff", -1.0);
-	if (flBossAngerPageGrabTimeDiffReq < 0.0)
-	{
-		flBossAngerPageGrabTimeDiffReq = KvGetFloat(kv, "anger_page_time_diff", -1.0);		// backwards compatibility
-		if (flBossAngerPageGrabTimeDiffReq < 0.0)
-		{
-			flBossAngerPageGrabTimeDiffReq = 0.0;
-		}
-	}
-	
-	new Float:flBossSearchRadius = KvGetFloat(kv, "search_radius", -1.0);
-	if (flBossSearchRadius < 0.0)
-	{
-		flBossSearchRadius = KvGetFloat(kv, "search_range", -1.0);		// backwards compatibility
-		if (flBossSearchRadius < 0.0)
-		{
-			flBossSearchRadius = 0.0;
-		}
-	}
-	
-	new Float:flBossDefaultSpeed = KvGetFloat(kv, "speed", 150.0);
-	new Float:flBossSpeedEasy = KvGetFloat(kv, "speed_easy", flBossDefaultSpeed);
-	new Float:flBossSpeedHard = KvGetFloat(kv, "speed_hard", flBossDefaultSpeed);
-	new Float:flBossSpeedInsane = KvGetFloat(kv, "speed_insane", flBossDefaultSpeed);
-	
-	new Float:flBossDefaultMaxSpeed = KvGetFloat(kv, "speed_max", 150.0);
-	new Float:flBossMaxSpeedEasy = KvGetFloat(kv, "speed_max_easy", flBossDefaultMaxSpeed);
-	new Float:flBossMaxSpeedHard = KvGetFloat(kv, "speed_max_hard", flBossDefaultMaxSpeed);
-	new Float:flBossMaxSpeedInsane = KvGetFloat(kv, "speed_max_insane", flBossDefaultMaxSpeed);
-	
-	decl Float:flBossEyePosOffset[3];
-	KvGetVector(kv, "eye_pos", flBossEyePosOffset);
-	
-	decl Float:flBossEyeAngOffset[3];
-	KvGetVector(kv, "eye_ang_offset", flBossEyeAngOffset);
-	
-	// Parse through flags.
-	new iBossFlags = 0;
-	if (KvGetNum(kv, "static_shake")) iBossFlags |= SFF_HASSTATICSHAKE;
-	if (KvGetNum(kv, "static_on_look")) iBossFlags |= SFF_STATICONLOOK;
-	if (KvGetNum(kv, "static_on_radius")) iBossFlags |= SFF_STATICONRADIUS;
-	if (KvGetNum(kv, "proxies")) iBossFlags |= SFF_PROXIES;
-	if (KvGetNum(kv, "jumpscare")) iBossFlags |= SFF_HASJUMPSCARE;
-	if (KvGetNum(kv, "sound_sight_enabled")) iBossFlags |= SFF_HASSIGHTSOUNDS;
-	if (KvGetNum(kv, "sound_static_loop_local_enabled")) iBossFlags |= SFF_HASSTATICLOOPLOCALSOUND;
-	if (KvGetNum(kv, "view_shake", 1)) iBossFlags |= SFF_HASVIEWSHAKE;
-	if (KvGetNum(kv, "copy")) iBossFlags |= SFF_COPIES;
-	if (KvGetNum(kv, "wander_move", 1)) iBossFlags |= SFF_WANDERMOVE;
-	
-	// Try validating unique profile.
-	new iUniqueProfileIndex = -1;
-	
-	switch (iBossType)
-	{
-		case SF2BossType_Chaser:
-		{
-			if (!LoadChaserBossProfile(kv, sProfile, iUniqueProfileIndex, sLoadFailReasonBuffer, iLoadFailReasonBufferLen))
-			{
-				return false;
-			}
-		}
-	}
-	
-	// Add the section to our config.
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile, true);
-	KvCopySubkeys(kv, g_hConfig);
-	
-	new bool:createNewBoss = false;
-	new iIndex = FindStringInArray(GetBossProfileList(), sProfile);
-	if (iIndex == -1)
-	{
-		createNewBoss = true;
-	}
-	
-	// Add to/Modify our array.
-	if (createNewBoss)
-	{
-		iIndex = PushArrayCell(g_hBossProfileData, -1);
-		SetTrieValue(g_hBossProfileNames, sProfile, iIndex);
-		
-		// Add to the boss list since it's not there already.
-		PushArrayString(GetBossProfileList(), sProfile);
-	}
-	
-	SetArrayCell(g_hBossProfileData, iIndex, iUniqueProfileIndex, BossProfileData_UniqueProfileIndex);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, iBossType, BossProfileData_Type);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossModelScale, BossProfileData_ModelScale);
-	SetArrayCell(g_hBossProfileData, iIndex, iBossSkin, BossProfileData_Skin);
-	SetArrayCell(g_hBossProfileData, iIndex, iBossBodyGroups, BossProfileData_Body);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, iBossFlags, BossProfileData_Flags);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossDefaultSpeed, BossProfileData_SpeedNormal);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossSpeedEasy, BossProfileData_SpeedEasy);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossSpeedHard, BossProfileData_SpeedHard);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossSpeedInsane, BossProfileData_SpeedInsane);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossDefaultMaxSpeed, BossProfileData_MaxSpeedNormal);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxSpeedEasy, BossProfileData_MaxSpeedEasy);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxSpeedHard, BossProfileData_MaxSpeedHard);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxSpeedInsane, BossProfileData_MaxSpeedInsane);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossEyePosOffset[0], BossProfileData_EyePosOffsetX);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossEyePosOffset[1], BossProfileData_EyePosOffsetY);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossEyePosOffset[2], BossProfileData_EyePosOffsetZ);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossEyeAngOffset[0], BossProfileData_EyeAngOffsetX);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossEyeAngOffset[1], BossProfileData_EyeAngOffsetY);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossEyeAngOffset[2], BossProfileData_EyeAngOffsetZ);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossAngerStart, BossProfileData_AngerStart);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossAngerAddOnPageGrab, BossProfileData_AngerAddOnPageGrab);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossAngerPageGrabTimeDiffReq, BossProfileData_AngerPageGrabTimeDiffReq);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossInstantKillRadius, BossProfileData_InstantKillRadius);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossScareRadius, BossProfileData_ScareRadius);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossScareCooldown, BossProfileData_ScareCooldown);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, iBossTeleportType, BossProfileData_TeleportType);
-	
-	SetArrayCell(g_hBossProfileData, iIndex, flBossSearchRadius, BossProfileData_SearchRange);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossFOV, BossProfileData_FieldOfView);
-	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxTurnRate, BossProfileData_TurnRate);
-	
-	if (bool:KvGetNum(kv, "enable_random_selection", 1))
-	{
-		if (FindStringInArray(GetSelectableBossProfileList(), sProfile) == -1)
-		{
-			// Add to the selectable boss list if it isn't there already.
-			PushArrayString(GetSelectableBossProfileList(), sProfile);
-		}
-	}
-	else
-	{
-		new selectIndex = FindStringInArray(GetSelectableBossProfileList(), sProfile);
-		if (selectIndex != -1)
-		{
-			RemoveFromArray(GetSelectableBossProfileList(), selectIndex);
-		}
-	}
-	
-	if (KvGotoFirstSubKey(kv))
-	{
-		decl String:s2[64], String:s3[64], String:s4[PLATFORM_MAX_PATH], String:s5[PLATFORM_MAX_PATH];
-		
-		do
-		{
-			KvGetSectionName(kv, s2, sizeof(s2));
-			
-			if (!StrContains(s2, "sound_"))
-			{
-				for (new i = 1;; i++)
-				{
-					IntToString(i, s3, sizeof(s3));
-					KvGetString(kv, s3, s4, sizeof(s4));
-					if (!s4[0]) break;
-					
-					PrecacheSound2(s4);
-				}
-			}
-			else if (StrEqual(s2, "download"))
-			{
-				for (new i = 1;; i++)
-				{
-					IntToString(i, s3, sizeof(s3));
-					KvGetString(kv, s3, s4, sizeof(s4));
-					if (!s4[0]) break;
-					
-					AddFileToDownloadsTable(s4);
-				}
-			}
-			else if (StrEqual(s2, "mod_precache"))
-			{
-				for (new i = 1;; i++)
-				{
-					IntToString(i, s3, sizeof(s3));
-					KvGetString(kv, s3, s4, sizeof(s4));
-					if (!s4[0]) break;
-					
-					PrecacheModel(s4, true);
-				}
-			}
-			else if (StrEqual(s2, "mat_download"))
-			{	
-				for (new i = 1;; i++)
-				{
-					IntToString(i, s3, sizeof(s3));
-					KvGetString(kv, s3, s4, sizeof(s4));
-					if (!s4[0]) break;
-					
-					Format(s5, sizeof(s5), "%s.vtf", s4);
-					AddFileToDownloadsTable(s5);
-					Format(s5, sizeof(s5), "%s.vmt", s4);
-					AddFileToDownloadsTable(s5);
-				}
-			}
-			else if (StrEqual(s2, "mod_download"))
-			{
-				static const String:extensions[][] = { ".mdl", ".phy", ".dx80.vtx", ".dx90.vtx", ".sw.vtx", ".vvd" };
-				
-				for (new i = 1;; i++)
-				{
-					IntToString(i, s3, sizeof(s3));
-					KvGetString(kv, s3, s4, sizeof(s4));
-					if (!s4[0]) break;
-					
-					for (new is = 0; is < sizeof(extensions); is++)
-					{
-						Format(s5, sizeof(s5), "%s%s", s4, extensions[is]);
-						AddFileToDownloadsTable(s5);
-					}
-				}
-			}
-		}
-		while (KvGotoNextKey(kv));
-		
-		KvGoBack(kv);
-	}
-	
-	return true;
-}
-
-static Handle:g_hBossPackVoteMapTimer;
-static Handle:g_hBossPackVoteTimer;
-static bool:g_bBossPackVoteCompleted;
-static bool:g_bBossPackVoteStarted;
-
-InitializeBossPackVotes()
-{
-	g_hBossPackVoteMapTimer = INVALID_HANDLE;
-	g_hBossPackVoteTimer = INVALID_HANDLE;
-	g_bBossPackVoteCompleted = false;
-	g_bBossPackVoteStarted = false;
-}
-
-SetupTimeLimitTimerForBossPackVote()
-{
-	new time;
-	if (GetMapTimeLeft(time) && time > 0)
-	{
-		if (GetConVarBool(g_cvBossPackEndOfMapVote) && g_bBossPackVoteEnabled && !g_bBossPackVoteCompleted && !g_bBossPackVoteStarted)
-		{
-			new startTime = GetConVarInt(g_cvBossPackVoteStartTime) * 60;
-			if ((time - startTime) <= 0)
-			{
-				if (!IsVoteInProgress())
-				{
-					InitiateBossPackVote();
-				}
-				else
-				{
-					g_hBossPackVoteTimer = CreateTimer(5.0, Timer_BossPackVoteLoop, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-				}
-			}
-			else
-			{
-				if (g_hBossPackVoteMapTimer != INVALID_HANDLE)
-				{
-					CloseHandle(g_hBossPackVoteMapTimer);
-					g_hBossPackVoteMapTimer = INVALID_HANDLE;
-				}
-				
-				g_hBossPackVoteMapTimer = CreateTimer(float(time - startTime), Timer_StartBossPackVote, _, TIMER_FLAG_NO_MAPCHANGE);
-			}
-		}
-	}
-}
-
-CheckRoundLimitForBossPackVote(roundCount)
-{
-	if (!GetConVarBool(g_cvBossPackEndOfMapVote) || !g_bBossPackVoteEnabled || g_bBossPackVoteStarted || g_bBossPackVoteCompleted) return;
-	
-	if (g_cvMaxRounds == INVALID_HANDLE) return;
-	
-	if (GetConVarInt(g_cvMaxRounds) > 0)
-	{
-		if (roundCount >= (GetConVarInt(g_cvMaxRounds) - GetConVarInt(g_cvBossPackVoteStartRound)))
-		{
-			if (!IsVoteInProgress())
-			{
-				InitiateBossPackVote();
-			}
-			else
-			{
-				g_hBossPackVoteTimer = CreateTimer(5.0, Timer_BossPackVoteLoop, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			}
-		}
-	}
-	
-	CloseHandle(g_cvMaxRounds);
-}
-
-InitiateBossPackVote()
-{
-	if (g_bBossPackVoteStarted || g_bBossPackVoteCompleted || IsVoteInProgress()) return;
-	
-	// Gather boss packs, if any.
-	if (g_hBossPackConfig == INVALID_HANDLE) return;
-	
-	KvRewind(g_hBossPackConfig);
-	if (!KvJumpToKey(g_hBossPackConfig, "packs")) return;
-	if (!KvGotoFirstSubKey(g_hBossPackConfig)) return;
-	
-	new Handle:voteMenu = CreateMenu(Menu_BossPackVote);
-	SetMenuTitle(voteMenu, "%t%t\n \n", "SF2 Prefix", "SF2 Boss Pack Vote Menu Title");
-	SetMenuExitBackButton(voteMenu, false);
-	SetMenuExitButton(voteMenu, false);
-	
-	new Handle:menuDisplayNamesTrie = CreateTrie();
-	new Handle:menuOptionsInfo = CreateArray(128);
-	
-	do
-	{
-		if (!bool:KvGetNum(g_hBossPackConfig, "autoload") && bool:KvGetNum(g_hBossPackConfig, "show_in_vote", 1))
-		{
-			decl String:bossPack[128];
-			KvGetSectionName(g_hBossPackConfig, bossPack, sizeof(bossPack));
-			
-			decl String:bossPackName[64];
-			KvGetString(g_hBossPackConfig, "name", bossPackName, sizeof(bossPackName), bossPack);
-			
-			SetTrieString(menuDisplayNamesTrie, bossPack, bossPackName);
-			PushArrayString(menuOptionsInfo, bossPack);
-		}
-	}
-	while (KvGotoNextKey(g_hBossPackConfig));
-	
-	if (GetArraySize(menuOptionsInfo) == 0)
-	{
-		CloseHandle(menuDisplayNamesTrie);
-		CloseHandle(menuOptionsInfo);
-		CloseHandle(voteMenu);
-		return;
-	}
-	
-	if (GetConVarBool(g_cvBossPackVoteShuffle))
-	{
-		SortADTArray(menuOptionsInfo, Sort_Random, Sort_String);
-	}
-	
-	for (new i = 0; i < GetArraySize(menuOptionsInfo); i++)
-	{
-		decl String:bossPack[128], String:bossPackName[64];
-		GetArrayString(menuOptionsInfo, i, bossPack, sizeof(bossPack));
-		GetTrieString(menuDisplayNamesTrie, bossPack, bossPackName, sizeof(bossPackName));
-		
-		AddMenuItem(voteMenu, bossPack, bossPackName);
-	}
-	
-	CloseHandle(menuDisplayNamesTrie);
-	CloseHandle(menuOptionsInfo);
-	
-	g_bBossPackVoteStarted = true;
-	if (g_hBossPackVoteMapTimer != INVALID_HANDLE)
-	{
-		CloseHandle(g_hBossPackVoteMapTimer);
-		g_hBossPackVoteMapTimer = INVALID_HANDLE;
-	}
-	
-	if (g_hBossPackVoteTimer != INVALID_HANDLE)
-	{
-		CloseHandle(g_hBossPackVoteTimer);
-		g_hBossPackVoteTimer = INVALID_HANDLE;
-	}
-	
-	VoteMenuToAll(voteMenu, 20);
-}
-
-public Menu_BossPackVote(Handle:menu, MenuAction:action, param1, param2)
-{
-	switch (action)
-	{
-		case MenuAction_VoteStart:
-		{
-			g_bBossPackVoteStarted = true;
-		}
-		case MenuAction_VoteEnd:
-		{
-			g_bBossPackVoteCompleted = true;
-		
-			decl String:bossPack[128], String:bossPackName[64];
-			GetMenuItem(menu, param1, bossPack, sizeof(bossPack), _, bossPackName, sizeof(bossPackName));
-			
-			SetConVarString(g_cvBossProfilePack, bossPack);
-			
-			CPrintToChatAll("%t%t", "SF2 Prefix", "SF2 Boss Pack Vote Successful", bossPackName);
-		}
-		case MenuAction_End:
-		{
-			g_bBossPackVoteStarted = false;
-			CloseHandle(menu);
-		}
-	}
-}
-
-public Action:Timer_StartBossPackVote(Handle:timer)
-{
-	if (timer != g_hBossPackVoteMapTimer) return;
-	
-	g_hBossPackVoteTimer = CreateTimer(5.0, Timer_BossPackVoteLoop, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hBossPackVoteTimer, true);
-}
-
-public Action:Timer_BossPackVoteLoop(Handle:timer)
-{
-	if (timer != g_hBossPackVoteTimer || g_bBossPackVoteCompleted || g_bBossPackVoteStarted) return Plugin_Stop;
-	
-	if (!IsVoteInProgress())
-	{
-		g_hBossPackVoteTimer = INVALID_HANDLE;
-		InitiateBossPackVote();
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-bool:IsProfileValid(const String:sProfile[])
-{
-	return bool:(FindStringInArray(GetBossProfileList(), sProfile) != -1);
-}
-
-stock GetProfileNum(const String:sProfile[], const String:keyValue[], defaultValue=0)
-{
-	if (!IsProfileValid(sProfile)) return defaultValue;
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	return KvGetNum(g_hConfig, keyValue, defaultValue);
-}
-
-stock Float:GetProfileFloat(const String:sProfile[], const String:keyValue[], Float:defaultValue=0.0)
-{
-	if (!IsProfileValid(sProfile)) return defaultValue;
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	return KvGetFloat(g_hConfig, keyValue, defaultValue);
-}
-
-stock bool:GetProfileVector(const String:sProfile[], const String:keyValue[], Float:buffer[3], const Float:defaultValue[3]=NULL_VECTOR)
-{
-	for (new i = 0; i < 3; i++) buffer[i] = defaultValue[i];
-	
-	if (!IsProfileValid(sProfile)) return false;
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	KvGetVector(g_hConfig, keyValue, buffer, defaultValue);
-	return true;
-}
-
-stock bool:GetProfileColor(const String:sProfile[], 
-	const String:keyValue[], 
-	&r, 
-	&g, 
-	&b, 
-	&a,
-	dr=255,
-	dg=255,
-	db=255,
-	da=255)
-{
-	r = dr;
-	g = dg;
-	b = db;
-	a = da;
-	
-	if (!IsProfileValid(sProfile)) return false;
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	decl String:sValue[64];
-	KvGetString(g_hConfig, keyValue, sValue, sizeof(sValue));
-	
-	if (strlen(sValue) != 0)
-	{
-		KvGetColor(g_hConfig, keyValue, r, g, b, a);
-	}
-	
-	return true;
-}
-
-stock bool:GetProfileString(const String:sProfile[], const String:keyValue[], String:buffer[], bufferlen, const String:defaultValue[]="")
-{
-	strcopy(buffer, bufferlen, defaultValue);
-	
-	if (!IsProfileValid(sProfile)) return false;
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	KvGetString(g_hConfig, keyValue, buffer, bufferlen, defaultValue);
-	return true;
-}
-
-GetBossProfileIndexFromName(const String:sProfile[])
-{
-	new iReturn = -1;
-	GetTrieValue(g_hBossProfileNames, sProfile, iReturn);
-	return iReturn;
-}
-
-GetBossProfileUniqueProfileIndex(iProfileIndex)
-{
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_UniqueProfileIndex);
-}
-
-GetBossProfileSkin(iProfileIndex)
-{
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Skin);
-}
-
-GetBossProfileBodyGroups(iProfileIndex)
-{
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Body);
-}
-
-Float:GetBossProfileModelScale(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_ModelScale);
-}
-
-GetBossProfileType(iProfileIndex)
-{
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Type);
-}
-
-GetBossProfileFlags(iProfileIndex)
-{
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Flags);
-}
-
-Float:GetBossProfileSpeed(iProfileIndex, iDifficulty)
-{
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedEasy);
-		case Difficulty_Hard: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedHard);
-		case Difficulty_Insane: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedInsane);
-	}
-	
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedNormal);
-}
-
-Float:GetBossProfileMaxSpeed(iProfileIndex, iDifficulty)
-{
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedEasy);
-		case Difficulty_Hard: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedHard);
-		case Difficulty_Insane: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedInsane);
-	}
-	
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedNormal);
-}
-
-Float:GetBossProfileSearchRadius(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SearchRange);
-}
-
-Float:GetBossProfileFOV(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_FieldOfView);
-}
-
-Float:GetBossProfileTurnRate(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_TurnRate);
-}
-
-GetBossProfileEyePositionOffset(iProfileIndex, Float:buffer[3])
-{
-	buffer[0] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyePosOffsetX);
-	buffer[1] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyePosOffsetY);
-	buffer[2] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyePosOffsetZ);
-}
-
-GetBossProfileEyeAngleOffset(iProfileIndex, Float:buffer[3])
-{
-	buffer[0] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyeAngOffsetX);
-	buffer[1] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyeAngOffsetY);
-	buffer[2] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyeAngOffsetZ);
-}
-
-Float:GetBossProfileAngerStart(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_AngerStart);
-}
-
-Float:GetBossProfileAngerAddOnPageGrab(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_AngerAddOnPageGrab);
-}
-
-Float:GetBossProfileAngerPageGrabTimeDiff(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_AngerPageGrabTimeDiffReq);
-}
-
-Float:GetBossProfileInstantKillRadius(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_InstantKillRadius);
-}
-
-Float:GetBossProfileScareRadius(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_ScareRadius);
-}
-
-Float:GetBossProfileScareCooldown(iProfileIndex)
-{
-	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_ScareCooldown);
-}
-
-GetBossProfileTeleportType(iProfileIndex)
-{
-	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_TeleportType);
-}
-
-// Code originally from FF2. Credits to the original authors Rainbolt Dash and FlaminSarge.
-stock bool:GetRandomStringFromProfile(const String:sProfile[], const String:strKeyValue[], String:buffer[], bufferlen, index=-1)
-{
-	strcopy(buffer, bufferlen, "");
-	
-	if (!IsProfileValid(sProfile)) return false;
-	
-	KvRewind(g_hConfig);
-	KvJumpToKey(g_hConfig, sProfile);
-	
-	if (!KvJumpToKey(g_hConfig, strKeyValue)) return false;
-	
-	decl String:s[32], String:s2[PLATFORM_MAX_PATH];
-	
-	new i = 1;
-	for (;;)
-	{
-		IntToString(i, s, sizeof(s));
-		KvGetString(g_hConfig, s, s2, sizeof(s2));
-		if (!s2[0]) break;
-		
-		i++;
-	}
-	
-	if (i == 1) return false;
-	
-	IntToString(index < 0 ? GetRandomInt(1, i - 1) : index, s, sizeof(s));
-	KvGetString(g_hConfig, s, buffer, bufferlen);
-	return true;
-}
-
-/**
- *	Returns an array of strings of the profile names of every valid boss.
- */
-Handle:GetBossProfileList()
-{
-	return g_hBossProfileList;
-}
-
-/**
- *	Returns an array of strings of the profile names of every valid boss that can be randomly selected.
- */
-Handle:GetSelectableBossProfileList()
-{
-	return g_hSelectableBossProfileList;
+#if defined _sf2_profiles_included
+ #endinput
+#endif
+#define _sf2_profiles_included
+
+#define FILE_PROFILES "configs/sf2/profiles.cfg"
+#define FILE_PROFILES_PACKS "configs/sf2/profiles_packs.cfg"
+#define FILE_PROFILES_PACKS_DIR "configs/sf2/profiles/packs"
+
+static Handle:g_hBossProfileList = INVALID_HANDLE;
+static Handle:g_hSelectableBossProfileList = INVALID_HANDLE;
+
+static Handle:g_hBossProfileNames = INVALID_HANDLE;
+static Handle:g_hBossProfileData = INVALID_HANDLE;
+
+new Handle:g_cvBossProfilePack = INVALID_HANDLE;
+new Handle:g_cvBossProfilePackDefault = INVALID_HANDLE;
+
+new Handle:g_hBossPackConfig = INVALID_HANDLE;
+
+new Handle:g_cvBossPackEndOfMapVote;
+new Handle:g_cvBossPackVoteStartTime;
+new Handle:g_cvBossPackVoteStartRound;
+new Handle:g_cvBossPackVoteShuffle;
+
+static bool:g_bBossPackVoteEnabled = false;
+
+#if defined METHODMAPS
+
+methodmap SF2BossProfile
+{
+	property int Index
+	{
+		public get() { return _:this; }
+	}
+	
+	property int UniqueProfileIndex
+	{
+		public get() { return GetBossProfileUniqueProfileIndex(this.Index); }
+	}
+	
+	property int Skin
+	{
+		public get() { return GetBossProfileSkin(this.Index); }
+	}
+	
+	property int BodyGroups
+	{
+		public get() { return GetBossProfileBodyGroups(this.Index); }
+	}
+	
+	property float ModelScale
+	{
+		public get() { return GetBossProfileModelScale(this.Index); }
+	}
+	
+	property int Type
+	{
+		public get() { return GetBossProfileType(this.Index); }
+	}
+	
+	property int Flags
+	{
+		public get() { return GetBossProfileFlags(this.Index); }
+	}
+	
+	property float SearchRadius
+	{
+		public get() { return GetBossProfileSearchRadius(this.Index); }
+	}
+	
+	property float FOV
+	{
+		public get() { return GetBossProfileFOV(this.Index); }
+	}
+	
+	property float TurnRate
+	{
+		public get() { return GetBossProfileTurnRate(this.Index); }
+	}
+	
+	property float AngerStart
+	{
+		public get() { return GetBossProfileAngerStart(this.Index); }
+	}
+	
+	property float AngerAddOnPageGrab
+	{
+		public get() { return GetBossProfileAngerAddOnPageGrab(this.Index); }
+	}
+	
+	property float AngerAddOnPageGrabTimeDiff
+	{
+		public get() { return GetBossProfileAngerPageGrabTimeDiff(this.Index); }
+	}
+	
+	property float InstantKillRadius
+	{
+		public get() { return GetBossProfileInstantKillRadius(this.Index); }
+	}
+	
+	property float ScareRadius
+	{
+		public get() { return GetBossProfileScareRadius(this.Index); }
+	}
+	
+	property float ScareCooldown
+	{
+		public get() { return GetBossProfileScareCooldown(this.Index); }
+	}
+	
+	property int TeleportType
+	{
+		public get() { return GetBossProfileTeleportType(this.Index); }
+	}
+	
+	public float GetSpeed(int difficulty)
+	{
+		return GetBossProfileSpeed(this.Index, difficulty);
+	}
+	
+	public float GetMaxSpeed(int difficulty)
+	{
+		return GetBossProfileMaxSpeed(this.Index, difficulty);
+	}
+	
+	public void GetEyePositionOffset(float buffer[3])
+	{
+		GetBossProfileEyePositionOffset(this.Index, buffer);
+	}
+	
+	public void GetEyeAngleOffset(float buffer[3])
+	{
+		GetBossProfileEyeAngleOffset(this.Index, buffer);
+	}
+}
+
+#endif
+
+#include "rytp_horror/profiles/profile_chaser.sp"
+
+enum
+{
+	BossProfileData_UniqueProfileIndex,
+	BossProfileData_Type,
+	BossProfileData_ModelScale,
+	BossProfileData_Skin,
+	BossProfileData_Body,
+	BossProfileData_Flags,
+	
+	BossProfileData_SpeedEasy,
+	BossProfileData_SpeedNormal,
+	BossProfileData_SpeedHard,
+	BossProfileData_SpeedInsane,
+	
+	BossProfileData_WalkSpeedEasy,
+	BossProfileData_WalkSpeedNormal,
+	BossProfileData_WalkSpeedHard,
+	BossProfileData_WalkSpeedInsane,
+	
+	BossProfileData_AirSpeedEasy,
+	BossProfileData_AirSpeedNormal,
+	BossProfileData_AirSpeedHard,
+	BossProfileData_AirSpeedInsane,
+	
+	BossProfileData_MaxSpeedEasy,
+	BossProfileData_MaxSpeedNormal,
+	BossProfileData_MaxSpeedHard,
+	BossProfileData_MaxSpeedInsane,
+	
+	BossProfileData_MaxWalkSpeedEasy,
+	BossProfileData_MaxWalkSpeedNormal,
+	BossProfileData_MaxWalkSpeedHard,
+	BossProfileData_MaxWalkSpeedInsane,
+	
+	BossProfileData_MaxAirSpeedEasy,
+	BossProfileData_MaxAirSpeedNormal,
+	BossProfileData_MaxAirSpeedHard,
+	BossProfileData_MaxAirSpeedInsane,
+	
+	BossProfileData_SearchRange,
+	BossProfileData_FieldOfView,
+	BossProfileData_TurnRate,
+	BossProfileData_EyePosOffsetX,
+	BossProfileData_EyePosOffsetY,
+	BossProfileData_EyePosOffsetZ,
+	BossProfileData_EyeAngOffsetX,
+	BossProfileData_EyeAngOffsetY,
+	BossProfileData_EyeAngOffsetZ,
+	BossProfileData_AngerStart,
+	BossProfileData_AngerAddOnPageGrab,
+	BossProfileData_AngerPageGrabTimeDiffReq,
+	BossProfileData_InstantKillRadius,
+	
+	BossProfileData_ScareRadius,
+	BossProfileData_ScareCooldown,
+	
+	BossProfileData_TeleportType,
+	BossProfileData_MaxStats
+};
+
+InitializeBossProfiles()
+{
+	g_hBossProfileNames = CreateTrie();
+	g_hBossProfileData = CreateArray(BossProfileData_MaxStats);
+	
+	g_cvBossProfilePack = CreateConVar("sf2_boss_profile_pack", "", "The boss pack referenced in profiles_packs.cfg that should be loaded.", FCVAR_NOTIFY | FCVAR_DONTRECORD);
+	g_cvBossProfilePackDefault = CreateConVar("sf2_boss_profile_pack_default", "", "If the boss pack defined in sf2_boss_profile_pack is blank or could not be loaded, this pack will be used instead.", FCVAR_NOTIFY);
+	g_cvBossPackEndOfMapVote = CreateConVar("sf2_boss_profile_pack_endvote", "0", "Enables/Disables a boss pack vote at the end of the map.");
+	g_cvBossPackVoteStartTime = CreateConVar("sf2_boss_profile_pack_endvote_start", "4", "Specifies when to start the vote based on time remaining on the map, in minutes.", FCVAR_NOTIFY);
+	g_cvBossPackVoteStartRound = CreateConVar("sf2_boss_profile_pack_endvote_startround", "2", "Specifies when to start the vote based on rounds remaining on the map.", FCVAR_NOTIFY);
+	g_cvBossPackVoteShuffle = CreateConVar("sf2_boss_profile_pack_endvote_shuffle", "0", "Shuffles the menu options of boss pack endvotes if enabled.");
+	
+	InitializeChaserProfiles();
+}
+
+BossProfilesOnMapEnd()
+{
+	ClearBossProfiles();
+}
+
+/**
+ *	Clears all data and memory currently in use by all boss profiles.
+ */
+ClearBossProfiles()
+{
+	if (g_hBossProfileList != INVALID_HANDLE)
+	{
+		CloseHandle(g_hBossProfileList);
+		g_hBossProfileList = INVALID_HANDLE;
+	}
+	
+	if (g_hSelectableBossProfileList != INVALID_HANDLE)
+	{
+		CloseHandle(g_hSelectableBossProfileList);
+		g_hSelectableBossProfileList = INVALID_HANDLE;
+	}
+	
+	ClearTrie(g_hBossProfileNames);
+	ClearArray(g_hBossProfileData);
+	
+	ClearChaserProfiles();
+}
+
+ReloadBossProfiles()
+{
+	if (g_hConfig != INVALID_HANDLE)
+	{
+		CloseHandle(g_hConfig);
+		g_hConfig = INVALID_HANDLE;
+	}
+	
+	if (g_hBossPackConfig != INVALID_HANDLE)
+	{
+		CloseHandle(g_hBossPackConfig);
+		g_hBossPackConfig = INVALID_HANDLE;
+	}
+	
+	// Clear and reload the lists.
+	ClearBossProfiles();
+	
+	g_hConfig = CreateKeyValues("root");
+	g_hBossPackConfig = CreateKeyValues("root");
+	
+	if (g_hBossProfileList == INVALID_HANDLE)
+	{
+		g_hBossProfileList = CreateArray(SF2_MAX_PROFILE_NAME_LENGTH);
+	}
+	
+	if (g_hSelectableBossProfileList == INVALID_HANDLE)
+	{
+		g_hSelectableBossProfileList = CreateArray(SF2_MAX_PROFILE_NAME_LENGTH);
+	}
+	
+	decl String:configPath[PLATFORM_MAX_PATH];
+	
+	// First load from configs/sf2/profiles.cfg
+	BuildPath(Path_SM, configPath, sizeof(configPath), FILE_PROFILES);
+	LoadProfilesFromFile(configPath);
+	
+	BuildPath(Path_SM, configPath, sizeof(configPath), FILE_PROFILES_PACKS);
+	FileToKeyValues(g_hBossPackConfig, configPath);
+	
+	g_bBossPackVoteEnabled = true;
+	
+	// Try loading boss packs, if they're set to load.
+	KvRewind(g_hBossPackConfig);
+	if (KvJumpToKey(g_hBossPackConfig, "packs"))
+	{
+		if (KvGotoFirstSubKey(g_hBossPackConfig))
+		{
+			new endVoteItemCount = 0;
+		
+			decl String:forceLoadBossPackName[128];
+			GetConVarString(g_cvBossProfilePack, forceLoadBossPackName, sizeof(forceLoadBossPackName));
+			
+			new bool:voteBossPackLoaded = false;
+			
+			do
+			{
+				decl String:bossPackName[128];
+				KvGetSectionName(g_hBossPackConfig, bossPackName, sizeof(bossPackName));
+				
+				new bool:autoLoad = bool:KvGetNum(g_hBossPackConfig, "autoload");
+				
+				if (autoLoad || (strlen(forceLoadBossPackName) > 0 && StrEqual(forceLoadBossPackName, bossPackName)))
+				{
+					decl String:packConfigFile[PLATFORM_MAX_PATH];
+					KvGetString(g_hBossPackConfig, "file", packConfigFile, sizeof(packConfigFile));
+					
+					decl String:packConfigFilePath[PLATFORM_MAX_PATH];
+					Format(packConfigFilePath, sizeof(packConfigFilePath), "%s/%s", FILE_PROFILES_PACKS_DIR, packConfigFile);
+					
+					BuildPath(Path_SM, configPath, sizeof(configPath), packConfigFilePath);
+					LoadProfilesFromFile(configPath);
+					
+					if (!voteBossPackLoaded)
+					{
+						if (StrEqual(forceLoadBossPackName, bossPackName))
+						{
+							voteBossPackLoaded = true;
+						}
+					}
+				}
+				
+				if (!autoLoad)
+				{
+					endVoteItemCount++; 
+				}
+			}
+			while (KvGotoNextKey(g_hBossPackConfig));
+			
+			KvGoBack(g_hBossPackConfig);
+			
+			if (!voteBossPackLoaded)
+			{
+				GetConVarString(g_cvBossProfilePackDefault, forceLoadBossPackName, sizeof(forceLoadBossPackName));
+				if (strlen(forceLoadBossPackName) > 0)
+				{
+					if (KvJumpToKey(g_hBossPackConfig, forceLoadBossPackName))
+					{
+						decl String:packConfigFile[PLATFORM_MAX_PATH];
+						KvGetString(g_hBossPackConfig, "file", packConfigFile, sizeof(packConfigFile));
+						
+						decl String:packConfigFilePath[PLATFORM_MAX_PATH];
+						Format(packConfigFilePath, sizeof(packConfigFilePath), "%s/%s", FILE_PROFILES_PACKS_DIR, packConfigFile);
+						
+						BuildPath(Path_SM, configPath, sizeof(configPath), packConfigFilePath);
+						LoadProfilesFromFile(configPath);
+					}
+				}
+			}
+			
+			if (endVoteItemCount <= 0)
+			{
+				g_bBossPackVoteEnabled = false;
+			}
+		}
+		else
+		{
+			g_bBossPackVoteEnabled = false;
+		}
+	}
+	else
+	{
+		g_bBossPackVoteEnabled = false;
+	}
+}
+
+static LoadProfilesFromFile(const String:configPath[])
+{
+	LogSF2Message("Loading boss profiles from file %s...", configPath);
+	
+	if (!FileExists(configPath))
+	{
+		LogSF2Message("File not found! Skipping...");
+		return;
+	}
+	
+	new Handle:kv = CreateKeyValues("root");
+	if (!FileToKeyValues(kv, configPath))
+	{
+		CloseHandle(kv);
+		LogSF2Message("Unexpected error while reading file! Skipping...");
+		return;
+	}
+	else
+	{
+		if (KvGotoFirstSubKey(kv))
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			decl String:sProfileLoadFailReason[512];
+			
+			new iLoadedCount = 0;
+			
+			do
+			{
+				KvGetSectionName(kv, sProfile, sizeof(sProfile));
+				if (LoadBossProfile(kv, sProfile, sProfileLoadFailReason, sizeof(sProfileLoadFailReason)))
+				{
+					iLoadedCount++;
+					LogSF2Message("%s...", sProfile);
+				}
+				else
+				{
+					LogSF2Message("%s...FAILED (reason: %s)", sProfile, sProfileLoadFailReason);
+				}
+			}
+			while (KvGotoNextKey(kv));
+			
+			LogSF2Message("Loaded %d boss profile(s) from file!", iLoadedCount);
+		}
+		else
+		{
+			LogSF2Message("No boss profiles loaded from file!");
+		}
+		
+		CloseHandle(kv);
+	}
+}
+
+/**
+ *	Loads a profile in the current KeyValues position in kv.
+ */
+static bool:LoadBossProfile(Handle:kv, const String:sProfile[], String:sLoadFailReasonBuffer[], iLoadFailReasonBufferLen)
+{
+	new iBossType = KvGetNum(kv, "type", SF2BossType_Unknown);
+	if (iBossType == SF2BossType_Unknown || iBossType >= SF2BossType_MaxTypes) 
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "boss type is unknown!");
+		return false;
+	}
+	
+	new Float:flBossModelScale = KvGetFloat(kv, "model_scale", 1.0);
+	if (flBossModelScale <= 0.0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "model_scale must be a value greater than 0!");
+		return false;
+	}
+	
+	new iBossSkin = KvGetNum(kv, "skin");
+	if (iBossSkin < 0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "skin must be a value that is at least 0!");
+		return false;
+	}
+	
+	new iBossBodyGroups = KvGetNum(kv, "body");
+	if (iBossBodyGroups < 0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "body must be a value that is at least 0!");
+		return false;
+	}
+	
+	new Float:flBossAngerStart = KvGetFloat(kv, "anger_start", 1.0);
+	if (flBossAngerStart < 0.0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "anger_start must be a value that is at least 0!");
+		return false;
+	}
+	
+	new Float:flBossInstantKillRadius = KvGetFloat(kv, "kill_radius");
+	if (flBossInstantKillRadius < 0.0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "kill_radius must be a value that is at least 0!");
+		return false;
+	}
+	
+	new Float:flBossScareRadius = KvGetFloat(kv, "scare_radius");
+	if (flBossScareRadius < 0.0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "scare_radius must be a value that is at least 0!");
+		return false;
+	}
+	
+	new iBossTeleportType = KvGetNum(kv, "teleport_type");
+	if (iBossTeleportType < 0)
+	{
+		Format(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "unknown teleport type!");
+		return false;
+	}
+	
+	new Float:flBossFOV = KvGetFloat(kv, "fov", 90.0);
+	if (flBossFOV < 0.0)
+	{
+		flBossFOV = 0.0;
+	}
+	else if (flBossFOV > 360.0)
+	{
+		flBossFOV = 360.0;
+	}
+	
+	new Float:flBossMaxTurnRate = KvGetFloat(kv, "turnrate", 90.0);
+	if (flBossMaxTurnRate < 0.0)
+	{
+		flBossMaxTurnRate = 0.0;
+	}
+	
+	new Float:flBossScareCooldown = KvGetFloat(kv, "scare_cooldown");
+	if (flBossScareCooldown < 0.0)
+	{
+		// clamp value 
+		flBossScareCooldown = 0.0;
+	}
+	
+	new Float:flBossAngerAddOnPageGrab = KvGetFloat(kv, "anger_add_on_page_grab", -1.0);
+	if (flBossAngerAddOnPageGrab < 0.0)
+	{
+		flBossAngerAddOnPageGrab = KvGetFloat(kv, "anger_page_add", -1.0);		// backwards compatibility
+		if (flBossAngerAddOnPageGrab < 0.0)
+		{
+			flBossAngerAddOnPageGrab = 0.0;
+		}
+	}
+	
+	new Float:flBossAngerPageGrabTimeDiffReq = KvGetFloat(kv, "anger_req_page_grab_time_diff", -1.0);
+	if (flBossAngerPageGrabTimeDiffReq < 0.0)
+	{
+		flBossAngerPageGrabTimeDiffReq = KvGetFloat(kv, "anger_page_time_diff", -1.0);		// backwards compatibility
+		if (flBossAngerPageGrabTimeDiffReq < 0.0)
+		{
+			flBossAngerPageGrabTimeDiffReq = 0.0;
+		}
+	}
+	
+	new Float:flBossSearchRadius = KvGetFloat(kv, "search_radius", -1.0);
+	if (flBossSearchRadius < 0.0)
+	{
+		flBossSearchRadius = KvGetFloat(kv, "search_range", -1.0);		// backwards compatibility
+		if (flBossSearchRadius < 0.0)
+		{
+			flBossSearchRadius = 0.0;
+		}
+	}
+	
+	new Float:flBossDefaultSpeed = KvGetFloat(kv, "speed", 150.0);
+	new Float:flBossSpeedEasy = KvGetFloat(kv, "speed_easy", flBossDefaultSpeed);
+	new Float:flBossSpeedHard = KvGetFloat(kv, "speed_hard", flBossDefaultSpeed);
+	new Float:flBossSpeedInsane = KvGetFloat(kv, "speed_insane", flBossDefaultSpeed);
+	
+	new Float:flBossDefaultMaxSpeed = KvGetFloat(kv, "speed_max", 150.0);
+	new Float:flBossMaxSpeedEasy = KvGetFloat(kv, "speed_max_easy", flBossDefaultMaxSpeed);
+	new Float:flBossMaxSpeedHard = KvGetFloat(kv, "speed_max_hard", flBossDefaultMaxSpeed);
+	new Float:flBossMaxSpeedInsane = KvGetFloat(kv, "speed_max_insane", flBossDefaultMaxSpeed);
+	
+	decl Float:flBossEyePosOffset[3];
+	KvGetVector(kv, "eye_pos", flBossEyePosOffset);
+	
+	decl Float:flBossEyeAngOffset[3];
+	KvGetVector(kv, "eye_ang_offset", flBossEyeAngOffset);
+	
+	// Parse through flags.
+	new iBossFlags = 0;
+	if (KvGetNum(kv, "static_shake")) iBossFlags |= SFF_HASSTATICSHAKE;
+	if (KvGetNum(kv, "static_on_look")) iBossFlags |= SFF_STATICONLOOK;
+	if (KvGetNum(kv, "static_on_radius")) iBossFlags |= SFF_STATICONRADIUS;
+	if (KvGetNum(kv, "proxies")) iBossFlags |= SFF_PROXIES;
+	if (KvGetNum(kv, "jumpscare")) iBossFlags |= SFF_HASJUMPSCARE;
+	if (KvGetNum(kv, "sound_sight_enabled")) iBossFlags |= SFF_HASSIGHTSOUNDS;
+	if (KvGetNum(kv, "sound_static_loop_local_enabled")) iBossFlags |= SFF_HASSTATICLOOPLOCALSOUND;
+	if (KvGetNum(kv, "view_shake", 1)) iBossFlags |= SFF_HASVIEWSHAKE;
+	if (KvGetNum(kv, "copy")) iBossFlags |= SFF_COPIES;
+	if (KvGetNum(kv, "wander_move", 1)) iBossFlags |= SFF_WANDERMOVE;
+	
+	// Try validating unique profile.
+	new iUniqueProfileIndex = -1;
+	
+	switch (iBossType)
+	{
+		case SF2BossType_Chaser:
+		{
+			if (!LoadChaserBossProfile(kv, sProfile, iUniqueProfileIndex, sLoadFailReasonBuffer, iLoadFailReasonBufferLen))
+			{
+				return false;
+			}
+		}
+	}
+	
+	// Add the section to our config.
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile, true);
+	KvCopySubkeys(kv, g_hConfig);
+	
+	new bool:createNewBoss = false;
+	new iIndex = FindStringInArray(GetBossProfileList(), sProfile);
+	if (iIndex == -1)
+	{
+		createNewBoss = true;
+	}
+	
+	// Add to/Modify our array.
+	if (createNewBoss)
+	{
+		iIndex = PushArrayCell(g_hBossProfileData, -1);
+		SetTrieValue(g_hBossProfileNames, sProfile, iIndex);
+		
+		// Add to the boss list since it's not there already.
+		PushArrayString(GetBossProfileList(), sProfile);
+	}
+	
+	SetArrayCell(g_hBossProfileData, iIndex, iUniqueProfileIndex, BossProfileData_UniqueProfileIndex);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, iBossType, BossProfileData_Type);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossModelScale, BossProfileData_ModelScale);
+	SetArrayCell(g_hBossProfileData, iIndex, iBossSkin, BossProfileData_Skin);
+	SetArrayCell(g_hBossProfileData, iIndex, iBossBodyGroups, BossProfileData_Body);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, iBossFlags, BossProfileData_Flags);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossDefaultSpeed, BossProfileData_SpeedNormal);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossSpeedEasy, BossProfileData_SpeedEasy);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossSpeedHard, BossProfileData_SpeedHard);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossSpeedInsane, BossProfileData_SpeedInsane);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossDefaultMaxSpeed, BossProfileData_MaxSpeedNormal);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxSpeedEasy, BossProfileData_MaxSpeedEasy);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxSpeedHard, BossProfileData_MaxSpeedHard);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxSpeedInsane, BossProfileData_MaxSpeedInsane);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossEyePosOffset[0], BossProfileData_EyePosOffsetX);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossEyePosOffset[1], BossProfileData_EyePosOffsetY);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossEyePosOffset[2], BossProfileData_EyePosOffsetZ);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossEyeAngOffset[0], BossProfileData_EyeAngOffsetX);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossEyeAngOffset[1], BossProfileData_EyeAngOffsetY);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossEyeAngOffset[2], BossProfileData_EyeAngOffsetZ);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossAngerStart, BossProfileData_AngerStart);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossAngerAddOnPageGrab, BossProfileData_AngerAddOnPageGrab);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossAngerPageGrabTimeDiffReq, BossProfileData_AngerPageGrabTimeDiffReq);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossInstantKillRadius, BossProfileData_InstantKillRadius);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossScareRadius, BossProfileData_ScareRadius);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossScareCooldown, BossProfileData_ScareCooldown);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, iBossTeleportType, BossProfileData_TeleportType);
+	
+	SetArrayCell(g_hBossProfileData, iIndex, flBossSearchRadius, BossProfileData_SearchRange);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossFOV, BossProfileData_FieldOfView);
+	SetArrayCell(g_hBossProfileData, iIndex, flBossMaxTurnRate, BossProfileData_TurnRate);
+	
+	if (bool:KvGetNum(kv, "enable_random_selection", 1))
+	{
+		if (FindStringInArray(GetSelectableBossProfileList(), sProfile) == -1)
+		{
+			// Add to the selectable boss list if it isn't there already.
+			PushArrayString(GetSelectableBossProfileList(), sProfile);
+		}
+	}
+	else
+	{
+		new selectIndex = FindStringInArray(GetSelectableBossProfileList(), sProfile);
+		if (selectIndex != -1)
+		{
+			RemoveFromArray(GetSelectableBossProfileList(), selectIndex);
+		}
+	}
+	
+	if (KvGotoFirstSubKey(kv))
+	{
+		decl String:s2[64], String:s3[64], String:s4[PLATFORM_MAX_PATH], String:s5[PLATFORM_MAX_PATH];
+		
+		do
+		{
+			KvGetSectionName(kv, s2, sizeof(s2));
+			
+			if (!StrContains(s2, "sound_"))
+			{
+				for (new i = 1;; i++)
+				{
+					IntToString(i, s3, sizeof(s3));
+					KvGetString(kv, s3, s4, sizeof(s4));
+					if (!s4[0]) break;
+					
+					PrecacheSound2(s4);
+				}
+			}
+			else if (StrEqual(s2, "download"))
+			{
+				for (new i = 1;; i++)
+				{
+					IntToString(i, s3, sizeof(s3));
+					KvGetString(kv, s3, s4, sizeof(s4));
+					if (!s4[0]) break;
+					
+					AddFileToDownloadsTable(s4);
+				}
+			}
+			else if (StrEqual(s2, "mod_precache"))
+			{
+				for (new i = 1;; i++)
+				{
+					IntToString(i, s3, sizeof(s3));
+					KvGetString(kv, s3, s4, sizeof(s4));
+					if (!s4[0]) break;
+					
+					PrecacheModel(s4, true);
+				}
+			}
+			else if (StrEqual(s2, "mat_download"))
+			{	
+				for (new i = 1;; i++)
+				{
+					IntToString(i, s3, sizeof(s3));
+					KvGetString(kv, s3, s4, sizeof(s4));
+					if (!s4[0]) break;
+					
+					Format(s5, sizeof(s5), "%s.vtf", s4);
+					AddFileToDownloadsTable(s5);
+					Format(s5, sizeof(s5), "%s.vmt", s4);
+					AddFileToDownloadsTable(s5);
+				}
+			}
+			else if (StrEqual(s2, "mod_download"))
+			{
+				static const String:extensions[][] = { ".mdl", ".phy", ".dx80.vtx", ".dx90.vtx", ".sw.vtx", ".vvd" };
+				
+				for (new i = 1;; i++)
+				{
+					IntToString(i, s3, sizeof(s3));
+					KvGetString(kv, s3, s4, sizeof(s4));
+					if (!s4[0]) break;
+					
+					for (new is = 0; is < sizeof(extensions); is++)
+					{
+						Format(s5, sizeof(s5), "%s%s", s4, extensions[is]);
+						AddFileToDownloadsTable(s5);
+					}
+				}
+			}
+		}
+		while (KvGotoNextKey(kv));
+		
+		KvGoBack(kv);
+	}
+	
+	return true;
+}
+
+static Handle:g_hBossPackVoteMapTimer;
+static Handle:g_hBossPackVoteTimer;
+static bool:g_bBossPackVoteCompleted;
+static bool:g_bBossPackVoteStarted;
+
+InitializeBossPackVotes()
+{
+	g_hBossPackVoteMapTimer = INVALID_HANDLE;
+	g_hBossPackVoteTimer = INVALID_HANDLE;
+	g_bBossPackVoteCompleted = false;
+	g_bBossPackVoteStarted = false;
+}
+
+SetupTimeLimitTimerForBossPackVote()
+{
+	new time;
+	if (GetMapTimeLeft(time) && time > 0)
+	{
+		if (GetConVarBool(g_cvBossPackEndOfMapVote) && g_bBossPackVoteEnabled && !g_bBossPackVoteCompleted && !g_bBossPackVoteStarted)
+		{
+			new startTime = GetConVarInt(g_cvBossPackVoteStartTime) * 60;
+			if ((time - startTime) <= 0)
+			{
+				if (!IsVoteInProgress())
+				{
+					InitiateBossPackVote();
+				}
+				else
+				{
+					g_hBossPackVoteTimer = CreateTimer(5.0, Timer_BossPackVoteLoop, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+				}
+			}
+			else
+			{
+				if (g_hBossPackVoteMapTimer != INVALID_HANDLE)
+				{
+					CloseHandle(g_hBossPackVoteMapTimer);
+					g_hBossPackVoteMapTimer = INVALID_HANDLE;
+				}
+				
+				g_hBossPackVoteMapTimer = CreateTimer(float(time - startTime), Timer_StartBossPackVote, _, TIMER_FLAG_NO_MAPCHANGE);
+			}
+		}
+	}
+}
+
+CheckRoundLimitForBossPackVote(roundCount)
+{
+	if (!GetConVarBool(g_cvBossPackEndOfMapVote) || !g_bBossPackVoteEnabled || g_bBossPackVoteStarted || g_bBossPackVoteCompleted) return;
+	
+	if (g_cvMaxRounds == INVALID_HANDLE) return;
+	
+	if (GetConVarInt(g_cvMaxRounds) > 0)
+	{
+		if (roundCount >= (GetConVarInt(g_cvMaxRounds) - GetConVarInt(g_cvBossPackVoteStartRound)))
+		{
+			if (!IsVoteInProgress())
+			{
+				InitiateBossPackVote();
+			}
+			else
+			{
+				g_hBossPackVoteTimer = CreateTimer(5.0, Timer_BossPackVoteLoop, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			}
+		}
+	}
+	
+	CloseHandle(g_cvMaxRounds);
+}
+
+InitiateBossPackVote()
+{
+	if (g_bBossPackVoteStarted || g_bBossPackVoteCompleted || IsVoteInProgress()) return;
+	
+	// Gather boss packs, if any.
+	if (g_hBossPackConfig == INVALID_HANDLE) return;
+	
+	KvRewind(g_hBossPackConfig);
+	if (!KvJumpToKey(g_hBossPackConfig, "packs")) return;
+	if (!KvGotoFirstSubKey(g_hBossPackConfig)) return;
+	
+	new Handle:voteMenu = CreateMenu(Menu_BossPackVote);
+	SetMenuTitle(voteMenu, "%t%t\n \n", "SF2 Prefix", "SF2 Boss Pack Vote Menu Title");
+	SetMenuExitBackButton(voteMenu, false);
+	SetMenuExitButton(voteMenu, false);
+	
+	new Handle:menuDisplayNamesTrie = CreateTrie();
+	new Handle:menuOptionsInfo = CreateArray(128);
+	
+	do
+	{
+		if (!bool:KvGetNum(g_hBossPackConfig, "autoload") && bool:KvGetNum(g_hBossPackConfig, "show_in_vote", 1))
+		{
+			decl String:bossPack[128];
+			KvGetSectionName(g_hBossPackConfig, bossPack, sizeof(bossPack));
+			
+			decl String:bossPackName[64];
+			KvGetString(g_hBossPackConfig, "name", bossPackName, sizeof(bossPackName), bossPack);
+			
+			SetTrieString(menuDisplayNamesTrie, bossPack, bossPackName);
+			PushArrayString(menuOptionsInfo, bossPack);
+		}
+	}
+	while (KvGotoNextKey(g_hBossPackConfig));
+	
+	if (GetArraySize(menuOptionsInfo) == 0)
+	{
+		CloseHandle(menuDisplayNamesTrie);
+		CloseHandle(menuOptionsInfo);
+		CloseHandle(voteMenu);
+		return;
+	}
+	
+	if (GetConVarBool(g_cvBossPackVoteShuffle))
+	{
+		SortADTArray(menuOptionsInfo, Sort_Random, Sort_String);
+	}
+	
+	for (new i = 0; i < GetArraySize(menuOptionsInfo); i++)
+	{
+		decl String:bossPack[128], String:bossPackName[64];
+		GetArrayString(menuOptionsInfo, i, bossPack, sizeof(bossPack));
+		GetTrieString(menuDisplayNamesTrie, bossPack, bossPackName, sizeof(bossPackName));
+		
+		AddMenuItem(voteMenu, bossPack, bossPackName);
+	}
+	
+	CloseHandle(menuDisplayNamesTrie);
+	CloseHandle(menuOptionsInfo);
+	
+	g_bBossPackVoteStarted = true;
+	if (g_hBossPackVoteMapTimer != INVALID_HANDLE)
+	{
+		CloseHandle(g_hBossPackVoteMapTimer);
+		g_hBossPackVoteMapTimer = INVALID_HANDLE;
+	}
+	
+	if (g_hBossPackVoteTimer != INVALID_HANDLE)
+	{
+		CloseHandle(g_hBossPackVoteTimer);
+		g_hBossPackVoteTimer = INVALID_HANDLE;
+	}
+	
+	VoteMenuToAll(voteMenu, 20);
+}
+
+public Menu_BossPackVote(Handle:menu, MenuAction:action, param1, param2)
+{
+	switch (action)
+	{
+		case MenuAction_VoteStart:
+		{
+			g_bBossPackVoteStarted = true;
+		}
+		case MenuAction_VoteEnd:
+		{
+			g_bBossPackVoteCompleted = true;
+		
+			decl String:bossPack[128], String:bossPackName[64];
+			GetMenuItem(menu, param1, bossPack, sizeof(bossPack), _, bossPackName, sizeof(bossPackName));
+			
+			SetConVarString(g_cvBossProfilePack, bossPack);
+			
+			CPrintToChatAll("%t%t", "SF2 Prefix", "SF2 Boss Pack Vote Successful", bossPackName);
+		}
+		case MenuAction_End:
+		{
+			g_bBossPackVoteStarted = false;
+			CloseHandle(menu);
+		}
+	}
+}
+
+public Action:Timer_StartBossPackVote(Handle:timer)
+{
+	if (timer != g_hBossPackVoteMapTimer) return;
+	
+	g_hBossPackVoteTimer = CreateTimer(5.0, Timer_BossPackVoteLoop, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hBossPackVoteTimer, true);
+}
+
+public Action:Timer_BossPackVoteLoop(Handle:timer)
+{
+	if (timer != g_hBossPackVoteTimer || g_bBossPackVoteCompleted || g_bBossPackVoteStarted) return Plugin_Stop;
+	
+	if (!IsVoteInProgress())
+	{
+		g_hBossPackVoteTimer = INVALID_HANDLE;
+		InitiateBossPackVote();
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+bool:IsProfileValid(const String:sProfile[])
+{
+	return bool:(FindStringInArray(GetBossProfileList(), sProfile) != -1);
+}
+
+stock GetProfileNum(const String:sProfile[], const String:keyValue[], defaultValue=0)
+{
+	if (!IsProfileValid(sProfile)) return defaultValue;
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	return KvGetNum(g_hConfig, keyValue, defaultValue);
+}
+
+stock Float:GetProfileFloat(const String:sProfile[], const String:keyValue[], Float:defaultValue=0.0)
+{
+	if (!IsProfileValid(sProfile)) return defaultValue;
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	return KvGetFloat(g_hConfig, keyValue, defaultValue);
+}
+
+stock bool:GetProfileVector(const String:sProfile[], const String:keyValue[], Float:buffer[3], const Float:defaultValue[3]=NULL_VECTOR)
+{
+	for (new i = 0; i < 3; i++) buffer[i] = defaultValue[i];
+	
+	if (!IsProfileValid(sProfile)) return false;
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	KvGetVector(g_hConfig, keyValue, buffer, defaultValue);
+	return true;
+}
+
+stock bool:GetProfileColor(const String:sProfile[], 
+	const String:keyValue[], 
+	&r, 
+	&g, 
+	&b, 
+	&a,
+	dr=255,
+	dg=255,
+	db=255,
+	da=255)
+{
+	r = dr;
+	g = dg;
+	b = db;
+	a = da;
+	
+	if (!IsProfileValid(sProfile)) return false;
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	decl String:sValue[64];
+	KvGetString(g_hConfig, keyValue, sValue, sizeof(sValue));
+	
+	if (strlen(sValue) != 0)
+	{
+		KvGetColor(g_hConfig, keyValue, r, g, b, a);
+	}
+	
+	return true;
+}
+
+stock bool:GetProfileString(const String:sProfile[], const String:keyValue[], String:buffer[], bufferlen, const String:defaultValue[]="")
+{
+	strcopy(buffer, bufferlen, defaultValue);
+	
+	if (!IsProfileValid(sProfile)) return false;
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	KvGetString(g_hConfig, keyValue, buffer, bufferlen, defaultValue);
+	return true;
+}
+
+GetBossProfileIndexFromName(const String:sProfile[])
+{
+	new iReturn = -1;
+	GetTrieValue(g_hBossProfileNames, sProfile, iReturn);
+	return iReturn;
+}
+
+GetBossProfileUniqueProfileIndex(iProfileIndex)
+{
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_UniqueProfileIndex);
+}
+
+GetBossProfileSkin(iProfileIndex)
+{
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Skin);
+}
+
+GetBossProfileBodyGroups(iProfileIndex)
+{
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Body);
+}
+
+Float:GetBossProfileModelScale(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_ModelScale);
+}
+
+GetBossProfileType(iProfileIndex)
+{
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Type);
+}
+
+GetBossProfileFlags(iProfileIndex)
+{
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_Flags);
+}
+
+Float:GetBossProfileSpeed(iProfileIndex, iDifficulty)
+{
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedEasy);
+		case Difficulty_Hard: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedHard);
+		case Difficulty_Insane: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedInsane);
+	}
+	
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SpeedNormal);
+}
+
+Float:GetBossProfileMaxSpeed(iProfileIndex, iDifficulty)
+{
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedEasy);
+		case Difficulty_Hard: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedHard);
+		case Difficulty_Insane: return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedInsane);
+	}
+	
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_MaxSpeedNormal);
+}
+
+Float:GetBossProfileSearchRadius(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_SearchRange);
+}
+
+Float:GetBossProfileFOV(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_FieldOfView);
+}
+
+Float:GetBossProfileTurnRate(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_TurnRate);
+}
+
+GetBossProfileEyePositionOffset(iProfileIndex, Float:buffer[3])
+{
+	buffer[0] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyePosOffsetX);
+	buffer[1] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyePosOffsetY);
+	buffer[2] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyePosOffsetZ);
+}
+
+GetBossProfileEyeAngleOffset(iProfileIndex, Float:buffer[3])
+{
+	buffer[0] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyeAngOffsetX);
+	buffer[1] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyeAngOffsetY);
+	buffer[2] = Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_EyeAngOffsetZ);
+}
+
+Float:GetBossProfileAngerStart(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_AngerStart);
+}
+
+Float:GetBossProfileAngerAddOnPageGrab(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_AngerAddOnPageGrab);
+}
+
+Float:GetBossProfileAngerPageGrabTimeDiff(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_AngerPageGrabTimeDiffReq);
+}
+
+Float:GetBossProfileInstantKillRadius(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_InstantKillRadius);
+}
+
+Float:GetBossProfileScareRadius(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_ScareRadius);
+}
+
+Float:GetBossProfileScareCooldown(iProfileIndex)
+{
+	return Float:GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_ScareCooldown);
+}
+
+GetBossProfileTeleportType(iProfileIndex)
+{
+	return GetArrayCell(g_hBossProfileData, iProfileIndex, BossProfileData_TeleportType);
+}
+
+// Code originally from FF2. Credits to the original authors Rainbolt Dash and FlaminSarge.
+stock bool:GetRandomStringFromProfile(const String:sProfile[], const String:strKeyValue[], String:buffer[], bufferlen, index=-1)
+{
+	strcopy(buffer, bufferlen, "");
+	
+	if (!IsProfileValid(sProfile)) return false;
+	
+	KvRewind(g_hConfig);
+	KvJumpToKey(g_hConfig, sProfile);
+	
+	if (!KvJumpToKey(g_hConfig, strKeyValue)) return false;
+	
+	decl String:s[32], String:s2[PLATFORM_MAX_PATH];
+	
+	new i = 1;
+	for (;;)
+	{
+		IntToString(i, s, sizeof(s));
+		KvGetString(g_hConfig, s, s2, sizeof(s2));
+		if (!s2[0]) break;
+		
+		i++;
+	}
+	
+	if (i == 1) return false;
+	
+	IntToString(index < 0 ? GetRandomInt(1, i - 1) : index, s, sizeof(s));
+	KvGetString(g_hConfig, s, buffer, bufferlen);
+	return true;
+}
+
+/**
+ *	Returns an array of strings of the profile names of every valid boss.
+ */
+Handle:GetBossProfileList()
+{
+	return g_hBossProfileList;
+}
+
+/**
+ *	Returns an array of strings of the profile names of every valid boss that can be randomly selected.
+ */
+Handle:GetSelectableBossProfileList()
+{
+	return g_hSelectableBossProfileList;
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/profiles/profile_chaser.sp b/addons/sourcemod/scripting/rytp_horror/profiles/profile_chaser.sp
index 773bc16..e939dfe 100644
--- a/addons/sourcemod/scripting/rytp_horror/profiles/profile_chaser.sp
+++ b/addons/sourcemod/scripting/rytp_horror/profiles/profile_chaser.sp
@@ -1,571 +1,571 @@
-#if defined _sf2_profiles_chaser
- #endinput
-#endif
-
-#define _sf2_profiles_chaser
-
-#define SF2_CHASER_BOSS_MAX_ATTACKS 8
-
-new Handle:g_hChaserProfileNames;
-new Handle:g_hChaserProfileData;
-
-enum
-{
-	SF2BossAttackType_Invalid = -1,
-	SF2BossAttackType_Melee = 0,
-	SF2BossAttackType_Ranged,
-	SF2BossAttackType_Projectile,
-	SF2BossAttackType_Custom
-};
-
-enum
-{
-	ChaserProfileData_StepSize,
-	ChaserProfileData_WalkSpeedEasy,
-	ChaserProfileData_WalkSpeedNormal,
-	ChaserProfileData_WalkSpeedHard,
-	ChaserProfileData_WalkSpeedInsane,
-	
-	ChaserProfileData_AirSpeedEasy,
-	ChaserProfileData_AirSpeedNormal,
-	ChaserProfileData_AirSpeedHard,
-	ChaserProfileData_AirSpeedInsane,
-	
-	ChaserProfileData_MaxWalkSpeedEasy,
-	ChaserProfileData_MaxWalkSpeedNormal,
-	ChaserProfileData_MaxWalkSpeedHard,
-	ChaserProfileData_MaxWalkSpeedInsane,
-	
-	ChaserProfileData_MaxAirSpeedEasy,
-	ChaserProfileData_MaxAirSpeedNormal,
-	ChaserProfileData_MaxAirSpeedHard,
-	ChaserProfileData_MaxAirSpeedInsane,
-	
-	ChaserProfileData_WakeRadius,
-	
-	ChaserProfileData_Attacks,		// array that contains data about attacks
-	
-	ChaserProfileData_Animations,						// Array that contains data of animations.
-	
-	ChaserProfileData_CanBeStunned,
-	ChaserProfileData_StunDuration,
-	ChaserProfileData_StunHealth,
-	ChaserProfileData_CanBeStunnedByFlashlight,
-	ChaserProfileData_StunFlashlightDamage,
-	
-	ChaserProfileData_MemoryLifeTime,
-	
-	ChaserProfileData_AwarenessIncreaseRateEasy,
-	ChaserProfileData_AwarenessIncreaseRateNormal,
-	ChaserProfileData_AwarenessIncreaseRateHard,
-	ChaserProfileData_AwarenessIncreaseRateInsane,
-	ChaserProfileData_AwarenessDecreaseRateEasy,
-	ChaserProfileData_AwarenessDecreaseRateNormal,
-	ChaserProfileData_AwarenessDecreaseRateHard,
-	ChaserProfileData_AwarenessDecreaseRateInsane,
-	
-	ChaserProfileData_MaxStats
-};
-
-enum
-{
-	ChaserProfileAttackData_Type = 0,
-	ChaserProfileAttackData_CanUseAgainstProps,
-	ChaserProfileAttackData_Damage,
-	ChaserProfileAttackData_DamageVsProps,
-	ChaserProfileAttackData_DamageForce,
-	ChaserProfileAttackData_DamageType,
-	ChaserProfileAttackData_DamageDelay,
-	ChaserProfileAttackData_Range,
-	ChaserProfileAttackData_Duration,
-	ChaserProfileAttackData_Spread,
-	ChaserProfileAttackData_BeginRange,
-	ChaserProfileAttackData_BeginFOV,
-	ChaserProfileAttackData_Cooldown,
-	ChaserProfileAttackData_MaxStats
-};
-
-enum 
-{
-	ChaserAnimationType_Idle = 0,
-	ChaserAnimationType_IdlePlaybackRate,
-	ChaserAnimationType_Walk,
-	ChaserAnimationType_WalkPlaybackRate,
-	ChaserAnimationType_Run,
-	ChaserAnimationType_RunPlaybackRate,
-	ChaserAnimationType_Attack,
-	ChaserAnimationType_AttackPlaybackRate,
-	ChaserAnimationType_Stunned,
-	ChaserAnimationType_StunnedPlaybackRate,
-	ChaserAnimationType_Death,
-	ChaserAnimationType_DeathPlaybackRate,
-	ChaserAnimationType_Max
-};
-
-InitializeChaserProfiles()
-{
-	g_hChaserProfileNames = CreateTrie();
-	g_hChaserProfileData = CreateArray(ChaserProfileData_MaxStats);
-}
-
-/**
- *	Clears all data and memory currently in use by chaser profiles.
- */
-ClearChaserProfiles()
-{
-	for (new i = 0, iSize = GetArraySize(g_hChaserProfileData); i < iSize; i++)
-	{
-		new Handle:hHandle = Handle:GetArrayCell(g_hChaserProfileData, i, ChaserProfileData_Attacks);
-		if (hHandle != INVALID_HANDLE)
-		{
-			CloseHandle(hHandle);
-		}
-		
-		hHandle = Handle:GetArrayCell(g_hChaserProfileData, i, ChaserProfileData_Animations);
-		if (hHandle != INVALID_HANDLE)
-		{
-			CloseHandle(hHandle);
-		}
-	}
-	
-	ClearTrie(g_hChaserProfileNames);
-	ClearArray(g_hChaserProfileData);
-}
-
-/**
- *	Parses and stores the unique values of a chaser profile from the current position in the profiles config.
- *	Returns true if loading was successful, false if not.
- */
-bool:LoadChaserBossProfile(Handle:kv, const String:sProfile[], &iUniqueProfileIndex, String:sLoadFailReasonBuffer[], iLoadFailReasonBufferLen)
-{
-	strcopy(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "");
-	
-	iUniqueProfileIndex = PushArrayCell(g_hChaserProfileData, -1);
-	SetTrieValue(g_hChaserProfileNames, sProfile, iUniqueProfileIndex);
-	
-	new Float:flBossStepSize = KvGetFloat(kv, "stepsize", 16.0);
-	
-	new Float:flBossDefaultWalkSpeed = KvGetFloat(kv, "walkspeed", 30.0);
-	new Float:flBossWalkSpeedEasy = KvGetFloat(kv, "walkspeed_easy", flBossDefaultWalkSpeed);
-	new Float:flBossWalkSpeedHard = KvGetFloat(kv, "walkspeed_hard", flBossDefaultWalkSpeed);
-	new Float:flBossWalkSpeedInsane = KvGetFloat(kv, "walkspeed_insane", flBossDefaultWalkSpeed);
-	
-	new Float:flBossDefaultAirSpeed = KvGetFloat(kv, "airspeed", 50.0);
-	new Float:flBossAirSpeedEasy = KvGetFloat(kv, "airspeed_easy", flBossDefaultAirSpeed);
-	new Float:flBossAirSpeedHard = KvGetFloat(kv, "airspeed_hard", flBossDefaultAirSpeed);
-	new Float:flBossAirSpeedInsane = KvGetFloat(kv, "airspeed_insane", flBossDefaultAirSpeed);
-	
-	new Float:flBossDefaultMaxWalkSpeed = KvGetFloat(kv, "walkspeed_max", 30.0);
-	new Float:flBossMaxWalkSpeedEasy = KvGetFloat(kv, "walkspeed_max_easy", flBossDefaultMaxWalkSpeed);
-	new Float:flBossMaxWalkSpeedHard = KvGetFloat(kv, "walkspeed_max_hard", flBossDefaultMaxWalkSpeed);
-	new Float:flBossMaxWalkSpeedInsane = KvGetFloat(kv, "walkspeed_max_insane", flBossDefaultMaxWalkSpeed);
-	
-	new Float:flBossDefaultMaxAirSpeed = KvGetFloat(kv, "airspeed_max", 50.0);
-	new Float:flBossMaxAirSpeedEasy = KvGetFloat(kv, "airspeed_max_easy", flBossDefaultMaxAirSpeed);
-	new Float:flBossMaxAirSpeedHard = KvGetFloat(kv, "airspeed_max_hard", flBossDefaultMaxAirSpeed);
-	new Float:flBossMaxAirSpeedInsane = KvGetFloat(kv, "airspeed_max_insane", flBossDefaultMaxAirSpeed);
-	
-	new Float:flWakeRange = KvGetFloat(kv, "wake_radius");
-	if (flWakeRange < 0.0) flWakeRange = 0.0;
-	
-	new bool:bCanBeStunned = bool:KvGetNum(kv, "stun_enabled");
-	
-	new Float:flStunDuration = KvGetFloat(kv, "stun_duration");
-	if (flStunDuration < 0.0) flStunDuration = 0.0;
-	
-	new Float:flStunHealth = KvGetFloat(kv, "stun_health");
-	if (flStunHealth < 0.0) flStunHealth = 0.0;
-	
-	new bool:bStunTakeDamageFromFlashlight = bool:KvGetNum(kv, "stun_damage_flashlight_enabled");
-	
-	new Float:flStunFlashlightDamage = KvGetFloat(kv, "stun_damage_flashlight");
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossStepSize, ChaserProfileData_StepSize);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultWalkSpeed, ChaserProfileData_WalkSpeedNormal);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossWalkSpeedEasy, ChaserProfileData_WalkSpeedEasy);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossWalkSpeedHard, ChaserProfileData_WalkSpeedHard);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossWalkSpeedInsane, ChaserProfileData_WalkSpeedInsane);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultAirSpeed, ChaserProfileData_AirSpeedNormal);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossAirSpeedEasy, ChaserProfileData_AirSpeedEasy);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossAirSpeedHard, ChaserProfileData_AirSpeedHard);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossAirSpeedInsane, ChaserProfileData_AirSpeedInsane);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultMaxWalkSpeed, ChaserProfileData_MaxWalkSpeedNormal);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxWalkSpeedEasy, ChaserProfileData_MaxWalkSpeedEasy);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxWalkSpeedHard, ChaserProfileData_MaxWalkSpeedHard);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxWalkSpeedInsane, ChaserProfileData_MaxWalkSpeedInsane);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultMaxAirSpeed, ChaserProfileData_MaxAirSpeedNormal);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxAirSpeedEasy, ChaserProfileData_MaxAirSpeedEasy);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxAirSpeedHard, ChaserProfileData_MaxAirSpeedHard);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxAirSpeedInsane, ChaserProfileData_MaxAirSpeedInsane);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flWakeRange, ChaserProfileData_WakeRadius);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, bCanBeStunned, ChaserProfileData_CanBeStunned);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flStunDuration, ChaserProfileData_StunDuration);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flStunHealth, ChaserProfileData_StunHealth);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, bStunTakeDamageFromFlashlight, ChaserProfileData_CanBeStunnedByFlashlight);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flStunFlashlightDamage, ChaserProfileData_StunFlashlightDamage);
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "memory_lifetime", 10.0), ChaserProfileData_MemoryLifeTime);
-	
-	new Float:flDefaultAwarenessIncreaseRate = KvGetFloat(kv, "awareness_rate_increase", 75.0);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_increase_easy", flDefaultAwarenessIncreaseRate), ChaserProfileData_AwarenessIncreaseRateEasy);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flDefaultAwarenessIncreaseRate, ChaserProfileData_AwarenessIncreaseRateNormal);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_increase_hard", flDefaultAwarenessIncreaseRate), ChaserProfileData_AwarenessIncreaseRateHard);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_increase_insane", flDefaultAwarenessIncreaseRate), ChaserProfileData_AwarenessIncreaseRateInsane);
-	
-	new Float:flDefaultAwarenessDecreaseRate = KvGetFloat(kv, "awareness_rate_decrease", 150.0);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_decrease_easy", flDefaultAwarenessDecreaseRate), ChaserProfileData_AwarenessDecreaseRateEasy);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flDefaultAwarenessDecreaseRate, ChaserProfileData_AwarenessDecreaseRateNormal);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_decrease_hard", flDefaultAwarenessDecreaseRate), ChaserProfileData_AwarenessDecreaseRateHard);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_decrease_insane", flDefaultAwarenessDecreaseRate), ChaserProfileData_AwarenessDecreaseRateInsane);
-	
-	ParseChaserProfileAttacks(kv, iUniqueProfileIndex);
-	
-	ParseChaserProfileAnimations(kv, iUniqueProfileIndex);
-	
-	return true;
-}
-
-static ParseChaserProfileAttacks(Handle:kv, iUniqueProfileIndex)
-{
-	//decl String:sBuffer[PLATFORM_MAX_PATH];
-	
-	// Create the array.
-	new Handle:hAttacks = CreateArray(ChaserProfileAttackData_MaxStats);
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, hAttacks, ChaserProfileData_Attacks);
-	
-	//new iAttackType = KvGetNum(kv, "attack_type");
-	new iAttackType = SF2BossAttackType_Melee;
-	
-	new Float:flAttackRange = KvGetFloat(kv, "attack_range");
-	if (flAttackRange < 0.0) flAttackRange = 0.0;
-	
-	new Float:flAttackDamage = KvGetFloat(kv, "attack_damage");
-	new Float:flAttackDamageVsProps = KvGetFloat(kv, "attack_damage_vs_props", flAttackDamage);
-	new Float:flAttackDamageForce = KvGetFloat(kv, "attack_damageforce");
-	
-	new iAttackDamageType = KvGetNum(kv, "attack_damagetype");
-	if (iAttackDamageType < 0) iAttackDamageType = 0;
-	
-	new Float:flAttackDamageDelay = KvGetFloat(kv, "attack_delay");
-	if (flAttackDamageDelay < 0.0) flAttackDamageDelay = 0.0;
-	
-	new Float:flAttackDuration = KvGetFloat(kv, "attack_duration");
-	if (flAttackDuration < 0.0) flAttackDuration = 0.0;
-	
-	new bool:bAttackProps = bool:KvGetNum(kv, "attack_props");
-	
-	new Float:flAttackSpreadOld = KvGetFloat(kv, "attack_fov", 45.0);
-	new Float:flAttackSpread = KvGetFloat(kv, "attack_spread", flAttackSpreadOld);
-	
-	if (flAttackSpread < 0.0) flAttackSpread = 0.0;
-	else if (flAttackSpread > 360.0) flAttackSpread = 360.0;
-	
-	new Float:flAttackBeginRange = KvGetFloat(kv, "attack_begin_range", flAttackRange);
-	if (flAttackBeginRange < 0.0) flAttackBeginRange = 0.0;
-	
-	new Float:flAttackBeginFOV = KvGetFloat(kv, "attack_begin_fov", flAttackSpread);
-	if (flAttackBeginFOV < 0.0) flAttackBeginFOV = 0.0;
-	else if (flAttackBeginFOV > 360.0) flAttackBeginFOV = 360.0;
-	
-	new Float:flAttackCooldown = KvGetFloat(kv, "attack_cooldown");
-	if (flAttackCooldown < 0.0) flAttackCooldown = 0.0;
-	
-	new iAttackIndex = PushArrayCell(hAttacks, -1);
-	
-	SetArrayCell(hAttacks, iAttackIndex, iAttackType, ChaserProfileAttackData_Type);
-	SetArrayCell(hAttacks, iAttackIndex, bAttackProps, ChaserProfileAttackData_CanUseAgainstProps);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackRange, ChaserProfileAttackData_Range);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackDamage, ChaserProfileAttackData_Damage);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackDamageVsProps, ChaserProfileAttackData_DamageVsProps);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackDamageForce, ChaserProfileAttackData_DamageForce);
-	SetArrayCell(hAttacks, iAttackIndex, iAttackDamageType, ChaserProfileAttackData_DamageType);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackDamageDelay, ChaserProfileAttackData_DamageDelay);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackDuration, ChaserProfileAttackData_Duration);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackSpread, ChaserProfileAttackData_Spread);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackBeginRange, ChaserProfileAttackData_BeginRange);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackBeginFOV, ChaserProfileAttackData_BeginFOV);
-	SetArrayCell(hAttacks, iAttackIndex, flAttackCooldown, ChaserProfileAttackData_Cooldown);
-}
-
-/**
- *	Parses and stores the default animations of a chaser boss profile.
- */
-static ParseChaserProfileAnimations(Handle:kv, iUniqueProfileIndex)
-{
-	new Handle:hAnimations = CreateArray(64);
-	for (new i = 0; i < ChaserAnimationType_Max / 2; i++)
-	{
-		PushArrayString(hAnimations, "");
-		PushArrayCell(hAnimations, 1.0);
-	}
-	
-	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, hAnimations, ChaserProfileData_Animations);
-	
-	decl String:sAnimation[64];
-	decl Float:flAnimationPlaybackRate;
-	new animationCount = 0;
-	
-	KvGetString(kv, "animation_idle", sAnimation, sizeof(sAnimation));
-	flAnimationPlaybackRate = KvGetFloat(kv, "animation_idle_playbackrate", 1.0);
-	if (sAnimation[0])
-	{
-		animationCount++;
-		SetArrayString(hAnimations, ChaserAnimationType_Idle, sAnimation);
-		SetArrayCell(hAnimations, ChaserAnimationType_IdlePlaybackRate, flAnimationPlaybackRate);
-	}
-	
-	KvGetString(kv, "animation_walk", sAnimation, sizeof(sAnimation));
-	flAnimationPlaybackRate = KvGetFloat(kv, "animation_walk_playbackrate", 1.0);
-	if (sAnimation[0])
-	{
-		animationCount++;
-		SetArrayString(hAnimations, ChaserAnimationType_Walk, sAnimation);
-		SetArrayCell(hAnimations, ChaserAnimationType_WalkPlaybackRate, flAnimationPlaybackRate);
-	}
-	
-	KvGetString(kv, "animation_run", sAnimation, sizeof(sAnimation));
-	flAnimationPlaybackRate = KvGetFloat(kv, "animation_run_playbackrate", 1.0);
-	if (sAnimation[0])
-	{
-		animationCount++;
-		SetArrayString(hAnimations, ChaserAnimationType_Run, sAnimation);
-		SetArrayCell(hAnimations, ChaserAnimationType_RunPlaybackRate, flAnimationPlaybackRate);
-	}
-	
-	KvGetString(kv, "animation_attack", sAnimation, sizeof(sAnimation));
-	flAnimationPlaybackRate = KvGetFloat(kv, "animation_attack_playbackrate", 1.0);
-	if (sAnimation[0])
-	{
-		animationCount++;
-		SetArrayString(hAnimations, ChaserAnimationType_Attack, sAnimation);
-		SetArrayCell(hAnimations, ChaserAnimationType_AttackPlaybackRate, flAnimationPlaybackRate);
-	}
-	
-	KvGetString(kv, "animation_stun", sAnimation, sizeof(sAnimation));
-	flAnimationPlaybackRate = KvGetFloat(kv, "animation_stun_playbackrate", 1.0);
-	if (sAnimation[0])
-	{
-		animationCount++;
-		SetArrayString(hAnimations, ChaserAnimationType_Stunned, sAnimation);
-		SetArrayCell(hAnimations, ChaserAnimationType_StunnedPlaybackRate, flAnimationPlaybackRate);
-	}
-	
-	KvGetString(kv, "animation_death", sAnimation, sizeof(sAnimation));
-	flAnimationPlaybackRate = KvGetFloat(kv, "animation_death_playbackrate", 1.0);
-	if (sAnimation[0])
-	{
-		animationCount++;
-		SetArrayString(hAnimations, ChaserAnimationType_Stunned, sAnimation);
-		SetArrayCell(hAnimations, ChaserAnimationType_StunnedPlaybackRate, flAnimationPlaybackRate);
-	}
-	
-	if (animationCount == 0)
-	{
-		CloseHandle(hAnimations);
-		SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, INVALID_HANDLE, ChaserProfileData_Animations);
-	}
-}
-
-Float:GetChaserProfileStepSize(iChaserProfileIndex)
-{
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StepSize);
-}
-
-Float:GetChaserProfileWalkSpeed(iChaserProfileIndex, iDifficulty)
-{
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedEasy);
-		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedHard);
-		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedInsane);
-	}
-	
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedNormal);
-}
-
-Float:GetChaserProfileAirSpeed(iChaserProfileIndex, iDifficulty)
-{
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedEasy);
-		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedHard);
-		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedInsane);
-	}
-	
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedNormal);
-}
-
-Float:GetChaserProfileMaxWalkSpeed(iChaserProfileIndex, iDifficulty)
-{
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedEasy);
-		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedHard);
-		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedInsane);
-	}
-	
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedNormal);
-}
-
-Float:GetChaserProfileMaxAirSpeed(iChaserProfileIndex, iDifficulty)
-{
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedEasy);
-		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedHard);
-		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedInsane);
-	}
-	
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedNormal);
-}
-
-Float:GetChaserProfileWakeRadius(iChaserProfileIndex)
-{
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WakeRadius);
-}
-
-GetChaserProfileAttackCount(iChaserProfileIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-	
-	return GetArraySize(hAttacks);
-}
-
-GetChaserProfileAttackType(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-	
-	return GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Type);
-}
-
-Float:GetChaserProfileAttackDamage(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-	
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Damage);
-}
-
-Float:GetChaserProfileAttackDamageVsProps(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageVsProps);
-}
-
-Float:GetChaserProfileAttackDamageForce(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageForce);
-}
-
-GetChaserProfileAttackDamageType(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageType);
-}
-
-Float:GetChaserProfileAttackDamageDelay(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageDelay);
-}
-
-Float:GetChaserProfileAttackRange(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Range);
-}
-
-Float:GetChaserProfileAttackDuration(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Duration);
-}
-
-Float:GetChaserProfileAttackSpread(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Spread);
-}
-
-Float:GetChaserProfileAttackBeginRange(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_BeginRange);
-}
-
-Float:GetChaserProfileAttackBeginFOV(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_BeginFOV);
-}
-
-Float:GetChaserProfileAttackCooldown(iChaserProfileIndex, iAttackIndex)
-{
-	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
-	
-	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Cooldown);
-}
-
-bool:GetChaserProfileStunState(iChaserProfileIndex)
-{
-	return bool:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_CanBeStunned);
-}
-
-Float:GetChaserProfileStunDuration(iChaserProfileIndex)
-{
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StunDuration);
-}
-
-bool:GetChaserProfileStunFlashlightState(iChaserProfileIndex)
-{
-	return bool:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_CanBeStunnedByFlashlight);
-}
-
-Float:GetChaserProfileStunFlashlightDamage(iChaserProfileIndex)
-{
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StunFlashlightDamage);
-}
-
-Float:GetChaserProfileStunHealth(iChaserProfileIndex)
-{
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StunHealth);
-}
-
-stock Float:GetChaserProfileAwarenessIncreaseRate(iChaserProfileIndex, difficulty)
-{
-	switch (difficulty)
-	{
-		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateEasy);
-		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateHard);
-		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateInsane);
-	}
-	
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateNormal);
-}
-
-stock Float:GetChaserProfileAwarenessDecreaseRate(iChaserProfileIndex, difficulty)
-{
-	switch (difficulty)
-	{
-		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateEasy);
-		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateHard);
-		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateInsane);
-	}
-	
-	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateNormal);
+#if defined _sf2_profiles_chaser
+ #endinput
+#endif
+
+#define _sf2_profiles_chaser
+
+#define SF2_CHASER_BOSS_MAX_ATTACKS 8
+
+new Handle:g_hChaserProfileNames;
+new Handle:g_hChaserProfileData;
+
+enum
+{
+	SF2BossAttackType_Invalid = -1,
+	SF2BossAttackType_Melee = 0,
+	SF2BossAttackType_Ranged,
+	SF2BossAttackType_Projectile,
+	SF2BossAttackType_Custom
+};
+
+enum
+{
+	ChaserProfileData_StepSize,
+	ChaserProfileData_WalkSpeedEasy,
+	ChaserProfileData_WalkSpeedNormal,
+	ChaserProfileData_WalkSpeedHard,
+	ChaserProfileData_WalkSpeedInsane,
+	
+	ChaserProfileData_AirSpeedEasy,
+	ChaserProfileData_AirSpeedNormal,
+	ChaserProfileData_AirSpeedHard,
+	ChaserProfileData_AirSpeedInsane,
+	
+	ChaserProfileData_MaxWalkSpeedEasy,
+	ChaserProfileData_MaxWalkSpeedNormal,
+	ChaserProfileData_MaxWalkSpeedHard,
+	ChaserProfileData_MaxWalkSpeedInsane,
+	
+	ChaserProfileData_MaxAirSpeedEasy,
+	ChaserProfileData_MaxAirSpeedNormal,
+	ChaserProfileData_MaxAirSpeedHard,
+	ChaserProfileData_MaxAirSpeedInsane,
+	
+	ChaserProfileData_WakeRadius,
+	
+	ChaserProfileData_Attacks,		// array that contains data about attacks
+	
+	ChaserProfileData_Animations,						// Array that contains data of animations.
+	
+	ChaserProfileData_CanBeStunned,
+	ChaserProfileData_StunDuration,
+	ChaserProfileData_StunHealth,
+	ChaserProfileData_CanBeStunnedByFlashlight,
+	ChaserProfileData_StunFlashlightDamage,
+	
+	ChaserProfileData_MemoryLifeTime,
+	
+	ChaserProfileData_AwarenessIncreaseRateEasy,
+	ChaserProfileData_AwarenessIncreaseRateNormal,
+	ChaserProfileData_AwarenessIncreaseRateHard,
+	ChaserProfileData_AwarenessIncreaseRateInsane,
+	ChaserProfileData_AwarenessDecreaseRateEasy,
+	ChaserProfileData_AwarenessDecreaseRateNormal,
+	ChaserProfileData_AwarenessDecreaseRateHard,
+	ChaserProfileData_AwarenessDecreaseRateInsane,
+	
+	ChaserProfileData_MaxStats
+};
+
+enum
+{
+	ChaserProfileAttackData_Type = 0,
+	ChaserProfileAttackData_CanUseAgainstProps,
+	ChaserProfileAttackData_Damage,
+	ChaserProfileAttackData_DamageVsProps,
+	ChaserProfileAttackData_DamageForce,
+	ChaserProfileAttackData_DamageType,
+	ChaserProfileAttackData_DamageDelay,
+	ChaserProfileAttackData_Range,
+	ChaserProfileAttackData_Duration,
+	ChaserProfileAttackData_Spread,
+	ChaserProfileAttackData_BeginRange,
+	ChaserProfileAttackData_BeginFOV,
+	ChaserProfileAttackData_Cooldown,
+	ChaserProfileAttackData_MaxStats
+};
+
+enum 
+{
+	ChaserAnimationType_Idle = 0,
+	ChaserAnimationType_IdlePlaybackRate,
+	ChaserAnimationType_Walk,
+	ChaserAnimationType_WalkPlaybackRate,
+	ChaserAnimationType_Run,
+	ChaserAnimationType_RunPlaybackRate,
+	ChaserAnimationType_Attack,
+	ChaserAnimationType_AttackPlaybackRate,
+	ChaserAnimationType_Stunned,
+	ChaserAnimationType_StunnedPlaybackRate,
+	ChaserAnimationType_Death,
+	ChaserAnimationType_DeathPlaybackRate,
+	ChaserAnimationType_Max
+};
+
+InitializeChaserProfiles()
+{
+	g_hChaserProfileNames = CreateTrie();
+	g_hChaserProfileData = CreateArray(ChaserProfileData_MaxStats);
+}
+
+/**
+ *	Clears all data and memory currently in use by chaser profiles.
+ */
+ClearChaserProfiles()
+{
+	for (new i = 0, iSize = GetArraySize(g_hChaserProfileData); i < iSize; i++)
+	{
+		new Handle:hHandle = Handle:GetArrayCell(g_hChaserProfileData, i, ChaserProfileData_Attacks);
+		if (hHandle != INVALID_HANDLE)
+		{
+			CloseHandle(hHandle);
+		}
+		
+		hHandle = Handle:GetArrayCell(g_hChaserProfileData, i, ChaserProfileData_Animations);
+		if (hHandle != INVALID_HANDLE)
+		{
+			CloseHandle(hHandle);
+		}
+	}
+	
+	ClearTrie(g_hChaserProfileNames);
+	ClearArray(g_hChaserProfileData);
+}
+
+/**
+ *	Parses and stores the unique values of a chaser profile from the current position in the profiles config.
+ *	Returns true if loading was successful, false if not.
+ */
+bool:LoadChaserBossProfile(Handle:kv, const String:sProfile[], &iUniqueProfileIndex, String:sLoadFailReasonBuffer[], iLoadFailReasonBufferLen)
+{
+	strcopy(sLoadFailReasonBuffer, iLoadFailReasonBufferLen, "");
+	
+	iUniqueProfileIndex = PushArrayCell(g_hChaserProfileData, -1);
+	SetTrieValue(g_hChaserProfileNames, sProfile, iUniqueProfileIndex);
+	
+	new Float:flBossStepSize = KvGetFloat(kv, "stepsize", 16.0);
+	
+	new Float:flBossDefaultWalkSpeed = KvGetFloat(kv, "walkspeed", 30.0);
+	new Float:flBossWalkSpeedEasy = KvGetFloat(kv, "walkspeed_easy", flBossDefaultWalkSpeed);
+	new Float:flBossWalkSpeedHard = KvGetFloat(kv, "walkspeed_hard", flBossDefaultWalkSpeed);
+	new Float:flBossWalkSpeedInsane = KvGetFloat(kv, "walkspeed_insane", flBossDefaultWalkSpeed);
+	
+	new Float:flBossDefaultAirSpeed = KvGetFloat(kv, "airspeed", 50.0);
+	new Float:flBossAirSpeedEasy = KvGetFloat(kv, "airspeed_easy", flBossDefaultAirSpeed);
+	new Float:flBossAirSpeedHard = KvGetFloat(kv, "airspeed_hard", flBossDefaultAirSpeed);
+	new Float:flBossAirSpeedInsane = KvGetFloat(kv, "airspeed_insane", flBossDefaultAirSpeed);
+	
+	new Float:flBossDefaultMaxWalkSpeed = KvGetFloat(kv, "walkspeed_max", 30.0);
+	new Float:flBossMaxWalkSpeedEasy = KvGetFloat(kv, "walkspeed_max_easy", flBossDefaultMaxWalkSpeed);
+	new Float:flBossMaxWalkSpeedHard = KvGetFloat(kv, "walkspeed_max_hard", flBossDefaultMaxWalkSpeed);
+	new Float:flBossMaxWalkSpeedInsane = KvGetFloat(kv, "walkspeed_max_insane", flBossDefaultMaxWalkSpeed);
+	
+	new Float:flBossDefaultMaxAirSpeed = KvGetFloat(kv, "airspeed_max", 50.0);
+	new Float:flBossMaxAirSpeedEasy = KvGetFloat(kv, "airspeed_max_easy", flBossDefaultMaxAirSpeed);
+	new Float:flBossMaxAirSpeedHard = KvGetFloat(kv, "airspeed_max_hard", flBossDefaultMaxAirSpeed);
+	new Float:flBossMaxAirSpeedInsane = KvGetFloat(kv, "airspeed_max_insane", flBossDefaultMaxAirSpeed);
+	
+	new Float:flWakeRange = KvGetFloat(kv, "wake_radius");
+	if (flWakeRange < 0.0) flWakeRange = 0.0;
+	
+	new bool:bCanBeStunned = bool:KvGetNum(kv, "stun_enabled");
+	
+	new Float:flStunDuration = KvGetFloat(kv, "stun_duration");
+	if (flStunDuration < 0.0) flStunDuration = 0.0;
+	
+	new Float:flStunHealth = KvGetFloat(kv, "stun_health");
+	if (flStunHealth < 0.0) flStunHealth = 0.0;
+	
+	new bool:bStunTakeDamageFromFlashlight = bool:KvGetNum(kv, "stun_damage_flashlight_enabled");
+	
+	new Float:flStunFlashlightDamage = KvGetFloat(kv, "stun_damage_flashlight");
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossStepSize, ChaserProfileData_StepSize);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultWalkSpeed, ChaserProfileData_WalkSpeedNormal);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossWalkSpeedEasy, ChaserProfileData_WalkSpeedEasy);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossWalkSpeedHard, ChaserProfileData_WalkSpeedHard);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossWalkSpeedInsane, ChaserProfileData_WalkSpeedInsane);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultAirSpeed, ChaserProfileData_AirSpeedNormal);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossAirSpeedEasy, ChaserProfileData_AirSpeedEasy);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossAirSpeedHard, ChaserProfileData_AirSpeedHard);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossAirSpeedInsane, ChaserProfileData_AirSpeedInsane);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultMaxWalkSpeed, ChaserProfileData_MaxWalkSpeedNormal);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxWalkSpeedEasy, ChaserProfileData_MaxWalkSpeedEasy);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxWalkSpeedHard, ChaserProfileData_MaxWalkSpeedHard);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxWalkSpeedInsane, ChaserProfileData_MaxWalkSpeedInsane);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossDefaultMaxAirSpeed, ChaserProfileData_MaxAirSpeedNormal);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxAirSpeedEasy, ChaserProfileData_MaxAirSpeedEasy);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxAirSpeedHard, ChaserProfileData_MaxAirSpeedHard);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flBossMaxAirSpeedInsane, ChaserProfileData_MaxAirSpeedInsane);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flWakeRange, ChaserProfileData_WakeRadius);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, bCanBeStunned, ChaserProfileData_CanBeStunned);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flStunDuration, ChaserProfileData_StunDuration);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flStunHealth, ChaserProfileData_StunHealth);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, bStunTakeDamageFromFlashlight, ChaserProfileData_CanBeStunnedByFlashlight);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flStunFlashlightDamage, ChaserProfileData_StunFlashlightDamage);
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "memory_lifetime", 10.0), ChaserProfileData_MemoryLifeTime);
+	
+	new Float:flDefaultAwarenessIncreaseRate = KvGetFloat(kv, "awareness_rate_increase", 75.0);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_increase_easy", flDefaultAwarenessIncreaseRate), ChaserProfileData_AwarenessIncreaseRateEasy);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flDefaultAwarenessIncreaseRate, ChaserProfileData_AwarenessIncreaseRateNormal);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_increase_hard", flDefaultAwarenessIncreaseRate), ChaserProfileData_AwarenessIncreaseRateHard);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_increase_insane", flDefaultAwarenessIncreaseRate), ChaserProfileData_AwarenessIncreaseRateInsane);
+	
+	new Float:flDefaultAwarenessDecreaseRate = KvGetFloat(kv, "awareness_rate_decrease", 150.0);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_decrease_easy", flDefaultAwarenessDecreaseRate), ChaserProfileData_AwarenessDecreaseRateEasy);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, flDefaultAwarenessDecreaseRate, ChaserProfileData_AwarenessDecreaseRateNormal);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_decrease_hard", flDefaultAwarenessDecreaseRate), ChaserProfileData_AwarenessDecreaseRateHard);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, KvGetFloat(kv, "awareness_rate_decrease_insane", flDefaultAwarenessDecreaseRate), ChaserProfileData_AwarenessDecreaseRateInsane);
+	
+	ParseChaserProfileAttacks(kv, iUniqueProfileIndex);
+	
+	ParseChaserProfileAnimations(kv, iUniqueProfileIndex);
+	
+	return true;
+}
+
+static ParseChaserProfileAttacks(Handle:kv, iUniqueProfileIndex)
+{
+	//decl String:sBuffer[PLATFORM_MAX_PATH];
+	
+	// Create the array.
+	new Handle:hAttacks = CreateArray(ChaserProfileAttackData_MaxStats);
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, hAttacks, ChaserProfileData_Attacks);
+	
+	//new iAttackType = KvGetNum(kv, "attack_type");
+	new iAttackType = SF2BossAttackType_Melee;
+	
+	new Float:flAttackRange = KvGetFloat(kv, "attack_range");
+	if (flAttackRange < 0.0) flAttackRange = 0.0;
+	
+	new Float:flAttackDamage = KvGetFloat(kv, "attack_damage");
+	new Float:flAttackDamageVsProps = KvGetFloat(kv, "attack_damage_vs_props", flAttackDamage);
+	new Float:flAttackDamageForce = KvGetFloat(kv, "attack_damageforce");
+	
+	new iAttackDamageType = KvGetNum(kv, "attack_damagetype");
+	if (iAttackDamageType < 0) iAttackDamageType = 0;
+	
+	new Float:flAttackDamageDelay = KvGetFloat(kv, "attack_delay");
+	if (flAttackDamageDelay < 0.0) flAttackDamageDelay = 0.0;
+	
+	new Float:flAttackDuration = KvGetFloat(kv, "attack_duration");
+	if (flAttackDuration < 0.0) flAttackDuration = 0.0;
+	
+	new bool:bAttackProps = bool:KvGetNum(kv, "attack_props");
+	
+	new Float:flAttackSpreadOld = KvGetFloat(kv, "attack_fov", 45.0);
+	new Float:flAttackSpread = KvGetFloat(kv, "attack_spread", flAttackSpreadOld);
+	
+	if (flAttackSpread < 0.0) flAttackSpread = 0.0;
+	else if (flAttackSpread > 360.0) flAttackSpread = 360.0;
+	
+	new Float:flAttackBeginRange = KvGetFloat(kv, "attack_begin_range", flAttackRange);
+	if (flAttackBeginRange < 0.0) flAttackBeginRange = 0.0;
+	
+	new Float:flAttackBeginFOV = KvGetFloat(kv, "attack_begin_fov", flAttackSpread);
+	if (flAttackBeginFOV < 0.0) flAttackBeginFOV = 0.0;
+	else if (flAttackBeginFOV > 360.0) flAttackBeginFOV = 360.0;
+	
+	new Float:flAttackCooldown = KvGetFloat(kv, "attack_cooldown");
+	if (flAttackCooldown < 0.0) flAttackCooldown = 0.0;
+	
+	new iAttackIndex = PushArrayCell(hAttacks, -1);
+	
+	SetArrayCell(hAttacks, iAttackIndex, iAttackType, ChaserProfileAttackData_Type);
+	SetArrayCell(hAttacks, iAttackIndex, bAttackProps, ChaserProfileAttackData_CanUseAgainstProps);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackRange, ChaserProfileAttackData_Range);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackDamage, ChaserProfileAttackData_Damage);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackDamageVsProps, ChaserProfileAttackData_DamageVsProps);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackDamageForce, ChaserProfileAttackData_DamageForce);
+	SetArrayCell(hAttacks, iAttackIndex, iAttackDamageType, ChaserProfileAttackData_DamageType);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackDamageDelay, ChaserProfileAttackData_DamageDelay);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackDuration, ChaserProfileAttackData_Duration);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackSpread, ChaserProfileAttackData_Spread);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackBeginRange, ChaserProfileAttackData_BeginRange);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackBeginFOV, ChaserProfileAttackData_BeginFOV);
+	SetArrayCell(hAttacks, iAttackIndex, flAttackCooldown, ChaserProfileAttackData_Cooldown);
+}
+
+/**
+ *	Parses and stores the default animations of a chaser boss profile.
+ */
+static ParseChaserProfileAnimations(Handle:kv, iUniqueProfileIndex)
+{
+	new Handle:hAnimations = CreateArray(64);
+	for (new i = 0; i < ChaserAnimationType_Max / 2; i++)
+	{
+		PushArrayString(hAnimations, "");
+		PushArrayCell(hAnimations, 1.0);
+	}
+	
+	SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, hAnimations, ChaserProfileData_Animations);
+	
+	decl String:sAnimation[64];
+	decl Float:flAnimationPlaybackRate;
+	new animationCount = 0;
+	
+	KvGetString(kv, "animation_idle", sAnimation, sizeof(sAnimation));
+	flAnimationPlaybackRate = KvGetFloat(kv, "animation_idle_playbackrate", 1.0);
+	if (sAnimation[0])
+	{
+		animationCount++;
+		SetArrayString(hAnimations, ChaserAnimationType_Idle, sAnimation);
+		SetArrayCell(hAnimations, ChaserAnimationType_IdlePlaybackRate, flAnimationPlaybackRate);
+	}
+	
+	KvGetString(kv, "animation_walk", sAnimation, sizeof(sAnimation));
+	flAnimationPlaybackRate = KvGetFloat(kv, "animation_walk_playbackrate", 1.0);
+	if (sAnimation[0])
+	{
+		animationCount++;
+		SetArrayString(hAnimations, ChaserAnimationType_Walk, sAnimation);
+		SetArrayCell(hAnimations, ChaserAnimationType_WalkPlaybackRate, flAnimationPlaybackRate);
+	}
+	
+	KvGetString(kv, "animation_run", sAnimation, sizeof(sAnimation));
+	flAnimationPlaybackRate = KvGetFloat(kv, "animation_run_playbackrate", 1.0);
+	if (sAnimation[0])
+	{
+		animationCount++;
+		SetArrayString(hAnimations, ChaserAnimationType_Run, sAnimation);
+		SetArrayCell(hAnimations, ChaserAnimationType_RunPlaybackRate, flAnimationPlaybackRate);
+	}
+	
+	KvGetString(kv, "animation_attack", sAnimation, sizeof(sAnimation));
+	flAnimationPlaybackRate = KvGetFloat(kv, "animation_attack_playbackrate", 1.0);
+	if (sAnimation[0])
+	{
+		animationCount++;
+		SetArrayString(hAnimations, ChaserAnimationType_Attack, sAnimation);
+		SetArrayCell(hAnimations, ChaserAnimationType_AttackPlaybackRate, flAnimationPlaybackRate);
+	}
+	
+	KvGetString(kv, "animation_stun", sAnimation, sizeof(sAnimation));
+	flAnimationPlaybackRate = KvGetFloat(kv, "animation_stun_playbackrate", 1.0);
+	if (sAnimation[0])
+	{
+		animationCount++;
+		SetArrayString(hAnimations, ChaserAnimationType_Stunned, sAnimation);
+		SetArrayCell(hAnimations, ChaserAnimationType_StunnedPlaybackRate, flAnimationPlaybackRate);
+	}
+	
+	KvGetString(kv, "animation_death", sAnimation, sizeof(sAnimation));
+	flAnimationPlaybackRate = KvGetFloat(kv, "animation_death_playbackrate", 1.0);
+	if (sAnimation[0])
+	{
+		animationCount++;
+		SetArrayString(hAnimations, ChaserAnimationType_Stunned, sAnimation);
+		SetArrayCell(hAnimations, ChaserAnimationType_StunnedPlaybackRate, flAnimationPlaybackRate);
+	}
+	
+	if (animationCount == 0)
+	{
+		CloseHandle(hAnimations);
+		SetArrayCell(g_hChaserProfileData, iUniqueProfileIndex, INVALID_HANDLE, ChaserProfileData_Animations);
+	}
+}
+
+Float:GetChaserProfileStepSize(iChaserProfileIndex)
+{
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StepSize);
+}
+
+Float:GetChaserProfileWalkSpeed(iChaserProfileIndex, iDifficulty)
+{
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedEasy);
+		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedHard);
+		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedInsane);
+	}
+	
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WalkSpeedNormal);
+}
+
+Float:GetChaserProfileAirSpeed(iChaserProfileIndex, iDifficulty)
+{
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedEasy);
+		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedHard);
+		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedInsane);
+	}
+	
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AirSpeedNormal);
+}
+
+Float:GetChaserProfileMaxWalkSpeed(iChaserProfileIndex, iDifficulty)
+{
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedEasy);
+		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedHard);
+		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedInsane);
+	}
+	
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxWalkSpeedNormal);
+}
+
+Float:GetChaserProfileMaxAirSpeed(iChaserProfileIndex, iDifficulty)
+{
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedEasy);
+		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedHard);
+		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedInsane);
+	}
+	
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_MaxAirSpeedNormal);
+}
+
+Float:GetChaserProfileWakeRadius(iChaserProfileIndex)
+{
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_WakeRadius);
+}
+
+GetChaserProfileAttackCount(iChaserProfileIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+	
+	return GetArraySize(hAttacks);
+}
+
+GetChaserProfileAttackType(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+	
+	return GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Type);
+}
+
+Float:GetChaserProfileAttackDamage(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+	
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Damage);
+}
+
+Float:GetChaserProfileAttackDamageVsProps(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageVsProps);
+}
+
+Float:GetChaserProfileAttackDamageForce(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageForce);
+}
+
+GetChaserProfileAttackDamageType(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageType);
+}
+
+Float:GetChaserProfileAttackDamageDelay(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_DamageDelay);
+}
+
+Float:GetChaserProfileAttackRange(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Range);
+}
+
+Float:GetChaserProfileAttackDuration(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Duration);
+}
+
+Float:GetChaserProfileAttackSpread(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Spread);
+}
+
+Float:GetChaserProfileAttackBeginRange(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_BeginRange);
+}
+
+Float:GetChaserProfileAttackBeginFOV(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_BeginFOV);
+}
+
+Float:GetChaserProfileAttackCooldown(iChaserProfileIndex, iAttackIndex)
+{
+	new Handle:hAttacks = Handle:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_Attacks);
+	
+	return Float:GetArrayCell(hAttacks, iAttackIndex, ChaserProfileAttackData_Cooldown);
+}
+
+bool:GetChaserProfileStunState(iChaserProfileIndex)
+{
+	return bool:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_CanBeStunned);
+}
+
+Float:GetChaserProfileStunDuration(iChaserProfileIndex)
+{
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StunDuration);
+}
+
+bool:GetChaserProfileStunFlashlightState(iChaserProfileIndex)
+{
+	return bool:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_CanBeStunnedByFlashlight);
+}
+
+Float:GetChaserProfileStunFlashlightDamage(iChaserProfileIndex)
+{
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StunFlashlightDamage);
+}
+
+Float:GetChaserProfileStunHealth(iChaserProfileIndex)
+{
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_StunHealth);
+}
+
+stock Float:GetChaserProfileAwarenessIncreaseRate(iChaserProfileIndex, difficulty)
+{
+	switch (difficulty)
+	{
+		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateEasy);
+		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateHard);
+		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateInsane);
+	}
+	
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessIncreaseRateNormal);
+}
+
+stock Float:GetChaserProfileAwarenessDecreaseRate(iChaserProfileIndex, difficulty)
+{
+	switch (difficulty)
+	{
+		case Difficulty_Easy: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateEasy);
+		case Difficulty_Hard: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateHard);
+		case Difficulty_Insane: return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateInsane);
+	}
+	
+	return Float:GetArrayCell(g_hChaserProfileData, iChaserProfileIndex, ChaserProfileData_AwarenessDecreaseRateNormal);
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/pvp.sp b/addons/sourcemod/scripting/rytp_horror/pvp.sp
index f15ccd5..1cfc17f 100644
--- a/addons/sourcemod/scripting/rytp_horror/pvp.sp
+++ b/addons/sourcemod/scripting/rytp_horror/pvp.sp
@@ -1,582 +1,582 @@
-#if defined _sf2_pvp_included
- #endinput
-#endif
-#define _sf2_pvp_included
-
-
-#define SF2_PVP_SPAWN_SOUND "items/spawn_item.wav"
-
-new Handle:g_cvPvPArenaLeaveTime;
-new Handle:g_cvPvPArenaPlayerCollisions;
-
-static const String:g_sPvPProjectileClasses[][] = 
-{
-	"tf_projectile_rocket", 
-	"tf_projectile_sentryrocket", 
-	"tf_projectile_arrow", 
-	"tf_projectile_stun_ball",
-	"tf_projectile_ball_ornament",
-	"tf_projectile_cleaver",
-	"tf_projectile_energy_ball",
-	"tf_projectile_energy_ring",
-	"tf_projectile_flare",
-	"tf_projectile_healing_bolt",
-	"tf_projectile_jar",
-	"tf_projectile_jar_milk",
-	"tf_projectile_pipe",
-	"tf_projectile_pipe_remote",
-	"tf_projectile_syringe"
-};
-
-static bool:g_bPlayerInPvP[MAXPLAYERS + 1];
-static Handle:g_hPlayerPvPTimer[MAXPLAYERS + 1];
-static Handle:g_hPlayerPvPRespawnTimer[MAXPLAYERS + 1];
-static g_iPlayerPvPTimerCount[MAXPLAYERS + 1];
-static bool:g_bPlayerInPvPTrigger[MAXPLAYERS + 1];
-
-static Handle:g_hPvPFlameEntities;
-
-enum
-{
-	PvPFlameEntData_EntRef = 0,
-	PvPFlameEntData_LastHitEntRef,
-	PvPFlameEntData_MaxStats
-};
-
-public PvP_Initialize()
-{
-	g_cvPvPArenaLeaveTime = CreateConVar("sf2_player_pvparena_leavetime", "3");
-	g_cvPvPArenaPlayerCollisions = CreateConVar("sf2_player_pvparena_collisions", "1");
-	
-	g_hPvPFlameEntities = CreateArray(PvPFlameEntData_MaxStats);
-}
-
-public PvP_SetupMenus()
-{
-	g_hMenuSettingsPvP = CreateMenu(Menu_SettingsPvP);
-	SetMenuTitle(g_hMenuSettingsPvP, "%t%t\n \n", "SF2 Prefix", "SF2 Settings PvP Menu Title");
-	AddMenuItem(g_hMenuSettingsPvP, "0", "Toggle automatic spawning");
-	SetMenuExitBackButton(g_hMenuSettingsPvP, true);
-}
-
-public PvP_OnMapStart()
-{
-	ClearArray(g_hPvPFlameEntities);
-}
-
-public PvP_Precache()
-{
-	PrecacheSound2(SF2_PVP_SPAWN_SOUND);
-}
-
-public PvP_OnClientPutInServer(client)
-{
-	PvP_ForceResetPlayerPvPData(client);
-}
-
-public PvP_OnClientDisconnect(client)
-{
-	PvP_SetPlayerPvPState(client, false, false, false);
-}
-
-public PvP_OnGameFrame()
-{
-	// Process through PvP projectiles.
-	for (new i = 0; i < sizeof(g_sPvPProjectileClasses); i++)
-	{
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, g_sPvPProjectileClasses[i])) != -1)
-		{
-			new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
-			new bool:bChangeProjectileTeam = false;
-			
-			new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
-			if (IsValidClient(iOwnerEntity) && IsClientInPvP(iOwnerEntity))
-			{
-				bChangeProjectileTeam = true;
-			}
-			else if (iThrowerOffset != -1)
-			{
-				iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
-				if (IsValidClient(iOwnerEntity) && IsClientInPvP(iOwnerEntity))
-				{
-					bChangeProjectileTeam = true;
-				}
-			}
-			
-			if (bChangeProjectileTeam)
-			{
-				SetEntProp(ent, Prop_Data, "m_iInitialTeamNum", 0);
-				SetEntProp(ent, Prop_Send, "m_iTeamNum", 0);
-			}
-		}
-	}
-
-	// Process through PvP flame entities.
-	{
-		static Float:flMins[3] = { -6.0, ... };
-		static Float:flMaxs[3] = { 6.0, ... };
-		
-		decl Float:flOrigin[3];
-		
-		new Handle:hTrace = INVALID_HANDLE;
-		new ent = -1;
-		new iOwnerEntity = INVALID_ENT_REFERENCE; 
-		new iHitEntity = INVALID_ENT_REFERENCE;
-		
-		while ((ent = FindEntityByClassname(ent, "tf_flame")) != -1)
-		{
-			iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
-			
-			if (IsValidEdict(iOwnerEntity))
-			{
-				// tf_flame's initial owner SHOULD be the flamethrower that it originates from.
-				// If not, then something's completely bogus.
-				
-				iOwnerEntity = GetEntPropEnt(iOwnerEntity, Prop_Data, "m_hOwnerEntity");
-			}
-			
-			if (IsValidClient(iOwnerEntity) && (IsRoundInWarmup() || IsClientInPvP(iOwnerEntity)))
-			{
-				GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flOrigin);
-				
-				hTrace = TR_TraceHullFilterEx(flOrigin, flOrigin, flMins, flMaxs, MASK_PLAYERSOLID, TraceRayDontHitEntity, iOwnerEntity);
-				iHitEntity = TR_GetEntityIndex(hTrace);
-				CloseHandle(hTrace);
-				
-				if (IsValidEntity(iHitEntity))
-				{
-					new entref = EntIndexToEntRef(ent);
-					
-					new iIndex = FindValueInArray(g_hPvPFlameEntities, entref);
-					if (iIndex != -1)
-					{
-						new iLastHitEnt = EntRefToEntIndex(GetArrayCell(g_hPvPFlameEntities, iIndex, PvPFlameEntData_LastHitEntRef));
-					
-						if (iHitEntity != iLastHitEnt)
-						{
-							SetArrayCell(g_hPvPFlameEntities, iIndex, EntIndexToEntRef(iHitEntity), PvPFlameEntData_LastHitEntRef);
-							PvP_OnFlameEntityStartTouchPost(ent, iHitEntity);
-						}
-					}
-				}
-			}
-		}
-	}
-}
-
-public PvP_OnEntityCreated(ent, const String:sClassname[])
-{
-	if (StrEqual(sClassname, "tf_flame", false))
-	{
-		new iIndex = PushArrayCell(g_hPvPFlameEntities, EntIndexToEntRef(ent));
-		if (iIndex != -1)
-		{
-			SetArrayCell(g_hPvPFlameEntities, iIndex, INVALID_ENT_REFERENCE, PvPFlameEntData_LastHitEntRef);
-		}
-	}
-	else
-	{
-		for (new i = 0; i < sizeof(g_sPvPProjectileClasses); i++)
-		{
-			if (StrEqual(sClassname, g_sPvPProjectileClasses[i], false))
-			{
-				SDKHook(ent, SDKHook_Spawn, Hook_PvPProjectileSpawn);
-				SDKHook(ent, SDKHook_SpawnPost, Hook_PvPProjectileSpawnPost);
-				break;
-			}
-		}
-	}
-}
-
-public PvP_OnEntityDestroyed(ent, const String:sClassname[])
-{
-	if (StrEqual(sClassname, "tf_flame", false))
-	{
-		new entref = EntIndexToEntRef(ent);
-		new iIndex = FindValueInArray(g_hPvPFlameEntities, entref);
-		if (iIndex != -1)
-		{
-			RemoveFromArray(g_hPvPFlameEntities, iIndex);
-		}
-	}
-}
-
-public Action:Hook_PvPProjectileSpawn(ent)
-{
-	decl String:sClass[64];
-	GetEntityClassname(ent, sClass, sizeof(sClass));
-	
-	new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
-	new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
-	
-	if (iOwnerEntity == -1 && iThrowerOffset != -1)
-	{
-		iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
-	}
-	
-	if (IsValidClient(iOwnerEntity))
-	{
-		if (IsClientInPvP(iOwnerEntity))
-		{
-			SetEntProp(ent, Prop_Data, "m_iInitialTeamNum", 0);
-			SetEntProp(ent, Prop_Send, "m_iTeamNum", 0);
-		}
-	}
-
-	return Plugin_Continue;
-}
-
-public Hook_PvPProjectileSpawnPost(ent)
-{
-	decl String:sClass[64];
-	GetEntityClassname(ent, sClass, sizeof(sClass));
-	
-	new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
-	new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
-	
-	if (iOwnerEntity == -1 && iThrowerOffset != -1)
-	{
-		iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
-	}
-	
-	if (IsValidClient(iOwnerEntity))
-	{
-		if (IsClientInPvP(iOwnerEntity))
-		{
-			SetEntProp(ent, Prop_Data, "m_iInitialTeamNum", 0);
-			SetEntProp(ent, Prop_Send, "m_iTeamNum", 0);
-		}
-	}
-}
-
-public PvP_OnPlayerSpawn(client)
-{
-	PvP_SetPlayerPvPState(client, false, false, false);
-
-	if (IsPlayerAlive(client) && IsClientParticipating(client))
-	{
-		if (!IsClientInGhostMode(client) && !g_bPlayerProxy[client])
-		{
-			if (g_bPlayerEliminated[client] || g_bPlayerEscaped[client])
-			{
-				new bool:bAutoSpawn = g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn];
-				
-				if (bAutoSpawn)
-				{
-					g_hPlayerPvPRespawnTimer[client] = CreateTimer(0.12, Timer_TeleportPlayerToPvP, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-			}
-			else
-			{
-				g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
-			}
-		}
-	}
-}
-
-public PvP_OnPlayerDeath(client, bool:bFake)
-{
-	if (!bFake)
-	{
-		if (!IsClientInGhostMode(client) && !g_bPlayerProxy[client])
-		{
-			new bool:bAutoSpawn = g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn];
-			
-			if (bAutoSpawn)
-			{
-				if (g_bPlayerEliminated[client] || g_bPlayerEscaped[client])
-				{
-					if (!IsRoundEnding())
-					{
-						g_hPlayerPvPRespawnTimer[client] = CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-					}
-				}
-			}
-		}
-	}
-}
-
-public PvP_OnClientGhostModeEnable(client)
-{
-	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
-}
-
-public PvP_OnClientPutInPlay(client)
-{
-	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
-}
-
-public bool:Hook_ClientPvPShouldCollide(ent, collisiongroup, contentsmask, bool:originalResult)
-{
-	if (!g_bEnabled) return originalResult;
-	return true;
-}
-
-public PvP_OnTriggerStartTouch(trigger, other)
-{
-	decl String:sName[64];
-	GetEntPropString(trigger, Prop_Data, "m_iName", sName, sizeof(sName));
-	
-	if (StrContains(sName, "sf2_pvp_trigger", false) == 0)
-	{
-		if (IsValidClient(other) && IsPlayerAlive(other))
-		{
-			g_bPlayerInPvPTrigger[other] = true;
-			
-			if (IsClientInPvP(other))
-			{
-				// Player left and came back again, but is still in PvP mode.
-				g_iPlayerPvPTimerCount[other] = 0;
-				g_hPlayerPvPTimer[other] = INVALID_HANDLE;
-			}
-			else
-			{
-				PvP_SetPlayerPvPState(other, true);
-			}
-		}
-	}
-}
-
-public PvP_OnTriggerEndTouch(trigger, other)
-{
-	decl String:sName[64];
-	GetEntPropString(trigger, Prop_Data, "m_iName", sName, sizeof(sName));
-	
-	if (StrContains(sName, "sf2_pvp_trigger", false) == 0)
-	{
-		if (IsValidClient(other))
-		{
-			g_bPlayerInPvPTrigger[other] = false;
-			
-			if (IsClientInPvP(other))
-			{
-				g_iPlayerPvPTimerCount[other] = GetConVarInt(g_cvPvPArenaLeaveTime);
-				g_hPlayerPvPTimer[other] = CreateTimer(1.0, Timer_PlayerPvPLeaveCountdown, GetClientUserId(other), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
-			}
-		}
-	}
-}
-
-/**
- *	Enables/Disables PvP mode on the player.
- */
-PvP_SetPlayerPvPState(client, bool:bStatus, bool:bRemoveProjectiles=true, bool:bRegenerate=true)
-{
-	if (!IsValidClient(client)) return;
-	
-	new bool:bOldInPvP = g_bPlayerInPvP[client];
-	if (bStatus == bOldInPvP) return; // no change
-	
-	g_bPlayerInPvP[client] = bStatus;
-	g_hPlayerPvPTimer[client] = INVALID_HANDLE;
-	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
-	g_iPlayerPvPTimerCount[client] = 0;
-	
-	if (bRemoveProjectiles)
-	{
-		// Remove previous projectiles.
-		PvP_RemovePlayerProjectiles(client);
-	}
-	
-	if (bRegenerate)
-	{
-		// Regenerate player but keep health the same.
-		new iHealth = GetEntProp(client, Prop_Send, "m_iHealth");
-		TF2_RegeneratePlayer(client);
-		SetEntProp(client, Prop_Data, "m_iHealth", iHealth);
-		SetEntProp(client, Prop_Send, "m_iHealth", iHealth);
-	}
-	
-	if (bStatus && GetConVarBool(g_cvPvPArenaPlayerCollisions))
-	{
-		SDKHook(client, SDKHook_ShouldCollide, Hook_ClientPvPShouldCollide);
-	}
-	else
-	{
-		SDKUnhook(client, SDKHook_ShouldCollide, Hook_ClientPvPShouldCollide);
-	}
-}
-
-static PvP_OnFlameEntityStartTouchPost(flame, other)
-{
-	if (IsValidClient(other))
-	{
-		if ((IsRoundInWarmup() || IsClientInPvP(other)) && !IsRoundEnding())
-		{
-			new iFlamethrower = GetEntPropEnt(flame, Prop_Data, "m_hOwnerEntity");
-			if (IsValidEdict(iFlamethrower))
-			{
-				new iOwnerEntity = GetEntPropEnt(iFlamethrower, Prop_Data, "m_hOwnerEntity");
-				if (iOwnerEntity != other && IsValidClient(iOwnerEntity))
-				{
-					if (IsRoundInWarmup() || IsClientInPvP(iOwnerEntity))
-					{
-						if (GetClientTeam(other) == GetClientTeam(iOwnerEntity))
-						{
-							TF2_IgnitePlayer(other, iOwnerEntity);
-							SDKHooks_TakeDamage(other, iOwnerEntity, iOwnerEntity, 7.0, IsClientCritBoosted(iOwnerEntity) ? (DMG_BURN | DMG_PREVENT_PHYSICS_FORCE | DMG_ACID) : DMG_BURN | DMG_PREVENT_PHYSICS_FORCE); 
-						}
-					}
-				}
-			}
-		}
-	}
-}
-
-/**
- *	Forcibly resets global vars of the player relating to PvP. Ignores checking.
- */
-PvP_ForceResetPlayerPvPData(client)
-{
-	g_bPlayerInPvP[client] = false;
-	g_hPlayerPvPTimer[client] = INVALID_HANDLE;
-	g_iPlayerPvPTimerCount[client] = 0;
-	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
-}
-
-static PvP_RemovePlayerProjectiles(client)
-{
-	for (new i = 0; i < sizeof(g_sPvPProjectileClasses); i++)
-	{
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, g_sPvPProjectileClasses[i])) != -1)
-		{
-			new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
-			new bool:bMine = false;
-		
-			new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
-			if (iOwnerEntity == client)
-			{
-				bMine = true;
-			}
-			else if (iThrowerOffset != -1)
-			{
-				iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
-				if (iOwnerEntity == client)
-				{
-					bMine = true;
-				}
-			}
-			
-			if (bMine) AcceptEntityInput(ent, "Kill");
-		}
-	}
-}
-
-public Action:Timer_TeleportPlayerToPvP(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerPvPRespawnTimer[client]) return;
-	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
-	
-	new Handle:hSpawnPointList = CreateArray();
-	
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-	{
-		decl String:sName[32];
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		if (!StrContains(sName, "sf2_pvp_spawnpoint", false))
-		{
-			PushArrayCell(hSpawnPointList, ent);
-		}
-	}
-	
-	decl Float:flMins[3], Float:flMaxs[3];
-	GetEntPropVector(client, Prop_Send, "m_vecMins", flMins);
-	GetEntPropVector(client, Prop_Send, "m_vecMaxs", flMaxs);
-	
-	new Handle:hClearSpawnPointList = CloneArray(hSpawnPointList);
-	for (new i = 0; i < GetArraySize(hSpawnPointList); i++)
-	{
-		new iEnt = GetArrayCell(hSpawnPointList, i);
-		
-		decl Float:flMyPos[3];
-		GetEntPropVector(iEnt, Prop_Data, "m_vecAbsOrigin", flMyPos);
-		
-		if (IsSpaceOccupiedPlayer(flMyPos, flMins, flMaxs, client))
-		{
-			new iIndex = FindValueInArray(hClearSpawnPointList, iEnt);
-			if (iIndex != -1)
-			{
-				RemoveFromArray(hClearSpawnPointList, iIndex);
-			}
-		}
-	}
-	
-	new iNum;
-	if ((iNum = GetArraySize(hClearSpawnPointList)) > 0)
-	{
-		ent = GetArrayCell(hClearSpawnPointList, GetRandomInt(0, iNum - 1));
-	}
-	else if ((iNum = GetArraySize(hSpawnPointList)) > 0)
-	{
-		ent = GetArrayCell(hSpawnPointList, GetRandomInt(0, iNum - 1));
-	}
-	
-	if (iNum > 0)
-	{
-		decl Float:flPos[3], Float:flAng[3];
-		GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
-		GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", flAng);
-		TeleportEntity(client, flPos, flAng, Float:{ 0.0, 0.0, 0.0 });
-		
-		EmitAmbientSound(SF2_PVP_SPAWN_SOUND, flPos, _, SNDLEVEL_NORMAL, _, 1.0);
-	}
-	
-	CloseHandle(hSpawnPointList);
-	CloseHandle(hClearSpawnPointList);
-}
-
-public Action:Timer_PlayerPvPLeaveCountdown(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerPvPTimer[client]) return Plugin_Stop;
-	
-	if (!IsClientInPvP(client)) return Plugin_Stop;
-	
-	if (g_iPlayerPvPTimerCount[client] <= 0)
-	{
-		PvP_SetPlayerPvPState(client, false);
-		return Plugin_Stop;
-	}
-	
-	g_iPlayerPvPTimerCount[client]--;
-	
-	//if (!g_bPlayerProxyAvailableInForce[client])
-	{
-		SetHudTextParams(-1.0, 0.75, 
-			1.0,
-			255, 255, 255, 255,
-			_,
-			_,
-			0.25, 1.25);
-		
-		ShowSyncHudText(client, g_hHudSync, "%T", "SF2 Exiting PvP Arena", client, g_iPlayerPvPTimerCount[client]);
-	}
-	
-	return Plugin_Continue;
-}
-
-bool:IsClientInPvP(client)
-{
-	return g_bPlayerInPvP[client];
-}
-
-
-// API
-
-public PvP_InitializeAPI()
-{
-	CreateNative("SF2_IsClientInPvP", Native_IsClientInPvP);
-}
-
-public Native_IsClientInPvP(Handle:plugin, numParams)
-{
-	return IsClientInPvP(GetNativeCell(1));
+#if defined _sf2_pvp_included
+ #endinput
+#endif
+#define _sf2_pvp_included
+
+
+#define SF2_PVP_SPAWN_SOUND "items/spawn_item.wav"
+
+new Handle:g_cvPvPArenaLeaveTime;
+new Handle:g_cvPvPArenaPlayerCollisions;
+
+static const String:g_sPvPProjectileClasses[][] = 
+{
+	"tf_projectile_rocket", 
+	"tf_projectile_sentryrocket", 
+	"tf_projectile_arrow", 
+	"tf_projectile_stun_ball",
+	"tf_projectile_ball_ornament",
+	"tf_projectile_cleaver",
+	"tf_projectile_energy_ball",
+	"tf_projectile_energy_ring",
+	"tf_projectile_flare",
+	"tf_projectile_healing_bolt",
+	"tf_projectile_jar",
+	"tf_projectile_jar_milk",
+	"tf_projectile_pipe",
+	"tf_projectile_pipe_remote",
+	"tf_projectile_syringe"
+};
+
+static bool:g_bPlayerInPvP[MAXPLAYERS + 1];
+static Handle:g_hPlayerPvPTimer[MAXPLAYERS + 1];
+static Handle:g_hPlayerPvPRespawnTimer[MAXPLAYERS + 1];
+static g_iPlayerPvPTimerCount[MAXPLAYERS + 1];
+static bool:g_bPlayerInPvPTrigger[MAXPLAYERS + 1];
+
+static Handle:g_hPvPFlameEntities;
+
+enum
+{
+	PvPFlameEntData_EntRef = 0,
+	PvPFlameEntData_LastHitEntRef,
+	PvPFlameEntData_MaxStats
+};
+
+public PvP_Initialize()
+{
+	g_cvPvPArenaLeaveTime = CreateConVar("sf2_player_pvparena_leavetime", "3");
+	g_cvPvPArenaPlayerCollisions = CreateConVar("sf2_player_pvparena_collisions", "1");
+	
+	g_hPvPFlameEntities = CreateArray(PvPFlameEntData_MaxStats);
+}
+
+public PvP_SetupMenus()
+{
+	g_hMenuSettingsPvP = CreateMenu(Menu_SettingsPvP);
+	SetMenuTitle(g_hMenuSettingsPvP, "%t%t\n \n", "SF2 Prefix", "SF2 Settings PvP Menu Title");
+	AddMenuItem(g_hMenuSettingsPvP, "0", "Toggle automatic spawning");
+	SetMenuExitBackButton(g_hMenuSettingsPvP, true);
+}
+
+public PvP_OnMapStart()
+{
+	ClearArray(g_hPvPFlameEntities);
+}
+
+public PvP_Precache()
+{
+	PrecacheSound2(SF2_PVP_SPAWN_SOUND);
+}
+
+public PvP_OnClientPutInServer(client)
+{
+	PvP_ForceResetPlayerPvPData(client);
+}
+
+public PvP_OnClientDisconnect(client)
+{
+	PvP_SetPlayerPvPState(client, false, false, false);
+}
+
+public PvP_OnGameFrame()
+{
+	// Process through PvP projectiles.
+	for (new i = 0; i < sizeof(g_sPvPProjectileClasses); i++)
+	{
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, g_sPvPProjectileClasses[i])) != -1)
+		{
+			new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
+			new bool:bChangeProjectileTeam = false;
+			
+			new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
+			if (IsValidClient(iOwnerEntity) && IsClientInPvP(iOwnerEntity))
+			{
+				bChangeProjectileTeam = true;
+			}
+			else if (iThrowerOffset != -1)
+			{
+				iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
+				if (IsValidClient(iOwnerEntity) && IsClientInPvP(iOwnerEntity))
+				{
+					bChangeProjectileTeam = true;
+				}
+			}
+			
+			if (bChangeProjectileTeam)
+			{
+				SetEntProp(ent, Prop_Data, "m_iInitialTeamNum", 0);
+				SetEntProp(ent, Prop_Send, "m_iTeamNum", 0);
+			}
+		}
+	}
+
+	// Process through PvP flame entities.
+	{
+		static Float:flMins[3] = { -6.0, ... };
+		static Float:flMaxs[3] = { 6.0, ... };
+		
+		decl Float:flOrigin[3];
+		
+		new Handle:hTrace = INVALID_HANDLE;
+		new ent = -1;
+		new iOwnerEntity = INVALID_ENT_REFERENCE; 
+		new iHitEntity = INVALID_ENT_REFERENCE;
+		
+		while ((ent = FindEntityByClassname(ent, "tf_flame")) != -1)
+		{
+			iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
+			
+			if (IsValidEdict(iOwnerEntity))
+			{
+				// tf_flame's initial owner SHOULD be the flamethrower that it originates from.
+				// If not, then something's completely bogus.
+				
+				iOwnerEntity = GetEntPropEnt(iOwnerEntity, Prop_Data, "m_hOwnerEntity");
+			}
+			
+			if (IsValidClient(iOwnerEntity) && (IsRoundInWarmup() || IsClientInPvP(iOwnerEntity)))
+			{
+				GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flOrigin);
+				
+				hTrace = TR_TraceHullFilterEx(flOrigin, flOrigin, flMins, flMaxs, MASK_PLAYERSOLID, TraceRayDontHitEntity, iOwnerEntity);
+				iHitEntity = TR_GetEntityIndex(hTrace);
+				CloseHandle(hTrace);
+				
+				if (IsValidEntity(iHitEntity))
+				{
+					new entref = EntIndexToEntRef(ent);
+					
+					new iIndex = FindValueInArray(g_hPvPFlameEntities, entref);
+					if (iIndex != -1)
+					{
+						new iLastHitEnt = EntRefToEntIndex(GetArrayCell(g_hPvPFlameEntities, iIndex, PvPFlameEntData_LastHitEntRef));
+					
+						if (iHitEntity != iLastHitEnt)
+						{
+							SetArrayCell(g_hPvPFlameEntities, iIndex, EntIndexToEntRef(iHitEntity), PvPFlameEntData_LastHitEntRef);
+							PvP_OnFlameEntityStartTouchPost(ent, iHitEntity);
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+public PvP_OnEntityCreated(ent, const String:sClassname[])
+{
+	if (StrEqual(sClassname, "tf_flame", false))
+	{
+		new iIndex = PushArrayCell(g_hPvPFlameEntities, EntIndexToEntRef(ent));
+		if (iIndex != -1)
+		{
+			SetArrayCell(g_hPvPFlameEntities, iIndex, INVALID_ENT_REFERENCE, PvPFlameEntData_LastHitEntRef);
+		}
+	}
+	else
+	{
+		for (new i = 0; i < sizeof(g_sPvPProjectileClasses); i++)
+		{
+			if (StrEqual(sClassname, g_sPvPProjectileClasses[i], false))
+			{
+				SDKHook(ent, SDKHook_Spawn, Hook_PvPProjectileSpawn);
+				SDKHook(ent, SDKHook_SpawnPost, Hook_PvPProjectileSpawnPost);
+				break;
+			}
+		}
+	}
+}
+
+public PvP_OnEntityDestroyed(ent, const String:sClassname[])
+{
+	if (StrEqual(sClassname, "tf_flame", false))
+	{
+		new entref = EntIndexToEntRef(ent);
+		new iIndex = FindValueInArray(g_hPvPFlameEntities, entref);
+		if (iIndex != -1)
+		{
+			RemoveFromArray(g_hPvPFlameEntities, iIndex);
+		}
+	}
+}
+
+public Action:Hook_PvPProjectileSpawn(ent)
+{
+	decl String:sClass[64];
+	GetEntityClassname(ent, sClass, sizeof(sClass));
+	
+	new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
+	new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
+	
+	if (iOwnerEntity == -1 && iThrowerOffset != -1)
+	{
+		iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
+	}
+	
+	if (IsValidClient(iOwnerEntity))
+	{
+		if (IsClientInPvP(iOwnerEntity))
+		{
+			SetEntProp(ent, Prop_Data, "m_iInitialTeamNum", 0);
+			SetEntProp(ent, Prop_Send, "m_iTeamNum", 0);
+		}
+	}
+
+	return Plugin_Continue;
+}
+
+public Hook_PvPProjectileSpawnPost(ent)
+{
+	decl String:sClass[64];
+	GetEntityClassname(ent, sClass, sizeof(sClass));
+	
+	new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
+	new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
+	
+	if (iOwnerEntity == -1 && iThrowerOffset != -1)
+	{
+		iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
+	}
+	
+	if (IsValidClient(iOwnerEntity))
+	{
+		if (IsClientInPvP(iOwnerEntity))
+		{
+			SetEntProp(ent, Prop_Data, "m_iInitialTeamNum", 0);
+			SetEntProp(ent, Prop_Send, "m_iTeamNum", 0);
+		}
+	}
+}
+
+public PvP_OnPlayerSpawn(client)
+{
+	PvP_SetPlayerPvPState(client, false, false, false);
+
+	if (IsPlayerAlive(client) && IsClientParticipating(client))
+	{
+		if (!IsClientInGhostMode(client) && !g_bPlayerProxy[client])
+		{
+			if (g_bPlayerEliminated[client] || g_bPlayerEscaped[client])
+			{
+				new bool:bAutoSpawn = g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn];
+				
+				if (bAutoSpawn)
+				{
+					g_hPlayerPvPRespawnTimer[client] = CreateTimer(0.12, Timer_TeleportPlayerToPvP, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+			}
+			else
+			{
+				g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
+			}
+		}
+	}
+}
+
+public PvP_OnPlayerDeath(client, bool:bFake)
+{
+	if (!bFake)
+	{
+		if (!IsClientInGhostMode(client) && !g_bPlayerProxy[client])
+		{
+			new bool:bAutoSpawn = g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn];
+			
+			if (bAutoSpawn)
+			{
+				if (g_bPlayerEliminated[client] || g_bPlayerEscaped[client])
+				{
+					if (!IsRoundEnding())
+					{
+						g_hPlayerPvPRespawnTimer[client] = CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+					}
+				}
+			}
+		}
+	}
+}
+
+public PvP_OnClientGhostModeEnable(client)
+{
+	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
+}
+
+public PvP_OnClientPutInPlay(client)
+{
+	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
+}
+
+public bool:Hook_ClientPvPShouldCollide(ent, collisiongroup, contentsmask, bool:originalResult)
+{
+	if (!g_bEnabled) return originalResult;
+	return true;
+}
+
+public PvP_OnTriggerStartTouch(trigger, other)
+{
+	decl String:sName[64];
+	GetEntPropString(trigger, Prop_Data, "m_iName", sName, sizeof(sName));
+	
+	if (StrContains(sName, "sf2_pvp_trigger", false) == 0)
+	{
+		if (IsValidClient(other) && IsPlayerAlive(other))
+		{
+			g_bPlayerInPvPTrigger[other] = true;
+			
+			if (IsClientInPvP(other))
+			{
+				// Player left and came back again, but is still in PvP mode.
+				g_iPlayerPvPTimerCount[other] = 0;
+				g_hPlayerPvPTimer[other] = INVALID_HANDLE;
+			}
+			else
+			{
+				PvP_SetPlayerPvPState(other, true);
+			}
+		}
+	}
+}
+
+public PvP_OnTriggerEndTouch(trigger, other)
+{
+	decl String:sName[64];
+	GetEntPropString(trigger, Prop_Data, "m_iName", sName, sizeof(sName));
+	
+	if (StrContains(sName, "sf2_pvp_trigger", false) == 0)
+	{
+		if (IsValidClient(other))
+		{
+			g_bPlayerInPvPTrigger[other] = false;
+			
+			if (IsClientInPvP(other))
+			{
+				g_iPlayerPvPTimerCount[other] = GetConVarInt(g_cvPvPArenaLeaveTime);
+				g_hPlayerPvPTimer[other] = CreateTimer(1.0, Timer_PlayerPvPLeaveCountdown, GetClientUserId(other), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
+			}
+		}
+	}
+}
+
+/**
+ *	Enables/Disables PvP mode on the player.
+ */
+PvP_SetPlayerPvPState(client, bool:bStatus, bool:bRemoveProjectiles=true, bool:bRegenerate=true)
+{
+	if (!IsValidClient(client)) return;
+	
+	new bool:bOldInPvP = g_bPlayerInPvP[client];
+	if (bStatus == bOldInPvP) return; // no change
+	
+	g_bPlayerInPvP[client] = bStatus;
+	g_hPlayerPvPTimer[client] = INVALID_HANDLE;
+	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
+	g_iPlayerPvPTimerCount[client] = 0;
+	
+	if (bRemoveProjectiles)
+	{
+		// Remove previous projectiles.
+		PvP_RemovePlayerProjectiles(client);
+	}
+	
+	if (bRegenerate)
+	{
+		// Regenerate player but keep health the same.
+		new iHealth = GetEntProp(client, Prop_Send, "m_iHealth");
+		TF2_RegeneratePlayer(client);
+		SetEntProp(client, Prop_Data, "m_iHealth", iHealth);
+		SetEntProp(client, Prop_Send, "m_iHealth", iHealth);
+	}
+	
+	if (bStatus && GetConVarBool(g_cvPvPArenaPlayerCollisions))
+	{
+		SDKHook(client, SDKHook_ShouldCollide, Hook_ClientPvPShouldCollide);
+	}
+	else
+	{
+		SDKUnhook(client, SDKHook_ShouldCollide, Hook_ClientPvPShouldCollide);
+	}
+}
+
+static PvP_OnFlameEntityStartTouchPost(flame, other)
+{
+	if (IsValidClient(other))
+	{
+		if ((IsRoundInWarmup() || IsClientInPvP(other)) && !IsRoundEnding())
+		{
+			new iFlamethrower = GetEntPropEnt(flame, Prop_Data, "m_hOwnerEntity");
+			if (IsValidEdict(iFlamethrower))
+			{
+				new iOwnerEntity = GetEntPropEnt(iFlamethrower, Prop_Data, "m_hOwnerEntity");
+				if (iOwnerEntity != other && IsValidClient(iOwnerEntity))
+				{
+					if (IsRoundInWarmup() || IsClientInPvP(iOwnerEntity))
+					{
+						if (GetClientTeam(other) == GetClientTeam(iOwnerEntity))
+						{
+							TF2_IgnitePlayer(other, iOwnerEntity);
+							SDKHooks_TakeDamage(other, iOwnerEntity, iOwnerEntity, 7.0, IsClientCritBoosted(iOwnerEntity) ? (DMG_BURN | DMG_PREVENT_PHYSICS_FORCE | DMG_ACID) : DMG_BURN | DMG_PREVENT_PHYSICS_FORCE); 
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+/**
+ *	Forcibly resets global vars of the player relating to PvP. Ignores checking.
+ */
+PvP_ForceResetPlayerPvPData(client)
+{
+	g_bPlayerInPvP[client] = false;
+	g_hPlayerPvPTimer[client] = INVALID_HANDLE;
+	g_iPlayerPvPTimerCount[client] = 0;
+	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
+}
+
+static PvP_RemovePlayerProjectiles(client)
+{
+	for (new i = 0; i < sizeof(g_sPvPProjectileClasses); i++)
+	{
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, g_sPvPProjectileClasses[i])) != -1)
+		{
+			new iThrowerOffset = FindDataMapOffs(ent, "m_hThrower");
+			new bool:bMine = false;
+		
+			new iOwnerEntity = GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity");
+			if (iOwnerEntity == client)
+			{
+				bMine = true;
+			}
+			else if (iThrowerOffset != -1)
+			{
+				iOwnerEntity = GetEntDataEnt2(ent, iThrowerOffset);
+				if (iOwnerEntity == client)
+				{
+					bMine = true;
+				}
+			}
+			
+			if (bMine) AcceptEntityInput(ent, "Kill");
+		}
+	}
+}
+
+public Action:Timer_TeleportPlayerToPvP(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerPvPRespawnTimer[client]) return;
+	g_hPlayerPvPRespawnTimer[client] = INVALID_HANDLE;
+	
+	new Handle:hSpawnPointList = CreateArray();
+	
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+	{
+		decl String:sName[32];
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		if (!StrContains(sName, "sf2_pvp_spawnpoint", false))
+		{
+			PushArrayCell(hSpawnPointList, ent);
+		}
+	}
+	
+	decl Float:flMins[3], Float:flMaxs[3];
+	GetEntPropVector(client, Prop_Send, "m_vecMins", flMins);
+	GetEntPropVector(client, Prop_Send, "m_vecMaxs", flMaxs);
+	
+	new Handle:hClearSpawnPointList = CloneArray(hSpawnPointList);
+	for (new i = 0; i < GetArraySize(hSpawnPointList); i++)
+	{
+		new iEnt = GetArrayCell(hSpawnPointList, i);
+		
+		decl Float:flMyPos[3];
+		GetEntPropVector(iEnt, Prop_Data, "m_vecAbsOrigin", flMyPos);
+		
+		if (IsSpaceOccupiedPlayer(flMyPos, flMins, flMaxs, client))
+		{
+			new iIndex = FindValueInArray(hClearSpawnPointList, iEnt);
+			if (iIndex != -1)
+			{
+				RemoveFromArray(hClearSpawnPointList, iIndex);
+			}
+		}
+	}
+	
+	new iNum;
+	if ((iNum = GetArraySize(hClearSpawnPointList)) > 0)
+	{
+		ent = GetArrayCell(hClearSpawnPointList, GetRandomInt(0, iNum - 1));
+	}
+	else if ((iNum = GetArraySize(hSpawnPointList)) > 0)
+	{
+		ent = GetArrayCell(hSpawnPointList, GetRandomInt(0, iNum - 1));
+	}
+	
+	if (iNum > 0)
+	{
+		decl Float:flPos[3], Float:flAng[3];
+		GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
+		GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", flAng);
+		TeleportEntity(client, flPos, flAng, Float:{ 0.0, 0.0, 0.0 });
+		
+		EmitAmbientSound(SF2_PVP_SPAWN_SOUND, flPos, _, SNDLEVEL_NORMAL, _, 1.0);
+	}
+	
+	CloseHandle(hSpawnPointList);
+	CloseHandle(hClearSpawnPointList);
+}
+
+public Action:Timer_PlayerPvPLeaveCountdown(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerPvPTimer[client]) return Plugin_Stop;
+	
+	if (!IsClientInPvP(client)) return Plugin_Stop;
+	
+	if (g_iPlayerPvPTimerCount[client] <= 0)
+	{
+		PvP_SetPlayerPvPState(client, false);
+		return Plugin_Stop;
+	}
+	
+	g_iPlayerPvPTimerCount[client]--;
+	
+	//if (!g_bPlayerProxyAvailableInForce[client])
+	{
+		SetHudTextParams(-1.0, 0.75, 
+			1.0,
+			255, 255, 255, 255,
+			_,
+			_,
+			0.25, 1.25);
+		
+		ShowSyncHudText(client, g_hHudSync, "%T", "SF2 Exiting PvP Arena", client, g_iPlayerPvPTimerCount[client]);
+	}
+	
+	return Plugin_Continue;
+}
+
+bool:IsClientInPvP(client)
+{
+	return g_bPlayerInPvP[client];
+}
+
+
+// API
+
+public PvP_InitializeAPI()
+{
+	CreateNative("SF2_IsClientInPvP", Native_IsClientInPvP);
+}
+
+public Native_IsClientInPvP(Handle:plugin, numParams)
+{
+	return IsClientInPvP(GetNativeCell(1));
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/pvp/menus.sp b/addons/sourcemod/scripting/rytp_horror/pvp/menus.sp
index 7fe9882..d00ac8f 100644
--- a/addons/sourcemod/scripting/rytp_horror/pvp/menus.sp
+++ b/addons/sourcemod/scripting/rytp_horror/pvp/menus.sp
@@ -1,62 +1,62 @@
-#if defined _sf2_pvp_menus
- #endinput
-#endif
-
-#define _sf2_pvp_menus
-
-new Handle:g_hMenuSettingsPvP;
-
-public Menu_SettingsPvP(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 0:
-			{
-				decl String:sBuffer[512];
-				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings PvP Spawn Menu Title", param1);
-				
-				new Handle:hPanel = CreatePanel();
-				SetPanelTitle(hPanel, sBuffer);
-				
-				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
-				DrawPanelItem(hPanel, sBuffer);
-				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
-				DrawPanelItem(hPanel, sBuffer);
-				
-				SendPanelToClient(hPanel, param1, Panel_SettingsPvPSpawn, 30);
-				CloseHandle(hPanel);
-			}
-		}
-	}
-	else if (action == MenuAction_Cancel)
-	{
-		if (param2 == MenuCancel_ExitBack)
-		{
-			DisplayMenu(g_hMenuSettings, param1, 30);
-		}
-	}
-}
-
-public Panel_SettingsPvPSpawn(Handle:menu, MenuAction:action, param1, param2)
-{
-	if (action == MenuAction_Select)
-	{
-		switch (param2)
-		{
-			case 1:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_PvPAutoSpawn] = true;
-				CPrintToChat(param1, "%T", "SF2 PvP Spawn Accept", param1);
-			}
-			case 2:
-			{
-				g_iPlayerPreferences[param1][PlayerPreference_PvPAutoSpawn] = false;
-				CPrintToChat(param1, "%T", "SF2 PvP Spawn Decline", param1);
-			}
-		}
-		
-		DisplayMenu(g_hMenuSettings, param1, 30);
-	}
+#if defined _sf2_pvp_menus
+ #endinput
+#endif
+
+#define _sf2_pvp_menus
+
+new Handle:g_hMenuSettingsPvP;
+
+public Menu_SettingsPvP(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 0:
+			{
+				decl String:sBuffer[512];
+				Format(sBuffer, sizeof(sBuffer), "%T\n \n", "SF2 Settings PvP Spawn Menu Title", param1);
+				
+				new Handle:hPanel = CreatePanel();
+				SetPanelTitle(hPanel, sBuffer);
+				
+				Format(sBuffer, sizeof(sBuffer), "%T", "Yes", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				Format(sBuffer, sizeof(sBuffer), "%T", "No", param1);
+				DrawPanelItem(hPanel, sBuffer);
+				
+				SendPanelToClient(hPanel, param1, Panel_SettingsPvPSpawn, 30);
+				CloseHandle(hPanel);
+			}
+		}
+	}
+	else if (action == MenuAction_Cancel)
+	{
+		if (param2 == MenuCancel_ExitBack)
+		{
+			DisplayMenu(g_hMenuSettings, param1, 30);
+		}
+	}
+}
+
+public Panel_SettingsPvPSpawn(Handle:menu, MenuAction:action, param1, param2)
+{
+	if (action == MenuAction_Select)
+	{
+		switch (param2)
+		{
+			case 1:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_PvPAutoSpawn] = true;
+				CPrintToChat(param1, "%T", "SF2 PvP Spawn Accept", param1);
+			}
+			case 2:
+			{
+				g_iPlayerPreferences[param1][PlayerPreference_PvPAutoSpawn] = false;
+				CPrintToChat(param1, "%T", "SF2 PvP Spawn Decline", param1);
+			}
+		}
+		
+		DisplayMenu(g_hMenuSettings, param1, 30);
+	}
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/specialround.sp b/addons/sourcemod/scripting/rytp_horror/specialround.sp
index a6e2d5d..f930500 100644
--- a/addons/sourcemod/scripting/rytp_horror/specialround.sp
+++ b/addons/sourcemod/scripting/rytp_horror/specialround.sp
@@ -1,379 +1,378 @@
-#if defined _sf2_specialround_included
- #endinput
-#endif
-#define _sf2_specialround_included
-
-#define SR_CYCLELENGTH 10.0
-#define SR_STARTDELAY 1.25
-#define SR_MUSIC "rytp_horror/specialround_music.mp3"
-#define SR_SOUND_SELECT "rytp_horror/specialround_select.mp3"
-
-#define FILE_SPECIALROUNDS "configs/sf2/specialrounds.cfg"
-
-static Handle:g_hSpecialRoundCycleNames = INVALID_HANDLE;
-
-static Handle:g_hSpecialRoundTimer = INVALID_HANDLE;
-static g_iSpecialRoundCycleNum = 0;
-static Float:g_flSpecialRoundCycleEndTime = -1.0;
-
-ReloadSpecialRounds()
-{
-	if (g_hSpecialRoundCycleNames == INVALID_HANDLE)
-	{
-		g_hSpecialRoundCycleNames = CreateArray(128);
-	}
-	
-	ClearArray(g_hSpecialRoundCycleNames);
-
-	if (g_hSpecialRoundsConfig != INVALID_HANDLE)
-	{
-		CloseHandle(g_hSpecialRoundsConfig);
-		g_hSpecialRoundsConfig = INVALID_HANDLE;
-	}
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	BuildPath(Path_SM, buffer, sizeof(buffer), FILE_SPECIALROUNDS);
-	new Handle:kv = CreateKeyValues("root");
-	if (!FileToKeyValues(kv, buffer))
-	{
-		CloseHandle(kv);
-		LogError("Failed to load special rounds! File %s not found!", FILE_SPECIALROUNDS);
-	}
-	else
-	{
-		g_hSpecialRoundsConfig = kv;
-		LogMessage("Loaded special rounds file!");
-		
-		// Load names for the cycle.
-		decl String:sBuffer[128];
-		SpecialRoundGetDescriptionHud(SPECIALROUND_DOUBLETROUBLE, sBuffer, sizeof(sBuffer));
-		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
-		
-		SpecialRoundGetDescriptionHud(SPECIALROUND_DOUBLETROUBLE, sBuffer, sizeof(sBuffer));
-		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
-		/*
-		SpecialRoundGetDescriptionHud(SPECIALROUND_SINGLEPLAYER, sBuffer, sizeof(sBuffer));
-		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
-		
-		SpecialRoundGetDescriptionHud(SPECIALROUND_DOUBLEMAXPLAYERS, sBuffer, sizeof(sBuffer));
-		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
-		*/
-		SpecialRoundGetDescriptionHud(SPECIALROUND_LIGHTSOUT, sBuffer, sizeof(sBuffer));
-		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
-		
-		KvRewind(kv);
-		if (KvJumpToKey(kv, "jokes"))
-		{
-			if (KvGotoFirstSubKey(kv, false))
-			{
-				do
-				{
-					KvGetString(kv, NULL_STRING, sBuffer, sizeof(sBuffer));
-					if (strlen(sBuffer) > 0)
-					{
-						PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
-					}
-				}
-				while (KvGotoNextKey(kv, false));
-			}
-		}
-		
-		SortADTArray(g_hSpecialRoundCycleNames, Sort_Random, Sort_String);
-	}
-}
-
-stock SpecialRoundGetDescriptionHud(iSpecialRound, String:buffer[], bufferlen)
-{
-	strcopy(buffer, bufferlen, "");
-
-	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return;
-	
-	KvRewind(g_hSpecialRoundsConfig);
-	decl String:sSpecialRound[32];
-	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
-	
-	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return;
-	
-	KvGetString(g_hSpecialRoundsConfig, "display_text_hud", buffer, bufferlen);
-}
-
-stock SpecialRoundGetDescriptionChat(iSpecialRound, String:buffer[], bufferlen)
-{
-	strcopy(buffer, bufferlen, "");
-
-	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return;
-	
-	KvRewind(g_hSpecialRoundsConfig);
-	decl String:sSpecialRound[32];
-	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
-	
-	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return;
-	
-	KvGetString(g_hSpecialRoundsConfig, "display_text_chat", buffer, bufferlen);
-}
-
-stock SpecialRoundGetIconHud(iSpecialRound, String:buffer[], bufferlen)
-{
-	strcopy(buffer, bufferlen, "");
-
-	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return;
-	
-	KvRewind(g_hSpecialRoundsConfig);
-	decl String:sSpecialRound[32];
-	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
-	
-	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return;
-	
-	KvGetString(g_hSpecialRoundsConfig, "display_icon_hud", buffer, bufferlen);
-}
-
-stock bool:SpecialRoundCanBeSelected(iSpecialRound)
-{
-	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return false;
-	
-	KvRewind(g_hSpecialRoundsConfig);
-	decl String:sSpecialRound[32];
-	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
-	
-	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return false;
-	
-	return bool:KvGetNum(g_hSpecialRoundsConfig, "enabled", 1);
-}
-
-public Action:Timer_SpecialRoundCycle(Handle:timer)
-{
-	if (timer != g_hSpecialRoundTimer) return Plugin_Stop;
-	
-	if (GetGameTime() >= g_flSpecialRoundCycleEndTime)
-	{
-		SpecialRoundCycleFinish();
-		return Plugin_Stop;
-	}
-	
-	decl String:sBuffer[128];
-	GetArrayString(g_hSpecialRoundCycleNames, g_iSpecialRoundCycleNum, sBuffer, sizeof(sBuffer));
-	
-	GameTextTFMessage(sBuffer);
-	
-	g_iSpecialRoundCycleNum++;
-	if (g_iSpecialRoundCycleNum >= GetArraySize(g_hSpecialRoundCycleNames))
-	{
-		g_iSpecialRoundCycleNum = 0;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_SpecialRoundStart(Handle:timer)
-{
-	if (timer != g_hSpecialRoundTimer) return;
-	if (!g_bSpecialRound) return;
-	
-	SpecialRoundStart();
-}
-
-/*
-public Action:Timer_SpecialRoundAttribute(Handle:timer)
-{
-	if (timer != g_hSpecialRoundTimer) return Plugin_Stop;
-	if (!g_bSpecialRound) return Plugin_Stop;
-	
-	new iCond = -1;
-	
-	switch (g_iSpecialRoundType)
-	{
-		case SPECIALROUND_DEFENSEBUFF: iCond = _:TFCond_DefenseBuffed;
-		case SPECIALROUND_MARKEDFORDEATH: iCond = _:TFCond_MarkedForDeath;
-	}
-	
-	if (iCond != -1)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || g_bPlayerGhostMode[i]) continue;
-			
-			TF2_AddCondition(i, TFCond:iCond, 0.8);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-*/
-
-SpecialRoundCycleStart()
-{
-	if (!g_bSpecialRound) return;
-	
-	EmitSoundToAll(SR_MUSIC, _, MUSIC_CHAN);
-	g_iSpecialRoundType = 0;
-	g_iSpecialRoundCycleNum = 0;
-	g_flSpecialRoundCycleEndTime = GetGameTime() + SR_CYCLELENGTH;
-	g_hSpecialRoundTimer = CreateTimer(0.12, Timer_SpecialRoundCycle, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-SpecialRoundCycleFinish()
-{
-	//EmitSoundToAll(SR_SOUND_SELECT, _, SNDCHAN_AUTO);
-	
-	new iOverride = GetConVarInt(g_cvSpecialRoundOverride);
-	if (iOverride >= 1 && iOverride < SPECIALROUND_MAXROUNDS)
-	{
-		g_iSpecialRoundType = iOverride;
-	}
-	else
-	{
-		new Handle:hEnabledRounds = CreateArray();
-		
-		if (GetArraySize(GetSelectableBossProfileList()) > 0)
-		{
-			PushArrayCell(hEnabledRounds, SPECIALROUND_DOUBLETROUBLE);
-		}
-		/*
-		if (GetActivePlayerCount() <= GetConVarInt(g_cvMaxPlayers) * 2)
-		{
-			PushArrayCell(hEnabledRounds, SPECIALROUND_DOUBLEMAXPLAYERS);
-		}
-		
-		if (GetActivePlayerCount() > 1)
-		{
-			PushArrayCell(hEnabledRounds, SPECIALROUND_SINGLEPLAYER);
-		}
-		*/
-		
-		PushArrayCell(hEnabledRounds, SPECIALROUND_INSANEDIFFICULTY);
-		PushArrayCell(hEnabledRounds, SPECIALROUND_LIGHTSOUT);
-	
-		g_iSpecialRoundType = GetArrayCell(hEnabledRounds, GetRandomInt(0, GetArraySize(hEnabledRounds) - 1));
-		
-		CloseHandle(hEnabledRounds);
-	}
-	
-	SetConVarInt(g_cvSpecialRoundOverride, -1);
-	
-	decl String:sDescHud[64];
-	SpecialRoundGetDescriptionHud(g_iSpecialRoundType, sDescHud, sizeof(sDescHud));
-	
-	decl String:sIconHud[64];
-	SpecialRoundGetIconHud(g_iSpecialRoundType, sIconHud, sizeof(sIconHud));
-	
-	decl String:sDescChat[64];
-	SpecialRoundGetDescriptionChat(g_iSpecialRoundType, sDescChat, sizeof(sDescChat));
-	
-	GameTextTFMessage(sDescHud, sIconHud);
-	CPrintToChatAll("%t", "SF2 Special Round Announce Chat", sDescChat); // For those who are using minimized HUD...
-	
-	g_hSpecialRoundTimer = CreateTimer(SR_STARTDELAY, Timer_SpecialRoundStart, _, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-SpecialRoundStart()
-{
-	if (!g_bSpecialRound) return;
-	if (g_iSpecialRoundType < 1 || g_iSpecialRoundType >= SPECIALROUND_MAXROUNDS) return;
-	
-	// What to do with the timer...
-	switch (g_iSpecialRoundType)
-	{
-		/*
-		case SPECIALROUND_DEFENSEBUFF, SPECIALROUND_MARKEDFORDEATH:
-		{
-			g_hSpecialRoundTimer = CreateTimer(0.5, Timer_SpecialRoundAttribute, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-		}
-		*/
-		default:
-		{
-			g_hSpecialRoundTimer = INVALID_HANDLE;
-		}
-	}
-	
-	switch (g_iSpecialRoundType)
-	{
-		case SPECIALROUND_DOUBLETROUBLE:
-		{
-			decl String:sBuffer[SF2_MAX_PROFILE_NAME_LENGTH];
-			new Handle:hSelectableBosses = GetSelectableBossProfileList();
-			
-			if (GetArraySize(hSelectableBosses) > 0)
-			{
-				GetArrayString(hSelectableBosses, GetRandomInt(0, GetArraySize(hSelectableBosses) - 1), sBuffer, sizeof(sBuffer));
-				AddProfile(sBuffer);
-			}
-		}
-		case SPECIALROUND_INSANEDIFFICULTY:
-		{
-			SetConVarString(g_cvDifficulty, "3"); // Override difficulty to Insane.
-		}
-		/*
-		case SPECIALROUND_SINGLEPLAYER:
-		{
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i)) continue;
-				
-				ClientUpdateListeningFlags(i);
-			}
-		}
-		case SPECIALROUND_DOUBLEMAXPLAYERS:
-		{
-			ForceInNextPlayersInQueue(GetConVarInt(g_cvMaxPlayers));
-			SetConVarString(g_cvDifficulty, "3"); // Override difficulty to Insane.
-		}
-		*/
-		case SPECIALROUND_LIGHTSOUT:
-		{
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i)) continue;
-				
-				if (!g_bPlayerEliminated[i])
-				{
-					ClientResetFlashlight(i);
-					ClientActivateUltravision(i);
-				}
-			}
-		}
-	}
-}
-
-public Action:Timer_DisplaySpecialRound(Handle:timer)
-{
-	decl String:sDescHud[64];
-	SpecialRoundGetDescriptionHud(g_iSpecialRoundType, sDescHud, sizeof(sDescHud));
-	
-	decl String:sIconHud[64];
-	SpecialRoundGetIconHud(g_iSpecialRoundType, sIconHud, sizeof(sIconHud));
-	
-	decl String:sDescChat[64];
-	SpecialRoundGetDescriptionChat(g_iSpecialRoundType, sDescChat, sizeof(sDescChat));
-	
-	GameTextTFMessage(sDescHud, sIconHud);
-	CPrintToChatAll("%t", "SF2 Special Round Announce Chat", sDescChat); // For those who are using minimized HUD...
-}
-
-SpecialRoundReset()
-{
-	g_iSpecialRoundType = 0;
-	g_hSpecialRoundTimer = INVALID_HANDLE;
-	g_iSpecialRoundCycleNum = 0;
-	g_flSpecialRoundCycleEndTime = -1.0;
-}
-
-bool:IsSpecialRoundRunning()
-{
-	return g_bSpecialRound;
-}
-
-public SpecialRoundInitializeAPI()
-{
-	CreateNative("SF2_IsSpecialRoundRunning", Native_IsSpecialRoundRunning);
-	CreateNative("SF2_GetSpecialRoundType", Native_GetSpecialRoundType);
-}
-
-public Native_IsSpecialRoundRunning(Handle:plugin, numParams)
-{
-	return g_bSpecialRound;
-}
-
-public Native_GetSpecialRoundType(Handle:plugin, numParams)
-{
-	return g_iSpecialRoundType;
+#if defined _sf2_specialround_included
+ #endinput
+#endif
+#define _sf2_specialround_included
+
+#define SR_CYCLELENGTH 10.0
+#define SR_STARTDELAY 1.25
+#define SR_MUSIC "rytp_horror/specialround_music.mp3"
+#define SR_SOUND_SELECT "rytp_horror/specialround_select.mp3"
+
+#define FILE_SPECIALROUNDS "configs/sf2/specialrounds.cfg"
+
+static Handle:g_hSpecialRoundCycleNames = INVALID_HANDLE;
+
+static Handle:g_hSpecialRoundTimer = INVALID_HANDLE;
+static g_iSpecialRoundCycleNum = 0;
+static Float:g_flSpecialRoundCycleEndTime = -1.0;
+
+ReloadSpecialRounds()
+{
+	if (g_hSpecialRoundCycleNames == INVALID_HANDLE)
+	{
+		g_hSpecialRoundCycleNames = CreateArray(128);
+	}
+	
+	ClearArray(g_hSpecialRoundCycleNames);
+
+	if (g_hSpecialRoundsConfig != INVALID_HANDLE)
+	{
+		CloseHandle(g_hSpecialRoundsConfig);
+		g_hSpecialRoundsConfig = INVALID_HANDLE;
+	}
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	BuildPath(Path_SM, buffer, sizeof(buffer), FILE_SPECIALROUNDS);
+	new Handle:kv = CreateKeyValues("root");
+	if (!FileToKeyValues(kv, buffer))
+	{
+		CloseHandle(kv);
+		LogError("Failed to load special rounds! File %s not found!", FILE_SPECIALROUNDS);
+	}
+	else
+	{
+		g_hSpecialRoundsConfig = kv;
+		LogMessage("Loaded special rounds file!");
+		
+		// Load names for the cycle.
+		decl String:sBuffer[128];
+		SpecialRoundGetDescriptionHud(SPECIALROUND_DOUBLETROUBLE, sBuffer, sizeof(sBuffer));
+		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
+		
+		SpecialRoundGetDescriptionHud(SPECIALROUND_DOUBLETROUBLE, sBuffer, sizeof(sBuffer));
+		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
+		
+		SpecialRoundGetDescriptionHud(SPECIALROUND_SINGLEPLAYER, sBuffer, sizeof(sBuffer));
+		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
+		
+		SpecialRoundGetDescriptionHud(SPECIALROUND_DOUBLEMAXPLAYERS, sBuffer, sizeof(sBuffer));
+		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
+		
+		SpecialRoundGetDescriptionHud(SPECIALROUND_LIGHTSOUT, sBuffer, sizeof(sBuffer));
+		PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
+		
+		KvRewind(kv);
+		if (KvJumpToKey(kv, "jokes"))
+		{
+			if (KvGotoFirstSubKey(kv, false))
+			{
+				do
+				{
+					KvGetString(kv, NULL_STRING, sBuffer, sizeof(sBuffer));
+					if (strlen(sBuffer) > 0)
+					{
+						PushArrayString(g_hSpecialRoundCycleNames, sBuffer);
+					}
+				}
+				while (KvGotoNextKey(kv, false));
+			}
+		}
+		
+		SortADTArray(g_hSpecialRoundCycleNames, Sort_Random, Sort_String);
+	}
+}
+
+stock SpecialRoundGetDescriptionHud(iSpecialRound, String:buffer[], bufferlen)
+{
+	strcopy(buffer, bufferlen, "");
+
+	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return;
+	
+	KvRewind(g_hSpecialRoundsConfig);
+	decl String:sSpecialRound[32];
+	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
+	
+	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return;
+	
+	KvGetString(g_hSpecialRoundsConfig, "display_text_hud", buffer, bufferlen);
+}
+
+stock SpecialRoundGetDescriptionChat(iSpecialRound, String:buffer[], bufferlen)
+{
+	strcopy(buffer, bufferlen, "");
+
+	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return;
+	
+	KvRewind(g_hSpecialRoundsConfig);
+	decl String:sSpecialRound[32];
+	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
+	
+	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return;
+	
+	KvGetString(g_hSpecialRoundsConfig, "display_text_chat", buffer, bufferlen);
+}
+
+stock SpecialRoundGetIconHud(iSpecialRound, String:buffer[], bufferlen)
+{
+	strcopy(buffer, bufferlen, "");
+
+	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return;
+	
+	KvRewind(g_hSpecialRoundsConfig);
+	decl String:sSpecialRound[32];
+	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
+	
+	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return;
+	
+	KvGetString(g_hSpecialRoundsConfig, "display_icon_hud", buffer, bufferlen);
+}
+
+stock bool:SpecialRoundCanBeSelected(iSpecialRound)
+{
+	if (g_hSpecialRoundsConfig == INVALID_HANDLE) return false;
+	
+	KvRewind(g_hSpecialRoundsConfig);
+	decl String:sSpecialRound[32];
+	IntToString(iSpecialRound, sSpecialRound, sizeof(sSpecialRound));
+	
+	if (!KvJumpToKey(g_hSpecialRoundsConfig, sSpecialRound)) return false;
+	
+	return bool:KvGetNum(g_hSpecialRoundsConfig, "enabled", 1);
+}
+
+public Action:Timer_SpecialRoundCycle(Handle:timer)
+{
+	if (timer != g_hSpecialRoundTimer) return Plugin_Stop;
+	
+	if (GetGameTime() >= g_flSpecialRoundCycleEndTime)
+	{
+		SpecialRoundCycleFinish();
+		return Plugin_Stop;
+	}
+	
+	decl String:sBuffer[128];
+	GetArrayString(g_hSpecialRoundCycleNames, g_iSpecialRoundCycleNum, sBuffer, sizeof(sBuffer));
+	
+	GameTextTFMessage(sBuffer);
+	
+	g_iSpecialRoundCycleNum++;
+	if (g_iSpecialRoundCycleNum >= GetArraySize(g_hSpecialRoundCycleNames))
+	{
+		g_iSpecialRoundCycleNum = 0;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_SpecialRoundStart(Handle:timer)
+{
+	if (timer != g_hSpecialRoundTimer) return;
+	if (!g_bSpecialRound) return;
+	
+	SpecialRoundStart();
+}
+
+/*
+public Action:Timer_SpecialRoundAttribute(Handle:timer)
+{
+	if (timer != g_hSpecialRoundTimer) return Plugin_Stop;
+	if (!g_bSpecialRound) return Plugin_Stop;
+	
+	new iCond = -1;
+	
+	switch (g_iSpecialRoundType)
+	{
+		case SPECIALROUND_DEFENSEBUFF: iCond = _:TFCond_DefenseBuffed;
+		case SPECIALROUND_MARKEDFORDEATH: iCond = _:TFCond_MarkedForDeath;
+	}
+	
+	if (iCond != -1)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || g_bPlayerGhostMode[i]) continue;
+			
+			TF2_AddCondition(i, TFCond:iCond, 0.8);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+*/
+
+SpecialRoundCycleStart()
+{
+	if (!g_bSpecialRound) return;
+	
+	EmitSoundToAll(SR_MUSIC, _, MUSIC_CHAN);
+	g_iSpecialRoundType = 0;
+	g_iSpecialRoundCycleNum = 0;
+	g_flSpecialRoundCycleEndTime = GetGameTime() + SR_CYCLELENGTH;
+	g_hSpecialRoundTimer = CreateTimer(0.12, Timer_SpecialRoundCycle, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+SpecialRoundCycleFinish()
+{
+	EmitSoundToAll(SR_SOUND_SELECT, _, SNDCHAN_AUTO);
+	
+	new iOverride = GetConVarInt(g_cvSpecialRoundOverride);
+	if (iOverride >= 1 && iOverride < SPECIALROUND_MAXROUNDS)
+	{
+		g_iSpecialRoundType = iOverride;
+	}
+	else
+	{
+		new Handle:hEnabledRounds = CreateArray();
+		
+		if (GetArraySize(GetSelectableBossProfileList()) > 0)
+		{
+			PushArrayCell(hEnabledRounds, SPECIALROUND_DOUBLETROUBLE);
+		}
+		
+		if (GetActivePlayerCount() <= GetConVarInt(g_cvMaxPlayers) * 2)
+		{
+			PushArrayCell(hEnabledRounds, SPECIALROUND_DOUBLEMAXPLAYERS);
+		}
+		
+		/*
+		if (GetActivePlayerCount() > 1)
+		{
+			PushArrayCell(hEnabledRounds, SPECIALROUND_SINGLEPLAYER);
+		}
+		*/
+		
+		PushArrayCell(hEnabledRounds, SPECIALROUND_INSANEDIFFICULTY);
+		PushArrayCell(hEnabledRounds, SPECIALROUND_LIGHTSOUT);
+	
+		g_iSpecialRoundType = GetArrayCell(hEnabledRounds, GetRandomInt(0, GetArraySize(hEnabledRounds) - 1));
+		
+		CloseHandle(hEnabledRounds);
+	}
+	
+	SetConVarInt(g_cvSpecialRoundOverride, -1);
+	
+	decl String:sDescHud[64];
+	SpecialRoundGetDescriptionHud(g_iSpecialRoundType, sDescHud, sizeof(sDescHud));
+	
+	decl String:sIconHud[64];
+	SpecialRoundGetIconHud(g_iSpecialRoundType, sIconHud, sizeof(sIconHud));
+	
+	decl String:sDescChat[64];
+	SpecialRoundGetDescriptionChat(g_iSpecialRoundType, sDescChat, sizeof(sDescChat));
+	
+	GameTextTFMessage(sDescHud, sIconHud);
+	CPrintToChatAll("%t", "SF2 Special Round Announce Chat", sDescChat); // For those who are using minimized HUD...
+	
+	g_hSpecialRoundTimer = CreateTimer(SR_STARTDELAY, Timer_SpecialRoundStart, _, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+SpecialRoundStart()
+{
+	if (!g_bSpecialRound) return;
+	if (g_iSpecialRoundType < 1 || g_iSpecialRoundType >= SPECIALROUND_MAXROUNDS) return;
+	
+	// What to do with the timer...
+	switch (g_iSpecialRoundType)
+	{
+		/*
+		case SPECIALROUND_DEFENSEBUFF, SPECIALROUND_MARKEDFORDEATH:
+		{
+			g_hSpecialRoundTimer = CreateTimer(0.5, Timer_SpecialRoundAttribute, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+		}
+		*/
+		default:
+		{
+			g_hSpecialRoundTimer = INVALID_HANDLE;
+		}
+	}
+	
+	switch (g_iSpecialRoundType)
+	{
+		case SPECIALROUND_DOUBLETROUBLE:
+		{
+			decl String:sBuffer[SF2_MAX_PROFILE_NAME_LENGTH];
+			new Handle:hSelectableBosses = GetSelectableBossProfileList();
+			
+			if (GetArraySize(hSelectableBosses) > 0)
+			{
+				GetArrayString(hSelectableBosses, GetRandomInt(0, GetArraySize(hSelectableBosses) - 1), sBuffer, sizeof(sBuffer));
+				AddProfile(sBuffer);
+			}
+		}
+		case SPECIALROUND_INSANEDIFFICULTY:
+		{
+			SetConVarString(g_cvDifficulty, "3"); // Override difficulty to Insane.
+		}
+		case SPECIALROUND_SINGLEPLAYER:
+		{
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i)) continue;
+				
+				ClientUpdateListeningFlags(i);
+			}
+		}
+		case SPECIALROUND_DOUBLEMAXPLAYERS:
+		{
+			ForceInNextPlayersInQueue(GetConVarInt(g_cvMaxPlayers));
+			SetConVarString(g_cvDifficulty, "3"); // Override difficulty to Insane.
+		}
+		case SPECIALROUND_LIGHTSOUT:
+		{
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i)) continue;
+				
+				if (!g_bPlayerEliminated[i])
+				{
+					ClientResetFlashlight(i);
+					ClientActivateUltravision(i);
+				}
+			}
+		}
+	}
+}
+
+public Action:Timer_DisplaySpecialRound(Handle:timer)
+{
+	decl String:sDescHud[64];
+	SpecialRoundGetDescriptionHud(g_iSpecialRoundType, sDescHud, sizeof(sDescHud));
+	
+	decl String:sIconHud[64];
+	SpecialRoundGetIconHud(g_iSpecialRoundType, sIconHud, sizeof(sIconHud));
+	
+	decl String:sDescChat[64];
+	SpecialRoundGetDescriptionChat(g_iSpecialRoundType, sDescChat, sizeof(sDescChat));
+	
+	GameTextTFMessage(sDescHud, sIconHud);
+	CPrintToChatAll("%t", "SF2 Special Round Announce Chat", sDescChat); // For those who are using minimized HUD...
+}
+
+SpecialRoundReset()
+{
+	g_iSpecialRoundType = 0;
+	g_hSpecialRoundTimer = INVALID_HANDLE;
+	g_iSpecialRoundCycleNum = 0;
+	g_flSpecialRoundCycleEndTime = -1.0;
+}
+
+bool:IsSpecialRoundRunning()
+{
+	return g_bSpecialRound;
+}
+
+public SpecialRoundInitializeAPI()
+{
+	CreateNative("SF2_IsSpecialRoundRunning", Native_IsSpecialRoundRunning);
+	CreateNative("SF2_GetSpecialRoundType", Native_GetSpecialRoundType);
+}
+
+public Native_IsSpecialRoundRunning(Handle:plugin, numParams)
+{
+	return g_bSpecialRound;
+}
+
+public Native_GetSpecialRoundType(Handle:plugin, numParams)
+{
+	return g_iSpecialRoundType;
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/stocks.sp b/addons/sourcemod/scripting/rytp_horror/stocks.sp
index 9d4dc79..cd0bb05 100644
--- a/addons/sourcemod/scripting/rytp_horror/stocks.sp
+++ b/addons/sourcemod/scripting/rytp_horror/stocks.sp
@@ -1,697 +1,702 @@
-#if defined _sf2_stocks_included
- #endinput
-#endif
-#define _sf2_stocks_included
-
-
-// Hud Element hiding flags (possibly outdated)
-#define	HIDEHUD_WEAPONSELECTION		( 1<<0 )	// Hide ammo count & weapon selection
-#define	HIDEHUD_FLASHLIGHT			( 1<<1 )
-#define	HIDEHUD_ALL					( 1<<2 )
-#define HIDEHUD_HEALTH				( 1<<3 )	// Hide health & armor / suit battery
-#define HIDEHUD_PLAYERDEAD			( 1<<4 )	// Hide when local player's dead
-#define HIDEHUD_NEEDSUIT			( 1<<5 )	// Hide when the local player doesn't have the HEV suit
-#define HIDEHUD_MISCSTATUS			( 1<<6 )	// Hide miscellaneous status elements (trains, pickup history, death notices, etc)
-#define HIDEHUD_CHAT				( 1<<7 )	// Hide all communication elements (saytext, voice icon, etc)
-#define	HIDEHUD_CROSSHAIR			( 1<<8 )	// Hide crosshairs
-#define	HIDEHUD_VEHICLE_CROSSHAIR	( 1<<9 )	// Hide vehicle crosshair
-#define HIDEHUD_INVEHICLE			( 1<<10 )
-#define HIDEHUD_BONUS_PROGRESS		( 1<<11 )	// Hide bonus progress display (for bonus map challenges)
-
-#define FFADE_IN            0x0001        // Just here so we don't pass 0 into the function
-#define FFADE_OUT           0x0002        // Fade out (not in)
-#define FFADE_MODULATE      0x0004        // Modulate (don't blend)
-#define FFADE_STAYOUT       0x0008        // ignores the duration, stays faded out until new ScreenFade message received
-#define FFADE_PURGE         0x0010        // Purges all other fades, replacing them with this one
-
-#define SF_FADE_IN				0x0001		// Fade in, not out
-#define SF_FADE_MODULATE		0x0002		// Modulate, don't blend
-#define SF_FADE_ONLYONE			0x0004
-#define SF_FADE_STAYOUT			0x0008
-
-#define MAX_BUTTONS 26
-
-#define FSOLID_CUSTOMRAYTEST 0x0001
-#define FSOLID_CUSTOMBOXTEST 0x0002
-#define FSOLID_NOT_SOLID 0x0004
-#define FSOLID_TRIGGER 0x0008
-
-#define COLLISION_GROUP_DEBRIS 1
-#define COLLISION_GROUP_PLAYER 5
-
-#define EFL_FORCE_CHECK_TRANSMIT (1 << 7)
-
-#define vec3_origin { 0.0, 0.0, 0.0 }
-
-// hull defines, mostly used for space checking.
-new Float:HULL_HUMAN_MINS[3] = { -13.0, -13.0, 0.0 }
-new Float:HULL_HUMAN_MAXS[3] = { 13.0, 13.0, 72.0 }
-
-//	==========================================================
-//	ENTITY FUNCTIONS
-//	==========================================================
-
-stock bool:IsEntityClassname(iEnt, const String:classname[], bool:bCaseSensitive=true)
-{
-	if (!IsValidEntity(iEnt)) return false;
-	
-	decl String:sBuffer[256];
-	GetEntityClassname(iEnt, sBuffer, sizeof(sBuffer));
-	
-	return StrEqual(sBuffer, classname, bCaseSensitive);
-}
-
-stock FindEntityByTargetname(const String:targetName[], const String:className[], bool:caseSensitive=true)
-{
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, className)) != -1)
-	{
-		decl String:sName[64];
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		if (StrEqual(sName, targetName, caseSensitive))
-		{
-			return ent;
-		}
-	}
-	
-	return INVALID_ENT_REFERENCE;
-}
-
-stock Float:EntityDistanceFromEntity(ent1, ent2, bool:bSquared=false)
-{
-	if (!IsValidEntity(ent1) || !IsValidEntity(ent2)) return -1.0;
-	
-	decl Float:flMyPos[3], Float:flHisPos[3];
-	GetEntPropVector(ent1, Prop_Data, "m_vecAbsOrigin", flMyPos);
-	GetEntPropVector(ent2, Prop_Data, "m_vecAbsOrigin", flHisPos);
-	return GetVectorDistance(flMyPos, flHisPos, bSquared);
-}
-
-stock GetEntityOBBCenterPosition(ent, Float:flBuffer)
-{
-	decl Float:flPos[3], Float:flMins[3], Float:flMaxs[3];
-	GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
-	GetEntPropVector(ent, Prop_Send, "m_vecMins", flMins);
-	GetEntPropVector(ent, Prop_Send, "m_vecMaxs", flMaxs);
-	
-	for (new i = 0; i < 3; i++) flBuffer[i] = flPos[i] + ((flMins[i] + flMaxs[i]) / 2.0);
-}
-
-stock bool:IsSpaceOccupied(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
-{
-	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_VISIBLE, TraceRayDontHitEntity, entity);
-	new bool:bHit = TR_DidHit(hTrace);
-	ref = TR_GetEntityIndex(hTrace);
-	CloseHandle(hTrace);
-	return bHit;
-}
-
-stock bool:IsSpaceOccupiedIgnorePlayers(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
-{
-	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_VISIBLE, TraceRayDontHitPlayersOrEntity, entity);
-	new bool:bHit = TR_DidHit(hTrace);
-	ref = TR_GetEntityIndex(hTrace);
-	CloseHandle(hTrace);
-	return bHit;
-}
-
-stock bool:IsSpaceOccupiedPlayer(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
-{
-	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_PLAYERSOLID, TraceRayDontHitEntity, entity);
-	new bool:bHit = TR_DidHit(hTrace);
-	ref = TR_GetEntityIndex(hTrace);
-	CloseHandle(hTrace);
-	return bHit;
-}
-
-stock bool:IsSpaceOccupiedNPC(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
-{
-	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_NPCSOLID, TraceRayDontHitEntity, entity);
-	new bool:bHit = TR_DidHit(hTrace);
-	ref = TR_GetEntityIndex(hTrace);
-	CloseHandle(hTrace);
-	return bHit;
-}
-
-stock EntitySetAnimation(iEntity, const String:sAnimation[], bool:bDefaultAnimation=true, Float:flPlaybackRate=1.0)
-{
-	// Set m_nSequence to 0 to fix an animation glitch with HL2/GMod models.
-	SetEntProp(iEntity, Prop_Send, "m_nSequence", 0);
-	
-	if (bDefaultAnimation)
-	{
-		SetVariantString(sAnimation);
-		AcceptEntityInput(iEntity, "SetDefaultAnimation");
-	}
-	
-	SetVariantString(sAnimation);
-	AcceptEntityInput(iEntity, "SetAnimation");
-	SetVariantFloat(flPlaybackRate);
-	AcceptEntityInput(iEntity, "SetPlaybackRate");
-}
-
-//	==========================================================
-//	CLIENT ENTITY FUNCTIONS
-//	==========================================================
-
-stock bool:IsClientCritBoosted(client)
-{
-	if (TF2_IsPlayerInCondition(client, TFCond_Kritzkrieged) ||
-		TF2_IsPlayerInCondition(client, TFCond_HalloweenCritCandy) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritCanteen) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritOnFirstBlood) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritOnWin) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritOnFlagCapture) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritOnKill) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritOnDamage) ||
-		TF2_IsPlayerInCondition(client, TFCond_CritMmmph))
-	{
-		return true;
-	}
-	
-	new iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
-	if (IsValidEdict(iActiveWeapon))
-	{
-		decl String:sNetClass[64];
-		GetEntityNetClass(iActiveWeapon, sNetClass, sizeof(sNetClass));
-		
-		if (StrEqual(sNetClass, "CTFFlameThrower"))
-		{
-			if (GetEntProp(iActiveWeapon, Prop_Send, "m_bCritFire")) return true;
-		
-			new iItemDef = GetEntProp(iActiveWeapon, Prop_Send, "m_iItemDefinitionIndex");
-			if (iItemDef == 594 && TF2_IsPlayerInCondition(client, TFCond_CritMmmph)) return true;
-		}
-		else if (StrEqual(sNetClass, "CTFMinigun"))
-		{
-			if (GetEntProp(iActiveWeapon, Prop_Send, "m_bCritShot")) return true;
-		}
-	}
-	
-	return false;
-}
-
-stock ClientSwitchToWeaponSlot(client, iSlot)
-{
-	new iWeapon = GetPlayerWeaponSlot(client, iSlot);
-	if (iWeapon == -1) return;
-	
-	// EquipPlayerWeapon(client, iWeapon); // doesn't work with TF2 that well.
-	SetEntPropEnt(client, Prop_Send, "m_hActiveWeapon", iWeapon);
-}
-
-stock ChangeClientTeamNoSuicide(client, team, bool:bRespawn=true)
-{
-	if (!IsClientInGame(client)) return;
-	
-	if (GetClientTeam(client) != team)
-	{
-		SetEntProp(client, Prop_Send, "m_lifeState", 2);
-		ChangeClientTeam(client, team);
-		SetEntProp(client, Prop_Send, "m_lifeState", 0);
-		if (bRespawn) TF2_RespawnPlayer(client);
-	}
-}
-
-stock UTIL_ScreenShake(client, Float:amplitude, Float:duration, Float:frequency)
-{
-	new Handle:hBf = StartMessageOne("Shake", client);
-	if (hBf != INVALID_HANDLE)
-	{
-		BfWriteByte(hBf, 0);
-		BfWriteFloat(hBf, amplitude);
-		BfWriteFloat(hBf, frequency);
-		BfWriteFloat(hBf, duration);
-		EndMessage();
-	}
-}
-
-public UTIL_ScreenFade(client, duration, time, flags, r, g, b, a)
-{
-	new clients[1], Handle:bf;
-	clients[0] = client;
-	
-	bf = StartMessage("Fade", clients, 1);
-	BfWriteShort(bf, duration);
-	BfWriteShort(bf, time);
-	BfWriteShort(bf, flags);
-	BfWriteByte(bf, r);
-	BfWriteByte(bf, g);
-	BfWriteByte(bf, b);
-	BfWriteByte(bf, a);
-	EndMessage();
-}
-
-stock bool:IsValidClient(client)
-{
-	return bool:(client > 0 && client <= MaxClients && IsClientInGame(client));
-}
-
-//	==========================================================
-//	TF2-SPECIFIC FUNCTIONS
-//	==========================================================
-
-stock ForceTeamWin(team)
-{
-	new ent = FindEntityByClassname(-1, "team_control_point_master");
-	if (ent == -1)
-	{
-		ent = CreateEntityByName("team_control_point_master");
-		DispatchSpawn(ent);
-		AcceptEntityInput(ent, "Enable");
-	}
-	
-	SetVariantInt(team);
-	AcceptEntityInput(ent, "SetWinner");
-}
-
-stock GameTextTFMessage(const String:message[], const String:icon[]="")
-{
-	new ent = CreateEntityByName("game_text_tf");
-	DispatchKeyValue(ent, "message", message);
-	DispatchKeyValue(ent, "display_to_team", "0");
-	DispatchKeyValue(ent, "icon", icon);
-	DispatchSpawn(ent);
-	AcceptEntityInput(ent, "Display");
-	AcceptEntityInput(ent, "Kill");
-}
-
-stock BuildAnnotationBitString(const clients[], iMaxClients)
-{
-	new iBitString = 1;
-	for (new i = 0; i < maxClients; i++)
-	{
-		new client = clients[i];
-		if (!IsClientInGame(client) || !IsPlayerAlive(client)) continue;
-	
-		iBitString |= RoundFloat(Pow(2.0, float(client)));
-	}
-	
-	return iBitString;
-}
-
-stock SpawnAnnotation(client, entity, const Float:pos[3], const String:message[], Float:lifetime)
-{
-	new Handle:event = CreateEvent("show_annotation", true);
-	if (event != INVALID_HANDLE)
-	{
-		new bitstring = BuildAnnotationBitString(id, pos, type, team);
-		if (bitstring > 1)
-		{
-			pos[2] -= 35.0;
-			SetEventFloat(event, "worldPosX", pos[0]);
-			SetEventFloat(event, "worldPosY", pos[1]);
-			SetEventFloat(event, "worldPosZ", pos[2]);
-			SetEventFloat(event, "lifetime", lifetime);
-			SetEventInt(event, "id", id);
-			SetEventString(event, "text", message);
-			SetEventInt(event, "visibilityBitfield", bitstring);
-			FireEvent(event);
-			KillTimer(event);
-		}
-		
-	}
-}
-
-stock Float:TF2_GetClassBaseSpeed(TFClassType:class)
-{
-	switch (class)
-	{
-		case TFClass_Scout:
-		{
-			return 400.0;
-		}
-		case TFClass_Soldier:
-		{
-			return 240.0;
-		}
-		case TFClass_Pyro:
-		{
-			return 300.0;
-		}
-		case TFClass_DemoMan:
-		{
-			return 280.0;
-		}
-		case TFClass_Heavy:
-		{
-			return 230.0;
-		}
-		case TFClass_Engineer:
-		{
-			return 300.0;
-		}
-		case TFClass_Medic:
-		{
-			return 320.0;
-		}
-		case TFClass_Sniper:
-		{
-			return 300.0;
-		}
-		case TFClass_Spy:
-		{
-			return 300.0;
-		}
-	}
-	
-	return 0.0;
-}
-
-stock Handle:PrepareItemHandle(String:classname[], index, level, quality, String:att[])
-{
-	new Handle:hItem = TF2Items_CreateItem(OVERRIDE_ALL | FORCE_GENERATION);
-	TF2Items_SetClassname(hItem, classname);
-	TF2Items_SetItemIndex(hItem, index);
-	TF2Items_SetLevel(hItem, level);
-	TF2Items_SetQuality(hItem, quality);
-	
-	// Set attributes.
-	new String:atts[32][32];
-	new count = ExplodeString(att, " ; ", atts, 32, 32);
-	if (count > 1)
-	{
-		TF2Items_SetNumAttributes(hItem, count / 2);
-		new i2 = 0;
-		for (new i = 0; i < count; i+= 2)
-		{
-			TF2Items_SetAttribute(hItem, i2, StringToInt(atts[i]), StringToFloat(atts[i+1]));
-			i2++;
-		}
-	}
-	else
-	{
-		TF2Items_SetNumAttributes(hItem, 0);
-	}
-	
-	return hItem;
-}
-
-// Removes wearables such as botkillers from weapons.
-stock TF2_RemoveWeaponSlotAndWearables(client, iSlot)
-{
-	new iWeapon = GetPlayerWeaponSlot(client, iSlot);
-	if (!IsValidEntity(iWeapon)) return;
-	
-	new iWearable = INVALID_ENT_REFERENCE;
-	while ((iWearable = FindEntityByClassname(iWearable, "tf_wearable")) != -1)
-	{
-		new iWeaponAssociated = GetEntPropEnt(iWearable, Prop_Send, "m_hWeaponAssociatedWith");
-		if (iWeaponAssociated == iWeapon)
-		{
-			AcceptEntityInput(iWearable, "Kill");
-		}
-	}
-	
-	iWearable = INVALID_ENT_REFERENCE;
-	while ((iWearable = FindEntityByClassname(iWearable, "tf_wearable_vm")) != -1)
-	{
-		new iWeaponAssociated = GetEntPropEnt(iWearable, Prop_Send, "m_hWeaponAssociatedWith");
-		if (iWeaponAssociated == iWeapon)
-		{
-			AcceptEntityInput(iWearable, "Kill");
-		}
-	}
-	
-	TF2_RemoveWeaponSlot(client, iSlot);
-}
-
-stock TE_SetupTFParticleEffect(iParticleSystemIndex, const Float:flOrigin[3], const Float:flStart[3]=NULL_VECTOR, iAttachType=0, iEntIndex=-1, iAttachmentPointIndex=0, bool:bControlPoint1=false, const Float:flControlPoint1Offset[3]=NULL_VECTOR)
-{
-	TE_Start("TFParticleEffect");
-	TE_WriteFloat("m_vecOrigin[0]", flOrigin[0]);
-	TE_WriteFloat("m_vecOrigin[1]", flOrigin[1]);
-	TE_WriteFloat("m_vecOrigin[2]", flOrigin[2]);
-	TE_WriteFloat("m_vecStart[0]", flStart[0]);
-	TE_WriteFloat("m_vecStart[1]", flStart[1]);
-	TE_WriteFloat("m_vecStart[2]", flStart[2]);
-	TE_WriteNum("m_iParticleSystemIndex", iParticleSystemIndex);
-	TE_WriteNum("m_iAttachType", iAttachType);
-	TE_WriteNum("entindex", iEntIndex);
-	TE_WriteNum("m_iAttachmentPointIndex", iAttachmentPointIndex);
-	TE_WriteNum("m_bControlPoint1", bControlPoint1);
-	TE_WriteFloat("m_ControlPoint1.m_vecOffset[0]", flControlPoint1Offset[0]);
-	TE_WriteFloat("m_ControlPoint1.m_vecOffset[1]", flControlPoint1Offset[1]);
-	TE_WriteFloat("m_ControlPoint1.m_vecOffset[2]", flControlPoint1Offset[2]);
-}
-
-//	==========================================================
-//	FLOAT FUNCTIONS
-//	==========================================================
-
-/**
- *	Converts a given timestamp into hours, minutes, and seconds.
- */
-stock FloatToTimeHMS(Float:time, &h=0, &m=0, &s=0)
-{
-	s = RoundFloat(time);
-	h = s / 3600;
-	s -= h * 3600;
-	m = s / 60;
-	s = s % 60;
-}
-
-stock FixedUnsigned16(Float:value, scale)
-{
-	new iOutput;
-	
-	iOutput = RoundToFloor(value * float(scale));
-	
-	if (iOutput < 0)
-	{
-		iOutput = 0;
-	}
-	
-	if (iOutput > 0xFFFF)
-	{
-		iOutput = 0xFFFF;
-	}
-	
-	return iOutput;
-}
-
-stock Float:FloatMin(Float:a, Float:b)
-{
-	if (a < b) return a;
-	return b;
-}
-
-stock Float:FloatMax(Float:a, Float:b)
-{
-	if (a > b) return a;
-	return b;
-}
-
-//	==========================================================
-//	VECTOR FUNCTIONS
-//	==========================================================
-
-/**
- *	Copies a vector into another vector.
- */
-stock CopyVector(const Float:flCopy[3], Float:flDest[3])
-{
-	flDest[0] = flCopy[0];
-	flDest[1] = flCopy[1];
-	flDest[2] = flCopy[2];
-}
-
-stock LerpVectors(const Float:fA[3], const Float:fB[3], Float:fC[3], Float:t)
-{
-    if (t < 0.0) t = 0.0;
-    if (t > 1.0) t = 1.0;
-    
-    fC[0] = fA[0] + (fB[0] - fA[0]) * t;
-    fC[1] = fA[1] + (fB[1] - fA[1]) * t;
-    fC[2] = fA[2] + (fB[2] - fA[2]) * t;
-}
-
-/**
- *	Translates and re-orients a given offset vector into world space, given a world position and angle.
- */
-stock VectorTransform(const Float:offset[3], const Float:worldpos[3], const Float:ang[3], Float:buffer[3])
-{
-	decl Float:fwd[3], Float:right[3], Float:up[3];
-	GetAngleVectors(ang, fwd, right, up);
-	
-	NormalizeVector(fwd, fwd);
-	NormalizeVector(right, right);
-	NormalizeVector(up, up);
-	
-	ScaleVector(right, offset[1]);
-	ScaleVector(fwd, offset[0]);
-	ScaleVector(up, offset[2]);
-	
-	buffer[0] = worldpos[0] + right[0] + fwd[0] + up[0];
-	buffer[1] = worldpos[1] + right[1] + fwd[1] + up[1];
-	buffer[2] = worldpos[2] + right[2] + fwd[2] + up[2];
-}
-
-//	==========================================================
-//	ANGLE FUNCTIONS
-//	==========================================================
-
-stock Float:ApproachAngle(Float:target, Float:value, Float:speed)
-{
-	new Float:delta = AngleDiff(value, target);
-	
-	if (speed < 0.0) speed = -speed;
-	
-	if (delta > speed) value += speed;
-	else if (delta < -speed) value -= speed;
-	else value = target;
-	
-	return AngleNormalize(value);
-}
-
-stock Float:AngleNormalize(Float:angle)
-{
-	while (angle > 180.0) angle -= 360.0;
-	while (angle < -180.0) angle += 360.0;
-	return angle;
-}
-
-stock Float:AngleDiff(Float:firstAngle, Float:secondAngle)
-{
-	new Float:diff = secondAngle - firstAngle;
-	return AngleNormalize(diff);
-}
-
-//	==========================================================
-//	PRECACHING FUNCTIONS
-//	==========================================================
-
-stock PrecacheSound2(const String:path[])
-{
-	PrecacheSound(path, true);
-	decl String:buffer[PLATFORM_MAX_PATH];
-	Format(buffer, sizeof(buffer), "sound/%s", path);
-	AddFileToDownloadsTable(buffer);
-}
-
-stock PrecacheMaterial2(const String:path[])
-{
-	decl String:buffer[PLATFORM_MAX_PATH];
-	Format(buffer, sizeof(buffer), "materials/%s.vmt", path);
-	AddFileToDownloadsTable(buffer);
-	Format(buffer, sizeof(buffer), "materials/%s.vtf", path);
-	AddFileToDownloadsTable(buffer);
-}
-
-stock PrecacheParticleSystem(const String:particleSystem[])
-{
-	static particleEffectNames = INVALID_STRING_TABLE;
-
-	if (particleEffectNames == INVALID_STRING_TABLE) {
-		if ((particleEffectNames = FindStringTable("ParticleEffectNames")) == INVALID_STRING_TABLE) {
-			return INVALID_STRING_INDEX;
-		}
-	}
-
-	new index = FindStringIndex2(particleEffectNames, particleSystem);
-	if (index == INVALID_STRING_INDEX) {
-		new numStrings = GetStringTableNumStrings(particleEffectNames);
-		if (numStrings >= GetStringTableMaxStrings(particleEffectNames)) {
-			return INVALID_STRING_INDEX;
-		}
-		
-		AddToStringTable(particleEffectNames, particleSystem);
-		index = numStrings;
-	}
-	
-	return index;
-}
-
-stock FindStringIndex2(tableidx, const String:str[])
-{
-	decl String:buf[1024];
-	
-	new numStrings = GetStringTableNumStrings(tableidx);
-	for (new i=0; i < numStrings; i++) {
-		ReadStringTable(tableidx, i, buf, sizeof(buf));
-		
-		if (StrEqual(buf, str)) {
-			return i;
-		}
-	}
-	
-	return INVALID_STRING_INDEX;
-}
-
-stock InsertNodesAroundPoint(Handle:hArray, const Float:flOrigin[3], Float:flDist, Float:flAddAng, Function:iCallback=INVALID_FUNCTION, any:data=-1)
-{
-	decl Float:flDirection[3];
-	decl Float:flPos[3];
-	
-	for (new Float:flAng = 0.0; flAng < 360.0; flAng += flAddAng)
-	{
-		flDirection[0] = 0.0;
-		flDirection[1] = flAng;
-		flDirection[2] = 0.0;
-		
-		GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
-		NormalizeVector(flDirection, flDirection);
-		ScaleVector(flDirection, flDist);
-		AddVectors(flDirection, flOrigin, flPos);
-		
-		new Float:flPos2[3];
-		for (new i = 0; i < 2; i++) flPos2[i] = flPos[i];
-		
-		if (iCallback != INVALID_FUNCTION)
-		{
-			new Action:iAction = Plugin_Continue;
-			
-			Call_StartFunction(INVALID_HANDLE, iCallback);
-			Call_PushArray(flOrigin, 3);
-			Call_PushArrayEx(flPos2, 3, SM_PARAM_COPYBACK);
-			Call_PushCell(data);
-			Call_Finish(iAction);
-			
-			if (iAction == Plugin_Stop || iAction == Plugin_Handled) continue;
-			else if (iAction == Plugin_Changed)
-			{
-				for (new i = 0; i < 2; i++) flPos[i] = flPos2[i];
-			}
-		}
-		
-		PushArrayArray(hArray, flPos, 3);
-	}
-}
-
-//	==========================================================
-//	TRACE FUNCTIONS
-//	==========================================================
-
-public bool:TraceRayDontHitEntity(entity, mask, any:data)
-{
-	if (entity == data) return false;
-	return true;
-}
-
-public bool:TraceRayDontHitPlayers(entity, mask, any:data)
-{
-	if (entity > 0 && entity <= MaxClients) return false;
-	
-	return true;
-}
-
-public bool:TraceRayDontHitPlayersOrEntity(entity, mask, any:data)
-{
-	if (entity == data) return false;
-
-	if (entity > 0 && entity <= MaxClients) return false;
-	
-	return true;
-}
-
-//	==========================================================
-//	TIMER/CALLBACK FUNCTIONS
-//	==========================================================
-
-public Action:Timer_KillEntity(Handle:timer, any:entref)
-{
-	new ent = EntRefToEntIndex(entref);
-	if (ent == INVALID_ENT_REFERENCE) return;
-	
-	AcceptEntityInput(ent, "Kill");
+#if defined _sf2_stocks_included
+ #endinput
+#endif
+#define _sf2_stocks_included
+
+
+// Hud Element hiding flags (possibly outdated)
+#define	HIDEHUD_WEAPONSELECTION		( 1<<0 )	// Hide ammo count & weapon selection
+#define	HIDEHUD_FLASHLIGHT			( 1<<1 )
+#define	HIDEHUD_ALL					( 1<<2 )
+#define HIDEHUD_HEALTH				( 1<<3 )	// Hide health & armor / suit battery
+#define HIDEHUD_PLAYERDEAD			( 1<<4 )	// Hide when local player's dead
+#define HIDEHUD_NEEDSUIT			( 1<<5 )	// Hide when the local player doesn't have the HEV suit
+#define HIDEHUD_MISCSTATUS			( 1<<6 )	// Hide miscellaneous status elements (trains, pickup history, death notices, etc)
+#define HIDEHUD_CHAT				( 1<<7 )	// Hide all communication elements (saytext, voice icon, etc)
+#define	HIDEHUD_CROSSHAIR			( 1<<8 )	// Hide crosshairs
+#define	HIDEHUD_VEHICLE_CROSSHAIR	( 1<<9 )	// Hide vehicle crosshair
+#define HIDEHUD_INVEHICLE			( 1<<10 )
+#define HIDEHUD_BONUS_PROGRESS		( 1<<11 )	// Hide bonus progress display (for bonus map challenges)
+
+#define FFADE_IN            0x0001        // Just here so we don't pass 0 into the function
+#define FFADE_OUT           0x0002        // Fade out (not in)
+#define FFADE_MODULATE      0x0004        // Modulate (don't blend)
+#define FFADE_STAYOUT       0x0008        // ignores the duration, stays faded out until new ScreenFade message received
+#define FFADE_PURGE         0x0010        // Purges all other fades, replacing them with this one
+
+#define SF_FADE_IN				0x0001		// Fade in, not out
+#define SF_FADE_MODULATE		0x0002		// Modulate, don't blend
+#define SF_FADE_ONLYONE			0x0004
+#define SF_FADE_STAYOUT			0x0008
+
+#define MAX_BUTTONS 26
+
+#define FSOLID_CUSTOMRAYTEST 0x0001
+#define FSOLID_CUSTOMBOXTEST 0x0002
+#define FSOLID_NOT_SOLID 0x0004
+#define FSOLID_TRIGGER 0x0008
+
+#define COLLISION_GROUP_DEBRIS 1
+#define COLLISION_GROUP_PLAYER 5
+
+#define EFL_FORCE_CHECK_TRANSMIT (1 << 7)
+
+#define vec3_origin { 0.0, 0.0, 0.0 }
+
+// hull defines, mostly used for space checking.
+new Float:HULL_HUMAN_MINS[3] = { -13.0, -13.0, 0.0 }
+new Float:HULL_HUMAN_MAXS[3] = { 13.0, 13.0, 72.0 }
+
+//	==========================================================
+//	ENTITY FUNCTIONS
+//	==========================================================
+
+stock bool:IsEntityClassname(iEnt, const String:classname[], bool:bCaseSensitive=true)
+{
+	if (!IsValidEntity(iEnt)) return false;
+	
+	decl String:sBuffer[256];
+	GetEntityClassname(iEnt, sBuffer, sizeof(sBuffer));
+	
+	return StrEqual(sBuffer, classname, bCaseSensitive);
+}
+
+stock FindEntityByTargetname(const String:targetName[], const String:className[], bool:caseSensitive=true)
+{
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, className)) != -1)
+	{
+		decl String:sName[64];
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		if (StrEqual(sName, targetName, caseSensitive))
+		{
+			return ent;
+		}
+	}
+	
+	return INVALID_ENT_REFERENCE;
+}
+
+stock Float:EntityDistanceFromEntity(ent1, ent2, bool:bSquared=false)
+{
+	if (!IsValidEntity(ent1) || !IsValidEntity(ent2)) return -1.0;
+	
+	decl Float:flMyPos[3], Float:flHisPos[3];
+	GetEntPropVector(ent1, Prop_Data, "m_vecAbsOrigin", flMyPos);
+	GetEntPropVector(ent2, Prop_Data, "m_vecAbsOrigin", flHisPos);
+	return GetVectorDistance(flMyPos, flHisPos, bSquared);
+}
+
+stock GetEntityOBBCenterPosition(ent, Float:flBuffer)
+{
+	decl Float:flPos[3], Float:flMins[3], Float:flMaxs[3];
+	GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
+	GetEntPropVector(ent, Prop_Send, "m_vecMins", flMins);
+	GetEntPropVector(ent, Prop_Send, "m_vecMaxs", flMaxs);
+	
+	for (new i = 0; i < 3; i++) flBuffer[i] = flPos[i] + ((flMins[i] + flMaxs[i]) / 2.0);
+}
+
+stock bool:IsSpaceOccupied(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
+{
+	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_VISIBLE, TraceRayDontHitEntity, entity);
+	new bool:bHit = TR_DidHit(hTrace);
+	ref = TR_GetEntityIndex(hTrace);
+	CloseHandle(hTrace);
+	return bHit;
+}
+
+stock bool:IsSpaceOccupiedIgnorePlayers(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
+{
+	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_VISIBLE, TraceRayDontHitPlayersOrEntity, entity);
+	new bool:bHit = TR_DidHit(hTrace);
+	ref = TR_GetEntityIndex(hTrace);
+	CloseHandle(hTrace);
+	return bHit;
+}
+
+stock bool:IsSpaceOccupiedPlayer(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
+{
+	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_PLAYERSOLID, TraceRayDontHitEntity, entity);
+	new bool:bHit = TR_DidHit(hTrace);
+	ref = TR_GetEntityIndex(hTrace);
+	CloseHandle(hTrace);
+	return bHit;
+}
+
+stock bool:IsSpaceOccupiedNPC(const Float:pos[3], const Float:mins[3], const Float:maxs[3], entity=-1, &ref=-1)
+{
+	new Handle:hTrace = TR_TraceHullFilterEx(pos, pos, mins, maxs, MASK_NPCSOLID, TraceRayDontHitEntity, entity);
+	new bool:bHit = TR_DidHit(hTrace);
+	ref = TR_GetEntityIndex(hTrace);
+	CloseHandle(hTrace);
+	return bHit;
+}
+
+stock EntitySetAnimation(iEntity, const String:sAnimation[], bool:bDefaultAnimation=true, Float:flPlaybackRate=1.0)
+{
+	// Set m_nSequence to 0 to fix an animation glitch with HL2/GMod models.
+	SetEntProp(iEntity, Prop_Send, "m_nSequence", 0);
+	
+	if (bDefaultAnimation)
+	{
+		SetVariantString(sAnimation);
+		AcceptEntityInput(iEntity, "SetDefaultAnimation");
+	}
+	else
+	{
+		SetVariantString("");
+		AcceptEntityInput(iEntity, "SetDefaultAnimation");
+	}
+	
+	SetVariantString(sAnimation);
+	AcceptEntityInput(iEntity, "SetAnimation");
+	SetVariantFloat(flPlaybackRate);
+	AcceptEntityInput(iEntity, "SetPlaybackRate");
+}
+
+//	==========================================================
+//	CLIENT ENTITY FUNCTIONS
+//	==========================================================
+
+stock bool:IsClientCritBoosted(client)
+{
+	if (TF2_IsPlayerInCondition(client, TFCond_Kritzkrieged) ||
+		TF2_IsPlayerInCondition(client, TFCond_HalloweenCritCandy) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritCanteen) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritOnFirstBlood) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritOnWin) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritOnFlagCapture) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritOnKill) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritOnDamage) ||
+		TF2_IsPlayerInCondition(client, TFCond_CritMmmph))
+	{
+		return true;
+	}
+	
+	new iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
+	if (IsValidEdict(iActiveWeapon))
+	{
+		decl String:sNetClass[64];
+		GetEntityNetClass(iActiveWeapon, sNetClass, sizeof(sNetClass));
+		
+		if (StrEqual(sNetClass, "CTFFlameThrower"))
+		{
+			if (GetEntProp(iActiveWeapon, Prop_Send, "m_bCritFire")) return true;
+		
+			new iItemDef = GetEntProp(iActiveWeapon, Prop_Send, "m_iItemDefinitionIndex");
+			if (iItemDef == 594 && TF2_IsPlayerInCondition(client, TFCond_CritMmmph)) return true;
+		}
+		else if (StrEqual(sNetClass, "CTFMinigun"))
+		{
+			if (GetEntProp(iActiveWeapon, Prop_Send, "m_bCritShot")) return true;
+		}
+	}
+	
+	return false;
+}
+
+stock ClientSwitchToWeaponSlot(client, iSlot)
+{
+	new iWeapon = GetPlayerWeaponSlot(client, iSlot);
+	if (iWeapon == -1) return;
+	
+	// EquipPlayerWeapon(client, iWeapon); // doesn't work with TF2 that well.
+	SetEntPropEnt(client, Prop_Send, "m_hActiveWeapon", iWeapon);
+}
+
+stock ChangeClientTeamNoSuicide(client, team, bool:bRespawn=true)
+{
+	if (!IsClientInGame(client)) return;
+	
+	if (GetClientTeam(client) != team)
+	{
+		SetEntProp(client, Prop_Send, "m_lifeState", 2);
+		ChangeClientTeam(client, team);
+		SetEntProp(client, Prop_Send, "m_lifeState", 0);
+		if (bRespawn) TF2_RespawnPlayer(client);
+	}
+}
+
+stock UTIL_ScreenShake(client, Float:amplitude, Float:duration, Float:frequency)
+{
+	new Handle:hBf = StartMessageOne("Shake", client);
+	if (hBf != INVALID_HANDLE)
+	{
+		BfWriteByte(hBf, 0);
+		BfWriteFloat(hBf, amplitude);
+		BfWriteFloat(hBf, frequency);
+		BfWriteFloat(hBf, duration);
+		EndMessage();
+	}
+}
+
+public UTIL_ScreenFade(client, duration, time, flags, r, g, b, a)
+{
+	new clients[1], Handle:bf;
+	clients[0] = client;
+	
+	bf = StartMessage("Fade", clients, 1);
+	BfWriteShort(bf, duration);
+	BfWriteShort(bf, time);
+	BfWriteShort(bf, flags);
+	BfWriteByte(bf, r);
+	BfWriteByte(bf, g);
+	BfWriteByte(bf, b);
+	BfWriteByte(bf, a);
+	EndMessage();
+}
+
+stock bool:IsValidClient(client)
+{
+	return bool:(client > 0 && client <= MaxClients && IsClientInGame(client));
+}
+
+//	==========================================================
+//	TF2-SPECIFIC FUNCTIONS
+//	==========================================================
+
+stock ForceTeamWin(team)
+{
+	new ent = FindEntityByClassname(-1, "team_control_point_master");
+	if (ent == -1)
+	{
+		ent = CreateEntityByName("team_control_point_master");
+		DispatchSpawn(ent);
+		AcceptEntityInput(ent, "Enable");
+	}
+	
+	SetVariantInt(team);
+	AcceptEntityInput(ent, "SetWinner");
+}
+
+stock GameTextTFMessage(const String:message[], const String:icon[]="")
+{
+	new ent = CreateEntityByName("game_text_tf");
+	DispatchKeyValue(ent, "message", message);
+	DispatchKeyValue(ent, "display_to_team", "0");
+	DispatchKeyValue(ent, "icon", icon);
+	DispatchSpawn(ent);
+	AcceptEntityInput(ent, "Display");
+	AcceptEntityInput(ent, "Kill");
+}
+
+stock BuildAnnotationBitString(const clients[], iMaxClients)
+{
+	new iBitString = 1;
+	for (new i = 0; i < maxClients; i++)
+	{
+		new client = clients[i];
+		if (!IsClientInGame(client) || !IsPlayerAlive(client)) continue;
+	
+		iBitString |= RoundFloat(Pow(2.0, float(client)));
+	}
+	
+	return iBitString;
+}
+
+stock SpawnAnnotation(client, entity, const Float:pos[3], const String:message[], Float:lifetime)
+{
+	new Handle:event = CreateEvent("show_annotation", true);
+	if (event != INVALID_HANDLE)
+	{
+		new bitstring = BuildAnnotationBitString(id, pos, type, team);
+		if (bitstring > 1)
+		{
+			pos[2] -= 35.0;
+			SetEventFloat(event, "worldPosX", pos[0]);
+			SetEventFloat(event, "worldPosY", pos[1]);
+			SetEventFloat(event, "worldPosZ", pos[2]);
+			SetEventFloat(event, "lifetime", lifetime);
+			SetEventInt(event, "id", id);
+			SetEventString(event, "text", message);
+			SetEventInt(event, "visibilityBitfield", bitstring);
+			FireEvent(event);
+			KillTimer(event);
+		}
+		
+	}
+}
+
+stock Float:TF2_GetClassBaseSpeed(TFClassType:class)
+{
+	switch (class)
+	{
+		case TFClass_Scout:
+		{
+			return 400.0;
+		}
+		case TFClass_Soldier:
+		{
+			return 240.0;
+		}
+		case TFClass_Pyro:
+		{
+			return 300.0;
+		}
+		case TFClass_DemoMan:
+		{
+			return 280.0;
+		}
+		case TFClass_Heavy:
+		{
+			return 230.0;
+		}
+		case TFClass_Engineer:
+		{
+			return 300.0;
+		}
+		case TFClass_Medic:
+		{
+			return 320.0;
+		}
+		case TFClass_Sniper:
+		{
+			return 300.0;
+		}
+		case TFClass_Spy:
+		{
+			return 300.0;
+		}
+	}
+	
+	return 0.0;
+}
+
+stock Handle:PrepareItemHandle(String:classname[], index, level, quality, String:att[])
+{
+	new Handle:hItem = TF2Items_CreateItem(OVERRIDE_ALL | FORCE_GENERATION);
+	TF2Items_SetClassname(hItem, classname);
+	TF2Items_SetItemIndex(hItem, index);
+	TF2Items_SetLevel(hItem, level);
+	TF2Items_SetQuality(hItem, quality);
+	
+	// Set attributes.
+	new String:atts[32][32];
+	new count = ExplodeString(att, " ; ", atts, 32, 32);
+	if (count > 1)
+	{
+		TF2Items_SetNumAttributes(hItem, count / 2);
+		new i2 = 0;
+		for (new i = 0; i < count; i+= 2)
+		{
+			TF2Items_SetAttribute(hItem, i2, StringToInt(atts[i]), StringToFloat(atts[i+1]));
+			i2++;
+		}
+	}
+	else
+	{
+		TF2Items_SetNumAttributes(hItem, 0);
+	}
+	
+	return hItem;
+}
+
+// Removes wearables such as botkillers from weapons.
+stock TF2_RemoveWeaponSlotAndWearables(client, iSlot)
+{
+	new iWeapon = GetPlayerWeaponSlot(client, iSlot);
+	if (!IsValidEntity(iWeapon)) return;
+	
+	new iWearable = INVALID_ENT_REFERENCE;
+	while ((iWearable = FindEntityByClassname(iWearable, "tf_wearable")) != -1)
+	{
+		new iWeaponAssociated = GetEntPropEnt(iWearable, Prop_Send, "m_hWeaponAssociatedWith");
+		if (iWeaponAssociated == iWeapon)
+		{
+			AcceptEntityInput(iWearable, "Kill");
+		}
+	}
+	
+	iWearable = INVALID_ENT_REFERENCE;
+	while ((iWearable = FindEntityByClassname(iWearable, "tf_wearable_vm")) != -1)
+	{
+		new iWeaponAssociated = GetEntPropEnt(iWearable, Prop_Send, "m_hWeaponAssociatedWith");
+		if (iWeaponAssociated == iWeapon)
+		{
+			AcceptEntityInput(iWearable, "Kill");
+		}
+	}
+	
+	TF2_RemoveWeaponSlot(client, iSlot);
+}
+
+stock TE_SetupTFParticleEffect(iParticleSystemIndex, const Float:flOrigin[3], const Float:flStart[3]=NULL_VECTOR, iAttachType=0, iEntIndex=-1, iAttachmentPointIndex=0, bool:bControlPoint1=false, const Float:flControlPoint1Offset[3]=NULL_VECTOR)
+{
+	TE_Start("TFParticleEffect");
+	TE_WriteFloat("m_vecOrigin[0]", flOrigin[0]);
+	TE_WriteFloat("m_vecOrigin[1]", flOrigin[1]);
+	TE_WriteFloat("m_vecOrigin[2]", flOrigin[2]);
+	TE_WriteFloat("m_vecStart[0]", flStart[0]);
+	TE_WriteFloat("m_vecStart[1]", flStart[1]);
+	TE_WriteFloat("m_vecStart[2]", flStart[2]);
+	TE_WriteNum("m_iParticleSystemIndex", iParticleSystemIndex);
+	TE_WriteNum("m_iAttachType", iAttachType);
+	TE_WriteNum("entindex", iEntIndex);
+	TE_WriteNum("m_iAttachmentPointIndex", iAttachmentPointIndex);
+	TE_WriteNum("m_bControlPoint1", bControlPoint1);
+	TE_WriteFloat("m_ControlPoint1.m_vecOffset[0]", flControlPoint1Offset[0]);
+	TE_WriteFloat("m_ControlPoint1.m_vecOffset[1]", flControlPoint1Offset[1]);
+	TE_WriteFloat("m_ControlPoint1.m_vecOffset[2]", flControlPoint1Offset[2]);
+}
+
+//	==========================================================
+//	FLOAT FUNCTIONS
+//	==========================================================
+
+/**
+ *	Converts a given timestamp into hours, minutes, and seconds.
+ */
+stock FloatToTimeHMS(Float:time, &h=0, &m=0, &s=0)
+{
+	s = RoundFloat(time);
+	h = s / 3600;
+	s -= h * 3600;
+	m = s / 60;
+	s = s % 60;
+}
+
+stock FixedUnsigned16(Float:value, scale)
+{
+	new iOutput;
+	
+	iOutput = RoundToFloor(value * float(scale));
+	
+	if (iOutput < 0)
+	{
+		iOutput = 0;
+	}
+	
+	if (iOutput > 0xFFFF)
+	{
+		iOutput = 0xFFFF;
+	}
+	
+	return iOutput;
+}
+
+stock Float:FloatMin(Float:a, Float:b)
+{
+	if (a < b) return a;
+	return b;
+}
+
+stock Float:FloatMax(Float:a, Float:b)
+{
+	if (a > b) return a;
+	return b;
+}
+
+//	==========================================================
+//	VECTOR FUNCTIONS
+//	==========================================================
+
+/**
+ *	Copies a vector into another vector.
+ */
+stock CopyVector(const Float:flCopy[3], Float:flDest[3])
+{
+	flDest[0] = flCopy[0];
+	flDest[1] = flCopy[1];
+	flDest[2] = flCopy[2];
+}
+
+stock LerpVectors(const Float:fA[3], const Float:fB[3], Float:fC[3], Float:t)
+{
+    if (t < 0.0) t = 0.0;
+    if (t > 1.0) t = 1.0;
+    
+    fC[0] = fA[0] + (fB[0] - fA[0]) * t;
+    fC[1] = fA[1] + (fB[1] - fA[1]) * t;
+    fC[2] = fA[2] + (fB[2] - fA[2]) * t;
+}
+
+/**
+ *	Translates and re-orients a given offset vector into world space, given a world position and angle.
+ */
+stock VectorTransform(const Float:offset[3], const Float:worldpos[3], const Float:ang[3], Float:buffer[3])
+{
+	decl Float:fwd[3], Float:right[3], Float:up[3];
+	GetAngleVectors(ang, fwd, right, up);
+	
+	NormalizeVector(fwd, fwd);
+	NormalizeVector(right, right);
+	NormalizeVector(up, up);
+	
+	ScaleVector(right, offset[1]);
+	ScaleVector(fwd, offset[0]);
+	ScaleVector(up, offset[2]);
+	
+	buffer[0] = worldpos[0] + right[0] + fwd[0] + up[0];
+	buffer[1] = worldpos[1] + right[1] + fwd[1] + up[1];
+	buffer[2] = worldpos[2] + right[2] + fwd[2] + up[2];
+}
+
+//	==========================================================
+//	ANGLE FUNCTIONS
+//	==========================================================
+
+stock Float:ApproachAngle(Float:target, Float:value, Float:speed)
+{
+	new Float:delta = AngleDiff(value, target);
+	
+	if (speed < 0.0) speed = -speed;
+	
+	if (delta > speed) value += speed;
+	else if (delta < -speed) value -= speed;
+	else value = target;
+	
+	return AngleNormalize(value);
+}
+
+stock Float:AngleNormalize(Float:angle)
+{
+	while (angle > 180.0) angle -= 360.0;
+	while (angle < -180.0) angle += 360.0;
+	return angle;
+}
+
+stock Float:AngleDiff(Float:firstAngle, Float:secondAngle)
+{
+	new Float:diff = secondAngle - firstAngle;
+	return AngleNormalize(diff);
+}
+
+//	==========================================================
+//	PRECACHING FUNCTIONS
+//	==========================================================
+
+stock PrecacheSound2(const String:path[])
+{
+	PrecacheSound(path, true);
+	decl String:buffer[PLATFORM_MAX_PATH];
+	Format(buffer, sizeof(buffer), "sound/%s", path);
+	AddFileToDownloadsTable(buffer);
+}
+
+stock PrecacheMaterial2(const String:path[])
+{
+	decl String:buffer[PLATFORM_MAX_PATH];
+	Format(buffer, sizeof(buffer), "materials/%s.vmt", path);
+	AddFileToDownloadsTable(buffer);
+	Format(buffer, sizeof(buffer), "materials/%s.vtf", path);
+	AddFileToDownloadsTable(buffer);
+}
+
+stock PrecacheParticleSystem(const String:particleSystem[])
+{
+	static particleEffectNames = INVALID_STRING_TABLE;
+
+	if (particleEffectNames == INVALID_STRING_TABLE) {
+		if ((particleEffectNames = FindStringTable("ParticleEffectNames")) == INVALID_STRING_TABLE) {
+			return INVALID_STRING_INDEX;
+		}
+	}
+
+	new index = FindStringIndex2(particleEffectNames, particleSystem);
+	if (index == INVALID_STRING_INDEX) {
+		new numStrings = GetStringTableNumStrings(particleEffectNames);
+		if (numStrings >= GetStringTableMaxStrings(particleEffectNames)) {
+			return INVALID_STRING_INDEX;
+		}
+		
+		AddToStringTable(particleEffectNames, particleSystem);
+		index = numStrings;
+	}
+	
+	return index;
+}
+
+stock FindStringIndex2(tableidx, const String:str[])
+{
+	decl String:buf[1024];
+	
+	new numStrings = GetStringTableNumStrings(tableidx);
+	for (new i=0; i < numStrings; i++) {
+		ReadStringTable(tableidx, i, buf, sizeof(buf));
+		
+		if (StrEqual(buf, str)) {
+			return i;
+		}
+	}
+	
+	return INVALID_STRING_INDEX;
+}
+
+stock InsertNodesAroundPoint(Handle:hArray, const Float:flOrigin[3], Float:flDist, Float:flAddAng, Function:iCallback=INVALID_FUNCTION, any:data=-1)
+{
+	decl Float:flDirection[3];
+	decl Float:flPos[3];
+	
+	for (new Float:flAng = 0.0; flAng < 360.0; flAng += flAddAng)
+	{
+		flDirection[0] = 0.0;
+		flDirection[1] = flAng;
+		flDirection[2] = 0.0;
+		
+		GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
+		NormalizeVector(flDirection, flDirection);
+		ScaleVector(flDirection, flDist);
+		AddVectors(flDirection, flOrigin, flPos);
+		
+		new Float:flPos2[3];
+		for (new i = 0; i < 2; i++) flPos2[i] = flPos[i];
+		
+		if (iCallback != INVALID_FUNCTION)
+		{
+			new Action:iAction = Plugin_Continue;
+			
+			Call_StartFunction(INVALID_HANDLE, iCallback);
+			Call_PushArray(flOrigin, 3);
+			Call_PushArrayEx(flPos2, 3, SM_PARAM_COPYBACK);
+			Call_PushCell(data);
+			Call_Finish(iAction);
+			
+			if (iAction == Plugin_Stop || iAction == Plugin_Handled) continue;
+			else if (iAction == Plugin_Changed)
+			{
+				for (new i = 0; i < 2; i++) flPos[i] = flPos2[i];
+			}
+		}
+		
+		PushArrayArray(hArray, flPos, 3);
+	}
+}
+
+//	==========================================================
+//	TRACE FUNCTIONS
+//	==========================================================
+
+public bool:TraceRayDontHitEntity(entity, mask, any:data)
+{
+	if (entity == data) return false;
+	return true;
+}
+
+public bool:TraceRayDontHitPlayers(entity, mask, any:data)
+{
+	if (entity > 0 && entity <= MaxClients) return false;
+	
+	return true;
+}
+
+public bool:TraceRayDontHitPlayersOrEntity(entity, mask, any:data)
+{
+	if (entity == data) return false;
+
+	if (entity > 0 && entity <= MaxClients) return false;
+	
+	return true;
+}
+
+//	==========================================================
+//	TIMER/CALLBACK FUNCTIONS
+//	==========================================================
+
+public Action:Timer_KillEntity(Handle:timer, any:entref)
+{
+	new ent = EntRefToEntIndex(entref);
+	if (ent == INVALID_ENT_REFERENCE) return;
+	
+	AcceptEntityInput(ent, "Kill");
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/spcomp.exe b/addons/sourcemod/scripting/spcomp.exe
index 0da62a81aff47bb6d4d52ede151def06c0dc6a48..fe100b61e6cef038060fb7f0c318da6433051909 100644
GIT binary patch
literal 403968
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
AfB*mh

literal 345600
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
J{*S$Ze+3K?e=-07

diff --git a/addons/sourcemod/translations/ru/sf2.phrases.txt b/addons/sourcemod/translations/ru/sf2.phrases.txt
index 29d7bef..59a44b4 100644
--- a/addons/sourcemod/translations/ru/sf2.phrases.txt
+++ b/addons/sourcemod/translations/ru/sf2.phrases.txt
@@ -316,11 +316,21 @@
 		"ru"	"Вкл беззвучный режим"
 	}
 	
+	"SF2 Settings Film Grain Menu Title"
+	{
+		"ru"	"Вкл/выкл зернистость"
+	}
+	
 	"SF2 Settings Proxy Menu Title"
 	{
 		"ru"	"Разрешить быть выбранным в качестве Прокси"
 	}
 	
+	"SF2 Settings Ghost Overlay Menu Title"
+	{
+		"ru"	"Вкл/выкл интерфейс призрака"
+	}
+	
 	"SF2 Ad Message 1"
 	{
 		"ru"	"{lightgreen}RYTP Horror {olive}- проект {lightgreen}Penek-Gaming.Ru{olive}. Узнать больше об этом и других режимах можно на нашем сайте: {lightgreen}http://www.penek-gaming.ru/tf{default}"
@@ -372,6 +382,26 @@
 		"ru"	"{lightgreen}Выключены подсказки."
 	}
 	
+	"SF2 Enabled Film Grain"
+	{
+		"ru"	"{lightgreen}Зернистость включена."
+	}
+	
+	"SF2 Disabled Film Grain"
+	{
+		"ru"	"{lightgreen}Зернистость выключена."
+	}
+	
+	"SF2 Enabled Ghost Overlay"
+	{
+		"ru"	"{lightgreen}Интерфейс призрака включен."
+	}
+	
+	"SF2 Disabled Ghost Overlay"
+	{
+		"ru"	"{lightgreen}Интерфейс призрака выключен."
+	}
+	
 	"SF2 Enabled Proxy"
 	{
 		"ru"	"{lightgreen}Вы будете выбираться в качестве Прокси."
diff --git a/addons/sourcemod/translations/sf2.phrases.txt b/addons/sourcemod/translations/sf2.phrases.txt
index 6799cca..f696075 100644
--- a/addons/sourcemod/translations/sf2.phrases.txt
+++ b/addons/sourcemod/translations/sf2.phrases.txt
@@ -316,11 +316,21 @@
 		"en"	"Set mute mode"
 	}
 	
+	"SF2 Settings Film Grain Menu Title"
+	{
+		"en"	"Toggle film grain"
+	}
+	
 	"SF2 Settings Proxy Menu Title"
 	{
 		"en"	"Allow being picked as a proxy"
 	}
 	
+	"SF2 Settings Ghost Overlay Menu Title"
+	{
+		"en"	"Toggle Ghost Mode overlay"
+	}
+	
 	"SF2 Ad Message 1"
 	{
 		"en"	"{olive}Slender Fortress official Steam group: {lightgreen}http://steamcommunity.com/groups/SlenderFortress{default}"
@@ -367,6 +377,26 @@
 		"en"	"{lightgreen}Disabled hints."
 	}
 	
+	"SF2 Enabled Film Grain"
+	{
+		"en"	"{lightgreen}Enabled film grain."
+	}
+	
+	"SF2 Disabled Film Grain"
+	{
+		"en"	"{lightgreen}Disabled film grain."
+	}
+	
+	"SF2 Enabled Ghost Overlay"
+	{
+		"en"	"{lightgreen}Enabled Ghost Mode overlay."
+	}
+	
+	"SF2 Disabled Ghost Overlay"
+	{
+		"en"	"{lightgreen}Disabled Ghost Mode overlay."
+	}
+	
 	"SF2 Enabled Proxy"
 	{
 		"en"	"{lightgreen}You are now opt'd in to be chosen as a Proxy."
-- 
GitLab


From d35eebb382a9f721440510b4f1fa48e84034e212 Mon Sep 17 00:00:00 2001
From: Alexey <lexuzieel@gmail.com>
Date: Wed, 14 Aug 2019 02:17:35 +0300
Subject: [PATCH 2/6] Migrate previously implemented features

---
 addons/sourcemod/scripting/rytp_horror.sp     | 12901 ++++++++--------
 .../sourcemod/scripting/rytp_horror/client.sp | 11811 +++++++-------
 2 files changed, 12450 insertions(+), 12262 deletions(-)

diff --git a/addons/sourcemod/scripting/rytp_horror.sp b/addons/sourcemod/scripting/rytp_horror.sp
index b26e668..0ad5e9c 100644
--- a/addons/sourcemod/scripting/rytp_horror.sp
+++ b/addons/sourcemod/scripting/rytp_horror.sp
@@ -1,6376 +1,6527 @@
-#include <sourcemod>
-#include <sdktools>
-#include <sdkhooks>
-#include <clientprefs>
-#include <steamtools>
-#include <tf2items>
-#include <dhooks>
-#include <navmesh>
-
-#include <tf2>
-#include <tf2_stocks>
-#include <morecolors>
-#include <sf2>
-
-#undef REQUIRE_PLUGIN
-#include <adminmenu>
-#tryinclude <store/store-tf2footprints>
-#define REQUIRE_PLUGIN
-
-//#define DEBUG
-
-// If compiling with SM 1.7+, uncomment to compile and use SF2 methodmaps.
-//#define METHODMAPS
-
-#define PLUGIN_VERSION "0.2.6-git136"
-#define PLUGIN_VERSION_DISPLAY "0.2.6"
-
-public Plugin:myinfo = 
-{
-    name = "RYTP Horror (Slender Fortress edit by lexuzieel special for Penek-Gaming.Ru)",
-    author	= "KitRifty",
-    description	= "Based on the game Slender: The Eight Pages.",
-    version = PLUGIN_VERSION,
-    url = "http://steamcommunity.com/groups/SlenderFortress"
-}
-
-#define FILE_RESTRICTEDWEAPONS "configs/sf2/restrictedweapons.cfg"
-
-#define BOSS_THINKRATE 0.1 // doesn't really matter much since timers go at a minimum of 0.1 seconds anyways
-
-#define CRIT_SOUND "player/crit_hit.wav"
-#define CRIT_PARTICLENAME "crit_text"
-
-#define PAGE_MODEL "models/rytp/horror/props/hint_paper.mdl"
-#define PAGE_MODELSCALE 1.1
-
-#define FLASHLIGHT_CLICKSOUND "rytp_horror/toggleflashlight.wav"
-#define FLASHLIGHT_BREAKSOUND "ambient/energy/spark6.wav"
-#define FLASHLIGHT_NOSOUND "player/suit_denydevice.wav"
-#define PAGE_GRABSOUND "rytp_horror/grabpage_sound.wav"
-
-#define MUSIC_CHAN SNDCHAN_AUTO
-
-#define MUSIC_GOTPAGES1_SOUND "rytp_horror/grabpage_music_1.wav"
-#define MUSIC_GOTPAGES2_SOUND "rytp_horror/grabpage_music_2.wav"
-#define MUSIC_GOTPAGES3_SOUND "rytp_horror/grabpage_music_3.wav"
-#define MUSIC_GOTPAGES4_SOUND "rytp_horror/grabpage_music_4.wav"
-#define MUSIC_PAGE_VOLUME 1.0
-
-#define SF2_INTRO_DEFAULT_MUSIC "rytp_horror/intro_music.mp3"
-
-#define SF2_HUD_TEXT_COLOR_R 127
-#define SF2_HUD_TEXT_COLOR_G 167
-#define SF2_HUD_TEXT_COLOR_B 141
-#define SF2_HUD_TEXT_COLOR_A 255
-
-enum MuteMode
-{
-	MuteMode_Normal = 0,
-	MuteMode_DontHearOtherTeam,
-	MuteMode_DontHearOtherTeamIfNotProxy
-};
-
-// Offsets.
-new g_offsPlayerFOV = -1;
-new g_offsPlayerDefaultFOV = -1;
-new g_offsPlayerFogCtrl = -1;
-new g_offsPlayerPunchAngle = -1;
-new g_offsPlayerPunchAngleVel = -1;
-new g_offsFogCtrlEnable = -1;
-new g_offsFogCtrlEnd = -1;
-
-new g_iParticleCriticalHit = -1;
-
-new bool:g_bEnabled;
-
-new Handle:g_hConfig;
-new Handle:g_hRestrictedWeaponsConfig;
-new Handle:g_hSpecialRoundsConfig;
-
-new Handle:g_hPageMusicRanges;
-
-new g_iSlenderModel[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-new g_iSlenderPoseEnt[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-new g_iSlenderCopyMaster[MAX_BOSSES] = { -1, ... };
-new Float:g_flSlenderEyePosOffset[MAX_BOSSES][3];
-new Float:g_flSlenderEyeAngOffset[MAX_BOSSES][3];
-new Float:g_flSlenderDetectMins[MAX_BOSSES][3];
-new Float:g_flSlenderDetectMaxs[MAX_BOSSES][3];
-new Handle:g_hSlenderThink[MAX_BOSSES];
-new Handle:g_hSlenderEntityThink[MAX_BOSSES];
-new Handle:g_hSlenderFakeTimer[MAX_BOSSES];
-new Float:g_flSlenderLastKill[MAX_BOSSES];
-new g_iSlenderState[MAX_BOSSES];
-new g_iSlenderTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-new Float:g_flSlenderAcceleration[MAX_BOSSES];
-new Float:g_flSlenderGoalPos[MAX_BOSSES][3];
-new Float:g_flSlenderStaticRadius[MAX_BOSSES];
-new Float:g_flSlenderChaseDeathPosition[MAX_BOSSES][3];
-new bool:g_bSlenderChaseDeathPosition[MAX_BOSSES];
-new Float:g_flSlenderIdleAnimationPlaybackRate[MAX_BOSSES];
-new Float:g_flSlenderWalkAnimationPlaybackRate[MAX_BOSSES];
-new Float:g_flSlenderRunAnimationPlaybackRate[MAX_BOSSES];
-new Float:g_flSlenderJumpSpeed[MAX_BOSSES];
-new Float:g_flSlenderPathNodeTolerance[MAX_BOSSES];
-new Float:g_flSlenderPathNodeLookAhead[MAX_BOSSES];
-new bool:g_bSlenderFeelerReflexAdjustment[MAX_BOSSES];
-new Float:g_flSlenderFeelerReflexAdjustmentPos[MAX_BOSSES][3];
-
-new g_iSlenderTeleportTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
-
-new Float:g_flSlenderNextTeleportTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportTargetTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMinRange[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMaxRange[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMaxTargetTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTeleportMaxTargetStress[MAX_BOSSES] = { 0.0, ... };
-new Float:g_flSlenderTeleportPlayersRestTime[MAX_BOSSES][MAXPLAYERS + 1];
-
-// For boss type 2
-// General variables
-new g_iSlenderHealth[MAX_BOSSES];
-new Handle:g_hSlenderPath[MAX_BOSSES];
-new g_iSlenderCurrentPathNode[MAX_BOSSES] = { -1, ... };
-new bool:g_bSlenderAttacking[MAX_BOSSES];
-new Handle:g_hSlenderAttackTimer[MAX_BOSSES];
-new Float:g_flSlenderNextJump[MAX_BOSSES] = { -1.0, ... };
-new g_iSlenderInterruptConditions[MAX_BOSSES];
-new Float:g_flSlenderLastFoundPlayer[MAX_BOSSES][MAXPLAYERS + 1];
-new Float:g_flSlenderLastFoundPlayerPos[MAX_BOSSES][MAXPLAYERS + 1][3];
-new Float:g_flSlenderNextPathTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderCalculatedWalkSpeed[MAX_BOSSES];
-new Float:g_flSlenderCalculatedSpeed[MAX_BOSSES];
-new Float:g_flSlenderTimeUntilNoPersistence[MAX_BOSSES];
-
-new Float:g_flSlenderProxyTeleportMinRange[MAX_BOSSES];
-new Float:g_flSlenderProxyTeleportMaxRange[MAX_BOSSES];
-
-// Sound variables
-new Float:g_flSlenderTargetSoundLastTime[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTargetSoundMasterPos[MAX_BOSSES][3]; // to determine hearing focus
-new Float:g_flSlenderTargetSoundTempPos[MAX_BOSSES][3];
-new Float:g_flSlenderTargetSoundDiscardMasterPosTime[MAX_BOSSES];
-new bool:g_bSlenderInvestigatingSound[MAX_BOSSES];
-new SoundType:g_iSlenderTargetSoundType[MAX_BOSSES] = { SoundType_None, ... };
-new g_iSlenderTargetSoundCount[MAX_BOSSES];
-new Float:g_flSlenderLastHeardVoice[MAX_BOSSES];
-new Float:g_flSlenderLastHeardFootstep[MAX_BOSSES];
-new Float:g_flSlenderLastHeardWeapon[MAX_BOSSES];
-
-
-new Float:g_flSlenderNextJumpScare[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderNextVoiceSound[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderNextMoanSound[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderNextWanderPos[MAX_BOSSES] = { -1.0, ... };
-
-
-new Float:g_flSlenderTimeUntilRecover[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilAlert[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilIdle[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilChase[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilKill[MAX_BOSSES] = { -1.0, ... };
-new Float:g_flSlenderTimeUntilNextProxy[MAX_BOSSES] = { -1.0, ... };
-
-// Page data.
-new g_iPageCount;
-new g_iPageMax;
-new Float:g_flPageFoundLastTime;
-new bool:g_bPageRef;
-new String:g_strPageRefModel[PLATFORM_MAX_PATH];
-new Float:g_flPageRefModelScale;
-
-static Handle:g_hPlayerIntroMusicTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Seeing Mr. Slendy data.
-new bool:g_bPlayerSeesSlender[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerSeesSlenderLastTime[MAXPLAYERS + 1][MAX_BOSSES];
-
-new Float:g_flPlayerSightSoundNextTime[MAXPLAYERS + 1][MAX_BOSSES];
-
-new Float:g_flPlayerScareLastTime[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerScareNextTime[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerStaticAmount[MAXPLAYERS + 1];
-
-new Float:g_flPlayerLastChaseBossEncounterTime[MAXPLAYERS + 1][MAX_BOSSES];
-
-// Player static data.
-new g_iPlayerStaticMode[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerStaticIncreaseRate[MAXPLAYERS + 1];
-new Float:g_flPlayerStaticDecreaseRate[MAXPLAYERS + 1];
-new Handle:g_hPlayerStaticTimer[MAXPLAYERS + 1];
-new g_iPlayerStaticMaster[MAXPLAYERS + 1] = { -1, ... };
-new String:g_strPlayerStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new String:g_strPlayerLastStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerLastStaticTime[MAXPLAYERS + 1];
-new Float:g_flPlayerLastStaticVolume[MAXPLAYERS + 1];
-new Handle:g_hPlayerLastStaticTimer[MAXPLAYERS + 1];
-
-// Static shake data.
-new g_iPlayerStaticShakeMaster[MAXPLAYERS + 1];
-new bool:g_bPlayerInStaticShake[MAXPLAYERS + 1];
-new String:g_strPlayerStaticShakeSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerStaticShakeMinVolume[MAXPLAYERS + 1];
-new Float:g_flPlayerStaticShakeMaxVolume[MAXPLAYERS + 1];
-
-// Fake lag compensation for FF.
-new bool:g_bPlayerLagCompensation[MAXPLAYERS + 1];
-new g_iPlayerLagCompensationTeam[MAXPLAYERS + 1];
-
-// Hint data.
-enum
-{
-	PlayerHint_Sprint = 0,
-	PlayerHint_Flashlight,
-	PlayerHint_MainMenu,
-	PlayerHint_Blink,
-	PlayerHint_MaxNum
-};
-
-enum PlayerPreferences
-{
-	bool:PlayerPreference_PvPAutoSpawn,
-	MuteMode:PlayerPreference_MuteMode,
-	bool:PlayerPreference_FilmGrain,
-	bool:PlayerPreference_ShowHints,
-	bool:PlayerPreference_EnableProxySelection,
-	bool:PlayerPreference_ProjectedFlashlight,
-	bool:PlayerPreference_GhostOverlay
-};
-
-new bool:g_bPlayerHints[MAXPLAYERS + 1][PlayerHint_MaxNum];
-new g_iPlayerPreferences[MAXPLAYERS + 1][PlayerPreferences];
-
-// Player data.
-new g_iPlayerLastButtons[MAXPLAYERS + 1];
-new bool:g_bPlayerChoseTeam[MAXPLAYERS + 1];
-new bool:g_bPlayerEliminated[MAXPLAYERS + 1];
-new bool:g_bPlayerEscaped[MAXPLAYERS + 1];
-new g_iPlayerPageCount[MAXPLAYERS + 1];
-new g_iPlayerQueuePoints[MAXPLAYERS + 1];
-new bool:g_bPlayerPlaying[MAXPLAYERS + 1];
-new Handle:g_hPlayerOverlayCheck[MAXPLAYERS + 1];
-
-new Handle:g_hPlayerSwitchBlueTimer[MAXPLAYERS + 1];
-
-// Player stress data.
-new Float:g_flPlayerStress[MAXPLAYERS + 1];
-new Float:g_flPlayerStressNextUpdateTime[MAXPLAYERS + 1];
-
-// Proxy data.
-new bool:g_bPlayerProxy[MAXPLAYERS + 1];
-new bool:g_bPlayerProxyAvailable[MAXPLAYERS + 1];
-new Handle:g_hPlayerProxyAvailableTimer[MAXPLAYERS + 1];
-new bool:g_bPlayerProxyAvailableInForce[MAXPLAYERS + 1];
-new g_iPlayerProxyAvailableCount[MAXPLAYERS + 1];
-new g_iPlayerProxyMaster[MAXPLAYERS + 1];
-new g_iPlayerProxyControl[MAXPLAYERS + 1];
-new Handle:g_hPlayerProxyControlTimer[MAXPLAYERS + 1];
-new Float:g_flPlayerProxyControlRate[MAXPLAYERS + 1];
-new Handle:g_flPlayerProxyVoiceTimer[MAXPLAYERS + 1];
-new g_iPlayerProxyAskMaster[MAXPLAYERS + 1] = { -1, ... };
-new Float:g_iPlayerProxyAskPosition[MAXPLAYERS + 1][3];
-
-new g_iPlayerDesiredFOV[MAXPLAYERS + 1];
-
-new Handle:g_hPlayerPostWeaponsTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Music system.
-new g_iPlayerMusicFlags[MAXPLAYERS + 1];
-new String:g_strPlayerMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerMusicVolume[MAXPLAYERS + 1];
-new Float:g_flPlayerMusicTargetVolume[MAXPLAYERS + 1];
-new Handle:g_hPlayerMusicTimer[MAXPLAYERS + 1];
-new g_iPlayerPageMusicMaster[MAXPLAYERS + 1];
-
-// Chase music system, which apparently also uses the alert song system. And the idle sound system.
-new String:g_strPlayerChaseMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new String:g_strPlayerChaseMusicSee[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerChaseMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Float:g_flPlayerChaseMusicSeeVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayerChaseMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayerChaseMusicSeeTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new g_iPlayerChaseMusicMaster[MAXPLAYERS + 1] = { -1, ... };
-new g_iPlayerChaseMusicSeeMaster[MAXPLAYERS + 1] = { -1, ... };
-
-new String:g_strPlayerAlertMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayerAlertMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayerAlertMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new g_iPlayerAlertMusicMaster[MAXPLAYERS + 1] = { -1, ... };
-
-new String:g_strPlayer20DollarsMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
-new Float:g_flPlayer20DollarsMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
-new Handle:g_hPlayer20DollarsMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
-new g_iPlayer20DollarsMusicMaster[MAXPLAYERS + 1] = { -1, ... };
-
-
-new SF2RoundState:g_iRoundState = SF2RoundState_Invalid;
-new bool:g_bRoundGrace = false;
-new Float:g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
-new bool:g_bRoundInfiniteFlashlight = false;
-new bool:g_bRoundInfiniteBlink = false;
-new bool:g_bRoundInfiniteSprint = false;
-
-static Handle:g_hRoundGraceTimer = INVALID_HANDLE;
-static Handle:g_hRoundTimer = INVALID_HANDLE;
-static Handle:g_hVoteTimer = INVALID_HANDLE;
-static String:g_strRoundBossProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-
-static g_iRoundCount = 0;
-static g_iRoundEndCount = 0;
-static g_iRoundActiveCount = 0;
-static g_iRoundTime = 0;
-static g_iRoundTimeLimit = 0;
-static g_iRoundEscapeTimeLimit = 0;
-static g_iRoundTimeGainFromPage = 0;
-static bool:g_bRoundHasEscapeObjective = false;
-
-static g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
-
-static g_iRoundIntroFadeColor[4] = { 255, ... };
-static Float:g_flRoundIntroFadeHoldTime;
-static Float:g_flRoundIntroFadeDuration;
-static Handle:g_hRoundIntroTimer = INVALID_HANDLE;
-static bool:g_bRoundIntroTextDefault = true;
-static Handle:g_hRoundIntroTextTimer = INVALID_HANDLE;
-static g_iRoundIntroText;
-static String:g_strRoundIntroMusic[PLATFORM_MAX_PATH] = "";
-
-static g_iRoundWarmupRoundCount = 0;
-
-static bool:g_bRoundWaitingForPlayers = false;
-
-// Special round variables.
-new bool:g_bSpecialRound = false;
-new g_iSpecialRoundType = 0;
-new bool:g_bSpecialRoundNew = false;
-new bool:g_bSpecialRoundContinuous = false;
-new g_iSpecialRoundCount = 1;
-new bool:g_bPlayerPlayedSpecialRound[MAXPLAYERS + 1] = { true, ... };
-
-// New boss round variables.
-static bool:g_bNewBossRound = false;
-static bool:g_bNewBossRoundNew = false;
-static bool:g_bNewBossRoundContinuous = false;
-static g_iNewBossRoundCount = 1;
-static bool:g_bPlayerPlayedNewBossRound[MAXPLAYERS + 1] = { true, ... };
-static String:g_strNewBossRoundProfile[64] = "";
-
-static Handle:g_hRoundMessagesTimer = INVALID_HANDLE;
-static g_iRoundMessagesNum = 0;
-
-static Handle:g_hBossCountUpdateTimer = INVALID_HANDLE;
-static Handle:g_hClientAverageUpdateTimer = INVALID_HANDLE;
-
-// Server variables.
-new Handle:g_cvVersion;
-new Handle:g_cvEnabled;
-new Handle:g_cvSlenderMapsOnly;
-new Handle:g_cvPlayerViewbobEnabled;
-new Handle:g_cvPlayerShakeEnabled;
-new Handle:g_cvPlayerShakeFrequencyMax;
-new Handle:g_cvPlayerShakeAmplitudeMax;
-new Handle:g_cvGraceTime;
-new Handle:g_cvAllChat;
-new Handle:g_cv20Dollars;
-new Handle:g_cvMaxPlayers;
-new Handle:g_cvMaxPlayersOverride;
-new Handle:g_cvCampingEnabled;
-new Handle:g_cvCampingMaxStrikes;
-new Handle:g_cvCampingStrikesWarn;
-new Handle:g_cvCampingMinDistance;
-new Handle:g_cvCampingNoStrikeSanity;
-new Handle:g_cvCampingNoStrikeBossDistance;
-new Handle:g_cvDifficulty;
-new Handle:g_cvBossMain;
-new Handle:g_cvBossProfileOverride;
-new Handle:g_cvPlayerBlinkRate;
-new Handle:g_cvPlayerBlinkHoldTime;
-new Handle:g_cvSpecialRoundBehavior;
-new Handle:g_cvSpecialRoundForce;
-new Handle:g_cvSpecialRoundOverride;
-new Handle:g_cvSpecialRoundInterval;
-new Handle:g_cvNewBossRoundBehavior;
-new Handle:g_cvNewBossRoundInterval;
-new Handle:g_cvNewBossRoundForce;
-new Handle:g_cvPlayerVoiceDistance;
-new Handle:g_cvPlayerVoiceWallScale;
-new Handle:g_cvUltravisionEnabled;
-new Handle:g_cvUltravisionRadiusRed;
-new Handle:g_cvUltravisionRadiusBlue;
-new Handle:g_cvUltravisionBrightness;
-new Handle:g_cvGhostModeConnectionCheck;
-new Handle:g_cvGhostModeConnectionTolerance;
-new Handle:g_cvIntroEnabled;
-new Handle:g_cvIntroDefaultHoldTime;
-new Handle:g_cvIntroDefaultFadeTime;
-new Handle:g_cvTimeLimit;
-new Handle:g_cvTimeLimitEscape;
-new Handle:g_cvTimeGainFromPageGrab;
-new Handle:g_cvWarmupRound;
-new Handle:g_cvWarmupRoundNum;
-new Handle:g_cvPlayerViewbobHurtEnabled;
-new Handle:g_cvPlayerViewbobSprintEnabled;
-new Handle:g_cvPlayerFakeLagCompensation;
-new Handle:g_cvPlayerProxyWaitTime;
-new Handle:g_cvPlayerProxyAsk;
-new Handle:g_cvHalfZatoichiHealthGain;
-new Handle:g_cvBlockSuicideDuringRound;
-
-new Handle:g_cvPlayerInfiniteSprintOverride;
-new Handle:g_cvPlayerInfiniteFlashlightOverride;
-new Handle:g_cvPlayerInfiniteBlinkOverride;
-
-new Handle:g_cvGravity;
-new Float:g_flGravity;
-
-new Handle:g_cvMaxRounds;
-
-new bool:g_b20Dollars;
-
-new bool:g_bPlayerShakeEnabled;
-new bool:g_bPlayerViewbobEnabled;
-new bool:g_bPlayerViewbobHurtEnabled;
-new bool:g_bPlayerViewbobSprintEnabled;
-
-new Handle:g_hHudSync;
-new Handle:g_hHudSync2;
-new Handle:g_hRoundTimerSync;
-
-new Handle:g_hCookie;
-
-// Global forwards.
-new Handle:fOnBossAdded;
-new Handle:fOnBossSpawn;
-new Handle:fOnBossChangeState;
-new Handle:fOnBossRemoved;
-new Handle:fOnPagesSpawned;
-new Handle:fOnClientBlink;
-new Handle:fOnClientCaughtByBoss;
-new Handle:fOnClientGiveQueuePoints;
-new Handle:fOnClientActivateFlashlight;
-new Handle:fOnClientDeactivateFlashlight;
-new Handle:fOnClientBreakFlashlight;
-new Handle:fOnClientEscape;
-new Handle:fOnClientLooksAtBoss;
-new Handle:fOnClientLooksAwayFromBoss;
-new Handle:fOnClientStartDeathCam;
-new Handle:fOnClientEndDeathCam;
-new Handle:fOnClientGetDefaultWalkSpeed;
-new Handle:fOnClientGetDefaultSprintSpeed;
-new Handle:fOnClientSpawnedAsProxy;
-new Handle:fOnClientDamagedByBoss;
-new Handle:fOnGroupGiveQueuePoints;
-
-new Handle:g_hSDKWeaponScattergun;
-new Handle:g_hSDKWeaponPistolScout;
-new Handle:g_hSDKWeaponBat;
-new Handle:g_hSDKWeaponSniperRifle;
-new Handle:g_hSDKWeaponSMG;
-new Handle:g_hSDKWeaponKukri;
-new Handle:g_hSDKWeaponRocketLauncher;
-new Handle:g_hSDKWeaponShotgunSoldier;
-new Handle:g_hSDKWeaponShovel;
-new Handle:g_hSDKWeaponGrenadeLauncher;
-new Handle:g_hSDKWeaponStickyLauncher;
-new Handle:g_hSDKWeaponBottle;
-new Handle:g_hSDKWeaponMinigun;
-new Handle:g_hSDKWeaponShotgunHeavy;
-new Handle:g_hSDKWeaponFists;
-new Handle:g_hSDKWeaponSyringeGun;
-new Handle:g_hSDKWeaponMedigun;
-new Handle:g_hSDKWeaponBonesaw;
-new Handle:g_hSDKWeaponFlamethrower;
-new Handle:g_hSDKWeaponShotgunPyro;
-new Handle:g_hSDKWeaponFireaxe;
-new Handle:g_hSDKWeaponRevolver;
-new Handle:g_hSDKWeaponKnife;
-new Handle:g_hSDKWeaponInvis;
-new Handle:g_hSDKWeaponShotgunPrimary;
-new Handle:g_hSDKWeaponPistol;
-new Handle:g_hSDKWeaponWrench;
-
-new Handle:g_hSDKGetMaxHealth;
-new Handle:g_hSDKWantsLagCompensationOnEntity;
-new Handle:g_hSDKShouldTransmit;
-
-#include "rytp_horror/stocks.sp"
-#include "rytp_horror/overlay.sp"
-#include "rytp_horror/logging.sp"
-#include "rytp_horror/debug.sp"
-#include "rytp_horror/profiles.sp"
-#include "rytp_horror/nav.sp"
-#include "rytp_horror/effects.sp"
-#include "rytp_horror/playergroups.sp"
-#include "rytp_horror/menus.sp"
-#include "rytp_horror/pvp.sp"
-#include "rytp_horror/client.sp"
-#include "rytp_horror/npc.sp"
-#include "rytp_horror/specialround.sp"
-#include "rytp_horror/adminmenu.sp"
-
-
-#define SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND "ui/item_acquired.wav"
-
-//	==========================================================
-//	GENERAL PLUGIN HOOK FUNCTIONS
-//	==========================================================
-
-public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
-{
-	RegPluginLibrary("sf2");
-	
-	fOnBossAdded = CreateGlobalForward("SF2_OnBossAdded", ET_Ignore, Param_Cell);
-	fOnBossSpawn = CreateGlobalForward("SF2_OnBossSpawn", ET_Ignore, Param_Cell);
-	fOnBossChangeState = CreateGlobalForward("SF2_OnBossChangeState", ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
-	fOnBossRemoved = CreateGlobalForward("SF2_OnBossRemoved", ET_Ignore, Param_Cell);
-	fOnPagesSpawned = CreateGlobalForward("SF2_OnPagesSpawned", ET_Ignore);
-	fOnClientBlink = CreateGlobalForward("SF2_OnClientBlink", ET_Ignore, Param_Cell);
-	fOnClientCaughtByBoss = CreateGlobalForward("SF2_OnClientCaughtByBoss", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientGiveQueuePoints = CreateGlobalForward("SF2_OnClientGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
-	fOnClientActivateFlashlight = CreateGlobalForward("SF2_OnClientActivateFlashlight", ET_Ignore, Param_Cell);
-	fOnClientDeactivateFlashlight = CreateGlobalForward("SF2_OnClientDeactivateFlashlight", ET_Ignore, Param_Cell);
-	fOnClientBreakFlashlight = CreateGlobalForward("SF2_OnClientBreakFlashlight", ET_Ignore, Param_Cell);
-	fOnClientEscape = CreateGlobalForward("SF2_OnClientEscape", ET_Ignore, Param_Cell);
-	fOnClientLooksAtBoss = CreateGlobalForward("SF2_OnClientLooksAtBoss", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientLooksAwayFromBoss = CreateGlobalForward("SF2_OnClientLooksAwayFromBoss", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientStartDeathCam = CreateGlobalForward("SF2_OnClientStartDeathCam", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientEndDeathCam = CreateGlobalForward("SF2_OnClientEndDeathCam", ET_Ignore, Param_Cell, Param_Cell);
-	fOnClientGetDefaultWalkSpeed = CreateGlobalForward("SF2_OnClientGetDefaultWalkSpeed", ET_Hook, Param_Cell, Param_CellByRef);
-	fOnClientGetDefaultSprintSpeed = CreateGlobalForward("SF2_OnClientGetDefaultSprintSpeed", ET_Hook, Param_Cell, Param_CellByRef);
-	fOnClientSpawnedAsProxy = CreateGlobalForward("SF2_OnClientSpawnedAsProxy", ET_Ignore, Param_Cell);
-	fOnClientDamagedByBoss = CreateGlobalForward("SF2_OnClientDamagedByBoss", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell);
-	fOnGroupGiveQueuePoints = CreateGlobalForward("SF2_OnGroupGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
-	
-	CreateNative("SF2_IsRunning", Native_IsRunning);
-	CreateNative("SF2_GetCurrentDifficulty", Native_GetCurrentDifficulty);
-	CreateNative("SF2_GetDifficultyModifier", Native_GetDifficultyModifier);
-	CreateNative("SF2_IsClientEliminated", Native_IsClientEliminated);
-	CreateNative("SF2_IsClientInGhostMode", Native_IsClientInGhostMode);
-	CreateNative("SF2_IsClientProxy", Native_IsClientProxy);
-	CreateNative("SF2_GetClientBlinkCount", Native_GetClientBlinkCount);
-	CreateNative("SF2_GetClientProxyMaster", Native_GetClientProxyMaster);
-	CreateNative("SF2_GetClientProxyControlAmount", Native_GetClientProxyControlAmount);
-	CreateNative("SF2_GetClientProxyControlRate", Native_GetClientProxyControlRate);
-	CreateNative("SF2_SetClientProxyMaster", Native_SetClientProxyMaster);
-	CreateNative("SF2_SetClientProxyControlAmount", Native_SetClientProxyControlAmount);
-	CreateNative("SF2_SetClientProxyControlRate", Native_SetClientProxyControlRate);
-	CreateNative("SF2_IsClientLookingAtBoss", Native_IsClientLookingAtBoss);
-	CreateNative("SF2_CollectAsPage", Native_CollectAsPage);
-	CreateNative("SF2_GetMaxBossCount", Native_GetMaxBosses);
-	CreateNative("SF2_EntIndexToBossIndex", Native_EntIndexToBossIndex);
-	CreateNative("SF2_BossIndexToEntIndex", Native_BossIndexToEntIndex);
-	CreateNative("SF2_BossIDToBossIndex", Native_BossIDToBossIndex);
-	CreateNative("SF2_BossIndexToBossID", Native_BossIndexToBossID);
-	CreateNative("SF2_GetBossName", Native_GetBossName);
-	CreateNative("SF2_GetBossModelEntity", Native_GetBossModelEntity);
-	CreateNative("SF2_GetBossTarget", Native_GetBossTarget);
-	CreateNative("SF2_GetBossMaster", Native_GetBossMaster);
-	CreateNative("SF2_GetBossState", Native_GetBossState);
-	CreateNative("SF2_IsBossProfileValid", Native_IsBossProfileValid);
-	CreateNative("SF2_GetBossProfileNum", Native_GetBossProfileNum);
-	CreateNative("SF2_GetBossProfileFloat", Native_GetBossProfileFloat);
-	CreateNative("SF2_GetBossProfileString", Native_GetBossProfileString);
-	CreateNative("SF2_GetBossProfileVector", Native_GetBossProfileVector);
-	CreateNative("SF2_GetRandomStringFromBossProfile", Native_GetRandomStringFromBossProfile);
-	
-	PvP_InitializeAPI();
-	
-	SpecialRoundInitializeAPI();
-	
-	return APLRes_Success;
-}
-
-public OnPluginStart()
-{
-	LoadTranslations("core.phrases");
-	LoadTranslations("common.phrases");
-	LoadTranslations("sf2.phrases");
-	
-	// Get offsets.
-	g_offsPlayerFOV = FindSendPropInfo("CBasePlayer", "m_iFOV");
-	if (g_offsPlayerFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iFOV.");
-	
-	g_offsPlayerDefaultFOV = FindSendPropInfo("CBasePlayer", "m_iDefaultFOV");
-	if (g_offsPlayerDefaultFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iDefaultFOV.");
-	
-	g_offsPlayerFogCtrl = FindSendPropInfo("CBasePlayer", "m_PlayerFog.m_hCtrl");
-	if (g_offsPlayerFogCtrl == -1) LogError("Couldn't find CBasePlayer offset for m_PlayerFog.m_hCtrl!");
-	
-	g_offsPlayerPunchAngle = FindSendPropInfo("CBasePlayer", "m_vecPunchAngle");
-	if (g_offsPlayerPunchAngle == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngle!");
-	
-	g_offsPlayerPunchAngleVel = FindSendPropInfo("CBasePlayer", "m_vecPunchAngleVel");
-	if (g_offsPlayerPunchAngleVel == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngleVel!");
-	
-	g_offsFogCtrlEnable = FindSendPropInfo("CFogController", "m_fog.enable");
-	if (g_offsFogCtrlEnable == -1) LogError("Couldn't find CFogController offset for m_fog.enable!");
-	
-	g_offsFogCtrlEnd = FindSendPropInfo("CFogController", "m_fog.end");
-	if (g_offsFogCtrlEnd == -1) LogError("Couldn't find CFogController offset for m_fog.end!");
-	
-	g_hPageMusicRanges = CreateArray(3);
-	
-	// Register console variables.
-	g_cvVersion = CreateConVar("sf2_version", PLUGIN_VERSION, "The current version of Slender Fortress. DO NOT TOUCH!", FCVAR_SPONLY | FCVAR_NOTIFY | FCVAR_DONTRECORD);
-	SetConVarString(g_cvVersion, PLUGIN_VERSION);
-	
-	g_cvEnabled = CreateConVar("sf2_enabled", "1", "Enable/Disable the Slender Fortress gamemode. This will take effect on map change.", FCVAR_NOTIFY | FCVAR_DONTRECORD);
-	g_cvSlenderMapsOnly = CreateConVar("sf2_slendermapsonly", "1", "Only enable the Slender Fortress gamemode on map names prefixed with \"slender_\" or \"sf2_\".");
-	
-	g_cvGraceTime = CreateConVar("sf2_gracetime", "30.0");
-	g_cvIntroEnabled = CreateConVar("sf2_intro_enabled", "1");
-	g_cvIntroDefaultHoldTime = CreateConVar("sf2_intro_default_hold_time", "9.0");
-	g_cvIntroDefaultFadeTime = CreateConVar("sf2_intro_default_fade_time", "1.0");
-	
-	g_cvBlockSuicideDuringRound = CreateConVar("sf2_block_suicide_during_round", "0");
-	
-	g_cvAllChat = CreateConVar("sf2_alltalk", "0");
-	HookConVarChange(g_cvAllChat, OnConVarChanged);
-	
-	g_cvPlayerVoiceDistance = CreateConVar("sf2_player_voice_distance", "800.0", "The maximum distance RED can communicate in voice chat. Set to 0 if you want them to be heard at all times.", _, true, 0.0);
-	g_cvPlayerVoiceWallScale = CreateConVar("sf2_player_voice_scale_blocked", "0.5", "The distance required to hear RED in voice chat will be multiplied by this amount if something is blocking them.");
-	
-	g_cvPlayerViewbobEnabled = CreateConVar("sf2_player_viewbob_enabled", "1", "Enable/Disable player viewbobbing.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerViewbobEnabled, OnConVarChanged);
-	g_cvPlayerViewbobHurtEnabled = CreateConVar("sf2_player_viewbob_hurt_enabled", "0", "Enable/Disable player view tilting when hurt.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerViewbobHurtEnabled, OnConVarChanged);
-	g_cvPlayerViewbobSprintEnabled = CreateConVar("sf2_player_viewbob_sprint_enabled", "0", "Enable/Disable player step viewbobbing when sprinting.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerViewbobSprintEnabled, OnConVarChanged);
-	g_cvGravity = FindConVar("sv_gravity");
-	HookConVarChange(g_cvGravity, OnConVarChanged);
-	
-	g_cvPlayerFakeLagCompensation = CreateConVar("sf2_player_fakelagcompensation", "0", "(EXPERIMENTAL) Enable/Disable fake lag compensation for some hitscan weapons such as the Sniper Rifle.", _, true, 0.0, true, 1.0);
-	
-	g_cvPlayerShakeEnabled = CreateConVar("sf2_player_shake_enabled", "1", "Enable/Disable player view shake during boss encounters.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cvPlayerShakeEnabled, OnConVarChanged);
-	g_cvPlayerShakeFrequencyMax = CreateConVar("sf2_player_shake_frequency_max", "255", "Maximum frequency value of the shake. Should be a value between 1-255.", _, true, 1.0, true, 255.0);
-	g_cvPlayerShakeAmplitudeMax = CreateConVar("sf2_player_shake_amplitude_max", "5", "Maximum amplitude value of the shake. Should be a value between 1-16.", _, true, 1.0, true, 16.0);
-	
-	g_cvPlayerBlinkRate = CreateConVar("sf2_player_blink_rate", "0.33", "How long (in seconds) each bar on the player's Blink meter lasts.", _, true, 0.0);
-	g_cvPlayerBlinkHoldTime = CreateConVar("sf2_player_blink_holdtime", "0.15", "How long (in seconds) a player will stay in Blink mode when he or she blinks.", _, true, 0.0);
-	
-	g_cvUltravisionEnabled = CreateConVar("sf2_player_ultravision_enabled", "1", "Enable/Disable player Ultravision. This helps players see in the dark when their Flashlight is off or unavailable.", _, true, 0.0, true, 1.0);
-	g_cvUltravisionRadiusRed = CreateConVar("sf2_player_ultravision_radius_red", "512.0");
-	g_cvUltravisionRadiusBlue = CreateConVar("sf2_player_ultravision_radius_blue", "800.0");
-	g_cvUltravisionBrightness = CreateConVar("sf2_player_ultravision_brightness", "-4");
-	
-	g_cvGhostModeConnectionCheck = CreateConVar("sf2_ghostmode_check_connection", "1", "Checks a player's connection while in Ghost Mode. If the check fails, the client is booted out of Ghost Mode and the action and client's SteamID is logged in the main SF2 log.");
-	g_cvGhostModeConnectionTolerance = CreateConVar("sf2_ghostmode_connection_tolerance", "5.0", "If sf2_ghostmode_check_connection is set to 1 and the client has timed out for at least this amount of time, the client will be booted out of Ghost Mode.");
-	
-	g_cv20Dollars = CreateConVar("sf2_20dollarmode", "0", "Enable/Disable $20 mode.", _, true, 0.0, true, 1.0);
-	HookConVarChange(g_cv20Dollars, OnConVarChanged);
-	
-	g_cvMaxPlayers = CreateConVar("sf2_maxplayers", "5", "The maximum amount of players that can be in one round.", _, true, 1.0);
-	HookConVarChange(g_cvMaxPlayers, OnConVarChanged);
-	
-	g_cvMaxPlayersOverride = CreateConVar("sf2_maxplayers_override", "-1", "Overrides the maximum amount of players that can be in one round.", _, true, -1.0);
-	HookConVarChange(g_cvMaxPlayersOverride, OnConVarChanged);
-	
-	g_cvCampingEnabled = CreateConVar("sf2_anticamping_enabled", "1", "Enable/Disable anti-camping system for RED.", _, true, 0.0, true, 1.0);
-	g_cvCampingMaxStrikes = CreateConVar("sf2_anticamping_maxstrikes", "4", "How many 5-second intervals players are allowed to stay in one spot before he/she is forced to suicide.", _, true, 0.0);
-	g_cvCampingStrikesWarn = CreateConVar("sf2_anticamping_strikeswarn", "2", "The amount of strikes left where the player will be warned of camping.");
-	g_cvCampingMinDistance = CreateConVar("sf2_anticamping_mindistance", "128.0", "Every 5 seconds the player has to be at least this far away from his last position 5 seconds ago or else he'll get a strike.");
-	g_cvCampingNoStrikeSanity = CreateConVar("sf2_anticamping_no_strike_sanity", "0.1", "The camping system will NOT give any strikes under any circumstances if the players's Sanity is missing at least this much of his maximum Sanity (max is 1.0).");
-	g_cvCampingNoStrikeBossDistance = CreateConVar("sf2_anticamping_no_strike_boss_distance", "512.0", "The camping system will NOT give any strikes under any circumstances if the player is this close to a boss (ignoring LOS).");
-	g_cvBossMain = CreateConVar("sf2_boss_main", "slenderman", "The name of the main boss (its profile name, not its display name)");
-	g_cvBossProfileOverride = CreateConVar("sf2_boss_profile_override", "", "Overrides which boss will be chosen next. Only applies to the first boss being chosen.");
-	g_cvDifficulty = CreateConVar("sf2_difficulty", "1", "Difficulty of the game. 1 = Normal, 2 = Hard, 3 = Insane.", _, true, 1.0, true, 3.0);
-	HookConVarChange(g_cvDifficulty, OnConVarChanged);
-	
-	g_cvSpecialRoundBehavior = CreateConVar("sf2_specialround_mode", "0", "0 = Special Round resets on next round, 1 = Special Round keeps going until all players have played (not counting spectators, recently joined players, and those who reset their queue points during the round)", _, true, 0.0, true, 1.0);
-	g_cvSpecialRoundForce = CreateConVar("sf2_specialround_forceenable", "-1", "Sets whether a Special Round will occur on the next round or not.", _, true, -1.0, true, 1.0);
-	g_cvSpecialRoundOverride = CreateConVar("sf2_specialround_forcetype", "-1", "Sets the type of Special Round that will be chosen on the next Special Round. Set to -1 to let the game choose.", _, true, -1.0);
-	g_cvSpecialRoundInterval = CreateConVar("sf2_specialround_interval", "5", "If this many rounds are completed, the next round will be a Special Round.", _, true, 0.0);
-	
-	g_cvNewBossRoundBehavior = CreateConVar("sf2_newbossround_mode", "0", "0 = boss selection will return to normal after the boss round, 1 = the new boss will continue being the boss until all players in the server have played against it (not counting spectators, recently joined players, and those who reset their queue points during the round).", _, true, 0.0, true, 1.0);
-	g_cvNewBossRoundInterval = CreateConVar("sf2_newbossround_interval", "3", "If this many rounds are completed, the next round's boss will be randomly chosen, but will not be the main boss.", _, true, 0.0);
-	g_cvNewBossRoundForce = CreateConVar("sf2_newbossround_forceenable", "-1", "Sets whether a new boss will be chosen on the next round or not. Set to -1 to let the game choose.", _, true, -1.0, true, 1.0);
-	
-	g_cvTimeLimit = CreateConVar("sf2_timelimit_default", "300", "The time limit of the round. Maps can change the time limit.", _, true, 0.0);
-	g_cvTimeLimitEscape = CreateConVar("sf2_timelimit_escape_default", "90", "The time limit to escape. Maps can change the time limit.", _, true, 0.0);
-	g_cvTimeGainFromPageGrab = CreateConVar("sf2_time_gain_page_grab", "12", "The time gained from grabbing a page. Maps can change the time gain amount.");
-	
-	g_cvWarmupRound = CreateConVar("sf2_warmupround", "1", "Enables/disables Warmup Rounds after the \"Waiting for Players\" phase.", _, true, 0.0, true, 1.0);
-	g_cvWarmupRoundNum = CreateConVar("sf2_warmupround_num", "1", "Sets the amount of Warmup Rounds that occur after the \"Waiting for Players\" phase.", _, true, 0.0);
-	
-	g_cvPlayerProxyWaitTime = CreateConVar("sf2_player_proxy_waittime", "35", "How long (in seconds) after a player was chosen to be a Proxy must the system wait before choosing him again.");
-	g_cvPlayerProxyAsk = CreateConVar("sf2_player_proxy_ask", "0", "Set to 1 if the player can choose before becoming a Proxy, set to 0 to force.");
-	
-	g_cvHalfZatoichiHealthGain = CreateConVar("sf2_halfzatoichi_healthgain", "20", "How much health should be gained from killing a player with the Half-Zatoichi? Set to -1 for default behavior.");
-	
-	g_cvPlayerInfiniteSprintOverride = CreateConVar("sf2_player_infinite_sprint_override", "-1", "1 = infinite sprint, 0 = never have infinite sprint, -1 = let the game choose.", _, true, -1.0, true, 1.0);
-	g_cvPlayerInfiniteFlashlightOverride = CreateConVar("sf2_player_infinite_flashlight_override", "-1", "1 = infinite flashlight, 0 = never have infinite flashlight, -1 = let the game choose.", _, true, -1.0, true, 1.0);
-	g_cvPlayerInfiniteBlinkOverride = CreateConVar("sf2_player_infinite_blink_override", "-1", "1 = infinite blink, 0 = never have infinite blink, -1 = let the game choose.", _, true, -1.0, true, 1.0);
-	
-	g_cvMaxRounds = FindConVar("mp_maxrounds");
-	
-	g_hHudSync = CreateHudSynchronizer();
-	g_hHudSync2 = CreateHudSynchronizer();
-	g_hRoundTimerSync = CreateHudSynchronizer();
-	g_hCookie = RegClientCookie("slender_cookie", "", CookieAccess_Private);
-	
-	// Register console commands.
-	RegConsoleCmd("sm_sf2", Command_MainMenu);
-	RegConsoleCmd("sm_slender", Command_MainMenu);
-	RegConsoleCmd("sm_horror", Command_MainMenu);
-	RegConsoleCmd("sm_slnext", Command_Next);
-	RegConsoleCmd("sm_slgroup", Command_Group);
-	RegConsoleCmd("sm_slgroupname", Command_GroupName);
-	RegConsoleCmd("sm_slghost", Command_GhostMode);
-	RegConsoleCmd("sm_slhelp", Command_Help);
-	RegConsoleCmd("sm_slsettings", Command_Settings);
-	RegConsoleCmd("sm_slcredits", Command_Credits);
-	RegConsoleCmd("sm_flashlight", Command_ToggleFlashlight);
-	RegConsoleCmd("+sprint", Command_SprintOn);
-	RegConsoleCmd("-sprint", Command_SprintOff);
-	
-	RegAdminCmd("sm_sf2_scare", Command_ClientPerformScare, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_spawn_boss", Command_SpawnSlender, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_add_boss", Command_AddSlender, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_add_boss_fake", Command_AddSlenderFake, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_remove_boss", Command_RemoveSlender, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_getbossindexes", Command_GetBossIndexes, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_setplaystate", Command_ForceState, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_boss_attack_waiters", Command_SlenderAttackWaiters, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_boss_no_teleport", Command_SlenderNoTeleport, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_force_proxy", Command_ForceProxy, ADMFLAG_SLAY);
-	RegAdminCmd("sm_sf2_force_escape", Command_ForceEscape, ADMFLAG_CHEATS);
-	
-	// Hook onto existing console commands.
-	AddCommandListener(Hook_CommandBuild, "build");
-	AddCommandListener(Hook_CommandSuicideAttempt, "kill");
-	AddCommandListener(Hook_CommandSuicideAttempt, "explode");
-	AddCommandListener(Hook_CommandSuicideAttempt, "joinclass");
-	AddCommandListener(Hook_CommandSuicideAttempt, "join_class");
-	AddCommandListener(Hook_CommandSuicideAttempt, "jointeam");
-	AddCommandListener(Hook_CommandSuicideAttempt, "spectate");
-	AddCommandListener(Hook_CommandVoiceMenu, "voicemenu");
-	AddCommandListener(Hook_CommandSay, "say");
-	
-	// Hook events.
-	HookEvent("teamplay_round_start", Event_RoundStart);
-	HookEvent("teamplay_round_win", Event_RoundEnd);
-	HookEvent("player_team", Event_DontBroadcastToClients, EventHookMode_Pre);
-	HookEvent("player_team", Event_PlayerTeam);
-	HookEvent("player_spawn", Event_PlayerSpawn);
-	HookEvent("player_hurt", Event_PlayerHurt);
-	HookEvent("post_inventory_application", Event_PostInventoryApplication);
-	HookEvent("item_found", Event_DontBroadcastToClients, EventHookMode_Pre);
-	HookEvent("teamplay_teambalanced_player", Event_DontBroadcastToClients, EventHookMode_Pre);
-	HookEvent("fish_notice", Event_PlayerDeathPre, EventHookMode_Pre);
-	HookEvent("fish_notice__arm", Event_PlayerDeathPre, EventHookMode_Pre);
-	HookEvent("player_death", Event_PlayerDeathPre, EventHookMode_Pre);
-	HookEvent("player_death", Event_PlayerDeath);
-	
-	// Hook entities.
-	HookEntityOutput("trigger_multiple", "OnStartTouch", Hook_TriggerOnStartTouch);
-	HookEntityOutput("trigger_multiple", "OnEndTouch", Hook_TriggerOnEndTouch);
-	
-	// Hook usermessages.
-	HookUserMessage(GetUserMessageId("VoiceSubtitle"), Hook_BlockUserMessage, true);
-	
-	// Hook sounds.
-	AddNormalSoundHook(Hook_NormalSound);
-	
-	AddTempEntHook("Fire Bullets", Hook_TEFireBullets);
-	
-	InitializeBossProfiles();
-	
-	NPCInitialize();
-	
-	SetupMenus();
-	
-	SetupAdminMenu();
-	
-	SetupClassDefaultWeapons();
-	
-	SetupPlayerGroups();
-	
-	PvP_Initialize();
-	
-	// @TODO: When cvars are finalized, set this to true.
-	AutoExecConfig(false);
-	
-#if defined DEBUG
-	InitializeDebug();
-#endif
-}
-
-public OnAllPluginsLoaded()
-{
-	SetupHooks();
-}
-
-public OnPluginEnd()
-{
-	StopPlugin();
-}
-
-static SetupHooks()
-{
-	// Check SDKHooks gamedata.
-	new Handle:hConfig = LoadGameConfigFile("sdkhooks.games");
-	if (hConfig == INVALID_HANDLE) SetFailState("Couldn't find SDKHooks gamedata!");
-	
-	StartPrepSDKCall(SDKCall_Entity);
-	PrepSDKCall_SetFromConf(hConfig, SDKConf_Virtual, "GetMaxHealth");
-	PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
-	if ((g_hSDKGetMaxHealth = EndPrepSDKCall()) == INVALID_HANDLE)
-	{
-		SetFailState("Failed to retrieve GetMaxHealth offset from SDKHooks gamedata!");
-	}
-	
-	CloseHandle(hConfig);
-	
-	// Check our own gamedata.
-	hConfig = LoadGameConfigFile("sf2");
-	if (hConfig == INVALID_HANDLE) SetFailState("Could not find SF2 gamedata!");
-	
-	new iOffset = GameConfGetOffset(hConfig, "CTFPlayer::WantsLagCompensationOnEntity"); 
-	g_hSDKWantsLagCompensationOnEntity = DHookCreate(iOffset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_ClientWantsLagCompensationOnEntity); 
-	if (g_hSDKWantsLagCompensationOnEntity == INVALID_HANDLE)
-	{
-		SetFailState("Failed to create hook CTFPlayer::WantsLagCompensationOnEntity offset from SF2 gamedata!");
-	}
-	
-	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_CBaseEntity);
-	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_ObjectPtr);
-	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_Unknown);
-	
-	iOffset = GameConfGetOffset(hConfig, "CBaseEntity::ShouldTransmit");
-	g_hSDKShouldTransmit = DHookCreate(iOffset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, Hook_EntityShouldTransmit);
-	if (g_hSDKShouldTransmit == INVALID_HANDLE)
-	{
-		SetFailState("Failed to create hook CBaseEntity::ShouldTransmit offset from SF2 gamedata!");
-	}
-	
-	DHookAddParam(g_hSDKShouldTransmit, HookParamType_ObjectPtr);
-	
-	CloseHandle(hConfig);
-}
-
-static SetupClassDefaultWeapons()
-{
-	// Scout
-	g_hSDKWeaponScattergun = PrepareItemHandle("tf_weapon_scattergun", 13, 0, 0, "");
-	g_hSDKWeaponPistolScout = PrepareItemHandle("tf_weapon_pistol", 23, 0, 0, "");
-	g_hSDKWeaponBat = PrepareItemHandle("tf_weapon_bat", 0, 0, 0, "");
-	
-	// Sniper
-	g_hSDKWeaponSniperRifle = PrepareItemHandle("tf_weapon_sniperrifle", 14, 0, 0, "");
-	g_hSDKWeaponSMG = PrepareItemHandle("tf_weapon_smg", 16, 0, 0, "");
-	g_hSDKWeaponKukri = PrepareItemHandle("tf_weapon_club", 3, 0, 0, "");
-	
-	// Soldier
-	g_hSDKWeaponRocketLauncher = PrepareItemHandle("tf_weapon_rocketlauncher", 18, 0, 0, "");
-	g_hSDKWeaponShotgunSoldier = PrepareItemHandle("tf_weapon_shotgun", 10, 0, 0, "");
-	g_hSDKWeaponShovel = PrepareItemHandle("tf_weapon_shovel", 6, 0, 0, "");
-	
-	// Demoman
-	g_hSDKWeaponGrenadeLauncher = PrepareItemHandle("tf_weapon_grenadelauncher", 19, 0, 0, "");
-	g_hSDKWeaponStickyLauncher = PrepareItemHandle("tf_weapon_pipebomblauncher", 20, 0, 0, "");
-	g_hSDKWeaponBottle = PrepareItemHandle("tf_weapon_bottle", 1, 0, 0, "");
-	
-	// Heavy
-	g_hSDKWeaponMinigun = PrepareItemHandle("tf_weapon_minigun", 15, 0, 0, "");
-	g_hSDKWeaponShotgunHeavy = PrepareItemHandle("tf_weapon_shotgun", 11, 0, 0, "");
-	g_hSDKWeaponFists = PrepareItemHandle("tf_weapon_fists", 5, 0, 0, "");
-	
-	// Medic
-	g_hSDKWeaponSyringeGun = PrepareItemHandle("tf_weapon_syringegun_medic", 17, 0, 0, "");
-	g_hSDKWeaponMedigun = PrepareItemHandle("tf_weapon_medigun", 29, 0, 0, "");
-	g_hSDKWeaponBonesaw = PrepareItemHandle("tf_weapon_bonesaw", 8, 0, 0, "");
-	
-	// Pyro
-	g_hSDKWeaponFlamethrower = PrepareItemHandle("tf_weapon_flamethrower", 21, 0, 0, "254 ; 4.0");
-	g_hSDKWeaponShotgunPyro = PrepareItemHandle("tf_weapon_shotgun", 12, 0, 0, "");
-	g_hSDKWeaponFireaxe = PrepareItemHandle("tf_weapon_fireaxe", 2, 0, 0, "");
-	
-	// Spy
-	g_hSDKWeaponRevolver = PrepareItemHandle("tf_weapon_revolver", 24, 0, 0, "");
-	g_hSDKWeaponKnife = PrepareItemHandle("tf_weapon_knife", 4, 0, 0, "");
-	g_hSDKWeaponInvis = PrepareItemHandle("tf_weapon_invis", 297, 0, 0, "");
-	
-	// Engineer
-	g_hSDKWeaponShotgunPrimary = PrepareItemHandle("tf_weapon_shotgun", 9, 0, 0, "");
-	g_hSDKWeaponPistol = PrepareItemHandle("tf_weapon_pistol", 22, 0, 0, "");
-	g_hSDKWeaponWrench = PrepareItemHandle("tf_weapon_wrench", 7, 0, 0, "");
-}
-
-public OnMapStart()
-{
-	PvP_OnMapStart();
-}
-
-public OnConfigsExecuted()
-{
-	if (!GetConVarBool(g_cvEnabled))
-	{
-		StopPlugin();
-	}
-	else
-	{
-		if (GetConVarBool(g_cvSlenderMapsOnly))
-		{
-			decl String:sMap[256];
-			GetCurrentMap(sMap, sizeof(sMap));
-			
-			if (!StrContains(sMap, "slender_", false) || !StrContains(sMap, "sf2_", false))
-			{
-				StartPlugin();
-			}
-			else
-			{
-				LogMessage("%s is not a Slender Fortress map. Plugin disabled!", sMap);
-				StopPlugin();
-			}
-		}
-		else
-		{
-			StartPlugin();
-		}
-	}
-}
-
-static StartPlugin()
-{
-	if (g_bEnabled) return;
-	
-	g_bEnabled = true;
-	
-	InitializeLogging();
-	
-#if defined DEBUG
-	InitializeDebugLogging();
-#endif
-	
-	// Handle ConVars.
-	new Handle:hCvar = FindConVar("mp_friendlyfire");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
-	
-	hCvar = FindConVar("mp_flashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
-	
-	hCvar = FindConVar("mat_supportflashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
-	
-	hCvar = FindConVar("mp_autoteambalance");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	g_flGravity = GetConVarFloat(g_cvGravity);
-	
-	g_b20Dollars = GetConVarBool(g_cv20Dollars);
-	
-	g_bPlayerShakeEnabled = GetConVarBool(g_cvPlayerShakeEnabled);
-	g_bPlayerViewbobEnabled = GetConVarBool(g_cvPlayerViewbobEnabled);
-	g_bPlayerViewbobHurtEnabled = GetConVarBool(g_cvPlayerViewbobHurtEnabled);
-	g_bPlayerViewbobSprintEnabled = GetConVarBool(g_cvPlayerViewbobSprintEnabled);
-	
-	decl String:sBuffer[64];
-	Format(sBuffer, sizeof(sBuffer), "RYTP Horror", PLUGIN_VERSION_DISPLAY);
-	Steam_SetGameDescription(sBuffer);
-	
-	PrecacheStuff();
-	
-	// Reset special round.
-	g_bSpecialRound = false;
-	g_bSpecialRoundNew = false;
-	g_bSpecialRoundContinuous = false;
-	g_iSpecialRoundCount = 1;
-	g_iSpecialRoundType = 0;
-	
-	SpecialRoundReset();
-	
-	// Reset boss rounds.
-	g_bNewBossRound = false;
-	g_bNewBossRoundNew = false;
-	g_bNewBossRoundContinuous = false;
-	g_iNewBossRoundCount = 1;
-	strcopy(g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile), "");
-	
-	// Reset global round vars.
-	g_iRoundCount = 0;
-	g_iRoundEndCount = 0;
-	g_iRoundActiveCount = 0;
-	g_iRoundState = SF2RoundState_Invalid;
-	g_hRoundMessagesTimer = CreateTimer(200.0, Timer_RoundMessages, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	g_iRoundMessagesNum = 0;
-	
-	g_iRoundWarmupRoundCount = 0;
-	
-	g_hClientAverageUpdateTimer = CreateTimer(0.2, Timer_ClientAverageUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	g_hBossCountUpdateTimer = CreateTimer(2.0, Timer_BossCountUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	
-	SetRoundState(SF2RoundState_Waiting);
-	
-	ReloadBossProfiles();
-	ReloadRestrictedWeapons();
-	ReloadSpecialRounds();
-	
-	NPCOnConfigsExecuted();
-	
-	InitializeBossPackVotes();
-	SetupTimeLimitTimerForBossPackVote();
-	
-	// Late load compensation.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		OnClientPutInServer(i);
-	}
-}
-
-static PrecacheStuff()
-{
-	// Initialize particles.
-	g_iParticleCriticalHit = PrecacheParticleSystem(CRIT_PARTICLENAME);
-	
-	PrecacheSound2(CRIT_SOUND);
-	
-	// simple_bot;
-	PrecacheModel("models/humans/group01/female_01.mdl", true);
-	
-	PrecacheModel(PAGE_MODEL, true);
-	PrecacheModel(GHOST_MODEL, true);
-	
-	PrecacheSound2(FLASHLIGHT_CLICKSOUND);
-	PrecacheSound2(FLASHLIGHT_BREAKSOUND);
-	PrecacheSound2(FLASHLIGHT_NOSOUND);
-	PrecacheSound2(PAGE_GRABSOUND);
-	
-	PrecacheSound2(MUSIC_GOTPAGES1_SOUND);
-	PrecacheSound2(MUSIC_GOTPAGES2_SOUND);
-	PrecacheSound2(MUSIC_GOTPAGES3_SOUND);
-	PrecacheSound2(MUSIC_GOTPAGES4_SOUND);
-	
-	PrecacheSound2(SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
-	
-	for (new i = 0; i < sizeof(g_strPlayerBreathSounds); i++)
-	{
-		PrecacheSound2(g_strPlayerBreathSounds[i]);
-	}
-	
-	// Special round.
-	PrecacheSound2(SR_MUSIC);
-	PrecacheSound2(SR_SOUND_SELECT);
-	PrecacheSound2(SF2_INTRO_DEFAULT_MUSIC);
-	
-	PrecacheMaterial2(SF2_OVERLAY_DEFAULT);
-	PrecacheMaterial2(SF2_OVERLAY_DEFAULT_NO_FILMGRAIN);
-	PrecacheMaterial2(SF2_OVERLAY_GHOST);
-	
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.mdl");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx80.vtx");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx90.vtx");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.phy");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.sw.vtx");
-	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.vvd");
-	
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vmt");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vtf");
-	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vmt");
-	
-	// pvp
-	PvP_Precache();
-}
-
-static StopPlugin()
-{
-	if (!g_bEnabled) return;
-	
-	g_bEnabled = false;
-	
-	// Reset CVars.
-	new Handle:hCvar = FindConVar("mp_friendlyfire");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	hCvar = FindConVar("mp_flashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	hCvar = FindConVar("mat_supportflashlight");
-	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
-	
-	// Cleanup bosses.
-	NPCRemoveAll();
-	
-	// Cleanup clients.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		ClientResetFlashlight(i);
-		ClientDeactivateUltravision(i);
-		ClientDisableConstantGlow(i);
-		ClientRemoveInteractiveGlow(i);
-	}
-	
-	BossProfilesOnMapEnd();
-}
-
-public OnMapEnd()
-{
-	StopPlugin();
-}
-
-public OnMapTimeLeftChanged()
-{
-	if (g_bEnabled)
-	{
-		SetupTimeLimitTimerForBossPackVote();
-	}
-}
-
-public TF2_OnConditionAdded(client, TFCond:cond)
-{
-	if (cond == TFCond_Taunting)
-	{
-		if (IsClientInGhostMode(client))
-		{
-			// Stop ghosties from taunting.
-			TF2_RemoveCondition(client, TFCond_Taunting);
-		}
-	}
-}
-
-public OnGameFrame()
-{
-	if (!g_bEnabled) return;
-
-	// Process through boss movement.
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		new iBoss = NPCGetEntIndex(i);
-		if (!iBoss || iBoss == INVALID_ENT_REFERENCE) continue;
-		
-		if (NPCGetFlags(i) & SFF_MARKEDASFAKE) continue;
-		
-		new iType = NPCGetType(i);
-		
-		switch (iType)
-		{
-			case SF2BossType_Static:
-			{
-				decl Float:myPos[3], Float:hisPos[3];
-				SlenderGetAbsOrigin(i, myPos);
-				AddVectors(myPos, g_flSlenderEyePosOffset[i], myPos);
-				
-				new iBestPlayer = -1;
-				new Float:flBestDistance = 16384.0;
-				new Float:flTempDistance;
-				
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsClientInGame(iClient) || !IsPlayerAlive(iClient) || IsClientInGhostMode(iClient) || IsClientInDeathCam(iClient)) continue;
-					if (!IsPointVisibleToPlayer(iClient, myPos, false, false)) continue;
-					
-					GetClientAbsOrigin(iClient, hisPos);
-					
-					flTempDistance = GetVectorDistance(myPos, hisPos);
-					if (flTempDistance < flBestDistance)
-					{
-						iBestPlayer = iClient;
-						flBestDistance = flTempDistance;
-					}
-				}
-				
-				if (iBestPlayer > 0)
-				{
-					SlenderGetAbsOrigin(i, myPos);
-					GetClientAbsOrigin(iBestPlayer, hisPos);
-					
-					if (!SlenderOnlyLooksIfNotSeen(i) || !IsPointVisibleToAPlayer(myPos, false, SlenderUsesBlink(i)))
-					{
-						new Float:flTurnRate = NPCGetTurnRate(i);
-					
-						if (flTurnRate > 0.0)
-						{
-							decl Float:flMyEyeAng[3], Float:ang[3];
-							GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
-							AddVectors(flMyEyeAng, g_flSlenderEyeAngOffset[i], flMyEyeAng);
-							SubtractVectors(hisPos, myPos, ang);
-							GetVectorAngles(ang, ang);
-							ang[0] = 0.0;
-							ang[1] += (AngleDiff(ang[1], flMyEyeAng[1]) >= 0.0 ? 1.0 : -1.0) * flTurnRate * GetTickInterval();
-							ang[2] = 0.0;
-							
-							// Take care of angle offsets.
-							AddVectors(ang, g_flSlenderEyePosOffset[i], ang);
-							for (new i2 = 0; i2 < 3; i2++) ang[i2] = AngleNormalize(ang[i2]);
-							
-							TeleportEntity(iBoss, NULL_VECTOR, ang, NULL_VECTOR);
-						}
-					}
-				}
-			}
-			case SF2BossType_Chaser:
-			{
-				SlenderChaseBossProcessMovement(i);
-			}
-		}
-	}
-	
-	PvP_OnGameFrame();
-}
-
-//	==========================================================
-//	COMMANDS AND COMMAND HOOK FUNCTIONS
-//	==========================================================
-
-public Action:Command_Help(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayMenu(g_hMenuHelp, client, 30);
-	return Plugin_Handled;
-}
-
-public Action:Command_Settings(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayMenu(g_hMenuSettings, client, 30);
-	return Plugin_Handled;
-}
-
-public Action:Command_Credits(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayMenu(g_hMenuCredits, client, MENU_TIME_FOREVER);
-	return Plugin_Handled;
-}
-
-public Action:Command_ToggleFlashlight(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return Plugin_Handled;
-	
-	if (!IsRoundInWarmup() && !IsRoundInIntro() && !IsRoundEnding() && !DidClientEscape(client))
-	{
-		if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
-		{
-			ClientHandleFlashlight(client);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SprintOn(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
-	{
-		ClientHandleSprint(client, true);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SprintOff(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
-	{
-		ClientHandleSprint(client, false);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_MainMenu(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	DisplayMenu(g_hMenuMain, client, 30);
-	return Plugin_Handled;
-}
-
-public Action:Command_Next(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayQueuePointsMenu(client);
-	return Plugin_Handled;
-}
-
-public Action:Command_Group(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	DisplayGroupMainMenuToClient(client);
-	return Plugin_Handled;
-}
-
-public Action:Command_GroupName(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_slgroupname <name>");
-		return Plugin_Handled;
-	}
-	
-	new iGroupIndex = ClientGetPlayerGroup(client);
-	if (!IsPlayerGroupActive(iGroupIndex))
-	{
-		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
-		return Plugin_Handled;
-	}
-	
-	if (GetPlayerGroupLeader(iGroupIndex) != client)
-	{
-		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	GetCmdArg(1, sGroupName, sizeof(sGroupName));
-	if (!sGroupName[0])
-	{
-		CPrintToChat(client, "%T", "SF2 Invalid Group Name", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:sOldGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
-	GetPlayerGroupName(iGroupIndex, sOldGroupName, sizeof(sOldGroupName));
-	SetPlayerGroupName(iGroupIndex, sGroupName);
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i)) continue;
-		if (ClientGetPlayerGroup(i) != iGroupIndex) continue;
-		CPrintToChat(i, "%T", "SF2 Group Name Set", i, sOldGroupName, sGroupName);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_GhostMode(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	DisplayMenu(g_hMenuGhostMode, client, 15);
-	return Plugin_Handled;
-}
-
-public Action:Hook_CommandSay(client, const String:command[], argc)
-{
-	if (!g_bEnabled || GetConVarBool(g_cvAllChat)) return Plugin_Continue;
-	
-	if (!IsRoundEnding())
-	{
-		if (g_bPlayerEliminated[client])
-		{
-			decl String:sMessage[256];
-			GetCmdArgString(sMessage, sizeof(sMessage));
-			FakeClientCommand(client, "say_team %s", sMessage);
-			return Plugin_Handled;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_CommandSuicideAttempt(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsClientInGhostMode(client)) return Plugin_Handled;
-	
-	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
-	
-	if (GetConVarBool(g_cvBlockSuicideDuringRound))
-	{
-		if (!g_bRoundGrace && !g_bPlayerEliminated[client] && !DidClientEscape(client))
-		{
-			return Plugin_Handled;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_CommandBlockInGhostMode(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsClientInGhostMode(client)) return Plugin_Handled;
-	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_CommandVoiceMenu(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsClientInGhostMode(client))
-	{
-		ClientGhostModeNextTarget(client);
-		return Plugin_Handled;
-	}
-	
-	if (g_bPlayerProxy[client])
-	{
-		new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-		if (iMaster != -1)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
-		
-			if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
-			{
-				return Plugin_Handled;
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Command_ClientPerformScare(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_scare <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32], String:arg2[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			COMMAND_FILTER_ALIVE,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new target = target_list[i];
-		ClientPerformScare(target, StringToInt(arg2));
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SpawnSlender(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args == 0)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_spawn_boss <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl Float:eyePos[3], Float:eyeAng[3], Float:endPos[3];
-	GetClientEyePosition(client, eyePos);
-	GetClientEyeAngles(client, eyeAng);
-	
-	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
-	TR_GetEndPosition(endPos, hTrace);
-	CloseHandle(hTrace);
-	
-	SpawnSlender(iBossIndex, endPos);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Spawned Boss", client);
-	LogAction(client, -1, "%N spawned boss %d! (%s)", client, iBossIndex, sProfile);
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_RemoveSlender(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args == 0)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_remove_boss <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	NPCRemove(iBossIndex);
-	
-	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Removed Boss", client);
-	LogAction(client, -1, "%N removed boss %d! (%s)", client, iBossIndex, sProfile);
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_GetBossIndexes(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	decl String:sMessage[512];
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	ClientCommand(client, "echo Active Boss Indexes:");
-	ClientCommand(client, "echo ----------------------------");
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		Format(sMessage, sizeof(sMessage), "%d - %s", i, sProfile);
-		if (NPCGetFlags(i) & SFF_FAKE)
-		{
-			StrCat(sMessage, sizeof(sMessage), " (fake)");
-		}
-		
-		if (g_iSlenderCopyMaster[i] != -1)
-		{
-			decl String:sCat[64];
-			Format(sCat, sizeof(sCat), " (copy of %d)", g_iSlenderCopyMaster[i]);
-			StrCat(sMessage, sizeof(sMessage), sCat);
-		}
-		
-		ClientCommand(client, "echo %s", sMessage);
-	}
-	
-	ClientCommand(client, "echo ----------------------------");
-	
-	ReplyToCommand(client, "Printed active boss indexes to your console!");
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SlenderAttackWaiters(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_boss_attack_waiters <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iBossFlags = NPCGetFlags(iBossIndex);
-	
-	new bool:bState = bool:StringToInt(arg2);
-	new bool:bOldState = bool:(iBossFlags & SFF_ATTACKWAITERS);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (bState)
-	{
-		if (!bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags | SFF_ATTACKWAITERS);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Attack Waiters", client);
-			LogAction(client, -1, "%N forced boss %d to attack waiters! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	else
-	{
-		if (bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_ATTACKWAITERS);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Do Not Attack Waiters", client);
-			LogAction(client, -1, "%N forced boss %d to not attack waiters! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_SlenderNoTeleport(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_boss_no_teleport <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	new iBossIndex = StringToInt(arg1);
-	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iBossFlags = NPCGetFlags(iBossIndex);
-	
-	new bool:bState = bool:StringToInt(arg2);
-	new bool:bOldState = bool:(iBossFlags & SFF_NOTELEPORT);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (bState)
-	{
-		if (!bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags | SFF_NOTELEPORT);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Not Teleport", client);
-			LogAction(client, -1, "%N disabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	else
-	{
-		if (bOldState)
-		{
-			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_NOTELEPORT);
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Teleport", client);
-			LogAction(client, -1, "%N enabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_ForceProxy(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_force_proxy <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
-		return Plugin_Handled;
-	}
-	
-	if (IsRoundEnding() || IsRoundInWarmup())
-	{
-		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			0,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iBossIndex = StringToInt(arg2);
-	if (iBossIndex < 0 || iBossIndex >= MAX_BOSSES)
-	{
-		ReplyToCommand(client, "Boss index is out of range!");
-		return Plugin_Handled;
-	}
-	else if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		ReplyToCommand(client, "Boss index is invalid! Boss index not active!");
-		return Plugin_Handled;
-	}
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new iTarget = target_list[i];
-		
-		decl String:sName[MAX_NAME_LENGTH];
-		GetClientName(iTarget, sName, sizeof(sName));
-		
-		if (!g_bPlayerEliminated[iTarget])
-		{
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Unable To Perform Action On Player In Round", client, sName);
-			continue;
-		}
-		
-		if (g_bPlayerProxy[iTarget]) continue;
-		
-		decl Float:flNewPos[3];
-		
-		if (!SlenderCalculateNewPlace(iBossIndex, flNewPos, true, true, client)) 
-		{
-			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Player No Place For Proxy", client, sName);
-			continue;
-		}
-		
-		ClientEnableProxy(iTarget, iBossIndex);
-		TeleportEntity(iTarget, flNewPos, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-		
-		LogAction(client, iTarget, "%N forced %N to be a Proxy!", client, iTarget);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_ForceEscape(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_force_escape <name|#userid>");
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			COMMAND_FILTER_ALIVE,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new target = target_list[i];
-		if (!g_bPlayerEliminated[i] && !DidClientEscape(i))
-		{
-			ClientEscape(target);
-			TeleportClientToEscapePoint(target);
-			
-			LogAction(client, target, "%N forced %N to escape!", client, target);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_AddSlender(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_add_boss <name>");
-		return Plugin_Handled;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetCmdArg(1, sProfile, sizeof(sProfile));
-	
-	KvRewind(g_hConfig);
-	if (!KvJumpToKey(g_hConfig, sProfile)) 
-	{
-		ReplyToCommand(client, "That boss does not exist!");
-		return Plugin_Handled;
-	}
-	
-	new iBossIndex = AddProfile(sProfile);
-	if (iBossIndex != -1)
-	{
-		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
-		GetClientEyePosition(client, eyePos);
-		GetClientEyeAngles(client, eyeAng);
-		
-		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
-		TR_GetEndPosition(flPos, hTrace);
-		CloseHandle(hTrace);
-	
-		SpawnSlender(iBossIndex, flPos);
-		
-		LogAction(client, -1, "%N added a boss! (%s)", client, sProfile);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_AddSlenderFake(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 1)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_add_boss_fake <name>");
-		return Plugin_Handled;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetCmdArg(1, sProfile, sizeof(sProfile));
-	
-	KvRewind(g_hConfig);
-	if (!KvJumpToKey(g_hConfig, sProfile)) 
-	{
-		ReplyToCommand(client, "That boss does not exist!");
-		return Plugin_Handled;
-	}
-	
-	new iBossIndex = AddProfile(sProfile, SFF_FAKE);
-	if (iBossIndex != -1)
-	{
-		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
-		GetClientEyePosition(client, eyePos);
-		GetClientEyeAngles(client, eyeAng);
-		
-		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
-		TR_GetEndPosition(flPos, hTrace);
-		CloseHandle(hTrace);
-	
-		SpawnSlender(iBossIndex, flPos);
-		
-		LogAction(client, -1, "%N added a fake boss! (%s)", client, sProfile);
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Command_ForceState(client, args)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (args < 2)
-	{
-		ReplyToCommand(client, "Usage: sm_sf2_setplaystate <name|#userid> <0/1>");
-		return Plugin_Handled;
-	}
-	
-	if (IsRoundEnding() || IsRoundInWarmup())
-	{
-		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg1[32];
-	GetCmdArg(1, arg1, sizeof(arg1));
-	
-	decl String:target_name[MAX_TARGET_LENGTH];
-	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
-	
-	if ((target_count = ProcessTargetString(
-			arg1,
-			client,
-			target_list,
-			MAXPLAYERS,
-			0,
-			target_name,
-			sizeof(target_name),
-			tn_is_ml)) <= 0)
-	{
-		ReplyToTargetError(client, target_count);
-		return Plugin_Handled;
-	}
-	
-	decl String:arg2[32];
-	GetCmdArg(2, arg2, sizeof(arg2));
-	
-	new iState = StringToInt(arg2);
-	
-	decl String:sName[MAX_NAME_LENGTH];
-	
-	for (new i = 0; i < target_count; i++)
-	{
-		new target = target_list[i];
-		GetClientName(target, sName, sizeof(sName));
-		
-		if (iState && g_bPlayerEliminated[target])
-		{
-			SetClientPlayState(target, true);
-			
-			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced In Game", sName);
-			LogAction(client, target, "%N forced %N into the game.", client, target);
-		}
-		else if (!iState && !g_bPlayerEliminated[target])
-		{
-			SetClientPlayState(target, false);
-			
-			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced Out Of Game", sName);
-			LogAction(client, target, "%N took %N out of the game.", client, target);
-		}
-	}
-	
-	return Plugin_Handled;
-}
-
-public Action:Hook_CommandBuild(client, const String:command[], argc)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (!IsClientInPvP(client)) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_BossCountUpdate(Handle:timer)
-{
-	if (timer != g_hBossCountUpdateTimer) return Plugin_Stop;
-	
-	if (!g_bEnabled) return Plugin_Stop;
-
-	new iBossCount = NPCGetCount();
-	new iBossPreferredCount;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1 ||
-			g_iSlenderCopyMaster[i] != -1 ||
-			(NPCGetFlags(i) & SFF_FAKE))
-		{
-			continue;
-		}
-		
-		iBossPreferredCount++;
-	}
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsValidClient(i) ||
-			!IsPlayerAlive(i) ||
-			g_bPlayerEliminated[i] ||
-			IsClientInGhostMode(i) ||
-			IsClientInDeathCam(i) ||
-			DidClientEscape(i)) continue;
-		
-		// Check if we're near any bosses.
-		new iClosest = -1;
-		new Float:flBestDist = SF2_BOSS_PAGE_CALCULATION;
-		
-		for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
-		{
-			if (NPCGetUniqueID(iBoss) == -1) continue;
-			if (NPCGetEntIndex(iBoss) == INVALID_ENT_REFERENCE) continue;
-			if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
-			
-			new Float:flDist = NPCGetDistanceFromEntity(iBoss, i);
-			if (flDist < flBestDist)
-			{
-				iClosest = iBoss;
-				flBestDist = flDist;
-				break;
-			}
-		}
-		
-		if (iClosest != -1) continue;
-		
-		iClosest = -1;
-		flBestDist = SF2_BOSS_PAGE_CALCULATION;
-		
-		for (new iClient = 1; iClient <= MaxClients; iClient++)
-		{
-			if (!IsValidClient(iClient) ||
-				!IsPlayerAlive(iClient) ||
-				g_bPlayerEliminated[iClient] ||
-				IsClientInGhostMode(iClient) ||
-				IsClientInDeathCam(iClient) ||
-				DidClientEscape(iClient)) 
-			{
-				continue;
-			}
-			
-			new bool:bwub = false;
-			for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
-			{
-				if (NPCGetUniqueID(iBoss) == -1) continue;
-				if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
-				
-				if (g_iSlenderTarget[iBoss] == iClient)
-				{
-					bwub = true;
-					break;
-				}
-			}
-			
-			if (!bwub) continue;
-			
-			new Float:flDist = EntityDistanceFromEntity(i, iClient);
-			if (flDist < flBestDist)
-			{
-				iClosest = iClient;
-				flBestDist = flDist;
-			}
-		}
-		
-		if (!IsValidClient(iClosest))
-		{
-			// No one's close to this dude? DUDE! WE NEED ANOTHER BOSS!
-			iBossPreferredCount++;
-		}
-	}
-	
-	new iDiff = iBossCount - iBossPreferredCount;
-	if (iDiff)
-	{	
-		if (iDiff > 0)
-		{
-			new iCount = iDiff;
-			// We need less bosses. Try and see if we can remove some.
-			for (new i = 0; i < MAX_BOSSES; i++)
-			{
-				if (g_iSlenderCopyMaster[i] == -1) continue;
-				if (PeopleCanSeeSlender(i, _, false)) continue;
-				if (NPCGetFlags(i) & SFF_FAKE) continue;
-				
-				if (SlenderCanRemove(i))
-				{
-					NPCRemove(i);
-					iCount--;
-				}
-				
-				if (iCount <= 0)
-				{
-					break;
-				}
-			}
-		}
-		else
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		
-			new iCount = RoundToFloor(FloatAbs(float(iDiff)));
-			// Add new bosses (copy of the first boss).
-			for (new i = 0; i < MAX_BOSSES && iCount > 0; i++)
-			{
-				if (NPCGetUniqueID(i) == -1) continue;
-				if (g_iSlenderCopyMaster[i] != -1) continue;
-				if (!(NPCGetFlags(i) & SFF_COPIES)) continue;
-				
-				// Get the number of copies I already have and see if I can have more copies.
-				new iCopyCount;
-				for (new i2 = 0; i2 < MAX_BOSSES; i2++)
-				{
-					if (NPCGetUniqueID(i2) == -1) continue;
-					if (g_iSlenderCopyMaster[i2] != i) continue;
-					
-					iCopyCount++;
-				}
-				
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-				
-				if (iCopyCount >= GetProfileNum(sProfile, "copy_max", 10)) 
-				{
-					continue;
-				}
-				
-				new iBossIndex = AddProfile(sProfile, _, i);
-				if (iBossIndex == -1)
-				{
-					LogError("Could not add copy for %d: No free slots!", i);
-				}
-				
-				iCount--;
-			}
-		}
-	}
-	
-	// Check if we can add some proxies.
-	if (!g_bRoundGrace)
-	{
-		if (NavMesh_Exists())
-		{
-			new Handle:hProxyCandidates = CreateArray();
-			
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			
-			for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-			{
-				if (NPCGetUniqueID(iBossIndex) == -1) continue;
-				
-				if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) continue;
-				
-				if (g_iSlenderCopyMaster[iBossIndex] != -1) continue; // Copies cannot generate proxies.
-				
-				if (GetGameTime() < g_flSlenderTimeUntilNextProxy[iBossIndex]) continue; // Proxy spawning hasn't cooled down yet.
-				
-				new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
-				if (!iTeleportTarget || iTeleportTarget == INVALID_ENT_REFERENCE) continue; // No teleport target.
-				
-				NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-				
-				new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
-				new iNumActiveProxies = 0;
-				
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-					if (!g_bPlayerProxy[iClient]) continue;
-					
-					if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) == iBossIndex)
-					{
-						iNumActiveProxies++;
-					}
-				}
-				
-				if (iNumActiveProxies >= iMaxProxies) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d has too many active proxies!", iBossIndex);
-#endif
-					continue;
-				}
-				
-				new Float:flSpawnChanceMin = GetProfileFloat(sProfile, "proxies_spawn_chance_min");
-				new Float:flSpawnChanceMax = GetProfileFloat(sProfile, "proxies_spawn_chance_max");
-				new Float:flSpawnChanceThreshold = GetProfileFloat(sProfile, "proxies_spawn_chance_threshold") * NPCGetAnger(iBossIndex);
-				
-				new Float:flChance = GetRandomFloat(flSpawnChanceMin, flSpawnChanceMax);
-				if (flChance > flSpawnChanceThreshold) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's chances weren't in his favor!", iBossIndex);
-#endif
-					continue;
-				}
-				
-				new iAvailableProxies = iMaxProxies - iNumActiveProxies;
-				
-				new iSpawnNumMin = GetProfileNum(sProfile, "proxies_spawn_num_min");
-				new iSpawnNumMax = GetProfileNum(sProfile, "proxies_spawn_num_max");
-				
-				new iSpawnNum = 0;
-				
-				// Get a list of people we can transform into a good Proxy.
-				ClearArray(hProxyCandidates);
-				
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-					if (g_bPlayerProxy[iClient]) continue;
-					
-					if (!g_iPlayerPreferences[iClient][PlayerPreference_EnableProxySelection])
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your preferences.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					if (!g_bPlayerProxyAvailable[iClient])
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your cooldown.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					if (g_bPlayerProxyAvailableInForce[iClient])
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're already being forced into a Proxy.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					if (!IsClientParticipating(iClient))
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're not participating.", iBossIndex);
-#endif
-						continue;
-					}
-					
-					PushArrayCell(hProxyCandidates, iClient);
-					iSpawnNum++;
-				}
-				
-				if (iSpawnNum >= iSpawnNumMax)
-				{
-					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNumMax);
-				}
-				else if (iSpawnNum >= iSpawnNumMin)
-				{
-					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNum);
-				}
-				
-				if (iSpawnNum <= 0) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d had a set spawn number of 0!", iBossIndex);
-#endif
-					continue;
-				}
-				
-				decl Float:flTargetPos[3];
-				GetClientAbsOrigin(iTeleportTarget, flTargetPos);
-				
-				new iTargetAreaIndex = NavMesh_GetNearestArea(flTargetPos);
-				if (iTargetAreaIndex == -1) 
-				{
-#if defined DEBUG
-					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's teleport target is not on the navmesh!", iBossIndex);
-#endif
-					continue; // target is not on the nav mesh.
-				}
-				
-				// Search outwards until travel distance is at maximum range.
-				new Handle:hAreaArray = CreateArray(2);
-				new Handle:hAreas = CreateStack();
-				NavMesh_CollectSurroundingAreas(hAreas, iTargetAreaIndex, g_flSlenderProxyTeleportMaxRange[iBossIndex]);
-				
-				new Float:flTeleportMinRange = CalculateTeleportMinRange(iBossIndex, g_flSlenderProxyTeleportMinRange[iBossIndex], g_flSlenderProxyTeleportMaxRange[iBossIndex]);
-				
-				{
-					new iAreaIndex = -1;
-					new iPoppedAreas = 0;
-					
-					while (!IsStackEmpty(hAreas))
-					{
-						PopStackCell(hAreas, iAreaIndex);
-						new iCostSoFar = NavMeshArea_GetCostSoFar(iAreaIndex);
-						
-						if (float(iCostSoFar) >= flTeleportMinRange)
-						{
-							new iIndex = PushArrayCell(hAreaArray, iAreaIndex);
-							SetArrayCell(hAreaArray, iIndex, float(iCostSoFar), 1);
-							iPoppedAreas++;
-						}
-					}
-					
-					CloseHandle(hAreas);
-					
-					if (iPoppedAreas == 0)
-					{
-						// no areas to use!
-						CloseHandle(hAreaArray);
-
-#if defined DEBUG
-						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any sufficient surrounding areas!", iBossIndex);
-#endif
-						
-						continue;
-					}
-#if defined DEBUG
-					else
-					{
-						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d found %d surrounding areas", iBossIndex, iPoppedAreas);
-					}
-#endif
-				}
-				
-				new Handle:hAreaArrayClose = CreateArray();
-				new Handle:hAreaArrayAverage = CreateArray();
-				new Handle:hAreaArrayFar = CreateArray();
-				
-				for (new iRangeSection = 1; iRangeSection <= 3; iRangeSection++)
-				{
-					new Float:flRangeSectionMin = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection - 1) / 3.0);
-					new Float:flRangeSectionMax = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection) / 3.0);
-					
-					for (new i = 0, iSize = GetArraySize(hAreaArray); i < iSize; i++)
-					{
-						new iAreaIndex = GetArrayCell(hAreaArray, i);
-						
-						decl Float:flAreaCenter[3];
-						NavMeshArea_GetCenter(iAreaIndex, flAreaCenter);
-						
-						decl Float:flTestPos[3];
-						decl Float:flEyeOffset[3];
-						flEyeOffset[0] = 0.0;
-						flEyeOffset[1] = 0.0;
-						flEyeOffset[2] = HalfHumanHeight * 2.0;
-						
-						// Check visibility first.
-						if (IsPointVisibleToAPlayer(flAreaCenter, false, false)) 
-						{
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (1)", iBossIndex, iAreaIndex);
-#endif
-							continue;
-						}
-						
-						AddVectors(flAreaCenter, flEyeOffset, flTestPos);
-						
-						if (IsPointVisibleToAPlayer(flTestPos, false, false)) 
-						{
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (2)", iBossIndex, iAreaIndex);
-#endif
-						
-							continue;
-						}
-						
-						new iBoss = NPCGetEntIndex(iBossIndex);
-						
-						// Check space. First raise to HalfHumanHeight * 2, then trace downwards to get ground level.
-						{
-							decl Float:flTraceStartPos[3];
-							flTraceStartPos[0] = flAreaCenter[0];
-							flTraceStartPos[1] = flAreaCenter[1];
-							flTraceStartPos[2] = flAreaCenter[2] + (HalfHumanHeight * 2.0);
-							
-							decl Float:flTraceMins[3];
-							flTraceMins[0] = -20.0;
-							flTraceMins[1] = -20.0;
-							flTraceMins[2] = 0.0;
-							
-							decl Float:flTraceMaxs[3];
-							flTraceMaxs[0] = 20.0;
-							flTraceMaxs[1] = 20.0;
-							flTraceMaxs[2] = 0.0;
-							
-							new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
-								flAreaCenter,
-								flTraceMins,
-								flTraceMaxs,
-								MASK_NPCSOLID,
-								TraceRayDontHitEntity,
-								iBoss);
-							
-							decl Float:flTraceHitPos[3];
-							TR_GetEndPosition(flTraceHitPos, hTrace);
-							flTraceHitPos[2] += 1.0;
-							CloseHandle(hTrace);
-							
-							static Float:flTraceSpaceMin[3] = { -20.0, -20.0, 0.0 };
-							static Float:flTraceSpaceMax[3] = { 20.0, 20.0, 72.0 };
-							
-							flTraceSpaceMax[2] = HalfHumanHeight * 2.0;
-							
-							if (IsSpaceOccupiedPlayer(flTraceHitPos,
-								flTraceSpaceMin,
-								flTraceSpaceMax,
-								iBoss == INVALID_ENT_REFERENCE ? -1 : iBoss))
-							{
-#if defined DEBUG
-								SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected too small area index %d! (2)", iBossIndex, iAreaIndex);
-#endif
-							
-								continue;
-							}
-						}
-						
-						new bool:bTooNear = false;
-						
-						// Check minimum range.
-						for (new iClient = 1; iClient <= MaxClients; iClient++)
-						{
-							if (!IsClientInGame(iClient) ||
-								!IsPlayerAlive(iClient) ||
-								g_bPlayerEliminated[iClient] ||
-								DidClientEscape(iClient) ||
-								g_bPlayerProxy[iClient] ||
-								IsClientInGhostMode(iClient))
-							{
-								continue;
-							}
-							
-							decl Float:flTempPos[3];
-							GetClientAbsOrigin(iClient, flTempPos);
-							
-							if (GetVectorDistance(flAreaCenter, flTempPos) <= flTeleportMinRange)
-							{
-								bTooNear = true;
-								break;
-							}
-						}
-						
-						if (bTooNear) 
-						{
-#if defined DEBUG
-							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected near area index %d!", iBossIndex, iAreaIndex);
-#endif
-						
-							continue;	// This area is too close to a player.
-						}
-						
-						// Check travel distance.
-						new Float:flDist = Float:GetArrayCell(hAreaArray, i, 1);
-						if (flDist > flRangeSectionMin && flDist < flRangeSectionMax)
-						{
-							switch (iRangeSection)
-							{
-								case 1: PushArrayCell(hAreaArrayClose, iAreaIndex);
-								case 2: PushArrayCell(hAreaArrayAverage, iAreaIndex);
-								case 3: PushArrayCell(hAreaArrayFar, iAreaIndex);
-							}
-						}
-					}
-				}
-				
-				CloseHandle(hAreaArray);
-				
-				// Set the cooldown time!
-				new Float:flSpawnCooldownMin = GetProfileFloat(sProfile, "proxies_spawn_cooldown_min");
-				new Float:flSpawnCooldownMax = GetProfileFloat(sProfile, "proxies_spawn_cooldown_max");
-				
-				g_flSlenderTimeUntilNextProxy[iBossIndex] = GetGameTime() + GetRandomFloat(flSpawnCooldownMin, flSpawnCooldownMax);
-				
-				// Randomize the array.
-				SortADTArray(hProxyCandidates, Sort_Random, Sort_Integer);
-				
-				decl Float:flDestinationPos[3];
-				
-				for (new iNum = 0; iNum < iSpawnNum && iNum < iAvailableProxies; iNum++)
-				{
-					new iClient = GetArrayCell(hProxyCandidates, iNum);
-					new iBestAreaIndex = -1;
-					
-					if (GetArraySize(hAreaArrayClose) > 0)
-					{
-						iBestAreaIndex = GetArrayCell(hAreaArrayClose, GetRandomInt(0, GetArraySize(hAreaArrayClose) - 1));
-					}
-					else if (GetArraySize(hAreaArrayAverage) > 0)
-					{
-						iBestAreaIndex = GetArrayCell(hAreaArrayAverage, GetRandomInt(0, GetArraySize(hAreaArrayAverage) - 1));
-					}
-					else if (GetArraySize(hAreaArrayFar) > 0)
-					{
-						iBestAreaIndex = GetArrayCell(hAreaArrayFar, GetRandomInt(0, GetArraySize(hAreaArrayFar) - 1));
-					}
-					
-					if (iBestAreaIndex == -1) 
-					{
-#if defined DEBUG
-						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any areas to place proxies (spawned %d)!", iBossIndex, iNum);
-#endif
-						break;
-					}
-					
-					NavMeshArea_GetCenter(iBestAreaIndex, flDestinationPos);
-					
-					if (!GetConVarBool(g_cvPlayerProxyAsk))
-					{
-						ClientStartProxyForce(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
-					}
-					else
-					{
-						DisplayProxyAskMenu(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
-					}
-				}
-				
-				CloseHandle(hAreaArrayClose);
-				CloseHandle(hAreaArrayAverage);
-				CloseHandle(hAreaArrayFar);
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d finished proxy process!", iBossIndex);
-#endif
-			}
-			
-			CloseHandle(hProxyCandidates);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-ReloadRestrictedWeapons()
-{
-	if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
-	{
-		CloseHandle(g_hRestrictedWeaponsConfig);
-		g_hRestrictedWeaponsConfig = INVALID_HANDLE;
-	}
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	BuildPath(Path_SM, buffer, sizeof(buffer), FILE_RESTRICTEDWEAPONS);
-	new Handle:kv = CreateKeyValues("root");
-	if (!FileToKeyValues(kv, buffer))
-	{
-		CloseHandle(kv);
-		LogError("Failed to load restricted weapons list! File not found!");
-	}
-	else
-	{
-		g_hRestrictedWeaponsConfig = kv;
-		LogSF2Message("Reloaded restricted weapons configuration file successfully");
-	}
-}
-
-public Action:Timer_RoundMessages(Handle:timer)
-{
-	if (!g_bEnabled) return Plugin_Stop;
-	
-	if (timer != g_hRoundMessagesTimer) return Plugin_Stop;
-	
-	switch (g_iRoundMessagesNum)
-	{
-		case 0: CPrintToChatAll("{olive}==== {lightgreen}Slender Fortress (%s){olive} coded by {lightgreen}Kit o' Rifty{olive} ====", PLUGIN_VERSION_DISPLAY);
-		case 1: CPrintToChatAll("%t", "SF2 Ad Message 1");
-		case 2: CPrintToChatAll("%t", "SF2 Ad Message 2");
-	}
-	
-	g_iRoundMessagesNum++;
-	if (g_iRoundMessagesNum > 2) g_iRoundMessagesNum = 0;
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_WelcomeMessage(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	CPrintToChat(client, "%T", "SF2 Welcome Message", client);
-}
-
-GetMaxPlayersForRound()
-{
-	new iOverride = GetConVarInt(g_cvMaxPlayersOverride);
-	if (iOverride != -1) return iOverride;
-	return GetConVarInt(g_cvMaxPlayers);
-}
-
-public OnConVarChanged(Handle:cvar, const String:oldValue[], const String:newValue[])
-{
-	if (cvar == g_cvDifficulty)
-	{
-		switch (StringToInt(newValue))
-		{
-			case Difficulty_Easy: g_flRoundDifficultyModifier = DIFFICULTY_EASY;
-			case Difficulty_Hard: g_flRoundDifficultyModifier = DIFFICULTY_HARD;
-			case Difficulty_Insane: g_flRoundDifficultyModifier = DIFFICULTY_INSANE;
-			default: g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
-		}
-	}
-	else if (cvar == g_cvMaxPlayers || cvar == g_cvMaxPlayersOverride)
-	{
-		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-		{
-			CheckPlayerGroup(i);
-		}
-	}
-	else if (cvar == g_cvPlayerShakeEnabled)
-	{
-		g_bPlayerShakeEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvPlayerViewbobEnabled)
-	{
-		g_bPlayerViewbobEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvPlayerViewbobHurtEnabled)
-	{
-		g_bPlayerViewbobHurtEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvPlayerViewbobSprintEnabled)
-	{
-		g_bPlayerViewbobSprintEnabled = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvGravity)
-	{
-		g_flGravity = StringToFloat(newValue);
-	}
-	else if (cvar == g_cv20Dollars)
-	{
-		g_b20Dollars = bool:StringToInt(newValue);
-	}
-	else if (cvar == g_cvAllChat)
-	{
-		if (g_bEnabled)
-		{
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				ClientUpdateListeningFlags(i);
-			}
-		}
-	}
-}
-
-//	==========================================================
-//	IN-GAME AND ENTITY HOOK FUNCTIONS
-//	==========================================================
-
-
-public OnEntityCreated(ent, const String:classname[])
-{
-	if (!g_bEnabled) return;
-	
-	if (!IsValidEntity(ent) || ent <= 0) return;
-	
-	if (StrEqual(classname, "spotlight_end", false))
-	{
-		SDKHook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
-	}
-	else if (StrEqual(classname, "beam", false))
-	{
-		SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightBeamSetTransmit);
-	}
-	
-	PvP_OnEntityCreated(ent, classname);
-}
-
-public OnEntityDestroyed(ent)
-{
-	if (!g_bEnabled) return;
-
-	if (!IsValidEntity(ent) || ent <= 0) return;
-	
-	decl String:sClassname[64];
-	GetEntityClassname(ent, sClassname, sizeof(sClassname));
-	
-	if (StrEqual(sClassname, "light_dynamic", false))
-	{
-		AcceptEntityInput(ent, "TurnOff");
-		
-		new iEnd = INVALID_ENT_REFERENCE;
-		while ((iEnd = FindEntityByClassname(iEnd, "spotlight_end")) != -1)
-		{
-			if (GetEntPropEnt(iEnd, Prop_Data, "m_hOwnerEntity") == ent)
-			{
-				AcceptEntityInput(iEnd, "Kill");
-				break;
-			}
-		}
-	}
-	
-	PvP_OnEntityDestroyed(ent, sClassname);
-}
-
-public Action:Hook_BlockUserMessage(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init) 
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	return Plugin_Handled;
-}
-
-public Action:Hook_NormalSound(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsValidClient(entity))
-	{
-		if (IsClientInGhostMode(entity))
-		{
-			switch (channel)
-			{
-				case SNDCHAN_VOICE, SNDCHAN_WEAPON, SNDCHAN_ITEM, SNDCHAN_BODY: return Plugin_Handled;
-			}
-		}
-		else if (g_bPlayerProxy[entity])
-		{
-			new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[entity]);
-			if (iMaster != -1)
-			{
-				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-				NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
-				
-				switch (channel)
-				{
-					case SNDCHAN_VOICE:
-					{
-						if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
-						{
-							return Plugin_Handled;
-						}
-					}
-				}
-			}
-		}
-		else if (!g_bPlayerEliminated[entity])
-		{
-			switch (channel)
-			{
-				case SNDCHAN_VOICE:
-				{
-					if (IsRoundInIntro()) return Plugin_Handled;
-				
-					for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-					{
-						if (NPCGetUniqueID(iBossIndex) == -1) continue;
-						
-						if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Voice))
-						{
-							GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
-							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
-							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDVOICE;
-						}
-					}
-				}
-				case SNDCHAN_BODY:
-				{
-					if (!StrContains(sample, "player/footsteps", false) || StrContains(sample, "step", false) != -1)
-					{
-						if (GetConVarBool(g_cvPlayerViewbobSprintEnabled) && IsClientReallySprinting(entity))
-						{
-							// Viewpunch.
-							new Float:flPunchVelStep[3];
-							
-							decl Float:flVelocity[3];
-							GetEntPropVector(entity, Prop_Data, "m_vecAbsVelocity", flVelocity);
-							new Float:flSpeed = GetVectorLength(flVelocity);
-							
-							flPunchVelStep[0] = flSpeed / 300.0;
-							flPunchVelStep[1] = 0.0;
-							flPunchVelStep[2] = 0.0;
-							
-							ClientViewPunch(entity, flPunchVelStep);
-						}
-						
-						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-						{
-							if (NPCGetUniqueID(iBossIndex) == -1) continue;
-							
-							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Footstep))
-							{
-								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEP;
-								
-								if (IsClientSprinting(entity) && !(GetEntProp(entity, Prop_Send, "m_bDucking") || GetEntProp(entity, Prop_Send, "m_bDucked")))
-								{
-									g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEPLOUD;
-								}
-							}
-						}
-					}
-				}
-				case SNDCHAN_ITEM, SNDCHAN_WEAPON:
-				{
-					if (StrContains(sample, "impact", false) != -1 || StrContains(sample, "hit", false) != -1)
-					{
-						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-						{
-							if (NPCGetUniqueID(iBossIndex) == -1) continue;
-							
-							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Weapon))
-							{
-								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
-								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDWEAPON;
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	new bool:bModified = false;
-	
-	for (new i = 0; i < numClients; i++)
-	{
-		new iClient = clients[i];
-		if (IsValidClient(iClient) && IsPlayerAlive(iClient) && !IsClientInGhostMode(iClient))
-		{
-			new bool:bCanHearSound = true;
-			
-			if (IsValidClient(entity) && entity != iClient)
-			{
-				if (!g_bPlayerEliminated[iClient])
-				{
-					if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-					{
-						if (!g_bPlayerEliminated[entity] && !DidClientEscape(entity))
-						{
-							bCanHearSound = false;
-						}
-					}
-				}
-			}
-			
-			if (!bCanHearSound)
-			{
-				bModified = true;
-				clients[i] = -1;
-			}
-		}
-	}
-	
-	if (bModified) return Plugin_Changed;
-	return Plugin_Continue;
-}
-
-public MRESReturn:Hook_EntityShouldTransmit(thisPointer, Handle:hReturn, Handle:hParams)
-{
-	if (!g_bEnabled) return MRES_Ignored;
-	
-	if (IsValidClient(thisPointer))
-	{
-		if (DoesClientHaveConstantGlow(thisPointer))
-		{
-			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
-			return MRES_Supercede;
-		}
-	}
-	else
-	{
-		new iBossIndex = NPCGetFromEntIndex(thisPointer);
-		if (iBossIndex != -1)
-		{
-			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
-			return MRES_Supercede;
-		}
-	}
-	
-	return MRES_Ignored;
-}
-
-public Hook_TriggerOnStartTouch(const String:output[], caller, activator, Float:delay)
-{
-	if (!g_bEnabled) return;
-
-	if (!IsValidEntity(caller)) return;
-	
-	decl String:sName[64];
-	GetEntPropString(caller, Prop_Data, "m_iName", sName, sizeof(sName));
-	
-	if (StrContains(sName, "sf2_escape_trigger", false) == 0)
-	{
-		if (IsRoundInEscapeObjective())
-		{
-			if (IsValidClient(activator) && IsPlayerAlive(activator) && !IsClientInDeathCam(activator) && !g_bPlayerEliminated[activator] && !DidClientEscape(activator))
-			{
-				ClientEscape(activator);
-				TeleportClientToEscapePoint(activator);
-			}
-		}
-	}
-	
-	PvP_OnTriggerStartTouch(caller, activator);
-}
-
-public Hook_TriggerOnEndTouch(const String:sOutput[], caller, activator, Float:flDelay)
-{
-	if (!g_bEnabled) return;
-	
-	PvP_OnTriggerEndTouch(caller, activator);
-}
-
-public Action:Hook_PageOnTakeDamage(page, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsValidClient(attacker))
-	{
-		if (!g_bPlayerEliminated[attacker])
-		{
-			if (damagetype & 0x80) // 0x80 == melee damage
-			{
-				CollectPage(page, attacker);
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-static CollectPage(page, activator)
-{
-	SetPageCount(g_iPageCount + 1);
-	g_iPlayerPageCount[activator] += 1;
-	EmitSoundToAll(PAGE_GRABSOUND, activator, SNDCHAN_ITEM, SNDLEVEL_SCREAMING);
-				
-	// Gives points. Credit to the makers of VSH/FF2.
-	new Handle:hEvent = CreateEvent("player_escort_score", true);
-	SetEventInt(hEvent, "player", activator);
-	SetEventInt(hEvent, "points", 1);
-	FireEvent(hEvent);
-				
-	AcceptEntityInput(page, "FireUser1");
-	AcceptEntityInput(page, "Kill");
-}
-	
-//	==========================================================
-//	GENERIC CLIENT HOOKS AND FUNCTIONS
-//	==========================================================
-
-
-public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	ClientDisableFakeLagCompensation(client);
-	
-	// Check impulse (block spraying and built-in flashlight)
-	switch (impulse)
-	{
-		case 100:
-		{
-			impulse = 0;
-		}
-		case 201:
-		{
-			if (IsClientInGhostMode(client))
-			{
-				impulse = 0;
-			}
-		}
-	}
-	
-	for (new i = 0; i < MAX_BUTTONS; i++)
-	{
-		new button = (1 << i);
-		
-		if ((buttons & button))
-		{
-			if (!(g_iPlayerLastButtons[client] & button))
-			{
-				ClientOnButtonPress(client, button);
-			}
-		}
-		else if ((g_iPlayerLastButtons[client] & button))
-		{
-			ClientOnButtonRelease(client, button);
-		}
-	}
-	
-	g_iPlayerLastButtons[client] = buttons;
-	
-	return Plugin_Continue;
-}
-
-
-public OnClientCookiesCached(client)
-{
-	if (!g_bEnabled) return;
-	
-	// Load our saved settings.
-	new String:sCookie[64];
-	GetClientCookie(client, g_hCookie, sCookie, sizeof(sCookie));
-	
-		g_iPlayerQueuePoints[client] = 0;
-		
-		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
-		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
-	g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = true;
-		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
-	g_iPlayerPreferences[client][PlayerPreference_GhostOverlay] = true;
-	
-	if (sCookie[0])
-	{
-		new String:s2[12][32];
-		new count = ExplodeString(sCookie, " ; ", s2, 12, 32);
-		
-		if (count > 0)
-		g_iPlayerQueuePoints[client] = StringToInt(s2[0]);
-		if (count > 1)
-		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = bool:StringToInt(s2[1]);
-		if (count > 2)
-		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode:StringToInt(s2[2]);
-		if (count > 3)
-			g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = bool:StringToInt(s2[3]);
-		if (count > 4)
-		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = bool:StringToInt(s2[4]);
-		if (count > 5)
-			g_iPlayerPreferences[client][PlayerPreference_GhostOverlay] = bool:StringToInt(s2[5]);
-	}
-}
-
-public OnClientPutInServer(client)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientPutInServer(%d)", client);
-#endif
-	
-	ClientSetPlayerGroup(client, -1);
-	
-	g_bPlayerEscaped[client] = false;
-	g_bPlayerEliminated[client] = true;
-	g_bPlayerChoseTeam[client] = false;
-	g_bPlayerPlayedSpecialRound[client] = true;
-	g_bPlayerPlayedNewBossRound[client] = true;
-	
-	g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn] = false;
-	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
-	
-	g_iPlayerPageCount[client] = 0;
-	g_iPlayerDesiredFOV[client] = 90;
-	
-	SDKHook(client, SDKHook_PreThink, Hook_ClientPreThink);
-	SDKHook(client, SDKHook_SetTransmit, Hook_ClientSetTransmit);
-	SDKHook(client, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage);
-	
-	DHookEntity(g_hSDKWantsLagCompensationOnEntity, true, client); 
-	DHookEntity(g_hSDKShouldTransmit, true, client);
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		
-		SetPlayerGroupInvitedPlayer(i, client, false);
-		SetPlayerGroupInvitedPlayerCount(i, client, 0);
-		SetPlayerGroupInvitedPlayerTime(i, client, 0.0);
-	}
-	
-	ClientDisableFakeLagCompensation(client);
-	
-	ClientResetStatic(client);
-	ClientResetSlenderStats(client);
-	ClientResetCampingStats(client);
-	ClientResetOverlay(client);
-	ClientResetJumpScare(client);
-	ClientUpdateListeningFlags(client);
-	ClientUpdateMusicSystem(client);
-	ClientChaseMusicReset(client);
-	ClientChaseMusicSeeReset(client);
-	ClientAlertMusicReset(client);
-	Client20DollarsMusicReset(client);
-	ClientMusicReset(client);
-	ClientResetProxy(client);
-	ClientResetHints(client);
-	ClientResetScare(client);
-	
-	ClientResetDeathCam(client);
-	ClientResetFlashlight(client);
-	ClientDeactivateUltravision(client);
-	ClientResetSprint(client);
-	ClientResetBreathing(client);
-	ClientResetBlink(client);
-	ClientResetInteractiveGlow(client);
-	ClientDisableConstantGlow(client);
-	
-	ClientSetScareBoostEndTime(client, -1.0);
-	
-	ClientStartProxyAvailableTimer(client);
-	
-	if (!IsFakeClient(client))
-	{
-		// See if the player is using the projected flashlight.
-		QueryClientConVar(client, "mat_supportflashlight", OnClientGetProjectedFlashlightSetting);
-		
-		// Get desired FOV.
-		QueryClientConVar(client, "fov_desired", OnClientGetDesiredFOV);
-	}
-	
-	PvP_OnClientPutInServer(client);
-	
-#if defined DEBUG
-	g_iPlayerDebugFlags[client] = 0;
-
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientPutInServer(%d)", client);
-#endif
-}
-
-public OnClientGetProjectedFlashlightSetting(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
-{
-	if (result != ConVarQuery_Okay) 
-	{
-		LogError("Warning: Player %N failed to query for ConVar mat_supportflashlight", client);
-		return;
-	}
-	
-	if (StringToInt(cvarValue))
-	{
-		decl String:sAuth[64];
-		GetClientAuthString(client, sAuth, sizeof(sAuth));
-		
-		g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = true;
-		LogSF2Message("Player %N (%s) has mat_supportflashlight enabled, projected flashlight will be used", client, sAuth);
-	}
-}
-
-public OnClientGetDesiredFOV(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
-{
-	if (!IsValidClient(client)) return;
-	
-	g_iPlayerDesiredFOV[client] = StringToInt(cvarValue);
-}
-
-public OnClientDisconnect(client)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientDisconnect(%d)", client);
-#endif
-	
-	g_bPlayerEscaped[client] = false;
-	
-	// Save and reset settings for the next client.
-	ClientSaveCookies(client);
-	ClientSetPlayerGroup(client, -1);
-	
-	// Reset variables.
-	g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
-	g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
-	g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = true;
-	g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
-	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
-	
-	// Reset any client functions that may be still active.
-	ClientResetOverlay(client);
-	ClientResetFlashlight(client);
-	ClientDeactivateUltravision(client);
-	ClientSetGhostModeState(client, false);
-	ClientResetInteractiveGlow(client);
-	ClientDisableConstantGlow(client);
-	
-	ClientStopProxyForce(client);
-	
-	if (!IsRoundInWarmup())
-	{
-		if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
-		{
-			if (g_bRoundGrace)
-			{
-				// Force the next player in queue to take my place, if any.
-				ForceInNextPlayersInQueue(1, true);
-			}
-			else
-			{
-				if (!IsRoundEnding()) 
-				{
-					CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
-				}
-			}
-		}
-	}
-	
-	// Reset queue points global variable.
-	g_iPlayerQueuePoints[client] = 0;
-	
-	PvP_OnClientDisconnect(client);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientDisconnect(%d)", client);
-#endif
-}
-
-public OnClientDisconnect_Post(client)
-{
-    g_iPlayerLastButtons[client] = 0;
-}
-
-public TF2_OnWaitingForPlayersStart()
-{
-	g_bRoundWaitingForPlayers = true;
-}
-
-public TF2_OnWaitingForPlayersEnd()
-{
-	g_bRoundWaitingForPlayers = false;
-}
-
-SF2RoundState:GetRoundState()
-{
-	return g_iRoundState;
-}
-
-SetRoundState(SF2RoundState:iRoundState)
-{
-	if (g_iRoundState == iRoundState) return;
-	
-	PrintToServer("SetRoundState(%d)", iRoundState);
-	
-	new SF2RoundState:iOldRoundState = GetRoundState();
-	g_iRoundState = iRoundState;
-	
-	// Cleanup from old roundstate if needed.
-	switch (iOldRoundState)
-	{
-		case SF2RoundState_Waiting:
-		{
-		}
-		case SF2RoundState_Intro:
-		{
-			g_hRoundIntroTimer = INVALID_HANDLE;
-		}
-		case SF2RoundState_Active:
-		{
-			g_bRoundGrace = false;
-			g_hRoundGraceTimer = INVALID_HANDLE;
-			g_hRoundTimer = INVALID_HANDLE;
-		}
-		case SF2RoundState_Escape:
-		{
-			g_hRoundTimer = INVALID_HANDLE;
-		}
-		case SF2RoundState_Outro:
-		{
-		}
-	}
-	
-	switch (g_iRoundState)
-	{
-		case SF2RoundState_Waiting:
-		{
-		}
-		case SF2RoundState_Intro:
-		{
-			g_hRoundIntroTimer = INVALID_HANDLE;
-			g_iRoundIntroText = 0;
-			g_bRoundIntroTextDefault = false;
-			g_hRoundIntroTextTimer = CreateTimer(0.0, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
-			TriggerTimer(g_hRoundIntroTextTimer);
-			
-			// Gather data on the intro parameters set by the map.
-			new Float:flHoldTime = g_flRoundIntroFadeHoldTime;
-			g_hRoundIntroTimer = CreateTimer(flHoldTime, Timer_ActivateRoundFromIntro, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			// Trigger any intro logic entities, if any.
-			new ent = -1;
-			while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
-			{
-				decl String:sName[64];
-				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-				if (StrEqual(sName, "sf2_intro_relay", false))
-				{
-					AcceptEntityInput(ent, "Trigger");
-					break;
-				}
-			}
-		}
-		case SF2RoundState_Active:
-		{
-			// Start the grace period timer.
-			g_bRoundGrace = true;
-			g_hRoundGraceTimer = CreateTimer(GetConVarFloat(g_cvGraceTime), Timer_RoundGrace, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			CreateTimer(2.0, Timer_RoundStart, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			// Enable movement on players.
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
-				SetEntityFlags(i, GetEntityFlags(i) & ~FL_FROZEN);
-			}
-			
-			// Fade in.
-			new Float:flFadeTime = g_flRoundIntroFadeDuration;
-			new iFadeFlags = SF_FADE_IN | FFADE_PURGE;
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
-				UTIL_ScreenFade(i, FixedUnsigned16(flFadeTime, 1 << 12), 0, iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
-			}
-		}
-		case SF2RoundState_Escape:
-		{
-			// Initialize the escape timer, if needed.
-			if (g_iRoundEscapeTimeLimit > 0)
-			{
-				g_iRoundTime = g_iRoundEscapeTimeLimit;
-				g_hRoundTimer = CreateTimer(1.0, Timer_RoundTimeEscape, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			}
-			else
-			{
-				g_hRoundTimer = INVALID_HANDLE;
-			}
-		
-			decl String:sName[32];
-			new ent = -1;
-			while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-			{
-				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-				if (StrEqual(sName, "sf2_logic_escape", false))
-				{
-					AcceptEntityInput(ent, "FireUser1");
-					break;
-				}
-			}
-		}
-		case SF2RoundState_Outro:
-		{
-			if (!g_bRoundHasEscapeObjective)
-			{
-				// Teleport winning players to the escape point.
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i)) continue;
-					
-					if (!g_bPlayerEliminated[i])
-					{
-						TeleportClientToEscapePoint(i);
-					}
-				}
-			}
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i)) continue;
-				
-				if (IsClientInGhostMode(i))
-				{
-					// Take the player out of ghost mode.
-					ClientSetGhostModeState(i, false);	
-					TF2_RespawnPlayer(i);
-				}
-				else if (g_bPlayerProxy[i])
-				{
-					TF2_RespawnPlayer(i);
-				}
-				
-				if (!g_bPlayerEliminated[i])
-				{
-					// Give them back all their weapons so they can beat the crap out of the other team.
-					TF2_RegeneratePlayer(i);
-				}
-				
-				ClientUpdateListeningFlags(i);
-			}
-		}
-	}
-}
-
-bool:IsRoundInEscapeObjective()
-{
-	return bool:(GetRoundState() == SF2RoundState_Escape);
-}
-
-bool:IsRoundInWarmup()
-{
-	return bool:(GetRoundState() == SF2RoundState_Waiting);
-}
-
-bool:IsRoundInIntro()
-{
-	return bool:(GetRoundState() == SF2RoundState_Intro);
-}
-
-bool:IsRoundEnding()
-{
-	return bool:(GetRoundState() == SF2RoundState_Outro);
-}
-
-bool:IsInfiniteBlinkEnabled()
-{
-	return bool:(g_bRoundInfiniteBlink || (GetConVarInt(g_cvPlayerInfiniteBlinkOverride) == 1));
-}
-
-bool:IsInfiniteFlashlightEnabled()
-{
-	return bool:(g_bRoundInfiniteFlashlight || (GetConVarInt(g_cvPlayerInfiniteFlashlightOverride) == 1));
-}
-
-bool:IsInfiniteSprintEnabled()
-{
-	return bool:(g_bRoundInfiniteSprint || (GetConVarInt(g_cvPlayerInfiniteSprintOverride) == 1));
-}
-
-
-#define SF2_PLAYER_HUD_BLINK_SYMBOL "B"
-#define SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL "ÏŸ"
-#define SF2_PLAYER_HUD_BAR_SYMBOL "|"
-#define SF2_PLAYER_HUD_BAR_MISSING_SYMBOL ""
-#define SF2_PLAYER_HUD_INFINITY_SYMBOL "∞"
-#define SF2_PLAYER_HUD_SPRINT_SYMBOL "»"
-
-public Action:Timer_ClientAverageUpdate(Handle:timer)
-{
-	if (timer != g_hClientAverageUpdateTimer) return Plugin_Stop;
-	
-	if (!g_bEnabled) return Plugin_Stop;
-	
-	if (IsRoundInWarmup() || IsRoundEnding()) return Plugin_Continue;
-	
-	// First, process through HUD stuff.
-	decl String:buffer[256];
-	
-	static iHudColorHealthy[3] = { 150, 255, 150 };
-	static iHudColorCritical[3] = { 255, 10, 10 };
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (IsPlayerAlive(i) && !IsClientInDeathCam(i))
-		{
-			if (!g_bPlayerEliminated[i])
-			{
-				if (DidClientEscape(i)) continue;
-				
-				new iMaxBars = 12;
-				new iBars = RoundToCeil(float(iMaxBars) * ClientGetBlinkMeter(i));
-				if (iBars > iMaxBars) iBars = iMaxBars;
-				
-				Format(buffer, sizeof(buffer), "%s  ", SF2_PLAYER_HUD_BLINK_SYMBOL);
-				
-				if (IsInfiniteBlinkEnabled())
-				{
-					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
-				}
-				else
-				{
-					for (new i2 = 0; i2 < iMaxBars; i2++) 
-					{
-						if (i2 < iBars)
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-						}
-						else
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
-						}
-					}
-				}
-				
-				if (!g_bSpecialRound || g_iSpecialRoundType != SPECIALROUND_LIGHTSOUT)
-				{
-					iBars = RoundToCeil(float(iMaxBars) * ClientGetFlashlightBatteryLife(i));
-					if (iBars > iMaxBars) iBars = iMaxBars;
-					
-					decl String:sBuffer2[64];
-					Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL);
-					StrCat(buffer, sizeof(buffer), sBuffer2);
-					
-					if (IsInfiniteFlashlightEnabled())
-					{
-						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
-					}
-					else
-					{
-						for (new i2 = 0; i2 < iMaxBars; i2++) 
-						{
-							if (i2 < iBars)
-							{
-								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-							}
-							else
-							{
-								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
-							}
-						}
-					}
-				}
-				
-				iBars = RoundToCeil(float(iMaxBars) * (float(ClientGetSprintPoints(i)) / 100.0));
-				if (iBars > iMaxBars) iBars = iMaxBars;
-				
-				decl String:sBuffer2[64];
-				Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_SPRINT_SYMBOL);
-				StrCat(buffer, sizeof(buffer), sBuffer2);
-				
-				if (IsInfiniteSprintEnabled())
-				{
-					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
-				}
-				else
-				{
-					for (new i2 = 0; i2 < iMaxBars; i2++) 
-					{
-						if (i2 < iBars)
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-						}
-						else
-						{
-							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
-						}
-					}
-				}
-				
-				
-				new Float:flHealthRatio = float(GetEntProp(i, Prop_Send, "m_iHealth")) / float(SDKCall(g_hSDKGetMaxHealth, i));
-				
-				new iColor[3];
-				for (new i2 = 0; i2 < 3; i2++)
-				{
-					iColor[i2] = RoundFloat(float(iHudColorHealthy[i2]) + (float(iHudColorCritical[i2] - iHudColorHealthy[i2]) * (1.0 - flHealthRatio)));
-				}
-				
-				SetHudTextParams(0.035, 0.83,
-					0.3,
-					iColor[0],
-					iColor[1],
-					iColor[2],
-					40,
-					_,
-					1.0,
-					0.07,
-					0.5);
-				ShowSyncHudText(i, g_hHudSync2, buffer);
-			}
-			else
-			{
-				if (g_bPlayerProxy[i])
-				{
-					new iMaxBars = 12;
-					new iBars = RoundToCeil(float(iMaxBars) * (float(g_iPlayerProxyControl[i]) / 100.0));
-					if (iBars > iMaxBars) iBars = iMaxBars;
-					
-					strcopy(buffer, sizeof(buffer), "CONTROL\n");
-					
-					for (new i2 = 0; i2 < iBars; i2++)
-					{
-						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
-					}
-					
-					SetHudTextParams(-1.0, 0.83,
-						0.3,
-						SF2_HUD_TEXT_COLOR_R,
-						SF2_HUD_TEXT_COLOR_G,
-						SF2_HUD_TEXT_COLOR_B,
-						40,
-						_,
-						1.0,
-						0.07,
-						0.5);
-					ShowSyncHudText(i, g_hHudSync2, buffer);
-				}
-			}
-		}
-		
-		ClientUpdateListeningFlags(i);
-		ClientUpdateMusicSystem(i);
-	}
-	
-	return Plugin_Continue;
-}
-
-stock bool:IsClientParticipating(client)
-{
-	if (!IsValidClient(client)) return false;
-	
-	if (bool:GetEntProp(client, Prop_Send, "m_bIsCoaching")) 
-	{
-		// Who would coach in this game?
-		return false;
-	}
-	
-	new iTeam = GetClientTeam(client);
-	
-	if (g_bPlayerLagCompensation[client]) 
-	{
-		iTeam = g_iPlayerLagCompensationTeam[client];
-	}
-	
-	switch (iTeam)
-	{
-		case TFTeam_Unassigned, TFTeam_Spectator: return false;
-	}
-	
-	if (_:TF2_GetPlayerClass(client) == 0)
-	{
-		// Player hasn't chosen a class? What.
-		return false;
-	}
-	
-	return true;
-}
-
-Handle:GetQueueList()
-{
-	new Handle:hArray = CreateArray(3);
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientParticipating(i)) continue;
-		if (IsPlayerGroupActive(ClientGetPlayerGroup(i))) continue;
-		
-		new index = PushArrayCell(hArray, i);
-		SetArrayCell(hArray, index, g_iPlayerQueuePoints[i], 1);
-		SetArrayCell(hArray, index, false, 2);
-	}
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		new index = PushArrayCell(hArray, i);
-		SetArrayCell(hArray, index, GetPlayerGroupQueuePoints(i), 1);
-		SetArrayCell(hArray, index, true, 2);
-	}
-	
-	if (GetArraySize(hArray)) SortADTArrayCustom(hArray, SortQueueList);
-	return hArray;
-}
-
-SetClientPlayState(client, bool:bState, bool:bEnablePlay=true)
-{
-	if (bState)
-	{
-		if (!g_bPlayerEliminated[client]) return;
-		
-		g_bPlayerEliminated[client] = false;
-		g_bPlayerPlaying[client] = bEnablePlay;
-		g_hPlayerSwitchBlueTimer[client] = INVALID_HANDLE;
-		
-		ClientSetGhostModeState(client, false);
-		
-		PvP_SetPlayerPvPState(client, false, false, false);
-		
-		if (g_bSpecialRound) 
-		{
-			SetClientPlaySpecialRoundState(client, true);
-		}
-		
-		if (g_bNewBossRound) 
-		{
-			SetClientPlayNewBossRoundState(client, true);
-		}
-		
-		if (TF2_GetPlayerClass(client) == TFClassType:0)
-		{
-			// Player hasn't chosen a class for some reason. Choose one for him.
-			TF2_SetPlayerClass(client, TFClassType:GetRandomInt(1, 9), true, true);
-		}
-		
-		ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
-	}
-	else
-	{
-		if (g_bPlayerEliminated[client]) return;
-		
-		g_bPlayerEliminated[client] = true;
-		g_bPlayerPlaying[client] = false;
-		
-		ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
-	}
-}
-
-bool:DidClientPlayNewBossRound(client)
-{
-	return g_bPlayerPlayedNewBossRound[client];
-}
-
-SetClientPlayNewBossRoundState(client, bool:bState)
-{
-	g_bPlayerPlayedNewBossRound[client] = bState;
-}
-
-bool:DidClientPlaySpecialRound(client)
-{
-	return g_bPlayerPlayedNewBossRound[client];
-}
-
-SetClientPlaySpecialRoundState(client, bool:bState)
-{
-	g_bPlayerPlayedSpecialRound[client] = bState;
-}
-
-TeleportClientToEscapePoint(client)
-{
-	if (!IsClientInGame(client)) return;
-	
-	new ent = EntRefToEntIndex(g_iRoundEscapePointEntity);
-	if (ent && ent != -1)
-	{
-		decl Float:flPos[3], Float:flAng[3];
-		GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
-		GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", flAng);
-		
-		TeleportEntity(client, flPos, flAng, Float:{ 0.0, 0.0, 0.0 });
-		AcceptEntityInput(ent, "FireUser1", client);
-	}
-}
-
-ForceInNextPlayersInQueue(iAmount, bool:bShowMessage=false)
-{
-	// Grab the next person in line, or the next group in line if space allows.
-	new iAmountLeft = iAmount;
-	new Handle:hPlayers = CreateArray();
-	new Handle:hArray = GetQueueList();
-	
-	for (new i = 0, iSize = GetArraySize(hArray); i < iSize && iAmountLeft > 0; i++)
-	{
-		if (!GetArrayCell(hArray, i, 2))
-		{
-			new iClient = GetArrayCell(hArray, i);
-			if (g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
-			
-			PushArrayCell(hPlayers, iClient);
-			iAmountLeft--;
-		}
-		else
-		{
-			new iGroupIndex = GetArrayCell(hArray, i);
-			if (!IsPlayerGroupActive(iGroupIndex)) continue;
-			
-			new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
-			if (iMemberCount <= iAmountLeft)
-			{
-				for (new iClient = 1; iClient <= MaxClients; iClient++)
-				{
-					if (!IsValidClient(iClient) || g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
-					if (ClientGetPlayerGroup(iClient) == iGroupIndex)
-					{
-						PushArrayCell(hPlayers, iClient);
-					}
-				}
-				
-				SetPlayerGroupPlaying(iGroupIndex, true);
-				
-				iAmountLeft -= iMemberCount;
-			}
-		}
-	}
-	
-	CloseHandle(hArray);
-	
-	for (new i = 0, iSize = GetArraySize(hPlayers); i < iSize; i++)
-	{
-		new iClient = GetArrayCell(hPlayers, i);
-		ClientSetQueuePoints(iClient, 0);
-		SetClientPlayState(iClient, true);
-		
-		if (bShowMessage) CPrintToChat(iClient, "%T", "SF2 Force Play", iClient);
-	}
-	
-	CloseHandle(hPlayers);
-}
-
-public SortQueueList(index1, index2, Handle:array, Handle:hndl)
-{
-	new iQueuePoints1 = GetArrayCell(array, index1, 1);
-	new iQueuePoints2 = GetArrayCell(array, index2, 1);
-	
-	if (iQueuePoints1 > iQueuePoints2) return -1;
-	else if (iQueuePoints1 == iQueuePoints2) return 0;
-	return 1;
-}
-
-//	==========================================================
-//	GENERIC PAGE/BOSS HOOKS AND FUNCTIONS
-//	==========================================================
-
-public Action:Hook_SlenderObjectSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (!IsPlayerAlive(other) || IsClientInDeathCam(other))
-	{
-		if (!IsValidEdict(GetEntPropEnt(other, Prop_Send, "m_hObserverTarget"))) return Plugin_Handled;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_SlenderBlinkBossThink(Handle:timer, any:entref)
-{
-	new slender = EntRefToEntIndex(entref);
-	if (!slender || slender == INVALID_ENT_REFERENCE) return Plugin_Stop;
-	
-	new iBossIndex = NPCGetFromEntIndex(slender);
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	if (timer != g_hSlenderEntityThink[iBossIndex]) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (NPCGetType(iBossIndex) == SF2BossType_Creeper)
-	{
-		new bool:bMove = false;
-		
-		if ((GetGameTime() - g_flSlenderLastKill[iBossIndex]) >= GetProfileFloat(sProfile, "kill_cooldown"))
-		{
-			if (PeopleCanSeeSlender(iBossIndex, false, false) && !PeopleCanSeeSlender(iBossIndex, true, SlenderUsesBlink(iBossIndex)))
-			{
-				new iBestPlayer = -1;
-				new Handle:hArray = CreateArray();
-				
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientInDeathCam(i) || g_bPlayerEliminated[i] || DidClientEscape(i) || IsClientInGhostMode(i) || !PlayerCanSeeSlender(i, iBossIndex, false, false)) continue;
-					PushArrayCell(hArray, i);
-				}
-				
-				if (GetArraySize(hArray))
-				{
-					decl Float:flSlenderPos[3];
-					SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
-					
-					decl Float:flTempPos[3];
-					new iTempPlayer = -1;
-					new Float:flTempDist = 16384.0;
-					for (new i = 0; i < GetArraySize(hArray); i++)
-					{
-						new iClient = GetArrayCell(hArray, i);
-						GetClientAbsOrigin(iClient, flTempPos);
-						if (GetVectorDistance(flTempPos, flSlenderPos) < flTempDist)
-						{
-							iTempPlayer = iClient;
-							flTempDist = GetVectorDistance(flTempPos, flSlenderPos);
-						}
-					}
-					
-					iBestPlayer = iTempPlayer;
-				}
-				
-				CloseHandle(hArray);
-				
-				decl Float:buffer[3];
-				if (iBestPlayer != -1 && SlenderCalculateApproachToPlayer(iBossIndex, iBestPlayer, buffer))
-				{
-					bMove = true;
-					
-					decl Float:flAng[3], Float:flBuffer[3];
-					decl Float:flSlenderPos[3], Float:flPos[3];
-					GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flSlenderPos);
-					GetClientAbsOrigin(iBestPlayer, flPos);
-					SubtractVectors(flPos, buffer, flAng);
-					GetVectorAngles(flAng, flAng);
-					
-					// Take care of angle offsets.
-					AddVectors(flAng, g_flSlenderEyeAngOffset[iBossIndex], flAng);
-					for (new i = 0; i < 3; i++) flAng[i] = AngleNormalize(flAng[i]);
-					
-					flAng[0] = 0.0;
-					
-					// Take care of position offsets.
-					GetProfileVector(sProfile, "pos_offset", flBuffer);
-					AddVectors(buffer, flBuffer, buffer);
-					
-					TeleportEntity(slender, buffer, flAng, NULL_VECTOR);
-					
-					new Float:flMaxRange = GetProfileFloat(sProfile, "teleport_range_max");
-					new Float:flDist = GetVectorDistance(buffer, flPos);
-					
-					decl String:sBuffer[PLATFORM_MAX_PATH];
-					
-					if (flDist < (flMaxRange * 0.33)) 
-					{
-						GetProfileString(sProfile, "model_closedist", sBuffer, sizeof(sBuffer));
-					}
-					else if (flDist < (flMaxRange * 0.66)) 
-					{
-						GetProfileString(sProfile, "model_averagedist", sBuffer, sizeof(sBuffer));
-					}
-					else 
-					{
-						GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
-					}
-					
-					// Fallback if error.
-					if (!sBuffer[0]) GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
-					
-					SetEntProp(slender, Prop_Send, "m_nModelIndex", PrecacheModel(sBuffer));
-					
-					if (flDist <= NPCGetInstantKillRadius(iBossIndex))
-					{
-						if (NPCGetFlags(iBossIndex) & SFF_FAKE)
-						{
-							SlenderMarkAsFake(iBossIndex);
-							return Plugin_Stop;
-						}
-						else
-						{
-							g_flSlenderLastKill[iBossIndex] = GetGameTime();
-							ClientStartDeathCam(iBestPlayer, iBossIndex, buffer);
-						}
-					}
-				}
-			}
-		}
-		
-		if (bMove)
-		{
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_move_single", sBuffer, sizeof(sBuffer));
-			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-			
-			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
-			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, SND_CHANGEVOL);
-		}
-		else
-		{
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
-			if (sBuffer[0]) StopSound(slender, SNDCHAN_AUTO, sBuffer);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-
-SlenderOnClientStressUpdate(client)
-{
-	new Float:flStress = g_flPlayerStress[client];
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
-	{	
-		if (NPCGetUniqueID(iBossIndex) == -1) continue;
-		
-		new iBossFlags = NPCGetFlags(iBossIndex);
-		if (iBossFlags & SFF_MARKEDASFAKE ||
-			iBossFlags & SFF_NOTELEPORT)
-		{
-			continue;
-		}
-		
-		NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-		
-		new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
-		if (iTeleportTarget && iTeleportTarget != INVALID_ENT_REFERENCE)
-		{
-			if (g_bPlayerEliminated[iTeleportTarget] ||
-				DidClientEscape(iTeleportTarget) ||
-				flStress >= g_flSlenderTeleportMaxTargetStress[iBossIndex] ||
-				GetGameTime() >= g_flSlenderTeleportMaxTargetTime[iBossIndex])
-			{
-				// Queue for a new target and mark the old target in the rest period.
-				new Float:flRestPeriod = GetProfileFloat(sProfile, "teleport_target_rest_period", 15.0);
-				flRestPeriod = (flRestPeriod * GetRandomFloat(0.92, 1.08)) / (NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier);
-				
-				g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
-				g_flSlenderTeleportPlayersRestTime[iBossIndex][iTeleportTarget] = GetGameTime() + flRestPeriod;
-				g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
-				g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
-				g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: lost target, putting at rest period", iBossIndex);
-#endif
-			}
-		}
-		else if (!g_bRoundGrace)
-		{
-			new iPreferredTeleportTarget = INVALID_ENT_REFERENCE;
-			
-			new Float:flTargetStressMin = GetProfileFloat(sProfile, "teleport_target_stress_min", 0.2);
-			new Float:flTargetStressMax = GetProfileFloat(sProfile, "teleport_target_stress_max", 0.9);
-			
-			new Float:flTargetStress = flTargetStressMax - ((flTargetStressMax - flTargetStressMin) / (g_flRoundDifficultyModifier * NPCGetAnger(iBossIndex)));
-			
-			new Float:flPreferredTeleportTargetStress = flTargetStress;
-			
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) ||
-					!IsPlayerAlive(i) ||
-					g_bPlayerEliminated[i] ||
-					IsClientInGhostMode(i) ||
-					DidClientEscape(i))
-				{
-					continue;
-				}
-				
-				if (g_flPlayerStress[i] < flPreferredTeleportTargetStress)
-				{
-					if (g_flSlenderTeleportPlayersRestTime[iBossIndex][i] <= GetGameTime())
-					{
-						iPreferredTeleportTarget = i;
-						flPreferredTeleportTargetStress = g_flPlayerStress[i];
-					}
-				}
-			}
-			
-			if (iPreferredTeleportTarget && iPreferredTeleportTarget != INVALID_ENT_REFERENCE)
-			{
-				// Set our preferred target to the new guy.
-				new Float:flTargetDuration = GetProfileFloat(sProfile, "teleport_target_persistency_period", 13.0);
-				new Float:flDeviation = GetRandomFloat(0.92, 1.08);
-				flTargetDuration = Pow(flDeviation * flTargetDuration, ((g_flRoundDifficultyModifier * (NPCGetAnger(iBossIndex) - 1.0)) / 2.0)) + ((flDeviation * flTargetDuration) - 1.0);
-				
-				g_iSlenderTeleportTarget[iBossIndex] = EntIndexToEntRef(iPreferredTeleportTarget);
-				g_flSlenderTeleportPlayersRestTime[iBossIndex][iPreferredTeleportTarget] = -1.0;
-				g_flSlenderTeleportMaxTargetTime[iBossIndex] = GetGameTime() + flTargetDuration;
-				g_flSlenderTeleportTargetTime[iBossIndex] = GetGameTime();
-				g_flSlenderTeleportMaxTargetStress[iBossIndex] = flTargetStress;
-				
-				iTeleportTarget = iPreferredTeleportTarget;
-				
-#if defined DEBUG
-				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: got new target %N", iBossIndex, iPreferredTeleportTarget);
-#endif
-			}
-		}
-	}
-}
-
-static GetPageMusicRanges()
-{
-	ClearArray(g_hPageMusicRanges);
-	
-	decl String:sName[64];
-	
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		
-		if (sName[0] && !StrContains(sName, "sf2_page_music_", false))
-		{
-			ReplaceString(sName, sizeof(sName), "sf2_page_music_", "", false);
-			
-			new String:sPageRanges[2][32];
-			ExplodeString(sName, "-", sPageRanges, 2, 32);
-			
-			new iIndex = PushArrayCell(g_hPageMusicRanges, EntIndexToEntRef(ent));
-			if (iIndex != -1)
-			{
-				new iMin = StringToInt(sPageRanges[0]);
-				new iMax = StringToInt(sPageRanges[1]);
-				
-#if defined DEBUG
-				DebugMessage("Page range found: entity %d, iMin = %d, iMax = %d", ent, iMin, iMax);
-#endif
-				SetArrayCell(g_hPageMusicRanges, iIndex, iMin, 1);
-				SetArrayCell(g_hPageMusicRanges, iIndex, iMax, 2);
-			}
-		}
-	}
-	
-	// precache
-	if (GetArraySize(g_hPageMusicRanges) > 0)
-	{
-		decl String:sPath[PLATFORM_MAX_PATH];
-		
-		for (new i = 0; i < GetArraySize(g_hPageMusicRanges); i++)
-		{
-			ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
-			if (!ent || ent == INVALID_ENT_REFERENCE) continue;
-			
-			GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-			if (sPath[0])
-			{
-				PrecacheSound(sPath);
-			}
-		}
-	}
-	
-	LogSF2Message("Loaded page music ranges successfully!");
-}
-
-SetPageCount(iNum)
-{
-	if (iNum > g_iPageMax) iNum = g_iPageMax;
-	
-	new iOldPageCount = g_iPageCount;
-	g_iPageCount = iNum;
-	
-	if (g_iPageCount != iOldPageCount)
-	{
-		if (g_iPageCount > iOldPageCount)
-		{
-			if (g_hRoundGraceTimer != INVALID_HANDLE) 
-			{
-				TriggerTimer(g_hRoundGraceTimer);
-			}
-			
-			g_iRoundTime += g_iRoundTimeGainFromPage;
-			if (g_iRoundTime > g_iRoundTimeLimit) g_iRoundTime = g_iRoundTimeLimit;
-			
-			// Increase anger on selected bosses.
-			for (new i = 0; i < MAX_BOSSES; i++)
-			{
-				if (NPCGetUniqueID(i) == -1) continue;
-				
-				new Float:flPageDiff = NPCGetAngerAddOnPageGrabTimeDiff(i);
-				if (flPageDiff >= 0.0)
-				{
-					new iDiff = g_iPageCount - iOldPageCount;
-					if ((GetGameTime() - g_flPageFoundLastTime) < flPageDiff)
-					{
-						NPCAddAnger(i, NPCGetAngerAddOnPageGrab(i) * float(iDiff));
-					}
-				}
-			}
-			
-			g_flPageFoundLastTime = GetGameTime();
-		}
-		
-		// Notify logic entities.
-		decl String:sTargetName[64];
-		decl String:sFindTargetName[64];
-		Format(sFindTargetName, sizeof(sFindTargetName), "sf2_onpagecount_%d", g_iPageCount);
-		
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
-		{
-			GetEntPropString(ent, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
-			if (sTargetName[0] && StrEqual(sTargetName, sFindTargetName, false))
-			{
-				AcceptEntityInput(ent, "Trigger");
-				break;
-			}
-		}
-	
-		new iClients[MAXPLAYERS + 1] = { -1, ... };
-		new iClientsNum = 0;
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i)) continue;
-			if (!g_bPlayerEliminated[i] || IsClientInGhostMode(i))
-			{
-				if (g_iPageCount)
-				{
-					iClients[iClientsNum] = i;
-					iClientsNum++;
-				}
-			}
-		}
-		
-		if (g_iPageCount > 0 && g_bRoundHasEscapeObjective && g_iPageCount == g_iPageMax)
-		{
-			// Escape initialized!
-			SetRoundState(SF2RoundState_Escape);
-			
-			if (iClientsNum)
-			{
-				new iGameTextEscape = GetTextEntity("sf2_escape_message", false);
-				if (iGameTextEscape != -1)
-				{
-					// Custom escape message.
-					decl String:sMessage[512];
-					GetEntPropString(iGameTextEscape, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextEscape, g_hHudSync, sMessage);
-				}
-				else
-				{
-					// Default escape message.
-					for (new i = 0; i < iClientsNum; i++)
-					{
-						new client = iClients[i];
-						ClientShowMainMessage(client, "%d/%d\n%T", g_iPageCount, g_iPageMax, "SF2 Default Escape Message", i);
-					}
-				}
-			}
-		}
-		else
-		{
-			if (iClientsNum)
-			{
-				new iGameTextPage = GetTextEntity("sf2_page_message", false);
-				if (iGameTextPage != -1)
-				{
-					// Custom page message.
-					decl String:sMessage[512];
-					GetEntPropString(iGameTextPage, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextPage, g_hHudSync, sMessage, g_iPageCount, g_iPageMax);
-				}
-				else
-				{
-					// Default page message.
-					for (new i = 0; i < iClientsNum; i++)
-					{
-						new client = iClients[i];
-						ClientShowMainMessage(client, "%d/%d", g_iPageCount, g_iPageMax);
-					}
-				}
-			}
-		}
-		
-		CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
-	}
-}
-
-GetTextEntity(const String:sTargetName[], bool:bCaseSensitive=true)
-{
-	// Try to see if we can use a custom message instead of the default.
-	decl String:targetName[64];
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "game_text")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
-		if (targetName[0])
-		{
-			if (StrEqual(targetName, sTargetName, bCaseSensitive))
-			{
-				return ent;
-			}
-		}
-	}
-	
-	return -1;
-}
-
-ShowHudTextUsingTextEntity(const iClients[], iClientsNum, iGameText, Handle:hHudSync, const String:sMessage[], ...)
-{
-	if (!sMessage[0]) return;
-	if (!IsValidEntity(iGameText)) return;
-	
-	decl String:sTrueMessage[512];
-	VFormat(sTrueMessage, sizeof(sTrueMessage), sMessage, 6);
-	
-	new Float:flX = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.x");
-	new Float:flY = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.y");
-	new iEffect = GetEntProp(iGameText, Prop_Data, "m_textParms.effect");
-	new Float:flFadeInTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime");
-	new Float:flFadeOutTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime");
-	new Float:flHoldTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
-	new Float:flFxTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fxTime");
-	
-	new Color1[4] = { 255, 255, 255, 255 };
-	new Color2[4] = { 255, 255, 255, 255 };
-	
-	new iParmsOffset = FindDataMapOffs(iGameText, "m_textParms");
-	if (iParmsOffset != -1)
-	{
-		// hudtextparms_s m_textParms
-		
-		Color1[0] = GetEntData(iGameText, iParmsOffset + 12, 1);
-		Color1[1] = GetEntData(iGameText, iParmsOffset + 13, 1);
-		Color1[2] = GetEntData(iGameText, iParmsOffset + 14, 1);
-		Color1[3] = GetEntData(iGameText, iParmsOffset + 15, 1);
-		
-		Color2[0] = GetEntData(iGameText, iParmsOffset + 16, 1);
-		Color2[1] = GetEntData(iGameText, iParmsOffset + 17, 1);
-		Color2[2] = GetEntData(iGameText, iParmsOffset + 18, 1);
-		Color2[3] = GetEntData(iGameText, iParmsOffset + 19, 1);
-	}
-	
-	SetHudTextParamsEx(flX, flY, flHoldTime, Color1, Color2, iEffect, flFxTime, flFadeInTime, flFadeOutTime);
-	
-	for (new i = 0; i < iClientsNum; i++)
-	{
-		new iClient = iClients[i];
-		if (!IsValidClient(iClient) || IsFakeClient(iClient)) continue;
-		
-		ShowSyncHudText(iClient, hHudSync, sTrueMessage);
-	}
-}
-
-//	==========================================================
-//	EVENT HOOKS
-//	==========================================================
-
-public Event_RoundStart(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundStart");
-#endif
-	
-	// Reset some global variables.
-	g_iRoundCount++;
-	g_hRoundTimer = INVALID_HANDLE;
-	
-	SetRoundState(SF2RoundState_Invalid);
-	
-	SetPageCount(0);
-	g_iPageMax = 0;
-	g_flPageFoundLastTime = GetGameTime();
-	
-	g_hVoteTimer = INVALID_HANDLE;
-	
-	// Remove all bosses from the game.
-	NPCRemoveAll();
-	
-	// Refresh groups.
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		SetPlayerGroupPlaying(i, false);
-		CheckPlayerGroup(i);
-	}
-	
-	// Refresh players.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		ClientSetGhostModeState(i, false);
-		
-		g_bPlayerPlaying[i] = false;
-		g_bPlayerEliminated[i] = true;
-		g_bPlayerEscaped[i] = false;
-	}
-	
-	// Calculate the new round state.
-	if (g_bRoundWaitingForPlayers)
-	{
-		SetRoundState(SF2RoundState_Waiting);
-	}
-	else if (GetConVarBool(g_cvWarmupRound) && g_iRoundWarmupRoundCount < GetConVarInt(g_cvWarmupRoundNum))
-	{
-		g_iRoundWarmupRoundCount++;
-		
-		SetRoundState(SF2RoundState_Waiting);
-		
-		ServerCommand("mp_restartgame 15");
-		PrintCenterTextAll("Round restarting in 15 seconds");
-	}
-	else
-	{
-		g_iRoundActiveCount++;
-		
-		InitializeNewGame();
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundStart");
-#endif
-}
-
-public Event_RoundEnd(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundEnd");
-#endif
-	
-	SetRoundState(SF2RoundState_Outro);
-	
-	DistributeQueuePointsToPlayers();
-	
-	g_iRoundEndCount++;	
-	CheckRoundLimitForBossPackVote(g_iRoundEndCount);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundEnd");
-#endif
-}
-
-static DistributeQueuePointsToPlayers()
-{
-	// Give away queue points.
-	new iDefaultAmount = 5;
-	new iAmount = iDefaultAmount;
-	new iAmount2 = iAmount;
-	new Action:iAction = Plugin_Continue;
-	
-	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-	{
-		if (!IsPlayerGroupActive(i)) continue;
-		
-		if (IsPlayerGroupPlaying(i))
-		{
-			SetPlayerGroupQueuePoints(i, 0);
-		}
-		else
-		{
-			iAmount = iDefaultAmount;
-			iAmount2 = iAmount;
-			iAction = Plugin_Continue;
-			
-			Call_StartForward(fOnGroupGiveQueuePoints);
-			Call_PushCell(i);
-			Call_PushCellRef(iAmount2);
-			Call_Finish(iAction);
-			
-			if (iAction == Plugin_Changed) iAmount = iAmount2;
-			
-			SetPlayerGroupQueuePoints(i, GetPlayerGroupQueuePoints(i) + iAmount);
-		
-			for (new iClient = 1; iClient <= MaxClients; iClient++)
-			{
-				if (!IsValidClient(iClient)) continue;
-				if (ClientGetPlayerGroup(iClient) == i)
-				{
-					CPrintToChat(iClient, "%T", "SF2 Give Group Queue Points", iClient, iAmount);
-				}
-			}
-		}
-	}
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (g_bPlayerPlaying[i]) 
-		{
-			ClientSetQueuePoints(i, 0);
-		}
-		else
-		{
-			if (!IsClientParticipating(i))
-			{
-				CPrintToChat(i, "%T", "SF2 No Queue Points To Spectator", i);
-			}
-			else
-			{
-				iAmount = iDefaultAmount;
-				iAmount2 = iAmount;
-				iAction = Plugin_Continue;
-				
-				Call_StartForward(fOnClientGiveQueuePoints);
-				Call_PushCell(i);
-				Call_PushCellRef(iAmount2);
-				Call_Finish(iAction);
-				
-				if (iAction == Plugin_Changed) iAmount = iAmount2;
-				
-				ClientSetQueuePoints(i, g_iPlayerQueuePoints[i] + iAmount);
-				CPrintToChat(i, "%T", "SF2 Give Queue Points", i, iAmount);
-			}
-		}	
-	}
-}
-
-public Action:Event_PlayerTeamPre(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerTeamPre");
-#endif
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client > 0)
-	{
-		if (GetEventInt(event, "team") > 1 || GetEventInt(event, "oldteam") > 1) SetEventBroadcast(event, true);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerTeamPre");
-#endif
-	
-	return Plugin_Continue;
-}
-
-public Event_PlayerTeam(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerTeam");
-#endif
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client > 0)
-	{
-		new iNewTeam = GetEventInt(event, "team");
-		if (iNewTeam <= _:TFTeam_Spectator)
-		{
-			if (g_bRoundGrace)
-			{
-				if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
-				{
-					ForceInNextPlayersInQueue(1, true);
-				}
-			}
-			
-			// You're not playing anymore.
-			if (g_bPlayerPlaying[client])
-			{
-				ClientSetQueuePoints(client, 0);
-			}
-			
-			g_bPlayerPlaying[client] = false;
-			g_bPlayerEliminated[client] = true;
-			g_bPlayerEscaped[client] = false;
-			
-			ClientSetGhostModeState(client, false);
-			
-			if (!bool:GetEntProp(client, Prop_Send, "m_bIsCoaching"))
-			{
-				// This is to prevent player spawn spam when someone is coaching. Who coaches in SF2, anyway?
-				TF2_RespawnPlayer(client);
-			}
-			
-			// Special round.
-			if (g_bSpecialRound) g_bPlayerPlayedSpecialRound[client] = true;
-			
-			// Boss round.
-			if (g_bNewBossRound) g_bPlayerPlayedNewBossRound[client] = true;
-		}
-		else
-		{
-			if (!g_bPlayerChoseTeam[client])
-			{
-				g_bPlayerChoseTeam[client] = true;
-				
-				if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
-				{
-					EmitSoundToClient(client, SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
-					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Projected{olive}.");
-				}
-				else
-				{
-					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Normal{olive}.");
-				}
-				
-				CreateTimer(5.0, Timer_WelcomeMessage, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-			}
-		}
-	}
-	
-	// Check groups.
-	if (!IsRoundEnding())
-	{
-		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
-		{
-			if (!IsPlayerGroupActive(i)) continue;
-			CheckPlayerGroup(i);
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerTeam");
-#endif
-
-}
-
-/**
- *	Sets the player to the correct team if needed. Returns true if a change was necessary, false if no change occurred.
- */
-static bool:HandlePlayerTeam(client, bool:bRespawn=true)
-{
-	if (!IsClientInGame(client) || !IsClientParticipating(client)) return false;
-	
-	if (!g_bPlayerEliminated[client])
-	{
-		if (GetClientTeam(client) != _:TFTeam_Red)
-		{
-			if (bRespawn)
-				ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
-			else
-				ChangeClientTeam(client, _:TFTeam_Red);
-				
-			return true;
-		}
-	}
-	else
-	{
-		if (GetClientTeam(client) != _:TFTeam_Blue)
-		{
-			if (bRespawn)
-				ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
-			else
-				ChangeClientTeam(client, _:TFTeam_Blue);
-				
-			return true;
-		}
-	}
-	
-	return false;
-}
-
-static HandlePlayerIntroState(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client) || !IsClientParticipating(client)) return;
-	
-	if (!IsRoundInIntro()) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START HandlePlayerIntroState(%d)", client);
-#endif
-	
-	// Disable movement on player.
-	SetEntityFlags(client, GetEntityFlags(client) | FL_FROZEN);
-	
-	new Float:flDelay = 0.0;
-	if (!IsFakeClient(client))
-	{
-		flDelay = GetClientLatency(client, NetFlow_Outgoing);
-	}
-	
-	CreateTimer(flDelay * 4.0, Timer_IntroBlackOut, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END HandlePlayerIntroState(%d)", client);
-#endif
-}
-
-HandlePlayerHUD(client)
-{
-	if (IsRoundInWarmup() || IsClientInGhostMode(client))
-	{
-		SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
-	}
-	else
-	{
-		if (!g_bPlayerEliminated[client])
-		{
-			if (!DidClientEscape(client))
-			{
-				// Player is in the game; disable normal HUD.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
-			}
-			else
-			{
-				// Player isn't in the game; enable normal HUD behavior.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
-			}
-		}
-		else
-		{
-			if (g_bPlayerProxy[client])
-			{
-				// Player is in the game; disable normal HUD.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
-			}
-			else
-			{
-				// Player isn't in the game; enable normal HUD behavior.
-				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
-			}
-		}
-	}
-}
-
-public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client <= 0) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerSpawn(%d)", client);
-#endif
-	
-	if (!IsClientParticipating(client))
-	{
-		ClientSetGhostModeState(client, false);
-	}
-	
-	g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
-	
-	if (IsPlayerAlive(client) && IsClientParticipating(client))
-	{
-		if (HandlePlayerTeam(client))
-		{
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("client->HandlePlayerTeam()");
-#endif
-		}
-		else
-		{
-			g_iPlayerPageCount[client] = 0;
-			
-			ClientDisableFakeLagCompensation(client);
-			
-			ClientResetStatic(client);
-			ClientResetSlenderStats(client);
-			ClientResetCampingStats(client);
-			ClientResetOverlay(client);
-			ClientResetJumpScare(client);
-			ClientUpdateListeningFlags(client);
-			ClientUpdateMusicSystem(client);
-			ClientChaseMusicReset(client);
-			ClientChaseMusicSeeReset(client);
-			ClientAlertMusicReset(client);
-			Client20DollarsMusicReset(client);
-			ClientMusicReset(client);
-			ClientResetProxy(client);
-			ClientResetHints(client);
-			ClientResetScare(client);
-			
-			ClientResetDeathCam(client);
-			ClientResetFlashlight(client);
-			ClientDeactivateUltravision(client);
-			ClientResetSprint(client);
-			ClientResetBreathing(client);
-			ClientResetBlink(client);
-			ClientResetInteractiveGlow(client);
-			ClientDisableConstantGlow(client);
-			
-			ClientHandleGhostMode(client);
-			
-			if (!g_bPlayerEliminated[client])
-			{
-				ClientStartDrainingBlinkMeter(client);
-				ClientSetScareBoostEndTime(client, -1.0);
-				
-				ClientStartCampingTimer(client);
-				
-				HandlePlayerIntroState(client);
-				
-				// screen overlay timer
-				g_hPlayerOverlayCheck[client] = CreateTimer(0.0, Timer_PlayerOverlayCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-				TriggerTimer(g_hPlayerOverlayCheck[client], true);
-				
-				if (DidClientEscape(client))
-				{
-					CreateTimer(0.1, Timer_TeleportPlayerToEscapePoint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-				else
-				{
-					ClientEnableConstantGlow(client, "head");
-					ClientActivateUltravision(client);
-				}
-			}
-			else
-			{
-				g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
-			}
-			
-			g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-			
-			HandlePlayerHUD(client);
-		}
-	}
-	
-	PvP_OnPlayerSpawn(client);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerSpawn(%d)", client);
-#endif
-}
-
-public Action:Timer_IntroBlackOut(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (!IsRoundInIntro()) return;
-	
-	if (!IsPlayerAlive(client) || g_bPlayerEliminated[client]) return;
-	
-	// Black out the player's screen.
-	new iFadeFlags = FFADE_OUT | FFADE_STAYOUT | FFADE_PURGE;
-	UTIL_ScreenFade(client, 0, FixedUnsigned16(90.0, 1 << 12), iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
-}
-
-public Event_PostInventoryApplication(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PostInventoryApplication");
-#endif
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client > 0)
-	{
-		g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PostInventoryApplication");
-#endif
-}
-
-public Action:Event_DontBroadcastToClients(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	if (IsRoundInWarmup()) return Plugin_Continue;
-	
-	SetEventBroadcast(event, true);
-	return Plugin_Continue;
-}
-
-public Action:Event_PlayerDeathPre(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerDeathPre");
-#endif
-	
-	if (!IsRoundInWarmup())
-	{
-		new client = GetClientOfUserId(GetEventInt(event, "userid"));
-		if (client > 0)
-		{
-			if (!IsRoundEnding())
-			{
-				if (g_bRoundGrace || g_bPlayerEliminated[client] || IsClientInGhostMode(client))
-				{
-					SetEventBroadcast(event, true);
-				}
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerDeathPre");
-#endif
-	
-	return Plugin_Continue;
-}
-
-public Event_PlayerHurt(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client <= 0) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerHurt");
-#endif
-	
-	ClientDisableFakeLagCompensation(client);
-	
-	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
-	if (attacker > 0)
-	{
-		if (g_bPlayerProxy[attacker])
-		{
-			g_iPlayerProxyControl[attacker] = 100;
-		}
-	}
-	
-	// Play any sounds, if any.
-	if (g_bPlayerProxy[client])
-	{
-		new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-		if (iProxyMaster != -1)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
-		
-			decl String:sBuffer[PLATFORM_MAX_PATH];
-			if (GetRandomStringFromProfile(sProfile, "sound_proxy_hurt", sBuffer, sizeof(sBuffer)) && sBuffer[0])
-			{
-				new iChannel = GetProfileNum(sProfile, "sound_proxy_hurt_channel", SNDCHAN_AUTO);
-				new iLevel = GetProfileNum(sProfile, "sound_proxy_hurt_level", SNDLEVEL_NORMAL);
-				new iFlags = GetProfileNum(sProfile, "sound_proxy_hurt_flags", SND_NOFLAGS);
-				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_hurt_volume", SNDVOL_NORMAL);
-				new iPitch = GetProfileNum(sProfile, "sound_proxy_hurt_pitch", SNDPITCH_NORMAL);
-				
-				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerHurt");
-#endif
-}
-
-public Event_PlayerDeath(Handle:event, const String:name[], bool:dB)
-{
-	if (!g_bEnabled) return;
-	
-	new client = GetClientOfUserId(GetEventInt(event, "userid"));
-	if (client <= 0) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerDeath(%d)", client);
-#endif
-	
-	new bool:bFake = bool:(GetEventInt(event, "death_flags") & TF_DEATHFLAG_DEADRINGER);
-	new inflictor = GetEventInt(event, "inflictor_entindex");
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("inflictor = %d", inflictor);
-#endif
-	
-	if (!bFake)
-	{
-		ClientDisableFakeLagCompensation(client);
-		
-		ClientResetStatic(client);
-		ClientResetSlenderStats(client);
-		ClientResetCampingStats(client);
-		ClientResetOverlay(client);
-		ClientResetJumpScare(client);
-		ClientResetInteractiveGlow(client);
-		ClientDisableConstantGlow(client);
-		ClientChaseMusicReset(client);
-		ClientChaseMusicSeeReset(client);
-		ClientAlertMusicReset(client);
-		Client20DollarsMusicReset(client);
-		ClientMusicReset(client);
-		
-		ClientResetFlashlight(client);
-		ClientDeactivateUltravision(client);
-		ClientResetSprint(client);
-		ClientResetBreathing(client);
-		ClientResetBlink(client);
-		ClientResetDeathCam(client);
-		
-		ClientUpdateMusicSystem(client);
-		
-		PvP_SetPlayerPvPState(client, false, false, false);
-		
-		if (IsRoundInWarmup())
-		{
-			CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-		}
-		else
-		{
-			if (!g_bPlayerEliminated[client])
-			{
-				if (IsRoundInIntro() || g_bRoundGrace || DidClientEscape(client))
-				{
-					CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-				else
-				{
-					g_bPlayerEliminated[client] = true;
-					g_bPlayerEscaped[client] = false;
-					g_hPlayerSwitchBlueTimer[client] = CreateTimer(0.5, Timer_PlayerSwitchToBlue, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-				}
-			}
-			else
-			{
-			}
-			
-			{
-				// If this player was killed by a boss, play a sound.
-				new npcIndex = NPCGetFromEntIndex(inflictor);
-				if (npcIndex != -1)
-				{
-					decl String:npcProfile[SF2_MAX_PROFILE_NAME_LENGTH], String:buffer[PLATFORM_MAX_PATH];
-					NPCGetProfile(npcIndex, npcProfile, sizeof(npcProfile));
-					
-					if (GetRandomStringFromProfile(npcProfile, "sound_attack_killed_all", buffer, sizeof(buffer)) && strlen(buffer) > 0)
-					{
-						if (!g_bPlayerEliminated[client])
-						{
-							EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_HELICOPTER);
-						}
-					}
-					
-					SlenderPerformVoice(npcIndex, "sound_attack_killed");
-				}
-			}
-			
-			CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
-			
-			// Notify to other bosses that this player has died.
-			for (new i = 0; i < MAX_BOSSES; i++)
-			{
-				if (NPCGetUniqueID(i) == -1) continue;
-				
-				if (EntRefToEntIndex(g_iSlenderTarget[i]) == client)
-				{
-					g_iSlenderInterruptConditions[i] |= COND_CHASETARGETINVALIDATED;
-					GetClientAbsOrigin(client, g_flSlenderChaseDeathPosition[i]);
-				}
-			}
-		}
-		
-		if (g_bPlayerProxy[client])
-		{
-			// We're a proxy, so play some sounds.
-		
-			new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-			if (iProxyMaster != -1)
-			{
-				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-				NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
-				
-				decl String:sBuffer[PLATFORM_MAX_PATH];
-				if (GetRandomStringFromProfile(sProfile, "sound_proxy_death", sBuffer, sizeof(sBuffer)) && sBuffer[0])
-				{
-					new iChannel = GetProfileNum(sProfile, "sound_proxy_death_channel", SNDCHAN_AUTO);
-					new iLevel = GetProfileNum(sProfile, "sound_proxy_death_level", SNDLEVEL_NORMAL);
-					new iFlags = GetProfileNum(sProfile, "sound_proxy_death_flags", SND_NOFLAGS);
-					new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_death_volume", SNDVOL_NORMAL);
-					new iPitch = GetProfileNum(sProfile, "sound_proxy_death_pitch", SNDPITCH_NORMAL);
-					
-					EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
-				}
-			}
-		}
-		
-		ClientResetProxy(client, false);
-		ClientUpdateListeningFlags(client);
-		
-		// Half-Zatoichi nerf code.
-		new iKatanaHealthGain = GetConVarInt(g_cvHalfZatoichiHealthGain);
-		if (iKatanaHealthGain >= 0)
-		{
-			new iAttacker = GetClientOfUserId(GetEventInt(event, "attacker"));
-			if (iAttacker > 0)
-			{
-				if (!IsClientInPvP(iAttacker) && (!g_bPlayerEliminated[iAttacker] || g_bPlayerProxy[iAttacker]))
-				{
-					decl String:sWeapon[64];
-					GetEventString(event, "weapon", sWeapon, sizeof(sWeapon));
-					
-					if (StrEqual(sWeapon, "demokatana"))
-					{
-						new iAttackerPreHealth = GetEntProp(iAttacker, Prop_Send, "m_iHealth");
-						new Handle:hPack = CreateDataPack();
-						WritePackCell(hPack, GetClientUserId(iAttacker));
-						WritePackCell(hPack, iAttackerPreHealth + iKatanaHealthGain);
-						
-						CreateTimer(0.0, Timer_SetPlayerHealth, hPack, TIMER_FLAG_NO_MAPCHANGE);
-					}
-				}
-			}
-		}
-		
-		g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
-	}
-	
-	PvP_OnPlayerDeath(client, bFake);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerDeath(%d)", client);
-#endif
-}
-
-public Action:Timer_SetPlayerHealth(Handle:timer, any:data)
-{
-	new Handle:hPack = Handle:data;
-	ResetPack(hPack);
-	new iAttacker = GetClientOfUserId(ReadPackCell(hPack));
-	new iHealth = ReadPackCell(hPack);
-	CloseHandle(hPack);
-	
-	if (iAttacker <= 0) return;
-	
-	SetEntProp(iAttacker, Prop_Data, "m_iHealth", iHealth);
-	SetEntProp(iAttacker, Prop_Send, "m_iHealth", iHealth);
-}
-
-public Action:Timer_PlayerSwitchToBlue(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerSwitchBlueTimer[client]) return;
-	
-	ChangeClientTeam(client, _:TFTeam_Blue);
-}
-
-public Action:Timer_RoundStart(Handle:timer)
-{
-	if (g_iPageMax > 0)
-	{
-		new Handle:hArrayClients = CreateArray();
-		new iClients[MAXPLAYERS + 1];
-		new iClientsNum = 0;
-		
-		new iGameText = GetTextEntity("sf2_intro_message", false);
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || IsFakeClient(i) || g_bPlayerEliminated[i]) continue;
-			
-			if (iGameText == -1)
-			{
-				if (g_iPageMax > 1)
-				{
-					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Plural", i, g_iPageMax);
-				}
-				else
-				{
-					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Singular", i, g_iPageMax);
-				}
-			}
-			
-			PushArrayCell(hArrayClients, GetClientUserId(i));
-			iClients[iClientsNum] = i;
-			iClientsNum++;
-		}
-		
-		// Show difficulty menu.
-		if (iClientsNum)
-		{
-			// Automatically set it to Normal.
-			SetConVarInt(g_cvDifficulty, Difficulty_Normal);
-			
-			g_hVoteTimer = CreateTimer(1.0, Timer_VoteDifficulty, hArrayClients, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			TriggerTimer(g_hVoteTimer, true);
-			
-			if (iGameText != -1)
-			{
-				decl String:sMessage[512];
-				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-				
-				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
-			}
-		}
-		else
-		{
-			CloseHandle(hArrayClients);
-		}
-	}
-}
-
-public Action:Timer_CheckRoundWinConditions(Handle:timer)
-{
-	CheckRoundWinConditions();
-}
-
-public Action:Timer_RoundGrace(Handle:timer)
-{
-	if (timer != g_hRoundGraceTimer) return;
-	
-	g_bRoundGrace = false;
-	g_hRoundGraceTimer = INVALID_HANDLE;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientParticipating(i)) g_bPlayerEliminated[i] = true;
-	}
-	
-	// Initialize the main round timer.
-	if (g_iRoundTimeLimit > 0)
-	{
-		// Set round time.
-		g_iRoundTime = g_iRoundTimeLimit;
-		g_hRoundTimer = CreateTimer(1.0, Timer_RoundTime, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	}
-	else
-	{
-		// Infinite round time.
-		g_hRoundTimer = INVALID_HANDLE;
-	}
-	
-	CPrintToChatAll("{olive}%t", "SF2 Grace Period End");
-}
-
-public Action:Timer_RoundTime(Handle:timer)
-{
-	if (timer != g_hRoundTimer) return Plugin_Stop;
-	
-	if (g_iRoundTime <= 0)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i)) continue;
-			
-			decl Float:flBuffer[3];
-			GetClientAbsOrigin(i, flBuffer);
-			SDKHooks_TakeDamage(i, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-		}
-		
-		return Plugin_Stop;
-	}
-	
-	g_iRoundTime--;
-	
-	new hours, minutes, seconds;
-	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
-	
-	SetHudTextParams(-1.0, 0.1, 
-		1.0,
-		SF2_HUD_TEXT_COLOR_R, SF2_HUD_TEXT_COLOR_G, SF2_HUD_TEXT_COLOR_B, SF2_HUD_TEXT_COLOR_A,
-		_,
-		_,
-		1.5, 1.5);
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
-		ShowSyncHudText(i, g_hRoundTimerSync, "%d/%d\n%d:%02d", g_iPageCount, g_iPageMax, minutes, seconds);
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_RoundTimeEscape(Handle:timer)
-{
-	if (timer != g_hRoundTimer) return Plugin_Stop;
-	
-	if (g_iRoundTime <= 0)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i) || DidClientEscape(i)) continue;
-			
-			decl Float:flBuffer[3];
-			GetClientAbsOrigin(i, flBuffer);
-			ClientStartDeathCam(i, 0, flBuffer);
-		}
-		
-		return Plugin_Stop;
-	}
-	
-	new hours, minutes, seconds;
-	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
-	
-	SetHudTextParams(-1.0, 0.1, 
-		1.0,
-		SF2_HUD_TEXT_COLOR_R, 
-		SF2_HUD_TEXT_COLOR_G, 
-		SF2_HUD_TEXT_COLOR_B, 
-		SF2_HUD_TEXT_COLOR_A,
-		_,
-		_,
-		1.5, 1.5);
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
-		ShowSyncHudText(i, g_hRoundTimerSync, "%T\n%d:%02d", "SF2 Default Escape Message", i, minutes, seconds);
-	}
-	
-	g_iRoundTime--;
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_VoteDifficulty(Handle:timer, any:data)
-{
-	new Handle:hArrayClients = Handle:data;
-	
-	if (timer != g_hVoteTimer || IsRoundEnding()) 
-	{
-		CloseHandle(hArrayClients);
-		return Plugin_Stop;
-	}
-	
-	if (IsVoteInProgress()) return Plugin_Continue; // There's another vote in progess. Wait.
-	
-	new iClients[MAXPLAYERS + 1] = { -1, ... };
-	new iClientsNum;
-	for (new i = 0, iSize = GetArraySize(hArrayClients); i < iSize; i++)
-	{
-		new iClient = GetClientOfUserId(GetArrayCell(hArrayClients, i));
-		if (iClient <= 0) continue;
-		
-		iClients[iClientsNum] = iClient;
-		iClientsNum++;
-	}
-	
-	CloseHandle(hArrayClients);
-	
-	VoteMenu(g_hMenuVoteDifficulty, iClients, iClientsNum, 15);
-	
-	return Plugin_Stop;
-}
-
-static InitializeMapEntities()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeMapEntities()");
-#endif
-	
-	g_bRoundInfiniteFlashlight = false;
-	g_bRoundInfiniteBlink = false;
-	g_bRoundInfiniteSprint = false;
-	g_bRoundHasEscapeObjective = false;
-	
-	g_iRoundTimeLimit = GetConVarInt(g_cvTimeLimit);
-	g_iRoundEscapeTimeLimit = GetConVarInt(g_cvTimeLimitEscape);
-	g_iRoundTimeGainFromPage = GetConVarInt(g_cvTimeGainFromPageGrab);
-	
-	// Reset page reference.
-	g_bPageRef = false;
-	strcopy(g_strPageRefModel, sizeof(g_strPageRefModel), "");
-	g_flPageRefModelScale = 1.0;
-	
-	new Handle:hArray = CreateArray(2);
-	new Handle:hPageTrie = CreateTrie();
-	
-	decl String:targetName[64];
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
-		if (targetName[0])
-		{
-			if (!StrContains(targetName, "sf2_maxpages_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_maxpages_", "", false);
-				g_iPageMax = StringToInt(targetName);
-			}
-			else if (!StrContains(targetName, "sf2_page_spawnpoint", false))
-			{
-				if (!StrContains(targetName, "sf2_page_spawnpoint_", false))
-				{
-					ReplaceString(targetName, sizeof(targetName), "sf2_page_spawnpoint_", "", false);
-					if (targetName[0])
-					{
-						new Handle:hButtStallion = INVALID_HANDLE;
-						if (!GetTrieValue(hPageTrie, targetName, hButtStallion))
-						{
-							hButtStallion = CreateArray();
-							SetTrieValue(hPageTrie, targetName, hButtStallion);
-						}
-						
-						new iIndex = FindValueInArray(hArray, hButtStallion);
-						if (iIndex == -1)
-						{
-							iIndex = PushArrayCell(hArray, hButtStallion);
-						}
-						
-						PushArrayCell(hButtStallion, ent);
-						SetArrayCell(hArray, iIndex, true, 1);
-					}
-					else
-					{
-						new iIndex = PushArrayCell(hArray, ent);
-						SetArrayCell(hArray, iIndex, false, 1);
-					}
-				}
-				else
-				{
-					new iIndex = PushArrayCell(hArray, ent);
-					SetArrayCell(hArray, iIndex, false, 1);
-				}
-			}
-			else if (!StrContains(targetName, "sf2_logic_escape", false))
-			{
-				g_bRoundHasEscapeObjective = true;
-			}
-			else if (!StrContains(targetName, "sf2_infiniteflashlight", false))
-			{
-				g_bRoundInfiniteFlashlight = true;
-			}
-			else if (!StrContains(targetName, "sf2_infiniteblink", false))
-			{
-				g_bRoundInfiniteBlink = true;
-			}
-			else if (!StrContains(targetName, "sf2_infinitesprint", false))
-			{
-				g_bRoundInfiniteSprint = true;
-			}
-			else if (!StrContains(targetName, "sf2_time_limit_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_time_limit_", "", false);
-				g_iRoundTimeLimit = StringToInt(targetName);
-				
-				LogSF2Message("Found sf2_time_limit entity, set time limit to %d", g_iRoundTimeLimit);
-			}
-			else if (!StrContains(targetName, "sf2_escape_time_limit_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_escape_time_limit_", "", false);
-				g_iRoundEscapeTimeLimit = StringToInt(targetName);
-				
-				LogSF2Message("Found sf2_escape_time_limit entity, set escape time limit to %d", g_iRoundEscapeTimeLimit);
-			}
-			else if (!StrContains(targetName, "sf2_time_gain_from_page_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_time_gain_from_page_", "", false);
-				g_iRoundTimeGainFromPage = StringToInt(targetName);
-				
-				LogSF2Message("Found sf2_time_gain_from_page entity, set time gain to %d", g_iRoundTimeGainFromPage);
-			}
-			else if (g_iRoundActiveCount == 1 && (!StrContains(targetName, "sf2_maxplayers_", false)))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_maxplayers_", "", false);
-				SetConVarInt(g_cvMaxPlayers, StringToInt(targetName));
-				
-				LogSF2Message("Found sf2_maxplayers entity, set maxplayers to %d", StringToInt(targetName));
-			}
-			else if (!StrContains(targetName, "sf2_boss_override_", false))
-			{
-				ReplaceString(targetName, sizeof(targetName), "sf2_boss_override_", "", false);
-				SetConVarString(g_cvBossProfileOverride, targetName);
-				
-				LogSF2Message("Found sf2_boss_override entity, set boss profile override to %s", targetName);
-			}
-		}
-	}
-	
-	// Get a reference entity, if any.
-	
-	ent = -1;
-	while ((ent = FindEntityByClassname(ent, "prop_dynamic")) != -1)
-	{
-		if (g_bPageRef) break;
-	
-		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
-		if (targetName[0])
-		{
-			if (StrEqual(targetName, "sf2_page_model", false))
-			{
-				g_bPageRef = true;
-				GetEntPropString(ent, Prop_Data, "m_ModelName", g_strPageRefModel, sizeof(g_strPageRefModel));
-				g_flPageRefModelScale = 1.0;
-			}
-		}
-	}
-	
-	new iPageCount = GetArraySize(hArray);
-	if (iPageCount)
-	{
-		SortADTArray(hArray, Sort_Random, Sort_Integer);
-		
-		decl Float:vecPos[3], Float:vecAng[3], Float:vecDir[3];
-		decl page;
-		ent = -1;
-		
-		for (new i = 0; i < iPageCount && (i + 1) <= g_iPageMax; i++)
-		{
-			if (bool:GetArrayCell(hArray, i, 1))
-			{
-				new Handle:hButtStallion = Handle:GetArrayCell(hArray, i);
-				ent = GetArrayCell(hButtStallion, GetRandomInt(0, GetArraySize(hButtStallion) - 1));
-			}
-			else
-			{
-				ent = GetArrayCell(hArray, i);
-			}
-			
-			GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", vecPos);
-			GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", vecAng);
-			GetAngleVectors(vecAng, vecDir, NULL_VECTOR, NULL_VECTOR);
-			NormalizeVector(vecDir, vecDir);
-			ScaleVector(vecDir, 1.0);
-			
-			page = CreateEntityByName("prop_dynamic_override");
-			if (page != -1)
-			{
-				TeleportEntity(page, vecPos, vecAng, NULL_VECTOR);
-				DispatchKeyValue(page, "targetname", "sf2_page");
-				
-				if (g_bPageRef)
-				{
-					SetEntityModel(page, g_strPageRefModel);
-				}
-				else
-				{
-					SetEntityModel(page, PAGE_MODEL);
-				}
-				
-				DispatchKeyValue(page, "solid", "2");
-				DispatchSpawn(page);
-				ActivateEntity(page);
-				SetVariantInt(i);
-				AcceptEntityInput(page, "Skin");
-				AcceptEntityInput(page, "EnableCollision");
-				
-				if (g_bPageRef)
-				{
-					SetEntPropFloat(page, Prop_Send, "m_flModelScale", g_flPageRefModelScale);
-				}
-				else
-				{
-					SetEntPropFloat(page, Prop_Send, "m_flModelScale", PAGE_MODELSCALE);
-				}
-				
-				SDKHook(page, SDKHook_OnTakeDamage, Hook_PageOnTakeDamage);
-				SDKHook(page, SDKHook_SetTransmit, Hook_SlenderObjectSetTransmit);
-			}
-		}
-		
-		// Safely remove all handles.
-		for (new i = 0, iSize = GetArraySize(hArray); i < iSize; i++)
-		{
-			if (bool:GetArrayCell(hArray, i, 1))
-			{
-				CloseHandle(Handle:GetArrayCell(hArray, i));
-			}
-		}
-	
-		Call_StartForward(fOnPagesSpawned);
-		Call_Finish();
-	}
-	
-	CloseHandle(hPageTrie);
-	CloseHandle(hArray);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeMapEntities()");
-#endif
-}
-
-static HandleSpecialRoundState()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleSpecialRoundState()");
-#endif
-	
-	new bool:bOld = g_bSpecialRound;
-	new bool:bContinuousOld = g_bSpecialRoundContinuous;
-	g_bSpecialRound = false;
-	g_bSpecialRoundNew = false;
-	g_bSpecialRoundContinuous = false;
-	
-	new bool:bForceNew = false;
-	
-	if (bOld)
-	{
-		if (bContinuousOld)
-		{
-			// Check if there are players who haven't played the special round yet.
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || !IsClientParticipating(i))
-				{
-					g_bPlayerPlayedSpecialRound[i] = true;
-					continue;
-				}
-				
-				if (!g_bPlayerPlayedSpecialRound[i])
-				{
-					// Someone didn't get to play this yet. Continue the special round.
-					g_bSpecialRound = true;
-					g_bSpecialRoundContinuous = true;
-					break;
-				}
-			}
-		}
-	}
-	
-	new iRoundInterval = GetConVarInt(g_cvSpecialRoundInterval);
-	
-	if (iRoundInterval > 0 && g_iSpecialRoundCount >= iRoundInterval)
-	{
-		g_bSpecialRound = true;
-		bForceNew = true;
-	}
-	
-	// Do special round force override and reset it.
-	if (GetConVarInt(g_cvSpecialRoundForce) >= 0)
-	{
-		g_bSpecialRound = GetConVarBool(g_cvSpecialRoundForce);
-		SetConVarInt(g_cvSpecialRoundForce, -1);
-	}
-	
-	if (g_bSpecialRound)
-	{
-		if (bForceNew || !bOld || !bContinuousOld)
-		{
-			g_bSpecialRoundNew = true;
-		}
-		
-		if (g_bSpecialRoundNew)
-		{
-			if (GetConVarInt(g_cvSpecialRoundBehavior) == 1)
-			{
-				g_bSpecialRoundContinuous = true;
-			}
-			else
-			{
-				// New special round, but it's not continuous.
-				g_bSpecialRoundContinuous = false;
-			}
-		}
-	}
-	else
-	{
-		g_bSpecialRoundContinuous = false;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleSpecialRoundState() -> g_bSpecialRound = %d (count = %d, new = %d, continuous = %d)", g_bSpecialRound, g_iSpecialRoundCount, g_bSpecialRoundNew, g_bSpecialRoundContinuous);
-#endif
-}
-
-bool:IsNewBossRoundRunning()
-{
-	return g_bNewBossRound;
-}
-
-/**
- *	Returns an array which contains all the profile names valid to be chosen for a new boss round.
- */
-static Handle:GetNewBossRoundProfileList()
-{
-	new Handle:hBossList = CloneArray(GetSelectableBossProfileList());
-	
-	if (GetArraySize(hBossList) > 0)
-	{
-		decl String:sMainBoss[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetConVarString(g_cvBossMain, sMainBoss, sizeof(sMainBoss));
-		
-		new index = FindStringInArray(hBossList, sMainBoss);
-		if (index != -1)
-		{
-			// Main boss exists; remove him from the list.
-			RemoveFromArray(hBossList, index);
-		}
-		else
-		{
-			// Main boss doesn't exist; remove the first boss from the list.
-			RemoveFromArray(hBossList, 0);
-		}
-	}
-	
-	return hBossList;
-}
-
-static HandleNewBossRoundState()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleNewBossRoundState()");
-#endif
-	
-	new bool:bOld = g_bNewBossRound;
-	new bool:bContinuousOld = g_bNewBossRoundContinuous;
-	g_bNewBossRound = false;
-	g_bNewBossRoundNew = false;
-	g_bNewBossRoundContinuous = false;
-	
-	new bool:bForceNew = false;
-	
-	if (bOld)
-	{
-		if (bContinuousOld)
-		{
-			// Check if there are players who haven't played the boss round yet.
-			for (new i = 1; i <= MaxClients; i++)
-			{
-				if (!IsClientInGame(i) || !IsClientParticipating(i))
-				{
-					g_bPlayerPlayedNewBossRound[i] = true;
-					continue;
-				}
-				
-				if (!g_bPlayerPlayedNewBossRound[i])
-				{
-					// Someone didn't get to play this yet. Continue the boss round.
-					g_bNewBossRound = true;
-					g_bNewBossRoundContinuous = true;
-					break;
-				}
-			}
-		}
-	}
-	
-	// Don't force a new special round while a continuous round is going on.
-	if (!g_bNewBossRoundContinuous)
-	{
-		new iRoundInterval = GetConVarInt(g_cvNewBossRoundInterval);
-		
-		if (/*iRoundInterval > 0 &&*/ iRoundInterval <= 0 || g_iNewBossRoundCount >= iRoundInterval)
-		{
-			g_bNewBossRound = true;
-			bForceNew = true;
-		}
-	}
-	
-	// Do boss round force override and reset it.
-	if (GetConVarInt(g_cvNewBossRoundForce) >= 0)
-	{
-		g_bNewBossRound = GetConVarBool(g_cvNewBossRoundForce);
-		SetConVarInt(g_cvNewBossRoundForce, -1);
-	}
-	
-	// Check if we have enough bosses.
-	if (g_bNewBossRound)
-	{
-		new Handle:hBossList = GetNewBossRoundProfileList();
-	
-		if (GetArraySize(hBossList) < 1)
-		{
-			g_bNewBossRound = false; // Not enough bosses.
-		}
-		
-		CloseHandle(hBossList);
-	}
-	
-	if (g_bNewBossRound)
-	{
-		if (bForceNew || !bOld || !bContinuousOld)
-		{
-			g_bNewBossRoundNew = true;
-		}
-		
-		if (g_bNewBossRoundNew)
-		{
-			if (GetConVarInt(g_cvNewBossRoundBehavior) == 1)
-			{
-				g_bNewBossRoundContinuous = true;
-			}
-			else
-			{
-				// New "new boss round", but it's not continuous.
-				g_bNewBossRoundContinuous = false;
-			}
-		}
-	}
-	else
-	{
-		g_bNewBossRoundContinuous = false;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleNewBossRoundState() -> g_bNewBossRound = %d (count = %d, new = %d, continuous = %d)", g_bNewBossRound, g_iNewBossRoundCount, g_bNewBossRoundNew, g_bNewBossRoundContinuous);
-#endif
-}
-
-/**
- *	Returns the amount of players that are in game and currently not eliminated.
- */
-GetActivePlayerCount()
-{
-	new count = 0;
-
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i) || !IsClientParticipating(i)) continue;
-		
-		if (!g_bPlayerEliminated[i])
-		{
-			count++;
-		}
-	}
-	
-	return count;
-}
-
-static SelectStartingBossesForRound()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START SelectStartingBossesForRound()");
-#endif
-
-	new Handle:hSelectableBossList = GetSelectableBossProfileList();
-
-	// Select which boss profile to use.
-	decl String:sProfileOverride[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetConVarString(g_cvBossProfileOverride, sProfileOverride, sizeof(sProfileOverride));
-	
-	if (strlen(sProfileOverride) > 0 && IsProfileValid(sProfileOverride))
-	{
-		// Pick the overridden boss.
-		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfileOverride);
-		SetConVarString(g_cvBossProfileOverride, "");
-	}
-	else if (g_bNewBossRound)
-	{
-		if (g_bNewBossRoundNew)
-		{
-			new Handle:hBossList = GetNewBossRoundProfileList();
-		
-			GetArrayString(hBossList, GetRandomInt(0, GetArraySize(hBossList) - 1), g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile));
-		
-			CloseHandle(hBossList);
-		}
-		
-		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), g_strNewBossRoundProfile);
-	}
-	else
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		GetConVarString(g_cvBossMain, sProfile, sizeof(sProfile));
-		
-		if (strlen(sProfile) > 0 && IsProfileValid(sProfile))
-		{
-			strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfile);
-		}
-		else
-		{
-			if (GetArraySize(hSelectableBossList) > 0)
-			{
-				// Pick the first boss in our array if the main boss doesn't exist.
-				GetArrayString(hSelectableBossList, 0, g_strRoundBossProfile, sizeof(g_strRoundBossProfile));
-			}
-			else
-			{
-				// No bosses to pick. What?
-				strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), "");
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END SelectStartingBossesForRound() -> boss: %s", g_strRoundBossProfile);
-#endif
-}
-
-static GetRoundIntroParameters()
-{
-	g_iRoundIntroFadeColor[0] = 0;
-	g_iRoundIntroFadeColor[1] = 0;
-	g_iRoundIntroFadeColor[2] = 0;
-	g_iRoundIntroFadeColor[3] = 255;
-	
-	g_flRoundIntroFadeHoldTime = GetConVarFloat(g_cvIntroDefaultHoldTime);
-	g_flRoundIntroFadeDuration = GetConVarFloat(g_cvIntroDefaultFadeTime);
-	
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "env_fade")) != -1)
-	{
-		decl String:sName[32];
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		if (StrEqual(sName, "sf2_intro_fade", false))
-		{
-			new iColorOffset = FindSendPropOffs("CBaseEntity", "m_clrRender");
-			if (iColorOffset != -1)
-			{
-				g_iRoundIntroFadeColor[0] = GetEntData(ent, iColorOffset, 1);
-				g_iRoundIntroFadeColor[1] = GetEntData(ent, iColorOffset + 1, 1);
-				g_iRoundIntroFadeColor[2] = GetEntData(ent, iColorOffset + 2, 1);
-				g_iRoundIntroFadeColor[3] = GetEntData(ent, iColorOffset + 3, 1);
-			}
-			
-			g_flRoundIntroFadeHoldTime = GetEntPropFloat(ent, Prop_Data, "m_HoldTime");
-			g_flRoundIntroFadeDuration = GetEntPropFloat(ent, Prop_Data, "m_Duration");
-			
-			break;
-		}
-	}
-	
-	// Get the intro music.
-	strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), SF2_INTRO_DEFAULT_MUSIC);
-	
-	ent = -1;
-	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
-	{
-		decl String:sName[64];
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		
-		if (StrEqual(sName, "sf2_intro_music", false))
-		{
-			decl String:sSongPath[PLATFORM_MAX_PATH];
-			GetEntPropString(ent, Prop_Data, "m_iszSound", sSongPath, sizeof(sSongPath));
-			
-			if (strlen(sSongPath) == 0)
-			{
-				LogError("Found sf2_intro_music entity, but it has no sound path specified! Default intro music will be used instead.");
-			}
-			else
-			{
-				strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), sSongPath);
-			}
-			
-			break;
-		}
-	}
-}
-
-static GetRoundEscapeParameters()
-{
-	g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
-	
-	decl String:sName[64];
-	new ent = -1;
-	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-	{
-		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-		if (!StrContains(sName, "sf2_escape_spawnpoint", false))
-		{
-			g_iRoundEscapePointEntity = EntIndexToEntRef(ent);
-			break;
-		}
-	}
-}
-
-InitializeNewGame()
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeNewGame()");
-#endif
-	
-	GetRoundIntroParameters();
-	GetRoundEscapeParameters();
-	
-	// Choose round state.
-	if (GetConVarBool(g_cvIntroEnabled))
-	{
-		// Set the round state to the intro stage.
-		SetRoundState(SF2RoundState_Intro);
-	}
-	else
-	{
-		SetRoundState(SF2RoundState_Active);
-	}
-	
-	if (g_iRoundActiveCount == 1)
-	{
-		SetConVarString(g_cvBossProfileOverride, "");
-	}
-	
-	HandleSpecialRoundState();
-	
-	// Was a new special round initialized?
-	if (g_bSpecialRound)
-	{
-		if (g_bSpecialRoundNew)
-		{
-			// Reset round count.
-			g_iSpecialRoundCount = 1;
-			
-			if (g_bSpecialRoundContinuous)
-			{
-				// It's the start of a continuous special round.
-			
-				// Initialize all players' values.
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || !IsClientParticipating(i))
-					{
-						g_bPlayerPlayedSpecialRound[i] = true;
-						continue;
-					}
-					
-					g_bPlayerPlayedSpecialRound[i] = false;
-				}
-			}
-			
-			SpecialRoundCycleStart();
-		}
-		else
-		{
-			SpecialRoundStart();
-			
-			if (g_bSpecialRoundContinuous)
-			{
-				// Display the current special round going on to late players.
-				CreateTimer(3.0, Timer_DisplaySpecialRound, _, TIMER_FLAG_NO_MAPCHANGE);
-			}
-		}
-	}
-	else
-	{
-		g_iSpecialRoundCount++;
-	
-		SpecialRoundReset();
-	}
-	
-	// Determine boss round state.
-	HandleNewBossRoundState();
-	
-	if (g_bNewBossRound)
-	{
-		if (g_bNewBossRoundNew)
-		{
-			// Reset round count;
-			g_iNewBossRoundCount = 1;
-			
-			if (g_bNewBossRoundContinuous)
-			{
-				// It's the start of a continuous "new boss round".
-			
-				// Initialize all players' values.
-				for (new i = 1; i <= MaxClients; i++)
-				{
-					if (!IsClientInGame(i) || !IsClientParticipating(i))
-					{
-						g_bPlayerPlayedNewBossRound[i] = true;
-						continue;
-					}
-					
-					g_bPlayerPlayedNewBossRound[i] = false;
-				}
-			}
-		}
-	}
-	else
-	{
-		g_iNewBossRoundCount++;
-	}
-	
-	InitializeMapEntities();
-	
-	// Initialize pages and entities.
-	GetPageMusicRanges();
-	
-	SelectStartingBossesForRound();
-	
-	ForceInNextPlayersInQueue(GetMaxPlayersForRound());
-	
-	// Respawn all players, if needed.
-	for (new i = 1; i <= MaxClients; i++)
-	{
-			if (IsClientParticipating(i))
-			{
-				if (!HandlePlayerTeam(i))
-				{
-				if (!g_bPlayerEliminated[i])
-				{
-					// Players currently in the "game" still have to be respawned.
-					TF2_RespawnPlayer(i);
-				}
-			}
-		}
-	}
-	
-	if (GetRoundState() == SF2RoundState_Intro)
-	{
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i)) continue;
-			
-			if (!g_bPlayerEliminated[i])
-			{
-				if (!IsFakeClient(i))
-				{
-					// Currently in intro state, play intro music.
-					g_hPlayerIntroMusicTimer[i] = CreateTimer(0.5, Timer_PlayIntroMusicToPlayer, GetClientUserId(i), TIMER_FLAG_NO_MAPCHANGE);
-				}
-				else
-				{
-					g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
-				}
-			}
-			else
-			{
-				g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
-			}
-		}
-	}
-	else
-	{
-		// Spawn the boss!
-		SelectProfile(0, g_strRoundBossProfile);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeNewGame()");
-#endif
-}
-
-public Action:Timer_PlayIntroMusicToPlayer(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerIntroMusicTimer[client]) return;
-	
-	g_hPlayerIntroMusicTimer[client] = INVALID_HANDLE;
-	
-	EmitSoundToClient(client, g_strRoundIntroMusic, _, MUSIC_CHAN, SNDLEVEL_NONE);
-}
-
-public Action:Timer_IntroTextSequence(Handle:timer)
-{
-	if (!g_bEnabled) return;
-	if (g_hRoundIntroTextTimer != timer) return;
-	
-	new Float:flDuration = 0.0;
-	
-	if (g_iRoundIntroText != 0)
-	{
-		new bool:bFoundGameText = false;
-		
-		new iClients[MAXPLAYERS + 1];
-		new iClientsNum;
-		
-		for (new i = 1; i <= MaxClients; i++)
-		{
-			if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
-			
-			iClients[iClientsNum] = i;
-			iClientsNum++;
-		}
-		
-		if (!g_bRoundIntroTextDefault)
-		{
-			decl String:sTargetname[64];
-			Format(sTargetname, sizeof(sTargetname), "sf2_intro_text_%d", g_iRoundIntroText);
-		
-			new iGameText = FindEntityByTargetname(sTargetname, "game_text");
-			if (iGameText && iGameText != INVALID_ENT_REFERENCE)
-			{
-				bFoundGameText = true;
-				flDuration = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
-				
-				decl String:sMessage[512];
-				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
-				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
-			}
-		}
-		else
-		{
-			if (g_iRoundIntroText == 2)
-			{
-				bFoundGameText = false;
-				
-				decl String:sMessage[64];
-				GetCurrentMap(sMessage, sizeof(sMessage));
-				
-				for (new i = 0; i < iClientsNum; i++)
-				{
-					ClientShowMainMessage(iClients[i], sMessage, 1);
-				}
-			}
-		}
-		
-		if (g_iRoundIntroText == 1 && !bFoundGameText)
-		{
-			// Use default intro sequence. Eugh.
-			g_bRoundIntroTextDefault = true;
-			flDuration = GetConVarFloat(g_cvIntroDefaultHoldTime) / 2.0;
-			
-			for (new i = 0; i < iClientsNum; i++)
-			{
-				EmitSoundToClient(iClients[i], SF2_INTRO_DEFAULT_MUSIC, _, MUSIC_CHAN, SNDLEVEL_NONE);
-			}
-		}
-		else
-		{
-			if (!bFoundGameText) return; // done with sequence; don't check anymore.
-		}
-	}
-	
-	g_iRoundIntroText++;
-	g_hRoundIntroTextTimer = CreateTimer(flDuration, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_ActivateRoundFromIntro(Handle:timer)
-{
-	if (!g_bEnabled) return;
-	if (g_hRoundIntroTimer != timer) return;
-	
-	// Obviously we don't want to spawn the boss when g_strRoundBossProfile isn't set yet.
-	SetRoundState(SF2RoundState_Active);
-	
-	// Spawn the boss!
-	SelectProfile(0, g_strRoundBossProfile);
-}
-
-CheckRoundWinConditions()
-{
-	if (IsRoundInWarmup() || IsRoundEnding()) return;
-	
-	new iTotalCount = 0;
-	new iAliveCount = 0;
-	new iEscapedCount = 0;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		iTotalCount++;
-		if (!g_bPlayerEliminated[i] && !IsClientInDeathCam(i)) 
-		{
-			iAliveCount++;
-			if (DidClientEscape(i)) iEscapedCount++;
-		}
-	}
-	
-	if (iAliveCount == 0)
-	{
-		ForceTeamWin(_:TFTeam_Blue);
-	}
-	else
-	{
-		if (g_bRoundHasEscapeObjective)
-		{
-			if (iEscapedCount == iAliveCount)
-			{
-				ForceTeamWin(_:TFTeam_Red);
-			}
-		}
-		else
-		{
-			if (g_iPageMax > 0 && g_iPageCount == g_iPageMax)
-			{
-				ForceTeamWin(_:TFTeam_Red);
-			}
-		}
-	}
-}
-
-//	==========================================================
-//	API
-//	==========================================================
-
-public Native_IsRunning(Handle:plugin, numParams)
-{
-	return g_bEnabled;
-}
-
-public Native_GetCurrentDifficulty(Handle:plugin, numParams)
-{
-	return GetConVarInt(g_cvDifficulty);
-}
-
-public Native_GetDifficultyModifier(Handle:plugin, numParams)
-{
-	new iDifficulty = GetNativeCell(1);
-	if (iDifficulty < Difficulty_Easy || iDifficulty >= Difficulty_Max)
-	{
-		LogError("Difficulty parameter can only be from %d to %d!", Difficulty_Easy, Difficulty_Max - 1);
-		return _:1.0;
-	}
-	
-	switch (iDifficulty)
-	{
-		case Difficulty_Easy: return _:DIFFICULTY_EASY;
-		case Difficulty_Hard: return _:DIFFICULTY_HARD;
-		case Difficulty_Insane: return _:DIFFICULTY_INSANE;
-	}
-	
-	return _:DIFFICULTY_NORMAL;
-}
-
-public Native_IsClientEliminated(Handle:plugin, numParams)
-{
-	return g_bPlayerEliminated[GetNativeCell(1)];
-}
-
-public Native_IsClientInGhostMode(Handle:plugin, numParams)
-{
-	return IsClientInGhostMode(GetNativeCell(1));
-}
-
-public Native_IsClientProxy(Handle:plugin, numParams)
-{
-	return g_bPlayerProxy[GetNativeCell(1)];
-}
-
-public Native_GetClientBlinkCount(Handle:plugin, numParams)
-{
-	return ClientGetBlinkCount(GetNativeCell(1));
-}
-
-public Native_GetClientProxyMaster(Handle:plugin, numParams)
-{
-	return NPCGetFromUniqueID(g_iPlayerProxyMaster[GetNativeCell(1)]);
-}
-
-public Native_GetClientProxyControlAmount(Handle:plugin, numParams)
-{
-	return g_iPlayerProxyControl[GetNativeCell(1)];
-}
-
-public Native_GetClientProxyControlRate(Handle:plugin, numParams)
-{
-	return _:g_flPlayerProxyControlRate[GetNativeCell(1)];
-}
-
-public Native_SetClientProxyMaster(Handle:plugin, numParams)
-{
-	g_iPlayerProxyMaster[GetNativeCell(1)] = NPCGetUniqueID(GetNativeCell(2));
-}
-
-public Native_SetClientProxyControlAmount(Handle:plugin, numParams)
-{
-	g_iPlayerProxyControl[GetNativeCell(1)] = GetNativeCell(2);
-}
-
-public Native_SetClientProxyControlRate(Handle:plugin, numParams)
-{
-	g_flPlayerProxyControlRate[GetNativeCell(1)] = Float:GetNativeCell(2);
-}
-
-public Native_IsClientLookingAtBoss(Handle:plugin, numParams)
-{
-	return g_bPlayerSeesSlender[GetNativeCell(1)][GetNativeCell(2)];
-}
-
-public Native_CollectAsPage(Handle:plugin, numParams)
-{
-	CollectPage(GetNativeCell(1), GetNativeCell(2));
-}
-
-public Native_GetMaxBosses(Handle:plugin, numParams)
-{
-	return MAX_BOSSES;
-}
-
-public Native_EntIndexToBossIndex(Handle:plugin, numParams)
-{
-	return NPCGetFromEntIndex(GetNativeCell(1));
-}
-
-public Native_BossIndexToEntIndex(Handle:plugin, numParams)
-{
-	return NPCGetEntIndex(GetNativeCell(1));
-}
-
-public Native_BossIDToBossIndex(Handle:plugin, numParams)
-{
-	return NPCGetFromUniqueID(GetNativeCell(1));
-}
-
-public Native_BossIndexToBossID(Handle:plugin, numParams)
-{
-	return NPCGetUniqueID(GetNativeCell(1));
-}
-
-public Native_GetBossName(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(GetNativeCell(1), sProfile, sizeof(sProfile));
-	
-	SetNativeString(2, sProfile, GetNativeCell(3));
-}
-
-public Native_GetBossModelEntity(Handle:plugin, numParams)
-{
-	return EntRefToEntIndex(g_iSlenderModel[GetNativeCell(1)]);
-}
-
-public Native_GetBossTarget(Handle:plugin, numParams)
-{
-	return EntRefToEntIndex(g_iSlenderTarget[GetNativeCell(1)]);
-}
-
-public Native_GetBossMaster(Handle:plugin, numParams)
-{
-	return g_iSlenderCopyMaster[GetNativeCell(1)];
-}
-
-public Native_GetBossState(Handle:plugin, numParams)
-{
-	return g_iSlenderState[GetNativeCell(1)];
-}
-
-public Native_IsBossProfileValid(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-	
-	return IsProfileValid(sProfile);
-}
-
-public Native_GetBossProfileNum(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-	
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	return GetProfileNum(sProfile, sKeyValue, GetNativeCell(3));
-}
-
-public Native_GetBossProfileFloat(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	return _:GetProfileFloat(sProfile, sKeyValue, Float:GetNativeCell(3));
-}
-
-public Native_GetBossProfileString(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	new iResultLen = GetNativeCell(4);
-	decl String:sResult[iResultLen];
-	
-	decl String:sDefaultValue[512];
-	GetNativeString(5, sDefaultValue, sizeof(sDefaultValue));
-	
-	new bool:bSuccess = GetProfileString(sProfile, sKeyValue, sResult, iResultLen, sDefaultValue);
-	
-	SetNativeString(3, sResult, iResultLen);
-	return bSuccess;
-}
-
-public Native_GetBossProfileVector(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	decl Float:flResult[3];
-	decl Float:flDefaultValue[3];
-	GetNativeArray(4, flDefaultValue, 3);
-	
-	new bool:bSuccess = GetProfileVector(sProfile, sKeyValue, flResult, flDefaultValue);
-	
-	SetNativeArray(3, flResult, 3);
-	return bSuccess;
-}
-
-public Native_GetRandomStringFromBossProfile(Handle:plugin, numParams)
-{
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
-
-	decl String:sKeyValue[256];
-	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
-	
-	new iBufferLen = GetNativeCell(4);
-	decl String:sBuffer[iBufferLen];
-	
-	new iIndex = GetNativeCell(5);
-	
-	new bool:bSuccess = GetRandomStringFromProfile(sProfile, sKeyValue, sBuffer, iBufferLen, iIndex);
-	SetNativeString(3, sBuffer, iBufferLen);
-	return bSuccess;
+#include <sourcemod>
+#include <sdktools>
+#include <sdkhooks>
+#include <clientprefs>
+#include <steamtools>
+#include <tf2items>
+#include <dhooks>
+#include <navmesh>
+
+#include <tf2>
+#include <tf2_stocks>
+#include <morecolors>
+#include <sf2>
+
+#undef REQUIRE_PLUGIN
+#include <adminmenu>
+#tryinclude <store/store-tf2footprints>
+#define REQUIRE_PLUGIN
+
+// #define DEBUG
+
+// If compiling with SM 1.7+, uncomment to compile and use SF2 methodmaps.
+//#define METHODMAPS
+
+#define PLUGIN_VERSION "0.2.6-git136"
+#define PLUGIN_VERSION_DISPLAY "0.2.6"
+
+public Plugin:myinfo = 
+{
+    name = "RYTP Horror (Slender Fortress edit by lexuzieel special for Penek-Gaming.Ru)",
+    author	= "KitRifty",
+    description	= "Based on the game Slender: The Eight Pages.",
+    version = PLUGIN_VERSION,
+    url = "http://steamcommunity.com/groups/SlenderFortress"
+}
+
+#define FILE_RESTRICTEDWEAPONS "configs/sf2/restrictedweapons.cfg"
+
+#define BOSS_THINKRATE 0.1 // doesn't really matter much since timers go at a minimum of 0.1 seconds anyways
+
+#define CRIT_SOUND "player/crit_hit.wav"
+#define CRIT_PARTICLENAME "crit_text"
+
+#define PAGE_MODEL "models/rytp/horror/props/hint_paper.mdl"
+#define PAGE_MODELSCALE 1.1
+
+#define FLASHLIGHT_CLICKSOUND "rytp_horror/toggleflashlight.wav"
+#define FLASHLIGHT_BREAKSOUND "ambient/energy/spark6.wav"
+#define FLASHLIGHT_NOSOUND "player/suit_denydevice.wav"
+#define PAGE_GRABSOUND "rytp_horror/grabpage_sound.wav"
+
+#define MUSIC_CHAN SNDCHAN_AUTO
+
+#define MUSIC_GOTPAGES1_SOUND "rytp_horror/grabpage_music_1.wav"
+#define MUSIC_GOTPAGES2_SOUND "rytp_horror/grabpage_music_2.wav"
+#define MUSIC_GOTPAGES3_SOUND "rytp_horror/grabpage_music_3.wav"
+#define MUSIC_GOTPAGES4_SOUND "rytp_horror/grabpage_music_4.wav"
+#define MUSIC_PAGE_VOLUME 1.0
+
+#define SF2_INTRO_DEFAULT_MUSIC "rytp_horror/intro_music.mp3"
+
+#define SF2_HUD_TEXT_COLOR_R 127
+#define SF2_HUD_TEXT_COLOR_G 167
+#define SF2_HUD_TEXT_COLOR_B 141
+#define SF2_HUD_TEXT_COLOR_A 255
+
+enum MuteMode
+{
+	MuteMode_Normal = 0,
+	MuteMode_DontHearOtherTeam,
+	MuteMode_DontHearOtherTeamIfNotProxy
+};
+
+// Offsets.
+new g_offsPlayerFOV = -1;
+new g_offsPlayerDefaultFOV = -1;
+new g_offsPlayerFogCtrl = -1;
+new g_offsPlayerPunchAngle = -1;
+new g_offsPlayerPunchAngleVel = -1;
+new g_offsFogCtrlEnable = -1;
+new g_offsFogCtrlEnd = -1;
+
+new g_iParticleCriticalHit = -1;
+
+new bool:g_bEnabled;
+
+new Handle:g_hConfig;
+new Handle:g_hRestrictedWeaponsConfig;
+new Handle:g_hSpecialRoundsConfig;
+
+new Handle:g_hPageMusicRanges;
+
+new g_iSlenderModel[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+new g_iSlenderPoseEnt[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+new g_iSlenderCopyMaster[MAX_BOSSES] = { -1, ... };
+new Float:g_flSlenderEyePosOffset[MAX_BOSSES][3];
+new Float:g_flSlenderEyeAngOffset[MAX_BOSSES][3];
+new Float:g_flSlenderDetectMins[MAX_BOSSES][3];
+new Float:g_flSlenderDetectMaxs[MAX_BOSSES][3];
+new Handle:g_hSlenderThink[MAX_BOSSES];
+new Handle:g_hSlenderEntityThink[MAX_BOSSES];
+new Handle:g_hSlenderFakeTimer[MAX_BOSSES];
+new Float:g_flSlenderLastKill[MAX_BOSSES];
+new g_iSlenderState[MAX_BOSSES];
+new g_iSlenderTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+new Float:g_flSlenderAcceleration[MAX_BOSSES];
+new Float:g_flSlenderGoalPos[MAX_BOSSES][3];
+new Float:g_flSlenderStaticRadius[MAX_BOSSES];
+new Float:g_flSlenderChaseDeathPosition[MAX_BOSSES][3];
+new bool:g_bSlenderChaseDeathPosition[MAX_BOSSES];
+new Float:g_flSlenderIdleAnimationPlaybackRate[MAX_BOSSES];
+new Float:g_flSlenderWalkAnimationPlaybackRate[MAX_BOSSES];
+new Float:g_flSlenderRunAnimationPlaybackRate[MAX_BOSSES];
+new Float:g_flSlenderJumpSpeed[MAX_BOSSES];
+new Float:g_flSlenderPathNodeTolerance[MAX_BOSSES];
+new Float:g_flSlenderPathNodeLookAhead[MAX_BOSSES];
+new bool:g_bSlenderFeelerReflexAdjustment[MAX_BOSSES];
+new Float:g_flSlenderFeelerReflexAdjustmentPos[MAX_BOSSES][3];
+
+new g_iSlenderTeleportTarget[MAX_BOSSES] = { INVALID_ENT_REFERENCE, ... };
+
+new Float:g_flSlenderNextTeleportTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportTargetTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMinRange[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMaxRange[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMaxTargetTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTeleportMaxTargetStress[MAX_BOSSES] = { 0.0, ... };
+new Float:g_flSlenderTeleportPlayersRestTime[MAX_BOSSES][MAXPLAYERS + 1];
+
+// For boss type 2
+// General variables
+new g_iSlenderHealth[MAX_BOSSES];
+new Handle:g_hSlenderPath[MAX_BOSSES];
+new g_iSlenderCurrentPathNode[MAX_BOSSES] = { -1, ... };
+new bool:g_bSlenderAttacking[MAX_BOSSES];
+new Handle:g_hSlenderAttackTimer[MAX_BOSSES];
+new Float:g_flSlenderNextJump[MAX_BOSSES] = { -1.0, ... };
+new g_iSlenderInterruptConditions[MAX_BOSSES];
+new Float:g_flSlenderLastFoundPlayer[MAX_BOSSES][MAXPLAYERS + 1];
+new Float:g_flSlenderLastFoundPlayerPos[MAX_BOSSES][MAXPLAYERS + 1][3];
+new Float:g_flSlenderNextPathTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderCalculatedWalkSpeed[MAX_BOSSES];
+new Float:g_flSlenderCalculatedSpeed[MAX_BOSSES];
+new Float:g_flSlenderTimeUntilNoPersistence[MAX_BOSSES];
+
+new Float:g_flSlenderProxyTeleportMinRange[MAX_BOSSES];
+new Float:g_flSlenderProxyTeleportMaxRange[MAX_BOSSES];
+
+// Sound variables
+new Float:g_flSlenderTargetSoundLastTime[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTargetSoundMasterPos[MAX_BOSSES][3]; // to determine hearing focus
+new Float:g_flSlenderTargetSoundTempPos[MAX_BOSSES][3];
+new Float:g_flSlenderTargetSoundDiscardMasterPosTime[MAX_BOSSES];
+new bool:g_bSlenderInvestigatingSound[MAX_BOSSES];
+new SoundType:g_iSlenderTargetSoundType[MAX_BOSSES] = { SoundType_None, ... };
+new g_iSlenderTargetSoundCount[MAX_BOSSES];
+new Float:g_flSlenderLastHeardVoice[MAX_BOSSES];
+new Float:g_flSlenderLastHeardFootstep[MAX_BOSSES];
+new Float:g_flSlenderLastHeardWeapon[MAX_BOSSES];
+
+
+new Float:g_flSlenderNextJumpScare[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderNextVoiceSound[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderNextMoanSound[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderNextWanderPos[MAX_BOSSES] = { -1.0, ... };
+
+
+new Float:g_flSlenderTimeUntilRecover[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilAlert[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilIdle[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilChase[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilKill[MAX_BOSSES] = { -1.0, ... };
+new Float:g_flSlenderTimeUntilNextProxy[MAX_BOSSES] = { -1.0, ... };
+
+// Page data.
+new g_iPageCount;
+new g_iPageMax;
+new Float:g_flPageFoundLastTime;
+new bool:g_bPageRef;
+new String:g_strPageRefModel[PLATFORM_MAX_PATH];
+new Float:g_flPageRefModelScale;
+
+static Handle:g_hPlayerIntroMusicTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Seeing Mr. Slendy data.
+new bool:g_bPlayerSeesSlender[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerSeesSlenderLastTime[MAXPLAYERS + 1][MAX_BOSSES];
+
+new Float:g_flPlayerSightSoundNextTime[MAXPLAYERS + 1][MAX_BOSSES];
+
+new Float:g_flPlayerScareLastTime[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerScareNextTime[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerStaticAmount[MAXPLAYERS + 1];
+
+new Float:g_flPlayerLastChaseBossEncounterTime[MAXPLAYERS + 1][MAX_BOSSES];
+
+// Player static data.
+new g_iPlayerStaticMode[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerStaticIncreaseRate[MAXPLAYERS + 1];
+new Float:g_flPlayerStaticDecreaseRate[MAXPLAYERS + 1];
+new Handle:g_hPlayerStaticTimer[MAXPLAYERS + 1];
+new g_iPlayerStaticMaster[MAXPLAYERS + 1] = { -1, ... };
+new String:g_strPlayerStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new String:g_strPlayerLastStaticSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerLastStaticTime[MAXPLAYERS + 1];
+new Float:g_flPlayerLastStaticVolume[MAXPLAYERS + 1];
+new Handle:g_hPlayerLastStaticTimer[MAXPLAYERS + 1];
+
+// Static shake data.
+new g_iPlayerStaticShakeMaster[MAXPLAYERS + 1];
+new bool:g_bPlayerInStaticShake[MAXPLAYERS + 1];
+new String:g_strPlayerStaticShakeSound[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerStaticShakeMinVolume[MAXPLAYERS + 1];
+new Float:g_flPlayerStaticShakeMaxVolume[MAXPLAYERS + 1];
+
+// Fake lag compensation for FF.
+new bool:g_bPlayerLagCompensation[MAXPLAYERS + 1];
+new g_iPlayerLagCompensationTeam[MAXPLAYERS + 1];
+
+// Hint data.
+enum
+{
+	PlayerHint_Sprint = 0,
+	PlayerHint_Flashlight,
+	PlayerHint_MainMenu,
+	PlayerHint_Blink,
+	PlayerHint_MaxNum
+};
+
+enum PlayerPreferences
+{
+	bool:PlayerPreference_PvPAutoSpawn,
+	MuteMode:PlayerPreference_MuteMode,
+	bool:PlayerPreference_FilmGrain,
+	bool:PlayerPreference_ShowHints,
+	bool:PlayerPreference_EnableProxySelection,
+	bool:PlayerPreference_ProjectedFlashlight,
+	bool:PlayerPreference_GhostOverlay
+};
+
+new bool:g_bPlayerHints[MAXPLAYERS + 1][PlayerHint_MaxNum];
+new g_iPlayerPreferences[MAXPLAYERS + 1][PlayerPreferences];
+
+// Player data.
+new g_iPlayerLastButtons[MAXPLAYERS + 1];
+new bool:g_bPlayerChoseTeam[MAXPLAYERS + 1];
+new bool:g_bPlayerEliminated[MAXPLAYERS + 1];
+new bool:g_bPlayerEscaped[MAXPLAYERS + 1];
+new g_iPlayerPageCount[MAXPLAYERS + 1];
+new g_iPlayerQueuePoints[MAXPLAYERS + 1];
+new bool:g_bPlayerPlaying[MAXPLAYERS + 1];
+new Handle:g_hPlayerOverlayCheck[MAXPLAYERS + 1];
+
+new Handle:g_hPlayerSwitchBlueTimer[MAXPLAYERS + 1];
+
+// Player stress data.
+new Float:g_flPlayerStress[MAXPLAYERS + 1];
+new Float:g_flPlayerStressNextUpdateTime[MAXPLAYERS + 1];
+
+// Proxy data.
+new bool:g_bPlayerProxy[MAXPLAYERS + 1];
+new bool:g_bPlayerProxyAvailable[MAXPLAYERS + 1];
+new Handle:g_hPlayerProxyAvailableTimer[MAXPLAYERS + 1];
+new bool:g_bPlayerProxyAvailableInForce[MAXPLAYERS + 1];
+new g_iPlayerProxyAvailableCount[MAXPLAYERS + 1];
+new g_iPlayerProxyMaster[MAXPLAYERS + 1];
+new g_iPlayerProxyControl[MAXPLAYERS + 1];
+new Handle:g_hPlayerProxyControlTimer[MAXPLAYERS + 1];
+new Float:g_flPlayerProxyControlRate[MAXPLAYERS + 1];
+new Handle:g_flPlayerProxyVoiceTimer[MAXPLAYERS + 1];
+new g_iPlayerProxyAskMaster[MAXPLAYERS + 1] = { -1, ... };
+new Float:g_iPlayerProxyAskPosition[MAXPLAYERS + 1][3];
+
+new g_iPlayerDesiredFOV[MAXPLAYERS + 1];
+
+new Handle:g_hPlayerPostWeaponsTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Music system.
+new g_iPlayerMusicFlags[MAXPLAYERS + 1];
+new String:g_strPlayerMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerMusicVolume[MAXPLAYERS + 1];
+new Float:g_flPlayerMusicTargetVolume[MAXPLAYERS + 1];
+new Handle:g_hPlayerMusicTimer[MAXPLAYERS + 1];
+new g_iPlayerPageMusicMaster[MAXPLAYERS + 1];
+
+// Chase music system, which apparently also uses the alert song system. And the idle sound system.
+new String:g_strPlayerChaseMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new String:g_strPlayerChaseMusicSee[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerChaseMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Float:g_flPlayerChaseMusicSeeVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayerChaseMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayerChaseMusicSeeTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new g_iPlayerChaseMusicMaster[MAXPLAYERS + 1] = { -1, ... };
+new g_iPlayerChaseMusicSeeMaster[MAXPLAYERS + 1] = { -1, ... };
+
+new String:g_strPlayerAlertMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayerAlertMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayerAlertMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new g_iPlayerAlertMusicMaster[MAXPLAYERS + 1] = { -1, ... };
+
+new String:g_strPlayer20DollarsMusic[MAXPLAYERS + 1][PLATFORM_MAX_PATH];
+new Float:g_flPlayer20DollarsMusicVolumes[MAXPLAYERS + 1][MAX_BOSSES];
+new Handle:g_hPlayer20DollarsMusicTimer[MAXPLAYERS + 1][MAX_BOSSES];
+new g_iPlayer20DollarsMusicMaster[MAXPLAYERS + 1] = { -1, ... };
+
+// Player overlay data
+new Handle:g_hOverlayUpdateTimer[MAXPLAYERS + 1];
+
+new SF2RoundState:g_iRoundState = SF2RoundState_Invalid;
+new bool:g_bRoundGrace = false;
+new Float:g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
+new bool:g_bRoundInfiniteFlashlight = false;
+new bool:g_bRoundInfiniteBlink = false;
+new bool:g_bRoundInfiniteSprint = false;
+
+static Handle:g_hRoundGraceTimer = INVALID_HANDLE;
+static Handle:g_hRoundTimer = INVALID_HANDLE;
+static Handle:g_hVoteTimer = INVALID_HANDLE;
+static String:g_strRoundBossProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+
+static g_iRoundCount = 0;
+static g_iRoundEndCount = 0;
+static g_iRoundActiveCount = 0;
+static g_iRoundTime = 0;
+static g_iRoundTimeLimit = 0;
+static g_iRoundEscapeTimeLimit = 0;
+static g_iRoundTimeGainFromPage = 0;
+static bool:g_bRoundHasEscapeObjective = false;
+
+static g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
+
+static g_iRoundIntroFadeColor[4] = { 255, ... };
+static Float:g_flRoundIntroFadeHoldTime;
+static Float:g_flRoundIntroFadeDuration;
+static Handle:g_hRoundIntroTimer = INVALID_HANDLE;
+static bool:g_bRoundIntroTextDefault = true;
+static Handle:g_hRoundIntroTextTimer = INVALID_HANDLE;
+static g_iRoundIntroText;
+static String:g_strRoundIntroMusic[PLATFORM_MAX_PATH] = "";
+
+static g_iRoundWarmupRoundCount = 0;
+
+static bool:g_bRoundWaitingForPlayers = false;
+
+// Special round variables.
+new bool:g_bSpecialRound = false;
+new g_iSpecialRoundType = 0;
+new bool:g_bSpecialRoundNew = false;
+new bool:g_bSpecialRoundContinuous = false;
+new g_iSpecialRoundCount = 1;
+new bool:g_bPlayerPlayedSpecialRound[MAXPLAYERS + 1] = { true, ... };
+
+// New boss round variables.
+static bool:g_bNewBossRound = false;
+static bool:g_bNewBossRoundNew = false;
+static bool:g_bNewBossRoundContinuous = false;
+static g_iNewBossRoundCount = 1;
+static bool:g_bPlayerPlayedNewBossRound[MAXPLAYERS + 1] = { true, ... };
+static String:g_strNewBossRoundProfile[64] = "";
+
+static Handle:g_hRoundMessagesTimer = INVALID_HANDLE;
+static g_iRoundMessagesNum = 0;
+
+static Handle:g_hBossCountUpdateTimer = INVALID_HANDLE;
+static Handle:g_hClientAverageUpdateTimer = INVALID_HANDLE;
+
+// Server variables.
+new Handle:g_cvVersion;
+new Handle:g_cvEnabled;
+new Handle:g_cvSlenderMapsOnly;
+new Handle:g_cvPlayerViewbobEnabled;
+new Handle:g_cvPlayerShakeEnabled;
+new Handle:g_cvPlayerShakeFrequencyMax;
+new Handle:g_cvPlayerShakeAmplitudeMax;
+new Handle:g_cvGraceTime;
+new Handle:g_cvAllChat;
+new Handle:g_cv20Dollars;
+new Handle:g_cvMaxPlayers;
+new Handle:g_cvMaxPlayersOverride;
+new Handle:g_cvCampingEnabled;
+new Handle:g_cvCampingMaxStrikes;
+new Handle:g_cvCampingStrikesWarn;
+new Handle:g_cvCampingMinDistance;
+new Handle:g_cvCampingNoStrikeSanity;
+new Handle:g_cvCampingNoStrikeBossDistance;
+new Handle:g_cvDifficulty;
+new Handle:g_cvBossMain;
+new Handle:g_cvBossProfileOverride;
+new Handle:g_cvPlayerBlinkRate;
+new Handle:g_cvPlayerBlinkHoldTime;
+new Handle:g_cvSpecialRoundBehavior;
+new Handle:g_cvSpecialRoundForce;
+new Handle:g_cvSpecialRoundOverride;
+new Handle:g_cvSpecialRoundInterval;
+new Handle:g_cvNewBossRoundBehavior;
+new Handle:g_cvNewBossRoundInterval;
+new Handle:g_cvNewBossRoundForce;
+new Handle:g_cvPlayerVoiceDistance;
+new Handle:g_cvPlayerVoiceWallScale;
+new Handle:g_cvUltravisionEnabled;
+new Handle:g_cvUltravisionRadiusRed;
+new Handle:g_cvUltravisionRadiusBlue;
+new Handle:g_cvUltravisionBrightness;
+new Handle:g_cvGhostModeConnectionCheck;
+new Handle:g_cvGhostModeConnectionTolerance;
+new Handle:g_cvIntroEnabled;
+new Handle:g_cvIntroDefaultHoldTime;
+new Handle:g_cvIntroDefaultFadeTime;
+new Handle:g_cvTimeLimit;
+new Handle:g_cvTimeLimitEscape;
+new Handle:g_cvTimeGainFromPageGrab;
+new Handle:g_cvWarmupRound;
+new Handle:g_cvWarmupRoundNum;
+new Handle:g_cvPlayerViewbobHurtEnabled;
+new Handle:g_cvPlayerViewbobSprintEnabled;
+new Handle:g_cvPlayerFakeLagCompensation;
+new Handle:g_cvPlayerProxyWaitTime;
+new Handle:g_cvPlayerProxyAsk;
+new Handle:g_cvHalfZatoichiHealthGain;
+new Handle:g_cvBlockSuicideDuringRound;
+
+new Handle:g_cvPlayerInfiniteSprintOverride;
+new Handle:g_cvPlayerInfiniteFlashlightOverride;
+new Handle:g_cvPlayerInfiniteBlinkOverride;
+
+new Handle:g_cvGravity;
+new Float:g_flGravity;
+
+new Handle:g_cvMaxRounds;
+
+new bool:g_b20Dollars;
+
+new bool:g_bPlayerShakeEnabled;
+new bool:g_bPlayerViewbobEnabled;
+new bool:g_bPlayerViewbobHurtEnabled;
+new bool:g_bPlayerViewbobSprintEnabled;
+
+new Handle:g_hHudSync;
+new Handle:g_hHudSync2;
+new Handle:g_hRoundTimerSync;
+
+new Handle:g_hCookie;
+
+// Global forwards.
+new Handle:fOnBossAdded;
+new Handle:fOnBossSpawn;
+new Handle:fOnBossChangeState;
+new Handle:fOnBossRemoved;
+new Handle:fOnPagesSpawned;
+new Handle:fOnClientBlink;
+new Handle:fOnClientCaughtByBoss;
+new Handle:fOnClientGiveQueuePoints;
+new Handle:fOnClientActivateFlashlight;
+new Handle:fOnClientDeactivateFlashlight;
+new Handle:fOnClientBreakFlashlight;
+new Handle:fOnClientEscape;
+new Handle:fOnClientLooksAtBoss;
+new Handle:fOnClientLooksAwayFromBoss;
+new Handle:fOnClientStartDeathCam;
+new Handle:fOnClientEndDeathCam;
+new Handle:fOnClientGetDefaultWalkSpeed;
+new Handle:fOnClientGetDefaultSprintSpeed;
+new Handle:fOnClientSpawnedAsProxy;
+new Handle:fOnClientDamagedByBoss;
+new Handle:fOnGroupGiveQueuePoints;
+
+new Handle:g_hSDKWeaponScattergun;
+new Handle:g_hSDKWeaponPistolScout;
+new Handle:g_hSDKWeaponBat;
+new Handle:g_hSDKWeaponSniperRifle;
+new Handle:g_hSDKWeaponSMG;
+new Handle:g_hSDKWeaponKukri;
+new Handle:g_hSDKWeaponRocketLauncher;
+new Handle:g_hSDKWeaponShotgunSoldier;
+new Handle:g_hSDKWeaponShovel;
+new Handle:g_hSDKWeaponGrenadeLauncher;
+new Handle:g_hSDKWeaponStickyLauncher;
+new Handle:g_hSDKWeaponBottle;
+new Handle:g_hSDKWeaponMinigun;
+new Handle:g_hSDKWeaponShotgunHeavy;
+new Handle:g_hSDKWeaponFists;
+new Handle:g_hSDKWeaponSyringeGun;
+new Handle:g_hSDKWeaponMedigun;
+new Handle:g_hSDKWeaponBonesaw;
+new Handle:g_hSDKWeaponFlamethrower;
+new Handle:g_hSDKWeaponShotgunPyro;
+new Handle:g_hSDKWeaponFireaxe;
+new Handle:g_hSDKWeaponRevolver;
+new Handle:g_hSDKWeaponKnife;
+new Handle:g_hSDKWeaponInvis;
+new Handle:g_hSDKWeaponShotgunPrimary;
+new Handle:g_hSDKWeaponPistol;
+new Handle:g_hSDKWeaponWrench;
+
+new Handle:g_hSDKGetMaxHealth;
+new Handle:g_hSDKWantsLagCompensationOnEntity;
+new Handle:g_hSDKShouldTransmit;
+
+#include "rytp_horror/stocks.sp"
+#include "rytp_horror/overlay.sp"
+#include "rytp_horror/logging.sp"
+#include "rytp_horror/debug.sp"
+#include "rytp_horror/profiles.sp"
+#include "rytp_horror/nav.sp"
+#include "rytp_horror/effects.sp"
+#include "rytp_horror/playergroups.sp"
+#include "rytp_horror/menus.sp"
+#include "rytp_horror/pvp.sp"
+#include "rytp_horror/client.sp"
+#include "rytp_horror/npc.sp"
+#include "rytp_horror/specialround.sp"
+#include "rytp_horror/adminmenu.sp"
+
+
+#define SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND "ui/item_acquired.wav"
+
+//	==========================================================
+//	GENERAL PLUGIN HOOK FUNCTIONS
+//	==========================================================
+
+public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
+{
+	RegPluginLibrary("sf2");
+	
+	fOnBossAdded = CreateGlobalForward("SF2_OnBossAdded", ET_Ignore, Param_Cell);
+	fOnBossSpawn = CreateGlobalForward("SF2_OnBossSpawn", ET_Ignore, Param_Cell);
+	fOnBossChangeState = CreateGlobalForward("SF2_OnBossChangeState", ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
+	fOnBossRemoved = CreateGlobalForward("SF2_OnBossRemoved", ET_Ignore, Param_Cell);
+	fOnPagesSpawned = CreateGlobalForward("SF2_OnPagesSpawned", ET_Ignore);
+	fOnClientBlink = CreateGlobalForward("SF2_OnClientBlink", ET_Ignore, Param_Cell);
+	fOnClientCaughtByBoss = CreateGlobalForward("SF2_OnClientCaughtByBoss", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientGiveQueuePoints = CreateGlobalForward("SF2_OnClientGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
+	fOnClientActivateFlashlight = CreateGlobalForward("SF2_OnClientActivateFlashlight", ET_Ignore, Param_Cell);
+	fOnClientDeactivateFlashlight = CreateGlobalForward("SF2_OnClientDeactivateFlashlight", ET_Ignore, Param_Cell);
+	fOnClientBreakFlashlight = CreateGlobalForward("SF2_OnClientBreakFlashlight", ET_Ignore, Param_Cell);
+	fOnClientEscape = CreateGlobalForward("SF2_OnClientEscape", ET_Ignore, Param_Cell);
+	fOnClientLooksAtBoss = CreateGlobalForward("SF2_OnClientLooksAtBoss", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientLooksAwayFromBoss = CreateGlobalForward("SF2_OnClientLooksAwayFromBoss", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientStartDeathCam = CreateGlobalForward("SF2_OnClientStartDeathCam", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientEndDeathCam = CreateGlobalForward("SF2_OnClientEndDeathCam", ET_Ignore, Param_Cell, Param_Cell);
+	fOnClientGetDefaultWalkSpeed = CreateGlobalForward("SF2_OnClientGetDefaultWalkSpeed", ET_Hook, Param_Cell, Param_CellByRef);
+	fOnClientGetDefaultSprintSpeed = CreateGlobalForward("SF2_OnClientGetDefaultSprintSpeed", ET_Hook, Param_Cell, Param_CellByRef);
+	fOnClientSpawnedAsProxy = CreateGlobalForward("SF2_OnClientSpawnedAsProxy", ET_Ignore, Param_Cell);
+	fOnClientDamagedByBoss = CreateGlobalForward("SF2_OnClientDamagedByBoss", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Float, Param_Cell);
+	fOnGroupGiveQueuePoints = CreateGlobalForward("SF2_OnGroupGiveQueuePoints", ET_Hook, Param_Cell, Param_CellByRef);
+	
+	CreateNative("SF2_IsRunning", Native_IsRunning);
+	CreateNative("SF2_GetCurrentDifficulty", Native_GetCurrentDifficulty);
+	CreateNative("SF2_GetDifficultyModifier", Native_GetDifficultyModifier);
+	CreateNative("SF2_IsClientEliminated", Native_IsClientEliminated);
+	CreateNative("SF2_IsClientInGhostMode", Native_IsClientInGhostMode);
+	CreateNative("SF2_IsClientProxy", Native_IsClientProxy);
+	CreateNative("SF2_GetClientBlinkCount", Native_GetClientBlinkCount);
+	CreateNative("SF2_GetClientProxyMaster", Native_GetClientProxyMaster);
+	CreateNative("SF2_GetClientProxyControlAmount", Native_GetClientProxyControlAmount);
+	CreateNative("SF2_GetClientProxyControlRate", Native_GetClientProxyControlRate);
+	CreateNative("SF2_SetClientProxyMaster", Native_SetClientProxyMaster);
+	CreateNative("SF2_SetClientProxyControlAmount", Native_SetClientProxyControlAmount);
+	CreateNative("SF2_SetClientProxyControlRate", Native_SetClientProxyControlRate);
+	CreateNative("SF2_IsClientLookingAtBoss", Native_IsClientLookingAtBoss);
+	CreateNative("SF2_CollectAsPage", Native_CollectAsPage);
+	CreateNative("SF2_GetMaxBossCount", Native_GetMaxBosses);
+	CreateNative("SF2_EntIndexToBossIndex", Native_EntIndexToBossIndex);
+	CreateNative("SF2_BossIndexToEntIndex", Native_BossIndexToEntIndex);
+	CreateNative("SF2_BossIDToBossIndex", Native_BossIDToBossIndex);
+	CreateNative("SF2_BossIndexToBossID", Native_BossIndexToBossID);
+	CreateNative("SF2_GetBossName", Native_GetBossName);
+	CreateNative("SF2_GetBossModelEntity", Native_GetBossModelEntity);
+	CreateNative("SF2_GetBossTarget", Native_GetBossTarget);
+	CreateNative("SF2_GetBossMaster", Native_GetBossMaster);
+	CreateNative("SF2_GetBossState", Native_GetBossState);
+	CreateNative("SF2_IsBossProfileValid", Native_IsBossProfileValid);
+	CreateNative("SF2_GetBossProfileNum", Native_GetBossProfileNum);
+	CreateNative("SF2_GetBossProfileFloat", Native_GetBossProfileFloat);
+	CreateNative("SF2_GetBossProfileString", Native_GetBossProfileString);
+	CreateNative("SF2_GetBossProfileVector", Native_GetBossProfileVector);
+	CreateNative("SF2_GetRandomStringFromBossProfile", Native_GetRandomStringFromBossProfile);
+	
+	PvP_InitializeAPI();
+	
+	SpecialRoundInitializeAPI();
+	
+	return APLRes_Success;
+}
+
+public OnPluginStart()
+{
+	LoadTranslations("core.phrases");
+	LoadTranslations("common.phrases");
+	LoadTranslations("sf2.phrases");
+	
+	// Get offsets.
+	g_offsPlayerFOV = FindSendPropInfo("CBasePlayer", "m_iFOV");
+	if (g_offsPlayerFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iFOV.");
+	
+	g_offsPlayerDefaultFOV = FindSendPropInfo("CBasePlayer", "m_iDefaultFOV");
+	if (g_offsPlayerDefaultFOV == -1) SetFailState("Couldn't find CBasePlayer offset for m_iDefaultFOV.");
+	
+	g_offsPlayerFogCtrl = FindSendPropInfo("CBasePlayer", "m_PlayerFog.m_hCtrl");
+	if (g_offsPlayerFogCtrl == -1) LogError("Couldn't find CBasePlayer offset for m_PlayerFog.m_hCtrl!");
+	
+	g_offsPlayerPunchAngle = FindSendPropInfo("CBasePlayer", "m_vecPunchAngle");
+	if (g_offsPlayerPunchAngle == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngle!");
+	
+	g_offsPlayerPunchAngleVel = FindSendPropInfo("CBasePlayer", "m_vecPunchAngleVel");
+	if (g_offsPlayerPunchAngleVel == -1) LogError("Couldn't find CBasePlayer offset for m_vecPunchAngleVel!");
+	
+	g_offsFogCtrlEnable = FindSendPropInfo("CFogController", "m_fog.enable");
+	if (g_offsFogCtrlEnable == -1) LogError("Couldn't find CFogController offset for m_fog.enable!");
+	
+	g_offsFogCtrlEnd = FindSendPropInfo("CFogController", "m_fog.end");
+	if (g_offsFogCtrlEnd == -1) LogError("Couldn't find CFogController offset for m_fog.end!");
+	
+	g_hPageMusicRanges = CreateArray(3);
+	
+	// Register console variables.
+	g_cvVersion = CreateConVar("sf2_version", PLUGIN_VERSION, "The current version of Slender Fortress. DO NOT TOUCH!", FCVAR_SPONLY | FCVAR_NOTIFY | FCVAR_DONTRECORD);
+	SetConVarString(g_cvVersion, PLUGIN_VERSION);
+	
+	g_cvEnabled = CreateConVar("sf2_enabled", "1", "Enable/Disable the Slender Fortress gamemode. This will take effect on map change.", FCVAR_NOTIFY | FCVAR_DONTRECORD);
+	g_cvSlenderMapsOnly = CreateConVar("sf2_slendermapsonly", "1", "Only enable the Slender Fortress gamemode on map names prefixed with \"slender_\" or \"sf2_\".");
+	
+	g_cvGraceTime = CreateConVar("sf2_gracetime", "30.0");
+	g_cvIntroEnabled = CreateConVar("sf2_intro_enabled", "1");
+	g_cvIntroDefaultHoldTime = CreateConVar("sf2_intro_default_hold_time", "9.0");
+	g_cvIntroDefaultFadeTime = CreateConVar("sf2_intro_default_fade_time", "1.0");
+	
+	g_cvBlockSuicideDuringRound = CreateConVar("sf2_block_suicide_during_round", "0");
+	
+	g_cvAllChat = CreateConVar("sf2_alltalk", "0");
+	HookConVarChange(g_cvAllChat, OnConVarChanged);
+	
+	g_cvPlayerVoiceDistance = CreateConVar("sf2_player_voice_distance", "800.0", "The maximum distance RED can communicate in voice chat. Set to 0 if you want them to be heard at all times.", _, true, 0.0);
+	g_cvPlayerVoiceWallScale = CreateConVar("sf2_player_voice_scale_blocked", "0.5", "The distance required to hear RED in voice chat will be multiplied by this amount if something is blocking them.");
+	
+	g_cvPlayerViewbobEnabled = CreateConVar("sf2_player_viewbob_enabled", "1", "Enable/Disable player viewbobbing.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerViewbobEnabled, OnConVarChanged);
+	g_cvPlayerViewbobHurtEnabled = CreateConVar("sf2_player_viewbob_hurt_enabled", "0", "Enable/Disable player view tilting when hurt.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerViewbobHurtEnabled, OnConVarChanged);
+	g_cvPlayerViewbobSprintEnabled = CreateConVar("sf2_player_viewbob_sprint_enabled", "0", "Enable/Disable player step viewbobbing when sprinting.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerViewbobSprintEnabled, OnConVarChanged);
+	g_cvGravity = FindConVar("sv_gravity");
+	HookConVarChange(g_cvGravity, OnConVarChanged);
+	
+	g_cvPlayerFakeLagCompensation = CreateConVar("sf2_player_fakelagcompensation", "0", "(EXPERIMENTAL) Enable/Disable fake lag compensation for some hitscan weapons such as the Sniper Rifle.", _, true, 0.0, true, 1.0);
+	
+	g_cvPlayerShakeEnabled = CreateConVar("sf2_player_shake_enabled", "1", "Enable/Disable player view shake during boss encounters.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cvPlayerShakeEnabled, OnConVarChanged);
+	g_cvPlayerShakeFrequencyMax = CreateConVar("sf2_player_shake_frequency_max", "255", "Maximum frequency value of the shake. Should be a value between 1-255.", _, true, 1.0, true, 255.0);
+	g_cvPlayerShakeAmplitudeMax = CreateConVar("sf2_player_shake_amplitude_max", "5", "Maximum amplitude value of the shake. Should be a value between 1-16.", _, true, 1.0, true, 16.0);
+	
+	g_cvPlayerBlinkRate = CreateConVar("sf2_player_blink_rate", "0.33", "How long (in seconds) each bar on the player's Blink meter lasts.", _, true, 0.0);
+	g_cvPlayerBlinkHoldTime = CreateConVar("sf2_player_blink_holdtime", "0.15", "How long (in seconds) a player will stay in Blink mode when he or she blinks.", _, true, 0.0);
+	
+	g_cvUltravisionEnabled = CreateConVar("sf2_player_ultravision_enabled", "1", "Enable/Disable player Ultravision. This helps players see in the dark when their Flashlight is off or unavailable.", _, true, 0.0, true, 1.0);
+	g_cvUltravisionRadiusRed = CreateConVar("sf2_player_ultravision_radius_red", "512.0");
+	g_cvUltravisionRadiusBlue = CreateConVar("sf2_player_ultravision_radius_blue", "800.0");
+	g_cvUltravisionBrightness = CreateConVar("sf2_player_ultravision_brightness", "-4");
+	
+	g_cvGhostModeConnectionCheck = CreateConVar("sf2_ghostmode_check_connection", "1", "Checks a player's connection while in Ghost Mode. If the check fails, the client is booted out of Ghost Mode and the action and client's SteamID is logged in the main SF2 log.");
+	g_cvGhostModeConnectionTolerance = CreateConVar("sf2_ghostmode_connection_tolerance", "5.0", "If sf2_ghostmode_check_connection is set to 1 and the client has timed out for at least this amount of time, the client will be booted out of Ghost Mode.");
+	
+	g_cv20Dollars = CreateConVar("sf2_20dollarmode", "0", "Enable/Disable $20 mode.", _, true, 0.0, true, 1.0);
+	HookConVarChange(g_cv20Dollars, OnConVarChanged);
+	
+	g_cvMaxPlayers = CreateConVar("sf2_maxplayers", "5", "The maximum amount of players that can be in one round.", _, true, 1.0);
+	HookConVarChange(g_cvMaxPlayers, OnConVarChanged);
+	
+	g_cvMaxPlayersOverride = CreateConVar("sf2_maxplayers_override", "-1", "Overrides the maximum amount of players that can be in one round.", _, true, -1.0);
+	HookConVarChange(g_cvMaxPlayersOverride, OnConVarChanged);
+	
+	g_cvCampingEnabled = CreateConVar("sf2_anticamping_enabled", "1", "Enable/Disable anti-camping system for RED.", _, true, 0.0, true, 1.0);
+	g_cvCampingMaxStrikes = CreateConVar("sf2_anticamping_maxstrikes", "4", "How many 5-second intervals players are allowed to stay in one spot before he/she is forced to suicide.", _, true, 0.0);
+	g_cvCampingStrikesWarn = CreateConVar("sf2_anticamping_strikeswarn", "2", "The amount of strikes left where the player will be warned of camping.");
+	g_cvCampingMinDistance = CreateConVar("sf2_anticamping_mindistance", "128.0", "Every 5 seconds the player has to be at least this far away from his last position 5 seconds ago or else he'll get a strike.");
+	g_cvCampingNoStrikeSanity = CreateConVar("sf2_anticamping_no_strike_sanity", "0.1", "The camping system will NOT give any strikes under any circumstances if the players's Sanity is missing at least this much of his maximum Sanity (max is 1.0).");
+	g_cvCampingNoStrikeBossDistance = CreateConVar("sf2_anticamping_no_strike_boss_distance", "512.0", "The camping system will NOT give any strikes under any circumstances if the player is this close to a boss (ignoring LOS).");
+	g_cvBossMain = CreateConVar("sf2_boss_main", "slenderman", "The name of the main boss (its profile name, not its display name)");
+	g_cvBossProfileOverride = CreateConVar("sf2_boss_profile_override", "", "Overrides which boss will be chosen next. Only applies to the first boss being chosen.");
+	g_cvDifficulty = CreateConVar("sf2_difficulty", "1", "Difficulty of the game. 1 = Normal, 2 = Hard, 3 = Insane.", _, true, 1.0, true, 3.0);
+	HookConVarChange(g_cvDifficulty, OnConVarChanged);
+	
+	g_cvSpecialRoundBehavior = CreateConVar("sf2_specialround_mode", "0", "0 = Special Round resets on next round, 1 = Special Round keeps going until all players have played (not counting spectators, recently joined players, and those who reset their queue points during the round)", _, true, 0.0, true, 1.0);
+	g_cvSpecialRoundForce = CreateConVar("sf2_specialround_forceenable", "-1", "Sets whether a Special Round will occur on the next round or not.", _, true, -1.0, true, 1.0);
+	g_cvSpecialRoundOverride = CreateConVar("sf2_specialround_forcetype", "-1", "Sets the type of Special Round that will be chosen on the next Special Round. Set to -1 to let the game choose.", _, true, -1.0);
+	g_cvSpecialRoundInterval = CreateConVar("sf2_specialround_interval", "5", "If this many rounds are completed, the next round will be a Special Round.", _, true, 0.0);
+	
+	g_cvNewBossRoundBehavior = CreateConVar("sf2_newbossround_mode", "0", "0 = boss selection will return to normal after the boss round, 1 = the new boss will continue being the boss until all players in the server have played against it (not counting spectators, recently joined players, and those who reset their queue points during the round).", _, true, 0.0, true, 1.0);
+	g_cvNewBossRoundInterval = CreateConVar("sf2_newbossround_interval", "3", "If this many rounds are completed, the next round's boss will be randomly chosen, but will not be the main boss.", _, true, 0.0);
+	g_cvNewBossRoundForce = CreateConVar("sf2_newbossround_forceenable", "-1", "Sets whether a new boss will be chosen on the next round or not. Set to -1 to let the game choose.", _, true, -1.0, true, 1.0);
+	
+	g_cvTimeLimit = CreateConVar("sf2_timelimit_default", "300", "The time limit of the round. Maps can change the time limit.", _, true, 0.0);
+	g_cvTimeLimitEscape = CreateConVar("sf2_timelimit_escape_default", "90", "The time limit to escape. Maps can change the time limit.", _, true, 0.0);
+	g_cvTimeGainFromPageGrab = CreateConVar("sf2_time_gain_page_grab", "12", "The time gained from grabbing a page. Maps can change the time gain amount.");
+	
+	g_cvWarmupRound = CreateConVar("sf2_warmupround", "1", "Enables/disables Warmup Rounds after the \"Waiting for Players\" phase.", _, true, 0.0, true, 1.0);
+	g_cvWarmupRoundNum = CreateConVar("sf2_warmupround_num", "1", "Sets the amount of Warmup Rounds that occur after the \"Waiting for Players\" phase.", _, true, 0.0);
+	
+	g_cvPlayerProxyWaitTime = CreateConVar("sf2_player_proxy_waittime", "35", "How long (in seconds) after a player was chosen to be a Proxy must the system wait before choosing him again.");
+	g_cvPlayerProxyAsk = CreateConVar("sf2_player_proxy_ask", "0", "Set to 1 if the player can choose before becoming a Proxy, set to 0 to force.");
+	
+	g_cvHalfZatoichiHealthGain = CreateConVar("sf2_halfzatoichi_healthgain", "20", "How much health should be gained from killing a player with the Half-Zatoichi? Set to -1 for default behavior.");
+	
+	g_cvPlayerInfiniteSprintOverride = CreateConVar("sf2_player_infinite_sprint_override", "-1", "1 = infinite sprint, 0 = never have infinite sprint, -1 = let the game choose.", _, true, -1.0, true, 1.0);
+	g_cvPlayerInfiniteFlashlightOverride = CreateConVar("sf2_player_infinite_flashlight_override", "-1", "1 = infinite flashlight, 0 = never have infinite flashlight, -1 = let the game choose.", _, true, -1.0, true, 1.0);
+	g_cvPlayerInfiniteBlinkOverride = CreateConVar("sf2_player_infinite_blink_override", "-1", "1 = infinite blink, 0 = never have infinite blink, -1 = let the game choose.", _, true, -1.0, true, 1.0);
+	
+	g_cvMaxRounds = FindConVar("mp_maxrounds");
+	
+	g_hHudSync = CreateHudSynchronizer();
+	g_hHudSync2 = CreateHudSynchronizer();
+	g_hRoundTimerSync = CreateHudSynchronizer();
+	g_hCookie = RegClientCookie("slender_cookie", "", CookieAccess_Private);
+	
+	// Register console commands.
+	RegConsoleCmd("sm_sf2", Command_MainMenu);
+	RegConsoleCmd("sm_slender", Command_MainMenu);
+	RegConsoleCmd("sm_horror", Command_MainMenu);
+	RegConsoleCmd("sm_slnext", Command_Next);
+	RegConsoleCmd("sm_slgroup", Command_Group);
+	RegConsoleCmd("sm_slgroupname", Command_GroupName);
+	RegConsoleCmd("sm_slghost", Command_GhostMode);
+	RegConsoleCmd("sm_slhelp", Command_Help);
+	RegConsoleCmd("sm_slsettings", Command_Settings);
+	RegConsoleCmd("sm_slcredits", Command_Credits);
+	RegConsoleCmd("sm_flashlight", Command_ToggleFlashlight);
+	RegConsoleCmd("+sprint", Command_SprintOn);
+	RegConsoleCmd("-sprint", Command_SprintOff);
+	
+	RegAdminCmd("sm_sf2_scare", Command_ClientPerformScare, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_spawn_boss", Command_SpawnSlender, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_add_boss", Command_AddSlender, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_add_boss_fake", Command_AddSlenderFake, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_remove_boss", Command_RemoveSlender, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_getbossindexes", Command_GetBossIndexes, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_setplaystate", Command_ForceState, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_boss_attack_waiters", Command_SlenderAttackWaiters, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_boss_no_teleport", Command_SlenderNoTeleport, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_force_proxy", Command_ForceProxy, ADMFLAG_SLAY);
+	RegAdminCmd("sm_sf2_force_escape", Command_ForceEscape, ADMFLAG_CHEATS);
+	
+	// Hook onto existing console commands.
+	AddCommandListener(Hook_CommandBuild, "build");
+	AddCommandListener(Hook_CommandSuicideAttempt, "kill");
+	AddCommandListener(Hook_CommandSuicideAttempt, "explode");
+	AddCommandListener(Hook_CommandSuicideAttempt, "joinclass");
+	AddCommandListener(Hook_CommandSuicideAttempt, "join_class");
+	AddCommandListener(Hook_CommandSuicideAttempt, "jointeam");
+	AddCommandListener(Hook_CommandSuicideAttempt, "spectate");
+	AddCommandListener(Hook_CommandVoiceMenu, "voicemenu");
+	AddCommandListener(Hook_CommandSay, "say");
+	
+	// Hook events.
+	HookEvent("teamplay_round_start", Event_RoundStart);
+	HookEvent("teamplay_round_win", Event_RoundEnd);
+	HookEvent("player_team", Event_DontBroadcastToClients, EventHookMode_Pre);
+	HookEvent("player_team", Event_PlayerTeam);
+	HookEvent("player_spawn", Event_PlayerSpawn);
+	HookEvent("player_hurt", Event_PlayerHurt);
+	HookEvent("post_inventory_application", Event_PostInventoryApplication);
+	HookEvent("item_found", Event_DontBroadcastToClients, EventHookMode_Pre);
+	HookEvent("teamplay_teambalanced_player", Event_DontBroadcastToClients, EventHookMode_Pre);
+	HookEvent("fish_notice", Event_PlayerDeathPre, EventHookMode_Pre);
+	HookEvent("fish_notice__arm", Event_PlayerDeathPre, EventHookMode_Pre);
+	HookEvent("player_death", Event_PlayerDeathPre, EventHookMode_Pre);
+	HookEvent("player_death", Event_PlayerDeath);
+	
+	// Hook entities.
+	HookEntityOutput("trigger_multiple", "OnStartTouch", Hook_TriggerOnStartTouch);
+	HookEntityOutput("trigger_multiple", "OnEndTouch", Hook_TriggerOnEndTouch);
+	
+	// Hook usermessages.
+	HookUserMessage(GetUserMessageId("VoiceSubtitle"), Hook_BlockUserMessage, true);
+	
+	// Hook sounds.
+	AddNormalSoundHook(Hook_NormalSound);
+	
+	AddTempEntHook("Fire Bullets", Hook_TEFireBullets);
+	
+	InitializeBossProfiles();
+	
+	NPCInitialize();
+	
+	SetupMenus();
+	
+	SetupAdminMenu();
+	
+	SetupClassDefaultWeapons();
+	
+	SetupPlayerGroups();
+	
+	PvP_Initialize();
+	
+	// @TODO: When cvars are finalized, set this to true.
+	AutoExecConfig(false);
+	
+#if defined DEBUG
+	InitializeDebug();
+#endif
+}
+
+public OnAllPluginsLoaded()
+{
+	SetupHooks();
+}
+
+public OnPluginEnd()
+{
+	for(new c = 1; c < MaxClients; c++) DestroySpriteOverlay(c);
+	StopPlugin();
+}
+
+static SetupHooks()
+{
+	// Check SDKHooks gamedata.
+	new Handle:hConfig = LoadGameConfigFile("sdkhooks.games");
+	if (hConfig == INVALID_HANDLE) SetFailState("Couldn't find SDKHooks gamedata!");
+	
+	StartPrepSDKCall(SDKCall_Entity);
+	PrepSDKCall_SetFromConf(hConfig, SDKConf_Virtual, "GetMaxHealth");
+	PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
+	if ((g_hSDKGetMaxHealth = EndPrepSDKCall()) == INVALID_HANDLE)
+	{
+		SetFailState("Failed to retrieve GetMaxHealth offset from SDKHooks gamedata!");
+	}
+	
+	CloseHandle(hConfig);
+	
+	// Check our own gamedata.
+	hConfig = LoadGameConfigFile("sf2");
+	if (hConfig == INVALID_HANDLE) SetFailState("Could not find SF2 gamedata!");
+	
+	new iOffset = GameConfGetOffset(hConfig, "CTFPlayer::WantsLagCompensationOnEntity"); 
+	g_hSDKWantsLagCompensationOnEntity = DHookCreate(iOffset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_ClientWantsLagCompensationOnEntity); 
+	if (g_hSDKWantsLagCompensationOnEntity == INVALID_HANDLE)
+	{
+		SetFailState("Failed to create hook CTFPlayer::WantsLagCompensationOnEntity offset from SF2 gamedata!");
+	}
+	
+	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_CBaseEntity);
+	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_ObjectPtr);
+	DHookAddParam(g_hSDKWantsLagCompensationOnEntity, HookParamType_Unknown);
+	
+	iOffset = GameConfGetOffset(hConfig, "CBaseEntity::ShouldTransmit");
+	g_hSDKShouldTransmit = DHookCreate(iOffset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, Hook_EntityShouldTransmit);
+	if (g_hSDKShouldTransmit == INVALID_HANDLE)
+	{
+		SetFailState("Failed to create hook CBaseEntity::ShouldTransmit offset from SF2 gamedata!");
+	}
+	
+	DHookAddParam(g_hSDKShouldTransmit, HookParamType_ObjectPtr);
+	
+	CloseHandle(hConfig);
+}
+
+static SetupClassDefaultWeapons()
+{
+	// Scout
+	g_hSDKWeaponScattergun = PrepareItemHandle("tf_weapon_scattergun", 13, 0, 0, "");
+	g_hSDKWeaponPistolScout = PrepareItemHandle("tf_weapon_pistol", 23, 0, 0, "");
+	g_hSDKWeaponBat = PrepareItemHandle("tf_weapon_bat", 0, 0, 0, "");
+	
+	// Sniper
+	g_hSDKWeaponSniperRifle = PrepareItemHandle("tf_weapon_sniperrifle", 14, 0, 0, "");
+	g_hSDKWeaponSMG = PrepareItemHandle("tf_weapon_smg", 16, 0, 0, "");
+	g_hSDKWeaponKukri = PrepareItemHandle("tf_weapon_club", 3, 0, 0, "");
+	
+	// Soldier
+	g_hSDKWeaponRocketLauncher = PrepareItemHandle("tf_weapon_rocketlauncher", 18, 0, 0, "");
+	g_hSDKWeaponShotgunSoldier = PrepareItemHandle("tf_weapon_shotgun", 10, 0, 0, "");
+	g_hSDKWeaponShovel = PrepareItemHandle("tf_weapon_shovel", 6, 0, 0, "");
+	
+	// Demoman
+	g_hSDKWeaponGrenadeLauncher = PrepareItemHandle("tf_weapon_grenadelauncher", 19, 0, 0, "");
+	g_hSDKWeaponStickyLauncher = PrepareItemHandle("tf_weapon_pipebomblauncher", 20, 0, 0, "");
+	g_hSDKWeaponBottle = PrepareItemHandle("tf_weapon_bottle", 1, 0, 0, "");
+	
+	// Heavy
+	g_hSDKWeaponMinigun = PrepareItemHandle("tf_weapon_minigun", 15, 0, 0, "");
+	g_hSDKWeaponShotgunHeavy = PrepareItemHandle("tf_weapon_shotgun", 11, 0, 0, "");
+	g_hSDKWeaponFists = PrepareItemHandle("tf_weapon_fists", 5, 0, 0, "");
+	
+	// Medic
+	g_hSDKWeaponSyringeGun = PrepareItemHandle("tf_weapon_syringegun_medic", 17, 0, 0, "");
+	g_hSDKWeaponMedigun = PrepareItemHandle("tf_weapon_medigun", 29, 0, 0, "");
+	g_hSDKWeaponBonesaw = PrepareItemHandle("tf_weapon_bonesaw", 8, 0, 0, "");
+	
+	// Pyro
+	g_hSDKWeaponFlamethrower = PrepareItemHandle("tf_weapon_flamethrower", 21, 0, 0, "254 ; 4.0");
+	g_hSDKWeaponShotgunPyro = PrepareItemHandle("tf_weapon_shotgun", 12, 0, 0, "");
+	g_hSDKWeaponFireaxe = PrepareItemHandle("tf_weapon_fireaxe", 2, 0, 0, "");
+	
+	// Spy
+	g_hSDKWeaponRevolver = PrepareItemHandle("tf_weapon_revolver", 24, 0, 0, "");
+	g_hSDKWeaponKnife = PrepareItemHandle("tf_weapon_knife", 4, 0, 0, "");
+	g_hSDKWeaponInvis = PrepareItemHandle("tf_weapon_invis", 297, 0, 0, "");
+	
+	// Engineer
+	g_hSDKWeaponShotgunPrimary = PrepareItemHandle("tf_weapon_shotgun", 9, 0, 0, "");
+	g_hSDKWeaponPistol = PrepareItemHandle("tf_weapon_pistol", 22, 0, 0, "");
+	g_hSDKWeaponWrench = PrepareItemHandle("tf_weapon_wrench", 7, 0, 0, "");
+}
+
+public OnMapStart()
+{
+	PvP_OnMapStart();
+}
+
+public OnConfigsExecuted()
+{
+	if (!GetConVarBool(g_cvEnabled))
+	{
+		StopPlugin();
+	}
+	else
+	{
+		if (GetConVarBool(g_cvSlenderMapsOnly))
+		{
+			decl String:sMap[256];
+			GetCurrentMap(sMap, sizeof(sMap));
+			
+			if (!StrContains(sMap, "slender_", false) || !StrContains(sMap, "sf2_", false))
+			{
+				StartPlugin();
+			}
+			else
+			{
+				LogMessage("%s is not a Slender Fortress map. Plugin disabled!", sMap);
+				StopPlugin();
+			}
+		}
+		else
+		{
+			StartPlugin();
+		}
+	}
+}
+
+static StartPlugin()
+{
+	if (g_bEnabled) return;
+	
+	g_bEnabled = true;
+	
+	InitializeLogging();
+	
+#if defined DEBUG
+	InitializeDebugLogging();
+#endif
+	
+	// Handle ConVars.
+	new Handle:hCvar = FindConVar("mp_friendlyfire");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
+	
+	hCvar = FindConVar("mp_flashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
+	
+	hCvar = FindConVar("mat_supportflashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, true);
+	
+	hCvar = FindConVar("mp_autoteambalance");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	g_flGravity = GetConVarFloat(g_cvGravity);
+	
+	g_b20Dollars = GetConVarBool(g_cv20Dollars);
+	
+	g_bPlayerShakeEnabled = GetConVarBool(g_cvPlayerShakeEnabled);
+	g_bPlayerViewbobEnabled = GetConVarBool(g_cvPlayerViewbobEnabled);
+	g_bPlayerViewbobHurtEnabled = GetConVarBool(g_cvPlayerViewbobHurtEnabled);
+	g_bPlayerViewbobSprintEnabled = GetConVarBool(g_cvPlayerViewbobSprintEnabled);
+	
+	decl String:sBuffer[64];
+	Format(sBuffer, sizeof(sBuffer), "RYTP Horror", PLUGIN_VERSION_DISPLAY);
+	Steam_SetGameDescription(sBuffer);
+	
+	PrecacheStuff();
+	
+	// Reset special round.
+	g_bSpecialRound = false;
+	g_bSpecialRoundNew = false;
+	g_bSpecialRoundContinuous = false;
+	g_iSpecialRoundCount = 1;
+	g_iSpecialRoundType = 0;
+	
+	SpecialRoundReset();
+	
+	// Reset boss rounds.
+	g_bNewBossRound = false;
+	g_bNewBossRoundNew = false;
+	g_bNewBossRoundContinuous = false;
+	g_iNewBossRoundCount = 1;
+	strcopy(g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile), "");
+	
+	// Reset global round vars.
+	g_iRoundCount = 0;
+	g_iRoundEndCount = 0;
+	g_iRoundActiveCount = 0;
+	g_iRoundState = SF2RoundState_Invalid;
+	g_hRoundMessagesTimer = CreateTimer(200.0, Timer_RoundMessages, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	g_iRoundMessagesNum = 0;
+	
+	g_iRoundWarmupRoundCount = 0;
+	
+	g_hClientAverageUpdateTimer = CreateTimer(0.2, Timer_ClientAverageUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	g_hBossCountUpdateTimer = CreateTimer(2.0, Timer_BossCountUpdate, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	
+	SetRoundState(SF2RoundState_Waiting);
+	
+	ReloadBossProfiles();
+	ReloadRestrictedWeapons();
+	ReloadSpecialRounds();
+	
+	NPCOnConfigsExecuted();
+	
+	InitializeBossPackVotes();
+	SetupTimeLimitTimerForBossPackVote();
+	
+	// Late load compensation.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		OnClientPutInServer(i);
+	}
+}
+
+static PrecacheStuff()
+{
+	// Initialize particles.
+	g_iParticleCriticalHit = PrecacheParticleSystem(CRIT_PARTICLENAME);
+	
+	PrecacheSound2(CRIT_SOUND);
+	
+	// simple_bot;
+	PrecacheModel("models/humans/group01/female_01.mdl", true);
+	
+	PrecacheModel(PAGE_MODEL, true);
+	PrecacheModel(GHOST_MODEL, true);
+	
+	PrecacheSound2(FLASHLIGHT_CLICKSOUND);
+	PrecacheSound2(FLASHLIGHT_BREAKSOUND);
+	PrecacheSound2(FLASHLIGHT_NOSOUND);
+	PrecacheSound2(PAGE_GRABSOUND);
+	
+	PrecacheSound2(MUSIC_GOTPAGES1_SOUND);
+	PrecacheSound2(MUSIC_GOTPAGES2_SOUND);
+	PrecacheSound2(MUSIC_GOTPAGES3_SOUND);
+	PrecacheSound2(MUSIC_GOTPAGES4_SOUND);
+	
+	PrecacheSound2(SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
+	
+	for (new i = 0; i < sizeof(g_strPlayerBreathSounds); i++)
+	{
+		PrecacheSound2(g_strPlayerBreathSounds[i]);
+	}
+	
+	for (new i = 0; i < sizeof(g_strGhostHelpPhrases); i++)
+	{
+		PrecacheSound2(g_strGhostHelpPhrases[i]);
+	}
+	
+	for (new i = 0; i < sizeof(g_sOverlayMat); i++)
+	{
+		new String:path[PLATFORM_MAX_PATH];
+		Format(path, sizeof(path), "%s.vmt", g_sOverlayMat[i]);
+		PrecacheModel(path);
+		Format(path, sizeof(path), "%s.vtf", g_sOverlayMat[i]);
+		PrecacheModel(path);
+	}
+	PrecacheMaterial2(STATIC_OVERLAY);
+	PrecacheSound2(STATIC_SOUND);
+	
+	// Special round.
+	PrecacheSound2(SR_MUSIC);
+	PrecacheSound2(SR_SOUND_SELECT);
+	PrecacheSound2(SF2_INTRO_DEFAULT_MUSIC);
+	
+	PrecacheMaterial2(SF2_OVERLAY_DEFAULT);
+	PrecacheMaterial2(SF2_OVERLAY_DEFAULT_NO_FILMGRAIN);
+	PrecacheMaterial2(SF2_OVERLAY_GHOST);
+	
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.mdl");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx80.vtx");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.dx90.vtx");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.phy");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.sw.vtx");
+	AddFileToDownloadsTable("models/rytp/horror/props/hint_paper.vvd");
+	
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_1.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_2.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_3.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_4.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_5.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_6.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_7.vmt");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vtf");
+	AddFileToDownloadsTable("materials/models/rytp/horror/props/hint_paper/paper_8.vmt");
+	
+	// pvp
+	PvP_Precache();
+}
+
+static StopPlugin()
+{
+	if (!g_bEnabled) return;
+	
+	g_bEnabled = false;
+	
+	// Reset CVars.
+	new Handle:hCvar = FindConVar("mp_friendlyfire");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	hCvar = FindConVar("mp_flashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	hCvar = FindConVar("mat_supportflashlight");
+	if (hCvar != INVALID_HANDLE) SetConVarBool(hCvar, false);
+	
+	// Cleanup bosses.
+	NPCRemoveAll();
+	
+	// Cleanup clients.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		ClientResetFlashlight(i);
+		ClientDeactivateUltravision(i);
+		ClientDisableConstantGlow(i);
+		ClientRemoveInteractiveGlow(i);
+	}
+	
+	BossProfilesOnMapEnd();
+}
+
+public OnMapEnd()
+{
+	StopPlugin();
+}
+
+public OnMapTimeLeftChanged()
+{
+	if (g_bEnabled)
+	{
+		SetupTimeLimitTimerForBossPackVote();
+	}
+}
+
+public TF2_OnConditionAdded(client, TFCond:cond)
+{
+	if (cond == TFCond_Taunting)
+	{
+		if (IsClientInGhostMode(client))
+		{
+			// Stop ghosties from taunting.
+			TF2_RemoveCondition(client, TFCond_Taunting);
+		}
+	}
+}
+
+public OnGameFrame()
+{
+	if (!g_bEnabled) return;
+
+	// Process through boss movement.
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		new iBoss = NPCGetEntIndex(i);
+		if (!iBoss || iBoss == INVALID_ENT_REFERENCE) continue;
+		
+		if (NPCGetFlags(i) & SFF_MARKEDASFAKE) continue;
+		
+		new iType = NPCGetType(i);
+		
+		switch (iType)
+		{
+			case SF2BossType_Static:
+			{
+				decl Float:myPos[3], Float:hisPos[3];
+				SlenderGetAbsOrigin(i, myPos);
+				AddVectors(myPos, g_flSlenderEyePosOffset[i], myPos);
+				
+				new iBestPlayer = -1;
+				new Float:flBestDistance = 16384.0;
+				new Float:flTempDistance;
+				
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsClientInGame(iClient) || !IsPlayerAlive(iClient) || IsClientInGhostMode(iClient) || IsClientInDeathCam(iClient)) continue;
+					if (!IsPointVisibleToPlayer(iClient, myPos, false, false)) continue;
+					
+					GetClientAbsOrigin(iClient, hisPos);
+					
+					flTempDistance = GetVectorDistance(myPos, hisPos);
+					if (flTempDistance < flBestDistance)
+					{
+						iBestPlayer = iClient;
+						flBestDistance = flTempDistance;
+					}
+				}
+				
+				if (iBestPlayer > 0)
+				{
+					SlenderGetAbsOrigin(i, myPos);
+					GetClientAbsOrigin(iBestPlayer, hisPos);
+					
+					if (!SlenderOnlyLooksIfNotSeen(i) || !IsPointVisibleToAPlayer(myPos, false, SlenderUsesBlink(i)))
+					{
+						new Float:flTurnRate = NPCGetTurnRate(i);
+					
+						if (flTurnRate > 0.0)
+						{
+							decl Float:flMyEyeAng[3], Float:ang[3];
+							GetEntPropVector(iBoss, Prop_Data, "m_angAbsRotation", flMyEyeAng);
+							AddVectors(flMyEyeAng, g_flSlenderEyeAngOffset[i], flMyEyeAng);
+							SubtractVectors(hisPos, myPos, ang);
+							GetVectorAngles(ang, ang);
+							ang[0] = 0.0;
+							ang[1] += (AngleDiff(ang[1], flMyEyeAng[1]) >= 0.0 ? 1.0 : -1.0) * flTurnRate * GetTickInterval();
+							ang[2] = 0.0;
+							
+							// Take care of angle offsets.
+							AddVectors(ang, g_flSlenderEyePosOffset[i], ang);
+							for (new i2 = 0; i2 < 3; i2++) ang[i2] = AngleNormalize(ang[i2]);
+							
+							TeleportEntity(iBoss, NULL_VECTOR, ang, NULL_VECTOR);
+						}
+					}
+				}
+			}
+			case SF2BossType_Chaser:
+			{
+				SlenderChaseBossProcessMovement(i);
+			}
+		}
+	}
+	
+	PvP_OnGameFrame();
+}
+
+//	==========================================================
+//	COMMANDS AND COMMAND HOOK FUNCTIONS
+//	==========================================================
+
+public Action:Command_Help(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayMenu(g_hMenuHelp, client, 30);
+	return Plugin_Handled;
+}
+
+public Action:Command_Settings(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayMenu(g_hMenuSettings, client, 30);
+	return Plugin_Handled;
+}
+
+public Action:Command_Credits(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayMenu(g_hMenuCredits, client, MENU_TIME_FOREVER);
+	return Plugin_Handled;
+}
+
+public Action:Command_ToggleFlashlight(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return Plugin_Handled;
+	
+	if (!IsRoundInWarmup() && !IsRoundInIntro() && !IsRoundEnding() && !DidClientEscape(client))
+	{
+		if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
+		{
+			ClientHandleFlashlight(client);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SprintOn(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
+	{
+		ClientHandleSprint(client, true);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SprintOff(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsPlayerAlive(client) && !g_bPlayerEliminated[client])
+	{
+		ClientHandleSprint(client, false);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_MainMenu(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	DisplayMenu(g_hMenuMain, client, 30);
+	return Plugin_Handled;
+}
+
+public Action:Command_Next(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayQueuePointsMenu(client);
+	return Plugin_Handled;
+}
+
+public Action:Command_Group(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	DisplayGroupMainMenuToClient(client);
+	return Plugin_Handled;
+}
+
+public Action:Command_GroupName(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_slgroupname <name>");
+		return Plugin_Handled;
+	}
+	
+	new iGroupIndex = ClientGetPlayerGroup(client);
+	if (!IsPlayerGroupActive(iGroupIndex))
+	{
+		CPrintToChat(client, "%T", "SF2 Group Does Not Exist", client);
+		return Plugin_Handled;
+	}
+	
+	if (GetPlayerGroupLeader(iGroupIndex) != client)
+	{
+		CPrintToChat(client, "%T", "SF2 Not Group Leader", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:sGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	GetCmdArg(1, sGroupName, sizeof(sGroupName));
+	if (!sGroupName[0])
+	{
+		CPrintToChat(client, "%T", "SF2 Invalid Group Name", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:sOldGroupName[SF2_MAX_PLAYER_GROUP_NAME_LENGTH];
+	GetPlayerGroupName(iGroupIndex, sOldGroupName, sizeof(sOldGroupName));
+	SetPlayerGroupName(iGroupIndex, sGroupName);
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i)) continue;
+		if (ClientGetPlayerGroup(i) != iGroupIndex) continue;
+		CPrintToChat(i, "%T", "SF2 Group Name Set", i, sOldGroupName, sGroupName);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_GhostMode(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	DisplayMenu(g_hMenuGhostMode, client, 15);
+	return Plugin_Handled;
+}
+
+public Action:Hook_CommandSay(client, const String:command[], argc)
+{
+	if (!g_bEnabled || GetConVarBool(g_cvAllChat)) return Plugin_Continue;
+	
+	if (!IsRoundEnding())
+	{
+		if (g_bPlayerEliminated[client])
+		{
+			decl String:sMessage[256];
+			GetCmdArgString(sMessage, sizeof(sMessage));
+			FakeClientCommand(client, "say_team %s", sMessage);
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_CommandSuicideAttempt(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsClientInGhostMode(client)) return Plugin_Handled;
+	
+	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
+	
+	if (GetConVarBool(g_cvBlockSuicideDuringRound))
+	{
+		if (!g_bRoundGrace && !g_bPlayerEliminated[client] && !DidClientEscape(client))
+		{
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_CommandBlockInGhostMode(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsClientInGhostMode(client)) return Plugin_Handled;
+	if (IsRoundInIntro() && !g_bPlayerEliminated[client]) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_CommandVoiceMenu(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsClientInGhostMode(client))
+	{
+		ClientGhostModeNextTarget(client);
+		return Plugin_Handled;
+	}
+	
+	if (g_bPlayerProxy[client])
+	{
+		new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+		if (iMaster != -1)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
+		
+			if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
+			{
+				return Plugin_Handled;
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Command_ClientPerformScare(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_scare <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32], String:arg2[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			COMMAND_FILTER_ALIVE,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new target = target_list[i];
+		ClientPerformScare(target, StringToInt(arg2));
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SpawnSlender(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args == 0)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_spawn_boss <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl Float:eyePos[3], Float:eyeAng[3], Float:endPos[3];
+	GetClientEyePosition(client, eyePos);
+	GetClientEyeAngles(client, eyeAng);
+	
+	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
+	TR_GetEndPosition(endPos, hTrace);
+	CloseHandle(hTrace);
+	
+	SpawnSlender(iBossIndex, endPos);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Spawned Boss", client);
+	LogAction(client, -1, "%N spawned boss %d! (%s)", client, iBossIndex, sProfile);
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_RemoveSlender(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args == 0)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_remove_boss <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	NPCRemove(iBossIndex);
+	
+	CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Removed Boss", client);
+	LogAction(client, -1, "%N removed boss %d! (%s)", client, iBossIndex, sProfile);
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_GetBossIndexes(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	decl String:sMessage[512];
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	ClientCommand(client, "echo Active Boss Indexes:");
+	ClientCommand(client, "echo ----------------------------");
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		Format(sMessage, sizeof(sMessage), "%d - %s", i, sProfile);
+		if (NPCGetFlags(i) & SFF_FAKE)
+		{
+			StrCat(sMessage, sizeof(sMessage), " (fake)");
+		}
+		
+		if (g_iSlenderCopyMaster[i] != -1)
+		{
+			decl String:sCat[64];
+			Format(sCat, sizeof(sCat), " (copy of %d)", g_iSlenderCopyMaster[i]);
+			StrCat(sMessage, sizeof(sMessage), sCat);
+		}
+		
+		ClientCommand(client, "echo %s", sMessage);
+	}
+	
+	ClientCommand(client, "echo ----------------------------");
+	
+	ReplyToCommand(client, "Printed active boss indexes to your console!");
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SlenderAttackWaiters(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_boss_attack_waiters <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iBossFlags = NPCGetFlags(iBossIndex);
+	
+	new bool:bState = bool:StringToInt(arg2);
+	new bool:bOldState = bool:(iBossFlags & SFF_ATTACKWAITERS);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (bState)
+	{
+		if (!bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags | SFF_ATTACKWAITERS);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Attack Waiters", client);
+			LogAction(client, -1, "%N forced boss %d to attack waiters! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	else
+	{
+		if (bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_ATTACKWAITERS);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Do Not Attack Waiters", client);
+			LogAction(client, -1, "%N forced boss %d to not attack waiters! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_SlenderNoTeleport(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_boss_no_teleport <bossindex 0-%d> <0/1>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	new iBossIndex = StringToInt(arg1);
+	if (NPCGetUniqueID(iBossIndex) == -1) return Plugin_Handled;
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iBossFlags = NPCGetFlags(iBossIndex);
+	
+	new bool:bState = bool:StringToInt(arg2);
+	new bool:bOldState = bool:(iBossFlags & SFF_NOTELEPORT);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (bState)
+	{
+		if (!bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags | SFF_NOTELEPORT);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Not Teleport", client);
+			LogAction(client, -1, "%N disabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	else
+	{
+		if (bOldState)
+		{
+			NPCSetFlags(iBossIndex, iBossFlags & ~SFF_NOTELEPORT);
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Boss Should Teleport", client);
+			LogAction(client, -1, "%N enabled teleportation of boss %d! (%s)", client, iBossIndex, sProfile);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_ForceProxy(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_force_proxy <name|#userid> <bossindex 0-%d>", MAX_BOSSES - 1);
+		return Plugin_Handled;
+	}
+	
+	if (IsRoundEnding() || IsRoundInWarmup())
+	{
+		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			0,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iBossIndex = StringToInt(arg2);
+	if (iBossIndex < 0 || iBossIndex >= MAX_BOSSES)
+	{
+		ReplyToCommand(client, "Boss index is out of range!");
+		return Plugin_Handled;
+	}
+	else if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		ReplyToCommand(client, "Boss index is invalid! Boss index not active!");
+		return Plugin_Handled;
+	}
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new iTarget = target_list[i];
+		
+		decl String:sName[MAX_NAME_LENGTH];
+		GetClientName(iTarget, sName, sizeof(sName));
+		
+		if (!g_bPlayerEliminated[iTarget])
+		{
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Unable To Perform Action On Player In Round", client, sName);
+			continue;
+		}
+		
+		if (g_bPlayerProxy[iTarget]) continue;
+		
+		decl Float:flNewPos[3];
+		
+		if (!SlenderCalculateNewPlace(iBossIndex, flNewPos, true, true, client)) 
+		{
+			CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Player No Place For Proxy", client, sName);
+			continue;
+		}
+		
+		ClientEnableProxy(iTarget, iBossIndex);
+		TeleportEntity(iTarget, flNewPos, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+		
+		LogAction(client, iTarget, "%N forced %N to be a Proxy!", client, iTarget);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_ForceEscape(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_force_escape <name|#userid>");
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			COMMAND_FILTER_ALIVE,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new target = target_list[i];
+		if (!g_bPlayerEliminated[i] && !DidClientEscape(i))
+		{
+			ClientEscape(target);
+			TeleportClientToEscapePoint(target);
+			
+			LogAction(client, target, "%N forced %N to escape!", client, target);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_AddSlender(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_add_boss <name>");
+		return Plugin_Handled;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetCmdArg(1, sProfile, sizeof(sProfile));
+	
+	KvRewind(g_hConfig);
+	if (!KvJumpToKey(g_hConfig, sProfile)) 
+	{
+		ReplyToCommand(client, "That boss does not exist!");
+		return Plugin_Handled;
+	}
+	
+	new iBossIndex = AddProfile(sProfile);
+	if (iBossIndex != -1)
+	{
+		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
+		GetClientEyePosition(client, eyePos);
+		GetClientEyeAngles(client, eyeAng);
+		
+		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
+		TR_GetEndPosition(flPos, hTrace);
+		CloseHandle(hTrace);
+	
+		SpawnSlender(iBossIndex, flPos);
+		
+		LogAction(client, -1, "%N added a boss! (%s)", client, sProfile);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_AddSlenderFake(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 1)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_add_boss_fake <name>");
+		return Plugin_Handled;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetCmdArg(1, sProfile, sizeof(sProfile));
+	
+	KvRewind(g_hConfig);
+	if (!KvJumpToKey(g_hConfig, sProfile)) 
+	{
+		ReplyToCommand(client, "That boss does not exist!");
+		return Plugin_Handled;
+	}
+	
+	new iBossIndex = AddProfile(sProfile, SFF_FAKE);
+	if (iBossIndex != -1)
+	{
+		decl Float:eyePos[3], Float:eyeAng[3], Float:flPos[3];
+		GetClientEyePosition(client, eyePos);
+		GetClientEyeAngles(client, eyeAng);
+		
+		new Handle:hTrace = TR_TraceRayFilterEx(eyePos, eyeAng, MASK_NPCSOLID, RayType_Infinite, TraceRayDontHitEntity, client);
+		TR_GetEndPosition(flPos, hTrace);
+		CloseHandle(hTrace);
+	
+		SpawnSlender(iBossIndex, flPos);
+		
+		LogAction(client, -1, "%N added a fake boss! (%s)", client, sProfile);
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Command_ForceState(client, args)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (args < 2)
+	{
+		ReplyToCommand(client, "Usage: sm_sf2_setplaystate <name|#userid> <0/1>");
+		return Plugin_Handled;
+	}
+	
+	if (IsRoundEnding() || IsRoundInWarmup())
+	{
+		CPrintToChat(client, "%t%T", "SF2 Prefix", "SF2 Cannot Use Command", client);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg1[32];
+	GetCmdArg(1, arg1, sizeof(arg1));
+	
+	decl String:target_name[MAX_TARGET_LENGTH];
+	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
+	
+	if ((target_count = ProcessTargetString(
+			arg1,
+			client,
+			target_list,
+			MAXPLAYERS,
+			0,
+			target_name,
+			sizeof(target_name),
+			tn_is_ml)) <= 0)
+	{
+		ReplyToTargetError(client, target_count);
+		return Plugin_Handled;
+	}
+	
+	decl String:arg2[32];
+	GetCmdArg(2, arg2, sizeof(arg2));
+	
+	new iState = StringToInt(arg2);
+	
+	decl String:sName[MAX_NAME_LENGTH];
+	
+	for (new i = 0; i < target_count; i++)
+	{
+		new target = target_list[i];
+		GetClientName(target, sName, sizeof(sName));
+		
+		if (iState && g_bPlayerEliminated[target])
+		{
+			SetClientPlayState(target, true);
+			
+			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced In Game", sName);
+			LogAction(client, target, "%N forced %N into the game.", client, target);
+		}
+		else if (!iState && !g_bPlayerEliminated[target])
+		{
+			SetClientPlayState(target, false);
+			
+			CPrintToChatAll("%t %N: %t", "SF2 Prefix", client, "SF2 Player Forced Out Of Game", sName);
+			LogAction(client, target, "%N took %N out of the game.", client, target);
+		}
+	}
+	
+	return Plugin_Handled;
+}
+
+public Action:Hook_CommandBuild(client, const String:command[], argc)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (!IsClientInPvP(client)) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_BossCountUpdate(Handle:timer)
+{
+	if (timer != g_hBossCountUpdateTimer) return Plugin_Stop;
+	
+	if (!g_bEnabled) return Plugin_Stop;
+
+	new iBossCount = NPCGetCount();
+	new iBossPreferredCount;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1 ||
+			g_iSlenderCopyMaster[i] != -1 ||
+			(NPCGetFlags(i) & SFF_FAKE))
+		{
+			continue;
+		}
+		
+		iBossPreferredCount++;
+	}
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsValidClient(i) ||
+			!IsPlayerAlive(i) ||
+			g_bPlayerEliminated[i] ||
+			IsClientInGhostMode(i) ||
+			IsClientInDeathCam(i) ||
+			DidClientEscape(i)) continue;
+		
+		// Check if we're near any bosses.
+		new iClosest = -1;
+		new Float:flBestDist = SF2_BOSS_PAGE_CALCULATION;
+		
+		for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
+		{
+			if (NPCGetUniqueID(iBoss) == -1) continue;
+			if (NPCGetEntIndex(iBoss) == INVALID_ENT_REFERENCE) continue;
+			if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
+			
+			new Float:flDist = NPCGetDistanceFromEntity(iBoss, i);
+			if (flDist < flBestDist)
+			{
+				iClosest = iBoss;
+				flBestDist = flDist;
+				break;
+			}
+		}
+		
+		if (iClosest != -1) continue;
+		
+		iClosest = -1;
+		flBestDist = SF2_BOSS_PAGE_CALCULATION;
+		
+		for (new iClient = 1; iClient <= MaxClients; iClient++)
+		{
+			if (!IsValidClient(iClient) ||
+				!IsPlayerAlive(iClient) ||
+				g_bPlayerEliminated[iClient] ||
+				IsClientInGhostMode(iClient) ||
+				IsClientInDeathCam(iClient) ||
+				DidClientEscape(iClient)) 
+			{
+				continue;
+			}
+			
+			new bool:bwub = false;
+			for (new iBoss = 0; iBoss < MAX_BOSSES; iBoss++)
+			{
+				if (NPCGetUniqueID(iBoss) == -1) continue;
+				if (NPCGetFlags(iBoss) & SFF_FAKE) continue;
+				
+				if (g_iSlenderTarget[iBoss] == iClient)
+				{
+					bwub = true;
+					break;
+				}
+			}
+			
+			if (!bwub) continue;
+			
+			new Float:flDist = EntityDistanceFromEntity(i, iClient);
+			if (flDist < flBestDist)
+			{
+				iClosest = iClient;
+				flBestDist = flDist;
+			}
+		}
+		
+		if (!IsValidClient(iClosest))
+		{
+			// No one's close to this dude? DUDE! WE NEED ANOTHER BOSS!
+			iBossPreferredCount++;
+		}
+	}
+	
+	new iDiff = iBossCount - iBossPreferredCount;
+	if (iDiff)
+	{	
+		if (iDiff > 0)
+		{
+			new iCount = iDiff;
+			// We need less bosses. Try and see if we can remove some.
+			for (new i = 0; i < MAX_BOSSES; i++)
+			{
+				if (g_iSlenderCopyMaster[i] == -1) continue;
+				if (PeopleCanSeeSlender(i, _, false)) continue;
+				if (NPCGetFlags(i) & SFF_FAKE) continue;
+				
+				if (SlenderCanRemove(i))
+				{
+					NPCRemove(i);
+					iCount--;
+				}
+				
+				if (iCount <= 0)
+				{
+					break;
+				}
+			}
+		}
+		else
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		
+			new iCount = RoundToFloor(FloatAbs(float(iDiff)));
+			// Add new bosses (copy of the first boss).
+			for (new i = 0; i < MAX_BOSSES && iCount > 0; i++)
+			{
+				if (NPCGetUniqueID(i) == -1) continue;
+				if (g_iSlenderCopyMaster[i] != -1) continue;
+				if (!(NPCGetFlags(i) & SFF_COPIES)) continue;
+				
+				// Get the number of copies I already have and see if I can have more copies.
+				new iCopyCount;
+				for (new i2 = 0; i2 < MAX_BOSSES; i2++)
+				{
+					if (NPCGetUniqueID(i2) == -1) continue;
+					if (g_iSlenderCopyMaster[i2] != i) continue;
+					
+					iCopyCount++;
+				}
+				
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+				
+				if (iCopyCount >= GetProfileNum(sProfile, "copy_max", 10)) 
+				{
+					continue;
+				}
+				
+				new iBossIndex = AddProfile(sProfile, _, i);
+				if (iBossIndex == -1)
+				{
+					LogError("Could not add copy for %d: No free slots!", i);
+				}
+				
+				iCount--;
+			}
+		}
+	}
+	
+	// Check if we can add some proxies.
+	if (!g_bRoundGrace)
+	{
+		if (NavMesh_Exists())
+		{
+			new Handle:hProxyCandidates = CreateArray();
+			
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			
+			for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+			{
+				if (NPCGetUniqueID(iBossIndex) == -1) continue;
+				
+				if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) continue;
+				
+				if (g_iSlenderCopyMaster[iBossIndex] != -1) continue; // Copies cannot generate proxies.
+				
+				if (GetGameTime() < g_flSlenderTimeUntilNextProxy[iBossIndex]) continue; // Proxy spawning hasn't cooled down yet.
+				
+				new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
+				if (!iTeleportTarget || iTeleportTarget == INVALID_ENT_REFERENCE) continue; // No teleport target.
+				
+				NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+				
+				new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
+				new iNumActiveProxies = 0;
+				
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+					if (!g_bPlayerProxy[iClient]) continue;
+					
+					if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) == iBossIndex)
+					{
+						iNumActiveProxies++;
+					}
+				}
+				
+				if (iNumActiveProxies >= iMaxProxies) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d has too many active proxies!", iBossIndex);
+#endif
+					continue;
+				}
+				
+				new Float:flSpawnChanceMin = GetProfileFloat(sProfile, "proxies_spawn_chance_min");
+				new Float:flSpawnChanceMax = GetProfileFloat(sProfile, "proxies_spawn_chance_max");
+				new Float:flSpawnChanceThreshold = GetProfileFloat(sProfile, "proxies_spawn_chance_threshold") * NPCGetAnger(iBossIndex);
+				
+				new Float:flChance = GetRandomFloat(flSpawnChanceMin, flSpawnChanceMax);
+				if (flChance > flSpawnChanceThreshold) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's chances weren't in his favor!", iBossIndex);
+#endif
+					continue;
+				}
+				
+				new iAvailableProxies = iMaxProxies - iNumActiveProxies;
+				
+				new iSpawnNumMin = GetProfileNum(sProfile, "proxies_spawn_num_min");
+				new iSpawnNumMax = GetProfileNum(sProfile, "proxies_spawn_num_max");
+				
+				new iSpawnNum = 0;
+				
+				// Get a list of people we can transform into a good Proxy.
+				ClearArray(hProxyCandidates);
+				
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+					if (g_bPlayerProxy[iClient]) continue;
+					
+					if (!g_iPlayerPreferences[iClient][PlayerPreference_EnableProxySelection])
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your preferences.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					if (!g_bPlayerProxyAvailable[iClient])
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because of your cooldown.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					if (g_bPlayerProxyAvailableInForce[iClient])
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're already being forced into a Proxy.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					if (!IsClientParticipating(iClient))
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayer(iClient, DEBUG_BOSS_PROXIES, 0, "[PROXIES] You were rejected for being a proxy for boss %d because you're not participating.", iBossIndex);
+#endif
+						continue;
+					}
+					
+					PushArrayCell(hProxyCandidates, iClient);
+					iSpawnNum++;
+				}
+				
+				if (iSpawnNum >= iSpawnNumMax)
+				{
+					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNumMax);
+				}
+				else if (iSpawnNum >= iSpawnNumMin)
+				{
+					iSpawnNum = GetRandomInt(iSpawnNumMin, iSpawnNum);
+				}
+				
+				if (iSpawnNum <= 0) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d had a set spawn number of 0!", iBossIndex);
+#endif
+					continue;
+				}
+				
+				decl Float:flTargetPos[3];
+				GetClientAbsOrigin(iTeleportTarget, flTargetPos);
+				
+				new iTargetAreaIndex = NavMesh_GetNearestArea(flTargetPos);
+				if (iTargetAreaIndex == -1) 
+				{
+#if defined DEBUG
+					SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d's teleport target is not on the navmesh!", iBossIndex);
+#endif
+					continue; // target is not on the nav mesh.
+				}
+				
+				// Search outwards until travel distance is at maximum range.
+				new Handle:hAreaArray = CreateArray(2);
+				new Handle:hAreas = CreateStack();
+				NavMesh_CollectSurroundingAreas(hAreas, iTargetAreaIndex, g_flSlenderProxyTeleportMaxRange[iBossIndex]);
+				
+				new Float:flTeleportMinRange = CalculateTeleportMinRange(iBossIndex, g_flSlenderProxyTeleportMinRange[iBossIndex], g_flSlenderProxyTeleportMaxRange[iBossIndex]);
+				
+				{
+					new iAreaIndex = -1;
+					new iPoppedAreas = 0;
+					
+					while (!IsStackEmpty(hAreas))
+					{
+						PopStackCell(hAreas, iAreaIndex);
+						new iCostSoFar = NavMeshArea_GetCostSoFar(iAreaIndex);
+						
+						if (float(iCostSoFar) >= flTeleportMinRange)
+						{
+							new iIndex = PushArrayCell(hAreaArray, iAreaIndex);
+							SetArrayCell(hAreaArray, iIndex, float(iCostSoFar), 1);
+							iPoppedAreas++;
+						}
+					}
+					
+					CloseHandle(hAreas);
+					
+					if (iPoppedAreas == 0)
+					{
+						// no areas to use!
+						CloseHandle(hAreaArray);
+
+#if defined DEBUG
+						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any sufficient surrounding areas!", iBossIndex);
+#endif
+						
+						continue;
+					}
+#if defined DEBUG
+					else
+					{
+						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d found %d surrounding areas", iBossIndex, iPoppedAreas);
+					}
+#endif
+				}
+				
+				new Handle:hAreaArrayClose = CreateArray();
+				new Handle:hAreaArrayAverage = CreateArray();
+				new Handle:hAreaArrayFar = CreateArray();
+				
+				for (new iRangeSection = 1; iRangeSection <= 3; iRangeSection++)
+				{
+					new Float:flRangeSectionMin = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection - 1) / 3.0);
+					new Float:flRangeSectionMax = flTeleportMinRange + (g_flSlenderProxyTeleportMaxRange[iBossIndex] - flTeleportMinRange) * (float(iRangeSection) / 3.0);
+					
+					for (new i = 0, iSize = GetArraySize(hAreaArray); i < iSize; i++)
+					{
+						new iAreaIndex = GetArrayCell(hAreaArray, i);
+						
+						decl Float:flAreaCenter[3];
+						NavMeshArea_GetCenter(iAreaIndex, flAreaCenter);
+						
+						decl Float:flTestPos[3];
+						decl Float:flEyeOffset[3];
+						flEyeOffset[0] = 0.0;
+						flEyeOffset[1] = 0.0;
+						flEyeOffset[2] = HalfHumanHeight * 2.0;
+						
+						// Check visibility first.
+						if (IsPointVisibleToAPlayer(flAreaCenter, false, false)) 
+						{
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (1)", iBossIndex, iAreaIndex);
+#endif
+							continue;
+						}
+						
+						AddVectors(flAreaCenter, flEyeOffset, flTestPos);
+						
+						if (IsPointVisibleToAPlayer(flTestPos, false, false)) 
+						{
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected visible area index %d! (2)", iBossIndex, iAreaIndex);
+#endif
+						
+							continue;
+						}
+						
+						new iBoss = NPCGetEntIndex(iBossIndex);
+						
+						// Check space. First raise to HalfHumanHeight * 2, then trace downwards to get ground level.
+						{
+							decl Float:flTraceStartPos[3];
+							flTraceStartPos[0] = flAreaCenter[0];
+							flTraceStartPos[1] = flAreaCenter[1];
+							flTraceStartPos[2] = flAreaCenter[2] + (HalfHumanHeight * 2.0);
+							
+							decl Float:flTraceMins[3];
+							flTraceMins[0] = -20.0;
+							flTraceMins[1] = -20.0;
+							flTraceMins[2] = 0.0;
+							
+							decl Float:flTraceMaxs[3];
+							flTraceMaxs[0] = 20.0;
+							flTraceMaxs[1] = 20.0;
+							flTraceMaxs[2] = 0.0;
+							
+							new Handle:hTrace = TR_TraceHullFilterEx(flTraceStartPos,
+								flAreaCenter,
+								flTraceMins,
+								flTraceMaxs,
+								MASK_NPCSOLID,
+								TraceRayDontHitEntity,
+								iBoss);
+							
+							decl Float:flTraceHitPos[3];
+							TR_GetEndPosition(flTraceHitPos, hTrace);
+							flTraceHitPos[2] += 1.0;
+							CloseHandle(hTrace);
+							
+							static Float:flTraceSpaceMin[3] = { -20.0, -20.0, 0.0 };
+							static Float:flTraceSpaceMax[3] = { 20.0, 20.0, 72.0 };
+							
+							flTraceSpaceMax[2] = HalfHumanHeight * 2.0;
+							
+							if (IsSpaceOccupiedPlayer(flTraceHitPos,
+								flTraceSpaceMin,
+								flTraceSpaceMax,
+								iBoss == INVALID_ENT_REFERENCE ? -1 : iBoss))
+							{
+#if defined DEBUG
+								SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected too small area index %d! (2)", iBossIndex, iAreaIndex);
+#endif
+							
+								continue;
+							}
+						}
+						
+						new bool:bTooNear = false;
+						
+						// Check minimum range.
+						for (new iClient = 1; iClient <= MaxClients; iClient++)
+						{
+							if (!IsClientInGame(iClient) ||
+								!IsPlayerAlive(iClient) ||
+								g_bPlayerEliminated[iClient] ||
+								DidClientEscape(iClient) ||
+								g_bPlayerProxy[iClient] ||
+								IsClientInGhostMode(iClient))
+							{
+								continue;
+							}
+							
+							decl Float:flTempPos[3];
+							GetClientAbsOrigin(iClient, flTempPos);
+							
+							if (GetVectorDistance(flAreaCenter, flTempPos) <= flTeleportMinRange)
+							{
+								bTooNear = true;
+								break;
+							}
+						}
+						
+						if (bTooNear) 
+						{
+#if defined DEBUG
+							SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d rejected near area index %d!", iBossIndex, iAreaIndex);
+#endif
+						
+							continue;	// This area is too close to a player.
+						}
+						
+						// Check travel distance.
+						new Float:flDist = Float:GetArrayCell(hAreaArray, i, 1);
+						if (flDist > flRangeSectionMin && flDist < flRangeSectionMax)
+						{
+							switch (iRangeSection)
+							{
+								case 1: PushArrayCell(hAreaArrayClose, iAreaIndex);
+								case 2: PushArrayCell(hAreaArrayAverage, iAreaIndex);
+								case 3: PushArrayCell(hAreaArrayFar, iAreaIndex);
+							}
+						}
+					}
+				}
+				
+				CloseHandle(hAreaArray);
+				
+				// Set the cooldown time!
+				new Float:flSpawnCooldownMin = GetProfileFloat(sProfile, "proxies_spawn_cooldown_min");
+				new Float:flSpawnCooldownMax = GetProfileFloat(sProfile, "proxies_spawn_cooldown_max");
+				
+				g_flSlenderTimeUntilNextProxy[iBossIndex] = GetGameTime() + GetRandomFloat(flSpawnCooldownMin, flSpawnCooldownMax);
+				
+				// Randomize the array.
+				SortADTArray(hProxyCandidates, Sort_Random, Sort_Integer);
+				
+				decl Float:flDestinationPos[3];
+				
+				for (new iNum = 0; iNum < iSpawnNum && iNum < iAvailableProxies; iNum++)
+				{
+					new iClient = GetArrayCell(hProxyCandidates, iNum);
+					new iBestAreaIndex = -1;
+					
+					if (GetArraySize(hAreaArrayClose) > 0)
+					{
+						iBestAreaIndex = GetArrayCell(hAreaArrayClose, GetRandomInt(0, GetArraySize(hAreaArrayClose) - 1));
+					}
+					else if (GetArraySize(hAreaArrayAverage) > 0)
+					{
+						iBestAreaIndex = GetArrayCell(hAreaArrayAverage, GetRandomInt(0, GetArraySize(hAreaArrayAverage) - 1));
+					}
+					else if (GetArraySize(hAreaArrayFar) > 0)
+					{
+						iBestAreaIndex = GetArrayCell(hAreaArrayFar, GetRandomInt(0, GetArraySize(hAreaArrayFar) - 1));
+					}
+					
+					if (iBestAreaIndex == -1) 
+					{
+#if defined DEBUG
+						SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d could not find any areas to place proxies (spawned %d)!", iBossIndex, iNum);
+#endif
+						break;
+					}
+					
+					NavMeshArea_GetCenter(iBestAreaIndex, flDestinationPos);
+					
+					if (!GetConVarBool(g_cvPlayerProxyAsk))
+					{
+						ClientStartProxyForce(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
+					}
+					else
+					{
+						DisplayProxyAskMenu(iClient, NPCGetUniqueID(iBossIndex), flDestinationPos);
+					}
+				}
+				
+				CloseHandle(hAreaArrayClose);
+				CloseHandle(hAreaArrayAverage);
+				CloseHandle(hAreaArrayFar);
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_PROXIES, 0, "[PROXIES] Boss %d finished proxy process!", iBossIndex);
+#endif
+			}
+			
+			CloseHandle(hProxyCandidates);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+ReloadRestrictedWeapons()
+{
+	if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
+	{
+		CloseHandle(g_hRestrictedWeaponsConfig);
+		g_hRestrictedWeaponsConfig = INVALID_HANDLE;
+	}
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	BuildPath(Path_SM, buffer, sizeof(buffer), FILE_RESTRICTEDWEAPONS);
+	new Handle:kv = CreateKeyValues("root");
+	if (!FileToKeyValues(kv, buffer))
+	{
+		CloseHandle(kv);
+		LogError("Failed to load restricted weapons list! File not found!");
+	}
+	else
+	{
+		g_hRestrictedWeaponsConfig = kv;
+		LogSF2Message("Reloaded restricted weapons configuration file successfully");
+	}
+}
+
+public Action:Timer_RoundMessages(Handle:timer)
+{
+	if (!g_bEnabled) return Plugin_Stop;
+	
+	if (timer != g_hRoundMessagesTimer) return Plugin_Stop;
+	
+	switch (g_iRoundMessagesNum)
+	{
+		case 0: CPrintToChatAll("{olive}==== {lightgreen}Slender Fortress (%s){olive} coded by {lightgreen}Kit o' Rifty{olive} ====", PLUGIN_VERSION_DISPLAY);
+		case 1: CPrintToChatAll("%t", "SF2 Ad Message 1");
+		case 2: CPrintToChatAll("%t", "SF2 Ad Message 2");
+	}
+	
+	g_iRoundMessagesNum++;
+	if (g_iRoundMessagesNum > 2) g_iRoundMessagesNum = 0;
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_WelcomeMessage(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	CPrintToChat(client, "%T", "SF2 Welcome Message", client);
+}
+
+GetMaxPlayersForRound()
+{
+	new iOverride = GetConVarInt(g_cvMaxPlayersOverride);
+	if (iOverride != -1) return iOverride;
+	return GetConVarInt(g_cvMaxPlayers);
+}
+
+public OnConVarChanged(Handle:cvar, const String:oldValue[], const String:newValue[])
+{
+	if (cvar == g_cvDifficulty)
+	{
+		switch (StringToInt(newValue))
+		{
+			case Difficulty_Easy: g_flRoundDifficultyModifier = DIFFICULTY_EASY;
+			case Difficulty_Hard: g_flRoundDifficultyModifier = DIFFICULTY_HARD;
+			case Difficulty_Insane: g_flRoundDifficultyModifier = DIFFICULTY_INSANE;
+			default: g_flRoundDifficultyModifier = DIFFICULTY_NORMAL;
+		}
+	}
+	else if (cvar == g_cvMaxPlayers || cvar == g_cvMaxPlayersOverride)
+	{
+		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+		{
+			CheckPlayerGroup(i);
+		}
+	}
+	else if (cvar == g_cvPlayerShakeEnabled)
+	{
+		g_bPlayerShakeEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvPlayerViewbobEnabled)
+	{
+		g_bPlayerViewbobEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvPlayerViewbobHurtEnabled)
+	{
+		g_bPlayerViewbobHurtEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvPlayerViewbobSprintEnabled)
+	{
+		g_bPlayerViewbobSprintEnabled = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvGravity)
+	{
+		g_flGravity = StringToFloat(newValue);
+	}
+	else if (cvar == g_cv20Dollars)
+	{
+		g_b20Dollars = bool:StringToInt(newValue);
+	}
+	else if (cvar == g_cvAllChat)
+	{
+		if (g_bEnabled)
+		{
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				ClientUpdateListeningFlags(i);
+			}
+		}
+	}
+}
+
+//	==========================================================
+//	IN-GAME AND ENTITY HOOK FUNCTIONS
+//	==========================================================
+
+
+public OnEntityCreated(ent, const String:classname[])
+{
+	if (!g_bEnabled) return;
+	
+	if (!IsValidEntity(ent) || ent <= 0) return;
+	
+	if (StrEqual(classname, "spotlight_end", false))
+	{
+		SDKHook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
+	}
+	else if (StrEqual(classname, "beam", false))
+	{
+		SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightBeamSetTransmit);
+	}
+	
+	PvP_OnEntityCreated(ent, classname);
+}
+
+public OnEntityDestroyed(ent)
+{
+	if (!g_bEnabled) return;
+
+	if (!IsValidEntity(ent) || ent <= 0) return;
+	
+	decl String:sClassname[64];
+	GetEntityClassname(ent, sClassname, sizeof(sClassname));
+	
+	if (StrEqual(sClassname, "light_dynamic", false))
+	{
+		AcceptEntityInput(ent, "TurnOff");
+		
+		new iEnd = INVALID_ENT_REFERENCE;
+		while ((iEnd = FindEntityByClassname(iEnd, "spotlight_end")) != -1)
+		{
+			if (GetEntPropEnt(iEnd, Prop_Data, "m_hOwnerEntity") == ent)
+			{
+				AcceptEntityInput(iEnd, "Kill");
+				break;
+			}
+		}
+	}
+	
+	PvP_OnEntityDestroyed(ent, sClassname);
+}
+
+public Action:Hook_BlockUserMessage(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init) 
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	return Plugin_Handled;
+}
+
+public Action:Hook_NormalSound(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsValidClient(entity))
+	{
+		if (IsClientInGhostMode(entity))
+		{
+			switch (channel)
+			{
+				case SNDCHAN_VOICE, SNDCHAN_WEAPON, SNDCHAN_ITEM, SNDCHAN_BODY: return Plugin_Handled;
+			}
+		}
+		else if (g_bPlayerProxy[entity])
+		{
+			new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[entity]);
+			if (iMaster != -1)
+			{
+				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+				NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
+				
+				switch (channel)
+				{
+					case SNDCHAN_VOICE:
+					{
+						if (!bool:GetProfileNum(sProfile, "proxies_allownormalvoices", 1))
+						{
+							return Plugin_Handled;
+						}
+					}
+				}
+			}
+		}
+		else if (!g_bPlayerEliminated[entity])
+		{
+			switch (channel)
+			{
+				case SNDCHAN_VOICE:
+				{
+					if (IsRoundInIntro()) return Plugin_Handled;
+				
+					for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+					{
+						if (NPCGetUniqueID(iBossIndex) == -1) continue;
+						
+						if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Voice))
+						{
+							GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
+							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
+							g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDVOICE;
+						}
+					}
+				}
+				case SNDCHAN_BODY:
+				{
+					if (!StrContains(sample, "player/footsteps", false) || StrContains(sample, "step", false) != -1)
+					{
+						if (GetConVarBool(g_cvPlayerViewbobSprintEnabled) && IsClientReallySprinting(entity))
+						{
+							// Viewpunch.
+							new Float:flPunchVelStep[3];
+							
+							decl Float:flVelocity[3];
+							GetEntPropVector(entity, Prop_Data, "m_vecAbsVelocity", flVelocity);
+							new Float:flSpeed = GetVectorLength(flVelocity);
+							
+							flPunchVelStep[0] = flSpeed / 300.0;
+							flPunchVelStep[1] = 0.0;
+							flPunchVelStep[2] = 0.0;
+							
+							ClientViewPunch(entity, flPunchVelStep);
+						}
+						
+						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+						{
+							if (NPCGetUniqueID(iBossIndex) == -1) continue;
+							
+							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Footstep))
+							{
+								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEP;
+								
+								if (IsClientSprinting(entity) && !(GetEntProp(entity, Prop_Send, "m_bDucking") || GetEntProp(entity, Prop_Send, "m_bDucked")))
+								{
+									g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDFOOTSTEPLOUD;
+								}
+							}
+						}
+					}
+				}
+				case SNDCHAN_ITEM, SNDCHAN_WEAPON:
+				{
+					if (StrContains(sample, "impact", false) != -1 || StrContains(sample, "hit", false) != -1)
+					{
+						for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+						{
+							if (NPCGetUniqueID(iBossIndex) == -1) continue;
+							
+							if (SlenderCanHearPlayer(iBossIndex, entity, SoundType_Weapon))
+							{
+								GetClientAbsOrigin(entity, g_flSlenderTargetSoundTempPos[iBossIndex]);
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDSUSPICIOUSSOUND;
+								g_iSlenderInterruptConditions[iBossIndex] |= COND_HEARDWEAPON;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	new bool:bModified = false;
+	
+	for (new i = 0; i < numClients; i++)
+	{
+		new iClient = clients[i];
+		if (IsValidClient(iClient) && IsPlayerAlive(iClient) && !IsClientInGhostMode(iClient))
+		{
+			new bool:bCanHearSound = true;
+			
+			if (IsValidClient(entity) && entity != iClient)
+			{
+				if (!g_bPlayerEliminated[iClient])
+				{
+					if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+					{
+						if (!g_bPlayerEliminated[entity] && !DidClientEscape(entity))
+						{
+							bCanHearSound = false;
+						}
+					}
+				}
+			}
+			
+			if (!bCanHearSound)
+			{
+				bModified = true;
+				clients[i] = -1;
+			}
+		}
+	}
+	
+	if (bModified) return Plugin_Changed;
+	return Plugin_Continue;
+}
+
+public MRESReturn:Hook_EntityShouldTransmit(thisPointer, Handle:hReturn, Handle:hParams)
+{
+	if (!g_bEnabled) return MRES_Ignored;
+	
+	if (IsValidClient(thisPointer))
+	{
+		if (DoesClientHaveConstantGlow(thisPointer))
+		{
+			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
+			return MRES_Supercede;
+		}
+	}
+	else
+	{
+		new iBossIndex = NPCGetFromEntIndex(thisPointer);
+		if (iBossIndex != -1)
+		{
+			DHookSetReturn(hReturn, FL_EDICT_ALWAYS); // Should always transmit, but our SetTransmit hook gets the final say.
+			return MRES_Supercede;
+		}
+	}
+	
+	return MRES_Ignored;
+}
+
+public Hook_TriggerOnStartTouch(const String:output[], caller, activator, Float:delay)
+{
+	if (!g_bEnabled) return;
+
+	if (!IsValidEntity(caller)) return;
+	
+	decl String:sName[64];
+	GetEntPropString(caller, Prop_Data, "m_iName", sName, sizeof(sName));
+	
+	if (StrContains(sName, "sf2_escape_trigger", false) == 0)
+	{
+		if (IsRoundInEscapeObjective())
+		{
+			if (IsValidClient(activator) && IsPlayerAlive(activator) && !IsClientInDeathCam(activator) && !g_bPlayerEliminated[activator] && !DidClientEscape(activator))
+			{
+				ClientEscape(activator);
+				TeleportClientToEscapePoint(activator);
+			}
+		}
+	}
+	
+	PvP_OnTriggerStartTouch(caller, activator);
+}
+
+public Hook_TriggerOnEndTouch(const String:sOutput[], caller, activator, Float:flDelay)
+{
+	if (!g_bEnabled) return;
+	
+	PvP_OnTriggerEndTouch(caller, activator);
+}
+
+public Action:Hook_PageOnTakeDamage(page, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsValidClient(attacker))
+	{
+		if (!g_bPlayerEliminated[attacker])
+		{
+			if (damagetype & 0x80) // 0x80 == melee damage
+			{
+				CollectPage(page, attacker);
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+static CollectPage(page, activator)
+{
+	SetPageCount(g_iPageCount + 1);
+	g_iPlayerPageCount[activator] += 1;
+	EmitSoundToAll(PAGE_GRABSOUND, activator, SNDCHAN_ITEM, SNDLEVEL_SCREAMING);
+				
+	// Gives points. Credit to the makers of VSH/FF2.
+	new Handle:hEvent = CreateEvent("player_escort_score", true);
+	SetEventInt(hEvent, "player", activator);
+	SetEventInt(hEvent, "points", 1);
+	FireEvent(hEvent);
+				
+	AcceptEntityInput(page, "FireUser1");
+	AcceptEntityInput(page, "Kill");
+}
+	
+//	==========================================================
+//	GENERIC CLIENT HOOKS AND FUNCTIONS
+//	==========================================================
+
+
+public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	ClientDisableFakeLagCompensation(client);
+	
+	// Check impulse (block spraying and built-in flashlight)
+	switch (impulse)
+	{
+		case 100:
+		{
+			impulse = 0;
+		}
+		case 201:
+		{
+			if (IsClientInGhostMode(client))
+			{
+				impulse = 0;
+			}
+		}
+	}
+	
+	for (new i = 0; i < MAX_BUTTONS; i++)
+	{
+		new button = (1 << i);
+		
+		if ((buttons & button))
+		{
+			if (!(g_iPlayerLastButtons[client] & button))
+			{
+				ClientOnButtonPress(client, button);
+			}
+		}
+		else if ((g_iPlayerLastButtons[client] & button))
+		{
+			ClientOnButtonRelease(client, button);
+		}
+	}
+	
+	g_iPlayerLastButtons[client] = buttons;
+	
+	return Plugin_Continue;
+}
+
+
+public OnClientCookiesCached(client)
+{
+	if (!g_bEnabled) return;
+	
+	// Load our saved settings.
+	new String:sCookie[64];
+	GetClientCookie(client, g_hCookie, sCookie, sizeof(sCookie));
+	
+		g_iPlayerQueuePoints[client] = 0;
+		
+		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
+		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
+	g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = true;
+		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
+	g_iPlayerPreferences[client][PlayerPreference_GhostOverlay] = true;
+	
+	if (sCookie[0])
+	{
+		new String:s2[12][32];
+		new count = ExplodeString(sCookie, " ; ", s2, 12, 32);
+		
+		if (count > 0)
+		g_iPlayerQueuePoints[client] = StringToInt(s2[0]);
+		if (count > 1)
+		g_iPlayerPreferences[client][PlayerPreference_ShowHints] = bool:StringToInt(s2[1]);
+		if (count > 2)
+		g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode:StringToInt(s2[2]);
+		if (count > 3)
+			g_iPlayerPreferences[client][PlayerPreference_FilmGrain] = bool:StringToInt(s2[3]);
+		if (count > 4)
+		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = bool:StringToInt(s2[4]);
+		if (count > 5)
+			g_iPlayerPreferences[client][PlayerPreference_GhostOverlay] = bool:StringToInt(s2[5]);
+	}
+}
+
+public OnClientPutInServer(client)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientPutInServer(%d)", client);
+#endif
+	
+	ClientSetPlayerGroup(client, -1);
+	
+	g_bPlayerEscaped[client] = false;
+	g_bPlayerEliminated[client] = true;
+	g_bPlayerChoseTeam[client] = false;
+	g_bPlayerPlayedSpecialRound[client] = true;
+	g_bPlayerPlayedNewBossRound[client] = true;
+	
+	g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn] = false;
+	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
+	
+	g_iPlayerPageCount[client] = 0;
+	g_iPlayerDesiredFOV[client] = 90;
+	
+	SDKHook(client, SDKHook_PreThink, Hook_ClientPreThink);
+	SDKHook(client, SDKHook_SetTransmit, Hook_ClientSetTransmit);
+	SDKHook(client, SDKHook_OnTakeDamage, Hook_ClientOnTakeDamage);
+	
+	DHookEntity(g_hSDKWantsLagCompensationOnEntity, true, client); 
+	DHookEntity(g_hSDKShouldTransmit, true, client);
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		
+		SetPlayerGroupInvitedPlayer(i, client, false);
+		SetPlayerGroupInvitedPlayerCount(i, client, 0);
+		SetPlayerGroupInvitedPlayerTime(i, client, 0.0);
+	}
+	
+	ClientDisableFakeLagCompensation(client);
+	
+	ClientResetStatic(client);
+	ClientResetSlenderStats(client);
+	ClientResetCampingStats(client);
+	ClientResetOverlay(client);
+	ClientResetJumpScare(client);
+	ClientUpdateListeningFlags(client);
+	ClientUpdateMusicSystem(client);
+	ClientChaseMusicReset(client);
+	ClientChaseMusicSeeReset(client);
+	ClientAlertMusicReset(client);
+	Client20DollarsMusicReset(client);
+	ClientMusicReset(client);
+	ClientResetProxy(client);
+	ClientResetHints(client);
+	ClientResetScare(client);
+	
+	ClientResetDeathCam(client);
+	ClientResetFlashlight(client);
+	ClientDeactivateUltravision(client);
+	ClientResetSprint(client);
+	ClientResetBreathing(client);
+	ClientResetBlink(client);
+	ClientResetInteractiveGlow(client);
+	ClientDisableConstantGlow(client);
+	
+	ClientSetScareBoostEndTime(client, -1.0);
+	
+	ClientStartProxyAvailableTimer(client);
+	
+	if (!IsFakeClient(client))
+	{
+		// See if the player is using the projected flashlight.
+		QueryClientConVar(client, "mat_supportflashlight", OnClientGetProjectedFlashlightSetting);
+		
+		// Get desired FOV.
+		QueryClientConVar(client, "fov_desired", OnClientGetDesiredFOV);
+	}
+	
+	PvP_OnClientPutInServer(client);
+	
+#if defined DEBUG
+	g_iPlayerDebugFlags[client] = 0;
+
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientPutInServer(%d)", client);
+#endif
+}
+
+public OnClientGetProjectedFlashlightSetting(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
+{
+	if (result != ConVarQuery_Okay) 
+	{
+		LogError("Warning: Player %N failed to query for ConVar mat_supportflashlight", client);
+		return;
+	}
+	
+	if (StringToInt(cvarValue))
+	{
+		decl String:sAuth[64];
+		GetClientAuthString(client, sAuth, sizeof(sAuth));
+		
+		g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = true;
+		LogSF2Message("Player %N (%s) has mat_supportflashlight enabled, projected flashlight will be used", client, sAuth);
+	}
+}
+
+public OnClientGetDesiredFOV(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
+{
+	if (!IsValidClient(client)) return;
+	
+	g_iPlayerDesiredFOV[client] = StringToInt(cvarValue);
+}
+
+public OnClientDisconnect(client)
+{
+	DestroySpriteOverlay(client);
+	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
+	
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START OnClientDisconnect(%d)", client);
+#endif
+	
+	g_bPlayerEscaped[client] = false;
+	
+	// Save and reset settings for the next client.
+	ClientSaveCookies(client);
+	ClientSetPlayerGroup(client, -1);
+	
+	// Reset variables.
+	g_iPlayerPreferences[client][PlayerPreference_ShowHints] = true;
+	g_iPlayerPreferences[client][PlayerPreference_MuteMode] = MuteMode_Normal;
+	g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection] = true;
+	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
+	
+	// Reset any client functions that may be still active.
+	ClientResetOverlay(client);
+	ClientResetFlashlight(client);
+	ClientDeactivateUltravision(client);
+	ClientSetGhostModeState(client, false);
+	ClientResetInteractiveGlow(client);
+	ClientDisableConstantGlow(client);
+	
+	ClientStopProxyForce(client);
+	
+	if (!IsRoundInWarmup())
+	{
+		if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
+		{
+			if (g_bRoundGrace)
+			{
+				// Force the next player in queue to take my place, if any.
+				ForceInNextPlayersInQueue(1, true);
+			}
+			else
+			{
+				if (!IsRoundEnding()) 
+				{
+					CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
+				}
+			}
+		}
+	}
+	
+	// Reset queue points global variable.
+	g_iPlayerQueuePoints[client] = 0;
+	
+	PvP_OnClientDisconnect(client);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END OnClientDisconnect(%d)", client);
+#endif
+}
+
+public OnClientDisconnect_Post(client)
+{
+    g_iPlayerLastButtons[client] = 0;
+}
+
+public TF2_OnWaitingForPlayersStart()
+{
+	g_bRoundWaitingForPlayers = true;
+}
+
+public TF2_OnWaitingForPlayersEnd()
+{
+	g_bRoundWaitingForPlayers = false;
+}
+
+SF2RoundState:GetRoundState()
+{
+	return g_iRoundState;
+}
+
+SetRoundState(SF2RoundState:iRoundState)
+{
+	if (g_iRoundState == iRoundState) return;
+	
+	PrintToServer("SetRoundState(%d)", iRoundState);
+	
+	new SF2RoundState:iOldRoundState = GetRoundState();
+	g_iRoundState = iRoundState;
+	
+	// Cleanup from old roundstate if needed.
+	switch (iOldRoundState)
+	{
+		case SF2RoundState_Waiting:
+		{
+		}
+		case SF2RoundState_Intro:
+		{
+			g_hRoundIntroTimer = INVALID_HANDLE;
+		}
+		case SF2RoundState_Active:
+		{
+			g_bRoundGrace = false;
+			g_hRoundGraceTimer = INVALID_HANDLE;
+			g_hRoundTimer = INVALID_HANDLE;
+		}
+		case SF2RoundState_Escape:
+		{
+			g_hRoundTimer = INVALID_HANDLE;
+		}
+		case SF2RoundState_Outro:
+		{
+		}
+	}
+	
+	switch (g_iRoundState)
+	{
+		case SF2RoundState_Waiting:
+		{
+		}
+		case SF2RoundState_Intro:
+		{
+			g_hRoundIntroTimer = INVALID_HANDLE;
+			g_iRoundIntroText = 0;
+			g_bRoundIntroTextDefault = false;
+			g_hRoundIntroTextTimer = CreateTimer(0.0, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
+			TriggerTimer(g_hRoundIntroTextTimer);
+			
+			// Gather data on the intro parameters set by the map.
+			new Float:flHoldTime = g_flRoundIntroFadeHoldTime;
+			g_hRoundIntroTimer = CreateTimer(flHoldTime, Timer_ActivateRoundFromIntro, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			// Trigger any intro logic entities, if any.
+			new ent = -1;
+			while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
+			{
+				decl String:sName[64];
+				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+				if (StrEqual(sName, "sf2_intro_relay", false))
+				{
+					AcceptEntityInput(ent, "Trigger");
+					break;
+				}
+			}
+		}
+		case SF2RoundState_Active:
+		{
+			// Start the grace period timer.
+			g_bRoundGrace = true;
+			g_hRoundGraceTimer = CreateTimer(GetConVarFloat(g_cvGraceTime), Timer_RoundGrace, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			CreateTimer(2.0, Timer_RoundStart, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			// Enable movement on players.
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
+				SetEntityFlags(i, GetEntityFlags(i) & ~FL_FROZEN);
+			}
+			
+			// Fade in.
+			new Float:flFadeTime = g_flRoundIntroFadeDuration;
+			new iFadeFlags = SF_FADE_IN | FFADE_PURGE;
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
+				UTIL_ScreenFade(i, FixedUnsigned16(flFadeTime, 1 << 12), 0, iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
+			}
+		}
+		case SF2RoundState_Escape:
+		{
+			// Initialize the escape timer, if needed.
+			if (g_iRoundEscapeTimeLimit > 0)
+			{
+				g_iRoundTime = g_iRoundEscapeTimeLimit;
+				g_hRoundTimer = CreateTimer(1.0, Timer_RoundTimeEscape, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			}
+			else
+			{
+				g_hRoundTimer = INVALID_HANDLE;
+			}
+		
+			decl String:sName[32];
+			new ent = -1;
+			while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+			{
+				GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+				if (StrEqual(sName, "sf2_logic_escape", false))
+				{
+					AcceptEntityInput(ent, "FireUser1");
+					break;
+				}
+			}
+		}
+		case SF2RoundState_Outro:
+		{
+			if (!g_bRoundHasEscapeObjective)
+			{
+				// Teleport winning players to the escape point.
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i)) continue;
+					
+					if (!g_bPlayerEliminated[i])
+					{
+						TeleportClientToEscapePoint(i);
+					}
+				}
+			}
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i)) continue;
+				
+				if (IsClientInGhostMode(i))
+				{
+					// Take the player out of ghost mode.
+					ClientSetGhostModeState(i, false);	
+					TF2_RespawnPlayer(i);
+				}
+				else if (g_bPlayerProxy[i])
+				{
+					TF2_RespawnPlayer(i);
+				}
+				
+				if (!g_bPlayerEliminated[i])
+				{
+					// Give them back all their weapons so they can beat the crap out of the other team.
+					TF2_RegeneratePlayer(i);
+				}
+				
+				ClientUpdateListeningFlags(i);
+			}
+		}
+	}
+}
+
+bool:IsRoundInEscapeObjective()
+{
+	return bool:(GetRoundState() == SF2RoundState_Escape);
+}
+
+bool:IsRoundInWarmup()
+{
+	return bool:(GetRoundState() == SF2RoundState_Waiting);
+}
+
+bool:IsRoundInIntro()
+{
+	return bool:(GetRoundState() == SF2RoundState_Intro);
+}
+
+bool:IsRoundEnding()
+{
+	return bool:(GetRoundState() == SF2RoundState_Outro);
+}
+
+bool:IsInfiniteBlinkEnabled()
+{
+	return bool:(g_bRoundInfiniteBlink || (GetConVarInt(g_cvPlayerInfiniteBlinkOverride) == 1));
+}
+
+bool:IsInfiniteFlashlightEnabled()
+{
+	return bool:(g_bRoundInfiniteFlashlight || (GetConVarInt(g_cvPlayerInfiniteFlashlightOverride) == 1));
+}
+
+bool:IsInfiniteSprintEnabled()
+{
+	return bool:(g_bRoundInfiniteSprint || (GetConVarInt(g_cvPlayerInfiniteSprintOverride) == 1));
+}
+
+
+#define SF2_PLAYER_HUD_BLINK_SYMBOL "B"
+#define SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL "ÏŸ"
+#define SF2_PLAYER_HUD_BAR_SYMBOL "|"
+#define SF2_PLAYER_HUD_BAR_MISSING_SYMBOL ""
+#define SF2_PLAYER_HUD_INFINITY_SYMBOL "∞"
+#define SF2_PLAYER_HUD_SPRINT_SYMBOL "»"
+
+public Action:Timer_ClientAverageUpdate(Handle:timer)
+{
+	if (timer != g_hClientAverageUpdateTimer) return Plugin_Stop;
+	
+	if (!g_bEnabled) return Plugin_Stop;
+	
+	if (IsRoundInWarmup() || IsRoundEnding()) return Plugin_Continue;
+	
+	// First, process through HUD stuff.
+	decl String:buffer[256];
+	
+	static iHudColorHealthy[3] = { 150, 255, 150 };
+	static iHudColorCritical[3] = { 255, 10, 10 };
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (IsPlayerAlive(i) && !IsClientInDeathCam(i))
+		{
+			if (!g_bPlayerEliminated[i])
+			{
+				if (DidClientEscape(i)) continue;
+				
+				new iMaxBars = 12;
+				new iBars = RoundToCeil(float(iMaxBars) * ClientGetBlinkMeter(i));
+				if (iBars > iMaxBars) iBars = iMaxBars;
+				
+				Format(buffer, sizeof(buffer), "%s  ", SF2_PLAYER_HUD_BLINK_SYMBOL);
+				
+				if (IsInfiniteBlinkEnabled())
+				{
+					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
+				}
+				else
+				{
+					for (new i2 = 0; i2 < iMaxBars; i2++) 
+					{
+						if (i2 < iBars)
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+						}
+						else
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
+						}
+					}
+				}
+				
+				if (!g_bSpecialRound || g_iSpecialRoundType != SPECIALROUND_LIGHTSOUT)
+				{
+					iBars = RoundToCeil(float(iMaxBars) * ClientGetFlashlightBatteryLife(i));
+					if (iBars > iMaxBars) iBars = iMaxBars;
+					
+					decl String:sBuffer2[64];
+					Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_FLASHLIGHT_SYMBOL);
+					StrCat(buffer, sizeof(buffer), sBuffer2);
+					
+					if (IsInfiniteFlashlightEnabled())
+					{
+						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
+					}
+					else
+					{
+						for (new i2 = 0; i2 < iMaxBars; i2++) 
+						{
+							if (i2 < iBars)
+							{
+								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+							}
+							else
+							{
+								StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
+							}
+						}
+					}
+				}
+				
+				iBars = RoundToCeil(float(iMaxBars) * (float(ClientGetSprintPoints(i)) / 100.0));
+				if (iBars > iMaxBars) iBars = iMaxBars;
+				
+				decl String:sBuffer2[64];
+				Format(sBuffer2, sizeof(sBuffer2), "\n%s  ", SF2_PLAYER_HUD_SPRINT_SYMBOL);
+				StrCat(buffer, sizeof(buffer), sBuffer2);
+				
+				if (IsInfiniteSprintEnabled())
+				{
+					StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_INFINITY_SYMBOL);
+				}
+				else
+				{
+					for (new i2 = 0; i2 < iMaxBars; i2++) 
+					{
+						if (i2 < iBars)
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+						}
+						else
+						{
+							StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_MISSING_SYMBOL);
+						}
+					}
+				}
+				
+				
+				new Float:flHealthRatio = float(GetEntProp(i, Prop_Send, "m_iHealth")) / float(SDKCall(g_hSDKGetMaxHealth, i));
+				
+				new iColor[3];
+				for (new i2 = 0; i2 < 3; i2++)
+				{
+					iColor[i2] = RoundFloat(float(iHudColorHealthy[i2]) + (float(iHudColorCritical[i2] - iHudColorHealthy[i2]) * (1.0 - flHealthRatio)));
+				}
+				
+				SetHudTextParams(0.035, 0.83,
+					0.3,
+					iColor[0],
+					iColor[1],
+					iColor[2],
+					40,
+					_,
+					1.0,
+					0.07,
+					0.5);
+				ShowSyncHudText(i, g_hHudSync2, buffer);
+			}
+			else
+			{
+				if (g_bPlayerProxy[i])
+				{
+					new iMaxBars = 12;
+					new iBars = RoundToCeil(float(iMaxBars) * (float(g_iPlayerProxyControl[i]) / 100.0));
+					if (iBars > iMaxBars) iBars = iMaxBars;
+					
+					strcopy(buffer, sizeof(buffer), "CONTROL\n");
+					
+					for (new i2 = 0; i2 < iBars; i2++)
+					{
+						StrCat(buffer, sizeof(buffer), SF2_PLAYER_HUD_BAR_SYMBOL);
+					}
+					
+					SetHudTextParams(-1.0, 0.83,
+						0.3,
+						SF2_HUD_TEXT_COLOR_R,
+						SF2_HUD_TEXT_COLOR_G,
+						SF2_HUD_TEXT_COLOR_B,
+						40,
+						_,
+						1.0,
+						0.07,
+						0.5);
+					ShowSyncHudText(i, g_hHudSync2, buffer);
+				}
+			}
+		}
+		
+		ClientUpdateListeningFlags(i);
+		ClientUpdateMusicSystem(i);
+	}
+	
+	return Plugin_Continue;
+}
+
+stock bool:IsClientParticipating(client)
+{
+	if (!IsValidClient(client)) return false;
+	
+	if (bool:GetEntProp(client, Prop_Send, "m_bIsCoaching")) 
+	{
+		// Who would coach in this game?
+		return false;
+	}
+	
+	new iTeam = GetClientTeam(client);
+	
+	if (g_bPlayerLagCompensation[client]) 
+	{
+		iTeam = g_iPlayerLagCompensationTeam[client];
+	}
+	
+	switch (iTeam)
+	{
+		case TFTeam_Unassigned, TFTeam_Spectator: return false;
+	}
+	
+	if (_:TF2_GetPlayerClass(client) == 0)
+	{
+		// Player hasn't chosen a class? What.
+		return false;
+	}
+	
+	return true;
+}
+
+Handle:GetQueueList()
+{
+	new Handle:hArray = CreateArray(3);
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientParticipating(i)) continue;
+		if (IsPlayerGroupActive(ClientGetPlayerGroup(i))) continue;
+		
+		new index = PushArrayCell(hArray, i);
+		SetArrayCell(hArray, index, g_iPlayerQueuePoints[i], 1);
+		SetArrayCell(hArray, index, false, 2);
+	}
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		new index = PushArrayCell(hArray, i);
+		SetArrayCell(hArray, index, GetPlayerGroupQueuePoints(i), 1);
+		SetArrayCell(hArray, index, true, 2);
+	}
+	
+	if (GetArraySize(hArray)) SortADTArrayCustom(hArray, SortQueueList);
+	return hArray;
+}
+
+SetClientPlayState(client, bool:bState, bool:bEnablePlay=true)
+{
+	if (bState)
+	{
+		if (!g_bPlayerEliminated[client]) return;
+		
+		g_bPlayerEliminated[client] = false;
+		g_bPlayerPlaying[client] = bEnablePlay;
+		g_hPlayerSwitchBlueTimer[client] = INVALID_HANDLE;
+		
+		ClientSetGhostModeState(client, false);
+		
+		PvP_SetPlayerPvPState(client, false, false, false);
+		
+		if (g_bSpecialRound) 
+		{
+			SetClientPlaySpecialRoundState(client, true);
+		}
+		
+		if (g_bNewBossRound) 
+		{
+			SetClientPlayNewBossRoundState(client, true);
+		}
+		
+		if (TF2_GetPlayerClass(client) == TFClassType:0)
+		{
+			// Player hasn't chosen a class for some reason. Choose one for him.
+			TF2_SetPlayerClass(client, TFClassType:GetRandomInt(1, 9), true, true);
+		}
+		
+		ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
+	}
+	else
+	{
+		if (g_bPlayerEliminated[client]) return;
+		
+		g_bPlayerEliminated[client] = true;
+		g_bPlayerPlaying[client] = false;
+		
+		ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
+	}
+}
+
+bool:DidClientPlayNewBossRound(client)
+{
+	return g_bPlayerPlayedNewBossRound[client];
+}
+
+SetClientPlayNewBossRoundState(client, bool:bState)
+{
+	g_bPlayerPlayedNewBossRound[client] = bState;
+}
+
+bool:DidClientPlaySpecialRound(client)
+{
+	return g_bPlayerPlayedNewBossRound[client];
+}
+
+SetClientPlaySpecialRoundState(client, bool:bState)
+{
+	g_bPlayerPlayedSpecialRound[client] = bState;
+}
+
+TeleportClientToEscapePoint(client)
+{
+	if (!IsClientInGame(client)) return;
+	
+	new ent = EntRefToEntIndex(g_iRoundEscapePointEntity);
+	if (ent && ent != -1)
+	{
+		decl Float:flPos[3], Float:flAng[3];
+		GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", flPos);
+		GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", flAng);
+		
+		TeleportEntity(client, flPos, flAng, Float:{ 0.0, 0.0, 0.0 });
+		AcceptEntityInput(ent, "FireUser1", client);
+	}
+}
+
+ForceInNextPlayersInQueue(iAmount, bool:bShowMessage=false)
+{
+	// Grab the next person in line, or the next group in line if space allows.
+	new iAmountLeft = iAmount;
+	new Handle:hPlayers = CreateArray();
+	new Handle:hArray = GetQueueList();
+	
+	for (new i = 0, iSize = GetArraySize(hArray); i < iSize && iAmountLeft > 0; i++)
+	{
+		if (!GetArrayCell(hArray, i, 2))
+		{
+			new iClient = GetArrayCell(hArray, i);
+			if (g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
+			
+			PushArrayCell(hPlayers, iClient);
+			iAmountLeft--;
+		}
+		else
+		{
+			new iGroupIndex = GetArrayCell(hArray, i);
+			if (!IsPlayerGroupActive(iGroupIndex)) continue;
+			
+			new iMemberCount = GetPlayerGroupMemberCount(iGroupIndex);
+			if (iMemberCount <= iAmountLeft)
+			{
+				for (new iClient = 1; iClient <= MaxClients; iClient++)
+				{
+					if (!IsValidClient(iClient) || g_bPlayerPlaying[iClient] || !g_bPlayerEliminated[iClient] || !IsClientParticipating(iClient)) continue;
+					if (ClientGetPlayerGroup(iClient) == iGroupIndex)
+					{
+						PushArrayCell(hPlayers, iClient);
+					}
+				}
+				
+				SetPlayerGroupPlaying(iGroupIndex, true);
+				
+				iAmountLeft -= iMemberCount;
+			}
+		}
+	}
+	
+	CloseHandle(hArray);
+	
+	for (new i = 0, iSize = GetArraySize(hPlayers); i < iSize; i++)
+	{
+		new iClient = GetArrayCell(hPlayers, i);
+		ClientSetQueuePoints(iClient, 0);
+		SetClientPlayState(iClient, true);
+		
+		if (bShowMessage) CPrintToChat(iClient, "%T", "SF2 Force Play", iClient);
+	}
+	
+	CloseHandle(hPlayers);
+}
+
+public SortQueueList(index1, index2, Handle:array, Handle:hndl)
+{
+	new iQueuePoints1 = GetArrayCell(array, index1, 1);
+	new iQueuePoints2 = GetArrayCell(array, index2, 1);
+	
+	if (iQueuePoints1 > iQueuePoints2) return -1;
+	else if (iQueuePoints1 == iQueuePoints2) return 0;
+	return 1;
+}
+
+//	==========================================================
+//	GENERIC PAGE/BOSS HOOKS AND FUNCTIONS
+//	==========================================================
+
+public Action:Hook_SlenderObjectSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (!IsPlayerAlive(other) || IsClientInDeathCam(other))
+	{
+		if (!IsValidEdict(GetEntPropEnt(other, Prop_Send, "m_hObserverTarget"))) return Plugin_Handled;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_SlenderBlinkBossThink(Handle:timer, any:entref)
+{
+	new slender = EntRefToEntIndex(entref);
+	if (!slender || slender == INVALID_ENT_REFERENCE) return Plugin_Stop;
+	
+	new iBossIndex = NPCGetFromEntIndex(slender);
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	if (timer != g_hSlenderEntityThink[iBossIndex]) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (NPCGetType(iBossIndex) == SF2BossType_Creeper)
+	{
+		new bool:bMove = false;
+		
+		if ((GetGameTime() - g_flSlenderLastKill[iBossIndex]) >= GetProfileFloat(sProfile, "kill_cooldown"))
+		{
+			if (PeopleCanSeeSlender(iBossIndex, false, false) && !PeopleCanSeeSlender(iBossIndex, true, SlenderUsesBlink(iBossIndex)))
+			{
+				new iBestPlayer = -1;
+				new Handle:hArray = CreateArray();
+				
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || !IsPlayerAlive(i) || IsClientInDeathCam(i) || g_bPlayerEliminated[i] || DidClientEscape(i) || IsClientInGhostMode(i) || !PlayerCanSeeSlender(i, iBossIndex, false, false)) continue;
+					PushArrayCell(hArray, i);
+				}
+				
+				if (GetArraySize(hArray))
+				{
+					decl Float:flSlenderPos[3];
+					SlenderGetAbsOrigin(iBossIndex, flSlenderPos);
+					
+					decl Float:flTempPos[3];
+					new iTempPlayer = -1;
+					new Float:flTempDist = 16384.0;
+					for (new i = 0; i < GetArraySize(hArray); i++)
+					{
+						new iClient = GetArrayCell(hArray, i);
+						GetClientAbsOrigin(iClient, flTempPos);
+						if (GetVectorDistance(flTempPos, flSlenderPos) < flTempDist)
+						{
+							iTempPlayer = iClient;
+							flTempDist = GetVectorDistance(flTempPos, flSlenderPos);
+						}
+					}
+					
+					iBestPlayer = iTempPlayer;
+				}
+				
+				CloseHandle(hArray);
+				
+				decl Float:buffer[3];
+				if (iBestPlayer != -1 && SlenderCalculateApproachToPlayer(iBossIndex, iBestPlayer, buffer))
+				{
+					bMove = true;
+					
+					decl Float:flAng[3], Float:flBuffer[3];
+					decl Float:flSlenderPos[3], Float:flPos[3];
+					GetEntPropVector(slender, Prop_Data, "m_vecAbsOrigin", flSlenderPos);
+					GetClientAbsOrigin(iBestPlayer, flPos);
+					SubtractVectors(flPos, buffer, flAng);
+					GetVectorAngles(flAng, flAng);
+					
+					// Take care of angle offsets.
+					AddVectors(flAng, g_flSlenderEyeAngOffset[iBossIndex], flAng);
+					for (new i = 0; i < 3; i++) flAng[i] = AngleNormalize(flAng[i]);
+					
+					flAng[0] = 0.0;
+					
+					// Take care of position offsets.
+					GetProfileVector(sProfile, "pos_offset", flBuffer);
+					AddVectors(buffer, flBuffer, buffer);
+					
+					TeleportEntity(slender, buffer, flAng, NULL_VECTOR);
+					
+					new Float:flMaxRange = GetProfileFloat(sProfile, "teleport_range_max");
+					new Float:flDist = GetVectorDistance(buffer, flPos);
+					
+					decl String:sBuffer[PLATFORM_MAX_PATH];
+					
+					if (flDist < (flMaxRange * 0.33)) 
+					{
+						GetProfileString(sProfile, "model_closedist", sBuffer, sizeof(sBuffer));
+					}
+					else if (flDist < (flMaxRange * 0.66)) 
+					{
+						GetProfileString(sProfile, "model_averagedist", sBuffer, sizeof(sBuffer));
+					}
+					else 
+					{
+						GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
+					}
+					
+					// Fallback if error.
+					if (!sBuffer[0]) GetProfileString(sProfile, "model", sBuffer, sizeof(sBuffer));
+					
+					SetEntProp(slender, Prop_Send, "m_nModelIndex", PrecacheModel(sBuffer));
+					
+					if (flDist <= NPCGetInstantKillRadius(iBossIndex))
+					{
+						if (NPCGetFlags(iBossIndex) & SFF_FAKE)
+						{
+							SlenderMarkAsFake(iBossIndex);
+							return Plugin_Stop;
+						}
+						else
+						{
+							g_flSlenderLastKill[iBossIndex] = GetGameTime();
+							ClientStartDeathCam(iBestPlayer, iBossIndex, buffer);
+						}
+					}
+				}
+			}
+		}
+		
+		if (bMove)
+		{
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_move_single", sBuffer, sizeof(sBuffer));
+			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+			
+			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
+			if (sBuffer[0]) EmitSoundToAll(sBuffer, slender, SNDCHAN_AUTO, SNDLEVEL_SCREAMING, SND_CHANGEVOL);
+		}
+		else
+		{
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_move", sBuffer, sizeof(sBuffer), 1);
+			if (sBuffer[0]) StopSound(slender, SNDCHAN_AUTO, sBuffer);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+
+SlenderOnClientStressUpdate(client)
+{
+	new Float:flStress = g_flPlayerStress[client];
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new iBossIndex = 0; iBossIndex < MAX_BOSSES; iBossIndex++)
+	{	
+		if (NPCGetUniqueID(iBossIndex) == -1) continue;
+		
+		new iBossFlags = NPCGetFlags(iBossIndex);
+		if (iBossFlags & SFF_MARKEDASFAKE ||
+			iBossFlags & SFF_NOTELEPORT)
+		{
+			continue;
+		}
+		
+		NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+		
+		new iTeleportTarget = EntRefToEntIndex(g_iSlenderTeleportTarget[iBossIndex]);
+		if (iTeleportTarget && iTeleportTarget != INVALID_ENT_REFERENCE)
+		{
+			if (g_bPlayerEliminated[iTeleportTarget] ||
+				DidClientEscape(iTeleportTarget) ||
+				flStress >= g_flSlenderTeleportMaxTargetStress[iBossIndex] ||
+				GetGameTime() >= g_flSlenderTeleportMaxTargetTime[iBossIndex])
+			{
+				// Queue for a new target and mark the old target in the rest period.
+				new Float:flRestPeriod = GetProfileFloat(sProfile, "teleport_target_rest_period", 15.0);
+				flRestPeriod = (flRestPeriod * GetRandomFloat(0.92, 1.08)) / (NPCGetAnger(iBossIndex) * g_flRoundDifficultyModifier);
+				
+				g_iSlenderTeleportTarget[iBossIndex] = INVALID_ENT_REFERENCE;
+				g_flSlenderTeleportPlayersRestTime[iBossIndex][iTeleportTarget] = GetGameTime() + flRestPeriod;
+				g_flSlenderTeleportMaxTargetStress[iBossIndex] = 9999.0;
+				g_flSlenderTeleportMaxTargetTime[iBossIndex] = -1.0;
+				g_flSlenderTeleportTargetTime[iBossIndex] = -1.0;
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: lost target, putting at rest period", iBossIndex);
+#endif
+			}
+		}
+		else if (!g_bRoundGrace)
+		{
+			new iPreferredTeleportTarget = INVALID_ENT_REFERENCE;
+			
+			new Float:flTargetStressMin = GetProfileFloat(sProfile, "teleport_target_stress_min", 0.2);
+			new Float:flTargetStressMax = GetProfileFloat(sProfile, "teleport_target_stress_max", 0.9);
+			
+			new Float:flTargetStress = flTargetStressMax - ((flTargetStressMax - flTargetStressMin) / (g_flRoundDifficultyModifier * NPCGetAnger(iBossIndex)));
+			
+			new Float:flPreferredTeleportTargetStress = flTargetStress;
+			
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) ||
+					!IsPlayerAlive(i) ||
+					g_bPlayerEliminated[i] ||
+					IsClientInGhostMode(i) ||
+					DidClientEscape(i))
+				{
+					continue;
+				}
+				
+				if (g_flPlayerStress[i] < flPreferredTeleportTargetStress)
+				{
+					if (g_flSlenderTeleportPlayersRestTime[iBossIndex][i] <= GetGameTime())
+					{
+						iPreferredTeleportTarget = i;
+						flPreferredTeleportTargetStress = g_flPlayerStress[i];
+					}
+				}
+			}
+			
+			if (iPreferredTeleportTarget && iPreferredTeleportTarget != INVALID_ENT_REFERENCE)
+			{
+				// Set our preferred target to the new guy.
+				new Float:flTargetDuration = GetProfileFloat(sProfile, "teleport_target_persistency_period", 13.0);
+				new Float:flDeviation = GetRandomFloat(0.92, 1.08);
+				flTargetDuration = Pow(flDeviation * flTargetDuration, ((g_flRoundDifficultyModifier * (NPCGetAnger(iBossIndex) - 1.0)) / 2.0)) + ((flDeviation * flTargetDuration) - 1.0);
+				
+				g_iSlenderTeleportTarget[iBossIndex] = EntIndexToEntRef(iPreferredTeleportTarget);
+				g_flSlenderTeleportPlayersRestTime[iBossIndex][iPreferredTeleportTarget] = -1.0;
+				g_flSlenderTeleportMaxTargetTime[iBossIndex] = GetGameTime() + flTargetDuration;
+				g_flSlenderTeleportTargetTime[iBossIndex] = GetGameTime();
+				g_flSlenderTeleportMaxTargetStress[iBossIndex] = flTargetStress;
+				
+				iTeleportTarget = iPreferredTeleportTarget;
+				
+#if defined DEBUG
+				SendDebugMessageToPlayers(DEBUG_BOSS_TELEPORTATION, 0, "Teleport for boss %d: got new target %N", iBossIndex, iPreferredTeleportTarget);
+#endif
+			}
+		}
+	}
+}
+
+static GetPageMusicRanges()
+{
+	ClearArray(g_hPageMusicRanges);
+	
+	decl String:sName[64];
+	
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		
+		if (sName[0] && !StrContains(sName, "sf2_page_music_", false))
+		{
+			ReplaceString(sName, sizeof(sName), "sf2_page_music_", "", false);
+			
+			new String:sPageRanges[2][32];
+			ExplodeString(sName, "-", sPageRanges, 2, 32);
+			
+			new iIndex = PushArrayCell(g_hPageMusicRanges, EntIndexToEntRef(ent));
+			if (iIndex != -1)
+			{
+				new iMin = StringToInt(sPageRanges[0]);
+				new iMax = StringToInt(sPageRanges[1]);
+				
+#if defined DEBUG
+				DebugMessage("Page range found: entity %d, iMin = %d, iMax = %d", ent, iMin, iMax);
+#endif
+				SetArrayCell(g_hPageMusicRanges, iIndex, iMin, 1);
+				SetArrayCell(g_hPageMusicRanges, iIndex, iMax, 2);
+			}
+		}
+	}
+	
+	// precache
+	if (GetArraySize(g_hPageMusicRanges) > 0)
+	{
+		decl String:sPath[PLATFORM_MAX_PATH];
+		
+		for (new i = 0; i < GetArraySize(g_hPageMusicRanges); i++)
+		{
+			ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
+			if (!ent || ent == INVALID_ENT_REFERENCE) continue;
+			
+			GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+			if (sPath[0])
+			{
+				PrecacheSound(sPath);
+			}
+		}
+	}
+	
+	LogSF2Message("Loaded page music ranges successfully!");
+}
+
+SetPageCount(iNum)
+{
+	if (iNum > g_iPageMax) iNum = g_iPageMax;
+	
+	new iOldPageCount = g_iPageCount;
+	g_iPageCount = iNum;
+	
+	if (g_iPageCount != iOldPageCount)
+	{
+		if (g_iPageCount > iOldPageCount)
+		{
+			if (g_hRoundGraceTimer != INVALID_HANDLE) 
+			{
+				TriggerTimer(g_hRoundGraceTimer);
+			}
+			
+			g_iRoundTime += g_iRoundTimeGainFromPage;
+			if (g_iRoundTime > g_iRoundTimeLimit) g_iRoundTime = g_iRoundTimeLimit;
+			
+			// Increase anger on selected bosses.
+			for (new i = 0; i < MAX_BOSSES; i++)
+			{
+				if (NPCGetUniqueID(i) == -1) continue;
+				
+				new Float:flPageDiff = NPCGetAngerAddOnPageGrabTimeDiff(i);
+				if (flPageDiff >= 0.0)
+				{
+					new iDiff = g_iPageCount - iOldPageCount;
+					if ((GetGameTime() - g_flPageFoundLastTime) < flPageDiff)
+					{
+						NPCAddAnger(i, NPCGetAngerAddOnPageGrab(i) * float(iDiff));
+					}
+				}
+			}
+			
+			g_flPageFoundLastTime = GetGameTime();
+		}
+		
+		// Notify logic entities.
+		decl String:sTargetName[64];
+		decl String:sFindTargetName[64];
+		Format(sFindTargetName, sizeof(sFindTargetName), "sf2_onpagecount_%d", g_iPageCount);
+		
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "logic_relay")) != -1)
+		{
+			GetEntPropString(ent, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
+			if (sTargetName[0] && StrEqual(sTargetName, sFindTargetName, false))
+			{
+				AcceptEntityInput(ent, "Trigger");
+				break;
+			}
+		}
+	
+		new iClients[MAXPLAYERS + 1] = { -1, ... };
+		new iClientsNum = 0;
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i)) continue;
+			if (!g_bPlayerEliminated[i] || IsClientInGhostMode(i))
+			{
+				if (g_iPageCount)
+				{
+					iClients[iClientsNum] = i;
+					iClientsNum++;
+				}
+			}
+		}
+		
+		if (g_iPageCount > 0 && g_bRoundHasEscapeObjective && g_iPageCount == g_iPageMax)
+		{
+			// Escape initialized!
+			SetRoundState(SF2RoundState_Escape);
+			
+			if (iClientsNum)
+			{
+				new iGameTextEscape = GetTextEntity("sf2_escape_message", false);
+				if (iGameTextEscape != -1)
+				{
+					// Custom escape message.
+					decl String:sMessage[512];
+					GetEntPropString(iGameTextEscape, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextEscape, g_hHudSync, sMessage);
+				}
+				else
+				{
+					// Default escape message.
+					for (new i = 0; i < iClientsNum; i++)
+					{
+						new client = iClients[i];
+						ClientShowMainMessage(client, "%d/%d\n%T", g_iPageCount, g_iPageMax, "SF2 Default Escape Message", i);
+					}
+				}
+			}
+		}
+		else
+		{
+			if (iClientsNum)
+			{
+				new iGameTextPage = GetTextEntity("sf2_page_message", false);
+				if (iGameTextPage != -1)
+				{
+					// Custom page message.
+					decl String:sMessage[512];
+					GetEntPropString(iGameTextPage, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+					ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameTextPage, g_hHudSync, sMessage, g_iPageCount, g_iPageMax);
+				}
+				else
+				{
+					// Default page message.
+					for (new i = 0; i < iClientsNum; i++)
+					{
+						new client = iClients[i];
+						ClientShowMainMessage(client, "%d/%d", g_iPageCount, g_iPageMax);
+					}
+				}
+			}
+		}
+		
+		CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
+	}
+}
+
+GetTextEntity(const String:sTargetName[], bool:bCaseSensitive=true)
+{
+	// Try to see if we can use a custom message instead of the default.
+	decl String:targetName[64];
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "game_text")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
+		if (targetName[0])
+		{
+			if (StrEqual(targetName, sTargetName, bCaseSensitive))
+			{
+				return ent;
+			}
+		}
+	}
+	
+	return -1;
+}
+
+ShowHudTextUsingTextEntity(const iClients[], iClientsNum, iGameText, Handle:hHudSync, const String:sMessage[], ...)
+{
+	if (!sMessage[0]) return;
+	if (!IsValidEntity(iGameText)) return;
+	
+	decl String:sTrueMessage[512];
+	VFormat(sTrueMessage, sizeof(sTrueMessage), sMessage, 6);
+	
+	new Float:flX = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.x");
+	new Float:flY = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.y");
+	new iEffect = GetEntProp(iGameText, Prop_Data, "m_textParms.effect");
+	new Float:flFadeInTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime");
+	new Float:flFadeOutTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime");
+	new Float:flHoldTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
+	new Float:flFxTime = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fxTime");
+	
+	new Color1[4] = { 255, 255, 255, 255 };
+	new Color2[4] = { 255, 255, 255, 255 };
+	
+	new iParmsOffset = FindDataMapOffs(iGameText, "m_textParms");
+	if (iParmsOffset != -1)
+	{
+		// hudtextparms_s m_textParms
+		
+		Color1[0] = GetEntData(iGameText, iParmsOffset + 12, 1);
+		Color1[1] = GetEntData(iGameText, iParmsOffset + 13, 1);
+		Color1[2] = GetEntData(iGameText, iParmsOffset + 14, 1);
+		Color1[3] = GetEntData(iGameText, iParmsOffset + 15, 1);
+		
+		Color2[0] = GetEntData(iGameText, iParmsOffset + 16, 1);
+		Color2[1] = GetEntData(iGameText, iParmsOffset + 17, 1);
+		Color2[2] = GetEntData(iGameText, iParmsOffset + 18, 1);
+		Color2[3] = GetEntData(iGameText, iParmsOffset + 19, 1);
+	}
+	
+	SetHudTextParamsEx(flX, flY, flHoldTime, Color1, Color2, iEffect, flFxTime, flFadeInTime, flFadeOutTime);
+	
+	for (new i = 0; i < iClientsNum; i++)
+	{
+		new iClient = iClients[i];
+		if (!IsValidClient(iClient) || IsFakeClient(iClient)) continue;
+		
+		ShowSyncHudText(iClient, hHudSync, sTrueMessage);
+	}
+}
+
+//	==========================================================
+//	EVENT HOOKS
+//	==========================================================
+
+public Event_RoundStart(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundStart");
+#endif
+	
+	// Reset some global variables.
+	g_iRoundCount++;
+	g_hRoundTimer = INVALID_HANDLE;
+	
+	SetRoundState(SF2RoundState_Invalid);
+	
+	SetPageCount(0);
+	g_iPageMax = 0;
+	g_flPageFoundLastTime = GetGameTime();
+	
+	g_hVoteTimer = INVALID_HANDLE;
+	
+	// Remove all bosses from the game.
+	NPCRemoveAll();
+	
+	// Refresh groups.
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		SetPlayerGroupPlaying(i, false);
+		CheckPlayerGroup(i);
+	}
+	
+	// Refresh players.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		ClientSetGhostModeState(i, false);
+		
+		g_bPlayerPlaying[i] = false;
+		g_bPlayerEliminated[i] = true;
+		g_bPlayerEscaped[i] = false;
+	}
+	
+	// Calculate the new round state.
+	if (g_bRoundWaitingForPlayers)
+	{
+		SetRoundState(SF2RoundState_Waiting);
+	}
+	else if (GetConVarBool(g_cvWarmupRound) && g_iRoundWarmupRoundCount < GetConVarInt(g_cvWarmupRoundNum))
+	{
+		g_iRoundWarmupRoundCount++;
+		
+		SetRoundState(SF2RoundState_Waiting);
+		
+		ServerCommand("mp_restartgame 15");
+		PrintCenterTextAll("Round restarting in 15 seconds");
+	}
+	else
+	{
+		g_iRoundActiveCount++;
+		
+		InitializeNewGame();
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundStart");
+#endif
+}
+
+public Event_RoundEnd(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_RoundEnd");
+#endif
+	
+	SetRoundState(SF2RoundState_Outro);
+	
+	DistributeQueuePointsToPlayers();
+	
+	g_iRoundEndCount++;	
+	CheckRoundLimitForBossPackVote(g_iRoundEndCount);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_RoundEnd");
+#endif
+}
+
+static DistributeQueuePointsToPlayers()
+{
+	// Give away queue points.
+	new iDefaultAmount = 5;
+	new iAmount = iDefaultAmount;
+	new iAmount2 = iAmount;
+	new Action:iAction = Plugin_Continue;
+	
+	for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+	{
+		if (!IsPlayerGroupActive(i)) continue;
+		
+		if (IsPlayerGroupPlaying(i))
+		{
+			SetPlayerGroupQueuePoints(i, 0);
+		}
+		else
+		{
+			iAmount = iDefaultAmount;
+			iAmount2 = iAmount;
+			iAction = Plugin_Continue;
+			
+			Call_StartForward(fOnGroupGiveQueuePoints);
+			Call_PushCell(i);
+			Call_PushCellRef(iAmount2);
+			Call_Finish(iAction);
+			
+			if (iAction == Plugin_Changed) iAmount = iAmount2;
+			
+			SetPlayerGroupQueuePoints(i, GetPlayerGroupQueuePoints(i) + iAmount);
+		
+			for (new iClient = 1; iClient <= MaxClients; iClient++)
+			{
+				if (!IsValidClient(iClient)) continue;
+				if (ClientGetPlayerGroup(iClient) == i)
+				{
+					CPrintToChat(iClient, "%T", "SF2 Give Group Queue Points", iClient, iAmount);
+				}
+			}
+		}
+	}
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (g_bPlayerPlaying[i]) 
+		{
+			ClientSetQueuePoints(i, 0);
+		}
+		else
+		{
+			if (!IsClientParticipating(i))
+			{
+				CPrintToChat(i, "%T", "SF2 No Queue Points To Spectator", i);
+			}
+			else
+			{
+				iAmount = iDefaultAmount;
+				iAmount2 = iAmount;
+				iAction = Plugin_Continue;
+				
+				Call_StartForward(fOnClientGiveQueuePoints);
+				Call_PushCell(i);
+				Call_PushCellRef(iAmount2);
+				Call_Finish(iAction);
+				
+				if (iAction == Plugin_Changed) iAmount = iAmount2;
+				
+				ClientSetQueuePoints(i, g_iPlayerQueuePoints[i] + iAmount);
+				CPrintToChat(i, "%T", "SF2 Give Queue Points", i, iAmount);
+			}
+		}	
+	}
+}
+
+public Action:Event_PlayerTeamPre(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerTeamPre");
+#endif
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client > 0)
+	{
+		if (GetEventInt(event, "team") > 1 || GetEventInt(event, "oldteam") > 1) SetEventBroadcast(event, true);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerTeamPre");
+#endif
+	
+	return Plugin_Continue;
+}
+
+public Event_PlayerTeam(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerTeam");
+#endif
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client > 0)
+	{
+		new iNewTeam = GetEventInt(event, "team");
+		if (iNewTeam <= _:TFTeam_Spectator)
+		{
+			if (g_bRoundGrace)
+			{
+				if (g_bPlayerPlaying[client] && !g_bPlayerEliminated[client])
+				{
+					ForceInNextPlayersInQueue(1, true);
+				}
+			}
+			
+			// You're not playing anymore.
+			if (g_bPlayerPlaying[client])
+			{
+				ClientSetQueuePoints(client, 0);
+			}
+			
+			g_bPlayerPlaying[client] = false;
+			g_bPlayerEliminated[client] = true;
+			g_bPlayerEscaped[client] = false;
+			
+			ClientSetGhostModeState(client, false);
+			
+			if (!bool:GetEntProp(client, Prop_Send, "m_bIsCoaching"))
+			{
+				// This is to prevent player spawn spam when someone is coaching. Who coaches in SF2, anyway?
+				TF2_RespawnPlayer(client);
+			}
+			
+			// Special round.
+			if (g_bSpecialRound) g_bPlayerPlayedSpecialRound[client] = true;
+			
+			// Boss round.
+			if (g_bNewBossRound) g_bPlayerPlayedNewBossRound[client] = true;
+		}
+		else
+		{
+			if (!g_bPlayerChoseTeam[client])
+			{
+				g_bPlayerChoseTeam[client] = true;
+				
+				if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
+				{
+					EmitSoundToClient(client, SF2_PROJECTED_FLASHLIGHT_CONFIRM_SOUND);
+					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Projected{olive}.");
+				}
+				else
+				{
+					CPrintToChat(client, "{olive}Your flashlight mode has been set to {lightgreen}Normal{olive}.");
+				}
+				
+				CreateTimer(5.0, Timer_WelcomeMessage, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+			}
+		}
+	}
+	
+	// Check groups.
+	if (!IsRoundEnding())
+	{
+		for (new i = 0; i < SF2_MAX_PLAYER_GROUPS; i++)
+		{
+			if (!IsPlayerGroupActive(i)) continue;
+			CheckPlayerGroup(i);
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerTeam");
+#endif
+
+}
+
+/**
+ *	Sets the player to the correct team if needed. Returns true if a change was necessary, false if no change occurred.
+ */
+static bool:HandlePlayerTeam(client, bool:bRespawn=true)
+{
+	if (!IsClientInGame(client) || !IsClientParticipating(client)) return false;
+	
+	if (!g_bPlayerEliminated[client])
+	{
+		if (GetClientTeam(client) != _:TFTeam_Red)
+		{
+			if (bRespawn)
+				ChangeClientTeamNoSuicide(client, _:TFTeam_Red);
+			else
+				ChangeClientTeam(client, _:TFTeam_Red);
+				
+			return true;
+		}
+	}
+	else
+	{
+		if (GetClientTeam(client) != _:TFTeam_Blue)
+		{
+			if (bRespawn)
+				ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
+			else
+				ChangeClientTeam(client, _:TFTeam_Blue);
+				
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+static HandlePlayerIntroState(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client) || !IsClientParticipating(client)) return;
+	
+	if (!IsRoundInIntro()) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START HandlePlayerIntroState(%d)", client);
+#endif
+	
+	// Disable movement on player.
+	SetEntityFlags(client, GetEntityFlags(client) | FL_FROZEN);
+	
+	new Float:flDelay = 0.0;
+	if (!IsFakeClient(client))
+	{
+		flDelay = GetClientLatency(client, NetFlow_Outgoing);
+	}
+	
+	CreateTimer(flDelay * 4.0, Timer_IntroBlackOut, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END HandlePlayerIntroState(%d)", client);
+#endif
+}
+
+HandlePlayerHUD(client)
+{
+	if (IsRoundInWarmup() || IsClientInGhostMode(client))
+	{
+		SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
+	}
+	else
+	{
+		if (!g_bPlayerEliminated[client])
+		{
+			if (!DidClientEscape(client))
+			{
+				// Player is in the game; disable normal HUD.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
+			}
+			else
+			{
+				// Player isn't in the game; enable normal HUD behavior.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
+			}
+		}
+		else
+		{
+			if (g_bPlayerProxy[client])
+			{
+				// Player is in the game; disable normal HUD.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", HIDEHUD_CROSSHAIR | HIDEHUD_HEALTH);
+			}
+			else
+			{
+				// Player isn't in the game; enable normal HUD behavior.
+				SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
+			}
+		}
+	}
+}
+
+public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client <= 0) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerSpawn(%d)", client);
+#endif
+	
+	if (!IsClientParticipating(client))
+	{
+		ClientSetGhostModeState(client, false);
+	}
+	
+	g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
+	
+	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
+	g_iGhostNextHelpPhrase[client] = 0;
+	
+	if (IsPlayerAlive(client) && IsClientParticipating(client))
+	{
+		if (HandlePlayerTeam(client))
+		{
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("client->HandlePlayerTeam()");
+#endif
+		}
+		else
+		{
+			g_iPlayerPageCount[client] = 0;
+			
+			ClientDisableFakeLagCompensation(client);
+			
+			ClientResetStatic(client);
+			ClientResetSlenderStats(client);
+			ClientResetCampingStats(client);
+			ClientResetOverlay(client);
+			ClientResetJumpScare(client);
+			ClientUpdateListeningFlags(client);
+			ClientUpdateMusicSystem(client);
+			ClientChaseMusicReset(client);
+			ClientChaseMusicSeeReset(client);
+			ClientAlertMusicReset(client);
+			Client20DollarsMusicReset(client);
+			ClientMusicReset(client);
+			ClientResetProxy(client);
+			ClientResetHints(client);
+			ClientResetScare(client);
+			
+			ClientResetDeathCam(client);
+			ClientResetFlashlight(client);
+			ClientDeactivateUltravision(client);
+			ClientResetSprint(client);
+			ClientResetBreathing(client);
+			ClientResetBlink(client);
+			ClientResetInteractiveGlow(client);
+			ClientDisableConstantGlow(client);
+			
+			ClientHandleGhostMode(client);
+			
+			if (!g_bPlayerEliminated[client])
+			{
+				ClientStartDrainingBlinkMeter(client);
+				ClientSetScareBoostEndTime(client, -1.0);
+				
+				ClientStartCampingTimer(client);
+				
+				HandlePlayerIntroState(client);
+				
+				// screen overlay timer
+				g_hPlayerOverlayCheck[client] = CreateTimer(0.0, Timer_PlayerOverlayCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+				TriggerTimer(g_hPlayerOverlayCheck[client], true);
+				
+				if (DidClientEscape(client))
+				{
+					CreateTimer(0.1, Timer_TeleportPlayerToEscapePoint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+				else
+				{
+					ClientEnableConstantGlow(client, "head");
+					ClientActivateUltravision(client);
+					CreateTimer(0.1, Timer_CreateSpriteOverlay, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+			}
+			else
+			{
+				g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
+			}
+			
+			g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+			
+			HandlePlayerHUD(client);
+		}
+	}
+	
+	PvP_OnPlayerSpawn(client);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerSpawn(%d)", client);
+#endif
+}
+
+public Action:Timer_UpdateOverlayTime(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	new String:Time[64], String:DigitBuffer[2];
+	FormatTime(Time, sizeof(Time), "%d"); // Day
+	Format(DigitBuffer, 2, "%s", Time[0]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit0), StringToFloat(DigitBuffer));
+	Format(DigitBuffer, 2, "%s", Time[1]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit1), StringToFloat(DigitBuffer));
+	FormatTime(Time, sizeof(Time), "%m"); // Month
+	Format(DigitBuffer, 2, "%s", Time[0]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit3), StringToFloat(DigitBuffer));
+	Format(DigitBuffer, 2, "%s", Time[1]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit4), StringToFloat(DigitBuffer));
+	FormatTime(Time, sizeof(Time), "%H"); // Hours
+	Format(DigitBuffer, 2, "%s", Time[0]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit0), StringToFloat(DigitBuffer));
+	Format(DigitBuffer, 2, "%s", Time[1]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit1), StringToFloat(DigitBuffer));
+	FormatTime(Time, sizeof(Time), "%M"); // Minutes
+	Format(DigitBuffer, 2, "%s", Time[0]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit3), StringToFloat(DigitBuffer));
+	Format(DigitBuffer, 2, "%s", Time[1]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit4), StringToFloat(DigitBuffer));
+	if(g_hRoundTimer != INVALID_HANDLE) {
+		//g_iRoundTime
+		//g_iRoundTime = g_iRoundTimeLimit;g_iPageCount == g_iPageMax
+		new time = g_iRoundTime;
+		decl maxTime;
+		if(g_iPageCount == g_iPageMax) {
+			maxTime = g_iRoundEscapeTimeLimit;
+		} else {
+			maxTime = g_iRoundTimeLimit;
+		}
+		if(float(time) / float(maxTime) >= 0.75) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
+		else if(float(time) / float(maxTime) >= 0.5) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 1.0);
+		else if(float(time) / float(maxTime) >= 0.25) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 2.0);
+		else if(float(time) / float(maxTime) >= 0.17) Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 3.0);
+		else {
+			Overlay_Color_Red(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[0]);
+			Overlay_Color_Green(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
+			Overlay_Color_Blue(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
+			if(g_bHudBatteryToggle[client]) Overlay_Hide(OverlayRef_ByLayer(client, _:HudBattery));// Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 3.0);
+			else {
+				Overlay_Show(OverlayRef_ByLayer(client, _:HudBattery));
+				Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 3.0);
+			}
+			//PrintToServer("%d", g_bHudBatteryToggle[client]);
+			g_bHudBatteryToggle[client] = !g_bHudBatteryToggle[client];
+		}
+		//Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), float(g_iRoundTime));
+		/*
+			Overlay_Frame(OverlayRef_ByLayer(client, _:HudBattery), 0.0);
+			Overlay_Color_Red(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[0]);
+			Overlay_Color_Green(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[1]);
+			Overlay_Color_Blue(OverlayRef_ByLayer(client, _:HudBattery), g_fHudDigitIntensity[1]);
+		*/
+	}
+}
+
+public Action:Timer_CreateSpriteOverlay(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	/*
+	PrintToServer("Add_Sprite()");
+	Add_Sprite(client, OverlayGeneric, 14.0);
+	//Overlay_Render(client, _:OverlayGeneric, g_fOverlayMatOffset[OverlayGeneric], g_sOverlayMat[OverlayGeneric], -5.0);
+	new spr;
+	new String:cl[32];
+	PrintToServer("Overlay_Layer_Exists(client, _:OverlayGeneric): %d", Overlay_Layer_Exists(client, _:OverlayGeneric, spr));
+	Overlay_Show(spr);
+	GetEntityClassname(spr, cl, sizeof(cl));
+	PrintToServer("spr: %d (%s)", spr, cl);
+	*/
+	g_fOverlayMatRotation[OverlayGeneric][2] = GetRandomFloat(0.0, 180.0);
+	Add_Sprite(client, OverlayGeneric, 35.0);
+	Add_Sprite(client, Crosshair, 3.0);
+	
+	Add_Sprite(client, DateDigit0, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit1, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit2, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit3, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit4, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit5, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit6, g_fHudDigitScale);
+	Add_Sprite(client, DateDigit7, g_fHudDigitScale);
+	Add_Sprite(client, ClockDigit0, g_fHudDigitScale);
+	Add_Sprite(client, ClockDigit1, g_fHudDigitScale);
+	Add_Sprite(client, ClockDigit2, g_fHudDigitScale);
+	Add_Sprite(client, ClockDigit3, g_fHudDigitScale);
+	Add_Sprite(client, ClockDigit4, g_fHudDigitScale);
+	
+	Add_Sprite(client, HudRec, g_fHudDigitScale);
+	Add_Sprite(client, HudBattery, g_fHudDigitScale);
+	g_bHudBatteryToggle[client] = true;
+	//PrintToServer("%d", Overlay_Exists(OverlayRef_ByLayer(client, _:DateDigit0)));
+	for(new i = _:DateDigit0; i <= _:HudBattery; i++) {
+		Overlay_Framerate(OverlayRef_ByLayer(client, i), 0.0);
+		Overlay_Color_Red(OverlayRef_ByLayer(client, i), g_fHudDigitIntensity[0]);
+		Overlay_Color_Green(OverlayRef_ByLayer(client, i), g_fHudDigitIntensity[1]);
+		Overlay_Color_Blue(OverlayRef_ByLayer(client, i), g_fHudDigitIntensity[1]);
+	}
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit2), 10.0);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit5), 10.0);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:ClockDigit2), 11.0);
+	/*
+	new Float:yearDigits[2], String:buffer[16];
+	Format(buffer, 16, "0000%s", g_sCameraYear);
+	strcopy(g_sCameraYear, sizeof(g_sCameraYear), buffer);
+	Format(buffer, 1, "%s", g_sCameraYear[strlen(g_sCameraYear)-1]);
+	strcopy(g_sCameraYear, sizeof(g_sCameraYear), buffer);
+	yearDigits[0] = StringToFloat(buffer[0]);
+	Format(buffer, 1, "%s", g_sCameraYear[strlen(g_sCameraYear)-1]);
+	strcopy(g_sCameraYear, sizeof(g_sCameraYear), buffer);
+	yearDigits[1] = StringToFloat(buffer[0]);
+	*/
+	//PrintToServer("%s %d %s %s %s", g_sCameraYear, strlen(g_sCameraYear), g_sCameraYear[strlen(g_sCameraYear)-1], g_sCameraYear[strlen(g_sCameraYear)-2], g_sCameraYear[strlen(g_sCameraYear)-3]);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit6), 8.0);
+	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit7), 6.0);
+	g_hOverlayUpdateTimer[client] = CreateTimer(1.2, Timer_UpdateOverlayTime, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
+}
+
+public Action:Timer_IntroBlackOut(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (!IsRoundInIntro()) return;
+	
+	if (!IsPlayerAlive(client) || g_bPlayerEliminated[client]) return;
+	
+	// Black out the player's screen.
+	new iFadeFlags = FFADE_OUT | FFADE_STAYOUT | FFADE_PURGE;
+	UTIL_ScreenFade(client, 0, FixedUnsigned16(90.0, 1 << 12), iFadeFlags, g_iRoundIntroFadeColor[0], g_iRoundIntroFadeColor[1], g_iRoundIntroFadeColor[2], g_iRoundIntroFadeColor[3]);
+}
+
+public Event_PostInventoryApplication(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PostInventoryApplication");
+#endif
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client > 0)
+	{
+		g_hPlayerPostWeaponsTimer[client] = CreateTimer(0.1, Timer_ClientPostWeapons, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PostInventoryApplication");
+#endif
+}
+
+public Action:Event_DontBroadcastToClients(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	if (IsRoundInWarmup()) return Plugin_Continue;
+	
+	SetEventBroadcast(event, true);
+	return Plugin_Continue;
+}
+
+public Action:Event_PlayerDeathPre(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT START: Event_PlayerDeathPre");
+#endif
+	
+	if (!IsRoundInWarmup())
+	{
+		new client = GetClientOfUserId(GetEventInt(event, "userid"));
+		if (client > 0)
+		{
+			if (!IsRoundEnding())
+			{
+				if (g_bRoundGrace || g_bPlayerEliminated[client] || IsClientInGhostMode(client))
+				{
+					SetEventBroadcast(event, true);
+				}
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("EVENT END: Event_PlayerDeathPre");
+#endif
+	
+	return Plugin_Continue;
+}
+
+public Event_PlayerHurt(Handle:event, const String:name[], bool:dB)
+{
+	if (!g_bEnabled) return;
+	
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client <= 0) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerHurt");
+#endif
+	
+	ClientDisableFakeLagCompensation(client);
+	
+	new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
+	if (attacker > 0)
+	{
+		if (g_bPlayerProxy[attacker])
+		{
+			g_iPlayerProxyControl[attacker] = 100;
+		}
+	}
+	
+	// Play any sounds, if any.
+	if (g_bPlayerProxy[client])
+	{
+		new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+		if (iProxyMaster != -1)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
+		
+			decl String:sBuffer[PLATFORM_MAX_PATH];
+			if (GetRandomStringFromProfile(sProfile, "sound_proxy_hurt", sBuffer, sizeof(sBuffer)) && sBuffer[0])
+			{
+				new iChannel = GetProfileNum(sProfile, "sound_proxy_hurt_channel", SNDCHAN_AUTO);
+				new iLevel = GetProfileNum(sProfile, "sound_proxy_hurt_level", SNDLEVEL_NORMAL);
+				new iFlags = GetProfileNum(sProfile, "sound_proxy_hurt_flags", SND_NOFLAGS);
+				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_hurt_volume", SNDVOL_NORMAL);
+				new iPitch = GetProfileNum(sProfile, "sound_proxy_hurt_pitch", SNDPITCH_NORMAL);
+				
+				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerHurt");
+#endif
+}
+
+public Event_PlayerDeath(Handle:event, const String:name[], bool:dB)
+{
+	new client = GetClientOfUserId(GetEventInt(event, "userid"));
+	if (client <= 0) return;
+	
+	DestroySpriteOverlay(client);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerDeath(%d)", client);
+#endif
+	
+	new bool:bFake = bool:(GetEventInt(event, "death_flags") & TF_DEATHFLAG_DEADRINGER);
+	new inflictor = GetEventInt(event, "inflictor_entindex");
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("inflictor = %d", inflictor);
+#endif
+	
+	if (!bFake)
+	{
+		ClientDisableFakeLagCompensation(client);
+		
+		ClientResetStatic(client);
+		ClientResetSlenderStats(client);
+		ClientResetCampingStats(client);
+		ClientResetOverlay(client);
+		ClientResetJumpScare(client);
+		ClientResetInteractiveGlow(client);
+		ClientDisableConstantGlow(client);
+		ClientChaseMusicReset(client);
+		ClientChaseMusicSeeReset(client);
+		ClientAlertMusicReset(client);
+		Client20DollarsMusicReset(client);
+		ClientMusicReset(client);
+		
+		ClientResetFlashlight(client);
+		ClientDeactivateUltravision(client);
+		ClientResetSprint(client);
+		ClientResetBreathing(client);
+		ClientResetBlink(client);
+		ClientResetDeathCam(client);
+		
+		ClientUpdateMusicSystem(client);
+		
+		PvP_SetPlayerPvPState(client, false, false, false);
+		
+		if (IsRoundInWarmup())
+		{
+			CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+		}
+		else
+		{
+			if (!g_bPlayerEliminated[client])
+			{
+				if (IsRoundInIntro() || g_bRoundGrace || DidClientEscape(client))
+				{
+					CreateTimer(0.3, Timer_RespawnPlayer, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+				}
+				else
+				{
+					g_bPlayerEliminated[client] = true;
+					g_bPlayerEscaped[client] = false;
+					g_hPlayerSwitchBlueTimer[client] = CreateTimer(2.5, Timer_PlayerSwitchToBlue, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+					ClientCommand(client, "r_screenoverlay %s", STATIC_OVERLAY);
+					EmitSoundToClient(client, STATIC_SOUND, _, MUSIC_CHAN, SNDLEVEL_NONE);
+				}
+			}
+			else
+			{
+			}
+			
+			{
+				// If this player was killed by a boss, play a sound.
+				new npcIndex = NPCGetFromEntIndex(inflictor);
+				if (npcIndex != -1)
+				{
+					decl String:npcProfile[SF2_MAX_PROFILE_NAME_LENGTH], String:buffer[PLATFORM_MAX_PATH];
+					NPCGetProfile(npcIndex, npcProfile, sizeof(npcProfile));
+					
+					if (GetRandomStringFromProfile(npcProfile, "sound_attack_killed_all", buffer, sizeof(buffer)) && strlen(buffer) > 0)
+					{
+						if (!g_bPlayerEliminated[client])
+						{
+							EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_HELICOPTER);
+						}
+					}
+					
+					SlenderPerformVoice(npcIndex, "sound_attack_killed");
+				}
+			}
+			
+			CreateTimer(0.2, Timer_CheckRoundWinConditions, _, TIMER_FLAG_NO_MAPCHANGE);
+			
+			// Notify to other bosses that this player has died.
+			for (new i = 0; i < MAX_BOSSES; i++)
+			{
+				if (NPCGetUniqueID(i) == -1) continue;
+				
+				if (EntRefToEntIndex(g_iSlenderTarget[i]) == client)
+				{
+					g_iSlenderInterruptConditions[i] |= COND_CHASETARGETINVALIDATED;
+					GetClientAbsOrigin(client, g_flSlenderChaseDeathPosition[i]);
+				}
+			}
+		}
+		
+		if (g_bPlayerProxy[client])
+		{
+			// We're a proxy, so play some sounds.
+		
+			new iProxyMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+			if (iProxyMaster != -1)
+			{
+				decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+				NPCGetProfile(iProxyMaster, sProfile, sizeof(sProfile));
+				
+				decl String:sBuffer[PLATFORM_MAX_PATH];
+				if (GetRandomStringFromProfile(sProfile, "sound_proxy_death", sBuffer, sizeof(sBuffer)) && sBuffer[0])
+				{
+					new iChannel = GetProfileNum(sProfile, "sound_proxy_death_channel", SNDCHAN_AUTO);
+					new iLevel = GetProfileNum(sProfile, "sound_proxy_death_level", SNDLEVEL_NORMAL);
+					new iFlags = GetProfileNum(sProfile, "sound_proxy_death_flags", SND_NOFLAGS);
+					new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_death_volume", SNDVOL_NORMAL);
+					new iPitch = GetProfileNum(sProfile, "sound_proxy_death_pitch", SNDPITCH_NORMAL);
+					
+					EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
+				}
+			}
+		}
+		
+		ClientResetProxy(client, false);
+		ClientUpdateListeningFlags(client);
+		
+		// Half-Zatoichi nerf code.
+		new iKatanaHealthGain = GetConVarInt(g_cvHalfZatoichiHealthGain);
+		if (iKatanaHealthGain >= 0)
+		{
+			new iAttacker = GetClientOfUserId(GetEventInt(event, "attacker"));
+			if (iAttacker > 0)
+			{
+				if (!IsClientInPvP(iAttacker) && (!g_bPlayerEliminated[iAttacker] || g_bPlayerProxy[iAttacker]))
+				{
+					decl String:sWeapon[64];
+					GetEventString(event, "weapon", sWeapon, sizeof(sWeapon));
+					
+					if (StrEqual(sWeapon, "demokatana"))
+					{
+						new iAttackerPreHealth = GetEntProp(iAttacker, Prop_Send, "m_iHealth");
+						new Handle:hPack = CreateDataPack();
+						WritePackCell(hPack, GetClientUserId(iAttacker));
+						WritePackCell(hPack, iAttackerPreHealth + iKatanaHealthGain);
+						
+						CreateTimer(0.0, Timer_SetPlayerHealth, hPack, TIMER_FLAG_NO_MAPCHANGE);
+					}
+				}
+			}
+		}
+		
+		g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
+	}
+	
+	PvP_OnPlayerDeath(client, bFake);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT END: Event_PlayerDeath(%d)", client);
+#endif
+}
+
+public Action:Timer_SetPlayerHealth(Handle:timer, any:data)
+{
+	new Handle:hPack = Handle:data;
+	ResetPack(hPack);
+	new iAttacker = GetClientOfUserId(ReadPackCell(hPack));
+	new iHealth = ReadPackCell(hPack);
+	CloseHandle(hPack);
+	
+	if (iAttacker <= 0) return;
+	
+	SetEntProp(iAttacker, Prop_Data, "m_iHealth", iHealth);
+	SetEntProp(iAttacker, Prop_Send, "m_iHealth", iHealth);
+}
+
+public Action:Timer_PlayerSwitchToBlue(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerSwitchBlueTimer[client]) return;
+	
+	ChangeClientTeam(client, _:TFTeam_Blue);
+}
+
+public Action:Timer_RoundStart(Handle:timer)
+{
+	if (g_iPageMax > 0)
+	{
+		new Handle:hArrayClients = CreateArray();
+		new iClients[MAXPLAYERS + 1];
+		new iClientsNum = 0;
+		
+		new iGameText = GetTextEntity("sf2_intro_message", false);
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || IsFakeClient(i) || g_bPlayerEliminated[i]) continue;
+			
+			if (iGameText == -1)
+			{
+				if (g_iPageMax > 1)
+				{
+					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Plural", i, g_iPageMax);
+				}
+				else
+				{
+					ClientShowMainMessage(i, "%T", "SF2 Default Intro Message Singular", i, g_iPageMax);
+				}
+			}
+			
+			PushArrayCell(hArrayClients, GetClientUserId(i));
+			iClients[iClientsNum] = i;
+			iClientsNum++;
+		}
+		
+		// Show difficulty menu.
+		if (iClientsNum)
+		{
+			// Automatically set it to Normal.
+			SetConVarInt(g_cvDifficulty, Difficulty_Normal);
+			
+			g_hVoteTimer = CreateTimer(1.0, Timer_VoteDifficulty, hArrayClients, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			TriggerTimer(g_hVoteTimer, true);
+			
+			if (iGameText != -1)
+			{
+				decl String:sMessage[512];
+				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+				
+				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
+			}
+		}
+		else
+		{
+			CloseHandle(hArrayClients);
+		}
+	}
+}
+
+public Action:Timer_CheckRoundWinConditions(Handle:timer)
+{
+	CheckRoundWinConditions();
+}
+
+public Action:Timer_RoundGrace(Handle:timer)
+{
+	if (timer != g_hRoundGraceTimer) return;
+	
+	g_bRoundGrace = false;
+	g_hRoundGraceTimer = INVALID_HANDLE;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientParticipating(i)) g_bPlayerEliminated[i] = true;
+	}
+	
+	// Initialize the main round timer.
+	if (g_iRoundTimeLimit > 0)
+	{
+		// Set round time.
+		g_iRoundTime = g_iRoundTimeLimit;
+		g_hRoundTimer = CreateTimer(1.0, Timer_RoundTime, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	}
+	else
+	{
+		// Infinite round time.
+		g_hRoundTimer = INVALID_HANDLE;
+	}
+	
+	CPrintToChatAll("{olive}%t", "SF2 Grace Period End");
+}
+
+public Action:Timer_RoundTime(Handle:timer)
+{
+	if (timer != g_hRoundTimer) return Plugin_Stop;
+	
+	if (g_iRoundTime <= 0)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i)) continue;
+			
+			decl Float:flBuffer[3];
+			GetClientAbsOrigin(i, flBuffer);
+			SDKHooks_TakeDamage(i, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+		}
+		
+		return Plugin_Stop;
+	}
+	
+	g_iRoundTime--;
+	
+	new hours, minutes, seconds;
+	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
+	
+	SetHudTextParams(-1.0, 0.1, 
+		1.0,
+		SF2_HUD_TEXT_COLOR_R, SF2_HUD_TEXT_COLOR_G, SF2_HUD_TEXT_COLOR_B, SF2_HUD_TEXT_COLOR_A,
+		_,
+		_,
+		1.5, 1.5);
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
+		ShowSyncHudText(i, g_hRoundTimerSync, "%d/%d\n%d:%02d", g_iPageCount, g_iPageMax, minutes, seconds);
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_RoundTimeEscape(Handle:timer)
+{
+	if (timer != g_hRoundTimer) return Plugin_Stop;
+	
+	if (g_iRoundTime <= 0)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || !IsPlayerAlive(i) || g_bPlayerEliminated[i] || IsClientInGhostMode(i) || DidClientEscape(i)) continue;
+			
+			decl Float:flBuffer[3];
+			GetClientAbsOrigin(i, flBuffer);
+			ClientStartDeathCam(i, 0, flBuffer);
+		}
+		
+		return Plugin_Stop;
+	}
+	
+	new hours, minutes, seconds;
+	FloatToTimeHMS(float(g_iRoundTime), hours, minutes, seconds);
+	
+	SetHudTextParams(-1.0, 0.1, 
+		1.0,
+		SF2_HUD_TEXT_COLOR_R, 
+		SF2_HUD_TEXT_COLOR_G, 
+		SF2_HUD_TEXT_COLOR_B, 
+		SF2_HUD_TEXT_COLOR_A,
+		_,
+		_,
+		1.5, 1.5);
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || IsFakeClient(i) || (g_bPlayerEliminated[i] && !IsClientInGhostMode(i))) continue;
+		ShowSyncHudText(i, g_hRoundTimerSync, "%T\n%d:%02d", "SF2 Default Escape Message", i, minutes, seconds);
+	}
+	
+	g_iRoundTime--;
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_VoteDifficulty(Handle:timer, any:data)
+{
+	new Handle:hArrayClients = Handle:data;
+	
+	if (timer != g_hVoteTimer || IsRoundEnding()) 
+	{
+		CloseHandle(hArrayClients);
+		return Plugin_Stop;
+	}
+	
+	if (IsVoteInProgress()) return Plugin_Continue; // There's another vote in progess. Wait.
+	
+	new iClients[MAXPLAYERS + 1] = { -1, ... };
+	new iClientsNum;
+	for (new i = 0, iSize = GetArraySize(hArrayClients); i < iSize; i++)
+	{
+		new iClient = GetClientOfUserId(GetArrayCell(hArrayClients, i));
+		if (iClient <= 0) continue;
+		
+		iClients[iClientsNum] = iClient;
+		iClientsNum++;
+	}
+	
+	CloseHandle(hArrayClients);
+	
+	VoteMenu(g_hMenuVoteDifficulty, iClients, iClientsNum, 15);
+	
+	return Plugin_Stop;
+}
+
+static InitializeMapEntities()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeMapEntities()");
+#endif
+	
+	g_bRoundInfiniteFlashlight = false;
+	g_bRoundInfiniteBlink = false;
+	g_bRoundInfiniteSprint = false;
+	g_bRoundHasEscapeObjective = false;
+	
+	g_iRoundTimeLimit = GetConVarInt(g_cvTimeLimit);
+	g_iRoundEscapeTimeLimit = GetConVarInt(g_cvTimeLimitEscape);
+	g_iRoundTimeGainFromPage = GetConVarInt(g_cvTimeGainFromPageGrab);
+	
+	// Reset page reference.
+	g_bPageRef = false;
+	strcopy(g_strPageRefModel, sizeof(g_strPageRefModel), "");
+	g_flPageRefModelScale = 1.0;
+	
+	new Handle:hArray = CreateArray(2);
+	new Handle:hPageTrie = CreateTrie();
+	
+	decl String:targetName[64];
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
+		if (targetName[0])
+		{
+			if (!StrContains(targetName, "sf2_maxpages_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_maxpages_", "", false);
+				g_iPageMax = StringToInt(targetName);
+			}
+			else if (!StrContains(targetName, "sf2_page_spawnpoint", false))
+			{
+				if (!StrContains(targetName, "sf2_page_spawnpoint_", false))
+				{
+					ReplaceString(targetName, sizeof(targetName), "sf2_page_spawnpoint_", "", false);
+					if (targetName[0])
+					{
+						new Handle:hButtStallion = INVALID_HANDLE;
+						if (!GetTrieValue(hPageTrie, targetName, hButtStallion))
+						{
+							hButtStallion = CreateArray();
+							SetTrieValue(hPageTrie, targetName, hButtStallion);
+						}
+						
+						new iIndex = FindValueInArray(hArray, hButtStallion);
+						if (iIndex == -1)
+						{
+							iIndex = PushArrayCell(hArray, hButtStallion);
+						}
+						
+						PushArrayCell(hButtStallion, ent);
+						SetArrayCell(hArray, iIndex, true, 1);
+					}
+					else
+					{
+						new iIndex = PushArrayCell(hArray, ent);
+						SetArrayCell(hArray, iIndex, false, 1);
+					}
+				}
+				else
+				{
+					new iIndex = PushArrayCell(hArray, ent);
+					SetArrayCell(hArray, iIndex, false, 1);
+				}
+			}
+			else if (!StrContains(targetName, "sf2_logic_escape", false))
+			{
+				g_bRoundHasEscapeObjective = true;
+			}
+			else if (!StrContains(targetName, "sf2_infiniteflashlight", false))
+			{
+				g_bRoundInfiniteFlashlight = true;
+			}
+			else if (!StrContains(targetName, "sf2_infiniteblink", false))
+			{
+				g_bRoundInfiniteBlink = true;
+			}
+			else if (!StrContains(targetName, "sf2_infinitesprint", false))
+			{
+				g_bRoundInfiniteSprint = true;
+			}
+			else if (!StrContains(targetName, "sf2_time_limit_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_time_limit_", "", false);
+				g_iRoundTimeLimit = StringToInt(targetName);
+				
+				LogSF2Message("Found sf2_time_limit entity, set time limit to %d", g_iRoundTimeLimit);
+			}
+			else if (!StrContains(targetName, "sf2_escape_time_limit_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_escape_time_limit_", "", false);
+				g_iRoundEscapeTimeLimit = StringToInt(targetName);
+				
+				LogSF2Message("Found sf2_escape_time_limit entity, set escape time limit to %d", g_iRoundEscapeTimeLimit);
+			}
+			else if (!StrContains(targetName, "sf2_time_gain_from_page_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_time_gain_from_page_", "", false);
+				g_iRoundTimeGainFromPage = StringToInt(targetName);
+				
+				LogSF2Message("Found sf2_time_gain_from_page entity, set time gain to %d", g_iRoundTimeGainFromPage);
+			}
+			else if (g_iRoundActiveCount == 1 && (!StrContains(targetName, "sf2_maxplayers_", false)))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_maxplayers_", "", false);
+				SetConVarInt(g_cvMaxPlayers, StringToInt(targetName));
+				
+				LogSF2Message("Found sf2_maxplayers entity, set maxplayers to %d", StringToInt(targetName));
+			}
+			else if (!StrContains(targetName, "sf2_boss_override_", false))
+			{
+				ReplaceString(targetName, sizeof(targetName), "sf2_boss_override_", "", false);
+				SetConVarString(g_cvBossProfileOverride, targetName);
+				
+				LogSF2Message("Found sf2_boss_override entity, set boss profile override to %s", targetName);
+			}
+		}
+	}
+	
+	// Get a reference entity, if any.
+	
+	ent = -1;
+	while ((ent = FindEntityByClassname(ent, "prop_dynamic")) != -1)
+	{
+		if (g_bPageRef) break;
+	
+		GetEntPropString(ent, Prop_Data, "m_iName", targetName, sizeof(targetName));
+		if (targetName[0])
+		{
+			if (StrEqual(targetName, "sf2_page_model", false))
+			{
+				g_bPageRef = true;
+				GetEntPropString(ent, Prop_Data, "m_ModelName", g_strPageRefModel, sizeof(g_strPageRefModel));
+				g_flPageRefModelScale = 1.0;
+			}
+		}
+	}
+	
+	new iPageCount = GetArraySize(hArray);
+	if (iPageCount)
+	{
+		SortADTArray(hArray, Sort_Random, Sort_Integer);
+		
+		decl Float:vecPos[3], Float:vecAng[3], Float:vecDir[3];
+		decl page;
+		ent = -1;
+		
+		for (new i = 0; i < iPageCount && (i + 1) <= g_iPageMax; i++)
+		{
+			if (bool:GetArrayCell(hArray, i, 1))
+			{
+				new Handle:hButtStallion = Handle:GetArrayCell(hArray, i);
+				ent = GetArrayCell(hButtStallion, GetRandomInt(0, GetArraySize(hButtStallion) - 1));
+			}
+			else
+			{
+				ent = GetArrayCell(hArray, i);
+			}
+			
+			GetEntPropVector(ent, Prop_Data, "m_vecAbsOrigin", vecPos);
+			GetEntPropVector(ent, Prop_Data, "m_angAbsRotation", vecAng);
+			GetAngleVectors(vecAng, vecDir, NULL_VECTOR, NULL_VECTOR);
+			NormalizeVector(vecDir, vecDir);
+			ScaleVector(vecDir, 1.0);
+			
+			page = CreateEntityByName("prop_dynamic_override");
+			if (page != -1)
+			{
+				TeleportEntity(page, vecPos, vecAng, NULL_VECTOR);
+				DispatchKeyValue(page, "targetname", "sf2_page");
+				
+				if (g_bPageRef)
+				{
+					SetEntityModel(page, g_strPageRefModel);
+				}
+				else
+				{
+					SetEntityModel(page, PAGE_MODEL);
+				}
+				
+				DispatchKeyValue(page, "solid", "2");
+				DispatchSpawn(page);
+				ActivateEntity(page);
+				SetVariantInt(i);
+				AcceptEntityInput(page, "Skin");
+				AcceptEntityInput(page, "EnableCollision");
+				
+				if (g_bPageRef)
+				{
+					SetEntPropFloat(page, Prop_Send, "m_flModelScale", g_flPageRefModelScale);
+				}
+				else
+				{
+					SetEntPropFloat(page, Prop_Send, "m_flModelScale", PAGE_MODELSCALE);
+				}
+				
+				SDKHook(page, SDKHook_OnTakeDamage, Hook_PageOnTakeDamage);
+				SDKHook(page, SDKHook_SetTransmit, Hook_SlenderObjectSetTransmit);
+			}
+		}
+		
+		// Safely remove all handles.
+		for (new i = 0, iSize = GetArraySize(hArray); i < iSize; i++)
+		{
+			if (bool:GetArrayCell(hArray, i, 1))
+			{
+				CloseHandle(Handle:GetArrayCell(hArray, i));
+			}
+		}
+	
+		Call_StartForward(fOnPagesSpawned);
+		Call_Finish();
+	}
+	
+	CloseHandle(hPageTrie);
+	CloseHandle(hArray);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeMapEntities()");
+#endif
+}
+
+static HandleSpecialRoundState()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleSpecialRoundState()");
+#endif
+	
+	new bool:bOld = g_bSpecialRound;
+	new bool:bContinuousOld = g_bSpecialRoundContinuous;
+	g_bSpecialRound = false;
+	g_bSpecialRoundNew = false;
+	g_bSpecialRoundContinuous = false;
+	
+	new bool:bForceNew = false;
+	
+	if (bOld)
+	{
+		if (bContinuousOld)
+		{
+			// Check if there are players who haven't played the special round yet.
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || !IsClientParticipating(i))
+				{
+					g_bPlayerPlayedSpecialRound[i] = true;
+					continue;
+				}
+				
+				if (!g_bPlayerPlayedSpecialRound[i])
+				{
+					// Someone didn't get to play this yet. Continue the special round.
+					g_bSpecialRound = true;
+					g_bSpecialRoundContinuous = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	new iRoundInterval = GetConVarInt(g_cvSpecialRoundInterval);
+	
+	if (iRoundInterval > 0 && g_iSpecialRoundCount >= iRoundInterval)
+	{
+		g_bSpecialRound = true;
+		bForceNew = true;
+	}
+	
+	// Do special round force override and reset it.
+	if (GetConVarInt(g_cvSpecialRoundForce) >= 0)
+	{
+		g_bSpecialRound = GetConVarBool(g_cvSpecialRoundForce);
+		SetConVarInt(g_cvSpecialRoundForce, -1);
+	}
+	
+	if (g_bSpecialRound)
+	{
+		if (bForceNew || !bOld || !bContinuousOld)
+		{
+			g_bSpecialRoundNew = true;
+		}
+		
+		if (g_bSpecialRoundNew)
+		{
+			if (GetConVarInt(g_cvSpecialRoundBehavior) == 1)
+			{
+				g_bSpecialRoundContinuous = true;
+			}
+			else
+			{
+				// New special round, but it's not continuous.
+				g_bSpecialRoundContinuous = false;
+			}
+		}
+	}
+	else
+	{
+		g_bSpecialRoundContinuous = false;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleSpecialRoundState() -> g_bSpecialRound = %d (count = %d, new = %d, continuous = %d)", g_bSpecialRound, g_iSpecialRoundCount, g_bSpecialRoundNew, g_bSpecialRoundContinuous);
+#endif
+}
+
+bool:IsNewBossRoundRunning()
+{
+	return g_bNewBossRound;
+}
+
+/**
+ *	Returns an array which contains all the profile names valid to be chosen for a new boss round.
+ */
+static Handle:GetNewBossRoundProfileList()
+{
+	new Handle:hBossList = CloneArray(GetSelectableBossProfileList());
+	
+	if (GetArraySize(hBossList) > 0)
+	{
+		decl String:sMainBoss[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetConVarString(g_cvBossMain, sMainBoss, sizeof(sMainBoss));
+		
+		new index = FindStringInArray(hBossList, sMainBoss);
+		if (index != -1)
+		{
+			// Main boss exists; remove him from the list.
+			RemoveFromArray(hBossList, index);
+		}
+		else
+		{
+			// Main boss doesn't exist; remove the first boss from the list.
+			RemoveFromArray(hBossList, 0);
+		}
+	}
+	
+	return hBossList;
+}
+
+static HandleNewBossRoundState()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START HandleNewBossRoundState()");
+#endif
+	
+	new bool:bOld = g_bNewBossRound;
+	new bool:bContinuousOld = g_bNewBossRoundContinuous;
+	g_bNewBossRound = false;
+	g_bNewBossRoundNew = false;
+	g_bNewBossRoundContinuous = false;
+	
+	new bool:bForceNew = false;
+	
+	if (bOld)
+	{
+		if (bContinuousOld)
+		{
+			// Check if there are players who haven't played the boss round yet.
+			for (new i = 1; i <= MaxClients; i++)
+			{
+				if (!IsClientInGame(i) || !IsClientParticipating(i))
+				{
+					g_bPlayerPlayedNewBossRound[i] = true;
+					continue;
+				}
+				
+				if (!g_bPlayerPlayedNewBossRound[i])
+				{
+					// Someone didn't get to play this yet. Continue the boss round.
+					g_bNewBossRound = true;
+					g_bNewBossRoundContinuous = true;
+					break;
+				}
+			}
+		}
+	}
+	
+	// Don't force a new special round while a continuous round is going on.
+	if (!g_bNewBossRoundContinuous)
+	{
+		new iRoundInterval = GetConVarInt(g_cvNewBossRoundInterval);
+		
+		if (/*iRoundInterval > 0 &&*/ iRoundInterval <= 0 || g_iNewBossRoundCount >= iRoundInterval)
+		{
+			g_bNewBossRound = true;
+			bForceNew = true;
+		}
+	}
+	
+	// Do boss round force override and reset it.
+	if (GetConVarInt(g_cvNewBossRoundForce) >= 0)
+	{
+		g_bNewBossRound = GetConVarBool(g_cvNewBossRoundForce);
+		SetConVarInt(g_cvNewBossRoundForce, -1);
+	}
+	
+	// Check if we have enough bosses.
+	if (g_bNewBossRound)
+	{
+		new Handle:hBossList = GetNewBossRoundProfileList();
+	
+		if (GetArraySize(hBossList) < 1)
+		{
+			g_bNewBossRound = false; // Not enough bosses.
+		}
+		
+		CloseHandle(hBossList);
+	}
+	
+	if (g_bNewBossRound)
+	{
+		if (bForceNew || !bOld || !bContinuousOld)
+		{
+			g_bNewBossRoundNew = true;
+		}
+		
+		if (g_bNewBossRoundNew)
+		{
+			if (GetConVarInt(g_cvNewBossRoundBehavior) == 1)
+			{
+				g_bNewBossRoundContinuous = true;
+			}
+			else
+			{
+				// New "new boss round", but it's not continuous.
+				g_bNewBossRoundContinuous = false;
+			}
+		}
+	}
+	else
+	{
+		g_bNewBossRoundContinuous = false;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END HandleNewBossRoundState() -> g_bNewBossRound = %d (count = %d, new = %d, continuous = %d)", g_bNewBossRound, g_iNewBossRoundCount, g_bNewBossRoundNew, g_bNewBossRoundContinuous);
+#endif
+}
+
+/**
+ *	Returns the amount of players that are in game and currently not eliminated.
+ */
+stock GetActivePlayerCount()
+{
+	new count = 0;
+
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i) || !IsClientParticipating(i)) continue;
+		
+		if (!g_bPlayerEliminated[i])
+		{
+			count++;
+		}
+	}
+	
+	return count;
+}
+
+static SelectStartingBossesForRound()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START SelectStartingBossesForRound()");
+#endif
+
+	new Handle:hSelectableBossList = GetSelectableBossProfileList();
+
+	// Select which boss profile to use.
+	decl String:sProfileOverride[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetConVarString(g_cvBossProfileOverride, sProfileOverride, sizeof(sProfileOverride));
+	
+	if (strlen(sProfileOverride) > 0 && IsProfileValid(sProfileOverride))
+	{
+		// Pick the overridden boss.
+		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfileOverride);
+		SetConVarString(g_cvBossProfileOverride, "");
+	}
+	else if (g_bNewBossRound)
+	{
+		if (g_bNewBossRoundNew)
+		{
+			new Handle:hBossList = GetNewBossRoundProfileList();
+		
+			GetArrayString(hBossList, GetRandomInt(0, GetArraySize(hBossList) - 1), g_strNewBossRoundProfile, sizeof(g_strNewBossRoundProfile));
+		
+			CloseHandle(hBossList);
+		}
+		
+		strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), g_strNewBossRoundProfile);
+	}
+	else
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		GetConVarString(g_cvBossMain, sProfile, sizeof(sProfile));
+		
+		if (strlen(sProfile) > 0 && IsProfileValid(sProfile))
+		{
+			strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), sProfile);
+		}
+		else
+		{
+			if (GetArraySize(hSelectableBossList) > 0)
+			{
+				// Pick the first boss in our array if the main boss doesn't exist.
+				GetArrayString(hSelectableBossList, 0, g_strRoundBossProfile, sizeof(g_strRoundBossProfile));
+			}
+			else
+			{
+				// No bosses to pick. What?
+				strcopy(g_strRoundBossProfile, sizeof(g_strRoundBossProfile), "");
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END SelectStartingBossesForRound() -> boss: %s", g_strRoundBossProfile);
+#endif
+}
+
+static GetRoundIntroParameters()
+{
+	g_iRoundIntroFadeColor[0] = 0;
+	g_iRoundIntroFadeColor[1] = 0;
+	g_iRoundIntroFadeColor[2] = 0;
+	g_iRoundIntroFadeColor[3] = 255;
+	
+	g_flRoundIntroFadeHoldTime = GetConVarFloat(g_cvIntroDefaultHoldTime);
+	g_flRoundIntroFadeDuration = GetConVarFloat(g_cvIntroDefaultFadeTime);
+	
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "env_fade")) != -1)
+	{
+		decl String:sName[32];
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		if (StrEqual(sName, "sf2_intro_fade", false))
+		{
+			new iColorOffset = FindSendPropOffs("CBaseEntity", "m_clrRender");
+			if (iColorOffset != -1)
+			{
+				g_iRoundIntroFadeColor[0] = GetEntData(ent, iColorOffset, 1);
+				g_iRoundIntroFadeColor[1] = GetEntData(ent, iColorOffset + 1, 1);
+				g_iRoundIntroFadeColor[2] = GetEntData(ent, iColorOffset + 2, 1);
+				g_iRoundIntroFadeColor[3] = GetEntData(ent, iColorOffset + 3, 1);
+			}
+			
+			g_flRoundIntroFadeHoldTime = GetEntPropFloat(ent, Prop_Data, "m_HoldTime");
+			g_flRoundIntroFadeDuration = GetEntPropFloat(ent, Prop_Data, "m_Duration");
+			
+			break;
+		}
+	}
+	
+	// Get the intro music.
+	strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), SF2_INTRO_DEFAULT_MUSIC);
+	
+	ent = -1;
+	while ((ent = FindEntityByClassname(ent, "ambient_generic")) != -1)
+	{
+		decl String:sName[64];
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		
+		if (StrEqual(sName, "sf2_intro_music", false))
+		{
+			decl String:sSongPath[PLATFORM_MAX_PATH];
+			GetEntPropString(ent, Prop_Data, "m_iszSound", sSongPath, sizeof(sSongPath));
+			
+			if (strlen(sSongPath) == 0)
+			{
+				LogError("Found sf2_intro_music entity, but it has no sound path specified! Default intro music will be used instead.");
+			}
+			else
+			{
+				strcopy(g_strRoundIntroMusic, sizeof(g_strRoundIntroMusic), sSongPath);
+			}
+			
+			break;
+		}
+	}
+}
+
+static GetRoundEscapeParameters()
+{
+	g_iRoundEscapePointEntity = INVALID_ENT_REFERENCE;
+	
+	decl String:sName[64];
+	new ent = -1;
+	while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+	{
+		GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+		if (!StrContains(sName, "sf2_escape_spawnpoint", false))
+		{
+			g_iRoundEscapePointEntity = EntIndexToEntRef(ent);
+			break;
+		}
+	}
+}
+
+InitializeNewGame()
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("START InitializeNewGame()");
+#endif
+	
+	GetRoundIntroParameters();
+	GetRoundEscapeParameters();
+	
+	// Choose round state.
+	if (GetConVarBool(g_cvIntroEnabled))
+	{
+		// Set the round state to the intro stage.
+		SetRoundState(SF2RoundState_Intro);
+	}
+	else
+	{
+		SetRoundState(SF2RoundState_Active);
+	}
+	
+	if (g_iRoundActiveCount == 1)
+	{
+		SetConVarString(g_cvBossProfileOverride, "");
+	}
+	
+	HandleSpecialRoundState();
+	
+	// Was a new special round initialized?
+	if (g_bSpecialRound)
+	{
+		if (g_bSpecialRoundNew)
+		{
+			// Reset round count.
+			g_iSpecialRoundCount = 1;
+			
+			if (g_bSpecialRoundContinuous)
+			{
+				// It's the start of a continuous special round.
+			
+				// Initialize all players' values.
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || !IsClientParticipating(i))
+					{
+						g_bPlayerPlayedSpecialRound[i] = true;
+						continue;
+					}
+					
+					g_bPlayerPlayedSpecialRound[i] = false;
+				}
+			}
+			
+			SpecialRoundCycleStart();
+		}
+		else
+		{
+			SpecialRoundStart();
+			
+			if (g_bSpecialRoundContinuous)
+			{
+				// Display the current special round going on to late players.
+				CreateTimer(3.0, Timer_DisplaySpecialRound, _, TIMER_FLAG_NO_MAPCHANGE);
+			}
+		}
+	}
+	else
+	{
+		g_iSpecialRoundCount++;
+	
+		SpecialRoundReset();
+	}
+	
+	// Determine boss round state.
+	HandleNewBossRoundState();
+	
+	if (g_bNewBossRound)
+	{
+		if (g_bNewBossRoundNew)
+		{
+			// Reset round count;
+			g_iNewBossRoundCount = 1;
+			
+			if (g_bNewBossRoundContinuous)
+			{
+				// It's the start of a continuous "new boss round".
+			
+				// Initialize all players' values.
+				for (new i = 1; i <= MaxClients; i++)
+				{
+					if (!IsClientInGame(i) || !IsClientParticipating(i))
+					{
+						g_bPlayerPlayedNewBossRound[i] = true;
+						continue;
+					}
+					
+					g_bPlayerPlayedNewBossRound[i] = false;
+				}
+			}
+		}
+	}
+	else
+	{
+		g_iNewBossRoundCount++;
+	}
+	
+	InitializeMapEntities();
+	
+	// Initialize pages and entities.
+	GetPageMusicRanges();
+	
+	SelectStartingBossesForRound();
+	
+	ForceInNextPlayersInQueue(GetMaxPlayersForRound());
+	
+	// Respawn all players, if needed.
+	for (new i = 1; i <= MaxClients; i++)
+	{
+			if (IsClientParticipating(i))
+			{
+				if (!HandlePlayerTeam(i))
+				{
+				if (!g_bPlayerEliminated[i])
+				{
+					// Players currently in the "game" still have to be respawned.
+					TF2_RespawnPlayer(i);
+				}
+			}
+		}
+	}
+	
+	if (GetRoundState() == SF2RoundState_Intro)
+	{
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i)) continue;
+			
+			if (!g_bPlayerEliminated[i])
+			{
+				if (!IsFakeClient(i))
+				{
+					// Currently in intro state, play intro music.
+					g_hPlayerIntroMusicTimer[i] = CreateTimer(0.5, Timer_PlayIntroMusicToPlayer, GetClientUserId(i), TIMER_FLAG_NO_MAPCHANGE);
+				}
+				else
+				{
+					g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
+				}
+			}
+			else
+			{
+				g_hPlayerIntroMusicTimer[i] = INVALID_HANDLE;
+			}
+		}
+	}
+	else
+	{
+		// Spawn the boss!
+		SelectProfile(0, g_strRoundBossProfile);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("END InitializeNewGame()");
+#endif
+}
+
+public Action:Timer_PlayIntroMusicToPlayer(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerIntroMusicTimer[client]) return;
+	
+	g_hPlayerIntroMusicTimer[client] = INVALID_HANDLE;
+	
+	EmitSoundToClient(client, g_strRoundIntroMusic, _, MUSIC_CHAN, SNDLEVEL_NONE);
+}
+
+public Action:Timer_IntroTextSequence(Handle:timer)
+{
+	if (!g_bEnabled) return;
+	if (g_hRoundIntroTextTimer != timer) return;
+	
+	new Float:flDuration = 0.0;
+	
+	if (g_iRoundIntroText != 0)
+	{
+		new bool:bFoundGameText = false;
+		
+		new iClients[MAXPLAYERS + 1];
+		new iClientsNum;
+		
+		for (new i = 1; i <= MaxClients; i++)
+		{
+			if (!IsClientInGame(i) || g_bPlayerEliminated[i]) continue;
+			
+			iClients[iClientsNum] = i;
+			iClientsNum++;
+		}
+		
+		if (!g_bRoundIntroTextDefault)
+		{
+			decl String:sTargetname[64];
+			Format(sTargetname, sizeof(sTargetname), "sf2_intro_text_%d", g_iRoundIntroText);
+		
+			new iGameText = FindEntityByTargetname(sTargetname, "game_text");
+			if (iGameText && iGameText != INVALID_ENT_REFERENCE)
+			{
+				bFoundGameText = true;
+				flDuration = GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeinTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.fadeoutTime") + GetEntPropFloat(iGameText, Prop_Data, "m_textParms.holdTime");
+				
+				decl String:sMessage[512];
+				GetEntPropString(iGameText, Prop_Data, "m_iszMessage", sMessage, sizeof(sMessage));
+				ShowHudTextUsingTextEntity(iClients, iClientsNum, iGameText, g_hHudSync, sMessage);
+			}
+		}
+		else
+		{
+			if (g_iRoundIntroText == 2)
+			{
+				bFoundGameText = false;
+				
+				decl String:sMessage[64];
+				GetCurrentMap(sMessage, sizeof(sMessage));
+				
+				for (new i = 0; i < iClientsNum; i++)
+				{
+					ClientShowMainMessage(iClients[i], sMessage, 1);
+				}
+			}
+		}
+		
+		if (g_iRoundIntroText == 1 && !bFoundGameText)
+		{
+			// Use default intro sequence. Eugh.
+			g_bRoundIntroTextDefault = true;
+			flDuration = GetConVarFloat(g_cvIntroDefaultHoldTime) / 2.0;
+			
+			for (new i = 0; i < iClientsNum; i++)
+			{
+				EmitSoundToClient(iClients[i], SF2_INTRO_DEFAULT_MUSIC, _, MUSIC_CHAN, SNDLEVEL_NONE);
+			}
+		}
+		else
+		{
+			if (!bFoundGameText) return; // done with sequence; don't check anymore.
+		}
+	}
+	
+	g_iRoundIntroText++;
+	g_hRoundIntroTextTimer = CreateTimer(flDuration, Timer_IntroTextSequence, _, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_ActivateRoundFromIntro(Handle:timer)
+{
+	if (!g_bEnabled) return;
+	if (g_hRoundIntroTimer != timer) return;
+	
+	// Obviously we don't want to spawn the boss when g_strRoundBossProfile isn't set yet.
+	SetRoundState(SF2RoundState_Active);
+	
+	// Spawn the boss!
+	SelectProfile(0, g_strRoundBossProfile);
+}
+
+CheckRoundWinConditions()
+{
+	if (IsRoundInWarmup() || IsRoundEnding()) return;
+	
+	new iTotalCount = 0;
+	new iAliveCount = 0;
+	new iEscapedCount = 0;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		iTotalCount++;
+		if (!g_bPlayerEliminated[i] && !IsClientInDeathCam(i)) 
+		{
+			iAliveCount++;
+			if (DidClientEscape(i)) iEscapedCount++;
+		}
+	}
+	
+	if (iAliveCount == 0)
+	{
+		ForceTeamWin(_:TFTeam_Blue);
+	}
+	else
+	{
+		if (g_bRoundHasEscapeObjective)
+		{
+			if (iEscapedCount == iAliveCount)
+			{
+				ForceTeamWin(_:TFTeam_Red);
+			}
+		}
+		else
+		{
+			if (g_iPageMax > 0 && g_iPageCount == g_iPageMax)
+			{
+				ForceTeamWin(_:TFTeam_Red);
+			}
+		}
+	}
+}
+
+//	==========================================================
+//	API
+//	==========================================================
+
+public Native_IsRunning(Handle:plugin, numParams)
+{
+	return g_bEnabled;
+}
+
+public Native_GetCurrentDifficulty(Handle:plugin, numParams)
+{
+	return GetConVarInt(g_cvDifficulty);
+}
+
+public Native_GetDifficultyModifier(Handle:plugin, numParams)
+{
+	new iDifficulty = GetNativeCell(1);
+	if (iDifficulty < Difficulty_Easy || iDifficulty >= Difficulty_Max)
+	{
+		LogError("Difficulty parameter can only be from %d to %d!", Difficulty_Easy, Difficulty_Max - 1);
+		return _:1.0;
+	}
+	
+	switch (iDifficulty)
+	{
+		case Difficulty_Easy: return _:DIFFICULTY_EASY;
+		case Difficulty_Hard: return _:DIFFICULTY_HARD;
+		case Difficulty_Insane: return _:DIFFICULTY_INSANE;
+	}
+	
+	return _:DIFFICULTY_NORMAL;
+}
+
+public Native_IsClientEliminated(Handle:plugin, numParams)
+{
+	return g_bPlayerEliminated[GetNativeCell(1)];
+}
+
+public Native_IsClientInGhostMode(Handle:plugin, numParams)
+{
+	return IsClientInGhostMode(GetNativeCell(1));
+}
+
+public Native_IsClientProxy(Handle:plugin, numParams)
+{
+	return g_bPlayerProxy[GetNativeCell(1)];
+}
+
+public Native_GetClientBlinkCount(Handle:plugin, numParams)
+{
+	return ClientGetBlinkCount(GetNativeCell(1));
+}
+
+public Native_GetClientProxyMaster(Handle:plugin, numParams)
+{
+	return NPCGetFromUniqueID(g_iPlayerProxyMaster[GetNativeCell(1)]);
+}
+
+public Native_GetClientProxyControlAmount(Handle:plugin, numParams)
+{
+	return g_iPlayerProxyControl[GetNativeCell(1)];
+}
+
+public Native_GetClientProxyControlRate(Handle:plugin, numParams)
+{
+	return _:g_flPlayerProxyControlRate[GetNativeCell(1)];
+}
+
+public Native_SetClientProxyMaster(Handle:plugin, numParams)
+{
+	g_iPlayerProxyMaster[GetNativeCell(1)] = NPCGetUniqueID(GetNativeCell(2));
+}
+
+public Native_SetClientProxyControlAmount(Handle:plugin, numParams)
+{
+	g_iPlayerProxyControl[GetNativeCell(1)] = GetNativeCell(2);
+}
+
+public Native_SetClientProxyControlRate(Handle:plugin, numParams)
+{
+	g_flPlayerProxyControlRate[GetNativeCell(1)] = Float:GetNativeCell(2);
+}
+
+public Native_IsClientLookingAtBoss(Handle:plugin, numParams)
+{
+	return g_bPlayerSeesSlender[GetNativeCell(1)][GetNativeCell(2)];
+}
+
+public Native_CollectAsPage(Handle:plugin, numParams)
+{
+	CollectPage(GetNativeCell(1), GetNativeCell(2));
+}
+
+public Native_GetMaxBosses(Handle:plugin, numParams)
+{
+	return MAX_BOSSES;
+}
+
+public Native_EntIndexToBossIndex(Handle:plugin, numParams)
+{
+	return NPCGetFromEntIndex(GetNativeCell(1));
+}
+
+public Native_BossIndexToEntIndex(Handle:plugin, numParams)
+{
+	return NPCGetEntIndex(GetNativeCell(1));
+}
+
+public Native_BossIDToBossIndex(Handle:plugin, numParams)
+{
+	return NPCGetFromUniqueID(GetNativeCell(1));
+}
+
+public Native_BossIndexToBossID(Handle:plugin, numParams)
+{
+	return NPCGetUniqueID(GetNativeCell(1));
+}
+
+public Native_GetBossName(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(GetNativeCell(1), sProfile, sizeof(sProfile));
+	
+	SetNativeString(2, sProfile, GetNativeCell(3));
+}
+
+public Native_GetBossModelEntity(Handle:plugin, numParams)
+{
+	return EntRefToEntIndex(g_iSlenderModel[GetNativeCell(1)]);
+}
+
+public Native_GetBossTarget(Handle:plugin, numParams)
+{
+	return EntRefToEntIndex(g_iSlenderTarget[GetNativeCell(1)]);
+}
+
+public Native_GetBossMaster(Handle:plugin, numParams)
+{
+	return g_iSlenderCopyMaster[GetNativeCell(1)];
+}
+
+public Native_GetBossState(Handle:plugin, numParams)
+{
+	return g_iSlenderState[GetNativeCell(1)];
+}
+
+public Native_IsBossProfileValid(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+	
+	return IsProfileValid(sProfile);
+}
+
+public Native_GetBossProfileNum(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+	
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	return GetProfileNum(sProfile, sKeyValue, GetNativeCell(3));
+}
+
+public Native_GetBossProfileFloat(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	return _:GetProfileFloat(sProfile, sKeyValue, Float:GetNativeCell(3));
+}
+
+public Native_GetBossProfileString(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	new iResultLen = GetNativeCell(4);
+	decl String:sResult[iResultLen];
+	
+	decl String:sDefaultValue[512];
+	GetNativeString(5, sDefaultValue, sizeof(sDefaultValue));
+	
+	new bool:bSuccess = GetProfileString(sProfile, sKeyValue, sResult, iResultLen, sDefaultValue);
+	
+	SetNativeString(3, sResult, iResultLen);
+	return bSuccess;
+}
+
+public Native_GetBossProfileVector(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	decl Float:flResult[3];
+	decl Float:flDefaultValue[3];
+	GetNativeArray(4, flDefaultValue, 3);
+	
+	new bool:bSuccess = GetProfileVector(sProfile, sKeyValue, flResult, flDefaultValue);
+	
+	SetNativeArray(3, flResult, 3);
+	return bSuccess;
+}
+
+public Native_GetRandomStringFromBossProfile(Handle:plugin, numParams)
+{
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	GetNativeString(1, sProfile, SF2_MAX_PROFILE_NAME_LENGTH);
+
+	decl String:sKeyValue[256];
+	GetNativeString(2, sKeyValue, sizeof(sKeyValue));
+	
+	new iBufferLen = GetNativeCell(4);
+	decl String:sBuffer[iBufferLen];
+	
+	new iIndex = GetNativeCell(5);
+	
+	new bool:bSuccess = GetRandomStringFromProfile(sProfile, sKeyValue, sBuffer, iBufferLen, iIndex);
+	SetNativeString(3, sBuffer, iBufferLen);
+	return bSuccess;
 }
\ No newline at end of file
diff --git a/addons/sourcemod/scripting/rytp_horror/client.sp b/addons/sourcemod/scripting/rytp_horror/client.sp
index f3626f5..4e231e5 100644
--- a/addons/sourcemod/scripting/rytp_horror/client.sp
+++ b/addons/sourcemod/scripting/rytp_horror/client.sp
@@ -1,5888 +1,5925 @@
-#if defined _sf2_client_included
- #endinput
-#endif
-#define _sf2_client_included
-
-#define GHOST_MODEL "models/props_halloween/ghost_no_hat.mdl"
-#define SF2_OVERLAY_DEFAULT "overlays/rytp_horror/grain"
-#define SF2_OVERLAY_DEFAULT_NO_FILMGRAIN "overlays/rytp_horror/grain" // TODO: Update material?
-#define SF2_OVERLAY_GHOST "overlays/rytp_horror/grain"
-
-#define SF2_FLASHLIGHT_WIDTH 512.0 // How wide the player's Flashlight should be in world units.
-#define SF2_FLASHLIGHT_LENGTH 1024.0 // How far the player's Flashlight can reach in world units.
-#define SF2_FLASHLIGHT_BRIGHTNESS 0 // Intensity of the players' Flashlight.
-#define SF2_FLASHLIGHT_DRAIN_RATE 0.65 // How long (in seconds) each bar on the player's Flashlight meter lasts.
-#define SF2_FLASHLIGHT_RECHARGE_RATE 0.68 // How long (in seconds) it takes each bar on the player's Flashlight meter to recharge.
-#define SF2_FLASHLIGHT_FLICKERAT 0.25 // The percentage of the Flashlight battery where the Flashlight will start to blink.
-#define SF2_FLASHLIGHT_ENABLEAT 0.3 // The percentage of the Flashlight battery where the Flashlight will be able to be used again (if the player shortens out the Flashlight from excessive use).
-#define SF2_FLASHLIGHT_COOLDOWN 0.4 // How much time players have to wait before being able to switch their flashlight on again after turning it off.
-
-#define SF2_ULTRAVISION_WIDTH 800.0
-#define SF2_ULTRAVISION_LENGTH 800.0
-#define SF2_ULTRAVISION_BRIGHTNESS -4 // Intensity of Ultravision.
-#define SF2_ULTRAVISION_CONE 180.0
-
-#define SF2_PLAYER_BREATH_COOLDOWN_MIN 0.8
-#define SF2_PLAYER_BREATH_COOLDOWN_MAX 2.0
-
-new String:g_strPlayerBreathSounds[][] = 
-{
-	"rytp_horror/player_breath_1.wav"
-};
-
-static String:g_strPlayerLagCompensationWeapons[][] = 
-{
-	"tf_weapon_sniperrifle",
-	"tf_weapon_sniperrifle_decap",
-	"tf_weapon_sniperrifle_classic"
-};
-
-// Deathcam data.
-static g_iPlayerDeathCamBoss[MAXPLAYERS + 1] = { -1, ... };
-static bool:g_bPlayerDeathCam[MAXPLAYERS + 1] = { false, ... };
-static bool:g_bPlayerDeathCamShowOverlay[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerDeathCamEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static g_iPlayerDeathCamEnt2[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static Handle:g_hPlayerDeathCamTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Flashlight data.
-static bool:g_bPlayerFlashlight[MAXPLAYERS + 1] = { false, ... };
-static bool:g_bPlayerFlashlightBroken[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerFlashlightEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static g_iPlayerFlashlightEntAng[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static Float:g_flPlayerFlashlightBatteryLife[MAXPLAYERS + 1] = { 1.0, ... };
-static Handle:g_hPlayerFlashlightBatteryTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static Float:g_flPlayerFlashlightNextInputTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-// Ultravision data.
-static bool:g_bPlayerUltravision[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerUltravisionEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-
-// Sprint data.
-static bool:g_bPlayerSprint[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerSprintPoints[MAXPLAYERS + 1] = { 100, ... };
-static Handle:g_hPlayerSprintTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Blink data.
-static Handle:g_hPlayerBlinkTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static bool:g_bPlayerBlink[MAXPLAYERS + 1] = { false, ... };
-static Float:g_flPlayerBlinkMeter[MAXPLAYERS + 1] = { 0.0, ... };
-static g_iPlayerBlinkCount[MAXPLAYERS + 1] = { 0, ... };
-
-// Breathing data.
-static bool:g_bPlayerBreath[MAXPLAYERS + 1] = { false, ... };
-static Handle:g_hPlayerBreathTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-
-// Interactive glow data.
-static g_iPlayerInteractiveGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static g_iPlayerInteractiveGlowTargetEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-
-// Constant glow data.
-static g_iPlayerConstantGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static bool:g_bPlayerConstantGlowEnabled[MAXPLAYERS + 1] = { false, ... };
-
-// Jumpscare data.
-static g_iPlayerJumpScareBoss[MAXPLAYERS + 1] = { -1, ... };
-static Float:g_flPlayerJumpScareLifeTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-static Float:g_flPlayerScareBoostEndTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-// Anti-camping data.
-static g_iPlayerCampingStrikes[MAXPLAYERS + 1] = { 0, ... };
-static Handle:g_hPlayerCampingTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static Float:g_flPlayerCampingLastPosition[MAXPLAYERS + 1][3];
-static bool:g_bPlayerCampingFirstTime[MAXPLAYERS + 1] = { true, ... };
-
-
-//	==========================================================
-//	GENERAL CLIENT HOOK FUNCTIONS
-//	==========================================================
-
-#define SF2_PLAYER_VIEWBOB_TIMER 10.0
-#define SF2_PLAYER_VIEWBOB_SCALE_X 0.05
-#define SF2_PLAYER_VIEWBOB_SCALE_Y 0.0
-#define SF2_PLAYER_VIEWBOB_SCALE_Z 0.0
-
-
-public MRESReturn:Hook_ClientWantsLagCompensationOnEntity(thisPointer, Handle:hReturn, Handle:hParams)
-{
-	if (!g_bEnabled || IsFakeClient(thisPointer)) return MRES_Ignored;
-	
-	DHookSetReturn(hReturn, true);
-	return MRES_Supercede;
-}
-
-Float:ClientGetScareBoostEndTime(client)
-{
-	return g_flPlayerScareBoostEndTime[client];
-}
-
-ClientSetScareBoostEndTime(client, Float:time)
-{
-	g_flPlayerScareBoostEndTime[client] = time;
-}
-
-public Hook_ClientPreThink(client)
-{
-	if (!g_bEnabled) return;
-	
-	ClientProcessViewAngles(client);
-	ClientProcessVisibility(client);
-	ClientProcessStaticShake(client);
-	ClientProcessFlashlightAngles(client);
-	ClientProcessInteractiveGlow(client);
-	
-	if (IsClientInGhostMode(client))
-	{
-		SetEntPropFloat(client, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0);
-		SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 520.0);
-	}
-	else if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
-	{
-		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
-		{
-			new iRoundState = _:GameRules_GetRoundState();
-			
-			// No double jumping for players in play.
-			SetEntProp(client, Prop_Send, "m_iAirDash", 99999);
-		
-			if (!g_bPlayerProxy[client])
-			{
-				if (iRoundState == 4)
-				{
-					new bool:bDanger = false;
-					
-					if (!bDanger)
-					{
-						decl iState;
-						decl iBossTarget;
-						
-						for (new i = 0; i < MAX_BOSSES; i++)
-						{
-							if (NPCGetUniqueID(i) == -1) continue;
-							
-							if (NPCGetType(i) == SF2BossType_Chaser)
-							{
-								iBossTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
-								iState = g_iSlenderState[i];
-								
-								if ((iState == STATE_CHASE || iState == STATE_ATTACK || iState == STATE_STUN) &&
-									((iBossTarget && iBossTarget != INVALID_ENT_REFERENCE && (iBossTarget == client || ClientGetDistanceFromEntity(client, iBossTarget) < 512.0)) || NPCGetDistanceFromEntity(i, client) < 512.0 || PlayerCanSeeSlender(client, i, false)))
-								{
-									bDanger = true;
-									ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
-									
-									// Induce client stress levels.
-									new Float:flUnComfortZoneDist = 512.0;
-									new Float:flStressScalar = (flUnComfortZoneDist / NPCGetDistanceFromEntity(i, client));
-									ClientAddStress(client, 0.025 * flStressScalar);
-									
-									break;
-								}
-							}
-						}
-					}
-					
-					if (g_flPlayerStaticAmount[client] > 0.4) bDanger = true;
-					if (GetGameTime() < ClientGetScareBoostEndTime(client)) bDanger = true;
-					
-					if (!bDanger)
-					{
-						decl iState;
-						for (new i = 0; i < MAX_BOSSES; i++)
-						{
-							if (NPCGetUniqueID(i) == -1) continue;
-							
-							if (NPCGetType(i) == SF2BossType_Chaser)
-							{
-								if (iState == STATE_ALERT)
-								{
-									if (PlayerCanSeeSlender(client, i))
-									{
-										bDanger = true;
-										ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
-									}
-								}
-							}
-						}
-					}
-					
-					if (!bDanger)
-					{
-						new Float:flCurTime = GetGameTime();
-						new Float:flScareSprintDuration = 3.0;
-						if (TF2_GetPlayerClass(client) == TFClass_DemoMan) flScareSprintDuration *= 1.667;
-						
-						for (new i = 0; i < MAX_BOSSES; i++)
-						{
-							if (NPCGetUniqueID(i) == -1) continue;
-							
-							if ((flCurTime - g_flPlayerScareLastTime[client][i]) <= flScareSprintDuration)
-							{
-								bDanger = true;
-								break;
-							}
-						}
-					}
-					
-					new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
-					new Float:flSprintSpeed = ClientGetDefaultSprintSpeed(client);
-					
-					// Check for weapon speed changes.
-					new iWeapon = INVALID_ENT_REFERENCE;
-					
-					for (new iSlot = 0; iSlot <= 5; iSlot++)
-					{
-						iWeapon = GetPlayerWeaponSlot(client, iSlot);
-						if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
-						
-						new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-						switch (iItemDef)
-						{
-							case 239: // Gloves of Running Urgently
-							{
-								if (GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon") == iWeapon)
-								{
-									flSprintSpeed += (flSprintSpeed * 0.1);
-								}
-							}
-							case 775: // Escape Plan
-							{
-								new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
-								new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
-								new Float:flPercentage = flHealth / flMaxHealth;
-								
-								if (flPercentage < 0.805 && flPercentage >= 0.605) flSprintSpeed += (flSprintSpeed * 0.05);
-								else if (flPercentage < 0.605 && flPercentage >= 0.405) flSprintSpeed += (flSprintSpeed * 0.1);
-								else if (flPercentage < 0.405 && flPercentage >= 0.205) flSprintSpeed += (flSprintSpeed * 0.15);
-								else if (flPercentage < 0.205) flSprintSpeed += (flSprintSpeed * 0.2);
-							}
-						}
-					}
-					
-					// Speed buff?
-					if (TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly))
-					{
-						flWalkSpeed += (flWalkSpeed * 0.08);
-						flSprintSpeed += (flSprintSpeed * 0.08);
-					}
-					
-					if (bDanger)
-					{
-						flWalkSpeed *= 1.33;
-						flSprintSpeed *= 1.33;
-						
-						if (!g_bPlayerHints[client][PlayerHint_Sprint])
-						{
-							ClientShowHint(client, PlayerHint_Sprint);
-						}
-					}
-					
-					new Float:flSprintSpeedSubtract = ((flSprintSpeed - flWalkSpeed) * 0.5);
-					flSprintSpeedSubtract -= flSprintSpeedSubtract * (g_iPlayerSprintPoints[client] != 0 ? (float(g_iPlayerSprintPoints[client]) / 100.0) : 0.0);
-					flSprintSpeed -= flSprintSpeedSubtract;
-					
-					if (IsClientSprinting(client)) 
-					{
-						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flSprintSpeed);
-					}
-					else 
-					{
-						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flWalkSpeed);
-					}
-					
-					if (ClientCanBreath(client) && !g_bPlayerBreath[client])
-					{
-						ClientStartBreathing(client);
-					}
-				}
-			}
-			else
-			{
-				new TFClassType:iClass = TF2_GetPlayerClass(client);
-				new bool:bSpeedup = TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly);
-			
-				switch (iClass)
-				{
-					case TFClass_Scout:
-					{
-						if (iRoundState == 4)
-						{
-							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 405.0);
-							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
-						}
-					}
-					case TFClass_Medic:
-					{
-						if (iRoundState == 4)
-						{
-							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 385.0);
-							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	// Calculate player stress levels.
-	if (GetGameTime() >= g_flPlayerStressNextUpdateTime[client])
-	{
-		//new Float:flPagePercent = g_iPageMax != 0 ? float(g_iPageCount) / float(g_iPageMax) : 0.0;
-		//new Float:flPageCountPercent = g_iPageMax != 0? float(g_iPlayerPageCount[client]) / float(g_iPageMax) : 0.0;
-		
-		g_flPlayerStressNextUpdateTime[client] = GetGameTime() + 0.33;
-		ClientAddStress(client, -0.01);
-		
-#if defined DEBUG
-		SendDebugMessageToPlayer(client, DEBUG_PLAYER_STRESS, 1, "g_flPlayerStress[%d]: %0.1f", client, g_flPlayerStress[client]);
-#endif
-	}
-	
-	// Process screen shake, if enabled.
-	if (g_bPlayerShakeEnabled)
-	{
-		new bool:bDoShake = false;
-		
-		if (IsPlayerAlive(client))
-		{
-			new iStaticMaster = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
-			if (iStaticMaster != -1 && NPCGetFlags(iStaticMaster) & SFF_HASVIEWSHAKE)
-			{
-				bDoShake = true;
-			}
-		}
-		
-		if (bDoShake)
-		{
-			new Float:flPercent = g_flPlayerStaticAmount[client];
-			
-			new Float:flAmplitudeMax = GetConVarFloat(g_cvPlayerShakeAmplitudeMax);
-			new Float:flAmplitude = flAmplitudeMax * flPercent;
-			
-			new Float:flFrequencyMax = GetConVarFloat(g_cvPlayerShakeFrequencyMax);
-			new Float:flFrequency = flFrequencyMax * flPercent;
-			
-			UTIL_ScreenShake(client, flAmplitude, 0.5, flFrequency);
-		}
-	}
-}
-
-public Action:Hook_ClientSetTransmit(client, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (other != client)
-	{
-		if (IsClientInGhostMode(client) && !IsClientInGhostMode(other)) return Plugin_Handled;
-		
-		if (!IsRoundEnding())
-		{
-			// SPECIAL ROUND: Singleplayer
-			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-			{
-				if (!g_bPlayerEliminated[client] && !g_bPlayerEliminated[other] && !DidClientEscape(other)) return Plugin_Handled; 
-			}
-			
-			// pvp
-			if (IsClientInPvP(client) && IsClientInPvP(other)) 
-			{
-				if (TF2_IsPlayerInCondition(client, TFCond_Cloaked) &&
-					!TF2_IsPlayerInCondition(client, TFCond_CloakFlicker) &&
-					!TF2_IsPlayerInCondition(client, TFCond_Jarated) &&
-					!TF2_IsPlayerInCondition(client, TFCond_Milked) &&
-					!TF2_IsPlayerInCondition(client, TFCond_OnFire) &&
-					(GetGameTime() > GetEntPropFloat(client, Prop_Send, "m_flInvisChangeCompleteTime")))
-				{
-					return Plugin_Handled;
-				}
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:TF2_CalcIsAttackCritical(client, weapon, String:sWeaponName[], &bool:result)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if ((IsRoundInWarmup() || IsClientInPvP(client)) && !IsRoundEnding())
-	{
-		if (!GetConVarBool(g_cvPlayerFakeLagCompensation))
-		{
-			new bool:bNeedsManualDamage = false;
-			
-			// Fake lag compensation isn't enabled; check to see if we need to deal damage manually.
-			for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
-			{
-				if (StrEqual(sWeaponName, g_strPlayerLagCompensationWeapons[i], false))
-				{
-					bNeedsManualDamage = true;
-					break;
-				}
-			}
-			
-			if (bNeedsManualDamage)
-			{
-				decl Float:flStartPos[3], Float:flEyeAng[3];
-				GetClientEyePosition(client, flStartPos);
-				GetClientEyeAngles(client, flEyeAng);
-				
-				new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flEyeAng, MASK_SHOT, RayType_Infinite, TraceRayDontHitEntity, client);
-				new iHitEntity = TR_GetEntityIndex(hTrace);
-				new iHitGroup = TR_GetHitGroup(hTrace);
-				CloseHandle(hTrace);
-				
-				if (IsValidClient(iHitEntity))
-				{
-					if (GetClientTeam(iHitEntity) == GetClientTeam(client))
-					{
-						if (IsRoundInWarmup() || IsClientInPvP(iHitEntity))
-						{
-							new Float:flChargedDamage = GetEntPropFloat(weapon, Prop_Send, "m_flChargedDamage");
-							if (flChargedDamage < 50.0) flChargedDamage = 50.0;
-							new iDamageType = DMG_BULLET;
-							
-							if (IsClientCritBoosted(client))
-							{
-								result = true;
-								iDamageType |= DMG_ACID;
-							}
-							else if (iHitGroup == 1)
-							{
-								if (StrEqual(sWeaponName, "tf_weapon_sniperrifle_classic", false))
-								{
-									if (flChargedDamage >= 150.0)
-									{
-										result = true;
-										iDamageType |= DMG_ACID;
-									}
-								}
-								else
-								{
-									if (TF2_IsPlayerInCondition(client, TFCond_Zoomed))
-									{
-										result = true;
-										iDamageType |= DMG_ACID;
-									}
-								}
-							}
-							
-							SDKHooks_TakeDamage(iHitEntity, client, client, flChargedDamage, iDamageType);
-							return Plugin_Changed;
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_ClientOnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (IsRoundInWarmup()) return Plugin_Continue;
-	
-	if (attacker != victim && IsValidClient(attacker))
-	{
-		if (!IsRoundEnding())
-		{
-			if (IsClientInPvP(victim) && IsClientInPvP(attacker))
-			{
-				if (attacker == inflictor)
-				{
-					if (IsValidEdict(weapon))
-					{
-						decl String:sWeaponClass[64];
-						GetEdictClassname(weapon, sWeaponClass, sizeof(sWeaponClass));
-						
-						// Backstab check!
-						if ((StrEqual(sWeaponClass, "tf_weapon_knife", false) || (TF2_GetPlayerClass(attacker) == TFClass_Spy && StrEqual(sWeaponClass, "saxxy", false))) &&
-							(damagecustom != TF_CUSTOM_TAUNT_FENCING))
-						{
-							decl Float:flMyPos[3], Float:flHisPos[3], Float:flMyDirection[3];
-							GetClientAbsOrigin(victim, flMyPos);
-							GetClientAbsOrigin(attacker, flHisPos);
-							GetClientEyeAngles(victim, flMyDirection);
-							GetAngleVectors(flMyDirection, flMyDirection, NULL_VECTOR, NULL_VECTOR);
-							NormalizeVector(flMyDirection, flMyDirection);
-							ScaleVector(flMyDirection, 32.0);
-							AddVectors(flMyDirection, flMyPos, flMyDirection);
-							
-							decl Float:p[3], Float:s[3];
-							MakeVectorFromPoints(flMyPos, flHisPos, p);
-							MakeVectorFromPoints(flMyPos, flMyDirection, s);
-							if (GetVectorDotProduct(p, s) <= 0.0)
-							{
-								damage = float(GetEntProp(victim, Prop_Send, "m_iHealth")) * 2.0;
-								
-								new Handle:hCvar = FindConVar("tf_weapon_criticals");
-								if (hCvar != INVALID_HANDLE && GetConVarBool(hCvar)) damagetype |= DMG_ACID;
-								return Plugin_Changed;
-							}
-						}
-					}
-				}
-			}
-			/*
-			else if (g_bPlayerProxy[victim] || g_bPlayerProxy[attacker])
-			{
-				if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
-				{
-					damage = 0.0;
-					return Plugin_Changed;
-				}
-				
-				if (g_bPlayerProxy[attacker])
-				{
-					new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, victim);
-					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[attacker]);
-					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
-					{
-						if (damagecustom == TF_CUSTOM_TAUNT_GRAND_SLAM ||
-							damagecustom == TF_CUSTOM_TAUNT_FENCING ||
-							damagecustom == TF_CUSTOM_TAUNT_ARROW_STAB ||
-							damagecustom == TF_CUSTOM_TAUNT_GRENADE ||
-							damagecustom == TF_CUSTOM_TAUNT_BARBARIAN_SWING ||
-							damagecustom == TF_CUSTOM_TAUNT_ENGINEER_ARM ||
-							damagecustom == TF_CUSTOM_TAUNT_ARMAGEDDON)
-						{
-							if (damage >= float(iMaxHealth)) damage = float(iMaxHealth) * 0.5;
-							else damage = 0.0;
-						}
-						else if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage.
-						{
-							damage = float(iMaxHealth) * GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy_backstab", 0.25);
-							if (damagetype & DMG_ACID) damage /= 3.0;
-						}
-					
-						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitenemy");
-						if (g_iPlayerProxyControl[attacker] > 100)
-						{
-							g_iPlayerProxyControl[attacker] = 100;
-						}
-						
-						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy", 1.0);
-					}
-					
-					return Plugin_Changed;
-				}
-				else if (g_bPlayerProxy[victim])
-				{
-					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[victim]);
-					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
-					{
-						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitbyenemy");
-						if (g_iPlayerProxyControl[attacker] > 100)
-						{
-							g_iPlayerProxyControl[attacker] = 100;
-						}
-						
-						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_self", 1.0);
-					}
-					
-					return Plugin_Changed;
-				}
-			}
-			*/
-			else
-			{
-				damage = 0.0;
-				return Plugin_Changed;
-			}
-		}
-		else
-		{
-			if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
-			{
-				damage = 0.0;
-				return Plugin_Changed;
-			}
-		}
-		
-		if (IsClientInGhostMode(victim))
-		{
-			damage = 0.0;
-			return Plugin_Changed;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_TEFireBullets(const String:te_name[], const Players[], numClients, Float:delay)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	new client = TE_ReadNum("m_iPlayer") + 1;
-	if (IsValidClient(client))
-	{
-		if (GetConVarBool(g_cvPlayerFakeLagCompensation))
-		{
-			if ((IsRoundInWarmup() || IsClientInPvP(client)))
-			{
-				ClientEnableFakeLagCompensation(client);
-			}
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-ClientResetStatic(client)
-{
-	g_iPlayerStaticMaster[client] = -1;
-	g_hPlayerStaticTimer[client] = INVALID_HANDLE;
-	g_flPlayerStaticIncreaseRate[client] = 0.0;
-	g_flPlayerStaticDecreaseRate[client] = 0.0;
-	g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-	g_flPlayerLastStaticTime[client] = 0.0;
-	g_flPlayerLastStaticVolume[client] = 0.0;
-	g_bPlayerInStaticShake[client] = false;
-	g_iPlayerStaticShakeMaster[client] = -1;
-	g_flPlayerStaticShakeMinVolume[client] = 0.0;
-	g_flPlayerStaticShakeMaxVolume[client] = 0.0;
-	g_flPlayerStaticAmount[client] = 0.0;
-	
-	if (IsClientInGame(client))
-	{
-		if (g_strPlayerStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticSound[client]);
-		if (g_strPlayerLastStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-		if (g_strPlayerStaticShakeSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
-	}
-	
-	strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
-	strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), "");
-	strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
-}
-
-ClientResetHints(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetHints(%d)", client);
-#endif
-
-	for (new i = 0; i < PlayerHint_MaxNum; i++)
-	{
-		g_bPlayerHints[client][i] = false;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetHints(%d)", client);
-#endif
-}
-
-ClientShowHint(client, iHint)
-{
-	g_bPlayerHints[client][iHint] = true;
-	
-	switch (iHint)
-	{
-		case PlayerHint_Sprint: PrintHintText(client, "%T", "SF2 Hint Sprint", client);
-		case PlayerHint_Flashlight: PrintHintText(client, "%T", "SF2 Hint Flashlight", client);
-		case PlayerHint_Blink: PrintHintText(client, "%T", "SF2 Hint Blink", client);
-		case PlayerHint_MainMenu: PrintHintText(client, "%T", "SF2 Hint Main Menu", client);
-	}
-}
-
-bool:DidClientEscape(client)
-{
-	return g_bPlayerEscaped[client];
-}
-
-ClientEscape(client)
-{
-	if (DidClientEscape(client)) return;
-
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("START ClientEscape(%d)", client);
-#endif
-	
-	g_bPlayerEscaped[client] = true;
-	
-	ClientResetBreathing(client);
-	ClientResetSprint(client);
-	ClientResetFlashlight(client);
-	ClientDeactivateUltravision(client);
-	ClientDisableConstantGlow(client);
-	
-	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
-	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
-	
-	HandlePlayerHUD(client);
-	
-	decl String:sName[MAX_NAME_LENGTH];
-	GetClientName(client, sName, sizeof(sName));
-	CPrintToChatAll("%t", "SF2 Player Escaped", sName);
-	
-	CheckRoundWinConditions();
-	
-	Call_StartForward(fOnClientEscape);
-	Call_PushCell(client);
-	Call_Finish();
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("END ClientEscape(%d)", client);
-#endif
-}
-
-public Action:Timer_TeleportPlayerToEscapePoint(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (!DidClientEscape(client)) return;
-	
-	if (IsPlayerAlive(client))
-	{
-		TeleportClientToEscapePoint(client);
-	}
-}
-
-stock Float:ClientGetDistanceFromEntity(client, entity)
-{
-	decl Float:flStartPos[3], Float:flEndPos[3];
-	GetClientAbsOrigin(client, flStartPos);
-	GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", flEndPos);
-	return GetVectorDistance(flStartPos, flEndPos);
-}
-
-ClientEnableFakeLagCompensation(client)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client) || g_bPlayerLagCompensation[client]) return;
-	
-	// Can only enable lag compensation if we're in either of these two teams only.
-	new iMyTeam = GetClientTeam(client);
-	if (iMyTeam != _:TFTeam_Red && iMyTeam != _:TFTeam_Blue) return;
-	
-	// Can only enable lag compensation if there are other active teammates around. This is to prevent spontaneous round restarting.
-	new iCount;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (i == client) continue;
-		
-		if (IsValidClient(i) && IsPlayerAlive(i))
-		{
-			new iTeam = GetClientTeam(i);
-			if ((iTeam == _:TFTeam_Red || iTeam == _:TFTeam_Blue) && iTeam == iMyTeam)
-			{
-				iCount++;
-			}
-		}
-	}
-	
-	if (!iCount) return;
-	
-	// Can only enable lag compensation only for specific weapons.
-	new iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
-	if (!IsValidEdict(iActiveWeapon)) return;
-	
-	decl String:sClassName[64];
-	GetEdictClassname(iActiveWeapon, sClassName, sizeof(sClassName));
-	
-	new bool:bCompensate = false;
-	for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
-	{
-		if (StrEqual(sClassName, g_strPlayerLagCompensationWeapons[i], false))
-		{
-			bCompensate = true;
-			break;
-		}
-	}
-	
-	if (!bCompensate) return;
-	
-	g_bPlayerLagCompensation[client] = true;
-	g_iPlayerLagCompensationTeam[client] = iMyTeam;
-	SetEntProp(client, Prop_Send, "m_iTeamNum", 0);
-}
-
-ClientDisableFakeLagCompensation(client)
-{
-	if (!g_bPlayerLagCompensation[client]) return;
-	
-	SetEntProp(client, Prop_Send, "m_iTeamNum", g_iPlayerLagCompensationTeam[client]);
-	g_bPlayerLagCompensation[client] = false;
-	g_iPlayerLagCompensationTeam[client] = -1;
-}
-
-//	==========================================================
-//	FLASHLIGHT / ULTRAVISION FUNCTIONS
-//	==========================================================
-
-bool:IsClientUsingFlashlight(client)
-{
-	return g_bPlayerFlashlight[client];
-}
-
-Float:ClientGetFlashlightBatteryLife(client)
-{
-	return g_flPlayerFlashlightBatteryLife[client];
-}
-
-ClientSetFlashlightBatteryLife(client, Float:flPercent)
-{
-	g_flPlayerFlashlightBatteryLife[client] = flPercent;
-}
-
-/**
- *	Called in Hook_ClientPreThink, this makes sure the flashlight is oriented correctly on the player.
- */
-static ClientProcessFlashlightAngles(client)
-{
-	if (!IsClientInGame(client)) return;
-	
-	if (IsPlayerAlive(client))
-	{
-		decl fl, Float:eyeAng[3], Float:ang2[3];
-		
-		if (IsClientUsingFlashlight(client))
-		{
-			fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
-			if (fl && fl != INVALID_ENT_REFERENCE)
-			{
-				TeleportEntity(fl, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 }, NULL_VECTOR);
-			}
-			
-			fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
-			if (fl && fl != INVALID_ENT_REFERENCE)
-			{
-				GetClientEyeAngles(client, eyeAng);
-				GetClientAbsAngles(client, ang2);
-				SubtractVectors(eyeAng, ang2, eyeAng);
-				TeleportEntity(fl, NULL_VECTOR, eyeAng, NULL_VECTOR);
-			}
-		}
-	}
-}
-
-/**
- *	Handles whether or not the player's flashlight should be "flickering", a sign of a dying flashlight battery.
- */
-static ClientHandleFlashlightFlickerState(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	if (IsClientUsingFlashlight(client))
-	{
-		new bool:bFlicker = bool:(ClientGetFlashlightBatteryLife(client) <= SF2_FLASHLIGHT_FLICKERAT);
-	
-		new fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
-		if (fl && fl != INVALID_ENT_REFERENCE)
-		{
-			if (bFlicker)
-			{
-				SetEntProp(fl, Prop_Data, "m_LightStyle", 10);
-			}
-			else
-			{
-				SetEntProp(fl, Prop_Data, "m_LightStyle", 0);
-			}
-		}
-		
-		fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
-		if (fl && fl != INVALID_ENT_REFERENCE)
-		{
-			if (bFlicker) 
-			{
-				SetEntityRenderFx(fl, RenderFx:13);
-			}
-			else 
-			{
-				SetEntityRenderFx(fl, RenderFx:0);
-			}
-		}
-	}
-}
-
-bool:IsClientFlashlightBroken(client)
-{
-	return g_bPlayerFlashlightBroken[client];
-}
-
-Float:ClientGetFlashlightNextInputTime(client)
-{
-	return g_flPlayerFlashlightNextInputTime[client];
-}
-
-/**
- *	Breaks the player's flashlight. Nothing else.
- */
-ClientBreakFlashlight(client)
-{
-	if (IsClientFlashlightBroken(client)) return;
-	
-	g_bPlayerFlashlightBroken[client] = true;
-	
-	ClientSetFlashlightBatteryLife(client, 0.0);
-	ClientTurnOffFlashlight(client);
-	
-	ClientAddStress(client, 0.2);
-	
-	EmitSoundToAll(FLASHLIGHT_BREAKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
-	
-	Call_StartForward(fOnClientBreakFlashlight);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-/**
- *	Resets everything of the player's flashlight.
- */
-ClientResetFlashlight(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetFlashlight(%d)", client);
-#endif
-	
-	ClientTurnOffFlashlight(client);
-	ClientSetFlashlightBatteryLife(client, 1.0);
-	g_bPlayerFlashlightBroken[client] = false;
-	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
-	g_flPlayerFlashlightNextInputTime[client] = -1.0;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetFlashlight(%d)", client);
-#endif
-}
-
-public Action:Hook_FlashlightSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	if (EntRefToEntIndex(g_iPlayerFlashlightEnt[other]) != ent) return Plugin_Handled;
-	
-	// We've already checked for flashlight ownership in the last statement. So we can do just this.
-	if (g_iPlayerPreferences[other][PlayerPreference_ProjectedFlashlight]) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_Flashlight2SetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[other]) == ent) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-public Hook_FlashlightEndSpawnPost(ent)
-{
-	if (!g_bEnabled) return;
-
-	SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightEndSetTransmit);
-	SDKUnhook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
-}
-
-public Action:Hook_FlashlightBeamSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	new iOwner = -1;
-	new iSpotlight = -1;
-	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
-	{
-		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
-		{
-			iOwner = iSpotlight;
-			break;
-		}
-	}
-	
-	if (iOwner == -1) return Plugin_Continue;
-	
-	new iClient = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
-		{
-			iClient = i;
-			break;
-		}
-	}
-	
-	if (iClient == -1) return Plugin_Continue;
-	
-	if (iClient == other)
-	{
-		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
-		{
-			return Plugin_Handled;
-		}
-	}
-	else
-	{
-		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-		{
-			return Plugin_Handled;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Hook_FlashlightEndSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	new iOwner = -1;
-	new iSpotlight = -1;
-	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
-	{
-		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
-		{
-			iOwner = iSpotlight;
-			break;
-		}
-	}
-	
-	if (iOwner == -1) return Plugin_Continue;
-	
-	new iClient = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		
-		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
-		{
-			iClient = i;
-			break;
-		}
-	}
-	
-	if (iClient == -1) return Plugin_Continue;
-	
-	if (iClient == other)
-	{
-		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
-		{
-			return Plugin_Handled;
-		}
-	}
-	else
-	{
-		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-		{
-			return Plugin_Handled;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_DrainFlashlight(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
-	
-	new iOverride = GetConVarInt(g_cvPlayerInfiniteFlashlightOverride);
-	if ((!g_bRoundInfiniteFlashlight && iOverride != 1) || iOverride == 0)
-	{
-		ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) - 0.01);
-	}
-	
-	if (ClientGetFlashlightBatteryLife(client) <= 0.0)
-	{
-		// Break the player's flashlight, but also start recharging.
-		ClientBreakFlashlight(client);
-		ClientStartRechargingFlashlightBattery(client);
-		ClientActivateUltravision(client);
-		return Plugin_Stop;
-	}
-	else
-	{
-		ClientHandleFlashlightFlickerState(client);
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_RechargeFlashlight(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
-	
-	ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) + 0.01);
-	
-	if (IsClientFlashlightBroken(client) && ClientGetFlashlightBatteryLife(client) >= SF2_FLASHLIGHT_ENABLEAT)
-	{
-		// Repair the flashlight.
-		g_bPlayerFlashlightBroken[client] = false;
-	}
-	
-	if (ClientGetFlashlightBatteryLife(client) >= 1.0)
-	{
-		// I am fully charged!
-		ClientSetFlashlightBatteryLife(client, 1.0);
-		g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
-		
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-/**
- *	Turns on the player's flashlight. Nothing else.
- */
-ClientTurnOnFlashlight(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	if (IsClientUsingFlashlight(client)) return;
-	
-	g_bPlayerFlashlight[client] = true;
-	
-	decl Float:flEyePos[3];
-	GetClientEyePosition(client, flEyePos);
-	
-	if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
-	{
-		// If the player is using the projected flashlight, just set effect flags.
-		new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-		if (!(iEffects & (1 << 2)))
-		{
-			SetEntProp(client, Prop_Send, "m_fEffects", iEffects | (1 << 2));
-		}
-	}
-	else
-	{
-		// Spawn the light which only the user will see.
-		new ent = CreateEntityByName("light_dynamic");
-		if (ent != -1)
-		{
-			TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
-			DispatchKeyValue(ent, "targetname", "WUBADUBDUBMOTHERBUCKERS");
-			DispatchKeyValue(ent, "rendercolor", "255 255 255");
-			SetVariantFloat(SF2_FLASHLIGHT_WIDTH);
-			AcceptEntityInput(ent, "spotlight_radius");
-			SetVariantFloat(SF2_FLASHLIGHT_LENGTH);
-			AcceptEntityInput(ent, "distance");
-			SetVariantInt(SF2_FLASHLIGHT_BRIGHTNESS);
-			AcceptEntityInput(ent, "brightness");
-			
-			// Convert WU to inches.
-			new Float:cone = 55.0;
-			cone *= 0.75;
-			
-			SetVariantInt(RoundToFloor(cone));
-			AcceptEntityInput(ent, "_inner_cone");
-			SetVariantInt(RoundToFloor(cone));
-			AcceptEntityInput(ent, "_cone");
-			DispatchSpawn(ent);
-			ActivateEntity(ent);
-			SetVariantString("!activator");
-			AcceptEntityInput(ent, "SetParent", client);
-			AcceptEntityInput(ent, "TurnOn");
-			
-			g_iPlayerFlashlightEnt[client] = EntIndexToEntRef(ent);
-			
-			SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightSetTransmit);
-		}
-	}
-	
-	// Spawn the light that only everyone else will see.
-	new ent = CreateEntityByName("point_spotlight");
-	if (ent != -1)
-	{
-		TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
-		
-		decl String:sBuffer[256];
-		FloatToString(SF2_FLASHLIGHT_LENGTH, sBuffer, sizeof(sBuffer));
-		DispatchKeyValue(ent, "spotlightlength", sBuffer);
-		FloatToString(SF2_FLASHLIGHT_WIDTH, sBuffer, sizeof(sBuffer));
-		DispatchKeyValue(ent, "spotlightwidth", sBuffer);
-		DispatchKeyValue(ent, "rendercolor", "255 255 255");
-		DispatchSpawn(ent);
-		ActivateEntity(ent);
-		SetVariantString("!activator");
-		AcceptEntityInput(ent, "SetParent", client);
-		AcceptEntityInput(ent, "LightOn");
-		
-		g_iPlayerFlashlightEntAng[client] = EntIndexToEntRef(ent);
-	}
-	
-	Call_StartForward(fOnClientActivateFlashlight);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-/**
- *	Turns off the player's flashlight. Nothing else.
- */
-ClientTurnOffFlashlight(client)
-{
-	if (!IsClientUsingFlashlight(client)) return;
-	
-	g_bPlayerFlashlight[client] = false;
-	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
-	
-	// Remove user-only light.
-	new ent = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE) 
-	{
-		AcceptEntityInput(ent, "TurnOff");
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	// Remove everyone-else-only light.
-	ent = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE) 
-	{
-		AcceptEntityInput(ent, "LightOff");
-		CreateTimer(0.1, Timer_KillEntity, g_iPlayerFlashlightEntAng[client], TIMER_FLAG_NO_MAPCHANGE);
-	}
-	
-	g_iPlayerFlashlightEnt[client] = INVALID_ENT_REFERENCE;
-	g_iPlayerFlashlightEntAng[client] = INVALID_ENT_REFERENCE;
-	
-	if (IsClientInGame(client))
-	{
-		if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
-		{
-			new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-			if (iEffects & (1 << 2))
-			{
-				SetEntProp(client, Prop_Send, "m_fEffects", iEffects &= ~(1 << 2));
-			}
-		}
-	}
-	
-	Call_StartForward(fOnClientDeactivateFlashlight);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-ClientStartRechargingFlashlightBattery(client)
-{
-	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(SF2_FLASHLIGHT_RECHARGE_RATE, Timer_RechargeFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStartDrainingFlashlightBattery(client)
-{
-	new Float:flDrainRate = SF2_FLASHLIGHT_DRAIN_RATE;
-	if (TF2_GetPlayerClass(client) == TFClass_Engineer) 
-	{
-		// Engineers have a 33% longer battery life, basically.
-		// TODO: Make this value customizable via cvar.
-		flDrainRate *= 1.33;
-	}
-	
-	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(flDrainRate, Timer_DrainFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientHandleFlashlight(client)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client)) return;
-	
-	if (IsClientUsingFlashlight(client)) 
-	{
-		ClientTurnOffFlashlight(client);
-		ClientStartRechargingFlashlightBattery(client);
-		ClientActivateUltravision(client);
-		
-		g_flPlayerFlashlightNextInputTime[client] = GetGameTime() + SF2_FLASHLIGHT_COOLDOWN;
-		
-		EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
-	}
-	else
-	{
-		// Only players in the "game" can use the flashlight.
-		if (!g_bPlayerEliminated[client])
-		{
-			new bool:bCanUseFlashlight = true;
-			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_LIGHTSOUT) 
-			{
-				// Unequip the flashlight please.
-				bCanUseFlashlight = false;
-			}
-			
-			if (!IsClientFlashlightBroken(client) && bCanUseFlashlight)
-			{
-				ClientTurnOnFlashlight(client);
-				ClientStartDrainingFlashlightBattery(client);
-				ClientDeactivateUltravision(client);
-				
-				g_flPlayerFlashlightNextInputTime[client] = GetGameTime();
-				
-				EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
-			}
-			else
-			{
-				EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
-			}
-		}
-	}
-}
-
-bool:IsClientUsingUltravision(client)
-{
-	return g_bPlayerUltravision[client];
-}
-
-ClientActivateUltravision(client)
-{
-	if (!IsClientInGame(client) || IsClientUsingUltravision(client)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientActivateUltravision(%d)", client);
-#endif
-	
-	g_bPlayerUltravision[client] = true;
-	
-	new ent = CreateEntityByName("light_dynamic");
-	if (ent != -1)
-	{
-		decl Float:flEyePos[3];
-		GetClientEyePosition(client, flEyePos);
-		
-		TeleportEntity(ent, flEyePos, Float:{ 90.0, 0.0, 0.0 }, NULL_VECTOR);
-		DispatchKeyValue(ent, "rendercolor", "0 200 255");
-		
-		new Float:flRadius = 0.0;
-		if (g_bPlayerEliminated[client])
-		{
-			flRadius = GetConVarFloat(g_cvUltravisionRadiusBlue);
-		}
-		else
-		{
-			flRadius = GetConVarFloat(g_cvUltravisionRadiusRed);
-		}
-		
-		SetVariantFloat(flRadius);
-		AcceptEntityInput(ent, "spotlight_radius");
-		SetVariantFloat(flRadius);
-		AcceptEntityInput(ent, "distance");
-		
-		SetVariantInt(-15); // Start dark, then fade in via the Timer_UltravisionFadeInEffect timer func.
-		AcceptEntityInput(ent, "brightness");
-		
-		// Convert WU to inches.
-		new Float:cone = SF2_ULTRAVISION_CONE;
-		cone *= 0.75;
-		
-		SetVariantInt(RoundToFloor(cone));
-		AcceptEntityInput(ent, "_inner_cone");
-		SetVariantInt(0);
-		AcceptEntityInput(ent, "_cone");
-		DispatchSpawn(ent);
-		ActivateEntity(ent);
-		SetVariantString("!activator");
-		AcceptEntityInput(ent, "SetParent", client);
-		AcceptEntityInput(ent, "TurnOn");
-		SetEntityRenderFx(ent, RENDERFX_SOLID_SLOW);
-		SetEntityRenderColor(ent, 100, 200, 255, 255);
-		
-		g_iPlayerUltravisionEnt[client] = EntIndexToEntRef(ent);
-		
-		SDKHook(ent, SDKHook_SetTransmit, Hook_UltravisionSetTransmit);
-		
-		// Fade in effect.
-		CreateTimer(0.0, Timer_UltravisionFadeInEffect, g_iPlayerUltravisionEnt[client], TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	}
-
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientActivateUltravision(%d)", client);
-#endif
-}
-
-public Action:Timer_UltravisionFadeInEffect(Handle:timer, any:entref)
-{
-	new ent = EntRefToEntIndex(entref);
-	if (!ent || ent == INVALID_ENT_REFERENCE) return Plugin_Stop;
-	
-	new iBrightness = GetEntProp(ent, Prop_Send, "m_Exponent");
-	if (iBrightness >= GetConVarInt(g_cvUltravisionBrightness)) return Plugin_Stop;
-	
-	iBrightness++;
-	SetVariantInt(iBrightness);
-	AcceptEntityInput(ent, "brightness");
-	
-	return Plugin_Continue;
-}
-
-ClientDeactivateUltravision(client)
-{
-	if (!IsClientUsingUltravision(client)) return;
-	
-	g_bPlayerUltravision[client] = false;
-	
-	new ent = EntRefToEntIndex(g_iPlayerUltravisionEnt[client]);
-	if (ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "TurnOff");
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	g_iPlayerUltravisionEnt[client] = INVALID_ENT_REFERENCE;
-}
-
-public Action:Hook_UltravisionSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (!GetConVarBool(g_cvUltravisionEnabled) || EntRefToEntIndex(g_iPlayerUltravisionEnt[other]) != ent || !IsPlayerAlive(other)) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-static Float:ClientGetDefaultWalkSpeed(client)
-{
-	new Float:flReturn = 190.0;
-	new Float:flReturn2 = flReturn;
-	new Action:iAction = Plugin_Continue;
-	new TFClassType:iClass = TF2_GetPlayerClass(client);
-	
-	switch (iClass)
-	{
-		case TFClass_Scout: flReturn = 190.0;
-		case TFClass_Sniper: flReturn = 190.0;
-		case TFClass_Soldier: flReturn = 190.0;
-		case TFClass_DemoMan: flReturn = 190.0;
-		case TFClass_Heavy: flReturn = 190.0;
-		case TFClass_Medic: flReturn = 190.0;
-		case TFClass_Pyro: flReturn = 190.0;
-		case TFClass_Spy: flReturn = 190.0;
-		case TFClass_Engineer: flReturn = 190.0;
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnClientGetDefaultWalkSpeed);
-	Call_PushCell(client);
-	Call_PushCellRef(flReturn2);
-	Call_Finish(iAction);
-	
-	if (iAction == Plugin_Changed) flReturn = flReturn2;
-	
-	return flReturn;
-}
-
-static Float:ClientGetDefaultSprintSpeed(client)
-{
-	new Float:flReturn = 300.0;
-	new Float:flReturn2 = flReturn;
-	new Action:iAction = Plugin_Continue;
-	new TFClassType:iClass = TF2_GetPlayerClass(client);
-	
-	switch (iClass)
-	{
-		case TFClass_Scout: flReturn = 300.0;
-		case TFClass_Sniper: flReturn = 300.0;
-		case TFClass_Soldier: flReturn = 275.0;
-		case TFClass_DemoMan: flReturn = 285.0;
-		case TFClass_Heavy: flReturn = 270.0;
-		case TFClass_Medic: flReturn = 300.0;
-		case TFClass_Pyro: flReturn = 300.0;
-		case TFClass_Spy: flReturn = 300.0;
-		case TFClass_Engineer: flReturn = 300.0;
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnClientGetDefaultSprintSpeed);
-	Call_PushCell(client);
-	Call_PushCellRef(flReturn2);
-	Call_Finish(iAction);
-	
-	if (iAction == Plugin_Changed) flReturn = flReturn2;
-	
-	return flReturn;
-}
-
-// Static shaking should only affect the x, y portion of the player's view, not roll.
-// This is purely for cosmetic effect.
-
-ClientProcessStaticShake(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	new bool:bOldStaticShake = g_bPlayerInStaticShake[client];
-	new iOldStaticShakeMaster = NPCGetFromUniqueID(g_iPlayerStaticShakeMaster[client]);
-	new iNewStaticShakeMaster = -1;
-	new Float:flNewStaticShakeMasterAnger = -1.0;
-	
-	new Float:flOldPunchAng[3], Float:flOldPunchAngVel[3];
-	GetEntDataVector(client, g_offsPlayerPunchAngle, flOldPunchAng);
-	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flOldPunchAngVel);
-	
-	new Float:flNewPunchAng[3], Float:flNewPunchAngVel[3];
-	
-	for (new i = 0; i < 3; i++)
-	{
-		flNewPunchAng[i] = flOldPunchAng[i];
-		flNewPunchAngVel[i] = flOldPunchAngVel[i];
-	}
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		if (g_iPlayerStaticMode[client][i] != Static_Increase) continue;
-		if (!(NPCGetFlags(i) & SFF_HASSTATICSHAKE)) continue;
-		
-		if (NPCGetAnger(i) > flNewStaticShakeMasterAnger)
-		{
-			new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
-			if (iMaster == -1) iMaster = i;
-			
-			iNewStaticShakeMaster = iMaster;
-			flNewStaticShakeMasterAnger = NPCGetAnger(iMaster);
-		}
-	}
-	
-	if (iNewStaticShakeMaster != -1)
-	{
-		g_iPlayerStaticShakeMaster[client] = NPCGetUniqueID(iNewStaticShakeMaster);
-		
-		if (iNewStaticShakeMaster != iOldStaticShakeMaster)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iNewStaticShakeMaster, sProfile, sizeof(sProfile));
-		
-			if (g_strPlayerStaticShakeSound[client][0])
-			{
-				StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
-			}
-			
-			g_flPlayerStaticShakeMinVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_min", 0.0);
-			g_flPlayerStaticShakeMaxVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_max", 1.0);
-			
-			decl String:sStaticSound[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_static_shake_local", sStaticSound, sizeof(sStaticSound));
-			if (sStaticSound[0])
-			{
-				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), sStaticSound);
-			}
-			else
-			{
-				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
-			}
-		}
-	}
-	
-	if (g_bPlayerInStaticShake[client])
-	{
-		if (g_flPlayerStaticAmount[client] <= 0.0)
-		{
-			g_bPlayerInStaticShake[client] = false;
-		}
-	}
-	else
-	{
-		if (iNewStaticShakeMaster != -1)
-		{
-			g_bPlayerInStaticShake[client] = true;
-		}
-	}
-	
-	if (g_bPlayerInStaticShake[client] && !bOldStaticShake)
-	{	
-		for (new i = 0; i < 2; i++)
-		{
-			flNewPunchAng[i] = 0.0;
-			flNewPunchAngVel[i] = 0.0;
-		}
-		
-		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
-		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
-	}
-	else if (!g_bPlayerInStaticShake[client] && bOldStaticShake)
-	{
-		for (new i = 0; i < 2; i++)
-		{
-			flNewPunchAng[i] = 0.0;
-			flNewPunchAngVel[i] = 0.0;
-		}
-	
-		g_iPlayerStaticShakeMaster[client] = -1;
-		
-		if (g_strPlayerStaticShakeSound[client][0])
-		{
-			StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
-		}
-		
-		strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
-		
-		g_flPlayerStaticShakeMinVolume[client] = 0.0;
-		g_flPlayerStaticShakeMaxVolume[client] = 0.0;
-		
-		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
-		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
-	}
-	
-	if (g_bPlayerInStaticShake[client])
-	{
-		if (g_strPlayerStaticShakeSound[client][0])
-		{
-			new Float:flVolume = g_flPlayerStaticAmount[client];
-			if (GetRandomFloat(0.0, 1.0) <= 0.35)
-			{
-				flVolume = 0.0;
-			}
-			else
-			{
-				if (flVolume < g_flPlayerStaticShakeMinVolume[client])
-				{
-					flVolume = g_flPlayerStaticShakeMinVolume[client];
-				}
-				
-				if (flVolume > g_flPlayerStaticShakeMaxVolume[client])
-				{
-					flVolume = g_flPlayerStaticShakeMaxVolume[client];
-				}
-			}
-			
-			EmitSoundToClient(client, g_strPlayerStaticShakeSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL | SND_STOP, flVolume);
-		}
-		
-		// Spazz our view all over the place.
-		for (new i = 0; i < 2; i++) flNewPunchAng[i] = AngleNormalize(GetRandomFloat(0.0, 360.0));
-		NormalizeVector(flNewPunchAng, flNewPunchAng);
-		
-		new Float:flAngVelocityScalar = 5.0 * g_flPlayerStaticAmount[client];
-		if (flAngVelocityScalar < 1.0) flAngVelocityScalar = 1.0;
-		ScaleVector(flNewPunchAng, flAngVelocityScalar);
-		
-		for (new i = 0; i < 2; i++) flNewPunchAngVel[i] = 0.0;
-		
-		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
-		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
-	}
-}
-
-ClientProcessVisibility(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
-	
-	new String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	new bool:bWasSeeingSlender[MAX_BOSSES];
-	new iOldStaticMode[MAX_BOSSES];
-	
-	decl Float:flSlenderPos[3];
-	decl Float:flSlenderEyePos[3];
-	decl Float:flSlenderOBBCenterPos[3];
-	
-	decl Float:flMyPos[3];
-	GetClientAbsOrigin(client, flMyPos);
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		bWasSeeingSlender[i] = g_bPlayerSeesSlender[client][i];
-		iOldStaticMode[i] = g_iPlayerStaticMode[client][i];
-		g_bPlayerSeesSlender[client][i] = false;
-		g_iPlayerStaticMode[client][i] = Static_None;
-		
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		new iBoss = NPCGetEntIndex(i);
-		
-		if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-		{
-			SlenderGetAbsOrigin(i, flSlenderPos);
-			NPCGetEyePosition(i, flSlenderEyePos);
-			
-			decl Float:flSlenderMins[3], Float:flSlenderMaxs[3];
-			GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flSlenderMins);
-			GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flSlenderMaxs);
-			
-			for (new i2 = 0; i2 < 3; i2++) flSlenderOBBCenterPos[i2] = flSlenderPos[i2] + ((flSlenderMins[i2] + flSlenderMaxs[i2]) / 2.0);
-		}
-		
-		if (IsClientInGhostMode(client))
-		{
-		}
-		else if (!IsClientInDeathCam(client))
-		{
-			if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-			{
-				new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
-				
-				if (!IsPointVisibleToPlayer(client, flSlenderEyePos, true, SlenderUsesBlink(i)))
-				{
-					g_bPlayerSeesSlender[client][i] = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, true, SlenderUsesBlink(i));
-				}
-				else
-				{
-					g_bPlayerSeesSlender[client][i] = true;
-				}
-				
-				if ((GetGameTime() - g_flPlayerSeesSlenderLastTime[client][i]) > GetProfileFloat(sProfile, "static_on_look_gracetime", 1.0) ||
-					(iOldStaticMode[i] == Static_Increase && g_flPlayerStaticAmount[client] > 0.1))
-				{
-					if ((NPCGetFlags(i) & SFF_STATICONLOOK) && 
-						g_bPlayerSeesSlender[client][i])
-					{
-						if (iCopyMaster != -1)
-						{
-							g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
-						}
-						else
-						{
-							g_iPlayerStaticMode[client][i] = Static_Increase;
-						}
-					}
-					else if ((NPCGetFlags(i) & SFF_STATICONRADIUS) && 
-						GetVectorDistance(flMyPos, flSlenderPos) <= g_flSlenderStaticRadius[i])
-					{
-						new bool:bNoObstacles = IsPointVisibleToPlayer(client, flSlenderEyePos, false, false);
-						if (!bNoObstacles) bNoObstacles = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, false);
-						
-						if (bNoObstacles)
-						{
-							if (iCopyMaster != -1)
-							{
-								g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
-							}
-							else
-							{
-								g_iPlayerStaticMode[client][i] = Static_Increase;
-							}
-						}
-					}
-				}
-				
-				// Process death cam sequence conditions
-				if (SlenderKillsOnNear(i))
-				{
-					if (g_flPlayerStaticAmount[client] >= 1.0 ||
-						GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetInstantKillRadius(i))
-					{
-						new bool:bKillPlayer = true;
-						if (g_flPlayerStaticAmount[client] < 1.0)
-						{
-							bKillPlayer = IsPointVisibleToPlayer(client, flSlenderEyePos, false, SlenderUsesBlink(i));
-						}
-						
-						if (!bKillPlayer) bKillPlayer = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, SlenderUsesBlink(i));
-						
-						if (bKillPlayer)
-						{
-							g_flSlenderLastKill[i] = GetGameTime();
-							
-							if (g_flPlayerStaticAmount[client] >= 1.0)
-							{
-								ClientStartDeathCam(client, NPCGetFromUniqueID(g_iPlayerStaticMaster[client]), flSlenderPos);
-							}
-							else
-							{
-								ClientStartDeathCam(client, i, flSlenderPos);
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
-		if (iMaster == -1) iMaster = i;
-		
-		// Boss visiblity.
-		if (g_bPlayerSeesSlender[client][i] && !bWasSeeingSlender[i])
-		{
-			g_flPlayerSeesSlenderLastTime[client][iMaster] = GetGameTime();
-			
-			if (GetGameTime() >= g_flPlayerScareNextTime[client][iMaster])
-			{
-				if (GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetScareRadius(i))
-				{
-					ClientPerformScare(client, iMaster);
-					
-					if (NPCHasAttribute(iMaster, "ignite player on scare"))
-					{
-						new Float:flValue = NPCGetAttributeValue(iMaster, "ignite player on scare");
-						if (flValue > 0.0) TF2_IgnitePlayer(client, client);
-					}
-				}
-				else
-				{
-					g_flPlayerScareNextTime[client][iMaster] = GetGameTime() + GetProfileFloat(sProfile, "scare_cooldown");
-				}
-			}
-			
-			if (NPCGetType(i) == SF2BossType_Static)
-			{
-				if (NPCGetFlags(i) & SFF_FAKE)
-				{
-					SlenderMarkAsFake(i);
-					return;
-				}
-			}
-			
-			Call_StartForward(fOnClientLooksAtBoss);
-			Call_PushCell(client);
-			Call_PushCell(i);
-			Call_Finish();
-		}
-		else if (!g_bPlayerSeesSlender[client][i] && bWasSeeingSlender[i])
-		{
-			g_flPlayerScareLastTime[client][iMaster] = GetGameTime();
-			
-			Call_StartForward(fOnClientLooksAwayFromBoss);
-			Call_PushCell(client);
-			Call_PushCell(i);
-			Call_Finish();
-		}
-		
-		if (g_bPlayerSeesSlender[client][i])
-		{
-			if (GetGameTime() >= g_flPlayerSightSoundNextTime[client][iMaster])
-			{
-				ClientPerformSightSound(client, i);
-			}
-		}
-		
-		if (g_iPlayerStaticMode[client][i] == Static_Increase &&
-			iOldStaticMode[i] != Static_Increase)
-		{
-			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
-			{
-				decl String:sLoopSound[PLATFORM_MAX_PATH];
-				GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
-				
-				if (sLoopSound[0])
-				{
-					EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, GetProfileNum(sProfile, "sound_static_loop_local_level", SNDLEVEL_NORMAL), SND_CHANGEVOL, 1.0);
-					ClientAddStress(client, 0.03);
-				}
-				else
-				{
-					LogError("Warning! Boss %s supports static loop local sounds, but was given a blank sound path!", sProfile);
-				}
-			}
-		}
-		else if (g_iPlayerStaticMode[client][i] != Static_Increase &&
-			iOldStaticMode[i] == Static_Increase)
-		{
-			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
-			{
-				if (iBoss && iBoss != INVALID_ENT_REFERENCE)
-				{
-					decl String:sLoopSound[PLATFORM_MAX_PATH];
-					GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
-					
-					if (sLoopSound[0])
-					{
-						EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, _, SND_CHANGEVOL | SND_STOP, 0.0);
-					}
-				}
-			}
-		}
-	}
-	
-	// Initialize static timers.
-	new iBossLastStatic = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
-	new iBossNewStatic = -1;
-	if (iBossLastStatic != -1 && g_iPlayerStaticMode[client][iBossLastStatic] == Static_Increase)
-	{
-		iBossNewStatic = iBossLastStatic;
-	}
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		new iStaticMode = g_iPlayerStaticMode[client][i];
-		
-		// Determine new static rates.
-		if (iStaticMode != Static_Increase) continue;
-		
-		if (iBossLastStatic == -1 || 
-			g_iPlayerStaticMode[client][iBossLastStatic] != Static_Increase || 
-			NPCGetAnger(i) > NPCGetAnger(iBossLastStatic))
-		{
-			iBossNewStatic = i;
-		}
-	}
-	
-	if (iBossNewStatic != -1)
-	{
-		new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossNewStatic]);
-		if (iCopyMaster != -1)
-		{
-			iBossNewStatic = iCopyMaster;
-			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iCopyMaster);
-		}
-		else
-		{
-			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iBossNewStatic);
-		}
-	}
-	else
-	{
-		g_iPlayerStaticMaster[client] = -1;
-	}
-	
-	if (iBossNewStatic != iBossLastStatic)
-	{
-		if (!StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false))
-		{
-			// Stop last-last static sound entirely.
-			if (g_strPlayerLastStaticSound[client][0])
-			{
-				StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-			}
-		}
-		
-		// Move everything down towards the last arrays.
-		if (g_strPlayerStaticSound[client][0])
-		{
-			strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), g_strPlayerStaticSound[client]);
-		}
-		
-		if (iBossNewStatic == -1)
-		{
-			// No one is the static master.
-			g_hPlayerStaticTimer[client] = CreateTimer(g_flPlayerStaticDecreaseRate[client], 
-				Timer_ClientDecreaseStatic, 
-				GetClientUserId(client), 
-				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-				
-			TriggerTimer(g_hPlayerStaticTimer[client], true);
-		}
-		else
-		{
-			NPCGetProfile(iBossNewStatic, sProfile, sizeof(sProfile));
-		
-			strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
-			
-			new String:sStaticSound[PLATFORM_MAX_PATH];
-			GetRandomStringFromProfile(sProfile, "sound_static", sStaticSound, sizeof(sStaticSound), 1);
-			
-			if (sStaticSound[0]) 
-			{
-				strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), sStaticSound);
-			}
-			
-			// Cross-fade out the static sounds.
-			g_flPlayerLastStaticVolume[client] = g_flPlayerStaticAmount[client];
-			g_flPlayerLastStaticTime[client] = GetGameTime();
-			
-			g_hPlayerLastStaticTimer[client] = CreateTimer(0.0, 
-				Timer_ClientFadeOutLastStaticSound, 
-				GetClientUserId(client), 
-				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			
-			TriggerTimer(g_hPlayerLastStaticTimer[client], true);
-			
-			// Start up our own static timer.
-			new Float:flStaticIncreaseRate = GetProfileFloat(sProfile, "static_rate") / g_flRoundDifficultyModifier;
-			new Float:flStaticDecreaseRate = GetProfileFloat(sProfile, "static_rate_decay");
-			
-			g_flPlayerStaticIncreaseRate[client] = flStaticIncreaseRate;
-			g_flPlayerStaticDecreaseRate[client] = flStaticDecreaseRate;
-			
-			g_hPlayerStaticTimer[client] = CreateTimer(flStaticIncreaseRate, 
-				Timer_ClientIncreaseStatic, 
-				GetClientUserId(client), 
-				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			
-			TriggerTimer(g_hPlayerStaticTimer[client], true);
-		}
-	}
-}
-
-ClientProcessViewAngles(client)
-{
-	if ((!g_bPlayerEliminated[client] || g_bPlayerProxy[client]) && 
-		!DidClientEscape(client))
-	{
-		// Process view bobbing, if enabled.
-		// This code is based on the code in this page: https://developer.valvesoftware.com/wiki/Camera_Bob
-		// Many thanks to whomever created it in the first place.
-		
-		if (IsPlayerAlive(client))
-		{
-			if (g_bPlayerViewbobEnabled)
-			{
-				new Float:flPunchVel[3];
-			
-				if (!g_bPlayerViewbobSprintEnabled || !IsClientReallySprinting(client))
-				{
-					if (GetEntityFlags(client) & FL_ONGROUND)
-					{
-						decl Float:flVelocity[3];
-						GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
-						new Float:flSpeed = GetVectorLength(flVelocity);
-						
-						new Float:flPunchIdle[3];
-						
-						if (flSpeed > 0.0)
-						{
-							if (flSpeed >= 60.0)
-							{
-								flPunchIdle[0] = Sine(GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_X / 400.0;
-								flPunchIdle[1] = Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Y / 400.0;
-								flPunchIdle[2] = Sine(1.6 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Z / 400.0;
-								
-								AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-							}
-							
-							// Calculate roll.
-							decl Float:flForward[3], Float:flVelocityDirection[3];
-							GetClientEyeAngles(client, flForward);
-							GetVectorAngles(flVelocity, flVelocityDirection);
-							
-							new Float:flYawDiff = AngleDiff(flForward[1], flVelocityDirection[1]);
-							if (FloatAbs(flYawDiff) > 90.0) flYawDiff = AngleDiff(flForward[1] + 180.0, flVelocityDirection[1]) * -1.0;
-							
-							new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
-							new Float:flRollScalar = flSpeed / flWalkSpeed;
-							if (flRollScalar > 1.0) flRollScalar = 1.0;
-							
-							new Float:flRollScale = (flYawDiff / 90.0) * 0.25 * flRollScalar;
-							flPunchIdle[0] = 0.0;
-							flPunchIdle[1] = 0.0;
-							flPunchIdle[2] = flRollScale * -1.0;
-							
-							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-						}
-						
-						/*
-						if (flSpeed < 60.0) 
-						{
-							flPunchIdle[0] = FloatAbs(Cosine(GetGameTime() * 1.25) * 0.047);
-							flPunchIdle[1] = Sine(GetGameTime() * 1.25) * 0.075;
-							flPunchIdle[2] = 0.0;
-							
-							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
-						}
-						*/
-					}
-				}
-				
-				if (g_bPlayerViewbobHurtEnabled)
-				{
-					// Shake screen the more the player is hurt.
-					new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
-					new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
-					
-					decl Float:flPunchVelHurt[3];
-					flPunchVelHurt[0] = Sine(1.22 * GetGameTime()) * 48.5 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
-					flPunchVelHurt[1] = Sine(2.12 * GetGameTime()) * 80.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
-					flPunchVelHurt[2] = Sine(0.5 * GetGameTime()) * 36.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
-					
-					AddVectors(flPunchVel, flPunchVelHurt, flPunchVel);
-				}
-				
-				ClientViewPunch(client, flPunchVel);
-			}
-		}
-	}
-}
-
-public Action:Timer_ClientIncreaseStatic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
-	
-	g_flPlayerStaticAmount[client] += 0.05;
-	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
-	
-	if (g_strPlayerStaticSound[client][0])
-	{
-		EmitSoundToClient(client, g_strPlayerStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerStaticAmount[client]);
-		
-		if (g_flPlayerStaticAmount[client] >= 0.5) ClientAddStress(client, 0.03);
-		else
-		{
-			ClientAddStress(client, 0.02);
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_ClientDecreaseStatic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
-	
-	g_flPlayerStaticAmount[client] -= 0.05;
-	if (g_flPlayerStaticAmount[client] < 0.0) g_flPlayerStaticAmount[client] = 0.0;
-	
-	if (g_strPlayerLastStaticSound[client][0])
-	{
-		new Float:flVolume = g_flPlayerStaticAmount[client];
-		if (flVolume > 0.0)
-		{
-			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
-		}
-	}
-	
-	if (g_flPlayerStaticAmount[client] <= 0.0)
-	{
-		// I've done my job; no point to keep on doing it.
-		StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-		g_hPlayerStaticTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_ClientFadeOutLastStaticSound(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerLastStaticTimer[client]) return Plugin_Stop;
-	
-	if (StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false)) 
-	{
-		// Wait, the player's current static sound is the same one we're stopping. Abort!
-		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	if (g_strPlayerLastStaticSound[client][0])
-	{
-		new Float:flDiff = (GetGameTime() - g_flPlayerLastStaticTime[client]) / 1.0;
-		if (flDiff > 1.0) flDiff = 1.0;
-		
-		new Float:flVolume = g_flPlayerLastStaticVolume[client] - flDiff;
-		if (flVolume < 0.0) flVolume = 0.0;
-		
-		if (flVolume <= 0.0)
-		{
-			// I've done my job; no point to keep on doing it.
-			StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
-			g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-			return Plugin_Stop;
-		}
-		else
-		{
-			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
-		}
-	}
-	else
-	{
-		// I've done my job; no point to keep on doing it.
-		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	INTERACTIVE GLOW FUNCTIONS
-//	==========================================================
-
-static ClientProcessInteractiveGlow(client)
-{
-	if (!IsClientInGame(client) || !IsPlayerAlive(client) || (g_bPlayerEliminated[client] && !g_bPlayerProxy[client]) || IsClientInGhostMode(client)) return;
-	
-	new iOldLookEntity = EntRefToEntIndex(g_iPlayerInteractiveGlowTargetEntity[client]);
-	
-	decl Float:flStartPos[3], Float:flMyEyeAng[3];
-	GetClientEyePosition(client, flStartPos);
-	GetClientEyeAngles(client, flMyEyeAng);
-	
-	new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flMyEyeAng, MASK_VISIBLE, RayType_Infinite, TraceRayDontHitPlayers, -1);
-	new iEnt = TR_GetEntityIndex(hTrace);
-	CloseHandle(hTrace);
-	
-	if (IsValidEntity(iEnt))
-	{
-		g_iPlayerInteractiveGlowTargetEntity[client] = EntRefToEntIndex(iEnt);
-	}
-	else
-	{
-		g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
-	}
-	
-	if (iEnt != iOldLookEntity)
-	{
-		ClientRemoveInteractiveGlow(client);
-		
-		if (IsEntityClassname(iEnt, "prop_dynamic", false))
-		{
-			decl String:sTargetName[64];
-			GetEntPropString(iEnt, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
-			
-			if (StrContains(sTargetName, "sf2_page", false) == 0 || StrContains(sTargetName, "sf2_interact", false) == 0)
-			{
-				ClientCreateInteractiveGlow(client, iEnt);
-			}
-		}
-	}
-}
-
-ClientResetInteractiveGlow(client)
-{
-	ClientRemoveInteractiveGlow(client);
-	g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
-}
-
-/**
- *	Removes the player's current interactive glow entity.
- */
-ClientRemoveInteractiveGlow(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientRemoveInteractiveGlow(%d)", client);
-#endif
-
-	new ent = EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	g_iPlayerInteractiveGlowEntity[client] = INVALID_ENT_REFERENCE;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientRemoveInteractiveGlow(%d)", client);
-#endif
-}
-
-/**
- *	Creates an interactive glow for an entity to show to a player.
- */
-bool:ClientCreateInteractiveGlow(client, iEnt, const String:sAttachment[]="")
-{
-	ClientRemoveInteractiveGlow(client);
-	
-	if (!IsClientInGame(client)) return false;
-	
-	if (!iEnt || !IsValidEdict(iEnt)) return false;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientCreateInteractiveGlow(%d)", client);
-#endif
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetEntPropString(iEnt, Prop_Data, "m_ModelName", sBuffer, sizeof(sBuffer));
-	
-	if (strlen(sBuffer) == 0) 
-	{
-		return false;
-	}
-	
-	new ent = CreateEntityByName("tf_taunt_prop");
-	if (ent != -1)
-	{
-		g_iPlayerInteractiveGlowEntity[client] = EntIndexToEntRef(ent);
-		
-		new Float:flModelScale = GetEntPropFloat(iEnt, Prop_Send, "m_flModelScale");
-		
-		SetEntityModel(ent, sBuffer);
-		DispatchSpawn(ent);
-		ActivateEntity(ent);
-		SetEntityRenderMode(ent, RENDER_TRANSCOLOR);
-		SetEntityRenderColor(ent, 0, 0, 0, 0);
-		SetEntProp(ent, Prop_Send, "m_bGlowEnabled", 1);
-		SetEntPropFloat(ent, Prop_Send, "m_flModelScale", flModelScale);
-		
-		new iFlags = GetEntProp(ent, Prop_Send, "m_fEffects");
-		SetEntProp(ent, Prop_Send, "m_fEffects", iFlags | (1 << 0));
-		
-		SetVariantString("!activator");
-		AcceptEntityInput(ent, "SetParent", iEnt);
-		
-		if (sAttachment[0])
-		{
-			SetVariantString(sAttachment);
-			AcceptEntityInput(ent, "SetParentAttachment");
-		}
-		
-		SDKHook(ent, SDKHook_SetTransmit, Hook_InterativeGlowSetTransmit);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> true", client);
-#endif
-		
-		return true;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> false", client);
-#endif
-	
-	return false;
-}
-
-public Action:Hook_InterativeGlowSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[other]) != ent) return Plugin_Handled;
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	BREATHING FUNCTIONS
-//	==========================================================
-
-ClientResetBreathing(client)
-{
-	g_bPlayerBreath[client] = false;
-	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
-}
-
-Float:ClientCalculateBreathingCooldown(client)
-{
-	new Float:flAverage = 0.0;
-	new iAverageNum = 0;
-	
-	// Sprinting only, for now.
-	flAverage += (SF2_PLAYER_BREATH_COOLDOWN_MAX * 6.7765 * Pow((float(g_iPlayerSprintPoints[client]) / 100.0), 1.65));
-	iAverageNum++;
-	
-	flAverage /= float(iAverageNum)
-	
-	if (flAverage < SF2_PLAYER_BREATH_COOLDOWN_MIN) flAverage = SF2_PLAYER_BREATH_COOLDOWN_MIN;
-	
-	return flAverage;
-}
-
-ClientStartBreathing(client)
-{
-	g_bPlayerBreath[client] = true;
-	g_hPlayerBreathTimer[client] = CreateTimer(ClientCalculateBreathingCooldown(client), Timer_ClientBreath, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStopBreathing(client)
-{
-	g_bPlayerBreath[client] = false;
-	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
-}
-
-bool:ClientCanBreath(client)
-{
-	return bool:(ClientCalculateBreathingCooldown(client) < SF2_PLAYER_BREATH_COOLDOWN_MAX);
-}
-
-public Action:Timer_ClientBreath(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerBreathTimer[client]) return;
-	
-	if (!g_bPlayerBreath[client]) return;
-	
-	if (ClientCanBreath(client))
-	{
-		EmitSoundToAll(g_strPlayerBreathSounds[GetRandomInt(0, sizeof(g_strPlayerBreathSounds) - 1)], client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
-		
-		ClientStartBreathing(client);
-		return;
-	}
-	
-	ClientStopBreathing(client);
-}
-
-//	==========================================================
-//	SPRINTING FUNCTIONS
-//	==========================================================
-
-bool:IsClientSprinting(client)
-{
-	return g_bPlayerSprint[client];
-}
-
-ClientGetSprintPoints(client)
-{
-	return g_iPlayerSprintPoints[client];
-}
-
-ClientResetSprint(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSprint(%d)", client);
-#endif
-
-	g_bPlayerSprint[client] = false;
-	g_iPlayerSprintPoints[client] = 100;
-	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-	
-	if (IsValidClient(client))
-	{
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-		
-		ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSprint(%d)", client);
-#endif
-}
-
-ClientStartSprint(client)
-{
-	if (IsClientSprinting(client)) return;
-	
-	g_bPlayerSprint[client] = true;
-	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-	ClientSprintTimer(client);
-	TriggerTimer(g_hPlayerSprintTimer[client], true);
-	
-	SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-	SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-}
-
-static ClientSprintTimer(client, bool:bRecharge=false)
-{
-	new Float:flRate = 0.28;
-	if (bRecharge) flRate = 0.8;
-	
-	decl Float:flVelocity[3];
-	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
-	
-	if (bRecharge)
-	{
-		if (!(GetEntityFlags(client) & FL_ONGROUND)) flRate *= 0.75;
-		else if (GetVectorLength(flVelocity) == 0.0)
-		{
-			if (GetEntProp(client, Prop_Send, "m_bDucked")) flRate *= 0.66;
-			else flRate *= 0.75;
-		}
-	}
-	else
-	{
-		if (TF2_GetPlayerClass(client) == TFClass_Scout) flRate *= 1.15;
-	}
-	
-	if (bRecharge) g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientRechargeSprint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	else g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientSprinting, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStopSprint(client)
-{
-	if (!IsClientSprinting(client)) return;
-	
-	g_bPlayerSprint[client] = false;
-	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-	ClientSprintTimer(client, true);
-	
-	SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-	SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-}
-
-bool:IsClientReallySprinting(client)
-{
-	if (!IsClientSprinting(client)) return false;
-	if (!(GetEntityFlags(client) & FL_ONGROUND)) return false;
-	
-	decl Float:flVelocity[3];
-	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
-	if (GetVectorLength(flVelocity) < 30.0) return false;
-	
-	return true;
-}
-
-public Action:Timer_ClientSprinting(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerSprintTimer[client]) return;
-	
-	if (!IsClientSprinting(client)) return;
-	
-	if (g_iPlayerSprintPoints[client] <= 0)
-	{
-		ClientStopSprint(client);
-		g_iPlayerSprintPoints[client] = 0;
-		return;
-	}
-	
-	if (IsClientReallySprinting(client)) 
-	{
-		new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
-		if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
-		{
-			g_iPlayerSprintPoints[client]--;
-		}
-	}
-	
-	ClientSprintTimer(client);
-}
-
-public Hook_ClientSprintingPreThink(client)
-{
-	if (!IsClientReallySprinting(client))
-	{
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-		SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-		return;
-	}
-	
-	new iFOV = GetEntData(client, g_offsPlayerDefaultFOV);
-	
-	new iTargetFOV = g_iPlayerDesiredFOV[client] + 10;
-	
-	if (iFOV < iTargetFOV)
-	{
-		new iDiff = RoundFloat(FloatAbs(float(iFOV - iTargetFOV)));
-		if (iDiff >= 1)
-		{
-			ClientSetFOV(client, iFOV + 1);
-		}
-		else
-		{
-			ClientSetFOV(client, iTargetFOV);
-		}
-	}
-	else if (iFOV >= iTargetFOV)
-	{
-		ClientSetFOV(client, iTargetFOV);
-		//SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-	}
-}
-
-public Hook_ClientRechargeSprintPreThink(client)
-{
-	if (IsClientReallySprinting(client))
-	{
-		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
-		SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
-		return;
-	}
-	
-	new iFOV = GetEntData(client, g_offsPlayerDefaultFOV);
-	if (iFOV > g_iPlayerDesiredFOV[client])
-	{
-		new iDiff = RoundFloat(FloatAbs(float(iFOV - g_iPlayerDesiredFOV[client])));
-		if (iDiff >= 1)
-		{
-			ClientSetFOV(client, iFOV - 1);
-		}
-		else
-		{
-			ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
-		}
-	}
-	else if (iFOV <= g_iPlayerDesiredFOV[client])
-	{
-		ClientSetFOV(client, g_iPlayerDesiredFOV[client]);
-	}
-}
-
-public Action:Timer_ClientRechargeSprint(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerSprintTimer[client]) return;
-	
-	if (IsClientSprinting(client)) 
-	{
-		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-		return;
-	}
-	
-	if (g_iPlayerSprintPoints[client] >= 100)
-	{
-		g_iPlayerSprintPoints[client] = 100;
-		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
-		return;
-	}
-	
-	g_iPlayerSprintPoints[client]++;
-	ClientSprintTimer(client, true);
-}
-
-//	==========================================================
-//	PROXY / GHOST AND GLOW FUNCTIONS
-//	==========================================================
-
-ClientResetProxy(client, bool:bResetFull=true)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetProxy(%d)", client);
-#endif
-
-	new iOldMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-	new String:sOldProfileName[SF2_MAX_PROFILE_NAME_LENGTH];
-	if (iOldMaster >= 0)
-	{
-		NPCGetProfile(iOldMaster, sOldProfileName, sizeof(sOldProfileName));
-	}
-	
-	new bool:bOldProxy = g_bPlayerProxy[client];
-	if (bResetFull) 
-	{
-		g_bPlayerProxy[client] = false;
-		g_iPlayerProxyMaster[client] = -1;
-	}
-	
-	g_iPlayerProxyControl[client] = 0;
-	g_hPlayerProxyControlTimer[client] = INVALID_HANDLE;
-	g_flPlayerProxyControlRate[client] = 0.0;
-	g_flPlayerProxyVoiceTimer[client] = INVALID_HANDLE;
-	
-	if (IsClientInGame(client))
-	{
-		if (bOldProxy)
-		{
-			ClientStartProxyAvailableTimer(client);
-		
-			if (bResetFull)
-			{
-				SetVariantString("");
-				AcceptEntityInput(client, "SetCustomModel");
-			}
-			
-			if (sOldProfileName[0])
-			{
-				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_spawn", GetProfileNum(sOldProfileName, "sound_proxy_spawn_channel", SNDCHAN_AUTO));
-				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_hurt", GetProfileNum(sOldProfileName, "sound_proxy_hurt_channel", SNDCHAN_AUTO));
-			}
-		}
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetProxy(%d)", client);
-#endif
-}
-
-ClientStartProxyAvailableTimer(client)
-{
-	g_bPlayerProxyAvailable[client] = false;
-	g_hPlayerProxyAvailableTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerProxyWaitTime), Timer_ClientProxyAvailable, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-}
-
-ClientStartProxyForce(client, iSlenderID, const Float:flPos[3])
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
-#endif
-
-	g_iPlayerProxyAskMaster[client] = iSlenderID;
-	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
-
-	g_iPlayerProxyAvailableCount[client] = 0;
-	g_bPlayerProxyAvailableInForce[client] = true;
-	g_hPlayerProxyAvailableTimer[client] = CreateTimer(1.0, Timer_ClientForceProxy, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerProxyAvailableTimer[client], true);
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
-#endif
-}
-
-ClientStopProxyForce(client)
-{
-	g_iPlayerProxyAvailableCount[client] = 0;
-	g_bPlayerProxyAvailableInForce[client] = false;
-	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
-}
-
-public Action:Timer_ClientForceProxy(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerProxyAvailableTimer[client]) return Plugin_Stop;
-	
-	if (!IsRoundEnding())
-	{
-		new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[client]);
-		if (iBossIndex != -1)
-		{
-			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-			NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-		
-			new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
-			new iNumProxies = 0;
-			
-			for (new iClient = 1; iClient <= MaxClients; iClient++)
-			{
-				if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-				if (!g_bPlayerProxy[iClient]) continue;
-				if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
-				
-				iNumProxies++;
-			}
-			
-			if (iNumProxies < iMaxProxies)
-			{
-				if (g_iPlayerProxyAvailableCount[client] > 0)
-				{
-					g_iPlayerProxyAvailableCount[client]--;
-					
-					SetHudTextParams(-1.0, 0.25, 
-						1.0,
-						255, 255, 255, 255,
-						_,
-						_,
-						0.25, 1.25);
-					
-					ShowSyncHudText(client, g_hHudSync, "%T", "SF2 Proxy Force Message", client, g_iPlayerProxyAvailableCount[client]);
-					
-					return Plugin_Continue;
-				}
-				else
-				{
-					ClientEnableProxy(client, iBossIndex);
-					TeleportEntity(client, g_iPlayerProxyAskPosition[client], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-				}
-			}
-			else
-			{
-				PrintToChat(client, "%T", "SF2 Too Many Proxies", client);
-			}
-		}
-	}
-	
-	ClientStopProxyForce(client);
-	return Plugin_Stop;
-}
-
-DisplayProxyAskMenu(client, iAskMaster, const Float:flPos[3])
-{
-	decl String:sBuffer[512];
-	new Handle:hMenu = CreateMenu(Menu_ProxyAsk);
-	SetMenuTitle(hMenu, "%T\n \n%T\n \n", "SF2 Proxy Ask Menu Title", client, "SF2 Proxy Ask Menu Description", client);
-	
-	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
-	AddMenuItem(hMenu, "1", sBuffer);
-	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
-	AddMenuItem(hMenu, "0", sBuffer);
-	
-	g_iPlayerProxyAskMaster[client] = iAskMaster;
-	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
-	DisplayMenu(hMenu, client, 15);
-}
-
-public Menu_ProxyAsk(Handle:menu, MenuAction:action, param1, param2)
-{
-	switch (action)
-	{
-		case MenuAction_End: CloseHandle(menu);
-		case MenuAction_Select:
-		{
-			if (!IsRoundEnding())
-			{
-				new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[param1]);
-				if (iBossIndex != -1)
-				{
-					decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-					NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-				
-					new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
-					new iNumProxies;
-				
-					for (new iClient = 1; iClient <= MaxClients; iClient++)
-					{
-						if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
-						if (!g_bPlayerProxy[iClient]) continue;
-						if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
-						
-						iNumProxies++;
-					}
-					
-					if (iNumProxies < iMaxProxies)
-					{
-						if (param2 == 0)
-						{
-							ClientEnableProxy(param1, iBossIndex);
-							TeleportEntity(param1, g_iPlayerProxyAskPosition[param1], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-						}
-						else
-						{
-							ClientStartProxyAvailableTimer(param1);
-						}
-					}
-					else
-					{
-						PrintToChat(param1, "%T", "SF2 Too Many Proxies", param1);
-					}
-				}
-			}
-		}
-	}
-}
-
-public Action:Timer_ClientProxyAvailable(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerProxyAvailableTimer[client]) return;
-	
-	g_bPlayerProxyAvailable[client] = true;
-	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
-}
-
-ClientEnableProxy(client, iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1) return;
-	if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) return;
-	if (g_bPlayerProxy[client]) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	PvP_SetPlayerPvPState(client, false, false, false);
-	
-	ClientSetGhostModeState(client, false);
-	
-	ClientStopProxyForce(client);
-	
-	ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
-	if (!IsPlayerAlive(client)) TF2_RespawnPlayer(client);
-	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
-	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
-	
-	g_bPlayerProxy[client] = true;
-	g_iPlayerProxyMaster[client] = NPCGetUniqueID(iBossIndex);
-	g_iPlayerProxyControl[client] = 100;
-	g_flPlayerProxyControlRate[client] = GetProfileFloat(sProfile, "proxies_controldrainrate");
-	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	g_bPlayerProxyAvailable[client] = false;
-	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
-	
-	decl String:sAllowedClasses[512];
-	GetProfileString(sProfile, "proxies_classes", sAllowedClasses, sizeof(sAllowedClasses));
-	
-	decl String:sClassName[64];
-	TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
-	if (sAllowedClasses[0] && sClassName[0] && StrContains(sAllowedClasses, sClassName, false) == -1)
-	{
-		// Pick the first class that's allowed.
-		new String:sAllowedClassesList[32][32];
-		new iClassCount = ExplodeString(sAllowedClasses, " ", sAllowedClassesList, 32, 32);
-		if (iClassCount)
-		{
-			TF2_SetPlayerClass(client, TF2_GetClass(sAllowedClassesList[0]), _, false);
-			
-			new iMaxHealth = GetEntProp(client, Prop_Send, "m_iHealth");
-			TF2_RegeneratePlayer(client);
-			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
-			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
-		}
-	}
-	
-	UTIL_ScreenFade(client, 200, 1, FFADE_IN, 255, 255, 255, 100);
-	PrecacheSound("weapons/teleporter_send.wav");
-	EmitSoundToClient(client, "weapons/teleporter_send.wav", _, SNDCHAN_STATIC);
-	
-	ClientActivateUltravision(client);
-	
-	CreateTimer(0.33, Timer_ApplyCustomModel, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	
-	Call_StartForward(fOnClientSpawnedAsProxy);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-public Action:Timer_ClientProxyControl(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerProxyControlTimer[client]) return;
-	
-	g_iPlayerProxyControl[client]--;
-	if (g_iPlayerProxyControl[client] <= 0)
-	{
-		// ForcePlayerSuicide isn't really dependable, since the player doesn't suicide until several seconds after spawning has passed.
-		SDKHooks_TakeDamage(client, client, client, 9001.0, DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-		return;
-	}
-	
-	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, userid, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-bool:DoesClientHaveConstantGlow(client)
-{
-	return g_bPlayerConstantGlowEnabled[client];
-}
-
-ClientDisableConstantGlow(client)
-{
-	if (!DoesClientHaveConstantGlow(client)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientDisableConstantGlow(%d)", client);
-#endif
-	
-	g_bPlayerConstantGlowEnabled[client] = false;
-	
-	new iGlow = EntRefToEntIndex(g_iPlayerConstantGlowEntity[client]);
-	if (iGlow && iGlow != INVALID_ENT_REFERENCE) AcceptEntityInput(iGlow, "Kill");
-	
-	g_iPlayerConstantGlowEntity[client] = INVALID_ENT_REFERENCE;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientDisableConstantGlow(%d)", client);
-#endif
-}
-
-bool:ClientEnableConstantGlow(client, const String:sAttachment[]="")
-{
-	if (DoesClientHaveConstantGlow(client)) return true;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientEnableConstantGlow(%d)", client);
-#endif
-	
-	decl String:sModel[PLATFORM_MAX_PATH];
-	GetClientModel(client, sModel, sizeof(sModel));
-	
-	if (strlen(sModel) == 0) 
-	{
-		// For some reason the model couldn't be found, so no.
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false (no model specified)", client);
-#endif
-		
-		return false;
-	}
-	
-	new iGlow = CreateEntityByName("tf_taunt_prop");
-	if (iGlow != -1)
-	{
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> created");
-#endif
-	
-		g_bPlayerConstantGlowEnabled[client] = true;
-		g_iPlayerConstantGlowEntity[client] = EntIndexToEntRef(iGlow);
-		
-		new Float:flModelScale = GetEntPropFloat(client, Prop_Send, "m_flModelScale");
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) 
-		{
-			DebugMessage("tf_taunt_prop -> get model and model scale (%s, %f, player class: %d)", sModel, flModelScale, TF2_GetPlayerClass(client));
-		}
-#endif
-		
-		SetEntityModel(iGlow, sModel);
-		DispatchSpawn(iGlow);
-		ActivateEntity(iGlow);
-		SetEntityRenderMode(iGlow, RENDER_TRANSCOLOR);
-		SetEntityRenderColor(iGlow, 0, 0, 0, 0);
-		SetEntProp(iGlow, Prop_Send, "m_bGlowEnabled", 1);
-		SetEntPropFloat(iGlow, Prop_Send, "m_flModelScale", flModelScale);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set model and model scale");
-#endif
-		
-		// Set effect flags.
-		new iFlags = GetEntProp(iGlow, Prop_Send, "m_fEffects");
-		SetEntProp(iGlow, Prop_Send, "m_fEffects", iFlags | (1 << 0)); // EF_BONEMERGE
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set bonemerge flags");
-#endif
-		
-		SetVariantString("!activator");
-		AcceptEntityInput(iGlow, "SetParent", client);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent to client");
-#endif
-		
-		if (sAttachment[0])
-		{
-			SetVariantString(sAttachment);
-			AcceptEntityInput(iGlow, "SetParentAttachment");
-		}
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent attachment to %s", sAttachment);
-#endif
-		
-		SDKHook(iGlow, SDKHook_SetTransmit, Hook_ConstantGlowSetTransmit);
-		
-#if defined DEBUG
-		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> true", client);
-#endif
-		
-		return true;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false", client);
-#endif
-	
-	return false;
-}
-
-ClientResetJumpScare(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetJumpScare(%d)", client);
-#endif
-
-	g_iPlayerJumpScareBoss[client] = -1;
-	g_flPlayerJumpScareLifeTime[client] = -1.0;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetJumpScare(%d)", client);
-#endif
-}
-
-ClientDoJumpScare(client, iBossIndex, Float:flLifeTime)
-{
-	g_iPlayerJumpScareBoss[client] = NPCGetUniqueID(iBossIndex);
-	g_flPlayerJumpScareLifeTime[client] = GetGameTime() + flLifeTime;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_jumpscare", sBuffer, sizeof(sBuffer), 1);
-	
-	if (strlen(sBuffer) > 0)
-	{
-		EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN);
-	}
-}
-
- /**
-  *	Handles sprinting upon player input.
-  */
-ClientHandleSprint(client, bool:bSprint)
-{
-	if (!IsPlayerAlive(client) || 
-		g_bPlayerEliminated[client] || 
-		DidClientEscape(client) || 
-		g_bPlayerProxy[client] || 
-		IsClientInGhostMode(client)) return;
-	
-	if (bSprint)
-	{
-		if (g_iPlayerSprintPoints[client] > 0)
-		{
-			ClientStartSprint(client);
-		}
-		else
-		{
-			EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
-		}
-	}
-	else
-	{
-		if (IsClientSprinting(client))
-		{
-			ClientStopSprint(client);
-		}
-	}
-}
-
-ClientOnButtonPress(client, button)
-{
-	switch (button)
-	{
-		case IN_ATTACK2:
-		{
-			if (IsPlayerAlive(client))
-			{
-				if (!IsRoundInWarmup() &&
-					!IsRoundInIntro() &&
-					!IsRoundEnding() && 
-					!DidClientEscape(client))
-				{
-					if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
-					{
-						ClientHandleFlashlight(client);
-					}
-				}
-			}
-		}
-		case IN_ATTACK3:
-		{
-			ClientHandleSprint(client, true);
-			}
-		case IN_RELOAD:
-		{
-			if (IsPlayerAlive(client))
-			{
-				if (!g_bPlayerEliminated[client])
-				{
-					if (!IsRoundEnding() && 
-						!IsRoundInWarmup() &&
-						!IsRoundInIntro() &&
-						!DidClientEscape(client))
-					{
-						ClientBlink(client);
-					}
-				}
-			}
-		}
-		case IN_JUMP:
-		{
-			if (IsPlayerAlive(client) && !(GetEntityFlags(client) & FL_FROZEN))
-			{
-				if (!bool:GetEntProp(client, Prop_Send, "m_bDucked") && 
-					(GetEntityFlags(client) & FL_ONGROUND) &&
-					GetEntProp(client, Prop_Send, "m_nWaterLevel") < 2)
-				{
-					ClientOnJump(client);
-				}
-			}
-		}
-	}
-}
-
-ClientOnButtonRelease(client, button)
-{
-	switch (button)
-	{
-		case IN_ATTACK3:
-		{
-			ClientHandleSprint(client, false);
-		}
-	}
-}
-
-ClientOnJump(client)
-{
-	if (!g_bPlayerEliminated[client])
-	{
-		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
-		{
-			new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
-			if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
-			{
-				g_iPlayerSprintPoints[client] -= 7;
-				if (g_iPlayerSprintPoints[client] < 0) g_iPlayerSprintPoints[client] = 0;
-			}
-			
-			if (!IsClientSprinting(client))
-			{
-				if (g_hPlayerSprintTimer[client] == INVALID_HANDLE)
-				{
-					// If the player hasn't sprinted recently, force us to regenerate the stamina.
-					ClientSprintTimer(client, true);
-				}
-			}
-		}
-	}
-}
-
-//	==========================================================
-//	DEATH CAM FUNCTIONS
-//	==========================================================
-
-bool:IsClientInDeathCam(client)
-{
-	return g_bPlayerDeathCam[client];
-}
-
-public Action:Hook_DeathCamSetTransmit(slender, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-
-	if (EntRefToEntIndex(g_iPlayerDeathCamEnt2[other]) != slender) return Plugin_Handled;
-	return Plugin_Continue;
-}
-
-ClientResetDeathCam(client)
-{
-	if (!IsClientInDeathCam(client)) return; // no really need to reset if it wasn't set.
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetDeathCam(%d)", client);
-#endif
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	
-	g_iPlayerDeathCamBoss[client] = -1;
-	g_bPlayerDeathCam[client] = false;
-	g_bPlayerDeathCamShowOverlay[client] = false;
-	g_hPlayerDeathCamTimer[client] = INVALID_HANDLE;
-	
-	new ent = EntRefToEntIndex(g_iPlayerDeathCamEnt[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "Disable");
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	ent = EntRefToEntIndex(g_iPlayerDeathCamEnt2[client]);
-	if (ent && ent != INVALID_ENT_REFERENCE)
-	{
-		AcceptEntityInput(ent, "Kill");
-	}
-	
-	g_iPlayerDeathCamEnt[client] = INVALID_ENT_REFERENCE;
-	g_iPlayerDeathCamEnt2[client] = INVALID_ENT_REFERENCE;
-	
-	if (IsClientInGame(client))
-	{
-		SetClientViewEntity(client, client);
-	}
-	
-	Call_StartForward(fOnClientEndDeathCam);
-	Call_PushCell(client);
-	Call_PushCell(iDeathCamBoss);
-	Call_Finish();
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetDeathCam(%d)", client);
-#endif
-}
-
-ClientStartDeathCam(client, iBossIndex, const Float:vecLookPos[3])
-{
-	if (IsClientInDeathCam(client)) return;
-	if (!NPCIsValid(iBossIndex)) return;
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	if (GetProfileNum(sProfile, "death_cam_play_scare_sound"))
-	{
-		GetRandomStringFromProfile(sProfile, "sound_scare_player", buffer, sizeof(buffer));
-		if (buffer[0]) EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-	}
-	
-	GetRandomStringFromProfile(sProfile, "sound_player_deathcam", buffer, sizeof(buffer));
-	if (strlen(buffer) > 0) 
-	{
-		EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-	}
-	else
-	{
-		// Legacy support for "sound_player_death"
-		GetRandomStringFromProfile(sProfile, "sound_player_death", buffer, sizeof(buffer));
-		if (strlen(buffer) > 0)
-		{
-			EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		}
-	}
-	
-	GetRandomStringFromProfile(sProfile, "sound_player_deathcam_all", buffer, sizeof(buffer));
-	if (strlen(buffer) > 0) 
-	{
-		EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-	}
-	else
-	{
-		// Legacy support for "sound_player_death_all"
-		GetRandomStringFromProfile(sProfile, "sound_player_death_all", buffer, sizeof(buffer));
-		if (strlen(buffer) > 0) 
-		{
-			EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		}
-	}
-	
-	// Call our forward.
-	Call_StartForward(fOnClientCaughtByBoss);
-	Call_PushCell(client);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-	
-	if (!NPCHasDeathCamEnabled(iBossIndex))
-	{
-		SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol changes our lifestate.
-		
-		// TODO: Add more attributes!
-		if (NPCHasAttribute(iBossIndex, "ignite player on death"))
-		{
-			new Float:flValue = NPCGetAttributeValue(iBossIndex, "ignite player on death");
-			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
-		}
-		
-		SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-		return;
-	}
-	
-	g_iPlayerDeathCamBoss[client] = NPCGetUniqueID(iBossIndex);
-	g_bPlayerDeathCam[client] = true;
-	g_bPlayerDeathCamShowOverlay[client] = false;
-	
-	decl Float:eyePos[3], Float:eyeAng[3], Float:vecAng[3];
-	GetClientEyePosition(client, eyePos);
-	GetClientEyeAngles(client, eyeAng);
-	SubtractVectors(eyePos, vecLookPos, vecAng);
-	GetVectorAngles(vecAng, vecAng);
-	vecAng[0] = 0.0;
-	vecAng[2] = 0.0;
-	
-	// Create fake model.
-	new slender = SpawnSlenderModel(iBossIndex, vecLookPos);
-	TeleportEntity(slender, vecLookPos, vecAng, NULL_VECTOR);
-	g_iPlayerDeathCamEnt2[client] = EntIndexToEntRef(slender);
-	SDKHook(slender, SDKHook_SetTransmit, Hook_DeathCamSetTransmit);
-	
-	// Create camera look point.
-	decl String:sName[64];
-	Format(sName, sizeof(sName), "sf2_boss_%d", EntIndexToEntRef(slender));
-	
-	decl Float:flOffsetPos[3];
-	new target = CreateEntityByName("info_target");
-	GetProfileVector(sProfile, "death_cam_pos", flOffsetPos);
-	AddVectors(vecLookPos, flOffsetPos, flOffsetPos);
-	TeleportEntity(target, flOffsetPos, NULL_VECTOR, NULL_VECTOR);
-	DispatchKeyValue(target, "targetname", sName);
-	SetVariantString("!activator");
-	AcceptEntityInput(target, "SetParent", slender);
-	
-	// Create the camera itself.
-	new camera = CreateEntityByName("point_viewcontrol");
-	TeleportEntity(camera, eyePos, eyeAng, NULL_VECTOR);
-	DispatchKeyValue(camera, "spawnflags", "12");
-	DispatchKeyValue(camera, "target", sName);
-	DispatchSpawn(camera);
-	AcceptEntityInput(camera, "Enable", client);
-	g_iPlayerDeathCamEnt[client] = EntIndexToEntRef(camera);
-	
-	if (GetProfileNum(sProfile, "death_cam_overlay") && GetProfileFloat(sProfile, "death_cam_time_overlay_start") >= 0.0)
-	{
-		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_overlay_start"), Timer_ClientResetDeathCam1, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	}
-	else
-	{
-		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	}
-	
-	TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
-	
-	Call_StartForward(fOnClientStartDeathCam);
-	Call_PushCell(client);
-	Call_PushCell(iBossIndex);
-	Call_Finish();
-}
-
-public Action:Timer_ClientResetDeathCam1(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerDeathCamTimer[client]) return;
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
-	
-	g_bPlayerDeathCamShowOverlay[client] = true;
-	g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, userid, TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_ClientResetDeathCamEnd(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerDeathCamTimer[client]) return;
-	
-	SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol entity changes our damage state.
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	if (iDeathCamBoss != -1)
-	{
-		if (NPCHasAttribute(iDeathCamBoss, "ignite player on death"))
-		{
-			new Float:flValue = NPCGetAttributeValue(iDeathCamBoss, "ignite player on death");
-			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
-		}
-	}
-	
-	SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
-	ClientResetDeathCam(client);
-}
-
-//	==========================================================
-//	GHOST MODE FUNCTIONS
-//	==========================================================
-
-static bool:g_bPlayerGhostMode[MAXPLAYERS + 1] = { false, ... };
-static g_iPlayerGhostModeTarget[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
-static Handle:g_hPlayerGhostModeConnectionCheckTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
-static Float:g_flPlayerGhostModeConnectionTimeOutTime[MAXPLAYERS + 1] = { -1.0, ... };
-static Float:g_flPlayerGhostModeConnectionBootTime[MAXPLAYERS + 1] = { -1.0, ... };
-
-/**
- *	Enables/Disables ghost mode on the player.
- */
-ClientSetGhostModeState(client, bool:bState)
-{
-	if (bState == g_bPlayerGhostMode[client]) return;
-	
-	if (bState && !IsClientInGame(client)) return;
-	
-	g_bPlayerGhostMode[client] = bState;
-	g_iPlayerGhostModeTarget[client] = INVALID_ENT_REFERENCE;
-	
-	if (bState)
-	{
-		ClientHandleGhostMode(client, true);
-		
-		if (GetConVarBool(g_cvGhostModeConnectionCheck))
-		{
-			g_hPlayerGhostModeConnectionCheckTimer[client] = CreateTimer(0.0, Timer_GhostModeConnectionCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-			g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
-			g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
-		}
-		
-		PvP_OnClientGhostModeEnable(client);
-	}
-	else
-	{
-		g_hPlayerGhostModeConnectionCheckTimer[client] = INVALID_HANDLE;
-		g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
-		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
-	
-		if (IsClientInGame(client))
-		{
-			TF2_RemoveCondition(client, TFCond_HalloweenGhostMode);
-			SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_PLAYER);
-		}
-	}
-}
-
-public Action:Timer_GhostModeConnectionCheck(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerGhostModeConnectionCheckTimer[client]) return Plugin_Stop;
-	
-	if (!IsFakeClient(client) && IsClientTimingOut(client))
-	{
-		new Float:bootTime = g_flPlayerGhostModeConnectionBootTime[client];
-		if (bootTime < 0.0)
-		{
-			bootTime = GetGameTime() + GetConVarFloat(g_cvGhostModeConnectionTolerance);
-			g_flPlayerGhostModeConnectionBootTime[client] = bootTime;
-			g_flPlayerGhostModeConnectionTimeOutTime[client] = GetGameTime();
-		}
-		
-		if (GetGameTime() >= bootTime)
-		{
-			ClientSetGhostModeState(client, false);
-			TF2_RespawnPlayer(client);
-			
-			decl String:authString[128];
-			GetClientAuthString(client, authString, sizeof(authString));
-			
-			LogSF2Message("Removed %N (%s) from ghost mode due to timing out for %f seconds", client, authString, GetConVarFloat(g_cvGhostModeConnectionTolerance));
-			
-			new Float:timeOutTime = g_flPlayerGhostModeConnectionTimeOutTime[client];
-			CPrintToChat(client, "%T", "SF2 Ghost Mode Bad Connection", client, RoundFloat(bootTime - timeOutTime));
-			
-			return Plugin_Stop;
-		}
-	}
-	else
-	{
-		// Player regained connection; reset.
-		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
-	}
-	
-	return Plugin_Continue;
-}
-
-/**
- *	Makes sure that the player is a ghost when ghost mode is activated.
- */
-ClientHandleGhostMode(client, bool:bForceSpawn=false)
-{
-	if (!IsClientInGhostMode(client)) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
-#endif
-	
-	if (!TF2_IsPlayerInCondition(client, TFCond_HalloweenGhostMode) || bForceSpawn)
-	{
-		TF2_AddCondition(client, TFCond_HalloweenGhostMode, -1.0);
-		SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_DEBRIS);
-		
-		// Set first observer target.
-		ClientGhostModeNextTarget(client);
-		ClientActivateUltravision(client);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
-#endif
-}
-
-ClientGhostModeNextTarget(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientGhostModeNextTarget(%d)", client);
-#endif
-	
-	new iLastTarget = EntRefToEntIndex(g_iPlayerGhostModeTarget[client]);
-	new iNextTarget = -1;
-	new iFirstTarget = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (IsClientInGame(i) && (!g_bPlayerEliminated[i] || g_bPlayerProxy[i]) && !IsClientInGhostMode(i) && !DidClientEscape(i) && IsPlayerAlive(i))
-		{
-			if (iFirstTarget == -1) iFirstTarget = i;
-			if (i > iLastTarget) 
-			{
-				iNextTarget = i;
-				break;
-			}
-		}
-	}
-	
-	new iTarget = -1;
-	if (IsValidClient(iNextTarget)) iTarget = iNextTarget;
-	else iTarget = iFirstTarget;
-	
-	if (IsValidClient(iTarget))
-	{
-		g_iPlayerGhostModeTarget[client] = EntIndexToEntRef(iTarget);
-		
-		decl Float:flPos[3], Float:flAng[3], Float:flVelocity[3];
-		GetClientAbsOrigin(iTarget, flPos);
-		GetClientEyeAngles(iTarget, flAng);
-		GetEntPropVector(iTarget, Prop_Data, "m_vecAbsVelocity", flVelocity);
-		TeleportEntity(client, flPos, flAng, flVelocity);
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientGhostModeNextTarget(%d)", client);
-#endif
-}
-
-bool:IsClientInGhostMode(client)
-{
-	return g_bPlayerGhostMode[client];
-}
-
-//	==========================================================
-//	SCARE FUNCTIONS
-//	==========================================================
-
-ClientPerformScare(client, iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		LogError("Could not perform scare on client %d: boss does not exist!", client);
-		return;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	g_flPlayerScareLastTime[client][iBossIndex] = GetGameTime();
-	g_flPlayerScareNextTime[client][iBossIndex] = GetGameTime() + NPCGetScareCooldown(iBossIndex);
-	
-	// See how much Sanity should be drained from a scare.
-	new Float:flStaticAmount = GetProfileFloat(sProfile, "scare_static_amount", 0.0);
-	g_flPlayerStaticAmount[client] += flStaticAmount;
-	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
-	
-	decl String:sScareSound[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_scare_player", sScareSound, sizeof(sScareSound));
-	
-	if (sScareSound[0])
-	{
-		EmitSoundToClient(client, sScareSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		
-		if (NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)
-		{
-			new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
-			new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
-			
-			g_flPlayerSightSoundNextTime[client][iBossIndex] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
-		}
-		
-		if (g_flPlayerStress[client] > 0.4)
-		{
-			ClientAddStress(client, 0.4);
-		}
-		else
-		{
-			ClientAddStress(client, 0.66);
-		}
-	}
-	else
-	{
-		if (g_flPlayerStress[client] > 0.4)
-		{
-			ClientAddStress(client, 0.3);
-		}
-		else
-		{
-			ClientAddStress(client, 0.45);
-		}
-	}
-}
-
-ClientPerformSightSound(client, iBossIndex)
-{
-	if (NPCGetUniqueID(iBossIndex) == -1)
-	{
-		LogError("Could not perform sight sound on client %d: boss does not exist!", client);
-		return;
-	}
-	
-	if (!(NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)) return;
-	
-	new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]);
-	if (iMaster == -1) iMaster = iBossIndex;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sSightSound[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_sight", sSightSound, sizeof(sSightSound));
-	
-	if (sSightSound[0])
-	{
-		EmitSoundToClient(client, sSightSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
-		
-		new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
-		new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
-		
-		g_flPlayerSightSoundNextTime[client][iMaster] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
-		
-		decl Float:flBossPos[3], Float:flMyPos[3];
-		new iBoss = NPCGetEntIndex(iBossIndex);
-		GetClientAbsOrigin(client, flMyPos);
-		GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flBossPos);
-		new Float:flDistUnComfortZone = 400.0;
-		new Float:flBossDist = GetVectorDistance(flMyPos, flBossPos);
-		
-		new Float:flStressScalar = 1.0 + (flDistUnComfortZone / flBossDist);
-		
-		ClientAddStress(client, 0.1 * flStressScalar);
-	}
-	else
-	{
-		LogError("Warning! %s supports sight sounds, but was given a blank sound!", sProfile);
-	}
-}
-
-ClientResetScare(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetScare(%d)", client);
-#endif
-
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_flPlayerScareNextTime[client][i] = -1.0;
-		g_flPlayerScareLastTime[client][i] = -1.0;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetScare(%d)", client);
-#endif
-}
-
-//	==========================================================
-//	ANTI-CAMPING FUNCTIONS
-//	==========================================================
-
-stock ClientResetCampingStats(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetCampingStats(%d)", client);
-#endif
-
-	g_iPlayerCampingStrikes[client] = 0;
-	g_hPlayerCampingTimer[client] = INVALID_HANDLE;
-	g_bPlayerCampingFirstTime[client] = true;
-	g_flPlayerCampingLastPosition[client][0] = 0.0;
-	g_flPlayerCampingLastPosition[client][1] = 0.0;
-	g_flPlayerCampingLastPosition[client][2] = 0.0;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetCampingStats(%d)", client);
-#endif
-}
-
-ClientStartCampingTimer(client)
-{
-	g_hPlayerCampingTimer[client] = CreateTimer(5.0, Timer_ClientCheckCamp, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_ClientCheckCamp(Handle:timer, any:userid)
-{
-	if (IsRoundInWarmup()) return Plugin_Stop;
-
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerCampingTimer[client]) return Plugin_Stop;
-	
-	if (IsRoundEnding() || !IsPlayerAlive(client) || g_bPlayerEliminated[client] || DidClientEscape(client)) return Plugin_Stop;
-	
-	if (!g_bPlayerCampingFirstTime[client])
-	{
-		decl Float:flPos[3], Float:flMaxs[3], Float:flMins[3];
-		GetClientAbsOrigin(client, flPos);
-		GetEntPropVector(client, Prop_Send, "m_vecMins", flMins);
-		GetEntPropVector(client, Prop_Send, "m_vecMaxs", flMaxs);
-		
-		// Only do something if the player is NOT stuck.
-		new Float:flDistFromLastPosition = GetVectorDistance(g_flPlayerCampingLastPosition[client], flPos);
-		new Float:flDistFromClosestBoss = 9999999.0;
-		new iClosestBoss = -1;
-		
-		for (new i = 0; i < MAX_BOSSES; i++)
-		{
-			if (NPCGetUniqueID(i) == -1) continue;
-			
-			new iSlender = NPCGetEntIndex(i);
-			if (!iSlender || iSlender == INVALID_ENT_REFERENCE) continue;
-			
-			decl Float:flSlenderPos[3];
-			SlenderGetAbsOrigin(i, flSlenderPos);
-			
-			new Float:flDist = GetVectorDistance(flSlenderPos, flPos);
-			if (flDist < flDistFromClosestBoss)
-			{
-				iClosestBoss = i;
-				flDistFromClosestBoss = flDist;
-			}
-		}
-		
-		if (GetConVarBool(g_cvCampingEnabled) && 
-			!g_bRoundGrace && 
-			!IsSpaceOccupiedIgnorePlayers(flPos, flMins, flMaxs, client) && 
-			g_flPlayerStaticAmount[client] <= GetConVarFloat(g_cvCampingNoStrikeSanity) && 
-			(iClosestBoss == -1 || flDistFromClosestBoss >= GetConVarFloat(g_cvCampingNoStrikeBossDistance)) &&
-			flDistFromLastPosition <= GetConVarFloat(g_cvCampingMinDistance))
-		{
-			g_iPlayerCampingStrikes[client]++;
-			if (g_iPlayerCampingStrikes[client] < GetConVarInt(g_cvCampingMaxStrikes))
-			{
-				if (g_iPlayerCampingStrikes[client] >= GetConVarInt(g_cvCampingStrikesWarn))
-				{
-					CPrintToChat(client, "{red}%T", "SF2 Camping System Warning", client, (GetConVarInt(g_cvCampingMaxStrikes) - g_iPlayerCampingStrikes[client]) * 5);
-				}
-			}
-			else
-			{
-				g_iPlayerCampingStrikes[client] = 0;
-				ClientStartDeathCam(client, 0, flPos);
-			}
-		}
-		else
-		{
-			// Forgiveness.
-			if (g_iPlayerCampingStrikes[client] > 0) g_iPlayerCampingStrikes[client]--;
-		}
-		
-		g_flPlayerCampingLastPosition[client][0] = flPos[0];
-		g_flPlayerCampingLastPosition[client][1] = flPos[1];
-		g_flPlayerCampingLastPosition[client][2] = flPos[2];
-	}
-	else
-	{
-		g_bPlayerCampingFirstTime[client] = false;
-	}
-	
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	BLINK FUNCTIONS
-//	==========================================================
-
-bool:IsClientBlinking(client)
-{
-	return g_bPlayerBlink[client];
-}
-
-Float:ClientGetBlinkMeter(client)
-{
-	return g_flPlayerBlinkMeter[client];
-}
-
-ClientGetBlinkCount(client)
-{
-	return g_iPlayerBlinkCount[client];
-}
-
-/**
- *	Resets all data on blinking.
- */
-ClientResetBlink(client)
-{
-	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
-	g_bPlayerBlink[client] = false;
-	g_flPlayerBlinkMeter[client] = 1.0;
-	g_iPlayerBlinkCount[client] = 0;
-}
-
-/**
- *	Sets the player into a blinking state and blinds the player
- */
-ClientBlink(client)
-{
-	if (IsRoundInWarmup() || DidClientEscape(client)) return;
-	
-	if (IsClientBlinking(client)) return;
-	
-	g_bPlayerBlink[client] = true;
-	g_iPlayerBlinkCount[client]++;
-	g_flPlayerBlinkMeter[client] = 0.0;
-	g_hPlayerBlinkTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerBlinkHoldTime), Timer_BlinkTimer2, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
-	
-	UTIL_ScreenFade(client, 100, RoundToFloor(GetConVarFloat(g_cvPlayerBlinkHoldTime) * 1000.0), FFADE_IN, 0, 0, 0, 255);
-	
-	Call_StartForward(fOnClientBlink);
-	Call_PushCell(client);
-	Call_Finish();
-}
-
-/**
- *	Unsets the player from the blinking state.
- */
-ClientUnblink(client)
-{
-	if (!IsClientBlinking(client)) return;
-	
-	g_bPlayerBlink[client] = false;
-	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
-	g_flPlayerBlinkMeter[client] = 1.0;
-}
-
-ClientStartDrainingBlinkMeter(client)
-{
-	g_hPlayerBlinkTimer[client] = CreateTimer(ClientGetBlinkRate(client), Timer_BlinkTimer, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-}
-
-public Action:Timer_BlinkTimer(Handle:timer, any:userid)
-{
-	if (IsRoundInWarmup()) return Plugin_Stop;
-
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerBlinkTimer[client]) return Plugin_Stop;
-	
-	if (IsPlayerAlive(client) && !IsClientInDeathCam(client) && !g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !IsRoundEnding())
-	{
-		new iOverride = GetConVarInt(g_cvPlayerInfiniteBlinkOverride);
-		if ((!g_bRoundInfiniteBlink && iOverride != 1) || iOverride == 0)
-		{
-			g_flPlayerBlinkMeter[client] -= 0.05;
-		}
-		
-		if (g_flPlayerBlinkMeter[client] <= 0.0)
-		{
-			ClientBlink(client);
-			return Plugin_Stop;
-		}
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_BlinkTimer2(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (timer != g_hPlayerBlinkTimer[client]) return;
-	
-	ClientUnblink(client);
-	ClientStartDrainingBlinkMeter(client);
-}
-
-Float:ClientGetBlinkRate(client)
-{
-	new Float:flValue = GetConVarFloat(g_cvPlayerBlinkRate);
-	if (GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 3) 
-	{
-		// Being underwater makes you blink faster, obviously.
-		flValue *= 0.75;
-	}
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (NPCGetUniqueID(i) == -1) continue;
-		
-		NPCGetProfile(i, sProfile, sizeof(sProfile));
-		
-		if (g_bPlayerSeesSlender[client][i]) 
-		{
-			flValue *= GetProfileFloat(sProfile, "blink_look_rate_multiply", 1.0);
-		}
-		
-		else if (g_iPlayerStaticMode[client][i] == Static_Increase)
-		{
-			flValue *= GetProfileFloat(sProfile, "blink_static_rate_multiply", 1.0);
-		}
-	}
-	
-	if (TF2_GetPlayerClass(client) == TFClass_Sniper) flValue *= 1.4;
-	
-	if (IsClientUsingFlashlight(client))
-	{
-		decl Float:startPos[3], Float:endPos[3], Float:flDirection[3];
-		new Float:flLength = SF2_FLASHLIGHT_LENGTH;
-		GetClientEyePosition(client, startPos);
-		GetClientEyePosition(client, endPos);
-		GetClientEyeAngles(client, flDirection);
-		GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
-		NormalizeVector(flDirection, flDirection);
-		ScaleVector(flDirection, flLength);
-		AddVectors(endPos, flDirection, endPos);
-		new Handle:hTrace = TR_TraceRayFilterEx(startPos, endPos, MASK_VISIBLE, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
-		TR_GetEndPosition(endPos, hTrace);
-		new bool:bHit = TR_DidHit(hTrace);
-		CloseHandle(hTrace);
-		
-		if (bHit)
-		{
-			new Float:flPercent = (GetVectorDistance(startPos, endPos) / flLength);
-			flPercent *= 3.5;
-			if (flPercent > 1.0) flPercent = 1.0;
-			flValue *= flPercent;
-		}
-	}
-	
-	return flValue;
-}
-
-//	==========================================================
-//	SCREEN OVERLAY FUNCTIONS
-//	==========================================================
-
-ClientAddStress(client, Float:flStressAmount)
-{
-	g_flPlayerStress[client] += flStressAmount;
-	if (g_flPlayerStress[client] < 0.0) g_flPlayerStress[client] = 0.0;
-	if (g_flPlayerStress[client] > 1.0) g_flPlayerStress[client] = 1.0;
-	
-	//PrintCenterText(client, "g_flPlayerStress[%d] = %f", client, g_flPlayerStress[client]);
-	
-	SlenderOnClientStressUpdate(client);
-}
-
-stock ClientResetOverlay(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetOverlay(%d)", client);
-#endif
-	
-	g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
-	
-	if (IsClientInGame(client))
-	{
-		ClientCommand(client, "r_screenoverlay \"\"");
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetOverlay(%d)", client);
-#endif
-}
-
-public Action:Timer_PlayerOverlayCheck(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerOverlayCheck[client]) return Plugin_Stop;
-	
-	if (IsRoundInWarmup()) return Plugin_Continue;
-	
-	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
-	new iJumpScareBoss = NPCGetFromUniqueID(g_iPlayerJumpScareBoss[client]);
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	decl String:sMaterial[PLATFORM_MAX_PATH];
-	
-	if (IsClientInDeathCam(client) && iDeathCamBoss != -1 && g_bPlayerDeathCamShowOverlay[client])
-	{
-		NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
-		GetRandomStringFromProfile(sProfile, "overlay_player_death", sMaterial, sizeof(sMaterial), 1);
-	}
-	else if (iJumpScareBoss != -1 && GetGameTime() <= g_flPlayerJumpScareLifeTime[client])
-	{
-		NPCGetProfile(iJumpScareBoss, sProfile, sizeof(sProfile));
-		GetRandomStringFromProfile(sProfile, "overlay_jumpscare", sMaterial, sizeof(sMaterial), 1);
-	}
-	else if (IsClientInGhostMode(client))
-	{
-		strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_GHOST);
-	}
-	else if (IsRoundInWarmup() || g_bPlayerEliminated[client] || DidClientEscape(client) && !IsClientInGhostMode(client))
-	{
-		return Plugin_Continue;
-	}
-	else
-	{
-		if (!g_iPlayerPreferences[client][PlayerPreference_FilmGrain])
-			strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_DEFAULT_NO_FILMGRAIN);
-		else
-			strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_DEFAULT);
-	}
-	
-	ClientCommand(client, "r_screenoverlay %s", sMaterial);
-	return Plugin_Continue;
-}
-
-//	==========================================================
-//	MUSIC SYSTEM FUNCTIONS
-//	==========================================================
-
-stock ClientUpdateMusicSystem(client, bool:bInitialize=false)
-{
-	new iOldPageMusicMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
-	new iOldMusicFlags = g_iPlayerMusicFlags[client];
-	new iChasingBoss = -1;
-	new iChasingSeeBoss = -1;
-	new iAlertBoss = -1;
-	new i20DollarsBoss = -1;
-	
-	if (IsRoundEnding() || !IsClientInGame(client) || IsFakeClient(client) || DidClientEscape(client) || (g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !g_bPlayerProxy[client])) 
-	{
-		g_iPlayerMusicFlags[client] = 0;
-		g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-	}
-	else
-	{
-		new bool:bPlayMusicOnEscape = true;
-		decl String:sName[64];
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
-		{
-			GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
-			if (StrEqual(sName, "sf2_escape_custommusic", false))
-			{
-				bPlayMusicOnEscape = false;
-				break;
-			}
-		}
-		
-		// Page music first.
-		new iPageRange = 0;
-		
-		if (GetArraySize(g_hPageMusicRanges) > 0) // Map has its own defined page music?
-		{
-			for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
-			{
-				ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
-				if (!ent || ent == INVALID_ENT_REFERENCE) continue;
-				
-				new iMin = GetArrayCell(g_hPageMusicRanges, i, 1);
-				new iMax = GetArrayCell(g_hPageMusicRanges, i, 2);
-				
-				if (g_iPageCount >= iMin && g_iPageCount <= iMax)
-				{
-					g_iPlayerPageMusicMaster[client] = GetArrayCell(g_hPageMusicRanges, i);
-					break;
-				}
-			}
-		}
-		else // Nope. Use old system instead.
-		{
-			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-		
-			new Float:flPercent = g_iPageMax > 0 ? (float(g_iPageCount) / float(g_iPageMax)) : 0.0;
-			if (flPercent > 0.0 && flPercent <= 0.25) iPageRange = 1;
-			else if (flPercent > 0.25 && flPercent <= 0.5) iPageRange = 2;
-			else if (flPercent > 0.5 && flPercent <= 0.75) iPageRange = 3;
-			else if (flPercent > 0.75) iPageRange = 4;
-			
-			if (iPageRange == 1) ClientAddMusicFlag(client, MUSICF_PAGES1PERCENT);
-			else if (iPageRange == 2) ClientAddMusicFlag(client, MUSICF_PAGES25PERCENT);
-			else if (iPageRange == 3) ClientAddMusicFlag(client, MUSICF_PAGES50PERCENT);
-			else if (iPageRange == 4) ClientAddMusicFlag(client, MUSICF_PAGES75PERCENT);
-		}
-		
-		if (iPageRange != 1) ClientRemoveMusicFlag(client, MUSICF_PAGES1PERCENT);
-		if (iPageRange != 2) ClientRemoveMusicFlag(client, MUSICF_PAGES25PERCENT);
-		if (iPageRange != 3) ClientRemoveMusicFlag(client, MUSICF_PAGES50PERCENT);
-		if (iPageRange != 4) ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
-		
-		if (IsRoundInEscapeObjective() && !bPlayMusicOnEscape) 
-		{
-			ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
-			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-		}
-		
-		new iOldChasingBoss = g_iPlayerChaseMusicMaster[client];
-		new iOldChasingSeeBoss = g_iPlayerChaseMusicSeeMaster[client];
-		new iOldAlertBoss = g_iPlayerAlertMusicMaster[client];
-		new iOld20DollarsBoss = g_iPlayer20DollarsMusicMaster[client];
-		
-		new Float:flAnger = -1.0;
-		new Float:flSeeAnger = -1.0;
-		new Float:flAlertAnger = -1.0;
-		new Float:fl20DollarsAnger = -1.0;
-		
-		decl Float:flBuffer[3], Float:flBuffer2[3], Float:flBuffer3[3];
-		
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		
-		for (new i = 0; i < MAX_BOSSES; i++)
-		{
-			if (NPCGetUniqueID(i) == -1) continue;
-			
-			if (NPCGetEntIndex(i) == INVALID_ENT_REFERENCE) continue;
-			
-			NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-			new iBossType = NPCGetType(i);
-			
-			switch (iBossType)
-			{
-				case SF2BossType_Chaser:
-				{
-					GetClientAbsOrigin(client, flBuffer);
-					SlenderGetAbsOrigin(i, flBuffer3);
-					
-					new iTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
-					if (iTarget != -1)
-					{
-						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flBuffer2);
-						
-						if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK || g_iSlenderState[i] == STATE_STUN) &&
-							!(NPCGetFlags(i) & SFF_MARKEDASFAKE) && 
-							(iTarget == client || GetVectorDistance(flBuffer, flBuffer2) <= 850.0 || GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0))
-						{
-							decl String:sPath[PLATFORM_MAX_PATH];
-							GetRandomStringFromProfile(sProfile, "sound_chase_music", sPath, sizeof(sPath), 1);
-							if (sPath[0])
-							{
-								if (NPCGetAnger(i) > flAnger)
-								{
-									flAnger = NPCGetAnger(i);
-									iChasingBoss = i;
-								}
-							}
-							
-							if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK) &&
-								PlayerCanSeeSlender(client, i, false))
-							{
-								if (iOldChasingSeeBoss == -1 || !PlayerCanSeeSlender(client, iOldChasingSeeBoss, false) || (NPCGetAnger(i) > flSeeAnger))
-								{
-									GetRandomStringFromProfile(sProfile, "sound_chase_visible", sPath, sizeof(sPath), 1);
-									
-									if (sPath[0])
-									{
-										flSeeAnger = NPCGetAnger(i);
-										iChasingSeeBoss = i;
-									}
-								}
-								
-								if (g_b20Dollars)
-								{
-									if (iOld20DollarsBoss == -1 || !PlayerCanSeeSlender(client, iOld20DollarsBoss, false) || (NPCGetAnger(i) > fl20DollarsAnger))
-									{
-										GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sPath, sizeof(sPath), 1);
-										
-										if (sPath[0])
-										{
-											fl20DollarsAnger = NPCGetAnger(i);
-											i20DollarsBoss = i;
-										}
-									}
-								}
-							}
-						}
-					}
-					
-					if (g_iSlenderState[i] == STATE_ALERT)
-					{
-						decl String:sPath[PLATFORM_MAX_PATH];
-						GetRandomStringFromProfile(sProfile, "sound_alert_music", sPath, sizeof(sPath), 1);
-						if (!sPath[0]) continue;
-					
-						if (!(NPCGetFlags(i) & SFF_MARKEDASFAKE))
-						{
-							if (GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0)
-							{
-								if (NPCGetAnger(i) > flAlertAnger)
-								{
-									flAlertAnger = NPCGetAnger(i);
-									iAlertBoss = i;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		if (iChasingBoss != iOldChasingBoss)
-		{
-			if (iChasingBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_CHASE);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_CHASE);
-			}
-		}
-		
-		if (iChasingSeeBoss != iOldChasingSeeBoss)
-		{
-			if (iChasingSeeBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_CHASEVISIBLE);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_CHASEVISIBLE);
-			}
-		}
-		
-		if (iAlertBoss != iOldAlertBoss)
-		{
-			if (iAlertBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_ALERT);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_ALERT);
-			}
-		}
-		
-		if (i20DollarsBoss != iOld20DollarsBoss)
-		{
-			if (i20DollarsBoss != -1)
-			{
-				ClientAddMusicFlag(client, MUSICF_20DOLLARS);
-			}
-			else
-			{
-				ClientRemoveMusicFlag(client, MUSICF_20DOLLARS);
-			}
-		}
-	}
-	
-	if (IsValidClient(client))
-	{
-		new bool:bWasChase = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASE);
-		new bool:bChase = ClientHasMusicFlag(client, MUSICF_CHASE);
-		new bool:bWasChaseSee = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASEVISIBLE);
-		new bool:bChaseSee = ClientHasMusicFlag(client, MUSICF_CHASEVISIBLE);
-		new bool:bAlert = ClientHasMusicFlag(client, MUSICF_ALERT);
-		new bool:bWasAlert = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_ALERT);
-		new bool:b20Dollars = ClientHasMusicFlag(client, MUSICF_20DOLLARS);
-		new bool:bWas20Dollars = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_20DOLLARS);
-		
-		// Custom system.
-		if (GetArraySize(g_hPageMusicRanges) > 0) 
-		{
-			decl String:sPath[PLATFORM_MAX_PATH];
-		
-			new iMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
-			if (iMaster != INVALID_ENT_REFERENCE)
-			{
-				for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
-				{
-					new ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
-					if (!ent || ent == INVALID_ENT_REFERENCE) continue;
-					
-					GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-					
-					if (ent == iMaster && 
-						(iOldPageMusicMaster != iMaster || iOldPageMusicMaster == INVALID_ENT_REFERENCE))
-					{
-						if (!sPath[0])
-						{
-							LogError("Could not play music of page range %d-%d: no sound path specified!", GetArrayCell(g_hPageMusicRanges, i, 1), GetArrayCell(g_hPageMusicRanges, i, 2));
-						}
-						else
-						{
-							ClientMusicStart(client, sPath, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-						}
-						
-						if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
-						{
-							GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-							if (sPath[0])
-							{
-								StopSound(client, MUSIC_CHAN, sPath);
-							}
-						}
-					}
-				}
-			}
-			else
-			{
-				if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
-				{
-					GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
-					if (sPath[0])
-					{
-						StopSound(client, MUSIC_CHAN, sPath);
-					}
-				}
-			}
-		}
-		
-		// Old system.
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES1_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES1_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES2_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES2_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES3_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES3_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
-		{
-			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES4_SOUND);
-		}
-		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
-		{
-			ClientMusicStart(client, MUSIC_GOTPAGES4_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		
-		new iMainMusicState = 0;
-		
-		if (bAlert != bWasAlert || iAlertBoss != g_iPlayerAlertMusicMaster[client])
-		{
-			if (bAlert && !bChase)
-			{
-				ClientAlertMusicStart(client, iAlertBoss);
-				if (!bWasAlert) iMainMusicState = -1;
-			}
-			else
-			{
-				ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
-				if (!bChase && bWasAlert) iMainMusicState = 1;
-			}
-		}
-		
-		if (bChase != bWasChase || iChasingBoss != g_iPlayerChaseMusicMaster[client])
-		{
-			if (bChase)
-			{
-				ClientMusicChaseStart(client, iChasingBoss);
-				
-				if (!bWasChase)
-				{
-					iMainMusicState = -1;
-					
-					if (bAlert)
-					{
-						ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
-					}
-				}
-			}
-			else
-			{
-				ClientMusicChaseStop(client, g_iPlayerChaseMusicMaster[client]);
-				if (bWasChase)
-				{
-					if (bAlert)
-					{
-						ClientAlertMusicStart(client, iAlertBoss);
-					}
-					else
-					{
-						iMainMusicState = 1;
-					}
-				}
-			}
-		}
-		
-		if (bChaseSee != bWasChaseSee || iChasingSeeBoss != g_iPlayerChaseMusicSeeMaster[client])
-		{
-			if (bChaseSee)
-			{
-				ClientMusicChaseSeeStart(client, iChasingSeeBoss);
-			}
-			else
-			{
-				ClientMusicChaseSeeStop(client, g_iPlayerChaseMusicSeeMaster[client]);
-			}
-		}
-		
-		if (b20Dollars != bWas20Dollars || i20DollarsBoss != g_iPlayer20DollarsMusicMaster[client])
-		{
-			if (b20Dollars)
-			{
-				Client20DollarsMusicStart(client, i20DollarsBoss);
-			}
-			else
-			{
-				Client20DollarsMusicStop(client, g_iPlayer20DollarsMusicMaster[client]);
-			}
-		}
-		
-		if (iMainMusicState == 1)
-		{
-			ClientMusicStart(client, g_strPlayerMusic[client], _, MUSIC_PAGE_VOLUME, bChase || bAlert);
-		}
-		else if (iMainMusicState == -1)
-		{
-			ClientMusicStop(client);
-		}
-		
-		if (bChase || bAlert)
-		{
-			new iBossToUse = -1;
-			if (bChase)
-			{
-				iBossToUse = iChasingBoss;
-			}
-			else
-			{
-				iBossToUse = iAlertBoss;
-			}
-			
-			if (iBossToUse != -1)
-			{
-				// We got some alert/chase music going on! The player's excitement will no doubt go up!
-				// Excitement, though, really depends on how close the boss is in relation to the
-				// player.
-				
-				new Float:flBossDist = NPCGetDistanceFromEntity(iBossToUse, client);
-				new Float:flScalar = flBossDist / 700.0
-				if (flScalar > 1.0) flScalar = 1.0;
-				new Float:flStressAdd = 0.1 * (1.0 - flScalar);
-				
-				ClientAddStress(client, flStressAdd);
-			}
-		}
-	}
-}
-
-stock ClientMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
-	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerMusicFlags[client] = 0;
-	g_flPlayerMusicVolume[client] = 0.0;
-	g_flPlayerMusicTargetVolume[client] = 0.0;
-	g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-	g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
-}
-
-stock ClientMusicStart(client, const String:sNewMusic[], Float:flVolume=-1.0, Float:flTargetVolume=-1.0, bool:bCopyOnly=false)
-{
-	if (!IsValidClient(client)) return;
-	if (!sNewMusic[0]) return;
-	
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
-	
-	if (!StrEqual(sOldMusic, sNewMusic, false))
-	{
-		if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	}
-	
-	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), sNewMusic);
-	if (flVolume >= 0.0) g_flPlayerMusicVolume[client] = flVolume;
-	if (flTargetVolume >= 0.0) g_flPlayerMusicTargetVolume[client] = flTargetVolume;
-	
-	if (!bCopyOnly)
-	{
-		g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeInMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-		TriggerTimer(g_hPlayerMusicTimer[client], true);
-	}
-	else
-	{
-		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-	}
-}
-
-stock ClientMusicStop(client)
-{
-	g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeOutMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerMusicTimer[client], true);
-}
-
-stock Client20DollarsMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayer20DollarsMusic[client]);
-	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayer20DollarsMusicMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayer20DollarsMusicTimer[client][i] = INVALID_HANDLE;
-		g_flPlayer20DollarsMusicVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsValidClient(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-				GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock Client20DollarsMusicStart(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iOldMaster = g_iPlayer20DollarsMusicMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (!sBuffer[0]) return;
-	
-	g_iPlayer20DollarsMusicMaster[client] = iBossIndex;
-	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), sBuffer);
-	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeIn20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientAlertMusicStop(client, iOldMaster);
-	}
-}
-
-stock Client20DollarsMusicStop(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayer20DollarsMusicMaster[client])
-	{
-		g_iPlayer20DollarsMusicMaster[client] = -1;
-		strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
-	}
-	
-	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOut20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
-}
-
-stock ClientAlertMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerAlertMusic[client]);
-	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerAlertMusicMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayerAlertMusicTimer[client][i] = INVALID_HANDLE;
-		g_flPlayerAlertMusicVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsValidClient(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-				GetRandomStringFromProfile(sProfile, "sound_alert_music", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock ClientAlertMusicStart(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iOldMaster = g_iPlayerAlertMusicMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (!sBuffer[0]) return;
-	
-	g_iPlayerAlertMusicMaster[client] = iBossIndex;
-	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), sBuffer);
-	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientAlertMusicStop(client, iOldMaster);
-	}
-}
-
-stock ClientAlertMusicStop(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayerAlertMusicMaster[client])
-	{
-		g_iPlayerAlertMusicMaster[client] = -1;
-		strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
-	}
-	
-	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
-}
-
-stock ClientChaseMusicReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusic[client]);
-	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
-	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerChaseMusicMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayerChaseMusicTimer[client][i] = INVALID_HANDLE;
-		g_flPlayerChaseMusicVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsValidClient(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-				
-				GetRandomStringFromProfile(sProfile, "sound_chase_music", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock ClientMusicChaseStart(client, iBossIndex)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iOldMaster = g_iPlayerChaseMusicMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (!sBuffer[0]) return;
-	
-	g_iPlayerChaseMusicMaster[client] = iBossIndex;
-	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), sBuffer);
-	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientMusicChaseStop(client, iOldMaster);
-	}
-}
-
-stock ClientMusicChaseStop(client, iBossIndex)
-{
-	if (!IsClientInGame(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayerChaseMusicMaster[client])
-	{
-		g_iPlayerChaseMusicMaster[client] = -1;
-		strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
-	}
-	
-	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
-}
-
-stock ClientChaseMusicSeeReset(client)
-{
-	new String:sOldMusic[PLATFORM_MAX_PATH];
-	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusicSee[client]);
-	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
-	if (IsClientInGame(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-	
-	g_iPlayerChaseMusicSeeMaster[client] = -1;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_hPlayerChaseMusicSeeTimer[client][i] = INVALID_HANDLE;
-		g_flPlayerChaseMusicSeeVolumes[client][i] = 0.0;
-		
-		if (NPCGetUniqueID(i) != -1)
-		{
-			if (IsClientInGame(client))
-			{
-				NPCGetProfile(i, sProfile, sizeof(sProfile));
-			
-				GetRandomStringFromProfile(sProfile, "sound_chase_visible", sOldMusic, sizeof(sOldMusic), 1);
-				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
-			}
-		}
-	}
-}
-
-stock ClientMusicChaseSeeStart(client, iBossIndex)
-{
-	if (!IsClientInGame(client)) return;
-	
-	new iOldMaster = g_iPlayerChaseMusicSeeMaster[client];
-	if (iOldMaster == iBossIndex) return;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	new String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
-	if (!sBuffer[0]) return;
-	
-	g_iPlayerChaseMusicSeeMaster[client] = iBossIndex;
-	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), sBuffer);
-	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
-	
-	if (iOldMaster != -1)
-	{
-		ClientMusicChaseSeeStop(client, iOldMaster);
-	}
-}
-
-stock ClientMusicChaseSeeStop(client, iBossIndex)
-{
-	if (!IsClientInGame(client)) return;
-	if (iBossIndex == -1) return;
-	
-	if (iBossIndex == g_iPlayerChaseMusicSeeMaster[client])
-	{
-		g_iPlayerChaseMusicSeeMaster[client] = -1;
-		strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
-	}
-	
-	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
-	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
-}
-
-public Action:Timer_PlayerFadeInMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
-	
-	g_flPlayerMusicVolume[client] += 0.07;
-	if (g_flPlayerMusicVolume[client] > g_flPlayerMusicTargetVolume[client]) g_flPlayerMusicVolume[client] = g_flPlayerMusicTargetVolume[client];
-	
-	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
-
-	if (g_flPlayerMusicVolume[client] >= g_flPlayerMusicTargetVolume[client])
-	{
-		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
-
-	g_flPlayerMusicVolume[client] -= 0.07;
-	if (g_flPlayerMusicVolume[client] < 0.0) g_flPlayerMusicVolume[client] = 0.0;
-
-	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
-
-	if (g_flPlayerMusicVolume[client] <= 0.0)
-	{
-		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeIn20DollarsMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-	
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] > 1.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayer20DollarsMusic[client][0]) EmitSoundToClient(client, g_strPlayer20DollarsMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOut20DollarsMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
-	
-	if (StrEqual(sBuffer, g_strPlayer20DollarsMusic[client], false))
-	{
-		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] < 0.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeInAlertMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerAlertMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayerAlertMusicVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayerAlertMusic[client][0]) EmitSoundToClient(client, g_strPlayerAlertMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutAlertMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerAlertMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
-
-	if (StrEqual(sBuffer, g_strPlayerAlertMusic[client], false))
-	{
-		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayerAlertMusicVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeInChaseMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayerChaseMusicVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayerChaseMusic[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeInChaseMusicSee(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] += 0.07;
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 1.0;
-
-	if (g_strPlayerChaseMusicSee[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusicSee[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] >= 1.0)
-	{
-		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutChaseMusic(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
-
-	if (StrEqual(sBuffer, g_strPlayerChaseMusic[client], false))
-	{
-		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayerChaseMusicVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-public Action:Timer_PlayerFadeOutChaseMusicSee(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return Plugin_Stop;
-
-	new iBossIndex = -1;
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
-		{
-			iBossIndex = i;
-			break;
-		}
-	}
-	
-	if (iBossIndex == -1) return Plugin_Stop;
-	
-	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
-	
-	decl String:sBuffer[PLATFORM_MAX_PATH];
-	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
-
-	if (StrEqual(sBuffer, g_strPlayerChaseMusicSee[client], false))
-	{
-		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] -= 0.07;
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 0.0;
-
-	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
-	
-	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] <= 0.0)
-	{
-		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
-		return Plugin_Stop;
-	}
-	
-	return Plugin_Continue;
-}
-
-stock bool:ClientHasMusicFlag(client, iFlag)
-{
-	return bool:(g_iPlayerMusicFlags[client] & iFlag);
-}
-
-stock bool:ClientHasMusicFlag2(iValue, iFlag)
-{
-	return bool:(iValue & iFlag);
-}
-
-stock ClientAddMusicFlag(client, iFlag)
-{
-	if (!ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] |= iFlag;
-}
-
-stock ClientRemoveMusicFlag(client, iFlag)
-{
-	if (ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] &= ~iFlag;
-}
-
-//	==========================================================
-//	MISC FUNCTIONS
-//	==========================================================
-
-// This could be used for entities as well.
-stock ClientStopAllSlenderSounds(client, const String:profileName[], const String:sectionName[], iChannel)
-{
-	if (!client || !IsValidEntity(client)) return;
-	
-	if (!IsProfileValid(profileName)) return;
-	
-	decl String:buffer[PLATFORM_MAX_PATH];
-	
-	KvRewind(g_hConfig);
-	if (KvJumpToKey(g_hConfig, profileName))
-	{
-		decl String:s[32];
-		
-		if (KvJumpToKey(g_hConfig, sectionName))
-		{
-			for (new i2 = 1;; i2++)
-			{
-				IntToString(i2, s, sizeof(s));
-				KvGetString(g_hConfig, s, buffer, sizeof(buffer));
-				if (!buffer[0]) break;
-				
-				StopSound(client, iChannel, buffer);
-			}
-		}
-	}
-}
-
-stock ClientUpdateListeningFlags(client, bool:bReset=false)
-{
-	if (!IsClientInGame(client)) return;
-	
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (i == client || !IsClientInGame(i)) continue;
-		
-		if (bReset || IsRoundEnding() || GetConVarBool(g_cvAllChat))
-		{
-			SetListenOverride(client, i, Listen_Default);
-			continue;
-		}
-		
-		new MuteMode:iMuteMode = g_iPlayerPreferences[client][PlayerPreference_MuteMode];
-		
-		if (g_bPlayerEliminated[client])
-		{
-			if (!g_bPlayerEliminated[i])
-			{
-				if (iMuteMode == MuteMode_DontHearOtherTeam)
-				{
-					SetListenOverride(client, i, Listen_No);
-				}
-				else if (iMuteMode == MuteMode_DontHearOtherTeamIfNotProxy && !g_bPlayerProxy[client])
-				{
-					SetListenOverride(client, i, Listen_No);
-				}
-				else
-				{
-					SetListenOverride(client, i, Listen_Default);
-				}
-			}
-			else
-			{
-				SetListenOverride(client, i, Listen_Default);
-			}
-		}
-		else
-		{
-			if (!g_bPlayerEliminated[i])
-			{
-				if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
-				{
-					if (DidClientEscape(i))
-					{
-						if (!DidClientEscape(client))
-						{
-							SetListenOverride(client, i, Listen_No);
-						}
-						else
-						{
-							SetListenOverride(client, i, Listen_Default);
-						}
-					}
-					else
-					{
-						if (!DidClientEscape(client))
-						{
-							SetListenOverride(client, i, Listen_No);
-						}
-						else
-						{
-							SetListenOverride(client, i, Listen_Default);
-						}
-					}
-				}
-				else
-				{
-					new bool:bCanHear = false;
-					if (GetConVarFloat(g_cvPlayerVoiceDistance) <= 0.0) bCanHear = true;
-					
-					if (!bCanHear)
-					{
-						decl Float:flMyPos[3], Float:flHisPos[3];
-						GetClientEyePosition(client, flMyPos);
-						GetClientEyePosition(i, flHisPos);
-						
-						new Float:flDist = GetVectorDistance(flMyPos, flHisPos);
-						
-						if (GetConVarFloat(g_cvPlayerVoiceWallScale) > 0.0)
-						{
-							new Handle:hTrace = TR_TraceRayFilterEx(flMyPos, flHisPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, TraceRayDontHitCharacters);
-							new bool:bDidHit = TR_DidHit(hTrace);
-							CloseHandle(hTrace);
-							
-							if (bDidHit)
-							{
-								flDist *= GetConVarFloat(g_cvPlayerVoiceWallScale);
-							}
-						}
-						
-						if (flDist <= GetConVarFloat(g_cvPlayerVoiceDistance))
-						{
-							bCanHear = true;
-						}
-					}
-					
-					if (bCanHear)
-					{
-						if (IsClientInGhostMode(i) != IsClientInGhostMode(client) &&
-							DidClientEscape(i) != DidClientEscape(client))
-						{
-							bCanHear = false;
-						}
-					}
-					
-					if (bCanHear)
-					{
-						SetListenOverride(client, i, Listen_Default);
-					}
-					else
-					{
-						SetListenOverride(client, i, Listen_No);
-					}
-				}
-			}
-			else
-			{
-				SetListenOverride(client, i, Listen_No);
-			}
-		}
-	}
-}
-
-stock ClientShowMainMessage(client, const String:sMessage[], any:...)
-{
-	decl String:message[512];
-	VFormat(message, sizeof(message), sMessage, 3);
-	
-	SetHudTextParams(-1.0, 0.4,
-		5.0,
-		255,
-		255,
-		255,
-		200,
-		2,
-		1.0,
-		0.07,
-		2.0);
-	ShowSyncHudText(client, g_hHudSync, message);
-}
-
-stock ClientResetSlenderStats(client)
-{
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSlenderStats(%d)", client);
-#endif
-	
-	g_flPlayerStress[client] = 0.0;
-	g_flPlayerStressNextUpdateTime[client] = -1.0;
-	
-	for (new i = 0; i < MAX_BOSSES; i++)
-	{
-		g_bPlayerSeesSlender[client][i] = false;
-		g_flPlayerSeesSlenderLastTime[client][i] = -1.0;
-		g_flPlayerSightSoundNextTime[client][i] = -1.0;
-	}
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSlenderStats(%d)", client);
-#endif
-}
-
-bool:ClientSetQueuePoints(client, iAmount)
-{
-	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return false;
-	g_iPlayerQueuePoints[client] = iAmount;
-	ClientSaveCookies(client);
-	return true;
-}
-
-ClientSaveCookies(client)
-{
-	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return;
-	
-	// Save and reset our queue points.
-	decl String:s[64];
-	Format(s, sizeof(s), "%d ; %d ; %d ; %d ; %d ; %d", g_iPlayerQueuePoints[client], 
-		g_iPlayerPreferences[client][PlayerPreference_ShowHints], 
-		g_iPlayerPreferences[client][PlayerPreference_MuteMode], 
-		g_iPlayerPreferences[client][PlayerPreference_FilmGrain],
-		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection],
-		g_iPlayerPreferences[client][PlayerPreference_GhostOverlay]);
-		
-	SetClientCookie(client, g_hCookie, s);
-}
-
-stock ClientViewPunch(client, const Float:angleOffset[3])
-{
-	if (g_offsPlayerPunchAngleVel == -1) return;
-	
-	decl Float:flOffset[3];
-	for (new i = 0; i < 3; i++) flOffset[i] = angleOffset[i];
-	ScaleVector(flOffset, 20.0);
-	
-	/*
-	if (!IsFakeClient(client))
-	{
-		// Latency compensation.
-		new Float:flLatency = GetClientLatency(client, NetFlow_Outgoing);
-		new Float:flLatencyCalcDiff = 60.0 * Pow(flLatency, 2.0);
-		
-		for (new i = 0; i < 3; i++) flOffset[i] += (flOffset[i] * flLatencyCalcDiff);
-	}
-	*/
-	
-	decl Float:flAngleVel[3];
-	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flAngleVel);
-	AddVectors(flAngleVel, flOffset, flOffset);
-	SetEntDataVector(client, g_offsPlayerPunchAngleVel, flOffset, true);
-}
-
-public Action:Hook_ConstantGlowSetTransmit(ent, other)
-{
-	if (!g_bEnabled) return Plugin_Continue;
-	
-	new iOwner = -1;
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		if (EntRefToEntIndex(g_iPlayerConstantGlowEntity[i]) == ent)
-		{
-			iOwner = i;
-			break;
-		}
-	}
-	
-	if (iOwner != -1)
-	{
-		if (!IsPlayerAlive(iOwner) || g_bPlayerEliminated[iOwner]) return Plugin_Handled;
-		if (!IsPlayerAlive(other) || (!g_bPlayerProxy[other] && !IsClientInGhostMode(other))) return Plugin_Handled;
-	}
-	
-	return Plugin_Continue;
-}
-
-stock ClientSetFOV(client, iFOV)
-{
-	SetEntData(client, g_offsPlayerFOV, iFOV);
-	SetEntData(client, g_offsPlayerDefaultFOV, iFOV);
-}
-
-stock TF2_GetClassName(TFClassType:iClass, String:sBuffer[], sBufferLen)
-{
-	switch (iClass)
-	{
-		case TFClass_Scout: strcopy(sBuffer, sBufferLen, "scout");
-		case TFClass_Sniper: strcopy(sBuffer, sBufferLen, "sniper");
-		case TFClass_Soldier: strcopy(sBuffer, sBufferLen, "soldier");
-		case TFClass_DemoMan: strcopy(sBuffer, sBufferLen, "demoman");
-		case TFClass_Heavy: strcopy(sBuffer, sBufferLen, "heavyweapons");
-		case TFClass_Medic: strcopy(sBuffer, sBufferLen, "medic");
-		case TFClass_Pyro: strcopy(sBuffer, sBufferLen, "pyro");
-		case TFClass_Spy: strcopy(sBuffer, sBufferLen, "spy");
-		case TFClass_Engineer: strcopy(sBuffer, sBufferLen, "engineer");
-		default: strcopy(sBuffer, sBufferLen, "");
-	}
-}
-
-#define EF_DIMLIGHT (1 << 2)
-
-stock ClientSDKFlashlightTurnOn(client)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-	if (iEffects & EF_DIMLIGHT) return;
-
-	iEffects |= EF_DIMLIGHT;
-	
-	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
-}
-
-stock ClientSDKFlashlightTurnOff(client)
-{
-	if (!IsValidClient(client)) return;
-	
-	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
-	if (!(iEffects & EF_DIMLIGHT)) return;
-
-	iEffects &= ~EF_DIMLIGHT;
-	
-	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
-}
-
-stock bool:IsPointVisibleToAPlayer(const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false)
-{
-	for (new i = 1; i <= MaxClients; i++)
-	{
-		if (!IsClientInGame(i)) continue;
-		if (IsPointVisibleToPlayer(i, pos, bCheckFOV, bCheckBlink)) return true;
-	}
-	
-	return false;
-}
-
-stock bool:IsPointVisibleToPlayer(client, const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
-{
-	if (!IsValidClient(client) || !IsPlayerAlive(client) || IsClientInGhostMode(client)) return false;
-	
-	if (bCheckEliminated && g_bPlayerEliminated[client]) return false;
-	
-	if (bCheckBlink && IsClientBlinking(client)) return false;
-	
-	decl Float:eyePos[3];
-	GetClientEyePosition(client, eyePos);
-	
-	// Check fog, if we can.
-	if (g_offsPlayerFogCtrl != -1 && g_offsFogCtrlEnable != -1 && g_offsFogCtrlEnd != -1)
-	{
-		new iFogEntity = GetEntDataEnt2(client, g_offsPlayerFogCtrl);
-		if (IsValidEdict(iFogEntity))
-		{
-			if (GetEntData(iFogEntity, g_offsFogCtrlEnable) &&
-				GetVectorDistance(eyePos, pos) >= GetEntDataFloat(iFogEntity, g_offsFogCtrlEnd)) 
-			{
-				return false;
-			}
-		}
-	}
-	
-	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, pos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
-	new bool:bHit = TR_DidHit(hTrace);
-	CloseHandle(hTrace);
-	
-	if (bHit) return false;
-	
-	if (bCheckFOV)
-	{
-		decl Float:eyeAng[3], Float:reqVisibleAng[3];
-		GetClientEyeAngles(client, eyeAng);
-		
-		new Float:flFOV = float(g_iPlayerDesiredFOV[client]);
-		SubtractVectors(pos, eyePos, reqVisibleAng);
-		GetVectorAngles(reqVisibleAng, reqVisibleAng);
-		
-		new Float:difference = FloatAbs(AngleDiff(eyeAng[0], reqVisibleAng[0])) + FloatAbs(AngleDiff(eyeAng[1], reqVisibleAng[1]));
-		if (difference > ((flFOV * 0.5) + 10.0)) return false;
-	}
-	
-	return true;
-}
-
-public Action:Timer_ClientPostWeapons(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (!IsPlayerAlive(client)) return;
-	
-	if (timer != g_hPlayerPostWeaponsTimer[client]) return;
-	
-#if defined DEBUG
-	if (GetConVarInt(g_cvDebugDetail) > 0) 
-	{
-		DebugMessage("START Timer_ClientPostWeapons(%d)", client);
-	}
-	
-	new iOldWeaponItemIndexes[6] = { -1, ... };
-	new iNewWeaponItemIndexes[6] = { -1, ... };
-	
-	for (new i = 0; i <= 5; i++)
-	{
-		new iWeapon = GetPlayerWeaponSlot(client, i);
-		if (!IsValidEdict(iWeapon)) continue;
-		
-		iOldWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-	}
-	
-#endif
-	
-	new bool:bRemoveWeapons = true;
-	new bool:bRestrictWeapons = true;
-	
-	if (IsRoundEnding())
-	{
-		if (!g_bPlayerEliminated[client]) 
-		{
-			bRemoveWeapons = false;
-			bRestrictWeapons = false;
-		}
-	}
-	
-	// pvp
-	if (IsClientInPvP(client)) 
-	{
-		bRemoveWeapons = false;
-		bRestrictWeapons = false;
-	}
-	
-	if (IsRoundInWarmup()) 
-	{
-		bRemoveWeapons = false;
-		bRestrictWeapons = false;
-	}
-	
-	if (IsClientInGhostMode(client)) 
-	{
-		bRemoveWeapons = true;
-	}
-	
-	if (bRemoveWeapons)
-	{
-		for (new i = 0; i <= 5; i++)
-		{
-			if (i == TFWeaponSlot_Melee && !IsClientInGhostMode(client)) continue;
-			TF2_RemoveWeaponSlotAndWearables(client, i);
-		}
-		
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "tf_weapon_builder")) != -1)
-		{
-			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
-			{
-				AcceptEntityInput(ent, "Kill");
-			}
-		}
-		
-		ent = -1;
-		while ((ent = FindEntityByClassname(ent, "tf_wearable_demoshield")) != -1)
-		{
-			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
-			{
-				AcceptEntityInput(ent, "Kill");
-			}
-		}
-		
-		ClientSwitchToWeaponSlot(client, TFWeaponSlot_Melee);
-	}
-	
-	if (bRestrictWeapons)
-	{
-		new iHealth = GetEntProp(client, Prop_Send, "m_iHealth");
-		
-		if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
-		{
-			new TFClassType:iPlayerClass = TF2_GetPlayerClass(client);
-			new Handle:hItem = INVALID_HANDLE;
-			
-			new iWeapon = INVALID_ENT_REFERENCE;
-			for (new iSlot = 0; iSlot <= 5; iSlot++)
-			{
-				iWeapon = GetPlayerWeaponSlot(client, iSlot);
-				
-				if (IsValidEdict(iWeapon))
-				{
-					if (IsWeaponRestricted(iPlayerClass, GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex")))
-					{
-						hItem = INVALID_HANDLE;
-						TF2_RemoveWeaponSlotAndWearables(client, iSlot);
-						
-						switch (iSlot)
-						{
-							case TFWeaponSlot_Primary:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Scout: hItem = g_hSDKWeaponScattergun;
-									case TFClass_Sniper: hItem = g_hSDKWeaponSniperRifle;
-									case TFClass_Soldier: hItem = g_hSDKWeaponRocketLauncher;
-									case TFClass_DemoMan: hItem = g_hSDKWeaponGrenadeLauncher;
-									case TFClass_Heavy: hItem = g_hSDKWeaponMinigun;
-									case TFClass_Medic: hItem = g_hSDKWeaponSyringeGun;
-									case TFClass_Pyro: hItem = g_hSDKWeaponFlamethrower;
-									case TFClass_Spy: hItem = g_hSDKWeaponRevolver;
-									case TFClass_Engineer: hItem = g_hSDKWeaponShotgunPrimary;
-								}
-							}
-							case TFWeaponSlot_Secondary:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Scout: hItem = g_hSDKWeaponPistolScout;
-									case TFClass_Sniper: hItem = g_hSDKWeaponSMG;
-									case TFClass_Soldier: hItem = g_hSDKWeaponShotgunSoldier;
-									case TFClass_DemoMan: hItem = g_hSDKWeaponStickyLauncher;
-									case TFClass_Heavy: hItem = g_hSDKWeaponShotgunHeavy;
-									case TFClass_Medic: hItem = g_hSDKWeaponMedigun;
-									case TFClass_Pyro: hItem = g_hSDKWeaponShotgunPyro;
-									case TFClass_Engineer: hItem = g_hSDKWeaponPistol;
-								}
-							}
-							case TFWeaponSlot_Melee:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Scout: hItem = g_hSDKWeaponBat;
-									case TFClass_Sniper: hItem = g_hSDKWeaponKukri;
-									case TFClass_Soldier: hItem = g_hSDKWeaponShovel;
-									case TFClass_DemoMan: hItem = g_hSDKWeaponBottle;
-									case TFClass_Heavy: hItem = g_hSDKWeaponFists;
-									case TFClass_Medic: hItem = g_hSDKWeaponBonesaw;
-									case TFClass_Pyro: hItem = g_hSDKWeaponFireaxe;
-									case TFClass_Spy: hItem = g_hSDKWeaponKnife;
-									case TFClass_Engineer: hItem = g_hSDKWeaponWrench;
-								}
-							}
-							case 4:
-							{
-								switch (iPlayerClass)
-								{
-									case TFClass_Spy: hItem = g_hSDKWeaponInvis;
-								}
-							}
-						}
-						
-						if (hItem != INVALID_HANDLE)
-						{
-							new iNewWeapon = TF2Items_GiveNamedItem(client, hItem);
-							if (IsValidEntity(iNewWeapon)) 
-							{
-								EquipPlayerWeapon(client, iNewWeapon);
-							}
-						}
-					}
-				}
-			}
-		}
-		
-		// Fixes the Pretty Boy's Pocket Pistol glitch.
-		new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, client);
-		if (iHealth > iMaxHealth)
-		{
-			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
-			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
-		}
-	}
-	
-	// Change stats on some weapons.
-	if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
-	{
-		new iWeapon = INVALID_ENT_REFERENCE;
-		decl Handle:hWeapon;
-		for (new iSlot = 0; iSlot <= 5; iSlot++)
-		{
-			iWeapon = GetPlayerWeaponSlot(client, iSlot);
-			if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
-			
-			new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-			switch (iItemDef)
-			{
-				case 214: // Powerjack
-				{
-					TF2_RemoveWeaponSlot(client, iSlot);
-					
-					hWeapon = PrepareItemHandle("tf_weapon_fireaxe", 214, 0, 0, "180 ; 20.0 ; 206 ; 1.33");
-					new iEnt = TF2Items_GiveNamedItem(client, hWeapon);
-					CloseHandle(hWeapon);
-					EquipPlayerWeapon(client, iEnt);
-				}
-			}
-		}
-	}
-	
-	// Remove all hats.
-	if (IsClientInGhostMode(client))
-	{
-		new ent = -1;
-		while ((ent = FindEntityByClassname(ent, "tf_wearable")) != -1)
-		{
-			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
-			{
-				AcceptEntityInput(ent, "Kill");
-			}
-		}
-	}
-	
-#if defined DEBUG
-	for (new i = 0; i <= 5; i++)
-	{
-		new iWeapon = GetPlayerWeaponSlot(client, i);
-		if (!IsValidEdict(iWeapon)) continue;
-		
-		iNewWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
-	}
-
-	if (GetConVarInt(g_cvDebugDetail) > 0) 
-	{
-		for (new i = 0; i <= 5; i++)
-		{
-			DebugMessage("-> slot %d: %d (old: %d)", i, iNewWeaponItemIndexes[i], iOldWeaponItemIndexes[i]);
-		}
-	
-		DebugMessage("END Timer_ClientPostWeapons(%d) -> remove = %d, restrict = %d", client, bRemoveWeapons, bRestrictWeapons);
-	}
-#endif
-}
-
-public Action:Timer_ApplyCustomModel(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
-	
-	if (g_bPlayerProxy[client] && iMaster != -1)
-	{
-		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
-		NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
-		
-		// Set custom model, if any.
-		decl String:sBuffer[PLATFORM_MAX_PATH];
-		decl String:sSectionName[64];
-		
-		decl String:sClassName[64];
-		TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
-		
-		Format(sSectionName, sizeof(sSectionName), "mod_proxy_%s", sClassName);
-		if ((GetRandomStringFromProfile(sProfile, sSectionName, sBuffer, sizeof(sBuffer)) && sBuffer[0]) ||
-			(GetRandomStringFromProfile(sProfile, "mod_proxy_all", sBuffer, sizeof(sBuffer)) && sBuffer[0]))
-		{
-			SetVariantString(sBuffer);
-			AcceptEntityInput(client, "SetCustomModel");
-			SetEntProp(client, Prop_Send, "m_bUseClassAnimations", true);
-		}
-		
-		if (IsPlayerAlive(client))
-		{
-			// Play any sounds, if any.
-			if (GetRandomStringFromProfile(sProfile, "sound_proxy_spawn", sBuffer, sizeof(sBuffer)) && sBuffer[0])
-			{
-				new iChannel = GetProfileNum(sProfile, "sound_proxy_spawn_channel", SNDCHAN_AUTO);
-				new iLevel = GetProfileNum(sProfile, "sound_proxy_spawn_level", SNDLEVEL_NORMAL);
-				new iFlags = GetProfileNum(sProfile, "sound_proxy_spawn_flags", SND_NOFLAGS);
-				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_spawn_volume", SNDVOL_NORMAL);
-				new iPitch = GetProfileNum(sProfile, "sound_proxy_spawn_pitch", SNDPITCH_NORMAL);
-				
-				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
-			}
-		}
-	}
-}
-
-bool:IsWeaponRestricted(TFClassType:iClass, iItemDef)
-{
-	if (g_hRestrictedWeaponsConfig == INVALID_HANDLE) return false;
-	
-	new bool:bReturn = false;
-	
-	decl String:sItemDef[32];
-	IntToString(iItemDef, sItemDef, sizeof(sItemDef));
-	
-	KvRewind(g_hRestrictedWeaponsConfig);
-	if (KvJumpToKey(g_hRestrictedWeaponsConfig, "all"))
-	{
-		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef);
-	}
-	
-	new bool:bFoundSection = false;
-	KvRewind(g_hRestrictedWeaponsConfig);
-	
-	switch (iClass)
-	{
-		case TFClass_Scout: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "scout");
-		case TFClass_Soldier: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "soldier");
-		case TFClass_Sniper: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "sniper");
-		case TFClass_DemoMan: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "demoman");
-		case TFClass_Heavy: 
-		{
-			bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavy");
-		
-			if (!bFoundSection)
-			{
-				KvRewind(g_hRestrictedWeaponsConfig);
-				bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavyweapons");
-			}
-		}
-		case TFClass_Medic: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "medic");
-		case TFClass_Spy: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "spy");
-		case TFClass_Pyro: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "pyro");
-		case TFClass_Engineer: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "engineer");
-	}
-	
-	if (bFoundSection)
-	{
-		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef, bReturn);
-	}
-	
-	return bReturn;
-}
-
-public Action:Timer_RespawnPlayer(Handle:timer, any:userid)
-{
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
-	
-	if (IsPlayerAlive(client)) return;
-	
-	TF2_RespawnPlayer(client);
+#if defined _sf2_client_included
+ #endinput
+#endif
+#define _sf2_client_included
+
+#define GHOST_MODEL "models/props_halloween/ghost_no_hat.mdl"
+#define SF2_OVERLAY_DEFAULT "overlays/rytp_horror/grain"
+#define SF2_OVERLAY_DEFAULT_NO_FILMGRAIN "overlays/rytp_horror/grain" // TODO: Update material?
+#define SF2_OVERLAY_GHOST "overlays/rytp_horror/grain"
+
+#define EF_NODRAW 32
+
+#define SF2_FLASHLIGHT_WIDTH 512.0 // How wide the player's Flashlight should be in world units.
+#define SF2_FLASHLIGHT_LENGTH 1024.0 // How far the player's Flashlight can reach in world units.
+#define SF2_FLASHLIGHT_BRIGHTNESS 0 // Intensity of the players' Flashlight.
+#define SF2_FLASHLIGHT_DRAIN_RATE 0.65 // How long (in seconds) each bar on the player's Flashlight meter lasts.
+#define SF2_FLASHLIGHT_RECHARGE_RATE 0.68 // How long (in seconds) it takes each bar on the player's Flashlight meter to recharge.
+#define SF2_FLASHLIGHT_FLICKERAT 0.25 // The percentage of the Flashlight battery where the Flashlight will start to blink.
+#define SF2_FLASHLIGHT_ENABLEAT 0.3 // The percentage of the Flashlight battery where the Flashlight will be able to be used again (if the player shortens out the Flashlight from excessive use).
+#define SF2_FLASHLIGHT_COOLDOWN 0.4 // How much time players have to wait before being able to switch their flashlight on again after turning it off.
+
+#define SF2_ULTRAVISION_WIDTH 800.0
+#define SF2_ULTRAVISION_LENGTH 800.0
+#define SF2_ULTRAVISION_BRIGHTNESS -4 // Intensity of Ultravision.
+#define SF2_ULTRAVISION_CONE 180.0
+
+#define SF2_PLAYER_BREATH_COOLDOWN_MIN 0.8
+#define SF2_PLAYER_BREATH_COOLDOWN_MAX 2.0
+
+#define SF2_BREATH_VIEWBOB_SPEED 0.05
+#define SF2_BREATH_VIEWBOB_START 0.045
+#define SF2_BREATH_VIEWBOB_AMPLITUDE 0.17
+
+new String:g_strPlayerBreathSounds[][] = 
+{
+	"rytp_horror/player_breath_1.wav"
+};
+
+new String:g_strGhostHelpPhrases[][] = 
+{
+	"rytp_horror/ghost/epifancev_zdes.mp3",
+	"rytp_horror/ghost/pahom_ohh.mp3",
+	"rytp_horror/ghost/pahom_ja_nichego_net_net.mp3",
+	"rytp_horror/ghost/zs_epifan_vou.mp3",
+	"rytp_horror/ghost/zs_mmm.mp3",
+	"rytp_horror/ghost/zs_mmm2.mp3"
+};
+new g_iGhostHelpPhraseInterval = 2;
+new g_iGhostNextHelpPhrase[MAXPLAYERS + 1];
+
+static String:g_strPlayerLagCompensationWeapons[][] = 
+{
+	"tf_weapon_sniperrifle",
+	"tf_weapon_sniperrifle_decap",
+	"tf_weapon_sniperrifle_classic"
+};
+
+// Deathcam data.
+static g_iPlayerDeathCamBoss[MAXPLAYERS + 1] = { -1, ... };
+static bool:g_bPlayerDeathCam[MAXPLAYERS + 1] = { false, ... };
+static bool:g_bPlayerDeathCamShowOverlay[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerDeathCamEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static g_iPlayerDeathCamEnt2[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static Handle:g_hPlayerDeathCamTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Flashlight data.
+static bool:g_bPlayerFlashlight[MAXPLAYERS + 1] = { false, ... };
+static bool:g_bPlayerFlashlightBroken[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerFlashlightEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static g_iPlayerFlashlightEntAng[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static Float:g_flPlayerFlashlightBatteryLife[MAXPLAYERS + 1] = { 1.0, ... };
+static Handle:g_hPlayerFlashlightBatteryTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static Float:g_flPlayerFlashlightNextInputTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+// Ultravision data.
+static bool:g_bPlayerUltravision[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerUltravisionEnt[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+
+// Sprint data.
+static bool:g_bPlayerSprint[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerSprintPoints[MAXPLAYERS + 1] = { 100, ... };
+static Handle:g_hPlayerSprintTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+// Blink data.
+static Handle:g_hPlayerBlinkTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static bool:g_bPlayerBlink[MAXPLAYERS + 1] = { false, ... };
+static Float:g_flPlayerBlinkMeter[MAXPLAYERS + 1] = { 0.0, ... };
+static g_iPlayerBlinkCount[MAXPLAYERS + 1] = { 0, ... };
+
+// Breathing data.
+static bool:g_bPlayerBreath[MAXPLAYERS + 1] = { false, ... };
+static Handle:g_hPlayerBreathTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+
+new Float:g_flPlayerBreathViewbobPhase[MAXPLAYERS + 1];
+new Float:g_flPlayerBreathViewbobXMult[MAXPLAYERS + 1] = 1.0;
+new Float:g_flPlayerBreathViewbobYMult[MAXPLAYERS + 1] = 1.0;
+
+// Interactive glow data.
+static g_iPlayerInteractiveGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static g_iPlayerInteractiveGlowTargetEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+
+// Constant glow data.
+static g_iPlayerConstantGlowEntity[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static bool:g_bPlayerConstantGlowEnabled[MAXPLAYERS + 1] = { false, ... };
+
+// Jumpscare data.
+static g_iPlayerJumpScareBoss[MAXPLAYERS + 1] = { -1, ... };
+static Float:g_flPlayerJumpScareLifeTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+static Float:g_flPlayerScareBoostEndTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+// Anti-camping data.
+static g_iPlayerCampingStrikes[MAXPLAYERS + 1] = { 0, ... };
+static Handle:g_hPlayerCampingTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static Float:g_flPlayerCampingLastPosition[MAXPLAYERS + 1][3];
+static bool:g_bPlayerCampingFirstTime[MAXPLAYERS + 1] = { true, ... };
+
+
+//	==========================================================
+//	GENERAL CLIENT HOOK FUNCTIONS
+//	==========================================================
+
+#define SF2_PLAYER_VIEWBOB_TIMER 10.0
+#define SF2_PLAYER_VIEWBOB_SCALE_X 0.05
+#define SF2_PLAYER_VIEWBOB_SCALE_Y 0.0
+#define SF2_PLAYER_VIEWBOB_SCALE_Z 0.0
+
+
+public MRESReturn:Hook_ClientWantsLagCompensationOnEntity(thisPointer, Handle:hReturn, Handle:hParams)
+{
+	if (!g_bEnabled || IsFakeClient(thisPointer)) return MRES_Ignored;
+	
+	DHookSetReturn(hReturn, true);
+	return MRES_Supercede;
+}
+
+Float:ClientGetScareBoostEndTime(client)
+{
+	return g_flPlayerScareBoostEndTime[client];
+}
+
+ClientSetScareBoostEndTime(client, Float:time)
+{
+	g_flPlayerScareBoostEndTime[client] = time;
+}
+
+public Hook_ClientPreThink(client)
+{
+	if (!g_bEnabled) return;
+	
+	ClientProcessViewAngles(client);
+	ClientProcessVisibility(client);
+	ClientProcessStaticShake(client);
+	ClientProcessFlashlightAngles(client);
+	ClientProcessInteractiveGlow(client);
+	
+	if (IsClientInGhostMode(client))
+	{
+		SetEntPropFloat(client, Prop_Send, "m_flNextAttack", GetGameTime() + 2.0);
+		SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 520.0);
+	}
+	else if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
+	{
+		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
+		{
+			new iRoundState = _:GameRules_GetRoundState();
+		
+			// No double jumping for players in play.
+			SetEntProp(client, Prop_Send, "m_iAirDash", 99999);
+		
+			if (!g_bPlayerProxy[client])
+			{
+				if (iRoundState == 4)
+				{
+					new bool:bDanger = false;
+					
+					if (!bDanger)
+					{
+						decl iState;
+						decl iBossTarget;
+						
+						for (new i = 0; i < MAX_BOSSES; i++)
+						{
+							if (NPCGetUniqueID(i) == -1) continue;
+							
+							if (NPCGetType(i) == SF2BossType_Chaser)
+							{
+								iBossTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
+								iState = g_iSlenderState[i];
+								
+								if ((iState == STATE_CHASE || iState == STATE_ATTACK || iState == STATE_STUN) &&
+									((iBossTarget && iBossTarget != INVALID_ENT_REFERENCE && (iBossTarget == client || ClientGetDistanceFromEntity(client, iBossTarget) < 512.0)) || NPCGetDistanceFromEntity(i, client) < 512.0 || PlayerCanSeeSlender(client, i, false)))
+								{
+									bDanger = true;
+									ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
+									
+									// Induce client stress levels.
+									new Float:flUnComfortZoneDist = 512.0;
+									new Float:flStressScalar = (flUnComfortZoneDist / NPCGetDistanceFromEntity(i, client));
+									ClientAddStress(client, 0.025 * flStressScalar);
+									
+									break;
+								}
+							}
+						}
+					}
+					
+					if (g_flPlayerStaticAmount[client] > 0.4) bDanger = true;
+					if (GetGameTime() < ClientGetScareBoostEndTime(client)) bDanger = true;
+					
+					if (!bDanger)
+					{
+						decl iState;
+						for (new i = 0; i < MAX_BOSSES; i++)
+						{
+							if (NPCGetUniqueID(i) == -1) continue;
+							
+							if (NPCGetType(i) == SF2BossType_Chaser)
+							{
+								if (iState == STATE_ALERT)
+								{
+									if (PlayerCanSeeSlender(client, i))
+									{
+										bDanger = true;
+										ClientSetScareBoostEndTime(client, GetGameTime() + 5.0);
+									}
+								}
+							}
+						}
+					}
+					
+					if (!bDanger)
+					{
+						new Float:flCurTime = GetGameTime();
+						new Float:flScareSprintDuration = 3.0;
+						if (TF2_GetPlayerClass(client) == TFClass_DemoMan) flScareSprintDuration *= 1.667;
+						
+						for (new i = 0; i < MAX_BOSSES; i++)
+						{
+							if (NPCGetUniqueID(i) == -1) continue;
+							
+							if ((flCurTime - g_flPlayerScareLastTime[client][i]) <= flScareSprintDuration)
+							{
+								bDanger = true;
+								break;
+							}
+						}
+					}
+					
+					new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
+					new Float:flSprintSpeed = ClientGetDefaultSprintSpeed(client);
+					
+					// Check for weapon speed changes.
+					new iWeapon = INVALID_ENT_REFERENCE;
+					
+					for (new iSlot = 0; iSlot <= 5; iSlot++)
+					{
+						iWeapon = GetPlayerWeaponSlot(client, iSlot);
+						if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
+						
+						new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+						switch (iItemDef)
+						{
+							case 239: // Gloves of Running Urgently
+							{
+								if (GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon") == iWeapon)
+								{
+									flSprintSpeed += (flSprintSpeed * 0.1);
+								}
+							}
+							case 775: // Escape Plan
+							{
+								new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
+								new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
+								new Float:flPercentage = flHealth / flMaxHealth;
+								
+								if (flPercentage < 0.805 && flPercentage >= 0.605) flSprintSpeed += (flSprintSpeed * 0.05);
+								else if (flPercentage < 0.605 && flPercentage >= 0.405) flSprintSpeed += (flSprintSpeed * 0.1);
+								else if (flPercentage < 0.405 && flPercentage >= 0.205) flSprintSpeed += (flSprintSpeed * 0.15);
+								else if (flPercentage < 0.205) flSprintSpeed += (flSprintSpeed * 0.2);
+							}
+						}
+					}
+					
+					// Speed buff?
+					if (TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly))
+					{
+						flWalkSpeed += (flWalkSpeed * 0.08);
+						flSprintSpeed += (flSprintSpeed * 0.08);
+					}
+					
+					if (bDanger)
+					{
+						flWalkSpeed *= 1.33;
+						flSprintSpeed *= 1.33;
+						
+						if (!g_bPlayerHints[client][PlayerHint_Sprint])
+						{
+							ClientShowHint(client, PlayerHint_Sprint);
+						}
+					}
+					
+					new Float:flSprintSpeedSubtract = ((flSprintSpeed - flWalkSpeed) * 0.5);
+					flSprintSpeedSubtract -= flSprintSpeedSubtract * (g_iPlayerSprintPoints[client] != 0 ? (float(g_iPlayerSprintPoints[client]) / 100.0) : 0.0);
+					flSprintSpeed -= flSprintSpeedSubtract;
+					
+					if (IsClientSprinting(client)) 
+					{
+						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flSprintSpeed);
+					}
+					else 
+					{
+						SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", flWalkSpeed);
+					}
+					
+					if (ClientCanBreath(client) && !g_bPlayerBreath[client])
+					{
+						ClientStartBreathing(client);
+					}
+				}
+			}
+			else
+			{
+				new TFClassType:iClass = TF2_GetPlayerClass(client);
+				new bool:bSpeedup = TF2_IsPlayerInCondition(client, TFCond_SpeedBuffAlly);
+			
+				switch (iClass)
+				{
+					case TFClass_Scout:
+					{
+						if (iRoundState == 4)
+						{
+							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 405.0);
+							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
+						}
+					}
+					case TFClass_Medic:
+					{
+						if (iRoundState == 4)
+						{
+							if (bSpeedup) SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 385.0);
+							else SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", 300.0);
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	// Calculate player stress levels.
+	if (GetGameTime() >= g_flPlayerStressNextUpdateTime[client])
+	{
+		//new Float:flPagePercent = g_iPageMax != 0 ? float(g_iPageCount) / float(g_iPageMax) : 0.0;
+		//new Float:flPageCountPercent = g_iPageMax != 0? float(g_iPlayerPageCount[client]) / float(g_iPageMax) : 0.0;
+		
+		g_flPlayerStressNextUpdateTime[client] = GetGameTime() + 0.33;
+		ClientAddStress(client, -0.01);
+		
+#if defined DEBUG
+		SendDebugMessageToPlayer(client, DEBUG_PLAYER_STRESS, 1, "g_flPlayerStress[%d]: %0.1f", client, g_flPlayerStress[client]);
+#endif
+	}
+	
+	// Process screen shake, if enabled.
+	if (g_bPlayerShakeEnabled)
+	{
+		new bool:bDoShake = false;
+		
+		if (IsPlayerAlive(client))
+		{
+			new iStaticMaster = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
+			if (iStaticMaster != -1 && NPCGetFlags(iStaticMaster) & SFF_HASVIEWSHAKE)
+			{
+				bDoShake = true;
+			}
+		}
+		
+		if (bDoShake)
+		{
+			new Float:flPercent = g_flPlayerStaticAmount[client];
+			
+			new Float:flAmplitudeMax = GetConVarFloat(g_cvPlayerShakeAmplitudeMax);
+			new Float:flAmplitude = flAmplitudeMax * flPercent;
+			
+			new Float:flFrequencyMax = GetConVarFloat(g_cvPlayerShakeFrequencyMax);
+			new Float:flFrequency = flFrequencyMax * flPercent;
+			
+			UTIL_ScreenShake(client, flAmplitude, 0.5, flFrequency);
+		}
+	}
+}
+
+public Action:Hook_ClientSetTransmit(client, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (other != client)
+	{
+		if (IsClientInGhostMode(client) && !IsClientInGhostMode(other)) return Plugin_Handled;
+		
+		if (!IsRoundEnding())
+		{
+			// SPECIAL ROUND: Singleplayer
+			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+			{
+				if (!g_bPlayerEliminated[client] && !g_bPlayerEliminated[other] && !DidClientEscape(other)) return Plugin_Handled; 
+			}
+			
+			// pvp
+			if (IsClientInPvP(client) && IsClientInPvP(other)) 
+			{
+				if (TF2_IsPlayerInCondition(client, TFCond_Cloaked) &&
+					!TF2_IsPlayerInCondition(client, TFCond_CloakFlicker) &&
+					!TF2_IsPlayerInCondition(client, TFCond_Jarated) &&
+					!TF2_IsPlayerInCondition(client, TFCond_Milked) &&
+					!TF2_IsPlayerInCondition(client, TFCond_OnFire) &&
+					(GetGameTime() > GetEntPropFloat(client, Prop_Send, "m_flInvisChangeCompleteTime")))
+				{
+					return Plugin_Handled;
+				}
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:TF2_CalcIsAttackCritical(client, weapon, String:sWeaponName[], &bool:result)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if ((IsRoundInWarmup() || IsClientInPvP(client)) && !IsRoundEnding())
+	{
+		if (!GetConVarBool(g_cvPlayerFakeLagCompensation))
+		{
+			new bool:bNeedsManualDamage = false;
+			
+			// Fake lag compensation isn't enabled; check to see if we need to deal damage manually.
+			for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
+			{
+				if (StrEqual(sWeaponName, g_strPlayerLagCompensationWeapons[i], false))
+				{
+					bNeedsManualDamage = true;
+					break;
+				}
+			}
+			
+			if (bNeedsManualDamage)
+			{
+				decl Float:flStartPos[3], Float:flEyeAng[3];
+				GetClientEyePosition(client, flStartPos);
+				GetClientEyeAngles(client, flEyeAng);
+				
+				new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flEyeAng, MASK_SHOT, RayType_Infinite, TraceRayDontHitEntity, client);
+				new iHitEntity = TR_GetEntityIndex(hTrace);
+				new iHitGroup = TR_GetHitGroup(hTrace);
+				CloseHandle(hTrace);
+				
+				if (IsValidClient(iHitEntity))
+				{
+					if (GetClientTeam(iHitEntity) == GetClientTeam(client))
+					{
+						if (IsRoundInWarmup() || IsClientInPvP(iHitEntity))
+						{
+							new Float:flChargedDamage = GetEntPropFloat(weapon, Prop_Send, "m_flChargedDamage");
+							if (flChargedDamage < 50.0) flChargedDamage = 50.0;
+							new iDamageType = DMG_BULLET;
+							
+							if (IsClientCritBoosted(client))
+							{
+								result = true;
+								iDamageType |= DMG_ACID;
+							}
+							else if (iHitGroup == 1)
+							{
+								if (StrEqual(sWeaponName, "tf_weapon_sniperrifle_classic", false))
+								{
+									if (flChargedDamage >= 150.0)
+									{
+										result = true;
+										iDamageType |= DMG_ACID;
+									}
+								}
+								else
+								{
+									if (TF2_IsPlayerInCondition(client, TFCond_Zoomed))
+									{
+										result = true;
+										iDamageType |= DMG_ACID;
+									}
+								}
+							}
+							
+							SDKHooks_TakeDamage(iHitEntity, client, client, flChargedDamage, iDamageType);
+							return Plugin_Changed;
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_ClientOnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3], damagecustom)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (IsRoundInWarmup()) return Plugin_Continue;
+	
+	if (attacker != victim && IsValidClient(attacker))
+	{
+		if (!IsRoundEnding())
+		{
+			if (IsClientInPvP(victim) && IsClientInPvP(attacker))
+			{
+				if (attacker == inflictor)
+				{
+					if (IsValidEdict(weapon))
+					{
+						decl String:sWeaponClass[64];
+						GetEdictClassname(weapon, sWeaponClass, sizeof(sWeaponClass));
+						
+						// Backstab check!
+						if ((StrEqual(sWeaponClass, "tf_weapon_knife", false) || (TF2_GetPlayerClass(attacker) == TFClass_Spy && StrEqual(sWeaponClass, "saxxy", false))) &&
+							(damagecustom != TF_CUSTOM_TAUNT_FENCING))
+						{
+							decl Float:flMyPos[3], Float:flHisPos[3], Float:flMyDirection[3];
+							GetClientAbsOrigin(victim, flMyPos);
+							GetClientAbsOrigin(attacker, flHisPos);
+							GetClientEyeAngles(victim, flMyDirection);
+							GetAngleVectors(flMyDirection, flMyDirection, NULL_VECTOR, NULL_VECTOR);
+							NormalizeVector(flMyDirection, flMyDirection);
+							ScaleVector(flMyDirection, 32.0);
+							AddVectors(flMyDirection, flMyPos, flMyDirection);
+							
+							decl Float:p[3], Float:s[3];
+							MakeVectorFromPoints(flMyPos, flHisPos, p);
+							MakeVectorFromPoints(flMyPos, flMyDirection, s);
+							if (GetVectorDotProduct(p, s) <= 0.0)
+							{
+								damage = float(GetEntProp(victim, Prop_Send, "m_iHealth")) * 2.0;
+								
+								new Handle:hCvar = FindConVar("tf_weapon_criticals");
+								if (hCvar != INVALID_HANDLE && GetConVarBool(hCvar)) damagetype |= DMG_ACID;
+								return Plugin_Changed;
+							}
+						}
+					}
+				}
+			}
+			/*
+			else if (g_bPlayerProxy[victim] || g_bPlayerProxy[attacker])
+			{
+				if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
+				{
+					damage = 0.0;
+					return Plugin_Changed;
+				}
+				
+				if (g_bPlayerProxy[attacker])
+				{
+					new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, victim);
+					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[attacker]);
+					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
+					{
+						if (damagecustom == TF_CUSTOM_TAUNT_GRAND_SLAM ||
+							damagecustom == TF_CUSTOM_TAUNT_FENCING ||
+							damagecustom == TF_CUSTOM_TAUNT_ARROW_STAB ||
+							damagecustom == TF_CUSTOM_TAUNT_GRENADE ||
+							damagecustom == TF_CUSTOM_TAUNT_BARBARIAN_SWING ||
+							damagecustom == TF_CUSTOM_TAUNT_ENGINEER_ARM ||
+							damagecustom == TF_CUSTOM_TAUNT_ARMAGEDDON)
+						{
+							if (damage >= float(iMaxHealth)) damage = float(iMaxHealth) * 0.5;
+							else damage = 0.0;
+						}
+						else if (damagecustom == TF_CUSTOM_BACKSTAB) // Modify backstab damage.
+						{
+							damage = float(iMaxHealth) * GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy_backstab", 0.25);
+							if (damagetype & DMG_ACID) damage /= 3.0;
+						}
+					
+						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitenemy");
+						if (g_iPlayerProxyControl[attacker] > 100)
+						{
+							g_iPlayerProxyControl[attacker] = 100;
+						}
+						
+						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_enemy", 1.0);
+					}
+					
+					return Plugin_Changed;
+				}
+				else if (g_bPlayerProxy[victim])
+				{
+					new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[victim]);
+					if (iMaster != -1 && g_strSlenderProfile[iMaster][0])
+					{
+						g_iPlayerProxyControl[attacker] += GetProfileNum(g_strSlenderProfile[iMaster], "proxies_controlgain_hitbyenemy");
+						if (g_iPlayerProxyControl[attacker] > 100)
+						{
+							g_iPlayerProxyControl[attacker] = 100;
+						}
+						
+						damage *= GetProfileFloat(g_strSlenderProfile[iMaster], "proxies_damage_scale_vs_self", 1.0);
+					}
+					
+					return Plugin_Changed;
+				}
+			}
+			*/
+			else
+			{
+				damage = 0.0;
+				return Plugin_Changed;
+			}
+		}
+		else
+		{
+			if (g_bPlayerEliminated[attacker] == g_bPlayerEliminated[victim])
+			{
+				damage = 0.0;
+				return Plugin_Changed;
+			}
+		}
+		
+		if (IsClientInGhostMode(victim))
+		{
+			damage = 0.0;
+			return Plugin_Changed;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_TEFireBullets(const String:te_name[], const Players[], numClients, Float:delay)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	new client = TE_ReadNum("m_iPlayer") + 1;
+	if (IsValidClient(client))
+	{
+		if (GetConVarBool(g_cvPlayerFakeLagCompensation))
+		{
+			if ((IsRoundInWarmup() || IsClientInPvP(client)))
+			{
+				ClientEnableFakeLagCompensation(client);
+			}
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+ClientResetStatic(client)
+{
+	g_iPlayerStaticMaster[client] = -1;
+	g_hPlayerStaticTimer[client] = INVALID_HANDLE;
+	g_flPlayerStaticIncreaseRate[client] = 0.0;
+	g_flPlayerStaticDecreaseRate[client] = 0.0;
+	g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+	g_flPlayerLastStaticTime[client] = 0.0;
+	g_flPlayerLastStaticVolume[client] = 0.0;
+	g_bPlayerInStaticShake[client] = false;
+	g_iPlayerStaticShakeMaster[client] = -1;
+	g_flPlayerStaticShakeMinVolume[client] = 0.0;
+	g_flPlayerStaticShakeMaxVolume[client] = 0.0;
+	g_flPlayerStaticAmount[client] = 0.0;
+	
+	if (IsClientInGame(client))
+	{
+		if (g_strPlayerStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticSound[client]);
+		if (g_strPlayerLastStaticSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+		if (g_strPlayerStaticShakeSound[client][0]) StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
+	}
+	
+	strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
+	strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), "");
+	strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
+}
+
+ClientResetHints(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetHints(%d)", client);
+#endif
+
+	for (new i = 0; i < PlayerHint_MaxNum; i++)
+	{
+		g_bPlayerHints[client][i] = false;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetHints(%d)", client);
+#endif
+}
+
+ClientShowHint(client, iHint)
+{
+	g_bPlayerHints[client][iHint] = true;
+	
+	switch (iHint)
+	{
+		case PlayerHint_Sprint: PrintHintText(client, "%T", "SF2 Hint Sprint", client);
+		case PlayerHint_Flashlight: PrintHintText(client, "%T", "SF2 Hint Flashlight", client);
+		case PlayerHint_Blink: PrintHintText(client, "%T", "SF2 Hint Blink", client);
+		case PlayerHint_MainMenu: PrintHintText(client, "%T", "SF2 Hint Main Menu", client);
+	}
+}
+
+bool:DidClientEscape(client)
+{
+	return g_bPlayerEscaped[client];
+}
+
+ClientEscape(client)
+{
+	if (DidClientEscape(client)) return;
+
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("START ClientEscape(%d)", client);
+#endif
+	
+	g_bPlayerEscaped[client] = true;
+	
+	ClientResetBreathing(client);
+	ClientResetSprint(client);
+	ClientResetFlashlight(client);
+	ClientDeactivateUltravision(client);
+	ClientDisableConstantGlow(client);
+	
+	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
+	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
+	
+	HandlePlayerHUD(client);
+	
+	decl String:sName[MAX_NAME_LENGTH];
+	GetClientName(client, sName, sizeof(sName));
+	CPrintToChatAll("%t", "SF2 Player Escaped", sName);
+	
+	CheckRoundWinConditions();
+	
+	Call_StartForward(fOnClientEscape);
+	Call_PushCell(client);
+	Call_Finish();
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 1) DebugMessage("END ClientEscape(%d)", client);
+#endif
+}
+
+public Action:Timer_TeleportPlayerToEscapePoint(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (!DidClientEscape(client)) return;
+	
+	if (IsPlayerAlive(client))
+	{
+		TeleportClientToEscapePoint(client);
+	}
+}
+
+stock Float:ClientGetDistanceFromEntity(client, entity)
+{
+	decl Float:flStartPos[3], Float:flEndPos[3];
+	GetClientAbsOrigin(client, flStartPos);
+	GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", flEndPos);
+	return GetVectorDistance(flStartPos, flEndPos);
+}
+
+ClientEnableFakeLagCompensation(client)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client) || g_bPlayerLagCompensation[client]) return;
+	
+	// Can only enable lag compensation if we're in either of these two teams only.
+	new iMyTeam = GetClientTeam(client);
+	if (iMyTeam != _:TFTeam_Red && iMyTeam != _:TFTeam_Blue) return;
+	
+	// Can only enable lag compensation if there are other active teammates around. This is to prevent spontaneous round restarting.
+	new iCount;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (i == client) continue;
+		
+		if (IsValidClient(i) && IsPlayerAlive(i))
+		{
+			new iTeam = GetClientTeam(i);
+			if ((iTeam == _:TFTeam_Red || iTeam == _:TFTeam_Blue) && iTeam == iMyTeam)
+			{
+				iCount++;
+			}
+		}
+	}
+	
+	if (!iCount) return;
+	
+	// Can only enable lag compensation only for specific weapons.
+	new iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon");
+	if (!IsValidEdict(iActiveWeapon)) return;
+	
+	decl String:sClassName[64];
+	GetEdictClassname(iActiveWeapon, sClassName, sizeof(sClassName));
+	
+	new bool:bCompensate = false;
+	for (new i = 0; i < sizeof(g_strPlayerLagCompensationWeapons); i++)
+	{
+		if (StrEqual(sClassName, g_strPlayerLagCompensationWeapons[i], false))
+		{
+			bCompensate = true;
+			break;
+		}
+	}
+	
+	if (!bCompensate) return;
+	
+	g_bPlayerLagCompensation[client] = true;
+	g_iPlayerLagCompensationTeam[client] = iMyTeam;
+	SetEntProp(client, Prop_Send, "m_iTeamNum", 0);
+}
+
+ClientDisableFakeLagCompensation(client)
+{
+	if (!g_bPlayerLagCompensation[client]) return;
+	
+	SetEntProp(client, Prop_Send, "m_iTeamNum", g_iPlayerLagCompensationTeam[client]);
+	g_bPlayerLagCompensation[client] = false;
+	g_iPlayerLagCompensationTeam[client] = -1;
+}
+
+//	==========================================================
+//	FLASHLIGHT / ULTRAVISION FUNCTIONS
+//	==========================================================
+
+bool:IsClientUsingFlashlight(client)
+{
+	return g_bPlayerFlashlight[client];
+}
+
+Float:ClientGetFlashlightBatteryLife(client)
+{
+	return g_flPlayerFlashlightBatteryLife[client];
+}
+
+ClientSetFlashlightBatteryLife(client, Float:flPercent)
+{
+	g_flPlayerFlashlightBatteryLife[client] = flPercent;
+}
+
+/**
+ *	Called in Hook_ClientPreThink, this makes sure the flashlight is oriented correctly on the player.
+ */
+static ClientProcessFlashlightAngles(client)
+{
+	if (!IsClientInGame(client)) return;
+	
+	if (IsPlayerAlive(client))
+	{
+		decl fl, Float:eyeAng[3], Float:ang2[3];
+		
+		if (IsClientUsingFlashlight(client))
+		{
+			fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
+			if (fl && fl != INVALID_ENT_REFERENCE)
+			{
+				TeleportEntity(fl, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 }, NULL_VECTOR);
+			}
+			
+			fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
+			if (fl && fl != INVALID_ENT_REFERENCE)
+			{
+				GetClientEyeAngles(client, eyeAng);
+				GetClientAbsAngles(client, ang2);
+				SubtractVectors(eyeAng, ang2, eyeAng);
+				TeleportEntity(fl, NULL_VECTOR, eyeAng, NULL_VECTOR);
+			}
+		}
+	}
+}
+
+/**
+ *	Handles whether or not the player's flashlight should be "flickering", a sign of a dying flashlight battery.
+ */
+static ClientHandleFlashlightFlickerState(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	if (IsClientUsingFlashlight(client))
+	{
+		new bool:bFlicker = bool:(ClientGetFlashlightBatteryLife(client) <= SF2_FLASHLIGHT_FLICKERAT);
+	
+		new fl = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
+		if (fl && fl != INVALID_ENT_REFERENCE)
+		{
+			if (bFlicker)
+			{
+				SetEntProp(fl, Prop_Data, "m_LightStyle", 10);
+			}
+			else
+			{
+				SetEntProp(fl, Prop_Data, "m_LightStyle", 0);
+			}
+		}
+		
+		fl = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
+		if (fl && fl != INVALID_ENT_REFERENCE)
+		{
+			if (bFlicker) 
+			{
+				SetEntityRenderFx(fl, RenderFx:13);
+			}
+			else 
+			{
+				SetEntityRenderFx(fl, RenderFx:0);
+			}
+		}
+	}
+}
+
+bool:IsClientFlashlightBroken(client)
+{
+	return g_bPlayerFlashlightBroken[client];
+}
+
+Float:ClientGetFlashlightNextInputTime(client)
+{
+	return g_flPlayerFlashlightNextInputTime[client];
+}
+
+/**
+ *	Breaks the player's flashlight. Nothing else.
+ */
+ClientBreakFlashlight(client)
+{
+	if (IsClientFlashlightBroken(client)) return;
+	
+	g_bPlayerFlashlightBroken[client] = true;
+	
+	ClientSetFlashlightBatteryLife(client, 0.0);
+	ClientTurnOffFlashlight(client);
+	
+	ClientAddStress(client, 0.2);
+	
+	EmitSoundToAll(FLASHLIGHT_BREAKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
+	
+	Call_StartForward(fOnClientBreakFlashlight);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+/**
+ *	Resets everything of the player's flashlight.
+ */
+ClientResetFlashlight(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetFlashlight(%d)", client);
+#endif
+	
+	ClientTurnOffFlashlight(client);
+	ClientSetFlashlightBatteryLife(client, 1.0);
+	g_bPlayerFlashlightBroken[client] = false;
+	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
+	g_flPlayerFlashlightNextInputTime[client] = -1.0;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetFlashlight(%d)", client);
+#endif
+}
+
+public Action:Hook_FlashlightSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	if (EntRefToEntIndex(g_iPlayerFlashlightEnt[other]) != ent) return Plugin_Handled;
+	
+	// We've already checked for flashlight ownership in the last statement. So we can do just this.
+	if (g_iPlayerPreferences[other][PlayerPreference_ProjectedFlashlight]) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_Flashlight2SetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[other]) == ent) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+public Hook_FlashlightEndSpawnPost(ent)
+{
+	if (!g_bEnabled) return;
+
+	SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightEndSetTransmit);
+	SDKUnhook(ent, SDKHook_SpawnPost, Hook_FlashlightEndSpawnPost);
+}
+
+public Action:Hook_FlashlightBeamSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	new iOwner = -1;
+	new iSpotlight = -1;
+	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
+	{
+		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
+		{
+			iOwner = iSpotlight;
+			break;
+		}
+	}
+	
+	if (iOwner == -1) return Plugin_Continue;
+	
+	new iClient = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
+		{
+			iClient = i;
+			break;
+		}
+	}
+	
+	if (iClient == -1) return Plugin_Continue;
+	
+	if (iClient == other)
+	{
+		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
+		{
+			return Plugin_Handled;
+		}
+	}
+	else
+	{
+		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+		{
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Hook_FlashlightEndSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	new iOwner = -1;
+	new iSpotlight = -1;
+	while ((iSpotlight = FindEntityByClassname(iSpotlight, "point_spotlight")) != -1)
+	{
+		if (GetEntPropEnt(ent, Prop_Data, "m_hOwnerEntity") == iSpotlight)
+		{
+			iOwner = iSpotlight;
+			break;
+		}
+	}
+	
+	if (iOwner == -1) return Plugin_Continue;
+	
+	new iClient = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		
+		if (EntRefToEntIndex(g_iPlayerFlashlightEntAng[i]) == iOwner)
+		{
+			iClient = i;
+			break;
+		}
+	}
+	
+	if (iClient == -1) return Plugin_Continue;
+	
+	if (iClient == other)
+	{
+		if (!GetEntProp(iClient, Prop_Send, "m_nForceTauntCam") || !GetEntProp(iClient, Prop_Send, "m_iObserverMode"))
+		{
+			return Plugin_Handled;
+		}
+	}
+	else
+	{
+		if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+		{
+			return Plugin_Handled;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_DrainFlashlight(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
+	
+	new iOverride = GetConVarInt(g_cvPlayerInfiniteFlashlightOverride);
+	if ((!g_bRoundInfiniteFlashlight && iOverride != 1) || iOverride == 0)
+	{
+		ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) - 0.01);
+	}
+	
+	if (ClientGetFlashlightBatteryLife(client) <= 0.0)
+	{
+		// Break the player's flashlight, but also start recharging.
+		ClientBreakFlashlight(client);
+		ClientStartRechargingFlashlightBattery(client);
+		ClientActivateUltravision(client);
+		return Plugin_Stop;
+	}
+	else
+	{
+		ClientHandleFlashlightFlickerState(client);
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_RechargeFlashlight(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerFlashlightBatteryTimer[client]) return Plugin_Stop;
+	
+	ClientSetFlashlightBatteryLife(client, ClientGetFlashlightBatteryLife(client) + 0.01);
+	
+	if (IsClientFlashlightBroken(client) && ClientGetFlashlightBatteryLife(client) >= SF2_FLASHLIGHT_ENABLEAT)
+	{
+		// Repair the flashlight.
+		g_bPlayerFlashlightBroken[client] = false;
+	}
+	
+	if (ClientGetFlashlightBatteryLife(client) >= 1.0)
+	{
+		// I am fully charged!
+		ClientSetFlashlightBatteryLife(client, 1.0);
+		g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
+		
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+/**
+ *	Turns on the player's flashlight. Nothing else.
+ */
+ClientTurnOnFlashlight(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	if (IsClientUsingFlashlight(client)) return;
+	
+	g_bPlayerFlashlight[client] = true;
+	
+	decl Float:flEyePos[3];
+	GetClientEyePosition(client, flEyePos);
+	
+	if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
+	{
+		// If the player is using the projected flashlight, just set effect flags.
+		new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+		if (!(iEffects & (1 << 2)))
+		{
+			SetEntProp(client, Prop_Send, "m_fEffects", iEffects | (1 << 2));
+		}
+	}
+	else
+	{
+		// Spawn the light which only the user will see.
+		new ent = CreateEntityByName("light_dynamic");
+		if (ent != -1)
+		{
+			TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
+			DispatchKeyValue(ent, "targetname", "WUBADUBDUBMOTHERBUCKERS");
+			DispatchKeyValue(ent, "rendercolor", "255 255 255");
+			SetVariantFloat(SF2_FLASHLIGHT_WIDTH);
+			AcceptEntityInput(ent, "spotlight_radius");
+			SetVariantFloat(SF2_FLASHLIGHT_LENGTH);
+			AcceptEntityInput(ent, "distance");
+			SetVariantInt(SF2_FLASHLIGHT_BRIGHTNESS);
+			AcceptEntityInput(ent, "brightness");
+			
+			// Convert WU to inches.
+			new Float:cone = 55.0;
+			cone *= 0.75;
+			
+			SetVariantInt(RoundToFloor(cone));
+			AcceptEntityInput(ent, "_inner_cone");
+			SetVariantInt(RoundToFloor(cone));
+			AcceptEntityInput(ent, "_cone");
+			DispatchSpawn(ent);
+			ActivateEntity(ent);
+			SetVariantString("!activator");
+			AcceptEntityInput(ent, "SetParent", client);
+			AcceptEntityInput(ent, "TurnOn");
+			
+			g_iPlayerFlashlightEnt[client] = EntIndexToEntRef(ent);
+			
+			SDKHook(ent, SDKHook_SetTransmit, Hook_FlashlightSetTransmit);
+		}
+	}
+	
+	// Spawn the light that only everyone else will see.
+	new ent = CreateEntityByName("point_spotlight");
+	if (ent != -1)
+	{
+		TeleportEntity(ent, flEyePos, NULL_VECTOR, NULL_VECTOR);
+		
+		decl String:sBuffer[256];
+		FloatToString(SF2_FLASHLIGHT_LENGTH, sBuffer, sizeof(sBuffer));
+		DispatchKeyValue(ent, "spotlightlength", sBuffer);
+		FloatToString(SF2_FLASHLIGHT_WIDTH, sBuffer, sizeof(sBuffer));
+		DispatchKeyValue(ent, "spotlightwidth", sBuffer);
+		DispatchKeyValue(ent, "rendercolor", "255 255 255");
+		DispatchSpawn(ent);
+		ActivateEntity(ent);
+		SetVariantString("!activator");
+		AcceptEntityInput(ent, "SetParent", client);
+		AcceptEntityInput(ent, "LightOn");
+		
+		g_iPlayerFlashlightEntAng[client] = EntIndexToEntRef(ent);
+	}
+	
+	Call_StartForward(fOnClientActivateFlashlight);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+/**
+ *	Turns off the player's flashlight. Nothing else.
+ */
+ClientTurnOffFlashlight(client)
+{
+	if (!IsClientUsingFlashlight(client)) return;
+	
+	g_bPlayerFlashlight[client] = false;
+	g_hPlayerFlashlightBatteryTimer[client] = INVALID_HANDLE;
+	
+	// Remove user-only light.
+	new ent = EntRefToEntIndex(g_iPlayerFlashlightEnt[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE) 
+	{
+		AcceptEntityInput(ent, "TurnOff");
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	// Remove everyone-else-only light.
+	ent = EntRefToEntIndex(g_iPlayerFlashlightEntAng[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE) 
+	{
+		AcceptEntityInput(ent, "LightOff");
+		CreateTimer(0.1, Timer_KillEntity, g_iPlayerFlashlightEntAng[client], TIMER_FLAG_NO_MAPCHANGE);
+	}
+	
+	g_iPlayerFlashlightEnt[client] = INVALID_ENT_REFERENCE;
+	g_iPlayerFlashlightEntAng[client] = INVALID_ENT_REFERENCE;
+	
+	if (IsClientInGame(client))
+	{
+		if (g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight])
+		{
+			new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+			if (iEffects & (1 << 2))
+			{
+				SetEntProp(client, Prop_Send, "m_fEffects", iEffects &= ~(1 << 2));
+			}
+		}
+	}
+	
+	Call_StartForward(fOnClientDeactivateFlashlight);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+ClientStartRechargingFlashlightBattery(client)
+{
+	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(SF2_FLASHLIGHT_RECHARGE_RATE, Timer_RechargeFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStartDrainingFlashlightBattery(client)
+{
+	new Float:flDrainRate = SF2_FLASHLIGHT_DRAIN_RATE;
+	if (TF2_GetPlayerClass(client) == TFClass_Engineer) 
+	{
+		// Engineers have a 33% longer battery life, basically.
+		// TODO: Make this value customizable via cvar.
+		flDrainRate *= 1.33;
+	}
+	
+	g_hPlayerFlashlightBatteryTimer[client] = CreateTimer(flDrainRate, Timer_DrainFlashlight, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientHandleFlashlight(client)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client)) return;
+	
+	if (IsClientUsingFlashlight(client)) 
+	{
+		ClientTurnOffFlashlight(client);
+		ClientStartRechargingFlashlightBattery(client);
+		ClientActivateUltravision(client);
+		
+		g_flPlayerFlashlightNextInputTime[client] = GetGameTime() + SF2_FLASHLIGHT_COOLDOWN;
+		
+		EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
+	}
+	else
+	{
+		// Only players in the "game" can use the flashlight.
+		if (!g_bPlayerEliminated[client])
+		{
+			new bool:bCanUseFlashlight = true;
+			if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_LIGHTSOUT) 
+			{
+				// Unequip the flashlight please.
+				bCanUseFlashlight = false;
+			}
+			
+			if (!IsClientFlashlightBroken(client) && bCanUseFlashlight)
+			{
+				ClientTurnOnFlashlight(client);
+				ClientStartDrainingFlashlightBattery(client);
+				ClientDeactivateUltravision(client);
+				
+				g_flPlayerFlashlightNextInputTime[client] = GetGameTime();
+				
+				EmitSoundToAll(FLASHLIGHT_CLICKSOUND, client, SNDCHAN_STATIC, SNDLEVEL_DRYER);
+			}
+			else
+			{
+				EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
+			}
+		}
+	}
+}
+
+bool:IsClientUsingUltravision(client)
+{
+	return g_bPlayerUltravision[client];
+}
+
+ClientActivateUltravision(client)
+{
+	if (!IsClientInGame(client) || IsClientUsingUltravision(client)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientActivateUltravision(%d)", client);
+#endif
+	
+	g_bPlayerUltravision[client] = true;
+	
+	new ent = CreateEntityByName("light_dynamic");
+	if (ent != -1)
+	{
+		decl Float:flEyePos[3];
+		GetClientEyePosition(client, flEyePos);
+		
+		TeleportEntity(ent, flEyePos, Float:{ 90.0, 0.0, 0.0 }, NULL_VECTOR);
+		DispatchKeyValue(ent, "rendercolor", "0 200 255");
+		
+		new Float:flRadius = 0.0;
+		if (g_bPlayerEliminated[client])
+		{
+			flRadius = GetConVarFloat(g_cvUltravisionRadiusBlue);
+		}
+		else
+		{
+			flRadius = GetConVarFloat(g_cvUltravisionRadiusRed);
+		}
+		
+		SetVariantFloat(flRadius);
+		AcceptEntityInput(ent, "spotlight_radius");
+		SetVariantFloat(flRadius);
+		AcceptEntityInput(ent, "distance");
+		
+		SetVariantInt(-15); // Start dark, then fade in via the Timer_UltravisionFadeInEffect timer func.
+		AcceptEntityInput(ent, "brightness");
+		
+		// Convert WU to inches.
+		new Float:cone = SF2_ULTRAVISION_CONE;
+		cone *= 0.75;
+		
+		SetVariantInt(RoundToFloor(cone));
+		AcceptEntityInput(ent, "_inner_cone");
+		SetVariantInt(0);
+		AcceptEntityInput(ent, "_cone");
+		DispatchSpawn(ent);
+		ActivateEntity(ent);
+		SetVariantString("!activator");
+		AcceptEntityInput(ent, "SetParent", client);
+		AcceptEntityInput(ent, "TurnOn");
+		SetEntityRenderFx(ent, RENDERFX_SOLID_SLOW);
+		SetEntityRenderColor(ent, 100, 200, 255, 255);
+		
+		g_iPlayerUltravisionEnt[client] = EntIndexToEntRef(ent);
+		
+		SDKHook(ent, SDKHook_SetTransmit, Hook_UltravisionSetTransmit);
+		
+		// Fade in effect.
+		CreateTimer(0.0, Timer_UltravisionFadeInEffect, g_iPlayerUltravisionEnt[client], TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	}
+
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientActivateUltravision(%d)", client);
+#endif
+}
+
+public Action:Timer_UltravisionFadeInEffect(Handle:timer, any:entref)
+{
+	new ent = EntRefToEntIndex(entref);
+	if (!ent || ent == INVALID_ENT_REFERENCE) return Plugin_Stop;
+	
+	new iBrightness = GetEntProp(ent, Prop_Send, "m_Exponent");
+	if (iBrightness >= GetConVarInt(g_cvUltravisionBrightness)) return Plugin_Stop;
+	
+	iBrightness++;
+	SetVariantInt(iBrightness);
+	AcceptEntityInput(ent, "brightness");
+	
+	return Plugin_Continue;
+}
+
+ClientDeactivateUltravision(client)
+{
+	if (!IsClientUsingUltravision(client)) return;
+	
+	g_bPlayerUltravision[client] = false;
+	
+	new ent = EntRefToEntIndex(g_iPlayerUltravisionEnt[client]);
+	if (ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "TurnOff");
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	g_iPlayerUltravisionEnt[client] = INVALID_ENT_REFERENCE;
+}
+
+public Action:Hook_UltravisionSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (!GetConVarBool(g_cvUltravisionEnabled) || EntRefToEntIndex(g_iPlayerUltravisionEnt[other]) != ent || !IsPlayerAlive(other)) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+static Float:ClientGetDefaultWalkSpeed(client)
+{
+	new Float:flReturn = 190.0;
+	new Float:flReturn2 = flReturn;
+	new Action:iAction = Plugin_Continue;
+	new TFClassType:iClass = TF2_GetPlayerClass(client);
+	
+	switch (iClass)
+	{
+		case TFClass_Scout: flReturn = 190.0;
+		case TFClass_Sniper: flReturn = 190.0;
+		case TFClass_Soldier: flReturn = 190.0;
+		case TFClass_DemoMan: flReturn = 190.0;
+		case TFClass_Heavy: flReturn = 190.0;
+		case TFClass_Medic: flReturn = 190.0;
+		case TFClass_Pyro: flReturn = 190.0;
+		case TFClass_Spy: flReturn = 190.0;
+		case TFClass_Engineer: flReturn = 190.0;
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnClientGetDefaultWalkSpeed);
+	Call_PushCell(client);
+	Call_PushCellRef(flReturn2);
+	Call_Finish(iAction);
+	
+	if (iAction == Plugin_Changed) flReturn = flReturn2;
+	
+	return flReturn;
+}
+
+static Float:ClientGetDefaultSprintSpeed(client)
+{
+	new Float:flReturn = 300.0;
+	new Float:flReturn2 = flReturn;
+	new Action:iAction = Plugin_Continue;
+	new TFClassType:iClass = TF2_GetPlayerClass(client);
+	
+	switch (iClass)
+	{
+		case TFClass_Scout: flReturn = 300.0;
+		case TFClass_Sniper: flReturn = 300.0;
+		case TFClass_Soldier: flReturn = 275.0;
+		case TFClass_DemoMan: flReturn = 285.0;
+		case TFClass_Heavy: flReturn = 270.0;
+		case TFClass_Medic: flReturn = 300.0;
+		case TFClass_Pyro: flReturn = 300.0;
+		case TFClass_Spy: flReturn = 300.0;
+		case TFClass_Engineer: flReturn = 300.0;
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnClientGetDefaultSprintSpeed);
+	Call_PushCell(client);
+	Call_PushCellRef(flReturn2);
+	Call_Finish(iAction);
+	
+	if (iAction == Plugin_Changed) flReturn = flReturn2;
+	
+	return flReturn;
+}
+
+// Static shaking should only affect the x, y portion of the player's view, not roll.
+// This is purely for cosmetic effect.
+
+ClientProcessStaticShake(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	new bool:bOldStaticShake = g_bPlayerInStaticShake[client];
+	new iOldStaticShakeMaster = NPCGetFromUniqueID(g_iPlayerStaticShakeMaster[client]);
+	new iNewStaticShakeMaster = -1;
+	new Float:flNewStaticShakeMasterAnger = -1.0;
+	
+	new Float:flOldPunchAng[3], Float:flOldPunchAngVel[3];
+	GetEntDataVector(client, g_offsPlayerPunchAngle, flOldPunchAng);
+	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flOldPunchAngVel);
+	
+	new Float:flNewPunchAng[3], Float:flNewPunchAngVel[3];
+	
+	for (new i = 0; i < 3; i++)
+	{
+		flNewPunchAng[i] = flOldPunchAng[i];
+		flNewPunchAngVel[i] = flOldPunchAngVel[i];
+	}
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		if (g_iPlayerStaticMode[client][i] != Static_Increase) continue;
+		if (!(NPCGetFlags(i) & SFF_HASSTATICSHAKE)) continue;
+		
+		if (NPCGetAnger(i) > flNewStaticShakeMasterAnger)
+		{
+			new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
+			if (iMaster == -1) iMaster = i;
+			
+			iNewStaticShakeMaster = iMaster;
+			flNewStaticShakeMasterAnger = NPCGetAnger(iMaster);
+		}
+	}
+	
+	if (iNewStaticShakeMaster != -1)
+	{
+		g_iPlayerStaticShakeMaster[client] = NPCGetUniqueID(iNewStaticShakeMaster);
+		
+		if (iNewStaticShakeMaster != iOldStaticShakeMaster)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iNewStaticShakeMaster, sProfile, sizeof(sProfile));
+		
+			if (g_strPlayerStaticShakeSound[client][0])
+			{
+				StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
+			}
+			
+			g_flPlayerStaticShakeMinVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_min", 0.0);
+			g_flPlayerStaticShakeMaxVolume[client] = GetProfileFloat(sProfile, "sound_static_shake_local_volume_max", 1.0);
+			
+			decl String:sStaticSound[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_static_shake_local", sStaticSound, sizeof(sStaticSound));
+			if (sStaticSound[0])
+			{
+				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), sStaticSound);
+			}
+			else
+			{
+				strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
+			}
+		}
+	}
+	
+	if (g_bPlayerInStaticShake[client])
+	{
+		if (g_flPlayerStaticAmount[client] <= 0.0)
+		{
+			g_bPlayerInStaticShake[client] = false;
+		}
+	}
+	else
+	{
+		if (iNewStaticShakeMaster != -1)
+		{
+			g_bPlayerInStaticShake[client] = true;
+		}
+	}
+	
+	if (g_bPlayerInStaticShake[client] && !bOldStaticShake)
+	{	
+		for (new i = 0; i < 2; i++)
+		{
+			flNewPunchAng[i] = 0.0;
+			flNewPunchAngVel[i] = 0.0;
+		}
+		
+		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
+		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
+	}
+	else if (!g_bPlayerInStaticShake[client] && bOldStaticShake)
+	{
+		for (new i = 0; i < 2; i++)
+		{
+			flNewPunchAng[i] = 0.0;
+			flNewPunchAngVel[i] = 0.0;
+		}
+	
+		g_iPlayerStaticShakeMaster[client] = -1;
+		
+		if (g_strPlayerStaticShakeSound[client][0])
+		{
+			StopSound(client, SNDCHAN_STATIC, g_strPlayerStaticShakeSound[client]);
+		}
+		
+		strcopy(g_strPlayerStaticShakeSound[client], sizeof(g_strPlayerStaticShakeSound[]), "");
+		
+		g_flPlayerStaticShakeMinVolume[client] = 0.0;
+		g_flPlayerStaticShakeMaxVolume[client] = 0.0;
+		
+		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
+		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
+	}
+	
+	if (g_bPlayerInStaticShake[client])
+	{
+		if (g_strPlayerStaticShakeSound[client][0])
+		{
+			new Float:flVolume = g_flPlayerStaticAmount[client];
+			if (GetRandomFloat(0.0, 1.0) <= 0.35)
+			{
+				flVolume = 0.0;
+			}
+			else
+			{
+				if (flVolume < g_flPlayerStaticShakeMinVolume[client])
+				{
+					flVolume = g_flPlayerStaticShakeMinVolume[client];
+				}
+				
+				if (flVolume > g_flPlayerStaticShakeMaxVolume[client])
+				{
+					flVolume = g_flPlayerStaticShakeMaxVolume[client];
+				}
+			}
+			
+			EmitSoundToClient(client, g_strPlayerStaticShakeSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL | SND_STOP, flVolume);
+		}
+		
+		// Spazz our view all over the place.
+		for (new i = 0; i < 2; i++) flNewPunchAng[i] = AngleNormalize(GetRandomFloat(0.0, 360.0));
+		NormalizeVector(flNewPunchAng, flNewPunchAng);
+		
+		new Float:flAngVelocityScalar = 5.0 * g_flPlayerStaticAmount[client];
+		if (flAngVelocityScalar < 1.0) flAngVelocityScalar = 1.0;
+		ScaleVector(flNewPunchAng, flAngVelocityScalar);
+		
+		for (new i = 0; i < 2; i++) flNewPunchAngVel[i] = 0.0;
+		
+		SetEntDataVector(client, g_offsPlayerPunchAngle, flNewPunchAng, true);
+		SetEntDataVector(client, g_offsPlayerPunchAngleVel, flNewPunchAngVel, true);
+	}
+}
+
+ClientProcessVisibility(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client)) return;
+	
+	new String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	new bool:bWasSeeingSlender[MAX_BOSSES];
+	new iOldStaticMode[MAX_BOSSES];
+	
+	decl Float:flSlenderPos[3];
+	decl Float:flSlenderEyePos[3];
+	decl Float:flSlenderOBBCenterPos[3];
+	
+	decl Float:flMyPos[3];
+	GetClientAbsOrigin(client, flMyPos);
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		bWasSeeingSlender[i] = g_bPlayerSeesSlender[client][i];
+		iOldStaticMode[i] = g_iPlayerStaticMode[client][i];
+		g_bPlayerSeesSlender[client][i] = false;
+		g_iPlayerStaticMode[client][i] = Static_None;
+		
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		new iBoss = NPCGetEntIndex(i);
+		
+		if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+		{
+			SlenderGetAbsOrigin(i, flSlenderPos);
+			NPCGetEyePosition(i, flSlenderEyePos);
+			
+			decl Float:flSlenderMins[3], Float:flSlenderMaxs[3];
+			GetEntPropVector(iBoss, Prop_Send, "m_vecMins", flSlenderMins);
+			GetEntPropVector(iBoss, Prop_Send, "m_vecMaxs", flSlenderMaxs);
+			
+			for (new i2 = 0; i2 < 3; i2++) flSlenderOBBCenterPos[i2] = flSlenderPos[i2] + ((flSlenderMins[i2] + flSlenderMaxs[i2]) / 2.0);
+		}
+		
+		if (IsClientInGhostMode(client))
+		{
+		}
+		else if (!IsClientInDeathCam(client))
+		{
+			if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+			{
+				new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
+				
+				if (!IsPointVisibleToPlayer(client, flSlenderEyePos, true, SlenderUsesBlink(i)))
+				{
+					g_bPlayerSeesSlender[client][i] = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, true, SlenderUsesBlink(i));
+				}
+				else
+				{
+					g_bPlayerSeesSlender[client][i] = true;
+				}
+				
+				if ((GetGameTime() - g_flPlayerSeesSlenderLastTime[client][i]) > GetProfileFloat(sProfile, "static_on_look_gracetime", 1.0) ||
+					(iOldStaticMode[i] == Static_Increase && g_flPlayerStaticAmount[client] > 0.1))
+				{
+					if ((NPCGetFlags(i) & SFF_STATICONLOOK) && 
+						g_bPlayerSeesSlender[client][i])
+					{
+						if (iCopyMaster != -1)
+						{
+							g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
+						}
+						else
+						{
+							g_iPlayerStaticMode[client][i] = Static_Increase;
+						}
+					}
+					else if ((NPCGetFlags(i) & SFF_STATICONRADIUS) && 
+						GetVectorDistance(flMyPos, flSlenderPos) <= g_flSlenderStaticRadius[i])
+					{
+						new bool:bNoObstacles = IsPointVisibleToPlayer(client, flSlenderEyePos, false, false);
+						if (!bNoObstacles) bNoObstacles = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, false);
+						
+						if (bNoObstacles)
+						{
+							if (iCopyMaster != -1)
+							{
+								g_iPlayerStaticMode[client][iCopyMaster] = Static_Increase;
+							}
+							else
+							{
+								g_iPlayerStaticMode[client][i] = Static_Increase;
+							}
+						}
+					}
+				}
+				
+				// Process death cam sequence conditions
+				if (SlenderKillsOnNear(i))
+				{
+					if (g_flPlayerStaticAmount[client] >= 1.0 ||
+						GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetInstantKillRadius(i))
+					{
+						new bool:bKillPlayer = true;
+						if (g_flPlayerStaticAmount[client] < 1.0)
+						{
+							bKillPlayer = IsPointVisibleToPlayer(client, flSlenderEyePos, false, SlenderUsesBlink(i));
+						}
+						
+						if (!bKillPlayer) bKillPlayer = IsPointVisibleToPlayer(client, flSlenderOBBCenterPos, false, SlenderUsesBlink(i));
+						
+						if (bKillPlayer)
+						{
+							g_flSlenderLastKill[i] = GetGameTime();
+							
+							if (g_flPlayerStaticAmount[client] >= 1.0)
+							{
+								ClientStartDeathCam(client, NPCGetFromUniqueID(g_iPlayerStaticMaster[client]), flSlenderPos);
+							}
+							else
+							{
+								ClientStartDeathCam(client, i, flSlenderPos);
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[i]);
+		if (iMaster == -1) iMaster = i;
+		
+		// Boss visiblity.
+		if (g_bPlayerSeesSlender[client][i] && !bWasSeeingSlender[i])
+		{
+			g_flPlayerSeesSlenderLastTime[client][iMaster] = GetGameTime();
+			
+			if (GetGameTime() >= g_flPlayerScareNextTime[client][iMaster])
+			{
+				if (GetVectorDistance(flMyPos, flSlenderPos) <= NPCGetScareRadius(i))
+				{
+					ClientPerformScare(client, iMaster);
+					
+					if (NPCHasAttribute(iMaster, "ignite player on scare"))
+					{
+						new Float:flValue = NPCGetAttributeValue(iMaster, "ignite player on scare");
+						if (flValue > 0.0) TF2_IgnitePlayer(client, client);
+					}
+				}
+				else
+				{
+					g_flPlayerScareNextTime[client][iMaster] = GetGameTime() + GetProfileFloat(sProfile, "scare_cooldown");
+				}
+			}
+			
+			if (NPCGetType(i) == SF2BossType_Static)
+			{
+				if (NPCGetFlags(i) & SFF_FAKE)
+				{
+					SlenderMarkAsFake(i);
+					return;
+				}
+			}
+			
+			Call_StartForward(fOnClientLooksAtBoss);
+			Call_PushCell(client);
+			Call_PushCell(i);
+			Call_Finish();
+		}
+		else if (!g_bPlayerSeesSlender[client][i] && bWasSeeingSlender[i])
+		{
+			g_flPlayerScareLastTime[client][iMaster] = GetGameTime();
+			
+			Call_StartForward(fOnClientLooksAwayFromBoss);
+			Call_PushCell(client);
+			Call_PushCell(i);
+			Call_Finish();
+		}
+		
+		if (g_bPlayerSeesSlender[client][i])
+		{
+			if (GetGameTime() >= g_flPlayerSightSoundNextTime[client][iMaster])
+			{
+				ClientPerformSightSound(client, i);
+			}
+		}
+		
+		if (g_iPlayerStaticMode[client][i] == Static_Increase &&
+			iOldStaticMode[i] != Static_Increase)
+		{
+			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
+			{
+				decl String:sLoopSound[PLATFORM_MAX_PATH];
+				GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
+				
+				if (sLoopSound[0])
+				{
+					EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, GetProfileNum(sProfile, "sound_static_loop_local_level", SNDLEVEL_NORMAL), SND_CHANGEVOL, 1.0);
+					ClientAddStress(client, 0.03);
+				}
+				else
+				{
+					LogError("Warning! Boss %s supports static loop local sounds, but was given a blank sound path!", sProfile);
+				}
+			}
+		}
+		else if (g_iPlayerStaticMode[client][i] != Static_Increase &&
+			iOldStaticMode[i] == Static_Increase)
+		{
+			if (NPCGetFlags(i) & SFF_HASSTATICLOOPLOCALSOUND)
+			{
+				if (iBoss && iBoss != INVALID_ENT_REFERENCE)
+				{
+					decl String:sLoopSound[PLATFORM_MAX_PATH];
+					GetRandomStringFromProfile(sProfile, "sound_static_loop_local", sLoopSound, sizeof(sLoopSound), 1);
+					
+					if (sLoopSound[0])
+					{
+						EmitSoundToClient(client, sLoopSound, iBoss, SNDCHAN_STATIC, _, SND_CHANGEVOL | SND_STOP, 0.0);
+					}
+				}
+			}
+		}
+	}
+	
+	// Initialize static timers.
+	new iBossLastStatic = NPCGetFromUniqueID(g_iPlayerStaticMaster[client]);
+	new iBossNewStatic = -1;
+	if (iBossLastStatic != -1 && g_iPlayerStaticMode[client][iBossLastStatic] == Static_Increase)
+	{
+		iBossNewStatic = iBossLastStatic;
+	}
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		new iStaticMode = g_iPlayerStaticMode[client][i];
+		
+		// Determine new static rates.
+		if (iStaticMode != Static_Increase) continue;
+		
+		if (iBossLastStatic == -1 || 
+			g_iPlayerStaticMode[client][iBossLastStatic] != Static_Increase || 
+			NPCGetAnger(i) > NPCGetAnger(iBossLastStatic))
+		{
+			iBossNewStatic = i;
+		}
+	}
+	
+	if (iBossNewStatic != -1)
+	{
+		new iCopyMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossNewStatic]);
+		if (iCopyMaster != -1)
+		{
+			iBossNewStatic = iCopyMaster;
+			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iCopyMaster);
+		}
+		else
+		{
+			g_iPlayerStaticMaster[client] = NPCGetUniqueID(iBossNewStatic);
+		}
+	}
+	else
+	{
+		g_iPlayerStaticMaster[client] = -1;
+	}
+	
+	if (iBossNewStatic != iBossLastStatic)
+	{
+		if (!StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false))
+		{
+			// Stop last-last static sound entirely.
+			if (g_strPlayerLastStaticSound[client][0])
+			{
+				StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+			}
+		}
+		
+		// Move everything down towards the last arrays.
+		if (g_strPlayerStaticSound[client][0])
+		{
+			strcopy(g_strPlayerLastStaticSound[client], sizeof(g_strPlayerLastStaticSound[]), g_strPlayerStaticSound[client]);
+		}
+		
+		if (iBossNewStatic == -1)
+		{
+			// No one is the static master.
+			g_hPlayerStaticTimer[client] = CreateTimer(g_flPlayerStaticDecreaseRate[client], 
+				Timer_ClientDecreaseStatic, 
+				GetClientUserId(client), 
+				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+				
+			TriggerTimer(g_hPlayerStaticTimer[client], true);
+		}
+		else
+		{
+			NPCGetProfile(iBossNewStatic, sProfile, sizeof(sProfile));
+		
+			strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), "");
+			
+			new String:sStaticSound[PLATFORM_MAX_PATH];
+			GetRandomStringFromProfile(sProfile, "sound_static", sStaticSound, sizeof(sStaticSound), 1);
+			
+			if (sStaticSound[0]) 
+			{
+				strcopy(g_strPlayerStaticSound[client], sizeof(g_strPlayerStaticSound[]), sStaticSound);
+			}
+			
+			// Cross-fade out the static sounds.
+			g_flPlayerLastStaticVolume[client] = g_flPlayerStaticAmount[client];
+			g_flPlayerLastStaticTime[client] = GetGameTime();
+			
+			g_hPlayerLastStaticTimer[client] = CreateTimer(0.0, 
+				Timer_ClientFadeOutLastStaticSound, 
+				GetClientUserId(client), 
+				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			
+			TriggerTimer(g_hPlayerLastStaticTimer[client], true);
+			
+			// Start up our own static timer.
+			new Float:flStaticIncreaseRate = GetProfileFloat(sProfile, "static_rate") / g_flRoundDifficultyModifier;
+			new Float:flStaticDecreaseRate = GetProfileFloat(sProfile, "static_rate_decay");
+			
+			g_flPlayerStaticIncreaseRate[client] = flStaticIncreaseRate;
+			g_flPlayerStaticDecreaseRate[client] = flStaticDecreaseRate;
+			
+			g_hPlayerStaticTimer[client] = CreateTimer(flStaticIncreaseRate, 
+				Timer_ClientIncreaseStatic, 
+				GetClientUserId(client), 
+				TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			
+			TriggerTimer(g_hPlayerStaticTimer[client], true);
+		}
+	}
+}
+
+ClientProcessViewAngles(client)
+{
+	if ((!g_bPlayerEliminated[client] || g_bPlayerProxy[client]) && 
+		!DidClientEscape(client))
+	{
+		// Process view bobbing, if enabled.
+		// This code is based on the code in this page: https://developer.valvesoftware.com/wiki/Camera_Bob
+		// Many thanks to whomever created it in the first place.
+		
+		if (IsPlayerAlive(client))
+		{
+			if (g_bPlayerViewbobEnabled)
+			{
+				new Float:flPunchVel[3];
+			
+				if (!g_bPlayerViewbobSprintEnabled || !IsClientReallySprinting(client))
+				{
+					if (GetEntityFlags(client) & FL_ONGROUND)
+					{
+						decl Float:flVelocity[3];
+						GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
+						new Float:flSpeed = GetVectorLength(flVelocity);
+						
+						new Float:flPunchIdle[3];
+						
+						if (flSpeed > 0.0)
+						{
+							if (flSpeed >= 60.0)
+							{
+								flPunchIdle[0] = Sine(GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_X / 400.0;
+								flPunchIdle[1] = Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Y / 400.0;
+								flPunchIdle[2] = Sine(1.6 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Z / 400.0;
+								
+								AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+							}
+							
+							// Calculate roll.
+							decl Float:flForward[3], Float:flVelocityDirection[3];
+							GetClientEyeAngles(client, flForward);
+							GetVectorAngles(flVelocity, flVelocityDirection);
+							
+							new Float:flYawDiff = AngleDiff(flForward[1], flVelocityDirection[1]);
+							if (FloatAbs(flYawDiff) > 90.0) flYawDiff = AngleDiff(flForward[1] + 180.0, flVelocityDirection[1]) * -1.0;
+							
+							new Float:flWalkSpeed = ClientGetDefaultWalkSpeed(client);
+							new Float:flRollScalar = flSpeed / flWalkSpeed;
+							if (flRollScalar > 1.0) flRollScalar = 1.0;
+							
+							new Float:flRollScale = (flYawDiff / 90.0) * 0.25 * flRollScalar;
+							flPunchIdle[0] = 0.0;
+							flPunchIdle[1] = 0.0;
+							flPunchIdle[2] = flRollScale * -1.0;
+							
+							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+						}
+						
+						g_flPlayerBreathViewbobPhase[client] += SF2_BREATH_VIEWBOB_SPEED;
+						if(g_flPlayerBreathViewbobPhase[client] > 3.14159265355) {
+							g_flPlayerBreathViewbobPhase[client] = 0.0; // Sine cycle
+							g_flPlayerBreathViewbobXMult[client] = GetRandomFloat(-1.0, 1.0);
+							g_flPlayerBreathViewbobYMult[client] = GetRandomFloat(-1.0, 1.0);
+						}
+						new Float:sine = Sine(g_flPlayerBreathViewbobPhase[client]);
+						flPunchIdle[0] = SF2_BREATH_VIEWBOB_START * sine * g_flPlayerBreathViewbobXMult[client] + SF2_BREATH_VIEWBOB_AMPLITUDE * sine * g_flPlayerBreathViewbobXMult[client] *  float(100 - g_iPlayerSprintPoints[client]) / 100.0;
+						flPunchIdle[1] = SF2_BREATH_VIEWBOB_START / 2.0 * sine * g_flPlayerBreathViewbobYMult[client] + SF2_BREATH_VIEWBOB_AMPLITUDE / 2.0 * sine * g_flPlayerBreathViewbobYMult[client] * float(100 - g_iPlayerSprintPoints[client]) / 100.0;
+						flPunchIdle[2] = 0.0;//Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) ;//Sine(2.0 * GetGameTime() * SF2_PLAYER_VIEWBOB_TIMER) * flSpeed * SF2_PLAYER_VIEWBOB_SCALE_Z / 400.0;
+						
+						AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+						/*
+						if (flSpeed < 60.0) 
+						{
+							flPunchIdle[0] = FloatAbs(Cosine(GetGameTime() * 1.25) * 0.047);
+							flPunchIdle[1] = Sine(GetGameTime() * 1.25) * 0.075;
+							flPunchIdle[2] = 0.0;
+							
+							AddVectors(flPunchVel, flPunchIdle, flPunchVel);
+						}
+						*/
+					}
+				}
+				
+				if (g_bPlayerViewbobHurtEnabled)
+				{
+					// Shake screen the more the player is hurt.
+					new Float:flHealth = float(GetEntProp(client, Prop_Send, "m_iHealth"));
+					new Float:flMaxHealth = float(SDKCall(g_hSDKGetMaxHealth, client));
+					
+					decl Float:flPunchVelHurt[3];
+					flPunchVelHurt[0] = Sine(1.22 * GetGameTime()) * 48.5 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
+					flPunchVelHurt[1] = Sine(2.12 * GetGameTime()) * 80.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
+					flPunchVelHurt[2] = Sine(0.5 * GetGameTime()) * 36.0 * ((flMaxHealth - flHealth) / (flMaxHealth * 0.75)) / flMaxHealth;
+					
+					AddVectors(flPunchVel, flPunchVelHurt, flPunchVel);
+				}
+				
+				ClientViewPunch(client, flPunchVel);
+			}
+		}
+	}
+}
+
+public Action:Timer_ClientIncreaseStatic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
+	
+	g_flPlayerStaticAmount[client] += 0.05;
+	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
+	
+	if (g_strPlayerStaticSound[client][0])
+	{
+		EmitSoundToClient(client, g_strPlayerStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerStaticAmount[client]);
+		
+		if (g_flPlayerStaticAmount[client] >= 0.5) ClientAddStress(client, 0.03);
+		else
+		{
+			ClientAddStress(client, 0.02);
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_ClientDecreaseStatic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerStaticTimer[client]) return Plugin_Stop;
+	
+	g_flPlayerStaticAmount[client] -= 0.05;
+	if (g_flPlayerStaticAmount[client] < 0.0) g_flPlayerStaticAmount[client] = 0.0;
+	
+	if (g_strPlayerLastStaticSound[client][0])
+	{
+		new Float:flVolume = g_flPlayerStaticAmount[client];
+		if (flVolume > 0.0)
+		{
+			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
+		}
+	}
+	
+	if (g_flPlayerStaticAmount[client] <= 0.0)
+	{
+		// I've done my job; no point to keep on doing it.
+		StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+		g_hPlayerStaticTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_ClientFadeOutLastStaticSound(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerLastStaticTimer[client]) return Plugin_Stop;
+	
+	if (StrEqual(g_strPlayerLastStaticSound[client], g_strPlayerStaticSound[client], false)) 
+	{
+		// Wait, the player's current static sound is the same one we're stopping. Abort!
+		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	if (g_strPlayerLastStaticSound[client][0])
+	{
+		new Float:flDiff = (GetGameTime() - g_flPlayerLastStaticTime[client]) / 1.0;
+		if (flDiff > 1.0) flDiff = 1.0;
+		
+		new Float:flVolume = g_flPlayerLastStaticVolume[client] - flDiff;
+		if (flVolume < 0.0) flVolume = 0.0;
+		
+		if (flVolume <= 0.0)
+		{
+			// I've done my job; no point to keep on doing it.
+			StopSound(client, SNDCHAN_STATIC, g_strPlayerLastStaticSound[client]);
+			g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+			return Plugin_Stop;
+		}
+		else
+		{
+			EmitSoundToClient(client, g_strPlayerLastStaticSound[client], _, SNDCHAN_STATIC, SNDLEVEL_NONE, SND_CHANGEVOL, flVolume);
+		}
+	}
+	else
+	{
+		// I've done my job; no point to keep on doing it.
+		g_hPlayerLastStaticTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	INTERACTIVE GLOW FUNCTIONS
+//	==========================================================
+
+static ClientProcessInteractiveGlow(client)
+{
+	if (!IsClientInGame(client) || !IsPlayerAlive(client) || (g_bPlayerEliminated[client] && !g_bPlayerProxy[client]) || IsClientInGhostMode(client)) return;
+	
+	new iOldLookEntity = EntRefToEntIndex(g_iPlayerInteractiveGlowTargetEntity[client]);
+	
+	decl Float:flStartPos[3], Float:flMyEyeAng[3];
+	GetClientEyePosition(client, flStartPos);
+	GetClientEyeAngles(client, flMyEyeAng);
+	
+	new Handle:hTrace = TR_TraceRayFilterEx(flStartPos, flMyEyeAng, MASK_VISIBLE, RayType_Infinite, TraceRayDontHitPlayers, -1);
+	new iEnt = TR_GetEntityIndex(hTrace);
+	CloseHandle(hTrace);
+	
+	if (IsValidEntity(iEnt))
+	{
+		g_iPlayerInteractiveGlowTargetEntity[client] = EntRefToEntIndex(iEnt);
+	}
+	else
+	{
+		g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
+	}
+	
+	if (iEnt != iOldLookEntity)
+	{
+		ClientRemoveInteractiveGlow(client);
+		
+		if (IsEntityClassname(iEnt, "prop_dynamic", false))
+		{
+			decl String:sTargetName[64];
+			GetEntPropString(iEnt, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
+			
+			if (StrContains(sTargetName, "sf2_page", false) == 0 || StrContains(sTargetName, "sf2_interact", false) == 0)
+			{
+				ClientCreateInteractiveGlow(client, iEnt);
+			}
+		}
+	}
+}
+
+ClientResetInteractiveGlow(client)
+{
+	ClientRemoveInteractiveGlow(client);
+	g_iPlayerInteractiveGlowTargetEntity[client] = INVALID_ENT_REFERENCE;
+}
+
+/**
+ *	Removes the player's current interactive glow entity.
+ */
+ClientRemoveInteractiveGlow(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientRemoveInteractiveGlow(%d)", client);
+#endif
+
+	new ent = EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	g_iPlayerInteractiveGlowEntity[client] = INVALID_ENT_REFERENCE;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientRemoveInteractiveGlow(%d)", client);
+#endif
+}
+
+/**
+ *	Creates an interactive glow for an entity to show to a player.
+ */
+bool:ClientCreateInteractiveGlow(client, iEnt, const String:sAttachment[]="")
+{
+	ClientRemoveInteractiveGlow(client);
+	
+	if (!IsClientInGame(client)) return false;
+	
+	if (!iEnt || !IsValidEdict(iEnt)) return false;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientCreateInteractiveGlow(%d)", client);
+#endif
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetEntPropString(iEnt, Prop_Data, "m_ModelName", sBuffer, sizeof(sBuffer));
+	
+	if (strlen(sBuffer) == 0) 
+	{
+		return false;
+	}
+	
+	new ent = CreateEntityByName("tf_taunt_prop");
+	if (ent != -1)
+	{
+		g_iPlayerInteractiveGlowEntity[client] = EntIndexToEntRef(ent);
+		
+		new Float:flModelScale = GetEntPropFloat(iEnt, Prop_Send, "m_flModelScale");
+		
+		SetEntityModel(ent, sBuffer);
+		DispatchSpawn(ent);
+		ActivateEntity(ent);
+		SetEntityRenderMode(ent, RENDER_TRANSCOLOR);
+		SetEntityRenderColor(ent, 0, 0, 0, 0);
+		SetEntProp(ent, Prop_Send, "m_bGlowEnabled", 1);
+		SetEntPropFloat(ent, Prop_Send, "m_flModelScale", flModelScale);
+		
+		new iFlags = GetEntProp(ent, Prop_Send, "m_fEffects");
+		SetEntProp(ent, Prop_Send, "m_fEffects", iFlags | (1 << 0));
+		
+		SetVariantString("!activator");
+		AcceptEntityInput(ent, "SetParent", iEnt);
+		
+		if (sAttachment[0])
+		{
+			SetVariantString(sAttachment);
+			AcceptEntityInput(ent, "SetParentAttachment");
+		}
+		
+		SDKHook(ent, SDKHook_SetTransmit, Hook_InterativeGlowSetTransmit);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> true", client);
+#endif
+		
+		return true;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientCreateInteractiveGlow(%d) -> false", client);
+#endif
+	
+	return false;
+}
+
+public Action:Hook_InterativeGlowSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (EntRefToEntIndex(g_iPlayerInteractiveGlowEntity[other]) != ent) return Plugin_Handled;
+	
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	BREATHING FUNCTIONS
+//	==========================================================
+
+ClientResetBreathing(client)
+{
+	g_bPlayerBreath[client] = false;
+	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
+}
+
+Float:ClientCalculateBreathingCooldown(client)
+{
+	new Float:flAverage = 0.0;
+	new iAverageNum = 0;
+	
+	// Sprinting only, for now.
+	flAverage += (SF2_PLAYER_BREATH_COOLDOWN_MAX * 6.7765 * Pow((float(g_iPlayerSprintPoints[client]) / 100.0), 1.65));
+	iAverageNum++;
+	
+	flAverage /= float(iAverageNum)
+	
+	if (flAverage < SF2_PLAYER_BREATH_COOLDOWN_MIN) flAverage = SF2_PLAYER_BREATH_COOLDOWN_MIN;
+	
+	return flAverage;
+}
+
+ClientStartBreathing(client)
+{
+	g_bPlayerBreath[client] = true;
+	g_hPlayerBreathTimer[client] = CreateTimer(ClientCalculateBreathingCooldown(client), Timer_ClientBreath, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStopBreathing(client)
+{
+	g_bPlayerBreath[client] = false;
+	g_hPlayerBreathTimer[client] = INVALID_HANDLE;
+}
+
+bool:ClientCanBreath(client)
+{
+	return bool:(ClientCalculateBreathingCooldown(client) < SF2_PLAYER_BREATH_COOLDOWN_MAX);
+}
+
+public Action:Timer_ClientBreath(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerBreathTimer[client]) return;
+	
+	if (!g_bPlayerBreath[client]) return;
+	
+	if (ClientCanBreath(client))
+	{
+		EmitSoundToAll(g_strPlayerBreathSounds[GetRandomInt(0, sizeof(g_strPlayerBreathSounds) - 1)], client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+		
+		ClientStartBreathing(client);
+		return;
+	}
+	
+	ClientStopBreathing(client);
+}
+
+//	==========================================================
+//	SPRINTING FUNCTIONS
+//	==========================================================
+
+bool:IsClientSprinting(client)
+{
+	return g_bPlayerSprint[client];
+}
+
+ClientGetSprintPoints(client)
+{
+	return g_iPlayerSprintPoints[client];
+}
+
+ClientResetSprint(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSprint(%d)", client);
+#endif
+
+	g_bPlayerSprint[client] = false;
+	g_iPlayerSprintPoints[client] = 100;
+	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+	
+	if (IsValidClient(client))
+	{
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSprint(%d)", client);
+#endif
+}
+
+ClientStartSprint(client)
+{
+	if (IsClientSprinting(client)) return;
+	
+	g_bPlayerSprint[client] = true;
+	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+	ClientSprintTimer(client);
+	TriggerTimer(g_hPlayerSprintTimer[client], true);
+	
+	SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+	SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+}
+
+static ClientSprintTimer(client, bool:bRecharge=false)
+{
+	new Float:flRate = 0.28;
+	if (bRecharge) flRate = 0.8;
+	
+	decl Float:flVelocity[3];
+	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
+	
+	if (bRecharge)
+	{
+		if (!(GetEntityFlags(client) & FL_ONGROUND)) flRate *= 0.75;
+		else if (GetVectorLength(flVelocity) == 0.0)
+		{
+			if (GetEntProp(client, Prop_Send, "m_bDucked")) flRate *= 0.66;
+			else flRate *= 0.75;
+		}
+	}
+	else
+	{
+		if (TF2_GetPlayerClass(client) == TFClass_Scout) flRate *= 1.15;
+	}
+	
+	if (bRecharge) g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientRechargeSprint, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	else g_hPlayerSprintTimer[client] = CreateTimer(flRate, Timer_ClientSprinting, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStopSprint(client)
+{
+	if (!IsClientSprinting(client)) return;
+	
+	g_bPlayerSprint[client] = false;
+	g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+	ClientSprintTimer(client, true);
+	
+	SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+	SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+}
+
+bool:IsClientReallySprinting(client)
+{
+	if (!IsClientSprinting(client)) return false;
+	if (!(GetEntityFlags(client) & FL_ONGROUND)) return false;
+	
+	decl Float:flVelocity[3];
+	GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", flVelocity);
+	if (GetVectorLength(flVelocity) < 30.0) return false;
+	
+	return true;
+}
+
+public Action:Timer_ClientSprinting(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerSprintTimer[client]) return;
+	
+	if (!IsClientSprinting(client)) return;
+	
+	if (g_iPlayerSprintPoints[client] <= 0)
+	{
+		ClientStopSprint(client);
+		g_iPlayerSprintPoints[client] = 0;
+		return;
+	}
+	
+	if (IsClientReallySprinting(client)) 
+	{
+		new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
+		if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
+		{
+			g_iPlayerSprintPoints[client]--;
+		}
+	}
+	
+	ClientSprintTimer(client);
+}
+
+public Hook_ClientSprintingPreThink(client)
+{
+	if (!IsClientReallySprinting(client))
+	{
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+		SDKHook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+		return;
+	}}
+
+public Hook_ClientRechargeSprintPreThink(client)
+{
+	if (IsClientReallySprinting(client))
+	{
+		SDKUnhook(client, SDKHook_PreThink, Hook_ClientRechargeSprintPreThink);
+		SDKHook(client, SDKHook_PreThink, Hook_ClientSprintingPreThink);
+		return;
+	}
+}
+
+public Action:Timer_ClientRechargeSprint(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerSprintTimer[client]) return;
+	
+	if (IsClientSprinting(client)) 
+	{
+		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+		return;
+	}
+	
+	if (g_iPlayerSprintPoints[client] >= 100)
+	{
+		g_iPlayerSprintPoints[client] = 100;
+		g_hPlayerSprintTimer[client] = INVALID_HANDLE;
+		return;
+	}
+	
+	g_iPlayerSprintPoints[client]++;
+	ClientSprintTimer(client, true);
+}
+
+//	==========================================================
+//	PROXY / GHOST AND GLOW FUNCTIONS
+//	==========================================================
+
+ClientResetProxy(client, bool:bResetFull=true)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetProxy(%d)", client);
+#endif
+
+	new iOldMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+	new String:sOldProfileName[SF2_MAX_PROFILE_NAME_LENGTH];
+	if (iOldMaster >= 0)
+	{
+		NPCGetProfile(iOldMaster, sOldProfileName, sizeof(sOldProfileName));
+	}
+	
+	new bool:bOldProxy = g_bPlayerProxy[client];
+	if (bResetFull) 
+	{
+		g_bPlayerProxy[client] = false;
+		g_iPlayerProxyMaster[client] = -1;
+	}
+	
+	g_iPlayerProxyControl[client] = 0;
+	g_hPlayerProxyControlTimer[client] = INVALID_HANDLE;
+	g_flPlayerProxyControlRate[client] = 0.0;
+	g_flPlayerProxyVoiceTimer[client] = INVALID_HANDLE;
+	
+	if (IsClientInGame(client))
+	{
+		if (bOldProxy)
+		{
+			ClientStartProxyAvailableTimer(client);
+		
+			if (bResetFull)
+			{
+				SetVariantString("");
+				AcceptEntityInput(client, "SetCustomModel");
+			}
+			
+			if (sOldProfileName[0])
+			{
+				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_spawn", GetProfileNum(sOldProfileName, "sound_proxy_spawn_channel", SNDCHAN_AUTO));
+				ClientStopAllSlenderSounds(client, sOldProfileName, "sound_proxy_hurt", GetProfileNum(sOldProfileName, "sound_proxy_hurt_channel", SNDCHAN_AUTO));
+			}
+		}
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetProxy(%d)", client);
+#endif
+}
+
+ClientStartProxyAvailableTimer(client)
+{
+	g_bPlayerProxyAvailable[client] = false;
+	g_hPlayerProxyAvailableTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerProxyWaitTime), Timer_ClientProxyAvailable, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+}
+
+ClientStartProxyForce(client, iSlenderID, const Float:flPos[3])
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
+#endif
+
+	g_iPlayerProxyAskMaster[client] = iSlenderID;
+	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
+
+	g_iPlayerProxyAvailableCount[client] = 0;
+	g_bPlayerProxyAvailableInForce[client] = true;
+	g_hPlayerProxyAvailableTimer[client] = CreateTimer(1.0, Timer_ClientForceProxy, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerProxyAvailableTimer[client], true);
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientStartProxyForce(%d, %d, flPos)", client, iSlenderID);
+#endif
+}
+
+ClientStopProxyForce(client)
+{
+	g_iPlayerProxyAvailableCount[client] = 0;
+	g_bPlayerProxyAvailableInForce[client] = false;
+	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
+}
+
+public Action:Timer_ClientForceProxy(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerProxyAvailableTimer[client]) return Plugin_Stop;
+	
+	if (!IsRoundEnding())
+	{
+		new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[client]);
+		if (iBossIndex != -1)
+		{
+			decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+			NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+		
+			new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
+			new iNumProxies = 0;
+			
+			for (new iClient = 1; iClient <= MaxClients; iClient++)
+			{
+				if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+				if (!g_bPlayerProxy[iClient]) continue;
+				if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
+				
+				iNumProxies++;
+			}
+			
+			if (iNumProxies < iMaxProxies)
+			{
+				if (g_iPlayerProxyAvailableCount[client] > 0)
+				{
+					g_iPlayerProxyAvailableCount[client]--;
+					
+					SetHudTextParams(-1.0, 0.25, 
+						1.0,
+						255, 255, 255, 255,
+						_,
+						_,
+						0.25, 1.25);
+					
+					ShowSyncHudText(client, g_hHudSync, "%T", "SF2 Proxy Force Message", client, g_iPlayerProxyAvailableCount[client]);
+					
+					return Plugin_Continue;
+				}
+				else
+				{
+					ClientEnableProxy(client, iBossIndex);
+					TeleportEntity(client, g_iPlayerProxyAskPosition[client], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+				}
+			}
+			else
+			{
+				PrintToChat(client, "%T", "SF2 Too Many Proxies", client);
+			}
+		}
+	}
+	
+	ClientStopProxyForce(client);
+	return Plugin_Stop;
+}
+
+DisplayProxyAskMenu(client, iAskMaster, const Float:flPos[3])
+{
+	decl String:sBuffer[512];
+	new Handle:hMenu = CreateMenu(Menu_ProxyAsk);
+	SetMenuTitle(hMenu, "%T\n \n%T\n \n", "SF2 Proxy Ask Menu Title", client, "SF2 Proxy Ask Menu Description", client);
+	
+	Format(sBuffer, sizeof(sBuffer), "%T", "Yes", client);
+	AddMenuItem(hMenu, "1", sBuffer);
+	Format(sBuffer, sizeof(sBuffer), "%T", "No", client);
+	AddMenuItem(hMenu, "0", sBuffer);
+	
+	g_iPlayerProxyAskMaster[client] = iAskMaster;
+	for (new i = 0; i < 3; i++) g_iPlayerProxyAskPosition[client][i] = flPos[i];
+	DisplayMenu(hMenu, client, 15);
+}
+
+public Menu_ProxyAsk(Handle:menu, MenuAction:action, param1, param2)
+{
+	switch (action)
+	{
+		case MenuAction_End: CloseHandle(menu);
+		case MenuAction_Select:
+		{
+			if (!IsRoundEnding())
+			{
+				new iBossIndex = NPCGetFromUniqueID(g_iPlayerProxyAskMaster[param1]);
+				if (iBossIndex != -1)
+				{
+					decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+					NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+				
+					new iMaxProxies = GetProfileNum(sProfile, "proxies_max");
+					new iNumProxies;
+				
+					for (new iClient = 1; iClient <= MaxClients; iClient++)
+					{
+						if (!IsClientInGame(iClient) || !g_bPlayerEliminated[iClient]) continue;
+						if (!g_bPlayerProxy[iClient]) continue;
+						if (NPCGetFromUniqueID(g_iPlayerProxyMaster[iClient]) != iBossIndex) continue;
+						
+						iNumProxies++;
+					}
+					
+					if (iNumProxies < iMaxProxies)
+					{
+						if (param2 == 0)
+						{
+							ClientEnableProxy(param1, iBossIndex);
+							TeleportEntity(param1, g_iPlayerProxyAskPosition[param1], NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+						}
+						else
+						{
+							ClientStartProxyAvailableTimer(param1);
+						}
+					}
+					else
+					{
+						PrintToChat(param1, "%T", "SF2 Too Many Proxies", param1);
+					}
+				}
+			}
+		}
+	}
+}
+
+public Action:Timer_ClientProxyAvailable(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerProxyAvailableTimer[client]) return;
+	
+	g_bPlayerProxyAvailable[client] = true;
+	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
+}
+
+ClientEnableProxy(client, iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1) return;
+	if (!(NPCGetFlags(iBossIndex) & SFF_PROXIES)) return;
+	if (g_bPlayerProxy[client]) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	PvP_SetPlayerPvPState(client, false, false, false);
+	
+	ClientSetGhostModeState(client, false);
+	
+	ClientStopProxyForce(client);
+	
+	ChangeClientTeamNoSuicide(client, _:TFTeam_Blue);
+	if (!IsPlayerAlive(client)) TF2_RespawnPlayer(client);
+	// Speed recalculation. Props to the creators of FF2/VSH for this snippet.
+	TF2_AddCondition(client, TFCond_SpeedBuffAlly, 0.001);
+	
+	g_bPlayerProxy[client] = true;
+	g_iPlayerProxyMaster[client] = NPCGetUniqueID(iBossIndex);
+	g_iPlayerProxyControl[client] = 100;
+	g_flPlayerProxyControlRate[client] = GetProfileFloat(sProfile, "proxies_controldrainrate");
+	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	g_bPlayerProxyAvailable[client] = false;
+	g_hPlayerProxyAvailableTimer[client] = INVALID_HANDLE;
+	
+	decl String:sAllowedClasses[512];
+	GetProfileString(sProfile, "proxies_classes", sAllowedClasses, sizeof(sAllowedClasses));
+	
+	decl String:sClassName[64];
+	TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
+	if (sAllowedClasses[0] && sClassName[0] && StrContains(sAllowedClasses, sClassName, false) == -1)
+	{
+		// Pick the first class that's allowed.
+		new String:sAllowedClassesList[32][32];
+		new iClassCount = ExplodeString(sAllowedClasses, " ", sAllowedClassesList, 32, 32);
+		if (iClassCount)
+		{
+			TF2_SetPlayerClass(client, TF2_GetClass(sAllowedClassesList[0]), _, false);
+			
+			new iMaxHealth = GetEntProp(client, Prop_Send, "m_iHealth");
+			TF2_RegeneratePlayer(client);
+			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
+			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
+		}
+	}
+	
+	UTIL_ScreenFade(client, 200, 1, FFADE_IN, 255, 255, 255, 100);
+	PrecacheSound("weapons/teleporter_send.wav");
+	EmitSoundToClient(client, "weapons/teleporter_send.wav", _, SNDCHAN_STATIC);
+	
+	ClientActivateUltravision(client);
+	
+	CreateTimer(0.33, Timer_ApplyCustomModel, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	
+	Call_StartForward(fOnClientSpawnedAsProxy);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+public Action:Timer_ClientProxyControl(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerProxyControlTimer[client]) return;
+	
+	g_iPlayerProxyControl[client]--;
+	if (g_iPlayerProxyControl[client] <= 0)
+	{
+		// ForcePlayerSuicide isn't really dependable, since the player doesn't suicide until several seconds after spawning has passed.
+		SDKHooks_TakeDamage(client, client, client, 9001.0, DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+		return;
+	}
+	
+	g_hPlayerProxyControlTimer[client] = CreateTimer(g_flPlayerProxyControlRate[client], Timer_ClientProxyControl, userid, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+bool:DoesClientHaveConstantGlow(client)
+{
+	return g_bPlayerConstantGlowEnabled[client];
+}
+
+ClientDisableConstantGlow(client)
+{
+	if (!DoesClientHaveConstantGlow(client)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientDisableConstantGlow(%d)", client);
+#endif
+	
+	g_bPlayerConstantGlowEnabled[client] = false;
+	
+	new iGlow = EntRefToEntIndex(g_iPlayerConstantGlowEntity[client]);
+	if (iGlow && iGlow != INVALID_ENT_REFERENCE) AcceptEntityInput(iGlow, "Kill");
+	
+	g_iPlayerConstantGlowEntity[client] = INVALID_ENT_REFERENCE;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientDisableConstantGlow(%d)", client);
+#endif
+}
+
+bool:ClientEnableConstantGlow(client, const String:sAttachment[]="")
+{
+	if (DoesClientHaveConstantGlow(client)) return true;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientEnableConstantGlow(%d)", client);
+#endif
+	
+	decl String:sModel[PLATFORM_MAX_PATH];
+	GetClientModel(client, sModel, sizeof(sModel));
+	
+	if (strlen(sModel) == 0) 
+	{
+		// For some reason the model couldn't be found, so no.
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false (no model specified)", client);
+#endif
+		
+		return false;
+	}
+	
+	new iGlow = CreateEntityByName("tf_taunt_prop");
+	if (iGlow != -1)
+	{
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> created");
+#endif
+	
+		g_bPlayerConstantGlowEnabled[client] = true;
+		g_iPlayerConstantGlowEntity[client] = EntIndexToEntRef(iGlow);
+		
+		new Float:flModelScale = GetEntPropFloat(client, Prop_Send, "m_flModelScale");
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) 
+		{
+			DebugMessage("tf_taunt_prop -> get model and model scale (%s, %f, player class: %d)", sModel, flModelScale, TF2_GetPlayerClass(client));
+		}
+#endif
+		
+		SetEntityModel(iGlow, sModel);
+		DispatchSpawn(iGlow);
+		ActivateEntity(iGlow);
+		SetEntityRenderMode(iGlow, RENDER_TRANSCOLOR);
+		SetEntityRenderColor(iGlow, 0, 0, 0, 0);
+		SetEntProp(iGlow, Prop_Send, "m_bGlowEnabled", 1);
+		SetEntPropFloat(iGlow, Prop_Send, "m_flModelScale", flModelScale);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set model and model scale");
+#endif
+		
+		// Set effect flags.
+		new iFlags = GetEntProp(iGlow, Prop_Send, "m_fEffects");
+		SetEntProp(iGlow, Prop_Send, "m_fEffects", iFlags | (1 << 0)); // EF_BONEMERGE
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set bonemerge flags");
+#endif
+		
+		SetVariantString("!activator");
+		AcceptEntityInput(iGlow, "SetParent", client);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent to client");
+#endif
+		
+		if (sAttachment[0])
+		{
+			SetVariantString(sAttachment);
+			AcceptEntityInput(iGlow, "SetParentAttachment");
+		}
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("tf_taunt_prop -> set parent attachment to %s", sAttachment);
+#endif
+		
+		SDKHook(iGlow, SDKHook_SetTransmit, Hook_ConstantGlowSetTransmit);
+		
+#if defined DEBUG
+		if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> true", client);
+#endif
+		
+		return true;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientEnableConstantGlow(%d) -> false", client);
+#endif
+	
+	return false;
+}
+
+ClientResetJumpScare(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetJumpScare(%d)", client);
+#endif
+
+	g_iPlayerJumpScareBoss[client] = -1;
+	g_flPlayerJumpScareLifeTime[client] = -1.0;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetJumpScare(%d)", client);
+#endif
+}
+
+ClientDoJumpScare(client, iBossIndex, Float:flLifeTime)
+{
+	g_iPlayerJumpScareBoss[client] = NPCGetUniqueID(iBossIndex);
+	g_flPlayerJumpScareLifeTime[client] = GetGameTime() + flLifeTime;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_jumpscare", sBuffer, sizeof(sBuffer), 1);
+	
+	if (strlen(sBuffer) > 0)
+	{
+		EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN);
+	}
+}
+
+ /**
+  *	Handles sprinting upon player input.
+  */
+ClientHandleSprint(client, bool:bSprint)
+{
+	if (!IsPlayerAlive(client) || 
+		g_bPlayerEliminated[client] || 
+		DidClientEscape(client) || 
+		g_bPlayerProxy[client] || 
+		IsClientInGhostMode(client)) return;
+	
+	if (bSprint)
+	{
+		if (g_iPlayerSprintPoints[client] > 0)
+		{
+			ClientStartSprint(client);
+		}
+		else
+		{
+			EmitSoundToClient(client, FLASHLIGHT_NOSOUND, _, SNDCHAN_ITEM, SNDLEVEL_NONE);
+		}
+	}
+	else
+	{
+		if (IsClientSprinting(client))
+		{
+			ClientStopSprint(client);
+		}
+	}
+}
+
+ClientOnButtonPress(client, button)
+{
+	switch (button)
+	{
+		case IN_ATTACK2:
+		{
+			if (IsPlayerAlive(client))
+			{
+				if (!IsRoundInWarmup() &&
+					!IsRoundInIntro() &&
+					!IsRoundEnding() && 
+					!DidClientEscape(client))
+				{
+					if (GetGameTime() >= ClientGetFlashlightNextInputTime(client))
+					{
+						ClientHandleFlashlight(client);
+					}
+				}
+			}
+		}
+		case IN_RELOAD:
+		{
+			ClientHandleSprint(client, true);
+			if(IsClientInGhostMode(client) && g_iGhostNextHelpPhrase[client] < GetTime()) {
+				EmitSoundToAll(g_strGhostHelpPhrases[GetRandomInt(0, sizeof(g_strGhostHelpPhrases) - 1)], client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
+				g_iGhostNextHelpPhrase[client] = GetTime() + g_iGhostHelpPhraseInterval;
+			}
+		}
+		case IN_ATTACK3:
+		{
+			if (IsPlayerAlive(client))
+			{
+				if (!g_bPlayerEliminated[client])
+				{
+					if (!IsRoundEnding() && 
+						!IsRoundInWarmup() &&
+						!IsRoundInIntro() &&
+						!DidClientEscape(client))
+					{
+						ClientBlink(client);
+					}
+				}
+			}
+		}
+		case IN_JUMP:
+		{
+			if (IsPlayerAlive(client) && !(GetEntityFlags(client) & FL_FROZEN))
+			{
+				if (!bool:GetEntProp(client, Prop_Send, "m_bDucked") && 
+					(GetEntityFlags(client) & FL_ONGROUND) &&
+					GetEntProp(client, Prop_Send, "m_nWaterLevel") < 2)
+				{
+					ClientOnJump(client);
+				}
+			}
+		}
+	}
+}
+
+ClientOnButtonRelease(client, button)
+{
+	switch (button)
+	{
+		case IN_RELOAD:
+		{
+			ClientHandleSprint(client, false);
+		}
+	}
+}
+
+ClientOnJump(client)
+{
+	if (!g_bPlayerEliminated[client])
+	{
+		if (!IsRoundEnding() && !IsRoundInWarmup() && !DidClientEscape(client))
+		{
+			new iOverride = GetConVarInt(g_cvPlayerInfiniteSprintOverride);
+			if ((!g_bRoundInfiniteSprint && iOverride != 1) || iOverride == 0)
+			{
+				g_iPlayerSprintPoints[client] -= 7;
+				if (g_iPlayerSprintPoints[client] < 0) g_iPlayerSprintPoints[client] = 0;
+			}
+			
+			if (!IsClientSprinting(client))
+			{
+				if (g_hPlayerSprintTimer[client] == INVALID_HANDLE)
+				{
+					// If the player hasn't sprinted recently, force us to regenerate the stamina.
+					ClientSprintTimer(client, true);
+				}
+			}
+		}
+	}
+}
+
+//	==========================================================
+//	DEATH CAM FUNCTIONS
+//	==========================================================
+
+bool:IsClientInDeathCam(client)
+{
+	return g_bPlayerDeathCam[client];
+}
+
+public Action:Hook_DeathCamSetTransmit(slender, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+
+	if (EntRefToEntIndex(g_iPlayerDeathCamEnt2[other]) != slender) return Plugin_Handled;
+	return Plugin_Continue;
+}
+
+ClientResetDeathCam(client)
+{
+	if (!IsClientInDeathCam(client)) return; // no really need to reset if it wasn't set.
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetDeathCam(%d)", client);
+#endif
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	
+	g_iPlayerDeathCamBoss[client] = -1;
+	g_bPlayerDeathCam[client] = false;
+	g_bPlayerDeathCamShowOverlay[client] = false;
+	g_hPlayerDeathCamTimer[client] = INVALID_HANDLE;
+	
+	new ent = EntRefToEntIndex(g_iPlayerDeathCamEnt[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "Disable");
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	ent = EntRefToEntIndex(g_iPlayerDeathCamEnt2[client]);
+	if (ent && ent != INVALID_ENT_REFERENCE)
+	{
+		AcceptEntityInput(ent, "Kill");
+	}
+	
+	g_iPlayerDeathCamEnt[client] = INVALID_ENT_REFERENCE;
+	g_iPlayerDeathCamEnt2[client] = INVALID_ENT_REFERENCE;
+	
+	if (IsClientInGame(client))
+	{
+		SetClientViewEntity(client, client);
+	}
+	
+	Call_StartForward(fOnClientEndDeathCam);
+	Call_PushCell(client);
+	Call_PushCell(iDeathCamBoss);
+	Call_Finish();
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetDeathCam(%d)", client);
+#endif
+}
+
+ClientStartDeathCam(client, iBossIndex, const Float:vecLookPos[3])
+{
+	if (IsClientInDeathCam(client)) return;
+	if (!NPCIsValid(iBossIndex)) return;
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	if (GetProfileNum(sProfile, "death_cam_play_scare_sound"))
+	{
+		GetRandomStringFromProfile(sProfile, "sound_scare_player", buffer, sizeof(buffer));
+		if (buffer[0]) EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+	}
+	
+	GetRandomStringFromProfile(sProfile, "sound_player_deathcam", buffer, sizeof(buffer));
+	if (strlen(buffer) > 0) 
+	{
+		EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+	}
+	else
+	{
+		// Legacy support for "sound_player_death"
+		GetRandomStringFromProfile(sProfile, "sound_player_death", buffer, sizeof(buffer));
+		if (strlen(buffer) > 0)
+		{
+			EmitSoundToClient(client, buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		}
+	}
+	
+	GetRandomStringFromProfile(sProfile, "sound_player_deathcam_all", buffer, sizeof(buffer));
+	if (strlen(buffer) > 0) 
+	{
+		EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+	}
+	else
+	{
+		// Legacy support for "sound_player_death_all"
+		GetRandomStringFromProfile(sProfile, "sound_player_death_all", buffer, sizeof(buffer));
+		if (strlen(buffer) > 0) 
+		{
+			EmitSoundToAll(buffer, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		}
+	}
+	
+	// Call our forward.
+	Call_StartForward(fOnClientCaughtByBoss);
+	Call_PushCell(client);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+	
+	if (!NPCHasDeathCamEnabled(iBossIndex))
+	{
+		SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol changes our lifestate.
+		
+		// TODO: Add more attributes!
+		if (NPCHasAttribute(iBossIndex, "ignite player on death"))
+		{
+			new Float:flValue = NPCGetAttributeValue(iBossIndex, "ignite player on death");
+			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
+		}
+		
+		SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+		return;
+	}
+	
+	g_iPlayerDeathCamBoss[client] = NPCGetUniqueID(iBossIndex);
+	g_bPlayerDeathCam[client] = true;
+	g_bPlayerDeathCamShowOverlay[client] = false;
+	
+	decl Float:eyePos[3], Float:eyeAng[3], Float:vecAng[3];
+	GetClientEyePosition(client, eyePos);
+	GetClientEyeAngles(client, eyeAng);
+	SubtractVectors(eyePos, vecLookPos, vecAng);
+	GetVectorAngles(vecAng, vecAng);
+	vecAng[0] = 0.0;
+	vecAng[2] = 0.0;
+	
+	// Create fake model.
+	new slender = SpawnSlenderModel(iBossIndex, vecLookPos);
+	TeleportEntity(slender, vecLookPos, vecAng, NULL_VECTOR);
+	g_iPlayerDeathCamEnt2[client] = EntIndexToEntRef(slender);
+	SDKHook(slender, SDKHook_SetTransmit, Hook_DeathCamSetTransmit);
+	
+	// Create camera look point.
+	decl String:sName[64];
+	Format(sName, sizeof(sName), "sf2_boss_%d", EntIndexToEntRef(slender));
+	
+	decl Float:flOffsetPos[3];
+	new target = CreateEntityByName("info_target");
+	GetProfileVector(sProfile, "death_cam_pos", flOffsetPos);
+	AddVectors(vecLookPos, flOffsetPos, flOffsetPos);
+	TeleportEntity(target, flOffsetPos, NULL_VECTOR, NULL_VECTOR);
+	DispatchKeyValue(target, "targetname", sName);
+	SetVariantString("!activator");
+	AcceptEntityInput(target, "SetParent", slender);
+	
+	// Create the camera itself.
+	new camera = CreateEntityByName("point_viewcontrol");
+	TeleportEntity(camera, eyePos, eyeAng, NULL_VECTOR);
+	DispatchKeyValue(camera, "spawnflags", "12");
+	DispatchKeyValue(camera, "target", sName);
+	DispatchSpawn(camera);
+	AcceptEntityInput(camera, "Enable", client);
+	g_iPlayerDeathCamEnt[client] = EntIndexToEntRef(camera);
+	
+	if (GetProfileNum(sProfile, "death_cam_overlay") && GetProfileFloat(sProfile, "death_cam_time_overlay_start") >= 0.0)
+	{
+		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_overlay_start"), Timer_ClientResetDeathCam1, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	}
+	else
+	{
+		g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	}
+	
+	TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, Float:{ 0.0, 0.0, 0.0 });
+	
+	Call_StartForward(fOnClientStartDeathCam);
+	Call_PushCell(client);
+	Call_PushCell(iBossIndex);
+	Call_Finish();
+}
+
+public Action:Timer_ClientResetDeathCam1(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerDeathCamTimer[client]) return;
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
+	
+	g_bPlayerDeathCamShowOverlay[client] = true;
+	g_hPlayerDeathCamTimer[client] = CreateTimer(GetProfileFloat(sProfile, "death_cam_time_death"), Timer_ClientResetDeathCamEnd, userid, TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_ClientResetDeathCamEnd(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerDeathCamTimer[client]) return;
+	
+	SetEntProp(client, Prop_Data, "m_takedamage", 2); // We do this because the point_viewcontrol entity changes our damage state.
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	if (iDeathCamBoss != -1)
+	{
+		if (NPCHasAttribute(iDeathCamBoss, "ignite player on death"))
+		{
+			new Float:flValue = NPCGetAttributeValue(iDeathCamBoss, "ignite player on death");
+			if (flValue > 0.0) TF2_IgnitePlayer(client, client);
+		}
+	}
+	
+	SDKHooks_TakeDamage(client, 0, 0, 9001.0, 0x80 | DMG_PREVENT_PHYSICS_FORCE, _, Float:{ 0.0, 0.0, 0.0 });
+	ClientResetDeathCam(client);
+}
+
+//	==========================================================
+//	GHOST MODE FUNCTIONS
+//	==========================================================
+
+static bool:g_bPlayerGhostMode[MAXPLAYERS + 1] = { false, ... };
+static g_iPlayerGhostModeTarget[MAXPLAYERS + 1] = { INVALID_ENT_REFERENCE, ... };
+static Handle:g_hPlayerGhostModeConnectionCheckTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
+static Float:g_flPlayerGhostModeConnectionTimeOutTime[MAXPLAYERS + 1] = { -1.0, ... };
+static Float:g_flPlayerGhostModeConnectionBootTime[MAXPLAYERS + 1] = { -1.0, ... };
+
+/**
+ *	Enables/Disables ghost mode on the player.
+ */
+ClientSetGhostModeState(client, bool:bState)
+{
+	if (bState == g_bPlayerGhostMode[client]) return;
+	
+	if (bState && !IsClientInGame(client)) return;
+	
+	g_bPlayerGhostMode[client] = bState;
+	g_iPlayerGhostModeTarget[client] = INVALID_ENT_REFERENCE;
+	
+	if (bState)
+	{
+		ClientHandleGhostMode(client, true);
+		
+		if (GetConVarBool(g_cvGhostModeConnectionCheck))
+		{
+			g_hPlayerGhostModeConnectionCheckTimer[client] = CreateTimer(0.0, Timer_GhostModeConnectionCheck, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+			g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
+			g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
+		}
+		
+		PvP_OnClientGhostModeEnable(client);
+	}
+	else
+	{
+		DestroySpriteOverlay(client);
+		g_hPlayerGhostModeConnectionCheckTimer[client] = INVALID_HANDLE;
+		g_flPlayerGhostModeConnectionTimeOutTime[client] = -1.0;
+		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
+	
+		if (IsClientInGame(client))
+		{
+			TF2_RemoveCondition(client, TFCond_HalloweenGhostMode);
+			SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_PLAYER);
+		}
+	}
+}
+
+public Action:Timer_GhostModeConnectionCheck(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerGhostModeConnectionCheckTimer[client]) return Plugin_Stop;
+	
+	if (!IsFakeClient(client) && IsClientTimingOut(client))
+	{
+		new Float:bootTime = g_flPlayerGhostModeConnectionBootTime[client];
+		if (bootTime < 0.0)
+		{
+			bootTime = GetGameTime() + GetConVarFloat(g_cvGhostModeConnectionTolerance);
+			g_flPlayerGhostModeConnectionBootTime[client] = bootTime;
+			g_flPlayerGhostModeConnectionTimeOutTime[client] = GetGameTime();
+		}
+		
+		if (GetGameTime() >= bootTime)
+		{
+			ClientSetGhostModeState(client, false);
+			TF2_RespawnPlayer(client);
+			
+			decl String:authString[128];
+			GetClientAuthString(client, authString, sizeof(authString));
+			
+			LogSF2Message("Removed %N (%s) from ghost mode due to timing out for %f seconds", client, authString, GetConVarFloat(g_cvGhostModeConnectionTolerance));
+			
+			new Float:timeOutTime = g_flPlayerGhostModeConnectionTimeOutTime[client];
+			CPrintToChat(client, "%T", "SF2 Ghost Mode Bad Connection", client, RoundFloat(bootTime - timeOutTime));
+			
+			return Plugin_Stop;
+		}
+	}
+	else
+	{
+		// Player regained connection; reset.
+		g_flPlayerGhostModeConnectionBootTime[client] = -1.0;
+	}
+	
+	return Plugin_Continue;
+}
+
+/**
+ *	Makes sure that the player is a ghost when ghost mode is activated.
+ */
+ClientHandleGhostMode(client, bool:bForceSpawn=false)
+{
+	if (!IsClientInGhostMode(client)) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
+#endif
+	
+	if (!TF2_IsPlayerInCondition(client, TFCond_HalloweenGhostMode) || bForceSpawn)
+	{
+		TF2_AddCondition(client, TFCond_HalloweenGhostMode, -1.0);
+		SetEntProp(client, Prop_Send, "m_CollisionGroup", COLLISION_GROUP_DEBRIS);
+		
+		// Set first observer target.
+		ClientGhostModeNextTarget(client);
+		ClientActivateUltravision(client);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientHandleGhostMode(%d, %d)", client, bForceSpawn);
+#endif
+}
+
+ClientGhostModeNextTarget(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientGhostModeNextTarget(%d)", client);
+#endif
+	
+	new iLastTarget = EntRefToEntIndex(g_iPlayerGhostModeTarget[client]);
+	new iNextTarget = -1;
+	new iFirstTarget = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (IsClientInGame(i) && (!g_bPlayerEliminated[i] || g_bPlayerProxy[i]) && !IsClientInGhostMode(i) && !DidClientEscape(i) && IsPlayerAlive(i))
+		{
+			if (iFirstTarget == -1) iFirstTarget = i;
+			if (i > iLastTarget) 
+			{
+				iNextTarget = i;
+				break;
+			}
+		}
+	}
+	
+	new iTarget = -1;
+	if (IsValidClient(iNextTarget)) iTarget = iNextTarget;
+	else iTarget = iFirstTarget;
+	
+	if (IsValidClient(iTarget))
+	{
+		g_iPlayerGhostModeTarget[client] = EntIndexToEntRef(iTarget);
+		
+		decl Float:flPos[3], Float:flAng[3], Float:flVelocity[3];
+		GetClientAbsOrigin(iTarget, flPos);
+		GetClientEyeAngles(iTarget, flAng);
+		GetEntPropVector(iTarget, Prop_Data, "m_vecAbsVelocity", flVelocity);
+		TeleportEntity(client, flPos, flAng, flVelocity);
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientGhostModeNextTarget(%d)", client);
+#endif
+}
+
+bool:IsClientInGhostMode(client)
+{
+	return g_bPlayerGhostMode[client];
+}
+
+//	==========================================================
+//	SCARE FUNCTIONS
+//	==========================================================
+
+ClientPerformScare(client, iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		LogError("Could not perform scare on client %d: boss does not exist!", client);
+		return;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	g_flPlayerScareLastTime[client][iBossIndex] = GetGameTime();
+	g_flPlayerScareNextTime[client][iBossIndex] = GetGameTime() + NPCGetScareCooldown(iBossIndex);
+	
+	// See how much Sanity should be drained from a scare.
+	new Float:flStaticAmount = GetProfileFloat(sProfile, "scare_static_amount", 0.0);
+	g_flPlayerStaticAmount[client] += flStaticAmount;
+	if (g_flPlayerStaticAmount[client] > 1.0) g_flPlayerStaticAmount[client] = 1.0;
+	
+	decl String:sScareSound[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_scare_player", sScareSound, sizeof(sScareSound));
+	
+	if (sScareSound[0])
+	{
+		EmitSoundToClient(client, sScareSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		
+		if (NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)
+		{
+			new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
+			new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
+			
+			g_flPlayerSightSoundNextTime[client][iBossIndex] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
+		}
+		
+		if (g_flPlayerStress[client] > 0.4)
+		{
+			ClientAddStress(client, 0.4);
+		}
+		else
+		{
+			ClientAddStress(client, 0.66);
+		}
+	}
+	else
+	{
+		if (g_flPlayerStress[client] > 0.4)
+		{
+			ClientAddStress(client, 0.3);
+		}
+		else
+		{
+			ClientAddStress(client, 0.45);
+		}
+	}
+}
+
+ClientPerformSightSound(client, iBossIndex)
+{
+	if (NPCGetUniqueID(iBossIndex) == -1)
+	{
+		LogError("Could not perform sight sound on client %d: boss does not exist!", client);
+		return;
+	}
+	
+	if (!(NPCGetFlags(iBossIndex) & SFF_HASSIGHTSOUNDS)) return;
+	
+	new iMaster = NPCGetFromUniqueID(g_iSlenderCopyMaster[iBossIndex]);
+	if (iMaster == -1) iMaster = iBossIndex;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sSightSound[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_sight", sSightSound, sizeof(sSightSound));
+	
+	if (sSightSound[0])
+	{
+		EmitSoundToClient(client, sSightSound, _, MUSIC_CHAN, SNDLEVEL_NONE);
+		
+		new Float:flCooldownMin = GetProfileFloat(sProfile, "sound_sight_cooldown_min", 8.0);
+		new Float:flCooldownMax = GetProfileFloat(sProfile, "sound_sight_cooldown_max", 14.0);
+		
+		g_flPlayerSightSoundNextTime[client][iMaster] = GetGameTime() + GetRandomFloat(flCooldownMin, flCooldownMax);
+		
+		decl Float:flBossPos[3], Float:flMyPos[3];
+		new iBoss = NPCGetEntIndex(iBossIndex);
+		GetClientAbsOrigin(client, flMyPos);
+		GetEntPropVector(iBoss, Prop_Data, "m_vecAbsOrigin", flBossPos);
+		new Float:flDistUnComfortZone = 400.0;
+		new Float:flBossDist = GetVectorDistance(flMyPos, flBossPos);
+		
+		new Float:flStressScalar = 1.0 + (flDistUnComfortZone / flBossDist);
+		
+		ClientAddStress(client, 0.1 * flStressScalar);
+	}
+	else
+	{
+		LogError("Warning! %s supports sight sounds, but was given a blank sound!", sProfile);
+	}
+}
+
+ClientResetScare(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetScare(%d)", client);
+#endif
+
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_flPlayerScareNextTime[client][i] = -1.0;
+		g_flPlayerScareLastTime[client][i] = -1.0;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetScare(%d)", client);
+#endif
+}
+
+//	==========================================================
+//	ANTI-CAMPING FUNCTIONS
+//	==========================================================
+
+stock ClientResetCampingStats(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetCampingStats(%d)", client);
+#endif
+
+	g_iPlayerCampingStrikes[client] = 0;
+	g_hPlayerCampingTimer[client] = INVALID_HANDLE;
+	g_bPlayerCampingFirstTime[client] = true;
+	g_flPlayerCampingLastPosition[client][0] = 0.0;
+	g_flPlayerCampingLastPosition[client][1] = 0.0;
+	g_flPlayerCampingLastPosition[client][2] = 0.0;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetCampingStats(%d)", client);
+#endif
+}
+
+ClientStartCampingTimer(client)
+{
+	g_hPlayerCampingTimer[client] = CreateTimer(5.0, Timer_ClientCheckCamp, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_ClientCheckCamp(Handle:timer, any:userid)
+{
+	if (IsRoundInWarmup()) return Plugin_Stop;
+
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerCampingTimer[client]) return Plugin_Stop;
+	
+	if (IsRoundEnding() || !IsPlayerAlive(client) || g_bPlayerEliminated[client] || DidClientEscape(client)) return Plugin_Stop;
+	
+	if (!g_bPlayerCampingFirstTime[client])
+	{
+		decl Float:flPos[3], Float:flMaxs[3], Float:flMins[3];
+		GetClientAbsOrigin(client, flPos);
+		GetEntPropVector(client, Prop_Send, "m_vecMins", flMins);
+		GetEntPropVector(client, Prop_Send, "m_vecMaxs", flMaxs);
+		
+		// Only do something if the player is NOT stuck.
+		new Float:flDistFromLastPosition = GetVectorDistance(g_flPlayerCampingLastPosition[client], flPos);
+		new Float:flDistFromClosestBoss = 9999999.0;
+		new iClosestBoss = -1;
+		
+		for (new i = 0; i < MAX_BOSSES; i++)
+		{
+			if (NPCGetUniqueID(i) == -1) continue;
+			
+			new iSlender = NPCGetEntIndex(i);
+			if (!iSlender || iSlender == INVALID_ENT_REFERENCE) continue;
+			
+			decl Float:flSlenderPos[3];
+			SlenderGetAbsOrigin(i, flSlenderPos);
+			
+			new Float:flDist = GetVectorDistance(flSlenderPos, flPos);
+			if (flDist < flDistFromClosestBoss)
+			{
+				iClosestBoss = i;
+				flDistFromClosestBoss = flDist;
+			}
+		}
+		
+		if (GetConVarBool(g_cvCampingEnabled) && 
+			!g_bRoundGrace && 
+			!IsSpaceOccupiedIgnorePlayers(flPos, flMins, flMaxs, client) && 
+			g_flPlayerStaticAmount[client] <= GetConVarFloat(g_cvCampingNoStrikeSanity) && 
+			(iClosestBoss == -1 || flDistFromClosestBoss >= GetConVarFloat(g_cvCampingNoStrikeBossDistance)) &&
+			flDistFromLastPosition <= GetConVarFloat(g_cvCampingMinDistance))
+		{
+			g_iPlayerCampingStrikes[client]++;
+			if (g_iPlayerCampingStrikes[client] < GetConVarInt(g_cvCampingMaxStrikes))
+			{
+				if (g_iPlayerCampingStrikes[client] >= GetConVarInt(g_cvCampingStrikesWarn))
+				{
+					CPrintToChat(client, "{red}%T", "SF2 Camping System Warning", client, (GetConVarInt(g_cvCampingMaxStrikes) - g_iPlayerCampingStrikes[client]) * 5);
+				}
+			}
+			else
+			{
+				g_iPlayerCampingStrikes[client] = 0;
+				ClientStartDeathCam(client, 0, flPos);
+			}
+		}
+		else
+		{
+			// Forgiveness.
+			if (g_iPlayerCampingStrikes[client] > 0) g_iPlayerCampingStrikes[client]--;
+		}
+		
+		g_flPlayerCampingLastPosition[client][0] = flPos[0];
+		g_flPlayerCampingLastPosition[client][1] = flPos[1];
+		g_flPlayerCampingLastPosition[client][2] = flPos[2];
+	}
+	else
+	{
+		g_bPlayerCampingFirstTime[client] = false;
+	}
+	
+	return Plugin_Continue;
+}
+
+//	==========================================================
+//	BLINK FUNCTIONS
+//	==========================================================
+
+bool:IsClientBlinking(client)
+{
+	return g_bPlayerBlink[client];
+}
+
+Float:ClientGetBlinkMeter(client)
+{
+	return g_flPlayerBlinkMeter[client];
+}
+
+ClientGetBlinkCount(client)
+{
+	return g_iPlayerBlinkCount[client];
+}
+
+/**
+ *	Resets all data on blinking.
+ */
+ClientResetBlink(client)
+{
+	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
+	g_bPlayerBlink[client] = false;
+	g_flPlayerBlinkMeter[client] = 1.0;
+	g_iPlayerBlinkCount[client] = 0;
+}
+
+/**
+ *	Sets the player into a blinking state and blinds the player
+ */
+ClientBlink(client)
+{
+	if (IsRoundInWarmup() || DidClientEscape(client)) return;
+	
+	if (IsClientBlinking(client)) return;
+	
+	g_bPlayerBlink[client] = true;
+	g_iPlayerBlinkCount[client]++;
+	g_flPlayerBlinkMeter[client] = 0.0;
+	g_hPlayerBlinkTimer[client] = CreateTimer(GetConVarFloat(g_cvPlayerBlinkHoldTime), Timer_BlinkTimer2, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
+	
+	UTIL_ScreenFade(client, 100, RoundToFloor(GetConVarFloat(g_cvPlayerBlinkHoldTime) * 1000.0), FFADE_IN, 0, 0, 0, 255);
+	
+	Call_StartForward(fOnClientBlink);
+	Call_PushCell(client);
+	Call_Finish();
+}
+
+/**
+ *	Unsets the player from the blinking state.
+ */
+ClientUnblink(client)
+{
+	if (!IsClientBlinking(client)) return;
+	
+	g_bPlayerBlink[client] = false;
+	g_hPlayerBlinkTimer[client] = INVALID_HANDLE;
+	g_flPlayerBlinkMeter[client] = 1.0;
+}
+
+ClientStartDrainingBlinkMeter(client)
+{
+	g_hPlayerBlinkTimer[client] = CreateTimer(ClientGetBlinkRate(client), Timer_BlinkTimer, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+}
+
+public Action:Timer_BlinkTimer(Handle:timer, any:userid)
+{
+	if (IsRoundInWarmup()) return Plugin_Stop;
+
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerBlinkTimer[client]) return Plugin_Stop;
+	
+	if (IsPlayerAlive(client) && !IsClientInDeathCam(client) && !g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !IsRoundEnding())
+	{
+		new iOverride = GetConVarInt(g_cvPlayerInfiniteBlinkOverride);
+		if ((!g_bRoundInfiniteBlink && iOverride != 1) || iOverride == 0)
+		{
+			g_flPlayerBlinkMeter[client] -= 0.05;
+		}
+		
+		if (g_flPlayerBlinkMeter[client] <= 0.0)
+		{
+			ClientBlink(client);
+			return Plugin_Stop;
+		}
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_BlinkTimer2(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (timer != g_hPlayerBlinkTimer[client]) return;
+	
+	ClientUnblink(client);
+	ClientStartDrainingBlinkMeter(client);
+}
+
+Float:ClientGetBlinkRate(client)
+{
+	new Float:flValue = GetConVarFloat(g_cvPlayerBlinkRate);
+	if (GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 3) 
+	{
+		// Being underwater makes you blink faster, obviously.
+		flValue *= 0.75;
+	}
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (NPCGetUniqueID(i) == -1) continue;
+		
+		NPCGetProfile(i, sProfile, sizeof(sProfile));
+		
+		if (g_bPlayerSeesSlender[client][i]) 
+		{
+			flValue *= GetProfileFloat(sProfile, "blink_look_rate_multiply", 1.0);
+		}
+		
+		else if (g_iPlayerStaticMode[client][i] == Static_Increase)
+		{
+			flValue *= GetProfileFloat(sProfile, "blink_static_rate_multiply", 1.0);
+		}
+	}
+	
+	if (TF2_GetPlayerClass(client) == TFClass_Sniper) flValue *= 1.4;
+	
+	if (IsClientUsingFlashlight(client))
+	{
+		decl Float:startPos[3], Float:endPos[3], Float:flDirection[3];
+		new Float:flLength = SF2_FLASHLIGHT_LENGTH;
+		GetClientEyePosition(client, startPos);
+		GetClientEyePosition(client, endPos);
+		GetClientEyeAngles(client, flDirection);
+		GetAngleVectors(flDirection, flDirection, NULL_VECTOR, NULL_VECTOR);
+		NormalizeVector(flDirection, flDirection);
+		ScaleVector(flDirection, flLength);
+		AddVectors(endPos, flDirection, endPos);
+		new Handle:hTrace = TR_TraceRayFilterEx(startPos, endPos, MASK_VISIBLE, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
+		TR_GetEndPosition(endPos, hTrace);
+		new bool:bHit = TR_DidHit(hTrace);
+		CloseHandle(hTrace);
+		
+		if (bHit)
+		{
+			new Float:flPercent = (GetVectorDistance(startPos, endPos) / flLength);
+			flPercent *= 3.5;
+			if (flPercent > 1.0) flPercent = 1.0;
+			flValue *= flPercent;
+		}
+	}
+	
+	return flValue;
+}
+
+//	==========================================================
+//	SCREEN OVERLAY FUNCTIONS
+//	==========================================================
+
+ClientAddStress(client, Float:flStressAmount)
+{
+	g_flPlayerStress[client] += flStressAmount;
+	if (g_flPlayerStress[client] < 0.0) g_flPlayerStress[client] = 0.0;
+	if (g_flPlayerStress[client] > 1.0) g_flPlayerStress[client] = 1.0;
+	
+	//PrintCenterText(client, "g_flPlayerStress[%d] = %f", client, g_flPlayerStress[client]);
+	
+	SlenderOnClientStressUpdate(client);
+}
+
+stock ClientResetOverlay(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetOverlay(%d)", client);
+#endif
+	
+	g_hPlayerOverlayCheck[client] = INVALID_HANDLE;
+	
+	if (IsClientInGame(client))
+	{
+		ClientCommand(client, "r_screenoverlay \"\"");
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetOverlay(%d)", client);
+#endif
+}
+
+public DestroySpriteOverlay(client)
+{
+	if(IsValidClient(client) && client > 0) {
+		for(new i = 0; i < sizeof(g_iOverlayRef[]); i++) {
+			Overlay_Render_Clear_Layer(client, i);
+		}
+		g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
+	}
+}
+
+public Action:Timer_PlayerOverlayCheck(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerOverlayCheck[client]) return Plugin_Stop;
+	
+	if (IsRoundInWarmup()) return Plugin_Continue;
+	
+	new iDeathCamBoss = NPCGetFromUniqueID(g_iPlayerDeathCamBoss[client]);
+	new iJumpScareBoss = NPCGetFromUniqueID(g_iPlayerJumpScareBoss[client]);
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	decl String:sMaterial[PLATFORM_MAX_PATH];
+	
+	if (IsClientInDeathCam(client) && iDeathCamBoss != -1 && g_bPlayerDeathCamShowOverlay[client])
+	{
+		DestroySpriteOverlay(client);
+		NPCGetProfile(iDeathCamBoss, sProfile, sizeof(sProfile));
+		GetRandomStringFromProfile(sProfile, "overlay_player_death", sMaterial, sizeof(sMaterial), 1);
+	}
+	else if (iJumpScareBoss != -1 && GetGameTime() <= g_flPlayerJumpScareLifeTime[client])
+	{
+		DestroySpriteOverlay(client);
+		NPCGetProfile(iJumpScareBoss, sProfile, sizeof(sProfile));
+		GetRandomStringFromProfile(sProfile, "overlay_jumpscare", sMaterial, sizeof(sMaterial), 1);
+	}
+	else if (IsRoundInWarmup() || g_bPlayerEliminated[client] || DidClientEscape(client) && !IsClientInGhostMode(client))
+	{
+		DestroySpriteOverlay(client);
+		return Plugin_Continue;
+	}
+	else
+	{
+		if (!g_iPlayerPreferences[client][PlayerPreference_FilmGrain])
+			strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_DEFAULT_NO_FILMGRAIN);
+		else
+			strcopy(sMaterial, sizeof(sMaterial), SF2_OVERLAY_DEFAULT);
+	}
+	
+	ClientCommand(client, "r_screenoverlay %s", sMaterial);
+	return Plugin_Continue;
+}
+
+public Hide_Weapon(client) {
+	if(!IsValidClient(client) || client < 1) return;
+	new v_model = GetEntPropEnt(client, Prop_Send, "m_hViewModel");
+	if(v_model < 1) return;
+	//SetEntProp(v_model, Prop_Send, "m_nModelIndex", -1);
+	new EntEffects = GetEntProp(v_model, Prop_Send, "m_fEffects");
+	EntEffects |= EF_NODRAW;
+	SetEntProp(v_model, Prop_Send, "m_fEffects", EntEffects);
+}
+
+public Show_Weapon(client) {
+	if(!IsValidClient(client) || client < 1) return;
+	new v_model = GetEntPropEnt(client, Prop_Send, "m_hViewModel");
+	if(v_model < 1) return;
+	//SetEntProp(v_model, Prop_Send, "m_nModelIndex", -1);
+	new EntEffects = GetEntProp(v_model, Prop_Send, "m_fEffects");
+	EntEffects &= ~EF_NODRAW;
+	SetEntProp(v_model, Prop_Send, "m_fEffects", EntEffects);
+}
+
+//	==========================================================
+//	MUSIC SYSTEM FUNCTIONS
+//	==========================================================
+
+stock ClientUpdateMusicSystem(client, bool:bInitialize=false)
+{
+	new iOldPageMusicMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
+	new iOldMusicFlags = g_iPlayerMusicFlags[client];
+	new iChasingBoss = -1;
+	new iChasingSeeBoss = -1;
+	new iAlertBoss = -1;
+	new i20DollarsBoss = -1;
+	
+	if (IsRoundEnding() || !IsClientInGame(client) || IsFakeClient(client) || DidClientEscape(client) || (g_bPlayerEliminated[client] && !IsClientInGhostMode(client) && !g_bPlayerProxy[client])) 
+	{
+		g_iPlayerMusicFlags[client] = 0;
+		g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+	}
+	else
+	{
+		new bool:bPlayMusicOnEscape = true;
+		decl String:sName[64];
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "info_target")) != -1)
+		{
+			GetEntPropString(ent, Prop_Data, "m_iName", sName, sizeof(sName));
+			if (StrEqual(sName, "sf2_escape_custommusic", false))
+			{
+				bPlayMusicOnEscape = false;
+				break;
+			}
+		}
+		
+		// Page music first.
+		new iPageRange = 0;
+		
+		if (GetArraySize(g_hPageMusicRanges) > 0) // Map has its own defined page music?
+		{
+			for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
+			{
+				ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
+				if (!ent || ent == INVALID_ENT_REFERENCE) continue;
+				
+				new iMin = GetArrayCell(g_hPageMusicRanges, i, 1);
+				new iMax = GetArrayCell(g_hPageMusicRanges, i, 2);
+				
+				if (g_iPageCount >= iMin && g_iPageCount <= iMax)
+				{
+					g_iPlayerPageMusicMaster[client] = GetArrayCell(g_hPageMusicRanges, i);
+					break;
+				}
+			}
+		}
+		else // Nope. Use old system instead.
+		{
+			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+		
+			new Float:flPercent = g_iPageMax > 0 ? (float(g_iPageCount) / float(g_iPageMax)) : 0.0;
+			if (flPercent > 0.0 && flPercent <= 0.25) iPageRange = 1;
+			else if (flPercent > 0.25 && flPercent <= 0.5) iPageRange = 2;
+			else if (flPercent > 0.5 && flPercent <= 0.75) iPageRange = 3;
+			else if (flPercent > 0.75) iPageRange = 4;
+			
+			if (iPageRange == 1) ClientAddMusicFlag(client, MUSICF_PAGES1PERCENT);
+			else if (iPageRange == 2) ClientAddMusicFlag(client, MUSICF_PAGES25PERCENT);
+			else if (iPageRange == 3) ClientAddMusicFlag(client, MUSICF_PAGES50PERCENT);
+			else if (iPageRange == 4) ClientAddMusicFlag(client, MUSICF_PAGES75PERCENT);
+		}
+		
+		if (iPageRange != 1) ClientRemoveMusicFlag(client, MUSICF_PAGES1PERCENT);
+		if (iPageRange != 2) ClientRemoveMusicFlag(client, MUSICF_PAGES25PERCENT);
+		if (iPageRange != 3) ClientRemoveMusicFlag(client, MUSICF_PAGES50PERCENT);
+		if (iPageRange != 4) ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
+		
+		if (IsRoundInEscapeObjective() && !bPlayMusicOnEscape) 
+		{
+			ClientRemoveMusicFlag(client, MUSICF_PAGES75PERCENT);
+			g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+		}
+		
+		new iOldChasingBoss = g_iPlayerChaseMusicMaster[client];
+		new iOldChasingSeeBoss = g_iPlayerChaseMusicSeeMaster[client];
+		new iOldAlertBoss = g_iPlayerAlertMusicMaster[client];
+		new iOld20DollarsBoss = g_iPlayer20DollarsMusicMaster[client];
+		
+		new Float:flAnger = -1.0;
+		new Float:flSeeAnger = -1.0;
+		new Float:flAlertAnger = -1.0;
+		new Float:fl20DollarsAnger = -1.0;
+		
+		decl Float:flBuffer[3], Float:flBuffer2[3], Float:flBuffer3[3];
+		
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		
+		for (new i = 0; i < MAX_BOSSES; i++)
+		{
+			if (NPCGetUniqueID(i) == -1) continue;
+			
+			if (NPCGetEntIndex(i) == INVALID_ENT_REFERENCE) continue;
+			
+			NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+			new iBossType = NPCGetType(i);
+			
+			switch (iBossType)
+			{
+				case SF2BossType_Chaser:
+				{
+					GetClientAbsOrigin(client, flBuffer);
+					SlenderGetAbsOrigin(i, flBuffer3);
+					
+					new iTarget = EntRefToEntIndex(g_iSlenderTarget[i]);
+					if (iTarget != -1)
+					{
+						GetEntPropVector(iTarget, Prop_Data, "m_vecAbsOrigin", flBuffer2);
+						
+						if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK || g_iSlenderState[i] == STATE_STUN) &&
+							!(NPCGetFlags(i) & SFF_MARKEDASFAKE) && 
+							(iTarget == client || GetVectorDistance(flBuffer, flBuffer2) <= 850.0 || GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0))
+						{
+							decl String:sPath[PLATFORM_MAX_PATH];
+							GetRandomStringFromProfile(sProfile, "sound_chase_music", sPath, sizeof(sPath), 1);
+							if (sPath[0])
+							{
+								if (NPCGetAnger(i) > flAnger)
+								{
+									flAnger = NPCGetAnger(i);
+									iChasingBoss = i;
+								}
+							}
+							
+							if ((g_iSlenderState[i] == STATE_CHASE || g_iSlenderState[i] == STATE_ATTACK) &&
+								PlayerCanSeeSlender(client, i, false))
+							{
+								if (iOldChasingSeeBoss == -1 || !PlayerCanSeeSlender(client, iOldChasingSeeBoss, false) || (NPCGetAnger(i) > flSeeAnger))
+								{
+									GetRandomStringFromProfile(sProfile, "sound_chase_visible", sPath, sizeof(sPath), 1);
+									
+									if (sPath[0])
+									{
+										flSeeAnger = NPCGetAnger(i);
+										iChasingSeeBoss = i;
+									}
+								}
+								
+								if (g_b20Dollars)
+								{
+									if (iOld20DollarsBoss == -1 || !PlayerCanSeeSlender(client, iOld20DollarsBoss, false) || (NPCGetAnger(i) > fl20DollarsAnger))
+									{
+										GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sPath, sizeof(sPath), 1);
+										
+										if (sPath[0])
+										{
+											fl20DollarsAnger = NPCGetAnger(i);
+											i20DollarsBoss = i;
+										}
+									}
+								}
+							}
+						}
+					}
+					
+					if (g_iSlenderState[i] == STATE_ALERT)
+					{
+						decl String:sPath[PLATFORM_MAX_PATH];
+						GetRandomStringFromProfile(sProfile, "sound_alert_music", sPath, sizeof(sPath), 1);
+						if (!sPath[0]) continue;
+					
+						if (!(NPCGetFlags(i) & SFF_MARKEDASFAKE))
+						{
+							if (GetVectorDistance(flBuffer, flBuffer3) <= 850.0 || GetVectorDistance(flBuffer, g_flSlenderGoalPos[i]) <= 850.0)
+							{
+								if (NPCGetAnger(i) > flAlertAnger)
+								{
+									flAlertAnger = NPCGetAnger(i);
+									iAlertBoss = i;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		if (iChasingBoss != iOldChasingBoss)
+		{
+			if (iChasingBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_CHASE);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_CHASE);
+			}
+		}
+		
+		if (iChasingSeeBoss != iOldChasingSeeBoss)
+		{
+			if (iChasingSeeBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_CHASEVISIBLE);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_CHASEVISIBLE);
+			}
+		}
+		
+		if (iAlertBoss != iOldAlertBoss)
+		{
+			if (iAlertBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_ALERT);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_ALERT);
+			}
+		}
+		
+		if (i20DollarsBoss != iOld20DollarsBoss)
+		{
+			if (i20DollarsBoss != -1)
+			{
+				ClientAddMusicFlag(client, MUSICF_20DOLLARS);
+			}
+			else
+			{
+				ClientRemoveMusicFlag(client, MUSICF_20DOLLARS);
+			}
+		}
+	}
+	
+	if (IsValidClient(client))
+	{
+		new bool:bWasChase = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASE);
+		new bool:bChase = ClientHasMusicFlag(client, MUSICF_CHASE);
+		new bool:bWasChaseSee = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_CHASEVISIBLE);
+		new bool:bChaseSee = ClientHasMusicFlag(client, MUSICF_CHASEVISIBLE);
+		new bool:bAlert = ClientHasMusicFlag(client, MUSICF_ALERT);
+		new bool:bWasAlert = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_ALERT);
+		new bool:b20Dollars = ClientHasMusicFlag(client, MUSICF_20DOLLARS);
+		new bool:bWas20Dollars = ClientHasMusicFlag2(iOldMusicFlags, MUSICF_20DOLLARS);
+		
+		// Custom system.
+		if (GetArraySize(g_hPageMusicRanges) > 0) 
+		{
+			decl String:sPath[PLATFORM_MAX_PATH];
+		
+			new iMaster = EntRefToEntIndex(g_iPlayerPageMusicMaster[client]);
+			if (iMaster != INVALID_ENT_REFERENCE)
+			{
+				for (new i = 0, iSize = GetArraySize(g_hPageMusicRanges); i < iSize; i++)
+				{
+					new ent = EntRefToEntIndex(GetArrayCell(g_hPageMusicRanges, i));
+					if (!ent || ent == INVALID_ENT_REFERENCE) continue;
+					
+					GetEntPropString(ent, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+					
+					if (ent == iMaster && 
+						(iOldPageMusicMaster != iMaster || iOldPageMusicMaster == INVALID_ENT_REFERENCE))
+					{
+						if (!sPath[0])
+						{
+							LogError("Could not play music of page range %d-%d: no sound path specified!", GetArrayCell(g_hPageMusicRanges, i, 1), GetArrayCell(g_hPageMusicRanges, i, 2));
+						}
+						else
+						{
+							ClientMusicStart(client, sPath, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+						}
+						
+						if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
+						{
+							GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+							if (sPath[0])
+							{
+								StopSound(client, MUSIC_CHAN, sPath);
+							}
+						}
+					}
+				}
+			}
+			else
+			{
+				if (iOldPageMusicMaster && iOldPageMusicMaster != INVALID_ENT_REFERENCE)
+				{
+					GetEntPropString(iOldPageMusicMaster, Prop_Data, "m_iszSound", sPath, sizeof(sPath));
+					if (sPath[0])
+					{
+						StopSound(client, MUSIC_CHAN, sPath);
+					}
+				}
+			}
+		}
+		
+		// Old system.
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES1_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES1PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES1PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES1_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES2_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES25PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES25PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES2_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES3_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES50PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES50PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES3_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		if ((bInitialize || ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && !ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
+		{
+			StopSound(client, MUSIC_CHAN, MUSIC_GOTPAGES4_SOUND);
+		}
+		else if ((bInitialize || !ClientHasMusicFlag2(iOldMusicFlags, MUSICF_PAGES75PERCENT)) && ClientHasMusicFlag(client, MUSICF_PAGES75PERCENT))
+		{
+			ClientMusicStart(client, MUSIC_GOTPAGES4_SOUND, _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		
+		new iMainMusicState = 0;
+		
+		if (bAlert != bWasAlert || iAlertBoss != g_iPlayerAlertMusicMaster[client])
+		{
+			if (bAlert && !bChase)
+			{
+				ClientAlertMusicStart(client, iAlertBoss);
+				if (!bWasAlert) iMainMusicState = -1;
+			}
+			else
+			{
+				ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
+				if (!bChase && bWasAlert) iMainMusicState = 1;
+			}
+		}
+		
+		if (bChase != bWasChase || iChasingBoss != g_iPlayerChaseMusicMaster[client])
+		{
+			if (bChase)
+			{
+				ClientMusicChaseStart(client, iChasingBoss);
+				
+				if (!bWasChase)
+				{
+					iMainMusicState = -1;
+					
+					if (bAlert)
+					{
+						ClientAlertMusicStop(client, g_iPlayerAlertMusicMaster[client]);
+					}
+				}
+			}
+			else
+			{
+				ClientMusicChaseStop(client, g_iPlayerChaseMusicMaster[client]);
+				if (bWasChase)
+				{
+					if (bAlert)
+					{
+						ClientAlertMusicStart(client, iAlertBoss);
+					}
+					else
+					{
+						iMainMusicState = 1;
+					}
+				}
+			}
+		}
+		
+		if (bChaseSee != bWasChaseSee || iChasingSeeBoss != g_iPlayerChaseMusicSeeMaster[client])
+		{
+			if (bChaseSee)
+			{
+				ClientMusicChaseSeeStart(client, iChasingSeeBoss);
+			}
+			else
+			{
+				ClientMusicChaseSeeStop(client, g_iPlayerChaseMusicSeeMaster[client]);
+			}
+		}
+		
+		if (b20Dollars != bWas20Dollars || i20DollarsBoss != g_iPlayer20DollarsMusicMaster[client])
+		{
+			if (b20Dollars)
+			{
+				Client20DollarsMusicStart(client, i20DollarsBoss);
+			}
+			else
+			{
+				Client20DollarsMusicStop(client, g_iPlayer20DollarsMusicMaster[client]);
+			}
+		}
+		
+		if (iMainMusicState == 1)
+		{
+			ClientMusicStart(client, g_strPlayerMusic[client], _, MUSIC_PAGE_VOLUME, bChase || bAlert);
+		}
+		else if (iMainMusicState == -1)
+		{
+			ClientMusicStop(client);
+		}
+		
+		if (bChase || bAlert)
+		{
+			new iBossToUse = -1;
+			if (bChase)
+			{
+				iBossToUse = iChasingBoss;
+			}
+			else
+			{
+				iBossToUse = iAlertBoss;
+			}
+			
+			if (iBossToUse != -1)
+			{
+				// We got some alert/chase music going on! The player's excitement will no doubt go up!
+				// Excitement, though, really depends on how close the boss is in relation to the
+				// player.
+				
+				new Float:flBossDist = NPCGetDistanceFromEntity(iBossToUse, client);
+				new Float:flScalar = flBossDist / 700.0
+				if (flScalar > 1.0) flScalar = 1.0;
+				new Float:flStressAdd = 0.1 * (1.0 - flScalar);
+				
+				ClientAddStress(client, flStressAdd);
+			}
+		}
+	}
+}
+
+stock ClientMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
+	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerMusicFlags[client] = 0;
+	g_flPlayerMusicVolume[client] = 0.0;
+	g_flPlayerMusicTargetVolume[client] = 0.0;
+	g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+	g_iPlayerPageMusicMaster[client] = INVALID_ENT_REFERENCE;
+}
+
+stock ClientMusicStart(client, const String:sNewMusic[], Float:flVolume=-1.0, Float:flTargetVolume=-1.0, bool:bCopyOnly=false)
+{
+	if (!IsValidClient(client)) return;
+	if (!sNewMusic[0]) return;
+	
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerMusic[client]);
+	
+	if (!StrEqual(sOldMusic, sNewMusic, false))
+	{
+		if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	}
+	
+	strcopy(g_strPlayerMusic[client], sizeof(g_strPlayerMusic[]), sNewMusic);
+	if (flVolume >= 0.0) g_flPlayerMusicVolume[client] = flVolume;
+	if (flTargetVolume >= 0.0) g_flPlayerMusicTargetVolume[client] = flTargetVolume;
+	
+	if (!bCopyOnly)
+	{
+		g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeInMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+		TriggerTimer(g_hPlayerMusicTimer[client], true);
+	}
+	else
+	{
+		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+	}
+}
+
+stock ClientMusicStop(client)
+{
+	g_hPlayerMusicTimer[client] = CreateTimer(0.01, Timer_PlayerFadeOutMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerMusicTimer[client], true);
+}
+
+stock Client20DollarsMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayer20DollarsMusic[client]);
+	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayer20DollarsMusicMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayer20DollarsMusicTimer[client][i] = INVALID_HANDLE;
+		g_flPlayer20DollarsMusicVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsValidClient(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+				GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock Client20DollarsMusicStart(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iOldMaster = g_iPlayer20DollarsMusicMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (!sBuffer[0]) return;
+	
+	g_iPlayer20DollarsMusicMaster[client] = iBossIndex;
+	strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), sBuffer);
+	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeIn20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientAlertMusicStop(client, iOldMaster);
+	}
+}
+
+stock Client20DollarsMusicStop(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayer20DollarsMusicMaster[client])
+	{
+		g_iPlayer20DollarsMusicMaster[client] = -1;
+		strcopy(g_strPlayer20DollarsMusic[client], sizeof(g_strPlayer20DollarsMusic[]), "");
+	}
+	
+	g_hPlayer20DollarsMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOut20DollarsMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayer20DollarsMusicTimer[client][iBossIndex], true);
+}
+
+stock ClientAlertMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerAlertMusic[client]);
+	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerAlertMusicMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayerAlertMusicTimer[client][i] = INVALID_HANDLE;
+		g_flPlayerAlertMusicVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsValidClient(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+				GetRandomStringFromProfile(sProfile, "sound_alert_music", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock ClientAlertMusicStart(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iOldMaster = g_iPlayerAlertMusicMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (!sBuffer[0]) return;
+	
+	g_iPlayerAlertMusicMaster[client] = iBossIndex;
+	strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), sBuffer);
+	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientAlertMusicStop(client, iOldMaster);
+	}
+}
+
+stock ClientAlertMusicStop(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayerAlertMusicMaster[client])
+	{
+		g_iPlayerAlertMusicMaster[client] = -1;
+		strcopy(g_strPlayerAlertMusic[client], sizeof(g_strPlayerAlertMusic[]), "");
+	}
+	
+	g_hPlayerAlertMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutAlertMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerAlertMusicTimer[client][iBossIndex], true);
+}
+
+stock ClientChaseMusicReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusic[client]);
+	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
+	if (IsValidClient(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerChaseMusicMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayerChaseMusicTimer[client][i] = INVALID_HANDLE;
+		g_flPlayerChaseMusicVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsValidClient(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+				
+				GetRandomStringFromProfile(sProfile, "sound_chase_music", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock ClientMusicChaseStart(client, iBossIndex)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iOldMaster = g_iPlayerChaseMusicMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (!sBuffer[0]) return;
+	
+	g_iPlayerChaseMusicMaster[client] = iBossIndex;
+	strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), sBuffer);
+	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientMusicChaseStop(client, iOldMaster);
+	}
+}
+
+stock ClientMusicChaseStop(client, iBossIndex)
+{
+	if (!IsClientInGame(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayerChaseMusicMaster[client])
+	{
+		g_iPlayerChaseMusicMaster[client] = -1;
+		strcopy(g_strPlayerChaseMusic[client], sizeof(g_strPlayerChaseMusic[]), "");
+	}
+	
+	g_hPlayerChaseMusicTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusic, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicTimer[client][iBossIndex], true);
+}
+
+stock ClientChaseMusicSeeReset(client)
+{
+	new String:sOldMusic[PLATFORM_MAX_PATH];
+	strcopy(sOldMusic, sizeof(sOldMusic), g_strPlayerChaseMusicSee[client]);
+	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
+	if (IsClientInGame(client) && sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+	
+	g_iPlayerChaseMusicSeeMaster[client] = -1;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_hPlayerChaseMusicSeeTimer[client][i] = INVALID_HANDLE;
+		g_flPlayerChaseMusicSeeVolumes[client][i] = 0.0;
+		
+		if (NPCGetUniqueID(i) != -1)
+		{
+			if (IsClientInGame(client))
+			{
+				NPCGetProfile(i, sProfile, sizeof(sProfile));
+			
+				GetRandomStringFromProfile(sProfile, "sound_chase_visible", sOldMusic, sizeof(sOldMusic), 1);
+				if (sOldMusic[0]) StopSound(client, MUSIC_CHAN, sOldMusic);
+			}
+		}
+	}
+}
+
+stock ClientMusicChaseSeeStart(client, iBossIndex)
+{
+	if (!IsClientInGame(client)) return;
+	
+	new iOldMaster = g_iPlayerChaseMusicSeeMaster[client];
+	if (iOldMaster == iBossIndex) return;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	new String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
+	if (!sBuffer[0]) return;
+	
+	g_iPlayerChaseMusicSeeMaster[client] = iBossIndex;
+	strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), sBuffer);
+	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeInChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
+	
+	if (iOldMaster != -1)
+	{
+		ClientMusicChaseSeeStop(client, iOldMaster);
+	}
+}
+
+stock ClientMusicChaseSeeStop(client, iBossIndex)
+{
+	if (!IsClientInGame(client)) return;
+	if (iBossIndex == -1) return;
+	
+	if (iBossIndex == g_iPlayerChaseMusicSeeMaster[client])
+	{
+		g_iPlayerChaseMusicSeeMaster[client] = -1;
+		strcopy(g_strPlayerChaseMusicSee[client], sizeof(g_strPlayerChaseMusicSee[]), "");
+	}
+	
+	g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = CreateTimer(0.01, Timer_PlayerFadeOutChaseMusicSee, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
+	TriggerTimer(g_hPlayerChaseMusicSeeTimer[client][iBossIndex], true);
+}
+
+public Action:Timer_PlayerFadeInMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
+	
+	g_flPlayerMusicVolume[client] += 0.07;
+	if (g_flPlayerMusicVolume[client] > g_flPlayerMusicTargetVolume[client]) g_flPlayerMusicVolume[client] = g_flPlayerMusicTargetVolume[client];
+	
+	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
+
+	if (g_flPlayerMusicVolume[client] >= g_flPlayerMusicTargetVolume[client])
+	{
+		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	if (timer != g_hPlayerMusicTimer[client]) return Plugin_Stop;
+
+	g_flPlayerMusicVolume[client] -= 0.07;
+	if (g_flPlayerMusicVolume[client] < 0.0) g_flPlayerMusicVolume[client] = 0.0;
+
+	if (g_strPlayerMusic[client][0]) EmitSoundToClient(client, g_strPlayerMusic[client], _, MUSIC_CHAN, SNDLEVEL_NONE, SND_CHANGEVOL, g_flPlayerMusicVolume[client]);
+
+	if (g_flPlayerMusicVolume[client] <= 0.0)
+	{
+		g_hPlayerMusicTimer[client] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeIn20DollarsMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+	
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] > 1.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayer20DollarsMusic[client][0]) EmitSoundToClient(client, g_strPlayer20DollarsMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOut20DollarsMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayer20DollarsMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_20dollars_music", sBuffer, sizeof(sBuffer), 1);
+	
+	if (StrEqual(sBuffer, g_strPlayer20DollarsMusic[client], false))
+	{
+		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayer20DollarsMusicVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] < 0.0) g_flPlayer20DollarsMusicVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayer20DollarsMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayer20DollarsMusicVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayer20DollarsMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeInAlertMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerAlertMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayerAlertMusicVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayerAlertMusic[client][0]) EmitSoundToClient(client, g_strPlayerAlertMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutAlertMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerAlertMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_alert_music", sBuffer, sizeof(sBuffer), 1);
+
+	if (StrEqual(sBuffer, g_strPlayerAlertMusic[client], false))
+	{
+		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayerAlertMusicVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerAlertMusicVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerAlertMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerAlertMusicVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayerAlertMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeInChaseMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayerChaseMusicVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayerChaseMusic[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusic[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeInChaseMusicSee(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] += 0.07;
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] > 1.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 1.0;
+
+	if (g_strPlayerChaseMusicSee[client][0]) EmitSoundToClient(client, g_strPlayerChaseMusicSee[client], _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] >= 1.0)
+	{
+		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutChaseMusic(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_music", sBuffer, sizeof(sBuffer), 1);
+
+	if (StrEqual(sBuffer, g_strPlayerChaseMusic[client], false))
+	{
+		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayerChaseMusicVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayerChaseMusicTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+public Action:Timer_PlayerFadeOutChaseMusicSee(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return Plugin_Stop;
+
+	new iBossIndex = -1;
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		if (g_hPlayerChaseMusicSeeTimer[client][i] == timer)
+		{
+			iBossIndex = i;
+			break;
+		}
+	}
+	
+	if (iBossIndex == -1) return Plugin_Stop;
+	
+	decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+	NPCGetProfile(iBossIndex, sProfile, sizeof(sProfile));
+	
+	decl String:sBuffer[PLATFORM_MAX_PATH];
+	GetRandomStringFromProfile(sProfile, "sound_chase_visible", sBuffer, sizeof(sBuffer), 1);
+
+	if (StrEqual(sBuffer, g_strPlayerChaseMusicSee[client], false))
+	{
+		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] -= 0.07;
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] < 0.0) g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] = 0.0;
+
+	if (sBuffer[0]) EmitSoundToClient(client, sBuffer, _, MUSIC_CHAN, _, SND_CHANGEVOL, g_flPlayerChaseMusicSeeVolumes[client][iBossIndex]);
+	
+	if (g_flPlayerChaseMusicSeeVolumes[client][iBossIndex] <= 0.0)
+	{
+		g_hPlayerChaseMusicSeeTimer[client][iBossIndex] = INVALID_HANDLE;
+		return Plugin_Stop;
+	}
+	
+	return Plugin_Continue;
+}
+
+stock bool:ClientHasMusicFlag(client, iFlag)
+{
+	return bool:(g_iPlayerMusicFlags[client] & iFlag);
+}
+
+stock bool:ClientHasMusicFlag2(iValue, iFlag)
+{
+	return bool:(iValue & iFlag);
+}
+
+stock ClientAddMusicFlag(client, iFlag)
+{
+	if (!ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] |= iFlag;
+}
+
+stock ClientRemoveMusicFlag(client, iFlag)
+{
+	if (ClientHasMusicFlag(client, iFlag)) g_iPlayerMusicFlags[client] &= ~iFlag;
+}
+
+//	==========================================================
+//	MISC FUNCTIONS
+//	==========================================================
+
+// This could be used for entities as well.
+stock ClientStopAllSlenderSounds(client, const String:profileName[], const String:sectionName[], iChannel)
+{
+	if (!client || !IsValidEntity(client)) return;
+	
+	if (!IsProfileValid(profileName)) return;
+	
+	decl String:buffer[PLATFORM_MAX_PATH];
+	
+	KvRewind(g_hConfig);
+	if (KvJumpToKey(g_hConfig, profileName))
+	{
+		decl String:s[32];
+		
+		if (KvJumpToKey(g_hConfig, sectionName))
+		{
+			for (new i2 = 1;; i2++)
+			{
+				IntToString(i2, s, sizeof(s));
+				KvGetString(g_hConfig, s, buffer, sizeof(buffer));
+				if (!buffer[0]) break;
+				
+				StopSound(client, iChannel, buffer);
+			}
+		}
+	}
+}
+
+stock ClientUpdateListeningFlags(client, bool:bReset=false)
+{
+	if (!IsClientInGame(client)) return;
+	
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (i == client || !IsClientInGame(i)) continue;
+		
+		if (bReset || IsRoundEnding() || GetConVarBool(g_cvAllChat))
+		{
+			SetListenOverride(client, i, Listen_Default);
+			continue;
+		}
+		
+		new MuteMode:iMuteMode = g_iPlayerPreferences[client][PlayerPreference_MuteMode];
+		
+		if (g_bPlayerEliminated[client])
+		{
+			if (!g_bPlayerEliminated[i])
+			{
+				if (iMuteMode == MuteMode_DontHearOtherTeam)
+				{
+					SetListenOverride(client, i, Listen_No);
+				}
+				else if (iMuteMode == MuteMode_DontHearOtherTeamIfNotProxy && !g_bPlayerProxy[client])
+				{
+					SetListenOverride(client, i, Listen_No);
+				}
+				else
+				{
+					SetListenOverride(client, i, Listen_Default);
+				}
+			}
+			else
+			{
+				SetListenOverride(client, i, Listen_Default);
+			}
+		}
+		else
+		{
+			if (!g_bPlayerEliminated[i])
+			{
+				if (g_bSpecialRound && g_iSpecialRoundType == SPECIALROUND_SINGLEPLAYER)
+				{
+					if (DidClientEscape(i))
+					{
+						if (!DidClientEscape(client))
+						{
+							SetListenOverride(client, i, Listen_No);
+						}
+						else
+						{
+							SetListenOverride(client, i, Listen_Default);
+						}
+					}
+					else
+					{
+						if (!DidClientEscape(client))
+						{
+							SetListenOverride(client, i, Listen_No);
+						}
+						else
+						{
+							SetListenOverride(client, i, Listen_Default);
+						}
+					}
+				}
+				else
+				{
+					new bool:bCanHear = false;
+					if (GetConVarFloat(g_cvPlayerVoiceDistance) <= 0.0) bCanHear = true;
+					
+					if (!bCanHear)
+					{
+						decl Float:flMyPos[3], Float:flHisPos[3];
+						GetClientEyePosition(client, flMyPos);
+						GetClientEyePosition(i, flHisPos);
+						
+						new Float:flDist = GetVectorDistance(flMyPos, flHisPos);
+						
+						if (GetConVarFloat(g_cvPlayerVoiceWallScale) > 0.0)
+						{
+							new Handle:hTrace = TR_TraceRayFilterEx(flMyPos, flHisPos, MASK_SOLID_BRUSHONLY, RayType_EndPoint, TraceRayDontHitCharacters);
+							new bool:bDidHit = TR_DidHit(hTrace);
+							CloseHandle(hTrace);
+							
+							if (bDidHit)
+							{
+								flDist *= GetConVarFloat(g_cvPlayerVoiceWallScale);
+							}
+						}
+						
+						if (flDist <= GetConVarFloat(g_cvPlayerVoiceDistance))
+						{
+							bCanHear = true;
+						}
+					}
+					
+					if (bCanHear)
+					{
+						if (IsClientInGhostMode(i) != IsClientInGhostMode(client) &&
+							DidClientEscape(i) != DidClientEscape(client))
+						{
+							bCanHear = false;
+						}
+					}
+					
+					if (bCanHear)
+					{
+						SetListenOverride(client, i, Listen_Default);
+					}
+					else
+					{
+						SetListenOverride(client, i, Listen_No);
+					}
+				}
+			}
+			else
+			{
+				SetListenOverride(client, i, Listen_No);
+			}
+		}
+	}
+}
+
+stock ClientShowMainMessage(client, const String:sMessage[], any:...)
+{
+	decl String:message[512];
+	VFormat(message, sizeof(message), sMessage, 3);
+	
+	SetHudTextParams(-1.0, 0.4,
+		5.0,
+		255,
+		255,
+		255,
+		200,
+		2,
+		1.0,
+		0.07,
+		2.0);
+	ShowSyncHudText(client, g_hHudSync, message);
+}
+
+stock ClientResetSlenderStats(client)
+{
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("START ClientResetSlenderStats(%d)", client);
+#endif
+	
+	g_flPlayerStress[client] = 0.0;
+	g_flPlayerStressNextUpdateTime[client] = -1.0;
+	
+	for (new i = 0; i < MAX_BOSSES; i++)
+	{
+		g_bPlayerSeesSlender[client][i] = false;
+		g_flPlayerSeesSlenderLastTime[client][i] = -1.0;
+		g_flPlayerSightSoundNextTime[client][i] = -1.0;
+	}
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 2) DebugMessage("END ClientResetSlenderStats(%d)", client);
+#endif
+}
+
+bool:ClientSetQueuePoints(client, iAmount)
+{
+	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return false;
+	g_iPlayerQueuePoints[client] = iAmount;
+	ClientSaveCookies(client);
+	return true;
+}
+
+ClientSaveCookies(client)
+{
+	if (!IsClientConnected(client) || !AreClientCookiesCached(client)) return;
+	
+	// Save and reset our queue points.
+	decl String:s[64];
+	Format(s, sizeof(s), "%d ; %d ; %d ; %d ; %d ; %d", g_iPlayerQueuePoints[client], 
+		g_iPlayerPreferences[client][PlayerPreference_ShowHints], 
+		g_iPlayerPreferences[client][PlayerPreference_MuteMode], 
+		g_iPlayerPreferences[client][PlayerPreference_FilmGrain],
+		g_iPlayerPreferences[client][PlayerPreference_EnableProxySelection],
+		g_iPlayerPreferences[client][PlayerPreference_GhostOverlay]);
+		
+	SetClientCookie(client, g_hCookie, s);
+}
+
+stock ClientViewPunch(client, const Float:angleOffset[3])
+{
+	if (g_offsPlayerPunchAngleVel == -1) return;
+	
+	decl Float:flOffset[3];
+	for (new i = 0; i < 3; i++) flOffset[i] = angleOffset[i];
+	ScaleVector(flOffset, 20.0);
+	
+	/*
+	if (!IsFakeClient(client))
+	{
+		// Latency compensation.
+		new Float:flLatency = GetClientLatency(client, NetFlow_Outgoing);
+		new Float:flLatencyCalcDiff = 60.0 * Pow(flLatency, 2.0);
+		
+		for (new i = 0; i < 3; i++) flOffset[i] += (flOffset[i] * flLatencyCalcDiff);
+	}
+	*/
+	
+	decl Float:flAngleVel[3];
+	GetEntDataVector(client, g_offsPlayerPunchAngleVel, flAngleVel);
+	AddVectors(flAngleVel, flOffset, flOffset);
+	SetEntDataVector(client, g_offsPlayerPunchAngleVel, flOffset, true);
+}
+
+public Action:Hook_ConstantGlowSetTransmit(ent, other)
+{
+	if (!g_bEnabled) return Plugin_Continue;
+	
+	new iOwner = -1;
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		if (EntRefToEntIndex(g_iPlayerConstantGlowEntity[i]) == ent)
+		{
+			iOwner = i;
+			break;
+		}
+	}
+	
+	if (iOwner != -1)
+	{
+		if (!IsPlayerAlive(iOwner) || g_bPlayerEliminated[iOwner]) return Plugin_Handled;
+		if (!IsPlayerAlive(other) || (!g_bPlayerProxy[other] && !IsClientInGhostMode(other))) return Plugin_Handled;
+	}
+	
+	return Plugin_Continue;
+}
+
+stock ClientSetFOV(client, iFOV)
+{
+	SetEntData(client, g_offsPlayerFOV, iFOV);
+	SetEntData(client, g_offsPlayerDefaultFOV, iFOV);
+}
+
+stock TF2_GetClassName(TFClassType:iClass, String:sBuffer[], sBufferLen)
+{
+	switch (iClass)
+	{
+		case TFClass_Scout: strcopy(sBuffer, sBufferLen, "scout");
+		case TFClass_Sniper: strcopy(sBuffer, sBufferLen, "sniper");
+		case TFClass_Soldier: strcopy(sBuffer, sBufferLen, "soldier");
+		case TFClass_DemoMan: strcopy(sBuffer, sBufferLen, "demoman");
+		case TFClass_Heavy: strcopy(sBuffer, sBufferLen, "heavyweapons");
+		case TFClass_Medic: strcopy(sBuffer, sBufferLen, "medic");
+		case TFClass_Pyro: strcopy(sBuffer, sBufferLen, "pyro");
+		case TFClass_Spy: strcopy(sBuffer, sBufferLen, "spy");
+		case TFClass_Engineer: strcopy(sBuffer, sBufferLen, "engineer");
+		default: strcopy(sBuffer, sBufferLen, "");
+	}
+}
+
+#define EF_DIMLIGHT (1 << 2)
+
+stock ClientSDKFlashlightTurnOn(client)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+	if (iEffects & EF_DIMLIGHT) return;
+
+	iEffects |= EF_DIMLIGHT;
+	
+	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
+}
+
+stock ClientSDKFlashlightTurnOff(client)
+{
+	if (!IsValidClient(client)) return;
+	
+	new iEffects = GetEntProp(client, Prop_Send, "m_fEffects");
+	if (!(iEffects & EF_DIMLIGHT)) return;
+
+	iEffects &= ~EF_DIMLIGHT;
+	
+	SetEntProp(client, Prop_Send, "m_fEffects", iEffects);
+}
+
+stock bool:IsPointVisibleToAPlayer(const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false)
+{
+	for (new i = 1; i <= MaxClients; i++)
+	{
+		if (!IsClientInGame(i)) continue;
+		if (IsPointVisibleToPlayer(i, pos, bCheckFOV, bCheckBlink)) return true;
+	}
+	
+	return false;
+}
+
+stock bool:IsPointVisibleToPlayer(client, const Float:pos[3], bool:bCheckFOV=true, bool:bCheckBlink=false, bool:bCheckEliminated=true)
+{
+	if (!IsValidClient(client) || !IsPlayerAlive(client) || IsClientInGhostMode(client)) return false;
+	
+	if (bCheckEliminated && g_bPlayerEliminated[client]) return false;
+	
+	if (bCheckBlink && IsClientBlinking(client)) return false;
+	
+	decl Float:eyePos[3];
+	GetClientEyePosition(client, eyePos);
+	
+	// Check fog, if we can.
+	if (g_offsPlayerFogCtrl != -1 && g_offsFogCtrlEnable != -1 && g_offsFogCtrlEnd != -1)
+	{
+		new iFogEntity = GetEntDataEnt2(client, g_offsPlayerFogCtrl);
+		if (IsValidEdict(iFogEntity))
+		{
+			if (GetEntData(iFogEntity, g_offsFogCtrlEnable) &&
+				GetVectorDistance(eyePos, pos) >= GetEntDataFloat(iFogEntity, g_offsFogCtrlEnd)) 
+			{
+				return false;
+			}
+		}
+	}
+	
+	new Handle:hTrace = TR_TraceRayFilterEx(eyePos, pos, CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_MIST, RayType_EndPoint, TraceRayDontHitCharactersOrEntity, client);
+	new bool:bHit = TR_DidHit(hTrace);
+	CloseHandle(hTrace);
+	
+	if (bHit) return false;
+	
+	if (bCheckFOV)
+	{
+		decl Float:eyeAng[3], Float:reqVisibleAng[3];
+		GetClientEyeAngles(client, eyeAng);
+		
+		new Float:flFOV = float(g_iPlayerDesiredFOV[client]);
+		SubtractVectors(pos, eyePos, reqVisibleAng);
+		GetVectorAngles(reqVisibleAng, reqVisibleAng);
+		
+		new Float:difference = FloatAbs(AngleDiff(eyeAng[0], reqVisibleAng[0])) + FloatAbs(AngleDiff(eyeAng[1], reqVisibleAng[1]));
+		if (difference > ((flFOV * 0.5) + 10.0)) return false;
+	}
+	
+	return true;
+}
+
+public Action:Timer_ClientPostWeapons(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (!IsPlayerAlive(client)) return;
+	
+	if (timer != g_hPlayerPostWeaponsTimer[client]) return;
+	
+#if defined DEBUG
+	if (GetConVarInt(g_cvDebugDetail) > 0) 
+	{
+		DebugMessage("START Timer_ClientPostWeapons(%d)", client);
+	}
+	
+	new iOldWeaponItemIndexes[6] = { -1, ... };
+	new iNewWeaponItemIndexes[6] = { -1, ... };
+	
+	for (new i = 0; i <= 5; i++)
+	{
+		new iWeapon = GetPlayerWeaponSlot(client, i);
+		if (!IsValidEdict(iWeapon)) continue;
+		
+		iOldWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+	}
+	
+#endif
+	
+	new bool:bRemoveWeapons = true;
+	new bool:bRestrictWeapons = true;
+	
+	if (IsRoundEnding())
+	{
+		if (!g_bPlayerEliminated[client]) 
+		{
+			bRemoveWeapons = false;
+			bRestrictWeapons = false;
+		}
+	}
+	
+	// pvp
+	if (IsClientInPvP(client)) 
+	{
+		bRemoveWeapons = false;
+		bRestrictWeapons = false;
+	}
+	
+	if (IsRoundInWarmup()) 
+	{
+		bRemoveWeapons = false;
+		bRestrictWeapons = false;
+	}
+	
+	if (IsClientInGhostMode(client)) 
+	{
+		bRemoveWeapons = true;
+	}
+	
+	if (bRemoveWeapons)
+	{
+		if(!IsClientInGhostMode(client))
+		{
+			for (new i = 0; i <= 5; i++)
+			{
+				TF2_RemoveWeaponSlotAndWearables(client, i);
+				if (i == TFWeaponSlot_Melee)
+				{
+					// Give scout bat to every player to fix camera displacement.
+					new iNewWeapon = TF2Items_GiveNamedItem(client, g_hSDKWeaponBat);
+					EquipPlayerWeapon(client, iNewWeapon);
+				}
+			}
+		}
+		
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "tf_weapon_builder")) != -1)
+		{
+			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
+			{
+				AcceptEntityInput(ent, "Kill");
+			}
+		}
+		
+		ent = -1;
+		while ((ent = FindEntityByClassname(ent, "tf_wearable_demoshield")) != -1)
+		{
+			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
+			{
+				AcceptEntityInput(ent, "Kill");
+			}
+		}
+		
+		ClientSwitchToWeaponSlot(client, TFWeaponSlot_Melee);
+
+		Hide_Weapon(client);
+	} else {
+		Show_Weapon(client);
+	}
+	
+	if (bRestrictWeapons)
+	{
+		new iHealth = GetEntProp(client, Prop_Send, "m_iHealth");
+		
+		if (g_hRestrictedWeaponsConfig != INVALID_HANDLE)
+		{
+			new TFClassType:iPlayerClass = TF2_GetPlayerClass(client);
+			new Handle:hItem = INVALID_HANDLE;
+			
+			new iWeapon = INVALID_ENT_REFERENCE;
+			for (new iSlot = 0; iSlot <= 5; iSlot++)
+			{
+				iWeapon = GetPlayerWeaponSlot(client, iSlot);
+				
+				if (IsValidEdict(iWeapon))
+				{
+					if (IsWeaponRestricted(iPlayerClass, GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex")))
+					{
+						hItem = INVALID_HANDLE;
+						TF2_RemoveWeaponSlotAndWearables(client, iSlot);
+						
+						switch (iSlot)
+						{
+							case TFWeaponSlot_Primary:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Scout: hItem = g_hSDKWeaponScattergun;
+									case TFClass_Sniper: hItem = g_hSDKWeaponSniperRifle;
+									case TFClass_Soldier: hItem = g_hSDKWeaponRocketLauncher;
+									case TFClass_DemoMan: hItem = g_hSDKWeaponGrenadeLauncher;
+									case TFClass_Heavy: hItem = g_hSDKWeaponMinigun;
+									case TFClass_Medic: hItem = g_hSDKWeaponSyringeGun;
+									case TFClass_Pyro: hItem = g_hSDKWeaponFlamethrower;
+									case TFClass_Spy: hItem = g_hSDKWeaponRevolver;
+									case TFClass_Engineer: hItem = g_hSDKWeaponShotgunPrimary;
+								}
+							}
+							case TFWeaponSlot_Secondary:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Scout: hItem = g_hSDKWeaponPistolScout;
+									case TFClass_Sniper: hItem = g_hSDKWeaponSMG;
+									case TFClass_Soldier: hItem = g_hSDKWeaponShotgunSoldier;
+									case TFClass_DemoMan: hItem = g_hSDKWeaponStickyLauncher;
+									case TFClass_Heavy: hItem = g_hSDKWeaponShotgunHeavy;
+									case TFClass_Medic: hItem = g_hSDKWeaponMedigun;
+									case TFClass_Pyro: hItem = g_hSDKWeaponShotgunPyro;
+									case TFClass_Engineer: hItem = g_hSDKWeaponPistol;
+								}
+							}
+							case TFWeaponSlot_Melee:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Scout: hItem = g_hSDKWeaponBat;
+									case TFClass_Sniper: hItem = g_hSDKWeaponKukri;
+									case TFClass_Soldier: hItem = g_hSDKWeaponShovel;
+									case TFClass_DemoMan: hItem = g_hSDKWeaponBottle;
+									case TFClass_Heavy: hItem = g_hSDKWeaponFists;
+									case TFClass_Medic: hItem = g_hSDKWeaponBonesaw;
+									case TFClass_Pyro: hItem = g_hSDKWeaponFireaxe;
+									case TFClass_Spy: hItem = g_hSDKWeaponKnife;
+									case TFClass_Engineer: hItem = g_hSDKWeaponWrench;
+								}
+							}
+							case 4:
+							{
+								switch (iPlayerClass)
+								{
+									case TFClass_Spy: hItem = g_hSDKWeaponInvis;
+								}
+							}
+						}
+						
+						if (hItem != INVALID_HANDLE)
+						{
+							new iNewWeapon = TF2Items_GiveNamedItem(client, hItem);
+							if (IsValidEntity(iNewWeapon)) 
+							{
+								EquipPlayerWeapon(client, iNewWeapon);
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		// Fixes the Pretty Boy's Pocket Pistol glitch.
+		new iMaxHealth = SDKCall(g_hSDKGetMaxHealth, client);
+		if (iHealth > iMaxHealth)
+		{
+			SetEntProp(client, Prop_Data, "m_iHealth", iMaxHealth);
+			SetEntProp(client, Prop_Send, "m_iHealth", iMaxHealth);
+		}
+	}
+	
+	// Change stats on some weapons.
+	if (!g_bPlayerEliminated[client] || g_bPlayerProxy[client])
+	{
+		new iWeapon = INVALID_ENT_REFERENCE;
+		decl Handle:hWeapon;
+		for (new iSlot = 0; iSlot <= 5; iSlot++)
+		{
+			iWeapon = GetPlayerWeaponSlot(client, iSlot);
+			if (!iWeapon || iWeapon == INVALID_ENT_REFERENCE) continue;
+			
+			new iItemDef = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+			switch (iItemDef)
+			{
+				case 214: // Powerjack
+				{
+					TF2_RemoveWeaponSlot(client, iSlot);
+					
+					hWeapon = PrepareItemHandle("tf_weapon_fireaxe", 214, 0, 0, "180 ; 20.0 ; 206 ; 1.33");
+					new iEnt = TF2Items_GiveNamedItem(client, hWeapon);
+					CloseHandle(hWeapon);
+					EquipPlayerWeapon(client, iEnt);
+				}
+			}
+		}
+	}
+	
+	// Remove all hats.
+	if (IsClientInGhostMode(client))
+	{
+		new ent = -1;
+		while ((ent = FindEntityByClassname(ent, "tf_wearable")) != -1)
+		{
+			if (GetEntPropEnt(ent, Prop_Send, "m_hOwnerEntity") == client)
+			{
+				AcceptEntityInput(ent, "Kill");
+			}
+		}
+	}
+	
+#if defined DEBUG
+	for (new i = 0; i <= 5; i++)
+	{
+		new iWeapon = GetPlayerWeaponSlot(client, i);
+		if (!IsValidEdict(iWeapon)) continue;
+		
+		iNewWeaponItemIndexes[i] = GetEntProp(iWeapon, Prop_Send, "m_iItemDefinitionIndex");
+	}
+
+	if (GetConVarInt(g_cvDebugDetail) > 0) 
+	{
+		for (new i = 0; i <= 5; i++)
+		{
+			DebugMessage("-> slot %d: %d (old: %d)", i, iNewWeaponItemIndexes[i], iOldWeaponItemIndexes[i]);
+		}
+	
+		DebugMessage("END Timer_ClientPostWeapons(%d) -> remove = %d, restrict = %d", client, bRemoveWeapons, bRestrictWeapons);
+	}
+#endif
+}
+
+public Action:Timer_ApplyCustomModel(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	new iMaster = NPCGetFromUniqueID(g_iPlayerProxyMaster[client]);
+	
+	if (g_bPlayerProxy[client] && iMaster != -1)
+	{
+		decl String:sProfile[SF2_MAX_PROFILE_NAME_LENGTH];
+		NPCGetProfile(iMaster, sProfile, sizeof(sProfile));
+		
+		// Set custom model, if any.
+		decl String:sBuffer[PLATFORM_MAX_PATH];
+		decl String:sSectionName[64];
+		
+		decl String:sClassName[64];
+		TF2_GetClassName(TF2_GetPlayerClass(client), sClassName, sizeof(sClassName));
+		
+		Format(sSectionName, sizeof(sSectionName), "mod_proxy_%s", sClassName);
+		if ((GetRandomStringFromProfile(sProfile, sSectionName, sBuffer, sizeof(sBuffer)) && sBuffer[0]) ||
+			(GetRandomStringFromProfile(sProfile, "mod_proxy_all", sBuffer, sizeof(sBuffer)) && sBuffer[0]))
+		{
+			SetVariantString(sBuffer);
+			AcceptEntityInput(client, "SetCustomModel");
+			SetEntProp(client, Prop_Send, "m_bUseClassAnimations", true);
+		}
+		
+		if (IsPlayerAlive(client))
+		{
+			// Play any sounds, if any.
+			if (GetRandomStringFromProfile(sProfile, "sound_proxy_spawn", sBuffer, sizeof(sBuffer)) && sBuffer[0])
+			{
+				new iChannel = GetProfileNum(sProfile, "sound_proxy_spawn_channel", SNDCHAN_AUTO);
+				new iLevel = GetProfileNum(sProfile, "sound_proxy_spawn_level", SNDLEVEL_NORMAL);
+				new iFlags = GetProfileNum(sProfile, "sound_proxy_spawn_flags", SND_NOFLAGS);
+				new Float:flVolume = GetProfileFloat(sProfile, "sound_proxy_spawn_volume", SNDVOL_NORMAL);
+				new iPitch = GetProfileNum(sProfile, "sound_proxy_spawn_pitch", SNDPITCH_NORMAL);
+				
+				EmitSoundToAll(sBuffer, client, iChannel, iLevel, iFlags, flVolume, iPitch);
+			}
+		}
+	}
+}
+
+bool:IsWeaponRestricted(TFClassType:iClass, iItemDef)
+{
+	if (g_hRestrictedWeaponsConfig == INVALID_HANDLE) return false;
+	
+	new bool:bReturn = false;
+	
+	decl String:sItemDef[32];
+	IntToString(iItemDef, sItemDef, sizeof(sItemDef));
+	
+	KvRewind(g_hRestrictedWeaponsConfig);
+	if (KvJumpToKey(g_hRestrictedWeaponsConfig, "all"))
+	{
+		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef);
+	}
+	
+	new bool:bFoundSection = false;
+	KvRewind(g_hRestrictedWeaponsConfig);
+	
+	switch (iClass)
+	{
+		case TFClass_Scout: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "scout");
+		case TFClass_Soldier: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "soldier");
+		case TFClass_Sniper: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "sniper");
+		case TFClass_DemoMan: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "demoman");
+		case TFClass_Heavy: 
+		{
+			bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavy");
+		
+			if (!bFoundSection)
+			{
+				KvRewind(g_hRestrictedWeaponsConfig);
+				bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "heavyweapons");
+			}
+		}
+		case TFClass_Medic: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "medic");
+		case TFClass_Spy: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "spy");
+		case TFClass_Pyro: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "pyro");
+		case TFClass_Engineer: bFoundSection = KvJumpToKey(g_hRestrictedWeaponsConfig, "engineer");
+	}
+	
+	if (bFoundSection)
+	{
+		bReturn = bool:KvGetNum(g_hRestrictedWeaponsConfig, sItemDef, bReturn);
+	}
+	
+	return bReturn;
+}
+
+public Action:Timer_RespawnPlayer(Handle:timer, any:userid)
+{
+	new client = GetClientOfUserId(userid);
+	if (client <= 0) return;
+	
+	if (IsPlayerAlive(client)) return;
+	
+	TF2_RespawnPlayer(client);
 }
\ No newline at end of file
-- 
GitLab


From 846bb4a04aa7788ae79ad781a334e027ae2a83bd Mon Sep 17 00:00:00 2001
From: Alexey <lexuzieel@gmail.com>
Date: Wed, 14 Aug 2019 03:20:48 +0300
Subject: [PATCH 3/6] Update ghost mode default state

---
 addons/sourcemod/scripting/rytp_horror.sp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/addons/sourcemod/scripting/rytp_horror.sp b/addons/sourcemod/scripting/rytp_horror.sp
index 0ad5e9c..90db43e 100644
--- a/addons/sourcemod/scripting/rytp_horror.sp
+++ b/addons/sourcemod/scripting/rytp_horror.sp
@@ -5186,6 +5186,9 @@ public Action:Timer_PlayerSwitchToBlue(Handle:timer, any:userid)
 	if (timer != g_hPlayerSwitchBlueTimer[client]) return;
 	
 	ChangeClientTeam(client, _:TFTeam_Blue);
+
+	ClientSetGhostModeState(client, true);
+	TF2_RespawnPlayer(client);
 }
 
 public Action:Timer_RoundStart(Handle:timer)
-- 
GitLab


From b7f0da326c229e75bcb617f31a73812dc99be5ab Mon Sep 17 00:00:00 2001
From: Alexey <lexuzieel@gmail.com>
Date: Wed, 14 Aug 2019 03:21:15 +0300
Subject: [PATCH 4/6] Display ghost mode menu on death

---
 addons/sourcemod/scripting/rytp_horror.sp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/addons/sourcemod/scripting/rytp_horror.sp b/addons/sourcemod/scripting/rytp_horror.sp
index 90db43e..03215b4 100644
--- a/addons/sourcemod/scripting/rytp_horror.sp
+++ b/addons/sourcemod/scripting/rytp_horror.sp
@@ -5061,6 +5061,8 @@ public Event_PlayerDeath(Handle:event, const String:name[], bool:dB)
 					g_hPlayerSwitchBlueTimer[client] = CreateTimer(2.5, Timer_PlayerSwitchToBlue, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
 					ClientCommand(client, "r_screenoverlay %s", STATIC_OVERLAY);
 					EmitSoundToClient(client, STATIC_SOUND, _, MUSIC_CHAN, SNDLEVEL_NONE);
+					
+					DisplayMenu(g_hMenuGhostMode, client, 15);
 				}
 			}
 			else
-- 
GitLab


From 496c80d3340ebceacedc34a63f3d77d343c7a3a3 Mon Sep 17 00:00:00 2001
From: Alexey <lexuzieel@gmail.com>
Date: Wed, 14 Aug 2019 04:37:47 +0300
Subject: [PATCH 5/6] Hide camera overlay in third person

---
 addons/sourcemod/scripting/rytp_horror.sp     | 41 ++++++++++++++++++-
 .../sourcemod/scripting/rytp_horror/client.sp |  2 +-
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/addons/sourcemod/scripting/rytp_horror.sp b/addons/sourcemod/scripting/rytp_horror.sp
index 03215b4..398fe6a 100644
--- a/addons/sourcemod/scripting/rytp_horror.sp
+++ b/addons/sourcemod/scripting/rytp_horror.sp
@@ -250,6 +250,7 @@ new g_iPlayerPageCount[MAXPLAYERS + 1];
 new g_iPlayerQueuePoints[MAXPLAYERS + 1];
 new bool:g_bPlayerPlaying[MAXPLAYERS + 1];
 new Handle:g_hPlayerOverlayCheck[MAXPLAYERS + 1];
+int g_nForceTauntCam[MAXPLAYERS + 1];
 
 new Handle:g_hPlayerSwitchBlueTimer[MAXPLAYERS + 1];
 
@@ -305,6 +306,7 @@ new g_iPlayer20DollarsMusicMaster[MAXPLAYERS + 1] = { -1, ... };
 
 // Player overlay data
 new Handle:g_hOverlayUpdateTimer[MAXPLAYERS + 1];
+new Handle:g_hOverlayUpdateVisibility[MAXPLAYERS + 1];
 
 new SF2RoundState:g_iRoundState = SF2RoundState_Invalid;
 new bool:g_bRoundGrace = false;
@@ -3041,6 +3043,7 @@ public OnClientPutInServer(client)
 	g_bPlayerChoseTeam[client] = false;
 	g_bPlayerPlayedSpecialRound[client] = true;
 	g_bPlayerPlayedNewBossRound[client] = true;
+	g_nForceTauntCam[client] = 0;
 	
 	g_iPlayerPreferences[client][PlayerPreference_PvPAutoSpawn] = false;
 	g_iPlayerPreferences[client][PlayerPreference_ProjectedFlashlight] = false;
@@ -3142,6 +3145,8 @@ public OnClientDisconnect(client)
 {
 	DestroySpriteOverlay(client);
 	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
+	CloseHandle(g_hOverlayUpdateVisibility[client]);
+	g_hOverlayUpdateVisibility[client] = INVALID_HANDLE;
 	
 	if (!g_bEnabled) return;
 	
@@ -3150,6 +3155,7 @@ public OnClientDisconnect(client)
 #endif
 	
 	g_bPlayerEscaped[client] = false;
+	g_nForceTauntCam[client] = 0;
 	
 	// Save and reset settings for the next client.
 	ClientSaveCookies(client);
@@ -4496,6 +4502,7 @@ public Event_PlayerTeam(Handle:event, const String:name[], bool:dB)
 			g_bPlayerPlaying[client] = false;
 			g_bPlayerEliminated[client] = true;
 			g_bPlayerEscaped[client] = false;
+			g_nForceTauntCam[client] = GetEntProp(client, Prop_Send, "m_nForceTauntCam");
 			
 			ClientSetGhostModeState(client, false);
 			
@@ -4653,6 +4660,8 @@ public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
 	new client = GetClientOfUserId(GetEventInt(event, "userid"));
 	if (client <= 0) return;
 	
+	g_nForceTauntCam[client] = GetEntProp(client, Prop_Send, "m_nForceTauntCam");
+	
 #if defined DEBUG
 	if (GetConVarInt(g_cvDebugDetail) > 0) DebugMessage("EVENT START: Event_PlayerSpawn(%d)", client);
 #endif
@@ -4665,6 +4674,8 @@ public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
 	g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
 	
 	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
+	CloseHandle(g_hOverlayUpdateVisibility[client]);
+	g_hOverlayUpdateVisibility[client] = INVALID_HANDLE;
 	g_iGhostNextHelpPhrase[client] = 0;
 	
 	if (IsPlayerAlive(client) && IsClientParticipating(client))
@@ -4750,7 +4761,33 @@ public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
 #endif
 }
 
-public Action:Timer_UpdateOverlayTime(Handle:timer, any:userid)
+public Action:Timer_UpdateOverlayVisibility(Handle timer, int client)
+{
+	if (!IsValidClient(client)) return;
+
+	int nForceTauntCam = GetEntProp(client, Prop_Send, "m_nForceTauntCam");
+
+	if(nForceTauntCam == g_nForceTauntCam[client]) return;
+
+	g_nForceTauntCam[client] = nForceTauntCam;
+
+	PrintToChat(client, "Update overlay visibility: %d", g_nForceTauntCam[client]);
+
+	for(new i = 0; i < sizeof(g_iOverlayRef[]); i++)
+	{
+		new sprite = INVALID_HANDLE;
+		if(Overlay_Layer_Exists(client, i, sprite))
+		{
+			if (g_nForceTauntCam[client])
+			{
+				Overlay_Hide(sprite);
+			} else
+			{
+				Overlay_Show(sprite);
+			}
+		}
+	}
+}
 {
 	new client = GetClientOfUserId(userid);
 	if (client <= 0) return;
@@ -4871,7 +4908,7 @@ public Action:Timer_CreateSpriteOverlay(Handle:timer, any:userid)
 	//PrintToServer("%s %d %s %s %s", g_sCameraYear, strlen(g_sCameraYear), g_sCameraYear[strlen(g_sCameraYear)-1], g_sCameraYear[strlen(g_sCameraYear)-2], g_sCameraYear[strlen(g_sCameraYear)-3]);
 	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit6), 8.0);
 	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit7), 6.0);
-	g_hOverlayUpdateTimer[client] = CreateTimer(1.2, Timer_UpdateOverlayTime, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
+	g_hOverlayUpdateVisibility[client] = CreateTimer(0.1, Timer_UpdateOverlayVisibility, client, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
 }
 
 public Action:Timer_IntroBlackOut(Handle:timer, any:userid)
diff --git a/addons/sourcemod/scripting/rytp_horror/client.sp b/addons/sourcemod/scripting/rytp_horror/client.sp
index 4e231e5..bbcbb63 100644
--- a/addons/sourcemod/scripting/rytp_horror/client.sp
+++ b/addons/sourcemod/scripting/rytp_horror/client.sp
@@ -393,7 +393,7 @@ public Hook_ClientPreThink(client)
 public Action:Hook_ClientSetTransmit(client, other)
 {
 	if (!g_bEnabled) return Plugin_Continue;
-	
+
 	if (other != client)
 	{
 		if (IsClientInGhostMode(client) && !IsClientInGhostMode(other)) return Plugin_Handled;
-- 
GitLab


From 94409004096166d9d5f81b8a2a91f5159693564c Mon Sep 17 00:00:00 2001
From: Alexey <lexuzieel@gmail.com>
Date: Wed, 14 Aug 2019 04:38:39 +0300
Subject: [PATCH 6/6] Update overlay update timer code

Add handle close functions
---
 addons/sourcemod/scripting/rytp_horror.sp | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/addons/sourcemod/scripting/rytp_horror.sp b/addons/sourcemod/scripting/rytp_horror.sp
index 398fe6a..a03053b 100644
--- a/addons/sourcemod/scripting/rytp_horror.sp
+++ b/addons/sourcemod/scripting/rytp_horror.sp
@@ -3144,6 +3144,8 @@ public OnClientGetDesiredFOV(QueryCookie:cookie, client, ConVarQueryResult:resul
 public OnClientDisconnect(client)
 {
 	DestroySpriteOverlay(client);
+
+	CloseHandle(g_hOverlayUpdateTimer[client]);
 	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
 	CloseHandle(g_hOverlayUpdateVisibility[client]);
 	g_hOverlayUpdateVisibility[client] = INVALID_HANDLE;
@@ -4659,7 +4661,7 @@ public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
 	
 	new client = GetClientOfUserId(GetEventInt(event, "userid"));
 	if (client <= 0) return;
-	
+
 	g_nForceTauntCam[client] = GetEntProp(client, Prop_Send, "m_nForceTauntCam");
 	
 #if defined DEBUG
@@ -4673,6 +4675,7 @@ public Event_PlayerSpawn(Handle:event, const String:name[], bool:dB)
 	
 	g_hPlayerPostWeaponsTimer[client] = INVALID_HANDLE;
 	
+	CloseHandle(g_hOverlayUpdateTimer[client]);
 	g_hOverlayUpdateTimer[client] = INVALID_HANDLE;
 	CloseHandle(g_hOverlayUpdateVisibility[client]);
 	g_hOverlayUpdateVisibility[client] = INVALID_HANDLE;
@@ -4788,9 +4791,11 @@ public Action:Timer_UpdateOverlayVisibility(Handle timer, int client)
 		}
 	}
 }
+
+public Action:Timer_UpdateOverlayTime(Handle timer, int client)
 {
-	new client = GetClientOfUserId(userid);
-	if (client <= 0) return;
+	if (!IsValidClient(client)) return;
+
 	new String:Time[64], String:DigitBuffer[2];
 	FormatTime(Time, sizeof(Time), "%d"); // Day
 	Format(DigitBuffer, 2, "%s", Time[0]);
@@ -4908,6 +4913,7 @@ public Action:Timer_CreateSpriteOverlay(Handle:timer, any:userid)
 	//PrintToServer("%s %d %s %s %s", g_sCameraYear, strlen(g_sCameraYear), g_sCameraYear[strlen(g_sCameraYear)-1], g_sCameraYear[strlen(g_sCameraYear)-2], g_sCameraYear[strlen(g_sCameraYear)-3]);
 	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit6), 8.0);
 	Overlay_Frame(OverlayRef_ByLayer(client, _:DateDigit7), 6.0);
+	g_hOverlayUpdateTimer[client] = CreateTimer(1.2, Timer_UpdateOverlayTime, client, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
 	g_hOverlayUpdateVisibility[client] = CreateTimer(0.1, Timer_UpdateOverlayVisibility, client, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
 }
 
-- 
GitLab