@storylet-studio/runtime 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2090,28 +2090,42 @@ var Flow = class {
2090
2090
  }
2091
2091
  /** Apply an outcome (schema 3.7): the card must sit in a hand on the
2092
2092
  * board (you never play a card from inside the deck). Throws before any
2093
- * mutation on a gated-shut outcome or a bad write target. */
2093
+ * mutation on a gated-shut outcome or a bad write target.
2094
+ *
2095
+ * A card with NO outcomes is played with none, named as "" (the
2096
+ * no-outcome-play brief, 2026-09-14): a masthead, a notice, a codex entry,
2097
+ * whose play means "shown". It is everything a play is except the writes:
2098
+ * the play log and the history functions count it, the box's turn moves by
2099
+ * the usual rule, the redraw rests it and it leaves its hand. "" is the one
2100
+ * spelling in all four runtimes, because a Blueprint pin cannot be absent.
2101
+ * Only the empty-for-empty case is new: "" on a card that has outcomes is
2102
+ * refused, and a named outcome on a card with none is refused as before. */
2094
2103
  play(cardId, outcomeGameId, from, opts = {}) {
2095
2104
  this.assertOpen();
2096
2105
  const { entry, ask } = this.resolveDealt(cardId, from);
2097
- const outcome = entry.card.outcomes.find((o) => effectiveGameId(o) === outcomeGameId);
2098
- if (!outcome) throw new Error(`card "${effectiveGameId(entry.card)}" has no outcome "${outcomeGameId}"`);
2106
+ const bare = outcomeGameId === "";
2107
+ if (bare && entry.card.outcomes.length > 0) {
2108
+ throw new Error(`card "${effectiveGameId(entry.card)}" has outcomes (${entry.card.outcomes.map((o) => effectiveGameId(o)).join(", ")}); name the one played`);
2109
+ }
2110
+ const outcome = bare ? void 0 : entry.card.outcomes.find((o) => effectiveGameId(o) === outcomeGameId);
2111
+ if (!bare && !outcome) throw new Error(`card "${effectiveGameId(entry.card)}" has no outcome "${outcomeGameId}"`);
2099
2112
  const handEnv = this.buildHandEnv(ask);
2100
2113
  const ctx = this.evalCtx(entry.box, entry.deck, handEnv);
2101
- if (!this.passes(outcome.condition, ctx)) {
2114
+ if (outcome && !this.passes(outcome.condition, ctx)) {
2102
2115
  throw new Error(`outcome "${outcomeGameId}" on "${effectiveGameId(entry.card)}" is gated shut`);
2103
2116
  }
2104
2117
  const perPlay = entry.box.turn !== void 0 ? 0 : this.internals.bundle.settings.playAdvancesTurns;
2105
2118
  const newTurn = (this.turnCounts.get(entry.box.id) ?? 0) + (opts.advanceTurns ?? perPlay);
2106
2119
  const writes = [];
2107
- for (const [target, expr] of Object.entries(outcome.changes)) {
2120
+ for (const [target, expr] of Object.entries(outcome?.changes ?? {})) {
2108
2121
  writes.push({ target, value: this.eval(expr, ctx) });
2109
2122
  }
2110
2123
  for (const { target, value } of writes) {
2111
2124
  const { path, prev } = this.applyWrite(target, value, entry, handEnv);
2112
2125
  if (this.tracing) this.emit({ type: "write", target, path, value, ...prev !== void 0 ? { prev } : {} }, newTurn);
2113
2126
  }
2114
- const record = { card: effectiveGameId(entry.card), outcome: effectiveGameId(outcome), turn: newTurn };
2127
+ const outcomeId = outcome ? effectiveGameId(outcome) : "";
2128
+ const record = { card: effectiveGameId(entry.card), outcome: outcomeId, turn: newTurn };
2115
2129
  this.playLog.push(record);
2116
2130
  this.indexPlay(record);
2117
2131
  if (entry.card.redraw === "never") {
@@ -2126,7 +2140,7 @@ var Flow = class {
2126
2140
  (this.boardContents.get(handId) ?? []).filter((id) => id !== entry.card.id)
2127
2141
  );
2128
2142
  this.turnCounts.set(entry.box.id, newTurn);
2129
- if (this.tracing) this.emit({ type: "play", card: effectiveGameId(entry.card), outcome: effectiveGameId(outcome), turn: newTurn }, newTurn);
2143
+ if (this.tracing) this.emit({ type: "play", card: effectiveGameId(entry.card), outcome: outcomeId, turn: newTurn }, newTurn);
2130
2144
  }
2131
2145
  /** One owned property's address, owner segment and all (4.4). */
2132
2146
  address(kind, id) {