I've looked into how LoS works to fix guided arrow today (which I did manage to do, more on that at a later time). In the process I ran across the function that parses aurafilters, GA and many other skills use hardcoded aurafilters.
Here is what I managed to uncover and the parsing code (an identical copy of this code also exists inside D2Client.dll)
Code: Select all
L
1 1 1 FindPlayers
2 2 2 FindMonsters
3 4 4 FindOnlyUndead
4 8 8 FindMissiles (will not find missiles with 'explosion' set to true)
5 10 10 FindObjects
6 20 20 FindItems
8 80 80 target units flagged as IsAtt in monstats2
H
9 1 100 NotInsideTowns
10 2 200 UseLineOfSight
11 4 400 target units that are selectable (also checked by curse funcs manually)
13 10 1000 FindCorpses (of monsters and players)
14 20 2000 NotInsideTowns(B)
15 40 4000 IgnoreSpecialMonsters (those set to 'boss' in MonStats)
16 80 8000 IgnoreAllies? (will return true when the unit is not allied with the player)
17 1 10000 TargetAllies? (if the unit is set as 'npc' in MonStats it will be ignored)
18 2 20000 This is a very specific test, testing for tentacle1-3 for example
19 4 40000 IgnorePrimeEvils (those set to 'primeevil' in MonStats)
20 8 80000 IgnoreJustHitUnits (used by chainlightning, which sets state_JustHit on whatever it hits, and this prevents the same target from being picked twice)
[ flags 7, 12, and 21-32 are unused ]
Slow Missiles - players, monsters, legaltargets, ignoretowns, legaltargets2, ignorespecial, ignoreallies,
Lightning Fury & Conviction - players, monsters, legaltargets, ignoretowns, legaltargets2, ignoretownsB (overrides all others), ignoreallies,
Static Field - players, monsters, legaltargets, ignoretowns, LoS, legaltargets2, ignoreallies,
Curse (stats) - players, monsters
Curse (AI) - monsters
Aura (stats) - players, monsters, ignoretownsB (overrides all others), targetallies,
Aura (damage) - players, monsters, legaltargets, ignoretowns, LoS, ignoretownsB (overrides all others), ignoreallies,
Aura (freeze) - players, monsters, legaltargets, LoS, legaltargets2, ignoretownsB (overrides all others), ignoreallies, ignoreprimeevils
Sanctuary - monsters, onlyUndead, legaltargets, ignoretowns, LoS, legaltargets2, ignoretownsB (overrides all others), ignorespecial, ignoreallies,
FoH - players, monsters, onlyUndead, legaltargets, ignoretowns,, legaltargets2, ignoretownsB (overrides all others), ignoreallies,
Redemption - monsters, ignoretowns, corpsesonly
Battle Cry - ignoreallies, targetallies, (...)
Cloak of Shadows - players, monsters, ignoretownsB (overrides all others), ignorespecial, ignoreallies,
Mind Blast & Blade Shield - players, monsters, legaltargets, ignoretowns, LoS, ignoreallies,
Blades Of Ice - players, monsters, missiles (bug I guess), ignoretowns, LoS, legaltargets2, ignoreallies,
Druid Spirit Aura - players, monsters, ignoretowns, targetallies,
Server Side Parsing Code
Code: Select all
6FC2F380 SUB ESP,10
6FC2F383 TEST EDI,EDI edi = unit
6FC2F385 PUSH EBX
6FC2F386 PUSH ESI
6FC2F387 MOV EBX,EAX ebx = flags
6FC2F389 MOV ESI,ECX esi = player
6FC2F38B JE SHORT D2GAME.6FC2F3B1 (unit = null) -> ret 0
6FC2F38D MOV EAX,[EDI]
6FC2F38F CMP EAX,4
6FC2F392 JA SHORT D2GAME.6FC2F3B1
6FC2F394 JMP [EAX*4+6FC2F620] (switch unit->eType)
[ case player ]
6FC2F39B TEST BL,1
6FC2F39E JE SHORT D2GAME.6FC2F3B1 (flags.FindPlayers == false) -> exit
6FC2F3A0 TEST BH,10
6FC2F3A3 MOV EAX,[EDI+10]
6FC2F3A6 JE SHORT D2GAME.6FC2F3B9 (flags.FindCorpses == false) -> next
6FC2F3A8 CMP EAX,11
6FC2F3AB JE D2GAME.6FC2F461 (unit->mode == PLRMODE_DEAD) -> all
[ case tile ]
6FC2F3B1 POP ESI
6FC2F3B2 XOR EAX,EAX
6FC2F3B4 POP EBX
6FC2F3B5 ADD ESP,10
6FC2F3B8 RETN
[ player cont ]
6FC2F3B9 CMP EAX,11
6FC2F3BC JE SHORT D2GAME.6FC2F3B1 (unit->mode == PLRMODE_DEAD) -> exit
6FC2F3BE TEST EAX,EAX
6FC2F3C0 JNZ D2GAME.6FC2F461 (unit->mode != PLRMODE_DEATH) -> all
6FC2F3C6 POP ESI
6FC2F3C7 POP EBX
6FC2F3C8 ADD ESP,10
6FC2F3CB RETN
[ case monster ]
6FC2F3CC TEST BL,2
6FC2F3CF JE SHORT D2GAME.6FC2F3B1 (flags.FindMonsters == false) -> exit
6FC2F3D1 TEST BH,10
6FC2F3D4 MOV EAX,[EDI+10]
6FC2F3D7 JE SHORT D2GAME.6FC2F3E6 (flags.FindCorpses == false) -> next
6FC2F3D9 CMP EAX,0C
6FC2F3DC JE SHORT D2GAME.6FC2F3EF (unit->mode == MONMODE_DEAD) -> next
6FC2F3DE POP ESI
6FC2F3DF XOR EAX,EAX
6FC2F3E1 POP EBX
6FC2F3E2 ADD ESP,10
6FC2F3E5 RETN
6FC2F3E6 CMP EAX,0C
6FC2F3E9 JE SHORT D2GAME.6FC2F3B1 (unit->mode == MONMODE_DEAD) -> exit
6FC2F3EB TEST EAX,EAX
6FC2F3ED JE SHORT D2GAME.6FC2F3B1 (unit->mode == MONMODE_DEATH) -> exit
6FC2F3EF TEST BL,4
6FC2F3F2 JE SHORT D2GAME.6FC2F3FE (flags.FindUndead == false) -> next
6FC2F3F4 PUSH EDI
6FC2F3F5 CALL <JMP.&D2Common.#10833>
6FC2F3FA TEST EAX,EAX
6FC2F3FC JE SHORT D2GAME.6FC2F3B1 (unit != UNDEAD) -> exit
6FC2F3FE TEST BH,40
6FC2F401 JE SHORT D2GAME.6FC2F40F (flags.IgnoreSpecial == false) -> next
6FC2F403 PUSH EDI
6FC2F404 PUSH 0
6FC2F406 CALL <JMP.&D2Common.#11056> check if unit is special (set to boss in monstats)
6FC2F40B TEST EAX,EAX
6FC2F40D JNZ SHORT D2GAME.6FC2F3B1 (unit is special) -> exit
6FC2F40F TEST EBX,40000
6FC2F415 JE SHORT D2GAME.6FC2F461 (flags.IgnorePrimeEvils == false) -> all
6FC2F417 PUSH EDI
6FC2F418 CALL <JMP.&D2Common.#10529>
6FC2F41D TEST EAX,EAX
6FC2F41F JMP SHORT D2GAME.6FC2F3AB
[ case object ]
6FC2F421 TEST BL,10
6FC2F424 JNZ SHORT D2GAME.6FC2F461 (flags.FindObjects == true) -> all
6FC2F426 POP ESI
6FC2F427 XOR EAX,EAX
6FC2F429 POP EBX
6FC2F42A ADD ESP,10
6FC2F42D RETN
[ case missile ]
6FC2F42E TEST BL,8
6FC2F431 JE D2GAME.6FC2F3B1 (flags.FindMissiles == false) -> exit
6FC2F437 MOV EAX,[EDI+4]
6FC2F43A CALL D2GAME.6FC21310
6FC2F43F TEST EAX,EAX
6FC2F441 JE D2GAME.6FC2F3B1 (pRecord of missile is null) -> exit
6FC2F447 MOV ECX,[<&Fog.gdwBitMasks>]
6FC2F44D MOV AL,[EAX+4]
6FC2F450 TEST [ECX+4],AL check missile.IsExplosion
6FC2F453 JMP D2GAME.6FC2F3AB
[ case item ]
6FC2F458 TEST BL,20
6FC2F45B JE D2GAME.6FC2F3B1 (flags.FindItems == false) -> exit
[ all ]
6FC2F461 TEST BL,BL
6FC2F463 JNS SHORT D2GAME.6FC2F47B (flags.8 == false) -> next
6FC2F465 MOV EDX,[EDI+C4] edx = unit->flags
6FC2F46B SHR EDX,2 flags / 4
6FC2F46E AND EDX,1 check flag.3
6FC2F471 MOV [ESP+8],EDX
6FC2F475 JE D2GAME.6FC2F3B1 (flag.3 = false) -> exit
6FC2F47B TEST BH,4
6FC2F47E JE SHORT D2GAME.6FC2F496 (flags.40 == false) -> next
6FC2F480 MOV EAX,[EDI+C4] eax = unit->flags
6FC2F486 SHR EAX,3 flags / 8
6FC2F489 AND EAX,1 check flag.4
6FC2F48C MOV [ESP+8],EAX
6FC2F490 JE D2GAME.6FC2F3B1 (flag.4 = false) -> exit
6FC2F496 TEST BH,1
6FC2F499 JE SHORT D2GAME.6FC2F4AF (flags.FindInsideTowns == false) -> next
6FC2F49B PUSH EDI
6FC2F49C CALL <JMP.&D2Common.#10933> get room from unit
6FC2F4A1 PUSH EAX
6FC2F4A2 CALL <JMP.&D2Common.#10845> check if room is inside town
6FC2F4A7 TEST EAX,EAX
6FC2F4A9 JNZ D2GAME.6FC2F3B1 (exit if room is inside town)
6FC2F4AF TEST EBX,10000
6FC2F4B5 JE SHORT D2GAME.6FC2F517 (flags.targetowners == false) -> next
6FC2F4B7 TEST ESI,ESI
6FC2F4B9 JE SHORT D2GAME.6FC2F4D9 (pUnit == null) -> skip
6FC2F4BB CMP [ESI],3
6FC2F4BE JNZ SHORT D2GAME.6FC2F4D9 (pUnit != missile) -> skip
6FC2F4C0 MOV EAX,ESI
6FC2F4C2 CALL D2GAME.6FCDE540 get game from unit
6FC2F4C7 PUSH EAX
6FC2F4C8 MOV EAX,ESI
6FC2F4CA CALL D2GAME.6FCDF3F0 get missile owner
6FC2F4CF TEST EAX,EAX
6FC2F4D1 JE D2GAME.6FC2F3B1 (owner == null) -> exit
6FC2F4D7 MOV ESI,EAX
6FC2F4D9 MOV EAX,ESI
6FC2F4DB CALL D2GAME.6FCDE540 get game from owner or unit
6FC2F4E0 MOV EAX,EDI
6FC2F4E2 MOV ECX,ESI
6FC2F4E4 CALL D2GAME.6FCDF0B0 get owner of unit
6FC2F4E9 TEST EAX,EAX
6FC2F4EB JE D2GAME.6FC2F3B1 (no owner of summon found) -> exit
6FC2F4F1 CMP [EDI],1
6FC2F4F4 JNZ SHORT D2GAME.6FC2F517 (owner != unit monster) -> next
6FC2F4F6 MOV EAX,[EDI+4]
6FC2F4F9 CALL D2GAME.6FC21180
6FC2F4FE TEST EAX,EAX
6FC2F500 JE D2GAME.6FC2F3B1 (get pRecord of monster)
6FC2F506 MOV CL,[EAX+D]
6FC2F509 MOV EDX,[gdwBitMasks]
6FC2F50F TEST [EDX],CL
6FC2F511 JNZ D2GAME.6FC2F3B1 (exit if owner is npc)
6FC2F517 TEST BH,BH
6FC2F519 JNS SHORT D2GAME.6FC2F556 (flags.8000 == false) -> next
6FC2F51B TEST ESI,ESI
6FC2F51D JE SHORT D2GAME.6FC2F53D (unit == 0) -> skip
6FC2F51F CMP [ESI],3
6FC2F522 JNZ SHORT D2GAME.6FC2F53D (unit != missile) -> skip
6FC2F524 MOV EAX,ESI
6FC2F526 CALL D2GAME.6FCDE540 get game from unit
6FC2F52B PUSH EAX
6FC2F52C MOV EAX,ESI
6FC2F52E CALL D2GAME.6FCDF3F0 get missile owner
6FC2F533 TEST EAX,EAX
6FC2F535 JE D2GAME.6FC2F3B1 (no missile owner) -> exit
6FC2F53B MOV ESI,EAX
6FC2F53D MOV EAX,ESI
6FC2F53F CALL D2GAME.6FCDE540 get game from unit
6FC2F544 PUSH EAX
6FC2F545 MOV EAX,EDI
6FC2F547 MOV ECX,ESI
6FC2F549 CALL D2GAME.6FCDF540 get owner of unit
6FC2F54E TEST EAX,EAX
6FC2F550 JE D2GAME.6FC2F3B1 (no owner found) -> exit
6FC2F556 TEST EBX,20000
6FC2F55C JE SHORT D2GAME.6FC2F591 (flag.0x20000 == false) -> next
6FC2F55E TEST ESI,ESI
6FC2F560 JE SHORT D2GAME.6FC2F580 (unit == null) -> skip
6FC2F562 CMP [ESI],3
6FC2F565 JNZ SHORT D2GAME.6FC2F580 (unit != missile) -> skip
6FC2F567 MOV EAX,ESI
6FC2F569 CALL D2GAME.6FCDE540 get game from unit
6FC2F56E PUSH EAX
6FC2F56F MOV EAX,ESI
6FC2F571 CALL D2GAME.6FCDF3F0 get missile owner
6FC2F576 TEST EAX,EAX
6FC2F578 JE D2GAME.6FC2F3B1 (no owner of missile) -> exit
6FC2F57E MOV ESI,EAX
6FC2F580 PUSH 0
6FC2F582 PUSH EDI
6FC2F583 PUSH ESI
6FC2F584 CALL <JMP.&D2Common.#10913> check something regarding monstats
6FC2F589 TEST EAX,EAX
6FC2F58B JE D2GAME.6FC2F3B1
6FC2F591 TEST EBX,80000
6FC2F597 JE SHORT D2GAME.6FC2F5A9 (flags.IgnoreJustHit == false) -> next
6FC2F599 PUSH 56
6FC2F59B PUSH EDI
6FC2F59C CALL <JMP.&D2Common.#10604>
6FC2F5A1 TEST EAX,EAX
6FC2F5A3 JNZ D2GAME.6FC2F3B1 (unit has state JustHit) -> exit
6FC2F5A9 TEST BH,2
6FC2F5AC JE SHORT D2GAME.6FC2F612 (flag.2000 == false) -> return true
^ change to JMP to disable [acronym="Line of Sight"]LoS[/acronym]
6FC2F5AE PUSH ESI
6FC2F5AF CALL <JMP.&D2Common.#10933> get room of player
6FC2F5B4 MOV EBX,EAX
6FC2F5B6 TEST EBX,EBX
6FC2F5B8 JE D2GAME.6FC2F3B1 (room of player == null) -> exit
6FC2F5BE PUSH EDI
6FC2F5BF CALL <JMP.&D2Common.#10933> get room of unit
6FC2F5C4 TEST EAX,EAX
6FC2F5C6 JE D2GAME.6FC2F3B1 (room of unit == null) -> exit
6FC2F5CC MOV ECX,ESI
6FC2F5CE CALL D2GAME.6FC21370 get x of player
6FC2F5D3 MOV ECX,ESI
6FC2F5D5 MOV [ESP+10],EAX
6FC2F5D9 CALL D2GAME.6FC213A0 get y of player
6FC2F5DE MOV ECX,EDI
6FC2F5E0 MOV [ESP+14],EAX
6FC2F5E4 CALL D2GAME.6FC21370 get x of unit
6FC2F5E9 MOV ECX,EDI
6FC2F5EB MOV [ESP+8],EAX
6FC2F5EF CALL D2GAME.6FC213A0 get y of unit
6FC2F5F6 MOV [ESP+C],EAX
6FC2F5FA LEA EAX,[ESP+8]
6FC2F5FF LEA ECX,[ESP+10]
6FC2F5F4 PUSH 4 4
6FC2F5FE PUSH EAX &CoordUnit
6FC2F603 PUSH ECX &CoordPlayer
6FC2F604 PUSH EBX room (of player)
6FC2F605 CALL <JMP.&D2Common.#10621>
6FC2F60A TEST EAX,EAX
6FC2F60C JNZ D2GAME.6FC2F3B1 (blocked sight?) -> exit
6FC2F612 POP ESI
6FC2F613 MOV EAX,1
6FC2F618 POP EBX
6FC2F619 ADD ESP,10
6FC2F61C RETN
Code: Select all
6FC2FD00 SUB ESP,1C
6FC2FD03 PUSH EDI
6FC2FD04 MOV EDI,EAX
6FC2FD06 TEST EDI,EDI
6FC2FD08 JE D2GAME.6FC2FF02 (game == null) -> exit
6FC2FD0E PUSH EBP
6FC2FD0F MOV EBP,[ESP+28]
6FC2FD13 TEST EBP,EBP
6FC2FD15 JE D2GAME.6FC2FF01 (player == null) -> exit
6FC2FD1B MOV EAX,[ESP+3C]
6FC2FD1F TEST EAX,EAX
6FC2FD21 JE D2GAME.6FC2FF01 (func == null) -> exit
6FC2FD27 PUSH EBX
6FC2FD28 MOV EBX,[ESP+38]
6FC2FD2C TEST EBX,EBX
6FC2FD2E JLE D2GAME.6FC2FF00 (search radius <= 0) -> exit
6FC2FD35 PUSH EBP
6FC2FD36 CALL <JMP.&D2Common.#10933> get room from player
6FC2FD3B MOV ESI,EAX
6FC2FD3D TEST ESI,ESI
6FC2FD3F JE D2GAME.6FC2FEFF (room == null) -> exit
6FC2FD45 MOV EAX,[ESP+34]
6FC2FD49 TEST EAX,EAX
6FC2FD4B JE SHORT D2GAME.6FC2FD55 (tx == 0) -> get coords
6FC2FD4D MOV EAX,[ESP+38]
6FC2FD51 TEST EAX,EAX
6FC2FD53 JNZ SHORT D2GAME.6FC2FD6B (ty != 0) -> skip
[ get coords ]
6FC2FD55 MOV ECX,EBP
6FC2FD57 CALL D2GAME.6FC21370 get x from player
6FC2FD5C MOV ECX,EBP
6FC2FD5E MOV [ESP+34],EAX
6FC2FD62 CALL D2GAME.6FC213A0 get y from player
6FC2FD67 MOV [ESP+38],EAX
6FC2FD6B MOV EAX,[ESP+40]
6FC2FD6F TEST EAX,EAX
6FC2FD71 JNZ SHORT D2GAME.6FC2FD7B (flags != 0) -> skip
6FC2FD73 MOV [ESP+40],583 set flags 1, 2, 8, 9, 11 to true
6FC2FD7B MOV EAX,[ESP+48] eax = &var1
6FC2FD7F LEA ECX,[ESP+14]
6FC2FD84 LEA EDX,[ESP+10]
6FC2FD88 MOV [ESP+20],EBP save player
6FC2FD90 IMUL EBP,EBX ebp = radius
6FC2FD93 MOV [ESP+1C],EDI save game
6FC2FD97 MOV [ESP+28],EAX save &var
6FC2FD9B MOV [ESP+24],0 save 0
6FC2FD83 PUSH ECX &adjacentNo
6FC2FD8C PUSH EDX &pAdjacent
6FC2FD8F PUSH ESI room
6FC2FDA3 CALL <JMP.&D2Common.#10812> returns pAdjacent and adjacentNo in vars
6FC2FDA8 MOV EAX,[ESP+14] EAX = adjacentNo
6FC2FDAC XOR ESI,ESI
6FC2FDAE TEST EAX,EAX
6FC2FDB0 MOV [ESP+48],ESI save 0
6FC2FDB4 JBE D2GAME.6FC2FEFF (adjacentNo <= 0) -> exit
6FC2FDBA MOV EAX,[ESP+40]
6FC2FDBE AND EAX,2000 check if flag16 is true
6FC2FDC3 MOV [ESP+18],EAX save flag16
6FC2FDC7 JMP SHORT D2GAME.6FC2FDD0 go into loop
[ loop ]
6FC2FDC9 /MOV EAX,[ESP+18]
6FC2FDCD |LEA ECX,DWORD PTR DS:[ECX]
6FC2FDD0 TEST EAX,EAX
6FC2FDD2 |JE SHORT D2GAME.6FC2FDE9 (flag16 == 0) -> skip
6FC2FDD4 |MOV EAX,[ESP+10] eax = pAdjacent
6FC2FDD8 |MOV ECX,DWORD PTR DS:[EAX+ESI*4] ecx = pAdjacent[i]->room
6FC2FDDB |PUSH ECX
6FC2FDDC |CALL <JMP.&D2Common.#10845> check if room is inside town
6FC2FDE1 |TEST EAX,EAX
6FC2FDE3 |JNZ D2GAME.6FC2FEEE (if room is inside town) -> next iter
6FC2FDE9 |MOV ECX,[ESP+10] ecx = pAdjacent
6FC2FDED |MOV EAX,[ESP+38] eax = y
6FC2FDF1 |MOV EDX,[ESP+34] edx = x
6FC2FDF5 |MOV ECX,DWORD PTR DS:[ECX+ESI*4] ecx = pAdjacent[i]->room
6FC2FDF8 |MOV EDI,EBX edi = search radius
6FC2FDFA |CALL D2GAME.6FC2D6E0 check if x/y coordinates are inside this room
6FC2FDFF |TEST EAX,EAX
6FC2FE01 |JE D2GAME.6FC2FEEE (if they arent) -> next iter
6FC2FE07 |MOV EDX,[ESP+10]
6FC2FE0B |MOV EAX,DWORD PTR DS:[EDX+ESI*4] eax = pAdjacent[i]->room
6FC2FE0E |MOV EDI,DWORD PTR DS:[EAX+3C] edi = adjacent room->pFirst (first ptUnit in that room)
6FC2FE11 |TEST EDI,EDI
6FC2FE13 |JE D2GAME.6FC2FEEE (pFirst == null) -> next iter
[ sub loop ]
6FC2FE20 |/CMP EDI,[ESP+30]
6FC2FE24 ||MOV EBX,DWORD PTR DS:[EDI+E8] EBX = pFirst->pNextInRoom
6FC2FE2A ||JE D2GAME.6FC2FEDC (pFirst == pPlayer) -> next sub iter
... get X of pFirst into ESI ...
... get Y of pFirst into EAX ...
6FC2FE86 ||MOV ECX,[ESP+34]
6FC2FE8A ||PUSH ESI y
6FC2FE8B ||PUSH EAX ty
6FC2FE8C ||MOV EAX,[ESP+40]
6FC2FE90 ||PUSH EAX x
6FC2FE91 ||PUSH ECX tx
6FC2FE92 ||CALL <JMP.&D2Common.#11166> get distance between pFirst and pPlayer
6FC2FE97 ||CMP EBP,EAX
6FC2FE99 ||JL SHORT D2GAME.6FC2FEDC (radius < distance) -> next sub iter
6FC2FE9B ||MOV EAX,[ESP+40] eax = flags
6FC2FE9F ||MOV ECX,[ESP+30] ecx = player
6FC2FEA3 ||CALL D2GAME.6FC2F380 see below
6FC2FEA8 ||TEST EAX,EAX
6FC2FEAA ||JE SHORT D2GAME.6FC2FEDC (return false) -> next sub iter
6FC2FEAC ||MOV EAX,[ESP+4C]
6FC2FEB0 ||TEST EAX,EAX
6FC2FEB2 ||JE SHORT D2GAME.6FC2FECA (IsAura is false) -> skip
6FC2FEB4 ||CMP DWORD PTR DS:[EDI],1
6FC2FEB7 ||JNZ SHORT D2GAME.6FC2FECA (unit != monster) -> skip
6FC2FEB9 ||MOV EAX,DWORD PTR DS:[EDI+4]
6FC2FEBC ||MOV EDX,1B
6FC2FEC1 ||CALL D2GAME.6FC212C0
6FC2FEC6 ||TEST EAX,EAX
6FC2FEC8 ||JNZ SHORT D2GAME.6FC2FEDC (noaura flag == true) -> next sub iter
6FC2FECA ||MOV EDX,EDI edx = unit
6FC2FECC ||LEA ECX,[ESP+1C]
6FC2FED0 ||CALL [ESP+44] call func (which is passed as arg to this here)
6FC2FED4 ||TEST EAX,EAX
6FC2FED6 ||JE SHORT D2GAME.6FC2FEDC
6FC2FED8 ||INC [ESP+24]
[ next sub iter ]
6FC2FEDC ||TEST EBX,EBX
6FC2FEDE ||MOV EDI,EBX
6FC2FEE0 |\JNZ D2GAME.6FC2FE20 (if next unit inside room != null) -> sub loop
6FC2FEE6 |MOV EBX,[ESP+3C] ebx = search radius
6FC2FEEA |MOV ESI,[ESP+48] esi = counter
[ next iter ]
6FC2FEEE |MOV EAX,[ESP+14] eax = adjacentNo
6FC2FEF2 |INC ESI counter++
6FC2FEF3 |CMP ESI,EAX
6FC2FEF5 |MOV [ESP+48],ESI save counter
6FC2FEF9 \JB D2GAME.6FC2FDC9 (counter < adjacentNo) -> loop
6FC2FEFF POP ESI
6FC2FF00 POP EBX
6FC2FF01 POP EBP
6FC2FF02 POP EDI
6FC2FF03 ADD ESP,1C
6FC2FF06 RETN 20