From b634ef77bc18468501039378c670c4eeb048c6e6 Mon Sep 17 00:00:00 2001 From: Resurrected Trader Date: Sun, 11 Oct 2026 10:57:53 +0100 Subject: [PATCH] Scan target list slot 8 in sub_6FCF2110 After the eight player slots, the evil-alignment branch of sub_6FCF2110 walks a further target list. MOO walked whatever pTargetNode was left over from the player loop (slot 7's head, or nullptr), so the slot 8 list was never scanned. The game loads the next slot's head at the end of every player-slot iteration, so after slot 7 it holds pGame->pTargetNodes[8]. 1.10f (D2Game.0x6FCF2110), Hex-Rays (a1 = pGame, 4344 = 0x10F8 = pTargetNodes): v12 = *(int ***)(a1 + 4344); // pTargetNodes[0] v69 = (int *)(a1 + 4344); ... for ( i = 0; i < 8; ++i ) { ... v12 = (int **)*++v69; // next slot's head } for ( ; v12 != nullptr; v12 = (int **)v12[2] ) // slot 8 { ... } v44 = v69; v46 = (int **)v44[1]; // slot 9 Disassembly: 6FCF21A2 mov ebp, [edi+10F8h] ; pTargetNodes[0] 6FCF21A8 lea eax, [edi+10F8h] ; &pTargetNodes[0] 6FCF21B0 mov [esp+2Ch], eax ... 6FCF246E mov eax, [esp+2Ch] ; every player-slot path ends here 6FCF2472 add eax, 4 6FCF2475 mov [esp+2Ch], eax 6FCF2479 mov ebp, [eax] ; next slot's head 6FCF247B mov eax, [esp+38h] ; slot counter 6FCF247F inc eax 6FCF2480 cmp eax, 8 6FCF2487 jl 6FCF22E7 6FCF248D test ebp, ebp ; walk slot 8 6FCF248F jz 6FCF2551 ... 6FCF2551 mov eax, [esp+2Ch] ; &pTargetNodes[8] 6FCF2562 mov ebp, [eax+4] ; pTargetNodes[9], the list that follows 1.14d (Game.exe 0x005DD7F0) is the same: each iteration ends with v10 = *(int **)(v37 + 4); v37 += 4; (0x005DDA20 mov ebx, [eax+4]), then the bare for ( ; v10 != nullptr; ...) loop at 0x005DDA3B. Co-Authored-By: Claude Opus 5.5 (1M context) --- source/D2Game/src/AI/AiUtil.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/D2Game/src/AI/AiUtil.cpp b/source/D2Game/src/AI/AiUtil.cpp index e36eb1f30..da176e0b2 100644 --- a/source/D2Game/src/AI/AiUtil.cpp +++ b/source/D2Game/src/AI/AiUtil.cpp @@ -668,6 +668,7 @@ void __fastcall sub_6FCF20E0(D2UnitStrc* pUnit, void* pArg, void* ppUnit) } //D2Game.0x6FCF2110 +//1.14d: 0x005DD7F0 D2UnitStrc* __fastcall sub_6FCF2110(D2GameStrc* pGame, D2UnitStrc* pUnit, D2AiControlStrc* pAiControl, int32_t* pDistance, int32_t* pCombat) { D2ActiveRoomStrc* pRoom = UNITS_GetRoom(pUnit); @@ -796,6 +797,8 @@ D2UnitStrc* __fastcall sub_6FCF2110(D2GameStrc* pGame, D2UnitStrc* pUnit, D2AiCo } } + // The player loop leaves the next slot's head behind, which is slot 8 after the last player slot. + pTargetNode = pGame->pTargetNodes[8]; while (pTargetNode) { if (pUnit->nAct == pTargetNode->pUnit->nAct)