mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added more fixes for the arguments of attack_complex function:
* fixed result flags for the attacker and the target when calling attack_complex function (#323) * tweaked how attacker_results/target_results work when AttackComplexFix is enabled. Minor code edits.
This commit is contained in:
+3
-4
@@ -587,11 +587,10 @@ ObjCanHearObjFix=0
|
|||||||
;If the argument value is -1, the mood will be determined by the local variable 0 of the script (vanilla behavior)
|
;If the argument value is -1, the mood will be determined by the local variable 0 of the script (vanilla behavior)
|
||||||
StartGDialogFix=0
|
StartGDialogFix=0
|
||||||
|
|
||||||
;Set to 1 to fix and repurpose the unused called_shot/num_attacks arguments of attack_complex script function
|
;Set to 1 to fix attacker_results/target_results arguments and repurpose the unused called_shot/num_attacks arguments of attack_complex script function
|
||||||
;This also changes the behavior of the result flags arguments
|
;New behavior of the arguments:
|
||||||
;called_shot - additional damage, when the damage received by the target is above the specified minimum damage
|
;called_shot - additional damage, when the damage received by the target is above the specified minimum damage (minDmg argument)
|
||||||
;num_attacks - the number of free action points on the first turn only
|
;num_attacks - the number of free action points on the first turn only
|
||||||
;attacker_results - unused, must be 0 or not equal to the target_results argument when specifying result flags for the target
|
|
||||||
AttackComplexFix=0
|
AttackComplexFix=0
|
||||||
|
|
||||||
;Set to 1 to fix the issue with the division operator treating negative integers as unsigned
|
;Set to 1 to fix the issue with the division operator treating negative integers as unsigned
|
||||||
|
|||||||
@@ -2012,6 +2012,69 @@ static void __declspec(naked) op_attack_hook() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) op_attack_hook_flags() {
|
||||||
|
__asm {
|
||||||
|
and eax, 0xFF;
|
||||||
|
test ebp, ebp;
|
||||||
|
jz skip;
|
||||||
|
or al, 2; // set bit 2
|
||||||
|
skip:
|
||||||
|
// EAX: gcsd.changeFlags contains the attribute value for setting the flags
|
||||||
|
// bit 1 - set result flags for target, bit 2 - set result flags for attacker
|
||||||
|
test eax, eax;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) combat_attack_hack_gcsdFlags() {
|
||||||
|
__asm {
|
||||||
|
mov ebp, [eax + 0x24]; // gcsd.flagsTarget
|
||||||
|
mov ebx, [eax + 0x1C]; // gcsd.changeFlags
|
||||||
|
test bl, 2;
|
||||||
|
jz checkTarget;
|
||||||
|
// set source
|
||||||
|
mov eax, ds:[FO_VAR_main_ctd + 0x14]; // flagsSource
|
||||||
|
and eax, DAM_DEAD;
|
||||||
|
or edx, eax; // don't unset DAM_DEAD flag
|
||||||
|
mov ds:[FO_VAR_main_ctd + 0x14], edx; // flagsSource
|
||||||
|
checkTarget:
|
||||||
|
mov eax, ds:[FO_VAR_main_ctd + 0x30]; // flagsTarget
|
||||||
|
test bl, 1;
|
||||||
|
jnz setTarget;
|
||||||
|
retn;
|
||||||
|
setTarget:
|
||||||
|
and eax, DAM_DEAD;
|
||||||
|
or ebp, eax; // don't unset DAM_DEAD flag
|
||||||
|
mov eax, ebp;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) combat_attack_hack_gcsdMinDamage() {
|
||||||
|
__asm {
|
||||||
|
mov ds:[FO_VAR_main_ctd + 0x2C], ecx; // amountTarget (min)
|
||||||
|
mov edx, ecx;
|
||||||
|
lea ebx, ds:[FO_VAR_main_ctd + 0x30]; // flagsTarget
|
||||||
|
mov eax, ds:[FO_VAR_main_ctd + 0x20]; // Target
|
||||||
|
jmp fo::funcoffs::check_for_death_; // set DAM_DEAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) combat_attack_hack_gcsdMaxDamage() {
|
||||||
|
__asm {
|
||||||
|
mov ds:[FO_VAR_main_ctd + 0x2C], ebp; // amountTarget (max)
|
||||||
|
mov eax, ds:[FO_VAR_main_ctd + 0x20]; // Target
|
||||||
|
call fo::funcoffs::critter_get_hits_;
|
||||||
|
cmp eax, ebp; // curr.HP <= max.DMG
|
||||||
|
jle skip;
|
||||||
|
cmp eax, edx; // curr.HP > curr.DMG
|
||||||
|
jg skip;
|
||||||
|
and byte ptr ds:[FO_VAR_main_ctd + 0x30], ~DAM_DEAD; // flagsTarget (unset)
|
||||||
|
skip:
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void __declspec(naked) combat_attack_hack() {
|
static void __declspec(naked) combat_attack_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
mov ebx, ds:[FO_VAR_main_ctd + 0x2C]; // amountTarget
|
mov ebx, ds:[FO_VAR_main_ctd + 0x2C]; // amountTarget
|
||||||
@@ -3148,7 +3211,7 @@ void BugFixes::init()
|
|||||||
|
|
||||||
// Fix for the encounter description being displayed in two lines instead of one
|
// Fix for the encounter description being displayed in two lines instead of one
|
||||||
SafeWrite32(0x4C1011, 0x9090C789); // mov edi, eax;
|
SafeWrite32(0x4C1011, 0x9090C789); // mov edi, eax;
|
||||||
SafeWrite8(0x4C1015, 0x90);
|
SafeWrite8(0x4C1015, CodeType::Nop);
|
||||||
HookCall(0x4C1042, wmSetupRandomEncounter_hook);
|
HookCall(0x4C1042, wmSetupRandomEncounter_hook);
|
||||||
|
|
||||||
// Fix for being unable to sell/give items in the barter screen when the player/party member is overloaded
|
// Fix for being unable to sell/give items in the barter screen when the player/party member is overloaded
|
||||||
@@ -3217,18 +3280,28 @@ void BugFixes::init()
|
|||||||
HookCall(0x4C6162, db_freadInt_hook);
|
HookCall(0x4C6162, db_freadInt_hook);
|
||||||
|
|
||||||
// Fix and repurpose the unused called_shot/num_attack arguments of attack_complex function
|
// Fix and repurpose the unused called_shot/num_attack arguments of attack_complex function
|
||||||
// also change the behavior of the result flags arguments
|
|
||||||
// called_shot - additional damage, when the damage received by the target is above the specified minimum
|
// called_shot - additional damage, when the damage received by the target is above the specified minimum
|
||||||
// num_attacks - the number of free action points on the first turn only
|
// num_attacks - the number of free action points on the first turn only
|
||||||
// attacker_results - unused, must be 0 or not equal to the target_results argument when specifying result flags for the target
|
|
||||||
if (GetConfigInt("Misc", "AttackComplexFix", 0)) {
|
if (GetConfigInt("Misc", "AttackComplexFix", 0)) {
|
||||||
dlog("Applying attack_complex fix.", DL_INIT);
|
dlog("Applying attack_complex arguments fix.", DL_INIT);
|
||||||
HookCall(0x456D4A, op_attack_hook);
|
HookCall(0x456D4A, op_attack_hook);
|
||||||
SafeWrite8(0x456D61, 0x74); // mov [esp+x], esi
|
SafeWrite8(0x456D61, 0x74); // mov [esp+x], esi
|
||||||
SafeWrite8(0x456D92, 0x5C); // mov [esp+x], ebx
|
SafeWrite8(0x456D92, 0x5C); // mov [esp+x], ebx
|
||||||
SafeWrite8(0x456D98, 0x94); // setnz > setz (fix setting result flags)
|
|
||||||
|
// Fix setting result flags arguments for the attacker and the target (now work independently of each other)
|
||||||
|
SafeWrite16(0x456D95, 0xC085); // cmp eax, ebx > test eax, eax
|
||||||
|
MakeCall(0x456D9A, op_attack_hook_flags);
|
||||||
|
SafeWrite8(0x456D9F, CodeType::JumpNZ); // jz > jnz
|
||||||
|
SafeWrite16(0x456DA7, 0x8489); // mov [gcsd.changeFlags], 1 > mov [gcsd.changeFlags], eax
|
||||||
|
SafeWrite8(0x456DAB, 0);
|
||||||
|
SafeWrite8(0x456DAE, CodeType::Nop);
|
||||||
dlogr(" Done", DL_INIT);
|
dlogr(" Done", DL_INIT);
|
||||||
}
|
}
|
||||||
|
// Fix result flags for the attacker and the target when calling attack_complex function
|
||||||
|
MakeCall(0x42302B, combat_attack_hack_gcsdFlags, 4);
|
||||||
|
// Set/Unset the DAM_DEAD flag when changing the minimum/maximum damage to the target
|
||||||
|
MakeCall(0x422FFF, combat_attack_hack_gcsdMinDamage, 1);
|
||||||
|
MakeCall(0x423017, combat_attack_hack_gcsdMaxDamage, 1);
|
||||||
|
|
||||||
// Fix for attack_complex still causing minimum damage to the target when the attacker misses
|
// Fix for attack_complex still causing minimum damage to the target when the attacker misses
|
||||||
MakeCall(0x422FE5, combat_attack_hack, 1);
|
MakeCall(0x422FE5, combat_attack_hack, 1);
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ void Drugs::init() {
|
|||||||
MakeCall(0x47A5B8, pid_to_gvar_hack, 1);
|
MakeCall(0x47A5B8, pid_to_gvar_hack, 1);
|
||||||
MakeCall(0x47A50C, perform_withdrawal_start_hack);
|
MakeCall(0x47A50C, perform_withdrawal_start_hack);
|
||||||
SafeWrite32(0x47A523, 0x9090EBD1); // shr ebx, 1 (fix for trait drug addict)
|
SafeWrite32(0x47A523, 0x9090EBD1); // shr ebx, 1 (fix for trait drug addict)
|
||||||
SafeWrite8(0x47A527, 0x90);
|
SafeWrite8(0x47A527, CodeType::Nop);
|
||||||
|
|
||||||
if (addictionGvarCount) {
|
if (addictionGvarCount) {
|
||||||
LoadGameHook::OnAfterGameInit() += CheckValidGvarNumber;
|
LoadGameHook::OnAfterGameInit() += CheckValidGvarNumber;
|
||||||
|
|||||||
@@ -1496,7 +1496,7 @@ static void EnableHeroAppearanceMod() {
|
|||||||
HookCall(0x42613A, FixPcCriticalHitMsg);
|
HookCall(0x42613A, FixPcCriticalHitMsg);
|
||||||
|
|
||||||
// Force Criticals For Testing
|
// Force Criticals For Testing
|
||||||
//SafeMemSet(0x423A8F, 0x90, 8);
|
//SafeMemSet(0x423A8F, CodeType::Nop, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HeroAppearanceModExit() {
|
static void HeroAppearanceModExit() {
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ static void KillCounterInit() {
|
|||||||
|
|
||||||
// Overwrite the critter_kill_count_inc_ function that increments the kill counter
|
// Overwrite the critter_kill_count_inc_ function that increments the kill counter
|
||||||
MakeCall(0x42D89C, IncKillCounter, 1);
|
MakeCall(0x42D89C, IncKillCounter, 1);
|
||||||
SafeWrite8(0x42D88E, 0x45); // lea edx, [eax * 2]
|
SafeWrite8(0x42D88E, 0x45); // lea edx, [eax * 2]
|
||||||
SafeWrite8(0x42D899, 0x90); // inc ebx > nop
|
SafeWrite8(0x42D899, CodeType::Nop); // inc ebx > nop
|
||||||
|
|
||||||
const DWORD extraKillTypesCountAddr[] = {
|
const DWORD extraKillTypesCountAddr[] = {
|
||||||
0x42D8AF, // critter_kill_count_
|
0x42D8AF, // critter_kill_count_
|
||||||
|
|||||||
@@ -245,8 +245,8 @@ static void GetExtraPatches() {
|
|||||||
static void MultiPatchesPatch() {
|
static void MultiPatchesPatch() {
|
||||||
//if (GetConfigInt("Misc", "MultiPatches", 0)) {
|
//if (GetConfigInt("Misc", "MultiPatches", 0)) {
|
||||||
dlog("Applying load multiple patches patch.", DL_INIT);
|
dlog("Applying load multiple patches patch.", DL_INIT);
|
||||||
SafeWrite8(0x444354, 0x90); // Change step from 2 to 1
|
SafeWrite8(0x444354, CodeType::Nop); // Change step from 2 to 1
|
||||||
SafeWrite8(0x44435C, 0xC4); // Disable check
|
SafeWrite8(0x44435C, 0xC4); // Disable check
|
||||||
dlogr(" Done", DL_INIT);
|
dlogr(" Done", DL_INIT);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ void Objects::init() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
HookCall(0x4A38A5, new_obj_id_hook);
|
HookCall(0x4A38A5, new_obj_id_hook);
|
||||||
SafeWrite8(0x4A38B3, 0x90); // fix ID increment
|
SafeWrite8(0x4A38B3, CodeType::Nop); // fix ID increment
|
||||||
|
|
||||||
MakeCall(0x477A0E, item_identical_hack); // don't put item with unique ID to items stack
|
MakeCall(0x477A0E, item_identical_hack); // don't put item with unique ID to items stack
|
||||||
|
|
||||||
|
|||||||
@@ -247,9 +247,9 @@ static void __cdecl IncNPCLevel(const char* fmt, const char* name) {
|
|||||||
|
|
||||||
SafeWrite32(0x495C50, 0x01FB840F); // Want to keep this check intact. (restore)
|
SafeWrite32(0x495C50, 0x01FB840F); // Want to keep this check intact. (restore)
|
||||||
|
|
||||||
SafeMemSet(0x495C77, 0x90, 6); // Check that the player is high enough for the npc to consider this level
|
SafeMemSet(0x495C77, CodeType::Nop, 6); // Check that the player is high enough for the npc to consider this level
|
||||||
//SafeMemSet(0x495C8C, 0x90, 6); // Check that the npc isn't already at its maximum level
|
//SafeMemSet(0x495C8C, CodeType::Nop, 6); // Check that the npc isn't already at its maximum level
|
||||||
SafeMemSet(0x495CEC, 0x90, 6); // Check that the npc hasn't already levelled up recently
|
SafeMemSet(0x495CEC, CodeType::Nop, 6); // Check that the npc hasn't already levelled up recently
|
||||||
if (!npcAutoLevelEnabled) {
|
if (!npcAutoLevelEnabled) {
|
||||||
SafeWrite8(0x495CFB, CodeType::JumpShort); // Disable random element
|
SafeWrite8(0x495CFB, CodeType::JumpShort); // Disable random element
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,9 +170,9 @@ static void CreateSndWnd() {
|
|||||||
static DWORD GetSpeechDurationTime() {
|
static DWORD GetSpeechDurationTime() {
|
||||||
if (!speechSound || !speechSound->pSeek) return 0;
|
if (!speechSound || !speechSound->pSeek) return 0;
|
||||||
speechSound->pSeek->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
|
speechSound->pSeek->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
|
||||||
__int64 outVal;
|
__int64 outVal = -1;
|
||||||
speechSound->pSeek->GetDuration(&outVal);
|
speechSound->pSeek->GetDuration(&outVal);
|
||||||
return static_cast<DWORD>(outVal / 10000000) + 1;
|
return (outVal != -1) ? static_cast<DWORD>(outVal / 10000000) + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD GetSpeechPlayingPosition() {
|
static DWORD GetSpeechPlayingPosition() {
|
||||||
@@ -860,8 +860,8 @@ void Sound::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int sBuff = GetConfigInt("Sound", "NumSoundBuffers", 0);
|
int sBuff = GetConfigInt("Sound", "NumSoundBuffers", 0);
|
||||||
if (sBuff > 0 && sBuff <= 32) {
|
if (sBuff > 0) {
|
||||||
SafeWrite8(0x451129, (BYTE)sBuff);
|
SafeWrite8(0x451129, (sBuff > 32) ? (BYTE)32 : (BYTE)sBuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetConfigInt("Sound", "AllowSoundForFloats", 0)) {
|
if (GetConfigInt("Sound", "AllowSoundForFloats", 0)) {
|
||||||
|
|||||||
@@ -384,8 +384,8 @@ static void TimeLimitPatch() {
|
|||||||
0x4A34EF, // inc_game_time_
|
0x4A34EF, // inc_game_time_
|
||||||
0x4A3547 // inc_game_time_in_seconds_
|
0x4A3547 // inc_game_time_in_seconds_
|
||||||
});
|
});
|
||||||
SafeMemSet(0x4A34F4, 0x90, 16);
|
SafeMemSet(0x4A34F4, CodeType::Nop, 16);
|
||||||
SafeMemSet(0x4A354C, 0x90, 16);
|
SafeMemSet(0x4A354C, CodeType::Nop, 16);
|
||||||
} else {
|
} else {
|
||||||
SafeWrite8(0x4A34EC, limit);
|
SafeWrite8(0x4A34EC, limit);
|
||||||
SafeWrite8(0x4A3544, limit);
|
SafeWrite8(0x4A3544, limit);
|
||||||
|
|||||||
Reference in New Issue
Block a user