1// Tidewater: a coastline at changing tide. Hazards and identity:2// SINK (water swallows whatever enters, words included), DEFEAT (jellies),3// and transformation (becoming, or un-becoming, what crosses).4//5// Levels are drawn as text maps so nobody has to count coordinates.6// Each map row is a list of whitespace-separated cells:7// . empty8// m w r j c b s MIAU WATER ROCK JELLY CRAB BOAT SHELL (objects)9// MIAU, IS, YOU... uppercase tokens are word tiles10// a+b a stack (for example SINK+w would be a word on water)11const { word, object, level } = require('@miau/engine');1213const THINGS = { m: 'MIAU', w: 'WATER', r: 'ROCK', j: 'JELLY', c: 'CRAB', b: 'BOAT', s: 'SHELL', f: 'REEF' };1415function map(id, rows, metadata) {16 const grid = rows.map(row => row.trim().split(/\s+/));17 const width = Math.max(...grid.map(row => row.length));18 const objects = [];19 grid.forEach((row, y) => row.forEach((cell, x) => {20 if (cell === '.') return;21 cell.split('+').forEach((part, n) => {22 const uid = `${id}-${x}-${y}${n ? `-${n}` : ''}`;23 if (THINGS[part]) objects.push(object(THINGS[part], x, y, uid));24 else if (/^[A-Z]+$/.test(part)) objects.push(word(part, x, y, uid));25 else throw new Error(`${id}: unknown map cell "${part}" at column ${x + 1}, row ${y + 1}`);26 });27 }));28 return level(width, grid.length, objects, { id, ...metadata });29}3031module.exports = {32 manifest: {33 id: 'tidewater',34 name: 'Tidewater',35 version: '1.0.0',36 engine: 1,37 rules: 2, // authored against post-W6 rule semantics (D23)38 author: 'Tidewater world team',39 description: 'A coastline at changing tide. Water keeps what it takes; jellies sting; a crab sees the shore sideways.',40 world: { glyph: '🌊', tagline: 'The sea keeps whatever you give it.', accent: 'sink' },41 },42 vocabulary: ['MIAU', 'WATER', 'ROCK', 'JELLY', 'CRAB', 'BOAT', 'SHELL', 'REEF'],43 palette: {44 MIAU: { glyph: '🐈', faces: 'left' },45 WATER: '🌊',46 ROCK: '🪨',47 JELLY: '🪼',48 CRAB: '🦀',49 BOAT: '⛵',50 SHELL: '🐚',51 REEF: '🪸',52 },53 levels: [54 map('low-tide', [55 'MIAU IS YOU . . w SHELL IS WIN',56 '. . . . . w . . .',57 '. . . . . w . . .',58 '. m . . . w . s .',59 '. . . . . w . . .',60 'WATER IS SINK . . w . . .',61 '. . . . . w . . .',62 ], {63 title: 'Low tide',64 hint: 'Water only swallows things while a sentence says so.',65 category: 'required',66 introduces: ['WATER', 'SINK', 'SHELL'],67 }),68 map('paper-bridge', [69 'MIAU IS YOU . . . w SHELL IS WIN',70 'r r r r r r w . . .',71 '. . . . . r w . . .',72 '. m . . . r w . s .',73 'ROCK IS STOP . . r w . . .',74 '. . . . . r w . . .',75 '. . . . . r w WATER IS SINK',76 ], {77 title: 'Paper bridge',78 hint: 'The sea is not fussy about what you feed it.',79 category: 'required',80 introduces: ['ROCK', 'STOP'],81 }),82 map('sink-the-sting', [83 'MIAU IS YOU . . . w . . j .',84 '. . . . . . w . j s j',85 '. m . . . . w . . j .',86 '. . . . . . w . . . .',87 '. . JELLY IS DEFEAT . w . . . .',88 '. . . . . . w . . . .',89 'SHELL IS WIN . . . w WATER IS SINK',90 ], {91 title: 'Sink the sting',92 hint: 'Jellies defeat whatever is YOU. The sea can take one problem off your hands.',93 category: 'required',94 introduces: ['JELLY', 'DEFEAT'],95 }),96 map('sideways', [97 '. . . . . w w SHELL IS WIN .',98 '. . . . . w w . c . .',99 'MIAU IS YOU . . w w . . . .',100 '. . . . . w w . . . .',101 '. . . . . w w . . s .',102 'CRAB . . m . w w . . . .',103 '. . . . . w w WATER IS SINK .',104 ], {105 title: 'Sideways',106 mustForm: ['CRAB IS YOU'],107 hint: 'The shell is out of reach for a cat. Who else is on this map?',108 category: 'required',109 introduces: ['CRAB'],110 }),111 map('shell-game', [112 'j JELLY j . MIAU',113 'j IS j . IS',114 'j DEFEAT . . YOU',115 '. . . . .',116 '. SHELL . . SHELL',117 '. . . . IS',118 'm . . . WIN',119 ], {120 title: 'Shell game',121 hint: 'There is no shell on this beach. Yet.',122 category: 'required',123 introduces: ['transformation'],124 mustForm: ['JELLY IS SHELL'],125 }),126 map('one-for-the-tide', [127 '. . . . . w w SHELL IS WIN .',128 'MIAU IS YOU . . w w . . . .',129 '. . . . . w w . . . .',130 '. c c c . w w . . s .',131 '. . . . . w w . . . .',132 'CRAB m . . . w w . . . .',133 '. . . . . w w WATER IS SINK .',134 ], {135 title: 'One for the tide',136 hint: 'Every crab moves when you move. Not every crab has to arrive.',137 category: 'optional',138 introduces: ['sacrifice'],139 }),140 map('last-boat-out', [141 '. . . . w w w . . BOAT',142 '. j . . w w w . . IS',143 '. . . j w w w . b WIN',144 '. . . . w w w . . .',145 'JELLY IS DEFEAT . w w w . . WATER',146 '. . . m w w w . . IS',147 'MIAU IS YOU . w w w . . SINK',148 ], {149 title: 'Last boat out',150 hint: 'Three waves and one cat. Try reading MIAU from above.',151 mustForm: ['JELLY IS MIAU'],152 category: 'challenge',153 introduces: ['noun as predicate'],154 }),155 ],156};