|
| 1 | +# MVP-2 Zelda-lite — asset spec |
| 2 | + |
| 3 | +Drop assets in this directory (`examples/rpg/`). Manifest format |
| 4 | +matches `examples/shooter/manifest.txt`. Once delivered, the engine |
| 5 | ++ level files get scaffolded as `rpg.bas`, `level1.bas`, |
| 6 | +`level1_cave.bas`, all consuming `maplib.bas` (per |
| 7 | +`docs/map-format.md`). |
| 8 | + |
| 9 | +## Required |
| 10 | + |
| 11 | +### Tilesets — exercises multi-tileset support |
| 12 | + |
| 13 | +``` |
| 14 | +overworld.png 256x128 cellW=32 cellH=32 32 tiles: grass, water, sand, |
| 15 | + path, tree, rock, fence, sign, |
| 16 | + flowers, etc. |
| 17 | +cave.png 256x128 cellW=32 cellH=32 32 tiles: stone floor, wall, |
| 18 | + door, stairs, torch, chest, |
| 19 | + cracked-wall variant. |
| 20 | +``` |
| 21 | + |
| 22 | +### Player + NPCs + enemies |
| 23 | + |
| 24 | +``` |
| 25 | +link.png 160x32 cellW=32 cellH=32 5 frames: idle + up + down + |
| 26 | + left + right (one frame each; |
| 27 | + animate later). |
| 28 | +npc.png 32x32 single friendly NPC sprite |
| 29 | + (old man / merchant). |
| 30 | +enemy.png 64x32 cellW=32 cellH=32 1 enemy, 2-frame walk anim |
| 31 | + (slime / octorok). |
| 32 | +``` |
| 33 | + |
| 34 | +## Optional (skip if shipping faster matters) |
| 35 | + |
| 36 | +``` |
| 37 | +items.png 64x16 cellW=16 cellH=16 4 items: heart, key, sword, |
| 38 | + gem (chest drops + HUD). |
| 39 | +heart.png 8x8 HUD heart pip (lives display). |
| 40 | +effects.png 32x32 sword-slash / sparkle one-shot. |
| 41 | +``` |
| 42 | + |
| 43 | +## Per-tileset metadata to provide |
| 44 | + |
| 45 | +For each tileset, list the **local tile ids** that fall into each |
| 46 | +category. (Per the format spec, ids are 1-based local to each sheet; |
| 47 | +0 = blank.) |
| 48 | + |
| 49 | +### `overworld.png` |
| 50 | + |
| 51 | +- **solid** (block player + projectiles): _list ids_ |
| 52 | +- **damaging** + damage value (lava / spikes — optional): _list ids_ |
| 53 | +- **kind: door** — id of any tile that triggers map transition on |
| 54 | + walk-into: _list ids_ |
| 55 | + |
| 56 | +### `cave.png` |
| 57 | + |
| 58 | +- **solid**: _list ids_ |
| 59 | +- **kind: door** (back to overworld): _list ids_ |
| 60 | +- **kind: chest** (interactable, drops items): _list ids_ |
| 61 | + |
| 62 | +## Design choices to confirm before scaffold |
| 63 | + |
| 64 | +| Decision | Default proposal | |
| 65 | +|---|---| |
| 66 | +| Overworld map size | 32 × 32 cells (1024 × 1024 px world) | |
| 67 | +| Room size | 8 × 8 cells → 4 × 4 grid = 16 rooms (Zelda 1 screen-flip) | |
| 68 | +| Cave map | separate file `level1_cave.bas`, 8 × 8 cells (single room) | |
| 69 | +| Door pairing | one overworld door → cave entry; cave stairs → back to overworld | |
| 70 | +| Combat | sword swipe on bump — kills enemy if facing it (no projectiles) | |
| 71 | +| NPC interact | walk-into-NPC opens dialogue text in HUD strip; E or SPACE dismisses | |
| 72 | +| Camera mode | `room` — snap to current 8×8 room on player crossing boundary | |
| 73 | +| HUD | top 24 px strip: hearts (lives) + dialogue text | |
| 74 | + |
| 75 | +## What this MVP validates in `docs/map-format.md` |
| 76 | + |
| 77 | +- **multi-tileset map** (`tilesets[]` length 2; layers reference |
| 78 | + `tilesetId`) |
| 79 | +- **multi-layer rendering** (terrain + decoration + hidden collision) |
| 80 | +- **camera.mode = "room"** snap behaviour |
| 81 | +- **door pairing** via `props.leadsTo` + `props.spawnAt` |
| 82 | +- **objects** with `kind: npc | enemy | door | chest | spawn` |
| 83 | +- **per-instance state** vs static tile flag (player has key 5 lives |
| 84 | + in savegame domain; tile.solid is static tileset metadata) |
| 85 | + |
| 86 | +Together with MVP-1 shooter, every concept in v1 of the format |
| 87 | +(except polygon shapes — explicitly deferred) gets exercised. |
0 commit comments