Added comments; changed zero page so it will mostly work on the atari

This commit is contained in:
Rob McMullen 2017-08-01 19:27:54 -07:00
parent 51ef7374a9
commit b1a142d0f0
5 changed files with 65 additions and 93 deletions

View File

@ -5,6 +5,14 @@ Fujirun
My (winning!) entry in the `KansasFest <https://www.kansasfest.org/>`_ 2017 `HackFest <https://www.kansasfest.org/hackfest/>`_ competition.
Code Walkthrough
================
TBD
* any place you see the "_smc" extension, that's a target for self-modifying code. Got that from Quinn Dunki.
References
==========

View File

@ -1,7 +1,7 @@
level_enemies .byte 55, 4, 5, 6, 7, 8 ;# level starts counting from 1, so dummy zeroth level info
level_speed_l .byte 255, 200, 210, 220, 230, 240 ;# increment of fractional pixel per game frame
level_speed_h .byte 2, 2, 2, 2, 2, 2
;level_speed_h .byte 0, 0, 0, 0, 0, 0
level_speed_h .byte 2, 2, 2, 2, 2, 2 ; increment of whole pixels
player_score_row .byte 2, 7, 12, 17
player_lives_row .byte 3, 8, 13, 18
player_score_l .byte 0, 0, 0, 0

67
logic.s
View File

@ -1,51 +1,4 @@
; def draw_actors():
; zp.current_actor = 0
; while zp.current_actor <= zp.last_enemy:
; r = actor_row[zp.current_actor]
; c = actor_col[zp.current_actor]
; get_sprite()
; draw_sprite(r, c)
; zp.current_actor += 1
;
; def get_sprite():
; a = actor_status[zp.current_actor]
; if a == PLAYER_ALIVE:
; c = ord("$") + zp.current_actor
; elif a == PLAYER_EXPLODING:
; collision_log.debug("p%d: exploding, frame=%d" % (zp.current_actor, actor_frame_counter[zp.current_actor]))
; c = ord(exploding_char[actor_frame_counter[zp.current_actor]])
; actor_frame_counter[zp.current_actor] -= 1
; if actor_frame_counter[zp.current_actor] <= 0:
; actor_status[zp.current_actor] = PLAYER_DEAD
; actor_frame_counter[zp.current_actor] = DEAD_TIME
; elif a == PLAYER_DEAD:
; collision_log.debug("p%d: dead, waiting=%d" % (zp.current_actor, actor_frame_counter[zp.current_actor]))
; c = None
; actor_frame_counter[zp.current_actor] -= 1
; if actor_frame_counter[zp.current_actor] <= 0:
; player_lives[zp.current_actor] -= 1
; if player_lives[zp.current_actor] > 0:
; init_player()
; actor_status[zp.current_actor] = PLAYER_REGENERATING
; actor_frame_counter[zp.current_actor] = REGENERATING_TIME
; else:
; actor_status[zp.current_actor] = GAME_OVER
; elif a == PLAYER_REGENERATING:
; collision_log.debug("p%d: regenerating, frame=%d" % (zp.current_actor, actor_frame_counter[zp.current_actor]))
; if actor_frame_counter[zp.current_actor] & 1:
; c = ord("$") + zp.current_actor
; else:
; c = ord(" ")
; actor_frame_counter[zp.current_actor] -= 1
; if actor_frame_counter[zp.current_actor] <= 0:
; actor_status[zp.current_actor] = PLAYER_ALIVE
; elif a == AMIDAR_NORMAL or a == ORBITER_NORMAL:
; c = ord("0") + zp.current_actor - FIRST_AMIDAR
; else:
; c = None
; zp.sprite_addr = c
; check the player and change its state if necessary
evaluate_status nop
; update pixel position
lda actor_status,x
@ -100,7 +53,7 @@ evaluate_status nop
sta actor_status,x
?end rts
; convert tile and sub-tile position into coordinate on screen
get_sprite nop
lda actor_row,x
tay
@ -114,17 +67,10 @@ get_sprite nop
clc
adc actor_xpixel,x
sta actor_x,x
?end
rts
?game_over
rts
;
;
; ##### Game logic
;
; # Determine which of the 4 directions is allowed at the given row, col
; def get_allowed_dirs(r, c):
; addr = mazerow(r)
@ -140,7 +86,6 @@ get_allowed_dirs nop
rts
; # See if current tile has a dot
; def has_dot(r, c):
; addr = mazerow(r)
@ -154,11 +99,6 @@ has_dot nop
rts
; # clear a dot
; def clear_dot(r, c):
; addr = mazerow(r)
; addr[c] &= ~TILE_DOT
;
; # Determine the tile location given the direction of the actor's movement
; def get_next_tile(r, c, dir):
; if dir & TILE_UP:
@ -270,7 +210,8 @@ get_target_col nop
rts
; actor_target_col[zp.current_actor] = target_col
; return current
;
; def check_midpoint(current):
; # set up decision point flag to see if we have crossed the midpoint
; # after the movement

