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).
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 |
| 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
|