diff --git a/scripting/include/dhooks.inc b/scripting/include/dhooks.inc new file mode 100644 index 0000000..448be8c --- /dev/null +++ b/scripting/include/dhooks.inc @@ -0,0 +1,1015 @@ +#if defined _dhooks_included +#endinput +#endif +#define _dhooks_included + +// Needed for the SDKFuncConfSource enum. +#include + +#define INVALID_HOOK_ID -1 + +enum ObjectValueType +{ + ObjectValueType_Int = 0, + ObjectValueType_Bool, + ObjectValueType_Ehandle, + ObjectValueType_Float, + ObjectValueType_CBaseEntityPtr, + ObjectValueType_IntPtr, + ObjectValueType_BoolPtr, + ObjectValueType_EhandlePtr, + ObjectValueType_FloatPtr, + ObjectValueType_Vector, + ObjectValueType_VectorPtr, + ObjectValueType_CharPtr, + ObjectValueType_String +}; + +enum ListenType +{ + ListenType_Created, + ListenType_Deleted +}; + +enum ReturnType +{ + ReturnType_Unknown, + ReturnType_Void, + ReturnType_Int, + ReturnType_Bool, + ReturnType_Float, + ReturnType_String, //Note this is a string_t + ReturnType_StringPtr, //Note this is a string_t * + ReturnType_CharPtr, + ReturnType_Vector, + ReturnType_VectorPtr, + ReturnType_CBaseEntity, + ReturnType_Edict +}; + +enum HookParamType +{ + HookParamType_Unknown, + HookParamType_Int, + HookParamType_Bool, + HookParamType_Float, + HookParamType_String, //Note this is a string_t + HookParamType_StringPtr, //Note this is a string_t * + HookParamType_CharPtr, + HookParamType_VectorPtr, + HookParamType_CBaseEntity, + HookParamType_ObjectPtr, + HookParamType_Edict, + HookParamType_Object +}; + +enum ThisPointerType +{ + ThisPointer_Ignore, + ThisPointer_CBaseEntity, + ThisPointer_Address +}; + +enum HookType +{ + HookType_Entity, + HookType_GameRules, + HookType_Raw +}; + +enum CallingConvention +{ + CallConv_CDECL, + CallConv_THISCALL, + CallConv_STDCALL, + CallConv_FASTCALL, +}; + +enum HookMode +{ + Hook_Pre, // Callback will be executed BEFORE the original function. + Hook_Post // Callback will be executed AFTER the original function. +}; + +enum MRESReturn +{ + MRES_ChangedHandled = -2, // Use changed values and return MRES_Handled + MRES_ChangedOverride, // Use changed values and return MRES_Override + MRES_Ignored, // plugin didn't take any action + MRES_Handled, // plugin did something, but real function should still be called + 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), /**< 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 */ +}; + +enum DHookRegister +{ + // Don't change the register and use the default for the calling convention. + DHookRegister_Default, + + // 8-bit general purpose registers + DHookRegister_AL, + DHookRegister_CL, + DHookRegister_DL, + DHookRegister_BL, + DHookRegister_AH, + DHookRegister_CH, + DHookRegister_DH, + DHookRegister_BH, + + // 32-bit general purpose registers + DHookRegister_EAX, + DHookRegister_ECX, + DHookRegister_EDX, + DHookRegister_EBX, + DHookRegister_ESP, + DHookRegister_EBP, + DHookRegister_ESI, + DHookRegister_EDI, + + // 128-bit XMM registers + DHookRegister_XMM0, + DHookRegister_XMM1, + DHookRegister_XMM2, + DHookRegister_XMM3, + DHookRegister_XMM4, + DHookRegister_XMM5, + DHookRegister_XMM6, + DHookRegister_XMM7, + + // 80-bit FPU registers + DHookRegister_ST0 +}; + +typeset ListenCB +{ + //Deleted + function void (int entity); + + //Created + function void (int entity, const char[] classname); +}; + +typeset DHookRemovalCB +{ + function void (int hookid); +}; +typeset DHookCallback +{ + //Function Example: void Ham::Test() with this pointer ignore + function MRESReturn (); + + //Function Example: void Ham::Test() with this pointer passed + function MRESReturn (int pThis); + + //Function Example: void Ham::Test(int cake) with this pointer ignore + function MRESReturn (DHookParam hParams); + + //Function Example: void Ham::Test(int cake) with this pointer passed + function MRESReturn (int pThis, DHookParam hParams); + + //Function Example: int Ham::Test() with this pointer ignore + function MRESReturn (DHookReturn hReturn); + + //Function Example: int Ham::Test() with this pointer passed + function MRESReturn (int pThis, DHookReturn hReturn); + + //Function Example: int Ham::Test(int cake) with this pointer ignore + function MRESReturn (DHookReturn hReturn, DHookParam hParams); + + //Function Example: int Ham::Test(int cake) with this pointer passed + function MRESReturn (int pThis, DHookReturn hReturn, DHookParam hParams); + + //Address NOW + + //Function Example: void Ham::Test() with this pointer passed + function MRESReturn (Address pThis); + + //Function Example: void Ham::Test(int cake) with this pointer passed + function MRESReturn (Address pThis, DHookParam hParams); + + //Function Example: int Ham::Test() with this pointer passed + function MRESReturn (Address pThis, DHookReturn hReturn); + + //Function Example: int Ham::Test(int cake) with this pointer passed + function MRESReturn (Address pThis, DHookReturn hReturn, DHookParam hParams); + +}; + +// Represents the parameters of the hooked function. +methodmap DHookParam < Handle +{ + // Get the value of a parameter. + // Use only for: int, entity, edict, bool or float parameter types. + // + // @param num Parameter number to get, starting at 1. Parameter number 0 returns + // the number of parameters. + // + // @return Value if num greater than 0. If 0 returns parameter count. + // If CBaseEntity returns entity index. + // @error Invalid handle, invalid param number or invalid param type. + public native any Get(int num); + + // Get the value of a vector parameter. + // Use only for: vector or vectorptr parameter types. + // + // @param num Parameter number to get, starting at 1. + // @param vec Vector buffer to store result. + // + // @error Invalid handle, invalid param number or invalid param type. + public native void GetVector(int num, float vec[3]); + + // Get the value of a string parameter. + // Use only for: string, stringptr or charptr parameter types. + // + // @param num Parameter number to get, starting at 1. + // @param buffer String buffer to store result. + // @param size Buffer size. + // + // @error Invalid handle, invalid param number or invalid param type. + public native void GetString(int num, char[] buffer, int size); + + // Set the value of a parameter. + // Use only for: int, entity, edict, bool or float parameter types. + // + // The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride + // is returned in the callback. + // + // @param num Parameter number to set starting at 1. + // @param value Value to set it as (only pass int, bool, float or entity index). + // + // @error Invalid handle, invalid param number or invalid param type. + public native void Set(int num, any value); + + // Set the value of a vector parameter. + // Use only for: vector or vectorptr parameter types. + // + // The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride + // is returned in the callback. + // + // @param num Parameter number to set, starting at 1. + // @param vec Value to set vector as. + // + // @error Invalid handle, invalid param number or invalid param type. + public native void SetVector(int num, const float vec[3]); + + // Set the value of a string parameter. + // Use only for: string, stringptr or charptr parameter types. + // + // The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride + // is returned in the callback. + // + // @param num Parameter number to set, starting at 1. + // @param value Value to set string as. + // + // @error Invalid handle, invalid param number or invalid param type. + public native void SetString(int num, const char[] value); + + // Gets an object's variable value. + // + // @param num Parameter number to get, starting at 1. + // @param offset Byte offset within the object to the var to get. + // @param type Type of var it is. + // + // @return Value of the objects var. If EHANDLE type or entity returns entity index. + // @error Invalid handle, invalid param number, invalid param type or invalid Object type. + public native any GetObjectVar(int num, int offset, ObjectValueType type); + + // Gets an object's vector variable value. + // + // @param num Parameter number to get, starting at 1. + // @param offset Byte offset within the object to the var to get. + // @param type Type of var it is. + // @param vec Buffer to store the result vector. + // + // @error Invalid handle, invalid param number, invalid param type or invalid Object type. + public native void GetObjectVarVector(int num, int offset, ObjectValueType type, float vec[3]); + + // Gets an object's string variable value. + // + // @param num Parameter number to get, starting at 1. + // @param offset Byte offset within the object to the var to get. + // @param type Type of var it is. + // @param buffer Buffer to store the result string. + // @param size Size of the buffer. + // + // @error Invalid handle, invalid param number, invalid param type or invalid Object type. + public native void GetObjectVarString(int num, int offset, ObjectValueType type, char[] buffer, int size); + + // Sets an object's variable value. + // + // The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride + // is returned in the callback. + // + // @param num Parameter number to set, starting at 1. + // @param offset Byte 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. + // + // @error Invalid handle, invalid param number, invalid param type or invalid Object type. + public native void SetObjectVar(int num, int offset, ObjectValueType type, any value); + + // Sets an object's vector variable value. + // + // The changes are only applied when MRES_ChangedHandled or MRES_ChangedOverride + // is returned in the callback. + // + // @param num Parameter number to set, starting at 1. + // @param offset Byte offset within the object to the var to set. + // @param type Type of var it is. + // @param vec The value to set the vector var to. + // + // @error Invalid handle, invalid param number, invalid param type or invalid Object type. + public native void SetObjectVarVector(int num, int offset, ObjectValueType type, const float vec[3]); + + // No setter for object strings yet. Open an issue if you really need it. + + // Checks if a pointer parameter is null. + // + // @param num Parameter number to check, starting at 1. + // + // @return True if null, false otherwise. + // @error Non-pointer parameter. + public native bool IsNull(int num); +}; + + +// Represents the return value of the hooked function. +methodmap DHookReturn < Handle +{ + // Retrieves or sets the return value. + // Use only for: int, entity, edict, bool or float return types. + // + // The return value is only readable in a post hook. + // The value is only applied when MRES_Override or MRES_Supercede is returned + // in the callback. + property any Value { + public native get(); + public native set(any value); + } + + // Get return vector value. + // Use only for: vector or vectorptr return types. + // + // Only useful in post hooks. + // + // @param vec Vector buffer to store result in. + // + // @error Invalid Handle or invalid type. + public native void GetVector(float vec[3]); + + // Get return string value. + // Use only for: string, stringptr or charptr return types. + // + // Only useful in post hooks. + // + // @param buffer String buffer to store result in. + // @param size String buffer size. + // + // @error Invalid Handle or invalid type. + public native void GetString(char[] buffer, int size); + + // Set return vector value. + // Use only for: vector or vectorptr return types. + // + // The value is only applied when MRES_Override or MRES_Supercede is returned + // in the callback. + // + // @param vec Value to set return vector to. + // + // @error Invalid Handle or invalid type. + public native void SetVector(const float vec[3]); + + // Set return string value. + // Use only for: string, stringptr or charptr return types. + // + // The value is only applied when MRES_Override or MRES_Supercede is returned + // in the callback. + // + // @param buffer Value to set return string to. + // + // @error Invalid Handle or invalid type. + public native void SetString(const char[] buffer); +}; + +// Base method map for common functions between virtual hooks and detours. +methodmap DHookSetup < Handle +{ + // Load address or offset for a vtable hook or detour from a gamedata file. + // + // @param gameconf GameData handle. + // @param source Whether to look in Offsets, Signatures, or Addresses. + // @param name Name of the property to find. + // + // @return True on success, false if nothing was found. + // @error Invalid setup or gamedata handle. + public native bool SetFromConf(GameData gameconf, SDKFuncConfSource source, const char[] name); + + // Adds a parameter to a hook setup. + // + // @param type Parameter type. + // @param size Used for Objects (not Object ptr) to define the size of the object. + // @param flag Used to change the pass type (ignored by detours). + // @param custom_register The register this argument is passed in instead of the stack (ignored by vhooks). + // + // @error Invalid setup handle or too many params added (request upping the max in thread). + public native void AddParam(HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal, DHookRegister custom_register=DHookRegister_Default); +}; + +// A DynamicHook allows to hook a virtual function on any C++ object. +// Currently CBaseEntity and CGameRules have a convenience API for easy entity hooking, +// but it's possible to provide a raw this-pointer to hook any object in memory too. +// +// Internally this intercepts function calls by replacing the function pointer +// in the virtual table of the object with our own function. +methodmap DynamicHook < DHookSetup +{ + // Creates a vtable hook. + // + // @param offset Virtual table offset of function to hook. + // @param hooktype Type of hook. + // @param returntype Type of return value. + // @param thistype Type of this pointer or ignore (ignore can be used if not needed). + // + // @error Failed to create hook setup handle or invalid callback function. + public native DynamicHook(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype); + + // Setup a vtable hook for a function as described in a "Functions" section in gamedata. + // The "Functions" section is parsed once the gamedata file is loaded and cached globally. + // + // @param gameconf GameData handle to use for address lookup. + // Doesn't have to be the same as the one with the "Functions" section. + // @param name Name of the function in a "Functions" section to load. + // + // @return Setup handle for the detour or null if offset wasn't found. + // @error Failed to create detour setup handle, invalid gamedata handle, + // invalid callback function or failed to find function in cached "Functions" sections. + public static native DynamicHook FromConf(GameData gameconf, const char[] name); + + // Hook an entity. + // + // Entity hooks are auto-removed when the entity is destroyed. + // If you need to read the return value of the function, choose a post hook. + // + // @param mode The desired hook mode - pre or post. + // A pre hook calls your callback BEFORE the original function is called. + // You can access the parameters, set the return value, and skip the original function. + // A post hook calls your callback AFTER the original function executed. + // You can access the parameters and get/set the return value. + // @param entity Entity index to hook on. + // @param callback Callback function. + // @param removalcb Optional callback for when the hook is removed. + // + // @return A hookid on success, INVALID_HOOK_ID otherwise. + // @error Invalid setup handle, invalid address, invalid hook type or invalid callback. + public native int HookEntity(HookMode mode, int entity, DHookCallback callback, DHookRemovalCB removalcb=INVALID_FUNCTION); + + // Hook gamerules object. + // + // Game rules hooks are auto-removed on map end. + // If you need to read the return value of the function, choose a post hook. + // + // @param mode The desired hook mode - pre or post. + // A pre hook calls your callback BEFORE the original function is called. + // You can access the parameters, set the return value, and skip the original function. + // A post hook calls your callback AFTER the original function executed. + // You can access the parameters and get/set the return value. + // @param callback Callback function. + // @param removalcb Optional callback for when the hook is removed. + // + // @return A hookid on success, INVALID_HOOK_ID otherwise. + // @error Invalid setup handle, invalid address, invalid hook type or invalid callback. + public native int HookGamerules(HookMode mode, DHookCallback callback, DHookRemovalCB removalcb=INVALID_FUNCTION); + + // Hook a raw this-pointer. + // If you need to read the return value of the function, choose a post hook. + // + // @param mode The desired hook mode - pre or post. + // A pre hook calls your callback BEFORE the original function is called. + // You can access the parameters, set the return value, and skip the original function. + // A post hook calls your callback AFTER the original function executed. + // You can access the parameters and get/set the return value. + // @param addr This pointer address. + // @param callback Callback function. + // + // @return A hookid on success, INVALID_HOOK_ID otherwise. + // @error Invalid setup handle, invalid address, invalid hook type or invalid callback. + public native int HookRaw(HookMode mode, Address addr, DHookCallback callback); + + // Remove hook by hook id: + // This will NOT fire the removal callback! + // + // @param hookid Hook id to remove. + // + // @return True on success, false otherwise + public static native bool RemoveHook(int hookid); +}; + +// A DynamicDetour is a way to hook and block any function in memory. +// Given the address of a function, it can call a callback in your script whenever +// the function gets called. The callback has access to all parameters of the function +// as well as the return value. +// +// Internally this works by replacing the first instructions of the function +// with a jump to our own code. This means that the signature used to find +// the function address in the first place might not match anymore after a detour. +// If you need to detour the same function in different plugins make sure to +// wildcard \x2a the first 6 bytes of the signature to accommodate for the patched +// jump introduced by the detour. +methodmap DynamicDetour < DHookSetup +{ + // Creates a detour. + // + // @param funcaddr The address of the function to detour. + // Can be Address_Null if you want to load the address from gamedata using DHookSetFromConf. + // @param callConv Calling convention of the function. + // @param returnType Type of the return value. + // @param thisType Type of this pointer or ignore (ignore can be used if not needed). + // Only used for thiscall detours. + // + // @error Failed to create detour setup handle. + public native DynamicDetour(Address funcaddr, CallingConvention callConv, ReturnType returntype, ThisPointerType thisType=ThisPointer_Ignore); + + // Setup a detour for a function as described in a "Functions" section in gamedata. + // The "Functions" section is parsed once the gamedata file is loaded and cached globally. + // + // @param gameconf GameData handle to use for address lookup. + // Doesn't have to be the same as the one with the "Functions" section. + // @param name Name of the function in a "Functions" section to load. + // + // @return Setup handle for the detour or null if offset wasn't found. + // @error Failed to create detour setup handle, invalid gamedata handle, + // invalid callback function or failed to find function in cached "Functions" sections. + public static native DynamicDetour FromConf(GameData gameconf, const char[] name); + + // Enable the detour of the function described in this detour setup. + // If you need to read the return value of the function, choose a post hook. + // + // @param mode The desired hook mode - pre or post. + // A pre hook calls your callback BEFORE the original function is called. + // You can access the parameters, set the return value, and skip the original function. + // A post hook calls your callback AFTER the original function executed. + // You can access the parameters and get/set the return value. + // @param callback Callback function. + // + // @return True if detour was enabled, false otherwise. + // @error Hook handle is not setup for a detour. + public native bool Enable(HookMode mode, DHookCallback callback); + + // Disable the detour of the function described in this detour setup. + // + // @param mode The hook mode to disable - pre or post. + // @param callback Callback function. + // + // @return True if detour was disabled, false otherwise. + // @error Hook handle is not setup for a detour or function is not detoured. + public native bool Disable(HookMode mode, DHookCallback callback); +}; + +/* Adds an entity listener hook + * + * @param type Type of listener to add + * @param callback Callback to use + * + * @noreturn +*/ +native void DHookAddEntityListener(ListenType type, ListenCB callback); + +/* Removes an entity listener hook + * + * @param type Type of listener to remove + * @param callback Callback this listener was using + * + * @return True if one was removed false otherwise. +*/ +native bool DHookRemoveEntityListener(ListenType type, ListenCB callback); + +/* Creates a hook + * + * @param offset vtable offset of function to hook + * @param hooktype Type of hook + * @param returntype Type of return value + * @param thistype Type of this pointer or ignore (ignore can be used if not needed) + * @param callback Optional callback function, if not set here must be set when hooking. + * + * @return Returns setup handle for the hook. + * @error Failed to create hook setup handle or invalid callback function. +*/ +native DynamicHook DHookCreate(int offset, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback=INVALID_FUNCTION); + +/** + * Creates a detour + * + * @param funcaddr The address of the function to detour. + * Can be Address_Null if you want to load the address from gamedata using DHookSetFromConf. + * @param callConv Calling convention of the function. + * @param returnType Type of the return value. + * @param thisType Type of this pointer or ignore (ignore can be used if not needed) + * + * @return Setup handle for the detour. + * @error Failed to create detour setup handle. + */ +native DynamicDetour DHookCreateDetour(Address funcaddr, CallingConvention callConv, ReturnType returntype, ThisPointerType thisType); + +/** + * Setup a detour or hook for a function as described in a "Functions" section in gamedata. + * + * @param gameconf GameConfig handle + * @param name Name of the function in the gamedata to load. + * + * @return Setup handle for the detour or INVALID_HANDLE if offset/signature/address wasn't found. + * @error Failed to create detour setup handle, invalid gamedata handle, invalid callback function or failed to find function in gamedata. + */ +native DHookSetup DHookCreateFromConf(Handle gameconf, const char[] name); + +/** + * Load details for a vhook or detour from a gamedata file. + * + * @param setup Hook setup handle to set the offset or address on. + * @param gameconf GameConfig handle + * @param source Whether to look in Offsets or Signatures. + * @param name Name of the property to find. + * + * @return True on success, false if nothing was found. + * @error Invalid setup or gamedata handle. + */ +native bool DHookSetFromConf(Handle setup, Handle gameconf, SDKFuncConfSource source, const char[] name); + +/** + * Enable the detour of the function described in the hook setup handle. + * + * @param setup Hook setup handle + * @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 callback Callback function + * + * @return True if detour was enabled, false otherwise. + * @error Hook handle is not setup for a detour. + */ +native bool DHookEnableDetour(Handle setup, bool post, DHookCallback callback); + +/** + * Disable the detour of the function described in the hook setup handle. + * + * @param setup Hook setup handle + * @param post True to disable a post hook. + * @param callback Callback function + * + * @return True if detour was disabled, false otherwise. + * @error Hook handle is not setup for a detour or function is not detoured. + */ +native bool DHookDisableDetour(Handle setup, bool post, DHookCallback callback); + +/* Adds param to a hook setup + * + * @param setup Setup handle to add the param to. + * @param type Param type + * @param size Used for Objects (not Object ptr) to define the size of the object. + * @param flag Used to change the pass type. + * @param custom_register The register this argument is passed in instead of the stack. + * + * @error Invalid setup handle or too many params added (request upping the max in thread) + * @noreturn +*/ +native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal, DHookRegister custom_register=DHookRegister_Default); + +/* Hook entity + * + * @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 return 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 address, invalid hook type or invalid callback. + * @return INVALID_HOOK_ID on fail a hookid on success +*/ +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 return 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, invalid address, invalid hook type or invalid callback. + * @return INVALID_HOOK_ID on fail a hookid on success +*/ +native int DHookGamerules(Handle setup, bool post, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION); + +/* Hook a raw pointer + * + * @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 return 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, invalid hook type or invalid callback. + * @return INVALID_HOOK_ID on fail a hookid on success +*/ +native int DHookRaw(Handle setup, bool post, Address addr, DHookRemovalCB removalcb=INVALID_FUNCTION, DHookCallback callback=INVALID_FUNCTION); + +/* Remove hook by hook id + * + * @param hookid Hook id to remove + * + * @return true on success false otherwise + * @note This will not fire the removal callback! +*/ +native bool DHookRemoveHookID(int hookid); + +/* Get param value (Use only for: int, entity, bool or float param types) + * + * @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) + * + * @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, int num); + +/* Get vector param 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.) + * @param vec Vector buffer to store result. + * + * @error Invalid handle. Invalid param number. Invalid param type. + * @noreturn +*/ +native void DHookGetParamVector(Handle hParams, int num, float vec[3]); + +/* Get string param 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.) + * @param buffer String buffer to store result + * @param size Buffer size + * + * @error Invalid handle. Invalid param number. Invalid param type. + * @noreturn +*/ +native void DHookGetParamString(Handle hParams, int num, char[] buffer, int size); + +/* Set param value (Use only for: int, entity, bool or float param types) + * + * @param hParams Handle to params structure + * @param num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.) + * @param value Value to set it as (only pass int, bool, float or entity index) + * + * @error Invalid handle. Invalid param number. Invalid param type. + * @noreturn +*/ +native void DHookSetParam(Handle hParams, int num, any value); + +/* Set vector param value + * + * @param hParams Handle to params structure + * @param num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.) + * @param vec Value to set vector as. + * + * @error Invalid handle. Invalid param number. Invalid param type. + * @noreturn +*/ +native void DHookSetParamVector(Handle hParams, int num, float vec[3]); + +/* Set string param value + * + * @param hParams Handle to params structure + * @param num Param number to set (Example if the function has 2 params and you need to set the value of the first param num would be 1.) + * @param value Value to set string as. + * + * @error Invalid handle. Invalid param number. Invalid param type. + * @noreturn +*/ +native void DHookSetParamString(Handle hParams, int num, char[] value); + +/* Get return value (Use only for: int, entity, bool or float return types) + * + * @param hReturn Handle to return structure + * + * @error Invalid Handle, invalid type. + * @return Returns default value if prehook returns actual value if post hook. +*/ +native any DHookGetReturn(Handle hReturn); + +/* Get return vector value + * + * @param hReturn Handle to return structure + * @param vec Vector buffer to store result in. (In pre hooks will be default value (0.0,0.0,0.0)) + * + * @error Invalid Handle, invalid type. + * @noreturn +*/ +native void DHookGetReturnVector(Handle hReturn, float vec[3]); + +/* Get return string value + * + * @param hReturn Handle to return structure + * @param buffer String buffer to store result in. (In pre hooks will be default value "") + * @param size String buffer size + * + * @error Invalid Handle, invalid type. + * @noreturn +*/ +native void DHookGetReturnString(Handle hReturn, char[] buffer, int size); + +/* Set return value (Use only for: int, entity, bool or float return types) + * + * @param hReturn Handle to return structure + * @param value Value to set return as + * + * @error Invalid Handle, invalid type. + * @noreturn +*/ +native void DHookSetReturn(Handle hReturn, any value); + +/* Set return vector value + * + * @param hReturn Handle to return structure + * @param vec Value to set return vector as + * + * @error Invalid Handle, invalid type. + * @noreturn +*/ +native void DHookSetReturnVector(Handle hReturn, float vec[3]); + +/* Set return string value + * + * @param hReturn Handle to return structure + * @param value Value to set return string as + * + * @error Invalid Handle, invalid type. + * @noreturn +*/ +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. + * @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, int num, int offset, ObjectValueType type); + +/* Sets an objects variable value + * + * @param hParams Handle to params structure + * @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. + * + * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type. + * @noreturn +*/ +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. + * @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. + * @noreturn +*/ +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. + * @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. + * + * @error Invalid handle. Invalid param number. Invalid param type. Invalid Object type. + * @noreturn +*/ +native void DHookSetParamObjectPtrVarVector(Handle hParams, int num, int offset, ObjectValueType type, float value[3]); + +/* 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 + * + * @param hParams Handle to params structure + * @param num Param number to check. + * + * @error Non pointer param + * @return True if null false otherwise. +*/ +native bool DHookIsNullParam(Handle hParams, int num); + +public Extension __ext_dhooks = +{ + name = "dhooks", + file = "dhooks.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public __ext_dhooks_SetNTVOptional() +{ + MarkNativeAsOptional("DHookAddEntityListener"); + MarkNativeAsOptional("DHookRemoveEntityListener"); + MarkNativeAsOptional("DHookCreate"); + MarkNativeAsOptional("DHookCreateDetour"); + MarkNativeAsOptional("DHookCreateFromConf"); + MarkNativeAsOptional("DHookSetFromConf"); + MarkNativeAsOptional("DHookEnableDetour"); + MarkNativeAsOptional("DHookDisableDetour"); + MarkNativeAsOptional("DHookAddParam"); + MarkNativeAsOptional("DHookEntity"); + MarkNativeAsOptional("DHookGamerules"); + MarkNativeAsOptional("DHookRaw"); + MarkNativeAsOptional("DHookRemoveHookID"); + MarkNativeAsOptional("DHookGetParam"); + MarkNativeAsOptional("DHookGetParamVector"); + MarkNativeAsOptional("DHookGetParamString"); + MarkNativeAsOptional("DHookSetParam"); + MarkNativeAsOptional("DHookSetParamVector"); + MarkNativeAsOptional("DHookSetParamString"); + MarkNativeAsOptional("DHookGetReturn"); + MarkNativeAsOptional("DHookGetReturnVector"); + MarkNativeAsOptional("DHookGetReturnString"); + MarkNativeAsOptional("DHookSetReturn"); + MarkNativeAsOptional("DHookSetReturnVector"); + MarkNativeAsOptional("DHookSetReturnString"); + MarkNativeAsOptional("DHookGetParamObjectPtrVar"); + MarkNativeAsOptional("DHookSetParamObjectPtrVar"); + MarkNativeAsOptional("DHookGetParamObjectPtrVarVector"); + MarkNativeAsOptional("DHookSetParamObjectPtrVarVector"); + MarkNativeAsOptional("DHookIsNullParam"); + MarkNativeAsOptional("DHookGetParamObjectPtrString"); + + MarkNativeAsOptional("DHookParam.IsNull"); + MarkNativeAsOptional("DHookParam.Get"); + MarkNativeAsOptional("DHookParam.GetVector"); + MarkNativeAsOptional("DHookParam.GetString"); + MarkNativeAsOptional("DHookParam.Set"); + MarkNativeAsOptional("DHookParam.SetVector"); + MarkNativeAsOptional("DHookParam.SetString"); + MarkNativeAsOptional("DHookParam.GetObjectVar"); + MarkNativeAsOptional("DHookParam.GetObjectVarVector"); + MarkNativeAsOptional("DHookParam.GetObjectVarString"); + MarkNativeAsOptional("DHookParam.SetObjectVar"); + MarkNativeAsOptional("DHookParam.SetObjectVarVector"); + MarkNativeAsOptional("DHookReturn.Value.get"); + MarkNativeAsOptional("DHookReturn.Value.set"); + MarkNativeAsOptional("DHookReturn.GetVector"); + MarkNativeAsOptional("DHookReturn.GetString"); + MarkNativeAsOptional("DHookReturn.SetVector"); + MarkNativeAsOptional("DHookReturn.SetString"); + MarkNativeAsOptional("DHookSetup.SetFromConf"); + MarkNativeAsOptional("DHookSetup.AddParam"); + MarkNativeAsOptional("DynamicHook.DynamicHook"); + MarkNativeAsOptional("DynamicHook.FromConf"); + MarkNativeAsOptional("DynamicHook.HookEntity"); + MarkNativeAsOptional("DynamicHook.HookGamerules"); + MarkNativeAsOptional("DynamicHook.HookRaw"); + MarkNativeAsOptional("DynamicHook.RemoveHook"); + MarkNativeAsOptional("DynamicDetour.DynamicDetour"); + MarkNativeAsOptional("DynamicDetour.FromConf"); + MarkNativeAsOptional("DynamicDetour.Enable"); + MarkNativeAsOptional("DynamicDetour.Disable"); +} +#endif \ No newline at end of file diff --git a/scripting/include/l4d2.inc b/scripting/include/l4d2.inc new file mode 100644 index 0000000..ddf75da --- /dev/null +++ b/scripting/include/l4d2.inc @@ -0,0 +1,499 @@ +/** +* ___ _______ _______ _______ _ ___ ______ _______ _______ ______ +* | | | || || | | | | | | | | || _ || | +* | | | ___|| ___||_ _| | |_| | | _ || ___|| |_| || _ | +* | | | |___ | |___ | | | | | | | || |___ | || | | | +* | |___ | ___|| ___| | | |___ | | |_| || ___|| || |_| | +* | || |___ | | | | | | | || |___ | _ || | +* |_______||_______||___| |___| |___| |______| |_______||__| |__||______| +* +* This include contains a ton of useful stocks and functions you can use for Left 4 Dead (2). +* Author: Keith Warren (Drixevel) +* https://github.com/Drixevel +* +* NOTE: The best way to use this include is to copy and paste into your projects manually. +* Credits: +**/ + +#if defined _misc_l4d_included + #endinput +#endif +#define _misc_l4d_included + +enum L4DGame +{ + L4DGame_L4D = 0, + L4DGame_L4D2 = 1 +} + +enum L4DTeam +{ + L4DTeam_Unassigned = 0, + L4DTeam_Spectator = 1, + L4DTeam_Survivors = 2, + L4DTeam_Infected = 3 +} + +enum L4DSurvivor +{ + L4DSurvivor_Bill = 0, + L4DSurvivor_Zoey = 1, + L4DSurvivor_Louis = 2, + L4DSurvivor_Francis = 3 +} + +enum L4D2Survivor +{ + L4D2Survivor_Nick = 0, + L4D2Survivor_Rochelle = 1, + L4D2Survivor_Coach = 2, + L4D2Survivor_Ellis = 3 +} + +enum L4DInfected +{ + L4DInfected_None = 0, + L4DInfected_Smoker = 1, + L4DInfected_Boomer = 2, + L4DInfected_Hunter = 3, + L4DInfected_Witch = 4, + L4DInfected_Tank = 5 +} + +enum L4D2Infected +{ + L4D2Infected_None = 0, + L4D2Infected_Smoker = 1, + L4D2Infected_Boomer = 2, + L4D2Infected_Hunter = 3, + L4D2Infected_Spitter = 4, + L4D2Infected_Jockey = 5, + L4D2Infected_Charger = 6, + L4D2Infected_Witch = 7, + L4D2Infected_Tank = 8 +} + +/** + * Gets a client's current team. + * + * @param client Client index. + * @return Current L4DTeam of client. + * @error Invalid client index. + */ +stock L4DTeam L4D_GetClientTeam(int client) +{ + return view_as(GetClientTeam(client)); +} + +/** + * Gets the current group of survivors assigned to the map. + * @return L4DGame enum index. + */ +stock L4DGame L4D_GetSurvivorGroup() +{ + int entity = -1; char sCharacter[32]; + while ((entity = FindEntityByClassname(entity, "info_survivor_position")) != -1) + { + GetEntPropString(entity, Prop_Data, "m_iszSurvivorName", sCharacter, sizeof(sCharacter)); + + if (strlen(sCharacter) > 0 && (StrEqual(sCharacter, "Bill") || StrEqual(sCharacter, "Zoey") || StrEqual(sCharacter, "Louis") || StrEqual(sCharacter, "Francis"))) + return L4DGame_L4D; + } + + return L4DGame_L4D2; +} + +/** + * Checks if the survivor is incapped. + * + * @param client Players index. + * @return True if player is incapacitated, false otherwise. + */ +stock bool L4D_IsClientIncapacitated(int client) +{ + return view_as(GetEntProp(client, Prop_Send, "m_isIncapacitated")); +} + +stock bool L4D_IsClientIncapped(int client) +{ + return view_as(GetEntProp(client, Prop_Send, "m_isIncapacitated")); +} + +/** + * Checks if the survivor is capped. + * + * @param client Players index. + * @return True if the player is capped, false otherwise. + */ +stock bool L4D_IsPlayerCapped(int client) +{ + if(GetEntPropEnt(client, Prop_Send, "m_pummelAttacker") > 0 || + GetEntPropEnt(client, Prop_Send, "m_carryAttacker") > 0 || + GetEntPropEnt(client, Prop_Send, "m_pounceAttacker") > 0 || + GetEntPropEnt(client, Prop_Send, "m_jockeyAttacker") > 0 || + GetEntPropEnt(client, Prop_Send, "m_pounceAttacker") > 0 || + GetEntPropEnt(client, Prop_Send, "m_tongueOwner") > 0) + return true; + return false; +} + +/*********************************************************************/ +/*********************************************************************/ +//Survivors +/*********************************************************************/ +/*********************************************************************/ + +/** + * Retrieves the survivor ID of the client for L4D. + * + * @param client Players index. + * @return Index of the survivor, -1 otherwise. + */ +stock L4DSurvivor L4D_GetClientSurvivorId(int client) +{ + int offset = FindSendPropInfo("CTerrorPlayer", "m_survivorCharacter"); + return view_as(GetEntData(client, offset, 1)); +} + +/** + * Retrieves the survivor ID of the client for L4D2. + * + * @param client Players index. + * @return Index of the survivor, -1 otherwise. + */ +stock L4D2Survivor L4D2_GetClientSurvivorId(int client) +{ + int offset = FindSendPropInfo("CTerrorPlayer", "m_survivorCharacter"); + return view_as(GetEntData(client, offset, 1)); +} + +/** + * Retrieves the survivor name of the client for L4D. + * + * @param client Players index. + * @return True if found, false otherwise. + */ +stock bool L4D_GetClientSurvivorName(int client, char[] name, int size) +{ + return L4D_GetSurvivorName(L4D_GetClientSurvivorId(client), name, size); +} + +/** + * Retrieves the survivor name of the client for L4D2. + * + * @param client Players index. + * @return True if found, false otherwise. + */ +stock bool L4D2_GetClientSurvivorName(int client, char[] name, int size) +{ + return L4D2_GetSurvivorName(L4D2_GetClientSurvivorId(client), name, size); +} + +/** + * Retrieves the ID of any of the L4D survivors. + * + * @param name Name of the survivor. + * @return The ID of the survivor, -1 for not found. + */ +stock L4DSurvivor L4D_GetSurvivorID(const char[] name) +{ + if (StrEqual(name, "bill", false)) + return L4DSurvivor_Bill; + else if (StrEqual(name, "zoey", false)) + return L4DSurvivor_Zoey; + else if (StrEqual(name, "louis", false)) + return L4DSurvivor_Louis; + else if (StrEqual(name, "francis", false)) + return L4DSurvivor_Francis; + + return -1; +} + +/** + * Retrieves the ID of any of the L4D2 survivors. + * + * @param name Name of the survivor. + * @return The ID of the survivor, -1 for not found. + */ +stock L4D2Survivor L4D2_GetSurvivorID(const char[] name) +{ + if (StrEqual(name, "nick", false)) + return L4D2Survivor_Nick; + else if (StrEqual(name, "rochelle", false)) + return L4D2Survivor_Rochelle; + else if (StrEqual(name, "coach", false)) + return L4D2Survivor_Coach; + else if (StrEqual(name, "ellis", false)) + return L4D2Survivor_Ellis; + + return -1; +} + +/** + * Retrieves the name of any of the L4D survivors. + * + * @param id ID of the survivor. + * @return True if found and buffer filled, false otherwise. + */ +stock bool L4D_GetSurvivorName(L4DSurvivor id, char[] name, int size, bool capitalize = false) +{ + switch (id) + { + case L4DSurvivor_Bill: + { + strcopy(name, size, capitalize ? "Bill" : "bill"); + return true; + } + case L4DSurvivor_Zoey: + { + strcopy(name, size, capitalize ? "Zoey" : "zoey"); + return true; + } + case L4DSurvivor_Louis: + { + strcopy(name, size, capitalize ? "Louis" : "louis"); + return true; + } + case L4DSurvivor_Francis: + { + strcopy(name, size, capitalize ? "Francis" : "francis"); + return true; + } + } + + return false; +} + +/** + * Retrieves the name of any of the L4D2 survivors. + * + * @param id ID of the survivor. + * @return True if found and buffer filled, false otherwise. + */ +stock bool L4D2_GetSurvivorName(L4D2Survivor id, char[] name, int size, bool capitalize = false) +{ + switch (id) + { + case L4D2Survivor_Nick: + { + strcopy(name, size, capitalize ? "Nick" : "nick"); + return true; + } + case L4D2Survivor_Rochelle: + { + strcopy(name, size, capitalize ? "Rochelle" : "rochelle"); + return true; + } + case L4D2Survivor_Coach: + { + strcopy(name, size, capitalize ? "Coach" : "coach"); + return true; + } + case L4D2Survivor_Ellis: + { + strcopy(name, size, capitalize ? "Ellis" : "ellis"); + return true; + } + } + + return false; +} + +/*********************************************************************/ +/*********************************************************************/ +//Infected +/*********************************************************************/ +/*********************************************************************/ + +/** + * Retrieves the infected ID of the client for L4D. + * + * @param client Players index. + * @return Index of the infected, -1 otherwise. + */ +stock L4DInfected L4D_GetClientInfectedId(int client) +{ + return view_as(GetEntProp(client, Prop_Send, "m_zombieClass")); +} + +/** + * Retrieves the infected ID of the client for L4D2. + * + * @param client Players index. + * @return Index of the infected, -1 otherwise. + */ +stock L4D2Infected L4D2_GetClientInfectedId(int client) +{ + return view_as(GetEntProp(client, Prop_Send, "m_zombieClass")); +} + +/** + * Retrieves the infected name of the client for L4D. + * + * @param client Players index. + * @return True if found, false otherwise. + */ +stock bool L4D_GetClientInfectedName(int client, char[] name, int size) +{ + return L4D_GetInfectedName(L4D_GetClientInfectedId(client), name, size); +} + +/** + * Retrieves the infected name of the client for L4D2. + * + * @param client Players index. + * @return True if found, false otherwise. + */ +stock bool L4D2_GetClientInfectedName(int client, char[] name, int size) +{ + return L4D2_GetInfectedName(L4D2_GetClientInfectedId(client), name, size); +} + +/** + * Retrieves the ID of any of the L4D infected. + * + * @param name Name of the infected. + * @return The ID of the infected, -1 for not found. + */ +stock L4DInfected L4D_GetInfectedID(const char[] name) +{ + if (StrEqual(name, "smoker", false)) + return L4DInfected_Smoker; + else if (StrEqual(name, "boomer", false)) + return L4DInfected_Boomer; + else if (StrEqual(name, "hunter", false)) + return L4DInfected_Hunter; + else if (StrEqual(name, "witch", false)) + return L4DInfected_Witch; + else if (StrEqual(name, "tank", false)) + return L4DInfected_Tank; + + return L4DInfected_None; +} + +/** + * Retrieves the ID of any of the L4D2 infected. + * + * @param name Name of the infected. + * @return The ID of the infected, -1 for not found. + */ +stock L4D2Infected L4D2_GetInfectedID(const char[] name) +{ + if (StrEqual(name, "smoker", false)) + return L4D2Infected_Smoker; + else if (StrEqual(name, "boomer", false)) + return L4D2Infected_Boomer; + else if (StrEqual(name, "hunter", false)) + return L4D2Infected_Hunter; + else if (StrEqual(name, "spitter", false)) + return L4D2Infected_Spitter; + else if (StrEqual(name, "charger", false)) + return L4D2Infected_Charger; + else if (StrEqual(name, "jockey", false)) + return L4D2Infected_Jockey; + else if (StrEqual(name, "witch", false)) + return L4D2Infected_Witch; + else if (StrEqual(name, "tank", false)) + return L4D2Infected_Tank; + + return L4D2Infected_None; +} + +/** + * Retrieves the name of any of the L4D infected. + * + * @param id ID of the infected. + * @return True if found and buffer filled, false otherwise. + */ +stock bool L4D_GetInfectedName(L4DInfected id, char[] name, int size, bool capitalize = false) +{ + switch (id) + { + case L4DInfected_None: + return false; + case L4DInfected_Smoker: + { + strcopy(name, size, capitalize ? "Smoker" : "smoker"); + return true; + } + case L4DInfected_Boomer: + { + strcopy(name, size, capitalize ? "Boomer" : "boomer"); + return true; + } + case L4DInfected_Hunter: + { + strcopy(name, size, capitalize ? "Hunter" : "hunter"); + return true; + } + case L4DInfected_Witch: + { + strcopy(name, size, capitalize ? "Witch" : "witch"); + return true; + } + case L4DInfected_Tank: + { + strcopy(name, size, capitalize ? "Tank" : "tank"); + return true; + } + } + + return false; +} + +/** + * Retrieves the name of any of the L4D2 infected. + * + * @param id ID of the infected. + * @return True if found and buffer filled, false otherwise. + */ +stock bool L4D2_GetInfectedName(L4D2Infected id, char[] name, int size, bool capitalize = false) +{ + switch (id) + { + case L4D2Infected_None: + return false; + case L4D2Infected_Smoker: + { + strcopy(name, size, capitalize ? "Smoker" : "smoker"); + return true; + } + case L4D2Infected_Boomer: + { + strcopy(name, size, capitalize ? "Boomer" : "boomer"); + return true; + } + case L4D2Infected_Hunter: + { + strcopy(name, size, capitalize ? "Hunter" : "hunter"); + return true; + } + case L4D2Infected_Spitter: + { + strcopy(name, size, capitalize ? "Spitter" : "spitter"); + return true; + } + case L4D2Infected_Jockey: + { + strcopy(name, size, capitalize ? "Jockey" : "jockey"); + return true; + } + case L4D2Infected_Charger: + { + strcopy(name, size, capitalize ? "Charger" : "charger"); + return true; + } + case L4D2Infected_Witch: + { + strcopy(name, size, capitalize ? "Witch" : "witch"); + return true; + } + case L4D2Infected_Tank: + { + strcopy(name, size, capitalize ? "Tank" : "tank"); + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/scripting/include/l4d2_weapon_stocks.inc b/scripting/include/l4d2_weapon_stocks.inc new file mode 100644 index 0000000..f8b1e70 --- /dev/null +++ b/scripting/include/l4d2_weapon_stocks.inc @@ -0,0 +1,629 @@ +#if defined l4d2_weapons_inc_ + #endinput +#endif +#define l4d2_weapons_inc_ + +#define GETWEAPONNAME(%0) (IsValidWeaponId(WeaponId:(%0)) ? (WeaponNames[_:(%0)]) : "") +#define GETLONGWEAPONNAME(%0) (IsValidWeaponId(WeaponId:(%0)) ? (LongWeaponNames[_:(%0)]) : "") +#define GETMELEEWEAPONNAME(%0) (IsValidWeaponId(MeleeWeaponId:(%0)) ? (MeleeWeaponNames[_:(%0)]) : "") +#define GETLONGMELEEWEAPONNAME(%0) (IsValidWeaponId(MeleeWeaponId:(%0)) ? (LongMeleeWeaponNames[_:(%0)]) : "") +#define GETWEAPONMODEL(%0) (HasValidWeaponModel(WeaponId:(%0)) ? (WeaponModels[_:(%0)]) : "") +#define GETMELEEWEAPONMODEL(%0) (HasValidWeaponModel(MeleeWeaponId:(%0)) ? (MeleeWeaponModels[_:(%0)]) : "") + +// Weapon ID enumerations. +// These values are *NOT* arbitrary! +// They are used in game as the weaponid for weapon_spawn entities +enum WeaponId { + WEPID_NONE, // 0 + WEPID_PISTOL, // 1 + WEPID_SMG, // 2 + WEPID_PUMPSHOTGUN, // 3 + WEPID_AUTOSHOTGUN, // 4 + WEPID_RIFLE, // 5 + WEPID_HUNTING_RIFLE, // 6 + WEPID_SMG_SILENCED, // 7 + WEPID_SHOTGUN_CHROME, // 8 + WEPID_RIFLE_DESERT, // 9 + WEPID_SNIPER_MILITARY, // 10 + WEPID_SHOTGUN_SPAS, // 11 + WEPID_FIRST_AID_KIT, // 12 + WEPID_MOLOTOV, // 13 + WEPID_PIPE_BOMB, // 14 + WEPID_PAIN_PILLS, // 15 + WEPID_GASCAN, // 16 + WEPID_PROPANE_TANK, // 17 + WEPID_OXYGEN_TANK, // 18 + WEPID_MELEE, // 19 + WEPID_CHAINSAW, // 20 + WEPID_GRENADE_LAUNCHER, // 21 + WEPID_AMMO_PACK, // 22 + WEPID_ADRENALINE, // 23 + WEPID_DEFIBRILLATOR, // 24 + WEPID_VOMITJAR, // 25 + WEPID_RIFLE_AK47, // 26 + WEPID_GNOME_CHOMPSKI, // 27 + WEPID_COLA_BOTTLES, // 28 + WEPID_FIREWORKS_BOX, // 29 + WEPID_INCENDIARY_AMMO, // 30 + WEPID_FRAG_AMMO, // 31 + WEPID_PISTOL_MAGNUM, // 32 + WEPID_SMG_MP5, // 33 + WEPID_RIFLE_SG552, // 34 + WEPID_SNIPER_AWP, // 35 + WEPID_SNIPER_SCOUT, // 36 + WEPID_RIFLE_M60, // 37 + WEPID_TANK_CLAW, // 38 + WEPID_HUNTER_CLAW, // 39 + WEPID_CHARGER_CLAW, // 40 + WEPID_BOOMER_CLAW, // 41 + WEPID_SMOKER_CLAW, // 42 + WEPID_SPITTER_CLAW, // 43 + WEPID_JOCKEY_CLAW, // 44 + WEPID_MACHINEGUN, // 45 + WEPID_VOMIT, // 46 + WEPID_SPLAT, // 47 + WEPID_POUNCE, // 48 + WEPID_LOUNGE, // 49 + WEPID_PULL, // 50 + WEPID_CHOKE, // 51 + WEPID_ROCK, // 52 + WEPID_PHYSICS, // 53 + WEPID_AMMO, // 54 + WEPID_UPGRADE_ITEM // 55 +}; + +// These values are arbitrary +enum MeleeWeaponId +{ + WEPID_MELEE_NONE, + WEPID_KNIFE, + WEPID_BASEBALL_BAT, + WEPID_CHAINSAW, + WEPID_CRICKET_BAT, + WEPID_CROWBAR, + WEPID_DIDGERIDOO, + WEPID_ELECTRIC_GUITAR, + WEPID_FIREAXE, + WEPID_FRYING_PAN, + WEPID_GOLF_CLUB, + WEPID_KATANA, + WEPID_MACHETE, + WEPID_RIOT_SHIELD, + WEPID_TONFA +}; + +// Weapon names for each of the weapons, used in identification. +const char WeaponNames[WeaponId][] = +{ + "weapon_none", "weapon_pistol", "weapon_smg", // 0 + "weapon_pumpshotgun", "weapon_autoshotgun", "weapon_rifle", // 3 + "weapon_hunting_rifle", "weapon_smg_silenced", "weapon_shotgun_chrome", // 6 + "weapon_rifle_desert", "weapon_sniper_military", "weapon_shotgun_spas", // 9 + "weapon_first_aid_kit", "weapon_molotov", "weapon_pipe_bomb", // 12 + "weapon_pain_pills", "weapon_gascan", "weapon_propanetank", // 15 + "weapon_oxygentank", "weapon_melee", "weapon_chainsaw", // 18 + "weapon_grenade_launcher", "weapon_ammo_pack", "weapon_adrenaline", // 21 + "weapon_defibrillator", "weapon_vomitjar", "weapon_rifle_ak47", // 24 + "weapon_gnome", "weapon_cola_bottles", "weapon_fireworkcrate", // 27 + "weapon_upgradepack_incendiary", "weapon_upgradepack_explosive", "weapon_pistol_magnum", // 30 + "weapon_smg_mp5", "weapon_rifle_sg552", "weapon_sniper_awp", // 33 + "weapon_sniper_scout", "weapon_rifle_m60", "weapon_tank_claw", // 36 + "weapon_hunter_claw", "weapon_charger_claw", "weapon_boomer_claw", // 39 + "weapon_smoker_claw", "weapon_spitter_claw", "weapon_jockey_claw", // 42 + "weapon_machinegun", "vomit", "splat", // 45 + "pounce", "lounge", "pull", // 48 + "choke", "rock", "physics", // 51 + "ammo", "upgrade_item" // 54 +}; + +// Long weapon names +const char LongWeaponNames[WeaponId][] = +{ + "None", "Pistol", "Uzi", // 0 + "Pump", "Autoshotgun", "M-16", // 3 + "Hunting Rifle", "Mac", "Chrome", // 6 + "Desert Rifle", "Military Sniper", "SPAS Shotgun", // 9 + "First Aid Kit", "Molotov", "Pipe Bomb", // 12 + "Pills", "Gascan", "Propane Tank", // 15 + "Oxygen Tank", "Melee", "Chainsaw", // 18 + "Grenade Launcher", "Ammo Pack", "Adrenaline", // 21 + "Defibrillator", "Bile Bomb", "AK-47", // 24 + "Gnome", "Cola Bottles", "Fireworks", // 27 + "Incendiary Ammo Pack", "Explosive Ammo Pack", "Deagle", // 30 + "MP5", "SG552", "AWP", // 33 + "Scout", "M60", "Tank Claw", // 36 + "Hunter Claw", "Charger Claw", "Boomer Claw", // 39 + "Smoker Claw", "Spitter Claw", "Jockey Claw", // 42 + "Turret", "vomit", "splat", // 45 + "pounce", "lounge", "pull", // 48 + "choke", "rock", "physics", // 51 + "ammo", "upgrade_item" // 54 +}; + +// Internal names for melee weapons +char MeleeWeaponNames[MeleeWeaponId][] = +{ + "", + "knife", + "baseball_bat", + "chainsaw", + "cricket_bat", + "crowbar", + "didgeridoo", + "electric_guitar", + "fireaxe", + "frying_pan", + "golfclub", + "katana", + "machete", + "riotshield", + "tonfa" +}; + +// Long melee weapon names +const char LongMeleeWeaponNames[MeleeWeaponId][] = +{ + "None", + "Knife", + "Baseball Bat", + "Chainsaw", + "Cricket Bat", + "Crowbar", + "didgeridoo", // derp + "Guitar", + "Axe", + "Frying Pan", + "Golf Club", + "Katana", + "Machete", + "Riot Shield", + "Tonfa" +}; + +// World weapon models for each of the weapons. Useful for making new weapon spawns. +// Some models are left blank because no single model can be given, the model is known or none exist. +const char WeaponModels[WeaponId][] = +{ + "", + "/w_models/weapons/w_pistol_B.mdl", + "/w_models/weapons/w_smg_uzi.mdl", + "/w_models/weapons/w_shotgun.mdl", + "/w_models/weapons/w_autoshot_m4super.mdl", + "/w_models/weapons/w_rifle_m16a2.mdl", + "/w_models/weapons/w_sniper_mini14.mdl", + "/w_models/weapons/w_smg_a.mdl", + "/w_models/weapons/w_pumpshotgun_a.mdl", + "/w_models/weapons/w_desert_rifle.mdl", // "/w_models/weapons/w_rifle_b.mdl" + "/w_models/weapons/w_sniper_military.mdl", + "/w_models/weapons/w_shotgun_spas.mdl", + "/w_models/weapons/w_eq_medkit.mdl", + "/w_models/weapons/w_eq_molotov.mdl", + "/w_models/weapons/w_eq_pipebomb.mdl", + "/w_models/weapons/w_eq_painpills.mdl", + "/props_junk/gascan001a.mdl", + "/props_junk/propanecanister001.mdl", + "/props_equipment/oxygentank01.mdl", + "", + "/weapons/melee/w_chainsaw.mdl", + "/w_models/weapons/w_grenade_launcher.mdl", + "", + "/w_models/weapons/w_eq_adrenaline.mdl", + "/w_models/weapons/w_eq_defibrillator.mdl", + "/w_models/weapons/w_eq_bile_flask.mdl", + "/w_models/weapons/w_rifle_ak47.mdl", + "/props_junk/gnome.mdl", + "/w_models/weapons/w_cola.mdl", + "/props_junk/explosive_box001.mdl", + "/w_models/weapons/w_eq_incendiary_ammopack.mdl", + "/w_models/weapons/w_eq_explosive_ammopack.mdl", + "/w_models/weapons/w_desert_eagle.mdl", + "/w_models/weapons/w_smg_mp5.mdl", + "/w_models/weapons/w_rifle_sg552.mdl", + "/w_models/weapons/w_sniper_awp.mdl", + "/w_models/weapons/w_sniper_scout.mdl", + "/w_models/weapons/w_m60.mdl", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" +}; + +const char MeleeWeaponModels[MeleeWeaponId][] = +{ + "", + "/w_models/weapons/w_knife_t.mdl", + "/weapons/melee/w_bat.mdl", + "/weapons/melee/w_chainsaw.mdl", + "/weapons/melee/w_cricket_bat.mdl", + "/weapons/melee/w_crowbar.mdl", + "/weapons/melee/w_didgeridoo.mdl", + "/weapons/melee/w_electric_guitar.mdl", + "/weapons/melee/w_fireaxe.mdl", + "/weapons/melee/w_frying_pan.mdl", + "/weapons/melee/w_golfclub.mdl", + "/weapons/melee/w_katana.mdl", + "/weapons/melee/w_machete.mdl", + "/weapons/melee/w_riotshield.mdl", + "/weapons/melee/w_tonfa.mdl" +}; + +const int WeaponSlots[WeaponId] = +{ + -1, // WEPID_NONE + 1, // WEPID_PISTOL + 0, // WEPID_SMG + 0, // WEPID_PUMPSHOTGUN + 0, // WEPID_AUTOSHOTGUN + 0, // WEPID_RIFLE + 0, // WEPID_HUNTING_RIFLE + 0, // WEPID_SMG_SILENCED + 0, // WEPID_SHOTGUN_CHROME + 0, // WEPID_RIFLE_DESERT + 0, // WEPID_SNIPER_MILITARY + 0, // WEPID_SHOTGUN_SPAS + 3, // WEPID_FIRST_AID_KIT + 2, // WEPID_MOLOTOV + 2, // WEPID_PIPE_BOMB + 4, // WEPID_PAIN_PILLS + -1, // WEPID_GASCAN + -1, // WEPID_PROPANE_TANK + -1, // WEPID_OXYGEN_TANK + 1, // WEPID_MELEE + 1, // WEPID_CHAINSAW + 0, // WEPID_GRENADE_LAUNCHER + 3, // WEPID_AMMO_PACK + 4, // WEPID_ADRENALINE + 3, // WEPID_DEFIBRILLATOR + 2, // WEPID_VOMITJAR + 0, // WEPID_RIFLE_AK47 + -1, // WEPID_GNOME_CHOMPSKI + -1, // WEPID_COLA_BOTTLES + -1, // WEPID_FIREWORKS_BOX + 3, // WEPID_INCENDIARY_AMMO + 3, // WEPID_FRAG_AMMO + 1, // WEPID_PISTOL_MAGNUM + 0, // WEPID_SMG_MP5 + 0, // WEPID_RIFLE_SG552 + 0, // WEPID_SNIPER_AWP + 0, // WEPID_SNIPER_SCOUT + 0, // WEPID_RIFLE_M60 + -1, // WEPID_TANK_CLAW + -1, // WEPID_HUNTER_CLAW + -1, // WEPID_CHARGER_CLAW + -1, // WEPID_BOOMER_CLAW + -1, // WEPID_SMOKER_CLAW + -1, // WEPID_SPITTER_CLAW + -1, // WEPID_JOCKEY_CLAW + -1, // WEPID_MACHINEGUN + -1, // WEPID_FATAL_VOMIT + -1, // WEPID_EXPLODING_SPLAT + -1, // WEPID_LUNGE_POUNCE + -1, // WEPID_LOUNGE + -1, // WEPID_FULLPULL + -1, // WEPID_CHOKE + -1, // WEPID_THROWING_ROCK + -1, // WEPID_TURBO_PHYSICS + -1, // WEPID_AMMO + -1 // WEPID_UPGRADE_ITEM +}; + +enum L4D2WeaponSlot +{ + L4D2WeaponSlot_Primary, + L4D2WeaponSlot_Secondary, + L4D2WeaponSlot_Throwable, + L4D2WeaponSlot_HeavyHealthItem, + L4D2WeaponSlot_LightHealthItem +}; + +static Handle hWeaponNamesTrie = INVALID_HANDLE; +static Handle hMeleeWeaponNamesTrie = INVALID_HANDLE; +static Handle hMeleeWeaponModelsTrie = INVALID_HANDLE; + +stock void InitWeaponNamesTrie() { + hWeaponNamesTrie = CreateTrie(); + for(new i = 0; i < _:WeaponId; i++) + { + SetTrieValue(hWeaponNamesTrie, WeaponNames[WeaponId:i], i); + } + + hMeleeWeaponNamesTrie = CreateTrie(); + hMeleeWeaponModelsTrie = CreateTrie(); + for (new i = 0; i < _:MeleeWeaponId; ++i) + { + SetTrieValue(hMeleeWeaponNamesTrie, MeleeWeaponNames[MeleeWeaponId:i], i); + SetTrieString(hMeleeWeaponModelsTrie, MeleeWeaponModels[MeleeWeaponId:i], MeleeWeaponNames[MeleeWeaponId:i]); + } +} + +/** + * Performs bounds checking to determine if a WeaponId is valid + * @remark Simple check to see if wepid has a garbage value + * + * @param wepid WeaponId to check for validity + * @return True if wepid is valid, false otherwise. + */ +stock bool IsValidWeaponId({WeaponId, MeleeWeaponId} wepid, tagType = tagof(wepid)) +{ + if (tagType == tagof(MeleeWeaponId)) + { + return MeleeWeaponId:wepid >= WEPID_MELEE_NONE && MeleeWeaponId:wepid < MeleeWeaponId; + } + return wepid >= WEPID_NONE && wepid < WeaponId; +} + +/** + * Get the player weapon slot used by the given WeaponId. + * + * @param wepid WeaponId to get the slot for. + * @return Slot number (0-4) or -1 for invalid WeaponId or no slot + */ +stock int GetSlotFromWeaponId(WeaponId wepid) +{ + return IsValidWeaponId(wepid) ? WeaponSlots[wepid] : -1; +} + +/** + * Checks to see if a given weaponid has a known WeaponModel in this file's model array + * @remark Some weapons (like weapon_melee) have multiple valid models, and this will report false for them. + * + * @param wepid WeaponId to check for a known weapon model for. + * @return True if a valid weapon model exists for wepid, false otherwise. + */ +stock bool:HasValidWeaponModel({WeaponId, MeleeWeaponId}:wepid, tagType = tagof(wepid)) +{ + if (tagType == tagof(MeleeWeaponId)) + { + return IsValidWeaponId(MeleeWeaponId:wepid) && MeleeWeaponModels[MeleeWeaponId:wepid][0] != '\0'; + } + return IsValidWeaponId(wepid) && WeaponModels[wepid][0] != '\0'; +} + +/** + * Tries to look up a WeaponId for a given Weapon Name. + * + * @param weaponName Weapon name string to look up Id from + * @return The corresponding WeaponId if found, else WEPID_NONE + */ +stock WeaponId WeaponNameToId(const char weaponName[]) +{ + new WeaponID:id; + if(hWeaponNamesTrie == INVALID_HANDLE) + { + InitWeaponNamesTrie(); + } + if(GetTrieValue(hWeaponNamesTrie, weaponName, id)) + { + return WeaponId:id; + } + return WEPID_NONE; +} + +/** + * Tries to look up L4D2's internal weapon name for a given WeaponId. + * + * @param wepid WeaponId To get name of. + * @param nameBuffer String buffer to write the weapon name to. + * @param length Max length which can be written to the buffer. + * @return Number of bytes written to buffer, or 0 for invalid weaponId. + */ +stock GetWeaponName({WeaponId, MeleeWeaponId}:wepid, String:nameBuffer[], length, tagType = tagof(wepid)) +{ + if (tagType == tagof(MeleeWeaponId)) + { + strcopy(nameBuffer, length, GETMELEEWEAPONNAME(wepid)); + } + else + { + strcopy(nameBuffer, length, GETWEAPONNAME(wepid)); + } +} + +/** + * Tries to look up L4D2's internal weapon name for a given WeaponId. + * + * @param wepid WeaponId To get name of. + * @param nameBuffer String buffer to write the weapon name to. + * @param length Max length which can be written to the buffer. + * @return Number of bytes written to buffer, or 0 for invalid weaponId. + */ +stock GetLongWeaponName({WeaponId, MeleeWeaponId}:wepid, String:nameBuffer[], length, tagType = tagof(wepid)) +{ + if (tagType == tagof(MeleeWeaponId)) + { + strcopy(nameBuffer, length, GETLONGMELEEWEAPONNAME(wepid)); + } + else + { + strcopy(nameBuffer, length, GETLONGWEAPONNAME(wepid)); + } +} + +/** + * Tries to look up the weapon model for a given WeaponId. + * @remarks You should use HasValidWeaponModel to make sure the WeaponId you're looking up has a valid model associated with it. + * + * @param wepid WeaponId To get name of. + * @param nameBuffer String buffer to write the weapon name to. + * @param length Max length which can be written to the buffer. + * @return Number of bytes written to buffer, or 0 for invalid weaponid or no weapon model available. + */ +stock GetWeaponModel({WeaponId, MeleeWeaponId}:wepid, String:modelBuffer[], length, tagType = tagof(wepid)) +{ + if (tagType == tagof(MeleeWeaponId)) + { + strcopy(modelBuffer, length, GETMELEEWEAPONMODEL(wepid)); + } + else + { + strcopy(modelBuffer, length, GETWEAPONMODEL(wepid)); + } +} + +/** + * Identifies a weapon spawn or weapon entity as a WeaponID + * @remark Should work on most weapon ents--even spawns, singles, held, etc. + * + * @param entity Index of entity to identify + * @return WeaponID for the entity if it is a weapon, WEPID_NONE otherwise + */ +stock WeaponId:IdentifyWeapon(entity) +{ + if(!entity || !IsValidEntity(entity) || !IsValidEdict(entity)) + { + return WEPID_NONE; + } + decl String:class[64]; + if(!GetEdictClassname(entity, class, sizeof(class))) + { + return WEPID_NONE; + } + + if(StrEqual(class, "weapon_spawn")) + { + return WeaponId:GetEntProp(entity,Prop_Send,"m_weaponID"); + } + + new len = strlen(class); + if(len-6 > 0 && StrEqual(class[len-6], "_spawn")) + { + class[len-6]='\0'; + return WeaponNameToId(class); + } + + return WeaponNameToId(class); +} + +// Helper function used for getting an entity's internal melee name +stock bool:GetMeleeWeaponNameFromEntity(entity, String:buffer[], length) { + decl String:classname[64]; + if (! GetEdictClassname(entity, classname, sizeof(classname))) + { + return false; + } + + if (StrEqual(classname, "weapon_melee_spawn")) + { + if (hMeleeWeaponModelsTrie == INVALID_HANDLE) + { + InitWeaponNamesTrie(); + } + + decl String:sModelName[128]; + GetEntPropString(entity, Prop_Data, "m_ModelName", sModelName, sizeof(sModelName)); + + // Strip models directory + if (strncmp(sModelName, "models/", 7, false) == 0) + { + strcopy(sModelName, sizeof(sModelName), sModelName[6]); + } + + if (GetTrieString(hMeleeWeaponModelsTrie, sModelName, buffer, length)) + { + return true; + } + return false; + } + else if (StrEqual(classname, "weapon_melee")) + { + GetEntPropString(entity, Prop_Data, "m_strMapSetScriptName", buffer, length); + return true; + } + + return false; +} + +/** + * Identifies a melee weapon spawn or weapon entity as a MeleeWeaponId + * @remark Should work on most weapon ents--even spawns, singles, held, etc. + * + * @param entity Index of entity to identify + * @return MeleeWeaponId for the entity if it is a weapon, WEPID_MELEE_NONE otherwise + */ +stock MeleeWeaponId:IdentifyMeleeWeapon(entity) +{ + if (IdentifyWeapon(entity) != WEPID_MELEE) + { + return WEPID_MELEE_NONE; + } + + decl String:sName[128]; + if (! GetMeleeWeaponNameFromEntity(entity, sName, sizeof(sName))) + { + return WEPID_MELEE_NONE; + } + + if (hMeleeWeaponNamesTrie == INVALID_HANDLE) + { + InitWeaponNamesTrie(); + } + + new id; + if(GetTrieValue(hMeleeWeaponNamesTrie, sName, id)) + { + return MeleeWeaponId:id; + } + return WEPID_MELEE_NONE; +} + +/** + * Attempts to convert a weapon spawn entity to a given weapon spawn + * @remark Truthfully, this will work on any entity with origin/rotation. + * Also, requires the weapon to either have a Valid weapon model or have one provided + * + * @param entity Index of entity to convert to weapon spawn + * @param wepid WeaponId of the weapon to have the spawner hold + * @param count Weapon count for the spawner (default 5) + * @param model World model to use for the weapon spawn + * @return entity of the new weapon spawn, or -1 on errors. + */ +stock ConvertWeaponSpawn(entity, WeaponId:wepid, count=5, const String:model[] = "") +{ + if(!IsValidEntity(entity)) return -1; + if(!IsValidWeaponId(wepid)) return -1; + if(model[0] == '\0' && !HasValidWeaponModel(wepid)) return -1; + + + new Float:origins[3], Float:angles[3]; + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origins); + GetEntPropVector(entity, Prop_Send, "m_angRotation", angles); + + AcceptEntityInput(entity, "kill"); + + entity = CreateEntityByName("weapon_spawn"); + if(!IsValidEntity(entity)) return -1; + + SetEntProp(entity, Prop_Send, "m_weaponID", wepid); + + decl String:buf[64]; + if(model[0] == '\0') + { + SetEntityModel(entity, model); + } + else + { + GetWeaponModel(wepid, buf, sizeof(buf)); + SetEntityModel(entity, buf); + } + IntToString(count, buf, sizeof(buf)); + DispatchKeyValue(entity, "count", buf); + + TeleportEntity(entity, origins, angles, NULL_VECTOR); + DispatchSpawn(entity); + SetEntityMoveType(entity,MOVETYPE_NONE); + return entity; +} diff --git a/scripting/include/l4d2_weapons.inc b/scripting/include/l4d2_weapons.inc new file mode 100644 index 0000000..f39af4d --- /dev/null +++ b/scripting/include/l4d2_weapons.inc @@ -0,0 +1,71 @@ +const char WEAPON_GUN_GROUPS = [][] { + "rifle", + "sniper", + "smg", + "shotgun" +} +enum WEAPON_TYPES { + Weapon_Rifle, + Weapon_Sniper, + Weapon_SMG, + Weapon_Shotgun +} + +const char WEAPONS_RIFLE = [] + + +stock bool IsPrimaryWeapon(const char[] wpnName) { + return StrContains(wpnName, "rifle") > -1 + || StrContains(wpnName, "smg") > -1 + || StrContains(wpnName, "weapon_grenade_launcher") > -1 + || StrContains(wpnName, "sniper") > -1 + || StrContains(wpnName, "shotgun") > -1; +} +stock int GetClientWeaponEntIndex(int client, int slot) { + if(slot >= 0 && slot <= 4) { + int wpnRef = GetPlayerWeaponSlot(client, slot); + if(wpnRef != -1) { + int wpn = EntRefToEntIndex(wpnRef); + if(wpn != INVALID_ENT_REFERENCE) { + return wpn; + }else{ + return -1; + } + }else{ + return -1; + } + }else{ + return -1; + } +} +stock int GetClientSecondaryWeapon(int client) { + return GetClientWeaponEntIndex(client, 1); +} +stock bool GetClientWeaponName(int client, int slot, char[] name, int nameSize) { + int wpn = GetClientWeaponEntIndex(client, slot); + if(wpn > -1) { + GetEntityClassname(wpn, name, nameSize); + return true; + }else{ + return false; + } +} +stock bool DoesClientHaveWeapon(int client, int slot, const char[] name) { + char wpn[32]; + if(GetClientWeaponName(client, slot, wpn, sizeof(wpn))) { + return StrEqual(wpn, name, false); + }else{ + return false; + } +} + +stock bool DoesClientHaveMelee(int client) { + int wpnEnt = GetClientSecondaryWeapon(client); + if(wpnEnt > -1) { + char wpn[16]; + GetEdictClassname(wpnEnt, wpn, sizeof(wpn)); + return StrEqual(wpn, "weapon_melee"); + }else{ + return false; + } +} \ No newline at end of file diff --git a/scripting/include/l4d_survivor_identity_fix.inc b/scripting/include/l4d_survivor_identity_fix.inc new file mode 100644 index 0000000..c0d7078 --- /dev/null +++ b/scripting/include/l4d_survivor_identity_fix.inc @@ -0,0 +1,27 @@ +enum Character { + Character_Nick, + Character_Ellis, + Character_Rochelle, + Character_Coach, + Character_Bill, + Character_Francis, + Character_Zoey, + Character_Louis +} +native int IdentityFix_SetPlayerModel(int client, int args); + + +static bool nativeAvailable, nativeTested; +bool UpdatePlayerIdentity(int client, Character character) { + if(!nativeTested) { + nativeTested = true; + nativeAvailable = GetFeatureStatus(FeatureType_Native, "IdentityFix_SetPlayerModel") == FeatureStatus_Available; + } + if(nativeAvailable) { + int result = IdentityFix_SetPlayerModel(client, view_as(character)); + return result == 0; + }else{ + return false; + } +} + diff --git a/scripting/include/left4dhooks.inc b/scripting/include/left4dhooks.inc new file mode 100644 index 0000000..a2d1963 --- /dev/null +++ b/scripting/include/left4dhooks.inc @@ -0,0 +1,2793 @@ +/** + * vim set ts=4 + * ============================================================================= + * + * Left 4 Downtown 2 SourceMod Extension + * Copyright (C) 2010 Michael "ProdigySim" Busby + * + * Left 4 Downtown SourceMod Extension + * Copyright (C) 2009 Igor "Downtown1" Smirnov. + * + * Left 4 Downtown 2 Extension updates + * Copyright (C) 2012-2015 "Visor" + * + * Left 4 Downtown 2 Extension updates + * Copyright (C) 2015 "Attano" + * + * Left 4 Downtown 2 Extension updates + * Copyright (C) 2017 "Accelerator74" + * + * Left 4 DHooks SourceMod plugin + * Copyright (C) 2020 "SilverShot" / "Silvers" + * + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version $Id$ + */ + +#if defined _l4dh_included + #endinput +#endif +#define _l4dh_included + + + +public SharedPlugin __pl_l4dh = +{ + name = "left4dhooks", + file = "left4dhooks.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_l4dh_SetNTVOptional() +{ + // ========================= + // Silvers Natives + // ========================= + MarkNativeAsOptional("AnimHookEnable"); + MarkNativeAsOptional("AnimHookDisable"); + MarkNativeAsOptional("AnimGetActivity"); + MarkNativeAsOptional("AnimGetFromActivity"); + + MarkNativeAsOptional("L4D_Deafen"); + MarkNativeAsOptional("L4D_Dissolve"); + MarkNativeAsOptional("L4D_OnITExpired"); + MarkNativeAsOptional("L4D_AngularVelocity"); + MarkNativeAsOptional("L4D_GetRandomPZSpawnPosition"); + MarkNativeAsOptional("L4D_GetNearestNavArea"); + MarkNativeAsOptional("L4D_FindRandomSpot"); + MarkNativeAsOptional("L4D_HasAnySurvivorLeftSafeArea"); + MarkNativeAsOptional("L4D_IsAnySurvivorInStartArea"); + MarkNativeAsOptional("L4D_IsAnySurvivorInCheckpoint"); + MarkNativeAsOptional("L4D_IsInFirstCheckpoint"); + MarkNativeAsOptional("L4D_IsInLastCheckpoint"); + MarkNativeAsOptional("L4D2_IsReachable"); + MarkNativeAsOptional("L4D_PipeBombPrj"); + + MarkNativeAsOptional("L4D2_GetVScriptOutput"); + MarkNativeAsOptional("L4D2_SpitterPrj"); + MarkNativeAsOptional("L4D2_GetCurrentFinaleStage"); + MarkNativeAsOptional("L4D2_ForceNextStage"); + MarkNativeAsOptional("L4D2_IsTankInPlay"); + MarkNativeAsOptional("L4D2_GetFurthestSurvivorFlow"); + MarkNativeAsOptional("L4D2_GetScriptValueInt"); + + + + // ========================= + // left4downtown.inc + // ========================= + MarkNativeAsOptional("L4D_RestartScenarioFromVote"); + MarkNativeAsOptional("L4D_IsFirstMapInScenario"); + MarkNativeAsOptional("L4D_IsMissionFinalMap"); + MarkNativeAsOptional("L4D_NotifyNetworkStateChanged"); + MarkNativeAsOptional("L4D_StaggerPlayer"); + MarkNativeAsOptional("L4D2_SendInRescueVehicle"); + MarkNativeAsOptional("L4D_ReplaceTank"); + MarkNativeAsOptional("L4D2_SpawnTank"); + MarkNativeAsOptional("L4D2_SpawnSpecial"); + MarkNativeAsOptional("L4D2_SpawnWitch"); + MarkNativeAsOptional("L4D2_GetTankCount"); + MarkNativeAsOptional("L4D2_GetWitchCount"); + + MarkNativeAsOptional("L4D_ScavengeBeginRoundSetupTime"); + MarkNativeAsOptional("L4D_ResetMobTimer"); + MarkNativeAsOptional("L4D_GetPlayerSpawnTime"); + MarkNativeAsOptional("L4D_GetVersusMaxCompletionScore"); + MarkNativeAsOptional("L4D_SetVersusMaxCompletionScore"); + MarkNativeAsOptional("L4D_GetTeamScore"); + MarkNativeAsOptional("L4D_GetMobSpawnTimerRemaining"); + MarkNativeAsOptional("L4D_GetMobSpawnTimerDuration"); + MarkNativeAsOptional("L4D2_ChangeFinaleStage"); + MarkNativeAsOptional("L4D2_SpawnWitchBride"); + + // l4d2weapons.inc + MarkNativeAsOptional("L4D2_IsValidWeapon"); + MarkNativeAsOptional("L4D2_GetIntWeaponAttribute"); + MarkNativeAsOptional("L4D2_GetFloatWeaponAttribute"); + MarkNativeAsOptional("L4D2_SetIntWeaponAttribute"); + MarkNativeAsOptional("L4D2_SetFloatWeaponAttribute"); + MarkNativeAsOptional("L4D2_GetMeleeWeaponIndex"); + MarkNativeAsOptional("L4D2_GetIntMeleeAttribute"); + MarkNativeAsOptional("L4D2_GetFloatMeleeAttribute"); + MarkNativeAsOptional("L4D2_GetBoolMeleeAttribute"); + MarkNativeAsOptional("L4D2_SetIntMeleeAttribute"); + MarkNativeAsOptional("L4D2_SetFloatMeleeAttribute"); + MarkNativeAsOptional("L4D2_SetBoolMeleeAttribute"); + + // l4d2timers.inc + MarkNativeAsOptional("L4D2_CTimerReset"); + MarkNativeAsOptional("L4D2_CTimerStart"); + MarkNativeAsOptional("L4D2_CTimerInvalidate"); + MarkNativeAsOptional("L4D2_CTimerHasStarted"); + MarkNativeAsOptional("L4D2_CTimerIsElapsed"); + MarkNativeAsOptional("L4D2_CTimerGetElapsedTime"); + MarkNativeAsOptional("L4D2_CTimerGetRemainingTime"); + MarkNativeAsOptional("L4D2_CTimerGetCountdownDuration"); + MarkNativeAsOptional("L4D2_ITimerStart"); + MarkNativeAsOptional("L4D2_ITimerInvalidate"); + MarkNativeAsOptional("L4D2_ITimerHasStarted"); + MarkNativeAsOptional("L4D2_ITimerGetElapsedTime"); + + // l4d2director.inc + MarkNativeAsOptional("L4D2_GetVersusCampaignScores"); + MarkNativeAsOptional("L4D2_SetVersusCampaignScores"); + MarkNativeAsOptional("L4D2_GetVersusTankFlowPercent"); + MarkNativeAsOptional("L4D2_SetVersusTankFlowPercent"); + MarkNativeAsOptional("L4D2_GetVersusWitchFlowPercent"); + MarkNativeAsOptional("L4D2_SetVersusWitchFlowPercent"); + + + + // ========================= + // l4d2_direct.inc + // ========================= + MarkNativeAsOptional("L4D2Direct_GetPendingMobCount"); + MarkNativeAsOptional("L4D2Direct_SetPendingMobCount"); + MarkNativeAsOptional("L4D2Direct_GetTankPassedCount"); + MarkNativeAsOptional("L4D2Direct_SetTankPassedCount"); + MarkNativeAsOptional("L4D2Direct_GetVSCampaignScore"); + MarkNativeAsOptional("L4D2Direct_SetVSCampaignScore"); + MarkNativeAsOptional("L4D2Direct_GetVSTankFlowPercent"); + MarkNativeAsOptional("L4D2Direct_SetVSTankFlowPercent"); + MarkNativeAsOptional("L4D2Direct_GetVSTankToSpawnThisRound"); + MarkNativeAsOptional("L4D2Direct_SetVSTankToSpawnThisRound"); + MarkNativeAsOptional("L4D2Direct_GetVSWitchFlowPercent"); + MarkNativeAsOptional("L4D2Direct_SetVSWitchFlowPercent"); + MarkNativeAsOptional("L4D2Direct_GetVSWitchToSpawnThisRound"); + MarkNativeAsOptional("L4D2Direct_SetVSWitchToSpawnThisRound"); + MarkNativeAsOptional("L4D2Direct_GetMapMaxFlowDistance"); + MarkNativeAsOptional("L4D2Direct_GetInvulnerabilityTimer"); + MarkNativeAsOptional("L4D2Direct_GetTankTickets"); + MarkNativeAsOptional("L4D2Direct_SetTankTickets"); + MarkNativeAsOptional("L4D2Direct_GetTerrorNavArea"); + MarkNativeAsOptional("L4D2Direct_GetTerrorNavAreaFlow"); + MarkNativeAsOptional("L4D2Direct_TryOfferingTankBot"); + MarkNativeAsOptional("L4D2Direct_GetFlowDistance"); + MarkNativeAsOptional("L4D2Direct_DoAnimationEvent"); + + MarkNativeAsOptional("L4D2Direct_GetTankCount"); + MarkNativeAsOptional("L4D2Direct_GetMobSpawnTimer"); + MarkNativeAsOptional("L4D2Direct_GetSIClassDeathTimer"); + MarkNativeAsOptional("L4D2Direct_GetSIClassSpawnTimer"); + MarkNativeAsOptional("L4D2Direct_GetVSStartTimer"); + MarkNativeAsOptional("L4D2Direct_GetScavengeRoundSetupTimer"); + MarkNativeAsOptional("L4D2Direct_GetScavengeOvertimeGraceTimer"); + MarkNativeAsOptional("L4D2Direct_GetSpawnTimer"); + MarkNativeAsOptional("L4D2Direct_GetShovePenalty"); + MarkNativeAsOptional("L4D2Direct_SetShovePenalty"); + MarkNativeAsOptional("L4D2Direct_GetNextShoveTime"); + MarkNativeAsOptional("L4D2Direct_SetNextShoveTime"); + MarkNativeAsOptional("L4D2Direct_GetPreIncapHealth"); + MarkNativeAsOptional("L4D2Direct_SetPreIncapHealth"); + MarkNativeAsOptional("L4D2Direct_GetPreIncapHealthBuffer"); + MarkNativeAsOptional("L4D2Direct_SetPreIncapHealthBuffer"); + MarkNativeAsOptional("L4D2Direct_GetInfernoMaxFlames"); + MarkNativeAsOptional("L4D2Direct_SetInfernoMaxFlames"); + MarkNativeAsOptional("L4D2Direct_GetScriptedEventManager"); + + // l4d2d_timers.inc + MarkNativeAsOptional("CTimer_Reset"); + MarkNativeAsOptional("CTimer_Start"); + MarkNativeAsOptional("CTimer_Invalidate"); + MarkNativeAsOptional("CTimer_HasStarted"); + MarkNativeAsOptional("CTimer_IsElapsed"); + MarkNativeAsOptional("CTimer_GetElapsedTime"); + MarkNativeAsOptional("CTimer_GetRemainingTime"); + MarkNativeAsOptional("CTimer_GetCountdownDuration"); + MarkNativeAsOptional("ITimer_Reset"); + MarkNativeAsOptional("ITimer_Start"); + MarkNativeAsOptional("ITimer_Invalidate"); + MarkNativeAsOptional("ITimer_HasStarted"); + MarkNativeAsOptional("ITimer_GetElapsedTime"); + + MarkNativeAsOptional("CTimer_GetDuration"); + MarkNativeAsOptional("CTimer_SetDuration"); + MarkNativeAsOptional("CTimer_GetTimestamp"); + MarkNativeAsOptional("CTimer_SetTimestamp"); + MarkNativeAsOptional("ITimer_GetTimestamp"); + MarkNativeAsOptional("ITimer_SetTimestamp"); + + + + // ========================= + // l4d2addresses.txt + // ========================= + MarkNativeAsOptional("L4D_CTerrorPlayer_OnVomitedUpon"); + MarkNativeAsOptional("L4D_CancelStagger"); + MarkNativeAsOptional("L4D_CreateRescuableSurvivors"); + MarkNativeAsOptional("L4D_ReviveSurvivor"); + MarkNativeAsOptional("L4D_GetHighestFlowSurvivor"); + MarkNativeAsOptional("L4D_GetInfectedFlowDistance"); + MarkNativeAsOptional("L4D_TakeOverZombieBot"); + MarkNativeAsOptional("L4D_ReplaceWithBot"); + MarkNativeAsOptional("L4D_CullZombie"); + MarkNativeAsOptional("L4D_SetClass"); + MarkNativeAsOptional("L4D_MaterializeFromGhost"); + MarkNativeAsOptional("L4D_BecomeGhost"); + MarkNativeAsOptional("L4D_State_Transition"); + MarkNativeAsOptional("L4D_RegisterForbiddenTarget"); + MarkNativeAsOptional("L4D_UnRegisterForbiddenTarget"); + + MarkNativeAsOptional("L4D2_CTerrorPlayer_OnHitByVomitJar"); + MarkNativeAsOptional("L4D2_Infected_OnHitByVomitJar"); + MarkNativeAsOptional("L4D2_CTerrorPlayer_Fling"); + MarkNativeAsOptional("L4D2_GetVersusCompletionPlayer"); + MarkNativeAsOptional("L4D2_SwapTeams"); + MarkNativeAsOptional("L4D2_AreTeamsFlipped"); + MarkNativeAsOptional("L4D2_StartRematchVote"); + MarkNativeAsOptional("L4D2_FullRestart"); + MarkNativeAsOptional("L4D2_HideVersusScoreboard"); + MarkNativeAsOptional("L4D2_HideScavengeScoreboard"); + MarkNativeAsOptional("L4D2_HideScoreboard"); +} +#endif + + + + + +// ==================================================================================================== +// ANIMATION HOOK +// ==================================================================================================== +typeset AnimHookCallback +{ + /** + * @brief Callback called whenever animation is invoked. + * + * @param client Client triggering. + * @param sequence The animation "activity" (pre-hook) or "m_nSequence" (post-hook) sequence number being used. + * + * @return Plugin_Changed to change animation, Plugin_Continue otherwise. + */ + function Action(int client, int &sequence); +} + +/** + * @brief Add a client animation hook. + * @remarks All hooks are removed on map change. + * + * @param client The client to hook + * @param callback Callback function for your pre-hook (uses "ACT_*" activity numbers) or INVALID_FUNCTION to not use. + * @param callbackPost Callback function for your post-hook (uses "m_nSequence" animation numbers) or INVALID_FUNCTION to not use. + * + * @return True on success, false if client invalid. + */ +native bool AnimHookEnable(int client, AnimHookCallback callback, AnimHookCallback callbackPost = INVALID_FUNCTION); + +/** + * @brief Remove a client animation hook. + * @remarks All hooks are removed on map change. + * + * @param client The client to hook + * @param callback Callback function for your pre-hook (uses "ACT_*" activity numbers) or INVALID_FUNCTION if not used. + * @param callbackPost Callback function for your post-hook (uses "m_nSequence" animation numbers) or INVALID_FUNCTION if not used. + * + * @return True on success, false if client invalid. + */ +native bool AnimHookDisable(int client, AnimHookCallback callback, AnimHookCallback callbackPost = INVALID_FUNCTION); + +/** + * @brief Retrieves the activity string from it's relative activity number. + * @remarks activity numbers are different from a models "m_nSequence" animation numbers. + * @remarks The ACT_* list and values are for Survivors and differ from other models. Use the "m_nSequence" value in a post hook for Special Infected. + * @remarks The "m_nSequence" values for each model can be found using Left4Dead Authoring Tools > Model Viewer. + * + * @param sequence Activity number to retrieve from + * @param activity Destination string to store the activity + * @param maxlength Size of destination string + * + * @return True on success, false on failure to find. + */ +native bool AnimGetActivity(int sequence, char[] activity, int maxlength); + +/** + * @brief Retrieves the animation activity number from an activity string. + * + * @param activity The activity string to retrieve from. + * + * @return Activity number or -1 on failure. + */ +native int AnimGetFromActivity(char[] activity); + + + + + +// ==================================================================================================== +// FORWARDS - left4downtown.inc +// ==================================================================================================== +/** + * @brief Called whenever ZombieManager::SpawnSpecial(ZombieClassType,Vector&,QAngle&) is invoked + * @remarks Only used for bot special spawns (not players) + * @remarks zombieClass: 1=Smoker, 2=Boomer, 3=Hunter, 4=Spitter, 5=Jockey, 6=Charger + * + * @param zombieClass Zombie class that will be spawned. + * @param vecPos Vector coordinate where special will be spawned + * @param vecAng QAngle where spcial will be facing + * + * @return Plugin_Handled to block special from spawning, + * Plugin_Changed to change the zombie class type to spawn, Plugin_Continue otherwise. + */ +forward Action L4D_OnSpawnSpecial(int &zombieClass, const float vecPos[3], const float vecAng[3]); + +/** + * @brief Called whenever ZombieManager::SpawnTank(Vector&,QAngle&) is invoked + * @remarks Not invoked if z_spawn tank is used and it gives a ghosted/dead player tank + * + * @param vecPos Vector coordinate where tank is spawned + * @param vecAng QAngle where tank will be facing + * + * @return Plugin_Handled to block tank from spawning, Plugin_Continue otherwise. + */ +forward Action L4D_OnSpawnTank(const float vecPos[3], const float vecAng[3]); + +/** + * @brief Called whenever ZombieManager::SpawnWitch(Vector&,QAngle&) is invoked + * @brief Called when a Witch spawns + * + * @param vecPos Vector coordinate where witch is spawned + * @param vecAng QAngle where witch will be facing + * + * @return Plugin_Handled to block witch from spawning, Plugin_Continue otherwise. + */ +forward Action L4D_OnSpawnWitch(const float vecPos[3], const float vecAng[3]); + +/** + * @brief Called whenever ZombieManager::SpawnWitchBride(Vector&,QAngle&) is invoked + * @brief Called when a Witch Bride spawns + * + * @param vecPos Vector coordinate where witch is spawned + * @param vecAng QAngle where witch will be facing + * + * @return Plugin_Handled to block witch from spawning, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D2_OnSpawnWitchBride(const float vecPos[3], const float vecAng[3]); + +/** + * @brief Called whenever CDirector::OnMobRushStart(void) is invoked + * @remarks called on random hordes, mini and finale hordes, and boomer hordes, causes Zombies to attack + * Not called on "z_spawn mob", hook the console command and check arguments to catch plugin mobs + * This function is used to reset the Director's natural horde timer. + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +forward Action L4D_OnMobRushStart(); + +/** + * @brief Called whenever ZombieManager::SpawnITMob(int) is invoked + * @remarks called on boomer hordes, increases Zombie Spawn Queue + * + * @param amount Amount of Zombies to add to Queue + * + * @return Plugin_Handled to block, Plugin_Changed to use overwritten values from plugin, Plugin_Continue otherwise + */ +forward Action L4D_OnSpawnITMob(int &amount); + +/** + * @brief Called whenever ZombieManager::SpawnMob(int) is invoked + * @remarks called on natural hordes & z_spawn mob, increases Zombie Spawn + * Queue, triggers player OnMobSpawned (vocalizations), sets horde + * direction, and plays horde music. + * + * @param amount Amount of Zombies to add to Queue + * + * @return Plugin_Handled to block, Plugin_Changed to use overwritten values from plugin, Plugin_Continue otherwise + */ +forward Action L4D_OnSpawnMob(int &amount); + +/** + * @brief Called whenever CTerrorPlayer::OnEnterGhostState(CTerrorPlayer*) is invoked + * @remarks This happens when a player enters ghost mode (or in finales auto-materialized) + * + * @param client the client that has entered ghost mode + */ +forward void L4D_OnEnterGhostState(int client); + +/** + * @brief Called whenever IsTeamFull is invoked. + * @remarks called when bots or players are joining a team + * + * @param team Which team is being checked. 2=Survivors. 3=Special Infected. + * + * @return Plugin_Handled to block changing team, Plugin_Continue otherwise. + */ +forward Action L4D_OnIsTeamFull(int team, bool &full); + +/** + * @brief Called whenever CTerrorGameRules::ClearTeamScores(bool) is invoked + * @remarks This resets the map score at the beginning of a map, and by checking + * the campaign scores on a small timer you can see if they were reset as well. + * + * @param newCampaign if true then this is a new campaign, if false a new chapter. Not used for L4D1. + * + * @return Plugin_Handled to block scores from being cleared, Plugin_Continue otherwise. Does not block reset in L4D1. + */ +forward Action L4D_OnClearTeamScores(bool newCampaign); + +/** + * @brief Called whenever CTerrorGameRules::SetCampaignScores(int,int) is invoked + * @remarks The campaign scores are updated after the 2nd round is completed + * + * @param scoreA score of logical team A + * @param scoreB score of logical team B + * + * @return Plugin_Handled to block campaign scores from being set, Plugin_Continue otherwise. + */ +forward Action L4D_OnSetCampaignScores(int &scoreA, int &scoreB); + +/** + * @brief Called whenever CDirector::OnFirstSurvivorLeftSafeArea is invoked + * @remarks A versus round is started when survivors leave the safe room, or force started + * after 90 seconds regardless. + * + * @param client the survivor that left the safe area first + * + * @return Plugin_Handled to block round from being started, Plugin_Continue otherwise. + */ +forward Action L4D_OnFirstSurvivorLeftSafeArea(int client); + +/** + * @brief Called whenever CTerrorPlayer::GetCrouchTopSpeed() is invoked + * @remarks Constantly called to get players max Crouch speed + * + * @param target the client that its being called on (not changible) + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +forward Action L4D_OnGetCrouchTopSpeed(int target, float &retVal); + +/** + * @brief Called whenever CTerrorPlayer::GetRunTopSpeed() is invoked + * @remarks Constantly called to get players max Run speed + * + * @param target the client that its being called on (not changible) + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +forward Action L4D_OnGetRunTopSpeed(int target, float &retVal); + +/** + * @brief Called whenever CTerrorPlayer::GetWalkTopSpeed() is invoked + * @remarks Constantly called to get players max Walk speed + * + * @param target the client that its being called on (not changible) + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +forward Action L4D_OnGetWalkTopSpeed(int target, float &retVal); + +/** + * @brief Called whenever CDirector::GetScriptValue(const char*, int) is invoked + * @remarks A script value is map specific + * + * @param key the script's key name + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D_OnGetScriptValueInt(const char[] key, int &retVal); + +/** + * @brief Called whenever CDirector::GetScriptValue(const char*, float) is invoked + * @remarks A script value is map specific + * + * @param key the script's key name + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D_OnGetScriptValueFloat(const char[] key, float &retVal); + +/** + * @brief Called whenever CDirector::GetScriptValue(const char*, const char*, char*, int) is invoked + * @remarks A script value is map specific + * + * @param key the script's key name + * @param defaultVal default key return, usually empty + * @param retVal returned string + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D_OnGetScriptValueString(const char[] key, const char[] defaultVal, char retVal[128]); + +/** + * @brief Called whenever CTerrorGameRules::HasConfigurableDifficultySetting() is invoked + * @remarks used to deny/allow difficulty changes in different game modes + * + * @param retVal what to override the return value with. 1 to allow difficulty configuration, 0 to deny. + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D_OnHasConfigurableDifficulty(int &retVal); + +/** + * @brief Called whenever CTerrorGameRules::GetSurvivorSet(void) is invoked + * @remarks Constantly called to get the survivor character set + * + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D_OnGetSurvivorSet(int &retVal); + +/** + * @brief Called whenever CTerrorGameRules::FastGetSurvivorSet(void) is invoked + * @remarks Constantly called to get the survivor character set + * + * @param retVal what to override the return value with + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +// L4D2 only. +forward Action L4D_OnFastGetSurvivorSet(int &retVal); + +/** + * @brief Called whenever CDirectorVersusMode::GetMissionVersusBossSpawning() is invoked + * @remarks Passed values are from the map's Mission Keyvalues. If those keyvalues don't exist, they are from cvar and other globals + * + * @param spawn_pos_min Minimum spawn position (percent of flow distance) for bosses + * @param spawn_pos_max Maximum spawn position (percent of flow distance) for bosses + * @param tank_chance Chance for a tank to spawn on this map + * @param witch_chance Chance for a witch to spawn on this map + * + * @return Plugin_Handled to block reading map data, Plugin_Changed to use overwritten values from plugin, Plugin_Continue to continue to read from mission data. + */ +forward Action L4D_OnGetMissionVSBossSpawning(float &spawn_pos_min, float &spawn_pos_max, float &tank_chance, float &witch_chance); + +/** + * @brief Called whenever ZombieManager::ReplaceTank(CTerrorPlayer *,CTerrorPlayer *) is invoked + * @remarks Not invoked if tank is bot + * + * @param tank the player who was a tank + * @param newtank a player who has become a new tank + */ +forward void L4D_OnReplaceTank(int tank, int newtank); + +/** + * @brief Called whenever CDirector::TryOfferingTankBot is invoked + * @remarks Is used for displaying the "X gets Tank" window and transferring Tank control + * + * @param tank_index Client index of the tank + * @param enterStasis Is the tank in stasis + * + * @return Plugin_Handled to block window from showing and to keep Tank Bot, Plugin_Changed to use overwritten values from plugin, Plugin_Continue otherwise + */ +forward Action L4D_OnTryOfferingTankBot(int tank_index, bool &enterStasis); + +/** + * @brief Called whenever CThrow::ActivateAbility(void) is invoked + * @remarks Called when a tank throws a rock. Blocking this call will keep the tank from throwing a rock + * + * @param ability ability_throw entity index + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +forward Action L4D_OnCThrowActivate(int ability); + +/** + * @brief Called when CBaseAnimating::SelectWeightedSequence(int Activity) is invoked with tank attack activity + * @remarks Called whenever a tank uses his primary (punch) or secondary (throw) attack (uses ACT_* activity numbers) + * + * This detour uses activity sequence numbers. + * + * @param client the client that is playing as tank + * @param sequence current selected activity for attack, option to override the return value with it + * + * L4D2: + * ACT_HULK_THROW 761 + * ACT_TANK_OVERHEAD_THROW 762 + * ACT_HULK_ATTACK_LOW 763 + * ACT_TERROR_ATTACK_MOVING 790 + * + * L4D1: + * ACT_HULK_THROW 1254 + * ACT_TANK_OVERHEAD_THROW 1255 + * ACT_HULK_ATTACK_LOW 1256 + * ACT_TERROR_ATTACK_MOVING 1282 + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +forward Action L4D2_OnSelectTankAttackPre(int client, int &sequence); + +/** + * @brief Called when CBaseAnimating::SelectWeightedSequence(int Activity) is invoked with tank attack activity + * @remarks Called whenever a tank uses his primary (punch) or secondary (throw) attack (uses m_nSequence animation numbers) + * + * This detour uses models m_nSequence numbers. + * + * @param client the client that is playing as tank + * @param sequence current selected activity for attack, option to override the return value with it + * + * @remarks sequences, for L4D1: + * @remarks sequences(punches) 38 (uppercut), 41 (right hook), 43 (left hook), 44 and 45 (pounding the ground) + * @remarks sequences(throws) 46 (undercut), 47 (1handed overhand), 48 (throw from the hip), 49 (2handed overhand) + * + * @remarks sequences, for L4D2: + * @remarks sequences(punches) 40 uppercut), 43 (right hook), 45 (left hook), 46 and 47 (pounding the ground) + * @remarks sequences(throws) 48 undercut), 49 (1handed overhand), 50 (throw from the hip), 51 (2handed overhand) + * + * @return Plugin_Handled to override return value, Plugin_Continue otherwise. + */ +forward Action L4D2_OnSelectTankAttack(int client, int &sequence); + +/** + * @brief Called whenever CTerrorMeleeWeapon::StartMeleeSwing(CTerrorPlayer *, bool) is invoked + * @remarks Called when a player uses his melee weapons primary attack. This is before the game + * reads the melee weapon data (model etc) and decides if he CAN attack at all. + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +// L4D2 only. +forward Action L4D_OnStartMeleeSwing(int client, bool boolean); + +/** + * @brief Called whenever CDirectorScriptedEventManager::SendInRescueVehicle(void) is invoked + * @remarks Called when the last Finale stage is reached and the Rescue means becomes 'available'. + * Take note this forward WILL fire upon using the native of the same function. + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +// 2020 Left4DHooks update: Blocked on L4D1/L4D2 Linux to prevent crashes. Waiting for DHooks update to support object returns. +forward Action L4D2_OnSendInRescueVehicle(); + +/** + * @brief Called whenever CDirectorScriptedEventManager::ChangeFinaleStage is invoked + * + * @param FinaleStageType integer value + * @remarks Called when the director stage changes + * @remarks some values for FinaleStageType: 1 - Finale Started; 6 - Rescue Vehicle Ready; 7 - Zombie Hordes; 8 - Tank; 10 - Combat Respite (nothing spawns) + * @remarks SendInRescueVehicle does not depend on Finale Stage being 6, that only signals endless Hordes/Tanks + * + * @return Plugin_Handled to block, Plugin_Changed to change finaleType, Plugin_Continue otherwise + */ +// L4D2 only. +forward Action L4D2_OnChangeFinaleStage(int &finaleType, const char[] arg); + +/** + * @brief Called whenever CDirectorVersusMode::EndVersusModeRound(bool) is invoked + * @remarks Called before score calculations and the scoreboard display + * + * @param countSurvivors True if the survival multiplier count needs to be nonzero. I guess. + * @remarks Not sure what bool does exactly yet. Just monitor it. If true, survivors will be counted for multiplier. If false, survival multiplier will be set to 0. + * @remarks A lot of Score calculations happen on this function, and the round-end scoreboard comes up doing this. Don't block unless you're sure you can reproduce this logic. + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +forward Action L4D2_OnEndVersusModeRound(bool countSurvivors); + +/** + * @brief Called after CDirectorVersusMode::EndVersusModeRound(bool) + * @remarks Called after all score calculations are complete and the scoreboard shows + * @remarks Called after all score calculations inside CDirectorVersusMode::EndVersusModeRound(bool). This good forward to replace standard "round_end" hook. + * + * @return noreturn + */ +forward void L4D2_OnEndVersusModeRound_Post(); + +/** + * @brief Called whenever CTerrorPlayer::OnLedgeGrabbed(CTerrorPlayer *this, const Vector *) is invoked + * @remarks Called when a player is about to grab a ledge + * + * @param client client grabbing the ledge + * + * @return Plugin_Handled to prevent grabbing, Plugin_Continue otherwise + */ +forward Action L4D_OnLedgeGrabbed(int client); + +/** + * @brief Called when CTerrorPlayer::OnRevived(void) is invoked + * @remarks Called post-revive so all data values are post-revive status. + * + * @param client the client that has been revived + * + * @noreturn + */ +forward void L4D2_OnRevived(int client); + +/** + * @brief Called whenever CTerrorPlayer::OnStaggered(CBaseEntity *, Vector const *) is invoked + * @remarks Source is always null for Charger impacts (Valve) + * + * @param target the client that is about to get staggered + * @param source the client that is about to stagger the target + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +forward Action L4D2_OnStagger(int target, int source); + +/** + * @brief Called whenever CTerrorPlayer::OnShovedBySurvivor(CTerrorPlayer, Vector&) is invoked + * @remarks L4D2 only uses this on Special Infected + * @remarks Blocks hunter dead stop + * + * @param client the client that did the shoving + * @param victim the client that was shoved (CAUTION retrieved from function pointer, don't meddle with it) + * @param vecDir Vector Angle of Shoveforce + * + * @return Plugin_Handled to block melee effect (staggering), Plugin_Continue otherwise. + */ +forward Action L4D_OnShovedBySurvivor(int client, int victim, const float vecDir[3]); + +/** + * @brief Called whenever CTerrorWeapon::OnHit(CGameTrace &, Vector const&, bool) is invoked + * @remarks Called for every single shovable and even some of the unshovable entities in the game + * + * @param client survivor who did the shoving + * @param entity entity that is about to get shoved + * @param weapon weapon that has been held while shoving + * @param vecDir stagger direction + * @param bIsHighPounce a boolean to determine if it was a pounce from a height or not; reliable to a certain degree and should only be considered for hunters + * @param bIsHighPounce sometimes reset to 0 when punched before the detour retrieves the information. + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +forward Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce); + +/** + * @brief Called whenever CTerrorPlayer::OnShovedByPounceLanding(CTerrorPlayer*) is invoked + * + * @param victim the survivor that is about to get stumbled as a result of "attacker" capping someone in close proximity + * @param attacker the SI that is about to cause a stumble as a result of capping someone in close proximity to a survivor + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +forward Action L4D2_OnPounceOrLeapStumble(int victim, int attacker); + +/** + * @brief Called whenever CInferno::Spread(Vector const&) is invoked (only for spitters -- ignores fire) + * + * @param spitter spitter that spat (:D) + * @param projectile spitter's projectile entity + * @param x x coordinate of the new acid puddle (can be overridden) + * @param y y coordinate of the new acid puddle (can be overridden) + * @param z z coordinate of the new acid puddle (can be overridden) + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +// 2020 Left4DHooks update: Works for Molotovs and Spitters. +// return Plugin_Handled to make small fire or goo puddle. +// x,y,z has no affect, is 0,0,0 for spitter, molotovs is area size or something. +forward Action L4D2_OnSpitSpread(int spitter, int projectile, float &x, float &y, float &z); + +/** + * @brief Called when SurvivorBot::UseHealingItems(Action *) is invoked + * @remarks Causes bots to use or give healing items (except in safe room on non-expert) + * + * @param client the client that will decide whether to use healing items + * + * @return Plugin_Handled to block, Plugin_Continue otherwise. + */ +// 2020 Left4DHooks update: Blocked on L4D1/L4D2 Linux to prevent crashes. Waiting for DHooks update to support object returns. +forward Action L4D2_OnUseHealingItems(int client); + +/** + * @brief Called after SurvivorBot::FindScavengeItem(Action *) is invoked + * @remarks Indicates which item the Survivor Bot will attempt to pick up + * + * @param client the client that will try to pick something up + * @param item the item the client will try to pick up (null means no item) + * + * @return Plugin_Handled to block, Plugin_Changed to overwrite item, Plugin_Continue otherwise. + */ +forward Action L4D2_OnFindScavengeItem(int client, int &item); + +/** + * @brief Called whenever BossZombiePlayer(CTerrorPlayer *, int, CBaseEntity *) is invoked + * @remarks Called when Special Infected are targeting a victim + * + * @param specialInfected the SI entity index + * @param curTarget the survivor player index who is chosen victim + * + * @return Plugin_Handled to block, Plugin_Changed to use overwritten values from plugin, Plugin_Continue otherwise + */ +forward Action L4D2_OnChooseVictim(int specialInfected, int &curTarget); + +/** + * @brief Called when the client's material system is expecting instructions from the server in regards to addons + * @remarks Doesn't fire if l4d2_addons_eclipse is -1 or 0 + * + * @param SteamID SteamID of the client expecting a matsys reply + * + * @return Plugin_Handled to let the client through with addons, Plugin_Continue otherwise. + */ + // L4D2 only. +forward Action L4D2_OnClientDisableAddons(const char[] SteamID); + +/** + * @brief Called whenever InfectedShoved::OnShoved(Infected *, CBaseEntity *) is invoked + * @remarks Called when common Infected are about to get shoved + * + * @return Plugin_Handled to block, Plugin_Continue otherwise + */ +#pragma deprecated This was never enabled +forward Action L4D_OnInfectedShoved(int infected, int entity); + +/** + * @brief Called whenever CBasePlayer::WaterMove() is invoked + * @remarks Couple it with a FL_INWATER check to be sure + * + * @param client the client that is moving in the water + * + * @noreturn + */ +#pragma deprecated Does not return water state. Use FL_INWATER instead. See Swimming plugin for L4D/2. +forward void L4D2_OnWaterMove(int client); + + + + + +// ==================================================================================================== +// FORWARDS - Silvers +// ==================================================================================================== +/** + * @brief Called whenever ZombieManager::GetRandomPZSpawnPosition is invoked + * @remarks Attempts to find a valid position to spawn Special Infected + * + * @param client Client id to find an area near this player + * @param zombieClass Special Infected class to search for a spawn position for + * @param attempts How many tries to find a valid location + * @param vecPos The vector location. Sometimes is 0,0,0. Use post hook for real selected position. + * + * @return Plugin_Changed to change any values, Plugin_Continue otherwise. + */ +#pragma deprecated Removed because it spawns specials at 0,0,0 when modifying any value. +forward Action L4D_OnGetRandomPZSpawnPosition(int &client, int &zombieClass, int &attempts, float vecPos[3]); + + + + + +// ==================================================================================================== +// NATIVES - Silvers +// ==================================================================================================== +/** +* @brief Runs a specified VScript code and returns values from it. +* @remarks Can execute several code blocks on a single line separating them with ; as standard coding practice. +* @remarks Can also execute several lines of code from SourcePawn, you must end the line with a backslash. +* @remarks Can return specific data by wrapping what you want to return within "" and "". +* @remarks See the test plugin for examples to all the above. +* +* @param code The VScript code to execute. Maximum length seems to be 1006 characters. +* @param buffer Buffer to copy return data to. You can use StringToInt or StringToFloat if required. +* @param maxlength Maximum size of the buffer. +* +* @return True on success, false otherwise. +* @error Invalid code or failed to create logic_script or possibly an empty string. +*/ +// L4D2 only. +native bool L4D2_GetVScriptOutput(char[] code, char[] buffer, int maxlength); + +/** + * @brief Deafens a player with a high pitch ringing sound for a few seconds + * @remarks Used in the "Prototype Grenades" plugin by Silvers + * + * @param client Client id of the player to deafen + * + * @noreturn + */ +native int L4D_Deafen(int client); + +/** + * @brief Creates the dissolve effect on common infected, players or objects + * @remarks You must handle the fading or killing of an entity as required + * @remarks Used in the "Dissolve Infected" plugin by Silvers + * + * @param entity The entity to dissolve. + * + * @return Entity index of the dissolver, which should automatically delete itself when the effect is done + */ +native int L4D_Dissolve(int entity); + +/** + * @brief Removes the boomer vomit effect from a player + * + * @param client Client id of the player to remove the effect from + * @param vecAng Angular velocity vector, director to spin the projectile + * + * @noreturn + */ +native void L4D_OnITExpired(int client); + +/** + * @brief Sets a physics entity angular velocity vector + * @remarks Spins an entity, for example used in "Throwable Melee Weapons" plugin by Silvers + * @remarks See the "left4dhooks_test" plugin for an example on spinning the entity top over or sideways + * + * @param entity The entity to spin. + * @param vecAng Angular velocity vector, director to spin the projectile + * + * @noreturn + */ +native int L4D_AngularVelocity(int entity, const float vecAng[3]); + +/** + * @brief Attempts to find a random valid position to spawn a Special Infected + * @remarks The zombieClass does not matter but different values yield different results: + * @remarks Using the Tank zombieClass probably searches for a larger area that's clear of objects + * + * @param client Client id to find an area near this player + * @param zombieClass Special Infected class to search for a spawn position for + * @param attempts How many tries to find a valid location + * @param vecPos The vector array to store the valid location on success + * + * @return True on success, false on failure to find valid location + */ +native bool L4D_GetRandomPZSpawnPosition(int client, int zombieClass, int attempts, float vecPos[3]); + +/** + * @brief Given a vector position, returns the relative NavArea. + * @remarks This is more reliable than L4D2Direct_GetTerrorNavArea. + * + * @param vecPos The vector array to use to retrieve the NavArea + * + * @return The NavArea value, or 0 on failure probably + */ +native int L4D_GetNearestNavArea(const float vecPos[3]); + +/** + * @brief Given a nav area value, returns a randomly selected position for spawning. + * @remarks This is what Witches use to spawn. + * + * @param NavArea The NavArea to search for a valid location + * @param vecPos The vector array to store the valid location on success + * + * @noreturn + */ +native void L4D_FindRandomSpot(int NavArea, float vecPos[3]); + +/** + * @brief Returns true when any survivor has left the starting area and true in Versus when the saferoom door automatically opens. + * + * @return True if a survivor has left the starting area. False otherwise. + */ +native bool L4D_HasAnySurvivorLeftSafeArea(); + +/** + * @brief Returns true when any survivor is in the starting checkpoint area. + * + * @return True if any survivor is in the starting checkpoint area. False otherwise. + */ +native bool L4D_IsAnySurvivorInStartArea(); + +/** + * @brief Returns true when any survivor is in the starting or ending checkpoint area. + * + * @return True if a survivor is in the starting or ending checkpoint area. False otherwise. + */ +native bool L4D_IsAnySurvivorInCheckpoint(); + +/** + * @brief Returns true when the specified Survivor or Special Infected is in the starting checkpoint area. + * + * @param client Client id to check their checkpoint. + * + * @return True if a survivor is in the starting checkpoint area. False otherwise. + */ +native bool L4D_IsInFirstCheckpoint(int client); + +/** + * @brief Returns true when the specified Survivor or Special Infected is in the ending checkpoint area. + * + * @param client Client id to check their checkpoint. + * + * @return True if a survivor is in the ending checkpoint area. False otherwise. + */ +native bool L4D_IsInLastCheckpoint(int client); + +/** + * @brief Checks if a world position is accessible to a player. + * @remarks You can pass any client index into this (real or fake players, survivors or special infected). + * @remarks If the clients flow distance is too far away from the position to test it will return false. + * + * @param client Client id to use for testing + * @param vecPos Vector coordinate to test + * + * @return True if accessible, false otherwise + */ +// L4D2 only. +native bool L4D2_IsReachable(int client, const float vecPos[3]); + +/** + * @brief Creates an activated PipeBomb projectile + * @remarks Does not attach the "Fuse" or "Light" particles, see the "left4dhooks_test" plugin for example on attaching these + * @remarks Also used in the "PipeBomb Shove" plugin by Silvers + * + * @param client Client id to attribute the projectile to for damage credit + * @param vecPos Vector coordinate of the projectile on creation + * @param vecAng Vector velocity and direction of the projectile + * + * @return Entity index of the projectile + */ +native int L4D_PipeBombPrj(int client, const float vecPos[3], const float vecAng[3]); + +/** + * @brief Creates a Spitter goo projectile + * + * @param client Client id to attribute the projectile to for damage credit + * @param vecPos Vector coordinate of the projectile on creation + * @param vecAng Vector velocity and direction of the projectile + * + * @return Entity index of the projectile + */ +// L4D2 only. +native int L4D2_SpitterPrj(int client, const float vecPos[3], const float vecAng[3]); + +/** + * @brief Returns the current Finale stage type. + * @remarks some values for FinaleStageType: 1 - Finale Started; 6 - Rescue Vehicle Ready; 7 - Zombie Hordes; 8 - Tank; 10 - Combat Respite (nothing spawns) + * @remarks Seems to return 18 for non-finale maps + * + * @return finaleType stage value + */ +// L4D2 only. +native int L4D2_GetCurrentFinaleStage(); + +/** + * @brief Forces the ScriptedMode stage to advance to the next stage. + * + * @noreturn + */ +// L4D2 only. +native void L4D2_ForceNextStage(); + +/** + * @brief Returns true when any tanks are on the map + * + * @return True when any tanks are on the map. False when no tanks. + */ +// L4D2 only. +native bool L4D2_IsTankInPlay(); + +/** + * @brief Gets the maximum flow distance any survivor has achieved. + * + * @return Returns the maximum flow distance any survivor has achieved. + */ +// L4D2 only. +native float L4D2_GetFurthestSurvivorFlow(); + +/** + * @brief Returns the value of the specified Director Variable key + * + * @param key Director variable key name to search for + * @param value Default value to use when the variable is not found + * + * @return Value of the variable, or provided default value on failure + */ +// L4D2 only. +native int L4D2_GetScriptValueInt(const char[] key, int value); + +// // Only returns default value provided. +// native float L4D2_GetScriptValueFloat(const char[] key, float value); + +// Not implemented, request if really required. +// native void L4D2_GetScriptValueString(const char[] key, const char[] value, char[] retValue, int maxlength); + + + + + +// ==================================================================================================== +// NATIVES - left4downtown.inc +// ==================================================================================================== +/** + * @brief Restarts the setup timer (when in scavenge mode) + * @remarks If game has already started, the setup timer will show, + * but it still won't go back into setup. + */ +// L4D2 only. +native int L4D_ScavengeBeginRoundSetupTime(); + +/** + * @brief Resets the natural mob (horde) timer + * @remarks Requires the Director to be available--map must be started + * + * @noreturn + */ +// L4D2 only. +native void L4D_ResetMobTimer(); + +/** + * @brief Get the remaining spawn time for an SI + * @remarks This is meant for Special infected in ghost mode in versus. + * + * @return Time (seconds) until the SI will spawn. + */ +// L4D2 only. +native float L4D_GetPlayerSpawnTime(int player); + +/** + * @brief Restarts the round, switching the map if necessary + * @remarks Set the map to the current map to restart the round + * + * @param map the mapname it should go to after the round restarts + * + * @return 1 always + */ +native int L4D_RestartScenarioFromVote(const char[] map); + +/** + * @brief Gets the max versus completion score for the map + * @remarks Requires GameRules to be initialized--map must be loaded + * Seems to be updated before OnMapStart + * + * @return The map's max completion distance (map distance score) + */ +// L4D2 only. +native int L4D_GetVersusMaxCompletionScore(); + +/** + * @brief Sets the max versus completion score for the map + * @remarks Requires GameRules to be initialized--map must be loaded + * Seems to be updated before OnMapStart and checked on round_start + * + * @param score The versus max completion score to set for the round + */ +// L4D2 only. +native int L4D_SetVersusMaxCompletionScore(int score); + +/** + * @brief Get the team scores for the current map + * @remarks The campaign scores are not set until the end of round 2, + * use L4D_GetCampaignScores to get them earlier. + * + * @deprecated This function can be called through SDKTools using CTerrorGameRules, + * and so you should switch off to using SDKTools instead of this native. + * + * @param logical_team 1 for A, 2 for B + * @param campaign_score true to get campaign score instead of map score + * + * @return the logical team's map score + * or -1 if the team hasn't played the round yet, + * or the team's campaign score if campaign_score = true + */ +// L4D2 only. +native int L4D_GetTeamScore(int logical_team, bool campaign_score=false); + +/** + * @brief Tells if the Mission (map) is the first map of the campaign + * + * @return true if the map is the first map of the campaign + */ +native bool L4D_IsFirstMapInScenario(); + +/** + * @brief Tells if the Mission (map) is the final map of the campaign + * + * @return true if the map is the last map of the campaign (finale) + */ +native bool L4D_IsMissionFinalMap(); + +/** + * @brief Notifies the CGameRulesProxy that the game state has been changed + * @remarks Use this function before changing networked members of GameRules, + * like with L4D_SetVersusMaxCompletionScore() + * + * @noreturn + */ +native void L4D_NotifyNetworkStateChanged(); + +/** + * @brief Trigger's a target player's stagger behavior + * @remarks Works on any CTerrorPlayer--survivor or infected. + * + * @param target Player to stagger + * @param source_ent Source of the stagger (another player, etc) + * @param vecSource Source location of the stagger. If NULL_VECTOR, origins of source_ent is used. + * @noreturn + */ +native void L4D_StaggerPlayer(int target, int source_ent, float vecSource[3]); + +/** + * @brief Calls CDirectorScriptedEventManager::SendInRescueVehicle(void) + * @remarks Calls in the rescue vehicle + * @remarks will fire the forward of the same function + * + * @noreturn + */ +native void L4D2_SendInRescueVehicle(); + +/** + * @brief Calls CDirectorScriptedEventManager::ChangeFinaleStage(CDirectorScriptedEventManager FinaleStageType,char const*) + * @remarks Changes the Finale stage + * @remarks some values for FinaleStageType: 1 - Finale Started; 6 - Rescue Vehicle Ready; 7 - Zombie Hordes; 8 - Tank; 10 - Combat Respite (nothing spawns) + * @remarks will fire the forward of the same function + * + * @param FinaleStageType integer value + * + * @noreturn + */ +// L4D2 only. +native void L4D2_ChangeFinaleStage(int finaleType, const char[] arg); + +/** + * @brief Calls ZombieManager::ReplaceTank(CTerrorPlayer *,CTerrorPlayer *) + * @remarks Replaces a players tank control with another player + * + * @param tank the player who was a tank + * @param newtank a player who will become a new tank + */ +native void L4D_ReplaceTank(int tank, int newtank); + +/** + * @brief Calls ZombieManager::SpawnTank(Vector&,QAngle&) + * + * @param vecPos Vector coordinate where the tank will be spawned + * @param vecAng QAngle where the tank will be facing + * + * @return Entity index of the spawned tank + */ +native int L4D2_SpawnTank(const float vecPos[3], const float vecAng[3]); + +/** + * @brief Calls ZombieManager::SpawnSpecial(ZombieClassType,Vector&,QAngle&) + * @remarks Only used for bot special spawns (not players) + * + * @param vecPos Vector coordinate where the SI will be spawned + * @param vecAng QAngle where the SI will be facing + * + * @return Entity index of the spawned SI + */ +native int L4D2_SpawnSpecial(int zombieClass, const float vecPos[3], const float vecAng[3]); + +/** + * @brief Calls ZombieManager::SpawnWitch(Vector&,QAngle&) + * + * @param vecPos Vector coordinate where the witch will be spawned + * @param vecAng QAngle where the witch will be facing + * + * @return Entity index of the spawned witch + */ +native int L4D2_SpawnWitch(const float vecPos[3], const float vecAng[3]); + +/** + * @brief Calls ZombieManager::SpawnWitchBride(Vector&,QAngle&) + * + * @param vecPos Vector coordinate where the witch bride will be spawned + * @param vecAng QAngle where the witch bride will be facing + * + * @return Entity index of the spawned witch bride + */ +// L4D2 only. +native int L4D2_SpawnWitchBride(const float vecPos[3], const float vecAng[3]); + +/** + * @brief Removes lobby reservation from a server + * @remarks Sets the reservation cookie to 0, + * it is safe to call this even if it's unreserved. + */ +native void L4D_LobbyUnreserve(); + +/** + * @brief Get the current campaign scores stored in the Director + * @remarks The campaign scores are updated after L4D_OnSetCampaignScores + * + * @deprecated This will set the scores to -1 for both sides on L4D2, + * this function is no longer supported. + * + * @param scoreA score of logical team A + * @param scoreB score of logical team B + * + * @return 1 always + */ +#pragma deprecated Use GetTeamScore and OnClearTeamScores instead +native int L4D_GetCampaignScores(int &scoreA, int &scoreB); + +/** + * @brief Checks if the server is currently reserved for a lobby + * @remarks Server is automatically unreserved if it hibernates or + * if all players leave. + * + * @deprecated This will always return false on L4D2 or on Linux. + * + * @return true if reserved, false if not reserved + */ +#pragma deprecated This will always return false on L4D2 or on Linux. +native bool L4D_LobbyIsReserved(); +/** + * @brief Get the time remaining before the next director horde. + * @remarks This timer is used for scripted event hordes and natural timed hordes + * + * @return Time remaining before next director horde + */ +#pragma deprecated Use L4D2_CTimerGetRemainingTime(L4D2CT_MobSpawnTimer) +native float L4D_GetMobSpawnTimerRemaining(); + +/** + * @brief Get the duration the horde timer was set to after the last horde + * @remarks This timer is used for scripted event hordes and natural timed hordes + * + * @return Total time from last horde to next horde. + */ +#pragma deprecated Use L4D2_CTimerGetCountdownDuration(L4D2CT_MobSpawnTimer) +native float L4D_GetMobSpawnTimerDuration(); + + + + + +// ==================================================================================================== +// NATIVES - l4d2director.inc +// ==================================================================================================== +/** + * @brief Gets the number of tanks currently in play. + * @remarks This value is tracked by the director, and should be a good + * indicator that a tank is in play + * + * @return Current Tank count + */ +native int L4D2_GetTankCount(); + +/** + * @brief Gets the number of witches currently in play. + * @remarks This value is tracked by the director, and should be a good + * indicator that a witch is in play + * + * @return Current Witch count + */ +native int L4D2_GetWitchCount(); + +/** + * @brief Gets the campaign scores stored in the Versus Director + * @remarks These are the actual values used for campaign scores--not proxies + * + * @param scores Array to store the campaign scores in + * @noreturn + */ +// L4D2 only. +native void L4D2_GetVersusCampaignScores(int scores[2]); + +/** + * @brief Sets the campaign scores stored in the Versus Director + * @remarks These are the actual values used for campaign scores--not proxies + * + * @param scores Array of campaign scores to set the director's values to. + * @noreturn + */ +// L4D2 only. +native void L4D2_SetVersusCampaignScores(const int scores[2]); + +/** + * @brief Gets the flow percent for tank spawns for both versus rounds. + * @remarks These values are checked against as the survivors move through the + * map. Once they are passed, the tank spawns. Note that this is flow + * as a percent of the map's flow, not flow distance. + * + * @param tankFlows Array to store the Tank Spawn Flow percents in director + * @noreturn + */ +// L4D2 only. +native void L4D2_GetVersusTankFlowPercent(float tankFlows[2]); + +/** + * @brief Sets the flow percent for tank spawns for both versus rounds. + * @remarks These values are checked against as the survivors move through the + * map. Once they are passed, the tank spawns. Note that this is flow + * as a percent of the map's flow, not flow distance. + * + * @param tankFlows Array of Tank Spawn Flow percents to store in director + * @noreturn + */ +// L4D2 only. +native void L4D2_SetVersusTankFlowPercent(const float tankFlows[2]); + +/** + * @brief Gets the flow percent for witch spawns for both versus rounds. + * @remarks These values are checked against as the survivors move through the + * map. Once they are passed, the witch spawns. Note that this is flow + * as a percent of the map's flow, not flow distance. + * + * @param witchFlows Array to store the Witch Spawn Flow percents in director + * @noreturn + */ +// L4D2 only. +native void L4D2_GetVersusWitchFlowPercent(float witchFlows[2]); + +/** + * @brief Sets the flow percent for witch spawns for both versus rounds. + * @remarks These values are checked against as the survivors move through the + * map. Once they are passed, the witch spawns. Note that this is flow + * as a percent of the map's flow, not flow distance. + * + * @param witchFlows Array of Witch Spawn Flow percents to store in director + * @noreturn + */ +// L4D2 only. +native void L4D2_SetVersusWitchFlowPercent(const float witchFlows[2]); + + + + + +// ==================================================================================================== +// NATIVES - l4d2timers.inc +// ==================================================================================================== +enum L4D2CountdownTimer +{ + L4D2CT_MobSpawnTimer, + L4D2CT_SmokerSpawnTimer, + L4D2CT_BoomerSpawnTimer, + L4D2CT_HunterSpawnTimer, + L4D2CT_SpitterSpawnTimer, + L4D2CT_JockeySpawnTimer, + L4D2CT_ChargerSpawnTimer, + L4D2CT_VersusStartTimer, + L4D2CT_UpdateMarkersTimer +}; + +enum L4D2IntervalTimer +{ + L4D2IT_SmokerDeathTimer, + L4D2IT_BoomerDeathTimer, + L4D2IT_HunterDeathTimer, + L4D2IT_SpitterDeathTimer, + L4D2IT_JockeyDeathTimer, + L4D2IT_ChargerDeathTimer +}; + + + +/************************************* + CountdownTimer Natives +***********************************/ +/** + * @brief Resets a given CountdownTimer (start again with same duration) + * @remarks Equivalent to Start(timer, GetCountdownDuration(timer)) + * + * @param timer CountdownTimer to reset + * @noreturn + */ +// L4D2 only. +native void L4D2_CTimerReset(L4D2CountdownTimer timer); + +/** + * @brief Starts a given CountdownTimer with a given duration + * @remarks This sets a new duration and sets up the end timestamp + * + * @param timer CountdownTimer to start + * @param duration Duration for the timer to use + * @noreturn + */ +// L4D2 only. +native void L4D2_CTimerStart(L4D2CountdownTimer timer, float duration); + +/** + * @brief Invalidates a given CountdownTimer (Timer essentially does not run) + * @remarks Sets the timestamp to -1.0f + * + * @param timer CountdownTimer to Invalidate + * @noreturn + */ +// L4D2 only. +native void L4D2_CTimerInvalidate(L4D2CountdownTimer timer); + +/** + * @brief Tells if a given CountdownTimer has started + * @remarks Checks to see if the end timestamp is greater than 0.0f + * + * @param timer CountdownTimer to check + * + * @return true if timer has started, false if timer is not started/invalid. + */ +// L4D2 only. +native bool L4D2_CTimerHasStarted(L4D2CountdownTimer timer); + +/** + * @brief Tells if a given CountdownTimer is elapsed + * @remarks If a timer is "up," e.g duration has passed since start, this returns true; + * + * @param timer CountdownTimer to check + * + * @return true if timer has elapsed or timer invalid/not started, false otherwise + */ +// L4D2 only. +native bool L4D2_CTimerIsElapsed(L4D2CountdownTimer timer); + +/** + * @brief Gets elapsed time of a given CountdownTimer, from the timed it was started + * @remarks Value is (Now() - timestamp) + duration + * + * @param timer CountdownTimer to get elapsed time of + * + * @return float amount of time since timer started + */ +// L4D2 only. +native float L4D2_CTimerGetElapsedTime(L4D2CountdownTimer timer); + +/** + * @brief Gets remaining time on a given CountdownTimer + * @remarks Value is (timestamp - Now()) + * + * @param timer CountdownTimer to get remaining time of + * + * @return float amount of time remaining on the timer + */ +// L4D2 only. +native float L4D2_CTimerGetRemainingTime(L4D2CountdownTimer timer); + +/** + * @brief Gets the duration of a given CountdownTimer + * @remarks Value is (timestamp > 0.0f ? duration 0.0f) + * + * @param timer CountdownTimer to get duration of + * + * @return 0.0 for invalid/not started timers, timer duration otherwise. + */ +// L4D2 only. +native float L4D2_CTimerGetCountdownDuration(L4D2CountdownTimer timer); + + + +/************************************* + IntervalTimer Natives +***********************************/ + +/** + * @brief Starts a given IntervalTimer + * @remarks Just sets timestamp = Now(), so counting starts from now + * + * @param timer IntervalTimer to start + * + * @noreturn + */ +// L4D2 only. +native void L4D2_ITimerStart(L4D2IntervalTimer timer); + +/** + * @brief Invalidates a given IntervalTimer + * @remarks Just sets timestamp = -1.0f + * + * @param timer IntervalTimer to Invalidate + * @noreturn + */ +// L4D2 only. +native void L4D2_ITimerInvalidate(L4D2IntervalTimer timer); + +/** + * @brief Tells whether a given IntervalTimer has started + * @remarks Checks to see if timestamp > 0.0f + * + * @param timer IntervalTimer to check + * + * @return true if timer is started, false if it is invalid/not started + */ +// L4D2 only. +native bool L4D2_ITimerHasStarted(L4D2IntervalTimer timer); + +/** + * @brief Gets the elapsed time of a given IntervalTimer + * @remarks Value is Now() - Timestamp + * + * @param timer IntervalTimer to get elapsed time of + * + * @return Elapsed time if timer started and valid, 99999.9f otherwise + */ +// L4D2 only. +native float L4D2_ITimerGetElapsedTime(L4D2IntervalTimer timer); + + + + + +// ==================================================================================================== +// NATIVES - l4d2weapons.inc +// ==================================================================================================== +/* + * 2020 Update1: Use the "Info Editor" plugin by Silvers to edit the weapon scripts and increase clip size. + * 2020 Update2: Now works in Left4DHooks. Glitchy animation bug when reloading an already full weapon. + * Fix plugin coming soon. Maybe full plugin to modify maximum clip size with all fixes handled. + +A note regarding Clipsize: Any nonstandard value will NOT be in effect at weapon pickup, which means the client +has to reload once to achieve the modified value. To fix this, add a weapon pickup hook in your plugin (eg "player_use") +and use something like this with a small timer delay of 0.1 seconds or more (dont you love this engine). + + new weapon = GetPlayerWeaponSlot(client, 0); + if (weapon == INVALID_ENT_REFERENCE) return; + char class[56]; + GetEdictClassname(weapon, class, sizeof(class)); + SetEntProp(weapon, Prop_Send, "m_iClip1", L4D2_GetIntWeaponAttribute(class, L4D2IWA_ClipSize)); +*/ +enum L4D2IntWeaponAttributes +{ + L4D2IWA_Damage, + L4D2IWA_Bullets, + L4D2IWA_ClipSize, + MAX_SIZE_L4D2IntWeaponAttributes +}; + +enum L4D2FloatWeaponAttributes +{ + L4D2FWA_MaxPlayerSpeed, + L4D2FWA_SpreadPerShot, + L4D2FWA_MaxSpread, + L4D2FWA_SpreadDecay, + L4D2FWA_MinDuckingSpread, + L4D2FWA_MinStandingSpread, + L4D2FWA_MinInAirSpread, + L4D2FWA_MaxMovementSpread, + L4D2FWA_PenetrationNumLayers, + L4D2FWA_PenetrationPower, + L4D2FWA_PenetrationMaxDist, + L4D2FWA_CharPenetrationMaxDist, + L4D2FWA_Range, + L4D2FWA_RangeModifier, + L4D2FWA_CycleTime, + L4D2FWA_PelletScatterPitch, + L4D2FWA_PelletScatterYaw, + MAX_SIZE_L4D2FloatWeaponAttributes +}; + +enum L4D2BoolMeleeWeaponAttributes +{ + L4D2BMWA_Decapitates, + MAX_SIZE_L4D2BoolMeleeWeaponAttributes +}; + +enum L4D2IntMeleeWeaponAttributes +{ + L4D2IMWA_DamageFlags, + L4D2IMWA_RumbleEffect, + MAX_SIZE_L4D2IntMeleeWeaponAttributes +}; + +enum L4D2FloatMeleeWeaponAttributes +{ + L4D2FMWA_Damage, + L4D2FMWA_RefireDelay, + L4D2FMWA_WeaponIdleTime, + MAX_SIZE_L4D2FloatMeleeWeaponAttributes +}; + + + +/** + * @brief Checks for a given weapon string to exist in the WeaponInformationDatabase + * @remarks Throws an error if Database is unavailable + * + * @param weaponName Weapon to check up on + * + * @return True if weapon is found, false if not + */ +// L4D2 only. +native bool L4D2_IsValidWeapon(const char[] weaponName); + +/** + * @brief Read an int-typed attribute for a given weapon from the WeaponInformationDatabase + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * + * @return The value read. + */ +// L4D2 only. +native int L4D2_GetIntWeaponAttribute(const char[] weaponName, L4D2IntWeaponAttributes attr); + +/** + * @brief Read a float-typed attribute for a given weapon from the WeaponInformationDatabase + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * + * @return The value read. + */ +// L4D2 only. +native float L4D2_GetFloatWeaponAttribute(const char[] weaponName, L4D2FloatWeaponAttributes attr); + +/** + * @brief Set an int-typed attribute for a given weapon from the WeaponInformationDatabase to a given value + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * + * @noreturn + */ +// L4D2 only. +native void L4D2_SetIntWeaponAttribute(const char[] weaponName, L4D2IntWeaponAttributes attr, int value); + +/** + * @brief Set a float-typed attribute for a given weapon from the WeaponInformationDatabase to a given value + * @remarks Throws an error if the weapon is not found or the attribute is incorrect + * + * @param weaponName Weapon to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * + * @noreturn + */ +// L4D2 only. +native void L4D2_SetFloatWeaponAttribute(const char[] weaponName, L4D2FloatWeaponAttributes attr, float value); + + + +/** + * @brief Retrieve the index for a given melee weapon from the Melee Weapon Database. + * @remarks Index updated on OnMapStart - suggest using RequestFrame to find index. + * @remarks Index can change depending on available melee weapons each map. + * + * @param weaponName Weapon to lookup index id for + * + * @return The index id. Returns -1 if no match is found or melee unavailable. + */ +// L4D2 only. +native int L4D2_GetMeleeWeaponIndex(const char[] weaponName); + +/** + * @brief Read an int-typed attribute for a given id from the Melee Weapon Database + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * + * @return The value read. + */ +// L4D2 only. +native int L4D2_GetIntMeleeAttribute(int id, L4D2IntMeleeWeaponAttributes attr); + +/** + * @brief Read a float-typed attribute for a given id from the Melee Weapon Database + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * + * @return The value read. + */ +// L4D2 only. +native float L4D2_GetFloatMeleeAttribute(int id, L4D2FloatMeleeWeaponAttributes attr); + +/** + * @brief Read a bool-typed attribute for a given id from the Melee Weapon Database + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to read from the weapon's info struct + * + * @return The value read. + */ +// L4D2 only. +native bool L4D2_GetBoolMeleeAttribute(int id, L4D2BoolMeleeWeaponAttributes attr); + +/** + * @brief Set an int-typed attribute for a given id from the Melee Weapon Database to a given value + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * + * @noreturn + */ +// L4D2 only. +native void L4D2_SetIntMeleeAttribute(int id, L4D2IntMeleeWeaponAttributes attr, int value); + +/** + * @brief Set a float-typed attribute for a given id from the Melee Weapon Database to a given value + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * + * @noreturn + */ +// L4D2 only. +native void L4D2_SetFloatMeleeAttribute(int id, L4D2FloatMeleeWeaponAttributes attr, float value); + +/** + * @brief Set a bool-typed attribute for a given id from the Melee Weapon Database to a given value + * @remarks Throws an error if the id is not found or the attribute is incorrect + * + * @param id Melee id to lookup attribute for + * @param attr Attribute to alter in the weapon's info struct + * @param value Value to set the attribute to + * + * @noreturn + */ +// L4D2 only. +native void L4D2_SetBoolMeleeAttribute(int id, L4D2BoolMeleeWeaponAttributes attr, bool value); + + + + + +// ==================================================================================================== +// NATIVES - l4d2_direct.inc +// ==================================================================================================== +enum CountdownTimer +{ + CTimer_Null = 0 /**< Invalid Timer when lookup fails */ +}; + +enum IntervalTimer +{ + ITimer_Null = 0 /**< Invalid Timer when lookup fails */ +}; + + + +/* CDirector Variable access */ + +/** + * Get the current Tank count stored by the director. + * + * @note This should work on any gamemode, and is a good check to see if there is a tank in play + * + * @return The current number of tanks in play. + * @error Director address not found. + */ +// L4D2 only. +native int L4D2Direct_GetTankCount(); + +/** + * Returns the number of infected waiting to spawn + * + * @return Mob size + */ +native int L4D2Direct_GetPendingMobCount(); + +/** + * Sets the number of infected waiting to spawn + * + * @param count Mob size + * + * @noreturn + */ +native void L4D2Direct_SetPendingMobCount(int count); + +/** + * Get a reference to the CDirector natural mob spawn CountdownTimer + * @note This timer is used to control the spawning of natural hordes. + * @note This timer gets reset during unnatural hordes as well (boomer/car alarm hordes) + * @note Some scripted events will effectively "take over", by reducing the mob spawn time. + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. + */ +// L4D2 only. +native CountdownTimer L4D2Direct_GetMobSpawnTimer(); + +/** + * Get a reference to a IntervalTimer that counts up from the last death of a given SI class + * @note The main place I've seen these timers used is in the SI spawning algorithms (CDirector::UpdateSpecialSpawns) + * @note This timer gets checked against SI respawn interval for different gamemodes, some of which are cvar controlled (e.g. versus_special_respawn_interval) + * + * @param class SI Class to retrieve timer for + * + * @return IntervalTimer reference to the timer, or ITimer_Null on lookup failure or bad class. + */ +// L4D2 only. +native IntervalTimer L4D2Direct_GetSIClassDeathTimer(int class); + +/** + * Get a reference to a CountdownTimer that counts down from the last attempted director-controlled spawn of an SI + * @note The main place I've seen these timers used is in the SI spawning algorithms (CDirector::UpdateSpecialSpawns) + * @note This timer is hard-coded to use a duration of 20.0s. + * + * @param class SI Class to retrieve timer for + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure or bad class. + */ +// L4D2 only. +native CountdownTimer L4D2Direct_GetSIClassSpawnTimer(int class); + +/** + * Gets the number of times the tank has passed to a player. + * @note When this variable is >1 the tank will be replaced with a bot when the his frustration reaches 0. + * @note The initial pass from AI to a player counts as a pass. + * @note As this is global on the director weird things could potentially happen if more than one tank is alive at a time with z_frustration 1. + * + * @return The number of passes. + */ +native int L4D2Direct_GetTankPassedCount(); + +/** + * Sets the number of times the tank has passed to a player. + * @note When this variable is >1 the tank will be replaced with a bot when the his frustration reaches 0. + * @note The initial pass from AI to a player counts as a pass. + * @note As this is global on the director weird things could potentially happen if more than one tank is alive at a time with z_frustration 1. + * + * @param New number of passes value + * + * @noreturn + */ +native void L4D2Direct_SetTankPassedCount(int passes); + + + +/* CDirectorVersusMode Variable access */ + +/** + * Reads the director's stored campaign score for a given team. + * + * @note You can use the gamerules m_bAreTeamsFlipped property to figure out team numbers + * @note The campaign scores value is also stored in gamerules, however this is the "master" version. + * @note Campaign scores are only updated on round end, so this will not reflect current survivor distance score + * + * @param teamNumber Team number to read campaign score of, 0 or 1. + * + * @return Campaign score for the given team. + * @error Director or Versus Director address not found. + */ +native int L4D2Direct_GetVSCampaignScore(int teamNumber); + +/** + * Set the director's stored campaign score for a given team. + * + * @note You can use the gamerules m_bAreTeamsFlipped property to figure out team numbers + * @note The campaign scores value is also stored in gamerules, however this is the "master" version. + * @note Keep in mind the current survivor team's distance/bonus score will be added at the end of a round + * + * @param teamNumber Team number to set campaign score of, 0 or 1. + * @param score Score to set for the team + * + * @noreturn + * @error Director or Versus Director address not found. + */ +native void L4D2Direct_SetVSCampaignScore(int teamNumber, int score); + +/** + * Reads the tank flow percent for a given round for versus mode + * + * @note You should check GetVSTankToSpawnThisRound to find out if a tank is going to be spawned for this round. + * @note When the survivors reach this flow percent minus versus_boss_buffer converted to flow percent, a tank will spawn. + * + * @param roundNumber Round number to read tank spawn flow percent of + * + * @return Tank spawn flow percent for the given round + * @error Director or Versus Director address not found. + */ +native float L4D2Direct_GetVSTankFlowPercent(int roundNumber); + +/** + * Sets the tank flow percent for a given round for versus mode + * + * @note You should check GetVSTankToSpawnThisRound to find out if there is still a tank to spawn this round. + * @note When the survivors reach this flow percent minus versus_boss_buffer converted to flow percent, a tank will spawn. + * + * @param roundNumber Round number to set tank spawn flow percent of + * @param flow Floating point percent of flow distance. + * + * @noreturn + * @error Director or Versus Director address not found. + */ +native int L4D2Direct_SetVSTankFlowPercent(int roundNumber, float flow); + +/** + * Is there going to be a tank spawned during the given round + * + * @param roundNumber Round number to check for tank spawn on + * + * @return True if there is still a tank to spawn for the given round, false if it has already been spawned or will not spawn. + * @error Director or Versus Director address not found. + */ +native bool L4D2Direct_GetVSTankToSpawnThisRound(int roundNumber); + +/** + * Tell the director whether or not to spawn a(nother) flow distance-based tank for this round. + * @note If you set this to true after a flow-distance-based tank has been spawned, this can trigger another tank to be spawned based on flow distance + * + * @param roundNumber Round number to set a tank spawn on + * @param spawn Whether or not to spawn a flow-distance-based tank for this round. + * + * @noreturn + * @error Director or Versus Director address not found. + */ +native void L4D2Direct_SetVSTankToSpawnThisRound(int roundNumber, bool spawn); + +/** + * Reads the witch flow percent for a given round for versus mode + * + * @note You should check GetVSWitchToSpawnThisRound to find out if a witch is going to be spawned for this round. + * @note When the survivors reach this flow percent minus versus_boss_buffer converted to flow percent, a witch will spawn. + * + * @param roundNumber Round number to read witch spawn flow percent of + * + * @return Witch spawn flow percent for the given round + * @error Director or Versus Director address not found. + */ +native float L4D2Direct_GetVSWitchFlowPercent(int roundNumber); + +/** + * Sets the witch flow percent for a given round for versus mode + * + * @note You should check GetVSWitchToSpawnThisRound to find out if there is still a witch to spawn this round. + * @note When the survivors reach this flow percent minus versus_boss_buffer converted to flow percent, a witch will spawn. + * + * @param roundNumber Round number to set witch spawn flow percent of + * @param flow Floating point percent of flow distance. + * + * @noreturn + * @error Director or Versus Director address not found. + */ +native int L4D2Direct_SetVSWitchFlowPercent(int roundNumber, float flow); + +/** + * Is there going to be a witch spawned during the given round + * + * @param roundNumber Round number to check for witch spawn on + * + * @return True if there is still a witch to spawn for the given round, false if it has already been spawned or will not spawn. + * @error Director or Versus Director address not found. + */ +native bool L4D2Direct_GetVSWitchToSpawnThisRound(int roundNumber); + +/** + * Tell the director whether or not to spawn a(nother) flow distance-based witch for this round. + * @note If you set this to true after a flow-distance-based witch has been spawned, this can trigger another witch to be spawned based on flow distance + * + * @param roundNumber Round number to set a witch spawn on + * @param spawn Whether or not to spawn a flow-distance-based witch for this round. + * + * @noreturn + * @error Director or Versus Director address not found. + */ +native int L4D2Direct_SetVSWitchToSpawnThisRound(int roundNumber, bool spawn); + +/** + * Get a reference to the VersusStart CountdownTimer + * @note This timer controls when the saferoom door will open and PZ spawning is enabled + * @note The default duration for this timer is controlled by cvar: versus_force_start_time + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. + * @error Director address not found. + */ +// L4D2 only. +native CountdownTimer L4D2Direct_GetVSStartTimer(); + + + +/* CDirectorScavengeMode Variable access */ + +/** + * Get a reference to the Scavenge Round Setup CountdownTimer + * @note This timer controls when the scavenge "warmup" time ends and PZ/game timers start. + * @note The default duration for this timer is controlled by cvar: scavenge_round_setup_time + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. + * @error Director address not found. + */ +// L4D2 only. +native CountdownTimer L4D2Direct_GetScavengeRoundSetupTimer(); + +/** + * Get a reference to the Scavenge Overtime Grace CountdownTimer + * @note This timer keeps track of how long survivors have gone without holding a can during overtime. + * @note The default duration for this timer is controlled by cvar: scavenge_overtime_grace_time + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. + * @error Director address not found. + */ +// L4D2 only. +native CountdownTimer L4D2Direct_GetScavengeOvertimeGraceTimer(); + + + +/* TerrorNavMesh Variable access */ + +/** + * Get the max flow distance (in flow units) for the current map. + * @note The flow distance for each map is generated as it is loaded, and it can change slightly (a few hundred units) with each load. + * @note You can use this value to convert a flow distance to a flow percent, and vice versa. + * + * @return Max flow distance for the current loaded map. + * @error TerrorNavMesh address not found. + */ +native float L4D2Direct_GetMapMaxFlowDistance(); + + + +/* CTerrorPlayer Variable access */ + +/** + * Get a reference to a CountdownTimer that tracks when an SI player can next spawn. + * @note The duration of this timer is controlled by the cvars z_ghost_delay_min and z_ghost_delay_max. + * + * @param client Client id to get the spawn timer for + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. + * @error Invalid client. + */ +// L4D2 only. +native CountdownTimer L4D2Direct_GetSpawnTimer(int client); + +/** + * Get a reference to a CountdownTimer that tracks when an survivor player is invulnerable due to "godframes". + * + * @param client Client id to get the godframes timer for + * + * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. + * @error Invalid client. + */ +native CountdownTimer L4D2Direct_GetInvulnerabilityTimer(int client); + +/** + * Looks up the number of tickets a client has for entry into the tank lottery. + * @note The number of tickets you have is equal to your damage done as an SI and will still increase as you do damage with the Tank. + * @note When the tank is passed away from you your tickets are set back to zero. + * + * @param client Client id to get the tickets for + * + * @return Number of tickets. + * @error Invalid client. + */ +native int L4D2Direct_GetTankTickets(int client); + +/** + * Sets the number of tickets a player has for entry into the tank lottery. + * + * @param client Client id to set the tickets for + * @param tickets New value for the client's tank lottery tickets + * + * @noreturn + * @error Invalid client. + */ +native void L4D2Direct_SetTankTickets(int client, int tickets); + +/** + * Gets a client's shove penalty. + * @note The returned value will be between 0 and z_gun_swing_{vs,coop}_max_penalty. + * + * @param client Client id + * + * @return Shove penalty or -1 on error + */ +// L4D2 only. +native int L4D2Direct_GetShovePenalty(int client); + +/** + * Sets a client's shove penalty. + * @note The penalty should be set between 0 and z_gun_swing_{vs,coop}_max_penalty. + * + * @param client Client id + * @param penalty Shove penalty + * + * @noreturn + */ +// L4D2 only. +native void L4D2Direct_SetShovePenalty(int client, int penalty); + +/** + * Gets the time at which a survivor can perform his next +attack2. + * + * @param client Client id + * + * @return Time or 0.0 on error + */ +// L4D2 only. +native float L4D2Direct_GetNextShoveTime(int client); + +/** + * Sets the time at which a survivor can perform his next +attack2. + * + * @param client Client id + * @param time Game time + * + * @noreturn + */ +// L4D2 only. +native void L4D2Direct_SetNextShoveTime(int client, float time); + +/** + * Gets the health of the survivor from before they were incapacitated + * @note This may only apply to hanging players + * + * @param client Client id + * + * @return Real health before incapacitation + */ +// L4D2 only. +native int L4D2Direct_GetPreIncapHealth(int client); + +/** + * Sets the health of the survivor from before they were incapacitated + * @note This may only apply to hanging players + * + * @param client Client id + * @param health New pre-incap health + * + * @noreturn + */ +// L4D2 only. +native void L4D2Direct_SetPreIncapHealth(int client, int health); + +/** + * Gets the temporary health of the survivor from before they were incapacitated + * @note This may only apply to hanging players + * + * @param client Client id + * @return Temporary health before incapacitation + */ +// L4D2 only. +native int L4D2Direct_GetPreIncapHealthBuffer(int client); + +/** + * Sets the health of the survivor from before they were incapacitated + * @note This may only apply to hanging players + * + * @param client Client id + * @param health New pre-incap temporary health + * + * @noreturn + */ +// L4D2 only. +native void L4D2Direct_SetPreIncapHealthBuffer(int client, int health); + +/** + * Gets the maximum number of flames a CInferno is allowed to spawn. + * + * @param entity Entity id + * + * @return Number of flames or -1 on error + */ +// L4D2 only. +native int L4D2Direct_GetInfernoMaxFlames(int entity); + +/** + * Sets the maximum number of flames a CInferno is allowed to spawn. + * + * @param entity Entity id + * @param flames Number of flames + * + * @noreturn + */ +// L4D2 only. +native void L4D2Direct_SetInfernoMaxFlames(int entity, int flames); + +/** + * Returns the CDirectorScriptedEventManager address. + * This native replicates "L4D2_GetCDirectorScriptedEventManager" used by other plugins. + * + * @return Address pointer + */ +// L4D2 only. +native int L4D2Direct_GetScriptedEventManager(); + +/** + * Get the TerrorNavArea which holds a specific position. + * @note Some positions will not return a nav area (Address_Null). Notable examples are saferooms and small ledges like the guard rail at the start of c2m1_highway. + * @remarks This is less reliable than L4D_GetNearestNavArea. + * + * @param pos The position to find the containing nav area of + * @param beneathLimit + * + * @return Address to a TerrorNavArea or Address_Null + * @error Unable to prepare SDK call + */ +native Address L4D2Direct_GetTerrorNavArea(float pos[3], float beneathLimit = 120.0); + +/** + * Find the distance through the map (in flow units) that a TerrorNavArea is located. + * + * @param pTerrorNavArea Pointer to a TerrorNavArea + * + * @return The flow units through the map that the TerrorNavArea is located at. + * @error When passed an Address_Null + */ +native float L4D2Direct_GetTerrorNavAreaFlow(Address pTerrorNavArea); + +/** + * Force the director to pass the tank. + * + * @param client Client index of the tank + * @param bEnterStasis Should the tank be put in stasis + * + * @return False on error otherwise true + */ +native bool L4D2Direct_TryOfferingTankBot(int client, int bEnterStasis); + +/** + * Gets a player's distance in flow units. + * + * @param client Client ID + * + * @return 0.0 on error otherwise flow distance + */ +native float L4D2Direct_GetFlowDistance(int client); + +/** + * Plays the specified animation for a player + * @note The event argument is NOT the same as the sequence numbers found in the model viewer + * @note You can get the number for your animation by looking at the disasm for virtual calls to DoAnimationEvent + * + * @param client + * @param event PlayerAnimEvent_t + * + * @noreturn + */ +native void L4D2Direct_DoAnimationEvent(int client, int event); + + + +/* CountdownTimer funcs */ + +/** + * Reset a CountdownTimer to begin counting down again from now to its original duration + * + * @param timer CountdownTimer to reset + * + * @noreturn + */ +native void CTimer_Reset(CountdownTimer timer); + +/** + * Start a CountdownTimer from now for a given duration + * + * @param timer CountdownTimer to reset + * @param duration Duration for this CountdownTimer to use, in seconds + * + * @noreturn + */ +native void CTimer_Start(CountdownTimer timer, float duration); + +/** + * Invalidate a CountdownTimer, so it is considered not running + * + * @param timer CountdownTimer to Invalidate + * + * @noreturn + */ + +native void CTimer_Invalidate(CountdownTimer timer); + +/** + * Determine if a CountdownTimer has started counting down. + * + * @param timer CountdownTimer to check + * + * @return True if it has started running, False if it is not (Invalidated) + */ +native bool CTimer_HasStarted(CountdownTimer timer); + +/** + * Determine if a CountdownTimer is elapsed. + * + * @param timer CountdownTimer to check + * + * @return True if the timer's duration has passed since it started, false otherwise. + */ +native bool CTimer_IsElapsed(CountdownTimer timer); + +/** + * Check how long a CountdownTimer has been running + * + * @param timer CountdownTimer to check + * + * @return Time since the CountdownTimer was last Started or Reset, in seconds. + */ +native float CTimer_GetElapsedTime(CountdownTimer timer); + +/** + * Check how much time remains before a CountdownTimer is elapsed. + * + * @param timer CountdownTimer to check + * + * @return Time until the CountdownTimer is elapsed, in seconds. + */ +native float CTimer_GetRemainingTime(CountdownTimer timer); + +/** + * Get the countdown duration used for a CountdownTimer + * + * @param timer CountdownTimer to check + * + * @return Countdown duration in seconds if timer is running, or 0.0 if timer is invalidated (not running) + */ +native float CTimer_GetCountdownDuration(CountdownTimer timer); + +/* IntervalTimer funcs */ + +/** + * Reset an IntervalTimer to begin counting up again from now + * + * @param timer IntervalTimer to reset + * + * @noreturn + */ +native void ITimer_Reset(IntervalTimer timer); + +/** + * Start an IntervalTimer to begin counting up from now + * + * @note This is the same as reset for IntervalTimers... + * + * @param timer IntervalTimer to start + * + * @noreturn + */ +native void ITimer_Start(IntervalTimer timer); + +/** + * Invalidate an IntervalTimer, so it is considered not running + * + * @param timer IntervalTimer to Invalidate + * + * @noreturn + */ +native void ITimer_Invalidate(IntervalTimer timer); + +/** + * Check if an IntervalTimer has started + * + * @param timer IntervalTimer to check + * + * @return True if the IntervalTimer is running, false if it is Invalidated + */ +native bool ITimer_HasStarted(IntervalTimer timer); + +/** + * Get the elapsed time of an IntervalTimer + * + * @param timer IntervalTimer to check + * + * @return Elapsed time of the IntervalTimer in seconds if it has started, or 99999.9 ("infinite") if it is Invalidated + */ +native float ITimer_GetElapsedTime(IntervalTimer timer); + + + +/* Timer Internals */ + +/** + * Read duration variable in CTimer + * + * @param timer CountdownTimer to check + * + * @return CountdownTimer duration value + */ +native float CTimer_GetDuration(CountdownTimer timer); + +/** + * Set duration variable in CTimer + * + * @param timer CountdownTimer to check + * @param duration Duration to set + * + * @noreturn + */ +native void CTimer_SetDuration(CountdownTimer timer, float duration); + +/** + * Read timestamp variable in CTimer + * + * @param timer CountdownTimer to check + * + * @return CountdownTimer duration value + */ +native float CTimer_GetTimestamp(CountdownTimer timer); + +/** + * Set timestamp variable in CTimer + * + * @param timer CountdownTimer to check + * @param timestamp Timestamp to set + * + * @noreturn + */ +native void CTimer_SetTimestamp(CountdownTimer timer, float timestamp); + +/** + * Read timestamp variable in ITimer + * + * @param timer IntervalTimer to check + * + * @return IntervalTimer duration value + */ +native float ITimer_GetTimestamp(IntervalTimer timer); + +/** + * Set timestamp variable in ITimer + * + * @param timer IntervalTimer to check + * @param timestamp Timestamp to set + * + * @noreturn + */ +native void ITimer_SetTimestamp(IntervalTimer timer, float timestamp); + + + + + +// ==================================================================================================== +// NATIVES - l4d2addresses.txt +// ==================================================================================================== +/** + * @brief Creates the boomer vomit effect on Survivors or Special infected + * + * @param client Client ID of the person to affect + * @param attacker Client ID who caused the blindness, can be the same as client + * + * @noreturn + */ +native void L4D_CTerrorPlayer_OnVomitedUpon(int client, int attacker); + +/** + * @brief Creates the boomer vomit effect on Survivors or Special infected + * + * @param client Client ID of the person to affect + * @param attacker Client ID who caused the blindness, can be the same as client + * + * @noreturn + */ +// L4D2 only. +native void L4D2_CTerrorPlayer_OnHitByVomitJar(int client, int attacker); + +/** + * @brief Creates the boomer vomit effect on Common infected + * + * @param entity Entity ID of the common to affect + * @param attacker Client ID who caused the blindness, can be the same as client + * + * @noreturn + */ +// L4D2 only. +native void L4D2_Infected_OnHitByVomitJar(int entity, int attacker); + +/** + * @brief Flings a player to the ground, like they were hit by a Charger + * + * @param client Client ID of the person to affect + * @param attacker Client ID who caused the attack, can be the same as client + * @param vecDir Vector direction to throw the player + * + * @noreturn + */ +// L4D2 only. +native void L4D2_CTerrorPlayer_Fling(int client, int attacker, float vecDir[3]); + +/** + * @brief Cancels a player staggering + * + * @param client Client ID of the person to affect + * + * @noreturn + */ +native void L4D_CancelStagger(int client); + +/** + * @brief Spawns all dead survivors in rescuable rooms. + * @remarks L4D1: Any survivor must not be in the starting area for it to work. + * @remarks L4D2: Any survivor must have left the starting area for it to work, they can return and all be in the starting area. + * @remarks By default the game would spawn one per frame, but I've added a RequestFrame loop to spawn all dead. Request if you want a singular spawn native. + * + * @noreturn + */ +native void L4D_CreateRescuableSurvivors(); + +/** + * @brief Revives an incapacitated survivor, also from ledge hanging + * + * @param client Client ID of the person to affect + * + * @noreturn + */ +native void L4D_ReviveSurvivor(int client); + +/** + * @brief Retrieve a clients map flow progress percentage. Doesn't have to be Versus mode + * + * @param client Client ID of the person to affect + * + * @return Returns value from 0-100 + */ +// L4D2 only. +native int L4D2_GetVersusCompletionPlayer(int client); + +/** + * @brief Returns client who is furthest in flow + * + * @return Client ID of the player furthest ahead + */ +native int L4D_GetHighestFlowSurvivor(); + +/** + * @brief Retrieve the specified common infected map flow distance + * + * @param entity Common infected ID + * + * @return flow distance + */ +native float L4D_GetInfectedFlowDistance(int entity); + +/** + * @brief Takeover another special infected. + * @remarks L4D1: Due to some bug and a workaround, when spawning you'll hear another special infected sound other than your own type + * + * @param client Client ID of the special infected taking over + * @param target Client ID of the special infected losing control + * + * @noreturn + */ +native void L4D_TakeOverZombieBot(int client, int target); + +/** + * @brief Replaces the player with a bot + * @remarks Survivors: makes the player go into spectator mode and a bot takeover, like going idle + * @remarks Infected: basically spawns an identical bot in your position. The client is forced into ghost mode + * + * @param client Client ID of the player losing control + * + * @noreturn + */ +native void L4D_ReplaceWithBot(int client); + +/** + * @brief Kills the player. Teleports their view to a random survivor + * + * @param client Client ID of the player to kill. Not common infected + * + * @noreturn + */ +native void L4D_CullZombie(int client); + +/** + * @brief Sets a players zombie class, special infected can be alive and change! + * @remarks Valid values L4D1: 1-3. L4D2: 1-6 + * @remarks zombieClass: 1=Smoker, 2=Boomer, 3=Hunter, 4=Spitter, 5=Jockey, 6=Charger + * + * @param client Client ID of the player to kill. Not common infected + * @param zombieClass Zombie class number to change to + * + * @noreturn + */ +native void L4D_SetClass(int client, int zombieClass); + +/** + * @brief Spawns a special infected from ghost state. Returns the clients "m_customAbility" weapon, or -1 on error (possibly not a ghost) + * + * @param client Client ID of the player to materialize + * + * @return Clients "m_customAbility" weapon entity ID or -1 on error. + */ +native int L4D_MaterializeFromGhost(int client); + +/** + * @brief Turns an alive player into the ghost state + * + * @param client Client ID of the player to affect + * + * @return True on success, false on error or if already ghost state + */ +native bool L4D_BecomeGhost(int client); + +/** + * @brief Enter ghost/dead mode. Some state values may have different results. Unknown. + * @remarks 6 and 8 are commonly used by the game. + * + * @param client Client ID of the player to affect + * + * @noreturn + */ +native void L4D_State_Transition(int client, int state); + +/** + * @brief Swaps the teams in Versus + * @remarks Some survivors may spawn dead on swapping, seems to be random + * + * @noreturn + */ +// L4D2 only. +native void L4D2_SwapTeams(); + +/** + * @brief Returns if Versus team are flipped + * + * @return 0=Not flipped. 1=Flipped + */ +// L4D2 only. +native bool L4D2_AreTeamsFlipped(); + +/** + * @brief Starts a Versus rematch vote like end of game before credits roll + * @remarks Failing a successful vote players are kicked back to lobby + * + * @noreturn + */ +// L4D2 only. +native void L4D2_StartRematchVote(); + +/** + * @brief Seems to restart the chapter like "mp_restartgame". In Versus the teams flip. + * + * @noreturn + */ +// L4D2 only. +native void L4D2_FullRestart(); + +/** + * @brief Hides end of round scoreboard. + * + * @noreturn + */ +// L4D2 only. +native void L4D2_HideVersusScoreboard(); + +/** + * @brief Hides end of round scoreboard. + * + * @noreturn + */ +// L4D2 only. +native void L4D2_HideScavengeScoreboard(); + +/** + * @brief Hides end of round scoreboard. + * + * @noreturn + */ +// L4D2 only. +native void L4D2_HideScoreboard(); + +/** + * @brief NOT WORKING? Setup car alarm for object. Seems to have no affect. Only works on prop_breakable or prop_car_alarm? + * + * @return Some memory address (large value) or possibly ID if already registered (low value from 1+) + */ +native int L4D_RegisterForbiddenTarget(int entity); + +/** + * @brief NOT WORKING? Remove car alarm for object. Seems to have no affect. Only works on prop_breakable or prop_car_alarm? + * + * @return Some memory address (large value) or possibly ID if already registered (low value from 1+) + */ +native void L4D_UnRegisterForbiddenTarget(int entity); \ No newline at end of file diff --git a/scripting/include/multicolors.inc b/scripting/include/multicolors.inc new file mode 100644 index 0000000..e6612a7 --- /dev/null +++ b/scripting/include/multicolors.inc @@ -0,0 +1,460 @@ +#if defined _multicolors_included + #endinput +#endif +#define _multicolors_included + +#define MuCo_VERSION "2.1.2" + +#include +#include + +/* +* +* Credits: +* - Popoklopsi +* - Powerlord +* - exvel +* - Dr. McKay +* +* Based on stamm-colors +* - https://github.com/popoklopsi/Stamm/blob/master/include/stamm/stamm-colors.inc +* +*/ + + + +#define PREFIX_MAX_LENGTH 64 +#define PREFIX_SEPARATOR "{default} " + +/* Global var to check whether colors are fixed or not */ +static bool g_bCFixColors; + +static char g_sCPrefix[PREFIX_MAX_LENGTH]; + +/** + * Add a chat prefix before all chat msg + * + * @param sPrefix Prefix + */ +stock void CSetPrefix(const char[] sPrefix, any ...) { + if (!sPrefix[0]) { + return; + } + + SetGlobalTransTarget(LANG_SERVER); + VFormat(g_sCPrefix, sizeof(g_sCPrefix) - strlen(PREFIX_SEPARATOR), sPrefix, 2); + + // Add ending space + Format(g_sCPrefix, sizeof(g_sCPrefix), "%s%s", g_sCPrefix, PREFIX_SEPARATOR); +} + +/** + * Add a chat prefix before all chat msg + * + * @param sPrefix Prefix + */ +stock void CClearPrefix() { + g_sCPrefix[0] = '\0'; +} + +/** + * Writes a message to a client with the correct stock for the game. + * + * @param client Client index. + * @param message Message (formatting rules). + * + * @error If the client is not connected an error will be thrown. + */ +stock void CPrintToChat(int client, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_PrintToChat(client, "%s%s", g_sCPrefix, buffer); + } + else { + MC_PrintToChat(client, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules) + */ +stock void CPrintToChatAll(const char[] message, any ...) { + if (!g_bCFixColors) { + CFixColors(); + } + + char buffer[MAX_BUFFER_LENGTH]; + if (!IsSource2009()) { + for (int i = 1; i <= MaxClients; ++i) { + if (IsClientInGame(i) && !IsFakeClient(i) && !C_SkipList[i]) { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), message, 2); + + C_PrintToChat(i, "%s", buffer); + } + + C_SkipList[i] = false; + } + } + else { + MC_CheckTrie(); + + char buffer2[MAX_BUFFER_LENGTH]; + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || MC_SkipList[i]) { + MC_SkipList[i] = false; + continue; + } + + SetGlobalTransTarget(i); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 2); + + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(i, buffer2); + } + } +} + +/** + * Writes a message to all of a client's observers. + * + * @param target Client index. + * @param message Message (formatting rules). + */ +stock void CPrintToChatObservers(int target, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + for (int client = 1; client <= MaxClients; client++) { + if (IsClientInGame(client) && !IsPlayerAlive(client) && !IsFakeClient(client)) { + int observee = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + int ObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if (observee == target && (ObserverMode == 4 || ObserverMode == 5)) { + CPrintToChat(client, buffer); + } + } + } +} + +/** + * Writes a message to a client with the correct stock for the game. + * + * @param client Client index. + * @param author Author index. + * @param message Message (formatting rules). + * + * @error If the client is not connected an error will be thrown. + */ +stock void CPrintToChatEx(int client, int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_PrintToChatEx(client, author, "%s%s", g_sCPrefix, buffer); + } + else { + MC_PrintToChatEx(client, author, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Writes a message to all clients with the correct stock for the game. + * + * @param author Author index. + * @param message Message (formatting rules). + */ +stock void CPrintToChatAllEx(int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_PrintToChatAllEx(author, "%s%s", g_sCPrefix, buffer); + } + else { + MC_PrintToChatAllEx(author, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Writes a message to all of a client's observers with the correct + * game stock. + * + * @param target Client index. + * @param message Message (formatting rules). + */ +stock void CPrintToChatObserversEx(int target, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + for (int client = 1; client <= MaxClients; client++) { + if (IsClientInGame(client) && !IsPlayerAlive(client) && !IsFakeClient(client)) { + int observee = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + int ObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if (observee == target && (ObserverMode == 4 || ObserverMode == 5)) { + CPrintToChatEx(client, target, buffer); + } + } + } +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param message Message (formatting rules) + */ +stock void CReplyToCommand(int client, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ReplyToCommand(client, "%s%s", g_sCPrefix, buffer); + } + else { + MC_ReplyToCommand(client, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param author Client to use for {teamcolor} + * @param message Message (formatting rules) + */ +stock void CReplyToCommandEx(int client, int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ReplyToCommandEx(client, author, "%s%s", g_sCPrefix, buffer); + } + else { + MC_ReplyToCommandEx(client, author, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Remove all tags and print to server + * + * @param message Message (formatting rules) + */ +stock void CPrintToServer(const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + char prefixBuffer[PREFIX_MAX_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 2); + strcopy(prefixBuffer, sizeof(prefixBuffer), g_sCPrefix); + + if (!g_bCFixColors) { + CFixColors(); + } + + CRemoveTags(buffer, sizeof(buffer)); + CRemoveTags(prefixBuffer, sizeof(prefixBuffer)); + + PrintToServer("%s%s", prefixBuffer, buffer); +} + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * CShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * + * @error + */ +stock void CShowActivity(int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ShowActivity(author, "%s", buffer); + } + else { + MC_ShowActivity(author, "%s", buffer); + } +} + +/** + * Same as C_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * + * @error + */ +stock void CShowActivityEx(int author, const char[] tag, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ShowActivityEx(author, tag, "%s", buffer); + } + else { + MC_ShowActivityEx(author, tag, "%s", buffer); + } +} + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * + * @error + */ + stock void CShowActivity2(int author, const char[] tag, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ShowActivity2(author, tag, "%s", buffer); + } + else { + MC_ShowActivity2(author, tag, "%s", buffer); + } +} + +/** + * Replaces color tags in a string with color codes + * + * @param message String. + * @param maxlength Maximum length of the string buffer. + */ +stock void CFormatColor(char[] message, int maxlength, int author = -1) { + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + if (author == 0) { + author = -1; + } + + C_Format(message, maxlength, author); + } + else { + if (author == -1) { + author = 0; + } + + MC_ReplaceColorCodes(message, author, false, maxlength); + } +} + +/** + * Removes color tags from a message + * + * @param message Message to remove tags from + * @param maxlen Maximum buffer length + */ +stock void CRemoveTags(char[] message, int maxlen) { + if (!IsSource2009()) { + C_RemoveTags(message, maxlen); + } + else { + MC_RemoveTags(message, maxlen); + } +} + +/** + * Fixes missing Lightgreen color. + */ +stock void CFixColors() { + g_bCFixColors = true; + + // Replace lightgreen if not exists + if (!C_ColorAllowed(Color_Lightgreen)) { + if (C_ColorAllowed(Color_Lime)) { + C_ReplaceColor(Color_Lightgreen, Color_Lime); + } + else if (C_ColorAllowed(Color_Olive)) { + C_ReplaceColor(Color_Lightgreen, Color_Olive); + } + } +} + +stock bool IsSource2009() { + return (GetEngineVersion() == Engine_CSS + || GetEngineVersion() == Engine_HL2DM + || GetEngineVersion() == Engine_DODS + || GetEngineVersion() == Engine_TF2 + || GetEngineVersion() == Engine_SDK2013); +}