diff --git a/artifacts/scripting/headers/define_lite.h b/artifacts/scripting/headers/define_lite.h index 304a71df..5b991a9e 100644 --- a/artifacts/scripting/headers/define_lite.h +++ b/artifacts/scripting/headers/define_lite.h @@ -806,7 +806,10 @@ #define bit_32 (0x80000000) #define bit_ALL (0xFFFFFFFF) - +#define ROLL_CRITICAL_FAILURE 0 +#define ROLL_FAILURE 1 +#define ROLL_SUCCESS 2 +#define ROLL_CRITICAL_SUCCESS 3 //Misc commands #define obj_get_rot(obj) (has_trait(TRAIT_OBJECT, obj, OBJECT_CUR_ROT)) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 802cea30..6af56a50 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -70,6 +70,7 @@ #define HOOK_TARGETOBJECT (42) #define HOOK_ENCOUNTER (43) #define HOOK_ADJUSTPOISON (44) +#define HOOK_ADJUSTRADS (45) //Valid arguments to list_begin #define LIST_CRITTERS (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index d41419da..3bea8d76 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -707,3 +707,14 @@ int arg2 - the damage value at the time of applying the poison effect int ret0 - the new amount of poison being added/removed int ret1 - the new damage value, only negative values are allowed (will only be valid at the time of taking damage from the poison) + +------------------------------------------- + +HOOK_ADJUSTRADS (hs_adjustrads.int) + +Runs when a critter's radiation level is changed. + +Critter arg0 - the critter (usually dude_obj) +int arg1 - the amount of radiation being added/removed + +int ret0 - the new amount of radiation being added/removed diff --git a/sfall/Modules/DamageMod.cpp b/sfall/Modules/DamageMod.cpp index 42f7c51d..596eeb45 100644 --- a/sfall/Modules/DamageMod.cpp +++ b/sfall/Modules/DamageMod.cpp @@ -399,9 +399,7 @@ void DamageMod::init() { case 1: case 2: case 5: - if (!HookScripts::IsInjectHook(HOOK_SUBCOMBATDAMAGE)) { - HookScripts::InjectingHook(HOOK_SUBCOMBATDAMAGE); - } + HookScripts::InjectingHook(HOOK_SUBCOMBATDAMAGE); break; default: formula = 0; diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index de56cd4f..24a4c81e 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -40,16 +40,18 @@ namespace sfall // Number of types of hooks static constexpr int numHooks = HOOK_COUNT; -bool HookScripts::injectAllHooks; +bool injectAllHooks; + DWORD HookScripts::initingHookScripts; std::vector HookScripts::hookScriptFilesList; typedef void(*HookInjectFunc)(); + struct HooksInjectInfo { int id; HookInjectFunc inject; - bool isInject; + char injectState; }; static struct HooksPositionInfo { @@ -59,62 +61,64 @@ static struct HooksPositionInfo { } hooksInfo[numHooks]; static HooksInjectInfo injectHooks[] = { - {HOOK_TOHIT, Inject_ToHitHook, false}, - {HOOK_AFTERHITROLL, Inject_AfterHitRollHook, false}, - {HOOK_CALCAPCOST, Inject_CalcApCostHook, false}, - {HOOK_DEATHANIM1, Inject_DeathAnim1Hook, false}, - {HOOK_DEATHANIM2, Inject_DeathAnim2Hook, false}, - {HOOK_COMBATDAMAGE, Inject_CombatDamageHook, false}, - {HOOK_ONDEATH, Inject_OnDeathHook, false}, - {HOOK_FINDTARGET, Inject_FindTargetHook, false}, - {HOOK_USEOBJON, Inject_UseObjOnHook, false}, - {HOOK_REMOVEINVENOBJ, Inject_RemoveInvenObjHook, false}, - {HOOK_BARTERPRICE, Inject_BarterPriceHook, false}, - {HOOK_MOVECOST, Inject_MoveCostHook, false}, - {HOOK_HEXMOVEBLOCKING, Inject_HexMoveBlockHook, false}, - {HOOK_HEXAIBLOCKING, Inject_HexIABlockHook, false}, - {HOOK_HEXSHOOTBLOCKING, Inject_HexShootBlockHook, false}, - {HOOK_HEXSIGHTBLOCKING, Inject_HexSightBlockHook, false}, - {HOOK_ITEMDAMAGE, Inject_ItemDamageHook, false}, - {HOOK_AMMOCOST, Inject_AmmoCostHook, false}, - {HOOK_USEOBJ, Inject_UseObjHook, false}, - {HOOK_KEYPRESS, nullptr, true}, // no embed code to the engine - {HOOK_MOUSECLICK, nullptr, true}, // no embed code to the engine - {HOOK_USESKILL, Inject_UseSkillHook, false}, - {HOOK_STEAL, Inject_StealCheckHook, false}, - {HOOK_WITHINPERCEPTION, Inject_WithinPerceptionHook, false}, - {HOOK_INVENTORYMOVE, Inject_InventoryMoveHook, false}, - {HOOK_INVENWIELD, Inject_InvenWieldHook, false}, - {HOOK_ADJUSTFID, nullptr, true}, // always embedded to the engine - {HOOK_COMBATTURN, Inject_CombatTurnHook, false}, - {HOOK_CARTRAVEL, Inject_CarTravelHook, false}, - {HOOK_SETGLOBALVAR, Inject_SetGlobalVarHook, false}, - {HOOK_RESTTIMER, Inject_RestTimerHook, false}, - {HOOK_GAMEMODECHANGE, nullptr, true}, // always embedded to the engine - {HOOK_USEANIMOBJ, Inject_UseAnimateObjHook, false}, - {HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false}, - {HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false}, - {HOOK_USESKILLON, Inject_UseSkillOnHook, false}, - {HOOK_ONEXPLOSION, Inject_OnExplosionHook, false}, - {HOOK_SUBCOMBATDAMAGE, Inject_SubCombatDamageHook, false}, // replace the code logic - {HOOK_SETLIGHTING, Inject_SetLightingHook, false}, - {HOOK_SNEAK, Inject_SneakCheckHook, false}, - {HOOK_STDPROCEDURE, Inject_ScriptProcedureHook, false}, - {HOOK_STDPROCEDURE_END, Inject_ScriptProcedureHook2, false}, - {HOOK_TARGETOBJECT, Inject_TargetObjectHook, false}, - {HOOK_ENCOUNTER, Inject_EncounterHook, false}, - {HOOK_ADJUSTPOISON, Inject_AdjustPoisonHook, false}, + {HOOK_TOHIT, Inject_ToHitHook, 0}, + {HOOK_AFTERHITROLL, Inject_AfterHitRollHook, 0}, + {HOOK_CALCAPCOST, Inject_CalcApCostHook, 0}, + {HOOK_DEATHANIM1, Inject_DeathAnim1Hook, 0}, + {HOOK_DEATHANIM2, Inject_DeathAnim2Hook, 0}, + {HOOK_COMBATDAMAGE, Inject_CombatDamageHook, 0}, + {HOOK_ONDEATH, Inject_OnDeathHook, 0}, + {HOOK_FINDTARGET, Inject_FindTargetHook, 0}, + {HOOK_USEOBJON, Inject_UseObjOnHook, 0}, + {HOOK_REMOVEINVENOBJ, Inject_RemoveInvenObjHook, 0}, + {HOOK_BARTERPRICE, Inject_BarterPriceHook, 0}, + {HOOK_MOVECOST, Inject_MoveCostHook, 0}, + {HOOK_HEXMOVEBLOCKING, Inject_HexMoveBlockHook, 0}, + {HOOK_HEXAIBLOCKING, Inject_HexIABlockHook, 0}, + {HOOK_HEXSHOOTBLOCKING, Inject_HexShootBlockHook, 0}, + {HOOK_HEXSIGHTBLOCKING, Inject_HexSightBlockHook, 0}, + {HOOK_ITEMDAMAGE, Inject_ItemDamageHook, 0}, + {HOOK_AMMOCOST, Inject_AmmoCostHook, 0}, + {HOOK_USEOBJ, Inject_UseObjHook, 0}, + {HOOK_KEYPRESS, nullptr, 2}, // no embed code to the engine + {HOOK_MOUSECLICK, nullptr, 2}, // no embed code to the engine + {HOOK_USESKILL, Inject_UseSkillHook, 0}, + {HOOK_STEAL, Inject_StealCheckHook, 0}, + {HOOK_WITHINPERCEPTION, Inject_WithinPerceptionHook, 0}, + {HOOK_INVENTORYMOVE, Inject_InventoryMoveHook, 0}, + {HOOK_INVENWIELD, Inject_InvenWieldHook, 0}, + {HOOK_ADJUSTFID, nullptr, 2}, // always embedded to the engine + {HOOK_COMBATTURN, Inject_CombatTurnHook, 0}, + {HOOK_CARTRAVEL, Inject_CarTravelHook, 0}, + {HOOK_SETGLOBALVAR, Inject_SetGlobalVarHook, 0}, + {HOOK_RESTTIMER, Inject_RestTimerHook, 0}, + {HOOK_GAMEMODECHANGE, nullptr, 2}, // always embedded to the engine + {HOOK_USEANIMOBJ, Inject_UseAnimateObjHook, 0}, + {HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, 0}, + {HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, 0}, + {HOOK_USESKILLON, Inject_UseSkillOnHook, 0}, + {HOOK_ONEXPLOSION, Inject_OnExplosionHook, 0}, + {HOOK_SUBCOMBATDAMAGE, Inject_SubCombatDamageHook, 0}, // replace the code logic + {HOOK_SETLIGHTING, Inject_SetLightingHook, 0}, + {HOOK_SNEAK, Inject_SneakCheckHook, 0}, + {HOOK_STDPROCEDURE, Inject_ScriptProcedureHook, 0}, + {HOOK_STDPROCEDURE_END, Inject_ScriptProcedureHook2, 0}, + {HOOK_TARGETOBJECT, Inject_TargetObjectHook, 0}, + {HOOK_ENCOUNTER, Inject_EncounterHook, 0}, + {HOOK_ADJUSTPOISON, Inject_AdjustPoisonHook, 0}, + {HOOK_ADJUSTRADS, Inject_AdjustRadsHook, 1}, // always embedded for party control fix }; void HookScripts::InjectingHook(int hookId) { - if (!injectHooks[hookId].isInject && injectHooks[hookId].id == hookId) { - injectHooks[hookId].isInject = true; + if (!IsInjectHook(hookId) && injectHooks[hookId].id == hookId) { + injectHooks[hookId].injectState = 2; injectHooks[hookId].inject(); + devlog_f("Inject hook ID: %d\n", DL_INIT, hookId); } } bool HookScripts::IsInjectHook(int hookId) { - return injectHooks[hookId].isInject; + return injectHooks[hookId].injectState == 2; } bool HookScripts::HookHasScript(int hookId) { @@ -146,15 +150,7 @@ void HookScripts::RegisterHook(fo::Program* script, int id, int procNum, bool sp } hooks[id].insert(c_it, hook); - switch (id) { - case HOOK_KEYPRESS: - case HOOK_MOUSECLICK: - case HOOK_ADJUSTFID: - case HOOK_GAMEMODECHANGE: - break; - default: - HookScripts::InjectingHook(id); // inject hook to engine code - } + HookScripts::InjectingHook(id); // inject hook to engine code } } @@ -171,10 +167,11 @@ void HookScripts::LoadHookScript(const char* name, int id) { //if (id >= numHooks || IsGameScript(name)) return; bool hookIsLoaded = HookScripts::LoadHookScriptFile(name, id); - if (hookIsLoaded || (HookScripts::injectAllHooks && id != HOOK_SUBCOMBATDAMAGE)) { + if (hookIsLoaded || injectHooks[id].injectState == 1 || (injectAllHooks && id != HOOK_SUBCOMBATDAMAGE)) { HookScripts::InjectingHook(id); // inject hook to engine code - if (!hookIsLoaded) return; + if (!hookIsLoaded) return; // only inject + HookFile hookFile = { id, name }; HookScripts::hookScriptFilesList.push_back(hookFile); } @@ -258,8 +255,8 @@ void HookScripts::init() { LoadGameHook::OnGameModeChange() += HookCommon::GameModeChangeHook; LoadGameHook::OnAfterGameStarted() += SourceUseSkillOnInit; - HookScripts::injectAllHooks = isDebug && (iniGetInt("Debugging", "InjectAllGameHooks", 0, ::sfall::ddrawIni) != 0); - if (HookScripts::injectAllHooks) dlogr("Injecting all game hooks", DL_HOOK|DL_INIT); + injectAllHooks = isDebug && (iniGetInt("Debugging", "InjectAllGameHooks", 0, ::sfall::ddrawIni) != 0); + if (injectAllHooks) dlogr("Injecting all game hooks", DL_HOOK|DL_INIT); } } diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index 30fbad0b..ba4a6851 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -71,6 +71,7 @@ enum HookType HOOK_TARGETOBJECT = 42, HOOK_ENCOUNTER = 43, HOOK_ADJUSTPOISON = 44, + HOOK_ADJUSTRADS = 45, HOOK_COUNT }; @@ -97,7 +98,6 @@ public: static bool HookHasScript(int hookId); - static bool injectAllHooks; static void InjectingHook(int hookId); static bool IsInjectHook(int hookId); diff --git a/sfall/Modules/HookScripts/ObjectHs.cpp b/sfall/Modules/HookScripts/ObjectHs.cpp index 27f7c681..4482f5ee 100644 --- a/sfall/Modules/HookScripts/ObjectHs.cpp +++ b/sfall/Modules/HookScripts/ObjectHs.cpp @@ -333,6 +333,39 @@ static void __declspec(naked) critter_adjust_poison_hack() { } } +static DWORD __fastcall AdjustRads_Script(DWORD critter, long amount) { + if (HookScripts::HookHasScript(HOOK_ADJUSTRADS) == false) return amount; + + BeginHook(); + argCount = 2; + + args[0] = critter; // always dude + args[1] = amount; + + RunHookScript(HOOK_ADJUSTRADS); + if (cRet) amount = rets[0]; + + EndHook(); + return amount; +} + +void __declspec(naked) critter_adjust_rads_hack() { + using namespace fo; + using namespace Fields; + __asm { + cmp dword ptr [eax + protoId], PID_Player; // critter.pid + jne isNotDude; + push ecx; + call AdjustRads_Script; // ecx - critter, edx - amount + pop ecx; + mov ebx, eax; // old/new amount + mov edx, ds:[FO_VAR_obj_dude]; + xor eax, eax; // for continue func +isNotDude: + retn; + } +} + void Inject_UseObjOnHook() { HookCalls(UseObjOnHook, { 0x49C606, 0x473619 }); @@ -374,6 +407,11 @@ void Inject_AdjustPoisonHook() { MakeCall(0x42D21C, critter_adjust_poison_hack, 1); } +void Inject_AdjustRadsHook() { + MakeCall(0x42D3B0, critter_adjust_rads_hack, 1); + SafeWrite16(0x42D3B6, 0xC085); // test eax, eax +} + void InitObjectHookScripts() { HookScripts::LoadHookScript("hs_useobjon", HOOK_USEOBJON); HookScripts::LoadHookScript("hs_useobj", HOOK_USEOBJ); @@ -383,6 +421,7 @@ void InitObjectHookScripts() { HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE); // combo hook HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE_END); HookScripts::LoadHookScript("hs_adjustpoison", HOOK_ADJUSTPOISON); + HookScripts::LoadHookScript("hs_adjustrads", HOOK_ADJUSTRADS); } } diff --git a/sfall/Modules/HookScripts/ObjectHs.h b/sfall/Modules/HookScripts/ObjectHs.h index 3a05f626..6062d6f6 100644 --- a/sfall/Modules/HookScripts/ObjectHs.h +++ b/sfall/Modules/HookScripts/ObjectHs.h @@ -12,4 +12,5 @@ namespace sfall void Inject_ScriptProcedureHook(); void Inject_ScriptProcedureHook2(); void Inject_AdjustPoisonHook(); + void Inject_AdjustRadsHook(); } diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 7bd54ab2..dca8baee 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -138,7 +138,7 @@ long ScriptExtender::GetResetScriptReturnValue() { return val; } -static long FindOverrideSub(fo::Program* program) { +static __forceinline long FindProgram(fo::Program* program) { std::unordered_map::iterator overrideIt = selfOverrideMap.find(program); if (overrideIt != selfOverrideMap.end()) { DWORD scriptId = overrideIt->second.object->scriptId; // script @@ -167,11 +167,11 @@ static long FindOverrideSub(fo::Program* program) { return -1; // change nothing } -static long __fastcall FindOverride(fo::Program* program, fo::ScriptInstance* &script) { - long result = FindOverrideSub(program); +static long __fastcall FindOverride(fo::Program* program, fo::ScriptInstance** script) { + long result = FindProgram(program); if (result == -2) { if (script) { - script = &overrideScript; // unsafe method! script may contain an incorrect address value in some engine functions + *script = &overrideScript; // unsafe method! script may contain an incorrect address value in some engine functions } else { result--; // set -3 } diff --git a/sfall/Modules/Skills.cpp b/sfall/Modules/Skills.cpp index 04f701c1..4ee261a5 100644 --- a/sfall/Modules/Skills.cpp +++ b/sfall/Modules/Skills.cpp @@ -407,11 +407,11 @@ void Skills::init() { if (basedOnPoints) HookCall(0x4AA9EC, (void*)fo::funcoffs::skill_points_); // skill_dec_point_ int tagBonus = iniGetInt("Skills", "TagSkillBonus", 20, file); - if (tagBonus != 20 && tagBonus >=0 && tagBonus <= 100) SafeWrite8(0x4AA61E, static_cast(tagBonus)); + if (tagBonus != 20 && tagBonus >=0 && tagBonus <= 100) SafeWrite8(0x4AA61E, static_cast(tagBonus)); // skill_level_ int tagMode = iniGetInt("Skills", "TagSkillMode", 0, file); - if (tagMode & 1) SafeWrite8(0x4AA612, 0xEB); // 4th tag skill can have initial skill bonus (jz > jmp) - if (tagMode & 2) SafeWrite16(0x4AA60E, 0x9090); // skill_level_ disables 2x skill points bonus for tag skills + if (tagMode & 1) SafeWrite8(0x4AA612, 0xEB); // 4th tag skill can have initial skill bonus. skill_level_ (jz > jmp) + if (tagMode & 2) SafeWrite16(0x4AA60E, 0x9090); // disables double skill points bonus for tag skills. skill_level_ } }