47
main.s
View File

@ -16,7 +16,7 @@ param_index .ds 1
param_count .ds 1
param_save .ds 1
*= $0010
*= $0080
; scratch areas: these may be modified by child subroutines
scratch_addr .ds 2
scratch_ptr .ds 2
@ -28,8 +28,8 @@ scratch_count .ds 1
scratch_col .ds 1
scratch_row .ds 1
*= $0020
; required variables for HiSprite
*= $0090
; required variables for HiSprite/asmgen
damageindex .ds 1
damageindex1 .ds 1
damageindex2 .ds 1
@ -40,7 +40,7 @@ damageptr .ds 2
damageptr1 .ds 2
damageptr2 .ds 2
*= $0030
*= $00a0
tdamageindex .ds 1
tdamageindex1 .ds 1
tdamageindex2 .ds 1
@ -51,7 +51,7 @@ end .ds 2
count .ds 2
delta .ds 2
*= $0040
*= $00b0
; global variables for this program
rendercount .ds 1
drawpage .ds 1 ; pos = page1, neg = page2
@ -65,7 +65,7 @@ temprow .ds 1
tempcol .ds 1
tempcheck .ds 1
*= $0050
*= $00c0
mazeaddr .ds 2
next_level_box .ds 1
box_row_save .ds 1
@ -77,7 +77,7 @@ frame_count .ds 2
countdown_time .ds 1
still_alive .ds 1
*= $0060
*= $00d0
current_actor .ds 1
current .ds 1 ; current direction
last_dir .ds 1
@ -95,7 +95,7 @@ c2 .ds 1
size .ds 1
dot .ds 1
* = $0070
* = $00e0
before .ds 1
crossed .ds 1
round_robin_index .ds 2
@ -130,21 +130,19 @@ start jsr set_hires ; start with HGR page 1, full screen
sta dst+1
jsr unpack_lz4
;jsr clrscr
jsr init_once
restart jsr title_screen
restart jsr init_once
jsr title_screen
jsr init_game
jsr game_loop
check_restart ldx #34
check_restart ldx #34 ; x coord on screen for "GAME"
ldy player_score_row
lda #<game_text
sta scratch_ptr
lda #>game_text
sta scratch_ptr+1
jsr printstr
ldx #35
ldx #35 ; x coordinate for "OVER"
ldy player_lives_row
lda #<over_text
sta scratch_ptr
@ -196,8 +194,19 @@ initbackground jsr init_damage
jsr copy2to1
rts
; main game loop. Rather than optimize things and unroll all this stuff into
; a single big function, I'm calling a bunch of subroutines in hopes that
; it is easier to follow.
;
; The "actor" is either a player or an enemy, and the actor number is placed
; in the X register. Subroutines must save the X register and restore it
; upon return if they modify it.
;
; All of the game logic routines expect the player/enemy number in X as they
; use it as an index into whatever specific data they need, like position or
; direction.
game_loop nop
inc frame_count
inc frame_count ; frame count isn't used for anything other than debugging
bne ?1
inc frame_count+1
?1 jsr userinput
@ -234,7 +243,8 @@ game_loop nop
; if any player is still alive, the game continues. Once the last player
; dies, the countdown timer allows the enemies to continue to move a
; little while before the game ends
; little while before the game ends. Returning from the game loop means
; that the game is over.
?alive lda still_alive
bne ?draw
dec countdown_time
@ -254,8 +264,7 @@ game_loop nop
jmp game_loop
; updates the game state based on player status changes
handle_player nop
; if actor_status[zp.current_actor] == PLAYER_REGENERATING:
; # If regenerating, change to alive if the player starts to move
@ -283,7 +292,6 @@ handle_player nop
; # only check for points if still alive
; check_dots()
; check_boxes()
?dots lda actor_status,x
cmp #PLAYER_ALIVE
bne ?final
@ -293,7 +301,6 @@ handle_player nop
; if actor_status[zp.current_actor] != GAME_OVER:
; still_alive += 1
; zp.current_actor += 1
?final lda actor_status,x
cmp #GAME_OVER
beq ?end

