Fixed NPC stuck in an animation loop in combat (#321)

* this happens when trying to move close to a multihex critter.
This commit is contained in:
NovaRain
2020-07-01 09:47:02 +08:00
parent 467d895ba6
commit 30d249f02e
3 changed files with 67 additions and 49 deletions
+8 -2
View File
@@ -9,10 +9,14 @@ namespace sfall
std::multimap<long, long> writeAddress;
static std::vector<long> excludeAddr = {
static std::vector<long> excludeWarning = {
0x44E949, 0x44E94A, 0x44E937, 0x4F5F40, 0x4CB850, // from movies.cpp
};
static std::vector<long> excludeConflict = {
0x42A0F8, // bugfixes.cpp
};
struct HackPair {
long addr;
long len;
@@ -135,8 +139,10 @@ void PrintAddrList() {
if (diff == 0) {
dlog_f("0x%x L:%d [Overwriting]\n", DL_MAIN, el.addr, el.len);
} else if (diff < pl) {
if (std::find(excludeConflict.cbegin(), excludeConflict.cend(), el.addr) == excludeConflict.cend()) {
dlog_f("0x%x L:%d [Conflict] with 0x%x L:%d\n", DL_MAIN, el.addr, el.len, pa, pl);
MessageBoxA(0, "Conflict detected!", "", MB_TASKMODAL);
}
} else if (level >= 11 && diff == pl) {
dlog_f("0x%x L:%d [Warning] Hacking near:0x%x\n", DL_MAIN, el.addr, el.len, pa);
} else if (level >= 12) {
@@ -149,7 +155,7 @@ void PrintAddrList() {
void CheckConflict(DWORD addr, long len) {
if (writeAddress.find(addr) != writeAddress.cend()) {
if (std::find(excludeAddr.cbegin(), excludeAddr.cend(), addr) != excludeAddr.cend()) return;
if (std::find(excludeWarning.cbegin(), excludeWarning.cend(), addr) != excludeWarning.cend()) return;
char buf[64];
sprintf_s(buf, "Memory overwriting at address 0x%x", addr);
MessageBoxA(0, buf, "", MB_TASKMODAL);
+56 -44
View File
@@ -1237,42 +1237,6 @@ end:
}
}
static void __declspec(naked) wmTeleportToArea_hack() {
static const DWORD wmTeleportToArea_Ret = 0x4C5A77;
__asm {
xor ecx, ecx;
cmp ebx, ds:[FO_VAR_WorldMapCurrArea];
je end;
mov ds:[FO_VAR_WorldMapCurrArea], ebx;
sub eax, edx;
add eax, ds:[FO_VAR_wmAreaInfoList];
cmp dword ptr [eax + 0x34], 1; // wmAreaInfoList.size
mov edx, [eax + 0x30]; // wmAreaInfoList.world_posy
mov eax, [eax + 0x2C]; // wmAreaInfoList.world_posx
jg largeLoc;
je mediumLoc;
//smallLoc:
sub eax, 5;
lea edx, [edx - 5];
mediumLoc:
sub eax, 10
lea edx, [edx - 10];
// check negative values
test eax, eax;
cmovl eax, ecx;
test edx, edx;
cmovl edx, ecx;
largeLoc:
mov ds:[FO_VAR_world_ypos], edx;
mov ds:[FO_VAR_world_xpos], eax;
end:
mov ds:[FO_VAR_target_xpos], ecx;
mov ds:[FO_VAR_target_ypos], ecx;
mov ds:[FO_VAR_In_WorldMap], ecx;
jmp wmTeleportToArea_Ret;
}
}
static void __declspec(naked) db_get_file_list_hack() {
__asm {
push edi
@@ -2337,6 +2301,42 @@ static void __declspec(naked) action_climb_ladder_hack() {
}
}
static void __declspec(naked) wmTeleportToArea_hack() {
static const DWORD wmTeleportToArea_Ret = 0x4C5A77;
__asm {
xor ecx, ecx;
cmp ebx, ds:[FO_VAR_WorldMapCurrArea];
je end;
mov ds:[FO_VAR_WorldMapCurrArea], ebx;
sub eax, edx;
add eax, ds:[FO_VAR_wmAreaInfoList];
cmp dword ptr [eax + 0x34], 1; // wmAreaInfoList.size
mov edx, [eax + 0x30]; // wmAreaInfoList.world_posy
mov eax, [eax + 0x2C]; // wmAreaInfoList.world_posx
jg largeLoc;
je mediumLoc;
//smallLoc:
sub eax, 5;
lea edx, [edx - 5];
mediumLoc:
sub eax, 10
lea edx, [edx - 10];
// check negative values
test eax, eax;
cmovl eax, ecx;
test edx, edx;
cmovl edx, ecx;
largeLoc:
mov ds:[FO_VAR_world_ypos], edx;
mov ds:[FO_VAR_world_xpos], eax;
end:
mov ds:[FO_VAR_target_xpos], ecx;
mov ds:[FO_VAR_target_ypos], ecx;
mov ds:[FO_VAR_In_WorldMap], ecx;
jmp wmTeleportToArea_Ret;
}
}
static void __declspec(naked) wmAreaMarkVisitedState_hack() {
static const DWORD wmAreaMarkVisitedState_Ret = 0x4C46A2;
//static const DWORD wmAreaMarkVisitedState_Error = 0x4C4698;
@@ -3010,13 +3010,6 @@ void BugFixes::init()
// Fix for checking the horizontal position on the y-axis instead of x when setting coordinates on the world map
SafeWrite8(0x4C4743, 0xC6); // cmp esi, eax
// Partial fix for incorrect positioning after exiting small/medium locations (e.g. Ghost Farm)
//if (GetConfigInt("Misc", "SmallLocExitFix", 1)) {
dlog("Applying fix for incorrect positioning after exiting small/medium locations.", DL_INIT);
MakeJump(0x4C5A41, wmTeleportToArea_hack);
dlogr(" Done", DL_INIT);
//}
//if (GetConfigInt("Misc", "PrintToFileFix", 1)) {
dlog("Applying print to file fix.", DL_INIT);
MakeCall(0x4C67D4, db_get_file_list_hack);
@@ -3332,6 +3325,13 @@ void BugFixes::init()
MakeCall(0x411FD6, action_use_an_item_on_object_hack);
MakeCall(0x411DF7, action_climb_ladder_hack); // bug caused by anim_move_to_tile_ fix
// Partial fix for incorrect positioning after exiting small/medium locations (e.g. Ghost Farm)
//if (GetConfigInt("Misc", "SmallLocExitFix", 1)) {
dlog("Applying fix for incorrect positioning after exiting small/medium locations.", DL_INIT);
MakeJump(0x4C5A41, wmTeleportToArea_hack);
dlogr(" Done", DL_INIT);
//}
// Fix for Scout perk being taken into account when setting the visibility of locations with mark_area_known function
// also fix the incorrect coordinates for small/medium location circles that the engine uses to highlight their sub-tiles
// and fix visited tiles on the world map being darkened again when a location is added next to them
@@ -3417,7 +3417,19 @@ void BugFixes::init()
0x74, 0x1A, // jz 0x426D83
0x90
};
SafeWriteBytes(0x426D5C, codeData, 14);
SafeWriteBytes(0x426D5C, codeData, 14); // combat_is_shot_blocked_
// Fix for NPC stuck in an animation loop in combat when trying to move close to a multihex critter
// this prevents moving to the multihex critter when the critters are close together
BYTE codeData1[] = {
0x89, 0xF0, // mov eax, esi
0x89, 0xFA, // mov edx, edi
0xE8, 0x00, 0x00, 0x0, 0x0, // call obj_dist_
0x83, 0xF8, 0x01, // cmp eax, 1
0x0F, 0x8E, 0xAB, 0x0, 0x0, 0x0, // jle 0x42A1B1 (exit)
};
SafeWriteBytes(0x42A0F4, codeData1, 18); // ai_move_steps_closer_
HookCall(0x42A0F8, (void*)fo::funcoffs::obj_dist_);
}
}
+1 -1
View File
@@ -103,7 +103,7 @@ static void __declspec(naked) intface_item_reload_hook() {
mov eax, dword ptr ds:[FO_VAR_obj_dude];
call fo::funcoffs::register_clear_;
xor edx, edx; // ANIM_stand
xor ebx, ebx; // no delay
xor ebx, ebx; // delay (unused)
lea eax, [edx + 1]; // RB_UNRESERVED
call fo::funcoffs::register_begin_;
mov eax, dword ptr ds:[FO_VAR_obj_dude];