blessing of ra

This commit is contained in:
2026-07-26 19:01:43 +02:00
parent b5c4de4f75
commit 28f1191fde
17 changed files with 839 additions and 448 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
# Makefile C64 project builder (ACME + VICE)
# -----------------------------------------
PROJECT = labyrintwo
PROJECT = blessingofra
ASM = acme
EMU = x64sc
+44 -29
View File
@@ -1,51 +1,65 @@
# labyrintwo (LabyrinTwo)
# Blessing of Ra
**LabyrinTwo** - a two-player maze duel for the Commodore 64
**Blessing of Ra** - a two-player pyramid escape for the Commodore 64
(ACME + VICE), in the same spirit as [rabbitc64](../rabbitc64).
A fresh maze carves itself on screen at the start of 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 exit portal while dodging the roaming enemies. **Player 2**
(joystick 1, or `i j k l`) rides the corners of the walls with a
bracket 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 (the border
blips red); the spun pieces flash white.
The legend: when the great pyramid rose, a worker was sealed in its
peak. He prayed to Ra until the sun god took pity - now Ra bends the
pyramid's labyrinth walls to lead him out.
The look: brick walls and bolted pivot posts from a custom RAM
charset, every actor (runner, cursor, bullet, enemies) a hardware
sprite gliding smoothly between the cells, an animated exit portal,
a raster color band behind the status row, and a fade to black
between all screens. The menu floats over a dark maze backdrop.
**Player 1** (joystick 2, or `w a s d`) is the worker, running the
corridors toward the green exit portal. **Player 2** (joystick 1, or
`i j k l`) is Ra: a bracket cursor rides the corners of the walls -
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 (the border blips red);
the spun pieces flash white.
Eight levels, each maze one cell bigger than the last: a square that
starts at 4x4 cells and grows to 11x11 - the tallest square lattice
the screen fits - always centered on screen. One more enemy joins
each level (up to four): the cyan **scarabs** roam the corridors,
and the light-red **scorpions** also spit a venom sting whenever
they line up with the worker - the purple drop flies down the
corridor until a wall swallows it.
The look: a desert palette of sandstone walls and brown pivot posts
from a custom RAM charset, every actor (worker, cursor, bullet,
sting, enemies) a hardware sprite gliding smoothly between the
cells, an animated exit portal, a raster color band behind the
status row, and a fade to black between all screens. The menu floats
over a dark maze backdrop under the big gold-washed title.
The options screen adds two optional twists:
- **runner gun** - player 1 shoots a bullet with fire/`space`; a hit
- **worker gun** - player 1 shoots a bullet with fire/`space`; a hit
enemy respawns on a random cell after a pause.
- **spin cooldown** - each spin starts a recharge; further spins are
denied until the bar on the status row drains (pixel by pixel) and
the readout flips back from *wait* to *ready* (the cursor also
turns red while recharging).
Screens: TTG intro (ported from rabbitc64) -> main menu
(play / options / rules / controls / credits) -> game -> win (back
to the menu) or game over (fire retries with a fresh maze, `m` backs
out to the menu).
Screens: TTG intro (ported from rabbitc64) -> pyramid title card
(the pyramid, the trapped worker and the pulsing sun of Ra) -> main
menu (play / options / story / credits) -> game -> next level, and
after the last one the escape screen (back to the menu); game over
lets fire retry the same level with a fresh maze, `m` backs out to
the menu. The story screen tells the legend and lists who steers
what.
## Build & run
```
make deps # macOS: brew install acme vice
make build # -> labyrintwo.prg
make build # -> blessingofra.prg
make run # build + launch in x64sc
```
Test builds can boot straight into one state:
```
acme -DAUTOPLAY=1 -f cbm -o labyrintwo.prg main.asm
# also: AUTOOPTIONS, AUTORULES, AUTOCONTROLS, AUTOCREDITS,
acme -DAUTOPLAY=1 -f cbm -o blessingofra.prg main.asm
# also: AUTOOPTIONS, AUTOSTORY, AUTOPYRAMID, AUTOCREDITS,
# AUTOWIN, AUTOLOSE; add -DFORCEOPTS=1 to start with both
# options turned on
```
@@ -56,15 +70,16 @@ acme -DAUTOPLAY=1 -f cbm -o labyrintwo.prg main.asm
the border/status-band raster work
- `defs.asm` - registers, constants, zero page, macros
- `intro.asm` - TTG boot logo with the gold color wash
- `pyramid.asm` - title card: the pyramid, the worker, the sun of Ra
- `menu.asm` - main menu card over a dark maze backdrop
- `options.asm` - the optional extras and their toggle screen
- `rules.asm` - how to play
- `controls.asm` - joystick + keyboard mappings
- `story.asm` - the legend of the worker and Ra + the controls
- `credits.asm` - the crew
- `play.asm` - maze generation (recursive backtracker, animated)
+ the game
- `play.asm` - maze geometry + generation (recursive backtracker,
animated) + the game and its eight growing levels
- `win.asm` / `over.asm` - end screens
- `common.asm` - shared routines: printing, big block font, input, RNG
- `common.asm` - shared routines: printing, big block font, the
title wash, input, RNG
- `sound.asm` - single-voice SID SFX driver
- `gfx.asm` - RAM charset with the custom tiles, the sprite engine,
the portal animation and the fade-to-black transition
+41 -3
View File
@@ -356,10 +356,48 @@ bigmap: ; screen code (a=1..z=26) -> glyph index
!byte 0, 7, 8, 9, 10, 11, 0, 12, 13, 14 ; k-t
!byte 20, 18, 21, 0, 15, 0 ; u-z
; ---- gold wash over the two big title lines (rows 1-5 and
; 7-11): only the $a0 letter blocks are recolored, so it is
; safe over any backdrop ----
wash_title:
inc washphase
lda #0
sta g8row
wt_row:
ldx g8row
lda wtrows,x
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 #39
wt_col:
lda (scrlo),y
cmp #$a0 ; only touch the letter blocks
bne wt_skip
lda rtmp
sta (collo),y
wt_skip:
dey
bpl wt_col
inc g8row
lda g8row
cmp #10
bne wt_row
rts
wtrows: !byte 1, 2, 3, 4, 5, 7, 8, 9, 10, 11
; ---- shared texts (screen codes) ----
; the title is split so the two words can wear two colors
txt_t1: !scr "labyrin"
txt_t2: !scr "two"
; the title is split so the two lines can be placed apart
txt_t1: !scr "blessing"
txt_t2: !scr "of ra"
txt_ttgname: !scr "teletype games"
txt_presents:!scr "presents"
txt_return: !scr "fire = return"
-55
View File
@@ -1,55 +0,0 @@
; -----------------------------------------------------------
; 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 11, 6, LGREY, txt_c2b, txt_c2be-txt_c2b
+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
+fadeto 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_c2b: !scr "gun: fire or space, if enabled"
txt_c2be:
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:
+24 -13
View File
@@ -45,7 +45,7 @@ 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
SFX_SHOT = 6 ; gun fired: short high tick
SFX_SHOT = 6 ; gun / scorpion sting: short high tick
SFX_HIT = 7 ; enemy hit: noise burst
NSFX = 8
@@ -75,34 +75,45 @@ 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)
; a lattice of (2*cells+1) chars per side, centered on rows
; 1-23; local coordinates inside the lattice:
; cell = odd column, odd row (walkable)
; post = even column, even 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
; the levels are squares, one cell bigger each level: MZMIN
; up to MZMAX (11x11 cells = 23x23 chars, the tallest square
; the screen fits); the menu backdrop uses the full lattice
MZMIN = 4 ; level 1: 4x4 cells
MZMAX = 11 ; level 8: 11x11 cells
MAZE_CW = 19 ; the largest lattice: the menu backdrop
MAZE_CH = 11
NCELLS = MAZE_CW * MAZE_CH
NENEMIES = 4
NENEMIES = 4 ; enemy sprite slots (a level uses 1-4)
; ---- characters (the custom tiles live in the RAM charset) ----
CH_WALL = $e0 ; brick block: spinnable wall piece
CH_WALL = $e0 ; sandstone block: spinnable wall piece
CH_POST = $e1 ; bolted plate: fixed pivot post
CH_EXIT = $e2 ; the portal out (4 animated glyph frames)
CH_FLOOR = $20 ; space: corridor
CH_BAR = $e3 ; 7 chars: a bar cell 1-7 pixels full
; ---- the actors are hardware sprites ----
SP_RUN = 0 ; player 1, the runner
SP_CUR = 1 ; player 2, the corner cursor
SP_RUN = 0 ; player 1, the worker
SP_CUR = 1 ; player 2, ra's cursor
SP_SHOT = 2 ; the optional bullet
SP_EN = 3 ; the enemies ride sprites 3-6
SP_STING = 7 ; the scorpions' venom sting
COL_WALL = MGREY ; spinnable wall pieces
COL_POST = DGREY ; fixed pivot posts
; ---- desert palette ----
COL_WALL = ORANGE ; sandstone wall pieces
COL_POST = BROWN ; fixed pivot posts
COL_EXIT = LGREEN ; the exit portal
COL_HILITE = YELLOW ; walls the cursor's spin would move
STATCOL = BLUE ; background band behind the status row
COL_SCARAB = CYAN ; the scarabs
COL_SCORP = LRED ; the scorpions
COL_STING = PURPLE ; the venom sting
STATCOL = BROWN ; background band behind the status row
; ---- game timing ----
REP_HOLD = 10 ; runner: frames before a held dir repeats
+47 -36
View File
@@ -1,11 +1,11 @@
; -----------------------------------------------------------
; gfx.asm - the graphics layer:
; - the ROM font is copied into RAM and a handful of custom
; tiles are stamped over it (brick wall, pivot post, the
; animated exit portal, the 1/8-step cooldown bar cells)
; tiles are stamped over it (sandstone wall, pivot post,
; the animated exit portal, the 1/8-step cooldown bar)
; - a small sprite engine: every actor lives on the char
; grid, its sprite glides toward the cell a few pixels a
; frame (the runner bobs, the enemies wave)
; frame (the worker bobs, the enemies wave)
; - fade to black: the transition between two screens
; -----------------------------------------------------------
@@ -308,7 +308,7 @@ fadetbl: ; each color, one step darker
!byte $02, $00, $02, $00, $0b, $05, $06, $0c
; ---- the custom tiles ----
tile_gfx: ; CH_WALL: bricks with dark mortar
tile_gfx: ; CH_WALL: sandstone blocks, dark mortar
!byte %11111111
!byte %11110111
!byte %11110111
@@ -430,50 +430,61 @@ spr_cur0: ; the corner cursor: four brackets
!byte %10000001, 0, 0
!byte %11100111, 0, 0
!fill 40, 0
spr_ena0: ; enemies 0-1: a ghost, skirt waving
!byte %00111100, 0, 0
!byte %01111110, 0, 0
!byte %11011011, 0, 0
!byte %11011011, 0, 0
!byte %11111111, 0, 0
!byte %11111111, 0, 0
!byte %11111111, 0, 0
!byte %10110101, 0, 0
!fill 40, 0
spr_ena1:
!byte %00111100, 0, 0
!byte %01111110, 0, 0
!byte %11011011, 0, 0
!byte %11011011, 0, 0
!byte %11111111, 0, 0
!byte %11111111, 0, 0
!byte %11111111, 0, 0
!byte %01101101, 0, 0
!fill 40, 0
spr_enb0: ; enemies 2-3: a crawler, legs pumping
spr_sting0: ; the scorpion's venom sting: a drop
!byte %00000000, 0, 0
!byte %00011000, 0, 0
!byte %00111100, 0, 0
!byte %01111110, 0, 0
!byte %00111100, 0, 0
!byte %00011000, 0, 0
!byte %00000000, 0, 0
!byte %00000000, 0, 0
!fill 40, 0
spr_ena0: ; even enemies: a scarab, legs out...
!byte %00100100, 0, 0
!byte %10111101, 0, 0
!byte %01111110, 0, 0
!byte %11011011, 0, 0
!byte %01111110, 0, 0
!byte %10111101, 0, 0
!byte %00000000, 0, 0
!byte %00000000, 0, 0
!fill 40, 0
spr_enb1:
!byte %00000000, 0, 0
!byte %00111100, 0, 0
!byte %01111110, 0, 0
!byte %11011011, 0, 0
!byte %01111110, 0, 0
!byte %10111101, 0, 0
!byte %00100100, 0, 0
!fill 40, 0
spr_ena1: ; ...and tucked as it scuttles
!byte %00100100, 0, 0
!byte %00111100, 0, 0
!byte %00000000, 0, 0
!byte %00000000, 0, 0
!byte %11111111, 0, 0
!byte %01011010, 0, 0
!byte %01011010, 0, 0
!byte %11111111, 0, 0
!byte %00111100, 0, 0
!byte %00100100, 0, 0
!fill 40, 0
spr_enb0: ; odd enemies: a scorpion, claws up,
!byte %11000011, 0, 0 ; the tail swinging right...
!byte %01100110, 0, 0
!byte %00111100, 0, 0
!byte %01111110, 0, 0
!byte %00111100, 0, 0
!byte %00011000, 0, 0
!byte %00001100, 0, 0
!byte %00011110, 0, 0
!fill 40, 0
spr_enb1: ; ...and left
!byte %11000011, 0, 0
!byte %01100110, 0, 0
!byte %00111100, 0, 0
!byte %01111110, 0, 0
!byte %00111100, 0, 0
!byte %00011000, 0, 0
!byte %00110000, 0, 0
!byte %01111000, 0, 0
!fill 40, 0
SPR_RUN = spr_run0 DIV 64
SPR_SHOT = spr_shot0 DIV 64
SPR_CUR = spr_cur0 DIV 64
SPR_STING = spr_sting0 DIV 64
SPR_ENA = spr_ena0 DIV 64
SPR_ENB = spr_enb0 DIV 64
+4 -3
View File
@@ -2,7 +2,8 @@
; 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
; advances to the pyramid title card after a few seconds or
; on fire
; -----------------------------------------------------------
INTRO_LROW = 3 ; top cell row of the giant letters
@@ -78,11 +79,11 @@ iw_skip:
; fire skips, otherwise wait out the timer
jsr start_edge
beq iw_tick
+fadeto menu_init
+fadeto pyramid_init
iw_tick:
dec introt
bne iw_done
+fadeto menu_init
+fadeto pyramid_init
iw_done:
rts
+20 -17
View File
@@ -1,18 +1,21 @@
; -----------------------------------------------------------
; main.asm - LABYRINTWO for the C64
; two-player maze duel: player 1 runs the corridors toward
; the green exit portal 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
; main.asm - BLESSING OF RA for the C64
; two-player pyramid escape: player 1 is a worker sealed in
; the great pyramid, running the corridors toward the exit
; portal while dodging the scarabs and scorpions (whose
; venom stings fly down the corridors); player 2 is ra: the
; cursor rides the wall corners and fire spins the four
; wall pieces around it by 90 degrees, reshaping the maze
; under the worker's feet; eight levels, each maze one cell
; bigger than the last (4x4 up to 11x11)
;
; Files:
; defs.asm - constants, zero page, macros
; intro.asm - TTG boot logo (ported from rabbitc64)
; pyramid.asm - title card: the pyramid and the sun of ra
; menu.asm - main menu over a dark maze backdrop
; options.asm - optional extras: runner gun, spin cooldown
; rules.asm - how to play
; controls.asm- joystick + keyboard mappings
; options.asm - optional extras: worker gun, spin cooldown
; story.asm - the legend + who steers what
; credits.asm - the crew (content from rabbitc64, new look)
; play.asm - maze generation + the game itself
; win.asm - escape screen, returns to the menu
@@ -21,7 +24,7 @@
; sound.asm - single-voice SFX driver
; gfx.asm - RAM charset, sprite engine, fades
;
; Build: acme -f cbm -o labyrintwo.prg main.asm
; Build: acme -f cbm -o blessingofra.prg main.asm
; -----------------------------------------------------------
* = $0801
@@ -54,11 +57,11 @@ start:
!ifdef AUTOPLAY { ; test builds boot straight into one state
jsr play_init
} else {
!ifdef AUTORULES {
jsr rules_init
!ifdef AUTOSTORY {
jsr story_init
} else {
!ifdef AUTOCONTROLS {
jsr controls_init
!ifdef AUTOPYRAMID {
jsr pyramid_init
} else {
!ifdef AUTOOPTIONS {
jsr options_init
@@ -72,7 +75,7 @@ start:
!ifdef AUTOLOSE {
jsr lose_init
} else {
jsr intro_init ; TTG logo, then the menu
jsr intro_init ; TTG logo, then the pyramid, then the menu
}
}
}
@@ -145,10 +148,10 @@ wf_hit:
; the states and everything they share
; ============================================================
!src "intro.asm"
!src "pyramid.asm"
!src "menu.asm"
!src "options.asm"
!src "rules.asm"
!src "controls.asm"
!src "story.asm"
!src "credits.asm"
!src "play.asm"
!src "win.asm"
+39 -93
View File
@@ -1,26 +1,30 @@
; -----------------------------------------------------------
; menu.asm - full-screen menu card: big LABYRINTWO title in
; two colors (gold wash on LABYRIN, cool blue shimmer on
; TWO), and a five-item menu: play / options / rules /
; controls / credits (joystick or w/s up/down + fire, space
; or return)
; menu.asm - full-screen menu card: big BLESSING / OF RA
; title under the rolling gold sun wash, and a four-item
; menu: play / options / story / credits (joystick or w/s
; up/down + fire, space or return)
; -----------------------------------------------------------
MENU_ITEMS = 5
MENU_ITEMS = 4
menu_init:
jsr clear_screen
; a dark maze weaves behind the whole card
lda #DGREY
lda #MAZE_CW
sta mzcw
lda #MAZE_CH
sta mzch
jsr set_maze
lda #BROWN
sta latwcol
sta latpcol
jsr draw_lattice
jsr gen_init
jsr gen_maze_full
; a clean panel for the menu itself (rows 9-22, cols 4-35)
ldx #9
; a clean panel for the menu itself (rows 13-24, cols 4-35)
ldx #13
mi_panel:
stx ptmp
jsr row_ptr
@@ -35,12 +39,12 @@ mi_pcol:
bne mi_pcol
ldx ptmp
inx
cpx #23
cpx #25
bne mi_panel
+prbig 2, 0, YELLOW, txt_t1, 7
+prbig 2, 28, CYAN, txt_t2, 3
+prtext 9, 13, LGREY, txt_ttgname, 14
+prbig 1, 4, YELLOW, txt_t1, 8
+prbig 7, 10, ORANGE, txt_t2, 5
+prtext 13, 13, LGREY, txt_ttgname, 14
lda #0
sta menusel
@@ -50,58 +54,7 @@ mi_pcol:
rts
menu_update:
; the title rows 2-6: gold wash on LABYRIN (columns 0-26),
; cool blue shimmer on TWO (columns 27-38)
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 #26
mw_col:
lda (scrlo),y
cmp #$a0 ; only touch the letter blocks
bne mw_skip
lda rtmp
sta (collo),y
mw_skip:
dey
bpl mw_col
lda washphase
lsr
clc
adc g8row
and #7
tax
lda cooltbl,x
sta rtmp
ldy #38
mw_col2:
lda (scrlo),y
cmp #$a0
bne mw_skip2
lda rtmp
sta (collo),y
mw_skip2:
dey
cpy #26
bne mw_col2
inc g8row
lda g8row
cmp #5
bne mw_row
jsr wash_title ; gold sun wash on both title lines
; joystick up/down steps the cursor (edge detected)
jsr read_joy
@@ -135,8 +88,8 @@ mu_udrel:
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
+prtext 23, 7, LGREY, txt_info, txt_infoe-txt_info
+prtext 24, 11, LGREY, txt_info2, txt_info2e-txt_info2
; the menu items: the picked line is yellow
ldx #0
@@ -152,11 +105,10 @@ mm_items:
; blinking '>' cursor in front of the picked line
lda #$20
sta SCREEN+11*40+15
sta SCREEN+13*40+15
sta SCREEN+15*40+15
sta SCREEN+17*40+15
sta SCREEN+19*40+15
sta SCREEN+21*40+15
lda framectr
and #16
bne mu_start
@@ -186,18 +138,20 @@ mu_start:
cmp #1
beq mg_options
cmp #2
beq mg_rules
cmp #3
beq mg_controls
beq mg_story
+fadeto credits_init ; every screen change fades to black
mg_play:
lda #MZMIN ; a fresh run: level 1, clock zeroed
sta mzsize
lda #0
sta tframe
sta tsec
sta tmin
+fadeto play_init
mg_options:
+fadeto options_init
mg_rules:
+fadeto rules_init
mg_controls:
+fadeto controls_init
mg_story:
+fadeto story_init
mu_done:
rts
@@ -223,35 +177,27 @@ dm_store:
; ---- menu tables ----
mitem_lo:
!byte <txt_play, <txt_options, <txt_rules
!byte <txt_controls, <txt_credits
!byte <txt_play, <txt_options, <txt_story, <txt_credits
mitem_hi:
!byte >txt_play, >txt_options, >txt_rules
!byte >txt_controls, >txt_credits
mitem_len: !byte 4, 7, 5, 8, 7
mitem_row: !byte 11, 13, 15, 17, 19
!byte >txt_play, >txt_options, >txt_story, >txt_credits
mitem_len: !byte 4, 7, 5, 7
mitem_row: !byte 15, 17, 19, 21
mcur_lo: ; cursor cells: column 15 of those rows
!byte <(SCREEN+11*40+15), <(SCREEN+13*40+15)
!byte <(SCREEN+15*40+15), <(SCREEN+17*40+15)
!byte <(SCREEN+19*40+15)
!byte <(SCREEN+19*40+15), <(SCREEN+21*40+15)
mcur_hi:
!byte >(SCREEN+11*40+15), >(SCREEN+13*40+15)
!byte >(SCREEN+15*40+15), >(SCREEN+17*40+15)
!byte >(SCREEN+19*40+15)
cooltbl: ; blue-cyan-white shimmer for the TWO
!byte $06, $0e, $03, $01, $01, $03, $0e, $06
!byte >(SCREEN+19*40+15), >(SCREEN+21*40+15)
; ---- menu texts ----
txt_play: !scr "play"
txt_options: !scr "options"
txt_rules: !scr "rules"
txt_credits: !scr "credits"
txt_info: !scr "p1: joy2 / wasd - runner"
txt_info: !scr "p1: joy2/wasd - the worker"
txt_infoe:
txt_info2: !scr "p2: joy1 / ijkl - wall spinner"
txt_info2: !scr "p2: joy1/ijkl - ra"
txt_info2e:
; ---- menu variables ----
menusel: !byte 0 ; picked line: 0-2
menusel: !byte 0 ; picked line: 0-3
udheld: !byte 0 ; joystick up/down edge detection state
+4 -4
View File
@@ -1,9 +1,9 @@
{
"name": "labyrintwo",
"title": "LabyrinTwo",
"name": "blessingofra",
"title": "Blessing of Ra",
"author": "Teletype Games",
"desc": "Two-player maze duel: one player runs for the exit while the other spins the walls of the labyrintwo around their corners. Dodge the enemies, find the diamond.",
"desc": "Two-player pyramid escape: a worker sealed in the great pyramid runs for the exit while Ra bends the maze walls around him. Scarabs and scorpions - and their flying venom stings - hunt him through eight levels, from a 4x4 maze up to 11x11.",
"site": "https://git.teletype.hu/games/labyrintwo",
"license": "MIT",
"version": "1.0.0"
"version": "2.0.0"
}
+6 -6
View File
@@ -1,10 +1,10 @@
; -----------------------------------------------------------
; options.asm - optional extras, toggled with fire:
; runner gun - player 1 shoots with fire; a hit enemy
; worker gun - player 1 shoots with fire; a hit enemy
; respawns elsewhere after a pause
; spin cooldown - the wall spinner needs a recharge between
; two spins, shown on the status row
; the settings live here and survive between rounds
; spin cooldown - ra needs a recharge between two spins,
; shown on the status row
; the settings live here and survive between levels
; -----------------------------------------------------------
OPT_ITEMS = 3
@@ -173,7 +173,7 @@ ovtx_hi: !byte >txt_off, >txt_on
ovcol: !byte LGREY, LGREEN
; ---- option texts ----
txt_ogun: !scr "runner gun"
txt_ogun: !scr "worker gun"
txt_ocool: !scr "spin cooldown"
txt_oback: !scr "back"
txt_on: !scr "on "
@@ -188,7 +188,7 @@ txt_oh2e:
opt_shoot: !byte 1
opt_cool: !byte 1
} else {
opt_shoot: !byte 0 ; 0 = classic game, 1 = the runner shoots
opt_shoot: !byte 0 ; 0 = classic game, 1 = the worker shoots
opt_cool: !byte 0 ; 1 = spins need a recharge
}
optsel: !byte 0 ; picked line: 0-2
+14 -3
View File
@@ -1,6 +1,7 @@
; -----------------------------------------------------------
; over.asm - game over screen: big red GAME OVER, fire
; restarts with a fresh maze, the m key backs out to the menu
; retries the same level with a fresh maze, the m key backs
; out to the menu
; -----------------------------------------------------------
lose_init:
@@ -11,7 +12,14 @@ lose_init:
+prbig 3, 2, RED, txt_gameover, 9
+prtext 11, 10, WHITE, txt_caught, txt_caughte-txt_caught
+prtext 11, 8, WHITE, txt_caught, txt_caughte-txt_caught
lda mzsize ; which level claimed him
sec
sbc #MZMIN-1
ora #$30
sta txt_felld
+prtext 13, 10, LGREY, txt_fell, txt_felle-txt_fell
+prtext 21, 13, LGREY, txt_mmenu, txt_mmenue-txt_mmenu
@@ -51,8 +59,11 @@ lu_done:
; ---- game over texts ----
txt_gameover: !scr "game over"
txt_caught: !scr "the enemies got you"
txt_caught: !scr "the pyramid claimed you"
txt_caughte:
txt_fell: !scr "you fell on level "
txt_felld: !scr "1"
txt_felle:
txt_retry: !scr "fire = try again"
txt_retrye:
txt_mmenu: !scr "m = main menu"
+394 -116
View File
@@ -1,15 +1,20 @@
; -----------------------------------------------------------
; play.asm - the game: a fresh maze carves itself on screen
; every round (recursive backtracker, a few steps a frame),
; player 1 (joystick 2) runs the corridors toward the exit
; portal, player 2 (joystick 1) rides the wall corners and
; fire spins the four wall pieces around the cursor by 90
; degrees; the roaming enemies end the round on touch
; play.asm - the game: eight levels of pyramid maze, each one
; cell bigger than the last (4x4 up to 11x11, always square,
; centered on screen); a fresh maze carves itself at the
; start of every level (recursive backtracker, a few steps a
; frame), player 1 (joystick 2) is the trapped worker running
; for the exit, player 2 (joystick 1) is ra: the cursor rides
; the wall corners and fire spins the four wall pieces around
; it by 90 degrees; scarabs roam the corridors on the
; worker's life, and the scorpions also spit venom stings
; down them
;
; the walls, posts and the portal are chars (the screen stays
; the wall data structure), but every actor - runner, cursor,
; bullet, enemies - is a hardware sprite gliding between the
; cells; actor collisions are grid coordinate checks
; the wall data structure), but every actor - worker, cursor,
; bullet, enemies, sting - is a hardware sprite gliding
; between the cells; actor collisions are grid coordinate
; checks
;
; optional extras (see options.asm):
; opt_shoot - player 1's fire shoots a bullet in the last
@@ -19,15 +24,34 @@
; a draining 1/8-step bar on the status row
;
; screen layout: status on row 0 (over the colored raster
; band), the 39x23 maze lattice on rows 1-23, hints on row 24
; band), the centered lattice on rows 1-23, hints on row 24
; -----------------------------------------------------------
play_init:
jsr clear_screen
+prtext 0, 0, WHITE, txt_t1, 7
+prtext 0, 7, CYAN, txt_t2, 3
+prtext 0, 0, WHITE, txt_level, 5
lda mzsize ; level number 1-8 next to the label
sec
sbc #MZMIN-1
ora #$30
sta SCREEN+6
lda #YELLOW
sta COLRAM+6
+prtext 0, 34, LGREY, txt_goal, txt_goale-txt_goal
+prtext 24, 6, DGREY, txt_hint, txt_hinte-txt_hint
+prtext 24, 4, DGREY, txt_hint, txt_hinte-txt_hint
lda mzsize ; this level's lattice: a square
sta mzcw
sta mzch
jsr set_maze
lda mzsize ; one more enemy each level, capped
sec
sbc #MZMIN-1
cmp #NENEMIES
bcc pi_ne
lda #NENEMIES
pi_ne:
sta nenem
lda #COL_WALL
sta latwcol
@@ -60,26 +84,31 @@ play_start:
ps_exit:
jsr rand8
and #$0f
cmp #MAZE_CH
cmp mzch
bcs ps_exit
asl ; cell row -> screen row
clc
adc #2
asl ; cell row -> screen row (offy + 2*cy + 1)
sec
adc offy
sta exrow
tax
jsr row_ptr
ldy #38
ldy excol
lda #CH_EXIT
sta (scrlo),y
lda #COL_EXIT
sta (collo),y
; the runner starts in the top-left cell, facing right
lda #1
; the worker starts in the top-left cell, facing right
lda offx
clc
adc #1
sta px
sta fdx
lda #2
lda offy
clc
adc #1
sta py
lda #1
sta fdx
lda #0
sta fdy
lda px
@@ -90,10 +119,18 @@ ps_exit:
ldx #SP_RUN
jsr spr_jump
; the corner cursor starts on the center post
lda #18
; ra's cursor starts on the center post
lda mzcw
lsr
asl
clc
adc offx
sta kx
lda #11
lda mzch
lsr
asl
clc
adc offy
sta ky
lda #COL_HILITE
jsr mark_slots
@@ -107,9 +144,11 @@ ps_exit:
lda #WHITE
sta SPRCOL+SP_RUN
sta SPRCOL+SP_CUR
lda #YELLOW
sta SPRCOL+SP_SHOT
lda #COL_HILITE ; ra wears the sun's color
sta SPRCOL+SP_CUR
lda #COL_STING
sta SPRCOL+SP_STING
jsr spawn_enemies
@@ -122,11 +161,9 @@ ps_exit:
sta s_on
sta sx
sta sy
sta es_on
sta cool
sta rotflash
sta tframe ; the clock starts when the maze is done
sta tsec
sta tmin
lda #1
sta cfheld
sta rfheld
@@ -134,34 +171,101 @@ ps_exit:
jmp upd_sprites ; positions, shapes and enables now
; ============================================================
; maze generation - recursive backtracker over the 19x11
; cells; the screen itself is the wall data structure
; maze geometry - the lattice is sized and placed from the
; cell counts in mzcw / mzch (the levels are squares, the
; menu backdrop is the full 19x11)
; ============================================================
; fill rows 1-23 of the lattice: brick walls in latwcol, the
; pivot posts (even col, odd row) in latpcol
; from mzcw/mzch: screen offsets, the exit column, the
; visited-index multiply table, ra's post bounds and the
; enemies' spawn half
set_maze:
lda #19 ; offx = (39 - (2*cw+1)) / 2 = 19 - cw
sec
sbc mzcw
sta offx
lda #12 ; rows 1-23: offy = 12 - ch
sec
sbc mzch
sta offy
lda #0 ; multab[i] = i * mzcw
tax
sm_mul:
sta multab,x
clc
adc mzcw
inx
cpx #MZMAX
bne sm_mul
lda mzcw ; the right border column holds the exit
asl
clc
adc offx
sta excol
sec ; interior posts: offx+2 .. offx+2*cw-2
sbc #2
sta kmaxx
lda offx
clc
adc #2
sta kminx
lda mzch
asl
clc
adc offy
sec
sbc #2
sta kmaxy
lda offy
clc
adc #2
sta kminy
lda mzcw ; enemies spawn on the right half
lsr
sta enhalf
rts
; fill the lattice with sandstone in latwcol, the pivot posts
; (even local column and row) in latpcol
draw_lattice:
ldx #1
lda offy
sta ptmp
dl_fill:
stx ptmp
ldx ptmp
jsr row_ptr
ldy #38
lda mzcw
asl
sta lcnt
inc lcnt ; 2*cw+1 chars per lattice row
ldy offx
dl_col:
lda #CH_WALL
sta (scrlo),y
lda latwcol
sta (collo),y
dey
bpl dl_col
ldx ptmp
inx
cpx #24
bne dl_fill
ldx #1 ; post rows 1, 3, ... 23
iny
dec lcnt
bne dl_col
inc ptmp
lda mzch
asl
clc
adc offy ; the bottom lattice row
cmp ptmp
bcs dl_fill
lda offy ; post rows: offy, offy+2, ...
sta ptmp
dl_prow:
stx ptmp
ldx ptmp
jsr row_ptr
ldy #38 ; post columns 38, 36, ... 0
lda mzcw
asl
clc
adc offx
tay ; post columns from the right edge down
lda mzcw
sta lcnt
inc lcnt ; cw+1 posts per post row
dl_pcol:
lda #CH_POST
sta (scrlo),y
@@ -169,14 +273,23 @@ dl_pcol:
sta (collo),y
dey
dey
bpl dl_pcol
ldx ptmp
inx
inx
cpx #25
bcc dl_prow
dec lcnt
bne dl_pcol
inc ptmp
inc ptmp
lda mzch
asl
clc
adc offy
cmp ptmp
bcs dl_prow
rts
; ============================================================
; maze generation - recursive backtracker over the cells;
; the screen itself is the wall data structure
; ============================================================
; reset the generator: nothing visited, start on cell (0,0)
gen_init:
ldx #0
@@ -206,17 +319,17 @@ gm_scan:
clc
adc dxtab,x
sta gnx
cmp #MAZE_CW ; unsigned: -1 wraps to $ff and fails too
cmp mzcw ; unsigned: -1 wraps to $ff and fails too
bcs gm_next
ldx gtd
lda gcy
clc
adc dytab,x
sta gny
cmp #MAZE_CH
cmp mzch
bcs gm_next
ldx gny
lda mul19,x
lda multab,x
clc
adc gnx
tax
@@ -285,9 +398,9 @@ gen_maze_full: ; the menu backdrop wants it all at once
bcc gen_maze_full
rts
gv_mark: ; visited[gcy * 19 + gcx] = 1
gv_mark: ; visited[gcy * mzcw + gcx] = 1
ldx gcy
lda mul19,x
lda multab,x
clc
adc gcx
tax
@@ -295,17 +408,17 @@ gv_mark: ; visited[gcy * 19 + gcx] = 1
sta visited,x
rts
carve_cell: ; open the cell (2*gcx+1, 2*gcy+2)
carve_cell: ; open the cell at (offx+2*gcx+1, offy+2*gcy+1)
lda gcy
asl
clc
adc #2
sec
adc offy
tax
jsr row_ptr
lda gcx
asl
clc
adc #1
sec
adc offx
tay
lda #CH_FLOOR
sta (scrlo),y
@@ -317,8 +430,8 @@ carve_wall: ; open the wall slot toward direction gtd
ldx gtd
lda gcy
asl
clc
adc #2
sec
adc offy
clc
adc dytab,x
tax
@@ -326,8 +439,8 @@ carve_wall: ; open the wall slot toward direction gtd
ldx gtd
lda gcx
asl
clc
adc #1
sec
adc offx
clc
adc dxtab,x
tay
@@ -339,9 +452,9 @@ carve_wall: ; open the wall slot toward direction gtd
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 ----
; ---- enemies: even index = scarab, odd = scorpion; random
; right-half cells, away from the worker's start ----
spawn_enemies:
lda #0
sta ei
@@ -349,7 +462,7 @@ sn_all:
jsr spawn_one
inc ei
lda ei
cmp #NENEMIES
cmp nenem
bne sn_all
rts
@@ -357,22 +470,22 @@ spawn_one: ; place enemy ei on a random free cell
sn_rx:
jsr rand8
and #$0f
cmp #MAZE_CH
cmp mzcw
bcs sn_rx
clc
adc #MAZE_CW-MAZE_CH ; cell column 8-18: away from the start
cmp enhalf ; keep to the right half
bcc sn_rx
asl
clc
adc #1
sta ttx ; candidate screen column
sec
adc offx ; cell column -> screen column
sta ttx
sn_ry:
jsr rand8
and #$0f
cmp #MAZE_CH
cmp mzch
bcs sn_ry
asl
clc
adc #2
sec
adc offy
sta tty ; candidate screen row
ldx tty
jsr row_ptr
@@ -380,7 +493,7 @@ sn_ry:
lda (scrlo),y
cmp #CH_FLOOR ; only a carved cell will do...
bne sn_rx
lda ttx ; ...without the runner on it...
lda ttx ; ...without the worker on it...
cmp px
bne sn_free
lda tty
@@ -394,11 +507,10 @@ sn_free:
sta ex,x
lda tty
sta ey,x
jsr rand8
and #7
lda ei
and #1 ; the type wears its own color
tay
lda ecoltab,y
sta ecol,x
lda etypecol,y
sta SPRCOL+SP_EN,x
jsr rand8
and #3
@@ -416,14 +528,13 @@ sn_free:
tax
jmp spr_jump
ecoltab: ; anything but the white runner / grey walls
!byte RED, CYAN, PURPLE, YELLOW, ORANGE, LRED, LBLUE, BLUE
etypecol: !byte COL_SCARAB, COL_SCORP
; ============================================================
; one frame of play
; ============================================================
play_update:
inc tframe ; the round clock: 50 frames = one second
inc tframe ; the run clock: 50 frames = one second
lda tframe
cmp #50
bne pu_clock
@@ -453,6 +564,9 @@ pu_nocool:
jsr upd_enemies
lda endflag
bne pu_end
jsr upd_sting
lda endflag
bne pu_end
jsr upd_cursor
jsr upd_flash
jsr upd_status
@@ -467,6 +581,12 @@ pu_end:
pu_win:
lda #SFX_WIN
jsr sfx_play
lda mzsize ; the last level won: the blessing is earned
cmp #MZMAX
bcs pw_final
inc mzsize ; otherwise the next maze is one cell bigger
+fadeto play_init
pw_final:
+fadeto win_init
; ---- player 1: walk the corridors, one cell per step ----
@@ -543,6 +663,15 @@ ur_try:
bne ur_stop ; a wall or a post: blocked
jsr enemy_at ; walking into an enemy still hurts
bcs ur_dead
lda es_on ; and so does the venom sting
beq ur_go
lda ttx
cmp esx
bne ur_go
lda tty
cmp esy
beq ur_dead
ur_go:
lda ttx
sta px
lda tty
@@ -649,12 +778,12 @@ ea_loop:
rts
ea_next:
inx
cpx #NENEMIES
cpx nenem
bne ea_loop
clc
rts
; ---- player 2: the corner cursor + the wall spin ----
; ---- player 2: ra's corner cursor + the wall spin ----
upd_cursor:
jsr read_joy2
sta j2bits
@@ -689,26 +818,28 @@ uc_move:
bcs uc_down
lsr
bcs uc_left
cpx #36 ; right: interior posts end at column 36
cpx kmaxx ; right: the interior posts end here
bcs uc_fire
inx
inx
jmp uc_go
uc_up:
cpy #4 ; top interior post row is 3
cpy kminy
bcc uc_fire
beq uc_fire
dey
dey
jmp uc_go
uc_down:
cpy #21 ; bottom interior post row is 21
cpy kmaxy
bcs uc_fire
iny
iny
jmp uc_go
uc_left:
cpx #3 ; left interior post column is 2
cpx kminx
bcc uc_fire
beq uc_fire
dex
dex
uc_go:
@@ -849,13 +980,22 @@ so_norun:
jsr enemy_at
bcs so_yes
lda s_on
beq so_no
beq so_nosht
lda sx
cmp ttx
bne so_no
bne so_nosht
lda sy
cmp tty
beq so_yes
so_nosht:
lda es_on ; the sting blocks a spin too
beq so_no
lda esx
cmp ttx
bne so_no
lda esy
cmp tty
beq so_yes
so_no:
clc
rts
@@ -927,10 +1067,11 @@ ue_alive:
jsr enemy_step
lda endflag
bne ue_out
jsr try_sting
ue_next:
inc ei
lda ei
cmp #NENEMIES
cmp nenem
bne ue_loop
ue_out:
rts
@@ -970,7 +1111,7 @@ etry_dir: ; A = direction; C clear when it moved (or won)
clc
adc dytab,x
sta tty
lda px ; onto the runner: the round is over
lda px ; onto the worker: the level is over
cmp ttx
bne en_norun
lda py
@@ -1020,6 +1161,105 @@ en_move:
clc
rts
; ---- a scorpion (odd index) spits a venom sting when it
; lines up with the worker; one sting flies at a time ----
try_sting:
lda ei
and #1
beq ts_no ; scarabs do not shoot
lda es_on
bne ts_no
jsr rand8 ; menacing, not machine-gun constant
and #3
bne ts_no
ldx ei
lda ex,x
cmp px
beq ts_col
lda ey,x
cmp py
beq ts_row
ts_no:
rts
ts_col: ; same column: the sting flies vertically
lda #0
sta esdx
ldy #1
lda py
cmp ey,x
bcs ts_cgo
ldy #$ff
ts_cgo:
sty esdy
jmp ts_fire
ts_row: ; same row: horizontally
lda #0
sta esdy
ldy #1
lda px
cmp ex,x
bcs ts_rgo
ldy #$ff
ts_rgo:
sty esdx
ts_fire:
lda ex,x
sta esx
sta tgc
lda ey,x
sta esy
sta tgr
jsr set_target ; the sprite pops in on the scorpion,
ldx #SP_STING ; not gliding over from the last sting
jsr spr_jump
lda #1
sta es_on
lda #SFX_SHOT
jmp sfx_play
; ---- the sting flies a char every other frame; a wall
; swallows it, the worker dies on it ----
upd_sting:
lda es_on
beq ust_done
lda framectr
and #1
bne ust_done
lda esx
clc
adc esdx
sta ttx
lda esy
clc
adc esdy
sta tty
lda px ; onto the worker: the level is over
cmp ttx
bne ust_norun
lda py
cmp tty
bne ust_norun
lda #2
sta endflag
rts
ust_norun:
ldx tty
jsr row_ptr
ldy ttx
lda (scrlo),y
cmp #CH_FLOOR
beq ust_fly
lda #0 ; a wall swallows it
sta es_on
rts
ust_fly:
lda ttx
sta esx
lda tty
sta esy
ust_done:
rts
; ---- per-frame flashes: the portal spins and blinks, the
; freshly spun walls flash white, the cursor shows the
; recharge state on its own color ----
@@ -1027,7 +1267,7 @@ upd_flash:
jsr upd_portal ; cycle the portal glyph
ldx exrow
jsr row_ptr
ldy #38
ldy excol
lda framectr
and #8
bne uf_exw
@@ -1055,7 +1295,7 @@ uf_norf:
lda #RED
jmp uf_cset
uf_hot:
lda #WHITE
lda #COL_HILITE
uf_cset:
sta SPRCOL+SP_CUR
rts
@@ -1110,7 +1350,7 @@ us_clr:
bpl us_clr
rts
; ---- the round clock, live on the status row ----
; ---- the run clock, live on the status row ----
upd_clock:
lda tmin
jsr two_digits
@@ -1137,7 +1377,7 @@ upd_sprites:
lsr
lsr
sta frame8
; the runner glides 2 pixels a frame
; the worker glides 2 pixels a frame
lda px
sta tgc
lda py
@@ -1165,6 +1405,16 @@ upd_sprites:
jsr set_target
ldx #SP_SHOT
jsr spr_jump
; the sting glides 4: a char every other frame, smoothly
lda esx
sta tgc
lda esy
sta tgr
jsr set_target
lda #4
sta gspd
ldx #SP_STING
jsr spr_glide
; the enemies glide 1
lda #1
sta gspd
@@ -1183,9 +1433,9 @@ us_en:
jsr spr_glide
ldx ptmp
inx
cpx #NENEMIES
cpx nenem
bne us_en
; shapes: the runner bobs, each enemy waves on its own beat
; shapes: the worker bobs, each enemy waves on its own beat
lda frame8
and #1
clc
@@ -1195,6 +1445,8 @@ us_en:
sta SPRPTR+SP_CUR
lda #SPR_SHOT
sta SPRPTR+SP_SHOT
lda #SPR_STING
sta SPRPTR+SP_STING
ldx #0
us_shape:
txa
@@ -1202,23 +1454,30 @@ us_shape:
adc frame8
and #1
sta rtmp
lda #SPR_ENA ; enemies 0-1 are ghosts, 2-3 crawlers
cpx #2
bcc us_seta
txa
and #1 ; even index = scarab, odd = scorpion
beq us_scar
lda #SPR_ENB
bne us_seta ; always taken
us_scar:
lda #SPR_ENA
us_seta:
clc
adc rtmp
sta SPRPTR+SP_EN,x
inx
cpx #NENEMIES
cpx nenem
bne us_shape
; enable: runner + cursor + the bullet and the live enemies
; enable: worker + cursor + bullet, sting, live enemies
lda #%00000011
ldy s_on
beq us_nosht
ora #%00000100
us_nosht:
ldy es_on
beq us_nostg
ora #%10000000
us_nostg:
sta rtmp
ldx #0
us_alive:
@@ -1229,7 +1488,7 @@ us_alive:
sta rtmp
us_dead:
inx
cpx #NENEMIES
cpx nenem
bne us_alive
lda rtmp
sta SPR_EN
@@ -1238,18 +1497,31 @@ us_dead:
ebit: !byte 8, 16, 32, 64
; ---- play texts ----
txt_level: !scr "level"
txt_goal: !scr "exit "
!byte CH_EXIT
txt_goale:
txt_hint: !scr "p1: joy2/wasd p2: joy1/ijkl"
txt_hint: !scr "worker: joy2/wasd ra: joy1/ijkl"
txt_hinte:
txt_wait: !scr "wait"
txt_ready: !scr "ready"
; ---- play variables ----
px: !byte 0 ; runner position (screen col / row)
mzsize: !byte MZMIN ; this level's cells per side (4-11)
mzcw: !byte 0 ; lattice cells across / down
mzch: !byte 0
offx: !byte 0 ; screen offset of the lattice
offy: !byte 0
excol: !byte 0 ; screen column of the right border wall
enhalf: !byte 0 ; enemies spawn from this cell column
nenem: !byte 0 ; live enemy slots this level (1-4)
kminx: !byte 0 ; ra's interior post bounds
kmaxx: !byte 0
kminy: !byte 0
kmaxy: !byte 0
px: !byte 0 ; worker position (screen col / row)
py: !byte 0
fdx: !byte 0 ; runner facing: the gun aims this way
fdx: !byte 0 ; worker facing: the gun aims this way
fdy: !byte 0
kx: !byte 0 ; corner cursor position (post col / row)
ky: !byte 0
@@ -1262,16 +1534,22 @@ sx: !byte 0 ; bullet position and heading
sy: !byte 0
sdx: !byte 0
sdy: !byte 0
rheld: !byte 0 ; runner direction repeat state
es_on: !byte 0 ; venom sting in flight?
esx: !byte 0 ; sting position and heading
esy: !byte 0
esdx: !byte 0
esdy: !byte 0
rheld: !byte 0 ; worker direction repeat state
rtimer: !byte 0
rdir: !byte 0
rfheld: !byte 0 ; runner fire edge detection state
rfheld: !byte 0 ; worker fire edge detection state
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
lcnt: !byte 0 ; draw_lattice column counter
ttx: !byte 0 ; move target (col / row)
tty: !byte 0
nch: !byte 0 ; the four slot chars around the cursor
@@ -1281,7 +1559,7 @@ wch: !byte 0
hlcol: !byte 0 ; mark_slots color parameter
latwcol: !byte 0 ; draw_lattice colors: walls, posts
latpcol: !byte 0
tframe: !byte 0 ; round clock: frame, second, minute
tframe: !byte 0 ; run clock: frame, second, minute
tsec: !byte 0
tmin: !byte 0
frame8: !byte 0 ; framectr / 8: the animation beat
@@ -1296,10 +1574,10 @@ gtd: !byte 0
gnx: !byte 0
gny: !byte 0
gdlist: !fill 4, 0
ex: !fill NENEMIES, 0 ; enemy positions, headings, colors
multab: !fill MZMAX, 0 ; row * mzcw for the visited index
ex: !fill NENEMIES, 0 ; enemy positions and headings
ey: !fill NENEMIES, 0
edir: !fill NENEMIES, 0
ecol: !fill NENEMIES, 0
edead: !fill NENEMIES, 0 ; respawn countdown, 0 = alive
; ---- maze generator buffers ----
+116
View File
@@ -0,0 +1,116 @@
; -----------------------------------------------------------
; pyramid.asm - the title card between the TTG logo and the
; menu: big BLESSING / OF RA under the rolling gold wash, a
; sandstone pyramid rising below with the trapped worker
; glinting at its peak and the sun of ra pulsing beside it;
; advances to the menu after a few seconds or on fire
; -----------------------------------------------------------
PYR_TIME = 250 ; frames before it advances on its own
pyramid_init:
jsr clear_screen
+prbig 1, 4, YELLOW, txt_t1, 8
+prbig 7, 10, ORANGE, txt_t2, 5
; the pyramid: ten block rows, apex on row 13
lda #0
sta ptmp
py_prow:
lda #13
clc
adc ptmp
tax
jsr row_ptr
lda #19 ; row r spans columns 19-r .. 20+r
sec
sbc ptmp
tay
lda ptmp
asl
clc
adc #2 ; 2r+2 blocks on this row
sta rtmp2
py_pcol:
lda #$a0
sta (scrlo),y
ldx ptmp
lda pyrcols,x ; sunlit top, shaded base
sta (collo),y
iny
dec rtmp2
bne py_pcol
inc ptmp
lda ptmp
cmp #10
bne py_prow
; the worker glints at the peak
lda #$51 ; filled dot
sta SCREEN+12*40+19
lda #WHITE
sta COLRAM+12*40+19
; the sun of ra beside the pyramid
lda #$a0
sta SCREEN+14*40+32
sta SCREEN+14*40+33
sta SCREEN+15*40+31
sta SCREEN+15*40+32
sta SCREEN+15*40+33
sta SCREEN+15*40+34
sta SCREEN+16*40+32
sta SCREEN+16*40+33
+prtext 24, 5, LGREY, txt_pray, txt_praye-txt_pray
lda #PYR_TIME
sta pyrt
lda #0
sta washphase
+setupd pyramid_update
rts
pyramid_update:
jsr wash_title ; the gold wash rolls down the title
; the sun pulses
lda framectr
lsr
lsr
lsr
and #3
tax
lda sunpulse,x
sta COLRAM+14*40+32
sta COLRAM+14*40+33
sta COLRAM+15*40+31
sta COLRAM+15*40+32
sta COLRAM+15*40+33
sta COLRAM+15*40+34
sta COLRAM+16*40+32
sta COLRAM+16*40+33
; fire skips, otherwise wait out the timer
jsr start_edge
beq py_tick
+fadeto menu_init
py_tick:
dec pyrt
bne py_done
+fadeto menu_init
py_done:
rts
; ---- tables and texts ----
pyrcols: ; pyramid rows top to bottom
!byte YELLOW, YELLOW, ORANGE, ORANGE, ORANGE
!byte ORANGE, ORANGE, BROWN, BROWN, BROWN
sunpulse: ; the sun of ra breathes
!byte YELLOW, YELLOW, WHITE, YELLOW
txt_pray: !scr "a worker prays at the peak..."
txt_praye:
; ---- pyramid variables ----
pyrt: !byte 0 ; frames left before auto-advancing
-56
View File
@@ -1,56 +0,0 @@
; -----------------------------------------------------------
; 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
+fadeto 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:
+72
View File
@@ -0,0 +1,72 @@
; -----------------------------------------------------------
; story.asm - the legend of the trapped worker and ra, plus
; who steers what (the old rules and controls cards merged
; into one); a static card, fire returns to the menu
; -----------------------------------------------------------
story_init:
jsr clear_screen
+prbig 1, 10, WHITE, txt_story, 5
+prtext 7, 1, WHITE, txt_s1, txt_s1e-txt_s1
+prtext 8, 2, WHITE, txt_s2, txt_s2e-txt_s2
+prtext 9, 4, WHITE, txt_s3, txt_s3e-txt_s3
+prtext 10, 4, YELLOW, txt_s4, txt_s4e-txt_s4
+prtext 11, 8, YELLOW, txt_s5, txt_s5e-txt_s5
+prtext 13, 2, LRED, txt_s6, txt_s6e-txt_s6
+prtext 14, 4, LRED, txt_s7, txt_s7e-txt_s7
+prtext 16, 6, LGREEN, txt_s8, txt_s8e-txt_s8
+prtext 17, 5, LGREY, txt_s9, txt_s9e-txt_s9
+prtext 18, 10, LBLUE, txt_s10, txt_s10e-txt_s10
+prtext 19, 3, LGREY, txt_s11, txt_s11e-txt_s11
+prtext 21, 6, LGREY, txt_s12, txt_s12e-txt_s12
+setupd story_update
rts
story_update:
; blink the return prompt
lda framectr
and #32
bne st_hide
+prtext 23, 13, YELLOW, txt_return, 13
jmp st_input
st_hide:
+prtext 23, 13, YELLOW, txt_blank, 13
st_input:
jsr start_edge
beq st_stay
+fadeto menu_init
st_stay:
rts
; ---- story texts ----
txt_story: !scr "story"
txt_s1: !scr "when the great pyramid rose, a worker"
txt_s1e:
txt_s2: !scr "was sealed in its peak. he prayed to"
txt_s2e:
txt_s3: !scr "ra until the sun god took pity:"
txt_s3e:
txt_s4: !scr "now ra bends the pyramid's walls"
txt_s4e:
txt_s5: !scr "to lead the worker out."
txt_s5e:
txt_s6: !scr "beware the scarabs and the scorpions"
txt_s6e:
txt_s7: !scr "- a scorpion's sting flies far!"
txt_s7e:
txt_s8: !scr "p1 - the worker: joy2 / wasd"
txt_s8e:
txt_s9: !scr "gun: fire or space, if enabled"
txt_s9e:
txt_s10: !scr "p2 - ra: joy1 / ijkl"
txt_s10e:
txt_s11: !scr "fire spins the walls at the cursor"
txt_s11e:
txt_s12: !scr "menus: fire, space or return"
txt_s12e:
+6 -6
View File
@@ -1,6 +1,6 @@
; -----------------------------------------------------------
; win.asm - the escape screen: big ESCAPED with the gold
; wash; fire returns to the main menu
; win.asm - the escape screen after the last level: big
; ESCAPED with the gold wash; fire returns to the main menu
; -----------------------------------------------------------
win_init:
@@ -8,8 +8,8 @@ win_init:
+prbig 3, 6, YELLOW, txt_escaped, 7
+prtext 11, 15, WHITE, txt_welldone, txt_welldonee-txt_welldone
+prtext 13, 10, LGREY, txt_beaten, txt_beatene-txt_beaten
+prtext 11, 10, WHITE, txt_welldone, txt_welldonee-txt_welldone
+prtext 13, 5, LGREY, txt_beaten, txt_beatene-txt_beaten
; the round time into the readout: "time: mm:ss"
lda tmin
@@ -100,9 +100,9 @@ td_ones:
; ---- win texts ----
txt_escaped: !scr "escaped"
txt_welldone: !scr "well done!"
txt_welldone: !scr "ra smiles upon you!"
txt_welldonee:
txt_beaten: !scr "you beat labyrintwo"
txt_beaten: !scr "you escaped the pyramid of ra"
txt_beatene:
txt_time: !scr "time: "
txt_timev: !scr "00:00"