initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
*.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,35 @@
|
|||||||
|
steps:
|
||||||
|
- name: version
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- 'apk add --no-cache make'
|
||||||
|
- 'make ci-version'
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
image: debian:stable-slim
|
||||||
|
commands:
|
||||||
|
- 'apt-get update && apt-get install -y --no-install-recommends make acme'
|
||||||
|
- 'make ci-build'
|
||||||
|
|
||||||
|
- name: artifact
|
||||||
|
image: alpine
|
||||||
|
environment:
|
||||||
|
DROPAREA_HOST: vps.teletype.hu
|
||||||
|
DROPAREA_PORT: 2223
|
||||||
|
DROPAREA_TARGET_PATH: /home/drop
|
||||||
|
DROPAREA_USER: drop
|
||||||
|
DROPAREA_SSH_PASSWORD:
|
||||||
|
from_secret: droparea_ssh_password
|
||||||
|
commands:
|
||||||
|
- 'apk add --no-cache make openssh-client sshpass'
|
||||||
|
- 'make ci-artifact'
|
||||||
|
|
||||||
|
- name: update
|
||||||
|
image: alpine
|
||||||
|
environment:
|
||||||
|
UPDATE_SERVER: https://games.vps.teletype.hu
|
||||||
|
UPDATE_SECRET:
|
||||||
|
from_secret: update_secret_key
|
||||||
|
commands:
|
||||||
|
- 'apk add --no-cache make curl'
|
||||||
|
- 'make ci-update'
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# -----------------------------------------
|
||||||
|
# Makefile – C64 project builder (ACME + VICE)
|
||||||
|
# -----------------------------------------
|
||||||
|
|
||||||
|
PROJECT = labyrinth
|
||||||
|
|
||||||
|
ASM = acme
|
||||||
|
EMU = x64sc
|
||||||
|
SRC = main.asm
|
||||||
|
SRCS = $(wildcard *.asm)
|
||||||
|
TARGET ?= $(PROJECT).prg
|
||||||
|
|
||||||
|
METADATA = metadata.json
|
||||||
|
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
|
||||||
|
# CI/CD variables
|
||||||
|
VERSION_FILE = .version
|
||||||
|
DROPAREA_HOST ?= vps.teletype.hu
|
||||||
|
DROPAREA_PORT ?= 2223
|
||||||
|
DROPAREA_TARGET_PATH ?= /home/drop
|
||||||
|
DROPAREA_USER ?= drop
|
||||||
|
UPDATE_SERVER ?= https://games.vps.teletype.hu
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
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) $(PROJECT)-*.prg $(PROJECT)-*.metadata.json $(VERSION_FILE)
|
||||||
|
|
||||||
|
rebuild: clear build
|
||||||
|
|
||||||
|
rebuildrun: clear build run
|
||||||
|
|
||||||
|
# -----------------------------------------
|
||||||
|
# CI/CD Pipeline targets
|
||||||
|
# -----------------------------------------
|
||||||
|
|
||||||
|
ci-version:
|
||||||
|
@VERSION=$$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' $(METADATA) | head -n 1); \
|
||||||
|
if [ -z "$$VERSION" ]; then \
|
||||||
|
echo "ERROR: no \"version\" field in $(METADATA)!"; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
BRANCH=$${CI_COMMIT_BRANCH:-$${WOODPECKER_BRANCH}}; \
|
||||||
|
BRANCH=$$(echo "$$BRANCH" | tr '/' '-'); \
|
||||||
|
if [ "$$BRANCH" != "main" ] && [ "$$BRANCH" != "master" ] && [ -n "$$BRANCH" ]; then \
|
||||||
|
VERSION=dev-$$VERSION-$$BRANCH; \
|
||||||
|
fi; \
|
||||||
|
echo "VERSION is: $$VERSION"; \
|
||||||
|
echo $$VERSION > $(VERSION_FILE)
|
||||||
|
|
||||||
|
ci-build: build
|
||||||
|
@VERSION=$$(cat $(VERSION_FILE)); \
|
||||||
|
echo "==> Creating versioned files for $$VERSION"; \
|
||||||
|
cp $(TARGET) $(PROJECT)-$$VERSION.prg; \
|
||||||
|
cp $(METADATA) $(PROJECT)-$$VERSION.metadata.json; \
|
||||||
|
ls -lh $(PROJECT)-$$VERSION.*
|
||||||
|
|
||||||
|
ci-artifact:
|
||||||
|
@VERSION=$$(cat $(VERSION_FILE)); \
|
||||||
|
echo "==> Uploading artifacts for version $$VERSION"; \
|
||||||
|
SCP_TARGET="$(DROPAREA_USER)@$(DROPAREA_HOST):$(DROPAREA_TARGET_PATH)/"; \
|
||||||
|
sshpass -p "$(DROPAREA_SSH_PASSWORD)" scp -o StrictHostKeyChecking=no -P $(DROPAREA_PORT) \
|
||||||
|
$(PROJECT)-$$VERSION.prg \
|
||||||
|
$(PROJECT)-$$VERSION.metadata.json \
|
||||||
|
$$SCP_TARGET
|
||||||
|
|
||||||
|
ci-update:
|
||||||
|
@VERSION=$$(cat $(VERSION_FILE)); \
|
||||||
|
echo "==> Triggering update for version $$VERSION"; \
|
||||||
|
curl "$(UPDATE_SERVER)/update?secret=$(UPDATE_SECRET)&name=$(PROJECT)&platform=c64&version=$$VERSION"
|
||||||
|
|
||||||
|
.PHONY: all deps build run clear rebuild rebuildrun ci-version ci-build ci-artifact ci-update
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# labyrinth
|
||||||
|
|
||||||
|
Two-player maze duel for the Commodore 64 (ACME + VICE), in the same
|
||||||
|
spirit as [rabbitc64](../rabbitc64).
|
||||||
|
|
||||||
|
A fresh maze is carved every round on a 39x23 lattice where the walls
|
||||||
|
are exactly as wide as the corridors. **Player 1** (joystick 2, or
|
||||||
|
`w a s d`) runs the corridors toward the green diamond exit while
|
||||||
|
dodging the roaming colored enemies. **Player 2** (joystick 1, or
|
||||||
|
`i j k l`) rides the corners of the walls with a blinking cursor -
|
||||||
|
fire (or `return`) spins the four wall pieces around the cursor by
|
||||||
|
90 degrees, reshaping the maze in real time. A spin is denied while
|
||||||
|
anyone is standing in one of the four slots.
|
||||||
|
|
||||||
|
Screens: TTG intro (ported from rabbitc64) -> main menu
|
||||||
|
(play / rules / controls / credits) -> game -> win (back to the menu)
|
||||||
|
or game over (fire retries with a fresh maze, `m` backs out to the
|
||||||
|
menu).
|
||||||
|
|
||||||
|
## Build & run
|
||||||
|
|
||||||
|
```
|
||||||
|
make deps # macOS: brew install acme vice
|
||||||
|
make build # -> labyrinth.prg
|
||||||
|
make run # build + launch in x64sc
|
||||||
|
```
|
||||||
|
|
||||||
|
Test builds can boot straight into one state:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme -DAUTOPLAY=1 -f cbm -o labyrinth.prg main.asm
|
||||||
|
# also: AUTORULES, AUTOCONTROLS, AUTOCREDITS, AUTOWIN, AUTOLOSE
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `main.asm` - entry point, BASIC stub, per-frame state machine
|
||||||
|
- `defs.asm` - registers, constants, zero page, macros
|
||||||
|
- `intro.asm` - TTG boot logo with the gold color wash
|
||||||
|
- `menu.asm` - main menu card
|
||||||
|
- `rules.asm` - how to play
|
||||||
|
- `controls.asm` - joystick + keyboard mappings
|
||||||
|
- `credits.asm` - the crew
|
||||||
|
- `play.asm` - maze generation (recursive backtracker) + the game
|
||||||
|
- `win.asm` / `over.asm` - end screens
|
||||||
|
- `common.asm` - shared routines: printing, big block font, input, RNG
|
||||||
|
- `sound.asm` - single-voice SID SFX driver
|
||||||
+393
@@ -0,0 +1,393 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; common.asm - routines shared by the states: screen drawing,
|
||||||
|
; text printing, big block font, input and the RNG
|
||||||
|
; (ported from rabbitc64, trimmed to what this game needs)
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
; ---- 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
|
||||||
|
|
||||||
|
; ---- set scrlo/hi + collo/hi to the start of char row X ----
|
||||||
|
row_ptr:
|
||||||
|
lda mul40lo,x
|
||||||
|
sta scrlo
|
||||||
|
sta collo
|
||||||
|
lda mul40hi,x
|
||||||
|
clc
|
||||||
|
adc #>SCREEN
|
||||||
|
sta scrhi
|
||||||
|
clc
|
||||||
|
adc #$d4 ; COLRAM - SCREEN high byte distance
|
||||||
|
sta colhi
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- input ----
|
||||||
|
; joystick 1 shares the CIA port B lines the keyboard rows use,
|
||||||
|
; so before any key scan we note which rows the stick itself is
|
||||||
|
; grounding (jmask) and treat those rows as released - a held
|
||||||
|
; joystick 1 direction must not read as a phantom keypress
|
||||||
|
|
||||||
|
; read joystick port 2 merged with w/a/s/d + space (the runner),
|
||||||
|
; active-high bits in A and joyb
|
||||||
|
read_joy:
|
||||||
|
lda #$ff ; deselect every keyboard column first
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
eor #$ff
|
||||||
|
and #$1f
|
||||||
|
sta jmask ; rows grounded by joystick 1 right now
|
||||||
|
lda CIA1_PA
|
||||||
|
eor #$ff
|
||||||
|
and #$1f
|
||||||
|
sta joyb ; joystick 2 bits
|
||||||
|
lda #$fd ; keyboard column 1: w / a / s
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$02 ; 'w' = up: row bit 1
|
||||||
|
bne rj_now
|
||||||
|
lda joyb
|
||||||
|
ora #JOY_UP
|
||||||
|
sta joyb
|
||||||
|
rj_now:
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$04 ; 'a' = left: row bit 2
|
||||||
|
bne rj_noa
|
||||||
|
lda joyb
|
||||||
|
ora #JOY_LEFT
|
||||||
|
sta joyb
|
||||||
|
rj_noa:
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$20 ; 's' = down: row bit 5
|
||||||
|
bne rj_nos
|
||||||
|
lda joyb
|
||||||
|
ora #JOY_DOWN
|
||||||
|
sta joyb
|
||||||
|
rj_nos:
|
||||||
|
lda #$fb ; 'd' = right: keyboard column 2, row bit 2
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$04
|
||||||
|
bne rj_nod
|
||||||
|
lda joyb
|
||||||
|
ora #JOY_RIGHT
|
||||||
|
sta joyb
|
||||||
|
rj_nod:
|
||||||
|
lda #$7f ; space = fire: keyboard column 7, row bit 4
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$10
|
||||||
|
bne rj_nosp
|
||||||
|
lda joyb
|
||||||
|
ora #JOY_FIRE
|
||||||
|
sta joyb
|
||||||
|
rj_nosp:
|
||||||
|
lda #$ff
|
||||||
|
sta CIA1_PA
|
||||||
|
lda joyb
|
||||||
|
rts
|
||||||
|
|
||||||
|
; read joystick port 1 merged with i/j/k/l + return (the wall
|
||||||
|
; spinner), 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 ; joystick 1 bits
|
||||||
|
sta jmask ; ... which also ground the key rows below
|
||||||
|
lda #$ef ; keyboard column 4: i / j / k
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$02 ; 'i' = up: row bit 1
|
||||||
|
bne rk_noi
|
||||||
|
lda joyb2
|
||||||
|
ora #JOY_UP
|
||||||
|
sta joyb2
|
||||||
|
rk_noi:
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$04 ; 'j' = left: row bit 2
|
||||||
|
bne rk_noj
|
||||||
|
lda joyb2
|
||||||
|
ora #JOY_LEFT
|
||||||
|
sta joyb2
|
||||||
|
rk_noj:
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$20 ; 'k' = down: row bit 5
|
||||||
|
bne rk_nok
|
||||||
|
lda joyb2
|
||||||
|
ora #JOY_DOWN
|
||||||
|
sta joyb2
|
||||||
|
rk_nok:
|
||||||
|
lda #$df ; 'l' = right: keyboard column 5, row bit 2
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$04
|
||||||
|
bne rk_nol
|
||||||
|
lda joyb2
|
||||||
|
ora #JOY_RIGHT
|
||||||
|
sta joyb2
|
||||||
|
rk_nol:
|
||||||
|
lda #$fe ; return = fire: keyboard column 0, row bit 1
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
ora jmask
|
||||||
|
and #$02
|
||||||
|
bne rk_noret
|
||||||
|
lda joyb2
|
||||||
|
ora #JOY_FIRE
|
||||||
|
sta joyb2
|
||||||
|
rk_noret:
|
||||||
|
lda #$ff
|
||||||
|
sta CIA1_PA
|
||||||
|
lda joyb2
|
||||||
|
rts
|
||||||
|
|
||||||
|
; fire held on either side? (stick fire, space or return)
|
||||||
|
; returns A != 0 when pressed
|
||||||
|
start_pressed:
|
||||||
|
jsr read_joy
|
||||||
|
and #JOY_FIRE
|
||||||
|
bne sp_done
|
||||||
|
jsr read_joy2
|
||||||
|
and #JOY_FIRE
|
||||||
|
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
|
||||||
|
|
||||||
|
; ---- 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 titles (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
|
||||||
|
!byte 5, 5, 5, 5, 2 ; 18 V
|
||||||
|
!byte 5, 5, 7, 5, 5 ; 19 H
|
||||||
|
!byte 5, 5, 5, 5, 7 ; 20 U
|
||||||
|
!byte 5, 5, 7, 7, 5 ; 21 W
|
||||||
|
|
||||||
|
bigmap: ; screen code (a=1..z=26) -> glyph index
|
||||||
|
!byte 0 ; (unused)
|
||||||
|
!byte 1, 17, 2, 3, 4, 5, 16, 19, 6, 0 ; a-j
|
||||||
|
!byte 0, 7, 8, 9, 10, 11, 0, 12, 13, 14 ; k-t
|
||||||
|
!byte 20, 18, 21, 0, 15, 0 ; u-z
|
||||||
|
|
||||||
|
; ---- shared texts (screen codes) ----
|
||||||
|
txt_title: !scr "labyrinth"
|
||||||
|
txt_ttgname: !scr "teletype games"
|
||||||
|
txt_presents:!scr "presents"
|
||||||
|
txt_return: !scr "fire = return"
|
||||||
|
txt_blank: !fill 16, $20
|
||||||
|
|
||||||
|
washtbl: ; gold glow ramp (16 entries, cyclic)
|
||||||
|
!byte $09, $02, $08, $0a, $07, $07, $01, $01
|
||||||
|
!byte $01, $01, $07, $07, $0a, $08, $02, $09
|
||||||
|
|
||||||
|
; ---- shared variables ----
|
||||||
|
framectr: !byte 0 ; frame counter, incremented by the main loop
|
||||||
|
washphase: !byte 0 ; gold wash offset on the big letters
|
||||||
|
seed: !byte $a7 ; rand8 LFSR state
|
||||||
|
fheld: !byte 0 ; fire/space edge detection state
|
||||||
|
joyb: !byte 0 ; player 1 input bits from read_joy
|
||||||
|
joyb2: !byte 0 ; player 2 input bits from read_joy2
|
||||||
|
jmask: !byte 0 ; key rows grounded by joystick 1 this scan
|
||||||
|
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
|
||||||
|
rtmp: !byte 0 ; scratch
|
||||||
|
rtmp2: !byte 0
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; controls.asm - who steers what: joystick and keyboard
|
||||||
|
; mappings for both players, one static card; fire returns
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
controls_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
+prbig 1, 4, WHITE, txt_controls, 8
|
||||||
|
|
||||||
|
+prtext 8, 9, LGREEN, txt_c1, txt_c1e-txt_c1
|
||||||
|
+prtext 10, 6, WHITE, txt_c2, txt_c2e-txt_c2
|
||||||
|
|
||||||
|
+prtext 13, 6, LBLUE, txt_c3, txt_c3e-txt_c3
|
||||||
|
+prtext 15, 6, WHITE, txt_c4, txt_c4e-txt_c4
|
||||||
|
+prtext 17, 10, WHITE, txt_c5, txt_c5e-txt_c5
|
||||||
|
|
||||||
|
+prtext 20, 5, LGREY, txt_c6, txt_c6e-txt_c6
|
||||||
|
|
||||||
|
+setupd controls_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
controls_update:
|
||||||
|
; blink the return prompt
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne co_hide
|
||||||
|
+prtext 22, 13, YELLOW, txt_return, 13
|
||||||
|
jmp co_input
|
||||||
|
co_hide:
|
||||||
|
+prtext 22, 13, YELLOW, txt_blank, 13
|
||||||
|
co_input:
|
||||||
|
jsr start_edge
|
||||||
|
beq co_stay
|
||||||
|
jmp menu_init
|
||||||
|
co_stay:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- controls texts ----
|
||||||
|
txt_controls: !scr "controls"
|
||||||
|
txt_c1: !scr "player 1 - the runner"
|
||||||
|
txt_c1e:
|
||||||
|
txt_c2: !scr "move: joystick 2 or w a s d"
|
||||||
|
txt_c2e:
|
||||||
|
txt_c3: !scr "player 2 - the wall spinner"
|
||||||
|
txt_c3e:
|
||||||
|
txt_c4: !scr "move: joystick 1 or i j k l"
|
||||||
|
txt_c4e:
|
||||||
|
txt_c5: !scr "spin: fire or return"
|
||||||
|
txt_c5e:
|
||||||
|
txt_c6: !scr "menus: fire, space or return"
|
||||||
|
txt_c6e:
|
||||||
+164
@@ -0,0 +1,164 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; credits.asm - the same crew as rabbitc64, but a new look:
|
||||||
|
; rainbow bars scrolling along the top and bottom edges in
|
||||||
|
; opposite directions, a rainbow sweep across the big
|
||||||
|
; CREDITS, each crew line in its own fixed color and the
|
||||||
|
; ai warning pulsing grey-white (no scroller, no parade)
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
credits_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
; rainbow bars: solid blocks across rows 0 and 24
|
||||||
|
ldx #39
|
||||||
|
ci_bars:
|
||||||
|
lda #$a0
|
||||||
|
sta SCREEN,x
|
||||||
|
sta SCREEN+24*40,x
|
||||||
|
dex
|
||||||
|
bpl ci_bars
|
||||||
|
|
||||||
|
+prbig 2, 6, WHITE, txt_credits, 7
|
||||||
|
|
||||||
|
+prtext 9, 13, WHITE, txt_ttgname, 14
|
||||||
|
|
||||||
|
+prtext 12, 8, YELLOW, txt_crew0, txt_crew0e-txt_crew0
|
||||||
|
+prtext 13, 10, LGREEN, txt_crew1, txt_crew1e-txt_crew1
|
||||||
|
+prtext 14, 9, CYAN, txt_crew2, txt_crew2e-txt_crew2
|
||||||
|
+prtext 15, 10, LRED, txt_crew3, txt_crew3e-txt_crew3
|
||||||
|
|
||||||
|
+prtext 17, 9, LGREY, txt_ai1, txt_ai1e-txt_ai1
|
||||||
|
+prtext 18, 12, LGREY, txt_ai2, txt_ai2e-txt_ai2
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta barphase
|
||||||
|
+setupd credits_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
credits_update:
|
||||||
|
; the edge bars crawl in opposite directions
|
||||||
|
lda framectr
|
||||||
|
and #3
|
||||||
|
bne cu_barsdone
|
||||||
|
inc barphase
|
||||||
|
cu_barsdone:
|
||||||
|
ldx #39
|
||||||
|
cu_bars:
|
||||||
|
txa
|
||||||
|
clc
|
||||||
|
adc barphase
|
||||||
|
and #7
|
||||||
|
tay
|
||||||
|
lda raintbl,y
|
||||||
|
sta COLRAM,x ; top bar: colors drift left
|
||||||
|
lda barphase
|
||||||
|
stx rtmp
|
||||||
|
sec
|
||||||
|
sbc rtmp
|
||||||
|
and #7
|
||||||
|
tay
|
||||||
|
lda raintbl,y
|
||||||
|
sta COLRAM+24*40,x ; bottom bar: colors drift right
|
||||||
|
dex
|
||||||
|
bpl cu_bars
|
||||||
|
|
||||||
|
; rainbow sweep across the big CREDITS (rows 2-6)
|
||||||
|
lda #0
|
||||||
|
sta rtmp2
|
||||||
|
cu_sweep:
|
||||||
|
lda #2
|
||||||
|
clc
|
||||||
|
adc rtmp2
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
lda framectr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
clc
|
||||||
|
adc rtmp2
|
||||||
|
and #7
|
||||||
|
tax
|
||||||
|
lda raintbl,x
|
||||||
|
sta rtmp
|
||||||
|
ldy #32 ; the letters span columns 6-32
|
||||||
|
cu_scol:
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #$a0 ; only touch the letter blocks
|
||||||
|
bne cu_sskip
|
||||||
|
lda rtmp
|
||||||
|
sta (collo),y
|
||||||
|
cu_sskip:
|
||||||
|
dey
|
||||||
|
cpy #5
|
||||||
|
bne cu_scol
|
||||||
|
inc rtmp2
|
||||||
|
lda rtmp2
|
||||||
|
cmp #5
|
||||||
|
bne cu_sweep
|
||||||
|
|
||||||
|
; the ai warning pulses grey-white
|
||||||
|
lda framectr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
and #7
|
||||||
|
tax
|
||||||
|
lda pulsetbl,x
|
||||||
|
sta rtmp
|
||||||
|
ldx #17
|
||||||
|
jsr row_ptr
|
||||||
|
ldy #30
|
||||||
|
cu_p1:
|
||||||
|
lda rtmp
|
||||||
|
sta (collo),y
|
||||||
|
dey
|
||||||
|
cpy #8
|
||||||
|
bne cu_p1
|
||||||
|
ldx #18
|
||||||
|
jsr row_ptr
|
||||||
|
ldy #27
|
||||||
|
cu_p2:
|
||||||
|
lda rtmp
|
||||||
|
sta (collo),y
|
||||||
|
dey
|
||||||
|
cpy #11
|
||||||
|
bne cu_p2
|
||||||
|
|
||||||
|
; blink the return prompt
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne cu_hide
|
||||||
|
+prtext 21, 13, YELLOW, txt_return, 13
|
||||||
|
jmp cu_input
|
||||||
|
cu_hide:
|
||||||
|
+prtext 21, 13, YELLOW, txt_blank, 13
|
||||||
|
cu_input:
|
||||||
|
jsr start_edge
|
||||||
|
beq cu_stay
|
||||||
|
jmp menu_init ; back to the menu
|
||||||
|
cu_stay:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- tables ----
|
||||||
|
pulsetbl: ; grey-white pulse (8 entries, cyclic)
|
||||||
|
!byte $0b, $0c, $0f, $01, $01, $0f, $0c, $0b
|
||||||
|
|
||||||
|
raintbl: ; rainbow ramp
|
||||||
|
!byte $02, $08, $07, $0d, $03, $0e, $04, $0a
|
||||||
|
|
||||||
|
; ---- the crew (content ported from rabbitc64) ----
|
||||||
|
txt_crew0: !scr "mr.zero - tasnadi zsolt"
|
||||||
|
txt_crew0e:
|
||||||
|
txt_crew1: !scr "mr.one - tari balazs"
|
||||||
|
txt_crew1e:
|
||||||
|
txt_crew2: !scr "mr.two - timar zoltan"
|
||||||
|
txt_crew2e:
|
||||||
|
txt_crew3: !scr "mr.three - mezo bela"
|
||||||
|
txt_crew3e:
|
||||||
|
txt_ai1: !scr "warning: this game was"
|
||||||
|
txt_ai1e:
|
||||||
|
txt_ai2: !scr "written by an ai"
|
||||||
|
txt_ai2e:
|
||||||
|
|
||||||
|
; ---- credits variables ----
|
||||||
|
barphase: !byte 0 ; edge bar scroll offset
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; 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
|
||||||
|
SPR_EN = $d015 ; sprite enable bits (parked at 0)
|
||||||
|
CIA1_PA = $dc00 ; CIA1 port A: keyboard columns / joystick 2
|
||||||
|
CIA1_PB = $dc01 ; CIA1 port B: keyboard rows / joystick 1
|
||||||
|
CIA1_TA = $dc04 ; CIA1 timer A low byte: free-running entropy
|
||||||
|
|
||||||
|
; ---- SID registers (single-voice SFX driver) ----
|
||||||
|
SID_V1FL = $d400 ; voice 1 frequency low
|
||||||
|
SID_V1FH = $d401 ; voice 1 frequency high
|
||||||
|
SID_V1PL = $d402 ; voice 1 pulse width low
|
||||||
|
SID_V1PH = $d403 ; voice 1 pulse width high
|
||||||
|
SID_V1CR = $d404 ; voice 1 control (waveform + gate)
|
||||||
|
SID_V1AD = $d405 ; voice 1 attack/decay
|
||||||
|
SID_V1SR = $d406 ; voice 1 sustain/release
|
||||||
|
SID_VOL = $d418 ; filter mode + master volume
|
||||||
|
|
||||||
|
; ---- SFX IDs ----
|
||||||
|
SFX_CURSOR = 0 ; corner cursor step: click
|
||||||
|
SFX_SELECT = 1 ; menu fire: rising tone
|
||||||
|
SFX_ROTATE = 2 ; wall spin: noise whoosh
|
||||||
|
SFX_DENY = 3 ; blocked spin: low buzz
|
||||||
|
SFX_WIN = 4 ; escape: rising jingle
|
||||||
|
SFX_LOSE = 5 ; caught: descending sweep
|
||||||
|
NSFX = 6
|
||||||
|
|
||||||
|
; ---- colors ----
|
||||||
|
BLACK = 0
|
||||||
|
WHITE = 1
|
||||||
|
RED = 2
|
||||||
|
CYAN = 3
|
||||||
|
PURPLE = 4
|
||||||
|
GREEN = 5
|
||||||
|
BLUE = 6
|
||||||
|
YELLOW = 7
|
||||||
|
ORANGE = 8
|
||||||
|
BROWN = 9
|
||||||
|
LRED = 10
|
||||||
|
DGREY = 11
|
||||||
|
MGREY = 12
|
||||||
|
LGREEN = 13
|
||||||
|
LBLUE = 14
|
||||||
|
LGREY = 15
|
||||||
|
|
||||||
|
; ---- joystick bits (after read_joy / read_joy2, active high) ----
|
||||||
|
JOY_UP = 1
|
||||||
|
JOY_DOWN = 2
|
||||||
|
JOY_LEFT = 4
|
||||||
|
JOY_RIGHT = 8
|
||||||
|
JOY_FIRE = 16
|
||||||
|
|
||||||
|
; ---- the maze ----
|
||||||
|
; 19x11 cells on a 39x23 char lattice (screen rows 1-23):
|
||||||
|
; cell = odd column, even row (walkable)
|
||||||
|
; post = even column, odd row (pivot, always solid)
|
||||||
|
; slot = the rest: wall pieces that spin around the posts
|
||||||
|
; wall thickness therefore equals corridor width: one cell
|
||||||
|
MAZE_CW = 19 ; cells across
|
||||||
|
MAZE_CH = 11 ; cells down
|
||||||
|
NCELLS = MAZE_CW * MAZE_CH
|
||||||
|
NENEMIES = 4
|
||||||
|
|
||||||
|
CH_WALL = $a0 ; inverse space: solid wall block
|
||||||
|
CH_FLOOR = $20 ; space: corridor
|
||||||
|
CH_EXIT = $5a ; diamond: the goal
|
||||||
|
CH_PLAYER = $51 ; filled ball: the runner
|
||||||
|
CH_ENEMY = $57 ; open circle: an enemy
|
||||||
|
|
||||||
|
COL_WALL = MGREY ; spinnable wall pieces
|
||||||
|
COL_POST = DGREY ; fixed pivot posts
|
||||||
|
COL_EXIT = LGREEN ; the exit diamond
|
||||||
|
|
||||||
|
; ---- game timing ----
|
||||||
|
REP_HOLD = 10 ; runner: frames before a held dir repeats
|
||||||
|
REP_PERIOD = 5 ; runner: frames between repeat steps
|
||||||
|
CREP_HOLD = 12 ; cursor: same, a touch slower
|
||||||
|
CREP_PERIOD = 7
|
||||||
|
RAS_SYNC = 251 ; raster line polled for the frame sync
|
||||||
|
|
||||||
|
; ---- zero page pointers (same slots as rabbitc64) ----
|
||||||
|
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,146 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; intro.asm - boot screen ported from rabbitc64: giant TTG
|
||||||
|
; letters built from 8x8 bitmaps with a gold color wash
|
||||||
|
; running down them, TELETYPE GAMES / PRESENTS below;
|
||||||
|
; advances to the menu after a few seconds or on fire
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
INTRO_LROW = 3 ; top cell row of the giant letters
|
||||||
|
INTRO_TIME = 250 ; frames before it advances on its own
|
||||||
|
|
||||||
|
intro_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
; T T G at columns 6 / 16 / 26
|
||||||
|
lda #<glyph_t
|
||||||
|
sta txtlo
|
||||||
|
lda #>glyph_t
|
||||||
|
sta txthi
|
||||||
|
lda #6
|
||||||
|
sta g8col
|
||||||
|
jsr draw_glyph8
|
||||||
|
lda #16
|
||||||
|
sta g8col
|
||||||
|
jsr draw_glyph8
|
||||||
|
lda #<glyph_g
|
||||||
|
sta txtlo
|
||||||
|
lda #>glyph_g
|
||||||
|
sta txthi
|
||||||
|
lda #26
|
||||||
|
sta g8col
|
||||||
|
jsr draw_glyph8
|
||||||
|
|
||||||
|
+prtext 13, 13, WHITE, txt_ttgname, 14
|
||||||
|
+prtext 15, 16, LGREY, txt_presents, 8
|
||||||
|
|
||||||
|
lda #INTRO_TIME
|
||||||
|
sta introt
|
||||||
|
lda #0
|
||||||
|
sta washphase
|
||||||
|
+setupd intro_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
intro_update:
|
||||||
|
; gold wash: recolor the letter rows from the cyclic ramp
|
||||||
|
inc washphase
|
||||||
|
lda #0
|
||||||
|
sta g8row
|
||||||
|
iw_row:
|
||||||
|
lda #INTRO_LROW
|
||||||
|
clc
|
||||||
|
adc g8row
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
lda washphase
|
||||||
|
lsr ; half speed keeps the shimmer gentle
|
||||||
|
clc
|
||||||
|
adc g8row
|
||||||
|
and #15
|
||||||
|
tax
|
||||||
|
lda washtbl,x
|
||||||
|
sta rtmp
|
||||||
|
ldy #33 ; the letters span columns 6-33
|
||||||
|
iw_col:
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #$a0 ; only touch the letter blocks
|
||||||
|
bne iw_skip
|
||||||
|
lda rtmp
|
||||||
|
sta (collo),y
|
||||||
|
iw_skip:
|
||||||
|
dey
|
||||||
|
cpy #5
|
||||||
|
bne iw_col
|
||||||
|
inc g8row
|
||||||
|
lda g8row
|
||||||
|
cmp #8
|
||||||
|
bne iw_row
|
||||||
|
|
||||||
|
; fire skips, otherwise wait out the timer
|
||||||
|
jsr start_edge
|
||||||
|
beq iw_tick
|
||||||
|
jmp menu_init
|
||||||
|
iw_tick:
|
||||||
|
dec introt
|
||||||
|
bne iw_done
|
||||||
|
jmp menu_init
|
||||||
|
iw_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- draw an 8x8-cell giant letter: txtlo/hi = 8-byte
|
||||||
|
; bitmap, g8col = left cell column ----
|
||||||
|
draw_glyph8:
|
||||||
|
lda #0
|
||||||
|
sta g8row
|
||||||
|
g8_row:
|
||||||
|
lda #INTRO_LROW
|
||||||
|
clc
|
||||||
|
adc g8row
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
ldy g8row
|
||||||
|
lda (txtlo),y
|
||||||
|
sta curbits
|
||||||
|
ldy g8col
|
||||||
|
lda #8
|
||||||
|
sta bitcnt
|
||||||
|
g8_bit:
|
||||||
|
asl curbits ; leftmost pixel first
|
||||||
|
bcc g8_next
|
||||||
|
lda #$a0 ; inverse space = solid block
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #YELLOW
|
||||||
|
sta (collo),y
|
||||||
|
g8_next:
|
||||||
|
iny
|
||||||
|
dec bitcnt
|
||||||
|
bne g8_bit
|
||||||
|
inc g8row
|
||||||
|
lda g8row
|
||||||
|
cmp #8
|
||||||
|
bne g8_row
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- 8x8 letter bitmaps ----
|
||||||
|
glyph_t:
|
||||||
|
!byte %11111111
|
||||||
|
!byte %11111111
|
||||||
|
!byte %00111100
|
||||||
|
!byte %00111100
|
||||||
|
!byte %00111100
|
||||||
|
!byte %00111100
|
||||||
|
!byte %00111100
|
||||||
|
!byte %00111100
|
||||||
|
glyph_g:
|
||||||
|
!byte %00111100
|
||||||
|
!byte %01111110
|
||||||
|
!byte %11000011
|
||||||
|
!byte %11000000
|
||||||
|
!byte %11001111
|
||||||
|
!byte %11000011
|
||||||
|
!byte %01111110
|
||||||
|
!byte %00111100
|
||||||
|
|
||||||
|
; ---- intro variables ----
|
||||||
|
introt: !byte 0 ; frames left before auto-advancing
|
||||||
|
g8row: !byte 0 ; glyph renderer / wash internals
|
||||||
|
g8col: !byte 0
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; main.asm - LABYRINTH for the C64
|
||||||
|
; two-player maze duel: player 1 runs the corridors toward
|
||||||
|
; the green diamond exit while dodging the roaming colored
|
||||||
|
; enemies; player 2 rides the wall corners with a cursor
|
||||||
|
; and fire spins the four wall pieces around it by 90
|
||||||
|
; degrees, reshaping the maze under the runner's feet
|
||||||
|
;
|
||||||
|
; Files:
|
||||||
|
; defs.asm - constants, zero page, macros
|
||||||
|
; intro.asm - TTG boot logo (ported from rabbitc64)
|
||||||
|
; menu.asm - main menu: play / rules / credits
|
||||||
|
; rules.asm - how to play
|
||||||
|
; controls.asm- joystick + keyboard mappings
|
||||||
|
; credits.asm - the crew (content from rabbitc64, new look)
|
||||||
|
; play.asm - maze generation + the game itself
|
||||||
|
; win.asm - escape screen, returns to the menu
|
||||||
|
; over.asm - game over screen with retry
|
||||||
|
; common.asm - shared routines, input, RNG, texts
|
||||||
|
; sound.asm - single-voice SFX driver
|
||||||
|
;
|
||||||
|
; Build: acme -f cbm -o labyrinth.prg main.asm
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
* = $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
|
||||||
|
lda #BLACK
|
||||||
|
sta BORDER
|
||||||
|
sta BG
|
||||||
|
lda #0
|
||||||
|
sta SPR_EN ; character-only game: sprites stay off
|
||||||
|
sta framectr
|
||||||
|
sta fheld
|
||||||
|
jsr sfx_init
|
||||||
|
|
||||||
|
!ifdef AUTOPLAY { ; test builds boot straight into one state
|
||||||
|
jsr play_init
|
||||||
|
} else {
|
||||||
|
!ifdef AUTORULES {
|
||||||
|
jsr rules_init
|
||||||
|
} else {
|
||||||
|
!ifdef AUTOCONTROLS {
|
||||||
|
jsr controls_init
|
||||||
|
} else {
|
||||||
|
!ifdef AUTOCREDITS {
|
||||||
|
jsr credits_init
|
||||||
|
} else {
|
||||||
|
!ifdef AUTOWIN {
|
||||||
|
jsr win_init
|
||||||
|
} else {
|
||||||
|
!ifdef AUTOLOSE {
|
||||||
|
jsr lose_init
|
||||||
|
} else {
|
||||||
|
jsr intro_init ; TTG logo, then the menu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; 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 sfx_update ; advance the sound effect
|
||||||
|
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
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; the states and everything they share
|
||||||
|
; ============================================================
|
||||||
|
!src "intro.asm"
|
||||||
|
!src "menu.asm"
|
||||||
|
!src "rules.asm"
|
||||||
|
!src "controls.asm"
|
||||||
|
!src "credits.asm"
|
||||||
|
!src "play.asm"
|
||||||
|
!src "win.asm"
|
||||||
|
!src "over.asm"
|
||||||
|
!src "common.asm"
|
||||||
|
!src "sound.asm"
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; menu.asm - full-screen menu card: big LABYRINTH title with
|
||||||
|
; the gold wash, and a four-item menu: play / rules /
|
||||||
|
; controls / credits (joystick or w/s up/down + fire, space
|
||||||
|
; or return)
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
MENU_ITEMS = 4
|
||||||
|
|
||||||
|
menu_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
+prbig 2, 2, YELLOW, txt_title, 9
|
||||||
|
+prtext 9, 13, LGREY, txt_ttgname, 14
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta menusel
|
||||||
|
sta washphase
|
||||||
|
|
||||||
|
+setupd menu_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
menu_update:
|
||||||
|
; gold wash rolling down the big title (rows 2-6)
|
||||||
|
inc washphase
|
||||||
|
lda #0
|
||||||
|
sta g8row
|
||||||
|
mw_row:
|
||||||
|
lda #2
|
||||||
|
clc
|
||||||
|
adc g8row
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
lda washphase
|
||||||
|
lsr
|
||||||
|
clc
|
||||||
|
adc g8row
|
||||||
|
and #15
|
||||||
|
tax
|
||||||
|
lda washtbl,x
|
||||||
|
sta rtmp
|
||||||
|
ldy #37 ; the title spans columns 2-36
|
||||||
|
mw_col:
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #$a0 ; only touch the letter blocks
|
||||||
|
bne mw_skip
|
||||||
|
lda rtmp
|
||||||
|
sta (collo),y
|
||||||
|
mw_skip:
|
||||||
|
dey
|
||||||
|
cpy #1
|
||||||
|
bne mw_col
|
||||||
|
inc g8row
|
||||||
|
lda g8row
|
||||||
|
cmp #5
|
||||||
|
bne mw_row
|
||||||
|
|
||||||
|
; joystick up/down steps the cursor (edge detected)
|
||||||
|
jsr read_joy
|
||||||
|
lda joyb
|
||||||
|
and #3
|
||||||
|
beq mu_udrel
|
||||||
|
lda udheld
|
||||||
|
bne mu_udend
|
||||||
|
lda #1
|
||||||
|
sta udheld
|
||||||
|
lda joyb
|
||||||
|
and #1 ; up
|
||||||
|
beq mu_down
|
||||||
|
lda menusel
|
||||||
|
beq mu_udend
|
||||||
|
dec menusel
|
||||||
|
lda #SFX_CURSOR
|
||||||
|
jsr sfx_play
|
||||||
|
jmp mu_udend
|
||||||
|
mu_down:
|
||||||
|
lda menusel
|
||||||
|
cmp #MENU_ITEMS-1
|
||||||
|
beq mu_udend
|
||||||
|
inc menusel
|
||||||
|
lda #SFX_CURSOR
|
||||||
|
jsr sfx_play
|
||||||
|
jmp mu_udend
|
||||||
|
mu_udrel:
|
||||||
|
lda #0
|
||||||
|
sta udheld
|
||||||
|
mu_udend:
|
||||||
|
|
||||||
|
; footer: both control lines always visible
|
||||||
|
+prtext 21, 8, LGREY, txt_info, txt_infoe-txt_info
|
||||||
|
+prtext 22, 5, LGREY, txt_info2, txt_info2e-txt_info2
|
||||||
|
|
||||||
|
; the menu items: the picked line is yellow
|
||||||
|
ldx #0
|
||||||
|
mm_items:
|
||||||
|
txa
|
||||||
|
pha
|
||||||
|
jsr draw_mitem
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
inx
|
||||||
|
cpx #MENU_ITEMS
|
||||||
|
bne mm_items
|
||||||
|
|
||||||
|
; blinking '>' cursor in front of the picked line
|
||||||
|
lda #$20
|
||||||
|
sta SCREEN+12*40+15
|
||||||
|
sta SCREEN+14*40+15
|
||||||
|
sta SCREEN+16*40+15
|
||||||
|
sta SCREEN+18*40+15
|
||||||
|
lda framectr
|
||||||
|
and #16
|
||||||
|
bne mu_start
|
||||||
|
ldx menusel
|
||||||
|
lda mcur_lo,x
|
||||||
|
sta scrlo
|
||||||
|
lda mcur_hi,x
|
||||||
|
sta scrhi
|
||||||
|
ldy #0
|
||||||
|
lda #62 ; '>'
|
||||||
|
sta (scrlo),y
|
||||||
|
lda scrhi
|
||||||
|
clc
|
||||||
|
adc #$d4 ; same cell in color RAM
|
||||||
|
sta scrhi
|
||||||
|
lda #YELLOW
|
||||||
|
sta (scrlo),y
|
||||||
|
|
||||||
|
mu_start:
|
||||||
|
; fire or space opens the picked line
|
||||||
|
jsr start_edge
|
||||||
|
beq mu_done
|
||||||
|
lda #SFX_SELECT
|
||||||
|
jsr sfx_play
|
||||||
|
lda menusel
|
||||||
|
beq mg_play
|
||||||
|
cmp #1
|
||||||
|
beq mg_rules
|
||||||
|
cmp #2
|
||||||
|
beq mg_controls
|
||||||
|
jmp credits_init ; each init's rts returns to the main loop
|
||||||
|
mg_play:
|
||||||
|
jmp play_init
|
||||||
|
mg_rules:
|
||||||
|
jmp rules_init
|
||||||
|
mg_controls:
|
||||||
|
jmp controls_init
|
||||||
|
mu_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- draw menu item X, yellow when it is the picked one ----
|
||||||
|
draw_mitem:
|
||||||
|
lda mitem_lo,x
|
||||||
|
sta txtlo
|
||||||
|
lda mitem_hi,x
|
||||||
|
sta txthi
|
||||||
|
lda mitem_row,x
|
||||||
|
sta prow
|
||||||
|
lda #17
|
||||||
|
sta pcol
|
||||||
|
lda mitem_len,x
|
||||||
|
sta plen
|
||||||
|
lda #WHITE
|
||||||
|
cpx menusel
|
||||||
|
bne dm_store
|
||||||
|
lda #YELLOW
|
||||||
|
dm_store:
|
||||||
|
sta pcolor
|
||||||
|
jmp print_text
|
||||||
|
|
||||||
|
; ---- menu tables ----
|
||||||
|
mitem_lo: !byte <txt_play, <txt_rules, <txt_controls, <txt_credits
|
||||||
|
mitem_hi: !byte >txt_play, >txt_rules, >txt_controls, >txt_credits
|
||||||
|
mitem_len: !byte 4, 5, 8, 7
|
||||||
|
mitem_row: !byte 12, 14, 16, 18
|
||||||
|
mcur_lo: ; cursor cells: column 15 of those rows
|
||||||
|
!byte <(SCREEN+12*40+15), <(SCREEN+14*40+15)
|
||||||
|
!byte <(SCREEN+16*40+15), <(SCREEN+18*40+15)
|
||||||
|
mcur_hi:
|
||||||
|
!byte >(SCREEN+12*40+15), >(SCREEN+14*40+15)
|
||||||
|
!byte >(SCREEN+16*40+15), >(SCREEN+18*40+15)
|
||||||
|
|
||||||
|
; ---- menu texts ----
|
||||||
|
txt_play: !scr "play"
|
||||||
|
txt_rules: !scr "rules"
|
||||||
|
txt_credits: !scr "credits"
|
||||||
|
txt_info: !scr "p1: joy2 / wasd - runner"
|
||||||
|
txt_infoe:
|
||||||
|
txt_info2: !scr "p2: joy1 / ijkl - wall spinner"
|
||||||
|
txt_info2e:
|
||||||
|
|
||||||
|
; ---- menu variables ----
|
||||||
|
menusel: !byte 0 ; picked line: 0-2
|
||||||
|
udheld: !byte 0 ; joystick up/down edge detection state
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "labyrinth",
|
||||||
|
"title": "Labyrinth",
|
||||||
|
"author": "Teletype Games",
|
||||||
|
"desc": "Two-player maze duel: one player runs for the exit while the other spins the walls of the labyrinth around their corners. Dodge the enemies, find the diamond.",
|
||||||
|
"site": "https://git.teletype.hu/games/labyrinth",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; over.asm - game over screen: big red GAME OVER, fire
|
||||||
|
; restarts with a fresh maze, the m key backs out to the menu
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
lose_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
+prbig 3, 2, RED, txt_gameover, 9
|
||||||
|
|
||||||
|
+prtext 11, 10, WHITE, txt_caught, txt_caughte-txt_caught
|
||||||
|
|
||||||
|
+prtext 21, 13, LGREY, txt_mmenu, txt_mmenue-txt_mmenu
|
||||||
|
|
||||||
|
+setupd lose_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
lose_update:
|
||||||
|
; blink the retry prompt
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne lu_hide
|
||||||
|
+prtext 19, 12, YELLOW, txt_retry, txt_retrye-txt_retry
|
||||||
|
jmp lu_input
|
||||||
|
lu_hide:
|
||||||
|
+prtext 19, 12, YELLOW, txt_blank, txt_retrye-txt_retry
|
||||||
|
lu_input:
|
||||||
|
; fire or space: straight back in with a fresh maze
|
||||||
|
jsr start_edge
|
||||||
|
beq lu_nofire
|
||||||
|
jmp play_init
|
||||||
|
lu_nofire:
|
||||||
|
; the m key: keyboard column 4, row bit 4 (start_edge has
|
||||||
|
; already returned zero here, so joystick fire is not
|
||||||
|
; ghosting this row line)
|
||||||
|
lda #$ef
|
||||||
|
sta CIA1_PA
|
||||||
|
lda CIA1_PB
|
||||||
|
and #$10
|
||||||
|
bne lu_done
|
||||||
|
lda #$ff
|
||||||
|
sta CIA1_PA
|
||||||
|
jmp menu_init
|
||||||
|
lu_done:
|
||||||
|
lda #$ff
|
||||||
|
sta CIA1_PA
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- game over texts ----
|
||||||
|
txt_gameover: !scr "game over"
|
||||||
|
txt_caught: !scr "the enemies got you"
|
||||||
|
txt_caughte:
|
||||||
|
txt_retry: !scr "fire = try again"
|
||||||
|
txt_retrye:
|
||||||
|
txt_mmenu: !scr "m = main menu"
|
||||||
|
txt_mmenue:
|
||||||
@@ -0,0 +1,783 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; play.asm - the game: a fresh maze is carved with a
|
||||||
|
; recursive backtracker every round, player 1 (joystick 2)
|
||||||
|
; runs the corridors toward the exit diamond, player 2
|
||||||
|
; (joystick 1) rides the wall corners and fire spins the
|
||||||
|
; four wall pieces around the cursor by 90 degrees; the
|
||||||
|
; roaming colored enemies end the round on touch
|
||||||
|
;
|
||||||
|
; screen layout: status on row 0, the 39x23 maze lattice on
|
||||||
|
; rows 1-23 (cells = odd col / even row, posts = even col /
|
||||||
|
; odd row, wall slots = the rest), a hint line on row 24
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
play_init:
|
||||||
|
jsr clear_screen
|
||||||
|
+prtext 0, 0, WHITE, txt_title, 9
|
||||||
|
+prtext 0, 28, LGREY, txt_goal, txt_goale-txt_goal
|
||||||
|
+prtext 24, 6, DGREY, txt_hint, txt_hinte-txt_hint
|
||||||
|
|
||||||
|
; fill the whole lattice with wall blocks
|
||||||
|
ldx #1
|
||||||
|
pi_fillrow:
|
||||||
|
stx ptmp
|
||||||
|
jsr row_ptr
|
||||||
|
ldy #38
|
||||||
|
pi_fillcol:
|
||||||
|
lda #CH_WALL
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #COL_WALL
|
||||||
|
sta (collo),y
|
||||||
|
dey
|
||||||
|
bpl pi_fillcol
|
||||||
|
ldx ptmp
|
||||||
|
inx
|
||||||
|
cpx #24
|
||||||
|
bne pi_fillrow
|
||||||
|
|
||||||
|
; the pivot posts get their own darker shade
|
||||||
|
ldx #1 ; post rows 1, 3, ... 23
|
||||||
|
pi_postrow:
|
||||||
|
stx ptmp
|
||||||
|
jsr row_ptr
|
||||||
|
ldy #38 ; post columns 38, 36, ... 0
|
||||||
|
pi_postcol:
|
||||||
|
lda #COL_POST
|
||||||
|
sta (collo),y
|
||||||
|
dey
|
||||||
|
dey
|
||||||
|
bpl pi_postcol
|
||||||
|
ldx ptmp
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
cpx #25
|
||||||
|
bcc pi_postrow
|
||||||
|
|
||||||
|
; carve the maze
|
||||||
|
ldx #0
|
||||||
|
lda #0
|
||||||
|
pi_clrv:
|
||||||
|
sta visited,x
|
||||||
|
inx
|
||||||
|
cpx #NCELLS
|
||||||
|
bne pi_clrv
|
||||||
|
jsr gen_maze
|
||||||
|
|
||||||
|
; the exit: a green diamond in the right border wall
|
||||||
|
pi_exit:
|
||||||
|
jsr rand8
|
||||||
|
and #$0f
|
||||||
|
cmp #MAZE_CH
|
||||||
|
bcs pi_exit
|
||||||
|
asl ; cell row -> screen row
|
||||||
|
clc
|
||||||
|
adc #2
|
||||||
|
sta exrow
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
ldy #38
|
||||||
|
lda #CH_EXIT
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #COL_EXIT
|
||||||
|
sta (collo),y
|
||||||
|
|
||||||
|
; the runner starts in the top-left cell
|
||||||
|
lda #1
|
||||||
|
sta px
|
||||||
|
lda #2
|
||||||
|
sta py
|
||||||
|
jsr draw_player
|
||||||
|
|
||||||
|
; the corner cursor starts on the center post
|
||||||
|
lda #18
|
||||||
|
sta kx
|
||||||
|
lda #11
|
||||||
|
sta ky
|
||||||
|
|
||||||
|
jsr spawn_enemies
|
||||||
|
|
||||||
|
; input state: a fire still held from the previous screen
|
||||||
|
; must be released before it can spin walls
|
||||||
|
lda #0
|
||||||
|
sta rheld
|
||||||
|
sta cheld
|
||||||
|
sta endflag
|
||||||
|
lda #1
|
||||||
|
sta cfheld
|
||||||
|
+setupd play_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; maze generation - recursive backtracker over the 19x11
|
||||||
|
; cells; the screen itself is the wall data structure
|
||||||
|
; ============================================================
|
||||||
|
gen_maze:
|
||||||
|
lda #0
|
||||||
|
sta gcx
|
||||||
|
sta gcy
|
||||||
|
sta gsp
|
||||||
|
jsr gv_mark
|
||||||
|
jsr carve_cell
|
||||||
|
gm_loop:
|
||||||
|
; collect the unvisited neighbor directions
|
||||||
|
lda #0
|
||||||
|
sta gn
|
||||||
|
ldx #0
|
||||||
|
gm_scan:
|
||||||
|
stx gtd
|
||||||
|
lda gcx
|
||||||
|
clc
|
||||||
|
adc dxtab,x
|
||||||
|
sta gnx
|
||||||
|
cmp #MAZE_CW ; unsigned: -1 wraps to $ff and fails too
|
||||||
|
bcs gm_next
|
||||||
|
ldx gtd
|
||||||
|
lda gcy
|
||||||
|
clc
|
||||||
|
adc dytab,x
|
||||||
|
sta gny
|
||||||
|
cmp #MAZE_CH
|
||||||
|
bcs gm_next
|
||||||
|
ldx gny
|
||||||
|
lda mul19,x
|
||||||
|
clc
|
||||||
|
adc gnx
|
||||||
|
tax
|
||||||
|
lda visited,x
|
||||||
|
bne gm_next
|
||||||
|
ldx gn
|
||||||
|
lda gtd
|
||||||
|
sta gdlist,x
|
||||||
|
inc gn
|
||||||
|
gm_next:
|
||||||
|
ldx gtd
|
||||||
|
inx
|
||||||
|
cpx #4
|
||||||
|
bne gm_scan
|
||||||
|
lda gn
|
||||||
|
beq gm_pop
|
||||||
|
; pick a random one of them
|
||||||
|
gm_pick:
|
||||||
|
jsr rand8
|
||||||
|
and #3
|
||||||
|
cmp gn
|
||||||
|
bcs gm_pick
|
||||||
|
tax
|
||||||
|
lda gdlist,x
|
||||||
|
sta gtd
|
||||||
|
; push the current cell, open the wall, step through it
|
||||||
|
ldx gsp
|
||||||
|
lda gcx
|
||||||
|
sta stackx,x
|
||||||
|
lda gcy
|
||||||
|
sta stacky,x
|
||||||
|
inc gsp
|
||||||
|
jsr carve_wall
|
||||||
|
ldx gtd
|
||||||
|
lda gcx
|
||||||
|
clc
|
||||||
|
adc dxtab,x
|
||||||
|
sta gcx
|
||||||
|
ldx gtd
|
||||||
|
lda gcy
|
||||||
|
clc
|
||||||
|
adc dytab,x
|
||||||
|
sta gcy
|
||||||
|
jsr gv_mark
|
||||||
|
jsr carve_cell
|
||||||
|
jmp gm_loop
|
||||||
|
gm_pop:
|
||||||
|
; dead end: back up; empty stack = the maze is done
|
||||||
|
lda gsp
|
||||||
|
beq gm_done
|
||||||
|
dec gsp
|
||||||
|
ldx gsp
|
||||||
|
lda stackx,x
|
||||||
|
sta gcx
|
||||||
|
lda stacky,x
|
||||||
|
sta gcy
|
||||||
|
jmp gm_loop
|
||||||
|
gm_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
gv_mark: ; visited[gcy * 19 + gcx] = 1
|
||||||
|
ldx gcy
|
||||||
|
lda mul19,x
|
||||||
|
clc
|
||||||
|
adc gcx
|
||||||
|
tax
|
||||||
|
lda #1
|
||||||
|
sta visited,x
|
||||||
|
rts
|
||||||
|
|
||||||
|
carve_cell: ; open the cell (2*gcx+1, 2*gcy+2)
|
||||||
|
lda gcy
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc #2
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
lda gcx
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
tay
|
||||||
|
lda #CH_FLOOR
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #BLACK
|
||||||
|
sta (collo),y
|
||||||
|
rts
|
||||||
|
|
||||||
|
carve_wall: ; open the wall slot toward direction gtd
|
||||||
|
ldx gtd
|
||||||
|
lda gcy
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc #2
|
||||||
|
clc
|
||||||
|
adc dytab,x
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
ldx gtd
|
||||||
|
lda gcx
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
clc
|
||||||
|
adc dxtab,x
|
||||||
|
tay
|
||||||
|
lda #CH_FLOOR
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #BLACK
|
||||||
|
sta (collo),y
|
||||||
|
rts
|
||||||
|
|
||||||
|
dxtab: !byte 0, 0, $ff, 1 ; up, down, left, right
|
||||||
|
dytab: !byte $ff, 1, 0, 0
|
||||||
|
mul19: !byte 0, 19, 38, 57, 76, 95, 114, 133, 152, 171, 190
|
||||||
|
|
||||||
|
; ---- enemies: random colors, random right-half cells ----
|
||||||
|
spawn_enemies:
|
||||||
|
lda #0
|
||||||
|
sta ei
|
||||||
|
sn_loop:
|
||||||
|
sn_rx:
|
||||||
|
jsr rand8
|
||||||
|
and #$0f
|
||||||
|
cmp #MAZE_CH
|
||||||
|
bcs sn_rx
|
||||||
|
clc
|
||||||
|
adc #MAZE_CW-MAZE_CH ; cell column 8-18: away from the runner
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
sta gnx ; candidate screen column
|
||||||
|
sn_ry:
|
||||||
|
jsr rand8
|
||||||
|
and #$0f
|
||||||
|
cmp #MAZE_CH
|
||||||
|
bcs sn_ry
|
||||||
|
asl
|
||||||
|
clc
|
||||||
|
adc #2
|
||||||
|
sta gny ; candidate screen row
|
||||||
|
ldx gny
|
||||||
|
jsr row_ptr
|
||||||
|
ldy gnx
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #CH_FLOOR ; only an empty cell will do
|
||||||
|
bne sn_rx
|
||||||
|
lda #CH_ENEMY
|
||||||
|
sta (scrlo),y
|
||||||
|
jsr rand8
|
||||||
|
and #7
|
||||||
|
tax
|
||||||
|
lda ecoltab,x
|
||||||
|
sta (collo),y
|
||||||
|
ldx ei
|
||||||
|
sta ecol,x
|
||||||
|
lda gnx
|
||||||
|
sta ex,x
|
||||||
|
lda gny
|
||||||
|
sta ey,x
|
||||||
|
jsr rand8
|
||||||
|
and #3
|
||||||
|
sta edir,x
|
||||||
|
inc ei
|
||||||
|
lda ei
|
||||||
|
cmp #NENEMIES
|
||||||
|
bne sn_loop
|
||||||
|
rts
|
||||||
|
|
||||||
|
ecoltab: ; anything but the white runner / grey walls
|
||||||
|
!byte RED, CYAN, PURPLE, YELLOW, ORANGE, LRED, LBLUE, BLUE
|
||||||
|
|
||||||
|
; ============================================================
|
||||||
|
; one frame of play
|
||||||
|
; ============================================================
|
||||||
|
play_update:
|
||||||
|
jsr upd_runner
|
||||||
|
lda endflag
|
||||||
|
bne pu_end
|
||||||
|
jsr upd_enemies
|
||||||
|
lda endflag
|
||||||
|
bne pu_end
|
||||||
|
jsr upd_cursor
|
||||||
|
jsr upd_flash
|
||||||
|
rts
|
||||||
|
pu_end:
|
||||||
|
cmp #1
|
||||||
|
beq pu_win
|
||||||
|
lda #SFX_LOSE
|
||||||
|
jsr sfx_play
|
||||||
|
jmp lose_init ; its rts returns to the main loop
|
||||||
|
pu_win:
|
||||||
|
lda #SFX_WIN
|
||||||
|
jsr sfx_play
|
||||||
|
jmp win_init
|
||||||
|
|
||||||
|
; ---- player 1: walk the corridors, one char per step ----
|
||||||
|
upd_runner:
|
||||||
|
jsr read_joy
|
||||||
|
and #$0f
|
||||||
|
sta rdir
|
||||||
|
bne ur_held
|
||||||
|
lda #0
|
||||||
|
sta rheld
|
||||||
|
rts
|
||||||
|
ur_held:
|
||||||
|
lda rheld
|
||||||
|
beq ur_first
|
||||||
|
dec rtimer
|
||||||
|
beq ur_rep
|
||||||
|
rts
|
||||||
|
ur_rep:
|
||||||
|
lda #REP_PERIOD
|
||||||
|
sta rtimer
|
||||||
|
jmp ur_move
|
||||||
|
ur_first:
|
||||||
|
lda #1
|
||||||
|
sta rheld
|
||||||
|
lda #REP_HOLD
|
||||||
|
sta rtimer
|
||||||
|
ur_move:
|
||||||
|
ldx px
|
||||||
|
ldy py
|
||||||
|
lda rdir
|
||||||
|
lsr
|
||||||
|
bcs ur_up
|
||||||
|
lsr
|
||||||
|
bcs ur_down
|
||||||
|
lsr
|
||||||
|
bcs ur_left
|
||||||
|
inx ; right
|
||||||
|
jmp ur_try
|
||||||
|
ur_up:
|
||||||
|
dey
|
||||||
|
jmp ur_try
|
||||||
|
ur_down:
|
||||||
|
iny
|
||||||
|
jmp ur_try
|
||||||
|
ur_left:
|
||||||
|
dex
|
||||||
|
ur_try:
|
||||||
|
stx ttx
|
||||||
|
sty tty
|
||||||
|
ldx tty
|
||||||
|
jsr row_ptr
|
||||||
|
ldy ttx
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #CH_FLOOR
|
||||||
|
beq ur_go
|
||||||
|
cmp #CH_EXIT
|
||||||
|
beq ur_win
|
||||||
|
cmp #CH_ENEMY
|
||||||
|
beq ur_dead
|
||||||
|
rts ; a wall: blocked
|
||||||
|
ur_go:
|
||||||
|
ldx py
|
||||||
|
jsr row_ptr
|
||||||
|
ldy px
|
||||||
|
lda #CH_FLOOR
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #BLACK
|
||||||
|
sta (collo),y
|
||||||
|
lda ttx
|
||||||
|
sta px
|
||||||
|
lda tty
|
||||||
|
sta py
|
||||||
|
jmp draw_player
|
||||||
|
ur_win:
|
||||||
|
lda #1
|
||||||
|
sta endflag
|
||||||
|
rts
|
||||||
|
ur_dead:
|
||||||
|
lda #2
|
||||||
|
sta endflag
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw_player:
|
||||||
|
ldx py
|
||||||
|
jsr row_ptr
|
||||||
|
ldy px
|
||||||
|
lda #CH_PLAYER
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #WHITE
|
||||||
|
sta (collo),y
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- player 2: the corner cursor + the wall spin ----
|
||||||
|
upd_cursor:
|
||||||
|
jsr read_joy2
|
||||||
|
sta j2bits
|
||||||
|
and #$0f
|
||||||
|
sta cdir
|
||||||
|
bne uc_held
|
||||||
|
lda #0
|
||||||
|
sta cheld
|
||||||
|
jmp uc_fire
|
||||||
|
uc_held:
|
||||||
|
lda cheld
|
||||||
|
beq uc_first
|
||||||
|
dec ctimer
|
||||||
|
beq uc_rep
|
||||||
|
jmp uc_fire
|
||||||
|
uc_rep:
|
||||||
|
lda #CREP_PERIOD
|
||||||
|
sta ctimer
|
||||||
|
jmp uc_move
|
||||||
|
uc_first:
|
||||||
|
lda #1
|
||||||
|
sta cheld
|
||||||
|
lda #CREP_HOLD
|
||||||
|
sta ctimer
|
||||||
|
uc_move:
|
||||||
|
ldx kx
|
||||||
|
ldy ky
|
||||||
|
lda cdir
|
||||||
|
lsr
|
||||||
|
bcs uc_up
|
||||||
|
lsr
|
||||||
|
bcs uc_down
|
||||||
|
lsr
|
||||||
|
bcs uc_left
|
||||||
|
cpx #36 ; right: interior posts end at column 36
|
||||||
|
bcs uc_fire
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
jmp uc_go
|
||||||
|
uc_up:
|
||||||
|
cpy #4 ; top interior post row is 3
|
||||||
|
bcc uc_fire
|
||||||
|
dey
|
||||||
|
dey
|
||||||
|
jmp uc_go
|
||||||
|
uc_down:
|
||||||
|
cpy #21 ; bottom interior post row is 21
|
||||||
|
bcs uc_fire
|
||||||
|
iny
|
||||||
|
iny
|
||||||
|
jmp uc_go
|
||||||
|
uc_left:
|
||||||
|
cpx #3 ; left interior post column is 2
|
||||||
|
bcc uc_fire
|
||||||
|
dex
|
||||||
|
dex
|
||||||
|
uc_go:
|
||||||
|
stx ttx
|
||||||
|
sty tty
|
||||||
|
ldx ky ; the old post gets its color back
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
lda #COL_POST
|
||||||
|
sta (collo),y
|
||||||
|
lda ttx
|
||||||
|
sta kx
|
||||||
|
lda tty
|
||||||
|
sta ky
|
||||||
|
lda #SFX_CURSOR
|
||||||
|
jsr sfx_play
|
||||||
|
uc_fire:
|
||||||
|
lda j2bits
|
||||||
|
and #JOY_FIRE
|
||||||
|
beq uc_frel
|
||||||
|
lda cfheld
|
||||||
|
bne uc_done
|
||||||
|
lda #1
|
||||||
|
sta cfheld
|
||||||
|
jmp do_rotate ; its rts returns to play_update's caller
|
||||||
|
uc_frel:
|
||||||
|
lda #0
|
||||||
|
sta cfheld
|
||||||
|
uc_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- spin the four wall slots around post (kx, ky) by 90
|
||||||
|
; degrees clockwise; denied while anyone stands in them ----
|
||||||
|
do_rotate:
|
||||||
|
ldx ky ; gather the four slot chars
|
||||||
|
dex
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
lda (scrlo),y
|
||||||
|
sta nch
|
||||||
|
ldx ky
|
||||||
|
inx
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
lda (scrlo),y
|
||||||
|
sta sch
|
||||||
|
ldx ky
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
dey
|
||||||
|
lda (scrlo),y
|
||||||
|
sta wch
|
||||||
|
iny
|
||||||
|
iny
|
||||||
|
lda (scrlo),y
|
||||||
|
sta ech
|
||||||
|
; every slot must be plain wall or floor
|
||||||
|
lda nch
|
||||||
|
jsr rot_ok
|
||||||
|
bcs rot_deny
|
||||||
|
lda sch
|
||||||
|
jsr rot_ok
|
||||||
|
bcs rot_deny
|
||||||
|
lda wch
|
||||||
|
jsr rot_ok
|
||||||
|
bcs rot_deny
|
||||||
|
lda ech
|
||||||
|
jsr rot_ok
|
||||||
|
bcs rot_deny
|
||||||
|
; clockwise: north<-west, east<-north, south<-east, west<-south
|
||||||
|
ldx ky
|
||||||
|
dex
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
lda wch
|
||||||
|
jsr put_slot
|
||||||
|
ldx ky
|
||||||
|
inx
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
lda ech
|
||||||
|
jsr put_slot
|
||||||
|
ldx ky
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
dey
|
||||||
|
lda sch
|
||||||
|
jsr put_slot
|
||||||
|
iny
|
||||||
|
iny
|
||||||
|
lda nch
|
||||||
|
jsr put_slot
|
||||||
|
lda #SFX_ROTATE
|
||||||
|
jmp sfx_play
|
||||||
|
rot_deny:
|
||||||
|
lda #SFX_DENY
|
||||||
|
jmp sfx_play
|
||||||
|
|
||||||
|
rot_ok: ; C clear when A is spinnable (wall or floor)
|
||||||
|
cmp #CH_WALL
|
||||||
|
beq ro_yes
|
||||||
|
cmp #CH_FLOOR
|
||||||
|
beq ro_yes
|
||||||
|
sec
|
||||||
|
rts
|
||||||
|
ro_yes:
|
||||||
|
clc
|
||||||
|
rts
|
||||||
|
|
||||||
|
put_slot: ; write char A at (scrlo),y + matching color
|
||||||
|
sta (scrlo),y
|
||||||
|
cmp #CH_WALL
|
||||||
|
beq ps_wall
|
||||||
|
lda #BLACK
|
||||||
|
sta (collo),y
|
||||||
|
rts
|
||||||
|
ps_wall:
|
||||||
|
lda #COL_WALL
|
||||||
|
sta (collo),y
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- the enemies: staggered random walkers ----
|
||||||
|
upd_enemies:
|
||||||
|
lda #0
|
||||||
|
sta ei
|
||||||
|
ue_loop:
|
||||||
|
ldx ei
|
||||||
|
lda framectr
|
||||||
|
clc
|
||||||
|
adc estag,x
|
||||||
|
and #7 ; each enemy steps every 8th frame
|
||||||
|
bne ue_next
|
||||||
|
jsr enemy_step
|
||||||
|
lda endflag
|
||||||
|
bne ue_out
|
||||||
|
ue_next:
|
||||||
|
inc ei
|
||||||
|
lda ei
|
||||||
|
cmp #NENEMIES
|
||||||
|
bne ue_loop
|
||||||
|
ue_out:
|
||||||
|
rts
|
||||||
|
|
||||||
|
estag: !byte 0, 2, 4, 6
|
||||||
|
|
||||||
|
enemy_step:
|
||||||
|
jsr rand8 ; 1 in 4: wander off in a new direction
|
||||||
|
and #3
|
||||||
|
beq es_newdir
|
||||||
|
ldx ei
|
||||||
|
lda edir,x
|
||||||
|
jsr etry_dir
|
||||||
|
bcc es_done
|
||||||
|
es_newdir:
|
||||||
|
lda #8
|
||||||
|
sta etries
|
||||||
|
es_pick:
|
||||||
|
jsr rand8
|
||||||
|
and #3
|
||||||
|
jsr etry_dir
|
||||||
|
bcc es_done
|
||||||
|
dec etries ; walled in on all sides: sit this one out
|
||||||
|
bne es_pick
|
||||||
|
es_done:
|
||||||
|
rts
|
||||||
|
|
||||||
|
etry_dir: ; A = direction; C clear when it moved (or won)
|
||||||
|
sta etd
|
||||||
|
tax
|
||||||
|
ldy ei
|
||||||
|
lda ex,y
|
||||||
|
clc
|
||||||
|
adc dxtab,x
|
||||||
|
sta ttx
|
||||||
|
lda ey,y
|
||||||
|
clc
|
||||||
|
adc dytab,x
|
||||||
|
sta tty
|
||||||
|
ldx tty
|
||||||
|
jsr row_ptr
|
||||||
|
ldy ttx
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #CH_FLOOR
|
||||||
|
beq ed_move
|
||||||
|
cmp #CH_PLAYER
|
||||||
|
beq ed_kill
|
||||||
|
sec ; wall, exit or another enemy: blocked
|
||||||
|
rts
|
||||||
|
ed_kill:
|
||||||
|
lda #2
|
||||||
|
sta endflag
|
||||||
|
clc
|
||||||
|
rts
|
||||||
|
ed_move:
|
||||||
|
ldx ei
|
||||||
|
lda ey,x
|
||||||
|
sta gny ; old position
|
||||||
|
lda ex,x
|
||||||
|
sta gnx
|
||||||
|
lda ttx
|
||||||
|
sta ex,x
|
||||||
|
lda tty
|
||||||
|
sta ey,x
|
||||||
|
lda etd
|
||||||
|
sta edir,x
|
||||||
|
ldx gny ; erase the old cell
|
||||||
|
jsr row_ptr
|
||||||
|
ldy gnx
|
||||||
|
lda #CH_FLOOR
|
||||||
|
sta (scrlo),y
|
||||||
|
lda #BLACK
|
||||||
|
sta (collo),y
|
||||||
|
ldx tty ; draw at the new one
|
||||||
|
jsr row_ptr
|
||||||
|
ldy ttx
|
||||||
|
lda #CH_ENEMY
|
||||||
|
sta (scrlo),y
|
||||||
|
ldx ei
|
||||||
|
lda ecol,x
|
||||||
|
sta (collo),y
|
||||||
|
clc
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- per-frame flashes: the exit blinks, the cursor pulses ----
|
||||||
|
upd_flash:
|
||||||
|
ldx exrow
|
||||||
|
jsr row_ptr
|
||||||
|
ldy #38
|
||||||
|
lda framectr
|
||||||
|
and #8
|
||||||
|
bne uf_exw
|
||||||
|
lda #COL_EXIT
|
||||||
|
jmp uf_exset
|
||||||
|
uf_exw:
|
||||||
|
lda #WHITE
|
||||||
|
uf_exset:
|
||||||
|
sta (collo),y
|
||||||
|
ldx ky
|
||||||
|
jsr row_ptr
|
||||||
|
ldy kx
|
||||||
|
lda framectr
|
||||||
|
and #4
|
||||||
|
bne uf_cred
|
||||||
|
lda #YELLOW
|
||||||
|
jmp uf_cset
|
||||||
|
uf_cred:
|
||||||
|
lda #RED
|
||||||
|
uf_cset:
|
||||||
|
sta (collo),y
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- play texts ----
|
||||||
|
txt_goal: !scr "reach the "
|
||||||
|
!byte CH_EXIT
|
||||||
|
txt_goale:
|
||||||
|
txt_hint: !scr "p1: joy2/wasd p2: joy1/ijkl"
|
||||||
|
txt_hinte:
|
||||||
|
|
||||||
|
; ---- play variables ----
|
||||||
|
px: !byte 0 ; runner position (screen col / row)
|
||||||
|
py: !byte 0
|
||||||
|
kx: !byte 0 ; corner cursor position (post col / row)
|
||||||
|
ky: !byte 0
|
||||||
|
exrow: !byte 0 ; screen row of the exit diamond
|
||||||
|
endflag: !byte 0 ; 0 = playing, 1 = escaped, 2 = caught
|
||||||
|
rheld: !byte 0 ; runner direction repeat state
|
||||||
|
rtimer: !byte 0
|
||||||
|
rdir: !byte 0
|
||||||
|
cheld: !byte 0 ; cursor direction repeat state
|
||||||
|
ctimer: !byte 0
|
||||||
|
cdir: !byte 0
|
||||||
|
cfheld: !byte 0 ; cursor fire edge detection state
|
||||||
|
j2bits: !byte 0
|
||||||
|
ptmp: !byte 0 ; scratch
|
||||||
|
ttx: !byte 0 ; move target (col / row)
|
||||||
|
tty: !byte 0
|
||||||
|
nch: !byte 0 ; the four slot chars around the cursor
|
||||||
|
ech: !byte 0
|
||||||
|
sch: !byte 0
|
||||||
|
wch: !byte 0
|
||||||
|
ei: !byte 0 ; enemy loop index
|
||||||
|
etries: !byte 0
|
||||||
|
etd: !byte 0
|
||||||
|
gcx: !byte 0 ; maze generator state
|
||||||
|
gcy: !byte 0
|
||||||
|
gsp: !byte 0
|
||||||
|
gn: !byte 0
|
||||||
|
gtd: !byte 0
|
||||||
|
gnx: !byte 0
|
||||||
|
gny: !byte 0
|
||||||
|
gdlist: !fill 4, 0
|
||||||
|
ex: !fill NENEMIES, 0 ; enemy positions, headings, colors
|
||||||
|
ey: !fill NENEMIES, 0
|
||||||
|
edir: !fill NENEMIES, 0
|
||||||
|
ecol: !fill NENEMIES, 0
|
||||||
|
|
||||||
|
; ---- maze generator buffers ----
|
||||||
|
visited: !fill NCELLS, 0
|
||||||
|
stackx: !fill NCELLS, 0
|
||||||
|
stacky: !fill NCELLS, 0
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; rules.asm - how to play, one static card; fire returns
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
rules_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
+prbig 1, 10, WHITE, txt_rules, 5
|
||||||
|
|
||||||
|
+prtext 8, 9, LGREEN, txt_r1, txt_r1e-txt_r1
|
||||||
|
+prtext 9, 8, WHITE, txt_r2, txt_r2e-txt_r2
|
||||||
|
+prtext 10, 7, WHITE, txt_r3, txt_r3e-txt_r3
|
||||||
|
|
||||||
|
+prtext 12, 9, LBLUE, txt_r4, txt_r4e-txt_r4
|
||||||
|
+prtext 13, 6, WHITE, txt_r5, txt_r5e-txt_r5
|
||||||
|
+prtext 14, 6, WHITE, txt_r6, txt_r6e-txt_r6
|
||||||
|
+prtext 15, 7, WHITE, txt_r7, txt_r7e-txt_r7
|
||||||
|
|
||||||
|
+prtext 17, 7, LRED, txt_r8, txt_r8e-txt_r8
|
||||||
|
|
||||||
|
+setupd rules_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
rules_update:
|
||||||
|
; blink the return prompt
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne ru_hide
|
||||||
|
+prtext 21, 13, YELLOW, txt_return, 13
|
||||||
|
jmp ru_input
|
||||||
|
ru_hide:
|
||||||
|
+prtext 21, 13, YELLOW, txt_blank, 13
|
||||||
|
ru_input:
|
||||||
|
jsr start_edge
|
||||||
|
beq ru_stay
|
||||||
|
jmp menu_init
|
||||||
|
ru_stay:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- rules texts ----
|
||||||
|
txt_r1: !scr "player 1 - joystick 2"
|
||||||
|
txt_r1e:
|
||||||
|
txt_r2: !scr "run the maze and escape"
|
||||||
|
txt_r2e:
|
||||||
|
txt_r3: !scr "through the green diamond."
|
||||||
|
txt_r3e:
|
||||||
|
txt_r4: !scr "player 2 - joystick 1"
|
||||||
|
txt_r4e:
|
||||||
|
txt_r5: !scr "ride the corners of the walls;"
|
||||||
|
txt_r5e:
|
||||||
|
txt_r6: !scr "fire spins the four wall pieces"
|
||||||
|
txt_r6e:
|
||||||
|
txt_r7: !scr "around the cursor by 90 degrees."
|
||||||
|
txt_r7e:
|
||||||
|
txt_r8: !scr "avoid the colored enemies!"
|
||||||
|
txt_r8e:
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; sound.asm - single-voice SFX driver: each effect is a
|
||||||
|
; waveform + start pitch + per-frame pitch slide + duration,
|
||||||
|
; played on SID voice 1 (sustain 0, the decay shapes it)
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
sfx_init:
|
||||||
|
lda #$0f ; full volume, no filter
|
||||||
|
sta SID_VOL
|
||||||
|
lda #0
|
||||||
|
sta SID_V1CR
|
||||||
|
sta sfx_timer
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- start effect A ----
|
||||||
|
sfx_play:
|
||||||
|
tax
|
||||||
|
lda #0
|
||||||
|
sta SID_V1CR ; retrigger the envelope cleanly
|
||||||
|
lda sfxad,x
|
||||||
|
sta SID_V1AD
|
||||||
|
lda #0
|
||||||
|
sta SID_V1SR
|
||||||
|
sta SID_V1FL
|
||||||
|
lda sfxfreq,x
|
||||||
|
sta SID_V1FH
|
||||||
|
sta sfx_fh
|
||||||
|
lda #$08 ; 50% pulse width, if a pulse wave is used
|
||||||
|
sta SID_V1PH
|
||||||
|
lda #0
|
||||||
|
sta SID_V1PL
|
||||||
|
lda sfxctrl,x
|
||||||
|
sta SID_V1CR
|
||||||
|
sta sfx_ctrl
|
||||||
|
lda sfxslide,x
|
||||||
|
sta sfx_slide
|
||||||
|
lda sfxdur,x
|
||||||
|
sta sfx_timer
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- called once per frame by the main loop ----
|
||||||
|
sfx_update:
|
||||||
|
lda sfx_timer
|
||||||
|
beq su_idle
|
||||||
|
dec sfx_timer
|
||||||
|
bne su_slide
|
||||||
|
lda sfx_ctrl ; time is up: gate off
|
||||||
|
and #$fe
|
||||||
|
sta SID_V1CR
|
||||||
|
rts
|
||||||
|
su_slide:
|
||||||
|
lda sfx_fh ; bend the pitch by the slide value
|
||||||
|
clc
|
||||||
|
adc sfx_slide
|
||||||
|
sta sfx_fh
|
||||||
|
sta SID_V1FH
|
||||||
|
su_idle:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- effect tables: cursor, select, rotate, deny, win, lose ----
|
||||||
|
sfxfreq: !byte $50, $20, $12, $06, $20, $38
|
||||||
|
sfxslide: !byte $00, $04, $fe, $00, $02, $ff
|
||||||
|
sfxctrl: !byte $11, $21, $81, $21, $11, $21
|
||||||
|
sfxad: !byte $06, $08, $08, $08, $0a, $0a
|
||||||
|
sfxdur: !byte $04, $0a, $08, $0c, $28, $30
|
||||||
|
|
||||||
|
; ---- driver variables ----
|
||||||
|
sfx_timer: !byte 0 ; frames left of the current effect
|
||||||
|
sfx_fh: !byte 0 ; frequency high byte shadow
|
||||||
|
sfx_slide: !byte 0 ; signed per-frame pitch step
|
||||||
|
sfx_ctrl: !byte 0 ; control register shadow
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
; -----------------------------------------------------------
|
||||||
|
; win.asm - the escape screen: big ESCAPED with the gold
|
||||||
|
; wash; fire returns to the main menu
|
||||||
|
; -----------------------------------------------------------
|
||||||
|
|
||||||
|
win_init:
|
||||||
|
jsr clear_screen
|
||||||
|
|
||||||
|
+prbig 3, 6, YELLOW, txt_escaped, 7
|
||||||
|
|
||||||
|
+prtext 11, 15, WHITE, txt_welldone, txt_welldonee-txt_welldone
|
||||||
|
+prtext 13, 9, LGREY, txt_beaten, txt_beatene-txt_beaten
|
||||||
|
|
||||||
|
lda #0
|
||||||
|
sta washphase
|
||||||
|
+setupd win_update
|
||||||
|
rts
|
||||||
|
|
||||||
|
win_update:
|
||||||
|
; the gold wash rolls down the big letters (rows 3-7)
|
||||||
|
inc washphase
|
||||||
|
lda #0
|
||||||
|
sta rtmp2
|
||||||
|
wu_row:
|
||||||
|
lda #3
|
||||||
|
clc
|
||||||
|
adc rtmp2
|
||||||
|
tax
|
||||||
|
jsr row_ptr
|
||||||
|
lda washphase
|
||||||
|
lsr
|
||||||
|
clc
|
||||||
|
adc rtmp2
|
||||||
|
and #15
|
||||||
|
tax
|
||||||
|
lda washtbl,x
|
||||||
|
sta rtmp
|
||||||
|
ldy #32 ; the letters span columns 6-32
|
||||||
|
wu_col:
|
||||||
|
lda (scrlo),y
|
||||||
|
cmp #$a0
|
||||||
|
bne wu_skip
|
||||||
|
lda rtmp
|
||||||
|
sta (collo),y
|
||||||
|
wu_skip:
|
||||||
|
dey
|
||||||
|
cpy #5
|
||||||
|
bne wu_col
|
||||||
|
inc rtmp2
|
||||||
|
lda rtmp2
|
||||||
|
cmp #5
|
||||||
|
bne wu_row
|
||||||
|
|
||||||
|
; blink the prompt
|
||||||
|
lda framectr
|
||||||
|
and #32
|
||||||
|
bne wu_hide
|
||||||
|
+prtext 20, 14, YELLOW, txt_firemenu, txt_firemenue-txt_firemenu
|
||||||
|
jmp wu_input
|
||||||
|
wu_hide:
|
||||||
|
+prtext 20, 14, YELLOW, txt_blank, txt_firemenue-txt_firemenu
|
||||||
|
wu_input:
|
||||||
|
jsr start_edge
|
||||||
|
beq wu_stay
|
||||||
|
jmp menu_init ; a win leads back to the main screen
|
||||||
|
wu_stay:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ---- win texts ----
|
||||||
|
txt_escaped: !scr "escaped"
|
||||||
|
txt_welldone: !scr "well done!"
|
||||||
|
txt_welldonee:
|
||||||
|
txt_beaten: !scr "you beat the labyrinth"
|
||||||
|
txt_beatene:
|
||||||
|
txt_firemenu: !scr "fire = menu"
|
||||||
|
txt_firemenue:
|
||||||
Reference in New Issue
Block a user