HeroQuest EXE File
The original exe is compressed with EXEPACKER, you must decompress with UNP to manipulate it.
Format type | Executable / Script |
---|---|
Type | Compiled |
Platform | MS-DOS |
Code | 16-bit x86 |
Hidden data? | No |
Games |
Memory information: Code segment = 01EF Data segment = 0B6B Stack segment = 25F2 |
[CODE SEGMENT] Main Routines
These are the main routines of the game, disassembled with DOSBOX debugger and annotated.
in-game main loop
01EF:0413 E8E65F call 000063FC ($+5fe6) <---- ??? 01EF:0416 E8FA5F call 00006413 ($+5ffa) <---- Checks left mouse button and everityng under it 01EF:0419 C606CC40FF mov byte [40CC],FF ds:[40CC]=DFFF 01EF:041E F606923920 test byte [3992],20 ds:[3992]=9200 <---- Checks if right mouse button has been pressed 01EF:0423 7403 je 00000428 ($+3) (no jmp) 01EF:0425 E82E03 call 00000756 ($+32e) <---- ends the turn if right mouse button pressed 01EF:0428 E85963 call 00006784 ($+6359) <---- ??? 01EF:042B E8A202 call 000006D0 ($+2a2) <---- ??? 01EF:042E E8E564 call 00006916 ($+64e5) <---- draws in the correct order heroes and forniture 01EF:0431 E84553 call 00005779 ($+5345) <---- same as above? 01EF:0434 E8DD53 call 00005814 ($+53dd) <---- ??? 01EF:043A E87B53 call 000057B8 ($+537b) <---- draws heroes, monsters, forniture and doors (not the walls) 01EF:043D E8B454 call 000058F4 ($+54b4) <---- Checks if orthogonal tiles are walkable and updates the directional arrows 01EF:0440 E8A156 call 00005AE4 ($+56a1) <---- Checks if monsters are present in the room and updates search icons 01EF:0443 E81E60 call 00006464 ($+601e) <---- activates attack, magic, treasure, traps icons 01EF:0446 E8CF60 call 00006518 ($+60cf) <---- draws yellow figures on top left 01EF:0449 E8C859 call 00005E14 ($+59c8) <---- draws glove mouse pointer 01EF:044C 803E9A3F00 cmp byte [3F9A],00 ds:[3F9A]=0000 01EF:0451 7503 jne 00000456 ($+3) (down) 01EF:0453 E88E5C call 000060E4 ($+5c8e) <---- ??? 01EF:0456 E87E59 call 00005DD7 ($+597e) <---- Clean the previous mouse sprite 01EF:0459 E85954 call 000058B5 ($+5459) <---- Clean the previous hero sprite 01EF:045C E82100 call 00000480 ($+21) <---- Quest event checks 01EF:045F E8EC13 call 0000184E ($+13ec) <---- Checks if the hero stands on a stair tile 01EF:0462 803E973F00 cmp byte [3F97],00 ds:[3F97]=0000 01EF:0467 7403 je 0000046C ($+3) (no jmp) 01EF:0469 E8BA00 call 00000526 ($+ba) <---- End turn wrap up (resets registers and variables) 01EF:046C 803E9A3F00 cmp byte [3F9A],00 ds:[3F9A]=0000 01EF:0471 7401 je 00000474 ($+1) (no jmp) 01EF:0473 C3 ret 01EF:0474 803E923940 cmp byte [3992],40 ds:[3992]=9200 01EF:0479 7503 jne 0000047E ($+3) (down) 01EF:047B E94FFE jmp 000002CD ($-1b1) (up) 01EF:047E EB93 jmp short 00000413 ($-6d) (up) <--- goes back on top
Shooting routine
Shooting routine (magic and throwing weapons) is utterly broken in this game.
The code checks the map tile the projectile is above and determine if the line of sight is blocked or free.
The way the map is coded resulted in a convoluted code that fails to check LOS.
You can shoot past walls and always hit the target if the hero stands in contact with one wall and the target is the adjacent room exactly above or exactly to the right.
You can also hit the target standing in the perfect diagonal like bishop's movement, and this could happen even if there are no active rooms (solid rock, but marked with 00 like rooms' inner tiles) in between.
LOS is blocked by parallel unrevealed secret doors and opened doors.
Weapon check:
01EF:0AB2 32C0 xor al,al 01EF:0AB4 F6451110 test byte [di+11],10 ds:[46A8]=0010 <-- di+11 is equipped weapon. checks if it is crossbow? 01EF:0AB8 7501 jne 00000ABB ($+1) (no jmp) 01EF:0ABA C3 ret 01EF:0ABB B0FD mov al,FD <-- not crossbow 01EF:0ABD C3 ret 01EF:0ABE 807D1101 cmp byte [di+11],01 ds:[B1A7]=0000 <-- starts here 01EF:0ABF 7D11 jge 00000AD2 ($+11) (down) <-- jump if greater or equal 01EF:0AC1 0174EE add [si-12],si ds:[4DBA]=260D 01EF:0AC4 807D1102 cmp byte [di+11],02 ds:[46A8]=0010 <-- F64511/807D11 are the test/cmp of the equipped weapon 01EF:0AC8 74E8 je 00000AB2 ($-18) (up) 01EF:0ACA 807D1140 cmp byte [di+11],40 ds:[46A8]=0010 01EF:0ACE 74E2 je 00000AB2 ($-1e) (up) 01EF:0AD0 B0FC mov al,FC 01EF:0AD2 EBE0 jmp short 00000AB4 ($-20) (up) 01EF:0AD4 F6451110 test byte [di+11],10 ds:[46A8]=0010 <-- crossbow 01EF:0AD8 750F jne 00000AE9 ($+f) (no jmp) 01EF:0ADA F6451120 test byte [di+11],20 ds:[46A8]=0010 <-- throwing axe 01EF:0ADE 7509 jne 00000AE9 ($+9) (no jmp) 01EF:0AE0 F6451140 test byte [di+11],40 ds:[46A8]=0010 <-- spear 01EF:0AE4 7503 jne 00000AE9 ($+3) (no jmp) 01EF:0AE6 B0FC mov al,FC 01EF:0AE8 C3 ret
SHOOTING ROUTINE STARTS HERE:
01EF:0AE9 C606B73F01 mov byte [3FB7],01 ds:[3FB7]=0301 01EF:0AEE E82B00 call 00000B1C ($+2b) 01EF:0AF1 32C0 xor al,al 01EF:0AF3 803EA83F01 cmp byte [3FA8],01 ds:[3FA8]=0001 <-- check if LOS is blocked (1) 01EF:0AF8 7401 je 00000AFB ($+1) (down) 01EF:0AFA C3 ret 01EF:0AFB B0FE mov al,FE 01EF:0AFD C606B73F00 mov byte [3FB7],00 ds:[3FB7]=0300 01EF:0B02 C3 ret 01EF:0B1C E81F06 call 0000113E ($+61f) 01EF:0B1F A0A83F mov al,[3FA8] ds:[3FA8]=0001 01EF:0B22 3401 xor al,01 01EF:0B24 A2B23F mov [3FB2],al ds:[3FB2]=0000 01EF:0B27 C3 ret
Set global variables (shooter and target position/distance):
01EF:113E 8B36D43F mov si,[3FD4] ds:[3FD4]=4DC2 01EF:1142 8A7C01 mov bh,[si+01] ds:[4DC3]=0F0A <-- Target X 01EF:1145 8A5C02 mov bl,[si+02] ds:[4DC4]=270F <-- Target Y 01EF:1148 8BCB mov cx,bx 01EF:114A 8B3E3746 mov di,[4637] ds:[4637]=4697 01EF:114E 8A7501 mov dh,[di+01] ds:[4698]=120A <-- Hero X 01EF:1151 8A5502 mov dl,[di+02] ds:[4699]=1212 <-- Hero Y 01EF:1154 8836A53F mov [3FA5],dh ds:[3FA5]=0C0C <-- Hero X saved at 3FA5 01EF:1158 8816A63F mov [3FA6],dl ds:[3FA6]=020C <-- Hero Y saved at 3FA6 01EF:115C C6069F3F00 mov byte [3F9F],00 ds:[3F9F]=0000 <-- reset projectile temp distance (area used for math) 01EF:1161 C606A83F00 mov byte [3FA8],00 ds:[3FA8]=0002 <-- reset LOS 0=free, 1=blocked 01EF:1166 B7FF mov bh,FF 01EF:1168 8AC6 mov al,dh 01EF:116A 2AC5 sub al,ch 01EF:116C 7504 jne 00001172 ($+4) (down) 01EF:116E B700 mov bh,00 <-- target is on the RIGHT (>) 01EF:1170 EB06 jmp short 00001178 ($+6) (down) 01EF:1172 7304 jnc 00001178 ($+4) (down) 01EF:1174 F6D8 neg al 01EF:1176 B701 mov bh,01 <-- target is on the LEFT (<) 01EF:1178 A2A13F mov [3FA1],al ds:[3FA1]=0301 <-- horizontal distance shooter-target saved at 3FA1 01EF:117B 8AE8 mov ch,al 01EF:117D B3FF mov bl,FF 01EF:117F 8AC2 mov al,dl 01EF:1181 2AC1 sub al,cl 01EF:1183 7504 jne 00001189 ($+4) (down) 01EF:1185 B300 mov bl,00 <-- target is UNDER (v) 01EF:1187 EB06 jmp short 0000118F ($+6) (down) 01EF:1189 7304 jnc 0000118F ($+4) (down) 01EF:118B F6D8 neg al 01EF:118D B301 mov bl,01 <-- target is ABOVE (^) 01EF:118F A2A23F mov [3FA2],al ds:[3FA2]=0003 <-- vertical distance shooter-target saved at 3FA2 01EF:1192 3AC5 cmp al,ch 01EF:1194 7240 jc 000011D6 ($+40) (no jmp)
bx (bh+bl) registry status based on target/shooter position:
0101 | 0001 | FF01 |
0100 | TRGT | FF00 |
01FF | 00FF | FFFF |
VERTICAL shooting routine:
01EF:1196 8ACD mov cl,ch 01EF:1198 8AE8 mov ch,al 01EF:119A 8AD0 mov dl,al 01EF:119C 000E9F3F add [3F9F],cl ds:[3F9F]=0000 <-- update projectile travelled distance 01EF:11A0 38169F3F cmp [3F9F],dl ds:[3F9F]=0000 01EF:11A4 7208 jc 000011AE ($+8) (no jmp) 01EF:11A6 28169F3F sub [3F9F],dl ds:[3F9F]=0000 01EF:11AA 003EA53F add [3FA5],bh ds:[3FA5]=0F0D <-- Temp Projectile X (d 0:F655) 01EF:11AE 001EA63F add [3FA6],bl ds:[3FA6]=020F <-- Temp Projectile Y (d 0:F656) 01EF:11B2 C706E9370000 mov word [37E9],0000 ds:[37E9]=D238 <-- set Vertical flag 01EF:11B8 882EEB37 mov [37EB],ch ds:[37EB]=F1E0 <-- distance between projectile and target 01EF:11BC 80FD01 cmp ch,01 01EF:11BF 7505 jne 000011C6 ($+5) (down) 01EF:11C1 80FBFF cmp bl,FF 01EF:11C4 7403 je 000011C9 ($+3) (no jmp) 01EF:11C6 E84B00 call 00001214 ($+4b) 01EF:11C9 803EA83F00 cmp byte [3FA8],00 ds:[3FA8]=0000 <-- check if LOS is still free (0), if 1 exits 01EF:11CE 7401 je 000011D1 ($+1) (no jmp) 01EF:11D0 C3 ret 01EF:11D1 FECD dec ch 01EF:11D3 75C7 jne 0000119C ($-39) (up) 01EF:11D5 C3 ret
HORIZONTAL shooting routine:
01EF:11D6 8AD0 mov dl,al 01EF:11D8 8ACD mov cl,ch <-- it moves ch in cl 01EF:11DA 32ED xor ch,ch <-- and puts to 00 ch because uses loop (thus cx) instead of dec ch of vertical routine 01EF:11DC 00169F3F add [3F9F],dl ds:[3F9F]=0001 01EF:11E0 380E9F3F cmp [3F9F],cl ds:[3F9F]=0001 01EF:11E4 7208 jc 000011EE ($+8) (no jmp) 01EF:11E6 280E9F3F sub [3F9F],cl ds:[3F9F]=0001 01EF:11EA 001EA63F add [3FA6],bl ds:[3FA6]=020F <-- Temp Projectile Y 01EF:11EE 003EA53F add [3FA5],bh ds:[3FA5]=0F03 <-- Temp Projectile X 01EF:11F2 C706E9370100 mov word [37E9],0001 ds:[37E9]=0001 <-- set Horizontal flag 01EF:11F8 880EEB37 mov [37EB],cl ds:[37EB]=AA04 <-- distance between projectile and target 01EF:11FC 80F901 cmp cl,01 01EF:11FF 7505 jne 00001206 ($+5) (down) 01EF:1201 80FFFF cmp bh,FF 01EF:1204 7403 je 00001209 ($+3) (no jmp) 01EF:1206 E80B00 call 00001214 ($+b) 01EF:1209 803EA83F00 cmp byte [3FA8],00 ds:[3FA8]=0001 <-- check if LOS is still free (0), if 1 exits 01EF:120E 7401 je 00001211 ($+1) (no jmp) 01EF:1210 C3 ret 01EF:1211 E2C9 loop 000011DC ($-37) 01EF:1213 C3 ret
Collision check routine on current tile IN WALL/DOORS map (ds:566F):
01EF:1214 53 push bx 01EF:1215 52 push dx 01EF:1216 8A36A63F mov dh,[3FA6] ds:[3FA6]=0839 01EF:121A 8A16A53F mov dl,[3FA5] ds:[3FA5]=3936 01EF:121E E85D4E call 0000607E ($+4e5d) 01EF:1221 80BF6F5600 cmp byte [bx+566F],00 ds:[576C]=8128 <-- Check if tile is 00, if true jumps to the Object map check 01EF:1226 742A je 00001252 ($+2a) (no jmp) at 0B6B:566F is where WALLS/DOORS map is stored 01EF:1228 8A876F56 mov al,[bx+566F] ds:[576C]=8128 <-- mov into al the current TILE (28=is north secret door) 01EF:122C 833EE93701 cmp word [37E9],0001 ds:[37E9]=0001 <-- 1=H, 0=V check for opened door subroutines 01EF:1231 7411 je 00001244 ($+11) (no jmp)
Vertical shoot subroutine that checks for Horizontal walls/doors:
01EF:1233 24AC and al,AC <-- binary AND check if Horizontal walls/doors are present (block LOS) 01EF:1235 0AC0 or al,al AC= 10101100 01EF:1237 7419 je 00001252 ($+19) (no jmp) 01EF:1239 A820 test al,20 <-- if door is Horizontal 01EF:123B 7442 je 0000127F ($+42) (down) 01EF:123D A804 test al,04 <-- if door is opened 01EF:123F 743E je 0000127F ($+3e) (down) 01EF:1241 EB0F jmp short 00001252 ($+f) (down) 01EF:1243 90 nop
Horizontal shoot subroutine that checks for Vertical walls/doors:
01EF:1244 245C and al,5C <-- binary AND check if Horizontal walls/doors are present (block LOS) 01EF:1246 0AC0 or al,al 5C= 01011100 01EF:1248 7408 je 00001252 ($+8) (down) 01EF:124A A810 test al,10 <-- if door is Vertical 01EF:124C 7431 je 0000127F ($+31) (down) 01EF:124E A804 test al,04 <-- if door is opened 01EF:1250 742D je 0000127F ($+2d) (down)
Collision check routine on current tile IN OBJECTS map (ds:586F):
01EF:1252 803EEB3701 cmp byte [37EB],01 ds:[37EB]=6E03 <-- checks if the projectile is about to hit the target 01EF:1257 742B je 00001284 ($+2b) (down) 01EF:1259 80BF6F5800 cmp byte [bx+586F],00 ds:[1576F]=3637 <-- checks if the tile is passable (00) 01EF:125E 740E je 0000126E ($+e) (down) 01EF:1260 8A876F58 mov al,[bx+586F] ds:[1576F]=3637 <-- ds:586F is where OBJECTS map is stored 01EF:1264 BB4649 mov bx,4946 <-- ds:4946 check 01EF:1267 D7 xlat 01EF:1268 A2A83F mov [3FA8],al ds:[3FA8]=0000 01EF:126B EB17 jmp short 00001284 ($+17) (down) 01EF:126D 90 nop 01EF:126E 8A36A63F mov dh,[3FA6] ds:[3FA6]=004D 01EF:1272 8A16A53F mov dl,[3FA5] ds:[3FA5]=4D4D 01EF:1276 E80E00 call 00001287 ($+e) 01EF:1279 A2A83F mov [3FA8],al ds:[3FA8]=0000 01EF:127C EB06 jmp short 00001284 ($+6) (down) 01EF:127E 90 nop 01EF:127F C606A83F01 mov byte [3FA8],01 ds:[3FA8]=BA6B <-- sets LOS as blocked (1) and exits 01EF:1284 5A pop dx 01EF:1285 5B pop bx 01EF:1286 C3 ret
Updates with random numbers the first three bytes of heroes' equipment every movement (presumably used as seed for RNG):
01EF:1287 51 push cx 01EF:1288 57 push di 01EF:1289 B90500 mov cx,0005 01EF:128C BF6346 mov di,4663 <-- first byte of Barbarian equipment in memory 01EF:128F 33C0 xor ax,ax 01EF:1291 803D00 cmp byte [di],00 ds:[6CAA]=0000 01EF:1294 740C je 000012A2 ($+c) (down) 01EF:1296 385501 cmp [di+01],dl ds:[6CAB]=0000 01EF:1299 7507 jne 000012A2 ($+7) (no jmp) 01EF:129B 387502 cmp [di+02],dh ds:[6CAC]=0000 01EF:129E 7502 jne 000012A2 ($+2) (no jmp) 01EF:12A0 B001 mov al,01 01EF:12A2 83C71A add di,001A <-- jumps to the following hero's equipment 01EF:12A5 E2EA loop 00001291 ($-16) 01EF:12A7 5F pop di 01EF:12A8 59 pop cx 01EF:12A9 C3 ret
TBD
01EF:607E 8ADE mov bl,dh 01EF:6080 B700 mov bh,00 01EF:6082 03DB add bx,bx 01EF:6084 81C3C55A add bx,5AC5 <-- ds:5AC5 check 01EF:6088 8B07 mov ax,[bx] ds:[FF00]=3737 01EF:608A B600 mov dh,00 01EF:608C 03D0 add dx,ax 01EF:608E 8BDA mov bx,dx 01EF:6090 C3 ret
Monster attack routine
This first block defines the target priority: barbarian - dwarf - elf - wizard - ragnar
It is possible to revers it forcing the monster to chose the weaker hero first reversing the logic by starting from ragnar profile and then jump backward subtracting 1A.
See Heroes' default profiles for reference.
01EF:2257 BE6346 mov si,4663 <-- starting profile offset 4663=barbarian 01EF:225A B90500 mov cx,0005 <-- loop repeats 5 times 01EF:225D 51 push cx 01EF:225E 8936D63F mov [3FD6],si ds:[3FD6]=46B1 01EF:2262 8A4419 mov al,[si+19] ds:[46CA]=0003 <-- jumps to hero's ID position 01EF:2265 A2BC3F mov [3FBC],al ds:[3FBC]=0003 01EF:2268 E85800 call 000022C3 ($+58) 01EF:226B 59 pop cx 01EF:226C 8B36D63F mov si,[3FD6] ds:[3FD6]=46B1 01EF:2270 83C61A add si,001A <-- jumps to the next profile 01EF:2273 803EA83F00 cmp byte [3FA8],00 ds:[3FA8]=0102 01EF:2278 7503 jne 0000227D ($+3) (down) 01EF:227A E95102 jmp 000024CE ($+251) (down) 01EF:227D 803EA83F03 cmp byte [3FA8],03 ds:[3FA8]=0102 01EF:2282 7503 jne 00002287 ($+3) (down) 01EF:2284 E94702 jmp 000024CE ($+247) (down) 01EF:2287 E2D4 loop 0000225D ($-2c) 01EF:2289 C3 ret
01EF:22C3 C606A83F00 mov byte [3FA8],00 ds:[3FA8]=0000 01EF:22C8 803C00 cmp byte [si],00 ds:[4663]=06FF 01EF:22CB 7503 jne 000022D0 ($+3) (no jmp) 01EF:22CD E98101 jmp 00002451 ($+181) (down) 01EF:22D0 8A4403 mov al,[si+03] ds:[4666]=C726 <-- hero's room 01EF:22D3 3A4503 cmp al,[di+03] ds:[4DBB]=FB26 <-- monster's room 01EF:22D6 7403 je 000022DB ($+3) (down) 01EF:22D8 E97601 jmp 00002451 ($+176) (down) 01EF:22DB F6441801 test byte [si+18],01 ds:[467B]=0000 01EF:22DF 7403 je 000022E4 ($+3) (down) 01EF:22E1 E96D01 jmp 00002451 ($+16d) (down) 01EF:22E4 8B5401 mov dx,[si+01] ds:[4664]=0D06 01EF:22E7 52 push dx 01EF:22E8 57 push di 01EF:22E9 E864F7 call 00001A50 ($-89c) 01EF:22EC 5F pop di 01EF:22ED 57 push di 01EF:22EE E84E02 call 0000253F ($+24e) 01EF:22F1 E8F03D call 000060E4 ($+3df0) 01EF:22F4 B9F401 mov cx,01F4 01EF:22F7 E88D23 call 00004687 ($+238d) 01EF:22FA 5F pop di 01EF:22FB 5A pop dx 01EF:22FC 8816A53F mov [3FA5],dl ds:[3FA5]=1106 01EF:2300 8836A63F mov [3FA6],dh ds:[3FA6]=0411 01EF:2304 BBA240 mov bx,40A2 01EF:2307 891ECA40 mov [40CA],bx ds:[40CA]=40A2 01EF:230B E8703D call 0000607E ($+3d70) <-- if jumped the monster doesn't attack when in contact
01EF:230E 81C36F54 add bx,546F 01EF:2312 8A07 mov al,[bx] ds:[3F28]=4040 01EF:2314 243F and al,3F 01EF:2316 3A4503 cmp al,[di+03] ds:[4DBB]=FB26 <-- monster's room check. if removed the monster attack through walls and doors 01EF:2319 7403 je 0000231E ($+3) (down) 01EF:231B E93301 jmp 00002451 ($+133) (down) 01EF:231E B501 mov ch,01 01EF:2320 A0A53F mov al,[3FA5] ds:[3FA5]=1106 01EF:2323 2A4501 sub al,[di+01] ds:[4DB9]=0F06 01EF:2326 7504 jne 0000232C ($+4) (no jmp) 01EF:2328 B500 mov ch,00 01EF:232A EB08 jmp short 00002334 ($+8) (down) 01EF:232C 3C80 cmp al,80 01EF:232E 7204 jc 00002334 ($+4) (no jmp) 01EF:2330 F6D8 neg al 01EF:2332 B5FF mov ch,FF 01EF:2334 A2A13F mov [3FA1],al ds:[3FA1]=0100 01EF:2337 882EA33F mov [3FA3],ch ds:[3FA3]=0100 01EF:233B B501 mov ch,01 01EF:233D A0A63F mov al,[3FA6] ds:[3FA6]=0411 01EF:2340 2A4502 sub al,[di+02] ds:[4DBA]=260F 01EF:2343 7504 jne 00002349 ($+4) (no jmp) 01EF:2345 B500 mov ch,00 01EF:2347 EB08 jmp short 00002351 ($+8) (down) 01EF:2349 3C80 cmp al,80 01EF:234B 7204 jc 00002351 ($+4) (no jmp) 01EF:234D F6D8 neg al 01EF:234F B5FF mov ch,FF 01EF:2351 A2A23F mov [3FA2],al ds:[3FA2]=0001 01EF:2354 882EA43F mov [3FA4],ch ds:[3FA4]=0601 01EF:2358 8B5501 mov dx,[di+01] ds:[4DB9]=0F06 01EF:235B 89169F3F mov [3F9F],dx ds:[3F9F]=1006 01EF:235F C606A93F00 mov byte [3FA9],00 ds:[3FA9]=0000 01EF:2364 8A5D09 mov bl,[di+09] ds:[4DC1]=8100 01EF:2367 02DB add bl,bl 01EF:2369 02DB add bl,bl 01EF:236B 025D09 add bl,[di+09] ds:[4DC1]=8100 01EF:236E 32FF xor bh,bh 01EF:2370 8A870648 mov al,[bx+4806] [illegal] 01EF:2374 A29C3F mov [3F9C],al ds:[3F9C]=0003 01EF:2377 8A0EA23F mov cl,[3FA2] ds:[3FA2]=0001 01EF:237B A0A13F mov al,[3FA1] ds:[3FA1]=0100 01EF:237E 3AC1 cmp al,cl 01EF:2380 7203 jc 00002385 ($+3) (no jmp) 01EF:2382 EB6A jmp short 000023EE ($+6a) (down) 01EF:2384 90 nop 01EF:2385 8B169F3F mov dx,[3F9F] ds:[3F9F]=1006 01EF:2389 3836A63F cmp [3FA6],dh ds:[3FA6]=0411 01EF:238D 7425 je 000023B4 ($+25) (down) 01EF:238F A0A43F mov al,[3FA4] ds:[3FA4]=0601 01EF:2392 0AC0 or al,al 01EF:2394 741E je 000023B4 ($+1e) (down) 01EF:2396 02F0 add dh,al 01EF:2398 E8DD00 call 00002478 ($+dd) 01EF:239B 3CFF cmp al,FF 01EF:239D 7503 jne 000023A2 ($+3) (no jmp) 01EF:239F E9B500 jmp 00002457 ($+b5) (down) 01EF:23A2 0AC0 or al,al 01EF:23A4 750E jne 000023B4 ($+e) (no jmp) 01EF:23A6 8A26A43F mov ah,[3FA4] ds:[3FA4]=0601 01EF:23AA E8B000 call 0000245D ($+b0) 01EF:23AD 7303 jnc 000023B2 ($+3) (down) 01EF:23AF E99900 jmp 0000244B ($+99) (down) 01EF:23B2 EBD1 jmp short 00002385 ($-2f) (up) 01EF:23B4 8B169F3F mov dx,[3F9F] ds:[3F9F]=1006 01EF:23B8 A0A53F mov al,[3FA5] ds:[3FA5]=1106 01EF:23BB 3AC2 cmp al,dl 01EF:23BD 7503 jne 000023C2 ($+3) (no jmp) 01EF:23BF E98F00 jmp 00002451 ($+8f) (down) 01EF:23C2 A0A33F mov al,[3FA3] ds:[3FA3]=0100 01EF:23C5 0AC0 or al,al 01EF:23C7 7503 jne 000023CC ($+3) (no jmp) 01EF:23C9 E98500 jmp 00002451 ($+85) (down) 01EF:23CC 02D0 add dl,al 01EF:23CE E8A700 call 00002478 ($+a7) 01EF:23D1 3CFF cmp al,FF 01EF:23D3 7503 jne 000023D8 ($+3) (no jmp) 01EF:23D5 E97F00 jmp 00002457 ($+7f) (down) 01EF:23D8 0AC0 or al,al 01EF:23DA 7403 je 000023DF ($+3) (down) 01EF:23DC EB73 jmp short 00002451 ($+73) (down) 01EF:23DE 90 nop 01EF:23DF A0A33F mov al,[3FA3] ds:[3FA3]=0100 01EF:23E2 32E4 xor ah,ah 01EF:23E4 E87600 call 0000245D ($+76) 01EF:23E7 7303 jnc 000023EC ($+3) (down) 01EF:23E9 EB60 jmp short 0000244B ($+60) (down) 01EF:23EB 90 nop 01EF:23EC EB97 jmp short 00002385 ($-69) (up) 01EF:23EE 8B169F3F mov dx,[3F9F] ds:[3F9F]=1006 01EF:23F2 A0A53F mov al,[3FA5] ds:[3FA5]=1106 01EF:23F5 3AC2 cmp al,dl 01EF:23F7 7426 je 0000241F ($+26) (down) 01EF:23F9 A0A33F mov al,[3FA3] ds:[3FA3]=0100 01EF:23FC 0AC0 or al,al 01EF:23FE 741F je 0000241F ($+1f) (down) 01EF:2400 02D0 add dl,al 01EF:2402 E87300 call 00002478 ($+73) 01EF:2405 3CFF cmp al,FF 01EF:2407 7503 jne 0000240C ($+3) (no jmp) 01EF:2409 EB4C jmp short 00002457 ($+4c) (down) 01EF:240B 90 nop 01EF:240C 0AC0 or al,al 01EF:240E 750F jne 0000241F ($+f) (no jmp) 01EF:2410 A0A33F mov al,[3FA3] ds:[3FA3]=0100 01EF:2413 32E4 xor ah,ah 01EF:2415 E84500 call 0000245D ($+45) 01EF:2418 7303 jnc 0000241D ($+3) (down) 01EF:241A EB2F jmp short 0000244B ($+2f) (down) 01EF:241C 90 nop 01EF:241D EBCF jmp short 000023EE ($-31) (up) 01EF:241F 8B169F3F mov dx,[3F9F] ds:[3F9F]=1006 01EF:2423 3836A63F cmp [3FA6],dh ds:[3FA6]=0411 01EF:2427 7428 je 00002451 ($+28) (down) 01EF:2429 A0A43F mov al,[3FA4] ds:[3FA4]=0601 01EF:242C 0AC0 or al,al 01EF:242E 7421 je 00002451 ($+21) (down) 01EF:2430 02F0 add dh,al 01EF:2432 E84300 call 00002478 ($+43) 01EF:2435 3CFF cmp al,FF 01EF:2437 741E je 00002457 ($+1e) (down) 01EF:2439 0AC0 or al,al 01EF:243B 7514 jne 00002451 ($+14) (no jmp) 01EF:243D 8A26A43F mov ah,[3FA4] ds:[3FA4]=0601 01EF:2441 E81900 call 0000245D ($+19) 01EF:2444 7303 jnc 00002449 ($+3) (down) 01EF:2446 EB03 jmp short 0000244B ($+3) (down) 01EF:2448 90 nop 01EF:2449 EBA3 jmp short 000023EE ($-5d) (up) 01EF:244B C606A83F01 mov byte [3FA8],01 ds:[3FA8]=0000 <-- hero is not reachable 01EF:2450 C3 ret 01EF:2451 C606A83F02 mov byte [3FA8],02 ds:[3FA8]=0000 <-- hero is not reachable 01EF:2456 C3 ret 01EF:2457 C606A83F00 mov byte [3FA8],00 ds:[3FA8]=0000 <-- hero is reachable 01EF:245C C3 ret
01EF:245D 89169F3F mov [3F9F],dx ds:[3F9F]=1006 <-- called only when the monster needs to move 01EF:2461 8B1ECA40 mov bx,[40CA] ds:[40CA]=40A2 01EF:2465 8807 mov [bx],al ds:[3F28]=6148 01EF:2467 886701 mov [bx+01],ah ds:[3F29]=0061 01EF:246A 8306CA4002 add word [40CA],0002 ds:[40CA]=40A2 01EF:246F FE06A93F inc byte [3FA9] ds:[3FA9]=0000 01EF:2473 FE0E9C3F dec byte [3F9C] ds:[3F9C]=0003 01EF:2477 C3 ret
01EF:2478 A0BC3F mov al,[3FBC] ds:[3FBC]=0000 01EF:247B E80139 call 00005D7F ($+3901) 01EF:247E 803C00 cmp byte [si],00 ds:[4663]=06FF 01EF:2481 7408 je 0000248B ($+8) (down) 01EF:2483 3B5401 cmp dx,[si+01] ds:[4664]=0D06 01EF:2486 7503 jne 0000248B ($+3) (no jmp) 01EF:2488 B0FF mov al,FF 01EF:248A C3 ret
01EF:248B B500 mov ch,00 01EF:248D 382EBC3F cmp [3FBC],ch ds:[3FBC]=0000 01EF:2491 7412 je 000024A5 ($+12) (down) 01EF:2493 8AC5 mov al,ch 01EF:2495 E8E738 call 00005D7F ($+38e7) 01EF:2498 803C00 cmp byte [si],00 ds:[4663]=06FF 01EF:249B 7408 je 000024A5 ($+8) (down) 01EF:249D 3B5401 cmp dx,[si+01] ds:[4664]=0D06 01EF:24A0 7503 jne 000024A5 ($+3) (no jmp) 01EF:24A2 B001 mov al,01 01EF:24A4 C3 ret 01EF:24A5 FEC5 inc ch 01EF:24A7 80FD04 cmp ch,04 01EF:24AA 75E1 jne 0000248D ($-1f) (no jmp) 01EF:24AC 52 push dx 01EF:24AD E8CE3B call 0000607E ($+3bce) 01EF:24B0 5A pop dx 01EF:24B1 81C36F58 add bx,586F 01EF:24B5 803F00 cmp byte [bx],00 ds:[3F28]=6148 01EF:24B8 7403 je 000024BD ($+3) (down) 01EF:24BA B002 mov al,02 01EF:24BC C3 ret 01EF:24BD 8A8700FC mov al,[bx-0400] ds:[3B28]=E04B 01EF:24C1 243F and al,3F 01EF:24C3 3A4503 cmp al,[di+03] ds:[4DBB]=FB26 <-- monster's room check. 01EF:24C6 7503 jne 000024CB ($+3) (no jmp) 01EF:24C8 32C0 xor al,al 01EF:24CA C3 ret 01EF:24CB B003 mov al,03 01EF:24CD C3 ret
01EF:24CE 893ED43F mov [3FD4],di ds:[3FD4]=4DB8 01EF:24D2 8A0EA93F mov cl,[3FA9] ds:[3FA9]=0001 01EF:24D6 0AC9 or cl,cl 01EF:24D8 7455 je 0000252F ($+55) (down) 01EF:24DA 32ED xor ch,ch 01EF:24DC BBA240 mov bx,40A2 01EF:24DF 891ECA40 mov [40CA],bx ds:[40CA]=40A4 01EF:24E3 51 push cx 01EF:24E4 8B3ED43F mov di,[3FD4] ds:[3FD4]=4DB8 01EF:24E8 8B5501 mov dx,[di+01] ds:[4DB9]=0F06 01EF:24EB E8903B call 0000607E ($+3b90) 01EF:24EE 8A8F6F58 mov cl,[bx+586F] ds:[59FB]=0000 01EF:24F2 C6876F5800 mov byte [bx+586F],00 ds:[59FB]=0000 01EF:24F7 8B1ECA40 mov bx,[40CA] ds:[40CA]=40A2 01EF:24FB 8B5501 mov dx,[di+01] ds:[4DB9]=0F06 01EF:24FE 0217 add dl,[bx] ds:[018C]=1149 01EF:2500 027701 add dh,[bx+01] ds:[018D]=0611 01EF:2503 895501 mov [di+01],dx ds:[4DB9]=0F06 01EF:2506 8306CA4002 add word [40CA],0002 ds:[40CA]=40A2 01EF:250B E8703B call 0000607E ($+3b70) 01EF:250E 888F6F58 mov [bx+586F],cl ds:[AE50]=0A16 01EF:2512 81C36F54 add bx,546F 01EF:2516 895D04 mov [di+04],bx ds:[4DBC]=55E1 01EF:2519 E834F5 call 00001A50 ($-acc) 01EF:251C 8B3ED43F mov di,[3FD4] ds:[3FD4]=4DB8 01EF:2520 E81C00 call 0000253F ($+1c) 01EF:2523 E8BE3B call 000060E4 ($+3bbe) 01EF:2526 B9F401 mov cx,01F4 01EF:2529 E85B21 call 00004687 ($+215b) <-- 500.000 nop cycles, to slow down monster's animation 01EF:252C 59 pop cx 01EF:252D E2B4 loop 000024E3 ($-4c) 01EF:252F 51 push cx 01EF:2530 B93200 mov cx,0032 01EF:2533 E86A11 call 000036A0 ($+116a) <-- more nops 01EF:2536 E2FB loop 00002533 ($-5) 01EF:2538 59 pop cx 01EF:2539 E853F8 call 00001D8F ($-7ad) <-- here the monster attacks whein in contact with the hero 01EF:253C E99131 jmp 000056D0 ($+3191) (down) 01EF:253F 8A4502 mov al,[di+02] ds:[EF42]=3736 01EF:2542 32E4 xor ah,ah 01EF:2544 BA000A mov dx,0A00 01EF:2547 F7E2 mul dx 01EF:2549 8BD8 mov bx,ax
01EF:4687 51 push cx 01EF:4688 E820EF call 000035AB ($-10e0) 01EF:468B 59 pop cx 01EF:468C E2F9 loop 00004687 ($-7) 01EF:468E C3 ret
01EF:607E 8ADE mov bl,dh 01EF:6080 B700 mov bh,00 01EF:6082 03DB add bx,bx 01EF:6084 81C3C55A add bx,5AC5 01EF:6088 8B07 mov ax,[bx] ds:[0130]=0101 01EF:608A B600 mov dh,00 01EF:608C 03D0 add dx,ax 01EF:608E 8BDA mov bx,dx 01EF:6090 C3 ret
Hero's pathfinding routine
01EF:6449 E8E2D4 call 0000392E ($-2b1e) 01EF:644C E85800 call 000064A7 ($+58) 01EF:644F 833CFF cmp word [si],FFFF ds:[3911]=0000 01EF:6452 7503 jne 00006457 ($+3) (down) 01EF:6454 E95F03 jmp 000067B6 ($+35f) (down) 01EF:67B6 8B16E747 mov dx,[47E7] ds:[47E7]=0087 01EF:67BA 8B2EE947 mov bp,[47E9] ds:[47E9]=0097 01EF:67BE BB2D40 mov bx,402D 01EF:67C1 BE1941 mov si,4119 01EF:67C4 B93400 mov cx,0034 01EF:67C7 51 push cx 01EF:67C8 8B4402 mov ax,[si+02] ds:[491E]=01C0 01EF:67CB 051800 add ax,0018 01EF:67CE 2BC2 sub ax,dx 01EF:67D0 7302 jnc 000067D4 ($+2) (down) 01EF:67D0 7302 jnc 000067D4 ($+2) (no jmp) 01EF:67D2 F7D8 neg ax 01EF:67D4 D1E8 shr ax,1 01EF:67D6 8B0C mov cx,[si] ds:[4119]=0044 01EF:67D8 83C108 add cx,0008 01EF:67DB 2BCD sub cx,bp 01EF:67DD 7302 jnc 000067E1 ($+2) (no jmp) 01EF:67DF F7D9 neg cx 01EF:67E1 03C1 add ax,cx 01EF:67E3 D1E8 shr ax,1 01EF:67E5 8907 mov [bx],ax ds:[402D]=0000 01EF:67E7 83C302 add bx,0002 01EF:67EA 83C604 add si,0004 01EF:67ED 59 pop cx 01EF:67EE E2D7 loop 000067C7 ($-29) 01EF:67F0 BB2D40 mov bx,402D 01EF:67F3 B8FFFF mov ax,FFFF 01EF:67F6 B93400 mov cx,0034 01EF:67F9 3B07 cmp ax,[bx] ds:[402D]=0000 01EF:67FB 7204 jc 00006801 ($+4) (down) 01EF:67FD 8B07 mov ax,[bx] ds:[4095]=0000 01EF:67FF 8BD1 mov dx,cx 01EF:6801 83C302 add bx,0002 01EF:6804 E2F3 loop 000067F9 ($-d) 01EF:6806 3D0800 cmp ax,0008 01EF:6809 7201 jc 0000680C ($+1) (no jmp) 01EF:680B C3 ret 01EF:680C BB3400 mov bx,0034 01EF:680F 2BDA sub bx,dx 01EF:6811 83FB2D cmp bx,002D 01EF:6814 720B jc 00006821 ($+b) (down) 01EF:6816 83EB2D sub bx,002D 01EF:6819 D1E3 shl bx,1 01EF:681B 8B8F034A mov cx,[bx+4A03] ds:[4A14]=0E09 01EF:681F EB06 jmp short 00006827 ($+6) (down) 01EF:6821 8A8FD649 mov cl,[bx+49D6] ds:[49E7]=1E37 01EF:6825 32ED xor ch,ch 01EF:6827 A1E43F mov ax,[3FE4] ds:[3FE4]=5574 01EF:682A 03C1 add ax,cx 01EF:682C 2D6F54 sub ax,546F 01EF:682F 8BD8 mov bx,ax 01EF:6831 81C36F56 add bx,566F 01EF:6835 3B1E110E cmp bx,[0E11] ds:[0E11]=FFFF 01EF:6839 7501 jne 0000683C ($+1) (down) 01EF:683B C3 ret 01EF:683C 8BD8 mov bx,ax 01EF:683E B500 mov ch,00 01EF:6840 3D1A00 cmp ax,001A 01EF:6843 7207 jc 0000684C ($+7) (down) 01EF:6845 2D1A00 sub ax,001A 01EF:6848 FEC5 inc ch 01EF:684A EBF4 jmp short 00006840 ($-c) (up) 01EF:684C 8AC8 mov cl,al 01EF:684E 8A876F54 mov al,[bx+546F] ds:[AC1A]=0200 01EF:6852 243F and al,3F 01EF:6854 7501 jne 00006857 ($+1) (down) 01EF:6856 C3 ret 01EF:6857 80BF6F5800 cmp byte [bx+586F],00 ds:[B01A]=0101 01EF:685C 7503 jne 00006861 ($+3) (down) 01EF:685E EB11 jmp short 00006871 ($+11) (down) 01EF:6860 90 nop 01EF:6861 80BF6F5800 cmp byte [bx+586F],00 ds:[B01A]=0101 01EF:6866 7501 jne 00006869 ($+1) (down) 01EF:6868 C3 ret 01EF:6869 80BF6F5840 cmp byte [bx+586F],40 ds:[B01A]=0101 01EF:686E 7201 jc 00006871 ($+1) (down) 01EF:6870 C3 ret 01EF:6871 8BD1 mov dx,cx 01EF:6873 51 push cx 01EF:6874 E810AA call 00001287 ($-55f0) 01EF:6877 59 pop cx 01EF:6878 0AC0 or al,al 01EF:687A 7401 je 0000687D ($+1) (down) 01EF:687C C3 ret 01EF:687D 8B3E3746 mov di,[4637] ds:[4637]=4663 01EF:6881 880EF03F mov [3FF0],cl ds:[3FF0]=0000 01EF:6885 882EF13F mov [3FF1],ch ds:[3FF1]=0000 01EF:6889 8A4501 mov al,[di+01] ds:[3913]=0000 01EF:688C A2EE3F mov [3FEE],al ds:[3FEE]=0000 01EF:688F A2F53F mov [3FF5],al ds:[3FF5]=0C02 01EF:6892 8A4502 mov al,[di+02] ds:[4665]=200C 01EF:6895 A2EF3F mov [3FEF],al ds:[3FEF]=040C 01EF:6898 A2F63F mov [3FF6],al ds:[3FF6]=000C 01EF:689B E80EC5 call 00002DAC ($-3af2) 01EF:689E 803EC83F00 cmp byte [3FC8],00 ds:[3FC8]=0000 01EF:68A3 7501 jne 000068A6 ($+1) (no jmp) 01EF:68A5 C3 ret 01EF:68A6 BB1340 mov bx,4013 01EF:68A9 891ECC3F mov [3FCC],bx ds:[3FCC]=0000 01EF:68AD C3 ret
01EF:2DAC A0EE3F mov al,[3FEE] ds:[3FEE]=0000 01EF:2DAF 2A06F03F sub al,[3FF0] ds:[3FF0]=1515 01EF:2DB3 7902 jns 00002DB7 ($+2) (no jmp) 01EF:2DB5 F6D8 neg al 01EF:2DB7 8A26EF3F mov ah,[3FEF] ds:[3FEF]=1500 01EF:2DBB 2A26F13F sub ah,[3FF1] ds:[3FF1]=3915 01EF:2DBF 7902 jns 00002DC3 ($+2) (no jmp) 01EF:2DC1 F6DC neg ah 01EF:2DC3 02C4 add al,ah 01EF:2DC5 A2E937 mov [37E9],al ds:[37E9]=3737 01EF:2DC8 A09C3F mov al,[3F9C] ds:[3F9C]=3A3A 01EF:2DCB 32E4 xor ah,ah 01EF:2DCD A3F93F mov [3FF9],ax ds:[3FF9]=3F3E 01EF:2DD0 C606A83F00 mov byte [3FA8],00 ds:[3FA8]=3A3A 01EF:2DD5 C606C83F00 mov byte [3FC8],00 ds:[3FC8]=1515 01EF:2DDA C706F33F0000 mov word [3FF3],0000 ds:[3FF3]=1515 01EF:2DE0 C706CC3F0000 mov word [3FCC],0000 ds:[3FCC]=3B3C
Starting from memory location 0B6B:0A0E the subsequent 512 bytes are set to 1A1A x100h (256 times) by this function:
01EF:2DE6 BF0E0A mov di,0A0E 01EF:2DE9 B90001 mov cx,0100 01EF:2DEC 50 push ax 01EF:2DED B86B0B mov ax,0B6B 01EF:2DF0 8EC0 mov es,ax 01EF:2DF2 58 pop ax 01EF:2DF3 B81A1A mov ax,1A1A 01EF:2DF6 F3AB repe stosw
The code then creates a map with all possible paths of the hero:
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 07 06 07 08 09 -- 09 08 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 07 06 05 06 09 0A 09 08 07 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 06 05 04 05 0A 0B 0A 09 06 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 05 04 03 04 0B -- -- -- 05 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 03 02 01 02 01 02 03 04 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 05 04 03 02 -- -- -- -- 05 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 06 05 04 03 -- -- -- -- 06 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 07 06 05 04 -- -- -- -- 07 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 07 06 05 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
01EF:2DF8 8B3E3746 mov di,[4637] ds:[4637]=4663 01EF:2DFC EB74 jmp short 00002E72 ($+74) (down) 01EF:2DFE 90 nop 01EF:2DFF A0F23F mov al,[3FF2] ds:[3FF2]=0000 01EF:2E02 8B1EF33F mov bx,[3FF3] ds:[3FF3]=0000 01EF:2E06 8887FB3F mov [bx+3FFB],al ds:[411D]=0050 01EF:2E0A 43 inc bx 01EF:2E0B 3B1EF93F cmp bx,[3FF9] ds:[3FF9]=0009 01EF:2E0F 7601 jbe 00002E12 ($+1) (no jmp) 01EF:2E11 C3 ret 01EF:2E12 891EF33F mov [3FF3],bx ds:[3FF3]=0001 01EF:2E16 8A26F93F mov ah,[3FF9] ds:[3FF9]=0009 01EF:2E1A 2AE3 sub ah,bl 01EF:2E1C A0F03F mov al,[3FF0] ds:[3FF0]=0B04 01EF:2E1F 2A06F53F sub al,[3FF5] ds:[3FF5]=0B04 01EF:2E23 7902 jns 00002E27 ($+2) (down) 01EF:2E25 F6D8 neg al 01EF:2E27 3AC4 cmp al,ah 01EF:2E29 7603 jbe 00002E2E ($+3) (down) 01EF:2E2B E98400 jmp 00002EB2 ($+84) (down) 01EF:2E2E A0F13F mov al,[3FF1] ds:[3FF1]=000B 01EF:2E31 2A06F63F sub al,[3FF6] ds:[3FF6]=000B 01EF:2E35 7902 jns 00002E39 ($+2) (down) 01EF:2E37 F6D8 neg al 01EF:2E39 3AC4 cmp al,ah 01EF:2E3B 7775 ja 00002EB2 ($+75) (no jmp) 01EF:2E3D E87700 call 00002EB7 ($+77) 01EF:2E40 7270 jc 00002EB2 ($+70) (no jmp) 01EF:2E42 3E885E00 mov ds:[bp],bl ds:[007A]=0002 01EF:2E46 A0F53F mov al,[3FF5] ds:[3FF5]=0B04 01EF:2E49 3A06F03F cmp al,[3FF0] ds:[3FF0]=0B04 01EF:2E4D 7523 jne 00002E72 ($+23) (no jmp) 01EF:2E4F A0F63F mov al,[3FF6] ds:[3FF6]=000B 01EF:2E52 3A06F13F cmp al,[3FF1] ds:[3FF1]=000B 01EF:2E56 751A jne 00002E72 ($+1a) (no jmp) 01EF:2E58 881EC83F mov [3FC8],bl ds:[3FC8]=0000 01EF:2E5C 57 push di 01EF:2E5D BF1340 mov di,4013 01EF:2E60 BEFB3F mov si,3FFB 01EF:2E63 8A0EC83F mov cl,[3FC8] ds:[3FC8]=0000 01EF:2E67 32ED xor ch,ch 01EF:2E69 890EF93F mov [3FF9],cx ds:[3FF9]=0001 01EF:2E6D F3A4 repe movsb 01EF:2E6F 5F pop di 01EF:2E70 EB40 jmp short 00002EB2 ($+40) (down) 01EF:2E72 C606F23F00 mov byte [3FF2],00 ds:[3FF2]=0100 01EF:2E77 FE0EF63F dec byte [3FF6] ds:[3FF6]=000B
part of 2DF8 routine this writes the temporary math:
01EF:2E7B E881FF call 00002DFF ($-7f) <-- call itself again 01EF:2E7E FE06F63F inc byte [3FF6] ds:[3FF6]=000B 01EF:2E82 C606F23F01 mov byte [3FF2],01 ds:[3FF2]=0000 01EF:2E87 FE06F53F inc byte [3FF5] ds:[3FF5]=0B04 01EF:2E8B E871FF call 00002DFF ($-8f) <-- call itself again 01EF:2E8E FE0EF53F dec byte [3FF5] ds:[3FF5]=0B04 01EF:2E92 C606F23F02 mov byte [3FF2],02 ds:[3FF2]=0000 01EF:2E97 FE06F63F inc byte [3FF6] ds:[3FF6]=000B 01EF:2E9B E861FF call 00002DFF ($-9f) <-- call itself again 01EF:2E9E FE0EF63F dec byte [3FF6] ds:[3FF6]=000B 01EF:2EA2 C606F23F03 mov byte [3FF2],03 ds:[3FF2]=0000 01EF:2EA7 FE0EF53F dec byte [3FF5] ds:[3FF5]=0B04 01EF:2EAB E851FF call 00002DFF ($-af) <-- call itself again 01EF:2EAE FE06F53F inc byte [3FF5] ds:[3FF5]=0B04 01EF:2EB2 FF0EF33F dec word [3FF3] ds:[3FF3]=0000 01EF:2EB6 C3 ret
Notable Memory locations for hero's and monster's movement
3F92 = CURRENT QUEST 3F93 = Hero's current tile (see tilemap below) 3F94 = ACTIVE HERO'S ROOM 3F99 = 3F9A = END TURN FLAG 3F9B = action performed? 3F9C = REMAINING STEPS 3F9D = 3F9E = 3F9F = MONSTER'S X position 3FA0 = MONSTER'S Y position 3FA1 = Horizontal distance Monster-hero 3FA2 = Vertical distance Monster-hero 3FA3 = can be 00, 01 or FF 3FA4 = can be 00, 01 or FF 3FA5 = HERO'S X position 3FA6 = HERO'S Y position 3FA7 = Active hero 3FA8 = LOS 00=start 01=blocked 02=free 3FA9 = steps to take to reach the hero? 3FB9 = current total defense dice of the active hero during DEFENSE 3FEE = HERO'S X POSITION 3FEF = HERO'S Y POSITION 3FF0 = mouse click X position 3FF1 = mouse click Y position 3FF2 = 03 3FF3 = FF 3FF4 = FF 3FF5 = HERO'S X POSITION (copy) 3FF6 = HERO'S Y POSITION (copy) 3FF9 = rolled movement 3FFB - 4005 = math locations that varies among 00,01,02,03, at the end every byte is set to 03 (part of the hero's pathfinding routine) 4097 = infinite actions if set to a number different from 00
Screen tiles layout. The tile under the current hero is saved in [3F93] /\ /00\ /\ /\ /01\/02\ /\ /\ /\ /03\/04\/05\ /\ /\ /\ /\ /06\/07\/08\/09\ /\ /\ /\ /\ /\ /0A\/0B\/0C\/0D\/0E\ \ /\ /\ /\ /\ /\ \/0F\/10\/11\/12\/13\ \ /\ /\ /\ /\ / \/14\/15\/16\/17\/ \ /\ /\ /\ / \/18\/19\/1A\/ \ /\ /\ / \/1B\/1C\/ \ /\ / \/1D\/ \ / \/
The hero's moving animation is delegated to the in-game main loop routines.
[DATA SEGMENT] Main Pointers
The file inside the exe that represents the Data Segment (every byte that is not strictly CODE) starts at offset 0x9BE0. Every pointer is relative to this address.
Heroes' default profiles
offset mem pointer BP MP EQ AD DD ID 0xE243 0B6B:4663 00 00 00 00 00 00 08 02 1D 00 00 00 00 00 00 00 00 00 00 00 03 02 00 00 00 00 Barbarian 0xE25D 0B6B:467D 00 00 00 00 00 00 07 03 32 00 00 00 00 00 00 80 00 00 00 00 02 02 00 00 00 01 Dwarf 0xE277 0B6B:4697 00 00 00 00 00 00 06 04 35 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 02 Elf 0xE291 0B6B:46B1 00 00 00 00 00 00 04 06 4A 00 00 00 00 00 00 00 00 00 00 00 01 02 00 00 00 03 Wizard 0xE2AB 0B6B:46CB 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 01 02 00 00 00 04 Ragnar
The byte positions are the same of HeroQuest Savegame Format. Load and save operations read and write at these addreses.
When initializing the heroes the default values are resetted by the function 01EF:78D3 that resets all values to zero and Body and Mind points to default
0x00DF74 0B6B:4394 08 07 06 04 02 Default Body point values (last one is Ragnar's) 0x0148FB 0B6B:AD1B 02 03 04 06 00 Default Mind point values
Character initialization code:
01EF:78D3 8A1E9E40 mov bl,[409E] ds:[409E]=0002 01EF:78D7 B700 mov bh,00 01EF:78D9 8B879443 mov ax,[bx+4394] ds:[4396]=0406 01EF:78DD 884406 mov [si+06],al ds:[469D]=0406 <-- sets default body points 01EF:78E0 8A871BAD mov al,[bx-52E5] ds:[FFFFAD1D]=EC8B 01EF:78E4 884407 mov [si+07],al ds:[469E]=3804 <-- sets default mind points 01EF:78E7 C6440E00 mov byte [si+0E],00 ds:[46A5]=0000 <-- resets Owned weapon 01EF:78EB C6440F00 mov byte [si+0F],00 ds:[46A6]=0000 <-- resets Owned armour 01EF:78EF C6440D00 mov byte [si+0D],00 ds:[46A4]=0000 <-- resets Owned special items 01EF:78F3 C744090000 mov word [si+09],0000 ds:[46A0]=000A <-- resets GOLD 01EF:78F8 C6441100 mov byte [si+11],00 ds:[46A8]=0000 <-- resets Equipped weapon 01EF:78FC C6441200 mov byte [si+12],00 ds:[46A9]=0000 <-- resets Equipped special item 01EF:7900 C6441300 mov byte [si+13],00 ds:[46AA]=0200 <-- resets Equipped armour 01EF:7904 885C19 mov [si+19],bl ds:[46B0]=0002 <-- refresh hero's ID 01EF:7907 803E9E4001 cmp byte [409E],01 ds:[409E]=0002 <-- if dwarf 01EF:790C 7504 jne 00007912 ($+4) (down) 01EF:790E 804C0E80 or byte [si+0E],80 ds:[46A5]=0000 <-- gives him the toolkit 01EF:7912 BB0800 mov bx,0008 <-- "The character is renewed" string 01EF:7915 E8D50F call 000088ED ($+fd5) <-- draws the scroll
Searched room table
The game keeps track of the searched room by storing the value FF into two tables (treasure and traps searches) using the room number as relative offset (bx).
Room numbers go from 00 to 2A so each table is 2B bytes long and every byte of the table is set to 00 at the beginnng of the quest.
The code that puts FF into the table:
mov byte ptr [bx+4B70h], 0FFh [0B6B:4B70] starting address of TREASURE search mov byte ptr [bx+4B9Bh], 0FFh [0B6B:4B9B] starting address of TRAPS/SECRET PASSAGES search
NOTE: upon starting a quest, every Special event ID is put into these tables replacing the 00.
Equipment screen
With position on screen is intended the string header 11XXYY
0x014863 Hero's classes label (ie. Barbarian) position on screen 0x00DF2B pointers block to default Hero's classes (5 pointers) 0x00DF35 default Hero's classes labels (5 Labels)
0x014873 Hero's name label (ie. Sigmar) position on screen 0x00E1B7 pointers block to default Hero's names 0x00E1C5 default Hero's names labels (5 Labels)
0x0141A4 first epilogue panel text (its pointer A5C4 is written inside the code at offset 0x0649) 0x0143A2 second epilogue panel text (its pointer A7C2 is written inside the code at offset 0x0658)
0x0147F7 actual gear prices (hexadecimal) - 4x12 = 30 Bytes (2 bytes for equipment bit mask and 2 bytes for default price, little endian) 0x01482B pointers block to single gear costs - 2xC = 18 Bytes 0x014843 price (in decimal) labels - 1F Bytes
0x01486F "GOLD" label position on screen 0x014867 gold amount position on screen (default is 0000) 0x014877 equipment names position on screen 0x01487B pointers block to the pointers in [language].bin where the item names are - 0x18 Bytes
0x014943 equipment names position on screen during a quest (the subsequent 28 zeroes are the placeholder) 0x014920 position on screen of a bar filled with 20h char used to delete the equipment names while moving se mouse over the icons 0x014924 Text colour (1F is white) 0x014925 Background colour (14 is transparent)
not related but in the same exe area
0x014A42 sequence of 7 pointers in language.bin of the potion effect texts 0xE472 sequence of 5 pointers in language.bin of the potion finding texts (all but holy water and heroic brew, that has direct pointers inside the code)
Intro Sequence
Every text panel of the intro resides into INTRO.EXE and they're in English only.
In order to translate them (or change the lenght of the text) you have to uncompress the exe first, then Locate every pointers of each panel.
The data segment inside the exe starts at 0x01C0. Every pointer is relative to this address.
Panel # | default pointer value | pointer exe offset |
---|---|---|
1 | 0603 | 0x0212 |
2 | F203 | 0x0214 |
3 | 9B04 | 0x0216 |
4 | 8706 | 0x0218 |
5 | 7008 | 0x021A |
6 | CA0A | 0x021C |
The panels layout follows the same rules described under HeroQuest Strings Format
Protection screen
to restore shield protection in UNCOMPRESSED QUEST.EXE modify
offset 0x0541 from 90 90 90 to E8 DC FE (if you modify these bytes only the shield screen stays and regardless of page entered the game starts anyway) offset 0x0549 from EB to 74