From de2460845efda51820eb3c6343fb158661ae76bb Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Sun, 12 Jul 2026 18:33:51 -0500 Subject: Add 1MB roguelike, player README, and 1KB polish (#1) * commit WIP 1mb version * Fix beast-collision exploit and shadow-twist torch bug; add balance constants and mobile D-pad - Exit tiles no longer bypass the beast-adjacency death check - Shadow-twist turns now consume torch fuel like a normal wait - Extract torch/beast/relic magic numbers into named constants - Fix floor 2 beast enrage threshold (operator precedence bug) - Add viewport meta tag and on-screen D-pad for mobile play * Split game data into data.js for mod support * Add poisoned effigy hazard: decoy relics that kill on touch * Add minimalist Web Audio sound effects driven by existing fx events * Add camp-checkpoint save/continue via localStorage * Add optional floor 7 postgame descent, unlocked after winning * Add three character-class starting kits (heavy torch, swift, warded) * Check off completed roadmap items in BLUEPRINT.md * Fix relic spots colliding with higher-priority tiles across all floors RELIC_SPOTS coordinates on every floor overlapped exactly with BLOCK_SPOTS, SHRINE_SPOTS, or BRAZIER_SPOTS entries, and tile() resolves those categories before relics, so the relic silently became unreachable whenever the colliding spot was chosen. Floor 6 was the worst case: its relic and brazier candidate lists were identical, masking every relic every run. Moved each affected relic to a free, verified-floor coordinate in the same room instead. * Add player-facing README, drop dev blueprint, bump 1KB font size Replace 1mb/BLUEPRINT.md (a dev-oriented architecture doc) with a top-level README aimed at players, covering both games' controls and goals with links to the hosted versions. Also increase the 1KB version's font size for readability, trimming the now-redundant favicon-suppression tag to stay within the strict 1,024-byte budget. --- 1kb/index.html | 2 +- 1mb/data.js | 1255 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1mb/index.html | 957 ++++++++++++++++++++++++++++++++++++++++++ README.md | 69 ++++ 4 files changed, 2282 insertions(+), 1 deletion(-) create mode 100644 1mb/data.js create mode 100644 1mb/index.html create mode 100644 README.md diff --git a/1kb/index.html b/1kb/index.html index 84e8ad4..53475ea 100644 --- a/1kb/index.html +++ b/1kb/index.html @@ -1 +1 @@ -

gate

ruin.dark ahead.

left right in

bones

torch burns.dark hugs walls.

take on

beast

one eye opens.eaten

hall

stairs.bronze door.wall crack.dark arch.

stairs door crack arch

pit

too wide.dark below.

jump edge

idol

gold below.head bowed.

gold bow back

crack

cold air.fits.

squeeze return

vault

crown.small key.

crown key leave

dead.

again

key.

gate opens.dawn.

again

+

gate

ruin.dark ahead.

left right in

bones

torch burns.dark hugs walls.

take on

beast

one eye opens.eaten

hall

stairs.bronze door.wall crack.dark arch.

stairs door crack arch

pit

too wide.dark below.

jump edge

idol

gold below.head bowed.

gold bow back

crack

cold air.fits.

squeeze return

vault

crown.small key.

crown key leave

dead.

again

key.

gate opens.dawn.

again

diff --git a/1mb/data.js b/1mb/data.js new file mode 100644 index 0000000..1a9e32f --- /dev/null +++ b/1mb/data.js @@ -0,0 +1,1255 @@ +// Game data — edit this file to mod the run (floors, relics, hazards, balance). +// Loaded before the engine in index.html. +const W=12,H=12,FUEL=16 +const BEAST_CALM_RADIUS=4,BEAST_ENRAGED_SPEED=2,TORCH_DRAIN_BASE=1,TORCH_DRAIN_HAZARD=2,RELIC_SLOTS_LOW=2,RELIC_SLOTS_MID=3,RELIC_SLOTS_HIGH=4,RELIC_SLOTS_RICH_BONUS=1 +const P={g:[5,2],b:[2,2],e:[2,9],h:[2,9],p:[2,2],i:[2,2],c:[2,2],v:[2,2],d:[2,2]} +const PITS=[[ +"############", +"#OOOOOOOOOO#", +"#O....F...O#", +"#O...OO...O#", +"#O........O#", +"#O....>...O#", +"#O........O#", +"#O...OO...O#", +"#O........O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O.......OO#", +"#O.OOOOO..O#", +"#O.......OO#", +"#O..>.....O#", +"#O....F...O#", +"#O..OOOOO.O#", +"#O........O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O........O#", +"#O..OO....O#", +"#O........O#", +"#OF....>..O#", +"#O....OO..O#", +"#O........O#", +"#O..OO....O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"]] +const IDOLS=[[ +"############", +"#..........#", +"#...ggg....#", +"#...gIg....#", +"#...ggg....#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#....>.....#", +"############"],[ +"############", +"#..........#", +"#....gg....#", +"#...gIg....#", +"#....ggg...#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#....>.....#", +"############"],[ +"############", +"#..........#", +"#...gg.....#", +"#...gIgg...#", +"#.....gg...#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#....>.....#", +"############"]] +const IDOLS2=[[ +"############", +"#..........#", +"#..ggg.....#", +"#..gIgg....#", +"#....gg....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"#...>......#", +"############"],[ +"############", +"#..........#", +"#....ggg...#", +"#...ggIg...#", +"#....gg....#", +"#..........#", +"#..........#", +"#....#.....#", +"#..........#", +"#..........#", +"#.....>....#", +"############"],[ +"############", +"#..........#", +"#...gg.....#", +"#..ggIg....#", +"#...gg.....#", +"#..........#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#....>.....#", +"############"]] +const CRACKS=[[ +"############", +"#..........#", +"#.####.....#", +"#....#.....#", +"#..x.>.....#", +"#....#.....#", +"#....#.....#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#.....####.#", +"#.....#....#", +"#.....#....#", +"#...x.>....#", +"#.....#....#", +"#.....####.#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..######..#", +"#.......#..#", +"#...x...#..#", +"#....>..#..#", +"#.......#..#", +"#..######..#", +"#..........#", +"#..........#", +"#..........#", +"############"]] +const HALLS=[[ +"############", +"#..........#", +"#..a.......#", +"#......b...#", +"#..........#", +"#....c.....#", +"#......d...#", +"#..........#", +"#....F.....#", +"#....>.....#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#......b...#", +"#..........#", +"#..a.......#", +"#..........#", +"#....c..d..#", +"#..........#", +"#..F.>.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..a....b..#", +"#..........#", +"#..........#", +"#....c..F..#", +"#..........#", +"#......d...#", +"#..........#", +"#....>.....#", +"#..........#", +"############"]] +const ESCAPES=[[ +"############", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..........#", +"#...##.....#", +"#......>...#", +"#..........#", +"#.....##...#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#....##....#", +"#..........#", +"#..........#", +"#..>.......#", +"#.......##.#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"]] +const BEASTS=[[10,8],[9,7]] +const PITS2=[[ +"############", +"#OOOOOOOOOO#", +"#O..FOOO..O#", +"#O...OO...O#", +"#O........O#", +"#O...O>O..O#", +"#O........O#", +"#O...OO...O#", +"#O..OOOO..O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O......OOO#", +"#O.OOOOO..O#", +"#O....O...O#", +"#O..O>O...O#", +"#O....F...O#", +"#O..OOOOO.O#", +"#O....O...O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O....O...O#", +"#O..OOO...O#", +"#O........O#", +"#OF..O.>..O#", +"#O....OOO.O#", +"#O........O#", +"#O..OOO...O#", +"#O....O...O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O..F.....O#", +"#O.OOOO...O#", +"#O.....O..O#", +"#O..>.OO..O#", +"#O.....O..O#", +"#O...OOOO.O#", +"#O........O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"]] +const CRACKS2=[[ +"############", +"#.....x....#", +"#.#####....#", +"#....##....#", +"#..x.>#....#", +"#....##....#", +"#....##....#", +"#.....x....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....x.....#", +"#.....####.#", +"#....##....#", +"#....##....#", +"#...x.>....#", +"#....##....#", +"#.....####.#", +"#....x.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....x.....#", +"#..######..#", +"#.... ..#..#", +"#...x...#..#", +"#..x.>..#..#", +"#.......#..#", +"#..######..#", +"#....x.....#", +"#..........#", +"#..........#", +"############"]].map(m=>m.map(r=>r.replace(/ /g,"."))) +const HALLS2=[[ +"############", +"#..........#", +"#..a...b...#", +"#..........#", +"#....F.....#", +"#....c.....#", +"#......d...#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#....b.....#", +"#..a.......#", +"#....F.....#", +"#....c..d..#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..a....b..#", +"#....F.....#", +"#..........#", +"#....c.....#", +"#......d...#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"############"]] +const ESCAPES2=[[ +"############", +"#....##....#", +"#..........#", +"#..........#", +"#...>......#", +"#..........#", +"#..##......#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#...##.....#", +"#..........#", +"#..>.......#", +"#..........#", +"#.....##...#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..##......#", +"#..........#", +"#..>....##.#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"]] +const BEASTS2=[[9,8],[9,7],[10,7]] +const PITS3=[[ +"############", +"#OOOOOOOOOO#", +"#O..SFOO..O#", +"#O...OO...O#", +"#O........O#", +"#O...O>O..O#", +"#O........O#", +"#O...OO...O#", +"#O..OOOO..O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O.....SOOO#", +"#O.OOOOO..O#", +"#O....O...O#", +"#O..O>O...O#", +"#O....F...O#", +"#O..OOOOO.O#", +"#O....O...O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O....O...O#", +"#O..OOO...O#", +"#O....S...O#", +"#OF..O.>..O#", +"#O....OOO.O#", +"#O........O#", +"#O..OOO...O#", +"#O....O...O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O..S.O...O#", +"#O..OOO...O#", +"#O........O#", +"#O...O.>..O#", +"#O....OOO.O#", +"#O....F...O#", +"#O..OOO...O#", +"#O....O...O#", +"#OOOOOOOOOO#", +"############"]] +const IDOLS3=[[ +"############", +"#..........#", +"#..ggg.....#", +"#..gISg....#", +"#....gg....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"#...>......#", +"############"],[ +"############", +"#..........#", +"#....ggg...#", +"#...gSIg...#", +"#....gg....#", +"#..........#", +"#..........#", +"#....#.....#", +"#..........#", +"#..........#", +"#.....>....#", +"############"],[ +"############", +"#..........#", +"#...gg.....#", +"#..gSIg....#", +"#...gg.....#", +"#..........#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#....>.....#", +"############"]] +const CRACKS3=[[ +"############", +"#....Sx....#", +"#.#####....#", +"#....##....#", +"#..x.>#....#", +"#....##....#", +"#....##....#", +"#.....x....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....x.....#", +"#...S.####.#", +"#....##....#", +"#....##....#", +"#...x.>....#", +"#....##....#", +"#.....####.#", +"#....x.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....x.....#", +"#..######..#", +"#....S..#..#", +"#...x...#..#", +"#..x.>..#..#", +"#.......#..#", +"#..######..#", +"#....x.....#", +"#..........#", +"#..........#", +"############"]] +const HALLS3=[[ +"############", +"#..........#", +"#..a..S.b..#", +"#..........#", +"#....F.....#", +"#....c.....#", +"#......d...#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#....b..S..#", +"#..a.......#", +"#....F.....#", +"#....c..d..#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..a....b..#", +"#....F..S..#", +"#..........#", +"#....c.....#", +"#......d...#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..a..S.b..#", +"#....F.....#", +"#..........#", +"#....c.....#", +"#......d...#", +"#..........#", +"#....>..F..#", +"#..........#", +"#..........#", +"############"]] +const ESCAPES3=[[ +"############", +"#....##....#", +"#..........#", +"#....S.....#", +"#...>......#", +"#..........#", +"#..##......#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#...##.....#", +"#....S.....#", +"#....>.....#", +"#..........#", +"#.....##...#", +"#..........#", +"#..##......#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..##......#", +"#....S.....#", +"#..>....##.#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....##....#", +"#..........#", +"#..S.......#", +"#....>.....#", +"#..........#", +"#..##..S...#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"############"]] +const BEASTS3=[[9,8],[9,7],[9,6],[10,7]] +const ESCAPES4=[[ +"############", +"#....##....#", +"#....S.....#", +"#..........#", +"#...>......#", +"#..........#", +"#..##......#", +"#......S...#", +"#......##..#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#...##.....#", +"#....S.....#", +"#..>.......#", +"#..........#", +"#.....##...#", +"#.....S....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..##......#", +"#....S.....#", +"#..>....##.#", +"#..........#", +"#......##..#", +"#.....S....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....##....#", +"#..........#", +"#..S.......#", +"#....>.....#", +"#..........#", +"#..##..S...#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"############"]] +const BEASTS4=[[9,8],[10,8],[9,7],[10,7]] +const PITS4=[[ +"############", +"#OOOOOOOOOO#", +"#O..SFOO..O#", +"#O.O.OO...O#", +"#O........O#", +"#O..OO>O..O#", +"#O........O#", +"#O...OO...O#", +"#O..OOOO..O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O....SO..O#", +"#O.OOOOO..O#", +"#O....O...O#", +"#O..O>O...O#", +"#O....F...O#", +"#O..OOOOO.O#", +"#O....O...O#", +"#O........O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O....O...O#", +"#O..OOO...O#", +"#O....S...O#", +"#OF..O.>..O#", +"#O....OOO.O#", +"#O........O#", +"#O..OOO...O#", +"#O....O...O#", +"#OOOOOOOOOO#", +"############"],[ +"############", +"#OOOOOOOOOO#", +"#O..F.O...O#", +"#O..OOO...O#", +"#O....S...O#", +"#O...O.>..O#", +"#O....OOO.O#", +"#O........O#", +"#O..OOO...O#", +"#O....O...O#", +"#OOOOOOOOOO#", +"############"]] +const IDOLS4=[[ +"############", +"#..........#", +"#..ggg.....#", +"#..gISg....#", +"#...Sgg....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"#...>......#", +"############"],[ +"############", +"#..........#", +"#....ggg...#", +"#...gSIg...#", +"#....gg....#", +"#....S.....#", +"#..........#", +"#....#.....#", +"#..........#", +"#..........#", +"#.....>....#", +"############"],[ +"############", +"#..........#", +"#...gg.....#", +"#..gSIg....#", +"#...gg..S..#", +"#..........#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#....>.....#", +"############"]] +const CRACKS4=[[ +"############", +"#....Sx....#", +"#.#####....#", +"#....##....#", +"#..x.>#....#", +"#....##....#", +"#....##....#", +"#..x.......#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....x.....#", +"#...S.####.#", +"#....##....#", +"#....##....#", +"#..xx.>....#", +"#....##....#", +"#.....####.#", +"#....x.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....x.....#", +"#..######..#", +"#....S..#..#", +"#...x...#..#", +"#..x.>..#..#", +"#...x...#..#", +"#..######..#", +"#....x.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..S.x.....#", +"#..######..#", +"#.......#..#", +"#..xx...#..#", +"#....>..#..#", +"#.......#..#", +"#..######..#", +"#....x.....#", +"#..........#", +"#..........#", +"############"]] +const HALLS4=[[ +"############", +"#..........#", +"#..a..S.b..#", +"#..........#", +"#....F.....#", +"#....c.....#", +"#......d...#", +"#.....S....#", +"#....>.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#....b..S..#", +"#..a.......#", +"#....F.....#", +"#....c..d..#", +"#.....S....#", +"#....>.....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..a....b..#", +"#....F..S..#", +"#..........#", +"#....c.....#", +"#......d...#", +"#.....S....#", +"#....>.....#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..a..S.b..#", +"#....F.....#", +"#..........#", +"#....c.....#", +"#...S..d...#", +"#..........#", +"#....>..F..#", +"#..........#", +"#..........#", +"############"]] +const ESCAPES5=[[ +"############", +"#....##....#", +"#....S.....#", +"#..........#", +"#...>......#", +"#..........#", +"#..##......#", +"#..........#", +"#......##..#", +"#....S.....#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#...##.....#", +"#....S.....#", +"#..>.......#", +"#..........#", +"#.....##...#", +"#....S.....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..##......#", +"#....S.....#", +"#..>....##.#", +"#..........#", +"#......##..#", +"#....S.....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....##....#", +"#..........#", +"#..S.......#", +"#....>.....#", +"#..........#", +"#..##..S...#", +"#..........#", +"#......##..#", +"#....S.....#", +"#..........#", +"############"]] +const BEASTS5=[[10,8],[10,7],[9,7],[9,6]] +const ESCAPES6=[[ +"############", +"#....##....#", +"#....S.....#", +"#..........#", +"#...>......#", +"#....S.....#", +"#..##......#", +"#......S...#", +"#......##..#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#...##.....#", +"#....S.....#", +"#..>.......#", +"#.....S....#", +"#.....##...#", +"#.....S....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#..........#", +"#..##......#", +"#....S.....#", +"#..>....##.#", +"#.....S....#", +"#......##..#", +"#.....S....#", +"#..........#", +"#..........#", +"#..........#", +"############"],[ +"############", +"#....##....#", +"#....S.....#", +"#..S.......#", +"#....>.....#", +"#..........#", +"#..##..S...#", +"#..........#", +"#......##..#", +"#..........#", +"#..........#", +"############"]] +const BEASTS6=[[10,8],[10,7],[9,7],[10,6]] +const LEVEL_ORDER=[1,2,3,4,5,6] +const LEVEL_ARCS={1:"foundation",2:"pressure",3:"ward",4:"hunt",5:"hollow",6:"finale",7:"afterglow"} +const MODES={ + standard:{label:"standard",desc:"full campaign"}, + iron:{label:"iron",desc:"early beast"}, + greed:{label:"greed",desc:"hot relics, costly gold"}, + dark:{label:"dark",desc:"weak flame, fast dread"}, + daily:{label:"daily",desc:"fixed daily seed"}, + heavy:{label:"heavy torch",desc:"starts lit, more fuel"}, + swift:{label:"swift",desc:"pits never catch you"}, + warded:{label:"warded",desc:"starts warded, wards hold longer"} +} +const MODE_IDS=Object.keys(MODES) +const MODS={ + thin:{label:"thin flame",desc:"torches burn faster"}, + wake:{label:"wakeful beast",desc:"the beast starts hotter"}, + rich:{label:"rich relics",desc:"more relics surface"}, + gloom:{label:"heavy dread",desc:"darkness grips sooner"}, + grace:{label:"strong shrines",desc:"wards hold longer"} +} +const MOD_IDS=Object.keys(MODS) +const FLOOR_TEXT={ + 1:["A first descent through stale rites.","The old ruin still pretends to be fair."], + 2:["Pressure arrives before understanding catches up.","Every branch feels closer to pursuit."], + 3:["Wards answer, but never for free.","Blessing and burden share the same stone."], + 4:["The hunt floor wants you heard.","Noise becomes destiny down here."], + 5:["The hollow floor strips runs to their bones.","Only the sharpest choices still matter."], + 6:["The last gate weighs what you became.","Every surviving system cashes in here."], + 7:["Dawn should have ended this. The ruin has other plans.","Nothing left down here owes you mercy."] +} +const FLOOR_THEMES={ + 1:{name:"foundation",tag:"stale rite",accent:"verdigris",fog:"soft lantern fog"}, + 2:{name:"pressure",tag:"ember choke",accent:"rust flare",fog:"hot dust"}, + 3:{name:"ward",tag:"cold liturgy",accent:"aqua ward",fog:"glass mist"}, + 4:{name:"hunt",tag:"rose alarm",accent:"pink hunt",fog:"thin red haze"}, + 5:{name:"hollow",tag:"ash hush",accent:"bone gray",fog:"dry blackout"}, + 6:{name:"finale",tag:"crown weather",accent:"gold ruin",fog:"judging dark"}, + 7:{name:"afterglow",tag:"borrowed dawn",accent:"ash gold",fog:"embered haze"} +} +const ENEMY_TEXT={ + beast:["A one-eyed pursuer that reads space better than fear.","It wants a lane, not a duel."], + shade:["A cold pass-through that feeds dread and tells on you.","It does not block the path; it poisons it."], + watcher:["A fixed witness that turns position into pursuit.","Quiet fails where it stands."], + leech:["A grave thing that eats ward and heat.","It survives by thinning what protects you."], + effigy:["A second relic, and a third. Only one is true.","The others were never meant to be found."] +} +const SHRINE_TEXT=[ + "The shrine lends shape to your nerve.", + "A ward forms, thin and listening.", + "The shrine answers, and the answer is costly." +] +const BRAZIER_TEXT=[ + "The brazier spits up old warmth.", + "A hungry flame leans toward your torch.", + "The coals remember better fires than yours." +] +const CURSE_TEXT=[ + "The stone bites back.", + "A mean seam in the floor wakes underfoot.", + "The room answers touch with dread." +] +const SFX_MAP={ + hit:{freq:180,dur:.08,type:"square"}, + beast:{freq:90,dur:.12,type:"sawtooth"}, + win:{freq:660,dur:.4,type:"sine"}, + relic:{freq:520,dur:.15,type:"triangle"}, + ward:{freq:340,dur:.2,type:"sine"}, + shift:{freq:220,dur:.1,type:"sine"}, + dead:{freq:70,dur:.5,type:"sawtooth"} +} +const FINALE_NAMES=["Ash Gate","Gold Gate","Hush Gate","Ward Gate"] +const INTRO_TEXT=["Move with arrows or WASD.","Carry flame. Bow for gold.","Wards hold. Cracks strip. The beast reads haste."].join("\n") +const HINT_TEXT={ + torch:"Take the torch early. Darkness taxes every step without it.", + ward:"Shrines raise ward. Ward softens dark pressure, then burns down.", + crack:"Cracks are fast but costly. Mask or ward makes the crossing safer.", + beast:"Fire slows pursuit. A dropped torch can buy one clean lane." +} +const RELICS={ + ember:{name:"ember heart",label:"ember",up:"slower torch drain",down:"beast ignores dropped flame"}, + tooth:{name:"gold tooth",label:"tooth",up:"gold slips the crack",down:"beast enrages sooner"}, + hush:{name:"hush bell",label:"hush",up:"dread stays low",down:"fire never slows beast"}, + eye:{name:"idol eye",label:"eye",up:"idol bows easier, shrines strengthen",down:"crown scorches torch"}, + brand:{name:"night brand",label:"brand",up:"shades break on touch",down:"cursed ground bites harder"}, + wick:{name:"long wick",label:"wick",up:"sight and dropped flame last longer",down:"carried torch burns hotter"}, + chain:{name:"ward chain",label:"chain",up:"wards and shrines linger",down:"gold no longer softens torch loss"}, + veil:{name:"veil thread",label:"veil",up:"mask protects torch through the crack",down:"shrines grant less"}, + greave:{name:"pit greaves",label:"greave",up:"pit footing stays sure",down:"crack crossings cost extra"}, + lure:{name:"lure spool",label:"lure",up:"dropped flame always pulls the beast",down:"carried fire never slows it"}, + salt:{name:"salt sigil",label:"salt",up:"watchers and curses bite softer",down:"shades drain more torch"}, + ash:{name:"ash lung",label:"ash",up:"braziers flare stronger",down:"shrines sip your torch"} +} +const RELIC_IDS=Object.keys(RELICS) +const RELIC_SPOTS={ +1:[["b",7,2],["v",8,8],["h",6,6]], +2:[["h",6,6],["v",5,8],["p",8,8]], +3:[["i",2,8],["c",2,1],["v",8,8],["h",6,6]], +4:[["h",5,6],["i",5,8],["p",8,8],["v",8,8]], +5:[["h",5,6],["i",5,8],["c",2,1],["v",5,8],["p",8,8]], +6:[["e",7,3],["e",9,5],["e",5,8]], +7:[["h",5,6],["i",5,8],["c",2,1],["v",5,8],["p",8,8]] +} +const EFFIGY_SPOTS={ +1:[], +2:[["v",9,8]], +3:[["v",9,8]], +4:[["v",9,8]], +5:[["v",9,8]], +6:[], +7:[["v",9,8]] +} +const BRAZIER_SPOTS={ +1:[["h",8,8],["p",2,8]], +2:[["h",8,8],["v",2,8],["c",8,8]], +3:[["h",8,8],["i",8,8],["p",2,8],["v",2,8]], +4:[["h",8,8],["i",8,8],["p",2,8],["v",2,8]], +5:[["h",8,8],["i",8,8],["p",2,8],["v",2,8],["c",8,8]], +6:[["e",8,2],["e",2,8],["e",8,8]], +7:[["h",8,8],["i",8,8],["p",2,8],["v",2,8],["c",8,8]] +} +const SHRINE_SPOTS={ +1:[["i",2,8]], +2:[["h",8,4],["v",8,8]], +3:[["h",8,4],["i",8,8],["c",8,8]], +4:[["h",8,4],["i",8,8],["c",8,8],["p",8,4]], +5:[["h",8,4],["i",8,8],["c",8,8],["v",8,8],["p",8,4]], +6:[["e",8,4],["e",3,3],["e",8,8]], +7:[["h",8,4],["i",8,8],["c",8,8],["v",8,8],["p",8,4]] +} +const CURSE_SPOTS={ +1:[["h",8,8],["p",8,2],["c",8,8]], +2:[["h",7,4],["c",2,1],["p",8,8],["v",8,4]], +3:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4]], +4:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4]], +5:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4],["b",8,8]], +6:[["e",8,8],["e",2,2],["e",8,2],["e",3,8]], +7:[["h",7,4],["i",8,8],["c",7,1],["p",8,8],["v",8,4],["b",8,8]] +} +const SHADE_SPOTS={ +1:[["h",9,4],["p",8,8]], +2:[["h",9,4],["c",8,8],["v",8,8]], +3:[["h",9,4],["i",8,8],["c",8,8],["p",8,4]], +4:[["h",9,4],["i",8,8],["c",8,8],["p",8,4],["v",8,8]], +5:[["h",9,4],["i",8,8],["c",8,8],["p",8,4],["v",8,8],["b",8,8]], +6:[["e",8,8],["e",2,8],["e",8,2],["e",3,8]], +7:[["h",9,4],["i",8,8],["c",8,8],["p",8,4],["v",8,8],["b",8,8]] +} +const BLOCK_SPOTS={ +1:[], +2:[["h",7,8],["p",2,8],["v",2,4]], +3:[["h",7,8],["p",2,8],["c",8,2],["v",2,4]], +4:[["h",7,8],["p",2,8],["c",8,2],["v",2,4],["b",8,8]], +5:[["h",7,8],["p",2,8],["c",8,2],["v",2,4],["b",8,8],["i",8,4]], +6:[["e",2,4],["e",7,7],["e",2,7]], +7:[["h",7,8],["p",2,8],["c",8,2],["v",2,4],["b",8,8],["i",8,4]] +} +const WATCHER_SPOTS={ +1:[], +2:[["h",8,8],["v",8,8]], +3:[["h",8,8],["c",2,8],["v",8,8]], +4:[["h",8,8],["c",2,8],["p",8,8],["v",8,8]], +5:[["h",8,8],["c",2,8],["p",8,8],["v",8,8],["i",8,8]], +6:[["e",8,2],["e",2,8]], +7:[["h",8,8],["c",2,8],["p",8,8],["v",8,8],["i",8,8]] +} +const LEECH_SPOTS={ +1:[], +2:[], +3:[["p",8,8],["c",8,8]], +4:[["p",8,8],["c",8,8],["v",8,8]], +5:[["p",8,8],["c",8,8],["v",8,8],["h",8,4]], +6:[["e",8,8],["e",3,3]], +7:[["p",8,8],["c",8,8],["v",8,8],["h",8,4]] +} +const LEVELS={ +1:{pits:PITS,idols:IDOLS,cracks:CRACKS,halls:HALLS,escapes:ESCAPES,beasts:BEASTS,dark:"pecv",tone:"The air is stale with old rites."}, +2:{pits:PITS2,idols:IDOLS2,cracks:CRACKS2,halls:HALLS2,escapes:ESCAPES2,beasts:BEASTS2,dark:"behipcv",tone:"The ruin tightens. It knows your name now."}, +3:{pits:PITS3,idols:IDOLS3,cracks:CRACKS3,halls:HALLS3,escapes:ESCAPES3,beasts:BEASTS3,dark:"behipcv",tone:"The shrines still answer, but every blessing exacts a price."}, +4:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES4,beasts:BEASTS4,dark:"behipcv",tone:"The hunt floor listens for every sound you make."}, +5:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES5,beasts:BEASTS5,dark:"behipcv",tone:"The hollow floor strips away whatever was merely enough."}, +6:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES6,beasts:BEASTS6,dark:"behipcv",tone:"The final gate wakes. Everything left in you will be tested."}, +7:{pits:PITS4,idols:IDOLS4,cracks:CRACKS4,halls:HALLS4,escapes:ESCAPES6,beasts:BEASTS6,dark:"behipcv",tone:"You already won. The ruin didn't agree to let you leave."} +} +const BASE={ +g:{m:[ +"############", +"#..........#", +"#..L.....R.#", +"#..........#", +"#..........#", +"#....>.....#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],ex:{">":"h",L:"b",R:"e"}}, +b:{m:[ +"############", +"#..........#", +"#...MT.....#", +"#..........#", +"#..........#", +"#.....>....#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"############"],ex:{">":"h"}}, +v:{m:[ +"############", +"#..........#", +"#....C.K...#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#..........#", +"#....>.....#", +"#..........#", +"############"],ex:{">":"e"}}, +d:{m:["############","#..........#","#..........#","#..........#","#....X.....#","#..........#","#..........#","#..........#","#..........#","#..........#","#..........#","############"],ex:{}} +} +const BASE2={ +g:{m:[ +"############", +"#..........#", +"#..L..#..R.#", +"#..........#", +"#....#.....#", +"#....>.....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"############"],ex:{">":"h",L:"b",R:"e"}}, +b:{m:[ +"############", +"#..........#", +"#...MT.....#", +"#....#.....#", +"#..........#", +"#..#..>....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"############"],ex:{">":"h"}}, +v:{m:[ +"############", +"#..........#", +"#...#C.K...#", +"#..........#", +"#....#.....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#...>......#", +"#..........#", +"############"],ex:{">":"e"}}, +d:BASE.d +} +const BASE3={ +g:{m:[ +"############", +"#..........#", +"#..L..S..R.#", +"#..........#", +"#....#.....#", +"#....>.....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"############"],ex:{">":"h",L:"b",R:"e"}}, +b:{m:[ +"############", +"#..........#", +"#..SMT.....#", +"#....#.....#", +"#..........#", +"#..#..>....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#..........#", +"############"],ex:{">":"h"}}, +v:{m:[ +"############", +"#..........#", +"#...#C.K.S.#", +"#..........#", +"#....#.....#", +"#..........#", +"#.....#....#", +"#..........#", +"#..........#", +"#...>......#", +"#..........#", +"############"],ex:{">":"e"}}, +d:BASE.d +} +const BASES={1:BASE,2:BASE2,3:BASE3,4:BASE3,5:BASE3,6:BASE3,7:BASE3} diff --git a/1mb/index.html b/1mb/index.html new file mode 100644 index 0000000..32cc57c --- /dev/null +++ b/1mb/index.html @@ -0,0 +1,957 @@ +1MB Roguelike v1 + +
+ + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f2e6ae5 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# Micro-Roguelike + +Two tiny roguelikes, built at two very different size limits. Explore, grab loot, don't die, try to make it out. + +Pick one and open it in your browser — no install, no account, nothing to download but the file itself. + +--- + +## 1MB Version — the full game + +**[Play it](https://rogue.zerolabs.sh/1mb/)** + +A proper dungeon crawl: a 12x12 grid, torches and shadows, a beast that hunts you, and six floors between you and daylight (plus a secret seventh, if you make it out alive). + +### Goal +Reach the gate on floor 6 carrying the crown and the key. Survive long enough to use them. + +### Controls +| Key | Action | +|---|---| +| Arrow keys / WASD | Move | +| Space or `.` | Wait a turn | +| `t` | Drop your torch | +| `m` | Mute / unmute sound | +| `r` | Restart | +| `c` | Continue a saved run (from the title screen) | + +On mobile, an on-screen D-pad appears automatically. + +### The basics +- **Torch** — keeps the dark at bay. It burns down over time and can be refueled at braziers. +- **Ward** — a temporary shield. Shrines can raise one for you. +- **Relics** — pick one up for a real edge, with a real cost. Only one at a time. +- **Curses, shades, watchers, leeches** — the ruin's hazards. Learn to read them. +- **The beast** — always out there, always listening. It gets faster the deeper you go. + +Between floors, you'll stop at a camp and choose an upgrade for the road ahead. Your progress is saved automatically at each camp, so you can pick up where you left off. + +### Game modes +From the title screen, press a number to start: + +1. **Standard** — the full campaign, as intended +2. **Iron** — the beast wakes up early +3. **Greed** — richer loot, steeper prices +4. **Dark** — a weaker flame and faster dread +5. **Daily** — everyone gets the same seed today +6. **Heavy** — start with a lit torch and extra fuel +7. **Swift** — pits can't catch you +8. **Warded** — start already shielded + +Win once, and a hidden seventh floor opens up — for anyone who isn't done yet. + +--- + +## 1KB Version — the hypertext original + +**[Play it](https://rogue.zerolabs.sh/1kb/#g)** + +The whole game fits in about a kilobyte of HTML. No JavaScript — just links between rooms. Click your way through the ruin: find the torch, dodge the beast, don't reach for the wrong thing. + +### Controls +Click the links. That's it. + +### Goal +Find the key and the crown, and make it back out through the gate. Die, and you're one click from trying again. + +--- + +*Both versions are free and open source, licensed under the GPLv3 — see [LICENSE](LICENSE).* -- cgit v1.2.3