- commit
- 52483d92ecd1c812bcd17de47a76aaf5aceba6d1
- parent
- c6022a1d7b85d238095f013e94176abc4758a7d6
- author
- Dami <dami.etoile@gmail.com>
| M | docs/ | 14 | +++++++++++--- |
| M | src/ | 9 | ++++++++- |
| M | tests/ | 25 | +++++++++++++++++++++++++ |
@@ -153,9 +153,13 @@ observable for debugging and deterministic for mods.
153153 a new deterministic substep, then re-run rule and interaction phases if154154 they changed text or occupancy. Cap cascading substeps and report a cycle.155155 9. **Evaluate goals.** Evaluate `WIN` and mod goals against the settled state.156- If both win and defeat occur in a turn, use the explicit goal policy (the157- recommended default is defeat before win unless the level opts into158- “reaching win ends immediately”).156+ A surviving object with both `YOU` and `WIN` satisfies the goal by itself;157+ a `YOU` object and a distinct `WIN` object satisfy it when they share a158+ cell. Evaluate this after `SINK` and `DEFEAT` removals. If both win and159+ defeat occur in a turn, use the explicit goal policy (the recommended160+ default is defeat before win unless the level opts into “reaching win ends161+ immediately”). This self-win behavior is supported by Hempuli's patch note162+ for `EMPTY IS YOU AND WIN AND DEFEAT` ([official patch notes](https://www.hempuli.com/blog/index.php?page=8)).159163 10. **Commit presentation.** Emit a replay event list, sound/effect cues, and160164 text highlighting. Rendering and particles must not mutate simulation161165 state.@@ -248,3 +252,7 @@ and limited player access to the worst cases, while treating `IF` as not worth
248252 the implementation pain at that stage ([GDC talk PDF](https://media.gdcvault.com/gdc2020/presentations/Reading%20the%20rules_Teikari_Arvi.pdf), pp. 19–21).249253 That is a useful product constraint: keep the grammar deliberately small and250254 make quirky extensions opt-in and testable.255+256+## Sources257+258+- Hempuli, [official Baba Is You patch notes](https://www.hempuli.com/blog/index.php?page=8), documenting the `EMPTY IS YOU AND WIN AND DEFEAT` win-condition fix.@@ -117,6 +117,13 @@ export function createGame(level) {
117117 const removed = new Set();118118 const causes = new Map();119119 for (const occupants of cells.values()) {120+ // A single entity can carry both YOU and WIN after a rule changes. It121+ // wins without needing a second occupant in its cell.122+ if (occupants.length === 1) {123+ const only = occupants[0];124+ if (properties(only).has('YOU') && properties(only).has('WIN')) state.won = true;125+ continue;126+ }120127 if (occupants.length < 2) continue;121128 if (occupants.some(o => properties(o).has('SINK'))) { occupants.forEach(o => { removed.add(o.id); causes.set(o.id, { cause: 'sink', at: { x: o.x, y: o.y }, noun: o.noun, text: o.text }); }); continue; }122129 const survivors = occupants.filter(o => !removed.has(o.id));@@ -125,7 +132,7 @@ export function createGame(level) {
125132 const remaining = survivors.filter(o => !removed.has(o.id));126133 const remainingYou = remaining.filter(o => properties(o).has('YOU'));127134 const win = remaining.filter(o => properties(o).has('WIN'));128- if (remainingYou.some(a => win.some(b => a.id !== b.id))) state.won = true;135+ if (remainingYou.length && win.length) state.won = true;129136 }130137 if (removed.size) state.objects = state.objects.filter(o => !removed.has(o.id));131138 return causes;@@ -100,6 +100,31 @@ test('dynamic rules apply after words move and noun transformation is determinis
100100 assert.equal(game.getState().objects.find(o => o.id === 'ROCK-2-3').noun, 'WALL');101101 });102102 103+test('a YOU object wins when a formed rule also gives it WIN', () => {104+ const game = createGame(level([105+ word('MIAU', 0, 0), word('IS', 1, 0), word('YOU', 2, 0), word('AND', 3, 0),106+ word('WIN', 4, 1, 'win-word'), object('MIAU', 4, 2, 'player'),107+ ]));108+ assert.equal(game.getState().won, false);109+110+ const event = game.step(0, -1);111+ assert.equal(event.accepted, true);112+ assert.equal(game.has('MIAU', 'WIN'), true);113+ assert.equal(game.getState().won, true);114+});115+116+test('a singleton object with YOU and WIN is won on load and reset', () => {117+ const game = createGame(level([118+ word('MIAU', 0, 0), word('IS', 1, 0), word('YOU', 2, 0), word('AND', 3, 0), word('WIN', 4, 0),119+ object('MIAU', 6, 2, 'player'),120+ ]));121+ assert.equal(game.getState().won, true);122+ game.step(1, 0);123+ const reset = game.reset();124+ assert.equal(reset.kind, 'reset');125+ assert.equal(game.getState().won, true);126+});127+103128 test('WIN, SINK and DEFEAT resolve on contact', () => {104129 const game = createGame(level([105130 word('BABA', 0, 0), word('IS', 1, 0), word('YOU', 2, 0),