If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!
Notes:The Adventures of Captain Comic (DOS)
This page contains notes for the game The Adventures of Captain Comic (DOS).
Contents
Revisions
The Internet Archive has all five revisions under the item TheAdventuresOfCaptainComic:
It also has three other versions:
- swh11988 (file_id.diz labels it "Hacked/grafitti version 1")
- swh21988 (file_id.diz labels it "Hacked/grafitti version 2")
- R4a1sw1989 (file_id.diz labels it "Alternate version 1")
File Formats
Malvineous has documented the file formats here.
Executable Packing
In every revision, COMIC.EXE is packed with EXEPACK. Revision 1 uses an earlier version of EXEPACK that not all unpackers can handle. Try these ones:
R1swh21988 (a hacked version) doesn't have COMIC.EXE but rather MENU.EXE, and the EXEPACK layer appears to be wrapped in another layer that adds an advertisement for "Red Point".
Sound Effects
The format of a sound effect is an array of
struct {
uint16_t freq_divider;
uint16_t duration;
};
The 16-bit values are stored little-endian. Each freq_divider divides the Programmable Interval Timer base frequency of 1193182 Hz. For example, a freq_divider of 1c3f would result in an output frequency of 1193182 / 0x1c3f ≈ 165 Hz. The special freq_divider value 0028 indicates a rest. duration is in number of beats; each beat is about 55 ms (one tick of the 18.2 Hz IRQ 0 timer). The end of the sound is marked by a freq_divider of 0000.
Table of offsets to sound effects in the unpacked executable. Assumes that the unpacked executable has an EXE header of 512 bytes. Changed sounds are highlighted.
| R1sw1988 | R1swh11988 | R2sw1988 | R3sw1989 | R4a1sw1989 | R4sw1989 | R5sw1991 | |
|---|---|---|---|---|---|---|---|
| title | 2521 | 2521 | 25a2 | 25d2 | 27a2 | 27a2 | 29c4 |
| start | 2665 | 2665 | 2bc0 | 2bf2 | 2daa | 2d9e | |
| door | eda9 | eda9 | f309 | f339 | f4f9 | f4e9 | fc29 |
| player death | edd1 | edd1 | f331 | f361 | f521 | f511 | fc51 |
| teleport | edf9 | edf9 | f359 | f389 | f549 | f539 | fc79 |
| bonus | ee19 | ee19 | f379 | f3a9 | f569 | f559 | fc99 |
| materialize | ee25 | ee25 | f385 | f3b5 | f575 | f565 | fca5 |
| game over | ee85 | ee85 | f3e5 | f415 | f5d5 | f5c5 | fd05 |
| screen transition | eede | eede | f43e | f46f | f62f | f61f | fd3f |
| lost life | eefe | eefe | f45e | f48f | f64f | f63f | fd5f |
| shoot | ef4e | ef4e | f4ae | f4de | f69e | f68e | fdae |
| enemy death | ef5a | ef5a | f4ba | f4ea | f6aa | f69a | fdba |
| player damaged | ef71 | ef71 | f4d1 | f501 | f6c1 | f6b1 | fdd1 |
| item get | ef81 | ef81 | f4e1 | f511 | f6d1 | f6c1 | fde1 |
| extra life | ef95 | ef95 | f4f5 | f525 | f6e5 | f6d5 | fdf5 |
References for Code Changes
R2 Key Status
| Revision 1 @ 3bc | Revision 2 @ 419 |
|---|---|
int9_handler_continue: ; al is scancode, dl is press/release status
3c01 cmp al, 1 ; scancode == Esc?
7415 je int9_handler_Esc
2c38 sub al, 0x38 ; scancode < LAlt?
7216 jb int9_handler_done
3c1b cmp al, 0x1b ; scancode >= Del?
7312 jae int9_handler_done
8d1e8703 lea bx, word [key_status]
32e4 xor ah, ah
03d8 add bx, ax
2e8817 mov byte cs:[bx], dl ; key_status[scancode-0x38] = dl
eb05 jmp int9_handler_done
int9_handler_Esc:
2e88168603 mov byte cs:[key_Esc_state], dl
int9_handler_done:
|
int9_handler_continue: ; al is scancode, dl is press/release status
2e3a061900 cmp al, byte cs:[scancode_jump]
742a je int9_handler_jump
2e3a061a00 cmp al, byte cs:[scancode_fire]
742a je int9_handler_fire
2e3a061b00 cmp al, byte cs:[scancode_left]
742a je int9_handler_left
2e3a061c00 cmp al, byte cs:[scancode_right]
742a je int9_handler_right
2e3a061d00 cmp al, byte cs:[scancode_open]
742a je int9_handler_open
2e3a061e00 cmp al, byte cs:[scancode_teleport]
752a jne int9_handler_special
int9_handler_teleport:
2e88161500 mov byte cs:[key_teleport_state], dl
eb41 jmp int9_handler_done
int9_handler_jump:
2e88161400 mov byte cs:[key_jump_state], dl
eb3a jmp int9_handler_done
int9_handler_fire:
2e88161800 mov byte cs:[key_fire_state], dl
eb33 jmp int9_handler_done
int9_handler_left:
2e88161600 mov byte cs:[key_left_state], dl
eb2c jmp int9_handler_done
int9_handler_right:
2e88161700 mov byte cs:[key_right_state], dl
eb25 jmp int9_handler_done
int9_handler_open:
2e88161300 mov byte cs:[key_open_state], dl
eb1e jmp int9_handler_done
int9_handler_special:
3c01 cmp al, 1 ; scancode == Esc?
7415 je int9_handler_Esc
2c3b sub al, 0x3b ; scancode <= F1?
7216 jb int9_handler_done
3c04 cmp al, 4 ; scancode > F4?
7312 jae int9_handler_done
8d1e0f00 lea bx, word [keys_F_state]
32e4 xor ah, ah
03d8 add bx, ax
2e8817 mov byte cs:[bx], dl ; keys_F_state[scancode-0x3b] = dl
eb05 jmp int9_handler_done
int9_handler_esc:
2e88160e00 mov byte cs:[key_Esc_state], dl
int9_handler_done:
|
R3 Esc
| Revision 2 @ 76 | Revision 3 @ 76 |
|---|---|
cd16 int 0x16 ; get keystroke; al=ASCII code
3c6b cmp al, 0x6b ; 'k'
7407 je setup_keyboard
3c4b cmp al, 0x4b ; 'K'
7403 je setup_keyboard
e95001 jmp game_start
setup_keyboard:
|
cd16 int 0x16 ; get keystroke; al=ASCII code
3c6b cmp al, 0x6b ; 'k'
740e je setup_keyboard
3c4b cmp al, 0x4b ; 'K'
740a je setup_keyboard
3c1b cmp al, 0x1b ; Esc
7503 jne any_other_key
e95203 jmp terminate_program
any_other_key:
e95401 jmp game_start
setup_keyboard:
|
R3 Keyboard Setup Hack
| Revision 2 @ 83 | Revision 3 @ 8a |
|---|---|
setup_keyboard:
1e push ds
b8b70f mov ax, 0xfb7 ; segment containing keyboard-related strings
8ed8 mov ds, ax ; set ds to it
e8f200 call input_key_mapping ; eat the 'k' already released
b80200 mov ax, 2 ; video mode 2 (80x25 text)
cd10 int 0x10 ; set video mode (clear screen)
|
setup_keyboard:
1e push ds
b8b70f mov ax, 0xfb7 ; segment containing keyboard-related strings
8ed8 mov ds, ax ; set ds to it
b80200 mov ax, 2 ; video mode 2 (80x25 text)
cd10 int 0x10 ; set video mode (clear screen)
|
R3 Keyboard Buffer
Interrupts were disabled in two places:
| Revision 2 @ 115 | Revision 3 @ 1d1 |
|---|---|
; 0040:1a is pointer to beginning of the buffer of pending keystrokes
; 0040:1c is pointer to end
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl ; set end = beginning
|
; 0040:1a is pointer to beginning of the buffer of pending keystrokes
; 0040:1c is pointer to end
fa cli ; disable interrupts
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl ; set end = beginning
fb sti ; enable interrupts
|
| Revision 2 @ 2b4 | Revision 3 @ 2bf |
|---|---|
; 0040:1a is pointer to beginning of the buffer of pending keystrokes
; 0040:1c is pointer to end
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl ; set end = beginning
|
; 0040:1a is pointer to beginning of the buffer of pending keystrokes
; 0040:1c is pointer to end
fa cli ; disable interrupts
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl ; set end = beginning
fb sti ; enable interrupts
|
Interrupts were not disabled at four other instances of the same pattern:
| Revision 2 @ ff5 | Revision 3 @ 1004 |
|---|---|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
| Revision 2 @ 103f | Revision 3 @ 104e |
|---|---|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
| Revision 2 @ 110b | Revision 3 @ 111a |
|---|---|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
| Revision 2 @ 1228 | Revision 3 @ 1237 |
|---|---|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
|
R3 Key Mapping
| Revision 2 @ 17e | Revision 3 @ 174 |
|---|---|
input_key_mapping:
2ec6061f0000 mov byte cs:[last_key], 0 ; set in int9_handler
2e803e1f0000 cmp byte cs:[last_key], 0
74f8 je input_key_mapping ; loop until a key is released
2e8a1e1f00 mov bl, byte cs:[last_key]
32ff xor bh, bh ; bx = scancode
2e3a1e1900 cmp bl, byte cs:[scancode_jump]
74e4 je input_key_mapping
2e3a1e1b00 cmp bl, byte cs:[scancode_left]
74dd je input_key_mapping
2e3a1e1c00 cmp bl, byte cs:[scancode_right]
74d6 je input_key_mapping
2e3a1e1a00 cmp bl, byte cs:[scancode_fire]
74cf je input_key_mapping
2e3a1e1d00 cmp bl, byte cs:[scancode_open]
74c8 je input_key_mapping
4b dec bx ; scancode == 0x1 (Esc)?
74c5 je input_key_mapping
83fb51 cmp bx, 0x51 ; scancode > 0x52 (Ins)?
7fc0 jg input_key_mapping
d1e3 shl bx, 1
d1e3 shl bx, 1
d1e3 shl bx, 1
8d164a40 lea dx, word [key_names]
03d3 add dx, bx ; look up the key's name
b409 mov ah, 9
cd21 int 0x21 ; print string
2ea01f00 mov al, byte cs:[last_key] ; return scancode
c3 ret
|
input_key_mapping:
e84400 call wait_for_keypress
8ad8 mov bl, al
32ff xor bh, bh ; bx = scancode
8bf3 mov si, bx
2e3a1e1900 cmp bl, byte cs:[scancode_jump]
74f0 je input_key_mapping
2e3a1e1b00 cmp bl, byte cs:[scancode_left]
74e9 je input_key_mapping
2e3a1e1c00 cmp bl, byte cs:[scancode_right]
74e2 je input_key_mapping
2e3a1e1a00 cmp bl, byte cs:[scancode_fire]
74db je input_key_mapping
2e3a1e1d00 cmp bl, byte cs:[scancode_open]
74d4 je input_key_mapping
4b dec bx ; scancode == 0x1 (Esc)?
74d1 je input_key_mapping
83fb52 cmp bx, 0x52 ; scancode > 0x53 (Del)?
7fcc jg input_key_mapping
d1e3 shl bx, 1
d1e3 shl bx, 1
d1e3 shl bx, 1
8d164a40 lea dx, word [key_names]
03d3 add dx, bx ; look up the key's name
b409 mov ah, 9
cd21 int 0x21 ; print string
8bc6 mov ax, si ; return scancode
c3 ret
wait_for_keypress:
2ec6061f0000 mov byte cs:[last_key], 0 ; set in int9_handler
2e803e1f0000 cmp byte cs:[last_key], 0
74f8 je wait_for_keypress ; loop until a key is pressed
; clear BIOS keyboard buffer
33c0 xor ax, ax
8ec0 mov es, ax
2ea01f00 mov al, byte cs:[last_key] ; return scancode
fa cli
268a0e1a04 mov cl, byte es:[0x41a]
26880e1c04 mov byte es:[0x41c], cl
fb sti
c3 ret
|
R3 Key Press/Release
| Revision 2 @ 3f8 | Revision 3 @ 405 |
|---|---|
saved_int9_handler: ; pointer to the original handler for interrupt 9
00000000 dw 0x0000, 0x0000
int9_handler: ; IRQ 1, keyboard data ready, called for every keyboard event
50 push ax
53 push bx
51 push cx
52 push dx
e460 in al, 0x60 ; al = scancode
50 push ax ; save al
9c pushf
2eff1ef803 lcall cs:[saved_int9_handler] ; call original interrupt handler
58 pop ax ; restore al = scancode
ba0100 mov dx, 1 ; initially set dl = 1 to indicate key press
a880 test al, 0x80 ; check the high bit of the scancode
7408 jz continue ; if 0, it was indeed a key press
247f and al, 0x7f ; otherwise, it was a key release
2ea21f00 mov byte cs:[last_key], al ; clear high bit and store scancode
33d2 xor dx, dx ; set dl = 0 to indicate key release
int9_handler_continue:
|
saved_int9_handler: ; pointer to the original handler for interrupt 9
00000000 dw 0x0000, 0x0000
int9_handler: ; IRQ 1, keyboard data ready, called for every keyboard event
50 push ax
53 push bx
51 push cx
52 push dx
e460 in al, 0x60 ; al = scancode
50 push ax ; save al
9c pushf
2eff1e0504 lcall cs:[saved_int9_handler] ; call original interrupt handler
58 pop ax ; restore al = scancode
ba0100 mov dx, 1 ; initially set dl = 1 to indicate key press
a880 test al, 0x80 ; check the high bit of the scancode
7406 jz key_was_pressed ; if 0, it was indeed a key press
247f and al, 0x7f ; otherwise, it was a key release
33d2 xor dx, dx ; set dl = 0 to indicate key release
eb04 jmp continue ; do not store scancode
key_was_pressed:
2ea21f00 mov byte cs:[last_key], al ; clear high bit and store scancode
int9_handler_continue:
|
R3 Unpause
| Revision 2 @ 1374 | Revision 3 @ 1383 |
|---|---|
2e803e0e0001 cmp byte cs:[key_Esc_state], 1 ; Esc is pressed?
7503 jne do_not_pause
e851fc call pause_game ; returns after any key is pressed
do_not_pause:
|
2e803e0e0001 cmp byte cs:[key_Esc_state], 1 ; Esc is pressed?
750f jne do_not_pause
e851fc call pause_game ; returns after any key is pressed
wait_for_Esc_release:
2e803e0e0001 cmp byte cs:[key_Esc_state], 1
74f8 je wait_for_Esc_release ; wait until Esc is not pressed
8b364000 mov si, word [player_position]
do_not_pause:
|
R3 Initialize Jump Counter
| Revision 2 @ 147c | Revision 3 @ 1497 |
|---|---|
c60616cf00 mov byte [player_y_vel], 0
c60617cf00 mov byte [jump_counter], 0
c6061acf00 mov byte [player_run_cycle], 0
|
c60616cf00 mov byte [player_y_vel], 0
c60618cf04 mov byte [jump_counter], 4
c6061bcf00 mov byte [player_run_cycle], 0
|
R3 Jump Into Ceiling
| Revision 2 @ 1498 | Revision 3 @ 14b3 |
|---|---|
handle_falling_and_jumping:
fe0e17cf dec byte [jump_counter]
740f je .L1
2e803e140001 cmp byte cs:[key_jump_state], 1
750b jne .L3
802e16cf07 sub byte [comic_y_vel], 7 ; still jumping upward
eb04 jmp .L3
.L1:
fe0617cf inc byte [jump_counter] ; jump_counter bottoms out at 1
|
|
.L3:
a016cf mov al, byte [comic_y_vel]
8ac8 mov cl, al
d0f8 sar al, 1
d0f8 sar al, 1
d0f8 sar al, 1
8bde mov bx, si ; bl = comic_y_pos, bh = comic_x_pos
02d8 add bl, al ; bl = comic_y_pos + comic_y_vel/8
7d02 jge .L4 ; hit the top of the screen?
b300 mov bl, 0
.L4:
|
|
8bf3 mov si, bx ; comic_y_pos = max(0, comic_y_pos + comic_y_vel/8)
80fb11 cmp bl, 0x11 ; comic_y_pos >= 8.5 tiles?
7203 jb .L5
e946ff jmp comic_dies ; die from falling in a pit
.L5:
803e3e0002 cmp byte [current_level_number], 2 ; is this the space level?
7503 jne .L6
80e902 sub cl, 2 ; if so, comic_y_vel += 3
.L6:
80c105 add cl, 5 ; otherwise, comic_y_vel += 5
80f918 cmp cl, 0x18 ; comic_y_vel > 23?
7c02 jl .L7
b117 mov cl, 0x17 ; maximum falling velocity is 23
.L7:
880e16cf mov byte [comic_y_vel], cl
8a0e15cf mov cl, byte [comic_x_momentum]
check_key_left:
2e803e160001 cmp byte cs:[key_left_state], 1
750e jne check_key_right
c60619cf05 mov byte [comic_facing], 5 ; face left
; comic_x_momentum = max(comic_x_momentum - 1, -5)
fec9 dec cl
80f9fb cmp cl, -5
7d02 jge check_key_right
b1fb mov cl, -5
check_key_right:
2e803e170001 cmp byte cs:[key_right_state], 1
750e jne .L8
c60619cf00 mov byte [comic_facing], 0 ; face right
; comic_x_momentum = min(comic_x_momentum + 1, +5)
fec1 inc cl
80f905 cmp cl, +5
7e02 jle .L8
b105 mov cl, +5
.L8:
880e15cf mov byte [comic_x_momentum], cl
check_move_left:
0ac9 or cl, cl ; comic_x_momentum < 0?
7d07 jge check_move_right
fe0615cf inc byte [comic_x_momentum]
e87d00 call comic_moves_left
a015cf mov al, byte [comic_x_momentum]
check_move_right:
0ac0 or al, al ; comic_x_momentum > 0?
7e07 jle check_for_head_bonk
fe0e15cf dec byte [comic_x_momentum]
e8cb00 call comic_moves_right
check_for_head_bonk:
8bc6 mov ax, si ; al = comic_y_pos, ah = comic_x_pos
e890f4 call lookup_tile_at_coordinates ; tile at player's head
8a164007 mov dl, byte [last_solid_tile]
3817 cmp byte [bx], dl ; is it solid?
7f0a jg in_ceiling
f6c401 test ah, 1 ; is the player halfway between tiles?
740a je check_for_solid_ground
385701 cmp byte [bx + 1], dl ; if so, also check the next tile to the right
7e05 jle check_for_solid_ground
in_ceiling:
c60616cf08 mov byte [comic_y_vel], 8 ; bounce downward off the ceiling
|
|
|
|
|
check_for_solid_ground:
803e16cf00 cmp byte [comic_y_vel], 0 ; is the player moving downward?
7e1b jle not_on_solid_ground
8bce mov cx, si ; cl = comic_y_pos, ch = comic_x_pos
8bc1 mov ax, cx ; al = comic_y_pos, ah = comic_x_pos
0405 add al, 5 ; comic_y_pos + 5
e869f4 call lookup_tile_at_coordinates ; tile at player's feet (Comic is 4 units tall)
8a164007 mov dl, byte [last_solid_tile]
3817 cmp byte [bx], dl ; is it solid?
7f12 jg check_if_too_low
f6c401 test ah, 1 ; is the player halfway between tiles?
7405 je not_on_solid_ground
385701 cmp byte [bx + 1], dl ; if so, also check the next tile to the right
7f08 jg check_if_too_low
not_on_solid_ground:
c6061acf04 mov byte [comic_graphic], 4 ; jumping graphic
e9f7fd jmp return_to_game_loop
check_if_too_low:
80f90f cmp cl, 0xf ; comic_y_pos < 7.5 tiles?
7202 jb on_solid_ground ; if so, tile check was meaningful
ebf1 jmp not_on_solid_ground ; if not, player is too low for there to be ground
on_solid_ground:
fec1 inc cl
80e1fe and cl, 0xfe ; clamp player's feet to even tile offset
8bf1 mov si, cx ; player_y = (player_y + 1) & 0xfe
c60613cf00 mov byte [comic_is_airborne], 0
c60616cf00 mov byte [comic_y_vel], 0
e9dcfd jmp return_to_game_loop
|
handle_falling_and_jumping:
fe0e18cf dec byte [jump_counter]
740f je .L1
2e803e140001 cmp byte cs:[key_jump_state], 1
750b jne .L2
802e16cf07 sub byte [comic_y_vel], 7 ; still jumping upward
eb09 jmp .L3
.L1:
fe0618cf inc byte [jump_counter] ; jump_counter bottoms out at 1
.L2:
c60617cf00 mov byte [in_ceiling_flag], 0 ; no longer in ceiling if jump is finished
.L3:
a016cf mov al, byte [comic_y_vel]
8ac8 mov cl, al
d0f8 sar al, 1
d0f8 sar al, 1
d0f8 sar al, 1
8bde mov bx, si ; bl = comic_y_pos, bh = comic_x_pos
02d8 add bl, al ; bl = comic_y_pos + comic_y_vel/8
7d02 jge .L4 ; hit the top of the screen?
b300 mov bl, 0
.L4:
021e17cf add bl, byte [in_ceiling_flag]
c60617cf00 mov byte [in_ceiling_flag], 0
8bf3 mov si, bx ; comic_y_pos = max(0, comic_y_pos + comic_y_vel/8 + in_ceiling_flag)
80fb11 cmp bl, 0x11 ; comic_y_pos >= 8.5 tiles?
7203 jb .L5
e938ff jmp comic_dies ; die from falling in a pit
.L5:
803e3e0002 cmp byte [current_level_number], 2 ; is this the space level?
7503 jne .L6
80e902 sub cl, 2 ; if so, comic_y_vel += 3
.L6:
80c105 add cl, 5 ; otherwise, comic_y_vel += 5
80f918 cmp cl, 0x18 ; comic_y_vel > 23?
7c02 jl .L7
b117 mov cl, 0x17 ; maximum falling velocity is 23
.L7:
880e16cf mov byte [comic_y_vel], cl
8a0e15cf mov cl, byte [comic_x_momentum]
check_key_left:
2e803e160001 cmp byte cs:[key_left_state], 1
750e jne check_key_right
c6061acf05 mov byte [comic_facing], 5 ; face left
; comic_x_momentum = max(comic_x_momentum - 1, -5)
fec9 dec cl
80f9fb cmp cl, -5
7d02 jge check_key_right
b1fb mov cl, -5
check_key_right:
2e803e170001 cmp byte cs:[key_right_state], 1
750e jne .L8
c6061acf00 mov byte [comic_facing], 0 ; face right
; comic_x_momentum = min(comic_x_momentum + 1, +5)
fec1 inc cl
80f905 cmp cl, +5
7e02 jle .L8
b105 mov cl, +5
.L8:
880e15cf mov byte [comic_x_momentum], cl
check_move_left:
0ac9 or cl, cl ; comic_x_momentum < 0?
7d07 jge check_move_right
fe0615cf inc byte [comic_x_momentum]
e88b00 call comic_moves_left
a015cf mov al, byte [comic_x_momentum]
check_move_right:
0ac0 or al, al ; comic_x_momentum > 0?
7e07 jle check_for_head_bonk
fe0e15cf dec byte [comic_x_momentum]
e8d900 call comic_moves_right
check_for_head_bonk:
8bc6 mov ax, si ; al = comic_y_pos, ah = comic_x_pos
e876f4 call lookup_tile_at_coordinates ; tile at player's head
8a164007 mov dl, byte [last_solid_tile]
3817 cmp byte [bx], dl ; is it solid?
7f0a jg in_ceiling
f6c401 test ah, 1 ; is the player halfway between tiles?
7418 je check_for_solid_ground
385701 cmp byte [bx + 1], dl ; if so, also check the next tile to the right
7e13 jle check_for_solid_ground
in_ceiling:
|
803e16cf00 cmp byte [comic_y_vel], 0 ; is the player moving downward?
7f0c jg check_for_solid_ground
c60617cf01 mov byte [in_ceiling_flag], 1 ; stick to the ceiling
c60616cf00 mov byte [comic_y_vel], 0 ; but stop moving upward
eb22 jmp not_on_solid_ground
check_for_solid_ground:
803e16cf00 cmp byte [comic_y_vel], 0 ; is the player moving downward?
7e1b jle not_on_solid_ground
8bce mov cx, si ; cl = comic_y_pos, ch = comic_x_pos
8bc1 mov ax, cx ; al = comic_y_pos, ah = comic_x_pos
0405 add al, 5 ; comic_y_pos + 5
e841f4 call lookup_tile_at_coordinates ; tile at player's feet (Comic is 4 units tall)
8a164007 mov dl, byte [last_solid_tile]
3817 cmp byte [bx], dl ; is it solid?
7f12 jg check_if_too_low
f6c401 test ah, 1 ; is the player halfway between tiles?
7405 je not_on_solid_ground
385701 cmp byte [bx + 1], dl ; if so, also check the next tile to the right
7f08 jg check_if_too_low
not_on_solid_ground:
c6061bcf04 mov byte [comic_graphic], 4 ; jumping graphic
e9cffd jmp return_to_game_loop
check_if_too_low:
80f90f cmp cl, 0xf ; comic_y_pos < 7.5 tiles?
7202 jb on_solid_ground ; if so, tile check was meaningful
ebf1 jmp not_on_solid_ground ; if not, player is too low for there to be ground
on_solid_ground:
fec1 inc cl
80e1fe and cl, 0xfe ; clamp player's feet to even tile offset
8bf1 mov si, cx ; player_y = (player_y + 1) & 0xfe
c60613cf00 mov byte [comic_is_airborne], 0
c60616cf00 mov byte [comic_y_vel], 0
e9b4fd jmp return_to_game_loop
|