diff --git a/README.md b/README.md index 0800144..8c2a200 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,30 @@ **LabyrinTwo** - a two-player maze duel for the Commodore 64 (ACME + VICE), in the same spirit as [rabbitc64](../rabbitc64). -A fresh maze is carved every round on a 39x23 lattice where the walls -are exactly as wide as the corridors. **Player 1** (joystick 2, or -`w a s d`) runs the corridors toward the green diamond exit while -dodging the roaming colored enemies. **Player 2** (joystick 1, or -`i j k l`) rides the corners of the walls with a blinking cursor - -fire (or `return`) spins the four wall pieces around the cursor by -90 degrees, reshaping the maze in real time. A spin is denied while -anyone is standing in one of the four slots. +A fresh maze carves itself on screen at the start of every round on +a 39x23 lattice where the walls are exactly as wide as the corridors. +**Player 1** (joystick 2, or `w a s d`) runs the corridors toward the +green exit portal while dodging the roaming enemies. **Player 2** +(joystick 1, or `i j k l`) rides the corners of the walls with a +bracket cursor - fire (or `return`) spins the four wall pieces around +the cursor by 90 degrees, reshaping the maze in real time. A spin is +denied while anyone is standing in one of the four slots (the border +blips red); the spun pieces flash white. + +The look: brick walls and bolted pivot posts from a custom RAM +charset, every actor (runner, cursor, bullet, enemies) a hardware +sprite gliding smoothly between the cells, an animated exit portal, +a raster color band behind the status row, and a fade to black +between all screens. The menu floats over a dark maze backdrop. The options screen adds two optional twists: - **runner gun** - player 1 shoots a bullet with fire/`space`; a hit enemy respawns on a random cell after a pause. - **spin cooldown** - each spin starts a recharge; further spins are - denied until the draining bar on the status row runs out and the - readout flips back from *wait* to *ready* (the cursor also dims - while recharging). + denied until the bar on the status row drains (pixel by pixel) and + the readout flips back from *wait* to *ready* (the cursor also + turns red while recharging). Screens: TTG intro (ported from rabbitc64) -> main menu (play / options / rules / controls / credits) -> game -> win (back @@ -45,15 +52,19 @@ acme -DAUTOPLAY=1 -f cbm -o labyrintwo.prg main.asm ## Files -- `main.asm` - entry point, BASIC stub, per-frame state machine +- `main.asm` - entry point, BASIC stub, per-frame state machine, + the border/status-band raster work - `defs.asm` - registers, constants, zero page, macros - `intro.asm` - TTG boot logo with the gold color wash -- `menu.asm` - main menu card +- `menu.asm` - main menu card over a dark maze backdrop - `options.asm` - the optional extras and their toggle screen - `rules.asm` - how to play - `controls.asm` - joystick + keyboard mappings - `credits.asm` - the crew -- `play.asm` - maze generation (recursive backtracker) + the game +- `play.asm` - maze generation (recursive backtracker, animated) + + the game - `win.asm` / `over.asm` - end screens - `common.asm` - shared routines: printing, big block font, input, RNG - `sound.asm` - single-voice SID SFX driver +- `gfx.asm` - RAM charset with the custom tiles, the sprite engine, + the portal animation and the fade-to-black transition diff --git a/controls.asm b/controls.asm index b3f554c..86b975a 100644 --- a/controls.asm +++ b/controls.asm @@ -33,7 +33,7 @@ co_hide: co_input: jsr start_edge beq co_stay - jmp menu_init + +fadeto menu_init co_stay: rts diff --git a/credits.asm b/credits.asm index d31b57a..d20e92d 100644 --- a/credits.asm +++ b/credits.asm @@ -135,7 +135,7 @@ cu_hide: cu_input: jsr start_edge beq cu_stay - jmp menu_init ; back to the menu + +fadeto menu_init ; back to the menu cu_stay: rts diff --git a/defs.asm b/defs.asm index ee68dca..49e7154 100644 --- a/defs.asm +++ b/defs.asm @@ -9,11 +9,25 @@ BORDER = $d020 ; border color register BG = $d021 ; background color register SCREEN = $0400 ; screen RAM (40x25 chars) COLRAM = $d800 ; color RAM -SPR_EN = $d015 ; sprite enable bits (parked at 0) +SCRCTL = $d011 ; control 1: raster msb, y-scroll +SPR_EN = $d015 ; sprite enable bits +SPRX0 = $d000 ; sprite 0 x (x/y pairs go up from here) +SPRY0 = $d001 ; sprite 0 y +SPRMSB = $d010 ; 9th x position bit of each sprite +SPRDBLY = $d017 ; sprite y expand +VMCSB = $d018 ; memory setup: screen + charset base +SPRPRI = $d01b ; sprite/background priority +SPRMCEN = $d01c ; sprite multicolor enable +SPRDBLX = $d01d ; sprite x expand +SPRCOL = $d027 ; sprite colors, 8 registers +CPUPORT = $01 ; 6510 port: ROM/RAM banking CIA1_PA = $dc00 ; CIA1 port A: keyboard columns / joystick 2 CIA1_PB = $dc01 ; CIA1 port B: keyboard rows / joystick 1 CIA1_TA = $dc04 ; CIA1 timer A low byte: free-running entropy +CHARSET = $3800 ; RAM charset: ROM font + the custom tiles +SPRPTR = SCREEN + $3f8 ; sprite shape pointers + ; ---- SID registers (single-voice SFX driver) ---- SID_V1FL = $d400 ; voice 1 frequency low SID_V1FH = $d401 ; voice 1 frequency high @@ -71,16 +85,24 @@ MAZE_CH = 11 ; cells down NCELLS = MAZE_CW * MAZE_CH NENEMIES = 4 -CH_WALL = $a0 ; inverse space: solid wall block +; ---- characters (the custom tiles live in the RAM charset) ---- +CH_WALL = $e0 ; brick block: spinnable wall piece +CH_POST = $e1 ; bolted plate: fixed pivot post +CH_EXIT = $e2 ; the portal out (4 animated glyph frames) CH_FLOOR = $20 ; space: corridor -CH_EXIT = $5a ; diamond: the goal -CH_PLAYER = $51 ; filled ball: the runner -CH_ENEMY = $57 ; open circle: an enemy -CH_SHOT = $2a ; asterisk: the runner's bullet +CH_BAR = $e3 ; 7 chars: a bar cell 1-7 pixels full + +; ---- the actors are hardware sprites ---- +SP_RUN = 0 ; player 1, the runner +SP_CUR = 1 ; player 2, the corner cursor +SP_SHOT = 2 ; the optional bullet +SP_EN = 3 ; the enemies ride sprites 3-6 COL_WALL = MGREY ; spinnable wall pieces COL_POST = DGREY ; fixed pivot posts -COL_EXIT = LGREEN ; the exit diamond +COL_EXIT = LGREEN ; the exit portal +COL_HILITE = YELLOW ; walls the cursor's spin would move +STATCOL = BLUE ; background band behind the status row ; ---- game timing ---- REP_HOLD = 10 ; runner: frames before a held dir repeats @@ -90,6 +112,7 @@ CREP_PERIOD = 7 COOL_TIME = 160 ; spin cooldown option: recharge frames RESPAWN_TIME = 150 ; gun option: frames until a hit enemy returns RAS_SYNC = 251 ; raster line polled for the frame sync +BUILD_STEPS = 8 ; maze carve animation: generator steps a frame ; ---- zero page pointers (same slots as rabbitc64) ---- txtlo = $f5 ; text pointer for the print routines (2 bytes) @@ -140,3 +163,13 @@ colhi = $fe lda #>.addr sta updvec+1 } + +; ---- leave the current screen: fade to black, then run the +; init routine of the next one ---- +!macro fadeto .addr { + lda #<.addr + sta fadevec + lda #>.addr + sta fadevec+1 + jmp fade_start +} diff --git a/gfx.asm b/gfx.asm new file mode 100644 index 0000000..d8127e4 --- /dev/null +++ b/gfx.asm @@ -0,0 +1,481 @@ +; ----------------------------------------------------------- +; gfx.asm - the graphics layer: +; - the ROM font is copied into RAM and a handful of custom +; tiles are stamped over it (brick wall, pivot post, the +; animated exit portal, the 1/8-step cooldown bar cells) +; - a small sprite engine: every actor lives on the char +; grid, its sprite glides toward the cell a few pixels a +; frame (the runner bobs, the enemies wave) +; - fade to black: the transition between two screens +; ----------------------------------------------------------- + +; ---- one-time setup: font to RAM, custom tiles, VIC ---- +gfx_init: + lda #$33 ; char ROM in at $d000 (I/O out briefly) + sta CPUPORT + lda #$d0 + sta txthi + lda #>CHARSET + sta scrhi + lda #0 + sta txtlo + sta scrlo + ldx #8 ; 2 KB: the full uppercase set +gc_page: + ldy #0 +gc_byte: + lda (txtlo),y + sta (scrlo),y + iny + bne gc_byte + inc txthi + inc scrhi + dex + bne gc_page + lda #$37 ; I/O back in + sta CPUPORT + ; the brick wall + the pivot post (two consecutive codes) + ldx #15 +gc_tiles: + lda tile_gfx,x + sta CHARSET+CH_WALL*8,x + dex + bpl gc_tiles + ; the portal starts on frame 0 + ldx #7 +gc_portal: + lda portal_gfx,x + sta CHARSET+CH_EXIT*8,x + dex + bpl gc_portal + ; the seven bar cells: 1-7 pixels filled from the left + ldx #0 + ldy #0 +gc_bar: + lda barmask,x + sta rtmp + lda #8 + sta rtmp2 +gc_bar8: + lda rtmp + sta CHARSET+CH_BAR*8,y + iny + dec rtmp2 + bne gc_bar8 + inx + cpx #7 + bne gc_bar + ; VIC: screen at $0400, charset at $3800 + lda #$1e + sta VMCSB + ; sprites: hires, unexpanded, in front of the chars + lda #0 + sta SPRDBLY + sta SPRDBLX + sta SPRMCEN + sta SPRPRI + sta SPRMSB + rts + +; ---- cycle the portal glyph: 4 frames, one every 8 frames; +; rewriting the definition animates every portal on screen ---- +upd_portal: + lda framectr + and #7 + bne up_done + lda framectr + and #$18 ; (frame index) * 8 = data offset + tay + ldx #0 +up_copy: + lda portal_gfx,y + sta CHARSET+CH_EXIT*8,x + iny + inx + cpx #8 + bne up_copy +up_done: + rts + +; ============================================================ +; sprite engine +; ============================================================ + +; grid cell (tgc, tgr) -> pixel target tgxl/tgxh, tgy +set_target: + lda #0 + sta tgxh + lda tgc + asl + rol tgxh + asl + rol tgxh + asl + rol tgxh + clc + adc #24 ; first visible pixel column + sta tgxl + bcc st_y + inc tgxh +st_y: + lda tgr + asl + asl + asl + clc + adc #50 ; first visible raster line + sta tgy + rts + +; sprite X snaps straight onto the target +spr_jump: + lda tgxl + sta sprxl,x + lda tgxh + sta sprxh,x + lda tgy + sta spry,x + rts + +; sprite X slides gspd pixels per axis toward the target; the +; actors re-target every frame, so the distance always fits in +; a signed byte and a step never overshoots +spr_glide: + lda tgxl + sec + sbc sprxl,x + sta dtmp + lda tgxh + sbc sprxh,x ; the high byte only carries the sign + lda dtmp + beq sg_y + bmi sg_left + cmp gspd ; rightward: step = min(distance, speed) + bcc sg_rgo + lda gspd +sg_rgo: + clc + adc sprxl,x + sta sprxl,x + bcc sg_y + inc sprxh,x + jmp sg_y +sg_left: + eor #$ff ; leftward: the same on the distance + clc + adc #1 + cmp gspd + bcc sg_lgo + lda gspd +sg_lgo: + sta dtmp + lda sprxl,x + sec + sbc dtmp + sta sprxl,x + bcs sg_y + dec sprxh,x +sg_y: + lda tgy + sec + sbc spry,x + beq sg_done + bmi sg_up + cmp gspd + bcc sg_dgo + lda gspd +sg_dgo: + clc + adc spry,x + sta spry,x + rts +sg_up: + eor #$ff + clc + adc #1 + cmp gspd + bcc sg_ugo + lda gspd +sg_ugo: + sta dtmp + lda spry,x + sec + sbc dtmp + sta spry,x +sg_done: + rts + +; push all eight sprite positions + the x msb bits to the VIC +spr_commit: + lda #0 + sta dtmp + ldx #7 +sc_loop: + lda sprxh,x + beq sc_low + lda dtmp + ora sprbit,x + sta dtmp +sc_low: + txa + asl + tay + lda sprxl,x + sta SPRX0,y + lda spry,x + sta SPRY0,y + dex + bpl sc_loop + lda dtmp + sta SPRMSB + rts + +sprbit: !byte 1, 2, 4, 8, 16, 32, 64, 128 + +; ============================================================ +; fade to black - six passes walk every color RAM cell (and +; the sprite colors) down the luminance chains, half a screen +; per frame; then control jumps to the init routine the +; +fadeto macro left in fadevec +; ============================================================ +fade_start: + lda #$ff + sta statbg ; no status band while fading + lda #0 + sta bflash + sta borbase + sta fadecnt + sta fadehalf + +setupd fade_update + rts + +fade_update: + lda fadehalf ; half the color RAM per frame + eor #1 + sta fadehalf + bne fu_hi + ldx #0 +fu_lo: + lda COLRAM,x + and #15 + tay + lda fadetbl,y + sta COLRAM,x + lda COLRAM+$100,x + and #15 + tay + lda fadetbl,y + sta COLRAM+$100,x + inx + bne fu_lo + rts +fu_hi: + ldx #0 +fu_hi2: + lda COLRAM+$200,x + and #15 + tay + lda fadetbl,y + sta COLRAM+$200,x + lda COLRAM+$2e8,x + and #15 + tay + lda fadetbl,y + sta COLRAM+$2e8,x + inx + bne fu_hi2 + ldx #7 ; the sprites sink with the screen +fu_spr: + lda SPRCOL,x + and #15 + tay + lda fadetbl,y + sta SPRCOL,x + dex + bpl fu_spr + inc fadecnt + lda fadecnt + cmp #6 ; the longest chain is black after 5 + bne fu_stay + lda #0 + sta SPR_EN + jmp (fadevec) ; its rts returns to the main loop +fu_stay: + rts + +fadetbl: ; each color, one step darker + !byte $00, $0f, $09, $0c, $0b, $0b, $00, $08 + !byte $02, $00, $02, $00, $0b, $05, $06, $0c + +; ---- the custom tiles ---- +tile_gfx: ; CH_WALL: bricks with dark mortar + !byte %11111111 + !byte %11110111 + !byte %11110111 + !byte %00000000 + !byte %11111111 + !byte %01111111 + !byte %01111111 + !byte %00000000 + ; CH_POST: a bolted plate + !byte %11111111 + !byte %10000001 + !byte %10111101 + !byte %10100101 + !byte %10100101 + !byte %10111101 + !byte %10000001 + !byte %11111111 + +portal_gfx: ; CH_EXIT frame 0: closed + !byte %00000000 + !byte %00011000 + !byte %00111100 + !byte %01100110 + !byte %01100110 + !byte %00111100 + !byte %00011000 + !byte %00000000 + ; frame 1: opening + !byte %00011000 + !byte %00111100 + !byte %01100110 + !byte %11000011 + !byte %11000011 + !byte %01100110 + !byte %00111100 + !byte %00011000 + ; frame 2: wide open, sparkling + !byte %00111100 + !byte %01100110 + !byte %11011011 + !byte %10111101 + !byte %10111101 + !byte %11011011 + !byte %01100110 + !byte %00111100 + ; frame 3: closing again + !byte %00011000 + !byte %00111100 + !byte %01100110 + !byte %11000011 + !byte %11000011 + !byte %01100110 + !byte %00111100 + !byte %00011000 + +barmask: ; bar cell fills, 1-7 pixels + !byte $80, $c0, $e0, $f0, $f8, $fc, $fe + +; ---- graphics layer variables ---- +sprxl: !fill 8, 0 ; sprite pixel positions (x low/high, y) +sprxh: !fill 8, 0 +spry: !fill 8, 0 +tgc: !byte 0 ; set_target input: grid column / row +tgr: !byte 0 +tgxl: !byte 0 ; set_target output: pixel target +tgxh: !byte 0 +tgy: !byte 0 +gspd: !byte 0 ; spr_glide: pixels per frame +dtmp: !byte 0 ; scratch +statbg: !byte $ff ; status band color, $ff = no band +bflash: !byte 0 ; border flash: frames left + color +bcolor: !byte 0 +borbase: !byte 0 ; steady border color of the screen +fadevec: !byte 0, 0 ; where fade_update jumps when done +fadecnt: !byte 0 ; fade passes completed +fadehalf: !byte 0 ; which color RAM half is next + +!if (fadevec & 255) = 255 { !error "fadevec must not straddle a page" } + +; ---- sprite shapes: 8x8 art in the top-left of each block ---- +!align 63, 0 +spr_run0: ; the runner: a bright-eyed ball... + !byte %00111100, 0, 0 + !byte %01111110, 0, 0 + !byte %11011011, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %01111110, 0, 0 + !byte %00111100, 0, 0 + !fill 40, 0 +spr_run1: ; ...that bobs as it goes + !byte %00000000, 0, 0 + !byte %00111100, 0, 0 + !byte %01111110, 0, 0 + !byte %11011011, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %01111110, 0, 0 + !byte %00111100, 0, 0 + !fill 40, 0 +spr_shot0: ; the bullet + !byte %00000000, 0, 0 + !byte %00000000, 0, 0 + !byte %00011000, 0, 0 + !byte %00111100, 0, 0 + !byte %00111100, 0, 0 + !byte %00011000, 0, 0 + !byte %00000000, 0, 0 + !byte %00000000, 0, 0 + !fill 40, 0 +spr_cur0: ; the corner cursor: four brackets + !byte %11100111, 0, 0 + !byte %10000001, 0, 0 + !byte %10000001, 0, 0 + !byte %00000000, 0, 0 + !byte %00000000, 0, 0 + !byte %10000001, 0, 0 + !byte %10000001, 0, 0 + !byte %11100111, 0, 0 + !fill 40, 0 +spr_ena0: ; enemies 0-1: a ghost, skirt waving + !byte %00111100, 0, 0 + !byte %01111110, 0, 0 + !byte %11011011, 0, 0 + !byte %11011011, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %10110101, 0, 0 + !fill 40, 0 +spr_ena1: + !byte %00111100, 0, 0 + !byte %01111110, 0, 0 + !byte %11011011, 0, 0 + !byte %11011011, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %11111111, 0, 0 + !byte %01101101, 0, 0 + !fill 40, 0 +spr_enb0: ; enemies 2-3: a crawler, legs pumping + !byte %00000000, 0, 0 + !byte %10111101, 0, 0 + !byte %01111110, 0, 0 + !byte %11011011, 0, 0 + !byte %01111110, 0, 0 + !byte %10111101, 0, 0 + !byte %00000000, 0, 0 + !byte %00000000, 0, 0 + !fill 40, 0 +spr_enb1: + !byte %00000000, 0, 0 + !byte %00111100, 0, 0 + !byte %01111110, 0, 0 + !byte %11011011, 0, 0 + !byte %01111110, 0, 0 + !byte %00111100, 0, 0 + !byte %00000000, 0, 0 + !byte %00000000, 0, 0 + !fill 40, 0 + +SPR_RUN = spr_run0 DIV 64 +SPR_SHOT = spr_shot0 DIV 64 +SPR_CUR = spr_cur0 DIV 64 +SPR_ENA = spr_ena0 DIV 64 +SPR_ENB = spr_enb0 DIV 64 + +!if spr_run0 < $2000 { !error "sprite data slid under $2000: the VIC sees the char ROM shadow there" } +!if * > CHARSET { !error "the program ran into the charset at $3800" } diff --git a/intro.asm b/intro.asm index 2a4486f..5dfd647 100644 --- a/intro.asm +++ b/intro.asm @@ -78,11 +78,11 @@ iw_skip: ; fire skips, otherwise wait out the timer jsr start_edge beq iw_tick - jmp menu_init + +fadeto menu_init iw_tick: dec introt bne iw_done - jmp menu_init + +fadeto menu_init iw_done: rts diff --git a/main.asm b/main.asm index 9b1f4a0..ef434cc 100644 --- a/main.asm +++ b/main.asm @@ -1,7 +1,7 @@ ; ----------------------------------------------------------- ; main.asm - LABYRINTWO for the C64 ; two-player maze duel: player 1 runs the corridors toward -; the green diamond exit while dodging the roaming colored +; the green exit portal while dodging the roaming colored ; enemies; player 2 rides the wall corners with a cursor ; and fire spins the four wall pieces around it by 90 ; degrees, reshaping the maze under the runner's feet @@ -9,7 +9,7 @@ ; Files: ; defs.asm - constants, zero page, macros ; intro.asm - TTG boot logo (ported from rabbitc64) -; menu.asm - main menu: play / options / rules / ... +; menu.asm - main menu over a dark maze backdrop ; options.asm - optional extras: runner gun, spin cooldown ; rules.asm - how to play ; controls.asm- joystick + keyboard mappings @@ -19,6 +19,7 @@ ; over.asm - game over screen with retry ; common.asm - shared routines, input, RNG, texts ; sound.asm - single-voice SFX driver +; gfx.asm - RAM charset, sprite engine, fades ; ; Build: acme -f cbm -o labyrintwo.prg main.asm ; ----------------------------------------------------------- @@ -44,9 +45,10 @@ start: sta BORDER sta BG lda #0 - sta SPR_EN ; character-only game: sprites stay off + sta SPR_EN ; the actors arrive with the game screen sta framectr sta fheld + jsr gfx_init ; RAM charset + VIC + sprite registers jsr sfx_init !ifdef AUTOPLAY { ; test builds boot straight into one state @@ -81,13 +83,46 @@ start: ; ============================================================ ; main loop - one state update per PAL frame, synced to the -; raster beam in the lower border +; raster beam in the lower border; the loop also paints the +; border (event flashes decay back to the screen's base +; color) and, when a screen asks for one, lays a background +; band behind the status row with two more raster waits ; ============================================================ main: - jsr wait_frame + jsr wait_frame ; raster line RAS_SYNC, once a frame + lda bflash ; border: flash, else the base color + beq mb_base + dec bflash + lda bcolor + jmp mb_border +mb_base: + lda borbase +mb_border: + sta BORDER inc framectr jsr rand8 ; stir the RNG once per frame jsr sfx_update ; advance the sound effect + lda statbg ; $ff = no band: update right away + bmi mb_update +mb_w1: + bit SCRCTL ; the beam reaches line 256... + bpl mb_w1 +mb_w2: + bit SCRCTL ; ...and wraps to line 0 + bmi mb_w2 +mb_w3: + lda RASTER + cmp #49 ; still in the border above the window + bcc mb_w3 + lda statbg + sta BG +mb_w4: + lda RASTER + cmp #59 ; the switch back hides behind row 1's + bcc mb_w4 ; wall tops (their top line is solid) + lda #BLACK + sta BG +mb_update: jsr call_update jmp main @@ -120,3 +155,4 @@ wf_hit: !src "over.asm" !src "common.asm" !src "sound.asm" +!src "gfx.asm" diff --git a/menu.asm b/menu.asm index 6f9e670..9fa48a2 100644 --- a/menu.asm +++ b/menu.asm @@ -11,6 +11,33 @@ MENU_ITEMS = 5 menu_init: jsr clear_screen + ; a dark maze weaves behind the whole card + lda #DGREY + sta latwcol + sta latpcol + jsr draw_lattice + jsr gen_init + jsr gen_maze_full + + ; a clean panel for the menu itself (rows 9-22, cols 4-35) + ldx #9 +mi_panel: + stx ptmp + jsr row_ptr + ldy #35 +mi_pcol: + lda #$20 + sta (scrlo),y + lda #BLACK + sta (collo),y + dey + cpy #3 + bne mi_pcol + ldx ptmp + inx + cpx #23 + bne mi_panel + +prbig 2, 0, YELLOW, txt_t1, 7 +prbig 2, 28, CYAN, txt_t2, 3 +prtext 9, 13, LGREY, txt_ttgname, 14 @@ -162,15 +189,15 @@ mu_start: beq mg_rules cmp #3 beq mg_controls - jmp credits_init ; each init's rts returns to the main loop + +fadeto credits_init ; every screen change fades to black mg_play: - jmp play_init + +fadeto play_init mg_options: - jmp options_init + +fadeto options_init mg_rules: - jmp rules_init + +fadeto rules_init mg_controls: - jmp controls_init + +fadeto controls_init mu_done: rts diff --git a/options.asm b/options.asm index 6a1620f..5e53524 100644 --- a/options.asm +++ b/options.asm @@ -122,7 +122,7 @@ ou_done: ou_back: lda #SFX_SELECT jsr sfx_play - jmp menu_init + +fadeto menu_init ; ---- draw option line X, yellow when it is the picked one ---- draw_oitem: diff --git a/over.asm b/over.asm index cabf2c5..8ec951c 100644 --- a/over.asm +++ b/over.asm @@ -6,6 +6,9 @@ lose_init: jsr clear_screen + lda #RED ; the border mourns with the letters + sta borbase + +prbig 3, 2, RED, txt_gameover, 9 +prtext 11, 10, WHITE, txt_caught, txt_caughte-txt_caught @@ -28,7 +31,7 @@ lu_input: ; fire or space: straight back in with a fresh maze jsr start_edge beq lu_nofire - jmp play_init + +fadeto play_init lu_nofire: ; the m key: keyboard column 4, row bit 4 (start_edge has ; already returned zero here, so joystick fire is not @@ -40,7 +43,7 @@ lu_nofire: bne lu_done lda #$ff sta CIA1_PA - jmp menu_init + +fadeto menu_init lu_done: lda #$ff sta CIA1_PA diff --git a/play.asm b/play.asm index 7f06018..c767448 100644 --- a/play.asm +++ b/play.asm @@ -1,22 +1,25 @@ ; ----------------------------------------------------------- -; play.asm - the game: a fresh maze is carved with a -; recursive backtracker every round, player 1 (joystick 2) -; runs the corridors toward the exit diamond, player 2 -; (joystick 1) rides the wall corners and fire spins the -; four wall pieces around the cursor by 90 degrees; the -; roaming colored enemies end the round on touch +; play.asm - the game: a fresh maze carves itself on screen +; every round (recursive backtracker, a few steps a frame), +; player 1 (joystick 2) runs the corridors toward the exit +; portal, player 2 (joystick 1) rides the wall corners and +; fire spins the four wall pieces around the cursor by 90 +; degrees; the roaming enemies end the round on touch +; +; the walls, posts and the portal are chars (the screen stays +; the wall data structure), but every actor - runner, cursor, +; bullet, enemies - is a hardware sprite gliding between the +; cells; actor collisions are grid coordinate checks ; ; optional extras (see options.asm): ; opt_shoot - player 1's fire shoots a bullet in the last ; direction faced; a hit enemy respawns on a ; random cell after RESPAWN_TIME frames ; opt_cool - a spin starts a COOL_TIME recharge, shown as -; a draining bar on the status row; spins are -; denied (buzz) until it runs out +; a draining 1/8-step bar on the status row ; -; screen layout: status on row 0, the 39x23 maze lattice on -; rows 1-23 (cells = odd col / even row, posts = even col / -; odd row, wall slots = the rest), a hint line on row 24 +; screen layout: status on row 0 (over the colored raster +; band), the 39x23 maze lattice on rows 1-23, hints on row 24 ; ----------------------------------------------------------- play_init: @@ -26,58 +29,39 @@ play_init: +prtext 0, 28, LGREY, txt_goal, txt_goale-txt_goal +prtext 24, 6, DGREY, txt_hint, txt_hinte-txt_hint - ; fill the whole lattice with wall blocks - ldx #1 -pi_fillrow: - stx ptmp - jsr row_ptr - ldy #38 -pi_fillcol: - lda #CH_WALL - sta (scrlo),y lda #COL_WALL - sta (collo),y - dey - bpl pi_fillcol - ldx ptmp - inx - cpx #24 - bne pi_fillrow - - ; the pivot posts get their own darker shade - ldx #1 ; post rows 1, 3, ... 23 -pi_postrow: - stx ptmp - jsr row_ptr - ldy #38 ; post columns 38, 36, ... 0 -pi_postcol: + sta latwcol lda #COL_POST - sta (collo),y - dey - dey - bpl pi_postcol - ldx ptmp - inx - inx - cpx #25 - bcc pi_postrow + sta latpcol + jsr draw_lattice + jsr gen_init - ; carve the maze - ldx #0 - lda #0 -pi_clrv: - sta visited,x - inx - cpx #NCELLS - bne pi_clrv - jsr gen_maze + lda #0 ; the actors arrive when the maze is done + sta SPR_EN + lda #STATCOL ; the status row gets its color band + sta statbg + +setupd play_build + rts - ; the exit: a green diamond in the right border wall -pi_exit: +; ---- the maze carves itself, BUILD_STEPS steps a frame ---- +play_build: + lda #BUILD_STEPS + sta ptmp +pb_loop: + jsr gm_step + bcs play_start + dec ptmp + bne pb_loop + rts + +; ---- the maze is done: exit, actors, sprites, input ---- +play_start: + ; the exit: a portal in the right border wall +ps_exit: jsr rand8 and #$0f cmp #MAZE_CH - bcs pi_exit + bcs ps_exit asl ; cell row -> screen row clc adc #2 @@ -98,13 +82,34 @@ pi_exit: sta py lda #0 sta fdy - jsr draw_player + lda px + sta tgc + lda py + sta tgr + jsr set_target + ldx #SP_RUN + jsr spr_jump ; the corner cursor starts on the center post lda #18 sta kx lda #11 sta ky + lda #COL_HILITE + jsr mark_slots + lda kx + sta tgc + lda ky + sta tgr + jsr set_target + ldx #SP_CUR + jsr spr_jump + + lda #WHITE + sta SPRCOL+SP_RUN + sta SPRCOL+SP_CUR + lda #YELLOW + sta SPRCOL+SP_SHOT jsr spawn_enemies @@ -115,25 +120,79 @@ pi_exit: sta cheld sta endflag sta s_on + sta sx + sta sy sta cool + sta rotflash lda #1 sta cfheld sta rfheld +setupd play_update - rts + jmp upd_sprites ; positions, shapes and enables now ; ============================================================ ; maze generation - recursive backtracker over the 19x11 ; cells; the screen itself is the wall data structure ; ============================================================ -gen_maze: + +; fill rows 1-23 of the lattice: brick walls in latwcol, the +; pivot posts (even col, odd row) in latpcol +draw_lattice: + ldx #1 +dl_fill: + stx ptmp + jsr row_ptr + ldy #38 +dl_col: + lda #CH_WALL + sta (scrlo),y + lda latwcol + sta (collo),y + dey + bpl dl_col + ldx ptmp + inx + cpx #24 + bne dl_fill + ldx #1 ; post rows 1, 3, ... 23 +dl_prow: + stx ptmp + jsr row_ptr + ldy #38 ; post columns 38, 36, ... 0 +dl_pcol: + lda #CH_POST + sta (scrlo),y + lda latpcol + sta (collo),y + dey + dey + bpl dl_pcol + ldx ptmp + inx + inx + cpx #25 + bcc dl_prow + rts + +; reset the generator: nothing visited, start on cell (0,0) +gen_init: + ldx #0 + lda #0 +gi_clr: + sta visited,x + inx + cpx #NCELLS + bne gi_clr lda #0 sta gcx sta gcy sta gsp jsr gv_mark - jsr carve_cell -gm_loop: + jmp carve_cell + +; one generator step: carve toward a random unvisited +; neighbor, or back up one; C set when the maze is finished +gm_step: ; collect the unvisited neighbor directions lda #0 sta gn @@ -200,7 +259,8 @@ gm_pick: sta gcy jsr gv_mark jsr carve_cell - jmp gm_loop + clc + rts gm_pop: ; dead end: back up; empty stack = the maze is done lda gsp @@ -211,8 +271,15 @@ gm_pop: sta gcx lda stacky,x sta gcy - jmp gm_loop + clc + rts gm_done: + sec + rts + +gen_maze_full: ; the menu backdrop wants it all at once + jsr gm_step + bcc gen_maze_full rts gv_mark: ; visited[gcy * 19 + gcx] = 1 @@ -290,11 +357,11 @@ sn_rx: cmp #MAZE_CH bcs sn_rx clc - adc #MAZE_CW-MAZE_CH ; cell column 8-18: away from the runner + adc #MAZE_CW-MAZE_CH ; cell column 8-18: away from the start asl clc adc #1 - sta gnx ; candidate screen column + sta ttx ; candidate screen column sn_ry: jsr rand8 and #$0f @@ -303,32 +370,48 @@ sn_ry: asl clc adc #2 - sta gny ; candidate screen row - ldx gny + sta tty ; candidate screen row + ldx tty jsr row_ptr - ldy gnx + ldy ttx lda (scrlo),y - cmp #CH_FLOOR ; only an empty cell will do + cmp #CH_FLOOR ; only a carved cell will do... bne sn_rx - lda #CH_ENEMY - sta (scrlo),y + lda ttx ; ...without the runner on it... + cmp px + bne sn_free + lda tty + cmp py + beq sn_rx +sn_free: + jsr enemy_at ; ...or another live enemy + bcs sn_rx + ldx ei + lda ttx + sta ex,x + lda tty + sta ey,x jsr rand8 and #7 - tax - lda ecoltab,x - sta (collo),y - ldx ei + tay + lda ecoltab,y sta ecol,x - lda gnx - sta ex,x - lda gny - sta ey,x + sta SPRCOL+SP_EN,x jsr rand8 and #3 sta edir,x lda #0 sta edead,x - rts + lda ttx ; the sprite pops in on the cell + sta tgc + lda tty + sta tgr + jsr set_target + lda ei + clc + adc #SP_EN + tax + jmp spr_jump ecoltab: ; anything but the white runner / grey walls !byte RED, CYAN, PURPLE, YELLOW, ORANGE, LRED, LBLUE, BLUE @@ -351,19 +434,19 @@ pu_nocool: jsr upd_cursor jsr upd_flash jsr upd_status - rts + jmp upd_sprites pu_end: cmp #1 beq pu_win lda #SFX_LOSE jsr sfx_play - jmp lose_init ; its rts returns to the main loop + +fadeto lose_init pu_win: lda #SFX_WIN jsr sfx_play - jmp win_init + +fadeto win_init -; ---- player 1: walk the corridors, one char per step ---- +; ---- player 1: walk the corridors, one cell per step ---- upd_runner: jsr read_joy and #$0f @@ -431,26 +514,18 @@ ur_try: jsr row_ptr ldy ttx lda (scrlo),y - cmp #CH_FLOOR - beq ur_go cmp #CH_EXIT beq ur_win - cmp #CH_ENEMY - beq ur_dead - rts ; a wall (or the bullet): blocked -ur_go: - ldx py - jsr row_ptr - ldy px - lda #CH_FLOOR - sta (scrlo),y - lda #BLACK - sta (collo),y + cmp #CH_FLOOR + bne ur_stop ; a wall or a post: blocked + jsr enemy_at ; walking into an enemy still hurts + bcs ur_dead lda ttx sta px lda tty sta py - jmp draw_player +ur_stop: + rts ur_win: lda #1 sta endflag @@ -460,31 +535,10 @@ ur_dead: sta endflag rts -draw_player: - ldx py - jsr row_ptr - ldy px - lda #CH_PLAYER - sta (scrlo),y - lda #WHITE - sta (collo),y - rts - -; ---- the optional gun: one straight-flying bullet ---- +; ---- the optional gun: one straight-flying bullet sprite ---- upd_shot: lda s_on - beq sh_nofly - ldx sy ; wipe the bullet from its old spot - - jsr row_ptr ; but only if it is really there: right - ldy sx ; after firing this is the runner's own - lda (scrlo),y ; cell, and the runner must stay drawn - cmp #CH_SHOT - bne sh_step - lda #CH_FLOOR - sta (scrlo),y - lda #BLACK - sta (collo),y -sh_step: + beq sh_spawn lda sx ; one step along its heading clc adc sdx @@ -498,27 +552,23 @@ sh_step: ldy ttx lda (scrlo),y cmp #CH_FLOOR - beq sh_fly - cmp #CH_ENEMY - beq sh_hit - lda #0 ; a wall (or anything else) stops it + beq sh_open + lda #0 ; a wall (or the portal) stops it sta s_on - jmp sh_nofly + jmp sh_spawn +sh_open: + jsr enemy_at + bcc sh_fly + jsr kill_idx ; X = the victim + lda #0 + sta s_on + jmp sh_spawn sh_fly: lda ttx sta sx lda tty sta sy - lda #CH_SHOT - sta (scrlo),y - lda #YELLOW - sta (collo),y - jmp sh_nofly -sh_hit: - lda #0 - sta s_on - jsr kill_enemy ; scrlo/y still point at the victim -sh_nofly: +sh_spawn: lda opt_shoot ; fire spawns a bullet (edge detected) beq sh_done lda joyb ; read_joy ran in upd_runner this frame @@ -548,31 +598,37 @@ sh_frel: sh_done: rts -; ---- the bullet found an enemy at (ttx, tty): it starts its -; respawn timer; the caller's scrlo/y still address its cell ---- -kill_enemy: - ldx #0 -ke_loop: - lda edead,x - bne ke_next - lda ex,x - cmp ttx - bne ke_next - lda ey,x - cmp tty - bne ke_next +; ---- enemy X was hit: it starts its respawn timer ---- +kill_idx: lda #RESPAWN_TIME sta edead,x - lda #CH_FLOOR - sta (scrlo),y - lda #BLACK - sta (collo),y + lda #4 ; white border blip + sta bflash + lda #WHITE + sta bcolor lda #SFX_HIT jmp sfx_play -ke_next: + +; ---- is a live enemy standing on (ttx, tty)? +; returns C set + its index in X when one is ---- +enemy_at: + ldx #0 +ea_loop: + lda edead,x + bne ea_next + lda ex,x + cmp ttx + bne ea_next + lda ey,x + cmp tty + bne ea_next + sec + rts +ea_next: inx cpx #NENEMIES - bne ke_loop + bne ea_loop + clc rts ; ---- player 2: the corner cursor + the wall spin ---- @@ -635,15 +691,16 @@ uc_left: uc_go: stx ttx sty tty - ldx ky ; the old post gets its color back - jsr row_ptr - ldy kx - lda #COL_POST - sta (collo),y + lda #COL_WALL ; the old corner's walls lose the highlight + jsr mark_slots + lda #0 ; a spin flash does not follow the cursor + sta rotflash lda ttx sta kx lda tty sta ky + lda #COL_HILITE ; show the walls a spin here would move + jsr mark_slots lda #SFX_CURSOR jsr sfx_play uc_fire: @@ -669,9 +726,33 @@ do_rotate: beq dr_ready lda cool beq dr_ready - lda #SFX_DENY ; still recharging - jmp sfx_play +dr_deny: + jmp rot_deny ; still recharging / a slot is taken dr_ready: + lda kx ; nobody may stand in the four slots + sta ttx + ldx ky + dex + stx tty + jsr slot_occ + bcs dr_deny + ldx ky + inx + stx tty + jsr slot_occ + bcs dr_deny + lda ky + sta tty + ldx kx + dex + stx ttx + jsr slot_occ + bcs dr_deny + ldx kx + inx + stx ttx + jsr slot_occ + bcs dr_deny ldx ky ; gather the four slot chars dex jsr row_ptr @@ -694,19 +775,6 @@ dr_ready: iny lda (scrlo),y sta ech - ; every slot must be plain wall or floor - lda nch - jsr rot_ok - bcs rot_deny - lda sch - jsr rot_ok - bcs rot_deny - lda wch - jsr rot_ok - bcs rot_deny - lda ech - jsr rot_ok - bcs rot_deny ; clockwise: north<-west, east<-north, south<-east, west<-south ldx ky dex @@ -730,6 +798,8 @@ dr_ready: iny lda nch jsr put_slot + lda #10 ; the moved pieces flash white + sta rotflash lda opt_cool ; the spin starts the recharge beq dr_nocool lda #COOL_TIME @@ -738,19 +808,37 @@ dr_nocool: lda #SFX_ROTATE jmp sfx_play rot_deny: + lda #6 ; red border blip on a denied spin + sta bflash + lda #RED + sta bcolor lda #SFX_DENY jmp sfx_play -rot_ok: ; C clear when A is spinnable (wall or floor) - cmp #CH_WALL - beq ro_yes - cmp #CH_FLOOR - beq ro_yes - sec - rts -ro_yes: +slot_occ: ; C set when someone stands on (ttx, tty) + lda px + cmp ttx + bne so_norun + lda py + cmp tty + beq so_yes +so_norun: + jsr enemy_at + bcs so_yes + lda s_on + beq so_no + lda sx + cmp ttx + bne so_no + lda sy + cmp tty + beq so_yes +so_no: clc rts +so_yes: + sec + rts put_slot: ; write char A at (scrlo),y + matching color sta (scrlo),y @@ -764,6 +852,37 @@ ps_wall: sta (collo),y rts +; ---- paint the four slots around the cursor post with the +; color in A - only wall blocks change, so the highlight marks +; exactly the pieces a spin would move (floors stay black) ---- +mark_slots: + sta hlcol + ldx ky ; north + dex + jsr row_ptr + ldy kx + jsr mark_one + ldx ky ; south + inx + jsr row_ptr + ldy kx + jsr mark_one + ldx ky ; west + jsr row_ptr + ldy kx + dey + jsr mark_one + iny ; east: falls through to mark it + iny +mark_one: + lda (scrlo),y + cmp #CH_WALL + bne mo_skip + lda hlcol + sta (collo),y +mo_skip: + rts + ; ---- the enemies: staggered random walkers ---- upd_enemies: lda #0 @@ -828,54 +947,61 @@ etry_dir: ; A = direction; C clear when it moved (or won) clc adc dytab,x sta tty - ldx tty - jsr row_ptr - ldy ttx - lda (scrlo),y - cmp #CH_FLOOR - beq ed_move - cmp #CH_PLAYER - beq ed_kill - sec ; wall, exit, bullet or another enemy - rts -ed_kill: + lda px ; onto the runner: the round is over + cmp ttx + bne en_norun + lda py + cmp tty + bne en_norun lda #2 sta endflag clc rts -ed_move: +en_norun: + ldx tty ; anything but open floor blocks it + jsr row_ptr + ldy ttx + lda (scrlo),y + cmp #CH_FLOOR + beq en_open + sec + rts +en_open: + jsr enemy_at ; another enemy blocks it + bcc en_nofoe + sec + rts +en_nofoe: + lda s_on ; walking into the bullet hurts too + beq en_move + lda sx + cmp ttx + bne en_move + lda sy + cmp tty + bne en_move + lda #0 + sta s_on + ldx ei + jsr kill_idx + clc + rts +en_move: ldx ei - lda ey,x - sta gny ; old position - lda ex,x - sta gnx lda ttx sta ex,x lda tty sta ey,x lda etd sta edir,x - ldx gny ; erase the old cell - jsr row_ptr - ldy gnx - lda #CH_FLOOR - sta (scrlo),y - lda #BLACK - sta (collo),y - ldx tty ; draw at the new one - jsr row_ptr - ldy ttx - lda #CH_ENEMY - sta (scrlo),y - ldx ei - lda ecol,x - sta (collo),y clc rts -; ---- per-frame flashes: the exit blinks; the cursor pulses -; yellow-red, dimmed to grey-red while the spin recharges ---- +; ---- per-frame flashes: the portal spins and blinks, the +; freshly spun walls flash white, the cursor shows the +; recharge state on its own color ---- upd_flash: + jsr upd_portal ; cycle the portal glyph ldx exrow jsr row_ptr ldy #38 @@ -888,35 +1014,31 @@ uf_exw: lda #WHITE uf_exset: sta (collo),y - ldx ky - jsr row_ptr - ldy kx - lda opt_cool + lda rotflash ; the spun walls flash, then re-highlight + beq uf_norf + dec rotflash + bne uf_white + lda #COL_HILITE + jmp uf_mark +uf_white: + lda #WHITE +uf_mark: + jsr mark_slots +uf_norf: + lda opt_cool ; the cursor dims red while recharging beq uf_hot lda cool beq uf_hot - lda framectr ; recharging: dimmed pulse - and #4 - bne uf_cdred - lda #DGREY - jmp uf_cset -uf_cdred: lda #RED jmp uf_cset uf_hot: - lda framectr ; ready: bright pulse - and #4 - bne uf_cred - lda #YELLOW - jmp uf_cset -uf_cred: - lda #RED + lda #WHITE uf_cset: - sta (collo),y + sta SPRCOL+SP_CUR rts ; ---- status row: the spin recharge readout (cooldown option) -; "wait" + a draining bar while recharging, "ready" after ---- +; "wait" + a bar draining pixel by pixel, "ready" after ---- upd_status: lda opt_cool bne us_show @@ -925,28 +1047,35 @@ us_show: lda cool beq us_ready +prtext 0, 12, LRED, txt_wait, 4 - lda cool ; blocks left: (cool + 15) / 16 = 1-10 - clc - adc #15 - lsr - lsr - lsr + lda cool ; pixels left: cool / 2 = 0-80 lsr sta ptmp - ldx #9 + ldx #0 us_bar: - cpx ptmp - bcc us_blk ; x < blocks: still filled - lda #$20 - jmp us_put -us_blk: + lda ptmp + beq us_empty + cmp #8 + bcc us_part + sec ; a full cell, and onward + sbc #8 + sta ptmp lda #$a0 + jmp us_put +us_part: + clc ; 1-7 pixels: one of the bar chars + adc #CH_BAR-1 + ldy #0 + sty ptmp + jmp us_put +us_empty: + lda #$20 us_put: sta SCREEN+18,x ; bar cells: row 0, columns 18-27 lda #LRED sta COLRAM+18,x - dex - bpl us_bar + inx + cpx #10 + bne us_bar rts us_ready: +prtext 0, 12, LGREEN, txt_ready, 5 @@ -958,6 +1087,113 @@ us_clr: bpl us_clr rts +; ---- drive the eight sprites from the grid state ---- +upd_sprites: + lda framectr + lsr + lsr + lsr + sta frame8 + ; the runner glides 2 pixels a frame + lda px + sta tgc + lda py + sta tgr + jsr set_target + lda #2 + sta gspd + ldx #SP_RUN + jsr spr_glide + ; the cursor glides 4 (its step is two cells) + lda kx + sta tgc + lda ky + sta tgr + jsr set_target + lda #4 + sta gspd + ldx #SP_CUR + jsr spr_glide + ; the bullet snaps cell to cell + lda sx + sta tgc + lda sy + sta tgr + jsr set_target + ldx #SP_SHOT + jsr spr_jump + ; the enemies glide 1 + lda #1 + sta gspd + ldx #0 +us_en: + stx ptmp + lda ex,x + sta tgc + lda ey,x + sta tgr + jsr set_target + lda ptmp + clc + adc #SP_EN + tax + jsr spr_glide + ldx ptmp + inx + cpx #NENEMIES + bne us_en + ; shapes: the runner bobs, each enemy waves on its own beat + lda frame8 + and #1 + clc + adc #SPR_RUN + sta SPRPTR+SP_RUN + lda #SPR_CUR + sta SPRPTR+SP_CUR + lda #SPR_SHOT + sta SPRPTR+SP_SHOT + ldx #0 +us_shape: + txa + clc + adc frame8 + and #1 + sta rtmp + lda #SPR_ENA ; enemies 0-1 are ghosts, 2-3 crawlers + cpx #2 + bcc us_seta + lda #SPR_ENB +us_seta: + clc + adc rtmp + sta SPRPTR+SP_EN,x + inx + cpx #NENEMIES + bne us_shape + ; enable: runner + cursor + the bullet and the live enemies + lda #%00000011 + ldy s_on + beq us_nosht + ora #%00000100 +us_nosht: + sta rtmp + ldx #0 +us_alive: + lda edead,x + bne us_dead + lda rtmp + ora ebit,x + sta rtmp +us_dead: + inx + cpx #NENEMIES + bne us_alive + lda rtmp + sta SPR_EN + jmp spr_commit + +ebit: !byte 8, 16, 32, 64 + ; ---- play texts ---- txt_goal: !scr "reach the " !byte CH_EXIT @@ -974,9 +1210,10 @@ fdx: !byte 0 ; runner facing: the gun aims this way fdy: !byte 0 kx: !byte 0 ; corner cursor position (post col / row) ky: !byte 0 -exrow: !byte 0 ; screen row of the exit diamond +exrow: !byte 0 ; screen row of the exit portal endflag: !byte 0 ; 0 = playing, 1 = escaped, 2 = caught cool: !byte 0 ; spin recharge frames left (cooldown option) +rotflash:!byte 0 ; frames the freshly spun walls stay white s_on: !byte 0 ; bullet in flight? sx: !byte 0 ; bullet position and heading sy: !byte 0 @@ -998,6 +1235,10 @@ nch: !byte 0 ; the four slot chars around the cursor ech: !byte 0 sch: !byte 0 wch: !byte 0 +hlcol: !byte 0 ; mark_slots color parameter +latwcol: !byte 0 ; draw_lattice colors: walls, posts +latpcol: !byte 0 +frame8: !byte 0 ; framectr / 8: the animation beat ei: !byte 0 ; enemy loop index etries: !byte 0 etd: !byte 0 diff --git a/rules.asm b/rules.asm index e6809d4..2a58e04 100644 --- a/rules.asm +++ b/rules.asm @@ -33,7 +33,7 @@ ru_hide: ru_input: jsr start_edge beq ru_stay - jmp menu_init + +fadeto menu_init ru_stay: rts diff --git a/win.asm b/win.asm index 905e434..9c5b427 100644 --- a/win.asm +++ b/win.asm @@ -17,6 +17,15 @@ win_init: rts win_update: + ; the border celebrates along on the same gold ramp + lda framectr + lsr + lsr + and #15 + tax + lda washtbl,x + sta borbase + ; the gold wash rolls down the big letters (rows 3-7) inc washphase lda #0 @@ -62,7 +71,7 @@ wu_hide: wu_input: jsr start_edge beq wu_stay - jmp menu_init ; a win leads back to the main screen + +fadeto menu_init ; a win leads back to the main screen wu_stay: rts