Add Neon Rift demo

This commit is contained in:
Christian Johannesen 2026-10-16 12:21:40 +02:00
parent fb871d270e
commit 84f1d5defb
5 changed files with 683 additions and 2 deletions

View file

@ -1,6 +1,6 @@
# C64 Program Collection # C64 Program Collection
Thirty-one small, polished programs for the Commodore 64, written in stock Commodore BASIC V2 and 6502 machine code. The collection mixes arcade action, puzzles, simulations, creative tools, music, utilities, and visual effects. Every entry is self-contained and runs on an ordinary PAL or NTSC C64 without a cartridge or BASIC extension. Thirty-two small, polished programs for the Commodore 64, written in stock Commodore BASIC V2 and 6502 machine code. The collection mixes arcade action, puzzles, simulations, creative tools, music, utilities, and visual effects. Every entry is self-contained and runs on an ordinary PAL or NTSC C64 without a cartridge or BASIC extension.
Browse and run the collection at [c64.p20.dev](https://c64.p20.dev). Browse and run the collection at [c64.p20.dev](https://c64.p20.dev).
@ -39,6 +39,7 @@ Browse and run the collection at [c64.p20.dev](https://c64.p20.dev).
| PETSCII Aquarium | 2026-10-16 | Simulation | Machine Code | `F`, `1`-`3`, `Q` | Watch a tiny animated aquarium and feed its roaming fish. | [ASM](petscii-aquarium/petscii-aquarium.asm) | [Run](https://c64.p20.dev/program/petscii-aquarium) | | PETSCII Aquarium | 2026-10-16 | Simulation | Machine Code | `F`, `1`-`3`, `Q` | Watch a tiny animated aquarium and feed its roaming fish. | [ASM](petscii-aquarium/petscii-aquarium.asm) | [Run](https://c64.p20.dev/program/petscii-aquarium) |
| Fifteen Puzzle | 2026-10-16 | Puzzle | Machine Code | `W`, `A`, `S`, `D`, `R`, `Q` | Slide numbered tiles until the classic four-by-four board is restored. | [ASM](fifteen-puzzle/fifteen-puzzle.asm) | [Run](https://c64.p20.dev/program/fifteen-puzzle) | | Fifteen Puzzle | 2026-10-16 | Puzzle | Machine Code | `W`, `A`, `S`, `D`, `R`, `Q` | Slide numbered tiles until the classic four-by-four board is restored. | [ASM](fifteen-puzzle/fifteen-puzzle.asm) | [Run](https://c64.p20.dev/program/fifteen-puzzle) |
| Plasma Grid | 2026-10-16 | Demo | Machine Code | `1`-`3`, `C`, Space, `Q` | Fill the screen with a flowing field of color generated in real time. | [ASM](plasma-grid/plasma-grid.asm) | [Run](https://c64.p20.dev/program/plasma-grid) | | Plasma Grid | 2026-10-16 | Demo | Machine Code | `1`-`3`, `C`, Space, `Q` | Fill the screen with a flowing field of color generated in real time. | [ASM](plasma-grid/plasma-grid.asm) | [Run](https://c64.p20.dev/program/plasma-grid) |
| Neon Rift | 2026-10-16 | Demo | Machine Code | `1`-`3`, `C`, `M`, Space, `Q` | Enter a raster-lit world of orbiting sprites, smooth scrolling, and a three-voice SID score. | [ASM](neon-rift/neon-rift.asm) | [Run](https://c64.p20.dev/program/neon-rift) |
## Running the programs ## Running the programs

673
neon-rift/neon-rift.asm Normal file
View file

@ -0,0 +1,673 @@
!cpu 6510
; NEON RIFT
; Raster bands, eight sine-orbiting sprites, a split fine scroller and a
; three-voice SID sequence. All state touched by the demo is restored on Q.
; Self-starting BASIC line: 10 SYS2061
* = $0801
!word basic_end
!word 10
!byte $9e
!text "2061"
!byte 0
basic_end: !word 0
* = $080d
GETIN = $ffe4
CHROUT = $ffd2
start:
jsr save_state
lda #0
sta $d020
sta $d021
jsr show_splash
lda #147
jsr CHROUT
jsr initialize_demo
main_loop:
lda #250
jsr wait_raster
jsr read_controls
lda quit_flag
beq continue_demo
jmp exit
continue_demo:
lda paused
bne render_frame
jsr update_motion
lda music_muted
bne render_frame
jsr update_music
render_frame:
jsr draw_raster_frame
jmp main_loop
save_state:
lda $d020
sta old_border
lda $d021
sta old_background
lda $d015
sta old_sprite_enable
lda $d016
sta old_d016
lda $d01c
sta old_multicolor
lda $d025
sta old_sprite_mc0
lda $d026
sta old_sprite_mc1
lda $d010
sta old_sprite_msb
ldx #0
save_positions:
lda $d000,x
sta old_positions,x
inx
cpx #16
bne save_positions
ldx #0
save_colors:
lda $d027,x
sta old_sprite_colors,x
lda $07f8,x
sta old_sprite_pointers,x
inx
cpx #8
bne save_colors
ldx #0
save_sid:
lda $d400,x
sta old_sid,x
inx
cpx #25
bne save_sid
rts
initialize_demo:
lda #0
sta $d020
sta $d021
sta $d010
sta $d01c
sta motion_phase
sta motion_tick
sta palette
sta paused
sta music_muted
sta quit_flag
sta scroll_tick
sta scroll_position
sta music_tick
sta music_step
lda #2
sta motion_speed
lda #7
sta scroll_fine
jsr copy_sprite
jsr prepare_screen
lda #$ff
sta $d015
lda #6
sta $d025
lda #14
sta $d026
ldx #0
sprite_setup_loop:
lda #$c0
sta $07f8,x
lda sprite_colors,x
sta $d027,x
inx
cpx #8
bne sprite_setup_loop
jsr initialize_sid
jsr update_sprites
rts
copy_sprite:
ldx #0
copy_sprite_loop:
lda orb_sprite,x
sta $3000,x
inx
cpx #64
bne copy_sprite_loop
rts
prepare_screen:
ldx #0
clear_pages:
lda #32
sta $0400,x
sta $0500,x
sta $0600,x
lda #1
sta $d800,x
sta $d900,x
sta $da00,x
inx
bne clear_pages
ldx #0
clear_last_page:
lda #32
sta $0700,x
lda #1
sta $db00,x
inx
cpx #232
bne clear_last_page
ldx #0
draw_stars:
lda star_positions_lo,x
sta $fb
lda star_positions_hi,x
sta $fc
ldy #0
txa
and #1
beq use_dot
lda #42
bne store_star
use_dot:
lda #46
store_star:
sta ($fb),y
inx
cpx #28
bne draw_stars
ldx #0
seed_scroller:
lda #32
sta $07c0,x
lda #7
sta $dbc0,x
inx
cpx #40
bne seed_scroller
rts
read_controls:
jsr GETIN
beq controls_done
cmp #81
bne control_color
lda #1
sta quit_flag
rts
control_color:
cmp #67
bne control_mute
inc palette
lda palette
and #3
sta palette
jmp controls_done
control_mute:
cmp #77
bne control_pause
lda music_muted
eor #1
sta music_muted
bne mute_music
jsr initialize_sid
jmp controls_done
mute_music:
jsr silence_sid
jmp controls_done
control_pause:
cmp #32
bne control_speed_one
lda paused
eor #1
sta paused
bne pause_sound
lda music_muted
bne controls_done
jsr initialize_sid
jmp controls_done
pause_sound:
jsr silence_sid
jmp controls_done
control_speed_one:
cmp #49
bne control_speed_two
lda #4
sta motion_speed
jmp controls_done
control_speed_two:
cmp #50
bne control_speed_three
lda #2
sta motion_speed
jmp controls_done
control_speed_three:
cmp #51
bne controls_done
lda #1
sta motion_speed
controls_done:
rts
update_motion:
inc motion_tick
lda motion_tick
cmp motion_speed
bcc update_scroll
lda #0
sta motion_tick
inc motion_phase
lda motion_phase
and #63
sta motion_phase
jsr update_sprites
update_scroll:
inc scroll_tick
lda scroll_tick
cmp #2
bcc motion_done
lda #0
sta scroll_tick
dec scroll_fine
lda scroll_fine
and #7
sta scroll_fine
cmp #7
bne motion_done
jsr shift_scroller
motion_done:
rts
update_sprites:
ldx #0
sprite_motion_loop:
stx object_index
txa
asl
asl
asl
clc
adc motion_phase
and #63
tax
lda sine_x,x
sta position_temp
ldx object_index
txa
asl
tay
lda position_temp
sta $d000,y
ldx object_index
txa
asl
asl
asl
clc
adc motion_phase
clc
adc #16
and #63
tax
lda sine_y,x
sta position_temp
ldx object_index
txa
asl
tay
iny
lda position_temp
sta $d000,y
ldx object_index
inx
cpx #8
bne sprite_motion_loop
rts
shift_scroller:
ldx #0
scroll_shift_loop:
lda $07c1,x
sta $07c0,x
inx
cpx #39
bne scroll_shift_loop
ldy scroll_position
lda scroll_message,y
bne insert_scroll_char
ldy #0
sty scroll_position
lda scroll_message
insert_scroll_char:
sta $07e7
inc scroll_position
lda palette
asl
tax
lda scroller_colors,x
ldx #0
color_scroller:
sta $dbc0,x
inx
cpx #40
bne color_scroller
rts
initialize_sid:
jsr silence_sid
lda #$08
sta $d405
lda #$88
sta $d406
lda #0
sta $d402
lda #8
sta $d403
lda #$04
sta $d40c
lda #$a8
sta $d40d
lda #$02
sta $d413
lda #$84
sta $d414
lda #$00
sta $d417
lda #$0f
sta $d418
rts
update_music:
inc music_tick
lda music_tick
cmp #6
bcc music_done
lda #0
sta music_tick
ldx music_step
lda #0
sta $d404
sta $d40b
sta $d412
lda lead_notes,x
tay
lda note_lo,y
sta $d400
lda note_hi,y
sta $d401
lda #$41
sta $d404
lda bass_notes,x
tay
lda note_hi,y
lsr
sta $d408
lda note_lo,y
ror
sta $d407
lda #$11
sta $d40b
lda drum_steps,x
beq no_drum
lda #$35
sta $d40e
lda #$18
sta $d40f
lda #$81
sta $d412
no_drum:
inc music_step
lda music_step
and #15
sta music_step
music_done:
rts
silence_sid:
lda #0
sta $d404
sta $d40b
sta $d412
sta $d418
rts
draw_raster_frame:
lda #45
jsr wait_raster
lda old_d016
and #$f8
sta $d016
lda palette
asl
asl
asl
tax
stx palette_base
ldx #0
raster_band_loop:
stx band_index
lda raster_lines,x
jsr wait_raster
ldx band_index
txa
clc
adc palette_base
tay
lda raster_colors,y
sta $d021
ldx band_index
inx
cpx #8
bne raster_band_loop
lda #232
jsr wait_raster
lda #0
sta $d021
lda old_d016
and #$f8
ora scroll_fine
sta $d016
rts
wait_raster:
wait_raster_line:
cmp $d012
bne wait_raster_line
wait_raster_leave:
cmp $d012
beq wait_raster_leave
rts
show_splash:
lda #<splash_text
sta $fb
lda #>splash_text
sta $fc
ldy #0
print_splash:
lda ($fb),y
beq wait_for_space
jsr CHROUT
inc $fb
bne print_splash
inc $fc
jmp print_splash
wait_for_space:
jsr GETIN
cmp #32
bne wait_for_space
rts
exit:
jsr silence_sid
ldx #0
restore_sid:
lda old_sid,x
sta $d400,x
inx
cpx #25
bne restore_sid
lda old_sprite_enable
sta $d015
lda old_d016
sta $d016
lda old_multicolor
sta $d01c
lda old_sprite_mc0
sta $d025
lda old_sprite_mc1
sta $d026
lda old_sprite_msb
sta $d010
ldx #0
restore_positions:
lda old_positions,x
sta $d000,x
inx
cpx #16
bne restore_positions
ldx #0
restore_sprite_data:
lda old_sprite_colors,x
sta $d027,x
lda old_sprite_pointers,x
sta $07f8,x
inx
cpx #8
bne restore_sprite_data
lda old_border
sta $d020
lda old_background
sta $d021
lda #147
jsr CHROUT
rts
splash_text:
!byte 147,13,13,13
!byte 154
!text " NEON RIFT"
!byte 13,13
!byte 5
!text " RASTER LIGHT, SPRITES AND SID MUSIC"
!byte 13,13,13
!byte 153
!text " CONTROLS"
!byte 13,13
!text " "
!byte 158
!text "1-3"
!byte 5
!text " SPEED "
!byte 158
!text "C"
!byte 5
!text " COLOR "
!byte 158
!text "M"
!byte 5
!text " MUSIC"
!byte 13
!text " "
!byte 158
!text "SPACE"
!byte 5
!text " PAUSE "
!byte 158
!text "Q"
!byte 5
!text " QUIT"
!byte 13,13,13
!byte 5
!text " HTTPS://C64.P20.DEV"
!byte 13,13
!byte 152
!text " RELEASED 16 OCTOBER 2026"
!byte 13,13,13
!byte 158
!text " PRESS SPACE TO START"
!byte 0
; Shared 24x21 single-color sprite: a ringed neon orb.
orb_sprite:
!byte $00,$18,$00,$00,$7e,$00,$01,$ff,$80,$03,$c3,$c0
!byte $07,$81,$e0,$0f,$00,$f0,$1e,$18,$78,$1c,$3c,$38
!byte $38,$7e,$1c,$38,$ff,$1c,$79,$ff,$9e
!byte $38,$ff,$1c,$38,$7e,$1c,$1c,$3c,$38,$1e,$18,$78
!byte $0f,$00,$f0,$07,$81,$e0,$03,$c3,$c0,$01,$ff,$80
!byte $00,$7e,$00,$00,$18,$00,$00
sine_x:
!byte 136,145,154,163,172,181,189,197,204,211,217,223,228,232,235,238
!byte 239,240,239,238,235,232,228,223,217,211,204,197,189,181,172,163
!byte 154,145,136,127,118,109,101,93,86,79,73,67,62,58,55,52
!byte 51,50,51,52,55,58,62,67,73,79,86,93,101,109,118,127
sine_y:
!byte 126,132,138,144,150,156,161,166,171,175,179,182,185,187,189,190
!byte 190,190,189,187,185,182,179,175,171,166,161,156,150,144,138,132
!byte 126,120,114,108,102,96,91,86,81,77,73,70,67,65,63,62
!byte 62,62,63,65,67,70,73,77,81,86,91,96,102,108,114,120
raster_lines: !byte 56,78,100,122,144,166,188,210
raster_colors:
!byte 6,11,4,14,3,13,1,13
!byte 0,9,2,8,7,1,7,8
!byte 0,6,14,3,1,3,14,6
!byte 0,11,12,15,1,15,12,11
sprite_colors: !byte 3,14,1,13,7,10,8,2
scroller_colors: !byte 3,14,7,10,13,1,8,2
note_lo: !byte $c4,$22,$81,$e1,$4b,$b8,$2a,$a1
note_hi: !byte $10,$13,$15,$18,$1b,$1e,$22,$26
lead_notes: !byte 0,2,4,2,5,4,2,1,0,2,4,6,5,4,2,1
bass_notes: !byte 0,0,0,0,3,3,3,3,5,5,5,5,3,3,1,1
drum_steps: !byte 1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0
scroll_message:
!scr " NEON RIFT RASTER LIGHT MEETS EIGHT ORBITING SPRITES AND THREE VOICES OF SID GREETINGS FROM C64.P20.DEV "
!byte 0
star_positions_lo:
!byte <($0400+2*40+2),<($0400+5*40+7),<($0400+8*40+12),<($0400+11*40+17),<($0400+14*40+22),<($0400+17*40+27),<($0400+20*40+32)
!byte <($0400+3*40+37),<($0400+6*40+4),<($0400+9*40+9),<($0400+12*40+14),<($0400+15*40+19),<($0400+18*40+24),<($0400+21*40+29)
!byte <($0400+4*40+34),<($0400+7*40+6),<($0400+10*40+11),<($0400+13*40+16),<($0400+16*40+21),<($0400+19*40+26),<($0400+22*40+31)
!byte <($0400+2*40+36),<($0400+8*40+5),<($0400+14*40+15),<($0400+20*40+25),<($0400+6*40+35),<($0400+12*40+10),<($0400+18*40+30)
star_positions_hi:
!byte >($0400+2*40+2),>($0400+5*40+7),>($0400+8*40+12),>($0400+11*40+17),>($0400+14*40+22),>($0400+17*40+27),>($0400+20*40+32)
!byte >($0400+3*40+37),>($0400+6*40+4),>($0400+9*40+9),>($0400+12*40+14),>($0400+15*40+19),>($0400+18*40+24),>($0400+21*40+29)
!byte >($0400+4*40+34),>($0400+7*40+6),>($0400+10*40+11),>($0400+13*40+16),>($0400+16*40+21),>($0400+19*40+26),>($0400+22*40+31)
!byte >($0400+2*40+36),>($0400+8*40+5),>($0400+14*40+15),>($0400+20*40+25),>($0400+6*40+35),>($0400+12*40+10),>($0400+18*40+30)
star_rows: !byte 2,5,8,11,14,17,20,3,6,9,12,15,18,21,4,7,10,13,16,19,22,2,8,14,20,6,12,18
star_cols: !byte 2,7,12,17,22,27,32,37,4,9,14,19,24,29,34,6,11,16,21,26,31,36,5,15,25,35,10,30
motion_phase: !byte 0
motion_tick: !byte 0
motion_speed: !byte 0
object_index: !byte 0
position_temp: !byte 0
palette: !byte 0
palette_base: !byte 0
band_index: !byte 0
scroll_tick: !byte 0
scroll_fine: !byte 0
scroll_position: !byte 0
music_tick: !byte 0
music_step: !byte 0
music_muted: !byte 0
paused: !byte 0
quit_flag: !byte 0
old_border: !byte 0
old_background: !byte 0
old_sprite_enable: !byte 0
old_d016: !byte 0
old_multicolor: !byte 0
old_sprite_mc0: !byte 0
old_sprite_mc1: !byte 0
old_sprite_msb: !byte 0
old_positions: !fill 16,0
old_sprite_colors: !fill 8,0
old_sprite_pointers: !fill 8,0
old_sid: !fill 25,0

BIN
neon-rift/neon-rift.prg Normal file

Binary file not shown.

View file

@ -184,5 +184,11 @@
"description": "Fill the screen with a flowing field of color generated in real time.", "description": "Fill the screen with a flowing field of color generated in real time.",
"controls": [{"keys":["1","2","3"],"description":"Select slow, medium, or fast animation"},{"keys":["C"],"description":"Change color palette"},{"keys":["SPACE"],"description":"Pause or resume the animation"},{"keys":["Q"],"description":"Return to BASIC"}], "controls": [{"keys":["1","2","3"],"description":"Select slow, medium, or fast animation"},{"keys":["C"],"description":"Change color palette"},{"keys":["SPACE"],"description":"Pause or resume the animation"},{"keys":["Q"],"description":"Return to BASIC"}],
"path": "plasma-grid/plasma-grid.prg", "source": "plasma-grid/plasma-grid.asm" "path": "plasma-grid/plasma-grid.prg", "source": "plasma-grid/plasma-grid.asm"
},
{
"title": "Neon Rift", "category": "Demo", "language": "machine-code", "releaseDate": "2026-10-16",
"description": "Enter a raster-lit world of orbiting sprites, smooth scrolling, and a three-voice SID score.",
"controls": [{"keys":["1","2","3"],"description":"Select slow, medium, or fast motion"},{"keys":["C"],"description":"Change the visual palette"},{"keys":["M"],"description":"Mute or restore the SID track"},{"keys":["SPACE"],"description":"Pause or resume the demo"},{"keys":["Q"],"description":"Return to BASIC"}],
"path": "neon-rift/neon-rift.prg", "source": "neon-rift/neon-rift.asm"
} }
] ]

View file

@ -12,7 +12,8 @@ for source in \
typing-sprint/typing-sprint.asm \ typing-sprint/typing-sprint.asm \
petscii-aquarium/petscii-aquarium.asm \ petscii-aquarium/petscii-aquarium.asm \
fifteen-puzzle/fifteen-puzzle.asm \ fifteen-puzzle/fifteen-puzzle.asm \
plasma-grid/plasma-grid.asm plasma-grid/plasma-grid.asm \
neon-rift/neon-rift.asm
do do
output="${source%.asm}.prg" output="${source%.asm}.prg"
echo "Assembling $source -> $output" echo "Assembling $source -> $output"