Added a new hook: HOOK_ADJUSTRADS

Fixed a crash bug in ScriptExtender.cpp from commit c736e39.
Some adjustments to the hook injection mechanism.
This commit is contained in:
NovaRain
2021-01-13 11:11:32 +08:00
parent 4535ec9e20
commit bde6b94855
10 changed files with 125 additions and 75 deletions
+4 -1
View File
@@ -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))
+1
View File
@@ -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)
+11
View File
@@ -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
-2
View File
@@ -399,9 +399,7 @@ void DamageMod::init() {
case 1:
case 2:
case 5:
if (!HookScripts::IsInjectHook(HOOK_SUBCOMBATDAMAGE)) {
HookScripts::InjectingHook(HOOK_SUBCOMBATDAMAGE);
}
break;
default:
formula = 0;
+59 -62
View File
@@ -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<HookFile> 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,17 +150,9 @@ 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
}
}
}
// run specific event procedure for all hook scripts
void HookScripts::RunHookScriptsAtProc(DWORD procId) {
@@ -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);
}
}
+1 -1
View File
@@ -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);
+39
View File
@@ -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);
}
}
+1
View File
@@ -12,4 +12,5 @@ namespace sfall
void Inject_ScriptProcedureHook();
void Inject_ScriptProcedureHook2();
void Inject_AdjustPoisonHook();
void Inject_AdjustRadsHook();
}
+4 -4
View File
@@ -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<fo::Program*, SelfOverrideObj>::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
}
+3 -3
View File
@@ -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<BYTE>(tagBonus));
if (tagBonus != 20 && tagBonus >=0 && tagBonus <= 100) SafeWrite8(0x4AA61E, static_cast<BYTE>(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_
}
}