extra effects

This commit is contained in:
2026-07-13 22:57:03 +02:00
parent ed261028cb
commit 545e9153f2
8 changed files with 725 additions and 191 deletions
+18
View File
@@ -14,13 +14,25 @@ COLRAM = $d800 ; color RAM
CIA1_PA = $dc00 ; CIA1 port A: keyboard matrix column select
CIA1_PB = $dc01 ; CIA1 port B: keyboard matrix row read
; ---- sprite registers ----
SPRPOS = $d000 ; sprite 0 x; +1 = y, +2 = sprite 1 x, ...
SPR_MSBX = $d010 ; 9th bit of each sprite's x coordinate
SPR_EN = $d015 ; sprite enable bits
SPR_YEX = $d017 ; vertical expand
SPR_PRIO = $d01b ; 1 = sprite behind the characters
SPR_MC = $d01c ; multicolor enable
SPR_XEX = $d01d ; horizontal expand
SPR_COL = $d027 ; sprite 0 color, +1 = sprite 1, ...
; ---- colors ----
BLACK = 0
WHITE = 1
CYAN = 3
YELLOW = 7
ORANGE = 8
DGREY = 11
LGREEN = 13
LBLUE = 14
LGREY = 15
; ---- screen layout (slide 1) ----
@@ -41,9 +53,15 @@ BAR_STEPS = 57 ; 57 steps * 4 lines = up to line 244
NUM_SLIDES = 5
SLIDE_TIME = 300 ; 6 seconds per slide (PAL, 50 frames/s)
S5_TIME = 450 ; slide 5 is longer: the typewriter needs time
FADE_STEPS = 5 ; fade steps (longest fadetbl chain is 4)
FADE_SPEED = 4 ; frames between two fade steps
; ---- transition types (tin_tbl / tout_tbl in main.asm) ----
TR_FADE = 0 ; fade through black (the original)
TR_DISSOLVE = 1 ; cells appear/vanish in random order
TR_WIPE = 2 ; column sweep, left to right
FADEBUF = $c000 ; snapshot of color RAM for the fade-in
; ---- zero page pointers ----
+17 -169
View File
@@ -4,12 +4,14 @@
; slide 2: OUR FIRST GAME - Definitely not an Impostor
; slide 3: OUR SECOND GAME IS COMING (border raster bars)
; slide 4: CONTACT
; slide 5: the assembly confession
; slides cross-fade through black between switches
; slide 5: the assembly confession (typewriter)
; slides transition through black between switches
; (fade / random dissolve / column wipe, per slide)
; all timed by polling the raster beam
;
; Files:
; defs.asm - constants, zero page, macros
; transitions.asm - slide transitions: fade, dissolve, wipe
; common.asm - shared routines, tables, variables
; slideN.asm - one file per slide: sN_init, sN_update + data
;
@@ -90,7 +92,7 @@ dur_dec:
bne main
advance:
jsr fade_out ; fade the old slide to black
jsr trans_out ; hide the old slide (its out-transition)
adv_release:
jsr scan_space ; a held space must not race through
beq adv_release ; the whole show
@@ -106,7 +108,7 @@ slide_ok:
jmp main
go_back:
jsr fade_out
jsr trans_out
back_release:
jsr scan_del
beq back_release
@@ -176,170 +178,13 @@ slide_setup:
lda #BLACK
sta BORDER
sta BG
sta SPR_EN ; a slide that wants sprites enables them itself
jmp (vec) ; init ends with rts -> returns to slide_setup's caller
; ============================================================
; slide transition: fade through black
; ============================================================
; ---- draw the current slide while the display is switched off
; (everything shows border color = black), snapshot its colors,
; blacken them, switch the display back on and fade in ----
show_slide:
lda #$0b ; display off
sta SCRCTRL
jsr slide_setup
jsr snapshot_colram
lda #$1b ; display on
sta SCRCTRL
; fade in: fadecnt counts how many times the target color is
; darkened; counting 4 -> 0 walks each cell from black back
; up to its snapshot color
lda #FADE_STEPS-1
sta fadecnt
fi_step:
jsr build_map
jsr apply_map
ldx #FADE_SPEED
fi_wait:
jsr wait_frame
dex
bne fi_wait
lda fadecnt
beq fi_done
dec fadecnt
jmp fi_step
fi_done:
rts
; ---- darken the whole color RAM step by step until black ----
fade_out:
lda #FADE_STEPS
sta fadecnt
fo_step:
ldx #FADE_SPEED
fo_wait:
jsr wait_frame
dex
bne fo_wait
jsr apply_fade
dec fadecnt
bne fo_step
rts
; ---- wait for the next bottom-border arrival of the beam ----
wait_frame:
wf_leave:
lda RASTER ; first leave line RAS_BOTTOM if we are on it
cmp #RAS_BOTTOM
beq wf_leave
wf_reach:
lda RASTER
cmp #RAS_BOTTOM
bne wf_reach
rts
; ---- one fade-out step: every color RAM cell one shade darker ----
apply_fade:
ldx #0
af_loop:
lda COLRAM,x
and #15 ; color RAM reads have garbage upper bits
tay
lda fadetbl,y
sta COLRAM,x
lda COLRAM+250,x
and #15
tay
lda fadetbl,y
sta COLRAM+250,x
lda COLRAM+500,x
and #15
tay
lda fadetbl,y
sta COLRAM+500,x
lda COLRAM+750,x
and #15
tay
lda fadetbl,y
sta COLRAM+750,x
inx
cpx #250
bne af_loop
rts
; ---- copy color RAM to FADEBUF, then blacken color RAM ----
snapshot_colram:
ldx #0
sn_loop:
lda COLRAM,x
and #15
sta FADEBUF,x
lda COLRAM+250,x
and #15
sta FADEBUF+250,x
lda COLRAM+500,x
and #15
sta FADEBUF+500,x
lda COLRAM+750,x
and #15
sta FADEBUF+750,x
lda #BLACK
sta COLRAM,x
sta COLRAM+250,x
sta COLRAM+500,x
sta COLRAM+750,x
inx
cpx #250
bne sn_loop
rts
; ---- curmap[c] = color c darkened fadecnt times ----
build_map:
ldx #15
bm_color:
txa
tay
lda fadecnt
sta bmcnt
beq bm_store ; 0 steps: identity map
bm_apply:
lda fadetbl,y
tay
dec bmcnt
bne bm_apply
bm_store:
tya
sta curmap,x
dex
bpl bm_color
rts
; ---- write curmap[FADEBUF] into the whole color RAM ----
apply_map:
ldx #0
am_loop:
ldy FADEBUF,x
lda curmap,y
sta COLRAM,x
ldy FADEBUF+250,x
lda curmap,y
sta COLRAM+250,x
ldy FADEBUF+500,x
lda curmap,y
sta COLRAM+500,x
ldy FADEBUF+750,x
lda curmap,y
sta COLRAM+750,x
inx
cpx #250
bne am_loop
rts
; ============================================================
; shared routines and the slides
; transitions, shared routines and the slides
; ============================================================
!src "transitions.asm"
!src "common.asm"
!src "slide1.asm"
!src "slide2.asm"
@@ -357,16 +202,19 @@ slide_upd_lo:
slide_upd_hi:
!byte >s1_update, >s2_update, >s3_update, >s4_update, >s5_update
slide_dur_lo:
!byte <SLIDE_TIME, <SLIDE_TIME, <SLIDE_TIME, <SLIDE_TIME, <SLIDE_TIME
!byte <SLIDE_TIME, <SLIDE_TIME, <SLIDE_TIME, <SLIDE_TIME, <S5_TIME
slide_dur_hi:
!byte >SLIDE_TIME, >SLIDE_TIME, >SLIDE_TIME, >SLIDE_TIME, >SLIDE_TIME
!byte >SLIDE_TIME, >SLIDE_TIME, >SLIDE_TIME, >SLIDE_TIME, >S5_TIME
; ---- per-slide transitions: reveal type / hide type ----
tin_tbl:
!byte TR_FADE, TR_WIPE, TR_DISSOLVE, TR_FADE, TR_DISSOLVE
tout_tbl:
!byte TR_DISSOLVE, TR_FADE, TR_WIPE, TR_DISSOLVE, TR_WIPE
; ---- variables ----
slide: !byte 0 ; current slide index
durlo: !byte 0 ; frames left on this slide (16 bit)
durhi: !byte 0
fadecnt: !byte 0 ; fade step counter
bmcnt: !byte 0 ; build_map inner counter
curmap: !fill 16, 0 ; current fade-in color map
paused: !byte 0 ; 1 = slide countdown frozen
pheld: !byte 0 ; 'p' key edge detection state
+24 -3
View File
@@ -1,7 +1,7 @@
; -----------------------------------------------------------
; slide1.asm - giant TTG logo + credits scroller
; effects: gold wash on the logo, smooth pixel scroll,
; pulsing title
; pulsing title, raster color gradient behind the scroller
; -----------------------------------------------------------
s1_init:
@@ -12,9 +12,9 @@ s1_init:
+prtext 17, 9, LGREEN, txt_www, txt_www_end - txt_www
+prtext 19, 14, LGREY, txt_city, txt_city_end - txt_city
; scroller row color
; scroller row color: white, so it reads on the blue gradient
ldx #39
lda #CYAN
lda #WHITE
scrollcol_loop:
sta COLRAM+SCROLLROW*40,x
dex
@@ -36,12 +36,30 @@ wait_scrtop:
lda xscroll ; bits 0-2 = x scroll, bit 3 = 0 -> 38 columns
sta XCTRL
; blue raster gradient behind the scroller: one background
; color per line, chasing the beam through lines 161-170
ldx #0
s1_grad:
txa
clc
adc #RAS_SCRTOP+1
s1_gwait:
cmp RASTER
bne s1_gwait
lda gradtbl,x
sta BG
inx
cpx #10
bne s1_grad
wait_scrbot:
lda RASTER
cmp #RAS_SCRBOT
bne wait_scrbot
lda #$c8 ; back to default: 40 columns, no scroll
sta XCTRL
lda #BLACK ; gradient off below the scroller row
sta BG
; beam is in the lower border: do all updates now, invisibly
wait_bottom:
@@ -213,6 +231,9 @@ bigfont:
letter_off: ; column offset of each letter (8 wide + 2 gap)
!byte 0, 10, 20
gradtbl: ; scroller backdrop: blue ramp, cyan peak
!byte $06, $06, $0e, $0e, $03, $03, $0e, $0e, $06, $06
; texts in screen codes (!scr); lowercase source shows as uppercase on C64
txt_title:
!scr "teletype games"
+17 -2
View File
@@ -1,6 +1,8 @@
; -----------------------------------------------------------
; slide2.asm - OUR FIRST GAME: Definitely not an Impostor
; big block letters with the gold wash running across them
; big block letters with the gold wash running across them;
; each text block gets a shifted wash phase, so the glow
; rolls through the three lines diagonally
; -----------------------------------------------------------
s2_init:
@@ -24,7 +26,8 @@ s2_update:
inc washphase
s2_hold:
; gold wash across all 15 big-letter rows (4-8, 10-14, 16-20)
; gold wash across all 15 big-letter rows (4-8, 10-14, 16-20);
; each block is 5 wash steps behind the one above -> diagonal
ldx #39
s2_loop:
txa
@@ -38,11 +41,23 @@ s2_loop:
sta COLRAM + 6*40,x
sta COLRAM + 7*40,x
sta COLRAM + 8*40,x
tya
clc
adc #5
and #15
tay
lda washtbl,y
sta COLRAM + 10*40,x
sta COLRAM + 11*40,x
sta COLRAM + 12*40,x
sta COLRAM + 13*40,x
sta COLRAM + 14*40,x
tya
clc
adc #5
and #15
tay
lda washtbl,y
sta COLRAM + 16*40,x
sta COLRAM + 17*40,x
sta COLRAM + 18*40,x
+18 -2
View File
@@ -1,7 +1,8 @@
; -----------------------------------------------------------
; slide3.asm - OUR SECOND GAME: IS COMING
; raster bars running on the border only, drop-shadowed
; big letters in the middle
; raster bars on the border that also bleed into the empty
; top and bottom of the screen; the middle stays black, so
; the drop-shadowed big letters remain readable
; -----------------------------------------------------------
s3_init:
@@ -25,6 +26,8 @@ s3_hold:
; chase the beam: every 4th raster line from RAS_BARTOP down,
; set the BORDER color from the cyclic 64-entry bar table;
; above line 74 and from line 210 the screen rows are empty,
; there the bars run on the background too - in the middle
; the background stays black so the text remains readable
lda #RAS_BARTOP
sta s3line
@@ -40,7 +43,19 @@ s3_wait:
and #63
tay
lda rastbl,y
ldy s3line
cpy #74 ; top zone: bar color on the background too
bcc s3_bg
cpy #210 ; bottom zone likewise
bcs s3_bg
sta BORDER ; middle: border only, background back to
lda #BLACK ; black (the top zone left its last color)
sta BG
jmp s3_step
s3_bg:
sta BG
sta BORDER
s3_step:
lda s3line
clc
adc #4
@@ -51,6 +66,7 @@ s3_wait:
lda #BLACK ; below the bar area: back to black
sta BORDER
sta BG
s3_wbot: ; keep the one-call-per-frame contract
lda RASTER
+182 -1
View File
@@ -1,6 +1,8 @@
; -----------------------------------------------------------
; slide4.asm - CONTACT
; pulsing big title, contact lines below
; pulsing big title, contact lines, three-layer starfield
; drifting left, six star sprites floating on sine paths
; behind the text
; -----------------------------------------------------------
s4_init:
@@ -9,6 +11,43 @@ s4_init:
+prtext 10, 7, LGREEN, txt_web, txt_web_end - txt_web
+prtext 13, 6, YELLOW, txt_bbs, txt_bbs_end - txt_bbs
+prtext 16, 4, CYAN, txt_irc, txt_irc_end - txt_irc
; starfield: draw the stars at their current positions so
; the in-transition reveals them together with the text
ldx #11
s4i_star:
jsr star_ptr
ldy star_x,x
lda #$2e ; '.'
sta (scrlo),y
lda star_col,x
sta (collo),y
dex
bpl s4i_star
; sprites: same star shape on all six, floating behind the
; characters; enabled by the update, so they pop in only
; after the slide's in-transition is done
lda #(sprdata >> 6)
ldx #5
s4i_ptr:
sta SCREEN+$3f8,x
dex
bpl s4i_ptr
ldx #5
s4i_col:
lda sprcols,x
sta SPR_COL,x
dex
bpl s4i_col
lda #0
sta SPR_MC
sta SPR_XEX
sta SPR_YEX
lda #%00111111
sta SPR_PRIO ; behind the text
lda #%00100000 ; sprite 5 lives right of x=255
sta SPR_MSBX
rts
s4_update:
@@ -33,6 +72,79 @@ s4_loop:
sta COLRAM + 6*40,x
dex
bpl s4_loop
; starfield: three layers, each layer steps left on its own
; frame mask (fast/mid/slow parallax)
ldx #11
s4u_star:
lda framectr
and star_mask,x
bne s4u_next
jsr star_ptr
ldy star_x,x
lda #$20 ; erase at the old position
sta (scrlo),y
lda star_x,x ; step left, wrap at the edge
bne s4u_dec
lda #40
sta star_x,x
s4u_dec:
dec star_x,x
ldy star_x,x
lda #$2e
sta (scrlo),y
lda star_col,x
sta (collo),y
s4u_next:
dex
bpl s4u_star
; sprites: y from a sine table, x = base + slower sine wobble
lda #%00111111
sta SPR_EN
ldx #5
s4u_spr:
txa
asl
sta sprofs ; register offset = sprite * 2
lda framectr
lsr
clc
adc spr_yph,x
and #63
tay
lda ysin,y
ldy sprofs
sta SPRPOS+1,y
lda framectr
lsr
lsr
clc
adc spr_xph,x
and #63
tay
lda xwob,y
clc
adc spr_xbase,x
ldy sprofs
sta SPRPOS,y
dex
bpl s4u_spr
rts
; ---- scrlo/hi + collo/hi = screen/color RAM row of star X ----
star_ptr:
ldy star_row,x
lda mul40lo,y
sta scrlo
sta collo
lda mul40hi,y
clc
adc #>SCREEN
sta scrhi
clc
adc #$d4 ; COLRAM - SCREEN high byte distance
sta colhi
rts
; ---- data ----
@@ -47,3 +159,72 @@ txt_bbs_end:
txt_irc:
!scr "irc: libera.chat #teletypegames"
txt_irc_end:
; starfield: rows avoid the title (2-6) and text (10, 13, 16) rows
star_row:
!byte 0, 8, 11, 14, 17, 19, 1, 9, 12, 15, 21, 23
star_mask: ; move on framectr & mask == 0
!byte 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7
star_col: ; fast = white, mid = lgrey, slow = dgrey
!byte WHITE, LGREY, DGREY, WHITE, LGREY, DGREY
!byte WHITE, LGREY, DGREY, WHITE, LGREY, DGREY
sprcols:
!byte YELLOW, LBLUE, LGREEN, WHITE, ORANGE, CYAN
spr_xbase: ; spread across the screen; sprite 5 gets
!byte 40, 85, 130, 175, 220, 20 ; +256 via SPR_MSBX
spr_yph: ; sine phase offsets per sprite
!byte 0, 11, 21, 32, 43, 53
spr_xph:
!byte 0, 26, 52, 13, 39, 7
ysin: ; 64-entry sine, 134 +/- 60 (sprite y)
!byte $86, $8c, $92, $97, $9d, $a2, $a7, $ac
!byte $b0, $b4, $b8, $bb, $bd, $bf, $c1, $c2
!byte $c2, $c2, $c1, $bf, $bd, $bb, $b8, $b4
!byte $b0, $ac, $a7, $a2, $9d, $97, $92, $8c
!byte $86, $80, $7a, $75, $6f, $6a, $65, $60
!byte $5c, $58, $54, $51, $4f, $4d, $4b, $4a
!byte $4a, $4a, $4b, $4d, $4f, $51, $54, $58
!byte $5c, $60, $65, $6a, $6f, $75, $7a, $80
xwob: ; 64-entry sine, 12 +/- 12 (x wobble)
!byte $0c, $0d, $0e, $0f, $11, $12, $13, $14
!byte $14, $15, $16, $17, $17, $17, $18, $18
!byte $18, $18, $18, $17, $17, $17, $16, $15
!byte $14, $14, $13, $12, $11, $0f, $0e, $0d
!byte $0c, $0b, $0a, $09, $07, $06, $05, $04
!byte $04, $03, $02, $01, $01, $01, $00, $00
!byte $00, $00, $00, $01, $01, $01, $02, $03
!byte $04, $04, $05, $06, $07, $09, $0a, $0b
; 24x21 four-pointed star sprite (must sit on a 64-byte boundary
; and below $4000, the top of the VIC's bank)
!align 63, 0
sprdata:
!byte $00, $00, $00
!byte $00, $00, $00
!byte $00, $18, $00
!byte $00, $18, $00
!byte $00, $18, $00
!byte $00, $3c, $00
!byte $00, $3c, $00
!byte $00, $7e, $00
!byte $07, $ff, $e0
!byte $00, $7e, $00
!byte $00, $3c, $00
!byte $00, $3c, $00
!byte $00, $18, $00
!byte $00, $18, $00
!byte $00, $18, $00
!byte $00, $00, $00
!byte $00, $00, $00
!byte $00, $00, $00
!byte $00, $00, $00
!byte $00, $00, $00
!byte $00, $00, $00
; ---- variables ----
star_x: ; star columns (start scattered)
!byte 3, 17, 29, 8, 35, 22, 13, 31, 5, 26, 19, 37
sprofs: !byte 0 ; sprite register offset in the update loop
+73 -11
View File
@@ -1,16 +1,17 @@
; -----------------------------------------------------------
; slide5.asm - the assembly confession
; the body is typed in live, one character per frame, with a
; white block cursor; the closing line appears when the
; typing is done and pulses
; -----------------------------------------------------------
s5_init:
jsr clear_screen
+prtext 3, 11, WHITE, txt_conf1, txt_conf1_end - txt_conf1
+prtext 7, 3, LGREY, txt_conf2, txt_conf2_end - txt_conf2
+prtext 9, 3, LGREY, txt_conf3, txt_conf3_end - txt_conf3
+prtext 12, 3, WHITE, txt_conf4, txt_conf4_end - txt_conf4
+prtext 15, 3, LGREY, txt_conf5, txt_conf5_end - txt_conf5
+prtext 17, 3, LGREY, txt_conf6, txt_conf6_end - txt_conf6
+prtext 21, 11, CYAN, txt_conf7, txt_conf7_end - txt_conf7
lda #0 ; the body starts empty and gets typed in
sta t_line
sta t_chr
sta t_done
rts
s5_update:
@@ -19,6 +20,9 @@ s5_update:
bne s5_update
inc framectr
lda t_done
beq s5_type
lda framectr ; pulse on the "(the ai says hi.)" line
lsr
lsr
@@ -33,6 +37,55 @@ s5_loop:
bpl s5_loop
rts
; ---- type one character per frame ----
s5_type:
ldx t_line
ldy t_row,x ; screen/color pointers to the line start
lda mul40lo,y
clc
adc #3 ; body column
sta scrlo
sta collo
lda mul40hi,y
adc #>SCREEN ; carry still clear (row starts stay low)
sta scrhi
clc
adc #$d4
sta colhi
lda t_txtlo,x
sta txtlo
lda t_txthi,x
sta txthi
ldy t_chr
lda (txtlo),y ; the character lands where the cursor was
sta (scrlo),y
lda t_color,x
sta (collo),y
iny
cpy #34 ; all body lines are exactly 34 chars
beq s5_nextline
sty t_chr
lda #$a0 ; block cursor at the next cell
sta (scrlo),y
lda #WHITE
sta (collo),y
rts
s5_nextline:
lda #0
sta t_chr
inc t_line
lda t_line
cmp #5
bne s5_ret
; typing done: the closing line appears and starts pulsing
+prtext 21, 11, CYAN, txt_conf7, txt_conf7_end - txt_conf7
lda #1
sta t_done
s5_ret:
rts
; ---- data ----
txt_conf1:
!scr "a quick confession"
@@ -41,19 +94,28 @@ txt_conf1_end:
; exactly 34 chars, so both edges line up at columns 3 and 36
txt_conf2:
!scr "we speak c/c++, lua, python, java,"
txt_conf2_end:
txt_conf3:
!scr "go, ruby, js, elixir, pascal."
txt_conf3_end:
txt_conf4:
!scr "but 6502 assembly? not a word."
txt_conf4_end:
txt_conf5:
!scr "so this slideshow was written"
txt_conf5_end:
txt_conf6:
!scr "with a little help from an ai."
txt_conf6_end:
txt_conf7:
!scr "(the ai says hi.)"
txt_conf7_end:
t_row: ; body line rows
!byte 7, 9, 12, 15, 17
t_color:
!byte LGREY, LGREY, WHITE, LGREY, LGREY
t_txtlo:
!byte <txt_conf2, <txt_conf3, <txt_conf4, <txt_conf5, <txt_conf6
t_txthi:
!byte >txt_conf2, >txt_conf3, >txt_conf4, >txt_conf5, >txt_conf6
; ---- variables ----
t_line: !byte 0 ; body line being typed (0-4)
t_chr: !byte 0 ; next character within the line
t_done: !byte 0 ; 1 = typing finished, closing line pulses
+373
View File
@@ -0,0 +1,373 @@
; -----------------------------------------------------------
; transitions.asm - slide transitions
; every slide is drawn with the display switched off, its
; colors are snapshotted into FADEBUF and blackened, then an
; in-transition reveals it; an out-transition hides it again.
; types (picked per slide in tin_tbl/tout_tbl in main.asm):
; TR_FADE - fade through black via the fadetbl ramps
; TR_DISSOLVE - cells appear/vanish in random (LFSR) order
; TR_WIPE - column sweep from left to right
; each reveal starts with a short grey border flash
; -----------------------------------------------------------
; ---- draw the current slide while the display is switched off
; (everything shows border color = black), snapshot its colors,
; blacken them, switch the display back on, flash, transition in ----
show_slide:
lda #$0b ; display off
sta SCRCTRL
jsr slide_setup
jsr snapshot_colram
lda #$1b ; display on
sta SCRCTRL
ldx #0 ; short white-to-grey border flash: gives
ssf_loop: ; the reveal a beat
lda flashtbl,x
sta BORDER
jsr wait_frame
inx
cpx #3
bne ssf_loop
lda #BLACK
sta BORDER
ldx slide ; dispatch the slide's in-transition
ldy tin_tbl,x
lda tin_lo,y
sta vec
lda tin_hi,y
sta vec+1
jmp (vec) ; the transition ends with rts
; ---- dispatch the slide's out-transition ----
trans_out:
lda #0 ; sprites vanish with the slide
sta SPR_EN
ldx slide
ldy tout_tbl,x
lda tout_lo,y
sta vec
lda tout_hi,y
sta vec+1
jmp (vec)
tin_lo:
!byte <fade_in, <dissolve_in, <wipe_in
tin_hi:
!byte >fade_in, >dissolve_in, >wipe_in
tout_lo:
!byte <fade_out, <dissolve_out, <wipe_out
tout_hi:
!byte >fade_out, >dissolve_out, >wipe_out
flashtbl:
!byte WHITE, LGREY, DGREY
; ============================================================
; TR_FADE - fade through black
; ============================================================
; ---- fade in: fadecnt counts how many times the target color is
; darkened; counting 4 -> 0 walks each cell from black back
; up to its snapshot color ----
fade_in:
lda #FADE_STEPS-1
sta fadecnt
fi_step:
jsr build_map
jsr apply_map
ldx #FADE_SPEED
fi_wait:
jsr wait_frame
dex
bne fi_wait
lda fadecnt
beq fi_done
dec fadecnt
jmp fi_step
fi_done:
rts
; ---- darken the whole color RAM step by step until black ----
fade_out:
lda #FADE_STEPS
sta fadecnt
fo_step:
ldx #FADE_SPEED
fo_wait:
jsr wait_frame
dex
bne fo_wait
jsr apply_fade
dec fadecnt
bne fo_step
rts
; ---- one fade-out step: every color RAM cell one shade darker ----
apply_fade:
ldx #0
af_loop:
lda COLRAM,x
and #15 ; color RAM reads have garbage upper bits
tay
lda fadetbl,y
sta COLRAM,x
lda COLRAM+250,x
and #15
tay
lda fadetbl,y
sta COLRAM+250,x
lda COLRAM+500,x
and #15
tay
lda fadetbl,y
sta COLRAM+500,x
lda COLRAM+750,x
and #15
tay
lda fadetbl,y
sta COLRAM+750,x
inx
cpx #250
bne af_loop
rts
; ---- curmap[c] = color c darkened fadecnt times ----
build_map:
ldx #15
bm_color:
txa
tay
lda fadecnt
sta bmcnt
beq bm_store ; 0 steps: identity map
bm_apply:
lda fadetbl,y
tay
dec bmcnt
bne bm_apply
bm_store:
tya
sta curmap,x
dex
bpl bm_color
rts
; ---- write curmap[FADEBUF] into the whole color RAM ----
apply_map:
ldx #0
am_loop:
ldy FADEBUF,x
lda curmap,y
sta COLRAM,x
ldy FADEBUF+250,x
lda curmap,y
sta COLRAM+250,x
ldy FADEBUF+500,x
lda curmap,y
sta COLRAM+500,x
ldy FADEBUF+750,x
lda curmap,y
sta COLRAM+750,x
inx
cpx #250
bne am_loop
rts
; ============================================================
; TR_DISSOLVE - cells appear/vanish in random order
; a 10-bit LFSR walks all indexes 1..1023 exactly once per
; period; indexes >= 1000 are skipped, cell 0 (which the LFSR
; never yields) is handled up front. 25 cells per frame ->
; the full screen takes 40 frames (0.8 s).
; ============================================================
dissolve_in:
lda FADEBUF ; cell 0 first
sta COLRAM
lda #40
sta frcnt
din_frame:
jsr wait_frame
lda #25
sta cellcnt
din_cell:
jsr lfsr_next ; -> lfsrlo/hi = cell index 1..999
lda lfsrlo
sta scrlo
sta collo
lda lfsrhi
clc
adc #>FADEBUF
sta scrhi
lda lfsrhi
clc
adc #>COLRAM
sta colhi
ldy #0
lda (scrlo),y ; restore the snapshot color
sta (collo),y
dec cellcnt
bne din_cell
dec frcnt
bne din_frame
rts
dissolve_out:
lda #BLACK ; cell 0 first
sta COLRAM
lda #40
sta frcnt
dot_frame:
jsr wait_frame
lda #25
sta cellcnt
dot_cell:
jsr lfsr_next
lda lfsrlo
sta collo
lda lfsrhi
clc
adc #>COLRAM
sta colhi
ldy #0
lda #BLACK
sta (collo),y
dec cellcnt
bne dot_cell
dec frcnt
bne dot_frame
rts
; ---- 10-bit Galois LFSR (x^10 + x^7 + 1, period 1023) ----
; steps until the state is a valid cell index (< 1000); the
; state is never reset, coverage holds from any starting point
lfsr_next:
lsr lfsrhi
ror lfsrlo
bcc ln_notap
lda lfsrhi
eor #$02
sta lfsrhi
lda lfsrlo
eor #$40
sta lfsrlo
ln_notap:
lda lfsrhi ; skip 1000..1023 ($03e8..$03ff)
cmp #$03
bcc ln_ok
lda lfsrlo
cmp #$e8
bcs lfsr_next
ln_ok:
rts
; ============================================================
; TR_WIPE - column sweep, one column per frame, left to right
; ============================================================
wipe_in:
lda #0
sta wcol
wi_col:
jsr wait_frame
ldx #24
wi_row:
lda mul40lo,x
sta scrlo
sta collo
lda mul40hi,x
clc
adc #>FADEBUF
sta scrhi
lda mul40hi,x
clc
adc #>COLRAM
sta colhi
ldy wcol
lda (scrlo),y ; restore the snapshot color
sta (collo),y
dex
bpl wi_row
inc wcol
lda wcol
cmp #40
bne wi_col
rts
wipe_out:
lda #0
sta wcol
wo_col:
jsr wait_frame
ldx #24
wo_row:
lda mul40lo,x
sta collo
lda mul40hi,x
clc
adc #>COLRAM
sta colhi
ldy wcol
lda #BLACK
sta (collo),y
dex
bpl wo_row
inc wcol
lda wcol
cmp #40
bne wo_col
rts
; ============================================================
; shared helpers
; ============================================================
; ---- wait for the next bottom-border arrival of the beam ----
wait_frame:
wf_leave:
lda RASTER ; first leave line RAS_BOTTOM if we are on it
cmp #RAS_BOTTOM
beq wf_leave
wf_reach:
lda RASTER
cmp #RAS_BOTTOM
bne wf_reach
rts
; ---- copy color RAM to FADEBUF, then blacken color RAM ----
snapshot_colram:
ldx #0
sn_loop:
lda COLRAM,x
and #15
sta FADEBUF,x
lda COLRAM+250,x
and #15
sta FADEBUF+250,x
lda COLRAM+500,x
and #15
sta FADEBUF+500,x
lda COLRAM+750,x
and #15
sta FADEBUF+750,x
lda #BLACK
sta COLRAM,x
sta COLRAM+250,x
sta COLRAM+500,x
sta COLRAM+750,x
inx
cpx #250
bne sn_loop
rts
; ---- variables ----
fadecnt: !byte 0 ; fade step counter
bmcnt: !byte 0 ; build_map inner counter
curmap: !fill 16, 0 ; current fade-in color map
lfsrlo: !byte $37 ; LFSR state (any nonzero seed)
lfsrhi: !byte $01
cellcnt: !byte 0 ; dissolve: cells left this frame
frcnt: !byte 0 ; dissolve: frames left
wcol: !byte 0 ; wipe: current column