mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
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:
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,4 +12,5 @@ namespace sfall
|
||||
void Inject_ScriptProcedureHook();
|
||||
void Inject_ScriptProcedureHook2();
|
||||
void Inject_AdjustPoisonHook();
|
||||
void Inject_AdjustRadsHook();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user