View File

@ -78,7 +78,7 @@ input_up lda #TILE_UP
check_down cmp #$af ; down arrow
beq input_down
cmp #$bb ; ';' key (dvorak keyboards)
cmp #$bb ; ';' key (dvorak keyboards!)
beq input_down
cmp #$da ; 'Z' key
beq input_down
@ -159,6 +159,9 @@ wait_inner ; inner loop: 14 + 2 + 3
bne wait_outer
rts
; Offsets in pixels from upper left corner of sprite to where it should
; appear on screen given the tile coords of where the game logic thinks
; the sprite is.
; [i*7-3 for i in range(40)]
player_col_to_x .byte 0, 3, 10, 17, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94, 101, 108, 115, 122, 129, 136, 143, 150, 157, 164, 171, 178, 185, 192, 199, 206, 213, 220, 227, 234, 241, 248, 248, 248, 248, 248,
@ -168,15 +171,14 @@ player_col_to_x .byte 0, 3, 10, 17, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94,
player_row_to_y .byte 0, 3, 11, 19, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, 107, 115, 123, 131, 139, 147, 155, 163, 171, 179
; defines the zone around the midpoint where the player can change to any direction, not just backtracking.
; defines the zone around the midpoint where the player can change to any
; direction, not just backtracking. On the apple, there are 7 x positions but
; 8 y positions
x_allowed_turn .byte 0, 0, 1, 1, 1, 0, 0
y_allowed_turn .byte 0, 0, 1, 1, 1, 0, 0, 0
;# Returns address of tile in col 0 of row y
;def mazerow(y):
; return maze[y]
; Returns address of tile in col 0 of row y
; row in Y
mazerow lda textrows_l,y
sta mazeaddr
@ -185,8 +187,7 @@ mazerow lda textrows_l,y
rts
; text & hgr screen utils
; initialize screen to draw to page 1 (displays page 2)
init_screen_once nop
lda #0
sta KBDSTROBE
@ -195,6 +196,8 @@ init_screen_once nop
rts
; set an entire column (24 rows) of the HGR screen to the specified character
; on page 1
; character in A, col in X
text_put_col nop
sta $0400,x ; row 0
@ -223,6 +226,7 @@ text_put_col nop
sta $07d0,x ; row 23
rts
; ditto except for page 2
text_put_col2 nop
sta $0800,x ; row 0
sta $0880,x ; row 1
@ -259,6 +263,8 @@ textrows_h .byte $04, $04, $05, $05, $06, $06, $07, $07
.byte $04, $04, $05, $05, $06, $06, $07, $07
; sets HGR page 1 to all white using a vertical wipe starting from the
; top moving down
wipeclear1 ldy #0
sty param_y
wipeclear1_loop lda HGRROWS_L,y
@ -285,6 +291,9 @@ wipeclear1_wait nop
bcc wipeclear1_loop
rts
; sets HGR page 1 to the contents of page 2 using a vertical wipe starting
; from the top moving down
wipe2to1 ldy #0
sty param_y
wipe2to1_loop lda HGRROWS_H2,y
@ -314,6 +323,8 @@ wipe2to1_wait nop
bcc wipe2to1_loop
rts
; simple (slow, non-optimized) copy of the data from HGR page 2 to HGR page 1
copy2to1 lda #$40
sta ?source+2
lda #$20
@ -331,6 +342,9 @@ copy2to1 lda #$40
rts
; copy the entire text screen to the current HGR page. The dest_smc address
; is set in the pageflip routine below so they always point to the page
; in back, not the page currently being shown.
copytexthgr nop
ldy #0 ; y is rows
copytexthgr_outer
@ -353,6 +367,8 @@ copytexthgr_dest_smc
rts
; change pages based on the state of the drawpage variable. drawpage == 0
; is page 1, drawpage == $80 is page 2
pageflip nop
lda drawpage
eor #$80