@rpgm-tools/neo-angband-core 0.18.0 → 0.19.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 +1 -1
- package/dist/agent/perceive.d.ts.map +1 -1
- package/dist/agent/perceive.js +2 -2
- package/dist/agent/perceive.js.map +1 -1
- package/dist/combat/blow-vectors.d.ts +78 -0
- package/dist/combat/blow-vectors.d.ts.map +1 -0
- package/dist/combat/blow-vectors.fixtures.d.ts +19 -0
- package/dist/combat/blow-vectors.fixtures.d.ts.map +1 -0
- package/dist/combat/blow-vectors.fixtures.js +81 -0
- package/dist/combat/blow-vectors.fixtures.js.map +1 -0
- package/dist/combat/blow-vectors.js +195 -0
- package/dist/combat/blow-vectors.js.map +1 -0
- package/dist/combat/brand-slay.d.ts +22 -9
- package/dist/combat/brand-slay.d.ts.map +1 -1
- package/dist/combat/brand-slay.js +37 -10
- package/dist/combat/brand-slay.js.map +1 -1
- package/dist/combat/index.d.ts +1 -1
- package/dist/combat/index.js +1 -1
- package/dist/combat/melee.d.ts +25 -13
- package/dist/combat/melee.d.ts.map +1 -1
- package/dist/combat/melee.js +23 -19
- package/dist/combat/melee.js.map +1 -1
- package/dist/combat/mon-melee.d.ts +166 -7
- package/dist/combat/mon-melee.d.ts.map +1 -1
- package/dist/combat/mon-melee.js +469 -338
- package/dist/combat/mon-melee.js.map +1 -1
- package/dist/combat/ranged.d.ts +15 -13
- package/dist/combat/ranged.d.ts.map +1 -1
- package/dist/combat/ranged.js +31 -29
- package/dist/combat/ranged.js.map +1 -1
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +14 -0
- package/dist/constants.js.map +1 -1
- package/dist/datafile.d.ts +48 -0
- package/dist/datafile.d.ts.map +1 -0
- package/dist/datafile.js +102 -0
- package/dist/datafile.js.map +1 -0
- package/dist/effects/effect-info-registry.d.ts +237 -0
- package/dist/effects/effect-info-registry.d.ts.map +1 -0
- package/dist/effects/effect-info-registry.js +138 -0
- package/dist/effects/effect-info-registry.js.map +1 -0
- package/dist/effects/effect-info-vectors.d.ts +92 -0
- package/dist/effects/effect-info-vectors.d.ts.map +1 -0
- package/dist/effects/effect-info-vectors.fixtures.d.ts +18 -0
- package/dist/effects/effect-info-vectors.fixtures.d.ts.map +1 -0
- package/dist/effects/effect-info-vectors.fixtures.js +51 -0
- package/dist/effects/effect-info-vectors.fixtures.js.map +1 -0
- package/dist/effects/effect-info-vectors.js +315 -0
- package/dist/effects/effect-info-vectors.js.map +1 -0
- package/dist/effects/effect-info.d.ts +5 -1
- package/dist/effects/effect-info.d.ts.map +1 -1
- package/dist/effects/effect-info.js +245 -143
- package/dist/effects/effect-info.js.map +1 -1
- package/dist/effects/effect.d.ts +4 -3
- package/dist/effects/effect.d.ts.map +1 -1
- package/dist/effects/effect.js +88 -70
- package/dist/effects/effect.js.map +1 -1
- package/dist/effects/handlers.d.ts +1 -1
- package/dist/effects/handlers.d.ts.map +1 -1
- package/dist/effects/handlers.js +5 -2
- package/dist/effects/handlers.js.map +1 -1
- package/dist/effects/interpreter.d.ts +11 -0
- package/dist/effects/interpreter.d.ts.map +1 -1
- package/dist/effects/interpreter.js +13 -0
- package/dist/effects/interpreter.js.map +1 -1
- package/dist/game/cave-cmd.d.ts +9 -5
- package/dist/game/cave-cmd.d.ts.map +1 -1
- package/dist/game/cave-cmd.js +56 -11
- package/dist/game/cave-cmd.js.map +1 -1
- package/dist/game/cave-square.d.ts +42 -0
- package/dist/game/cave-square.d.ts.map +1 -0
- package/dist/game/cave-square.js +73 -0
- package/dist/game/cave-square.js.map +1 -0
- package/dist/game/char-sheet.d.ts +12 -8
- package/dist/game/char-sheet.d.ts.map +1 -1
- package/dist/game/char-sheet.js +41 -8
- package/dist/game/char-sheet.js.map +1 -1
- package/dist/game/chest.d.ts +2 -3
- package/dist/game/chest.d.ts.map +1 -1
- package/dist/game/chest.js +17 -6
- package/dist/game/chest.js.map +1 -1
- package/dist/game/context.d.ts +213 -22
- package/dist/game/context.d.ts.map +1 -1
- package/dist/game/context.js +109 -17
- package/dist/game/context.js.map +1 -1
- package/dist/game/describe.d.ts +13 -0
- package/dist/game/describe.d.ts.map +1 -1
- package/dist/game/describe.js +32 -4
- package/dist/game/describe.js.map +1 -1
- package/dist/game/display.d.ts +97 -8
- package/dist/game/display.d.ts.map +1 -1
- package/dist/game/display.js +157 -13
- package/dist/game/display.js.map +1 -1
- package/dist/game/dump-level.d.ts.map +1 -1
- package/dist/game/dump-level.js +3 -2
- package/dist/game/dump-level.js.map +1 -1
- package/dist/game/effect-attack.d.ts.map +1 -1
- package/dist/game/effect-attack.js +36 -27
- package/dist/game/effect-attack.js.map +1 -1
- package/dist/game/effect-detect.d.ts +4 -4
- package/dist/game/effect-detect.d.ts.map +1 -1
- package/dist/game/effect-detect.js +42 -9
- package/dist/game/effect-detect.js.map +1 -1
- package/dist/game/effect-env.d.ts +7 -1
- package/dist/game/effect-env.d.ts.map +1 -1
- package/dist/game/effect-env.js +1 -0
- package/dist/game/effect-env.js.map +1 -1
- package/dist/game/effect-general.d.ts +5 -3
- package/dist/game/effect-general.d.ts.map +1 -1
- package/dist/game/effect-general.js +94 -43
- package/dist/game/effect-general.js.map +1 -1
- package/dist/game/effect-item.d.ts +2 -1
- package/dist/game/effect-item.d.ts.map +1 -1
- package/dist/game/effect-item.js +136 -82
- package/dist/game/effect-item.js.map +1 -1
- package/dist/game/effect-melee.d.ts +10 -4
- package/dist/game/effect-melee.d.ts.map +1 -1
- package/dist/game/effect-melee.js +44 -19
- package/dist/game/effect-melee.js.map +1 -1
- package/dist/game/effect-monster.d.ts +26 -4
- package/dist/game/effect-monster.d.ts.map +1 -1
- package/dist/game/effect-monster.js +52 -9
- package/dist/game/effect-monster.js.map +1 -1
- package/dist/game/effect-teleport.d.ts +58 -19
- package/dist/game/effect-teleport.d.ts.map +1 -1
- package/dist/game/effect-teleport.js +143 -27
- package/dist/game/effect-teleport.js.map +1 -1
- package/dist/game/effect-terrain.d.ts +1 -3
- package/dist/game/effect-terrain.d.ts.map +1 -1
- package/dist/game/effect-terrain.js +38 -22
- package/dist/game/effect-terrain.js.map +1 -1
- package/dist/game/equip-cmp.d.ts.map +1 -1
- package/dist/game/equip-cmp.js +10 -7
- package/dist/game/equip-cmp.js.map +1 -1
- package/dist/game/floor.d.ts +16 -4
- package/dist/game/floor.d.ts.map +1 -1
- package/dist/game/floor.js +22 -4
- package/dist/game/floor.js.map +1 -1
- package/dist/game/gear.d.ts +101 -13
- package/dist/game/gear.d.ts.map +1 -1
- package/dist/game/gear.js +183 -24
- package/dist/game/gear.js.map +1 -1
- package/dist/game/harness.d.ts +2 -1
- package/dist/game/harness.d.ts.map +1 -1
- package/dist/game/harness.js +12 -1
- package/dist/game/harness.js.map +1 -1
- package/dist/game/ignore-cmd.d.ts +47 -8
- package/dist/game/ignore-cmd.d.ts.map +1 -1
- package/dist/game/ignore-cmd.js +76 -8
- package/dist/game/ignore-cmd.js.map +1 -1
- package/dist/game/known.d.ts +223 -34
- package/dist/game/known.d.ts.map +1 -1
- package/dist/game/known.js +301 -67
- package/dist/game/known.js.map +1 -1
- package/dist/game/loop.d.ts +4 -3
- package/dist/game/loop.d.ts.map +1 -1
- package/dist/game/loop.js +49 -29
- package/dist/game/loop.js.map +1 -1
- package/dist/game/lore-color.d.ts.map +1 -1
- package/dist/game/lore-color.js +13 -1
- package/dist/game/lore-color.js.map +1 -1
- package/dist/game/mon-cast.d.ts +3 -4
- package/dist/game/mon-cast.d.ts.map +1 -1
- package/dist/game/mon-cast.js +30 -2
- package/dist/game/mon-cast.js.map +1 -1
- package/dist/game/mon-cmd.d.ts +4 -5
- package/dist/game/mon-cmd.d.ts.map +1 -1
- package/dist/game/mon-cmd.js +80 -27
- package/dist/game/mon-cmd.js.map +1 -1
- package/dist/game/mon-death.d.ts +8 -4
- package/dist/game/mon-death.d.ts.map +1 -1
- package/dist/game/mon-death.js +6 -9
- package/dist/game/mon-death.js.map +1 -1
- package/dist/game/mon-group.d.ts +9 -5
- package/dist/game/mon-group.d.ts.map +1 -1
- package/dist/game/mon-group.js +9 -5
- package/dist/game/mon-group.js.map +1 -1
- package/dist/game/mon-message.d.ts +90 -40
- package/dist/game/mon-message.d.ts.map +1 -1
- package/dist/game/mon-message.js +267 -59
- package/dist/game/mon-message.js.map +1 -1
- package/dist/game/mon-place.d.ts +11 -1
- package/dist/game/mon-place.d.ts.map +1 -1
- package/dist/game/mon-place.js +15 -3
- package/dist/game/mon-place.js.map +1 -1
- package/dist/game/mon-ranged.d.ts +2 -1
- package/dist/game/mon-ranged.d.ts.map +1 -1
- package/dist/game/mon-ranged.js +11 -5
- package/dist/game/mon-ranged.js.map +1 -1
- package/dist/game/mon-side.d.ts +3 -2
- package/dist/game/mon-side.d.ts.map +1 -1
- package/dist/game/mon-side.js +15 -14
- package/dist/game/mon-side.js.map +1 -1
- package/dist/game/monster-turn.d.ts +20 -10
- package/dist/game/monster-turn.d.ts.map +1 -1
- package/dist/game/monster-turn.js +110 -83
- package/dist/game/monster-turn.js.map +1 -1
- package/dist/game/notice.d.ts +36 -0
- package/dist/game/notice.d.ts.map +1 -0
- package/dist/game/notice.js +79 -0
- package/dist/game/notice.js.map +1 -0
- package/dist/game/obj-cmd.d.ts +14 -3
- package/dist/game/obj-cmd.d.ts.map +1 -1
- package/dist/game/obj-cmd.js +109 -35
- package/dist/game/obj-cmd.js.map +1 -1
- package/dist/game/obj-list.d.ts +13 -2
- package/dist/game/obj-list.d.ts.map +1 -1
- package/dist/game/obj-list.js +42 -27
- package/dist/game/obj-list.js.map +1 -1
- package/dist/game/object-inspect.d.ts +9 -0
- package/dist/game/object-inspect.d.ts.map +1 -1
- package/dist/game/object-inspect.js +4 -0
- package/dist/game/object-inspect.js.map +1 -1
- package/dist/game/pickup.d.ts +0 -2
- package/dist/game/pickup.d.ts.map +1 -1
- package/dist/game/pickup.js +18 -3
- package/dist/game/pickup.js.map +1 -1
- package/dist/game/player-side-vectors.d.ts +174 -0
- package/dist/game/player-side-vectors.d.ts.map +1 -0
- package/dist/game/player-side-vectors.fixtures.d.ts +33 -0
- package/dist/game/player-side-vectors.fixtures.d.ts.map +1 -0
- package/dist/game/player-side-vectors.fixtures.js +191 -0
- package/dist/game/player-side-vectors.fixtures.js.map +1 -0
- package/dist/game/player-side-vectors.js +292 -0
- package/dist/game/player-side-vectors.js.map +1 -0
- package/dist/game/player-side.d.ts +129 -1
- package/dist/game/player-side.d.ts.map +1 -1
- package/dist/game/player-side.js +520 -338
- package/dist/game/player-side.js.map +1 -1
- package/dist/game/player-turn.d.ts +26 -7
- package/dist/game/player-turn.d.ts.map +1 -1
- package/dist/game/player-turn.js +180 -33
- package/dist/game/player-turn.js.map +1 -1
- package/dist/game/poly.d.ts +38 -0
- package/dist/game/poly.d.ts.map +1 -0
- package/dist/game/poly.js +82 -0
- package/dist/game/poly.js.map +1 -0
- package/dist/game/project-cast.d.ts +20 -3
- package/dist/game/project-cast.d.ts.map +1 -1
- package/dist/game/project-cast.js +49 -6
- package/dist/game/project-cast.js.map +1 -1
- package/dist/game/project-feat-vectors.d.ts +124 -0
- package/dist/game/project-feat-vectors.d.ts.map +1 -0
- package/dist/game/project-feat-vectors.fixtures.d.ts +13 -0
- package/dist/game/project-feat-vectors.fixtures.d.ts.map +1 -0
- package/dist/game/project-feat-vectors.fixtures.js +94 -0
- package/dist/game/project-feat-vectors.fixtures.js.map +1 -0
- package/dist/game/project-feat-vectors.js +229 -0
- package/dist/game/project-feat-vectors.js.map +1 -0
- package/dist/game/project-feat.d.ts +53 -1
- package/dist/game/project-feat.d.ts.map +1 -1
- package/dist/game/project-feat.js +374 -247
- package/dist/game/project-feat.js.map +1 -1
- package/dist/game/project-monster.d.ts +21 -8
- package/dist/game/project-monster.d.ts.map +1 -1
- package/dist/game/project-monster.js +45 -21
- package/dist/game/project-monster.js.map +1 -1
- package/dist/game/project-obj.d.ts +62 -0
- package/dist/game/project-obj.d.ts.map +1 -1
- package/dist/game/project-obj.js +72 -41
- package/dist/game/project-obj.js.map +1 -1
- package/dist/game/project-player.d.ts +8 -0
- package/dist/game/project-player.d.ts.map +1 -1
- package/dist/game/project-player.js.map +1 -1
- package/dist/game/projection-handlers.d.ts +81 -0
- package/dist/game/projection-handlers.d.ts.map +1 -0
- package/dist/game/projection-handlers.js +93 -0
- package/dist/game/projection-handlers.js.map +1 -0
- package/dist/game/quest.d.ts +23 -0
- package/dist/game/quest.d.ts.map +1 -1
- package/dist/game/quest.js +42 -0
- package/dist/game/quest.js.map +1 -1
- package/dist/game/ranged-cmd.d.ts +13 -2
- package/dist/game/ranged-cmd.d.ts.map +1 -1
- package/dist/game/ranged-cmd.js +32 -15
- package/dist/game/ranged-cmd.js.map +1 -1
- package/dist/game/repeat.d.ts +78 -0
- package/dist/game/repeat.d.ts.map +1 -0
- package/dist/game/repeat.js +88 -0
- package/dist/game/repeat.js.map +1 -0
- package/dist/game/shape-inspect.d.ts +74 -0
- package/dist/game/shape-inspect.d.ts.map +1 -0
- package/dist/game/shape-inspect.js +114 -0
- package/dist/game/shape-inspect.js.map +1 -0
- package/dist/game/spell-cmd.d.ts +15 -4
- package/dist/game/spell-cmd.d.ts.map +1 -1
- package/dist/game/spell-cmd.js +35 -6
- package/dist/game/spell-cmd.js.map +1 -1
- package/dist/game/spoil.d.ts.map +1 -1
- package/dist/game/spoil.js +89 -40
- package/dist/game/spoil.js.map +1 -1
- package/dist/game/steal.d.ts +3 -3
- package/dist/game/steal.d.ts.map +1 -1
- package/dist/game/steal.js +9 -4
- package/dist/game/steal.js.map +1 -1
- package/dist/game/target-loop.d.ts +10 -4
- package/dist/game/target-loop.d.ts.map +1 -1
- package/dist/game/target-loop.js +14 -8
- package/dist/game/target-loop.js.map +1 -1
- package/dist/game/target.d.ts +4 -4
- package/dist/game/target.d.ts.map +1 -1
- package/dist/game/target.js +19 -8
- package/dist/game/target.js.map +1 -1
- package/dist/game/ui-entry.d.ts +63 -4
- package/dist/game/ui-entry.d.ts.map +1 -1
- package/dist/game/ui-entry.js +151 -23
- package/dist/game/ui-entry.js.map +1 -1
- package/dist/game/wizard.d.ts +23 -5
- package/dist/game/wizard.d.ts.map +1 -1
- package/dist/game/wizard.js +93 -11
- package/dist/game/wizard.js.map +1 -1
- package/dist/game/world.d.ts.map +1 -1
- package/dist/game/world.js +6 -0
- package/dist/game/world.js.map +1 -1
- package/dist/gen/cave.d.ts +49 -8
- package/dist/gen/cave.d.ts.map +1 -1
- package/dist/gen/cave.js +200 -28
- package/dist/gen/cave.js.map +1 -1
- package/dist/gen/generate.d.ts +54 -9
- package/dist/gen/generate.d.ts.map +1 -1
- package/dist/gen/generate.js +55 -8
- package/dist/gen/generate.js.map +1 -1
- package/dist/gen/glyph-vectors.d.ts +109 -0
- package/dist/gen/glyph-vectors.d.ts.map +1 -0
- package/dist/gen/glyph-vectors.fixtures.d.ts +18 -0
- package/dist/gen/glyph-vectors.fixtures.d.ts.map +1 -0
- package/dist/gen/glyph-vectors.fixtures.js +94 -0
- package/dist/gen/glyph-vectors.fixtures.js.map +1 -0
- package/dist/gen/glyph-vectors.js +218 -0
- package/dist/gen/glyph-vectors.js.map +1 -0
- package/dist/gen/glyph.d.ts +104 -0
- package/dist/gen/glyph.d.ts.map +1 -0
- package/dist/gen/glyph.js +72 -0
- package/dist/gen/glyph.js.map +1 -0
- package/dist/gen/room.d.ts +26 -2
- package/dist/gen/room.d.ts.map +1 -1
- package/dist/gen/room.js +414 -264
- package/dist/gen/room.js.map +1 -1
- package/dist/gen/util.d.ts +11 -2
- package/dist/gen/util.d.ts.map +1 -1
- package/dist/gen/util.js +31 -9
- package/dist/gen/util.js.map +1 -1
- package/dist/i18n/i18n.d.ts +207 -0
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/i18n.js +405 -0
- package/dist/i18n/i18n.js.map +1 -0
- package/dist/i18n/text.d.ts +62 -0
- package/dist/i18n/text.d.ts.map +1 -0
- package/dist/i18n/text.js +120 -0
- package/dist/i18n/text.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -1
- package/dist/mod/extension.d.ts +115 -0
- package/dist/mod/extension.d.ts.map +1 -0
- package/dist/mod/extension.js +85 -0
- package/dist/mod/extension.js.map +1 -0
- package/dist/mod/ids.d.ts +10 -0
- package/dist/mod/ids.d.ts.map +1 -1
- package/dist/mod/ids.js +90 -21
- package/dist/mod/ids.js.map +1 -1
- package/dist/mod/record-keys.d.ts +43 -0
- package/dist/mod/record-keys.d.ts.map +1 -0
- package/dist/mod/record-keys.js +100 -0
- package/dist/mod/record-keys.js.map +1 -0
- package/dist/mod/registry-host.d.ts +472 -0
- package/dist/mod/registry-host.d.ts.map +1 -1
- package/dist/mod/registry-host.js +313 -0
- package/dist/mod/registry-host.js.map +1 -1
- package/dist/mod/save-blocks.d.ts +1 -1
- package/dist/mon/bind.d.ts.map +1 -1
- package/dist/mon/bind.js +6 -3
- package/dist/mon/bind.js.map +1 -1
- package/dist/mon/knowledge-groups.d.ts +0 -6
- package/dist/mon/knowledge-groups.d.ts.map +1 -1
- package/dist/mon/knowledge-groups.js +12 -8
- package/dist/mon/knowledge-groups.js.map +1 -1
- package/dist/mon/lore-describe.d.ts +46 -10
- package/dist/mon/lore-describe.d.ts.map +1 -1
- package/dist/mon/lore-describe.js +74 -22
- package/dist/mon/lore-describe.js.map +1 -1
- package/dist/mon/lore-file.d.ts +126 -0
- package/dist/mon/lore-file.d.ts.map +1 -0
- package/dist/mon/lore-file.js +291 -0
- package/dist/mon/lore-file.js.map +1 -0
- package/dist/mon/lore.d.ts +9 -3
- package/dist/mon/lore.d.ts.map +1 -1
- package/dist/mon/lore.js +9 -3
- package/dist/mon/lore.js.map +1 -1
- package/dist/mon/make.d.ts +4 -2
- package/dist/mon/make.d.ts.map +1 -1
- package/dist/mon/make.js +4 -2
- package/dist/mon/make.js.map +1 -1
- package/dist/mon/monster.d.ts +1 -1
- package/dist/mon/monster.js +1 -1
- package/dist/mon/predicate.d.ts +14 -9
- package/dist/mon/predicate.d.ts.map +1 -1
- package/dist/mon/predicate.js +14 -9
- package/dist/mon/predicate.js.map +1 -1
- package/dist/mon/project-mon.d.ts +16 -3
- package/dist/mon/project-mon.d.ts.map +1 -1
- package/dist/mon/project-mon.js +14 -5
- package/dist/mon/project-mon.js.map +1 -1
- package/dist/mon/steal.d.ts +31 -4
- package/dist/mon/steal.d.ts.map +1 -1
- package/dist/mon/steal.js +20 -7
- package/dist/mon/steal.js.map +1 -1
- package/dist/mon/take-hit.d.ts +8 -3
- package/dist/mon/take-hit.d.ts.map +1 -1
- package/dist/mon/take-hit.js +8 -3
- package/dist/mon/take-hit.js.map +1 -1
- package/dist/mon/timed.d.ts +15 -9
- package/dist/mon/timed.d.ts.map +1 -1
- package/dist/mon/timed.js +13 -8
- package/dist/mon/timed.js.map +1 -1
- package/dist/mon/types.d.ts +11 -4
- package/dist/mon/types.d.ts.map +1 -1
- package/dist/mon/types.js.map +1 -1
- package/dist/msg.d.ts +40 -1
- package/dist/msg.d.ts.map +1 -1
- package/dist/msg.js +42 -1
- package/dist/msg.js.map +1 -1
- package/dist/obj/artifact-fake.d.ts +46 -14
- package/dist/obj/artifact-fake.d.ts.map +1 -1
- package/dist/obj/artifact-fake.js +46 -17
- package/dist/obj/artifact-fake.js.map +1 -1
- package/dist/obj/bind.d.ts +23 -0
- package/dist/obj/bind.d.ts.map +1 -1
- package/dist/obj/bind.js +49 -9
- package/dist/obj/bind.js.map +1 -1
- package/dist/obj/desc-vectors.d.ts +68 -0
- package/dist/obj/desc-vectors.d.ts.map +1 -0
- package/dist/obj/desc-vectors.fixtures.d.ts +12 -0
- package/dist/obj/desc-vectors.fixtures.d.ts.map +1 -0
- package/dist/obj/desc-vectors.fixtures.js +95 -0
- package/dist/obj/desc-vectors.fixtures.js.map +1 -0
- package/dist/obj/desc-vectors.js +86 -0
- package/dist/obj/desc-vectors.js.map +1 -0
- package/dist/obj/desc.d.ts +17 -2
- package/dist/obj/desc.d.ts.map +1 -1
- package/dist/obj/desc.js +129 -54
- package/dist/obj/desc.js.map +1 -1
- package/dist/obj/effects-info.d.ts.map +1 -1
- package/dist/obj/effects-info.js +87 -58
- package/dist/obj/effects-info.js.map +1 -1
- package/dist/obj/fake-object.d.ts +70 -0
- package/dist/obj/fake-object.d.ts.map +1 -0
- package/dist/obj/fake-object.js +104 -0
- package/dist/obj/fake-object.js.map +1 -0
- package/dist/obj/ignore.d.ts +55 -12
- package/dist/obj/ignore.d.ts.map +1 -1
- package/dist/obj/ignore.js +68 -31
- package/dist/obj/ignore.js.map +1 -1
- package/dist/obj/knowledge.d.ts +46 -3
- package/dist/obj/knowledge.d.ts.map +1 -1
- package/dist/obj/knowledge.js +169 -151
- package/dist/obj/knowledge.js.map +1 -1
- package/dist/obj/known-object.d.ts +68 -8
- package/dist/obj/known-object.d.ts.map +1 -1
- package/dist/obj/known-object.js +90 -10
- package/dist/obj/known-object.js.map +1 -1
- package/dist/obj/make.d.ts +15 -4
- package/dist/obj/make.d.ts.map +1 -1
- package/dist/obj/make.js +49 -27
- package/dist/obj/make.js.map +1 -1
- package/dist/obj/object-info.d.ts +10 -0
- package/dist/obj/object-info.d.ts.map +1 -1
- package/dist/obj/object-info.js +93 -7
- package/dist/obj/object-info.js.map +1 -1
- package/dist/obj/object.d.ts +42 -4
- package/dist/obj/object.d.ts.map +1 -1
- package/dist/obj/object.js +362 -147
- package/dist/obj/object.js.map +1 -1
- package/dist/obj/power.d.ts +23 -4
- package/dist/obj/power.d.ts.map +1 -1
- package/dist/obj/power.js +231 -65
- package/dist/obj/power.js.map +1 -1
- package/dist/obj/randart-build.d.ts +27 -22
- package/dist/obj/randart-build.d.ts.map +1 -1
- package/dist/obj/randart-build.js +435 -357
- package/dist/obj/randart-build.js.map +1 -1
- package/dist/obj/randart-data.d.ts +62 -24
- package/dist/obj/randart-data.d.ts.map +1 -1
- package/dist/obj/randart-data.js +333 -189
- package/dist/obj/randart-data.js.map +1 -1
- package/dist/obj/randart-file.d.ts +21 -0
- package/dist/obj/randart-file.d.ts.map +1 -0
- package/dist/obj/randart-file.js +119 -0
- package/dist/obj/randart-file.js.map +1 -0
- package/dist/obj/randart-log.d.ts +63 -0
- package/dist/obj/randart-log.d.ts.map +1 -0
- package/dist/obj/randart-log.js +72 -0
- package/dist/obj/randart-log.js.map +1 -0
- package/dist/obj/randart-registry.d.ts +178 -0
- package/dist/obj/randart-registry.d.ts.map +1 -0
- package/dist/obj/randart-registry.js +140 -0
- package/dist/obj/randart-registry.js.map +1 -0
- package/dist/obj/randart-vectors.d.ts +97 -0
- package/dist/obj/randart-vectors.d.ts.map +1 -0
- package/dist/obj/randart-vectors.fixtures.d.ts +18 -0
- package/dist/obj/randart-vectors.fixtures.d.ts.map +1 -0
- package/dist/obj/randart-vectors.fixtures.js +50 -0
- package/dist/obj/randart-vectors.fixtures.js.map +1 -0
- package/dist/obj/randart-vectors.js +311 -0
- package/dist/obj/randart-vectors.js.map +1 -0
- package/dist/obj/randart.d.ts +53 -15
- package/dist/obj/randart.d.ts.map +1 -1
- package/dist/obj/randart.js +166 -44
- package/dist/obj/randart.js.map +1 -1
- package/dist/obj/rune-registry.d.ts +180 -0
- package/dist/obj/rune-registry.d.ts.map +1 -0
- package/dist/obj/rune-registry.js +161 -0
- package/dist/obj/rune-registry.js.map +1 -0
- package/dist/obj/rune-vectors.d.ts +99 -0
- package/dist/obj/rune-vectors.d.ts.map +1 -0
- package/dist/obj/rune-vectors.fixtures.d.ts +44 -0
- package/dist/obj/rune-vectors.fixtures.d.ts.map +1 -0
- package/dist/obj/rune-vectors.fixtures.js +125 -0
- package/dist/obj/rune-vectors.fixtures.js.map +1 -0
- package/dist/obj/rune-vectors.js +159 -0
- package/dist/obj/rune-vectors.js.map +1 -0
- package/dist/obj/tval-registry.d.ts +174 -0
- package/dist/obj/tval-registry.d.ts.map +1 -0
- package/dist/obj/tval-registry.js +151 -0
- package/dist/obj/tval-registry.js.map +1 -0
- package/dist/obj/tval-vectors.d.ts +85 -0
- package/dist/obj/tval-vectors.d.ts.map +1 -0
- package/dist/obj/tval-vectors.fixtures.d.ts +24 -0
- package/dist/obj/tval-vectors.fixtures.d.ts.map +1 -0
- package/dist/obj/tval-vectors.fixtures.js +41 -0
- package/dist/obj/tval-vectors.fixtures.js.map +1 -0
- package/dist/obj/tval-vectors.js +76 -0
- package/dist/obj/tval-vectors.js.map +1 -0
- package/dist/obj/types.d.ts +18 -7
- package/dist/obj/types.d.ts.map +1 -1
- package/dist/obj/types.js.map +1 -1
- package/dist/obj/value.d.ts.map +1 -1
- package/dist/obj/value.js +23 -20
- package/dist/obj/value.js.map +1 -1
- package/dist/parser.d.ts +116 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +205 -0
- package/dist/parser.js.map +1 -0
- package/dist/player/bind.d.ts.map +1 -1
- package/dist/player/bind.js +3 -2
- package/dist/player/bind.js.map +1 -1
- package/dist/player/birth.d.ts +2 -1
- package/dist/player/birth.d.ts.map +1 -1
- package/dist/player/birth.js +2 -1
- package/dist/player/birth.js.map +1 -1
- package/dist/player/calcs.d.ts +58 -23
- package/dist/player/calcs.d.ts.map +1 -1
- package/dist/player/calcs.js +93 -36
- package/dist/player/calcs.js.map +1 -1
- package/dist/player/death.d.ts +50 -0
- package/dist/player/death.d.ts.map +1 -0
- package/dist/player/death.js +46 -0
- package/dist/player/death.js.map +1 -0
- package/dist/player/options-file.d.ts +129 -0
- package/dist/player/options-file.d.ts.map +1 -0
- package/dist/player/options-file.js +309 -0
- package/dist/player/options-file.js.map +1 -0
- package/dist/player/options.d.ts +2 -1
- package/dist/player/options.d.ts.map +1 -1
- package/dist/player/options.js +2 -1
- package/dist/player/options.js.map +1 -1
- package/dist/player/player.d.ts +50 -3
- package/dist/player/player.d.ts.map +1 -1
- package/dist/player/player.js +10 -1
- package/dist/player/player.js.map +1 -1
- package/dist/player/shape-lore.d.ts +11 -7
- package/dist/player/shape-lore.d.ts.map +1 -1
- package/dist/player/shape-lore.js +24 -11
- package/dist/player/shape-lore.js.map +1 -1
- package/dist/player/timed.d.ts +5 -3
- package/dist/player/timed.d.ts.map +1 -1
- package/dist/player/timed.js +11 -2
- package/dist/player/timed.js.map +1 -1
- package/dist/player/types.d.ts +29 -4
- package/dist/player/types.d.ts.map +1 -1
- package/dist/player/types.js +24 -1
- package/dist/player/types.js.map +1 -1
- package/dist/session/boot.d.ts +26 -2
- package/dist/session/boot.d.ts.map +1 -1
- package/dist/session/boot.js +21 -2
- package/dist/session/boot.js.map +1 -1
- package/dist/session/game.d.ts +15 -0
- package/dist/session/game.d.ts.map +1 -1
- package/dist/session/game.js +616 -140
- package/dist/session/game.js.map +1 -1
- package/dist/session/save-migrate.d.ts.map +1 -1
- package/dist/session/save-migrate.js +76 -1
- package/dist/session/save-migrate.js.map +1 -1
- package/dist/session/save.d.ts +75 -12
- package/dist/session/save.d.ts.map +1 -1
- package/dist/session/save.js +177 -18
- package/dist/session/save.js.map +1 -1
- package/dist/store/bind.d.ts +1 -1
- package/dist/store/bind.d.ts.map +1 -1
- package/dist/store/bind.js +4 -3
- package/dist/store/bind.js.map +1 -1
- package/dist/store/mass-produce-vectors.d.ts +40 -0
- package/dist/store/mass-produce-vectors.d.ts.map +1 -0
- package/dist/store/mass-produce-vectors.fixtures.d.ts +13 -0
- package/dist/store/mass-produce-vectors.fixtures.d.ts.map +1 -0
- package/dist/store/mass-produce-vectors.fixtures.js +52 -0
- package/dist/store/mass-produce-vectors.fixtures.js.map +1 -0
- package/dist/store/mass-produce-vectors.js +44 -0
- package/dist/store/mass-produce-vectors.js.map +1 -0
- package/dist/store/store.d.ts +104 -7
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +199 -77
- package/dist/store/store.js.map +1 -1
- package/dist/store/transact.d.ts +14 -5
- package/dist/store/transact.d.ts.map +1 -1
- package/dist/store/transact.js +17 -16
- package/dist/store/transact.js.map +1 -1
- package/dist/store/types.d.ts +3 -2
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/types.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/visuals/index.d.ts +1 -0
- package/dist/visuals/index.d.ts.map +1 -1
- package/dist/visuals/index.js +1 -0
- package/dist/visuals/index.js.map +1 -1
- package/dist/visuals/map-text.d.ts +8 -0
- package/dist/visuals/map-text.d.ts.map +1 -1
- package/dist/visuals/map-text.js +1 -1
- package/dist/visuals/map-text.js.map +1 -1
- package/dist/visuals/object-glyph.d.ts +56 -0
- package/dist/visuals/object-glyph.d.ts.map +1 -0
- package/dist/visuals/object-glyph.js +52 -0
- package/dist/visuals/object-glyph.js.map +1 -0
- package/dist/visuals/prefs.d.ts +14 -22
- package/dist/visuals/prefs.d.ts.map +1 -1
- package/dist/visuals/prefs.js +4 -23
- package/dist/visuals/prefs.js.map +1 -1
- package/dist/visuals/tile-prefs.d.ts +26 -0
- package/dist/visuals/tile-prefs.d.ts.map +1 -1
- package/dist/visuals/tile-prefs.js +28 -0
- package/dist/visuals/tile-prefs.js.map +1 -1
- package/dist/world/feature.d.ts +2 -1
- package/dist/world/feature.d.ts.map +1 -1
- package/dist/world/feature.js +2 -0
- package/dist/world/feature.js.map +1 -1
- package/dist/world/project.d.ts +10 -2
- package/dist/world/project.d.ts.map +1 -1
- package/dist/world/project.js +18 -6
- package/dist/world/project.js.map +1 -1
- package/dist/world/projection.d.ts +37 -3
- package/dist/world/projection.d.ts.map +1 -1
- package/dist/world/projection.js +69 -7
- package/dist/world/projection.js.map +1 -1
- package/dist/world/trap.d.ts +2 -1
- package/dist/world/trap.d.ts.map +1 -1
- package/dist/world/trap.js +2 -1
- package/dist/world/trap.js.map +1 -1
- package/dist/world/view.d.ts +1 -1
- package/dist/world/view.d.ts.map +1 -1
- package/dist/world/view.js +11 -3
- package/dist/world/view.js.map +1 -1
- package/package.json +1 -1
- package/src/agent/perceive.ts +2 -3
- package/src/combat/blow-vectors.fixtures.ts +99 -0
- package/src/combat/blow-vectors.json +482 -0
- package/src/combat/blow-vectors.ts +280 -0
- package/src/combat/brand-slay.ts +42 -11
- package/src/combat/index.ts +1 -1
- package/src/combat/melee.ts +37 -19
- package/src/combat/mon-melee.ts +611 -364
- package/src/combat/ranged.ts +43 -26
- package/src/constants.ts +15 -0
- package/src/datafile.ts +148 -0
- package/src/effects/effect-info-registry.ts +313 -0
- package/src/effects/effect-info-vectors.fixtures.ts +61 -0
- package/src/effects/effect-info-vectors.json +11532 -0
- package/src/effects/effect-info-vectors.ts +376 -0
- package/src/effects/effect-info.ts +1005 -859
- package/src/effects/effect.ts +96 -62
- package/src/effects/handlers.ts +5 -2
- package/src/effects/interpreter.ts +14 -0
- package/src/game/cave-cmd.ts +54 -11
- package/src/game/cave-square.ts +80 -0
- package/src/game/char-sheet.ts +59 -16
- package/src/game/chest.ts +25 -8
- package/src/game/context.ts +293 -27
- package/src/game/describe.ts +34 -4
- package/src/game/display.ts +215 -19
- package/src/game/dump-level.ts +3 -2
- package/src/game/effect-attack.ts +41 -28
- package/src/game/effect-detect.ts +45 -8
- package/src/game/effect-env.ts +8 -0
- package/src/game/effect-general.ts +110 -47
- package/src/game/effect-item.ts +1075 -999
- package/src/game/effect-melee.ts +51 -18
- package/src/game/effect-monster.ts +55 -9
- package/src/game/effect-teleport.ts +173 -38
- package/src/game/effect-terrain.ts +38 -22
- package/src/game/equip-cmp.ts +483 -480
- package/src/game/floor.ts +22 -4
- package/src/game/gear.ts +210 -21
- package/src/game/harness.ts +12 -1
- package/src/game/ignore-cmd.ts +96 -8
- package/src/game/known.ts +392 -73
- package/src/game/loop.ts +52 -27
- package/src/game/lore-color.ts +13 -1
- package/src/game/mon-cast.ts +31 -6
- package/src/game/mon-cmd.ts +95 -30
- package/src/game/mon-death.ts +14 -12
- package/src/game/mon-group.ts +9 -5
- package/src/game/mon-message.ts +363 -65
- package/src/game/mon-place.ts +15 -3
- package/src/game/mon-ranged.ts +14 -5
- package/src/game/mon-side.ts +16 -12
- package/src/game/monster-turn.ts +120 -87
- package/src/game/notice.ts +85 -0
- package/src/game/obj-cmd.ts +126 -37
- package/src/game/obj-list.ts +44 -26
- package/src/game/object-inspect.ts +13 -0
- package/src/game/pickup.ts +29 -5
- package/src/game/player-side-vectors.fixtures.ts +215 -0
- package/src/game/player-side-vectors.json +6914 -0
- package/src/game/player-side-vectors.ts +420 -0
- package/src/game/player-side.ts +622 -340
- package/src/game/player-turn.ts +228 -31
- package/src/game/poly.ts +107 -0
- package/src/game/project-cast.ts +63 -6
- package/src/game/project-feat-vectors.fixtures.ts +106 -0
- package/src/game/project-feat-vectors.json +6554 -0
- package/src/game/project-feat-vectors.ts +323 -0
- package/src/game/project-feat.ts +417 -248
- package/src/game/project-monster.ts +69 -30
- package/src/game/project-obj-vectors.json +1 -0
- package/src/game/project-obj.ts +115 -47
- package/src/game/project-player.ts +8 -0
- package/src/game/projection-handlers.ts +110 -0
- package/src/game/quest.ts +48 -0
- package/src/game/ranged-cmd.ts +45 -11
- package/src/game/repeat.ts +92 -0
- package/src/game/shape-inspect.ts +166 -0
- package/src/game/spell-cmd.ts +39 -6
- package/src/game/spoil.ts +92 -39
- package/src/game/steal.ts +9 -4
- package/src/game/target-loop.ts +14 -7
- package/src/game/target.ts +18 -7
- package/src/game/ui-entry.ts +172 -22
- package/src/game/wizard.ts +97 -10
- package/src/game/world.ts +6 -0
- package/src/gen/cave.ts +225 -26
- package/src/gen/generate.ts +62 -9
- package/src/gen/glyph-vectors.fixtures.ts +122 -0
- package/src/gen/glyph-vectors.json +5996 -0
- package/src/gen/glyph-vectors.ts +280 -0
- package/src/gen/glyph.ts +132 -0
- package/src/gen/room.ts +446 -265
- package/src/gen/util.ts +32 -9
- package/src/i18n/i18n.ts +492 -0
- package/src/i18n/text.ts +117 -0
- package/src/index.ts +307 -254
- package/src/mod/extension.ts +136 -0
- package/src/mod/ids.ts +92 -21
- package/src/mod/record-keys.ts +102 -0
- package/src/mod/registry-host.ts +1063 -234
- package/src/mon/bind.ts +14 -8
- package/src/mon/knowledge-groups.ts +12 -12
- package/src/mon/lore-describe.ts +93 -26
- package/src/mon/lore-file.ts +365 -0
- package/src/mon/lore.ts +9 -3
- package/src/mon/make.ts +4 -2
- package/src/mon/monster.ts +1 -1
- package/src/mon/predicate.ts +14 -9
- package/src/mon/project-mon.ts +23 -5
- package/src/mon/steal.ts +39 -7
- package/src/mon/take-hit.ts +8 -3
- package/src/mon/timed.ts +15 -9
- package/src/mon/types.ts +11 -4
- package/src/msg.ts +55 -1
- package/src/obj/artifact-fake.ts +47 -17
- package/src/obj/bind.ts +52 -9
- package/src/obj/desc-vectors.fixtures.ts +119 -0
- package/src/obj/desc-vectors.json +2360 -0
- package/src/obj/desc-vectors.ts +128 -0
- package/src/obj/desc.ts +159 -55
- package/src/obj/effects-info.ts +90 -59
- package/src/obj/fake-object.ts +135 -0
- package/src/obj/ignore.ts +95 -28
- package/src/obj/knowledge.ts +291 -139
- package/src/obj/known-object.ts +126 -11
- package/src/obj/make.ts +53 -29
- package/src/obj/object-info.ts +103 -6
- package/src/obj/object.ts +392 -151
- package/src/obj/power.ts +297 -59
- package/src/obj/randart-build.ts +1875 -1705
- package/src/obj/randart-data.ts +1547 -1344
- package/src/obj/randart-file.ts +130 -0
- package/src/obj/randart-log.ts +78 -0
- package/src/obj/randart-registry.ts +247 -0
- package/src/obj/randart-vectors.fixtures.ts +61 -0
- package/src/obj/randart-vectors.json +836 -0
- package/src/obj/randart-vectors.ts +369 -0
- package/src/obj/randart.ts +722 -552
- package/src/obj/rune-registry.ts +270 -0
- package/src/obj/rune-vectors.fixtures.ts +164 -0
- package/src/obj/rune-vectors.json +121 -0
- package/src/obj/rune-vectors.ts +229 -0
- package/src/obj/tval-kind-vectors.json +391 -0
- package/src/obj/tval-registry.ts +243 -0
- package/src/obj/tval-vectors.fixtures.ts +50 -0
- package/src/obj/tval-vectors.json +38 -0
- package/src/obj/tval-vectors.ts +126 -0
- package/src/obj/types.ts +18 -7
- package/src/obj/value.ts +26 -20
- package/src/parser.ts +214 -0
- package/src/player/bind.ts +5 -2
- package/src/player/birth.ts +2 -1
- package/src/player/calcs.ts +123 -42
- package/src/player/death.ts +78 -0
- package/src/player/options-file.ts +387 -0
- package/src/player/options.ts +2 -1
- package/src/player/player.ts +60 -4
- package/src/player/shape-lore.ts +33 -14
- package/src/player/timed.ts +14 -4
- package/src/player/types.ts +30 -4
- package/src/session/boot.ts +51 -1
- package/src/session/game.ts +720 -163
- package/src/session/save-migrate.ts +81 -1
- package/src/session/save.ts +264 -22
- package/src/store/bind.ts +4 -3
- package/src/store/mass-produce-vectors.fixtures.ts +64 -0
- package/src/store/mass-produce-vectors.json +1169 -0
- package/src/store/mass-produce-vectors.ts +67 -0
- package/src/store/store.ts +266 -63
- package/src/store/transact.ts +39 -16
- package/src/store/types.ts +3 -2
- package/src/version.ts +1 -1
- package/src/visuals/index.ts +1 -0
- package/src/visuals/map-text.ts +1 -1
- package/src/visuals/object-glyph.ts +76 -0
- package/src/visuals/prefs.ts +22 -32
- package/src/visuals/tile-prefs.ts +32 -0
- package/src/world/feature.ts +4 -1
- package/src/world/project.ts +19 -4
- package/src/world/projection.ts +79 -8
- package/src/world/trap.ts +25 -21
- package/src/world/view.ts +11 -1
package/dist/session/game.js
CHANGED
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
* ui-game.c:757-760: store_reset, seed_randart, seed_flavor (back-to-back),
|
|
18
18
|
* then prepare_next_level generation.
|
|
19
19
|
*/
|
|
20
|
-
import { loc } from "../loc.js";
|
|
20
|
+
import { DDGRID, loc, locSum } from "../loc.js";
|
|
21
21
|
import { MessageLog } from "../msg.js";
|
|
22
|
-
import { SKILL, STAT_MAX } from "../player/types.js";
|
|
23
|
-
import { EF, ELEM, HIST, OF, PF, RF, STAT, TMD } from "../generated/index.js";
|
|
22
|
+
import { PN, SKILL, STAT_MAX } from "../player/types.js";
|
|
23
|
+
import { EF, ELEM, HIST, MSG, OF, PF, RF, STAT, TMD } from "../generated/index.js";
|
|
24
24
|
import { bindPlayer } from "../player/bind.js";
|
|
25
25
|
import { generatePlayer, optionsInitCheat, flavorSetAllAware, } from "../player/birth.js";
|
|
26
26
|
import { bonusChangeMessages, calcBonuses, calcHitpoints, toCombatState, toDefenderState, } from "../player/calcs.js";
|
|
@@ -28,15 +28,17 @@ import { playerBestDiggerDigging, playerBestDiggerWithClause, } from "../player/
|
|
|
28
28
|
import { playerExpGain, playerKillExp } from "../player/exp.js";
|
|
29
29
|
import { historyAdd, historyFindArtifact, historyLoseArtifact } from "../player/history.js";
|
|
30
30
|
import { artifactHistoryName, historyStamp } from "../game/history.js";
|
|
31
|
-
import { makePlayerSideEffects, makeIncCheckQueries } from "../game/player-side.js";
|
|
31
|
+
import { makePlayerSideEffects, makeIncCheckHooks, makeIncCheckQueries, makeTimedNotifyQueries, } from "../game/player-side.js";
|
|
32
|
+
import { ProjectionHandlerRegistry } from "../game/projection-handlers.js";
|
|
32
33
|
import { makeTakeHitHooks } from "../game/take-hit-hooks.js";
|
|
33
34
|
import { makeMonBlowEnv } from "../game/mon-side.js";
|
|
35
|
+
import { BlowEffectRegistry, registerCoreBlowEffects, } from "../combat/mon-melee.js";
|
|
34
36
|
import { adj_dex_safe } from "../player/calcs.js";
|
|
35
37
|
import { processCurseTimeouts } from "../game/curse-tick.js";
|
|
36
38
|
import { buildEffectContext } from "../game/effect-env.js";
|
|
37
39
|
import { attachGameEnv } from "../game/effect-game-env.js";
|
|
38
40
|
import { sourceMonster, sourceNone, sourcePlayer } from "../effects/interpreter.js";
|
|
39
|
-
import { DEFAULT_GAME_CONSTANTS, addMonster, deleteMonster, placePlayer, squareMonster, updateMonsterDistances, } from "../game/context.js";
|
|
41
|
+
import { DEFAULT_GAME_CONSTANTS, addMonster, deleteMonster, placePlayer, playerOfHas, squareMonster, updateMonsterDistances, } from "../game/context.js";
|
|
40
42
|
import { Chunk } from "../world/chunk.js";
|
|
41
43
|
import { chunkWriteTerrain } from "../gen/cave.js";
|
|
42
44
|
import { FEAT, SQUARE } from "../generated/index.js";
|
|
@@ -57,11 +59,11 @@ import { registerItemHandlers } from "../game/effect-item.js";
|
|
|
57
59
|
import { registerMeleeHandlers } from "../game/effect-melee.js";
|
|
58
60
|
import { registerSummonHandlers } from "../game/effect-summon.js";
|
|
59
61
|
import { registerDetectHandlers } from "../game/effect-detect.js";
|
|
60
|
-
import { becomeAware, caveIlluminateKnown, caveKnown, newKnownMap, noteSpots, viewerStateOf, } from "../game/known.js";
|
|
62
|
+
import { becomeAware, caveIlluminateKnown, caveKnown, newKnownMap, noteSpots, monsterLightSources, updateMon, viewerStateOf, } from "../game/known.js";
|
|
61
63
|
import { updateView } from "../world/view.js";
|
|
62
64
|
import { PY_EXERT, compactMonsters, isDaytime, playerOverExert } from "../game/world.js";
|
|
63
65
|
import { restoreMonsters } from "../game/scheduler.js";
|
|
64
|
-
import { newTargetState, targetSetMonster } from "../game/target.js";
|
|
66
|
+
import { newTargetState, targetGet, targetOkay, targetSetMonster, } from "../game/target.js";
|
|
65
67
|
import { getLore, loreCountU16, loreLearnFlagIfVisible, loreLearnSpellIfVisible, loreUpdate, } from "../mon/lore.js";
|
|
66
68
|
import { monsterIsVisible } from "../mon/predicate.js";
|
|
67
69
|
import { countMonsterRaces, multiplyMonster, pickAndPlaceDistantMonster, squareIsEmptyLive, wipeMonsterCounts, } from "../game/mon-place.js";
|
|
@@ -70,6 +72,7 @@ import { MonAllocTable } from "../mon/make.js";
|
|
|
70
72
|
import { thrustAway } from "../game/thrust.js";
|
|
71
73
|
import { basicPlayerActor } from "../game/project-cast.js";
|
|
72
74
|
import { installMonsterCasting } from "../game/mon-ranged.js";
|
|
75
|
+
import { polyRace, polymorphMonster } from "../game/poly.js";
|
|
73
76
|
import { buildMonSpellHooks, buildFailRuneEnv } from "../game/mon-cast.js";
|
|
74
77
|
import { installMonCommand } from "../game/mon-cmd.js";
|
|
75
78
|
import { monsterChangeShape, monsterRevertShape } from "../game/mon-shape.js";
|
|
@@ -83,29 +86,36 @@ import { calcMana, calcSpells, cumberArmorFrom, playerSpellsInit, registerBookKi
|
|
|
83
86
|
import { installSpellCommands, makeSpellChanceEnv } from "../game/spell-cmd.js";
|
|
84
87
|
import { installRangedCommands } from "../game/ranged-cmd.js";
|
|
85
88
|
import { markNoscore, NOSCORE } from "../game/wizard.js";
|
|
86
|
-
import { createTownStores, storeUpdate, storeWillBuy } from "../store/store.js";
|
|
89
|
+
import { createTownStores, registerCoreStoreBehaviour, StoreBehaviourRegistry, storeUpdate, storeWillBuy, } from "../store/store.js";
|
|
87
90
|
import { homeCarry, homeRetrieve, homeStash, storeBuy, storeSell, storeSellFloor, } from "../store/transact.js";
|
|
88
91
|
import { storeCheckNum } from "../store/store.js";
|
|
89
92
|
import { priceItem } from "../store/price.js";
|
|
90
|
-
import {
|
|
91
|
-
import { AutoinscriptionRegistry, RuneNoteRegistry, buildRuneList, runeKey, FlavorKnowledge, EverseenKnowledge, equipLearnElement, makeRuneEnv, NOOP_FLAVOR_AWARE_DEPS, OBJ_NOTICE, objectLearnOnWield, playerLearnInnate, playerLearnAllRunes, } from "../obj/knowledge.js";
|
|
93
|
+
import { addMonsterMessage, addMonsterMessageShowDamage, messagePain, messagePainShowDamage, monMessageCodeByName, } from "../game/mon-message.js";
|
|
94
|
+
import { AutoinscriptionRegistry, RuneNoteRegistry, buildRuneList, runeKey, FlavorKnowledge, EverseenKnowledge, equipLearnElement, equipLearnFlag, makeRuneEnv, NOOP_FLAVOR_AWARE_DEPS, OBJ_NOTICE, objectLearnOnWield, playerLearnInnate, playerLearnAllRunes, } from "../obj/knowledge.js";
|
|
92
95
|
import { flavorInit } from "../obj/flavor.js";
|
|
93
96
|
import { ELEM_MAX } from "../obj/types.js";
|
|
94
97
|
import { ArtifactState, ObjAllocState } from "../obj/make.js";
|
|
95
98
|
import { monsterDeath, installNonplayerHitDeps } from "../game/mon-death.js";
|
|
96
|
-
import { newGear, outfitPlayer, gearGet, calcInventory, minusAc as applyMinusAc, objectCopyAmt, } from "../game/gear.js";
|
|
99
|
+
import { newGear, outfitPlayer, gearGet, gearTotalWeight, calcInventory, combinePackForPlayer, minusAc as applyMinusAc, objectCopyAmt, } from "../game/gear.js";
|
|
97
100
|
import { objectValue as computeObjectValue } from "../obj/value.js";
|
|
98
101
|
import { buildCurseTimedFoil } from "../obj/object.js";
|
|
99
102
|
import { createDefaultRegistry, installMeleeSideEffects, search } from "../game/player-turn.js";
|
|
103
|
+
import { noticeNewLevel } from "../game/notice.js";
|
|
104
|
+
import { cmdDisableRepeatFloorItem } from "../game/repeat.js";
|
|
100
105
|
import { buildTempBrandSlay, playerIncCheck } from "../player/timed.js";
|
|
106
|
+
import { describeObject, knownDescOf, objectKnownView } from "../game/describe.js";
|
|
107
|
+
import { knownBonusView, objectFlagIsKnown, objectKnownShadow, } from "../obj/known-object.js";
|
|
108
|
+
import { ODESC, objDescNameFormat } from "../obj/desc.js";
|
|
101
109
|
import { disturb, installRunning } from "../game/player-path.js";
|
|
102
110
|
import { bindCore, bootLevel, genDeps } from "./boot.js";
|
|
103
111
|
import { dungeonGetNextLevel, isQuest, playerQuestsReset, questCheck, } from "../game/quest.js";
|
|
104
112
|
import { Rng } from "../rng.js";
|
|
105
113
|
import { OptionState } from "../player/options.js";
|
|
114
|
+
import { optionsInitDefaults } from "../player/options-file.js";
|
|
115
|
+
import { host } from "../host/io.js";
|
|
106
116
|
import { doRandart, RANDNAME_TOLKIEN } from "../obj/randart.js";
|
|
107
117
|
import { makeActivationSummarizer } from "../obj/effects-info.js";
|
|
108
|
-
import { generateLevel, getJoinInfo } from "../gen/generate.js";
|
|
118
|
+
import { generateLevel, getJoinInfo, getMinLevelSize, } from "../gen/generate.js";
|
|
109
119
|
import { iToGrid } from "../gen/util.js";
|
|
110
120
|
import { deserializeAutoinscriptions, deserializeEverseen, deserializeFlavor, deserializeIgnore, deserializeChunk, deserializeFloor, buildFeatRemap, deserializeArtifactsCreated, deserializeArtifactFlags, deserializeGear, deserializeKnown, deserializeLevelCache, deserializeLore, deserializeMessages, deserializeMonster, deserializePlayer, deserializeStores, deserializeTraps, serializeGame, } from "./save.js";
|
|
111
121
|
import { migrateSave } from "./save-migrate.js";
|
|
@@ -139,6 +149,28 @@ export function resolveTargetItem(state, req) {
|
|
|
139
149
|
state.itemRequest = req;
|
|
140
150
|
return null;
|
|
141
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* The getAimTarget seam body: effect_handler_TELEPORT_TO's own get_aim_dir
|
|
154
|
+
* (effect-handler-general.c:2770-2778), resolved from the direction the shell
|
|
155
|
+
* pre-asked and rode on the command.
|
|
156
|
+
*
|
|
157
|
+
* do { if (!get_aim_dir(&dir)) return false; } while (dir == DIR_TARGET && !target_okay());
|
|
158
|
+
* if (dir == DIR_TARGET) target_get(&aim);
|
|
159
|
+
* else aim = loc_offset(start, ddx[dir], ddy[dir]);
|
|
160
|
+
*
|
|
161
|
+
* The C loop re-asks until the answer is usable; a port that cannot block
|
|
162
|
+
* instead treats an unusable answer as the cancel the loop's ESC produces. No
|
|
163
|
+
* RNG either way.
|
|
164
|
+
*/
|
|
165
|
+
export function resolveEffectAim(state) {
|
|
166
|
+
const dir = state.effectAimDir;
|
|
167
|
+
if (dir === null || dir === undefined || dir < 1 || dir > 9)
|
|
168
|
+
return null;
|
|
169
|
+
/* DIR_TARGET: the while() means a target that is gone is not a direction. */
|
|
170
|
+
if (dir === 5)
|
|
171
|
+
return targetOkay(state) ? targetGet(state) : null;
|
|
172
|
+
return locSum(state.actor.grid, DDGRID[dir] ?? loc(0, 0));
|
|
173
|
+
}
|
|
142
174
|
/**
|
|
143
175
|
* The chooseCurse seam body (get_curse, effect-handler-general.c): return the
|
|
144
176
|
* shell's preset curse index when it is one of the removable curses, else the
|
|
@@ -155,18 +187,22 @@ export function resolveTargetCurse(state, removable) {
|
|
|
155
187
|
/**
|
|
156
188
|
* The real, in-play FlavorAwareDeps for object_flavor_aware's ignore fix
|
|
157
189
|
* (obj-knowledge.c L2276-2279, #89): reads the live ignore settings so a
|
|
158
|
-
* kind ignored while unaware keeps being ignored once identified, and
|
|
159
|
-
* player->upkeep->notice's PN_IGNORE (
|
|
160
|
-
*
|
|
161
|
-
*
|
|
190
|
+
* kind ignored while unaware keeps being ignored once identified, and raises
|
|
191
|
+
* player->upkeep->notice's PN_IGNORE (obj-knowledge.c L2279) so the next
|
|
192
|
+
* notice_stuff runs an ignore_drop pass. Shared by the two in-play
|
|
193
|
+
* becomes-aware sites: game/obj-cmd.ts's item-use knowledge gain
|
|
162
194
|
* (installObjCommands below) and store/transact.ts's buy/sell (makeStoreApi).
|
|
195
|
+
*
|
|
196
|
+
* This used to set a bespoke `state.noticeIgnore` boolean because there was no
|
|
197
|
+
* notice mask to raise a bit in - and nothing ever read the boolean, which is
|
|
198
|
+
* PORT_TODO 2.5. It raises the real bit now.
|
|
163
199
|
*/
|
|
164
200
|
function flavorAwareDeps(state) {
|
|
165
201
|
return {
|
|
166
202
|
isIgnoredUnaware: (kidx) => state.ignore.kindIsIgnoredUnaware(kidx),
|
|
167
203
|
ignoreWhenAware: (kidx) => state.ignore.kindIgnoreWhenAware(kidx),
|
|
168
204
|
requestIgnoreNotice: () => {
|
|
169
|
-
state.
|
|
205
|
+
state.actor.player.upkeep.notice |= PN.IGNORE;
|
|
170
206
|
},
|
|
171
207
|
};
|
|
172
208
|
}
|
|
@@ -178,7 +214,7 @@ function flavorAwareDeps(state) {
|
|
|
178
214
|
* captured by every closure, so a level change may swap the state's chunk
|
|
179
215
|
* and entity stores in place without rewiring.
|
|
180
216
|
*/
|
|
181
|
-
function wireGame(state, reg, players, pstate, seedFlavor
|
|
217
|
+
function wireGame(state, reg, players, pstate, seedFlavor) {
|
|
182
218
|
// Rolling message log (message.c file-statics; gap 12.8). Shared producer for
|
|
183
219
|
// both new-game and load paths: startGame arrives with no log so this creates
|
|
184
220
|
// it; loadGame already restored one via deserializeMessages, so preserve it
|
|
@@ -212,7 +248,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
212
248
|
// ignore_item_ok (obj-ignore.c): the player's ignore settings resolved with
|
|
213
249
|
// live flavor awareness. Everything reads it through state.isIgnored so the
|
|
214
250
|
// floor / pickup / running / projection paths need no flavor coupling.
|
|
215
|
-
state.isIgnored = (obj) => ignoreItemOk(obj, state.ignore, flavor.isAware(obj.kind));
|
|
251
|
+
state.isIgnored = (obj) => ignoreItemOk(obj, objectKnownView(state, obj), state.ignore, flavor.isAware(obj.kind));
|
|
216
252
|
// object_flavor_is_aware (obj-knowledge.c): the presentation view models
|
|
217
253
|
// (obj-list.c, #25) read kind awareness through this seam, keeping them
|
|
218
254
|
// decoupled from the flavor store just like isIgnored.
|
|
@@ -247,12 +283,16 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
247
283
|
});
|
|
248
284
|
// Rune learning (obj-knowledge.c learn-by-use): the registry tables plus
|
|
249
285
|
// live equipment access. Reads through the state object so level changes
|
|
250
|
-
// and gear swaps need no rewiring.
|
|
286
|
+
// and gear swaps need no rewiring. `describeBase` is the real ODESC_BASE for
|
|
287
|
+
// the six rune / flag / curse messages (PORT_TODO 3.23); it is supplied HERE
|
|
288
|
+
// and only here, because the two other makeRuneEnv calls in this file are the
|
|
289
|
+
// documented placeholders wireGame replaces.
|
|
251
290
|
state.runeEnv = makeRuneEnv((slot) => state.gear.store.get(state.actor.player.equipment[slot] ?? 0) ?? null, (v) => state.rng.randcalcVaries(v), {
|
|
252
291
|
brands: reg.objects.brands,
|
|
253
292
|
slays: reg.objects.slays,
|
|
254
293
|
curses: reg.objects.curses,
|
|
255
294
|
properties: reg.objects.properties,
|
|
295
|
+
describeBase: (obj) => describeObject(state, obj, ODESC.BASE),
|
|
256
296
|
...(reg.projections
|
|
257
297
|
? {
|
|
258
298
|
elementNames: reg.projections
|
|
@@ -278,6 +318,31 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
278
318
|
// fail-chance display always read the current stats.
|
|
279
319
|
const liveStatInd = [...pstate.statInd];
|
|
280
320
|
state.statInd = liveStatInd;
|
|
321
|
+
/**
|
|
322
|
+
* calc_bonuses(p, &known_state, TRUE, TRUE) (player-calcs.c:2349): the SECOND
|
|
323
|
+
* derive, the one the player is SHOWN. Same options and the same `update`
|
|
324
|
+
* flag upstream passes - its side effects (zeroing TMD_FASTCAST on a stun
|
|
325
|
+
* grade) are idempotent, so running them twice is what upstream does and
|
|
326
|
+
* costs nothing.
|
|
327
|
+
*
|
|
328
|
+
* knownBonusView is the whole difference: it hands the equipment loop each
|
|
329
|
+
* worn item's known twin, so an unlearned rune's to_a / to_h / to_d / resist
|
|
330
|
+
* / flag is left out of what gets printed while staying in what gets rolled.
|
|
331
|
+
*
|
|
332
|
+
* A named function rather than three lines inside refreshDerived because it
|
|
333
|
+
* is also called ONCE at the end of wiring. Without that seed, actor
|
|
334
|
+
* .knownCombat would hold the real state until the first equipment change,
|
|
335
|
+
* and a loaded character wearing unidentified gear would see true numbers on
|
|
336
|
+
* the sidebar for exactly as long as they stood still.
|
|
337
|
+
*/
|
|
338
|
+
const refreshKnownCombat = (p, bonusOptions) => {
|
|
339
|
+
const known = calcBonuses(p, {
|
|
340
|
+
...bonusOptions,
|
|
341
|
+
knownOnly: (obj) => knownBonusView(obj, p, state.runeEnv, knownDescOf(state)),
|
|
342
|
+
});
|
|
343
|
+
state.knownPlayerState = known;
|
|
344
|
+
state.actor.knownCombat = toCombatState(known);
|
|
345
|
+
};
|
|
281
346
|
const refreshDerived = () => {
|
|
282
347
|
const p = state.actor.player;
|
|
283
348
|
const equipment = p.equipment.map((h) => h ? gearGet(state.gear, h) : null);
|
|
@@ -285,15 +350,17 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
285
350
|
/* p->state before the memcpy at the end of calc_bonuses: the encumbrance
|
|
286
351
|
* notices below diff against it (player-calcs.c:2412-2453). */
|
|
287
352
|
const before = derived;
|
|
288
|
-
|
|
353
|
+
const bonusOptions = {
|
|
289
354
|
equipment,
|
|
290
355
|
timedEffects: players.timed,
|
|
291
356
|
curses: reg.objects.curses,
|
|
292
357
|
update: true,
|
|
293
358
|
depth: state.chunk.depth,
|
|
294
359
|
isDaytime: daytime,
|
|
295
|
-
}
|
|
360
|
+
};
|
|
361
|
+
derived = calcBonuses(p, bonusOptions);
|
|
296
362
|
state.playerState = derived;
|
|
363
|
+
refreshKnownCombat(p, bonusOptions);
|
|
297
364
|
/* calc_light's town-daytime branch (player-calcs.c 1608-1611) flags
|
|
298
365
|
* PU_UPDATE_VIEW | PU_MONSTERS before returning; reinstate that refresh so
|
|
299
366
|
* ambient town light tracks the day/night cycle. */
|
|
@@ -353,30 +420,47 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
353
420
|
* with nothing installed.
|
|
354
421
|
*
|
|
355
422
|
* `??=` rather than `=`: a host that wants its own events bus or light sources
|
|
356
|
-
* still
|
|
357
|
-
*
|
|
358
|
-
*
|
|
423
|
+
* can still replace this. NOTE that no shipped host does - the web calls core's
|
|
424
|
+
* (main.ts:8484 throws if wireGame did not install one) and so does the MCP
|
|
425
|
+
* session. This comment used to assert "and the web does", which is how the
|
|
426
|
+
* hardcoded `[]` below survived: a seam documented as host-supplied reads as
|
|
427
|
+
* deliberate rather than empty. Wired in wireGame so startGame and loadGame
|
|
428
|
+
* both get it - a resumed character has the same right to a map as a new one.
|
|
359
429
|
*
|
|
360
430
|
* The viewer fields come from `viewerStateOf` (game/known.ts) rather than being
|
|
361
431
|
* spelled out again here, because spelling them out twice is how both hosts came
|
|
362
432
|
* to pass `chunk.depth` where cave-view.c:778 reads `p->lev`.
|
|
363
433
|
*/
|
|
364
434
|
state.updateFov ??= (s) => {
|
|
365
|
-
updateView(s.chunk, viewerStateOf(s), { maxSight: reg.constants.maxSight, feelingNeed: reg.constants.feelingNeed },
|
|
435
|
+
updateView(s.chunk, viewerStateOf(s), { maxSight: reg.constants.maxSight, feelingNeed: reg.constants.feelingNeed },
|
|
436
|
+
/* calc_lighting's monster scan (cave-view.c L696-719). Was `[]`. */
|
|
437
|
+
monsterLightSources(s), s.events,
|
|
438
|
+
/* cave-view.c:852: the object feeling, the moment the player has seen
|
|
439
|
+
* enough of the level to earn it. objOnly is display_feeling(true) - the
|
|
440
|
+
* one-line object half, not the joined ^F line - and the disturb is
|
|
441
|
+
* upstream's, so a run or a rest stops on the news. */
|
|
442
|
+
() => {
|
|
443
|
+
displayFeeling(s, { objOnly: true });
|
|
444
|
+
disturb(s);
|
|
445
|
+
});
|
|
366
446
|
noteSpots(s);
|
|
367
447
|
};
|
|
448
|
+
/* The live calc_inventory inputs, shared by every closure below that has to
|
|
449
|
+
* re-derive upkeep->inven[] / upkeep->quiver[]. One function rather than a
|
|
450
|
+
* copy per seam, so a change to the options bag reaches all of them. */
|
|
451
|
+
const liveCalcInv = () => ({
|
|
452
|
+
ammoTval: state.playerState?.ammoTval ?? 0,
|
|
453
|
+
objectValue: (obj) => computeObjectValue(reg.objects, obj, 1, true),
|
|
454
|
+
rogueLike: state.options?.get("rogue_like_commands") ?? false,
|
|
455
|
+
characterDungeon: true,
|
|
456
|
+
...(state.msg ? { msg: state.msg } : {}),
|
|
457
|
+
});
|
|
368
458
|
/* game-world.c:941-947: the C refreshes upkeep->inven[] before its
|
|
369
459
|
* catch-all pack_overflow(NULL). This closure has the same live
|
|
370
460
|
* calc_inventory inputs used by pickup and command paths, preserving the
|
|
371
461
|
* earlier_object order of the derived gear.inven view. */
|
|
372
462
|
state.overflowPack = () => {
|
|
373
|
-
const calcInv =
|
|
374
|
-
ammoTval: state.playerState?.ammoTval ?? 0,
|
|
375
|
-
objectValue: (obj) => computeObjectValue(reg.objects, obj, 1, true),
|
|
376
|
-
rogueLike: state.options?.get("rogue_like_commands") ?? false,
|
|
377
|
-
characterDungeon: true,
|
|
378
|
-
...(state.msg ? { msg: state.msg } : {}),
|
|
379
|
-
};
|
|
463
|
+
const calcInv = liveCalcInv();
|
|
380
464
|
/* notice_stuff()/handle_stuff() precede pack_overflow(NULL) at
|
|
381
465
|
* game-world.c:941-947; materialize the current upkeep->inven[] analogue
|
|
382
466
|
* before selecting its final entry. */
|
|
@@ -386,6 +470,11 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
386
470
|
...(state.msg ? { msg: state.msg } : {}),
|
|
387
471
|
});
|
|
388
472
|
};
|
|
473
|
+
/* notice_stuff's PN_COMBINE branch (player-calcs.c L2546-2549). combine_pack
|
|
474
|
+
* ends in its own calc_inventory, so this needs the same options bag. */
|
|
475
|
+
state.combinePack = () => {
|
|
476
|
+
combinePackForPlayer(state.gear, state.actor.player, reg.constants, liveCalcInv());
|
|
477
|
+
};
|
|
389
478
|
/* Stash the class list so refreshTownStores can expand the bookseller's
|
|
390
479
|
* town-book always lines (object_kind_to_book, store.c:208-231). */
|
|
391
480
|
state.classes = players.classes;
|
|
@@ -467,8 +556,11 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
467
556
|
const expRace = mon.race;
|
|
468
557
|
/* Shapechanged monsters revert on death (mon-util.c L1027). */
|
|
469
558
|
monsterRevertShape(state, mon);
|
|
470
|
-
/* player_kill_monster: dead uniques stay dead (max_num = 0).
|
|
471
|
-
*
|
|
559
|
+
/* player_kill_monster: dead uniques stay dead (max_num = 0). This is NOT
|
|
560
|
+
* session-lifetime, contrary to what this comment used to say: the save
|
|
561
|
+
* carries the lore, and the load path re-derives maxNum = 0 for every
|
|
562
|
+
* unique with pkills > 0 (see the SV-01 block below), exactly as
|
|
563
|
+
* load.c:532-535 does. Nothing about it rides an unbuilt save format. */
|
|
472
564
|
if (mon.race.flags.has(RF.UNIQUE)) {
|
|
473
565
|
/* bug-fixes #4245 ("Unique coming back to life?"): a unique can produce
|
|
474
566
|
* multiple "Killed X" kill-history entries via shape-change / projection
|
|
@@ -615,6 +707,26 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
615
707
|
const floorEnv = {
|
|
616
708
|
isIgnored: (obj) => state.isIgnored(obj),
|
|
617
709
|
...(preds ? { isTrap: preds.isTrap } : {}),
|
|
710
|
+
/* floor_carry_fail's message (obj-pile.c:992-1011). Neither of these two
|
|
711
|
+
* had a producer, so an item that broke on a throw, or vanished because
|
|
712
|
+
* the floor had no room for it, disappeared in total silence - the player
|
|
713
|
+
* was simply short an item with no line to explain it. object_desc's mode
|
|
714
|
+
* is ODESC_BASE (:1002), the bare name. */
|
|
715
|
+
onBreak: (obj, broke) => {
|
|
716
|
+
const name = describeObject(state, obj, ODESC.BASE);
|
|
717
|
+
const verb = broke
|
|
718
|
+
? obj.number > 1
|
|
719
|
+
? "break"
|
|
720
|
+
: "breaks"
|
|
721
|
+
: obj.number > 1
|
|
722
|
+
? "disappear"
|
|
723
|
+
: "disappears";
|
|
724
|
+
state.msg?.(`The ${name} ${verb}.`);
|
|
725
|
+
},
|
|
726
|
+
/* sound(MSG_DROP) (obj-pile.c:1150), the moment an object lands. */
|
|
727
|
+
onDrop: () => {
|
|
728
|
+
state.sound?.(MSG.DROP);
|
|
729
|
+
},
|
|
618
730
|
};
|
|
619
731
|
// Monster-death loot deps: makeDeps builds the objects, reg.objects looks
|
|
620
732
|
// up specified drops, floorEnv places them, state.lore feeds the theft
|
|
@@ -625,32 +737,92 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
625
737
|
floorEnv,
|
|
626
738
|
lore: state.lore,
|
|
627
739
|
};
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
},
|
|
652
|
-
|
|
653
|
-
|
|
740
|
+
/* The teleport-family environment (game/effect-teleport.ts TeleportEnv).
|
|
741
|
+
*
|
|
742
|
+
* This used to be `preds ? {...seven fields} : undefined` - so a game
|
|
743
|
+
* without the trap registry had NO teleport env at all, and nine of the
|
|
744
|
+
* sixteen fields had no producer anywhere even when it did. Each of those
|
|
745
|
+
* nine is a live upstream read whose subsystem has since been built, so the
|
|
746
|
+
* "inert default" they fell back on was a silently missing feature: the
|
|
747
|
+
* OF_NO_TELEPORT curse never blocked a teleport and its rune was never
|
|
748
|
+
* learned, a teleport could land the player in lava, nexus resistance did
|
|
749
|
+
* not foil a hostile teleport-level, and Dimension Door aborted every time.
|
|
750
|
+
* Only the trap predicates are conditional now.
|
|
751
|
+
*
|
|
752
|
+
* The three player reads are GETTERS, not values: this object is built once
|
|
753
|
+
* per game and every consumer holds the same reference, so a captured
|
|
754
|
+
* boolean would freeze the answer at wiring time - before the player ever
|
|
755
|
+
* picked up the cursed ring. */
|
|
756
|
+
const teleport = {
|
|
757
|
+
...(preds
|
|
758
|
+
? {
|
|
759
|
+
isPlayerTrap: preds.isPlayerTrap,
|
|
760
|
+
isWarded: preds.isWarded,
|
|
761
|
+
isWebbed: preds.isWebbed,
|
|
762
|
+
}
|
|
763
|
+
: {}),
|
|
764
|
+
/* square_isdamaging (cave-square.c): fiery terrain. Nothing supplied it,
|
|
765
|
+
* so has_teleport_destination_prereqs happily landed the player in lava. */
|
|
766
|
+
isDamaging: (grid) => state.chunk.isDamaging(grid),
|
|
767
|
+
/* is_quest (player-quest.c L140): the real implementation behind the
|
|
768
|
+
* force_descend / teleport-level guards (effect-general.ts,
|
|
769
|
+
* effect-teleport.ts, effect-terrain.ts) - a quest level cannot be
|
|
770
|
+
* skipped or recalled away from. */
|
|
771
|
+
isQuest: (depth) => isQuest(state.actor.player, depth),
|
|
772
|
+
/* dungeon_get_next_level (player-util.c:1147). This seam existed but
|
|
773
|
+
* nothing ever wired it, so every consumer silently degraded to a
|
|
774
|
+
* bare `depth + dir` - no stair_skip, no max_depth clamp and, worst,
|
|
775
|
+
* no quest scan. */
|
|
776
|
+
getNextLevel: (from, dir) => dungeonGetNextLevel(state.actor.player, from, dir, state.z),
|
|
777
|
+
changeLevel: (targetDepth) => {
|
|
778
|
+
state.targetDepth = targetDepth;
|
|
779
|
+
state.generateLevel = true;
|
|
780
|
+
},
|
|
781
|
+
/* player_handle_post_move eval_trap half (player-util.c:1627-1629):
|
|
782
|
+
* immediate traps at the landing grid after teleport / thrust. */
|
|
783
|
+
onPlayerPostMove: (_byMonster) => {
|
|
784
|
+
state.onPlayerMoved?.(state, state.actor.grid);
|
|
785
|
+
},
|
|
786
|
+
/* handle_stuff(player) after a monster teleports (PU_UPDATE_VIEW): the
|
|
787
|
+
* monster's own visibility and lighting are monsterSwap's, but the
|
|
788
|
+
* player's field of view is not, and a light-carrying monster arriving
|
|
789
|
+
* next door has to change what the player can see. */
|
|
790
|
+
onMonsterPostMove: (_midx) => {
|
|
791
|
+
state.updateFov?.(state);
|
|
792
|
+
},
|
|
793
|
+
/* player_of_has(OF_NO_TELEPORT) and its equip_learn_flag, the pair that
|
|
794
|
+
* makes a Teleportation-forbidding curse do anything at all. */
|
|
795
|
+
get hasNoTeleport() {
|
|
796
|
+
return playerOfHas(state, OF.NO_TELEPORT);
|
|
797
|
+
},
|
|
798
|
+
onLearnNoTeleport: () => {
|
|
799
|
+
equipLearnFlag(state.actor.player, state.runeEnv, OF.NO_TELEPORT);
|
|
800
|
+
},
|
|
801
|
+
/* player_resists(player, ELEM_NEXUS) (player-util.c): res_level > 0, off
|
|
802
|
+
* the LIVE derived state, so a swapped-in resist ring counts. */
|
|
803
|
+
get resistsNexus() {
|
|
804
|
+
return (state.playerState?.elInfo[ELEM.NEXUS]?.resLevel ?? 0) > 0;
|
|
805
|
+
},
|
|
806
|
+
/* player->max_depth: EF_TELEPORT_LEVEL's force_descend target is the
|
|
807
|
+
* deepest level REACHED, not the current one. Defaulting to the current
|
|
808
|
+
* depth made "deep descent"-style descent one level, every time. */
|
|
809
|
+
get maxPlayerDepth() {
|
|
810
|
+
return state.actor.player.maxDepth;
|
|
811
|
+
},
|
|
812
|
+
/* z_info->max_depth, from the bound constants rather than the hardcoded
|
|
813
|
+
* 128 the default assumed - a mod may ship a different dungeon bottom. */
|
|
814
|
+
maxDepth: reg.constants.maxDepth,
|
|
815
|
+
/* OPT(player, birth_force_descend) off the live option store. */
|
|
816
|
+
get forceDescend() {
|
|
817
|
+
return state.options?.get("birth_force_descend") ?? false;
|
|
818
|
+
},
|
|
819
|
+
/* get_aim_dir inside effect_handler_TELEPORT_TO (Dimension Door,
|
|
820
|
+
* effect-handler-general.c:2770-2778). The port cannot block mid-turn, so
|
|
821
|
+
* the shell asks first and rides the direction on the command; core does
|
|
822
|
+
* the resolution because `start` is the player's grid and the offset
|
|
823
|
+
* arithmetic belongs next to the handler, not in a front end. */
|
|
824
|
+
getAimTarget: () => resolveEffectAim(state),
|
|
825
|
+
};
|
|
654
826
|
// Glyph / web creation needs the trap system; trapDeps joins below
|
|
655
827
|
// once it is built (the mutual reference is deliberate). The stat
|
|
656
828
|
// adjectives (desc_stat) come from the bound object properties, and
|
|
@@ -712,9 +884,28 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
712
884
|
* PARSE_ERROR_INVALID_EFFECT, exactly as before. */
|
|
713
885
|
lookupEffect: (name) => (effects.isRegistered(name) ? name : null),
|
|
714
886
|
};
|
|
887
|
+
/* Published on the state so buildObjectEffectChain has these by default.
|
|
888
|
+
* The chain is rebuilt from raw records on every USE and every INSPECT, and
|
|
889
|
+
* a caller that omitted them could not resolve `SUMMON:ANY` - it threw
|
|
890
|
+
* mid-turn. See GameState.effectInject. */
|
|
891
|
+
state.effectInject = inject;
|
|
892
|
+
/* The three projection handler tables (game/projection-handlers.ts), seeded
|
|
893
|
+
* with core's 69. Built here, per game, for the same reason as the blow and
|
|
894
|
+
* store registries: a module-level table would carry one character's mod
|
|
895
|
+
* into the next character's game.
|
|
896
|
+
*
|
|
897
|
+
* Handed to the engine BY IDENTITY below - `worldEnv` and the playerHandlers
|
|
898
|
+
* dep hold these very Maps. A mod's register() runs after this wiring, so a
|
|
899
|
+
* snapshot would be a seam that ignored every mod. */
|
|
900
|
+
const projectionHandlers = new ProjectionHandlerRegistry();
|
|
901
|
+
state.projectionHandlers = projectionHandlers;
|
|
715
902
|
// project_o / project_f world access; trapDeps joins it below once the
|
|
716
903
|
// trap system is wired (the mutual reference is deliberate).
|
|
717
|
-
const worldEnv = {
|
|
904
|
+
const worldEnv = {
|
|
905
|
+
makeDeps,
|
|
906
|
+
featHandlers: projectionHandlers.feat.table,
|
|
907
|
+
objHandlers: projectionHandlers.obj.table,
|
|
908
|
+
};
|
|
718
909
|
/* The projection view reads the LIVE derived state, so worn resistance
|
|
719
910
|
* gear reduces projection damage and equipment swaps take effect. */
|
|
720
911
|
const playerActor = basicPlayerActor(state, {
|
|
@@ -751,20 +942,19 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
751
942
|
monsterDeath(state, m, deathDeps);
|
|
752
943
|
},
|
|
753
944
|
/* add_monster_message: "the kobold dies", "wakes up", "catches
|
|
754
|
-
* fire" - the
|
|
755
|
-
* a
|
|
756
|
-
*
|
|
945
|
+
* fire" - STACKED on the mon_msg[] queue, not emitted here, so one
|
|
946
|
+
* breath over a pit produces "8 kobolds die." and the deaths come
|
|
947
|
+
* last. noticeStuff drains it. The projection already gates on
|
|
757
948
|
* visibility before calling this. */
|
|
758
|
-
message: (m, msgCode,
|
|
949
|
+
message: (m, msgCode, delay, damage) => {
|
|
759
950
|
/* add_monster_message_show_damage (mon-msg.c:288) when the driver
|
|
760
951
|
* passed a damage total, else add_monster_message (L252). */
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
state.sound?.(type);
|
|
952
|
+
if (damage === undefined) {
|
|
953
|
+
addMonsterMessage(state, m, msgCode, delay);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
addMonsterMessageShowDamage(state, m, msgCode, delay, damage);
|
|
957
|
+
}
|
|
768
958
|
},
|
|
769
959
|
/* OPT(player, show_damage): project_m_player_attack's display_dam
|
|
770
960
|
* (project-mon.c:1111) picks the *_show_damage message variants. */
|
|
@@ -772,19 +962,18 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
772
962
|
/* message_pain: the graded "shrugs off the attack" / "cries out in
|
|
773
963
|
* pain" line for a monster hurt but not killed. */
|
|
774
964
|
messagePain: (m, dam, showDamage) => {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
if (text)
|
|
780
|
-
state.msg?.(text, type);
|
|
781
|
-
state.sound?.(type);
|
|
965
|
+
if (showDamage)
|
|
966
|
+
messagePainShowDamage(state, m, dam);
|
|
967
|
+
else
|
|
968
|
+
messagePain(state, m, dam);
|
|
782
969
|
},
|
|
783
|
-
/* mon_set_timed's queued status messages (slowed, confused, held)
|
|
970
|
+
/* mon_set_timed's queued status messages (slowed, confused, held),
|
|
971
|
+
* add_monster_message(mon, m_note, true) at mon-timed.c:215 - the
|
|
972
|
+
* delayed pass, so a status line follows the blow that caused it. */
|
|
784
973
|
timedMessage: (m, note) => {
|
|
785
|
-
const
|
|
786
|
-
if (
|
|
787
|
-
state
|
|
974
|
+
const code = monMessageCodeByName(note);
|
|
975
|
+
if (code !== null)
|
|
976
|
+
addMonsterMessage(state, m, code, true);
|
|
788
977
|
},
|
|
789
978
|
/* Lore learning when a projection's outcome is seen. */
|
|
790
979
|
learnRaceFlag: (m, flag) => loreLearnFlagIfVisible(getLore(state.lore, m.race), m, flag),
|
|
@@ -793,8 +982,31 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
793
982
|
revertShape: (m) => {
|
|
794
983
|
monsterRevertShape(state, m);
|
|
795
984
|
},
|
|
985
|
+
/* poly_race + the delete/place swap (project-mon.c:45, :1225-1229).
|
|
986
|
+
* Both halves are supplied, and separately, because upstream queues
|
|
987
|
+
* MON_MSG_CHANGE between them - naming the old monster while it still
|
|
988
|
+
* exists. Until this was wired the hook had NO supplier at all, so a
|
|
989
|
+
* Wand of Polymorph rolled its saving throw, spent the charge and then
|
|
990
|
+
* reported "maintains its shape" every single time.
|
|
991
|
+
*
|
|
992
|
+
* ambientPlaceDeps is declared later in this same function; the
|
|
993
|
+
* forward reference is safe for the same reason state.monsterMultiply
|
|
994
|
+
* (which uses it too) is - these arrows only run during play. Reusing
|
|
995
|
+
* it rather than a private table also means the polymorphed monster
|
|
996
|
+
* gets its held drops, as place_monster does for any origin != 0. */
|
|
997
|
+
polyRace: (race) => polyRace(state, race, state.chunk.depth, ambientPlaceDeps),
|
|
998
|
+
replaceMonster: (m, race) => polymorphMonster(state, m, race, ambientPlaceDeps),
|
|
796
999
|
/* PROJ_AWAY_ALL teleports and PROJ_FORCE knockback for monsters. */
|
|
797
|
-
teleport: (m, dist) => teleportMonster(state, m.midx, dist, teleport
|
|
1000
|
+
teleport: (m, dist) => teleportMonster(state, m.midx, dist, teleport),
|
|
1001
|
+
/* update_mon(mon, cave, false) on a monster that SURVIVED the
|
|
1002
|
+
* projection (project-mon.c:1262). Unsupplied, so a monster that was
|
|
1003
|
+
* polymorphed, knocked back, woken or revealed by a spell kept its
|
|
1004
|
+
* pre-projection visibility until something else happened to move it.
|
|
1005
|
+
* updateMon has been ported since the FOV work; this hook was simply
|
|
1006
|
+
* never given a producer. */
|
|
1007
|
+
onUpdate: (mon) => {
|
|
1008
|
+
updateMon(state, mon, false);
|
|
1009
|
+
},
|
|
798
1010
|
/* project-mon.c:183-185 / 208-212 + player thrust landing. */
|
|
799
1011
|
thrustAway: (centre, target, gridsAway) => thrustAway(state, centre, target, gridsAway, {
|
|
800
1012
|
onPlayerPostMove: () => {
|
|
@@ -819,7 +1031,21 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
819
1031
|
projections: reg.projections,
|
|
820
1032
|
expDeps,
|
|
821
1033
|
lifeDrainPercent: reg.constants.lifeDrainPercent,
|
|
822
|
-
|
|
1034
|
+
playerHandlers: projectionHandlers.player.table,
|
|
1035
|
+
/* project_p's OWN messages (project-player.c): "You resist the
|
|
1036
|
+
* effect!", "The intense heat saps you.", "Your eyes fill with
|
|
1037
|
+
* smoke!" - thirty-odd lines across the 21 arms, plus every timed
|
|
1038
|
+
* effect's onMessage, which makePlayerSideEffects gates on this
|
|
1039
|
+
* same optional.
|
|
1040
|
+
*
|
|
1041
|
+
* UNSUPPLIED UNTIL 2026-08-09, so all of them were dropped in the
|
|
1042
|
+
* live game and only the outer "You are hit by fire!" survived.
|
|
1043
|
+
* The seam was optional, every harness that exercised the arms
|
|
1044
|
+
* supplied it, and the one caller that matters did not - found by
|
|
1045
|
+
* a mod handler calling ctx.msg and getting silence
|
|
1046
|
+
* (session/projection-registry-wiring.test.ts). */
|
|
1047
|
+
msg: (text) => state.msg?.(text),
|
|
1048
|
+
teleport,
|
|
823
1049
|
}),
|
|
824
1050
|
/* adjust_dam(actual=true) equip_learn_element (project-player.c
|
|
825
1051
|
* L60-62, audit 01 P5): being hit by an element teaches the resist
|
|
@@ -853,6 +1079,14 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
853
1079
|
* are gated. Absent, every increase was allowed. Same shape as
|
|
854
1080
|
* buildFailRuneEnv / makePlayerSideEffects. */
|
|
855
1081
|
const incQueries = makeIncCheckQueries(state);
|
|
1082
|
+
/* player_inc_check's equip-learn side effects on the INTERPRETER path -
|
|
1083
|
+
* traps, potions, wands, player spells. Only mon-cast.ts supplied incHooks
|
|
1084
|
+
* before, so a trap you were immune to taught nothing, where upstream's
|
|
1085
|
+
* non-lore branch always calls equip_learn_flag / equip_learn_element
|
|
1086
|
+
* (player-timed.c:945, :967, :985). No monster is passed: these sources are
|
|
1087
|
+
* not cave->mon_current, so update_smart_learn and "You resist the effect!"
|
|
1088
|
+
* correctly stay silent. */
|
|
1089
|
+
const incHooks = makeIncCheckHooks(state);
|
|
856
1090
|
const envDeps = {
|
|
857
1091
|
timedTable: players.timed,
|
|
858
1092
|
// Effect status/damage messages ("You feel better", "You feel yourself
|
|
@@ -860,6 +1094,10 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
860
1094
|
// them; absent, they would drop.
|
|
861
1095
|
onMessage: (text, msgt) => state.msg?.(text, msgt),
|
|
862
1096
|
incQueries,
|
|
1097
|
+
incHooks,
|
|
1098
|
+
/* player_set_timed's notify suppression: the obj_k reads that silence a
|
|
1099
|
+
* message duplicating known player state (player-timed.c:828-839). */
|
|
1100
|
+
notifyQueries: makeTimedNotifyQueries(state),
|
|
863
1101
|
/* on_begin_effect / on_end_effect (audit 01 T2): the interpreter timed
|
|
864
1102
|
* path (a SCRAMBLE / SPRINT potion or spell) must run the chain too, not
|
|
865
1103
|
* just the world clock. The thunk reads runTimedTransition (assigned just
|
|
@@ -892,7 +1130,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
892
1130
|
state,
|
|
893
1131
|
cast,
|
|
894
1132
|
takeHitHooks: sharedTakeHitHooks,
|
|
895
|
-
|
|
1133
|
+
teleport,
|
|
896
1134
|
general,
|
|
897
1135
|
item,
|
|
898
1136
|
summon,
|
|
@@ -913,7 +1151,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
913
1151
|
cast,
|
|
914
1152
|
envDeps,
|
|
915
1153
|
inject,
|
|
916
|
-
|
|
1154
|
+
teleport,
|
|
917
1155
|
general,
|
|
918
1156
|
item,
|
|
919
1157
|
summon,
|
|
@@ -927,7 +1165,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
927
1165
|
change: (m) => monsterChangeShape(state, m, {
|
|
928
1166
|
summon,
|
|
929
1167
|
spells: reg.monsters.spells,
|
|
930
|
-
|
|
1168
|
+
teleport,
|
|
931
1169
|
}),
|
|
932
1170
|
revert: (m) => monsterRevertShape(state, m),
|
|
933
1171
|
};
|
|
@@ -943,7 +1181,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
943
1181
|
envDeps,
|
|
944
1182
|
saveSkill: pstate.skills[SKILL.SAVE] ?? 0,
|
|
945
1183
|
inject,
|
|
946
|
-
|
|
1184
|
+
teleport,
|
|
947
1185
|
general,
|
|
948
1186
|
summon,
|
|
949
1187
|
monShape,
|
|
@@ -971,10 +1209,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
971
1209
|
* path - die/pain messages, loot via monster_death, fear rolls. The
|
|
972
1210
|
* scheduler reads these for monster_take_terrain_damage; without them
|
|
973
1211
|
* terrain damage was inert. */
|
|
974
|
-
installNonplayerHitDeps(state,
|
|
975
|
-
...deathDeps,
|
|
976
|
-
message: (text) => state.msg?.(text),
|
|
977
|
-
});
|
|
1212
|
+
installNonplayerHitDeps(state, deathDeps);
|
|
978
1213
|
/* does_resist lore (mon-timed.c L107-110, gap 8.6): when a monster resists a
|
|
979
1214
|
* timed effect via a race flag, learn that flag into visible lore. The
|
|
980
1215
|
* timed layer has no deps param (get_lore is a global upstream), so register
|
|
@@ -985,6 +1220,17 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
985
1220
|
* applies its full elemental / status / stat / theft / terrain
|
|
986
1221
|
* consequences in upstream RNG order. EF_EARTHQUAKE (SHATTER) routes
|
|
987
1222
|
* through the effect interpreter so its internal draws are shared. */
|
|
1223
|
+
/* The blow-effect handler table (combat/mon-melee.ts). Built here, per game,
|
|
1224
|
+
* and seeded with core's 30: a module-level singleton would carry one
|
|
1225
|
+
* character's mod-registered blow into the next character's game. */
|
|
1226
|
+
const blowEffects = new BlowEffectRegistry();
|
|
1227
|
+
registerCoreBlowEffects(blowEffects);
|
|
1228
|
+
state.blowEffects = blowEffects;
|
|
1229
|
+
/* Store behaviour (store/store.ts): what a shop will buy, and how many of a
|
|
1230
|
+
* thing it stocks. Per game for the same reason as the blow table. */
|
|
1231
|
+
const storeBehaviour = new StoreBehaviourRegistry();
|
|
1232
|
+
registerCoreStoreBehaviour(storeBehaviour);
|
|
1233
|
+
state.storeBehaviour = storeBehaviour;
|
|
988
1234
|
state.monBlowEnv = makeMonBlowEnv(state, {
|
|
989
1235
|
timed: players.timed,
|
|
990
1236
|
actor: playerActor,
|
|
@@ -994,7 +1240,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
994
1240
|
adjDexSafe: adj_dex_safe,
|
|
995
1241
|
packSize: reg.constants.packSize,
|
|
996
1242
|
makeDeps,
|
|
997
|
-
|
|
1243
|
+
teleport,
|
|
998
1244
|
earthquake: (mon, radius) => {
|
|
999
1245
|
effects.effectSimple(EF.EARTHQUAKE, buildEffectContext(state, envDeps), {
|
|
1000
1246
|
origin: sourceMonster(mon.midx),
|
|
@@ -1016,7 +1262,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1016
1262
|
* is applied by applyAutoinscription. */
|
|
1017
1263
|
autoNote: (kind, aware) => state.autoinscribe?.get(kind.kidx, aware) ?? null,
|
|
1018
1264
|
inject,
|
|
1019
|
-
|
|
1265
|
+
teleport,
|
|
1020
1266
|
general,
|
|
1021
1267
|
item,
|
|
1022
1268
|
summon,
|
|
@@ -1064,7 +1310,10 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1064
1310
|
radius: 10,
|
|
1065
1311
|
});
|
|
1066
1312
|
},
|
|
1067
|
-
|
|
1313
|
+
/* The ONE bound instance (state.tempBrandSlay), not a private second copy.
|
|
1314
|
+
* This used to build its own, which is why nothing outside the melee path
|
|
1315
|
+
* could ask the question - PORT_TODO 3.20. */
|
|
1316
|
+
temp: state.tempBrandSlay,
|
|
1068
1317
|
});
|
|
1069
1318
|
// Player spellcasting (cast / study) for casting classes.
|
|
1070
1319
|
installSpellCommands(registry, {
|
|
@@ -1073,7 +1322,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1073
1322
|
cast,
|
|
1074
1323
|
envDeps,
|
|
1075
1324
|
inject,
|
|
1076
|
-
|
|
1325
|
+
teleport,
|
|
1077
1326
|
general,
|
|
1078
1327
|
item,
|
|
1079
1328
|
summon,
|
|
@@ -1098,7 +1347,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1098
1347
|
// Player ranged attacks (fire launcher + ammo, throw an object). The hit
|
|
1099
1348
|
// math is combat/ranged.ts; the front-end walks the missile's path and
|
|
1100
1349
|
// routes hit / death messages through state.msg like the other commands.
|
|
1101
|
-
installRangedCommands(registry);
|
|
1350
|
+
installRangedCommands(registry, floorEnv);
|
|
1102
1351
|
// Traps: disarm + the step-onto-trap hook; a trapdoor drops a level.
|
|
1103
1352
|
if (reg.traps) {
|
|
1104
1353
|
trapDeps = {
|
|
@@ -1108,7 +1357,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1108
1357
|
cast,
|
|
1109
1358
|
envDeps,
|
|
1110
1359
|
inject,
|
|
1111
|
-
|
|
1360
|
+
teleport,
|
|
1112
1361
|
general,
|
|
1113
1362
|
item,
|
|
1114
1363
|
summon,
|
|
@@ -1118,6 +1367,15 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1118
1367
|
msg: (text) => state.msg?.(text),
|
|
1119
1368
|
/* player_of_has for trap saves / OF_TRAP_IMMUNE (trap.c:515-539). */
|
|
1120
1369
|
playerHasFlag: (flag) => state.playerState?.flags.has(flag) ?? false,
|
|
1370
|
+
/* is_quest(player->depth) (trap.c:310-311): no trap doors on a quest
|
|
1371
|
+
* level - the guardian's floor must not open under the player. The
|
|
1372
|
+
* generation path already supplied this (gen/util.ts, from dun.quest);
|
|
1373
|
+
* the RUNTIME path did not, so every trap laid after generation - by
|
|
1374
|
+
* EF_TOUCH:MAKE_TRAP, by square_add_trap - drew from a table that
|
|
1375
|
+
* still contained the trapdoor on depths 99 and 100. Dropping a kind
|
|
1376
|
+
* also shifts pick_trap's cumulative total, so the omission moved the
|
|
1377
|
+
* whole draw, not just the trapdoor. */
|
|
1378
|
+
isQuest: (depth) => isQuest(state.actor.player, depth),
|
|
1121
1379
|
changeLevel: (s) => {
|
|
1122
1380
|
/* trap.c:579-582: a TRF_DOWN trapdoor drops you through
|
|
1123
1381
|
* dungeon_get_next_level, not blindly one level. */
|
|
@@ -1144,7 +1402,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1144
1402
|
cast,
|
|
1145
1403
|
envDeps,
|
|
1146
1404
|
inject,
|
|
1147
|
-
|
|
1405
|
+
teleport,
|
|
1148
1406
|
general,
|
|
1149
1407
|
item,
|
|
1150
1408
|
summon,
|
|
@@ -1164,7 +1422,7 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1164
1422
|
cast,
|
|
1165
1423
|
envDeps,
|
|
1166
1424
|
inject,
|
|
1167
|
-
|
|
1425
|
+
teleport,
|
|
1168
1426
|
general,
|
|
1169
1427
|
item,
|
|
1170
1428
|
summon,
|
|
@@ -1280,6 +1538,10 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1280
1538
|
if (canDisturb)
|
|
1281
1539
|
disturb(state);
|
|
1282
1540
|
},
|
|
1541
|
+
/* player_set_timed's notify suppression on the WORLD CLOCK path too -
|
|
1542
|
+
* this is where a timed resist most often ticks down (player-timed.c:
|
|
1543
|
+
* 828-839). */
|
|
1544
|
+
notifyQueries: makeTimedNotifyQueries(state),
|
|
1283
1545
|
incCheck: (idx) => {
|
|
1284
1546
|
const eff = players.timed[idx];
|
|
1285
1547
|
return eff ? playerIncCheck(eff, worldIncQueries) : true;
|
|
@@ -1294,8 +1556,13 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1294
1556
|
* the {name}/{kind}/{s}/{is} tags in weapon-related timed messages (the
|
|
1295
1557
|
* temporary-brand on-begin/on-end lines) resolve against the CURRENTLY
|
|
1296
1558
|
* wielded weapon, so a getter keeps it live across wield/takeoff. name /
|
|
1297
|
-
*
|
|
1298
|
-
*
|
|
1559
|
+
* PORT_TODO 3.23: {name} and {kind} are DIFFERENT upstream functions, and
|
|
1560
|
+
* neither is the raw kind name this used to pass. {name} is
|
|
1561
|
+
* object_desc(ODESC_PREFIX | ODESC_BASE) - so it carries the article - and
|
|
1562
|
+
* {kind} is object_kind_name(kind, easy_know=true), which with easy_know
|
|
1563
|
+
* set is exactly obj_desc_name_format(kind->name, NULL, false). Passing
|
|
1564
|
+
* `w.kind.name` printed the raw `&` and `~` markers to the player.
|
|
1565
|
+
* No weapon => the obj == NULL tag forms. */
|
|
1299
1566
|
get weapon() {
|
|
1300
1567
|
const w = state.actor.weapon;
|
|
1301
1568
|
/* No weapon => the obj == NULL tag forms. A sentinel with name/kind
|
|
@@ -1305,7 +1572,11 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1305
1572
|
* that returns undefined. */
|
|
1306
1573
|
if (!w)
|
|
1307
1574
|
return { name: "hands", kind: "hands", number: 2 };
|
|
1308
|
-
return {
|
|
1575
|
+
return {
|
|
1576
|
+
name: describeObject(state, w, ODESC.PREFIX | ODESC.BASE),
|
|
1577
|
+
kind: objDescNameFormat(w.kind.name, null, false),
|
|
1578
|
+
number: w.number,
|
|
1579
|
+
};
|
|
1309
1580
|
},
|
|
1310
1581
|
},
|
|
1311
1582
|
/* The same shared consequences drive the world clock's DoT ticks, terrain
|
|
@@ -1333,6 +1604,15 @@ function wireGame(state, reg, players, pstate, seedFlavor, pack) {
|
|
|
1333
1604
|
...(wizardEffect ? { effect: wizardEffect } : {}),
|
|
1334
1605
|
...(trapDeps ? { trapDeps } : {}),
|
|
1335
1606
|
};
|
|
1607
|
+
/* Seed p->known_state now that runeEnv and the flavour store are live. */
|
|
1608
|
+
refreshKnownCombat(state.actor.player, {
|
|
1609
|
+
equipment: state.actor.player.equipment.map((h) => h ? gearGet(state.gear, h) : null),
|
|
1610
|
+
timedEffects: players.timed,
|
|
1611
|
+
curses: reg.objects.curses,
|
|
1612
|
+
update: true,
|
|
1613
|
+
depth: state.chunk.depth,
|
|
1614
|
+
isDaytime: isDaytime(state.turn, state.z.dayLength),
|
|
1615
|
+
});
|
|
1336
1616
|
return { registry, trapDeps, flavor, everseen, effects: effectRegistry, wizardBundles };
|
|
1337
1617
|
}
|
|
1338
1618
|
/**
|
|
@@ -1345,9 +1625,14 @@ function populateFromLevel(state, level, trapDeps) {
|
|
|
1345
1625
|
const spot = level.playerSpot ?? loc(1, 1);
|
|
1346
1626
|
state.actor.grid = spot;
|
|
1347
1627
|
placePlayer(state, spot);
|
|
1348
|
-
/* Track the deepest level reached (
|
|
1628
|
+
/* Track the deepest level reached: on_new_level (game-world.c:1023-1024)
|
|
1629
|
+
* sets `max_depth = recall_depth = depth`, BOTH of them. recall_depth is the
|
|
1630
|
+
* anchor Word of Recall drops you back to, and this assignment is its only
|
|
1631
|
+
* producer on the ordinary walk down - EF_RECALL re-anchors it only when the
|
|
1632
|
+
* scroll is read in the dungeon. Setting max_depth alone left recall_depth at
|
|
1633
|
+
* 0 forever for a character who never read one below the town. */
|
|
1349
1634
|
if (level.depth > state.actor.player.maxDepth) {
|
|
1350
|
-
state.actor.player.maxDepth = level.depth;
|
|
1635
|
+
state.actor.player.maxDepth = state.actor.player.recallDepth = level.depth;
|
|
1351
1636
|
}
|
|
1352
1637
|
/* A new level clears the decoy (glyph traps do not persist the swap). */
|
|
1353
1638
|
state.decoy = null;
|
|
@@ -1487,10 +1772,16 @@ function sanitizePlayerLoc(state) {
|
|
|
1487
1772
|
* object, whose chunk and entity stores are replaced).
|
|
1488
1773
|
*/
|
|
1489
1774
|
function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
1490
|
-
/* The level stashed when entering an arena
|
|
1491
|
-
*
|
|
1492
|
-
*
|
|
1493
|
-
|
|
1775
|
+
/* The level stashed when entering an arena lives on GameState
|
|
1776
|
+
* (state.arenaStash), not in this closure: leaving a level FOR an arena
|
|
1777
|
+
* persists it even without birth_levels_persist (generate.c L1349), and
|
|
1778
|
+
* upstream keeps that copy in the chunk_list, which the savefile carries. A
|
|
1779
|
+
* save taken mid-fight used to lose the level behind it and exit onto a
|
|
1780
|
+
* fresh one; now it exits where it went in.
|
|
1781
|
+
*
|
|
1782
|
+
* `inArena` stays a separate flag rather than "the stash exists", because a
|
|
1783
|
+
* save written before the stash was persisted restores with arena_level set
|
|
1784
|
+
* and no stash, and still has to be let out of the arena. */
|
|
1494
1785
|
let inArena = opts.inArena ?? false;
|
|
1495
1786
|
return (depth) => {
|
|
1496
1787
|
/* Consume the pending arrival-stair request (create_up_stair /
|
|
@@ -1504,7 +1795,7 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1504
1795
|
if (state.arenaLevel && !inArena) {
|
|
1505
1796
|
const mon = state.healthWho;
|
|
1506
1797
|
if (mon) {
|
|
1507
|
-
arenaStash = {
|
|
1798
|
+
state.arenaStash = {
|
|
1508
1799
|
chunk: state.chunk,
|
|
1509
1800
|
monsters: state.monsters,
|
|
1510
1801
|
groups: state.groups,
|
|
@@ -1513,6 +1804,11 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1513
1804
|
known: state.known,
|
|
1514
1805
|
decoy: state.decoy ?? null,
|
|
1515
1806
|
monMidx: mon.midx,
|
|
1807
|
+
/* StoredLevel's other two fields. The freeze turn is stamped as
|
|
1808
|
+
* cave_store does; `join` is empty because an arena exit restores
|
|
1809
|
+
* the level wholesale and never re-aligns stairs against it. */
|
|
1810
|
+
turn: state.turn,
|
|
1811
|
+
join: [],
|
|
1516
1812
|
};
|
|
1517
1813
|
/* arena_gen (gen-cave.c L3984): 6x6 floor bounded by perm rock,
|
|
1518
1814
|
* the player in one corner and the opponent in the other. */
|
|
@@ -1559,6 +1855,17 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1559
1855
|
placePlayer(state, loc(1, 4));
|
|
1560
1856
|
inArena = true;
|
|
1561
1857
|
delete state.targetDepth;
|
|
1858
|
+
/* on_new_level (game-world.c:1034-1035): PN_COMBINE then notice_stuff,
|
|
1859
|
+
* one line BEFORE update_stuff, so the combine lands first. */
|
|
1860
|
+
noticeNewLevel(state);
|
|
1861
|
+
/* cmd_disable_repeat_floor_item (game-world.c:1068). Upstream's call is
|
|
1862
|
+
* in on_leave_level, which this port has no single equivalent of -
|
|
1863
|
+
* `generateLevel = true` is set at fourteen sites. It rides the ENTRY
|
|
1864
|
+
* path instead, which is observationally identical: the change is
|
|
1865
|
+
* synchronous, so the repeat key cannot be pressed between leaving and
|
|
1866
|
+
* arriving. The old level's pile is gone either way, so a remembered
|
|
1867
|
+
* args.floor index must not be re-dispatched. */
|
|
1868
|
+
cmdDisableRepeatFloorItem(state.actor.player);
|
|
1562
1869
|
state.updateBonuses?.(); /* on_new_level PU_BONUS -> calc_light */
|
|
1563
1870
|
state.updateFov?.(state);
|
|
1564
1871
|
return;
|
|
@@ -1570,8 +1877,8 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1570
1877
|
if (inArena) {
|
|
1571
1878
|
inArena = false;
|
|
1572
1879
|
state.arenaLevel = false;
|
|
1573
|
-
const stash = arenaStash;
|
|
1574
|
-
arenaStash
|
|
1880
|
+
const stash = state.arenaStash;
|
|
1881
|
+
delete state.arenaStash;
|
|
1575
1882
|
if (stash) {
|
|
1576
1883
|
/* Restore the level left behind (the player marker stayed). */
|
|
1577
1884
|
state.chunk = stash.chunk;
|
|
@@ -1598,6 +1905,17 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1598
1905
|
state.healthWho = null;
|
|
1599
1906
|
targetSetMonster(state, null);
|
|
1600
1907
|
delete state.targetDepth;
|
|
1908
|
+
/* on_new_level (game-world.c:1034-1035): PN_COMBINE then notice_stuff,
|
|
1909
|
+
* one line BEFORE update_stuff, so the combine lands first. */
|
|
1910
|
+
noticeNewLevel(state);
|
|
1911
|
+
/* cmd_disable_repeat_floor_item (game-world.c:1068). Upstream's call is
|
|
1912
|
+
* in on_leave_level, which this port has no single equivalent of -
|
|
1913
|
+
* `generateLevel = true` is set at fourteen sites. It rides the ENTRY
|
|
1914
|
+
* path instead, which is observationally identical: the change is
|
|
1915
|
+
* synchronous, so the repeat key cannot be pressed between leaving and
|
|
1916
|
+
* arriving. The old level's pile is gone either way, so a remembered
|
|
1917
|
+
* args.floor index must not be re-dispatched. */
|
|
1918
|
+
cmdDisableRepeatFloorItem(state.actor.player);
|
|
1601
1919
|
state.updateBonuses?.(); /* on_new_level PU_BONUS -> calc_light */
|
|
1602
1920
|
state.updateFov?.(state);
|
|
1603
1921
|
return;
|
|
@@ -1606,9 +1924,12 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1606
1924
|
* fresh level of the same depth (ledgered). */
|
|
1607
1925
|
delete state.oldGrid;
|
|
1608
1926
|
}
|
|
1609
|
-
/* dungeon_change_level: track the deepest level reached.
|
|
1927
|
+
/* dungeon_change_level: track the deepest level reached. The same
|
|
1928
|
+
* `max_depth = recall_depth = depth` pair as populateFromLevel, because the
|
|
1929
|
+
* port checks on both the request and the arrival where upstream checks
|
|
1930
|
+
* once in on_new_level - whichever fires first, the other is a no-op. */
|
|
1610
1931
|
if (depth > state.actor.player.maxDepth) {
|
|
1611
|
-
state.actor.player.maxDepth = depth;
|
|
1932
|
+
state.actor.player.maxDepth = state.actor.player.recallDepth = depth;
|
|
1612
1933
|
}
|
|
1613
1934
|
/* birth_levels_persist (#30, off by default): when on, the level being
|
|
1614
1935
|
* left is frozen into a depth-keyed cache and a previously-frozen target
|
|
@@ -1703,10 +2024,25 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1703
2024
|
installChunkFeatHook(state);
|
|
1704
2025
|
refreshTownStores(state, reg);
|
|
1705
2026
|
delete state.targetDepth;
|
|
2027
|
+
/* on_new_level (game-world.c:1034-1035): PN_COMBINE then notice_stuff,
|
|
2028
|
+
* one line BEFORE update_stuff, so the combine lands first. */
|
|
2029
|
+
noticeNewLevel(state);
|
|
2030
|
+
/* cmd_disable_repeat_floor_item (game-world.c:1068). Upstream's call is
|
|
2031
|
+
* in on_leave_level, which this port has no single equivalent of -
|
|
2032
|
+
* `generateLevel = true` is set at fourteen sites. It rides the ENTRY
|
|
2033
|
+
* path instead, which is observationally identical: the change is
|
|
2034
|
+
* synchronous, so the repeat key cannot be pressed between leaving and
|
|
2035
|
+
* arriving. The old level's pile is gone either way, so a remembered
|
|
2036
|
+
* args.floor index must not be re-dispatched. */
|
|
2037
|
+
cmdDisableRepeatFloorItem(state.actor.player);
|
|
1706
2038
|
state.updateBonuses?.(); /* on_new_level PU_BONUS -> calc_light */
|
|
1707
2039
|
/* only_partial during level-entry FOV (ui-display.c:2522 / cave-view.c:851). */
|
|
1708
2040
|
state.chunk.onlyPartial = true;
|
|
1709
2041
|
state.updateFov?.(state);
|
|
2042
|
+
/* on_new_level's own disturb (game-world.c:1016-1017), immediately before
|
|
2043
|
+
* the feeling and the search: arriving on a level cancels whatever was
|
|
2044
|
+
* still queued from the level you left. */
|
|
2045
|
+
disturb(state);
|
|
1710
2046
|
announceFeeling(state, reg);
|
|
1711
2047
|
search(state); /* on_new_level (game-world.c:1052). */
|
|
1712
2048
|
state.chunk.onlyPartial = false;
|
|
@@ -1727,6 +2063,7 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1727
2063
|
* and generateLevel builds exactly as before. */
|
|
1728
2064
|
const persistCache = state.levelCache;
|
|
1729
2065
|
let joinInfo;
|
|
2066
|
+
let minSize;
|
|
1730
2067
|
if (persist && persistCache) {
|
|
1731
2068
|
const above = persistCache.get(depth - 1)?.join;
|
|
1732
2069
|
const twoAbove = persistCache.get(depth - 2)?.join;
|
|
@@ -1738,13 +2075,27 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1738
2075
|
...(below ? { below } : {}),
|
|
1739
2076
|
...(twoBelow ? { twoBelow } : {}),
|
|
1740
2077
|
});
|
|
2078
|
+
/* get_min_level_size (prepare_next_level L1531-1546): the new level must
|
|
2079
|
+
* be big enough to hold the stairs its frozen neighbours already expect,
|
|
2080
|
+
* or build_staircase_rooms has nowhere to put them and quits. Only the
|
|
2081
|
+
* IMMEDIATE neighbours are measured - a one-off connector two levels away
|
|
2082
|
+
* seeds dun.one_off_* (an avoid list), never a staircase room, so it
|
|
2083
|
+
* imposes no minimum. Starts at 0/0 exactly as the C's locals do. */
|
|
2084
|
+
minSize = getMinLevelSize(below ?? [], false, getMinLevelSize(above ?? [], true));
|
|
1741
2085
|
}
|
|
1742
2086
|
/* choose_profile's NOSCORE_JUMPING request (generate.c L824-836): consumed
|
|
1743
2087
|
* once, cleared as it is passed on, exactly as the C clears the bit. */
|
|
1744
2088
|
const jumpProfileName = state.jumpProfileName;
|
|
1745
2089
|
state.jumpProfileName = undefined;
|
|
1746
2090
|
const g = generateLevel(state.rng, depth, {
|
|
1747
|
-
...genDeps(reg, true,
|
|
2091
|
+
...genDeps(reg, true,
|
|
2092
|
+
/* The player-dependent make_object / make_gold foils. These were
|
|
2093
|
+
* supplied to both STORE paths and to nothing else, so during level
|
|
2094
|
+
* generation - the path they exist for - every book was browsable, no
|
|
2095
|
+
* curse was ever foiled, and generated gold skipped the no-selling
|
|
2096
|
+
* inflation. Two of the three are RNG draws, so the generation stream
|
|
2097
|
+
* itself was off upstream's. */
|
|
2098
|
+
genFoilFields(state), state.artifacts, state.options?.get("birth_no_artifacts") ?? false,
|
|
1748
2099
|
/* mon_create_drop's unique theft reduction reads the live lore store. */
|
|
1749
2100
|
state.lore),
|
|
1750
2101
|
/* The mod behaviour seam, read at build time (this call is synchronous,
|
|
@@ -1774,6 +2125,10 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1774
2125
|
* unconditionally; only read under persist. */
|
|
1775
2126
|
hasAdjacentAbove: persistCache?.has(depth - 1) ?? false,
|
|
1776
2127
|
hasAdjacentBelow: persistCache?.has(depth + 1) ?? false,
|
|
2128
|
+
/* get_min_level_size's answer (prepare_next_level L1531-1546), the
|
|
2129
|
+
* only producer these two builder inputs have. Omitted entirely when
|
|
2130
|
+
* not persisting, so generateLevel keeps its own defaults. */
|
|
2131
|
+
...(minSize ? { minHeight: minSize.height, minWidth: minSize.width } : {}),
|
|
1777
2132
|
/* birth_connect_stairs (gen-util.c:427-433): lay the arrival stair the
|
|
1778
2133
|
* stair command requested ("up" after a descent, "down" after an
|
|
1779
2134
|
* ascent), unless the option is off. Recall/first-spawn leave
|
|
@@ -1846,6 +2201,12 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1846
2201
|
g.lightLevel = false;
|
|
1847
2202
|
}
|
|
1848
2203
|
delete state.targetDepth;
|
|
2204
|
+
/* on_new_level (game-world.c:1034-1035): PN_COMBINE then notice_stuff, one
|
|
2205
|
+
* line BEFORE update_stuff, so the combine lands first. */
|
|
2206
|
+
noticeNewLevel(state);
|
|
2207
|
+
/* cmd_disable_repeat_floor_item (game-world.c:1068); see the note at the
|
|
2208
|
+
* other level-entry sites for why it rides entry rather than leave. */
|
|
2209
|
+
cmdDisableRepeatFloorItem(state.actor.player);
|
|
1849
2210
|
/* on_new_level (game-world.c:1034-1037): PU_BONUS -> update_bonuses ->
|
|
1850
2211
|
* calc_light recomputes cur_light for the NEW depth, then the view is
|
|
1851
2212
|
* flooded. Without this the daytime-town cur_light (0) leaks into the
|
|
@@ -1855,6 +2216,10 @@ function makeChangeLevel(state, reg, trapDeps, opts = {}) {
|
|
|
1855
2216
|
/* only_partial during level-entry FOV (ui-display.c:2522 / cave-view.c:851). */
|
|
1856
2217
|
state.chunk.onlyPartial = true;
|
|
1857
2218
|
state.updateFov?.(state);
|
|
2219
|
+
/* on_new_level's own disturb (game-world.c:1016-1017), immediately before
|
|
2220
|
+
* the feeling and the search: arriving on a level cancels whatever was
|
|
2221
|
+
* still queued from the level you left. */
|
|
2222
|
+
disturb(state);
|
|
1858
2223
|
announceFeeling(state, reg);
|
|
1859
2224
|
search(state); /* on_new_level (game-world.c:1052). */
|
|
1860
2225
|
state.chunk.onlyPartial = false;
|
|
@@ -1959,6 +2324,11 @@ function refreshTownStores(state, reg) {
|
|
|
1959
2324
|
deps: storeDeps,
|
|
1960
2325
|
maxDepth: state.actor.player.maxDepth,
|
|
1961
2326
|
stores: state.stores,
|
|
2327
|
+
/* history_lose_artifact (store.c:1091 / :1307): an artifact the player
|
|
2328
|
+
* sold into stock and the store then turned over or purged is gone. */
|
|
2329
|
+
onArtifactLost: (art) => state.onArtifactLost?.(art),
|
|
2330
|
+
/* Store behaviour a mod may have added to (StoreBehaviourRegistry). */
|
|
2331
|
+
...(state.storeBehaviour ? { behaviour: state.storeBehaviour } : {}),
|
|
1962
2332
|
/* OPT(cheat_xtra) (store.c:1424, :1444). */
|
|
1963
2333
|
...(state.options?.get("cheat_xtra")
|
|
1964
2334
|
? { cheatMsg: (text) => state.msg?.(text) }
|
|
@@ -2006,17 +2376,24 @@ export function startGame(pack, opts = {}) {
|
|
|
2006
2376
|
const reg = bindCore(pack);
|
|
2007
2377
|
const players = bindPlayer(pack.player);
|
|
2008
2378
|
registerBookKinds(reg.objects, players.classes);
|
|
2009
|
-
// The player option store (option.c
|
|
2010
|
-
//
|
|
2011
|
-
//
|
|
2012
|
-
//
|
|
2013
|
-
//
|
|
2014
|
-
//
|
|
2015
|
-
//
|
|
2016
|
-
//
|
|
2379
|
+
// The player option store, options_init_defaults whole (option.c L186-205,
|
|
2380
|
+
// called from player_init at player.c:491). In upstream's order:
|
|
2381
|
+
//
|
|
2382
|
+
// 1. every option from its table `normal` (OPTION_ENTRIES),
|
|
2383
|
+
// 2. the player's customised BIRTH defaults from ANGBAND_DIR_USER,
|
|
2384
|
+
// 3. their customised INTERFACE defaults,
|
|
2385
|
+
// 4. delay_factor = 40 and hitpoint_warn = 3,
|
|
2386
|
+
//
|
|
2387
|
+
// and only then this call's explicit birth/interface CHOICES on top. Steps 2
|
|
2388
|
+
// and 3 read customized_<page>_options.txt through the installed host; with
|
|
2389
|
+
// no host, or no such file, they are exactly the table defaults, which is why
|
|
2390
|
+
// a test or an MCP session sees no change. Built before level generation so
|
|
2391
|
+
// birth_randarts can swap the artifact set first.
|
|
2392
|
+
const initial = optionsInitDefaults(host());
|
|
2017
2393
|
const options = new OptionState({
|
|
2018
|
-
|
|
2019
|
-
|
|
2394
|
+
overrides: { ...initial.opts, ...(opts.optionOverrides ?? {}) },
|
|
2395
|
+
hitpointWarn: opts.hitpointWarn ?? initial.hitpointWarn,
|
|
2396
|
+
delayFactor: initial.delayFactor,
|
|
2020
2397
|
});
|
|
2021
2398
|
// options_init_cheat (player-birth.c:1234, gap 1.12): at character accept,
|
|
2022
2399
|
// clear every cheat option and its score twin, THEN re-apply the port-only
|
|
@@ -2160,6 +2537,10 @@ export function startGame(pack, opts = {}) {
|
|
|
2160
2537
|
speed: pstate.speed,
|
|
2161
2538
|
totalEnergy: 0,
|
|
2162
2539
|
combat,
|
|
2540
|
+
/* p->known_state, seeded with the real state and replaced with the true
|
|
2541
|
+
* known derive at the end of wireGame - the flavour store and the rune env
|
|
2542
|
+
* it needs do not exist yet at this line. */
|
|
2543
|
+
knownCombat: combat,
|
|
2163
2544
|
defense: toDefenderState(pstate),
|
|
2164
2545
|
weapon,
|
|
2165
2546
|
stealth: combat.skills[SKILL.STEALTH] ?? 0,
|
|
@@ -2194,6 +2575,12 @@ export function startGame(pack, opts = {}) {
|
|
|
2194
2575
|
/* birth_levels_persist (#30) frozen-level cache; empty until a level is
|
|
2195
2576
|
* left with the option on (the whole persist path is option-gated). */
|
|
2196
2577
|
levelCache: new Map(),
|
|
2578
|
+
/* The STARTING level's stair connectors, on the same option gate
|
|
2579
|
+
* changeLevel uses. Without this the first level a character ever stands on
|
|
2580
|
+
* freezes with an empty join list and its neighbour cannot align to it. */
|
|
2581
|
+
...((options.get("birth_levels_persist") ?? false)
|
|
2582
|
+
? { currentJoins: [...booted.joins] }
|
|
2583
|
+
: {}),
|
|
2197
2584
|
turn: 0,
|
|
2198
2585
|
z: {
|
|
2199
2586
|
...DEFAULT_GAME_CONSTANTS,
|
|
@@ -2211,6 +2598,17 @@ export function startGame(pack, opts = {}) {
|
|
|
2211
2598
|
},
|
|
2212
2599
|
brands: reg.objects.brands,
|
|
2213
2600
|
slays: reg.objects.slays,
|
|
2601
|
+
curses: reg.objects.curses,
|
|
2602
|
+
/* player_has_temporary_brand / _slay (player-util.c), bound ONCE here from the
|
|
2603
|
+
* pack's timed records. The melee hooks used to build a private copy and
|
|
2604
|
+
* nothing else could reach one, so obj-info's brand/slay gathering carried a
|
|
2605
|
+
* "DEFERRED" note beside a predicate that already existed - PORT_TODO 3.20. */
|
|
2606
|
+
tempBrandSlay: buildTempBrandSlay(birth.player,
|
|
2607
|
+
/* The RAW pack records, not players.timed - bindPlayer's TimedEffect has no
|
|
2608
|
+
* brand/slay code arrays, so passing the bound table silently mapped every
|
|
2609
|
+
* index to -1 and hasBrand answered false for everything. Measured: the
|
|
2610
|
+
* first draft of this did exactly that and the test caught it. */
|
|
2611
|
+
pack.player.timed, reg.objects.brands, reg.objects.slays),
|
|
2214
2612
|
/* Placeholder; wireGame installs the full registry-backed env. */
|
|
2215
2613
|
runeEnv: makeRuneEnv(() => null, () => false),
|
|
2216
2614
|
playing: true,
|
|
@@ -2223,7 +2621,7 @@ export function startGame(pack, opts = {}) {
|
|
|
2223
2621
|
// seed_flavor already drawn above; flavor_init runs inside wireGame.
|
|
2224
2622
|
if (opts.updateFov)
|
|
2225
2623
|
state.updateFov = opts.updateFov;
|
|
2226
|
-
const wired = wireGame(state, reg, players, pstate, seedFlavor
|
|
2624
|
+
const wired = wireGame(state, reg, players, pstate, seedFlavor);
|
|
2227
2625
|
/* PU_INVEN from the starting kit's inven_carry (player-birth.c). */
|
|
2228
2626
|
buildGearViews(state, reg, pstate.ammoTval);
|
|
2229
2627
|
// kind->everseen = true for each bought start item (player-birth.c L658). At
|
|
@@ -2240,6 +2638,13 @@ export function startGame(pack, opts = {}) {
|
|
|
2240
2638
|
for (const kind of startKinds) {
|
|
2241
2639
|
wired.flavor.objectFlavorAware(kind, NOOP_FLAVOR_AWARE_DEPS);
|
|
2242
2640
|
}
|
|
2641
|
+
// obj->known->effect = obj->effect per start item (player-birth.c:650). The
|
|
2642
|
+
// objectFlavorAware pass above already covers every kind the outfit can
|
|
2643
|
+
// contain, so this is the C's line rather than a behaviour change - but it is
|
|
2644
|
+
// the line, and the field now exists to hold it.
|
|
2645
|
+
for (const obj of state.gear.store.values()) {
|
|
2646
|
+
obj.knownEffect = obj.effect;
|
|
2647
|
+
}
|
|
2243
2648
|
// birth_know_runes (player-birth.c L1261-1262): a birth_know_runes character
|
|
2244
2649
|
// knows every rune for ID-on-walkover (gap 1.5). No RNG. Before
|
|
2245
2650
|
// player_learn_innate, matching the C acceptance order.
|
|
@@ -2301,6 +2706,10 @@ export function startGame(pack, opts = {}) {
|
|
|
2301
2706
|
state.chunk.onlyPartial = true;
|
|
2302
2707
|
if (state.updateFov) {
|
|
2303
2708
|
state.updateFov(state);
|
|
2709
|
+
/* on_new_level's own disturb (game-world.c:1016-1017), immediately before
|
|
2710
|
+
* the feeling and the search: arriving on a level cancels whatever was
|
|
2711
|
+
* still queued from the level you left. */
|
|
2712
|
+
disturb(state);
|
|
2304
2713
|
announceFeeling(state, reg);
|
|
2305
2714
|
search(state); /* on_new_level (game-world.c:1052). */
|
|
2306
2715
|
state.chunk.onlyPartial = false;
|
|
@@ -2348,6 +2757,10 @@ function makeStoreApi(state, reg, flavor, options) {
|
|
|
2348
2757
|
},
|
|
2349
2758
|
maxDepth: state.actor.player.maxDepth,
|
|
2350
2759
|
stores: state.stores ?? [],
|
|
2760
|
+
/* The sell path decides through storeWillBuy too, so it reads the same
|
|
2761
|
+
* registry the maintenance path does - a seam supplied to every path but
|
|
2762
|
+
* one is the shape that lets a mod work in town and not in the shop. */
|
|
2763
|
+
...(state.storeBehaviour ? { behaviour: state.storeBehaviour } : {}),
|
|
2351
2764
|
});
|
|
2352
2765
|
const noSelling = () => options.get("birth_no_selling") ?? false;
|
|
2353
2766
|
/* update_stuff's PU_INVEN after a gear change (obj-gear.c: inven_carry /
|
|
@@ -2369,11 +2782,25 @@ function makeStoreApi(state, reg, flavor, options) {
|
|
|
2369
2782
|
msg: (text) => state.msg?.(text),
|
|
2370
2783
|
});
|
|
2371
2784
|
};
|
|
2785
|
+
/**
|
|
2786
|
+
* object_flag_is_known(player, obj, flag) bound to one object, for
|
|
2787
|
+
* store_will_buy's buy-list branch (store.c:551). PORT_TODO 2.10 / 5.8.
|
|
2788
|
+
*
|
|
2789
|
+
* The shadow is synthesised ONCE per object rather than per flag: a buy list
|
|
2790
|
+
* can name several flags for one tval, and objectKnownShadow walks the whole
|
|
2791
|
+
* rune set each time it is called.
|
|
2792
|
+
*/
|
|
2793
|
+
const flagKnownFor = (obj) => {
|
|
2794
|
+
const p = state.actor.player;
|
|
2795
|
+
const shadow = objectKnownShadow(obj, p, state.runeEnv, knownDescOf(state));
|
|
2796
|
+
return (flag) => objectFlagIsKnown(obj, shadow, p, state.runeEnv, flag);
|
|
2797
|
+
};
|
|
2372
2798
|
const txnKnow = (obj) => ({
|
|
2373
2799
|
flavor,
|
|
2374
2800
|
flavorDeps: flavorAwareDeps(state),
|
|
2375
2801
|
aware: flavor.isAware(obj.kind),
|
|
2376
2802
|
noSelling: noSelling(),
|
|
2803
|
+
flagKnown: flagKnownFor(obj),
|
|
2377
2804
|
/* do_cmd_sell L1946-1951: selling teaches the runes as well as the flavour.
|
|
2378
2805
|
* buildRuneList is rebuilt per call for the same reason effect-item.ts does
|
|
2379
2806
|
* it (L930): a mod can add runes mid-session, so a cached list would go
|
|
@@ -2385,7 +2812,7 @@ function makeStoreApi(state, reg, flavor, options) {
|
|
|
2385
2812
|
/* do_cmd_retrieve (store.c:1783): Home Take is free - no price, no
|
|
2386
2813
|
* ORIGIN_STORE, no shuffle/maint RNG. Reuse the existing homeRetrieve. */
|
|
2387
2814
|
if (store.feat === FEAT.HOME) {
|
|
2388
|
-
const r = homeRetrieve(store, obj, amt, state.gear, reg.constants);
|
|
2815
|
+
const r = homeRetrieve(store, obj, amt, state.actor.player, state.gear, reg.constants);
|
|
2389
2816
|
if (!r.ok) {
|
|
2390
2817
|
return {
|
|
2391
2818
|
ok: false,
|
|
@@ -2425,7 +2852,15 @@ function makeStoreApi(state, reg, flavor, options) {
|
|
|
2425
2852
|
const obj = state.gear.store.get(handle);
|
|
2426
2853
|
const know = obj
|
|
2427
2854
|
? txnKnow(obj)
|
|
2428
|
-
: {
|
|
2855
|
+
: {
|
|
2856
|
+
flavor,
|
|
2857
|
+
flavorDeps: flavorAwareDeps(state),
|
|
2858
|
+
aware: false,
|
|
2859
|
+
noSelling: noSelling(),
|
|
2860
|
+
/* No object behind the handle, so the sale is refused before the
|
|
2861
|
+
* buy list is consulted; nothing can be known about a flag on it. */
|
|
2862
|
+
flagKnown: () => false,
|
|
2863
|
+
};
|
|
2429
2864
|
const result = storeSell(storeCtx(), store, handle, amt, state.actor.player, state.gear, know);
|
|
2430
2865
|
/* do_cmd_sell: selling an artifact reveals it (history_find_artifact,
|
|
2431
2866
|
* store.c L1928); if the store then discards it, it is lost (L1992). */
|
|
@@ -2481,7 +2916,7 @@ function makeStoreApi(state, reg, flavor, options) {
|
|
|
2481
2916
|
price: (store, obj, storeBuying, qty) => priceItem(reg.objects, store, store.owner, obj, storeBuying, qty, flavor.isAware(obj.kind), noSelling()),
|
|
2482
2917
|
/* runesKnown matches storeSell's know (txnKnow never sets it, so the
|
|
2483
2918
|
* transaction treats it as false); keep the filter aligned with the sale. */
|
|
2484
|
-
willBuy: (store, obj) => storeWillBuy(reg.objects, store, obj, flavor.isAware(obj.kind), noSelling(), false),
|
|
2919
|
+
willBuy: (store, obj) => storeWillBuy(reg.objects, store, obj, flavor.isAware(obj.kind), noSelling(), false, flagKnownFor(obj), state.storeBehaviour),
|
|
2485
2920
|
};
|
|
2486
2921
|
}
|
|
2487
2922
|
/**
|
|
@@ -2533,7 +2968,7 @@ function swapRandartSet(reg, seed, timedFoil, activationSummarize) {
|
|
|
2533
2968
|
* (gap 3.8, effect_summarize_properties) is threaded via activationSummarize
|
|
2534
2969
|
* so remove_contradictory_activation can drop a redundant activation
|
|
2535
2970
|
* (obj-randart.c L2420); absent, it stays a conservative no-op. */
|
|
2536
|
-
const randarts = doRandart(reg.objects, seed, reg.nameSections.get(RANDNAME_TOLKIEN), timedFoil || activationSummarize
|
|
2971
|
+
const randarts = doRandart(reg.objects, reg.constants, seed, true, reg.nameSections.get(RANDNAME_TOLKIEN), timedFoil || activationSummarize
|
|
2537
2972
|
? { timedFoil, activationSummarize }
|
|
2538
2973
|
: undefined);
|
|
2539
2974
|
reg.objects.artifacts.length = 0;
|
|
@@ -2635,8 +3070,16 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2635
3070
|
if (!save.chunk && save.dungeonDepth !== undefined) {
|
|
2636
3071
|
chunk.depth = save.dungeonDepth;
|
|
2637
3072
|
}
|
|
2638
|
-
const player = deserializePlayer(save.player, players, reg.objects, ids);
|
|
3073
|
+
const player = deserializePlayer(save.player, players, reg.objects, ids, reg.quests);
|
|
2639
3074
|
const gear = deserializeGear(save.gear, reg.objects, ids);
|
|
3075
|
+
/* rd_gear (load.c L1179-1185): the carried-weight total is RE-SUMMED from the
|
|
3076
|
+
* restored gear, not trusted from the file. Upstream does this because its
|
|
3077
|
+
* gear list and the total are written separately; the port needs it for a
|
|
3078
|
+
* second reason - a character saved before this accounting existed carries a
|
|
3079
|
+
* stored total of 0, and reading that back would leave them weightless for
|
|
3080
|
+
* the rest of the game. It has to run before calcBonuses below, which reads
|
|
3081
|
+
* the total for the carrying-capacity speed penalty. */
|
|
3082
|
+
player.upkeep.totalWeight = gearTotalWeight(gear);
|
|
2640
3083
|
const equipment = player.equipment.map((h) => (h ? gearGet(gear, h) : null));
|
|
2641
3084
|
const weaponSlot = player.body.slots.findIndex((s) => s.type === "WEAPON");
|
|
2642
3085
|
const weapon = weaponSlot >= 0 ? (equipment[weaponSlot] ?? null) : null;
|
|
@@ -2662,6 +3105,10 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2662
3105
|
speed: pstate.speed,
|
|
2663
3106
|
totalEnergy: save.actor.totalEnergy,
|
|
2664
3107
|
combat,
|
|
3108
|
+
/* p->known_state, seeded with the real state and replaced with the true
|
|
3109
|
+
* known derive at the end of wireGame - the flavour store and the rune env
|
|
3110
|
+
* it needs do not exist yet at this line. */
|
|
3111
|
+
knownCombat: combat,
|
|
2665
3112
|
defense: toDefenderState(pstate),
|
|
2666
3113
|
weapon,
|
|
2667
3114
|
stealth: combat.skills[SKILL.STEALTH] ?? 0,
|
|
@@ -2675,6 +3122,11 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2675
3122
|
decoy = grid;
|
|
2676
3123
|
})
|
|
2677
3124
|
: new Map();
|
|
3125
|
+
/* Hoisted: the remembered pile is saved as locators into these very piles,
|
|
3126
|
+
* so deserializeKnown must be handed the same map the state runs on. */
|
|
3127
|
+
const loadedFloor = !save.isDead && save.floor
|
|
3128
|
+
? deserializeFloor(save.floor, reg.objects, chunk.width, ids)
|
|
3129
|
+
: new Map();
|
|
2678
3130
|
const state = {
|
|
2679
3131
|
rng,
|
|
2680
3132
|
chunk,
|
|
@@ -2683,13 +3135,11 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2683
3135
|
decoy,
|
|
2684
3136
|
monsters: (save.isDead ? [null] : (save.monsters ?? [null])).map((m) => m ? deserializeMonster(m, reg.monsters, reg.objects, ids) : null),
|
|
2685
3137
|
groups: (save.isDead ? [null] : (save.groups ?? [null])).map((g) => g ? { index: g.index, leader: g.leader, members: [...g.members] } : null),
|
|
2686
|
-
floor:
|
|
2687
|
-
? deserializeFloor(save.floor, reg.objects, chunk.width, ids)
|
|
2688
|
-
: new Map(),
|
|
3138
|
+
floor: loadedFloor,
|
|
2689
3139
|
traps: loadedTraps,
|
|
2690
3140
|
known: save.isDead
|
|
2691
3141
|
? newKnownMap(chunk.width, chunk.height)
|
|
2692
|
-
: deserializeKnown(save.known, chunk.width, chunk.height, featRemap),
|
|
3142
|
+
: deserializeKnown(save.known, chunk.width, chunk.height, featRemap, ids, loadedFloor, reg.objects),
|
|
2693
3143
|
/* birth_levels_persist (#30) frozen-level cache; empty in saves written
|
|
2694
3144
|
* before the field or with the option off (back-compat). */
|
|
2695
3145
|
levelCache: deserializeLevelCache(save.isDead ? undefined : save.levelCache, reg.features, reg.monsters, reg.objects, reg.traps, ids),
|
|
@@ -2770,6 +3220,17 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2770
3220
|
},
|
|
2771
3221
|
brands: reg.objects.brands,
|
|
2772
3222
|
slays: reg.objects.slays,
|
|
3223
|
+
curses: reg.objects.curses,
|
|
3224
|
+
/* player_has_temporary_brand / _slay (player-util.c), bound ONCE here from the
|
|
3225
|
+
* pack's timed records. The melee hooks used to build a private copy and
|
|
3226
|
+
* nothing else could reach one, so obj-info's brand/slay gathering carried a
|
|
3227
|
+
* "DEFERRED" note beside a predicate that already existed - PORT_TODO 3.20. */
|
|
3228
|
+
tempBrandSlay: buildTempBrandSlay(player,
|
|
3229
|
+
/* The RAW pack records, not players.timed - bindPlayer's TimedEffect has no
|
|
3230
|
+
* brand/slay code arrays, so passing the bound table silently mapped every
|
|
3231
|
+
* index to -1 and hasBrand answered false for everything. Measured: the
|
|
3232
|
+
* first draft of this did exactly that and the test caught it. */
|
|
3233
|
+
pack.player.timed, reg.objects.brands, reg.objects.slays),
|
|
2773
3234
|
/* Placeholder; wireGame installs the full registry-backed env. */
|
|
2774
3235
|
runeEnv: makeRuneEnv(() => null, () => false),
|
|
2775
3236
|
playing: save.playing,
|
|
@@ -2805,16 +3266,27 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2805
3266
|
player.noscore = markNoscore(player.noscore, NOSCORE.WIZARD);
|
|
2806
3267
|
state.isDead = false;
|
|
2807
3268
|
}
|
|
2808
|
-
/* A save taken in single combat resumes it
|
|
2809
|
-
*
|
|
3269
|
+
/* A save taken in single combat resumes it, INCLUDING the level it was
|
|
3270
|
+
* entered from - upstream keeps that in the chunk_list and the savefile
|
|
3271
|
+
* carries it. Rebuilt through the frozen-level cache deserializer, which is
|
|
3272
|
+
* the same code path the live level and the persistent cache use. A save
|
|
3273
|
+
* written before the stash was persisted has no `stash` key and reloads with
|
|
3274
|
+
* the old behaviour: winning exits to a fresh level of the same depth. */
|
|
2810
3275
|
if (save.arena) {
|
|
2811
3276
|
state.arenaLevel = true;
|
|
2812
3277
|
state.oldGrid = loc(save.arena.oldGrid.x, save.arena.oldGrid.y);
|
|
3278
|
+
if (save.arena.stash) {
|
|
3279
|
+
const rebuilt = deserializeLevelCache([save.arena.stash], reg.features, reg.monsters, reg.objects, reg.traps, ids);
|
|
3280
|
+
const level = rebuilt.get(save.arena.stash.depth);
|
|
3281
|
+
if (level) {
|
|
3282
|
+
state.arenaStash = { ...level, monMidx: save.arena.monMidx ?? 0 };
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
2813
3285
|
}
|
|
2814
3286
|
/* seed_flavor from the save (load.c L960). Older saves predate it; fall
|
|
2815
3287
|
* back to 0 so flavor_init still produces a stable per-load assignment. */
|
|
2816
3288
|
const seedFlavor = save.seedFlavor ?? 0;
|
|
2817
|
-
const wired = wireGame(state, reg, players, pstate, seedFlavor
|
|
3289
|
+
const wired = wireGame(state, reg, players, pstate, seedFlavor);
|
|
2818
3290
|
/* rd_gear's tail (load.c:1187). */
|
|
2819
3291
|
buildGearViews(state, reg, pstate.ammoTval);
|
|
2820
3292
|
/* restore() replaces the aware/tried sets, so it must run AFTER flavor_init's
|
|
@@ -2851,6 +3323,10 @@ export function loadGame(pack, saveDocument, present = new Set(["core"]), opts =
|
|
|
2851
3323
|
const booted = {
|
|
2852
3324
|
chunk,
|
|
2853
3325
|
depth: chunk.depth,
|
|
3326
|
+
/* The restored level's connectors live on state.currentJoins, which the
|
|
3327
|
+
* savefile already carries; this view describes a level nothing
|
|
3328
|
+
* generated, so it reports none. */
|
|
3329
|
+
joins: [],
|
|
2854
3330
|
playerSpot: actor.grid,
|
|
2855
3331
|
monsters: [],
|
|
2856
3332
|
objects: [],
|