From de72c5da1d48c7ffed273554771e418e6acc2d9d Mon Sep 17 00:00:00 2001 From: Jackz Date: Thu, 23 Sep 2021 08:47:42 -0500 Subject: [PATCH] add some libs --- scripting/include/l4d2_behavior.inc | 337 ++++++++++++++++++ .../include/l4d2_behavior_components.inc | 70 ++++ scripting/include/left4dhooks.inc | 38 +- 3 files changed, 442 insertions(+), 3 deletions(-) create mode 100644 scripting/include/l4d2_behavior.inc create mode 100644 scripting/include/l4d2_behavior_components.inc diff --git a/scripting/include/l4d2_behavior.inc b/scripting/include/l4d2_behavior.inc new file mode 100644 index 0000000..a52134f --- /dev/null +++ b/scripting/include/l4d2_behavior.inc @@ -0,0 +1,337 @@ +#if defined _behavior_included + #endinput +#endif + +#define _behavior_included + +enum IAssignment +{ + WITCH_QUERY = 0, + INFECTED_QUERY, + SURVIVOR_QUERY, + SPECIAL_QUERY +}; + +//enum IBehaviorProperties: (+= 0x4) +enum IActionProperties +{ + m_behavior = 0x8, + m_parent = 0xC, + m_child = 0x10, + m_buriedUnderMe = 0x14, + m_coveringMe = 0x18, + m_type = 0x1C, + m_action = 0x20, + m_priority = 0x2C, + m_isStarted = 0x30, + m_isSuspended = 0x31 +}; + +enum ActionResultType +{ + CONTINUE, // continue executing this action next frame - nothing has changed + CHANGE_TO, // change actions next frame + SUSPEND_FOR, // put the current action on hold for the new action + DONE, // this action has finished, resume suspended action + SUSTAIN, // for use with event handlers - a way to say "It's important to keep doing what I'm doing" +}; + +enum EventResultPriorityType +{ + RESULT_NONE, // no result + RESULT_TRY, // use this result, or toss it out, either is ok + RESULT_IMPORTANT, // try extra-hard to use this result + RESULT_CRITICAL // this result must be used - emit an error if it can't be +}; + +enum BehaviorAction +{ + INVALID_ACTION +}; + +enum struct IActionResult +{ + ActionResultType m_type; + BehaviorAction m_action; + EventResultPriorityType m_priority; + + Address retn; + + void FromAddr (Address retn) + { + this.retn = retn; + + this.m_type = view_as(RDereference(retn, 0)); + this.m_action = view_as(RDereference(retn, 4)); + this.m_priority = view_as(RDereference(retn, 12)); + } + + void Init (ActionResultType typea, BehaviorAction action, EventResultPriorityType priority = RESULT_TRY) + { + this.m_type = typea; + this.m_action = action; + this.m_priority = priority; + } + + void Set (Address retn) + { + StoreToAddress(retn + view_as
(4), view_as(this.m_action), NumberType_Int32); + StoreToAddress(retn + view_as
(12), view_as(this.m_priority), NumberType_Int32); + + StoreToAddress(retn, view_as(this.m_type), NumberType_Int32); + } + + void ForAction (BehaviorAction action) + { + StoreToAddress(view_as
(action) + view_as
(view_as(m_action) + 4), view_as(this.m_action), NumberType_Int32); + StoreToAddress(view_as
(action) + view_as
(view_as(m_type) + 4), view_as(this.m_type), NumberType_Int32); + StoreToAddress(view_as
(action) + view_as
(view_as(m_priority) + 4), view_as(this.m_priority), NumberType_Int32); + } + + void ToAction (BehaviorAction action) + { + this.ForAction(action); + } + + void Apply () + { + this.Set(this.retn); + } + + void GetTypeName ( char[] buffer, int length ) + { + switch ( this.m_type ) + { + case CHANGE_TO: strcopy(buffer, length, "CHANGE_TO"); + case SUSPEND_FOR: strcopy(buffer, length, "SUSPEND_FOR"); + case DONE: strcopy(buffer, length, "DONE"); + case SUSTAIN: strcopy(buffer, length, "SUSTAIN"); + + default: strcopy(buffer, length, "CONTINUE"); + } + } +} + +enum struct IContext +{ + int survivor; + int special; + int witch; + int infected; +} + +static IContext context; + +methodmap Behavior +{ + public static Behavior ToBehavior(Address entity, IAssignment assign) + { + if ( !context.survivor ) + { + GameData data = new GameData("l4d2_behavior"); + + context.special = data.GetOffset("g_iSpecial"); + context.survivor = data.GetOffset("g_iSurvivor"); + context.witch = data.GetOffset("g_iWitch"); + context.infected = data.GetOffset("g_iInfected"); + + delete data; + } + + static const int byte[] = + { + 0, 0x1C + }; + + int offs; + + switch(assign) + { + case WITCH_QUERY: offs = context.witch; + case INFECTED_QUERY: offs = context.infected; + case SURVIVOR_QUERY: offs = context.survivor; + case SPECIAL_QUERY: offs = context.special; + } + + Address behavior = view_as
(offs) + entity; + + for (int i; i < sizeof byte; i++) + behavior = RDereference(behavior, byte[i]); + + return view_as(behavior); + } + + public Behavior (int entity, IAssignment assign) + { + return Behavior.ToBehavior(GetEntityAddress(entity), assign); + } + + property Address ToAddress + { + public get() + { + return view_as
(this); + } + } + + property Address AsAddress + { + public get() + { + return this.ToAddress; + } + } + + property bool Valid + { + public get() + { + return this.ToAddress != Address_Null; + } + } + + property BehaviorAction CurrentAction + { + public get() + { + return view_as(RDereference(this.AsAddress, view_as(m_behavior))); + } + } +} + +methodmap BehaviorAction < Behavior +{ + public Address GetProperty (IActionProperties propertie, NumberType type = NumberType_Int32) + { + return RDereference(this.ToAddress, view_as(propertie), type); + } + + public void SetProperty (IActionProperties propertie, any value, NumberType type = NumberType_Int32) + { + StoreToAddress(this.ToAddress, value, type); + } + + property BehaviorAction Next + { + public get() + { + return view_as(this.GetProperty(m_child)); + } + } + + property BehaviorAction Prev + { + public get() + { + return view_as(this.GetProperty(m_parent)); + } + } + + property BehaviorAction Under + { + public get() + { + return view_as(this.GetProperty(m_buriedUnderMe)); + } + } + + property BehaviorAction Above + { + public get() + { + return view_as(this.GetProperty(m_coveringMe)); + } + } + + property Behavior Contain + { + public get() + { + return view_as(this.GetProperty(m_behavior)); + } + } + + property BehaviorAction Last + { + public get() + { + BehaviorAction action = this; + + while ( action.Next.Valid ) + action = action.Next; + + return action; + } + } + + property BehaviorAction First + { + public get() + { + BehaviorAction action = this; + + while ( action.Prev.Valid ) + action = action.Prev; + + return action; + } + } + + public void SetAction (IActionResult result) + { + this.SetProperty(m_action, result.m_action); + this.SetProperty(m_priority, result.m_priority); + this.SetProperty(m_type, result.m_type); + } + + public void GetName(char[] destination, int length) + { + static Handle call; + + if ( !call ) + { + int idx = (context.special == 17176 ? 41 : 40); + + StartPrepSDKCall(SDKCall_Raw); + PrepSDKCall_SetVirtual(idx); + PrepSDKCall_SetReturnInfo(SDKType_String, SDKPass_Pointer); + call = EndPrepSDKCall(); + } + + SDKCall(call, this, destination, length); + } + + public void GetFullName(char[] destination, int length) + { + static Handle call; + + if ( !call ) + { + int idx = (context.special == 17176 ? 43 : 42); + + StartPrepSDKCall(SDKCall_Raw); + PrepSDKCall_SetVirtual(idx); + PrepSDKCall_SetReturnInfo(SDKType_String, SDKPass_Pointer); + call = EndPrepSDKCall(); + } + + SDKCall(call, this, destination, length); + } +} + +/** + * Allocates memory + * + * @param size allocation size in bytes + * @return allocation address + */ +native Address AllocateMemory (int size); + +/** + * Deallocates memory + * + * @param mem allocation address + */ +native void DeallocateMemory (Address mem); + +stock Address RDereference (Address ptr, int offset = 0, NumberType type = NumberType_Int32) { return view_as
(LoadFromAddress(ptr + view_as
(offset), type)); } \ No newline at end of file diff --git a/scripting/include/l4d2_behavior_components.inc b/scripting/include/l4d2_behavior_components.inc new file mode 100644 index 0000000..ffe064e --- /dev/null +++ b/scripting/include/l4d2_behavior_components.inc @@ -0,0 +1,70 @@ +#if defined _behavior_components_included + #endinput +#endif + +#define _behavior_components_included + +#define E9_LEN 5 + +enum struct IHookHandler +{ + bool hooked; + + int hooklen; + int memlen; + + int original[12]; + + Address func; + Address detouraddr; + Address allocate; + + DynamicDetour detour; + + void Hook (Address _func, int _hooklen, int _memlen, int offs = 0) + { + this.memlen = _memlen; + this.allocate = AllocateMemory(this.memlen + offs); + this.func = _func; + this.hooklen = _hooklen; + this.detouraddr = this.allocate + view_as
(this.memlen - E9_LEN - _hooklen + offs); + + int i; + + for (;i < this.memlen + offs; i++) + { + StoreToAddress(this.allocate + view_as
(i), 0x90, NumberType_Int8); + } + + for (i = 0; i < this.hooklen; i++) + { + this.original[i] = view_as(RDereference(this.func, i, NumberType_Int8)); + StoreToAddress(this.func + view_as
(i), 0x90, NumberType_Int8); + StoreToAddress(this.detouraddr + view_as
(i), this.original[i], NumberType_Int8); + } + + this.hooked = true; + } + + void Unhook() + { + if ( this.hooked ) + { + for (int i = 0; i < this.hooklen; i++) + { + StoreToAddress(this.func + view_as
(i), this.original[i], NumberType_Int8); + } + + DeallocateMemory(this.allocate); + this.hooked = false; + } + } +} + +/** + * Hooks action handler + * + * @param func event handler address + * @param out IHookHandler struct + */ +native void HookActionEvent (Address func, any[] out); \ No newline at end of file diff --git a/scripting/include/left4dhooks.inc b/scripting/include/left4dhooks.inc index d9ce3cb..a8224dd 100644 --- a/scripting/include/left4dhooks.inc +++ b/scripting/include/left4dhooks.inc @@ -75,6 +75,7 @@ public void __pl_l4dh_SetNTVOptional() MarkNativeAsOptional("AnimGetActivity"); MarkNativeAsOptional("AnimGetFromActivity"); + MarkNativeAsOptional("L4D_GetGameModeType"); MarkNativeAsOptional("L4D_Deafen"); MarkNativeAsOptional("L4D_Dissolve"); MarkNativeAsOptional("L4D_OnITExpired"); @@ -300,6 +301,20 @@ public void __pl_l4dh_SetNTVOptional() +// For the game mode native and forward. +enum +{ + GAMEMODE_UNKNOWN = 0, + GAMEMODE_COOP = 1, + GAMEMODE_VERSUS = 2, + GAMEMODE_SURVIVAL = 4, + GAMEMODE_SCAVENGE = 8 +} + + + + + // ==================================================================================================== // ACT_* ANIMATION VALUES // ==================================================================================================== @@ -5020,6 +5035,15 @@ forward void L4D2_OnWaterMove(int client); // ==================================================================================================== // FORWARDS - Silvers // ==================================================================================================== +/** + * @brief Returns the current game mode type when it changes. 0=Unknown or error. 1=Coop. 2=Survival. 4=Versus. 8=Scavenge (L4D2). + * @remarks You can use the "GAMEMODE_*" enums provided above to match the mode. + * @remarks Only triggers when the server starts and after when the game mode changes. + * + * @return Current game mode. + */ +forward Action L4D_OnGameModeChange(int gamemode); + /** * @brief Called whenever ZombieManager::GetRandomPZSpawnPosition is invoked * @remarks Attempts to find a valid position to spawn Special Infected @@ -5071,6 +5095,14 @@ native bool L4D2_ExecVScriptCode(char[] code); // L4D2 only. native bool L4D2_GetVScriptOutput(char[] code, char[] buffer, int maxlength); +/** + * @brief Returns the current game mode type. 0=Unknown or error. 1=Coop. 2=Survival. 4=Versus. 8=Scavenge (L4D2). + * @remarks You can use the "GAMEMODE_*" enums provided above to match the mode. + * + * @return Current game mode. + */ +native int L4D_GetGameModeType(); + /** * @brief Deafens a player with a high pitch ringing sound for a few seconds. * @remarks Used in the "Prototype Grenades" plugin by Silvers @@ -6002,7 +6034,7 @@ native float L4D2_ITimerGetElapsedTime(L4D2IntervalTimer timer); /* * 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. + * 2021 Update3: Fix plugin for modified ammo clips found here: https://forums.alliedmods.net/showthread.php?t=327105 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") @@ -6246,7 +6278,6 @@ enum IntervalTimer * @return The current number of tanks in play. * @error Director address not found. */ -// L4D2 only. native int L4D2Direct_GetTankCount(); /** @@ -6273,7 +6304,6 @@ native void L4D2Direct_SetPendingMobCount(int count); * * @return CountdownTimer reference to the timer, or CTimer_Null on lookup failure. */ -// L4D2 only. native CountdownTimer L4D2Direct_GetMobSpawnTimer(); /** @@ -6734,6 +6764,7 @@ native void L4D2Direct_DoAnimationEvent(int client, int event); * @param client Client id whose health bonus is to be returned. * @return Int value of the survivors health bonus. */ +// L4D1 only. native int L4DDirect_GetSurvivorHealthBonus(int client); /** @@ -6758,6 +6789,7 @@ native void L4DDirect_SetSurvivorHealthBonus(int client, int health, bool recomp * @return False on error otherwise true * @error SDK call preparation failed */ +// L4D1 only. native void L4DDirect_RecomputeTeamScores();