initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
.claude
|
||||||
|
*.prg
|
||||||
Vendored
+45
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "deps",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make deps",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make build",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "run",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make run",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "clear",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make clear",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "rebuild",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make rebuild",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "rebuildrun",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make rebuildrun",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
ASM = acme
|
||||||
|
EMU = x64sc
|
||||||
|
SRC = main.asm
|
||||||
|
SRCS = $(wildcard *.asm)
|
||||||
|
TARGET = rabbit.prg
|
||||||
|
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
|
||||||
|
.PHONY: build run clear rebuild rebuildrun deps
|
||||||
|
|
||||||
|
deps:
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
@command -v brew >/dev/null 2>&1 || { echo "Homebrew kell ehhez. Telepitsd: https://brew.sh"; exit 1; }
|
||||||
|
brew install acme vice
|
||||||
|
else
|
||||||
|
@echo "A 'deps' target csak macOS-en (Darwin) automatikus. Detektalt OS: $(UNAME_S)"
|
||||||
|
@echo "Telepitsd kezzel: acme assembler + VICE emulator (x64sc)."
|
||||||
|
@exit 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(SRCS)
|
||||||
|
$(ASM) -f cbm -o $(TARGET) $(SRC)
|
||||||
|
|
||||||
|
run: build
|
||||||
|
$(EMU) $(TARGET)
|
||||||
|
|
||||||
|
clear:
|
||||||
|
rm -f $(TARGET)
|
||||||
|
|
||||||
|
rebuild: clear build
|
||||||
|
|
||||||
|
rebuildrun: clear build run
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Rabbit Scooter — C64
|
||||||
|
|
||||||
|
A Commodore 64 port of [rabbitroller](../rabbitroller), the Game & Watch
|
||||||
|
style LCD mini game, written in 6502 assembly (built with the ACME
|
||||||
|
assembler, using the same toolchain and layout as [c64-demo](../c64-demo)).
|
||||||
|
|
||||||
|
Rabbits hop toward you on a five-lane road. Steer your scooter left and
|
||||||
|
right to dodge them: a rabbit that reaches your lane is a **miss**, one
|
||||||
|
that passes in any other lane is a **point**. Three misses end the round.
|
||||||
|
The spawn rate and the rabbits' speed ramp up with your score, just like
|
||||||
|
in the original.
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
| Input | Action |
|
||||||
|
|-------|--------|
|
||||||
|
| Joystick port 2 left/right | change lane (auto-repeats while held) |
|
||||||
|
| Fire (or `SPACE`) | start / retry |
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
- PAL frame loop synced by polling the raster beam (no interrupts), one
|
||||||
|
state update per frame — title, play and game over are `updvec` states.
|
||||||
|
- The player is hardware sprite 0; up to seven rabbits live on sprites
|
||||||
|
1–7. Rabbits follow the road's perspective: a linear y ramp and a t²
|
||||||
|
horizontal fan-out, both precomputed into tables at assembly time
|
||||||
|
(`tables.asm`). Far rabbits use small sprite frames, near ones switch
|
||||||
|
to big frames and finally to double-sized expanded sprites.
|
||||||
|
- Random lanes and speeds come from an 8-bit LFSR stirred with the
|
||||||
|
free-running CIA timer.
|
||||||
|
- Sprite art sits below `$1000` so the VIC never sees the character ROM
|
||||||
|
shadow instead of it.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Contents |
|
||||||
|
|------|----------|
|
||||||
|
| `main.asm` | BASIC stub, init, frame loop, state dispatch |
|
||||||
|
| `defs.asm` | registers, constants, zero page, macros |
|
||||||
|
| `title.asm` | title screen: logo, parked scooters, demo rabbits |
|
||||||
|
| `play.asm` | gameplay: input, spawning, scoring, HUD |
|
||||||
|
| `over.asm` | game over box + retry |
|
||||||
|
| `common.asm` | shared routines: printing, road, input, RNG, rabbit positioning |
|
||||||
|
| `tables.asm` | assembly-time perspective and speed tables |
|
||||||
|
| `sprites.asm` | sprite art (scooter, 4+4 rabbit frames) |
|
||||||
|
|
||||||
|
## Build & run
|
||||||
|
|
||||||
|
```
|
||||||
|
make deps # macOS: brew install acme vice
|
||||||
|
make build # -> rabbit.prg
|
||||||
|
make run # build + launch in VICE (x64sc)
|
||||||
|
```
|
||||||
|
|
||||||
|
The same targets are available as VS Code tasks. A test build that boots
|
||||||
|
straight into gameplay: `acme -DAUTOPLAY=1 -f cbm -o test.prg main.asm`.
|
||||||
+484
@@ -0,0 +1,484 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; common.asm - routines shared by the states: screen drawing,
|
||||||
|
; text printing, input, RNG and the rabbit sprite positioning
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
; ---- clear screen RAM, fill color RAM with black ----
|
||||||
|
clear_screen:
|
||||||
|
ldx #0
|
||||||
|
cls_loop:
|
||||||
|
lda #$20 ; space
|
||||||
|
sta SCREEN,x
|
||||||
|
sta SCREEN+$100,x
|
||||||
|
sta SCREEN+$200,x
|
||||||
|
sta SCREEN+$2e8,x
|
||||||
|
lda #BLACK
|
||||||
|
sta COLRAM,x
|
||||||
|
sta COLRAM+$100,x
|
||||||
|
sta COLRAM+$200,x
|
||||||
|
sta COLRAM+$2e8,x
|
||||||
|
inx
|
||||||
|
bne cls_loop
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- print a text line: txtlo/hi, prow, pcol, pcolor, plen ----
|
||||||
|
print_text:
|
||||||
|
ldx prow
|
||||||
|
lda mul40lo,x
|
||||||
|
clc
|
||||||
|
adc pcol
|
||||||
|
sta scrlo
|
||||||
|
sta collo
|
||||||
|
lda mul40hi,x
|
||||||
|
adc #>SCREEN ; carry still valid from the low-byte add
|
||||||
|
sta scrhi
|
||||||
|
clc
|
||||||
|
adc #$d4 ; COLRAM - SCREEN high byte distance
|
||||||
|
sta colhi
|
||||||
|
ldy #0
|
||||||
|
pt_loop:
|
||||||
|
lda (txtlo),y
|
||||||
|
sta (scrlo),y
|
||||||
|
lda pcolor
|
||||||
|
sta (collo),y
|
||||||
|
iny
|
||||||
|
cpy plen
|
||||||
|
bne pt_loop
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- the road: two diagonals from the horizon apex down to
|
||||||
|
; the screen corners, plus a tree on the left shoulder ----
|
||||||
|
draw_road:
|
||||||
|
ldx #0
|
||||||
|
dr_loop:
|
||||||
|
txa
|
||||||
|
clc
|
||||||
|
adc #6 ; road runs from char row 6 to row 24
|
||||||
|
tay
|
||||||
|
lda mul40lo,y
|
||||||
|
sta scrlo
|
||||||
|
lda mul40hi,y
|
||||||
|
clc
|
||||||
|
adc #>SCREEN
|
||||||
|
sta scrhi
|
||||||
|
stx drtmp
|
||||||
|
lda #19 ; left edge: one column left per row
|
||||||
|
sec
|
||||||
|
sbc drtmp
|
||||||
|
tay
|
||||||
|
lda #$4e ; '/' diagonal
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #20 ; right edge: one column right per row
|
||||||
|
clc
|
||||||
|
adc drtmp
|
||||||
|
tay
|
||||||
|
lda #$4d ; '\' diagonal
|
||||||
|
sta (scrlo),y
|
||||||
|
inx
|
||||||
|
cpx #19
|
||||||
|
bne dr_loop
|
||||||
|
; tree on the left shoulder
|
||||||
|
lda #$51 ; ball
|
||||||
|
sta SCREEN+10*40+3
|
||||||
|
sta SCREEN+11*40+2
|
||||||
|
sta SCREEN+11*40+3
|
||||||
|
sta SCREEN+11*40+4
|
||||||
|
lda #$5d ; trunk
|
||||||
|
sta SCREEN+12*40+3
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- input ----
|
||||||
|
|
||||||
|
; read joystick port 2, return active-high bits in A and joyb
|
||||||
|
read_joy:
|
||||||
|
lda #$ff ; deselect every keyboard column first
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PA
|
||||||
|
eor #$ff
|
||||||
|
and #$1f
|
||||||
|
sta joyb
|
||||||
|
rts
|
||||||
|
|
||||||
|
; fire or space held? returns A != 0 when pressed
|
||||||
|
start_pressed:
|
||||||
|
jsr read_joy
|
||||||
|
and #JOY_FIRE
|
||||||
|
bne sp_done
|
||||||
|
lda #$7f ; space: keyboard column 7, row bit 4
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
and #$10
|
||||||
|
eor #$10
|
||||||
|
sp_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; edge-detected start: A = 1 only on the frame fire/space goes down
|
||||||
|
start_edge:
|
||||||
|
jsr start_pressed
|
||||||
|
beq se_up
|
||||||
|
lda fheld
|
||||||
|
bne se_no
|
||||||
|
lda #1
|
||||||
|
sta fheld
|
||||||
|
rts ; A = 1: fresh press
|
||||||
|
se_up:
|
||||||
|
lda #0
|
||||||
|
sta fheld
|
||||||
|
se_no:
|
||||||
|
lda #0
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- RNG: 8-bit LFSR stirred with the free-running CIA timer
|
||||||
|
; (the timer counts every cycle, so call timing = entropy) ----
|
||||||
|
rand8:
|
||||||
|
lda seed
|
||||||
|
asl
|
||||||
|
bcc r8_tap
|
||||||
|
eor #$1d
|
||||||
|
r8_tap:
|
||||||
|
eor CIA1_TA
|
||||||
|
sta seed
|
||||||
|
rts
|
||||||
|
|
||||||
|
; random lane 0-4
|
||||||
|
rand5:
|
||||||
|
jsr rand8
|
||||||
|
and #7
|
||||||
|
cmp #LANES
|
||||||
|
bcs rand5 ; every retry steps the LFSR, so it terminates
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- write the per-frame sprite register shadows ----
|
||||||
|
write_shadows:
|
||||||
|
lda en_sh
|
||||||
|
sta SPR_EN
|
||||||
|
lda msb_sh
|
||||||
|
sta SPR_MSBX
|
||||||
|
lda xex_sh
|
||||||
|
sta SPR_XEX
|
||||||
|
lda yex_sh
|
||||||
|
sta SPR_YEX
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; rab_pos - place rabbit slot X on hardware sprite X+1
|
||||||
|
; reads r_thi/r_lane, picks size stage + hop frame, writes
|
||||||
|
; the position registers and ORs the shadow bits; keeps X
|
||||||
|
; ============================================================
|
||||||
|
rab_pos:
|
||||||
|
stx rslot
|
||||||
|
lda r_thi,x
|
||||||
|
sta rt
|
||||||
|
lda r_lane,x
|
||||||
|
sta rlane
|
||||||
|
|
||||||
|
; hop offset: 8-entry wave, one hop per 64 t units
|
||||||
|
lda rt
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
and #7
|
||||||
|
tay
|
||||||
|
lda hoptab,y
|
||||||
|
sta rhop
|
||||||
|
|
||||||
|
; animation frame 0-3
|
||||||
|
lda rt
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
and #3
|
||||||
|
sta rfrm
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta rexp
|
||||||
|
lda rt
|
||||||
|
cmp #T_BIG
|
||||||
|
bcs rp_big
|
||||||
|
; -- far: small frames --
|
||||||
|
lda #SPRP_SMALL
|
||||||
|
clc
|
||||||
|
adc rfrm
|
||||||
|
sta rptr
|
||||||
|
lda #12
|
||||||
|
sta ranchor
|
||||||
|
jmp rp_y
|
||||||
|
rp_big:
|
||||||
|
; -- near: big frames, stronger hop --
|
||||||
|
lda #SPRP_BIG
|
||||||
|
clc
|
||||||
|
adc rfrm
|
||||||
|
sta rptr
|
||||||
|
asl rhop
|
||||||
|
lda #12
|
||||||
|
sta ranchor
|
||||||
|
lda rt
|
||||||
|
cmp #T_EXP
|
||||||
|
bcc rp_y
|
||||||
|
; -- closest: the same frames double-sized --
|
||||||
|
lda #1
|
||||||
|
sta rexp
|
||||||
|
lda #24
|
||||||
|
sta ranchor
|
||||||
|
rp_y:
|
||||||
|
; sprite y: feet ride the perspective line (art bottom row)
|
||||||
|
ldy rt
|
||||||
|
lda ytab,y
|
||||||
|
sec
|
||||||
|
sbc rhop
|
||||||
|
sec
|
||||||
|
sbc #21
|
||||||
|
ldx rexp
|
||||||
|
beq rp_ydone
|
||||||
|
sec
|
||||||
|
sbc #21 ; expanded sprite is 42 tall
|
||||||
|
rp_ydone:
|
||||||
|
sta ry
|
||||||
|
|
||||||
|
; x center = ROAD_CX +/- lane offset on the t^2 curve
|
||||||
|
ldy rt
|
||||||
|
lda offtab,y
|
||||||
|
sta roff
|
||||||
|
lda #ROAD_CX
|
||||||
|
sta rxlo
|
||||||
|
lda #0
|
||||||
|
sta rxhi
|
||||||
|
ldy rlane
|
||||||
|
cpy #2
|
||||||
|
beq rp_xdone ; middle lane: stay on the center line
|
||||||
|
bcs rp_right
|
||||||
|
lda roff ; lanes 0-1: left of center
|
||||||
|
cpy #1
|
||||||
|
bne rp_lfull
|
||||||
|
lsr ; lane 1 fans out half as far
|
||||||
|
rp_lfull:
|
||||||
|
sta rtmp
|
||||||
|
lda rxlo
|
||||||
|
sec
|
||||||
|
sbc rtmp ; max offset is 107, never underflows
|
||||||
|
sta rxlo
|
||||||
|
jmp rp_xdone
|
||||||
|
rp_right:
|
||||||
|
lda roff ; lanes 3-4: right of center
|
||||||
|
cpy #3
|
||||||
|
bne rp_rfull
|
||||||
|
lsr
|
||||||
|
rp_rfull:
|
||||||
|
sta rtmp
|
||||||
|
lda rxlo
|
||||||
|
clc
|
||||||
|
adc rtmp
|
||||||
|
sta rxlo
|
||||||
|
lda rxhi
|
||||||
|
adc #0
|
||||||
|
sta rxhi
|
||||||
|
rp_xdone:
|
||||||
|
; sprite left edge = center - anchor (16 bit)
|
||||||
|
lda rxlo
|
||||||
|
sec
|
||||||
|
sbc ranchor
|
||||||
|
sta rxlo
|
||||||
|
lda rxhi
|
||||||
|
sbc #0
|
||||||
|
sta rxhi
|
||||||
|
|
||||||
|
; ---- write the hardware registers + shadow bits ----
|
||||||
|
ldx rslot
|
||||||
|
ldy sprxreg,x
|
||||||
|
lda rxlo
|
||||||
|
sta SPRPOS,y
|
||||||
|
lda ry
|
||||||
|
sta SPRPOS+1,y
|
||||||
|
lda rptr
|
||||||
|
sta SPRPTR+1,x
|
||||||
|
lda sprbit,x
|
||||||
|
ora en_sh
|
||||||
|
sta en_sh
|
||||||
|
lda rxhi
|
||||||
|
beq rp_nomsb
|
||||||
|
lda sprbit,x
|
||||||
|
ora msb_sh
|
||||||
|
sta msb_sh
|
||||||
|
rp_nomsb:
|
||||||
|
lda rexp
|
||||||
|
beq rp_done
|
||||||
|
lda sprbit,x
|
||||||
|
ora xex_sh
|
||||||
|
sta xex_sh
|
||||||
|
lda sprbit,x
|
||||||
|
ora yex_sh
|
||||||
|
sta yex_sh
|
||||||
|
rp_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- draw a text line with big 3x5 block letters ----
|
||||||
|
; txtlo/hi = text (screen codes), bigrow/bigcol = top-left cell,
|
||||||
|
; bigcolor = color, biglen = char count; each letter is 3 cells
|
||||||
|
; wide + 1 gap, 5 cells tall
|
||||||
|
draw_big:
|
||||||
|
lda #0
|
||||||
|
sta bigi
|
||||||
|
db_char:
|
||||||
|
ldy bigi
|
||||||
|
lda (txtlo),y
|
||||||
|
cmp #$20 ; space: leave the cell empty
|
||||||
|
beq db_next
|
||||||
|
tax
|
||||||
|
lda bigmap,x ; screen code -> glyph index
|
||||||
|
sta glyphbase
|
||||||
|
asl ; glyph base = index * 5
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc glyphbase
|
||||||
|
sta glyphbase
|
||||||
|
lda bigi ; cell x = bigcol + charindex * 4
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc bigcol
|
||||||
|
sta charx
|
||||||
|
lda #0
|
||||||
|
sta rowidx
|
||||||
|
db_row:
|
||||||
|
lda bigrow ; row pointers from the row*40 tables
|
||||||
|
clc
|
||||||
|
adc rowidx
|
||||||
|
tax
|
||||||
|
lda mul40lo,x
|
||||||
|
sta scrlo
|
||||||
|
sta collo
|
||||||
|
lda mul40hi,x
|
||||||
|
clc
|
||||||
|
adc #>SCREEN
|
||||||
|
sta scrhi
|
||||||
|
clc
|
||||||
|
adc #$d4
|
||||||
|
sta colhi
|
||||||
|
lda glyphbase
|
||||||
|
clc
|
||||||
|
adc rowidx
|
||||||
|
tax
|
||||||
|
lda bigglyphs,x
|
||||||
|
asl ; 3-bit pattern up to bits 7-5
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
sta curbits
|
||||||
|
ldy charx
|
||||||
|
lda #3
|
||||||
|
sta bitcnt
|
||||||
|
db_bit:
|
||||||
|
asl curbits ; leftmost pixel first
|
||||||
|
bcc db_nobit
|
||||||
|
lda #$a0 ; inverse space = solid block
|
||||||
|
sta (scrlo),y
|
||||||
|
lda bigcolor
|
||||||
|
sta (collo),y
|
||||||
|
db_nobit:
|
||||||
|
iny
|
||||||
|
dec bitcnt
|
||||||
|
bne db_bit
|
||||||
|
inc rowidx
|
||||||
|
lda rowidx
|
||||||
|
cmp #5
|
||||||
|
bne db_row
|
||||||
|
db_next:
|
||||||
|
inc bigi
|
||||||
|
lda bigi
|
||||||
|
cmp biglen
|
||||||
|
beq db_done
|
||||||
|
jmp db_char ; too far for a relative branch
|
||||||
|
db_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- shared tables ----
|
||||||
|
|
||||||
|
; row * 40 lookup tables (25 rows)
|
||||||
|
mul40lo:
|
||||||
|
!byte $00, $28, $50, $78, $a0, $c8, $f0, $18, $40, $68
|
||||||
|
!byte $90, $b8, $e0, $08, $30, $58, $80, $a8, $d0, $f8
|
||||||
|
!byte $20, $48, $70, $98, $c0
|
||||||
|
mul40hi:
|
||||||
|
!byte $00, $00, $00, $00, $00, $00, $00, $01, $01, $01
|
||||||
|
!byte $01, $01, $01, $02, $02, $02, $02, $02, $02, $02
|
||||||
|
!byte $03, $03, $03, $03, $03
|
||||||
|
|
||||||
|
; 3x5 block font for the big title (5 bytes per glyph,
|
||||||
|
; low 3 bits used, MSB side = left)
|
||||||
|
bigglyphs:
|
||||||
|
!byte 0, 0, 0, 0, 0 ; 0 space
|
||||||
|
!byte 2, 5, 7, 5, 5 ; 1 A
|
||||||
|
!byte 3, 4, 4, 4, 3 ; 2 C
|
||||||
|
!byte 6, 5, 5, 5, 6 ; 3 D
|
||||||
|
!byte 7, 4, 6, 4, 7 ; 4 E
|
||||||
|
!byte 7, 4, 6, 4, 4 ; 5 F
|
||||||
|
!byte 7, 2, 2, 2, 7 ; 6 I
|
||||||
|
!byte 4, 4, 4, 4, 7 ; 7 L
|
||||||
|
!byte 5, 7, 7, 5, 5 ; 8 M
|
||||||
|
!byte 6, 5, 5, 5, 5 ; 9 N
|
||||||
|
!byte 7, 5, 5, 5, 7 ; 10 O
|
||||||
|
!byte 6, 5, 6, 4, 4 ; 11 P
|
||||||
|
!byte 6, 5, 6, 5, 5 ; 12 R
|
||||||
|
!byte 3, 4, 2, 1, 6 ; 13 S
|
||||||
|
!byte 7, 2, 2, 2, 2 ; 14 T
|
||||||
|
!byte 5, 5, 2, 2, 2 ; 15 Y
|
||||||
|
!byte 3, 4, 5, 5, 7 ; 16 G
|
||||||
|
!byte 6, 5, 6, 5, 6 ; 17 B
|
||||||
|
|
||||||
|
bigmap: ; screen code (a=1..z=26) -> glyph index
|
||||||
|
!byte 0 ; (unused)
|
||||||
|
!byte 1, 17, 2, 3, 4, 5, 16, 0, 6, 0 ; a-j
|
||||||
|
!byte 0, 7, 8, 9, 10, 11, 0, 12, 13, 14 ; k-t
|
||||||
|
!byte 0, 0, 0, 0, 15, 0 ; u-z
|
||||||
|
|
||||||
|
; ---- texts (screen codes) ----
|
||||||
|
txt_score: !scr "score"
|
||||||
|
txt_miss: !scr "miss"
|
||||||
|
txt_rabbit: !scr "rabbit"
|
||||||
|
txt_scooter: !scr "scooter"
|
||||||
|
txt_press: !scr "press fire to start"
|
||||||
|
txt_info: !scr "joystick 2 moves fire starts"
|
||||||
|
txt_over: !scr "game over"
|
||||||
|
txt_retry: !scr "fire = retry"
|
||||||
|
txt_blank: !fill 19, $20
|
||||||
|
|
||||||
|
; ---- shared variables ----
|
||||||
|
framectr: !byte 0 ; frame counter, incremented by the main loop
|
||||||
|
seed: !byte $a7 ; rand8 LFSR state
|
||||||
|
fheld: !byte 0 ; fire/space edge detection state
|
||||||
|
joyb: !byte 0 ; joystick bits from read_joy (active high)
|
||||||
|
en_sh: !byte 0 ; per-frame sprite register shadows
|
||||||
|
msb_sh: !byte 0
|
||||||
|
xex_sh: !byte 0
|
||||||
|
yex_sh: !byte 0
|
||||||
|
prow: !byte 0 ; print_text: row, column, color, length
|
||||||
|
pcol: !byte 0
|
||||||
|
pcolor: !byte 0
|
||||||
|
plen: !byte 0
|
||||||
|
bigrow: !byte 0 ; draw_big: row, column, color, length
|
||||||
|
bigcol: !byte 0
|
||||||
|
bigcolor: !byte 0
|
||||||
|
biglen: !byte 0
|
||||||
|
bigi: !byte 0 ; draw_big internals
|
||||||
|
glyphbase: !byte 0
|
||||||
|
charx: !byte 0
|
||||||
|
rowidx: !byte 0
|
||||||
|
bitcnt: !byte 0
|
||||||
|
curbits: !byte 0
|
||||||
|
drtmp: !byte 0 ; draw_road internals
|
||||||
|
rslot: !byte 0 ; rab_pos internals
|
||||||
|
rt: !byte 0
|
||||||
|
rlane: !byte 0
|
||||||
|
rhop: !byte 0
|
||||||
|
rfrm: !byte 0
|
||||||
|
rexp: !byte 0
|
||||||
|
rptr: !byte 0
|
||||||
|
ranchor: !byte 0
|
||||||
|
roff: !byte 0
|
||||||
|
rxlo: !byte 0
|
||||||
|
rxhi: !byte 0
|
||||||
|
ry: !byte 0
|
||||||
|
rtmp: !byte 0
|
||||||
|
rtmp2: !byte 0
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; defs.asm - hardware registers, constants, zero page, macros
|
||||||
|
; included first by main.asm
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
; ---- hardware registers ----
|
||||||
|
RASTER = $d012 ; current raster line
|
||||||
|
BORDER = $d020 ; border color register
|
||||||
|
BG = $d021 ; background color register
|
||||||
|
SCREEN = $0400 ; screen RAM (40x25 chars)
|
||||||
|
COLRAM = $d800 ; color RAM
|
||||||
|
SPRPTR = $07f8 ; sprite pointers (screen RAM + $3f8)
|
||||||
|
CIA1_PA = $dc00 ; CIA1 port A: keyboard columns / joystick 2
|
||||||
|
CIA1_PB = $dc01 ; CIA1 port B: keyboard matrix row read
|
||||||
|
CIA1_TA = $dc04 ; CIA1 timer A low byte: free-running entropy
|
||||||
|
|
||||||
|
; ---- 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
|
||||||
|
LGREY = 15
|
||||||
|
|
||||||
|
; ---- joystick port 2 bits (after read_joy, active high) ----
|
||||||
|
JOY_LEFT = 4
|
||||||
|
JOY_RIGHT = 8
|
||||||
|
JOY_FIRE = 16
|
||||||
|
|
||||||
|
; ---- game constants ----
|
||||||
|
LANES = 5
|
||||||
|
NRABBITS = 7 ; rabbit slots, hardware sprites 1-7
|
||||||
|
MAX_MISS = 3
|
||||||
|
ROAD_CX = 184 ; road center in sprite x coordinates
|
||||||
|
PLAYER_SY = 200 ; scooter sprite top (feet on raster line 221)
|
||||||
|
T_BIG = 112 ; rabbit distance where the big frames start
|
||||||
|
T_EXP = 192 ; ... and where the sprite gets double-sized
|
||||||
|
REP_HOLD = 12 ; frames before a held direction auto-repeats
|
||||||
|
REP_PERIOD = 6 ; frames between auto-repeat steps
|
||||||
|
RAS_SYNC = 251 ; raster line polled for the frame sync
|
||||||
|
|
||||||
|
; ---- zero page pointers (same slots as the c64-demo) ----
|
||||||
|
txtlo = $f5 ; text pointer for the print routines (2 bytes)
|
||||||
|
txthi = $f6
|
||||||
|
updvec = $f9 ; state update vector (2 bytes)
|
||||||
|
scrlo = $fb
|
||||||
|
scrhi = $fc
|
||||||
|
collo = $fd
|
||||||
|
colhi = $fe
|
||||||
|
|
||||||
|
; ---- helper macros: print a normal / big text line ----
|
||||||
|
!macro prtext .row, .col, .color, .txt, .len {
|
||||||
|
lda #<.txt
|
||||||
|
sta txtlo
|
||||||
|
lda #>.txt
|
||||||
|
sta txthi
|
||||||
|
lda #.row
|
||||||
|
sta prow
|
||||||
|
lda #.col
|
||||||
|
sta pcol
|
||||||
|
lda #.color
|
||||||
|
sta pcolor
|
||||||
|
lda #.len
|
||||||
|
sta plen
|
||||||
|
jsr print_text
|
||||||
|
}
|
||||||
|
|
||||||
|
!macro prbig .row, .col, .color, .txt, .len {
|
||||||
|
lda #<.txt
|
||||||
|
sta txtlo
|
||||||
|
lda #>.txt
|
||||||
|
sta txthi
|
||||||
|
lda #.row
|
||||||
|
sta bigrow
|
||||||
|
lda #.col
|
||||||
|
sta bigcol
|
||||||
|
lda #.color
|
||||||
|
sta bigcolor
|
||||||
|
lda #.len
|
||||||
|
sta biglen
|
||||||
|
jsr draw_big
|
||||||
|
}
|
||||||
|
|
||||||
|
; ---- set the state update vector ----
|
||||||
|
!macro setupd .addr {
|
||||||
|
lda #<.addr
|
||||||
|
sta updvec
|
||||||
|
lda #>.addr
|
||||||
|
sta updvec+1
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; main.asm - RABBIT SCOOTER for the C64
|
||||||
|
; port of the rabbitroller Game & Watch style LCD game:
|
||||||
|
; rabbits hop toward you on a five-lane road, dodge them
|
||||||
|
; on your scooter - a rabbit reaching your lane is a miss,
|
||||||
|
; one passing in another lane is a point; 3 misses = over
|
||||||
|
;
|
||||||
|
; Files:
|
||||||
|
; defs.asm - constants, zero page, macros
|
||||||
|
; title.asm - title screen: demo rabbits + press fire
|
||||||
|
; play.asm - the game itself
|
||||||
|
; over.asm - game over box + retry
|
||||||
|
; common.asm - shared routines, input, rabbit positioning
|
||||||
|
; tables.asm - perspective / speed tables (assembly-time)
|
||||||
|
; sprites.asm - sprite art (scooter, small + big rabbits)
|
||||||
|
;
|
||||||
|
; Build: acme -f cbm -o rabbit.prg main.asm
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
!to "rabbit.prg", cbm
|
||||||
|
|
||||||
|
* = $0801
|
||||||
|
|
||||||
|
; ---- BASIC stub: 10 SYS 2064 ----
|
||||||
|
; so after LOAD"*",8,1 it's enough to type RUN
|
||||||
|
!byte $0c, $08 ; address of next line
|
||||||
|
!byte $0a, $00 ; line number: 10
|
||||||
|
!byte $9e ; SYS token
|
||||||
|
!byte $20, $32, $30, $36, $34 ; " 2064"
|
||||||
|
!byte $00 ; end of line
|
||||||
|
!byte $00, $00 ; end of program
|
||||||
|
|
||||||
|
* = $0810 ; = 2064 in decimal
|
||||||
|
|
||||||
|
!src "defs.asm"
|
||||||
|
|
||||||
|
start:
|
||||||
|
sei ; no KERNAL IRQ - raster polling must not jitter
|
||||||
|
|
||||||
|
; LCD look: black bezel border, pale screen, black artwork
|
||||||
|
lda #BLACK
|
||||||
|
sta BORDER
|
||||||
|
lda #LGREY
|
||||||
|
sta BG
|
||||||
|
|
||||||
|
; sprites: all black, hires, in front of the characters
|
||||||
|
ldx #7
|
||||||
|
sprcol:
|
||||||
|
lda #BLACK
|
||||||
|
sta SPR_COL,x
|
||||||
|
dex
|
||||||
|
bpl sprcol
|
||||||
|
lda #0
|
||||||
|
sta SPR_EN
|
||||||
|
sta SPR_MC
|
||||||
|
sta SPR_PRIO
|
||||||
|
sta SPR_MSBX
|
||||||
|
sta SPR_XEX
|
||||||
|
sta SPR_YEX
|
||||||
|
sta framectr
|
||||||
|
sta fheld
|
||||||
|
|
||||||
|
!ifdef AUTOPLAY { ; test builds boot straight into the game
|
||||||
|
jsr play_init
|
||||||
|
} else {
|
||||||
|
jsr title_init
|
||||||
|
}
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; main loop - one state update per PAL frame, synced to the
|
||||||
|
; raster beam in the lower border
|
||||||
|
; ============================================================
|
||||||
|
main:
|
||||||
|
jsr wait_frame
|
||||||
|
inc framectr
|
||||||
|
jsr rand8 ; stir the RNG once per frame
|
||||||
|
jsr call_update
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
call_update:
|
||||||
|
jmp (updvec) ; each update runs exactly one frame, ends with rts
|
||||||
|
|
||||||
|
; ---- wait for raster line RAS_SYNC (leave it first, so a
|
||||||
|
; fast update cannot run twice in the same frame) ----
|
||||||
|
wait_frame:
|
||||||
|
lda RASTER
|
||||||
|
cmp #RAS_SYNC
|
||||||
|
beq wait_frame
|
||||||
|
wf_hit:
|
||||||
|
lda RASTER
|
||||||
|
cmp #RAS_SYNC
|
||||||
|
bne wf_hit
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; sprite art first: it must stay below $1000, where the VIC
|
||||||
|
; would see the character ROM shadow instead of our RAM
|
||||||
|
; ============================================================
|
||||||
|
!src "sprites.asm"
|
||||||
|
!if * > $1000 {
|
||||||
|
!error "sprite data ran into the char ROM shadow at $1000"
|
||||||
|
}
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; the states and everything they share
|
||||||
|
; ============================================================
|
||||||
|
!src "title.asm"
|
||||||
|
!src "play.asm"
|
||||||
|
!src "over.asm"
|
||||||
|
!src "common.asm"
|
||||||
|
!src "tables.asm"
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; over.asm - game over box over the frozen playfield: final
|
||||||
|
; score + blinking retry prompt, fire restarts the round
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
BOXROW = 10 ; box: rows 10-14, columns 12-27
|
||||||
|
BOXCOL = 12
|
||||||
|
BOXW = 16
|
||||||
|
|
||||||
|
over_init:
|
||||||
|
lda en_sh ; the scooter may be mid-blink: show it
|
||||||
|
ora #1
|
||||||
|
sta SPR_EN
|
||||||
|
|
||||||
|
; box interior + frame, drawn over the frozen road
|
||||||
|
ldx #0
|
||||||
|
oi_row:
|
||||||
|
txa
|
||||||
|
clc
|
||||||
|
adc #BOXROW
|
||||||
|
tay
|
||||||
|
lda mul40lo,y
|
||||||
|
clc
|
||||||
|
adc #BOXCOL
|
||||||
|
sta scrlo
|
||||||
|
lda mul40hi,y
|
||||||
|
adc #>SCREEN
|
||||||
|
sta scrhi
|
||||||
|
ldy #BOXW-1
|
||||||
|
oi_col:
|
||||||
|
jsr box_char
|
||||||
|
sta (scrlo),y
|
||||||
|
dey
|
||||||
|
bpl oi_col
|
||||||
|
inx
|
||||||
|
cpx #5
|
||||||
|
bne oi_row
|
||||||
|
|
||||||
|
+prtext BOXROW+1, 15, BLACK, txt_over, 9
|
||||||
|
+prtext BOXROW+2, 15, BLACK, txt_score, 5
|
||||||
|
|
||||||
|
; final score digits next to the label
|
||||||
|
lda sc_d0
|
||||||
|
ora #48
|
||||||
|
sta SCREEN+(BOXROW+2)*40+21
|
||||||
|
lda sc_d1
|
||||||
|
ora #48
|
||||||
|
sta SCREEN+(BOXROW+2)*40+22
|
||||||
|
lda sc_d2
|
||||||
|
ora #48
|
||||||
|
sta SCREEN+(BOXROW+2)*40+23
|
||||||
|
|
||||||
|
+setupd over_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
; pick the frame/fill character for box row X, column Y (keeps Y)
|
||||||
|
box_char:
|
||||||
|
cpx #0
|
||||||
|
beq bc_top
|
||||||
|
cpx #4
|
||||||
|
beq bc_bottom
|
||||||
|
cpy #0
|
||||||
|
beq bc_side
|
||||||
|
cpy #BOXW-1
|
||||||
|
beq bc_side
|
||||||
|
lda #$20 ; interior: erase the road behind the box
|
||||||
|
rts
|
||||||
|
bc_side:
|
||||||
|
lda #$5d ; vertical bar
|
||||||
|
rts
|
||||||
|
bc_top:
|
||||||
|
cpy #0
|
||||||
|
beq bc_tl
|
||||||
|
cpy #BOXW-1
|
||||||
|
beq bc_tr
|
||||||
|
lda #$40 ; horizontal bar
|
||||||
|
rts
|
||||||
|
bc_tl:
|
||||||
|
lda #$55 ; rounded corners
|
||||||
|
rts
|
||||||
|
bc_tr:
|
||||||
|
lda #$49
|
||||||
|
rts
|
||||||
|
bc_bottom:
|
||||||
|
cpy #0
|
||||||
|
beq bc_bl
|
||||||
|
cpy #BOXW-1
|
||||||
|
beq bc_br
|
||||||
|
lda #$40
|
||||||
|
rts
|
||||||
|
bc_bl:
|
||||||
|
lda #$4a
|
||||||
|
rts
|
||||||
|
bc_br:
|
||||||
|
lda #$4b
|
||||||
|
rts
|
||||||
|
|
||||||
|
over_update:
|
||||||
|
; blink the retry prompt
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne ou_hide
|
||||||
|
+prtext BOXROW+3, 14, BLACK, txt_retry, 12
|
||||||
|
jmp ou_start
|
||||||
|
ou_hide:
|
||||||
|
+prtext BOXROW+3, 14, BLACK, txt_blank, 12
|
||||||
|
ou_start:
|
||||||
|
jsr start_edge
|
||||||
|
beq ou_done
|
||||||
|
jmp play_init ; its rts returns to the main loop
|
||||||
|
ou_done:
|
||||||
|
rts
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; play.asm - the game: lane movement with key-repeat, rabbit
|
||||||
|
; spawning with a score-driven interval, arrivals scored or
|
||||||
|
; counted as a miss, HUD updates
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
; ---- start (or restart) a round ----
|
||||||
|
play_init:
|
||||||
|
jsr clear_screen
|
||||||
|
jsr draw_road
|
||||||
|
|
||||||
|
; HUD: score on the left, miss slots on the right
|
||||||
|
+prtext 0, 1, BLACK, txt_score, 5
|
||||||
|
+prtext 0, 30, BLACK, txt_miss, 4
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta score8
|
||||||
|
sta sc_d0
|
||||||
|
sta sc_d1
|
||||||
|
sta sc_d2
|
||||||
|
sta miss
|
||||||
|
sta flash
|
||||||
|
sta spawnt
|
||||||
|
sta lcnt
|
||||||
|
sta rcnt
|
||||||
|
jsr draw_score
|
||||||
|
|
||||||
|
lda #0 ; draw_score leaves a digit code in A
|
||||||
|
ldx #NRABBITS-1
|
||||||
|
pi_clr:
|
||||||
|
sta r_act,x
|
||||||
|
dex
|
||||||
|
bpl pi_clr
|
||||||
|
|
||||||
|
lda #2 ; start in the middle lane
|
||||||
|
sta player_lane
|
||||||
|
|
||||||
|
; player sprite: scooter, fixed row, rabbits come per frame
|
||||||
|
lda #SPRP_SCOOT
|
||||||
|
sta SPRPTR
|
||||||
|
lda #PLAYER_SY
|
||||||
|
sta SPRPOS+1
|
||||||
|
lda #1
|
||||||
|
sta SPR_EN
|
||||||
|
lda #0
|
||||||
|
sta SPR_XEX
|
||||||
|
sta SPR_YEX
|
||||||
|
|
||||||
|
+setupd play_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- one frame of gameplay ----
|
||||||
|
play_update:
|
||||||
|
jsr read_joy
|
||||||
|
|
||||||
|
; -- left: move on press, then auto-repeat while held --
|
||||||
|
lda joyb
|
||||||
|
and #JOY_LEFT
|
||||||
|
beq pu_lrel
|
||||||
|
inc lcnt
|
||||||
|
lda lcnt
|
||||||
|
cmp #1
|
||||||
|
beq pu_lmove
|
||||||
|
cmp #REP_HOLD+REP_PERIOD
|
||||||
|
bne pu_lend
|
||||||
|
lda #REP_HOLD
|
||||||
|
sta lcnt
|
||||||
|
pu_lmove:
|
||||||
|
lda player_lane
|
||||||
|
beq pu_lend
|
||||||
|
dec player_lane
|
||||||
|
jmp pu_lend
|
||||||
|
pu_lrel:
|
||||||
|
lda #0
|
||||||
|
sta lcnt
|
||||||
|
pu_lend:
|
||||||
|
|
||||||
|
; -- right, same dance --
|
||||||
|
lda joyb
|
||||||
|
and #JOY_RIGHT
|
||||||
|
beq pu_rrel
|
||||||
|
inc rcnt
|
||||||
|
lda rcnt
|
||||||
|
cmp #1
|
||||||
|
beq pu_rmove
|
||||||
|
cmp #REP_HOLD+REP_PERIOD
|
||||||
|
bne pu_rend
|
||||||
|
lda #REP_HOLD
|
||||||
|
sta rcnt
|
||||||
|
pu_rmove:
|
||||||
|
lda player_lane
|
||||||
|
cmp #LANES-1
|
||||||
|
beq pu_rend
|
||||||
|
inc player_lane
|
||||||
|
jmp pu_rend
|
||||||
|
pu_rrel:
|
||||||
|
lda #0
|
||||||
|
sta rcnt
|
||||||
|
pu_rend:
|
||||||
|
|
||||||
|
; -- shadow init: player sprite bit + its x MSB --
|
||||||
|
ldx player_lane
|
||||||
|
lda pxlo,x
|
||||||
|
sta SPRPOS ; sprite 0 x
|
||||||
|
lda pxhi,x
|
||||||
|
sta msb_sh ; lane 4 sits past x=255
|
||||||
|
lda #0
|
||||||
|
sta xex_sh
|
||||||
|
sta yex_sh
|
||||||
|
lda #1
|
||||||
|
sta en_sh
|
||||||
|
|
||||||
|
; -- a hit blinks the scooter for a dozen frames --
|
||||||
|
lda flash
|
||||||
|
beq pu_noflash
|
||||||
|
dec flash
|
||||||
|
lda framectr
|
||||||
|
and #4
|
||||||
|
bne pu_noflash
|
||||||
|
lda #0
|
||||||
|
sta en_sh
|
||||||
|
pu_noflash:
|
||||||
|
|
||||||
|
; -- spawn: interval = 70 - score/2, floor 22 (as the original) --
|
||||||
|
inc spawnt
|
||||||
|
lda score8
|
||||||
|
cmp #96
|
||||||
|
bcc pu_ivcalc
|
||||||
|
lda #22
|
||||||
|
jmp pu_ivgot
|
||||||
|
pu_ivcalc:
|
||||||
|
lsr
|
||||||
|
sta rtmp
|
||||||
|
lda #70
|
||||||
|
sec
|
||||||
|
sbc rtmp
|
||||||
|
pu_ivgot:
|
||||||
|
cmp spawnt
|
||||||
|
bcs pu_nospawn
|
||||||
|
lda #0
|
||||||
|
sta spawnt
|
||||||
|
jsr spawn_rabbit
|
||||||
|
pu_nospawn:
|
||||||
|
|
||||||
|
; -- advance every live rabbit --
|
||||||
|
ldx #NRABBITS-1
|
||||||
|
pu_rab:
|
||||||
|
lda r_act,x
|
||||||
|
beq pu_rnext
|
||||||
|
lda r_tlo,x ; t += speed (8.8 fixed point)
|
||||||
|
clc
|
||||||
|
adc r_splo,x
|
||||||
|
sta r_tlo,x
|
||||||
|
lda r_thi,x
|
||||||
|
adc r_sphi,x
|
||||||
|
sta r_thi,x
|
||||||
|
bcc pu_ralive
|
||||||
|
; arrived at the player line
|
||||||
|
lda #0
|
||||||
|
sta r_act,x
|
||||||
|
lda r_lane,x
|
||||||
|
cmp player_lane
|
||||||
|
beq pu_rhit
|
||||||
|
jsr add_score ; dodged: one point
|
||||||
|
jmp pu_rnext
|
||||||
|
pu_rhit:
|
||||||
|
jsr add_miss ; ran into you
|
||||||
|
jmp pu_rnext
|
||||||
|
pu_ralive:
|
||||||
|
jsr rab_pos
|
||||||
|
pu_rnext:
|
||||||
|
dex
|
||||||
|
bpl pu_rab
|
||||||
|
|
||||||
|
jsr write_shadows
|
||||||
|
|
||||||
|
; -- third miss ends the round --
|
||||||
|
lda miss
|
||||||
|
cmp #MAX_MISS
|
||||||
|
bcc pu_done
|
||||||
|
jmp over_init ; its rts returns to the main loop
|
||||||
|
pu_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- claim a free rabbit slot and roll its lane + speed ----
|
||||||
|
spawn_rabbit:
|
||||||
|
ldx #NRABBITS-1
|
||||||
|
sr_find:
|
||||||
|
lda r_act,x
|
||||||
|
beq sr_got
|
||||||
|
dex
|
||||||
|
bpl sr_find
|
||||||
|
rts ; every slot busy: skip this spawn
|
||||||
|
sr_got:
|
||||||
|
lda #1
|
||||||
|
sta r_act,x
|
||||||
|
jsr rand5
|
||||||
|
sta r_lane,x
|
||||||
|
lda #0
|
||||||
|
sta r_tlo,x
|
||||||
|
sta r_thi,x
|
||||||
|
; speed = $0260 base + random byte + score ramp (tops out at 64)
|
||||||
|
jsr rand8
|
||||||
|
clc
|
||||||
|
adc #$60
|
||||||
|
sta rtmp
|
||||||
|
lda #2
|
||||||
|
adc #0
|
||||||
|
sta rtmp2
|
||||||
|
lda score8
|
||||||
|
cmp #64
|
||||||
|
bcc sr_ramp
|
||||||
|
lda #64
|
||||||
|
sr_ramp:
|
||||||
|
tay
|
||||||
|
lda rtmp
|
||||||
|
clc
|
||||||
|
adc sptab_lo,y
|
||||||
|
sta r_splo,x
|
||||||
|
lda rtmp2
|
||||||
|
adc sptab_hi,y
|
||||||
|
sta r_sphi,x
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- score: bump the decimal digits and the difficulty byte ----
|
||||||
|
add_score:
|
||||||
|
lda score8
|
||||||
|
cmp #$ff
|
||||||
|
beq as_digits
|
||||||
|
inc score8
|
||||||
|
as_digits:
|
||||||
|
inc sc_d2
|
||||||
|
lda sc_d2
|
||||||
|
cmp #10
|
||||||
|
bne draw_score
|
||||||
|
lda #0
|
||||||
|
sta sc_d2
|
||||||
|
inc sc_d1
|
||||||
|
lda sc_d1
|
||||||
|
cmp #10
|
||||||
|
bne draw_score
|
||||||
|
lda #0
|
||||||
|
sta sc_d1
|
||||||
|
inc sc_d0
|
||||||
|
lda sc_d0
|
||||||
|
cmp #10
|
||||||
|
bne draw_score
|
||||||
|
lda #0
|
||||||
|
sta sc_d0
|
||||||
|
; falls through: repaint the three HUD digits
|
||||||
|
draw_score:
|
||||||
|
lda sc_d0
|
||||||
|
ora #48 ; digit screen codes start at 48
|
||||||
|
sta SCREEN+7
|
||||||
|
lda sc_d1
|
||||||
|
ora #48
|
||||||
|
sta SCREEN+8
|
||||||
|
lda sc_d2
|
||||||
|
ora #48
|
||||||
|
sta SCREEN+9
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- miss: X mark on the HUD + blink the scooter ----
|
||||||
|
add_miss:
|
||||||
|
inc miss
|
||||||
|
ldy miss ; Y: the rabbit loop still needs X
|
||||||
|
lda #24 ; 'x'
|
||||||
|
sta SCREEN+34,y ; marks land on columns 35-37
|
||||||
|
lda #12
|
||||||
|
sta flash
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- gameplay variables ----
|
||||||
|
player_lane: !byte 2
|
||||||
|
score8: !byte 0 ; score capped at 255, drives the difficulty
|
||||||
|
sc_d0: !byte 0 ; score digits: hundreds, tens, ones
|
||||||
|
sc_d1: !byte 0
|
||||||
|
sc_d2: !byte 0
|
||||||
|
miss: !byte 0
|
||||||
|
flash: !byte 0 ; frames left of the post-hit blink
|
||||||
|
spawnt: !byte 0 ; frames since the last spawn
|
||||||
|
lcnt: !byte 0 ; held-direction counters for the auto-repeat
|
||||||
|
rcnt: !byte 0
|
||||||
|
|
||||||
|
; ---- rabbit slots (hardware sprites 1-7) ----
|
||||||
|
r_act: !fill NRABBITS, 0
|
||||||
|
r_lane: !fill NRABBITS, 0
|
||||||
|
r_tlo: !fill NRABBITS, 0 ; distance along the lane, 8.8 fixed point
|
||||||
|
r_thi: !fill NRABBITS, 0
|
||||||
|
r_splo: !fill NRABBITS, 0 ; per-rabbit speed, 8.8 fixed point
|
||||||
|
r_sphi: !fill NRABBITS, 0
|
||||||
+231
@@ -0,0 +1,231 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; sprites.asm - hires sprite art, black silhouettes in the
|
||||||
|
; spirit of the original PNGs; one !be24 row per sprite line
|
||||||
|
; (`.` = transparent, `#` = pixel), 64-byte aligned
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
!align 63, 0
|
||||||
|
|
||||||
|
spr_data:
|
||||||
|
SPRP_SCOOT = spr_data DIV 64 ; sprite pointer of the scooter
|
||||||
|
SPRP_SMALL = SPRP_SCOOT + 1 ; 4 far rabbit frames
|
||||||
|
SPRP_BIG = SPRP_SCOOT + 5 ; 4 near rabbit frames
|
||||||
|
|
||||||
|
; ---- rabbit on a scooter, seen from behind ----
|
||||||
|
spr_scooter:
|
||||||
|
!be24 %.........##..##.........
|
||||||
|
!be24 %.........##..##.........
|
||||||
|
!be24 %.........##..##.........
|
||||||
|
!be24 %.........##..##.........
|
||||||
|
!be24 %........########........
|
||||||
|
!be24 %........########........
|
||||||
|
!be24 %........########........
|
||||||
|
!be24 %..........####..........
|
||||||
|
!be24 %....################....
|
||||||
|
!be24 %....##..########..##....
|
||||||
|
!be24 %........########........
|
||||||
|
!be24 %........########........
|
||||||
|
!be24 %.......##########.......
|
||||||
|
!be24 %.......##########.......
|
||||||
|
!be24 %.......##########.......
|
||||||
|
!be24 %.....##############.....
|
||||||
|
!be24 %.....##############.....
|
||||||
|
!be24 %..........####..........
|
||||||
|
!be24 %..........####..........
|
||||||
|
!be24 %..........####..........
|
||||||
|
!be24 %..........####..........
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
; ---- far rabbit, four hop frames (art hugs the bottom row) ----
|
||||||
|
spr_small0:
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %.........#..#...........
|
||||||
|
!be24 %.........#..#...........
|
||||||
|
!be24 %........######..........
|
||||||
|
!be24 %.....##########.........
|
||||||
|
!be24 %....############........
|
||||||
|
!be24 %.....##########.........
|
||||||
|
!be24 %....##...##...##........
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
spr_small1:
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %.........#..#...........
|
||||||
|
!be24 %.........#..#...........
|
||||||
|
!be24 %........######..........
|
||||||
|
!be24 %.....###########........
|
||||||
|
!be24 %....#############.......
|
||||||
|
!be24 %.....###.....###........
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
spr_small2:
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %..........##............
|
||||||
|
!be24 %..........##............
|
||||||
|
!be24 %........######..........
|
||||||
|
!be24 %.....##########.........
|
||||||
|
!be24 %....############........
|
||||||
|
!be24 %....############........
|
||||||
|
!be24 %......##.....##.........
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
spr_small3:
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %..........#..#..........
|
||||||
|
!be24 %..........#..#..........
|
||||||
|
!be24 %.........######.........
|
||||||
|
!be24 %......###########.......
|
||||||
|
!be24 %.....############.......
|
||||||
|
!be24 %....###.......###.......
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
; ---- near rabbit, four gallop frames (body shared, legs cycle) ----
|
||||||
|
spr_big0: ; stride: legs stretched wide
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %.......###..###.........
|
||||||
|
!be24 %......###########.......
|
||||||
|
!be24 %...###############......
|
||||||
|
!be24 %..#################.....
|
||||||
|
!be24 %..##################....
|
||||||
|
!be24 %...################.....
|
||||||
|
!be24 %....##############......
|
||||||
|
!be24 %...####......#####......
|
||||||
|
!be24 %..####.........####.....
|
||||||
|
!be24 %..###...........####....
|
||||||
|
!be24 %.###.............###....
|
||||||
|
!be24 %.##...............##....
|
||||||
|
!be24 %##.................##...
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
spr_big1: ; gathering the legs
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %.......###..###.........
|
||||||
|
!be24 %......###########.......
|
||||||
|
!be24 %...###############......
|
||||||
|
!be24 %..#################.....
|
||||||
|
!be24 %..##################....
|
||||||
|
!be24 %...################.....
|
||||||
|
!be24 %....##############......
|
||||||
|
!be24 %.....####...#####.......
|
||||||
|
!be24 %.....###.....####.......
|
||||||
|
!be24 %....###.......###.......
|
||||||
|
!be24 %....##.........##.......
|
||||||
|
!be24 %....##.........##.......
|
||||||
|
!be24 %...###.........###......
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
spr_big2: ; tucked into a ball
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %.......###..###.........
|
||||||
|
!be24 %......###########.......
|
||||||
|
!be24 %...###############......
|
||||||
|
!be24 %..#################.....
|
||||||
|
!be24 %..##################....
|
||||||
|
!be24 %...################.....
|
||||||
|
!be24 %....##############......
|
||||||
|
!be24 %.....#####....####......
|
||||||
|
!be24 %......####....###.......
|
||||||
|
!be24 %......###.....###.......
|
||||||
|
!be24 %......###.....###.......
|
||||||
|
!be24 %.....####.....####......
|
||||||
|
!be24 %....#####.....#####.....
|
||||||
|
!byte 0
|
||||||
|
|
||||||
|
spr_big3: ; reaching forward again
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........................
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %........##...##.........
|
||||||
|
!be24 %.......###..###.........
|
||||||
|
!be24 %......###########.......
|
||||||
|
!be24 %...###############......
|
||||||
|
!be24 %..#################.....
|
||||||
|
!be24 %..##################....
|
||||||
|
!be24 %...################.....
|
||||||
|
!be24 %....##############......
|
||||||
|
!be24 %....####......####......
|
||||||
|
!be24 %...####........###......
|
||||||
|
!be24 %..####..........###.....
|
||||||
|
!be24 %..###............###....
|
||||||
|
!be24 %..##..............##....
|
||||||
|
!be24 %.###...............##...
|
||||||
|
!byte 0
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; tables.asm - perspective and speed tables, generated at
|
||||||
|
; assembly time; t is the rabbit's distance (0 = horizon,
|
||||||
|
; 255 = the player's line)
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
; feet y along the lane: linear from the horizon to the player
|
||||||
|
ytab:
|
||||||
|
!for i, 0, 255 {
|
||||||
|
!byte 100 + (111*i) DIV 256
|
||||||
|
}
|
||||||
|
|
||||||
|
; horizontal fan-out on a t^2 curve (full offset of the outer
|
||||||
|
; lanes; the inner lanes use half of it)
|
||||||
|
offtab:
|
||||||
|
!for i, 0, 255 {
|
||||||
|
!byte (107*i*i) DIV 65536
|
||||||
|
}
|
||||||
|
|
||||||
|
; hop wave, subtracted from the feet y (doubled for big rabbits)
|
||||||
|
hoptab:
|
||||||
|
!byte 0, 1, 2, 4, 4, 3, 2, 1
|
||||||
|
|
||||||
|
; speed ramp: score (capped at 64) -> 16-bit speed bonus
|
||||||
|
sptab_lo:
|
||||||
|
!for i, 0, 64 {
|
||||||
|
!byte <(i*13)
|
||||||
|
}
|
||||||
|
sptab_hi:
|
||||||
|
!for i, 0, 64 {
|
||||||
|
!byte >(i*13)
|
||||||
|
}
|
||||||
|
|
||||||
|
; scooter sprite x per lane (lane center - 12); lane 4 crosses
|
||||||
|
; the 8-bit boundary, pxhi is its MSB flag
|
||||||
|
pxlo:
|
||||||
|
!byte 66, 119, 172, 225, 22
|
||||||
|
pxhi:
|
||||||
|
!byte 0, 0, 0, 0, 1
|
||||||
|
|
||||||
|
; rabbit slot -> sprite register offset (sprite = slot + 1)
|
||||||
|
sprxreg:
|
||||||
|
!byte 2, 4, 6, 8, 10, 12, 14
|
||||||
|
|
||||||
|
; rabbit slot -> sprite enable/MSB/expand bit
|
||||||
|
sprbit:
|
||||||
|
!byte 2, 4, 8, 16, 32, 64, 128
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; title.asm - big RABBIT logo over the road, scooters parked
|
||||||
|
; on all five lanes, three demo rabbits hopping in, blinking
|
||||||
|
; "press fire to start"
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
title_init:
|
||||||
|
jsr clear_screen
|
||||||
|
jsr draw_road
|
||||||
|
|
||||||
|
+prbig 1, 8, BLACK, txt_rabbit, 6
|
||||||
|
+prtext 6, 16, BLACK, txt_scooter, 7
|
||||||
|
+prtext 17, 5, BLACK, txt_info, 30
|
||||||
|
|
||||||
|
; one parked scooter per lane on sprites 0-4
|
||||||
|
ldx #4
|
||||||
|
ti_scoot:
|
||||||
|
txa
|
||||||
|
asl
|
||||||
|
tay
|
||||||
|
lda pxlo,x
|
||||||
|
sta SPRPOS,y
|
||||||
|
lda #PLAYER_SY
|
||||||
|
sta SPRPOS+1,y
|
||||||
|
lda #SPRP_SCOOT
|
||||||
|
sta SPRPTR,x
|
||||||
|
dex
|
||||||
|
bpl ti_scoot
|
||||||
|
lda #0
|
||||||
|
sta SPR_XEX
|
||||||
|
sta SPR_YEX
|
||||||
|
|
||||||
|
; demo rabbits on slots 4-6 (sprites 5-7), staggered starts
|
||||||
|
ldx #4
|
||||||
|
ti_demo:
|
||||||
|
jsr rand5
|
||||||
|
sta r_lane,x
|
||||||
|
lda demo_t-4,x
|
||||||
|
sta r_thi,x
|
||||||
|
lda #1
|
||||||
|
sta r_act,x
|
||||||
|
inx
|
||||||
|
cpx #NRABBITS
|
||||||
|
bne ti_demo
|
||||||
|
|
||||||
|
+setupd title_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
title_update:
|
||||||
|
; shadows: five scooters (lane 4 needs the x MSB), no expand
|
||||||
|
lda #%00011111
|
||||||
|
sta en_sh
|
||||||
|
lda #%00010000
|
||||||
|
sta msb_sh
|
||||||
|
lda #0
|
||||||
|
sta xex_sh
|
||||||
|
sta yex_sh
|
||||||
|
|
||||||
|
; demo rabbits: constant lope, respawn on a random lane
|
||||||
|
ldx #4
|
||||||
|
tu_rab:
|
||||||
|
lda r_thi,x
|
||||||
|
clc
|
||||||
|
adc #3
|
||||||
|
sta r_thi,x
|
||||||
|
bcc tu_pos
|
||||||
|
lda #0
|
||||||
|
sta r_thi,x
|
||||||
|
jsr rand5
|
||||||
|
sta r_lane,x
|
||||||
|
tu_pos:
|
||||||
|
jsr rab_pos
|
||||||
|
inx
|
||||||
|
cpx #NRABBITS
|
||||||
|
bne tu_rab
|
||||||
|
|
||||||
|
jsr write_shadows
|
||||||
|
|
||||||
|
; blink the start line
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne tu_hide
|
||||||
|
+prtext 15, 10, BLACK, txt_press, 19
|
||||||
|
jmp tu_start
|
||||||
|
tu_hide:
|
||||||
|
+prtext 15, 10, BLACK, txt_blank, 19
|
||||||
|
tu_start:
|
||||||
|
jsr start_edge
|
||||||
|
beq tu_done
|
||||||
|
jmp play_init ; its rts returns to the main loop
|
||||||
|
tu_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
demo_t: !byte 0, 85, 170
|
||||||
Reference in New Issue
Block a user