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
|
;Requires graphics mode 4 or 5
|
||||||
AllowDShowMovies=0
|
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
|
FadeMultiplier=100
|
||||||
|
|
||||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
;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
|
;Set to 1 to display party member's current level/AC/addict flag on the combat control panel
|
||||||
PartyMemberExtraInfo=0
|
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 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
|
;Set to 2 to also skip loading the game/combat difficulty settings
|
||||||
SkipLoadingGameSettings=0
|
SkipLoadingGameSettings=0
|
||||||
|
|||||||
@@ -55,6 +55,8 @@
|
|||||||
#define HOOK_GAMEMODECHANGE (31)
|
#define HOOK_GAMEMODECHANGE (31)
|
||||||
#define HOOK_USEANIMOBJ (32)
|
#define HOOK_USEANIMOBJ (32)
|
||||||
#define HOOK_EXPLOSIVETIMER (33)
|
#define HOOK_EXPLOSIVETIMER (33)
|
||||||
|
#define HOOK_DESCRIPTIONOBJ (34)
|
||||||
|
#define HOOK_USESKILLON (35)
|
||||||
|
|
||||||
//Valid arguments to list_begin
|
//Valid arguments to list_begin
|
||||||
#define LIST_CRITTERS (0)
|
#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
|
Obj arg1 - the item
|
||||||
|
|
||||||
int ret1 - a pointer to the new text received by using "get_string_pointer" function
|
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_USEANIMOBJ, Inject_UseAnimateObjHook, false},
|
||||||
{HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false},
|
{HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false},
|
||||||
{HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false},
|
{HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false},
|
||||||
|
{HOOK_USESKILLON, Inject_UseSkillOnHook, false},
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HookScripts::injectAllHooks;
|
bool HookScripts::injectAllHooks;
|
||||||
@@ -227,6 +228,7 @@ void HookScripts::init() {
|
|||||||
OnKeyPressed() += KeyPressHook;
|
OnKeyPressed() += KeyPressHook;
|
||||||
OnMouseClick() += MouseClickHook;
|
OnMouseClick() += MouseClickHook;
|
||||||
LoadGameHook::OnGameModeChange() += GameModeChangeHook;
|
LoadGameHook::OnGameModeChange() += GameModeChangeHook;
|
||||||
|
LoadGameHook::OnAfterGameStarted() += SourceUseSkillOnInit;
|
||||||
|
|
||||||
HookScripts::injectAllHooks = (isDebug && (GetConfigInt("Debugging", "InjectAllGameHooks", 0) != 0));
|
HookScripts::injectAllHooks = (isDebug && (GetConfigInt("Debugging", "InjectAllGameHooks", 0) != 0));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ enum HookType
|
|||||||
HOOK_USEANIMOBJ = 32,
|
HOOK_USEANIMOBJ = 32,
|
||||||
HOOK_EXPLOSIVETIMER = 33,
|
HOOK_EXPLOSIVETIMER = 33,
|
||||||
HOOK_DESCRIPTIONOBJ = 34,
|
HOOK_DESCRIPTIONOBJ = 34,
|
||||||
|
HOOK_USESKILLON = 35,
|
||||||
HOOK_COUNT
|
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() {
|
void Inject_BarterPriceHook() {
|
||||||
HookCalls(BarterPriceHook, {
|
HookCalls(BarterPriceHook, {
|
||||||
0x474D4C,
|
0x474D4C,
|
||||||
@@ -440,6 +519,16 @@ void Inject_ExplosiveTimerHook() {
|
|||||||
HookCall(0x49BDC4, 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() {
|
void InitMiscHookScripts() {
|
||||||
|
|
||||||
LoadHookScript("hs_barterprice", HOOK_BARTERPRICE);
|
LoadHookScript("hs_barterprice", HOOK_BARTERPRICE);
|
||||||
@@ -450,6 +539,7 @@ void InitMiscHookScripts() {
|
|||||||
LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR);
|
LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR);
|
||||||
LoadHookScript("hs_resttimer", HOOK_RESTTIMER);
|
LoadHookScript("hs_resttimer", HOOK_RESTTIMER);
|
||||||
LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER);
|
LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER);
|
||||||
|
LoadHookScript("hs_useskillon", HOOK_USESKILLON);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace sfall
|
namespace sfall
|
||||||
{
|
{
|
||||||
void InitMiscHookScripts();
|
void InitMiscHookScripts();
|
||||||
|
void SourceUseSkillOnInit();
|
||||||
|
|
||||||
void Inject_BarterPriceHook();
|
void Inject_BarterPriceHook();
|
||||||
void Inject_UseSkillHook();
|
void Inject_UseSkillHook();
|
||||||
@@ -12,4 +13,5 @@ namespace sfall
|
|||||||
void Inject_SetGlobalVarHook();
|
void Inject_SetGlobalVarHook();
|
||||||
void Inject_RestTimerHook();
|
void Inject_RestTimerHook();
|
||||||
void Inject_ExplosiveTimerHook();
|
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[] = {
|
static const DWORD EncounterTableSize[] = {
|
||||||
0x4BD1A3, 0x4BD1D9, 0x4BD270, 0x4BD604, 0x4BDA14, 0x4BDA44, 0x4BE707,
|
0x4BD1A3, 0x4BD1D9, 0x4BD270, 0x4BD604, 0x4BDA14, 0x4BDA44, 0x4BE707,
|
||||||
0x4C0815, 0x4C0D4A, 0x4C0FD4,
|
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() {
|
void SkipLoadingGameSettingsPatch() {
|
||||||
int skipLoading = GetConfigInt("Misc", "SkipLoadingGameSettings", 0);
|
int skipLoading = GetConfigInt("Misc", "SkipLoadingGameSettings", 0);
|
||||||
if (skipLoading) {
|
if (skipLoading) {
|
||||||
@@ -969,6 +1002,8 @@ void MiscPatches::init() {
|
|||||||
DisplaySecondWeaponRangePatch();
|
DisplaySecondWeaponRangePatch();
|
||||||
KeepWeaponSelectModePatch();
|
KeepWeaponSelectModePatch();
|
||||||
|
|
||||||
|
PartyMemberSkillPatch();
|
||||||
|
|
||||||
SkipLoadingGameSettingsPatch();
|
SkipLoadingGameSettingsPatch();
|
||||||
InterfaceDontMoveOnTopPatch();
|
InterfaceDontMoveOnTopPatch();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -279,7 +279,7 @@ static bool LoadOriginalDll(DWORD dwReason) {
|
|||||||
switch (dwReason) {
|
switch (dwReason) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
char path[MAX_PATH];
|
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);
|
ddraw.dll = LoadLibrary(path);
|
||||||
if (!ddraw.dll || ddraw.dll == INVALID_HANDLE_VALUE) {
|
if (!ddraw.dll || ddraw.dll == INVALID_HANDLE_VALUE) {
|
||||||
MessageBox(0, "Cannot load the original ddraw.dll library.", "sfall", MB_ICONERROR);
|
MessageBox(0, "Cannot load the original ddraw.dll library.", "sfall", MB_ICONERROR);
|
||||||
|
|||||||
Reference in New Issue
Block a user