From 9153c1199d7560d2db43532f2ef3d1f1335447e1 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Wed, 15 Jul 2026 23:17:11 +0200 Subject: [PATCH] credits screen --- README.md | 7 +- common.asm | 7 ++ credits.asm | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++ defs.asm | 1 + main.asm | 1 + title.asm | 179 ++++++++++++++++++++++-------- 6 files changed, 459 insertions(+), 50 deletions(-) create mode 100644 credits.asm diff --git a/README.md b/README.md index 7b04624..b66157e 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ steers the closest one left and right, trying to run the scooter down. | Input | Action | |-------|--------| -| Menu: joystick up/down, or the `S` / `M` keys | pick single player / multiplayer | -| Menu: fire (or `SPACE`); the `1` / `2` keys pick and start at once | start the picked mode | +| Menu: joystick up/down, or the `S` / `M` / `C` keys | pick single player / multiplayer / credits | +| Menu: fire (or `SPACE`); the `1` / `2` keys pick and start at once | open the picked line | | P1: joystick port 2 left/right, or `A` / `D` | move the scooter (auto-repeats while held) | | P2: joystick port 1 left/right, or `J` / `L` | steer the closest rabbit (multiplayer) | | Fire (or `SPACE`) | start; on the game over screen: back to the menu | @@ -51,7 +51,8 @@ steers the closest one left and right, trying to run the scooter down. | `main.asm` | BASIC stub, init, frame loop, state dispatch | | `defs.asm` | registers, constants, zero page, macros | | `intro.asm` | boot screen: giant TTG logo with the gold wash | -| `title.asm` | full-screen menu: big logo, start game, hopping rabbits | +| `title.asm` | full-screen menu: big logo, mode picker, hopping rabbits | +| `credits.asm` | demo-style credits: pixel scroller, gold wash, rainbow crew, sprite parade + AI warning | | `play.asm` | gameplay: input, spawning, scoring, HUD | | `over.asm` | full-screen game over: big title, score, retry | | `common.asm` | shared routines: printing, road, input, RNG, rabbit positioning | diff --git a/common.asm b/common.asm index 2acf053..0052142 100644 --- a/common.asm +++ b/common.asm @@ -586,6 +586,13 @@ txt_rabbit: !scr "rabbit" txt_scooter: !scr "scooter" txt_1p: !scr "single player" txt_2p: !scr "multiplayer" +txt_credits: !scr "credits" +txt_crew0: !scr "mr.zero - tasnadi zsolt" +txt_crew1: !scr "mr.one - tari balazs" +txt_crew2: !scr "mr.two - timar zoltan" +txt_crew3: !scr "mr.three - mezo bela" +txt_ai1: !scr "warning: this game was" +txt_ai2: !scr "written by an ai" txt_info: !scr "p1: joystick 2 or a/d" txt_info2: !scr "p2: joystick 1 or j/l" txt_ttgname: !scr "teletype games" diff --git a/credits.asm b/credits.asm new file mode 100644 index 0000000..a451319 --- /dev/null +++ b/credits.asm @@ -0,0 +1,314 @@ +; ----------------------------------------------------------- +; credits.asm - demo style credits: a smooth pixel scroller +; along the top (slide1's fine-scroll trick), gold wash on the +; big CREDITS, pulsing TELETYPE GAMES, rainbow crew names and +; a sprite parade of the scooter chasing the rabbits +; ----------------------------------------------------------- + +CR_SCROW = 1 ; scroller char row (raster lines 58-65) +CR_RASTOP = 56 ; switch fine scroll on just above it +CR_RASBOT = 66 ; ... and off just below (rows 0/2 are blank) +CR_STEP = 2 ; scroll speed: 8 px / 4 frames = 1 char +CR_PARADE_Y = 228 ; the parade runs along the bottom rows + +credits_init: + lda #BLACK ; same black card style as the menu + sta bg_top + sta bg_bot + jsr clear_screen + + +prbig 4, 6, YELLOW, txt_credits, 7 + + +prtext 11, 13, WHITE, txt_ttgname, 14 + + +prtext 13, 8, LGREEN, txt_crew0, 23 + +prtext 14, 10, LGREEN, txt_crew1, 20 + +prtext 15, 9, LGREEN, txt_crew2, 21 + +prtext 16, 10, LGREEN, txt_crew3, 20 + + +prtext 18, 9, LGREY, txt_ai1, 22 + +prtext 19, 12, LGREY, txt_ai2, 16 + + ; the scroller row renders in white + ldx #39 +ci_scol: + lda #WHITE + sta COLRAM+CR_SCROW*40,x + dex + bpl ci_scol + lda #6 ; multiple of CR_STEP -> clean 4-frame cycle + sta xscroll + lda #0 + sta scrollidx + sta washphase + + ; parade sprites: the red scooter chases seven white rabbits + lda #RED + sta SPR_COL + ldx #7 +ci_col: + lda #WHITE + sta SPR_COL,x + dex + bne ci_col + lda #SPRP_SCOOT + sta SPRPTR + lda #0 + sta SPR_XEX + sta SPR_YEX + lda #$ff + sta SPR_EN + + +setupd credits_update + rts + +credits_update: + ; ---- all the heavy drawing runs first, while the beam + ; is still far above the scroller row ---- + + ; scroller: step the fine scroll, shift on wrap-around + lda xscroll + sec + sbc #CR_STEP + bpl cu_noshift + clc + adc #8 + sta xscroll + ldx #0 +cu_shift: + lda SCREEN+CR_SCROW*40+1,x + sta SCREEN+CR_SCROW*40,x + inx + cpx #39 + bne cu_shift + ldx scrollidx ; feed the next char in on the right + lda scrolltext,x + sta SCREEN+CR_SCROW*40+39 + inx + cpx #scrolltext_end - scrolltext + bne cu_feedok + ldx #0 +cu_feedok: + stx scrollidx + jmp cu_scrolled +cu_noshift: + sta xscroll +cu_scrolled: + + ; gold wash rolling down the big CREDITS (rows 4-8; the + ; letters are inverse spaces, color RAM on blanks is moot) + inc washphase + lda #0 + sta g8row +cu_wash: + lda #4 + clc + adc g8row + tax + jsr row_ptr + lda washphase + lsr + clc + adc g8row + and #15 + tax + lda washtbl,x + ldy #33 +cu_wcol: + sta (collo),y + dey + cpy #5 + bne cu_wcol + inc g8row + lda g8row + cmp #5 + bne cu_wash + + ; TELETYPE GAMES pulses grey-white + ldx #11 + jsr row_ptr + lda framectr + lsr + lsr + lsr + and #7 + tax + lda pulsetbl,x + ldy #26 +cu_pulse: + sta (collo),y + dey + cpy #12 + bne cu_pulse + + ; rainbow runs down the crew lines + lda #0 + sta rtmp2 ; line counter +cu_crew: + lda #13 + clc + adc rtmp2 + tax + jsr row_ptr + lda framectr + lsr + lsr + clc + adc rtmp2 + and #7 + tax + lda raintbl,x + ldy #31 +cu_ccol: + sta (collo),y + dey + cpy #7 + bne cu_ccol + inc rtmp2 + lda rtmp2 + cmp #4 + bne cu_crew + + ; the parade: everything scoots right to left, wraps at 344 + ldx #7 +cu_par: + lda crx_lo,x + sec + sbc crspd,x + sta crx_lo,x + lda crx_hi,x + sbc #0 + sta crx_hi,x + bne cu_ponscr ; x >= 256: still on screen + lda crx_lo,x + cmp #24 + bcs cu_ponscr + lda #$58 ; wrapped: back to x = 344 + sta crx_lo,x + lda #1 + sta crx_hi,x +cu_ponscr: + txa + asl + tay + lda crx_lo,x + sta SPRPOS,y + cpx #0 + beq cu_pscoot + ; rabbits bob and cycle their hop frames + lda framectr + lsr + lsr + lsr + sta rtmp + txa + clc + adc rtmp + and #7 + tay + lda hoptab,y + sta rtmp + lda #CR_PARADE_Y + sec + sbc rtmp + pha + lda framectr + lsr + lsr + lsr + sta rtmp + txa + clc + adc rtmp + and #3 + clc + adc #SPRP_BIG + sta SPRPTR,x + txa + asl + tay + pla + sta SPRPOS+1,y + jmp cu_pnext +cu_pscoot: + lda #CR_PARADE_Y + sta SPRPOS+1 +cu_pnext: + dex + bpl cu_par + ; x MSB shadow from the high bytes + lda #0 + sta rtmp + ldx #7 +cu_pmsb: + lda crx_hi,x + beq cu_pmnext + lda crbit,x + ora rtmp + sta rtmp +cu_pmnext: + dex + bpl cu_pmsb + lda rtmp + sta SPR_MSBX + + ; blink the return prompt + lda framectr + and #32 + bne cu_hide + +prtext 21, 13, YELLOW, txt_return, 13 + jmp cu_input +cu_hide: + +prtext 21, 13, YELLOW, txt_blank, 13 +cu_input: + jsr start_edge + beq cu_stay + lda #$c8 ; leave with the scroll register clean + sta XCTRL + jmp title_init ; back to the menu +cu_stay: + + ; ---- beam work: fine scroll on for the scroller row only ---- +cu_wtop: + lda RASTER + cmp #CR_RASTOP + bne cu_wtop + lda xscroll ; bits 0-2 = x scroll, bit 3 = 0 -> 38 cols + sta XCTRL +cu_wbot: + lda RASTER + cmp #CR_RASBOT + bne cu_wbot + lda #$c8 ; back to default: 40 columns, no scroll + sta XCTRL + rts + +; ---- tables ---- +pulsetbl: ; grey-white pulse (8 entries, cyclic) + !byte $0b, $0c, $0f, $01, $01, $0f, $0c, $0b + +raintbl: ; rainbow ramp for the crew lines + !byte $02, $08, $07, $0d, $03, $0e, $04, $0a + +crbit: ; sprite number -> register bit + !byte 1, 2, 4, 8, 16, 32, 64, 128 + +crspd: ; parade speeds (sprite 0 = the scooter) + !byte 2, 1, 3, 1, 2, 1, 3, 2 +crx_lo: ; parade x positions (16 bit, start staggered) + !byte 60, 100, 140, 180, 220, 4, 44, 84 +crx_hi: + !byte 0, 0, 0, 0, 0, 1, 1, 1 + +; ---- scrolltext (wraps around) ---- +scrolltext: + !scr "welcome to rabbit scooter ... the crew: " + !scr "mr.zero - tasnadi zsolt ... mr.one - tari balazs ... " + !scr "mr.two - timar zoltan ... mr.three - mezo bela ... " + !scr "this whole game was written by an ai - honest! ... " + !scr "greetings to all sceners out there ... " +scrolltext_end: + +; ---- credits variables ---- +xscroll: !byte 6 ; fine scroll register value (0-7) +scrollidx: !byte 0 ; next scrolltext char to feed in diff --git a/defs.asm b/defs.asm index 7c06d1b..f8393db 100644 --- a/defs.asm +++ b/defs.asm @@ -5,6 +5,7 @@ ; ---- hardware registers ---- RASTER = $d012 ; current raster line +XCTRL = $d016 ; horizontal fine scroll + 38/40 column mode BORDER = $d020 ; border color register BG = $d021 ; background color register SCREEN = $0400 ; screen RAM (40x25 chars) diff --git a/main.asm b/main.asm index 34e1ecd..98810f4 100644 --- a/main.asm +++ b/main.asm @@ -116,6 +116,7 @@ wf_hit: ; ============================================================ !src "intro.asm" !src "title.asm" +!src "credits.asm" !src "play.asm" !src "over.asm" !src "common.asm" diff --git a/title.asm b/title.asm index c727f60..db9f93b 100644 --- a/title.asm +++ b/title.asm @@ -1,7 +1,8 @@ ; ----------------------------------------------------------- ; title.asm - full-screen menu card: big RABBIT / SCOOTER -; logo flanked by two hopping rabbits, single/multiplayer -; picker (joystick up/down + fire, or the 1 / 2 keys) +; logo flanked by two hopping rabbits, and a three-item menu: +; single player / multiplayer / credits (joystick up/down + +; fire; s, m, c pick; 1 and 2 pick and start at once) ; ----------------------------------------------------------- title_init: @@ -10,10 +11,11 @@ title_init: sta bg_bot jsr clear_screen - +prbig 2, 8, RED, txt_rabbit, 6 - +prbig 8, 6, WHITE, txt_scooter, 7 - +prtext 18, 9, LGREY, txt_info, 21 - +prtext 19, 9, LGREY, txt_info2, 21 + +prbig 1, 8, RED, txt_rabbit, 6 + +prbig 7, 6, WHITE, txt_scooter, 7 + + lda mp_mode ; cursor starts on the last played mode + sta menusel ; decoration: white rabbits flank the logo (sprites 1-2, ; double-sized), the red scooter waits at the bottom @@ -26,11 +28,11 @@ title_init: sta SPRPTR lda #172 ; center lane position sta SPRPOS - lda #210 + lda #226 ; just below the footer line sta SPRPOS+1 lda #30 ; left rabbit sta SPRPOS+2 - lda #66 + lda #58 sta SPRPOS+3 sta SPRPOS+5 lda #34 ; right rabbit: x = 290, MSB below @@ -66,29 +68,48 @@ title_update: adc #SPRP_BIG sta SPRPTR+2 - ; joystick up/down picks the mode + ; joystick up/down steps the cursor (edge detected) jsr read_joy lda joyb - and #1 ; up - beq tu_noup - lda #0 - sta mp_mode -tu_noup: - lda joyb - and #2 ; down - beq tu_nodown + and #3 + beq tu_udrel + lda udheld + bne tu_udend lda #1 - sta mp_mode -tu_nodown: + sta udheld + lda joyb + and #1 ; up + beq tu_down + lda menusel + beq tu_udend + dec menusel + jmp tu_udend +tu_down: + lda menusel + cmp #MENU_ITEMS-1 + beq tu_udend + inc menusel + jmp tu_udend +tu_udrel: + lda #0 + sta udheld +tu_udend: - ; the 's' / 'm' keys pick the mode (fire still starts) + ; letter keys pick a line (fire still starts); skipped + ; while joystick 1 fire is down, because it grounds the + ; same row line the 'm' and 'c' keys sit on + lda #$ff + sta CIA1_PA + lda CIA1_PB + and #$10 + beq tu_keydone lda #$fd ; 's': keyboard column 1, row bit 5 sta CIA1_PA lda CIA1_PB and #$20 bne tu_nos lda #0 - sta mp_mode + sta menusel tu_nos: lda #$ef ; 'm': keyboard column 4, row bit 4 sta CIA1_PA @@ -96,8 +117,16 @@ tu_nos: and #$10 bne tu_nom lda #1 - sta mp_mode + sta menusel tu_nom: + lda #$fb ; 'c': keyboard column 2, row bit 4 + sta CIA1_PA + lda CIA1_PB + and #$10 + bne tu_noc + lda #2 + sta menusel +tu_noc: ; the 1 / 2 keys pick and start right away (edge detected) lda #$7f ; keyboard column 7: '1' = bit 0, '2' = bit 3 @@ -107,58 +136,114 @@ tu_nom: cmp #$09 beq tu_keyup ; neither key held ldx k12held - bne tu_menu ; still held from an earlier frame + bne tu_keydone ; still held from an earlier frame inx stx k12held and #$01 bne tu_key2 lda #0 - sta mp_mode + sta menusel jmp title_go tu_key2: lda #1 - sta mp_mode + sta menusel jmp title_go tu_keyup: lda #0 sta k12held -tu_menu: +tu_keydone: + + ; footer: the two control lines take turns + lda framectr + and #64 + beq tu_foot2 + +prtext 21, 9, LGREY, txt_info, 21 + jmp tu_footdone +tu_foot2: + +prtext 21, 9, LGREY, txt_info2, 21 +tu_footdone: + + ; the menu items: the picked line is yellow + ldx #0 +tm_items: + txa + pha + jsr draw_mitem + pla + tax + inx + cpx #MENU_ITEMS + bne tm_items - ; the two options: the picked line is yellow - lda mp_mode - bne tm_multi - +prtext 14, 14, YELLOW, txt_1p, 13 - +prtext 16, 14, WHITE, txt_2p, 11 - jmp tm_cursor -tm_multi: - +prtext 14, 14, WHITE, txt_1p, 13 - +prtext 16, 14, YELLOW, txt_2p, 11 -tm_cursor: ; blinking '>' cursor in front of the picked line lda #$20 sta SCREEN+14*40+12 sta SCREEN+16*40+12 + sta SCREEN+18*40+12 lda framectr and #16 bne tu_start - lda mp_mode - bne tm_cur2 + ldx menusel + lda mcur_lo,x + sta scrlo + lda mcur_hi,x + sta scrhi + ldy #0 lda #62 ; '>' - sta SCREEN+14*40+12 + sta (scrlo),y + lda scrhi + clc + adc #$d4 ; same cell in color RAM + sta scrhi lda #YELLOW - sta COLRAM+14*40+12 - jmp tu_start -tm_cur2: - lda #62 - sta SCREEN+16*40+12 - lda #YELLOW - sta COLRAM+16*40+12 + sta (scrlo),y tu_start: - ; fire or space starts the picked mode + ; fire or space opens the picked line jsr start_edge beq tu_done title_go: + lda menusel + cmp #2 + beq tg_credits + sta mp_mode ; item 0 / 1 doubles as the player count jmp play_init ; its rts returns to the main loop +tg_credits: + jmp credits_init tu_done: rts + +; ---- draw menu item X, yellow when it is the picked one ---- +draw_mitem: + lda mitem_lo,x + sta txtlo + lda mitem_hi,x + sta txthi + lda mitem_row,x + sta prow + lda #14 + sta pcol + lda mitem_len,x + sta plen + lda #WHITE + cpx menusel + bne dm_store + lda #YELLOW +dm_store: + sta pcolor + jmp print_text + +; ---- menu tables ---- +MENU_ITEMS = 3 +mitem_lo: !byte txt_1p, >txt_2p, >txt_credits +mitem_len: !byte 13, 11, 7 +mitem_row: !byte 14, 16, 18 +mcur_lo: ; cursor cells: column 12 of those rows + !byte <(SCREEN+14*40+12), <(SCREEN+16*40+12), <(SCREEN+18*40+12) +mcur_hi: + !byte >(SCREEN+14*40+12), >(SCREEN+16*40+12), >(SCREEN+18*40+12) + +; ---- menu variables ---- +menusel: !byte 0 ; picked line: 0-2 +udheld: !byte 0 ; joystick up/down edge detection state