We just released a Feb. 5 '89 prototype of DuckTales for the NES!
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)

From The Cutting Room Floor
Revision as of 20:01, 7 December 2019 by Mouser (talk | contribs) (→‎References for Code Changes: R3 Jump Into Ceiling.)
Jump to navigation Jump to search

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