diff --git a/gamedata/randomizer.txt b/gamedata/randomizer.txt index e00bb45..b821185 100644 --- a/gamedata/randomizer.txt +++ b/gamedata/randomizer.txt @@ -4,51 +4,6 @@ { "Keys" { - "PatchReplace_01" //Demoman class check for eyelander health - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90" // Replace 'jnz short' to NOP (skip) - } - "PatchReplace_02" //Demoman class check for eyelander speed and charging - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90" // Replace 'jnz short' to NOP (skip) - } - "PatchReplace_03" //Medic class check for healing charging - { - "linux" "\x90\x90\x90\x90\x90\x90" // Replace 'jnz' to NOP (skip) - "windows" "\x90\x90\x90\x90\x90\x90" // Replace 'jz' (if '==' jump) to NOP (skip) - } - "PatchReplace_04" //Medic class check for Overdose speed - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90" // Replace 'jnz short' to NOP (skip) - } - "PatchReplace_05" //Heavy class check for steak speed - { - "linux" "\x90\x90\x90\x90\x90\x90" // Replace 'jz' (if '==' jump) to to NOP (skip) - "windows" "\xEB" // Replace 'jnz short' to 'jmp short' (always jump) - } - "PatchReplace_06" //Scout class check for Baby Face Blaster and Crit-A-Cola speed - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90" // Replace 'jnz short' to NOP (skip) - } - "PatchReplace_07" //Spy class check for Your Eternal Reward silent kill - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90" // Replace 'jnz short' to NOP (skip) - } - "PatchReplace_08" //Demoman class check for kill refilling meter - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90\x90\x90\x90\x90" // Replace 'jnz' to NOP (skip) - } - "PatchReplace_09" //Sniper class check for Hitman's Heatmaker rage on kill - { - "linux" "\x90\xE9" // Replace 'jz' (if '==' jump) to 'jmp' (always jump) - "windows" "\x90\x90" // Replace 'jnz short' to NOP (skip) - } "PatchReplace_IsPlayerClass" //Given class check, this patch makes it always return true { // \xB8\x01\x00\x00\x00 mov eax, 1 @@ -59,77 +14,24 @@ // \x90 nop "windows" "\xB8\x01\x00\x00\x00\x90" } - } - "Addresses" - { - "PatchSig_01" - { - "signature" "PatchSig_01" - "linux" - { - "offset" "95" - } - "windows" - { - "offset" "7" //Start is pushed back by 7 to make good unique sig - } - } - "PatchSig_02" - { - "signature" "PatchSig_02" - } - "PatchSig_03" - { - "signature" "PatchSig_03" - "linux" - { - "offset" "3" //Start is pushed back by 3 to make good unique sig - } - } - "PatchSig_04" - { - "signature" "PatchSig_04" - } - "PatchSig_05" - { - "signature" "PatchSig_05" - } - "PatchSig_06" - { - "signature" "PatchSig_06" - "linux" - { - "offset" "3" //Start is pushed back by 3 to make good unique sig - } - } - "PatchSig_07" + + "PatchSearch_Speed01" { - "signature" "PatchSig_07" - "linux" - { - "offset" "649" - } - "windows" - { - "offset" "4" //Start is pushed back by 4 to make good unique sig - } - } - "PatchSig_08" - { - "signature" "PatchSig_08" - "windows" - { - "offset" "4" //Start is pushed back by 4 to make good unique sig - } + "linux" "\x83\xFF\x2A\x0F" + "windows" "\x83\x7D\xEC\x2A" } - "PatchSig_09" + + "PatchSearch_Speed02" { - "signature" "PatchSig_09" - "linux" - { - "offset" "1890" - } + "windows" "\x83\xF8\x2A" } + + "PatchCount_Speed" "6" // How many patches we should expect from searches, errors out if found different amount of it + "PatchBits_Speed" "1800" // How many bits to read from start to function to collect address + "PatchWildcard_Speed" "\x01\x04\x05\x06" // List of possible values from \x2A wildcard to consider it valid and replace it + } + "Addresses" + { "PatchSig_IsPlayerClass" { "signature" "PatchSig_IsPlayerClass" @@ -145,51 +47,6 @@ } "Signatures" { - "PatchSig_01" //CTFPlayer::GetMaxHealthForBuffing - { - "linux" "@_ZN9CTFPlayer22GetMaxHealthForBuffingEv" - "windows" "\x83\xBF\x2A\x2A\x2A\x2A\x04\x75\x2A\x6A\x00" - } - "PatchSig_02" //CTFPlayer::TeamFortress_CalculateMaxSpeed - { - "linux" "\x0F\x84\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x80\xB8\x2A\x0C\x00\x00\x00\x75\x2A\x80\xBB\x2A\x1E\x00\x00\x00" - "windows" "\x75\x2A\x6A\x00\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\x6A\x40\x8B\xCE" - } - "PatchSig_03" //CTFPlayer::TeamFortress_CalculateMaxSpeed - { - "linux" "\x83\xFF\x05\x0F\x85\x2A\x2A\x2A\x2A" - "windows" "\x0F\x85\x2A\x2A\x2A\x2A\x85\xDB\x0F\x84\x2A\x2A\x2A\x2A\x6A\x00" - } - "PatchSig_04" //CTFPlayer::TeamFortress_CalculateMaxSpeed - { - "linux" "\x0F\x84\x2A\x2A\x2A\x2A\x83\xEC\x0C\x6A\x01\x6A\x00\xFF\x75\xD8" - "windows" "\x75\x2A\x6A\x00\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\x6A\x32" - } - "PatchSig_05" //CTFPlayer::TeamFortress_CalculateMaxSpeed - { - "linux" "\x0F\x84\x2A\x2A\x2A\x2A\x83\xFF\x01\x0F\x84\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x85\xC0" - "windows" "\x75\x2A\xF3\x0F\x10\x45\xE8\x8B\xCF" - } - "PatchSig_06" //CTFPlayer::TeamFortress_CalculateMaxSpeed - { - "linux" "\x83\xFF\x01\x0F\x84\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x85\xC0" - "windows" "\x75\x2A\x6A\x55\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x85\xC0" - } - "PatchSig_07" //CTFPlayer::Event_KilledOther - { - "linux" "@_ZN9CTFPlayer17Event_KilledOtherEP11CBaseEntityRK15CTakeDamageInfo" - "windows" "\x83\x78\x04\x08\x75\x2A\x56" - } - "PatchSig_08" //CTFPlayer::Event_KilledOther - { - "linux" "\x0F\x84\x2A\x2A\x2A\x2A\x83\xF8\x02\x0F\x84\x2A\x2A\x2A\x2A\x8B\x83\x2A\x2A\x2A\x2A" - "windows" "\x83\x78\x04\x04\x0F\x85\x2A\x2A\x2A\x2A" - } - "PatchSig_09" //CTFPlayer::Event_KilledOther - { - "linux" "@_ZN9CTFPlayer17Event_KilledOtherEP11CBaseEntityRK15CTakeDamageInfo" - "windows" "\x75\x2A\xD9\xEE\x6A\x01\x6A\x00\x53" - } "PatchSig_IsPlayerClass" //CTFPlayer::IsPlayerClass { "linux" "@_ZNK9CTFPlayer13IsPlayerClassEi" @@ -388,6 +245,11 @@ "linux" "69" "windows" "68" } + "CBaseEntity::Event_KilledOther" + { + "linux" "70" + "windows" "69" + } "CBaseEntity::GetMaxHealth" { "linux" "123" @@ -418,6 +280,16 @@ "linux" "486" "windows" "479" } + "CTFSword::GetSwordSpeedMod" + { + "linux" "492" + "windows" "484" + } + "CTFSword::GetSwordHealthMod" + { + "linux" "493" + "windows" "485" + } "CBaseObject::Killed" { "linux" "356" @@ -433,6 +305,11 @@ "linux" "337" "windows" "336" } + "CBasePlayer::ClientCommand" + { + "linux" "380" + "windows" "379" + } "CBasePlayer::EquipWearable" { "linux" "439" @@ -448,10 +325,10 @@ "linux" "277" "windows" "276" } - "CTFPlayer::ClientCommand" + "CBaseMultiplayerPlayer::SpeakConceptIfAllowed" { - "linux" "380" - "windows" "379" + "linux" "473" + "windows" "472" } "CTFPlayer::GiveNamedItem" { @@ -468,6 +345,16 @@ "linux" "16" "windows" "15" } + "CTakeDamageInfo::m_bitsDamageType" + { + "linux" "60" + "windows" "60" + } + "CTakeDamageInfo::m_iDamageCustom" + { + "linux" "64" + "windows" "64" + } } "Functions" { @@ -821,6 +708,24 @@ } } } + "CBaseEntity::Event_KilledOther" + { + "offset" "CBaseEntity::Event_KilledOther" + "hooktype" "entity" + "return" "void" + "this" "entity" + "arguments" + { + "pVictim" + { + "type" "cbaseentity" + } + "info" + { + "type" "objectptr" + } + } + } "CEconEntity::TranslateViewmodelHandActivityInternal" { "offset" "CEconEntity::TranslateViewmodelHandActivityInternal" @@ -870,6 +775,20 @@ } } } + "CTFSword::GetSwordSpeedMod" + { + "offset" "CTFSword::GetSwordSpeedMod" + "hooktype" "entity" + "return" "float" + "this" "entity" + } + "CTFSword::GetSwordHealthMod" + { + "offset" "CTFSword::GetSwordHealthMod" + "hooktype" "entity" + "return" "int" + "this" "entity" + } "CBaseObject::Killed" { "offset" "CBaseObject::Killed" @@ -908,6 +827,20 @@ "return" "void" "this" "entity" } + "CBasePlayer::ClientCommand" + { + "offset" "CBasePlayer::ClientCommand" + "hooktype" "entity" + "return" "bool" + "this" "entity" + "arguments" + { + "pArgs" + { + "type" "objectptr" + } + } + } "CBasePlayer::EquipWearable" { "offset" "CBasePlayer::EquipWearable" @@ -936,17 +869,33 @@ } } } - "CTFPlayer::ClientCommand" + "CBaseMultiplayerPlayer::SpeakConceptIfAllowed" { - "offset" "CTFPlayer::ClientCommand" + "offset" "CBaseMultiplayerPlayer::SpeakConceptIfAllowed" "hooktype" "entity" "return" "bool" "this" "entity" "arguments" { - "pArgs" + "iConcept" { - "type" "objectptr" + "type" "int" + } + "modifiers" + { + "type" "charptr" + } + "pszOutResponseChosen" + { + "type" "charptr" + } + "bufsize" + { + "type" "int" + } + "filter" + { + "type" "int" } } } diff --git a/scripting/randomizer.sp b/scripting/randomizer.sp index 7942d1c..3b4df91 100644 --- a/scripting/randomizer.sp +++ b/scripting/randomizer.sp @@ -15,7 +15,7 @@ #pragma newdecls required -#define PLUGIN_VERSION "1.10.4" +#define PLUGIN_VERSION "1.11.0" #define PLUGIN_VERSION_REVISION "manual" #define CONFIG_MAXCHAR 64 @@ -35,6 +35,12 @@ #define PARTICLE_BEAM_BLU "medicgun_beam_blue" #define PARTICLE_BEAM_RED "medicgun_beam_red" +// from mp_shareddefs.h +const int MP_CONCEPT_KILLED_PLAYER = 7; + +// from tf_shareddef.h +#define DMG_MELEE (DMG_BLAST_SURFACE) + // entity effects enum { @@ -322,6 +328,9 @@ bool g_bEnabled; bool g_bTF2Items; bool g_bAllowGiveNamedItem; int g_iRuneCount; + +int g_iOffsetDamageType; +int g_iOffsetDamageCustom; int g_iOffsetItem; int g_iOffsetItemDefinitionIndex; int g_iOffsetMyWearables; @@ -395,6 +404,9 @@ public void OnPluginStart() DHook_Init(hGameData); SDKCall_Init(hGameData); + g_iOffsetDamageType = hGameData.GetOffset("CTakeDamageInfo::m_bitsDamageType"); + g_iOffsetDamageCustom = hGameData.GetOffset("CTakeDamageInfo::m_iDamageCustom"); + delete hGameData; //Any weapons using m_Item would work to get offset @@ -713,7 +725,6 @@ public void OnEntityDestroyed(int iEntity) void EnableRandomizer() { g_bEnabled = true; - Patch_Enable(); DHook_EnableDetour(); DHook_HookGamerules(); @@ -742,7 +753,7 @@ void DisableRandomizer() DHook_DisableDetour(); DHook_UnhookGamerules(); - Patch_Disable(); + Patch_RevertSpeed(); g_bEnabled = false; ViewModels_RemoveAll(); diff --git a/scripting/randomizer/dhook.sp b/scripting/randomizer/dhook.sp index 94aa9a1..897fc60 100644 --- a/scripting/randomizer/dhook.sp +++ b/scripting/randomizer/dhook.sp @@ -6,23 +6,69 @@ enum struct Detour DHookCallback callbackPost; } -static ArrayList g_aDHookDetours; +enum struct Hook +{ + DynamicHook hHook; + DHookCallback callbackPre; + DHookCallback callbackPost; + DHookRemovalCB callbackRemoval; + int iHookIdPre[MAXPLAYERS + 1]; + int iHookIdPost[MAXPLAYERS + 1]; + + void HookClient(int iClient) + { + if (this.callbackPre != INVALID_FUNCTION) + this.iHookIdPre[iClient] = this.hHook.HookEntity(Hook_Pre, iClient, this.callbackPre, this.callbackRemoval); + + if (this.callbackPost != INVALID_FUNCTION) + this.iHookIdPost[iClient] = this.hHook.HookEntity(Hook_Post, iClient, this.callbackPost, this.callbackRemoval); + } + + void UnhookClient(int iClient) + { + DHook_UnhookId(this.iHookIdPre[iClient]); + DHook_UnhookId(this.iHookIdPost[iClient]); + } + + void HookEntity(int iEntity) + { + if (this.callbackPre != INVALID_FUNCTION) + this.hHook.HookEntity(Hook_Pre, iEntity, this.callbackPre, this.callbackRemoval); + + if (this.callbackPost != INVALID_FUNCTION) + this.hHook.HookEntity(Hook_Post, iEntity, this.callbackPost, this.callbackRemoval); + } + + void HookGamerules() + { + if (this.callbackPre != INVALID_FUNCTION) + this.iHookIdPre[0] = this.hHook.HookGamerules(Hook_Pre, this.callbackPre, this.callbackRemoval); + + if (this.callbackPost != INVALID_FUNCTION) + this.iHookIdPost[0] = this.hHook.HookGamerules(Hook_Post, this.callbackPost, this.callbackRemoval); + } + + void UnhookGamerules() + { + DHook_UnhookId(this.iHookIdPre[0]); + DHook_UnhookId(this.iHookIdPost[0]); + } +} -static DynamicHook g_hDHookEventKilled; -static DynamicHook g_hDHookTranslateViewmodelHandActivityInternal; -static DynamicHook g_hDHookSecondaryAttack; -static DynamicHook g_hDHookGetEffectBarAmmo; -static DynamicHook g_hDHookSmack; -static DynamicHook g_hDHookSwing; -static DynamicHook g_hDHookKilled; -static DynamicHook g_hDHookCanBeUpgraded; -static DynamicHook g_hDHookForceRespawn; -static DynamicHook g_hDHookEquipWearable; -static DynamicHook g_hDHookGetAmmoCount; -static DynamicHook g_hDHookClientCommand; -static DynamicHook g_hDHookGiveNamedItem; -static DynamicHook g_hDHookInitClass; -static DynamicHook g_hDHookFrameUpdatePostEntityThink; +static ArrayList g_aDHookDetours; +static ArrayList g_aDHookClientHooks; + +static Hook g_DHookGiveNamedItem; +static Hook g_DHookTranslateViewmodelHandActivityInternal; +static Hook g_DHookSecondaryAttack; +static Hook g_DHookGetEffectBarAmmo; +static Hook g_DHookSmack; +static Hook g_DHookSwing; +static Hook g_DHookGetSwordSpeedMod; +static Hook g_DHookGetSwordHealthMod; +static Hook g_DHookKilled; +static Hook g_DHookCanBeUpgraded; +static Hook g_DHookFrameUpdatePostEntityThink; static bool g_bSkipGetMaxAmmo; static ArrayList g_aAllowWearables; @@ -31,26 +77,15 @@ static int g_iInitClassActiveWeapon = INVALID_ENT_REFERENCE; static int g_iInitClassWeapons[48] = {INVALID_ENT_REFERENCE, ...}; static int g_iBuildingKilledSapper = INVALID_ENT_REFERENCE; -static int g_iHookIdEventKilledPre[MAXPLAYERS + 1]; -static int g_iHookIdForceRespawnPre[MAXPLAYERS + 1]; -static int g_iHookIdForceRespawnPost[MAXPLAYERS + 1]; -static int g_iHookIdEquipWearable[MAXPLAYERS + 1]; -static int g_iHookIdGetAmmoCount[MAXPLAYERS + 1]; -static int g_iHookIdClientCommand[MAXPLAYERS + 1]; -static int g_iHookIdGiveNamedItem[MAXPLAYERS + 1]; -static int g_iHookIdInitClassPre[MAXPLAYERS + 1]; -static int g_iHookIdInitClassPost[MAXPLAYERS + 1]; - -static int g_iDHookGamerulesPre; -static int g_iDHookGamerulesPost; - static bool g_bDoClassSpecialSkill[MAXPLAYERS + 1]; static bool g_bDoClassSpecialSkillClass[MAXPLAYERS + 1]; static bool g_bApplyBiteEffectsChocolate[MAXPLAYERS + 1]; +static bool g_bHalloweenGiant[MAXPLAYERS + 1]; public void DHook_Init(GameData hGameData) { g_aDHookDetours = new ArrayList(sizeof(Detour)); + g_aDHookClientHooks = new ArrayList(sizeof(Hook)); DHook_CreateDetour(hGameData, "CTFPlayer::GiveAmmo", DHook_GiveAmmoPre, _); DHook_CreateDetour(hGameData, "CTFPlayer::GetMaxAmmo", DHook_GetMaxAmmoPre, _); @@ -77,21 +112,26 @@ public void DHook_Init(GameData hGameData) DHook_CreateDetour(hGameData, "CTFGameRules::ApplyOnDamageModifyRules", DHook_ApplyOnDamageModifyRulesPre, _); DHook_CreateDetour(hGameData, "HandleRageGain", DHook_HandleRageGainPre, _); - g_hDHookEventKilled = DHook_CreateVirtual(hGameData, "CBaseEntity::Event_Killed"); - g_hDHookTranslateViewmodelHandActivityInternal = DHook_CreateVirtual(hGameData, "CEconEntity::TranslateViewmodelHandActivityInternal"); - g_hDHookSecondaryAttack = DHook_CreateVirtual(hGameData, "CBaseCombatWeapon::SecondaryAttack"); - g_hDHookGetEffectBarAmmo = DHook_CreateVirtual(hGameData, "CTFWeaponBase::GetEffectBarAmmo"); - g_hDHookSmack = DHook_CreateVirtual(hGameData, "CTFWeaponBaseMelee::Smack"); - g_hDHookSwing = DHook_CreateVirtual(hGameData, "CTFWeaponBaseMelee::Swing"); - g_hDHookKilled = DHook_CreateVirtual(hGameData, "CBaseObject::Killed"); - g_hDHookCanBeUpgraded = DHook_CreateVirtual(hGameData, "CBaseObject::CanBeUpgraded"); - g_hDHookForceRespawn = DHook_CreateVirtual(hGameData, "CBasePlayer::ForceRespawn"); - g_hDHookEquipWearable = DHook_CreateVirtual(hGameData, "CBasePlayer::EquipWearable"); - g_hDHookGetAmmoCount = DHook_CreateVirtual(hGameData, "CBaseCombatCharacter::GetAmmoCount"); - g_hDHookClientCommand = DHook_CreateVirtual(hGameData, "CTFPlayer::ClientCommand"); - g_hDHookGiveNamedItem = DHook_CreateVirtual(hGameData, "CTFPlayer::GiveNamedItem"); - g_hDHookInitClass = DHook_CreateVirtual(hGameData, "CTFPlayer::InitClass"); - g_hDHookFrameUpdatePostEntityThink = DHook_CreateVirtual(hGameData, "CGameRules::FrameUpdatePostEntityThink"); + DHook_CreateClientHook(hGameData, "CBaseEntity::Event_Killed", DHook_EventKilledPre); + DHook_CreateClientHook(hGameData, "CBaseEntity::Event_KilledOther", DHook_EventKilledOtherPre); + DHook_CreateClientHook(hGameData, "CBasePlayer::ForceRespawn", DHook_ForceRespawnPre, DHook_ForceRespawnPost); + DHook_CreateClientHook(hGameData, "CBasePlayer::ClientCommand", _, DHook_ClientCommandPost); + DHook_CreateClientHook(hGameData, "CBasePlayer::EquipWearable", _, DHook_EquipWearablePost); + DHook_CreateClientHook(hGameData, "CBaseCombatCharacter::GetAmmoCount", DHook_GetAmmoCountPre); + DHook_CreateClientHook(hGameData, "CBaseMultiplayerPlayer::SpeakConceptIfAllowed", DHook_SpeakConceptIfAllowedPre); + DHook_CreateClientHook(hGameData, "CTFPlayer::InitClass", DHook_InitClassPre, DHook_InitClassPost); + + g_DHookGiveNamedItem = DHook_CreateHook(hGameData, "CTFPlayer::GiveNamedItem", DHook_GiveNamedItemPre, _, DHook_GiveNamedItemRemoved); + g_DHookTranslateViewmodelHandActivityInternal = DHook_CreateHook(hGameData, "CEconEntity::TranslateViewmodelHandActivityInternal", DHook_TranslateViewmodelHandActivityInternalPre, DHook_TranslateViewmodelHandActivityInternalPost); + g_DHookSecondaryAttack = DHook_CreateHook(hGameData, "CBaseCombatWeapon::SecondaryAttack", _, DHook_SecondaryWeaponPost); + g_DHookGetEffectBarAmmo = DHook_CreateHook(hGameData, "CTFWeaponBase::GetEffectBarAmmo", _, DHook_GetEffectBarAmmoPost); + g_DHookSmack = DHook_CreateHook(hGameData, "CTFWeaponBaseMelee::Smack", _, DHook_SmackPost); + g_DHookSwing = DHook_CreateHook(hGameData, "CTFWeaponBaseMelee::Swing", DHook_SwingPre); + g_DHookGetSwordSpeedMod = DHook_CreateHook(hGameData, "CTFSword::GetSwordSpeedMod", DHook_GetSwordModPre, DHook_GetSwordModPost); + g_DHookGetSwordHealthMod = DHook_CreateHook(hGameData, "CTFSword::GetSwordHealthMod", DHook_GetSwordModPre, DHook_GetSwordModPost); + g_DHookKilled = DHook_CreateHook(hGameData, "CBaseObject::Killed", DHook_KilledPre, DHook_KilledPost); + g_DHookCanBeUpgraded = DHook_CreateHook(hGameData, "CBaseObject::CanBeUpgraded", DHook_CanBeUpgradedPre, DHook_CanBeUpgradedPost); + g_DHookFrameUpdatePostEntityThink = DHook_CreateHook(hGameData, "CGameRules::FrameUpdatePostEntityThink", DHook_FrameUpdatePostEntityThinkPre, DHook_FrameUpdatePostEntityThinkPost); } static void DHook_CreateDetour(GameData hGameData, const char[] sName, DHookCallback callbackPre = INVALID_FUNCTION, DHookCallback callbackPost = INVALID_FUNCTION) @@ -111,13 +151,30 @@ static void DHook_CreateDetour(GameData hGameData, const char[] sName, DHookCall } } -static DynamicHook DHook_CreateVirtual(GameData hGameData, const char[] sName) +static Hook DHook_CreateHook(GameData hGameData, const char[] sName, DHookCallback callbackPre = INVALID_FUNCTION, DHookCallback callbackPost = INVALID_FUNCTION, DHookRemovalCB callbackRemoval = INVALID_FUNCTION) { - DynamicHook hHook = DynamicHook.FromConf(hGameData, sName); - if (!hHook) + Hook hook; + hook.hHook = DynamicHook.FromConf(hGameData, sName); + if (!hook.hHook) + { LogError("Failed to create hook: %s", sName); + } + else + { + hook.callbackPre = callbackPre; + hook.callbackPost = callbackPost; + hook.callbackRemoval = callbackRemoval; + } - return hHook; + return hook; +} + +static void DHook_CreateClientHook(GameData hGameData, const char[] sName, DHookCallback callbackPre = INVALID_FUNCTION, DHookCallback callbackPost = INVALID_FUNCTION) +{ + Hook hook; + hook = DHook_CreateHook(hGameData, sName, callbackPre, callbackPost); + if (hook.hHook) + g_aDHookClientHooks.PushArray(hook); } void DHook_EnableDetour() @@ -158,23 +215,19 @@ void DHook_DisableDetour() void DHook_HookGiveNamedItem(int iClient) { - if (g_hDHookGiveNamedItem && !g_bTF2Items) - g_iHookIdGiveNamedItem[iClient] = g_hDHookGiveNamedItem.HookEntity(Hook_Pre, iClient, DHook_GiveNamedItemPre, DHook_GiveNamedItemRemoved); + if (g_DHookGiveNamedItem.hHook && !g_bTF2Items) + g_DHookGiveNamedItem.HookClient(iClient); } void DHook_UnhookGiveNamedItem(int iClient) { - if (g_iHookIdGiveNamedItem[iClient]) - { - DHookRemoveHookID(g_iHookIdGiveNamedItem[iClient]); - g_iHookIdGiveNamedItem[iClient] = 0; - } + g_DHookGiveNamedItem.UnhookClient(iClient); } bool DHook_IsGiveNamedItemActive() { for (int iClient = 1; iClient <= MaxClients; iClient++) - if (g_iHookIdGiveNamedItem[iClient]) + if (g_DHookGiveNamedItem.iHookIdPre[iClient]) return true; return false; @@ -182,26 +235,26 @@ bool DHook_IsGiveNamedItemActive() void DHook_HookClient(int iClient) { - g_iHookIdEventKilledPre[iClient] = g_hDHookEventKilled.HookEntity(Hook_Pre, iClient, DHook_EventKilledPre); - g_iHookIdForceRespawnPre[iClient] = g_hDHookForceRespawn.HookEntity(Hook_Pre, iClient, DHook_ForceRespawnPre); - g_iHookIdForceRespawnPost[iClient] = g_hDHookForceRespawn.HookEntity(Hook_Post, iClient, DHook_ForceRespawnPost); - g_iHookIdEquipWearable[iClient] = g_hDHookEquipWearable.HookEntity(Hook_Post, iClient, DHook_EquipWearablePost); - g_iHookIdGetAmmoCount[iClient] = g_hDHookGetAmmoCount.HookEntity(Hook_Pre, iClient, DHook_GetAmmoCountPre); - g_iHookIdClientCommand[iClient] = g_hDHookClientCommand.HookEntity(Hook_Post, iClient, DHook_ClientCommandPost); - g_iHookIdInitClassPre[iClient] = g_hDHookInitClass.HookEntity(Hook_Pre, iClient, DHook_InitClassPre); - g_iHookIdInitClassPost[iClient] = g_hDHookInitClass.HookEntity(Hook_Post, iClient, DHook_InitClassPost); + int iLength = g_aDHookClientHooks.Length; + for (int i = 0; i < iLength; i++) + { + Hook hook; + g_aDHookClientHooks.GetArray(i, hook); + hook.HookClient(iClient); + g_aDHookClientHooks.SetArray(i, hook); + } } void DHook_UnhookClient(int iClient) { - DHook_UnhookId(g_iHookIdEventKilledPre[iClient]); - DHook_UnhookId(g_iHookIdForceRespawnPre[iClient]); - DHook_UnhookId(g_iHookIdForceRespawnPost[iClient]); - DHook_UnhookId(g_iHookIdEquipWearable[iClient]); - DHook_UnhookId(g_iHookIdGetAmmoCount[iClient]); - DHook_UnhookId(g_iHookIdClientCommand[iClient]); - DHook_UnhookId(g_iHookIdInitClassPre[iClient]); - DHook_UnhookId(g_iHookIdInitClassPost[iClient]); + int iLength = g_aDHookClientHooks.Length; + for (int i = 0; i < iLength; i++) + { + Hook hook; + g_aDHookClientHooks.GetArray(i, hook); + hook.UnhookClient(iClient); + g_aDHookClientHooks.SetArray(i, hook); + } } static void DHook_UnhookId(int &iId) @@ -218,31 +271,26 @@ void DHook_OnEntityCreated(int iEntity, const char[] sClassname) if (StrContains(sClassname, "tf_weapon_") == 0) { SDKHook(iEntity, SDKHook_SpawnPost, DHook_SpawnPost); - g_hDHookTranslateViewmodelHandActivityInternal.HookEntity(Hook_Pre, iEntity, DHook_TranslateViewmodelHandActivityInternalPre); - g_hDHookTranslateViewmodelHandActivityInternal.HookEntity(Hook_Post, iEntity, DHook_TranslateViewmodelHandActivityInternalPost); - g_hDHookSecondaryAttack.HookEntity(Hook_Post, iEntity, DHook_SecondaryWeaponPost); - g_hDHookGetEffectBarAmmo.HookEntity(Hook_Post, iEntity, DHook_GetEffectBarAmmoPost); + g_DHookTranslateViewmodelHandActivityInternal.HookEntity(iEntity); + g_DHookSecondaryAttack.HookEntity(iEntity); + g_DHookGetEffectBarAmmo.HookEntity(iEntity); } if (StrContains(sClassname, "obj_") == 0 && !StrEqual(sClassname, "obj_attachment_sapper")) { - g_hDHookKilled.HookEntity(Hook_Pre, iEntity, DHook_KilledPre); - g_hDHookKilled.HookEntity(Hook_Post, iEntity, DHook_KilledPost); - g_hDHookCanBeUpgraded.HookEntity(Hook_Pre, iEntity, DHook_CanBeUpgradedPre); - g_hDHookCanBeUpgraded.HookEntity(Hook_Post, iEntity, DHook_CanBeUpgradedPost); + g_DHookKilled.HookEntity(iEntity); + g_DHookCanBeUpgraded.HookEntity(iEntity); } } void DHook_HookGamerules() { - g_iDHookGamerulesPre = g_hDHookFrameUpdatePostEntityThink.HookGamerules(Hook_Pre, DHook_FrameUpdatePostEntityThinkPre); - g_iDHookGamerulesPost = g_hDHookFrameUpdatePostEntityThink.HookGamerules(Hook_Post, DHook_FrameUpdatePostEntityThinkPost); + g_DHookFrameUpdatePostEntityThink.HookGamerules(); } void DHook_UnhookGamerules() { - DHookRemoveHookID(g_iDHookGamerulesPre); - DHookRemoveHookID(g_iDHookGamerulesPost); + g_DHookFrameUpdatePostEntityThink.UnhookGamerules(); } public void DHook_SpawnPost(int iWeapon) @@ -250,9 +298,15 @@ public void DHook_SpawnPost(int iWeapon) if (TF2_GetSlot(iWeapon) == WeaponSlot_Melee) { if (HasEntProp(iWeapon, Prop_Send, "m_bBroken")) - g_hDHookSmack.HookEntity(Hook_Post, iWeapon, DHook_SmackPost); + g_DHookSmack.HookEntity(iWeapon); - g_hDHookSwing.HookEntity(Hook_Pre, iWeapon, DHook_SwingPre); + g_DHookSwing.HookEntity(iWeapon); + } + + if (IsClassname(iWeapon, "tf_weapon_sword")) + { + g_DHookGetSwordSpeedMod.HookEntity(iWeapon); + g_DHookGetSwordHealthMod.HookEntity(iWeapon); } } @@ -532,24 +586,50 @@ public MRESReturn DHook_GetChargeEffectBeingProvidedPost(int iClient, DHookRetur public MRESReturn DHook_GetMaxHealthForBuffingPre(int iClient, DHookReturn hReturn) { - if (g_bWeaponDecap[iClient]) - return MRES_Ignored; - - //Set decap to any eyelanders, all should have same value - int iWeapon, iPos; - if (TF2_GetItemFromClassname(iClient, "tf_weapon_sword", iWeapon, iPos)) - Properties_LoadWeaponPropInt(iClient, iWeapon, "m_iDecapitations"); + if (TF2_IsPlayerInCondition(iClient, TFCond_HalloweenGiant)) + { + // Don't modify HP by giant yet, may need to update value from eyelander + g_bHalloweenGiant[iClient] = true; + TF2_RemoveConditionFake(iClient, TFCond_HalloweenGiant); + } return MRES_Ignored; } public MRESReturn DHook_GetMaxHealthForBuffingPost(int iClient, DHookReturn hReturn) { - if (g_bWeaponDecap[iClient]) - return MRES_Ignored; + int iMax = hReturn.Value; + int iNewMax = iMax; + + if (TF2_GetPlayerClass(iClient) != TFClass_DemoMan) + { + // Need to manually call virtual + + // Only need to call once, all swords should have same value + int iWeapon, iPos; + if (TF2_GetItemFromClassname(iClient, "tf_weapon_sword", iWeapon, iPos)) + iNewMax += SDKCall_GetSwordHealthMod(iWeapon); + } + + if (g_bHalloweenGiant[iClient]) + { + g_bHalloweenGiant[iClient] = false; + TF2_AddConditionFake(iClient, TFCond_HalloweenGiant); + + static ConVar cvHealthScale; + if (!cvHealthScale) + cvHealthScale = FindConVar("tf_halloween_giant_health_scale"); + + // Is it floor by default when float becomes int? + iNewMax = RoundToFloor(float(iNewMax) * cvHealthScale.FloatValue); + } + + if (iNewMax != iMax) + { + hReturn.Value = iNewMax; + return MRES_Supercede; + } - //Set back to active weapon - Properties_LoadActiveWeaponPropInt(iClient, "m_iDecapitations"); return MRES_Ignored; } @@ -562,16 +642,14 @@ public MRESReturn DHook_CalculateMaxSpeedPre(int iClient, DHookReturn hReturn, D if (TF2_GetPlayerClass(iClient) != TFClass_Unknown) SetClientClassOriginal(iClient); + Patch_SetSpeed(TF2_GetPlayerClass(iClient)); + int iWeapon, iPos; //Set hype to any baby face blaster, all should have same value if (TF2_GetItemFromClassname(iClient, "tf_weapon_pep_brawler_blaster", iWeapon, iPos)) Properties_LoadWeaponPropFloat(iClient, iWeapon, "m_flHypeMeter"); - //Set decap to any eyelanders, all should have same value - if (!g_bWeaponDecap[iClient] && TF2_GetItemFromClassname(iClient, "tf_weapon_sword", iWeapon, iPos)) - Properties_LoadWeaponPropInt(iClient, iWeapon, "m_iDecapitations"); - return MRES_Ignored; } @@ -586,10 +664,6 @@ public MRESReturn DHook_CalculateMaxSpeedPost(int iClient, DHookReturn hReturn, else Properties_LoadWeaponPropFloat(iClient, g_iHypeMeterLoaded[iClient], "m_flHypeMeter"); - //Set back to active weapon - if (!g_bWeaponDecap[iClient]) - Properties_LoadActiveWeaponPropInt(iClient, "m_iDecapitations"); - if (TF2_GetPlayerClass(iClient) != TFClass_Unknown) RevertClientClass(iClient); @@ -798,6 +872,32 @@ public MRESReturn DHook_SwingPre(int iWeapon, DHookReturn hReturn) return MRES_Ignored; } +public MRESReturn DHook_GetSwordModPre(int iWeapon, DHookReturn hReturn) +{ + // For both speed and health hooks + + int iClient = GetEntPropEnt(iWeapon, Prop_Send, "m_hOwnerEntity"); + if (g_bWeaponDecap[iClient]) + return MRES_Ignored; + + if (0 < iClient <= MaxClients) + Properties_LoadWeaponPropInt(iClient, iWeapon, "m_iDecapitations"); + + return MRES_Ignored; +} + +public MRESReturn DHook_GetSwordModPost(int iWeapon, DHookReturn hReturn) +{ + int iClient = GetEntPropEnt(iWeapon, Prop_Send, "m_hOwnerEntity"); + if (g_bWeaponDecap[iClient]) + return MRES_Ignored; + + if (0 < iClient <= MaxClients) + Properties_LoadActiveWeaponPropInt(iClient, "m_iDecapitations"); + + return MRES_Ignored; +} + public MRESReturn DHook_TranslateViewmodelHandActivityInternalPre(int iWeapon, DHookReturn hReturn, DHookParam hParams) { int iClient = GetEntPropEnt(iWeapon, Prop_Send, "m_hOwnerEntity"); @@ -933,6 +1033,44 @@ public MRESReturn DHook_EventKilledPre(int iClient, DHookParam hParams) return MRES_Ignored; } +public MRESReturn DHook_EventKilledOtherPre(int iClient, DHookParam hParams) +{ + int iVictim = hParams.Get(1); + if (iVictim <= 0 || iVictim > MaxClients) + return MRES_Ignored; + + if (TF2_GetPlayerClass(iClient) != TFClass_DemoMan && TF2_GetClientTeam(iClient) != TF2_GetClientTeam(iVictim)) + { + // Manually award charge meters + // There whole achivements were missing, but meh, too much effort to make it work + float flRefill = 0.0; + TF2Attrib_HookValueFloat(flRefill, "kill_refills_meter", iClient); + + if (TF2_IsPlayerInCondition(iClient, TFCond_RuneKnockout)) // really should be GetCarryingRuneType, but good enough + flRefill *= 0.2; + + int iDamageType = hParams.GetObjectVar(2, g_iOffsetDamageType, ObjectValueType_Int); + int iDamageCustom = hParams.GetObjectVar(2, g_iOffsetDamageCustom, ObjectValueType_Int); + + if (flRefill > 0 && ((iDamageType & DMG_MELEE) || (iDamageCustom == TF_CUSTOM_CHARGE_IMPACT))) + { + float flMeter = GetEntProp(iClient, Prop_Send, "m_flChargeMeter") + (flRefill * 100.0); + SetEntProp(iClient, Prop_Send, "m_flChargeMeter", clamp(flMeter, 0.0, 100.0)); + } + } + + if (TF2_GetPlayerClass(iClient) != TFClass_Sniper) + { + // Manually give rages + float flRageGain = 0.0; + TF2Attrib_HookValueFloat(flRageGain, "rage_on_kill", iClient); + if (flRageGain != 0.0) + SDKCall_ModifyRage(GetEntityAddress(iClient) + view_as
(g_iOffsetPlayerShared), flRageGain); + } + + return MRES_Ignored; +} + public MRESReturn DHook_ForceRespawnPre(int iClient) { //Update incase of changing group @@ -970,6 +1108,17 @@ public MRESReturn DHook_ForceRespawnPost(int iClient) return MRES_Ignored; } +public MRESReturn DHook_ClientCommandPost(int iClient, DHookReturn hReturn, DHookParam hParams) +{ + if (g_iClientEurekaTeleporting) + { + RevertClientClass(iClient); + g_iClientEurekaTeleporting = 0; + } + + return MRES_Ignored; +} + public MRESReturn DHook_EquipWearablePost(int iClient, DHookParam hParams) { //New wearable is given from somewhere, refresh controls and huds @@ -991,6 +1140,26 @@ public MRESReturn DHook_GetAmmoCountPre(int iClient, DHookReturn hReturn, DHookP return MRES_Ignored; } +public MRESReturn DHook_SpeakConceptIfAllowedPre(int iClient, DHookReturn hReturn, DHookParam hParams) +{ + // There a spy check for silent YER kill + int iConcept = hParams.Get(1); + if (iConcept == MP_CONCEPT_KILLED_PLAYER) + { + int iActiveWeapon = GetEntPropEnt(iClient, Prop_Send, "m_hActiveWeapon"); + + int iMode; + TF2Attrib_HookValueInt(iMode, "set_weapon_mode", iActiveWeapon); + if (iMode == 1) // KNIFE_DISGUISE_ONKILL + { + hReturn.Value = false; + return MRES_Supercede; + } + } + + return MRES_Ignored; +} + public MRESReturn DHook_GiveNamedItemPre(int iClient, DHookReturn hReturn, DHookParam hParams) { if (hParams.IsNull(1) || hParams.IsNull(3)) @@ -1014,25 +1183,14 @@ public void DHook_GiveNamedItemRemoved(int iHookId) { for (int iClient = 1; iClient <= MaxClients; iClient++) { - if (g_iHookIdGiveNamedItem[iClient] == iHookId) + if (g_DHookGiveNamedItem.iHookIdPre[iClient] == iHookId) { - g_iHookIdGiveNamedItem[iClient] = 0; + g_DHookGiveNamedItem.iHookIdPre[iClient] = 0; return; } } } -public MRESReturn DHook_ClientCommandPost(int iClient, DHookReturn hReturn, DHookParam hParams) -{ - if (g_iClientEurekaTeleporting) - { - RevertClientClass(iClient); - g_iClientEurekaTeleporting = 0; - } - - return MRES_Ignored; -} - public MRESReturn DHook_InitClassPre(int iClient) { g_bInitClass = true; diff --git a/scripting/randomizer/patch.sp b/scripting/randomizer/patch.sp index 8b52ccc..1fd5b1f 100644 --- a/scripting/randomizer/patch.sp +++ b/scripting/randomizer/patch.sp @@ -84,52 +84,127 @@ enum struct Patch } } -static ArrayList g_aPatches; //Arrays of Patch +enum struct PatchSpeed +{ + Address pAddress; + int iValueOriginal; + int bFirstPatch; +} + +static ArrayList g_aSpeedPatches; //Arrays of PatchSpeed static Patch g_pIsPlayerClass; int g_iAllowPlayerClass; void Patch_Init(GameData hGameData) { - g_aPatches = new ArrayList(sizeof(Patch)); + int iWildcardMemory[PATCH_MAX]; + int iWhitelistCount = Patch_GetGamedataMemory(hGameData, "PatchWildcard_Speed", iWildcardMemory); + + int iMaxBits = Patch_GetGamedataValueInt(hGameData, "PatchBits_Speed"); + + Address pAddress = hGameData.GetMemSig("CTFPlayer::TeamFortress_CalculateMaxSpeed"); + + g_aSpeedPatches = new ArrayList(sizeof(PatchSpeed)); int iCount = 0; do { iCount++; - char sNumber[16]; - Format(sNumber, sizeof(sNumber), "%02d", iCount); + char sKey[64]; + Format(sKey, sizeof(sKey), "PatchSearch_Speed%02d", iCount); - Patch patch; - if (!patch.Load(hGameData, sNumber, true)) + int iMemory[PATCH_MAX]; + int iMemoryCount = Patch_GetGamedataMemory(hGameData, sKey, iMemory); + if (iMemoryCount == 0) break; - g_aPatches.PushArray(patch); + int iPosition; + PatchSpeed patch; + for (Address pOffset; pOffset < view_as
(iMaxBits); pOffset++) + { + if (Patch_CheckValue(pAddress + pOffset, iMemory[iPosition], patch, iWildcardMemory, iWhitelistCount)) + { + iPosition++; + } + else if (iPosition > 0) + { + iPosition = 0; + if (Patch_CheckValue(pAddress + pOffset, iMemory[iPosition], patch, iWildcardMemory, iWhitelistCount)) + iPosition++; + } + + if (iPosition >= iMemoryCount) + { + g_aSpeedPatches.PushArray(patch); + iPosition = 0; + } + } } while (iCount); //Infinite loop until break + int iLength = g_aSpeedPatches.Length; + int iMaxCount = Patch_GetGamedataValueInt(hGameData, "PatchCount_Speed"); + if (iLength != iMaxCount) + { + LogError("Found unexpected amount of speed patches to apply (expected %d, found %d), listing offsets found:", iMaxCount, iLength); + for (int i = 0; i < iLength; i++) + { + PatchSpeed patch; + g_aSpeedPatches.GetArray(i, patch); + LogError("#%02d: %d", i + 1, patch.pAddress - pAddress); + } + + g_aSpeedPatches.Clear(); + } + g_pIsPlayerClass.Load(hGameData, "IsPlayerClass"); } -void Patch_Enable() +bool Patch_CheckValue(Address pAddress, int iExpected, PatchSpeed patch, int iWildcardMemory[PATCH_MAX], int iWhitelistCount) +{ + int iValue = LoadFromAddress(pAddress, NumberType_Int8); + + if (iValue == iExpected) + { + return true; + } + else if (iExpected == 0x2A) + { + patch.pAddress = pAddress; + patch.iValueOriginal = iValue; + + for (int i = 0; i < iWhitelistCount; i++) + if (iValue == iWildcardMemory[i]) + return true; + } + + return false; +} + +void Patch_SetSpeed(TFClassType nClass) { - int iLength = g_aPatches.Length; + int iLength = g_aSpeedPatches.Length; for (int i = 0; i < iLength; i++) { - Patch patch; - g_aPatches.GetArray(i, patch); - if (patch.Enable()) - g_aPatches.SetArray(i, patch); + PatchSpeed patch; + g_aSpeedPatches.GetArray(i, patch); + StoreToAddress(patch.pAddress, nClass, NumberType_Int8, !patch.bFirstPatch); + if (!patch.bFirstPatch) + { + patch.bFirstPatch = true; + g_aSpeedPatches.SetArray(i, patch); + } } } -void Patch_Disable() +void Patch_RevertSpeed() { - int iLength = g_aPatches.Length; + int iLength = g_aSpeedPatches.Length; for (int i = 0; i < iLength; i++) { - Patch patch; - g_aPatches.GetArray(i, patch); - patch.Disable(); + PatchSpeed patch; + g_aSpeedPatches.GetArray(i, patch); + StoreToAddress(patch.pAddress, patch.iValueOriginal, NumberType_Int8); } } @@ -160,4 +235,18 @@ int Patch_StringToMemory(const char[] sValue, int iMemory[PATCH_MAX]) } return iCount; -} \ No newline at end of file +} + +int Patch_GetGamedataMemory(GameData hGameData, const char[] sKey, int iMemory[PATCH_MAX]) +{ + char sBuffer[PATCH_MAX * 4]; + hGameData.GetKeyValue(sKey, sBuffer, sizeof(sBuffer)); + return Patch_StringToMemory(sBuffer, iMemory); +} + +int Patch_GetGamedataValueInt(GameData hGameData, const char[] sKey) +{ + char sValue[12]; + hGameData.GetKeyValue(sKey, sValue, sizeof(sValue)); + return StringToInt(sValue); +} diff --git a/scripting/randomizer/sdkcall.sp b/scripting/randomizer/sdkcall.sp index ac9e182..7b03762 100644 --- a/scripting/randomizer/sdkcall.sp +++ b/scripting/randomizer/sdkcall.sp @@ -1,3 +1,5 @@ +const SDKType SDKType_Unknown = view_as(-1); + static Handle g_hSDKGetMaxAmmo; static Handle g_hSDKAddObject; static Handle g_hSDKRemoveObject; @@ -12,144 +14,67 @@ static Handle g_hSDKHandleRageGain; static Handle g_hSDKSetItem; static Handle g_hSDKGetBaseEntity; static Handle g_hSDKGetMaxHealth; +static Handle g_hSDKGetSwordHealthMod; static Handle g_hSDKWeaponCanSwitchTo; static Handle g_hSDKEquipWearable; static Handle g_hSDKGiveNamedItem; public void SDKCall_Init(GameData hGameData) { - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayer::GetMaxAmmo"); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); - PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); - g_hSDKGetMaxAmmo = EndPrepSDKCall(); - if (!g_hSDKGetMaxAmmo) - LogMessage("Failed to create call: CTFPlayer::GetMaxAmmo"); - - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayer::AddObject"); - PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); - g_hSDKAddObject = EndPrepSDKCall(); - if (!g_hSDKAddObject) - LogError("Failed to create call: CTFPlayer::AddObject"); - - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayer::RemoveObject"); - PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); - g_hSDKRemoveObject = EndPrepSDKCall(); - if (!g_hSDKRemoveObject) - LogError("Failed to create call: CTFPlayer::RemoveObject"); - - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayer::DoClassSpecialSkill"); - PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain); - g_hSDKDoClassSpecialSkill = EndPrepSDKCall(); - if (!g_hSDKDoClassSpecialSkill) - LogError("Failed to create call: CTFPlayer::DoClassSpecialSkill"); - - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayer::EndClassSpecialSkill"); - PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain); - g_hSDKEndClassSpecialSkill = EndPrepSDKCall(); - if (!g_hSDKEndClassSpecialSkill) - LogError("Failed to create call: CTFPlayer::EndClassSpecialSkill"); - - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayer::GetLoadoutItem"); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_ByValue); - g_hSDKGetLoadoutItem = EndPrepSDKCall(); - if (!g_hSDKGetLoadoutItem) - LogError("Failed to create call: CTFPlayer::GetLoadoutItem"); - - StartPrepSDKCall(SDKCall_Entity); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFSpellBook::RollNewSpell"); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_ByValue); - g_hSDKRollNewSpell = EndPrepSDKCall(); - if (!g_hSDKRollNewSpell) - LogError("Failed to create call: CTFSpellBook::RollNewSpell"); - - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayerShared::UpdateRageBuffsAndRage"); - g_hSDKUpdateRageBuffsAndRage = EndPrepSDKCall(); - if (!g_hSDKUpdateRageBuffsAndRage) - LogError("Failed to create call: CTFPlayerShared::UpdateRageBuffsAndRage"); - - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayerShared::ModifyRage"); - PrepSDKCall_AddParameter(SDKType_Float, SDKPass_ByValue); - g_hSDKModifyRage = EndPrepSDKCall(); - if (!g_hSDKModifyRage) - LogError("Failed to create call: CTFPlayerShared::ModifyRage"); - - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CTFPlayerShared::SetCarryingRuneType"); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - g_hSDKSetCarryingRuneType = EndPrepSDKCall(); - if (!g_hSDKSetCarryingRuneType) - LogError("Failed to create call: CTFPlayerShared::SetCarryingRuneType"); - - StartPrepSDKCall(SDKCall_Static); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "HandleRageGain"); - PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); // unsigned int - PrepSDKCall_AddParameter(SDKType_Float, SDKPass_ByValue); - PrepSDKCall_AddParameter(SDKType_Float, SDKPass_ByValue); - g_hSDKHandleRageGain = EndPrepSDKCall(); - if (!g_hSDKHandleRageGain) - LogError("Failed to create call: HandleRageGain"); - - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "CEconItemView::operator="); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); // CEconItemView& - PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_ByValue); // CEconItemView& - g_hSDKSetItem = EndPrepSDKCall(); - if (!g_hSDKSetItem) - LogError("Failed to create call: CEconItemView::operator="); + g_hSDKGetMaxAmmo = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Signature, "CTFPlayer::GetMaxAmmo", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); + g_hSDKAddObject = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Signature, "CTFPlayer::AddObject", _, SDKType_CBaseEntity); + g_hSDKRemoveObject = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Signature, "CTFPlayer::RemoveObject", _, SDKType_CBaseEntity); + g_hSDKDoClassSpecialSkill = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Signature, "CTFPlayer::DoClassSpecialSkill", SDKType_Bool); + g_hSDKEndClassSpecialSkill = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Signature, "CTFPlayer::EndClassSpecialSkill", SDKType_Bool); + g_hSDKGetLoadoutItem = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Signature, "CTFPlayer::GetLoadoutItem", SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); + g_hSDKRollNewSpell = SDKCall_Create(hGameData, SDKCall_Entity, SDKConf_Signature, "CTFSpellBook::RollNewSpell", _, SDKType_PlainOldData, SDKType_Bool); + g_hSDKUpdateRageBuffsAndRage = SDKCall_Create(hGameData, SDKCall_Raw, SDKConf_Signature, "CTFPlayerShared::UpdateRageBuffsAndRage"); + g_hSDKModifyRage = SDKCall_Create(hGameData, SDKCall_Raw, SDKConf_Signature, "CTFPlayerShared::ModifyRage", _, SDKType_Float); + g_hSDKSetCarryingRuneType = SDKCall_Create(hGameData, SDKCall_Raw, SDKConf_Signature, "CTFPlayerShared::SetCarryingRuneType", _, SDKType_PlainOldData); + g_hSDKHandleRageGain = SDKCall_Create(hGameData, SDKCall_Static, SDKConf_Signature, "HandleRageGain", _, SDKType_CBaseEntity, SDKType_PlainOldData, SDKType_Float, SDKType_Float); + g_hSDKSetItem = SDKCall_Create(hGameData, SDKCall_Raw, SDKConf_Signature, "CEconItemView::operator=", SDKType_PlainOldData, SDKType_PlainOldData); + g_hSDKGetBaseEntity = SDKCall_Create(hGameData, SDKCall_Raw, SDKConf_Virtual, "CBaseEntity::GetBaseEntity", SDKType_CBaseEntity); + g_hSDKGetMaxHealth = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Virtual, "CBaseEntity::GetMaxHealth", SDKType_PlainOldData); + g_hSDKGetSwordHealthMod = SDKCall_Create(hGameData, SDKCall_Entity, SDKConf_Virtual, "CTFSword::GetSwordHealthMod", SDKType_PlainOldData); + g_hSDKWeaponCanSwitchTo = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Virtual, "CBaseCombatCharacter::Weapon_CanSwitchTo", SDKType_Bool, SDKType_CBaseEntity); + g_hSDKEquipWearable = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Virtual, "CBasePlayer::EquipWearable", _, SDKType_CBaseEntity); + g_hSDKGiveNamedItem = SDKCall_Create(hGameData, SDKCall_Player, SDKConf_Virtual, "CTFPlayer::GiveNamedItem", SDKType_CBaseEntity, SDKType_String, SDKType_PlainOldData, SDKType_PlainOldData, SDKType_PlainOldData); +} + +static Handle SDKCall_Create(GameData hGameData, SDKCallType nType, SDKFuncConfSource nSource, const char[] sName, SDKType nReturn = SDKType_Unknown, SDKType nParam1 = SDKType_Unknown, SDKType nParam2 = SDKType_Unknown, SDKType nParam3 = SDKType_Unknown, SDKType nParam4 = SDKType_Unknown) +{ + StartPrepSDKCall(nType); + PrepSDKCall_SetFromConf(hGameData, nSource, sName); - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Virtual, "CBaseEntity::GetBaseEntity"); - PrepSDKCall_SetReturnInfo(SDKType_CBaseEntity, SDKPass_Pointer); - g_hSDKGetBaseEntity = EndPrepSDKCall(); - if (!g_hSDKGetBaseEntity) - LogError("Failed to create call: CBaseEntity::GetBaseEntity"); + SDKCall_AddParameter(nParam1); + SDKCall_AddParameter(nParam2); + SDKCall_AddParameter(nParam3); + SDKCall_AddParameter(nParam4); - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Virtual, "CBaseEntity::GetMaxHealth"); - PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_ByValue); - g_hSDKGetMaxHealth = EndPrepSDKCall(); - if (!g_hSDKGetMaxHealth) - LogError("Failed to create call: CBaseEntity::GetMaxHealth"); + if (nReturn != SDKType_Unknown) + { + if (nReturn == SDKType_String || nReturn == SDKType_CBaseEntity) + PrepSDKCall_SetReturnInfo(nReturn, SDKPass_Pointer); + else + PrepSDKCall_SetReturnInfo(nReturn, SDKPass_ByValue); + } - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Virtual, "CBaseCombatCharacter::Weapon_CanSwitchTo"); - PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); - PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_ByValue); - g_hSDKWeaponCanSwitchTo = EndPrepSDKCall(); - if (!g_hSDKWeaponCanSwitchTo) - LogError("Failed to create call: CBaseCombatCharacter::Weapon_CanSwitchTo"); + Handle hSDKCall = EndPrepSDKCall(); + if (!hSDKCall) + LogError("Failed to create call: %s", sName); - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Virtual, "CBasePlayer::EquipWearable"); - PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); - g_hSDKEquipWearable = EndPrepSDKCall(); - if (!g_hSDKEquipWearable) - LogError("Failed to create call: CBasePlayer::EquipWearable"); + return hSDKCall; +} + +static void SDKCall_AddParameter(SDKType nParam) +{ + if (nParam == SDKType_Unknown) + return; - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(hGameData, SDKConf_Virtual, "CTFPlayer::GiveNamedItem"); - PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_ByValue); - PrepSDKCall_SetReturnInfo(SDKType_CBaseEntity, SDKPass_Pointer); - g_hSDKGiveNamedItem = EndPrepSDKCall(); - if (!g_hSDKGiveNamedItem) - LogError("Failed to create call: CTFPlayer::GiveNamedItem"); + if (nParam == SDKType_String || nParam == SDKType_CBaseEntity) + PrepSDKCall_AddParameter(nParam, SDKPass_Pointer); + else + PrepSDKCall_AddParameter(nParam, SDKPass_ByValue); } int SDKCall_GetMaxAmmo(int iClient, int iAmmoType, TFClassType nClass = view_as(-1)) @@ -217,11 +142,16 @@ int SDKCall_GetBaseEntity(Address pEntity) return SDKCall(g_hSDKGetBaseEntity, pEntity); } -bool SDKCall_GetMaxHealth(int iEntity) +int SDKCall_GetMaxHealth(int iEntity) { return SDKCall(g_hSDKGetMaxHealth, iEntity); } +int SDKCall_GetSwordHealthMod(int iSword) +{ + return SDKCall(g_hSDKGetSwordHealthMod, iSword); +} + bool SDKCall_WeaponCanSwitchTo(int iClient, int iWeapon) { return SDKCall(g_hSDKWeaponCanSwitchTo, iClient, iWeapon); diff --git a/scripting/randomizer/stocks.sp b/scripting/randomizer/stocks.sp index c29a08f..c4c08d4 100644 --- a/scripting/randomizer/stocks.sp +++ b/scripting/randomizer/stocks.sp @@ -167,6 +167,15 @@ stock bool TF2_IndexFindAttribute(int iIndex, const char[] sAttrib, float &flVal return false; } +stock float TF2_GetAttributeValue(int iEntity, const char[] sAttrib, float flDefault) +{ + Address pAttrib = TF2Attrib_GetByName(iEntity, sAttrib); + if (pAttrib) + return TF2Attrib_GetValue(pAttrib); + else + return flDefault; +} + stock bool TF2_GetItem(int iClient, int &iWeapon, int &iPos, bool bCosmetic = false) { //Could be looped through client slots, but would cause issues with >1 weapons in same slot