@rpgm-tools/neo-angband-core 0.17.0 → 0.18.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/README.md CHANGED
@@ -32,7 +32,7 @@ import { Rng, ENGINE_VERSION, PARITY_BASELINE } from "@rpgm-tools/neo-angband-co
32
32
  const rng = new Rng(1234);
33
33
  console.log(rng.damroll(3, 6), rng.damroll(3, 6), rng.damroll(3, 6)); // 9 13 8
34
34
 
35
- console.log(ENGINE_VERSION, PARITY_BASELINE); // 0.17.0 4.2.6
35
+ console.log(ENGINE_VERSION, PARITY_BASELINE); // 0.18.0 4.2.6
36
36
  ```
37
37
 
38
38
  Two entry points:
@@ -70,6 +70,7 @@
70
70
  * with a hook installed and asserting the level is bit-identical.
71
71
  */
72
72
  import type { GameState } from "../game/context.js";
73
+ import type { OptionStateData } from "../player/options.js";
73
74
  /**
74
75
  * A mod's behaviour contributions. Every member is optional; an absent member
75
76
  * means "this mod does not touch that point" and core takes its faithful path.
@@ -180,6 +181,31 @@ export interface ModHooks {
180
181
  * Serves: the bug-fixes mod's cosmetic string corrections.
181
182
  */
182
183
  messageText?: (raw: string) => string;
184
+ /**
185
+ * The player finished changing their options (the '=' menu closed).
186
+ *
187
+ * A NOTIFICATION, and the only one here: every other hook is asked a question
188
+ * and its answer changes what the engine does, whereas this one is told a
189
+ * thing that already happened and core does not read the return value. The
190
+ * fold is "all-observe" for that reason - there is no answer to pick between,
191
+ * so every contributor simply runs.
192
+ *
193
+ * The payload is a SNAPSHOT (OptionState.snapshot()), not the live store. A
194
+ * mod that wants to react to a setting should read what the player chose; a
195
+ * mod that wants to CHANGE a setting has state.options and does not need this.
196
+ * Handing over the live object would blur the two, and a hook that mutated the
197
+ * store while the host was mid-repaint is a bug with no obvious author.
198
+ *
199
+ * Fired by the HOST, because the option screens are the host's - core's
200
+ * OptionState is the pure port of option.c and has no idea a menu exists. The
201
+ * host's own tests pin the call sites; a screen that edits options and forgets
202
+ * to fire this is a mod silently missing an event, which is why they are
203
+ * asserted rather than trusted.
204
+ *
205
+ * Serves: the QoL mod's "remember my settings" (persisting the player's
206
+ * choices past the character they were made on).
207
+ */
208
+ optionsChanged?: (options: OptionStateData) => void;
183
209
  }
184
210
  /**
185
211
  * Fold several mods' contributions into the single ModHooks core holds.
@@ -227,7 +253,7 @@ export interface ModHooks {
227
253
  * (mod-sdk's `Fold`), so the host can hand these values straight to the conflict
228
254
  * report and the compiler checks the two agree.
229
255
  */
230
- export type ModHookFold = "all-must-agree" | "chained" | "last-answer" | "any-yes";
256
+ export type ModHookFold = "all-must-agree" | "chained" | "last-answer" | "any-yes" | "all-observe";
231
257
  /**
232
258
  * WHICH FOLD EACH HOOK USES, next to the function that implements it.
233
259
  *
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/mod/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,CACtB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAC9B,IAAI,EAAE,OAAO,KACV,MAAM,GAAG,IAAI,CAAC;IAEnB;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,CACnB,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAC/C,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAC5C,MAAM,CAAC;IAEZ;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAE3D;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,KAAK,OAAO,CAAC;IAEpE;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IAE/G;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;IAE/B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,SAAS,GACT,aAAa,GACb,SAAS,CAAC;AAEd;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,QAAQ,EAAE,WAAW,CAAC,CAQxE,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,QAAQ,CAAC;IAC9B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACrC,QAAQ,CAmEV;AAED,wBAAgB,eAAe,CAC7B,aAAa,EAAE,SAAS,QAAQ,EAAE,GACjC,QAAQ,GAAG,SAAS,CA8EtB"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/mod/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,CACtB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAC9B,IAAI,EAAE,OAAO,KACV,MAAM,GAAG,IAAI,CAAC;IAEnB;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,CACnB,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAC/C,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAC5C,MAAM,CAAC;IAEZ;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAE3D;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,KAAK,OAAO,CAAC;IAEpE;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IAE/G;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;IAE/B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,SAAS,GACT,aAAa,GACb,SAAS,GACT,aAAa,CAAC;AAElB;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,QAAQ,EAAE,WAAW,CAAC,CASxE,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,QAAQ,CAAC;IAC9B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACrC,QAAQ,CA4EV;AAED,wBAAgB,eAAe,CAC7B,aAAa,EAAE,SAAS,QAAQ,EAAE,GACjC,QAAQ,GAAG,SAAS,CA6FtB"}
package/dist/mod/hooks.js CHANGED
@@ -93,6 +93,7 @@ export const MOD_HOOK_FOLDS = {
93
93
  historyAdd: "all-must-agree",
94
94
  saveNoiseScent: "any-yes",
95
95
  messageText: "chained",
96
+ optionsChanged: "all-observe",
96
97
  };
97
98
  /**
98
99
  * ONE mod's contribution, with every hook wrapped so a throw cannot escape into
@@ -182,6 +183,14 @@ export function guardModHooks(hooks, onFault) {
182
183
  * eat a message the player needed to read. */
183
184
  out.messageText = (raw) => guard("messageText", () => text(raw), raw);
184
185
  }
186
+ const options = hooks.optionsChanged;
187
+ if (options) {
188
+ /* Nothing to neutralise: core does not read an answer, so the neutral value
189
+ * is undefined and the guard exists only for the latch and the report. */
190
+ out.optionsChanged = (data) => {
191
+ guard("optionsChanged", () => options(data), undefined);
192
+ };
193
+ }
185
194
  return out;
186
195
  }
187
196
  export function composeModHooks(contributions) {
@@ -261,6 +270,20 @@ export function composeModHooks(contributions) {
261
270
  if (text.length > 0) {
262
271
  out.messageText = (raw) => text.reduce((s, fn) => fn(s), raw);
263
272
  }
273
+ const optionsChanged = list.map((c) => c.optionsChanged).filter(isFn);
274
+ if (optionsChanged.length > 0) {
275
+ /* LOAD order, and every one of them is told. There is no answer to choose
276
+ * between, so "later wins" has nothing to win: two mods both remembering the
277
+ * player's settings are not in conflict, they are two mods doing their own
278
+ * job with the same fact. Each gets its OWN copy - a mod that keeps the
279
+ * object it was handed and edits it later must not be editing what the next
280
+ * mod is about to read. */
281
+ out.optionsChanged = (data) => {
282
+ for (const fn of optionsChanged) {
283
+ fn({ ...data, values: { ...data.values }, birth: { ...data.birth } });
284
+ }
285
+ };
286
+ }
264
287
  return out;
265
288
  }
266
289
  function isFn(v) {
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/mod/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/mod/hooks.ts"],"names":[],"mappings":"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"}
@@ -128,7 +128,7 @@ export type OrphanStore = Record<string, OrphanEntry[]>;
128
128
  * core pack outright, and versionMap's versions are only ever used to key
129
129
  * quarantined MOD entities. An existing save keeps whatever it recorded.
130
130
  */
131
- export declare const CORE_PACK_VERSION = "0.17.0";
131
+ export declare const CORE_PACK_VERSION = "0.18.0";
132
132
  /** A core-only manifest: the base game with no mods, deterministic. */
133
133
  export declare function coreOnlyManifest(): SaveManifest;
134
134
  /**
package/dist/version.d.ts CHANGED
@@ -21,5 +21,5 @@ export declare const PARITY_BASELINE = "4.2.6";
21
21
  * released tag is iterated takes a MINOR bump, because a published tag is pinned
22
22
  * by digest in a catalogue and must never be moved.
23
23
  */
24
- export declare const ENGINE_VERSION = "0.17.0";
24
+ export declare const ENGINE_VERSION = "0.18.0";
25
25
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -21,5 +21,5 @@ export const PARITY_BASELINE = "4.2.6";
21
21
  * released tag is iterated takes a MINOR bump, because a published tag is pinned
22
22
  * by digest in a catalogue and must never be moved.
23
23
  */
24
- export const ENGINE_VERSION = "0.17.0";
24
+ export const ENGINE_VERSION = "0.18.0";
25
25
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpgm-tools/neo-angband-core",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Headless Neo Angband game engine: rules, world, entities, effects, generation",
5
5
  "license": "GPL-2.0-only",
6
6
  "author": "neostryder (RPGM Tools)",
package/src/mod/hooks.ts CHANGED
@@ -71,6 +71,7 @@
71
71
  */
72
72
 
73
73
  import type { GameState } from "../game/context.js";
74
+ import type { OptionStateData } from "../player/options.js";
74
75
 
75
76
  /**
76
77
  * A mod's behaviour contributions. Every member is optional; an absent member
@@ -182,6 +183,32 @@ export interface ModHooks {
182
183
  * Serves: the bug-fixes mod's cosmetic string corrections.
183
184
  */
184
185
  messageText?: (raw: string) => string;
186
+
187
+ /**
188
+ * The player finished changing their options (the '=' menu closed).
189
+ *
190
+ * A NOTIFICATION, and the only one here: every other hook is asked a question
191
+ * and its answer changes what the engine does, whereas this one is told a
192
+ * thing that already happened and core does not read the return value. The
193
+ * fold is "all-observe" for that reason - there is no answer to pick between,
194
+ * so every contributor simply runs.
195
+ *
196
+ * The payload is a SNAPSHOT (OptionState.snapshot()), not the live store. A
197
+ * mod that wants to react to a setting should read what the player chose; a
198
+ * mod that wants to CHANGE a setting has state.options and does not need this.
199
+ * Handing over the live object would blur the two, and a hook that mutated the
200
+ * store while the host was mid-repaint is a bug with no obvious author.
201
+ *
202
+ * Fired by the HOST, because the option screens are the host's - core's
203
+ * OptionState is the pure port of option.c and has no idea a menu exists. The
204
+ * host's own tests pin the call sites; a screen that edits options and forgets
205
+ * to fire this is a mod silently missing an event, which is why they are
206
+ * asserted rather than trusted.
207
+ *
208
+ * Serves: the QoL mod's "remember my settings" (persisting the player's
209
+ * choices past the character they were made on).
210
+ */
211
+ optionsChanged?: (options: OptionStateData) => void;
185
212
  }
186
213
 
187
214
  /**
@@ -234,7 +261,8 @@ export type ModHookFold =
234
261
  | "all-must-agree" // every contributor runs; the first refusal decides
235
262
  | "chained" // each sees the previous one's output, so the last one speaks last
236
263
  | "last-answer" // the LAST contributor with an opinion decides; earlier ones are not asked
237
- | "any-yes"; // one contributor asking for it is enough
264
+ | "any-yes" // one contributor asking for it is enough
265
+ | "all-observe"; // a notification: every contributor is told, and none of them answers
238
266
 
239
267
  /**
240
268
  * WHICH FOLD EACH HOOK USES, next to the function that implements it.
@@ -260,6 +288,7 @@ export const MOD_HOOK_FOLDS: Readonly<Record<keyof ModHooks, ModHookFold>> = {
260
288
  historyAdd: "all-must-agree",
261
289
  saveNoiseScent: "any-yes",
262
290
  messageText: "chained",
291
+ optionsChanged: "all-observe",
263
292
  };
264
293
 
265
294
  /**
@@ -378,6 +407,15 @@ export function guardModHooks(
378
407
  out.messageText = (raw): string => guard("messageText", () => text(raw), raw);
379
408
  }
380
409
 
410
+ const options = hooks.optionsChanged;
411
+ if (options) {
412
+ /* Nothing to neutralise: core does not read an answer, so the neutral value
413
+ * is undefined and the guard exists only for the latch and the report. */
414
+ out.optionsChanged = (data): void => {
415
+ guard("optionsChanged", () => options(data), undefined);
416
+ };
417
+ }
418
+
381
419
  return out;
382
420
  }
383
421
 
@@ -460,6 +498,21 @@ export function composeModHooks(
460
498
  out.messageText = (raw): string => text.reduce((s, fn) => fn(s), raw);
461
499
  }
462
500
 
501
+ const optionsChanged = list.map((c) => c.optionsChanged).filter(isFn);
502
+ if (optionsChanged.length > 0) {
503
+ /* LOAD order, and every one of them is told. There is no answer to choose
504
+ * between, so "later wins" has nothing to win: two mods both remembering the
505
+ * player's settings are not in conflict, they are two mods doing their own
506
+ * job with the same fact. Each gets its OWN copy - a mod that keeps the
507
+ * object it was handed and edits it later must not be editing what the next
508
+ * mod is about to read. */
509
+ out.optionsChanged = (data): void => {
510
+ for (const fn of optionsChanged) {
511
+ fn({ ...data, values: { ...data.values }, birth: { ...data.birth } });
512
+ }
513
+ };
514
+ }
515
+
463
516
  return out;
464
517
  }
465
518
 
package/src/version.ts CHANGED
@@ -23,4 +23,4 @@ export const PARITY_BASELINE = "4.2.6";
23
23
  * released tag is iterated takes a MINOR bump, because a published tag is pinned
24
24
  * by digest in a catalogue and must never be moved.
25
25
  */
26
- export const ENGINE_VERSION = "0.17.0";
26
+ export const ENGINE_VERSION = "0.18.0";