multiplayer support

This commit is contained in:
2026-07-15 23:00:52 +02:00
parent c7da1be163
commit aa44c389ba
5 changed files with 232 additions and 20 deletions
+8 -2
View File
@@ -10,12 +10,18 @@ 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.
In **multiplayer** the rabbits still spawn on their own, but player 2
steers the closest one left and right, trying to run the scooter down.
## Controls
| Input | Action |
|-------|--------|
| Joystick port 2 left/right, or `A` / `D` | change lane (auto-repeats while held) |
| Fire (or `SPACE`) | start / retry |
| 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 |
| 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 |
## How it works
+48 -5
View File
@@ -206,11 +206,49 @@ rj_noright:
lda joyb
rts
; fire or space held? returns A != 0 when pressed
; read joystick port 1 merged with the j/l keys (player 2),
; return active-high bits in A and joyb2
read_joy2:
lda #$ff ; no column selected: port B = joystick 1
sta CIA1_PA
lda CIA1_PB
eor #$ff
and #$1f
sta joyb2
and #$0f ; a held direction grounds the same port B
bne rj2_done ; lines the key rows use: skip the scan
lda #$ef ; 'j' = left: keyboard column 4, row bit 2
sta CIA1_PA
lda CIA1_PB
and #$04
bne rj2_noleft
lda joyb2
ora #JOY_LEFT
sta joyb2
rj2_noleft:
lda #$df ; 'l' = right: keyboard column 5, row bit 2
sta CIA1_PA
lda CIA1_PB
and #$04
bne rj2_done
lda joyb2
ora #JOY_RIGHT
sta joyb2
rj2_done:
lda joyb2
rts
; fire on either stick or space held? returns A != 0 when pressed
start_pressed:
jsr read_joy
and #JOY_FIRE
bne sp_done
lda #$ff ; deselect the columns: port B = joystick 1
sta CIA1_PA
lda CIA1_PB
eor #$ff
and #JOY_FIRE
bne sp_done
lda #$7f ; space: keyboard column 7, row bit 4
sta CIA1_PA
lda CIA1_PB
@@ -546,12 +584,14 @@ txt_score: !scr "score"
txt_miss: !scr "miss"
txt_rabbit: !scr "rabbit"
txt_scooter: !scr "scooter"
txt_press: !scr "fire = start game"
txt_info: !scr "joystick 2 or a/d moves"
txt_1p: !scr "single player"
txt_2p: !scr "multiplayer"
txt_info: !scr "p1: joystick 2 or a/d"
txt_info2: !scr "p2: joystick 1 or j/l"
txt_ttgname: !scr "teletype games"
txt_presents:!scr "presents"
txt_over: !scr "game over"
txt_retry: !scr "fire = retry"
txt_return: !scr "fire = return"
txt_blank: !fill 19, $20
washtbl: ; gold glow ramp (16 entries, cyclic)
@@ -565,7 +605,10 @@ bg_top: !byte COL_SKY ; background color above / below the
bg_bot: !byte COL_GRASS ; horizon raster split
seed: !byte $a7 ; rand8 LFSR state
fheld: !byte 0 ; fire/space edge detection state
joyb: !byte 0 ; joystick bits from read_joy (active high)
joyb: !byte 0 ; player 1 input bits from read_joy
joyb2: !byte 0 ; player 2 input bits from read_joy2
mp_mode: !byte 0 ; 0 = single player, 1 = multiplayer
k12held: !byte 0 ; menu '1'/'2' key edge detection state
en_sh: !byte 0 ; per-frame sprite register shadows
msb_sh: !byte 0
xex_sh: !byte 0
+4 -4
View File
@@ -32,17 +32,17 @@ over_init:
rts
over_update:
; blink the retry prompt
; blink the return prompt
lda framectr
and #32
bne ou_hide
+prtext 16, 14, YELLOW, txt_retry, 12
+prtext 16, 13, YELLOW, txt_return, 13
jmp ou_start
ou_hide:
+prtext 16, 14, YELLOW, txt_blank, 12
+prtext 16, 13, YELLOW, txt_blank, 13
ou_start:
jsr start_edge
beq ou_done
jmp play_init ; its rts returns to the main loop
jmp title_init ; back to the menu, mode can be re-picked
ou_done:
rts
+80
View File
@@ -27,6 +27,8 @@ play_init:
sta spawnt
sta lcnt
sta rcnt
sta p2lcnt
sta p2rcnt
jsr draw_score
lda #0 ; draw_score leaves a digit code in A
@@ -113,6 +115,52 @@ pu_rrel:
sta rcnt
pu_rend:
; -- multiplayer: player 2 steers the closest rabbit --
lda mp_mode
beq pu_nop2
jsr read_joy2
lda joyb2
and #JOY_LEFT
beq pu_p2lrel
inc p2lcnt
lda p2lcnt
cmp #1
beq pu_p2lmove
cmp #REP_HOLD+REP_PERIOD
bne pu_p2lend
lda #REP_HOLD
sta p2lcnt
pu_p2lmove:
lda #$ff ; one lane to the left
sta rtmp2
jsr steer_closest
jmp pu_p2lend
pu_p2lrel:
lda #0
sta p2lcnt
pu_p2lend:
lda joyb2
and #JOY_RIGHT
beq pu_p2rrel
inc p2rcnt
lda p2rcnt
cmp #1
beq pu_p2rmove
cmp #REP_HOLD+REP_PERIOD
bne pu_p2rend
lda #REP_HOLD
sta p2rcnt
pu_p2rmove:
lda #1 ; one lane to the right
sta rtmp2
jsr steer_closest
jmp pu_p2rend
pu_p2rrel:
lda #0
sta p2rcnt
pu_p2rend:
pu_nop2:
; -- shadow init: player sprite bit + its x MSB --
ldx player_lane
lda pxlo,x
@@ -197,6 +245,36 @@ pu_rnext:
pu_done:
rts
; ---- shift the closest live rabbit's lane by rtmp2 (+/-1) ----
steer_closest:
ldx #$ff ; best slot so far
lda #0
sta rtmp ; best t so far
ldy #NRABBITS-1
stc_find:
lda r_act,y
beq stc_next
lda r_thi,y
cmp rtmp
bcc stc_next
sta rtmp
tya
tax
stc_next:
dey
bpl stc_find
cpx #$ff
beq stc_done ; no rabbit on the road
lda r_lane,x
clc
adc rtmp2
bmi stc_done ; already on the leftmost lane
cmp #LANES
bcs stc_done ; ... or the rightmost one
sta r_lane,x
stc_done:
rts
; ---- claim a free rabbit slot and roll its lane + speed ----
spawn_rabbit:
ldx #NRABBITS-1
@@ -298,6 +376,8 @@ 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
p2lcnt: !byte 0 ; the same for player 2's steering
p2rcnt: !byte 0
; ---- rabbit slots (hardware sprites 1-7) ----
r_act: !fill NRABBITS, 0
+92 -9
View File
@@ -1,7 +1,7 @@
; -----------------------------------------------------------
; title.asm - full-screen menu card: big RABBIT / SCOOTER
; logo flanked by two hopping rabbits, the scooter waiting at
; the bottom, blinking "fire = start game"
; logo flanked by two hopping rabbits, single/multiplayer
; picker (joystick up/down + fire, or the 1 / 2 keys)
; -----------------------------------------------------------
title_init:
@@ -12,7 +12,8 @@ title_init:
+prbig 2, 8, RED, txt_rabbit, 6
+prbig 8, 6, WHITE, txt_scooter, 7
+prtext 18, 8, WHITE, txt_info, 23
+prtext 18, 9, LGREY, txt_info, 21
+prtext 19, 9, LGREY, txt_info2, 21
; decoration: white rabbits flank the logo (sprites 1-2,
; double-sized), the red scooter waits at the bottom
@@ -65,17 +66,99 @@ title_update:
adc #SPRP_BIG
sta SPRPTR+2
; blink the start line
; joystick up/down picks the mode
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
lda #1
sta mp_mode
tu_nodown:
; the 's' / 'm' keys pick the mode (fire still starts)
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
tu_nos:
lda #$ef ; 'm': keyboard column 4, row bit 4
sta CIA1_PA
lda CIA1_PB
and #$10
bne tu_nom
lda #1
sta mp_mode
tu_nom:
; the 1 / 2 keys pick and start right away (edge detected)
lda #$7f ; keyboard column 7: '1' = bit 0, '2' = bit 3
sta CIA1_PA
lda CIA1_PB
and #$09
cmp #$09
beq tu_keyup ; neither key held
ldx k12held
bne tu_menu ; still held from an earlier frame
inx
stx k12held
and #$01
bne tu_key2
lda #0
sta mp_mode
jmp title_go
tu_key2:
lda #1
sta mp_mode
jmp title_go
tu_keyup:
lda #0
sta k12held
tu_menu:
; 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
lda framectr
and #32
bne tu_hide
+prtext 15, 11, YELLOW, txt_press, 17
and #16
bne tu_start
lda mp_mode
bne tm_cur2
lda #62 ; '>'
sta SCREEN+14*40+12
lda #YELLOW
sta COLRAM+14*40+12
jmp tu_start
tu_hide:
+prtext 15, 11, YELLOW, txt_blank, 17
tm_cur2:
lda #62
sta SCREEN+16*40+12
lda #YELLOW
sta COLRAM+16*40+12
tu_start:
; fire or space starts the picked mode
jsr start_edge
beq tu_done
title_go:
jmp play_init ; its rts returns to the main loop
tu_done:
rts