mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added new HOOK_USESKILLON and PartyMemberSkillFix option (#191)
This commit is contained in:
+9
-1
@@ -75,7 +75,8 @@ Use32BitHeadGraphics=0
|
||||
;Requires graphics mode 4 or 5
|
||||
AllowDShowMovies=0
|
||||
|
||||
;Fade effect time length percentage modifier
|
||||
;Fade effect time percentage modifier
|
||||
;Default is 100. Decrease/increase this value to speed up/slow down fade effects
|
||||
FadeMultiplier=100
|
||||
|
||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
@@ -631,6 +632,13 @@ DisplaySwiftLearnerExp=1
|
||||
;Set to 1 to display party member's current level/AC/addict flag on the combat control panel
|
||||
PartyMemberExtraInfo=0
|
||||
|
||||
;Set to 1 to fix the bug of using First Aid/Doctor skills when using them on the player
|
||||
;This will cause the party member to apply his/her skills when you use First Aid/Doctor skills on the player, but only if
|
||||
;the player is standing next to the party member
|
||||
;Note that because the related engine function is not fully implemented, enabling this option without a global script
|
||||
;that overrides First Aid/Doctor functions has very limited usefulness
|
||||
PartyMemberSkillFix=0
|
||||
|
||||
;Set to 1 to skip loading game settings from a saved game, except for the game/combat difficulty settings
|
||||
;Set to 2 to also skip loading the game/combat difficulty settings
|
||||
SkipLoadingGameSettings=0
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
#define HOOK_GAMEMODECHANGE (31)
|
||||
#define HOOK_USEANIMOBJ (32)
|
||||
#define HOOK_EXPLOSIVETIMER (33)
|
||||
#define HOOK_DESCRIPTIONOBJ (34)
|
||||
#define HOOK_USESKILLON (35)
|
||||
|
||||
//Valid arguments to list_begin
|
||||
#define LIST_CRITTERS (0)
|
||||
|
||||
@@ -544,3 +544,17 @@ An example usage would be to add an additional description to the item based on
|
||||
Obj arg1 - the item
|
||||
|
||||
int ret1 - a pointer to the new text received by using "get_string_pointer" function
|
||||
|
||||
-------------------------------------------
|
||||
|
||||
HOOK_USESKILLON (hs_useskillon.int)
|
||||
|
||||
Runs before using any skill on any object. Lets you override the critter that uses the skill.
|
||||
NOTE: the user critter can't be overridden when using Steal skill.
|
||||
|
||||
Critter arg1 - The user critter (usually dude_obj)
|
||||
Obj arg2 - the target object/critter
|
||||
int arg3 - skill being used
|
||||
|
||||
int ret1 - a new critter to override the user critter. Pass -1 to cancel the skill use, pass 0 to skip this return value
|
||||
int ret2 - pass 1 to allow the skill being used in combat (only for dude_obj or critter being controlled by the player)
|
||||
|
||||
@@ -79,6 +79,7 @@ static HooksInjectInfo injectHooks[] = {
|
||||
{HOOK_USEANIMOBJ, Inject_UseAnimateObjHook, false},
|
||||
{HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false},
|
||||
{HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false},
|
||||
{HOOK_USESKILLON, Inject_UseSkillOnHook, false},
|
||||
};
|
||||
|
||||
bool HookScripts::injectAllHooks;
|
||||
@@ -227,6 +228,7 @@ void HookScripts::init() {
|
||||
OnKeyPressed() += KeyPressHook;
|
||||
OnMouseClick() += MouseClickHook;
|
||||
LoadGameHook::OnGameModeChange() += GameModeChangeHook;
|
||||
LoadGameHook::OnAfterGameStarted() += SourceUseSkillOnInit;
|
||||
|
||||
HookScripts::injectAllHooks = (isDebug && (GetConfigInt("Debugging", "InjectAllGameHooks", 0) != 0));
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ enum HookType
|
||||
HOOK_USEANIMOBJ = 32,
|
||||
HOOK_EXPLOSIVETIMER = 33,
|
||||
HOOK_DESCRIPTIONOBJ = 34,
|
||||
HOOK_USESKILLON = 35,
|
||||
HOOK_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -392,6 +392,85 @@ end:
|
||||
}
|
||||
}
|
||||
|
||||
static fo::GameObject* sourceSkillOn = nullptr;
|
||||
void SourceUseSkillOnInit() { sourceSkillOn = fo::var::obj_dude; }
|
||||
|
||||
static char resultSkillOn;
|
||||
static long bakupCombatState;
|
||||
static void __cdecl UseSkillOnHook_Script(DWORD source, DWORD target, register DWORD skillId) {
|
||||
BeginHook();
|
||||
argCount = 3;
|
||||
|
||||
args[0] = source; // user
|
||||
args[1] = target; // target
|
||||
args[2] = skillId; // skill id
|
||||
|
||||
sourceSkillOn = fo::var::obj_dude;
|
||||
resultSkillOn = 0;
|
||||
bakupCombatState = -1;
|
||||
|
||||
RunHookScript(HOOK_USESKILLON);
|
||||
EndHook();
|
||||
|
||||
if (skillId != fo::Skill::SKILL_STEAL && cRet > 0) { // not work for steal skill
|
||||
if (rets[0] != 0) {
|
||||
resultSkillOn = (rets[0] == -1) ? -1 : 1;
|
||||
if (resultSkillOn == 1) {
|
||||
sourceSkillOn = (fo::GameObject*)rets[0];
|
||||
}
|
||||
}
|
||||
if (resultSkillOn != -1 && cRet > 1 && rets[1] == 1) {
|
||||
bakupCombatState = fo::var::combat_state;
|
||||
fo::var::combat_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) UseSkillOnHook() {
|
||||
__asm {
|
||||
push ecx;
|
||||
push ebx; // skill id
|
||||
push edx; // target
|
||||
push eax; // user
|
||||
call UseSkillOnHook_Script;
|
||||
pop eax;
|
||||
pop edx;
|
||||
add esp, 4; // ebx
|
||||
pop ecx;
|
||||
cmp resultSkillOn, -1; // skip handler
|
||||
jnz handler;
|
||||
retn;
|
||||
handler:
|
||||
jmp fo::funcoffs::action_use_skill_on_;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) UseSkillOnHack() {
|
||||
__asm {
|
||||
cmp bakupCombatState, -1;
|
||||
jz skip;
|
||||
mov ebp, bakupCombatState;
|
||||
mov dword ptr ds:[FO_VAR_combat_state], ebp;
|
||||
skip:
|
||||
cmp resultSkillOn, 0;
|
||||
jz default;
|
||||
mov edi, sourceSkillOn;
|
||||
retn; // flag ZF = 0
|
||||
default:
|
||||
// engine code
|
||||
cmp eax, dword ptr ds:[FO_VAR_obj_dude];
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) skill_use_hack() {
|
||||
__asm {
|
||||
cmp ebp, dword ptr ds:[FO_VAR_obj_dude];
|
||||
setnz al;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
void Inject_BarterPriceHook() {
|
||||
HookCalls(BarterPriceHook, {
|
||||
0x474D4C,
|
||||
@@ -440,6 +519,16 @@ void Inject_ExplosiveTimerHook() {
|
||||
HookCall(0x49BDC4, ExplosiveTimerHook);
|
||||
}
|
||||
|
||||
void Inject_UseSkillOnHook() {
|
||||
HookCalls(UseSkillOnHook, { 0x44C3CA, 0x44C81C });
|
||||
MakeCall(0x4127BA, UseSkillOnHack);
|
||||
SafeWrite8(0x4127BF, 0x90);
|
||||
MakeCalls(skill_use_hack, {0x4AB05D, 0x4AB558, 0x4ABA60}); // fix checking obj_dude's target
|
||||
// replace source skill user
|
||||
SafeWriteBatch<DWORD>((DWORD)&sourceSkillOn, {0x4AAF47, 0x4AB051, 0x4AB3FB, 0x4AB550, 0x4AB8FA, 0x4ABA54});
|
||||
SafeWriteBatch<DWORD>((DWORD)&sourceSkillOn, {0x4AB0EF, 0x4AB5C0, 0x4ABAF2}); // fix for time
|
||||
}
|
||||
|
||||
void InitMiscHookScripts() {
|
||||
|
||||
LoadHookScript("hs_barterprice", HOOK_BARTERPRICE);
|
||||
@@ -450,6 +539,7 @@ void InitMiscHookScripts() {
|
||||
LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR);
|
||||
LoadHookScript("hs_resttimer", HOOK_RESTTIMER);
|
||||
LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER);
|
||||
LoadHookScript("hs_useskillon", HOOK_USESKILLON);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace sfall
|
||||
{
|
||||
void InitMiscHookScripts();
|
||||
void SourceUseSkillOnInit();
|
||||
|
||||
void Inject_BarterPriceHook();
|
||||
void Inject_UseSkillHook();
|
||||
@@ -12,4 +13,5 @@ namespace sfall
|
||||
void Inject_SetGlobalVarHook();
|
||||
void Inject_RestTimerHook();
|
||||
void Inject_ExplosiveTimerHook();
|
||||
void Inject_UseSkillOnHook();
|
||||
}
|
||||
|
||||
@@ -448,6 +448,24 @@ end:
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) action_use_skill_on_hook() {
|
||||
__asm { // eax = dude_obj, edx = target, ebp = party_member
|
||||
cmp eax, edx;
|
||||
jnz end; // jump if target != dude_obj
|
||||
mov edx, ebp;
|
||||
call fo::funcoffs::obj_dist_; // check distance between dude_obj and party_member
|
||||
cmp eax, 1; // if the distance is greater than 1, then reset the register
|
||||
jg skip;
|
||||
inc eax;
|
||||
retn;
|
||||
skip:
|
||||
xor eax, eax;
|
||||
retn;
|
||||
end:
|
||||
jmp fo::funcoffs::obj_dist_;
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD EncounterTableSize[] = {
|
||||
0x4BD1A3, 0x4BD1D9, 0x4BD270, 0x4BD604, 0x4BDA14, 0x4BDA44, 0x4BE707,
|
||||
0x4C0815, 0x4C0D4A, 0x4C0FD4,
|
||||
@@ -855,6 +873,21 @@ void KeepWeaponSelectModePatch() {
|
||||
}
|
||||
}
|
||||
|
||||
void PartyMemberSkillPatch() {
|
||||
// Fixed getting distance from source to target when using skills
|
||||
// Note: this will cause the party member to apply his/her skill when you use First Aid/Doctor skill on the player, but only if
|
||||
// the player is standing next to the party member. Because the related engine function is not fully implemented, enabling
|
||||
// this option without a global script that overrides First Aid/Doctor functions has very limited usefulness
|
||||
if (GetConfigInt("Misc", "PartyMemberSkillFix", 0) != 0) {
|
||||
dlog("Applying party member using First Aid/Doctor skill patch.", DL_INIT);
|
||||
HookCall(0x412836, action_use_skill_on_hook);
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
// Small code patch for HOOK_USESKILLON (change obj_dude to source)
|
||||
SafeWrite32(0x4128F3, 0x90909090);
|
||||
SafeWrite16(0x4128F7, 0xFE39); // cmp esi, _obj_dude -> cmp esi, edi
|
||||
}
|
||||
|
||||
void SkipLoadingGameSettingsPatch() {
|
||||
int skipLoading = GetConfigInt("Misc", "SkipLoadingGameSettings", 0);
|
||||
if (skipLoading) {
|
||||
@@ -969,6 +1002,8 @@ void MiscPatches::init() {
|
||||
DisplaySecondWeaponRangePatch();
|
||||
KeepWeaponSelectModePatch();
|
||||
|
||||
PartyMemberSkillPatch();
|
||||
|
||||
SkipLoadingGameSettingsPatch();
|
||||
InterfaceDontMoveOnTopPatch();
|
||||
}
|
||||
|
||||
+1
-1
@@ -279,7 +279,7 @@ static bool LoadOriginalDll(DWORD dwReason) {
|
||||
switch (dwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
char path[MAX_PATH];
|
||||
CopyMemory(path + GetSystemDirectory(path , MAX_PATH - 10), "\\ddraw.dll", 11); // path to original dll
|
||||
CopyMemory(path + GetSystemDirectoryA(path , MAX_PATH - 10), "\\ddraw.dll", 11); // path to original dll
|
||||
ddraw.dll = LoadLibrary(path);
|
||||
if (!ddraw.dll || ddraw.dll == INVALID_HANDLE_VALUE) {
|
||||
MessageBox(0, "Cannot load the original ddraw.dll library.", "sfall", MB_ICONERROR);
|
||||
|
||||
Reference in New Issue
Block a user