@storylet-studio/runtime 0.5.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
@@ -2084,33 +2084,48 @@ var Flow = class {
2084
2084
  gameId: effectiveGameId(o),
2085
2085
  ...o.title !== void 0 ? { title: o.title } : {},
2086
2086
  ...o.purpose !== void 0 ? { purpose: o.purpose } : {},
2087
+ ...o.fields !== void 0 ? { fields: o.fields } : {},
2087
2088
  available: this.passes(o.condition, ctx)
2088
2089
  }));
2089
2090
  }
2090
2091
  /** Apply an outcome (schema 3.7): the card must sit in a hand on the
2091
2092
  * board (you never play a card from inside the deck). Throws before any
2092
- * 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. */
2093
2103
  play(cardId, outcomeGameId, from, opts = {}) {
2094
2104
  this.assertOpen();
2095
2105
  const { entry, ask } = this.resolveDealt(cardId, from);
2096
- const outcome = entry.card.outcomes.find((o) => effectiveGameId(o) === outcomeGameId);
2097
- 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}"`);
2098
2112
  const handEnv = this.buildHandEnv(ask);
2099
2113
  const ctx = this.evalCtx(entry.box, entry.deck, handEnv);
2100
- if (!this.passes(outcome.condition, ctx)) {
2114
+ if (outcome && !this.passes(outcome.condition, ctx)) {
2101
2115
  throw new Error(`outcome "${outcomeGameId}" on "${effectiveGameId(entry.card)}" is gated shut`);
2102
2116
  }
2103
2117
  const perPlay = entry.box.turn !== void 0 ? 0 : this.internals.bundle.settings.playAdvancesTurns;
2104
2118
  const newTurn = (this.turnCounts.get(entry.box.id) ?? 0) + (opts.advanceTurns ?? perPlay);
2105
2119
  const writes = [];
2106
- for (const [target, expr] of Object.entries(outcome.changes)) {
2120
+ for (const [target, expr] of Object.entries(outcome?.changes ?? {})) {
2107
2121
  writes.push({ target, value: this.eval(expr, ctx) });
2108
2122
  }
2109
2123
  for (const { target, value } of writes) {
2110
2124
  const { path, prev } = this.applyWrite(target, value, entry, handEnv);
2111
2125
  if (this.tracing) this.emit({ type: "write", target, path, value, ...prev !== void 0 ? { prev } : {} }, newTurn);
2112
2126
  }
2113
- 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 };
2114
2129
  this.playLog.push(record);
2115
2130
  this.indexPlay(record);
2116
2131
  if (entry.card.redraw === "never") {
@@ -2125,7 +2140,7 @@ var Flow = class {
2125
2140
  (this.boardContents.get(handId) ?? []).filter((id) => id !== entry.card.id)
2126
2141
  );
2127
2142
  this.turnCounts.set(entry.box.id, newTurn);
2128
- 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);
2129
2144
  }
2130
2145
  /** One owned property's address, owner segment and all (4.4). */
2131
2146
  address(kind, id) {