@rpgm-tools/neo-angband-core 0.10.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/LICENSE.md +43 -0
- package/README.md +80 -0
- package/dist/agent/act.d.ts +22 -0
- package/dist/agent/act.d.ts.map +1 -0
- package/dist/agent/act.js +88 -0
- package/dist/agent/act.js.map +1 -0
- package/dist/agent/controller.d.ts +34 -0
- package/dist/agent/controller.d.ts.map +1 -0
- package/dist/agent/controller.js +90 -0
- package/dist/agent/controller.js.map +1 -0
- package/dist/agent/events.d.ts +27 -0
- package/dist/agent/events.d.ts.map +1 -0
- package/dist/agent/events.js +31 -0
- package/dist/agent/events.js.map +1 -0
- package/dist/agent/index.d.ts +17 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +15 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/perceive.d.ts +21 -0
- package/dist/agent/perceive.d.ts.map +1 -0
- package/dist/agent/perceive.js +386 -0
- package/dist/agent/perceive.js.map +1 -0
- package/dist/agent/types.d.ts +436 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +63 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/bitflag.d.ts +199 -0
- package/dist/bitflag.d.ts.map +1 -0
- package/dist/bitflag.js +478 -0
- package/dist/bitflag.js.map +1 -0
- package/dist/cmd.d.ts +164 -0
- package/dist/cmd.d.ts.map +1 -0
- package/dist/cmd.js +350 -0
- package/dist/cmd.js.map +1 -0
- package/dist/color.d.ts +104 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +240 -0
- package/dist/color.js.map +1 -0
- package/dist/combat/brand-slay.d.ts +119 -0
- package/dist/combat/brand-slay.d.ts.map +1 -0
- package/dist/combat/brand-slay.js +264 -0
- package/dist/combat/brand-slay.js.map +1 -0
- package/dist/combat/hit.d.ts +198 -0
- package/dist/combat/hit.d.ts.map +1 -0
- package/dist/combat/hit.js +310 -0
- package/dist/combat/hit.js.map +1 -0
- package/dist/combat/index.d.ts +15 -0
- package/dist/combat/index.d.ts.map +1 -0
- package/dist/combat/index.js +15 -0
- package/dist/combat/index.js.map +1 -0
- package/dist/combat/melee.d.ts +261 -0
- package/dist/combat/melee.d.ts.map +1 -0
- package/dist/combat/melee.js +402 -0
- package/dist/combat/melee.js.map +1 -0
- package/dist/combat/mon-melee.d.ts +233 -0
- package/dist/combat/mon-melee.d.ts.map +1 -0
- package/dist/combat/mon-melee.js +883 -0
- package/dist/combat/mon-melee.js.map +1 -0
- package/dist/combat/ranged.d.ts +89 -0
- package/dist/combat/ranged.d.ts.map +1 -0
- package/dist/combat/ranged.js +253 -0
- package/dist/combat/ranged.js.map +1 -0
- package/dist/constants.d.ts +134 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +171 -0
- package/dist/constants.js.map +1 -0
- package/dist/dice.d.ts +91 -0
- package/dist/dice.d.ts.map +1 -0
- package/dist/dice.js +424 -0
- package/dist/dice.js.map +1 -0
- package/dist/effects/effect-choice.d.ts +15 -0
- package/dist/effects/effect-choice.d.ts.map +1 -0
- package/dist/effects/effect-choice.js +18 -0
- package/dist/effects/effect-choice.js.map +1 -0
- package/dist/effects/effect-info.d.ts +124 -0
- package/dist/effects/effect-info.d.ts.map +1 -0
- package/dist/effects/effect-info.js +706 -0
- package/dist/effects/effect-info.js.map +1 -0
- package/dist/effects/effect.d.ts +165 -0
- package/dist/effects/effect.d.ts.map +1 -0
- package/dist/effects/effect.js +452 -0
- package/dist/effects/effect.js.map +1 -0
- package/dist/effects/handlers.d.ts +70 -0
- package/dist/effects/handlers.d.ts.map +1 -0
- package/dist/effects/handlers.js +394 -0
- package/dist/effects/handlers.js.map +1 -0
- package/dist/effects/interpreter.d.ts +291 -0
- package/dist/effects/interpreter.d.ts.map +1 -0
- package/dist/effects/interpreter.js +325 -0
- package/dist/effects/interpreter.js.map +1 -0
- package/dist/events.d.ts +188 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +138 -0
- package/dist/events.js.map +1 -0
- package/dist/expression.d.ts +83 -0
- package/dist/expression.d.ts.map +1 -0
- package/dist/expression.js +333 -0
- package/dist/expression.js.map +1 -0
- package/dist/game/cave-cmd.d.ts +195 -0
- package/dist/game/cave-cmd.d.ts.map +1 -0
- package/dist/game/cave-cmd.js +968 -0
- package/dist/game/cave-cmd.js.map +1 -0
- package/dist/game/char-sheet.d.ts +189 -0
- package/dist/game/char-sheet.d.ts.map +1 -0
- package/dist/game/char-sheet.js +381 -0
- package/dist/game/char-sheet.js.map +1 -0
- package/dist/game/chest.d.ts +94 -0
- package/dist/game/chest.d.ts.map +1 -0
- package/dist/game/chest.js +267 -0
- package/dist/game/chest.js.map +1 -0
- package/dist/game/context.d.ts +970 -0
- package/dist/game/context.d.ts.map +1 -0
- package/dist/game/context.js +353 -0
- package/dist/game/context.js.map +1 -0
- package/dist/game/curse-tick.d.ts +35 -0
- package/dist/game/curse-tick.d.ts.map +1 -0
- package/dist/game/curse-tick.js +100 -0
- package/dist/game/curse-tick.js.map +1 -0
- package/dist/game/describe.d.ts +20 -0
- package/dist/game/describe.d.ts.map +1 -0
- package/dist/game/describe.js +45 -0
- package/dist/game/describe.js.map +1 -0
- package/dist/game/display.d.ts +196 -0
- package/dist/game/display.d.ts.map +1 -0
- package/dist/game/display.js +684 -0
- package/dist/game/display.js.map +1 -0
- package/dist/game/dump-level.d.ts +37 -0
- package/dist/game/dump-level.d.ts.map +1 -0
- package/dist/game/dump-level.js +110 -0
- package/dist/game/dump-level.js.map +1 -0
- package/dist/game/effect-attack.d.ts +36 -0
- package/dist/game/effect-attack.d.ts.map +1 -0
- package/dist/game/effect-attack.js +694 -0
- package/dist/game/effect-attack.js.map +1 -0
- package/dist/game/effect-detect.d.ts +34 -0
- package/dist/game/effect-detect.d.ts.map +1 -0
- package/dist/game/effect-detect.js +456 -0
- package/dist/game/effect-detect.js.map +1 -0
- package/dist/game/effect-env.d.ts +77 -0
- package/dist/game/effect-env.d.ts.map +1 -0
- package/dist/game/effect-env.js +166 -0
- package/dist/game/effect-env.js.map +1 -0
- package/dist/game/effect-game-env.d.ts +76 -0
- package/dist/game/effect-game-env.d.ts.map +1 -0
- package/dist/game/effect-game-env.js +23 -0
- package/dist/game/effect-game-env.js.map +1 -0
- package/dist/game/effect-general.d.ts +98 -0
- package/dist/game/effect-general.d.ts.map +1 -0
- package/dist/game/effect-general.js +914 -0
- package/dist/game/effect-general.js.map +1 -0
- package/dist/game/effect-item.d.ts +124 -0
- package/dist/game/effect-item.d.ts.map +1 -0
- package/dist/game/effect-item.js +789 -0
- package/dist/game/effect-item.js.map +1 -0
- package/dist/game/effect-melee.d.ts +43 -0
- package/dist/game/effect-melee.d.ts.map +1 -0
- package/dist/game/effect-melee.js +477 -0
- package/dist/game/effect-melee.js.map +1 -0
- package/dist/game/effect-mon-origin.d.ts +67 -0
- package/dist/game/effect-mon-origin.d.ts.map +1 -0
- package/dist/game/effect-mon-origin.js +164 -0
- package/dist/game/effect-mon-origin.js.map +1 -0
- package/dist/game/effect-monster.d.ts +29 -0
- package/dist/game/effect-monster.d.ts.map +1 -0
- package/dist/game/effect-monster.js +281 -0
- package/dist/game/effect-monster.js.map +1 -0
- package/dist/game/effect-summon.d.ts +37 -0
- package/dist/game/effect-summon.d.ts.map +1 -0
- package/dist/game/effect-summon.js +113 -0
- package/dist/game/effect-summon.js.map +1 -0
- package/dist/game/effect-teleport.d.ts +130 -0
- package/dist/game/effect-teleport.d.ts.map +1 -0
- package/dist/game/effect-teleport.js +529 -0
- package/dist/game/effect-teleport.js.map +1 -0
- package/dist/game/effect-terrain.d.ts +91 -0
- package/dist/game/effect-terrain.d.ts.map +1 -0
- package/dist/game/effect-terrain.js +812 -0
- package/dist/game/effect-terrain.js.map +1 -0
- package/dist/game/energy.d.ts +45 -0
- package/dist/game/energy.d.ts.map +1 -0
- package/dist/game/energy.js +51 -0
- package/dist/game/energy.js.map +1 -0
- package/dist/game/equip-cmp.d.ts +138 -0
- package/dist/game/equip-cmp.d.ts.map +1 -0
- package/dist/game/equip-cmp.js +363 -0
- package/dist/game/equip-cmp.js.map +1 -0
- package/dist/game/floor.d.ts +182 -0
- package/dist/game/floor.d.ts.map +1 -0
- package/dist/game/floor.js +435 -0
- package/dist/game/floor.js.map +1 -0
- package/dist/game/gear.d.ts +408 -0
- package/dist/game/gear.d.ts.map +1 -0
- package/dist/game/gear.js +1037 -0
- package/dist/game/gear.js.map +1 -0
- package/dist/game/harness.d.ts +61 -0
- package/dist/game/harness.d.ts.map +1 -0
- package/dist/game/harness.js +198 -0
- package/dist/game/harness.js.map +1 -0
- package/dist/game/history.d.ts +49 -0
- package/dist/game/history.d.ts.map +1 -0
- package/dist/game/history.js +55 -0
- package/dist/game/history.js.map +1 -0
- package/dist/game/ignore-cmd.d.ts +42 -0
- package/dist/game/ignore-cmd.d.ts.map +1 -0
- package/dist/game/ignore-cmd.js +59 -0
- package/dist/game/ignore-cmd.js.map +1 -0
- package/dist/game/inscription-confirm.d.ts +80 -0
- package/dist/game/inscription-confirm.d.ts.map +1 -0
- package/dist/game/inscription-confirm.js +95 -0
- package/dist/game/inscription-confirm.js.map +1 -0
- package/dist/game/known.d.ts +297 -0
- package/dist/game/known.d.ts.map +1 -0
- package/dist/game/known.js +849 -0
- package/dist/game/known.js.map +1 -0
- package/dist/game/loop.d.ts +139 -0
- package/dist/game/loop.d.ts.map +1 -0
- package/dist/game/loop.js +631 -0
- package/dist/game/loop.js.map +1 -0
- package/dist/game/lore-color.d.ts +25 -0
- package/dist/game/lore-color.d.ts.map +1 -0
- package/dist/game/lore-color.js +95 -0
- package/dist/game/lore-color.js.map +1 -0
- package/dist/game/mon-cast.d.ts +150 -0
- package/dist/game/mon-cast.d.ts.map +1 -0
- package/dist/game/mon-cast.js +301 -0
- package/dist/game/mon-cast.js.map +1 -0
- package/dist/game/mon-cmd.d.ts +51 -0
- package/dist/game/mon-cmd.d.ts.map +1 -0
- package/dist/game/mon-cmd.js +670 -0
- package/dist/game/mon-cmd.js.map +1 -0
- package/dist/game/mon-death.d.ts +143 -0
- package/dist/game/mon-death.d.ts.map +1 -0
- package/dist/game/mon-death.js +328 -0
- package/dist/game/mon-death.js.map +1 -0
- package/dist/game/mon-group.d.ts +81 -0
- package/dist/game/mon-group.d.ts.map +1 -0
- package/dist/game/mon-group.js +323 -0
- package/dist/game/mon-group.js.map +1 -0
- package/dist/game/mon-list.d.ts +85 -0
- package/dist/game/mon-list.d.ts.map +1 -0
- package/dist/game/mon-list.js +154 -0
- package/dist/game/mon-list.js.map +1 -0
- package/dist/game/mon-message.d.ts +100 -0
- package/dist/game/mon-message.d.ts.map +1 -0
- package/dist/game/mon-message.js +336 -0
- package/dist/game/mon-message.js.map +1 -0
- package/dist/game/mon-place.d.ts +226 -0
- package/dist/game/mon-place.d.ts.map +1 -0
- package/dist/game/mon-place.js +642 -0
- package/dist/game/mon-place.js.map +1 -0
- package/dist/game/mon-ranged.d.ts +87 -0
- package/dist/game/mon-ranged.d.ts.map +1 -0
- package/dist/game/mon-ranged.js +353 -0
- package/dist/game/mon-ranged.js.map +1 -0
- package/dist/game/mon-shape.d.ts +43 -0
- package/dist/game/mon-shape.d.ts.map +1 -0
- package/dist/game/mon-shape.js +115 -0
- package/dist/game/mon-shape.js.map +1 -0
- package/dist/game/mon-side.d.ts +63 -0
- package/dist/game/mon-side.d.ts.map +1 -0
- package/dist/game/mon-side.js +403 -0
- package/dist/game/mon-side.js.map +1 -0
- package/dist/game/monster-turn.d.ts +195 -0
- package/dist/game/monster-turn.d.ts.map +1 -0
- package/dist/game/monster-turn.js +1560 -0
- package/dist/game/monster-turn.js.map +1 -0
- package/dist/game/obj-cmd.d.ts +453 -0
- package/dist/game/obj-cmd.d.ts.map +1 -0
- package/dist/game/obj-cmd.js +1530 -0
- package/dist/game/obj-cmd.js.map +1 -0
- package/dist/game/obj-list.d.ts +92 -0
- package/dist/game/obj-list.d.ts.map +1 -0
- package/dist/game/obj-list.js +251 -0
- package/dist/game/obj-list.js.map +1 -0
- package/dist/game/object-inspect.d.ts +37 -0
- package/dist/game/object-inspect.d.ts.map +1 -0
- package/dist/game/object-inspect.js +106 -0
- package/dist/game/object-inspect.js.map +1 -0
- package/dist/game/pickup.d.ts +126 -0
- package/dist/game/pickup.d.ts.map +1 -0
- package/dist/game/pickup.js +367 -0
- package/dist/game/pickup.js.map +1 -0
- package/dist/game/player-path.d.ts +133 -0
- package/dist/game/player-path.d.ts.map +1 -0
- package/dist/game/player-path.js +1268 -0
- package/dist/game/player-path.js.map +1 -0
- package/dist/game/player-side.d.ts +59 -0
- package/dist/game/player-side.d.ts.map +1 -0
- package/dist/game/player-side.js +506 -0
- package/dist/game/player-side.js.map +1 -0
- package/dist/game/player-turn.d.ts +161 -0
- package/dist/game/player-turn.d.ts.map +1 -0
- package/dist/game/player-turn.js +739 -0
- package/dist/game/player-turn.js.map +1 -0
- package/dist/game/project-cast.d.ts +268 -0
- package/dist/game/project-cast.d.ts.map +1 -0
- package/dist/game/project-cast.js +496 -0
- package/dist/game/project-cast.js.map +1 -0
- package/dist/game/project-feat.d.ts +47 -0
- package/dist/game/project-feat.d.ts.map +1 -0
- package/dist/game/project-feat.js +350 -0
- package/dist/game/project-feat.js.map +1 -0
- package/dist/game/project-monster.d.ts +106 -0
- package/dist/game/project-monster.d.ts.map +1 -0
- package/dist/game/project-monster.js +272 -0
- package/dist/game/project-monster.js.map +1 -0
- package/dist/game/project-obj.d.ts +60 -0
- package/dist/game/project-obj.d.ts.map +1 -0
- package/dist/game/project-obj.js +245 -0
- package/dist/game/project-obj.js.map +1 -0
- package/dist/game/project-player.d.ts +120 -0
- package/dist/game/project-player.d.ts.map +1 -0
- package/dist/game/project-player.js +108 -0
- package/dist/game/project-player.js.map +1 -0
- package/dist/game/quest.d.ts +101 -0
- package/dist/game/quest.d.ts.map +1 -0
- package/dist/game/quest.js +192 -0
- package/dist/game/quest.js.map +1 -0
- package/dist/game/ranged-cmd.d.ts +32 -0
- package/dist/game/ranged-cmd.d.ts.map +1 -0
- package/dist/game/ranged-cmd.js +372 -0
- package/dist/game/ranged-cmd.js.map +1 -0
- package/dist/game/scheduler.d.ts +47 -0
- package/dist/game/scheduler.d.ts.map +1 -0
- package/dist/game/scheduler.js +141 -0
- package/dist/game/scheduler.js.map +1 -0
- package/dist/game/spell-cmd.d.ts +104 -0
- package/dist/game/spell-cmd.d.ts.map +1 -0
- package/dist/game/spell-cmd.js +320 -0
- package/dist/game/spell-cmd.js.map +1 -0
- package/dist/game/spoil.d.ts +28 -0
- package/dist/game/spoil.d.ts.map +1 -0
- package/dist/game/spoil.js +435 -0
- package/dist/game/spoil.js.map +1 -0
- package/dist/game/steal.d.ts +35 -0
- package/dist/game/steal.d.ts.map +1 -0
- package/dist/game/steal.js +145 -0
- package/dist/game/steal.js.map +1 -0
- package/dist/game/take-hit-hooks.d.ts +52 -0
- package/dist/game/take-hit-hooks.d.ts.map +1 -0
- package/dist/game/take-hit-hooks.js +127 -0
- package/dist/game/take-hit-hooks.js.map +1 -0
- package/dist/game/target-loop.d.ts +119 -0
- package/dist/game/target-loop.d.ts.map +1 -0
- package/dist/game/target-loop.js +408 -0
- package/dist/game/target-loop.js.map +1 -0
- package/dist/game/target.d.ts +133 -0
- package/dist/game/target.d.ts.map +1 -0
- package/dist/game/target.js +353 -0
- package/dist/game/target.js.map +1 -0
- package/dist/game/thrust.d.ts +37 -0
- package/dist/game/thrust.d.ts.map +1 -0
- package/dist/game/thrust.js +155 -0
- package/dist/game/thrust.js.map +1 -0
- package/dist/game/trap.d.ts +218 -0
- package/dist/game/trap.d.ts.map +1 -0
- package/dist/game/trap.js +618 -0
- package/dist/game/trap.js.map +1 -0
- package/dist/game/ui-entry.d.ts +282 -0
- package/dist/game/ui-entry.d.ts.map +1 -0
- package/dist/game/ui-entry.js +1838 -0
- package/dist/game/ui-entry.js.map +1 -0
- package/dist/game/wizard.d.ts +654 -0
- package/dist/game/wizard.d.ts.map +1 -0
- package/dist/game/wizard.js +1323 -0
- package/dist/game/wizard.js.map +1 -0
- package/dist/game/world.d.ts +183 -0
- package/dist/game/world.d.ts.map +1 -0
- package/dist/game/world.js +685 -0
- package/dist/game/world.js.map +1 -0
- package/dist/gen/cave.d.ts +247 -0
- package/dist/gen/cave.d.ts.map +1 -0
- package/dist/gen/cave.js +2406 -0
- package/dist/gen/cave.js.map +1 -0
- package/dist/gen/gen-monster.d.ts +151 -0
- package/dist/gen/gen-monster.d.ts.map +1 -0
- package/dist/gen/gen-monster.js +473 -0
- package/dist/gen/gen-monster.js.map +1 -0
- package/dist/gen/generate.d.ts +240 -0
- package/dist/gen/generate.d.ts.map +1 -0
- package/dist/gen/generate.js +358 -0
- package/dist/gen/generate.js.map +1 -0
- package/dist/gen/room.d.ts +160 -0
- package/dist/gen/room.d.ts.map +1 -0
- package/dist/gen/room.js +1910 -0
- package/dist/gen/room.js.map +1 -0
- package/dist/gen/util.d.ts +466 -0
- package/dist/gen/util.d.ts.map +1 -0
- package/dist/gen/util.js +1553 -0
- package/dist/gen/util.js.map +1 -0
- package/dist/generated/dun-profiles.d.ts +44 -0
- package/dist/generated/dun-profiles.d.ts.map +1 -0
- package/dist/generated/dun-profiles.js +28 -0
- package/dist/generated/dun-profiles.js.map +1 -0
- package/dist/generated/effects.d.ts +1021 -0
- package/dist/generated/effects.d.ts.map +1 -0
- package/dist/generated/effects.js +239 -0
- package/dist/generated/effects.js.map +1 -0
- package/dist/generated/elements.d.ts +83 -0
- package/dist/generated/elements.d.ts.map +1 -0
- package/dist/generated/elements.js +60 -0
- package/dist/generated/elements.js.map +1 -0
- package/dist/generated/equip-slots.d.ts +104 -0
- package/dist/generated/equip-slots.d.ts.map +1 -0
- package/dist/generated/equip-slots.js +34 -0
- package/dist/generated/equip-slots.js.map +1 -0
- package/dist/generated/history-types.d.ts +52 -0
- package/dist/generated/history-types.d.ts.map +1 -0
- package/dist/generated/history-types.js +32 -0
- package/dist/generated/history-types.js.map +1 -0
- package/dist/generated/ignore-types.d.ts +116 -0
- package/dist/generated/ignore-types.d.ts.map +1 -0
- package/dist/generated/ignore-types.js +64 -0
- package/dist/generated/ignore-types.js.map +1 -0
- package/dist/generated/index.d.ts +32 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +33 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/generated/kind-flags.d.ts +72 -0
- package/dist/generated/kind-flags.d.ts.map +1 -0
- package/dist/generated/kind-flags.js +42 -0
- package/dist/generated/kind-flags.js.map +1 -0
- package/dist/generated/message.d.ts +624 -0
- package/dist/generated/message.d.ts.map +1 -0
- package/dist/generated/message.js +318 -0
- package/dist/generated/message.js.map +1 -0
- package/dist/generated/mon-message.d.ts +386 -0
- package/dist/generated/mon-message.d.ts.map +1 -0
- package/dist/generated/mon-message.js +136 -0
- package/dist/generated/mon-message.js.map +1 -0
- package/dist/generated/mon-race-flags.d.ts +433 -0
- package/dist/generated/mon-race-flags.d.ts.map +1 -0
- package/dist/generated/mon-race-flags.js +180 -0
- package/dist/generated/mon-race-flags.js.map +1 -0
- package/dist/generated/mon-spells.d.ts +380 -0
- package/dist/generated/mon-spells.d.ts.map +1 -0
- package/dist/generated/mon-spells.js +196 -0
- package/dist/generated/mon-spells.js.map +1 -0
- package/dist/generated/mon-temp-flags.d.ts +52 -0
- package/dist/generated/mon-temp-flags.d.ts.map +1 -0
- package/dist/generated/mon-temp-flags.js +32 -0
- package/dist/generated/mon-temp-flags.js.map +1 -0
- package/dist/generated/mon-timed.d.ts +118 -0
- package/dist/generated/mon-timed.d.ts.map +1 -0
- package/dist/generated/mon-timed.js +32 -0
- package/dist/generated/mon-timed.js.map +1 -0
- package/dist/generated/object-flags.d.ts +169 -0
- package/dist/generated/object-flags.d.ts.map +1 -0
- package/dist/generated/object-flags.js +93 -0
- package/dist/generated/object-flags.js.map +1 -0
- package/dist/generated/object-modifiers.d.ts +50 -0
- package/dist/generated/object-modifiers.d.ts.map +1 -0
- package/dist/generated/object-modifiers.js +41 -0
- package/dist/generated/object-modifiers.js.map +1 -0
- package/dist/generated/options.d.ts +284 -0
- package/dist/generated/options.d.ts.map +1 -0
- package/dist/generated/options.js +102 -0
- package/dist/generated/options.js.map +1 -0
- package/dist/generated/origins.d.ts +138 -0
- package/dist/generated/origins.d.ts.map +1 -0
- package/dist/generated/origins.js +62 -0
- package/dist/generated/origins.js.map +1 -0
- package/dist/generated/parser-errors.d.ts +264 -0
- package/dist/generated/parser-errors.d.ts.map +1 -0
- package/dist/generated/parser-errors.js +138 -0
- package/dist/generated/parser-errors.js.map +1 -0
- package/dist/generated/player-flags.d.ts +62 -0
- package/dist/generated/player-flags.d.ts.map +1 -0
- package/dist/generated/player-flags.js +46 -0
- package/dist/generated/player-flags.js.map +1 -0
- package/dist/generated/player-timed.d.ts +273 -0
- package/dist/generated/player-timed.d.ts.map +1 -0
- package/dist/generated/player-timed.js +116 -0
- package/dist/generated/player-timed.js.map +1 -0
- package/dist/generated/projections.d.ts +130 -0
- package/dist/generated/projections.d.ts.map +1 -0
- package/dist/generated/projections.js +101 -0
- package/dist/generated/projections.js.map +1 -0
- package/dist/generated/randart-properties.d.ts +388 -0
- package/dist/generated/randart-properties.d.ts.map +1 -0
- package/dist/generated/randart-properties.js +200 -0
- package/dist/generated/randart-properties.js.map +1 -0
- package/dist/generated/room-flags.d.ts +21 -0
- package/dist/generated/room-flags.d.ts.map +1 -0
- package/dist/generated/room-flags.js +19 -0
- package/dist/generated/room-flags.js.map +1 -0
- package/dist/generated/rooms.d.ts +122 -0
- package/dist/generated/rooms.d.ts.map +1 -0
- package/dist/generated/rooms.js +48 -0
- package/dist/generated/rooms.js.map +1 -0
- package/dist/generated/square-flags.d.ts +96 -0
- package/dist/generated/square-flags.d.ts.map +1 -0
- package/dist/generated/square-flags.js +54 -0
- package/dist/generated/square-flags.js.map +1 -0
- package/dist/generated/stats.d.ts +23 -0
- package/dist/generated/stats.d.ts.map +1 -0
- package/dist/generated/stats.js +20 -0
- package/dist/generated/stats.js.map +1 -0
- package/dist/generated/terrain-flags.d.ts +136 -0
- package/dist/generated/terrain-flags.d.ts.map +1 -0
- package/dist/generated/terrain-flags.js +74 -0
- package/dist/generated/terrain-flags.js.map +1 -0
- package/dist/generated/terrain.d.ts +83 -0
- package/dist/generated/terrain.d.ts.map +1 -0
- package/dist/generated/terrain.js +60 -0
- package/dist/generated/terrain.js.map +1 -0
- package/dist/generated/trap-flags.d.ts +68 -0
- package/dist/generated/trap-flags.d.ts.map +1 -0
- package/dist/generated/trap-flags.js +40 -0
- package/dist/generated/trap-flags.js.map +1 -0
- package/dist/generated/tvals.d.ts +152 -0
- package/dist/generated/tvals.d.ts.map +1 -0
- package/dist/generated/tvals.js +82 -0
- package/dist/generated/tvals.js.map +1 -0
- package/dist/generated/ui-entry-renderers.d.ts +62 -0
- package/dist/generated/ui-entry-renderers.d.ts.map +1 -0
- package/dist/generated/ui-entry-renderers.js +22 -0
- package/dist/generated/ui-entry-renderers.js.map +1 -0
- package/dist/guard.d.ts +43 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +65 -0
- package/dist/guard.js.map +1 -0
- package/dist/host/args.d.ts +129 -0
- package/dist/host/args.d.ts.map +1 -0
- package/dist/host/args.js +251 -0
- package/dist/host/args.js.map +1 -0
- package/dist/host/bridge.d.ts +61 -0
- package/dist/host/bridge.d.ts.map +1 -0
- package/dist/host/bridge.js +176 -0
- package/dist/host/bridge.js.map +1 -0
- package/dist/host/index.d.ts +18 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +18 -0
- package/dist/host/index.js.map +1 -0
- package/dist/host/io.d.ts +169 -0
- package/dist/host/io.d.ts.map +1 -0
- package/dist/host/io.js +137 -0
- package/dist/host/io.js.map +1 -0
- package/dist/host/memory.d.ts +56 -0
- package/dist/host/memory.d.ts.map +1 -0
- package/dist/host/memory.js +105 -0
- package/dist/host/memory.js.map +1 -0
- package/dist/host/raw.d.ts +114 -0
- package/dist/host/raw.d.ts.map +1 -0
- package/dist/host/raw.js +107 -0
- package/dist/host/raw.js.map +1 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +222 -0
- package/dist/index.js.map +1 -0
- package/dist/loc.d.ts +63 -0
- package/dist/loc.d.ts.map +1 -0
- package/dist/loc.js +128 -0
- package/dist/loc.js.map +1 -0
- package/dist/mod/hooks.d.ts +204 -0
- package/dist/mod/hooks.d.ts.map +1 -0
- package/dist/mod/hooks.js +161 -0
- package/dist/mod/hooks.js.map +1 -0
- package/dist/mod/ids.d.ts +160 -0
- package/dist/mod/ids.d.ts.map +1 -0
- package/dist/mod/ids.js +343 -0
- package/dist/mod/ids.js.map +1 -0
- package/dist/mod/registry-host.d.ts +156 -0
- package/dist/mod/registry-host.d.ts.map +1 -0
- package/dist/mod/registry-host.js +142 -0
- package/dist/mod/registry-host.js.map +1 -0
- package/dist/mod/save-blocks.d.ts +201 -0
- package/dist/mod/save-blocks.d.ts.map +1 -0
- package/dist/mod/save-blocks.js +640 -0
- package/dist/mod/save-blocks.js.map +1 -0
- package/dist/mod/vocabulary.d.ts +104 -0
- package/dist/mod/vocabulary.d.ts.map +1 -0
- package/dist/mod/vocabulary.js +0 -0
- package/dist/mod/vocabulary.js.map +1 -0
- package/dist/mon/bind.d.ts +266 -0
- package/dist/mon/bind.d.ts.map +1 -0
- package/dist/mon/bind.js +610 -0
- package/dist/mon/bind.js.map +1 -0
- package/dist/mon/desc.d.ts +72 -0
- package/dist/mon/desc.d.ts.map +1 -0
- package/dist/mon/desc.js +237 -0
- package/dist/mon/desc.js.map +1 -0
- package/dist/mon/knowledge-groups.d.ts +61 -0
- package/dist/mon/knowledge-groups.d.ts.map +1 -0
- package/dist/mon/knowledge-groups.js +121 -0
- package/dist/mon/knowledge-groups.js.map +1 -0
- package/dist/mon/lore-describe.d.ts +216 -0
- package/dist/mon/lore-describe.d.ts.map +1 -0
- package/dist/mon/lore-describe.js +1105 -0
- package/dist/mon/lore-describe.js.map +1 -0
- package/dist/mon/lore.d.ts +117 -0
- package/dist/mon/lore.d.ts.map +1 -0
- package/dist/mon/lore.js +221 -0
- package/dist/mon/lore.js.map +1 -0
- package/dist/mon/make.d.ts +147 -0
- package/dist/mon/make.d.ts.map +1 -0
- package/dist/mon/make.js +353 -0
- package/dist/mon/make.js.map +1 -0
- package/dist/mon/monster.d.ts +94 -0
- package/dist/mon/monster.d.ts.map +1 -0
- package/dist/mon/monster.js +90 -0
- package/dist/mon/monster.js.map +1 -0
- package/dist/mon/predicate.d.ts +87 -0
- package/dist/mon/predicate.d.ts.map +1 -0
- package/dist/mon/predicate.js +190 -0
- package/dist/mon/predicate.js.map +1 -0
- package/dist/mon/project-mon.d.ts +129 -0
- package/dist/mon/project-mon.d.ts.map +1 -0
- package/dist/mon/project-mon.js +652 -0
- package/dist/mon/project-mon.js.map +1 -0
- package/dist/mon/spell.d.ts +155 -0
- package/dist/mon/spell.d.ts.map +1 -0
- package/dist/mon/spell.js +355 -0
- package/dist/mon/spell.js.map +1 -0
- package/dist/mon/steal.d.ts +112 -0
- package/dist/mon/steal.d.ts.map +1 -0
- package/dist/mon/steal.js +163 -0
- package/dist/mon/steal.js.map +1 -0
- package/dist/mon/summon.d.ts +62 -0
- package/dist/mon/summon.d.ts.map +1 -0
- package/dist/mon/summon.js +111 -0
- package/dist/mon/summon.js.map +1 -0
- package/dist/mon/take-hit.d.ts +75 -0
- package/dist/mon/take-hit.d.ts.map +1 -0
- package/dist/mon/take-hit.js +122 -0
- package/dist/mon/take-hit.js.map +1 -0
- package/dist/mon/timed.d.ts +74 -0
- package/dist/mon/timed.d.ts.map +1 -0
- package/dist/mon/timed.js +219 -0
- package/dist/mon/timed.js.map +1 -0
- package/dist/mon/types.d.ts +252 -0
- package/dist/mon/types.d.ts.map +1 -0
- package/dist/mon/types.js +46 -0
- package/dist/mon/types.js.map +1 -0
- package/dist/msg.d.ts +71 -0
- package/dist/msg.d.ts.map +1 -0
- package/dist/msg.js +126 -0
- package/dist/msg.js.map +1 -0
- package/dist/obj/artifact-fake.d.ts +39 -0
- package/dist/obj/artifact-fake.d.ts.map +1 -0
- package/dist/obj/artifact-fake.js +52 -0
- package/dist/obj/artifact-fake.js.map +1 -0
- package/dist/obj/artifact-known.d.ts +50 -0
- package/dist/obj/artifact-known.d.ts.map +1 -0
- package/dist/obj/artifact-known.js +55 -0
- package/dist/obj/artifact-known.js.map +1 -0
- package/dist/obj/bind.d.ts +219 -0
- package/dist/obj/bind.d.ts.map +1 -0
- package/dist/obj/bind.js +1239 -0
- package/dist/obj/bind.js.map +1 -0
- package/dist/obj/chest.d.ts +91 -0
- package/dist/obj/chest.d.ts.map +1 -0
- package/dist/obj/chest.js +220 -0
- package/dist/obj/chest.js.map +1 -0
- package/dist/obj/desc.d.ts +79 -0
- package/dist/obj/desc.d.ts.map +1 -0
- package/dist/obj/desc.js +602 -0
- package/dist/obj/desc.js.map +1 -0
- package/dist/obj/effects-info.d.ts +78 -0
- package/dist/obj/effects-info.d.ts.map +1 -0
- package/dist/obj/effects-info.js +240 -0
- package/dist/obj/effects-info.js.map +1 -0
- package/dist/obj/flavor.d.ts +68 -0
- package/dist/obj/flavor.d.ts.map +1 -0
- package/dist/obj/flavor.js +201 -0
- package/dist/obj/flavor.js.map +1 -0
- package/dist/obj/ignore.d.ts +143 -0
- package/dist/obj/ignore.d.ts.map +1 -0
- package/dist/obj/ignore.js +345 -0
- package/dist/obj/ignore.js.map +1 -0
- package/dist/obj/knowledge.d.ts +520 -0
- package/dist/obj/knowledge.d.ts.map +1 -0
- package/dist/obj/knowledge.js +1364 -0
- package/dist/obj/knowledge.js.map +1 -0
- package/dist/obj/known-object.d.ts +293 -0
- package/dist/obj/known-object.d.ts.map +1 -0
- package/dist/obj/known-object.js +532 -0
- package/dist/obj/known-object.js.map +1 -0
- package/dist/obj/make.d.ts +292 -0
- package/dist/obj/make.d.ts.map +1 -0
- package/dist/obj/make.js +1055 -0
- package/dist/obj/make.js.map +1 -0
- package/dist/obj/object-info.d.ts +188 -0
- package/dist/obj/object-info.d.ts.map +1 -0
- package/dist/obj/object-info.js +1407 -0
- package/dist/obj/object-info.js.map +1 -0
- package/dist/obj/object.d.ts +335 -0
- package/dist/obj/object.d.ts.map +1 -0
- package/dist/obj/object.js +1051 -0
- package/dist/obj/object.js.map +1 -0
- package/dist/obj/power.d.ts +65 -0
- package/dist/obj/power.d.ts.map +1 -0
- package/dist/obj/power.js +580 -0
- package/dist/obj/power.js.map +1 -0
- package/dist/obj/randart-build.d.ts +223 -0
- package/dist/obj/randart-build.d.ts.map +1 -0
- package/dist/obj/randart-build.js +1444 -0
- package/dist/obj/randart-build.js.map +1 -0
- package/dist/obj/randart-data.d.ts +179 -0
- package/dist/obj/randart-data.d.ts.map +1 -0
- package/dist/obj/randart-data.js +1153 -0
- package/dist/obj/randart-data.js.map +1 -0
- package/dist/obj/randart.d.ts +128 -0
- package/dist/obj/randart.d.ts.map +1 -0
- package/dist/obj/randart.js +458 -0
- package/dist/obj/randart.js.map +1 -0
- package/dist/obj/randname.d.ts +33 -0
- package/dist/obj/randname.d.ts.map +1 -0
- package/dist/obj/randname.js +116 -0
- package/dist/obj/randname.js.map +1 -0
- package/dist/obj/recharge.d.ts +28 -0
- package/dist/obj/recharge.d.ts.map +1 -0
- package/dist/obj/recharge.js +52 -0
- package/dist/obj/recharge.js.map +1 -0
- package/dist/obj/types.d.ts +584 -0
- package/dist/obj/types.d.ts.map +1 -0
- package/dist/obj/types.js +104 -0
- package/dist/obj/types.js.map +1 -0
- package/dist/obj/value.d.ts +64 -0
- package/dist/obj/value.d.ts.map +1 -0
- package/dist/obj/value.js +176 -0
- package/dist/obj/value.js.map +1 -0
- package/dist/player/abilities.d.ts +57 -0
- package/dist/player/abilities.d.ts.map +1 -0
- package/dist/player/abilities.js +118 -0
- package/dist/player/abilities.js.map +1 -0
- package/dist/player/best-digger.d.ts +42 -0
- package/dist/player/best-digger.d.ts.map +1 -0
- package/dist/player/best-digger.js +89 -0
- package/dist/player/best-digger.js.map +1 -0
- package/dist/player/bind.d.ts +270 -0
- package/dist/player/bind.d.ts.map +1 -0
- package/dist/player/bind.js +698 -0
- package/dist/player/bind.js.map +1 -0
- package/dist/player/birth.d.ts +258 -0
- package/dist/player/birth.d.ts.map +1 -0
- package/dist/player/birth.js +639 -0
- package/dist/player/birth.js.map +1 -0
- package/dist/player/calcs.d.ts +403 -0
- package/dist/player/calcs.d.ts.map +1 -0
- package/dist/player/calcs.js +1189 -0
- package/dist/player/calcs.js.map +1 -0
- package/dist/player/combat-regen.d.ts +14 -0
- package/dist/player/combat-regen.d.ts.map +1 -0
- package/dist/player/combat-regen.js +29 -0
- package/dist/player/combat-regen.js.map +1 -0
- package/dist/player/exp.d.ts +96 -0
- package/dist/player/exp.d.ts.map +1 -0
- package/dist/player/exp.js +229 -0
- package/dist/player/exp.js.map +1 -0
- package/dist/player/history.d.ts +91 -0
- package/dist/player/history.d.ts.map +1 -0
- package/dist/player/history.js +145 -0
- package/dist/player/history.js.map +1 -0
- package/dist/player/options.d.ts +123 -0
- package/dist/player/options.d.ts.map +1 -0
- package/dist/player/options.js +199 -0
- package/dist/player/options.js.map +1 -0
- package/dist/player/player.d.ts +242 -0
- package/dist/player/player.d.ts.map +1 -0
- package/dist/player/player.js +119 -0
- package/dist/player/player.js.map +1 -0
- package/dist/player/shape-lore.d.ts +56 -0
- package/dist/player/shape-lore.d.ts.map +1 -0
- package/dist/player/shape-lore.js +221 -0
- package/dist/player/shape-lore.js.map +1 -0
- package/dist/player/spell.d.ts +146 -0
- package/dist/player/spell.d.ts.map +1 -0
- package/dist/player/spell.js +519 -0
- package/dist/player/spell.js.map +1 -0
- package/dist/player/take-hit.d.ts +87 -0
- package/dist/player/take-hit.d.ts.map +1 -0
- package/dist/player/take-hit.js +99 -0
- package/dist/player/take-hit.js.map +1 -0
- package/dist/player/timed.d.ts +205 -0
- package/dist/player/timed.d.ts.map +1 -0
- package/dist/player/timed.js +310 -0
- package/dist/player/timed.js.map +1 -0
- package/dist/player/types.d.ts +390 -0
- package/dist/player/types.d.ts.map +1 -0
- package/dist/player/types.js +51 -0
- package/dist/player/types.js.map +1 -0
- package/dist/rational.d.ts +99 -0
- package/dist/rational.d.ts.map +1 -0
- package/dist/rational.js +345 -0
- package/dist/rational.js.map +1 -0
- package/dist/rng.d.ts +168 -0
- package/dist/rng.d.ts.map +1 -0
- package/dist/rng.js +404 -0
- package/dist/rng.js.map +1 -0
- package/dist/save/buffer.d.ts +120 -0
- package/dist/save/buffer.d.ts.map +1 -0
- package/dist/save/buffer.js +238 -0
- package/dist/save/buffer.js.map +1 -0
- package/dist/save/compress.d.ts +79 -0
- package/dist/save/compress.d.ts.map +1 -0
- package/dist/save/compress.js +97 -0
- package/dist/save/compress.js.map +1 -0
- package/dist/save/description.d.ts +61 -0
- package/dist/save/description.d.ts.map +1 -0
- package/dist/save/description.js +51 -0
- package/dist/save/description.js.map +1 -0
- package/dist/save/integrity.d.ts +59 -0
- package/dist/save/integrity.d.ts.map +1 -0
- package/dist/save/integrity.js +103 -0
- package/dist/save/integrity.js.map +1 -0
- package/dist/score/display.d.ts +40 -0
- package/dist/score/display.d.ts.map +1 -0
- package/dist/score/display.js +86 -0
- package/dist/score/display.js.map +1 -0
- package/dist/score/score.d.ts +166 -0
- package/dist/score/score.d.ts.map +1 -0
- package/dist/score/score.js +244 -0
- package/dist/score/score.js.map +1 -0
- package/dist/score/types.d.ts +98 -0
- package/dist/score/types.d.ts.map +1 -0
- package/dist/score/types.js +27 -0
- package/dist/score/types.js.map +1 -0
- package/dist/session/boot.d.ts +207 -0
- package/dist/session/boot.d.ts.map +1 -0
- package/dist/session/boot.js +151 -0
- package/dist/session/boot.js.map +1 -0
- package/dist/session/game.d.ts +257 -0
- package/dist/session/game.d.ts.map +1 -0
- package/dist/session/game.js +2880 -0
- package/dist/session/game.js.map +1 -0
- package/dist/session/save.d.ts +847 -0
- package/dist/session/save.d.ts.map +1 -0
- package/dist/session/save.js +1306 -0
- package/dist/session/save.js.map +1 -0
- package/dist/sound/engine.d.ts +146 -0
- package/dist/sound/engine.d.ts.map +1 -0
- package/dist/sound/engine.js +332 -0
- package/dist/sound/engine.js.map +1 -0
- package/dist/sound/index.d.ts +13 -0
- package/dist/sound/index.d.ts.map +1 -0
- package/dist/sound/index.js +13 -0
- package/dist/sound/index.js.map +1 -0
- package/dist/sound/sound-prefs-data.d.ts +10 -0
- package/dist/sound/sound-prefs-data.d.ts.map +1 -0
- package/dist/sound/sound-prefs-data.js +165 -0
- package/dist/sound/sound-prefs-data.js.map +1 -0
- package/dist/sound/types.d.ts +64 -0
- package/dist/sound/types.d.ts.map +1 -0
- package/dist/sound/types.js +23 -0
- package/dist/sound/types.js.map +1 -0
- package/dist/store/bind.d.ts +43 -0
- package/dist/store/bind.d.ts.map +1 -0
- package/dist/store/bind.js +130 -0
- package/dist/store/bind.js.map +1 -0
- package/dist/store/price.d.ts +27 -0
- package/dist/store/price.d.ts.map +1 -0
- package/dist/store/price.js +81 -0
- package/dist/store/price.js.map +1 -0
- package/dist/store/store-cmd.d.ts +51 -0
- package/dist/store/store-cmd.d.ts.map +1 -0
- package/dist/store/store-cmd.js +73 -0
- package/dist/store/store-cmd.js.map +1 -0
- package/dist/store/store.d.ts +156 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +616 -0
- package/dist/store/store.js.map +1 -0
- package/dist/store/transact.d.ts +198 -0
- package/dist/store/transact.d.ts.map +1 -0
- package/dist/store/transact.js +383 -0
- package/dist/store/transact.js.map +1 -0
- package/dist/store/types.d.ts +101 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +14 -0
- package/dist/store/types.js.map +1 -0
- package/dist/version.d.ts +25 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +25 -0
- package/dist/version.js.map +1 -0
- package/dist/visuals/engine.d.ts +223 -0
- package/dist/visuals/engine.d.ts.map +1 -0
- package/dist/visuals/engine.js +357 -0
- package/dist/visuals/engine.js.map +1 -0
- package/dist/visuals/glyph-table.d.ts +112 -0
- package/dist/visuals/glyph-table.d.ts.map +1 -0
- package/dist/visuals/glyph-table.js +156 -0
- package/dist/visuals/glyph-table.js.map +1 -0
- package/dist/visuals/grafmode-data.d.ts +4 -0
- package/dist/visuals/grafmode-data.d.ts.map +1 -0
- package/dist/visuals/grafmode-data.js +88 -0
- package/dist/visuals/grafmode-data.js.map +1 -0
- package/dist/visuals/grafmode.d.ts +83 -0
- package/dist/visuals/grafmode.d.ts.map +1 -0
- package/dist/visuals/grafmode.js +82 -0
- package/dist/visuals/grafmode.js.map +1 -0
- package/dist/visuals/index.d.ts +19 -0
- package/dist/visuals/index.d.ts.map +1 -0
- package/dist/visuals/index.js +19 -0
- package/dist/visuals/index.js.map +1 -0
- package/dist/visuals/map-text.d.ts +79 -0
- package/dist/visuals/map-text.d.ts.map +1 -0
- package/dist/visuals/map-text.js +122 -0
- package/dist/visuals/map-text.js.map +1 -0
- package/dist/visuals/pref-expr.d.ts +56 -0
- package/dist/visuals/pref-expr.d.ts.map +1 -0
- package/dist/visuals/pref-expr.js +173 -0
- package/dist/visuals/pref-expr.js.map +1 -0
- package/dist/visuals/prefs.d.ts +280 -0
- package/dist/visuals/prefs.d.ts.map +1 -0
- package/dist/visuals/prefs.js +835 -0
- package/dist/visuals/prefs.js.map +1 -0
- package/dist/visuals/tile-prefs.d.ts +132 -0
- package/dist/visuals/tile-prefs.d.ts.map +1 -0
- package/dist/visuals/tile-prefs.js +105 -0
- package/dist/visuals/tile-prefs.js.map +1 -0
- package/dist/world/chunk.d.ts +195 -0
- package/dist/world/chunk.d.ts.map +1 -0
- package/dist/world/chunk.js +422 -0
- package/dist/world/chunk.js.map +1 -0
- package/dist/world/feature.d.ts +86 -0
- package/dist/world/feature.d.ts.map +1 -0
- package/dist/world/feature.js +153 -0
- package/dist/world/feature.js.map +1 -0
- package/dist/world/flow.d.ts +33 -0
- package/dist/world/flow.d.ts.map +1 -0
- package/dist/world/flow.js +115 -0
- package/dist/world/flow.js.map +1 -0
- package/dist/world/project.d.ts +176 -0
- package/dist/world/project.d.ts.map +1 -0
- package/dist/world/project.js +543 -0
- package/dist/world/project.js.map +1 -0
- package/dist/world/projection.d.ts +100 -0
- package/dist/world/projection.d.ts.map +1 -0
- package/dist/world/projection.js +152 -0
- package/dist/world/projection.js.map +1 -0
- package/dist/world/scatter.d.ts +25 -0
- package/dist/world/scatter.d.ts.map +1 -0
- package/dist/world/scatter.js +54 -0
- package/dist/world/scatter.js.map +1 -0
- package/dist/world/trap.d.ts +84 -0
- package/dist/world/trap.d.ts.map +1 -0
- package/dist/world/trap.js +106 -0
- package/dist/world/trap.js.map +1 -0
- package/dist/world/view.d.ts +60 -0
- package/dist/world/view.d.ts.map +1 -0
- package/dist/world/view.js +436 -0
- package/dist/world/view.js.map +1 -0
- package/dist/z-queue.d.ts +133 -0
- package/dist/z-queue.d.ts.map +1 -0
- package/dist/z-queue.js +283 -0
- package/dist/z-queue.js.map +1 -0
- package/package.json +75 -0
- package/src/agent/act.ts +114 -0
- package/src/agent/controller.ts +109 -0
- package/src/agent/events.ts +47 -0
- package/src/agent/index.ts +36 -0
- package/src/agent/perceive.ts +440 -0
- package/src/agent/types.ts +464 -0
- package/src/bitflag.ts +536 -0
- package/src/cmd.ts +547 -0
- package/src/color.ts +267 -0
- package/src/combat/brand-slay.ts +360 -0
- package/src/combat/hit.ts +471 -0
- package/src/combat/index.ts +15 -0
- package/src/combat/melee.ts +728 -0
- package/src/combat/mon-melee.ts +1153 -0
- package/src/combat/ranged.ts +397 -0
- package/src/constants.ts +324 -0
- package/src/dice.ts +467 -0
- package/src/effects/effect-choice.ts +32 -0
- package/src/effects/effect-info.ts +859 -0
- package/src/effects/effect.ts +560 -0
- package/src/effects/handlers.ts +452 -0
- package/src/effects/interpreter.ts +603 -0
- package/src/events.ts +317 -0
- package/src/expression.ts +360 -0
- package/src/game/cave-cmd.ts +1147 -0
- package/src/game/char-sheet.ts +557 -0
- package/src/game/chest.ts +348 -0
- package/src/game/context.ts +1218 -0
- package/src/game/curse-tick.ts +130 -0
- package/src/game/describe.ts +62 -0
- package/src/game/display.ts +838 -0
- package/src/game/dump-level.ts +114 -0
- package/src/game/effect-attack.ts +746 -0
- package/src/game/effect-detect.ts +542 -0
- package/src/game/effect-env.ts +252 -0
- package/src/game/effect-game-env.ts +86 -0
- package/src/game/effect-general.ts +1122 -0
- package/src/game/effect-item.ts +999 -0
- package/src/game/effect-melee.ts +557 -0
- package/src/game/effect-mon-origin.ts +196 -0
- package/src/game/effect-monster.ts +310 -0
- package/src/game/effect-summon.ts +161 -0
- package/src/game/effect-teleport.ts +645 -0
- package/src/game/effect-terrain.ts +881 -0
- package/src/game/energy.ts +61 -0
- package/src/game/equip-cmp.ts +476 -0
- package/src/game/floor.ts +524 -0
- package/src/game/gear.ts +1352 -0
- package/src/game/harness.ts +270 -0
- package/src/game/history.ts +78 -0
- package/src/game/ignore-cmd.ts +68 -0
- package/src/game/inscription-confirm.ts +115 -0
- package/src/game/known.ts +960 -0
- package/src/game/loop.ts +671 -0
- package/src/game/lore-color.ts +108 -0
- package/src/game/mon-cast.ts +409 -0
- package/src/game/mon-cmd.ts +767 -0
- package/src/game/mon-death.ts +459 -0
- package/src/game/mon-group.ts +368 -0
- package/src/game/mon-list.ts +213 -0
- package/src/game/mon-message.ts +359 -0
- package/src/game/mon-place.ts +1012 -0
- package/src/game/mon-ranged.ts +405 -0
- package/src/game/mon-shape.ts +161 -0
- package/src/game/mon-side.ts +511 -0
- package/src/game/monster-turn.ts +1750 -0
- package/src/game/obj-cmd.ts +1970 -0
- package/src/game/obj-list.ts +302 -0
- package/src/game/object-inspect.ts +162 -0
- package/src/game/pickup.ts +483 -0
- package/src/game/player-path.ts +1434 -0
- package/src/game/player-side.ts +555 -0
- package/src/game/player-turn.ts +852 -0
- package/src/game/project-cast.ts +766 -0
- package/src/game/project-feat.ts +386 -0
- package/src/game/project-monster.ts +407 -0
- package/src/game/project-obj.ts +298 -0
- package/src/game/project-player.ts +236 -0
- package/src/game/quest.ts +248 -0
- package/src/game/ranged-cmd.ts +417 -0
- package/src/game/scheduler.ts +150 -0
- package/src/game/spell-cmd.ts +404 -0
- package/src/game/spoil.ts +562 -0
- package/src/game/steal.ts +169 -0
- package/src/game/take-hit-hooks.ts +152 -0
- package/src/game/target-loop.ts +501 -0
- package/src/game/target.ts +424 -0
- package/src/game/thrust.ts +174 -0
- package/src/game/trap.ts +791 -0
- package/src/game/ui-entry.ts +2075 -0
- package/src/game/wizard.ts +1760 -0
- package/src/game/world.ts +786 -0
- package/src/gen/cave.ts +2858 -0
- package/src/gen/gen-monster.ts +592 -0
- package/src/gen/generate.ts +523 -0
- package/src/gen/room.ts +2213 -0
- package/src/gen/util.ts +1958 -0
- package/src/generated/dun-profiles.ts +30 -0
- package/src/generated/effects.ts +241 -0
- package/src/generated/elements.ts +62 -0
- package/src/generated/equip-slots.ts +36 -0
- package/src/generated/history-types.ts +34 -0
- package/src/generated/ignore-types.ts +66 -0
- package/src/generated/index.ts +33 -0
- package/src/generated/kind-flags.ts +44 -0
- package/src/generated/message.ts +320 -0
- package/src/generated/mon-message.ts +138 -0
- package/src/generated/mon-race-flags.ts +182 -0
- package/src/generated/mon-spells.ts +198 -0
- package/src/generated/mon-temp-flags.ts +34 -0
- package/src/generated/mon-timed.ts +34 -0
- package/src/generated/object-flags.ts +95 -0
- package/src/generated/object-modifiers.ts +43 -0
- package/src/generated/options.ts +104 -0
- package/src/generated/origins.ts +64 -0
- package/src/generated/parser-errors.ts +140 -0
- package/src/generated/player-flags.ts +48 -0
- package/src/generated/player-timed.ts +118 -0
- package/src/generated/projections.ts +103 -0
- package/src/generated/randart-properties.ts +202 -0
- package/src/generated/room-flags.ts +21 -0
- package/src/generated/rooms.ts +50 -0
- package/src/generated/square-flags.ts +56 -0
- package/src/generated/stats.ts +22 -0
- package/src/generated/terrain-flags.ts +76 -0
- package/src/generated/terrain.ts +62 -0
- package/src/generated/trap-flags.ts +42 -0
- package/src/generated/tvals.ts +84 -0
- package/src/generated/ui-entry-renderers.ts +24 -0
- package/src/guard.ts +70 -0
- package/src/host/args.ts +334 -0
- package/src/host/bridge.ts +193 -0
- package/src/host/index.ts +18 -0
- package/src/host/io.ts +239 -0
- package/src/host/memory.ts +134 -0
- package/src/host/raw.ts +190 -0
- package/src/index.ts +250 -0
- package/src/loc.ts +157 -0
- package/src/mod/hooks.ts +278 -0
- package/src/mod/ids.ts +390 -0
- package/src/mod/registry-host.ts +258 -0
- package/src/mod/save-blocks.ts +787 -0
- package/src/mod/vocabulary.ts +0 -0
- package/src/mon/bind.ts +899 -0
- package/src/mon/desc.ts +212 -0
- package/src/mon/knowledge-groups.ts +164 -0
- package/src/mon/lore-describe.ts +1414 -0
- package/src/mon/lore.ts +306 -0
- package/src/mon/make.ts +422 -0
- package/src/mon/monster.ts +161 -0
- package/src/mon/predicate.ts +220 -0
- package/src/mon/project-mon.ts +855 -0
- package/src/mon/spell.ts +418 -0
- package/src/mon/steal.ts +246 -0
- package/src/mon/summon.ts +145 -0
- package/src/mon/take-hit.ts +195 -0
- package/src/mon/timed.ts +300 -0
- package/src/mon/types.ts +286 -0
- package/src/msg.ts +146 -0
- package/src/obj/artifact-fake.ts +63 -0
- package/src/obj/artifact-known.ts +69 -0
- package/src/obj/bind.ts +1345 -0
- package/src/obj/chest.ts +249 -0
- package/src/obj/desc.ts +699 -0
- package/src/obj/effects-info.ts +349 -0
- package/src/obj/flavor.ts +256 -0
- package/src/obj/ignore.ts +387 -0
- package/src/obj/knowledge.ts +1577 -0
- package/src/obj/known-object.ts +718 -0
- package/src/obj/make.ts +1367 -0
- package/src/obj/object-info.ts +1737 -0
- package/src/obj/object.ts +1296 -0
- package/src/obj/power.ts +674 -0
- package/src/obj/randart-build.ts +1705 -0
- package/src/obj/randart-data.ts +1344 -0
- package/src/obj/randart.ts +552 -0
- package/src/obj/randname.ts +128 -0
- package/src/obj/recharge.ts +62 -0
- package/src/obj/types.ts +559 -0
- package/src/obj/value.ts +215 -0
- package/src/player/abilities.ts +142 -0
- package/src/player/best-digger.ts +118 -0
- package/src/player/bind.ts +1021 -0
- package/src/player/birth.ts +794 -0
- package/src/player/calcs.ts +1522 -0
- package/src/player/combat-regen.ts +33 -0
- package/src/player/exp.ts +275 -0
- package/src/player/history.ts +211 -0
- package/src/player/options.ts +244 -0
- package/src/player/player.ts +356 -0
- package/src/player/shape-lore.ts +250 -0
- package/src/player/spell.ts +627 -0
- package/src/player/take-hit.ts +173 -0
- package/src/player/timed.ts +482 -0
- package/src/player/types.ts +415 -0
- package/src/rational.ts +388 -0
- package/src/rng.ts +476 -0
- package/src/save/buffer.ts +287 -0
- package/src/save/compress.ts +132 -0
- package/src/save/description.ts +70 -0
- package/src/save/integrity.ts +133 -0
- package/src/score/display.ts +125 -0
- package/src/score/score.ts +341 -0
- package/src/score/types.ts +104 -0
- package/src/session/boot.ts +338 -0
- package/src/session/game.ts +3712 -0
- package/src/session/save.ts +2074 -0
- package/src/sound/engine.ts +375 -0
- package/src/sound/index.ts +13 -0
- package/src/sound/sound-prefs-data.ts +173 -0
- package/src/sound/types.ts +68 -0
- package/src/store/bind.ts +145 -0
- package/src/store/price.ts +97 -0
- package/src/store/store-cmd.ts +73 -0
- package/src/store/store.ts +723 -0
- package/src/store/transact.ts +644 -0
- package/src/store/types.ts +110 -0
- package/src/version.ts +26 -0
- package/src/visuals/engine.ts +444 -0
- package/src/visuals/glyph-table.ts +191 -0
- package/src/visuals/grafmode-data.ts +90 -0
- package/src/visuals/grafmode.ts +123 -0
- package/src/visuals/index.ts +19 -0
- package/src/visuals/map-text.ts +152 -0
- package/src/visuals/pref-expr.ts +182 -0
- package/src/visuals/prefs.ts +981 -0
- package/src/visuals/tile-prefs.ts +183 -0
- package/src/world/chunk.ts +531 -0
- package/src/world/feature.ts +215 -0
- package/src/world/flow.ts +128 -0
- package/src/world/project.ts +687 -0
- package/src/world/projection.ts +228 -0
- package/src/world/scatter.ts +72 -0
- package/src/world/trap.ts +155 -0
- package/src/world/view.ts +513 -0
- package/src/z-queue.ts +300 -0
package/src/gen/util.ts
ADDED
|
@@ -0,0 +1,1958 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dungeon generation utilities, ported from reference/src/gen-util.c and the
|
|
3
|
+
* gen-room.c geometry helpers (Angband 4.2.6), plus the dun_data-style
|
|
4
|
+
* bookkeeping structure from generate.h and the low-level monster/object
|
|
5
|
+
* placement wiring.
|
|
6
|
+
*
|
|
7
|
+
* DIVERGENCES BY DESIGN (ledgered in parity/ledger/gen-framework.yaml):
|
|
8
|
+
* - The upstream Chunk stores objects and traps as pointer piles on each
|
|
9
|
+
* square; this port's Chunk only stores a monster index and no object or
|
|
10
|
+
* trap handles (those domains attach later via world integration). During
|
|
11
|
+
* generation we therefore track placed objects, placed monsters, and trap
|
|
12
|
+
* grids on the Gen context and mirror monster occupancy into the Chunk's
|
|
13
|
+
* mon array so square_isempty / square_canputitem behave exactly as
|
|
14
|
+
* upstream for placement decisions.
|
|
15
|
+
* - place_trap only records the grid (no trap object is created; the trap
|
|
16
|
+
* domain is not ported).
|
|
17
|
+
* - Monster group/escort spawning (mon-make.c place_new_monster /
|
|
18
|
+
* place_friends / place_new_monster_group) is ported; group indices are
|
|
19
|
+
* allocated from a per-generation counter and recorded on each monster's
|
|
20
|
+
* group_info, and the live GameState rebuilds its group structures from
|
|
21
|
+
* them at start (the savefile-loading path of monster_group_assign).
|
|
22
|
+
* Unique cur_num tracking is kept level-local so a unique appears at most
|
|
23
|
+
* once per level without mutating the shared registry. The shared count is
|
|
24
|
+
* established once at the populate boundary by countMonsterRaces; see the
|
|
25
|
+
* note at the placement site below for why it must not also be bumped here.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { FEAT, ORIGIN, RF, SQUARE } from "../generated/index.js";
|
|
29
|
+
import type { Loc } from "../loc.js";
|
|
30
|
+
import {
|
|
31
|
+
DDGRID,
|
|
32
|
+
DDGRID_DDD,
|
|
33
|
+
distance,
|
|
34
|
+
loc,
|
|
35
|
+
locDiff,
|
|
36
|
+
locEq,
|
|
37
|
+
locSum,
|
|
38
|
+
} from "../loc.js";
|
|
39
|
+
import type { Rng } from "../rng.js";
|
|
40
|
+
import type { Constants } from "../constants.js";
|
|
41
|
+
import type { Chunk } from "../world/chunk.js";
|
|
42
|
+
import {
|
|
43
|
+
featIsBright,
|
|
44
|
+
featIsFloor,
|
|
45
|
+
featIsPassable,
|
|
46
|
+
featIsSmooth,
|
|
47
|
+
featIsTrapHolding,
|
|
48
|
+
} from "../world/chunk.js";
|
|
49
|
+
import type { TrapKind } from "../world/trap.js";
|
|
50
|
+
import { pickTrapKind } from "../game/trap.js";
|
|
51
|
+
import { GET_ANGLE_TO_GRID } from "../world/project.js";
|
|
52
|
+
import type { FeatureRegistry } from "../world/feature.js";
|
|
53
|
+
import type { GameObject } from "../obj/object.js";
|
|
54
|
+
import type { MakeDeps, MakeObjectRating } from "../obj/make.js";
|
|
55
|
+
import { makeGold, makeObject } from "../obj/make.js";
|
|
56
|
+
import type { Monster, MonsterGroupInfo } from "../mon/monster.js";
|
|
57
|
+
import { createMonster, type MonAllocTable } from "../mon/make.js";
|
|
58
|
+
import { createMimickedObject } from "../game/mon-place.js";
|
|
59
|
+
import { createDrop } from "../game/mon-death.js";
|
|
60
|
+
import type { LoreStore } from "../mon/lore.js";
|
|
61
|
+
import type { MonsterRace } from "../mon/types.js";
|
|
62
|
+
import type { ResolvedPit } from "./gen-monster.js";
|
|
63
|
+
import { MON_GROUP } from "../mon/types.js";
|
|
64
|
+
import { scatterExt } from "../world/scatter.js";
|
|
65
|
+
|
|
66
|
+
/* ------------------------------------------------------------------ *
|
|
67
|
+
* Keypad direction helpers (z-type.h / cave.c next_grid).
|
|
68
|
+
* ------------------------------------------------------------------ */
|
|
69
|
+
|
|
70
|
+
export const DIR_NONE = 5;
|
|
71
|
+
export const DIR_N = 8;
|
|
72
|
+
export const DIR_S = 2;
|
|
73
|
+
export const DIR_E = 6;
|
|
74
|
+
export const DIR_W = 4;
|
|
75
|
+
export const DIR_NE = 9;
|
|
76
|
+
export const DIR_NW = 7;
|
|
77
|
+
export const DIR_SE = 3;
|
|
78
|
+
export const DIR_SW = 1;
|
|
79
|
+
|
|
80
|
+
/** next_grid: the neighbour of grid in keypad direction dir. */
|
|
81
|
+
export function nextGrid(grid: Loc, dir: number): Loc {
|
|
82
|
+
const d = DDGRID[dir] as Loc;
|
|
83
|
+
return loc(grid.x + d.x, grid.y + d.y);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** grid_to_i / i_to_grid (index <-> location in a width-w area). */
|
|
87
|
+
export function gridToI(grid: Loc, w: number): number {
|
|
88
|
+
return grid.y * w + grid.x;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function iToGrid(i: number, w: number): Loc {
|
|
92
|
+
return loc(i % w, Math.trunc(i / w));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** shuffle: Knuth shuffle, faithful RNG order. */
|
|
96
|
+
export function shuffle(rng: Rng, arr: number[], n: number): void {
|
|
97
|
+
for (let i = 0; i < n; i++) {
|
|
98
|
+
const j = rng.randint0(n - i) + i;
|
|
99
|
+
const k = arr[j] as number;
|
|
100
|
+
arr[j] = arr[i] as number;
|
|
101
|
+
arr[i] = k;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ------------------------------------------------------------------ *
|
|
106
|
+
* dun_data bookkeeping (generate.h struct dun_data).
|
|
107
|
+
* ------------------------------------------------------------------ */
|
|
108
|
+
|
|
109
|
+
/** A connection to an adjacent level (persistent-level stairs). */
|
|
110
|
+
export interface Connector {
|
|
111
|
+
grid: Loc;
|
|
112
|
+
feat: number;
|
|
113
|
+
/** SQUARE_SIZE bytes copied by save.c:1205-1211 for persistent levels. */
|
|
114
|
+
info?: number[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The mutable state a level builder threads through room allocation,
|
|
119
|
+
* tunneling and stair placement. One per generation attempt.
|
|
120
|
+
*/
|
|
121
|
+
export class Dun {
|
|
122
|
+
/** Centres of placed rooms (index is the room number). */
|
|
123
|
+
readonly cent: Loc[] = [];
|
|
124
|
+
centN = 0;
|
|
125
|
+
|
|
126
|
+
/** Marked entrance points, per room, plus a reverse lookup by grid. */
|
|
127
|
+
readonly ent: Loc[][] = [];
|
|
128
|
+
readonly entN: number[] = [];
|
|
129
|
+
/** ent2room[y * width + x] = room index, or -1. */
|
|
130
|
+
ent2room: Int32Array = new Int32Array(0);
|
|
131
|
+
|
|
132
|
+
/** Candidate door / wall-piercing / tunnel grids for the current tunnel. */
|
|
133
|
+
readonly door: Loc[] = [];
|
|
134
|
+
doorN = 0;
|
|
135
|
+
readonly wall: Loc[] = [];
|
|
136
|
+
wallN = 0;
|
|
137
|
+
readonly tunn: Loc[] = [];
|
|
138
|
+
tunnN = 0;
|
|
139
|
+
|
|
140
|
+
/** Block grid dimensions and counts. */
|
|
141
|
+
blockHgt = 1;
|
|
142
|
+
blockWid = 1;
|
|
143
|
+
rowBlocks = 0;
|
|
144
|
+
colBlocks = 0;
|
|
145
|
+
/** room_map[by][bx] = block reserved. */
|
|
146
|
+
roomMap: boolean[][] = [];
|
|
147
|
+
|
|
148
|
+
pitNum = 0;
|
|
149
|
+
quest = false;
|
|
150
|
+
persist = false;
|
|
151
|
+
|
|
152
|
+
/** Persistent-level connection info (empty for non-persistent levels). */
|
|
153
|
+
join: Connector[] = [];
|
|
154
|
+
oneOffAbove: Connector[] = [];
|
|
155
|
+
oneOffBelow: Connector[] = [];
|
|
156
|
+
currJoin: Connector | null = null;
|
|
157
|
+
nstairRoom = 0;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* dun->profile->name (set once per generation attempt, generate.c L1157).
|
|
161
|
+
* Read by help_greater_vault (gen-room.c L3099), which rejects a further 2/3
|
|
162
|
+
* of greater-vault attempts on any profile that is not "classic". Assigned by
|
|
163
|
+
* makeGen (gen/cave.ts) alongside profileTun/profileStr; "" in bare
|
|
164
|
+
* unit-test Gen contexts, which behaves like any other non-classic profile.
|
|
165
|
+
*/
|
|
166
|
+
profileName = "";
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Whether an adjacent persistent level already exists above/below this one
|
|
170
|
+
* (gen-chunk.c:147 chunk_find_adjacent). Only consulted under `persist`, by
|
|
171
|
+
* handle_level_stairs (gen-cave.c:959-966): when the neighbour exists its
|
|
172
|
+
* staircase rooms already seed dun.join here, so alloc_stairs is skipped for
|
|
173
|
+
* that direction. Off by default, leaving the non-persistent path unchanged. */
|
|
174
|
+
hasAdjacentAbove = false;
|
|
175
|
+
hasAdjacentBelow = false;
|
|
176
|
+
|
|
177
|
+
constructor(private readonly constants: Constants) {}
|
|
178
|
+
|
|
179
|
+
get levelRoomMax(): number {
|
|
180
|
+
return this.constants.levelRoomMax;
|
|
181
|
+
}
|
|
182
|
+
get levelDoorMax(): number {
|
|
183
|
+
return this.constants.levelDoorMax;
|
|
184
|
+
}
|
|
185
|
+
get wallPierceMax(): number {
|
|
186
|
+
return this.constants.wallPierceMax;
|
|
187
|
+
}
|
|
188
|
+
get tunnGridMax(): number {
|
|
189
|
+
return this.constants.tunnGridMax;
|
|
190
|
+
}
|
|
191
|
+
get levelPitMax(): number {
|
|
192
|
+
return this.constants.levelPitMax;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** reset_entrance_data: clear per-room entrances and the reverse lookup. */
|
|
196
|
+
resetEntranceData(c: Chunk): void {
|
|
197
|
+
for (let i = 0; i < this.levelRoomMax; i++) {
|
|
198
|
+
this.entN[i] = 0;
|
|
199
|
+
this.ent[i] = [];
|
|
200
|
+
}
|
|
201
|
+
this.ent2room = new Int32Array(c.height * c.width).fill(-1);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* ------------------------------------------------------------------ *
|
|
206
|
+
* Object generation dependencies.
|
|
207
|
+
* ------------------------------------------------------------------ */
|
|
208
|
+
|
|
209
|
+
/** Monster placement dependencies. */
|
|
210
|
+
export interface MonPlaceDeps {
|
|
211
|
+
table: MonAllocTable;
|
|
212
|
+
/**
|
|
213
|
+
* Resolved pit profiles (set_pit_type / mon_pit_hook), when themed pit,
|
|
214
|
+
* nest and chamber generation is wired. Absent for bare unit-test contexts;
|
|
215
|
+
* builders that need theming bail (empty room) when it is missing.
|
|
216
|
+
*/
|
|
217
|
+
pits?: ResolvedPit[];
|
|
218
|
+
/**
|
|
219
|
+
* The shared lore store, for mon_create_drop's unique theft reduction
|
|
220
|
+
* (mon-make.c L778). Threaded by the session so a regenerated unique that was
|
|
221
|
+
* stolen from keeps its reduced drop count; absent (standalone bootLevel /
|
|
222
|
+
* unit tests) => thefts treated as 0, faithful for a never-stolen-from unique.
|
|
223
|
+
*/
|
|
224
|
+
lore?: LoreStore;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Tunnel parameters read by build_tunnel (cave_profile.tun). */
|
|
228
|
+
export interface TunnelParams {
|
|
229
|
+
rnd: number;
|
|
230
|
+
chg: number;
|
|
231
|
+
con: number;
|
|
232
|
+
pen: number;
|
|
233
|
+
jct: number;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Streamer parameters read by build_streamer (cave_profile.str). */
|
|
237
|
+
export interface StreamerParams {
|
|
238
|
+
den: number;
|
|
239
|
+
rng: number;
|
|
240
|
+
mag: number;
|
|
241
|
+
mc: number;
|
|
242
|
+
qua: number;
|
|
243
|
+
qc: number;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const ZERO_TUNNEL: TunnelParams = { rnd: 0, chg: 0, con: 0, pen: 0, jct: 0 };
|
|
247
|
+
const ZERO_STREAMER: StreamerParams = { den: 0, rng: 0, mag: 0, mc: 0, qua: 0, qc: 0 };
|
|
248
|
+
|
|
249
|
+
export interface PlacedObject {
|
|
250
|
+
grid: Loc;
|
|
251
|
+
obj: GameObject;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* A trap chosen at generation time (place_trap, trap.c:356): the grid plus the
|
|
256
|
+
* pick_trap-selected kind index and the randcalc-rolled power. The live level
|
|
257
|
+
* populate path instantiates these directly (game/trap.ts installTrap) so the
|
|
258
|
+
* pick / power RNG draws are spent during generation, matching upstream's draw
|
|
259
|
+
* order, instead of being re-rolled at populate time.
|
|
260
|
+
*/
|
|
261
|
+
export interface GenTrap {
|
|
262
|
+
grid: Loc;
|
|
263
|
+
tidx: number;
|
|
264
|
+
power: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface PlacedMonster {
|
|
268
|
+
grid: Loc;
|
|
269
|
+
mon: Monster;
|
|
270
|
+
index: number;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface PitTelemetry {
|
|
274
|
+
attempts: { pit: number; nest: number };
|
|
275
|
+
selected: { pit: Record<string, number>; nest: Record<string, number> };
|
|
276
|
+
empty: { pit: number; nest: number };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The generation context: the chunk under construction plus the RNG, feature
|
|
281
|
+
* registry, constants, dun bookkeeping, and the placement side-tables the
|
|
282
|
+
* upstream Chunk stores directly. Passed to every builder and placement
|
|
283
|
+
* helper.
|
|
284
|
+
*/
|
|
285
|
+
export class Gen {
|
|
286
|
+
readonly objects: PlacedObject[] = [];
|
|
287
|
+
readonly monsters: PlacedMonster[] = [];
|
|
288
|
+
/** Optional RNG-neutral diagnostics for the S-3 pit residual. */
|
|
289
|
+
readonly pitTelemetry: PitTelemetry = {
|
|
290
|
+
attempts: { pit: 0, nest: 0 },
|
|
291
|
+
selected: { pit: {}, nest: {} },
|
|
292
|
+
empty: { pit: 0, nest: 0 },
|
|
293
|
+
};
|
|
294
|
+
/** grid index -> square holds a generated object. */
|
|
295
|
+
readonly objOccupied = new Set<number>();
|
|
296
|
+
/** grid index -> square holds a trap (player trap for gen purposes). */
|
|
297
|
+
readonly trapGrids = new Set<number>();
|
|
298
|
+
/**
|
|
299
|
+
* Traps whose kind and power were chosen at generation time (place_trap).
|
|
300
|
+
* Populated only when trapKinds are threaded in; the populate path prefers
|
|
301
|
+
* these to trapGrids so the pick / power draws are not spent twice.
|
|
302
|
+
*/
|
|
303
|
+
readonly traps: GenTrap[] = [];
|
|
304
|
+
/** Doors rolled locked at generation (grid + 1d7 lock power). */
|
|
305
|
+
readonly lockedDoors: Array<{ grid: Loc; power: number }> = [];
|
|
306
|
+
/**
|
|
307
|
+
* Stair connectors of the finished level (generate.c:1203-1214 chunk->join):
|
|
308
|
+
* every staircase grid + its feature. A persistent-level dungeon feeds the
|
|
309
|
+
* NEXT level's get_join_info from these so up/down stairs line up across
|
|
310
|
+
* depths. Populated by generateLevel; consumed only when persistent levels
|
|
311
|
+
* are wired (gap 9.4).
|
|
312
|
+
*/
|
|
313
|
+
readonly joins: Connector[] = [];
|
|
314
|
+
/** ridx of uniques already placed on this level. */
|
|
315
|
+
private readonly placedUniques = new Set<number>();
|
|
316
|
+
private monCounter = 0;
|
|
317
|
+
private groupCounter = 0;
|
|
318
|
+
/** The player start, set by the cave builder via new_player_spot. */
|
|
319
|
+
playerSpot: Loc | null = null;
|
|
320
|
+
/**
|
|
321
|
+
* p->upkeep->light_level (gen-cave.c:1594-1596): a builder asking the level to
|
|
322
|
+
* be revealed on arrival. Only labyrinth_gen sets it, for a "known" labyrinth;
|
|
323
|
+
* cave_generate consumes it with `wiz_light(chunk, p, false)` and clears it
|
|
324
|
+
* (generate.c:1255-1258). Because `chunk` is not yet `cave` at that point,
|
|
325
|
+
* that call reduces to a pure SQUARE_GLOW pass (square_memorize /
|
|
326
|
+
* square_know_pile / square_forget all short-circuit on `c != cave`).
|
|
327
|
+
*/
|
|
328
|
+
lightLevel = false;
|
|
329
|
+
/**
|
|
330
|
+
* msg() for the handful of generation-time messages upstream prints to the
|
|
331
|
+
* player: new_player_spot's placement failure (gen-util.c:422) is UNgated -
|
|
332
|
+
* unlike the cheat_room restart narration - so it must reach a real player.
|
|
333
|
+
* Set by the cave builder from CaveBuildContext; absent in bare unit-test Gen
|
|
334
|
+
* contexts, which then generate silently.
|
|
335
|
+
*/
|
|
336
|
+
msg?: (text: string) => void;
|
|
337
|
+
/** Current tunnel/streamer parameters (set by the cave builder). */
|
|
338
|
+
profileTun: TunnelParams = ZERO_TUNNEL;
|
|
339
|
+
profileStr: StreamerParams = ZERO_STREAMER;
|
|
340
|
+
|
|
341
|
+
constructor(
|
|
342
|
+
readonly c: Chunk,
|
|
343
|
+
readonly rng: Rng,
|
|
344
|
+
readonly reg: FeatureRegistry,
|
|
345
|
+
readonly constants: Constants,
|
|
346
|
+
readonly dun: Dun,
|
|
347
|
+
/** Object-make dependencies, or null to skip object placement. */
|
|
348
|
+
readonly objDeps: MakeDeps | null,
|
|
349
|
+
/** Monster-placement dependencies, or null to skip monster placement. */
|
|
350
|
+
readonly monDeps: MonPlaceDeps | null,
|
|
351
|
+
/**
|
|
352
|
+
* The trap kind table (trap_info). When present, place_trap picks the kind
|
|
353
|
+
* and rolls the power at generation time (gap 9.2). Live boot always
|
|
354
|
+
* supplies this; null is bare unit-test Gen contexts only (marker-only).
|
|
355
|
+
*/
|
|
356
|
+
readonly trapKinds: readonly TrapKind[] | null = null,
|
|
357
|
+
) {}
|
|
358
|
+
|
|
359
|
+
get depth(): number {
|
|
360
|
+
return this.c.depth;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
private idx(grid: Loc): number {
|
|
364
|
+
return grid.y * this.c.width + grid.x;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** square_istrap-ish: a generated trap occupies this grid. */
|
|
368
|
+
hasTrap(grid: Loc): boolean {
|
|
369
|
+
return this.trapGrids.has(this.idx(grid));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** square_object-ish: a generated object occupies this grid. */
|
|
373
|
+
hasObject(grid: Loc): boolean {
|
|
374
|
+
return this.objOccupied.has(this.idx(grid));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
markTrap(grid: Loc): void {
|
|
378
|
+
this.trapGrids.add(this.idx(grid));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Attach a generated object; mirrors floor_carry + list_object. */
|
|
382
|
+
addObject(grid: Loc, obj: GameObject): void {
|
|
383
|
+
this.objects.push({ grid, obj });
|
|
384
|
+
this.objOccupied.add(this.idx(grid));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Assign a fresh monster index (upstream indices start at 1). */
|
|
388
|
+
nextMonIndex(): number {
|
|
389
|
+
return ++this.monCounter;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* monster_group_index_new for generation: a fresh group index. The live
|
|
394
|
+
* GameState rebuilds its group structures from these at start.
|
|
395
|
+
*/
|
|
396
|
+
nextGroupIndex(): number {
|
|
397
|
+
return ++this.groupCounter;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
attachMonster(grid: Loc, mon: Monster, index: number): void {
|
|
401
|
+
mon.grid = grid;
|
|
402
|
+
mon.midx = index;
|
|
403
|
+
this.c.setMon(grid, index);
|
|
404
|
+
this.monsters.push({ grid, mon, index });
|
|
405
|
+
if (mon.race.flags.has(RF.UNIQUE)) {
|
|
406
|
+
this.placedUniques.add(mon.race.ridx);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
uniqueAlreadyPlaced(race: MonsterRace): boolean {
|
|
411
|
+
return this.placedUniques.has(race.ridx);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* The same test, pre-bound for handing straight to getMonNum. Generation
|
|
416
|
+
* passes this so the allocation table stops offering a unique that is already
|
|
417
|
+
* on the level, which is what C gets for free by bumping race->cur_num at
|
|
418
|
+
* placement time (see the note in placeNewMonsterOne below).
|
|
419
|
+
*/
|
|
420
|
+
readonly uniquePlaced = (race: MonsterRace): boolean =>
|
|
421
|
+
this.placedUniques.has(race.ridx);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/* ------------------------------------------------------------------ *
|
|
425
|
+
* Square predicates that the upstream generation code needs and which are
|
|
426
|
+
* not (or cannot be) on the Chunk because they depend on generated objects
|
|
427
|
+
* and traps.
|
|
428
|
+
* ------------------------------------------------------------------ */
|
|
429
|
+
|
|
430
|
+
/** square_isopen: floor with no monster. */
|
|
431
|
+
export function squareIsOpen(g: Gen, grid: Loc): boolean {
|
|
432
|
+
return g.c.isFloor(grid) && g.c.mon(grid) === 0;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/** square_isempty: open with no object and no player trap. */
|
|
436
|
+
export function squareIsEmpty(g: Gen, grid: Loc): boolean {
|
|
437
|
+
if (!g.c.inBounds(grid)) return false;
|
|
438
|
+
if (g.hasTrap(grid)) return false;
|
|
439
|
+
return squareIsOpen(g, grid) && !g.hasObject(grid);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** square_isarrivable: reachable landing spot. */
|
|
443
|
+
export function squareIsArrivable(g: Gen, grid: Loc): boolean {
|
|
444
|
+
if (g.c.mon(grid) !== 0) return false;
|
|
445
|
+
if (g.hasTrap(grid)) return false;
|
|
446
|
+
if (g.c.isFloor(grid)) return true;
|
|
447
|
+
if (g.c.isStairs(grid)) return true;
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** square_canputitem: object-holding, untrapped, unoccupied. */
|
|
452
|
+
export function squareCanPutItem(g: Gen, grid: Loc): boolean {
|
|
453
|
+
if (!g.c.isObjectHolding(grid)) return false;
|
|
454
|
+
if (g.hasTrap(grid)) return false;
|
|
455
|
+
return !g.hasObject(grid);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/** square_isroom (SQUARE_ROOM flag). */
|
|
459
|
+
export function squareIsRoom(c: Chunk, grid: Loc): boolean {
|
|
460
|
+
return c.sqinfoHas(grid, SQUARE.ROOM);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** square_isvault (SQUARE_VAULT flag). */
|
|
464
|
+
export function squareIsVault(c: Chunk, grid: Loc): boolean {
|
|
465
|
+
return c.sqinfoHas(grid, SQUARE.VAULT);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** square_isno_stairs (SQUARE_NO_STAIRS flag). */
|
|
469
|
+
export function squareIsNoStairs(c: Chunk, grid: Loc): boolean {
|
|
470
|
+
return c.sqinfoHas(grid, SQUARE.NO_STAIRS);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** square_iswall_outer (cave-square.c L514): the SQUARE_WALL_OUTER flag alone. */
|
|
474
|
+
export function squareIswallOuter(c: Chunk, grid: Loc): boolean {
|
|
475
|
+
return c.sqinfoHas(grid, SQUARE.WALL_OUTER);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** square_is_granite_with_flag. */
|
|
479
|
+
export function squareIsGraniteWithFlag(
|
|
480
|
+
c: Chunk,
|
|
481
|
+
grid: Loc,
|
|
482
|
+
flag: number,
|
|
483
|
+
): boolean {
|
|
484
|
+
return c.isGranite(grid) && c.sqinfoHas(grid, flag);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** square_isstrongwall: mineral wall or permanent. */
|
|
488
|
+
export function squareIsStrongWall(c: Chunk, grid: Loc): boolean {
|
|
489
|
+
return c.isMineralWall(grid) || c.isPerm(grid);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** count_neighbors: matches among the (up to 9) neighbours in ddd order. */
|
|
493
|
+
export function countNeighbors(
|
|
494
|
+
c: Chunk,
|
|
495
|
+
grid: Loc,
|
|
496
|
+
test: (c: Chunk, grid: Loc) => boolean,
|
|
497
|
+
under: boolean,
|
|
498
|
+
): number {
|
|
499
|
+
const dlim = under ? 9 : 8;
|
|
500
|
+
let count = 0;
|
|
501
|
+
for (let d = 0; d < dlim; d++) {
|
|
502
|
+
const off = DDGRID_DDD[d] as Loc;
|
|
503
|
+
const g = loc(grid.x + off.x, grid.y + off.y);
|
|
504
|
+
if (!c.inBounds(g)) continue;
|
|
505
|
+
if (test(c, g)) count++;
|
|
506
|
+
}
|
|
507
|
+
return count;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** square_num_walls_adjacent: cardinal wall neighbours. */
|
|
511
|
+
export function squareNumWallsAdjacent(c: Chunk, grid: Loc): number {
|
|
512
|
+
let k = 0;
|
|
513
|
+
for (const dir of [DIR_S, DIR_N, DIR_E, DIR_W]) {
|
|
514
|
+
if (c.isWall(nextGrid(grid, dir))) k++;
|
|
515
|
+
}
|
|
516
|
+
return k;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** square_num_walls_diagonal: diagonal wall neighbours. */
|
|
520
|
+
export function squareNumWallsDiagonal(c: Chunk, grid: Loc): number {
|
|
521
|
+
let k = 0;
|
|
522
|
+
for (const dir of [DIR_SE, DIR_NW, DIR_NE, DIR_SW]) {
|
|
523
|
+
if (c.isWall(nextGrid(grid, dir))) k++;
|
|
524
|
+
}
|
|
525
|
+
return k;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/** square_suits_stairs_well. */
|
|
529
|
+
export function squareSuitsStairsWell(g: Gen, grid: Loc): boolean {
|
|
530
|
+
if (squareIsVault(g.c, grid) || squareIsNoStairs(g.c, grid)) return false;
|
|
531
|
+
return (
|
|
532
|
+
squareNumWallsAdjacent(g.c, grid) === 3 &&
|
|
533
|
+
squareNumWallsDiagonal(g.c, grid) === 4 &&
|
|
534
|
+
squareIsEmpty(g, grid)
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/** square_suits_stairs_ok. */
|
|
539
|
+
export function squareSuitsStairsOk(g: Gen, grid: Loc): boolean {
|
|
540
|
+
if (squareIsVault(g.c, grid) || squareIsNoStairs(g.c, grid)) return false;
|
|
541
|
+
return (
|
|
542
|
+
squareNumWallsAdjacent(g.c, grid) === 2 &&
|
|
543
|
+
squareNumWallsDiagonal(g.c, grid) === 4 &&
|
|
544
|
+
squareIsEmpty(g, grid)
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/* ------------------------------------------------------------------ *
|
|
549
|
+
* Randomised rectangular search (cave_find_init / get_grid / cave_find).
|
|
550
|
+
* ------------------------------------------------------------------ */
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* A left-to-right, top-to-bottom index list drawn in a uniformly random
|
|
554
|
+
* order without replacement, exactly as cave_find_get_grid() does.
|
|
555
|
+
*/
|
|
556
|
+
export class CaveFinder {
|
|
557
|
+
private readonly order: number[];
|
|
558
|
+
private readonly n: number;
|
|
559
|
+
private readonly stride: number;
|
|
560
|
+
private readonly x0: number;
|
|
561
|
+
private readonly y0: number;
|
|
562
|
+
private next = 0;
|
|
563
|
+
|
|
564
|
+
constructor(topLeft: Loc, bottomRight: Loc) {
|
|
565
|
+
const dx = bottomRight.x - topLeft.x;
|
|
566
|
+
const dy = bottomRight.y - topLeft.y;
|
|
567
|
+
this.n = dx < 0 || dy < 0 ? 0 : (dx + 1) * (dy + 1);
|
|
568
|
+
this.stride = dx + 1;
|
|
569
|
+
this.x0 = topLeft.x;
|
|
570
|
+
this.y0 = topLeft.y;
|
|
571
|
+
this.order = new Array<number>(this.n);
|
|
572
|
+
for (let i = 0; i < this.n; i++) this.order[i] = i;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/** cave_find_reset (gen-util.c L187): restart the scan from the first grid. */
|
|
576
|
+
reset(): void {
|
|
577
|
+
this.next = 0;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/** Draw the next random grid, or null when exhausted. */
|
|
581
|
+
get(rng: Rng): Loc | null {
|
|
582
|
+
if (this.next >= this.n) return null;
|
|
583
|
+
const j = rng.randint0(this.n - this.next) + this.next;
|
|
584
|
+
const k = this.order[j] as number;
|
|
585
|
+
this.order[j] = this.order[this.next] as number;
|
|
586
|
+
this.order[this.next] = k;
|
|
587
|
+
this.next++;
|
|
588
|
+
return loc((k % this.stride) + this.x0, Math.trunc(k / this.stride) + this.y0);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/** cave_find_in_range: first grid in the rectangle satisfying pred. */
|
|
593
|
+
export function caveFindInRange(
|
|
594
|
+
c: Chunk,
|
|
595
|
+
rng: Rng,
|
|
596
|
+
topLeft: Loc,
|
|
597
|
+
bottomRight: Loc,
|
|
598
|
+
pred: (c: Chunk, grid: Loc) => boolean,
|
|
599
|
+
): Loc | null {
|
|
600
|
+
const finder = new CaveFinder(topLeft, bottomRight);
|
|
601
|
+
for (;;) {
|
|
602
|
+
const grid = finder.get(rng);
|
|
603
|
+
if (!grid) return null;
|
|
604
|
+
if (pred(c, grid)) return grid;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/** cave_find: first grid in the whole chunk satisfying pred. */
|
|
609
|
+
export function caveFind(
|
|
610
|
+
c: Chunk,
|
|
611
|
+
rng: Rng,
|
|
612
|
+
pred: (c: Chunk, grid: Loc) => boolean,
|
|
613
|
+
): Loc | null {
|
|
614
|
+
return caveFindInRange(c, rng, loc(0, 0), loc(c.width - 1, c.height - 1), pred);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/** find_empty: a random empty square anywhere in the chunk. */
|
|
618
|
+
export function findEmpty(g: Gen): Loc | null {
|
|
619
|
+
return caveFind(g.c, g.rng, (_c, grid) => squareIsEmpty(g, grid));
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** find_nearby_grid: a fully-in-bounds grid within +/- yd, xd of centre. */
|
|
623
|
+
export function findNearbyGrid(
|
|
624
|
+
c: Chunk,
|
|
625
|
+
rng: Rng,
|
|
626
|
+
centre: Loc,
|
|
627
|
+
yd: number,
|
|
628
|
+
xd: number,
|
|
629
|
+
): Loc | null {
|
|
630
|
+
return caveFindInRange(
|
|
631
|
+
c,
|
|
632
|
+
rng,
|
|
633
|
+
loc(centre.x - xd, centre.y - yd),
|
|
634
|
+
loc(centre.x + xd, centre.y + yd),
|
|
635
|
+
(cc, grid) => cc.inBoundsFully(grid),
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* ------------------------------------------------------------------ *
|
|
640
|
+
* Directions (correct_dir / rand_dir).
|
|
641
|
+
* ------------------------------------------------------------------ */
|
|
642
|
+
|
|
643
|
+
function cmp(a: number, b: number): number {
|
|
644
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/** correct_dir: a cardinal step from grid1 toward grid2 (random if diagonal). */
|
|
648
|
+
export function correctDir(rng: Rng, grid1: Loc, grid2: Loc): Loc {
|
|
649
|
+
let ox = cmp(grid2.x, grid1.x);
|
|
650
|
+
let oy = cmp(grid2.y, grid1.y);
|
|
651
|
+
if (ox !== 0 && oy !== 0) {
|
|
652
|
+
if (rng.randint0(100) < 50) oy = 0;
|
|
653
|
+
else ox = 0;
|
|
654
|
+
}
|
|
655
|
+
return loc(ox, oy);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** rand_dir: a random cardinal offset. */
|
|
659
|
+
export function randDir(rng: Rng): Loc {
|
|
660
|
+
return DDGRID_DDD[rng.randint0(4)] as Loc;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/* ------------------------------------------------------------------ *
|
|
664
|
+
* Geometry helpers (gen-room.c fill/draw/mark, set_marked_granite).
|
|
665
|
+
* ------------------------------------------------------------------ */
|
|
666
|
+
|
|
667
|
+
/** generate_room: mark a rectangle as room (and lit, if light). */
|
|
668
|
+
export function generateRoom(
|
|
669
|
+
c: Chunk,
|
|
670
|
+
y1: number,
|
|
671
|
+
x1: number,
|
|
672
|
+
y2: number,
|
|
673
|
+
x2: number,
|
|
674
|
+
light: boolean,
|
|
675
|
+
): void {
|
|
676
|
+
for (let y = y1; y <= y2; y++) {
|
|
677
|
+
for (let x = x1; x <= x2; x++) {
|
|
678
|
+
c.sqinfoOn(loc(x, y), SQUARE.ROOM);
|
|
679
|
+
if (light) c.sqinfoOn(loc(x, y), SQUARE.GLOW);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/** generate_mark: set a sqinfo flag over a rectangle. */
|
|
685
|
+
export function generateMark(
|
|
686
|
+
c: Chunk,
|
|
687
|
+
y1: number,
|
|
688
|
+
x1: number,
|
|
689
|
+
y2: number,
|
|
690
|
+
x2: number,
|
|
691
|
+
flag: number,
|
|
692
|
+
): void {
|
|
693
|
+
for (let y = y1; y <= y2; y++) {
|
|
694
|
+
for (let x = x1; x <= x2; x++) {
|
|
695
|
+
c.sqinfoOn(loc(x, y), flag);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/** fill_rectangle: set a feature over a rectangle, optionally marking. */
|
|
701
|
+
export function fillRectangle(
|
|
702
|
+
c: Chunk,
|
|
703
|
+
y1: number,
|
|
704
|
+
x1: number,
|
|
705
|
+
y2: number,
|
|
706
|
+
x2: number,
|
|
707
|
+
feat: number,
|
|
708
|
+
flag: number,
|
|
709
|
+
): void {
|
|
710
|
+
for (let y = y1; y <= y2; y++) {
|
|
711
|
+
for (let x = x1; x <= x2; x++) c.setFeat(loc(x, y), feat);
|
|
712
|
+
}
|
|
713
|
+
if (flag) generateMark(c, y1, x1, y2, x2, flag);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/** draw_rectangle: set a feature around the border of a rectangle. */
|
|
717
|
+
export function drawRectangle(
|
|
718
|
+
c: Chunk,
|
|
719
|
+
y1: number,
|
|
720
|
+
x1: number,
|
|
721
|
+
y2: number,
|
|
722
|
+
x2: number,
|
|
723
|
+
feat: number,
|
|
724
|
+
flag: number,
|
|
725
|
+
overwritePerm: boolean,
|
|
726
|
+
): void {
|
|
727
|
+
for (let y = y1; y <= y2; y++) {
|
|
728
|
+
if (overwritePerm || !c.isPerm(loc(x1, y))) c.setFeat(loc(x1, y), feat);
|
|
729
|
+
if (overwritePerm || !c.isPerm(loc(x2, y))) c.setFeat(loc(x2, y), feat);
|
|
730
|
+
}
|
|
731
|
+
if (flag) {
|
|
732
|
+
generateMark(c, y1, x1, y2, x1, flag);
|
|
733
|
+
generateMark(c, y1, x2, y2, x2, flag);
|
|
734
|
+
}
|
|
735
|
+
for (let x = x1; x <= x2; x++) {
|
|
736
|
+
if (overwritePerm || !c.isPerm(loc(x, y1))) c.setFeat(loc(x, y1), feat);
|
|
737
|
+
if (overwritePerm || !c.isPerm(loc(x, y2))) c.setFeat(loc(x, y2), feat);
|
|
738
|
+
}
|
|
739
|
+
if (flag) {
|
|
740
|
+
generateMark(c, y1, x1, y1, x2, flag);
|
|
741
|
+
generateMark(c, y2, x1, y2, x2, flag);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function fillXrange(
|
|
746
|
+
c: Chunk,
|
|
747
|
+
y: number,
|
|
748
|
+
x1: number,
|
|
749
|
+
x2: number,
|
|
750
|
+
feat: number,
|
|
751
|
+
flag: number,
|
|
752
|
+
light: boolean,
|
|
753
|
+
): void {
|
|
754
|
+
for (let x = x1; x <= x2; x++) {
|
|
755
|
+
const grid = loc(x, y);
|
|
756
|
+
c.setFeat(grid, feat);
|
|
757
|
+
c.sqinfoOn(grid, SQUARE.ROOM);
|
|
758
|
+
if (flag) c.sqinfoOn(grid, flag);
|
|
759
|
+
if (light) c.sqinfoOn(grid, SQUARE.GLOW);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function fillYrange(
|
|
764
|
+
c: Chunk,
|
|
765
|
+
x: number,
|
|
766
|
+
y1: number,
|
|
767
|
+
y2: number,
|
|
768
|
+
feat: number,
|
|
769
|
+
flag: number,
|
|
770
|
+
light: boolean,
|
|
771
|
+
): void {
|
|
772
|
+
for (let y = y1; y <= y2; y++) {
|
|
773
|
+
const grid = loc(x, y);
|
|
774
|
+
c.setFeat(grid, feat);
|
|
775
|
+
c.sqinfoOn(grid, SQUARE.ROOM);
|
|
776
|
+
if (flag) c.sqinfoOn(grid, flag);
|
|
777
|
+
if (light) c.sqinfoOn(grid, SQUARE.GLOW);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/** fill_circle: a filled disc of a feature (used by circular rooms). */
|
|
782
|
+
export function fillCircle(
|
|
783
|
+
c: Chunk,
|
|
784
|
+
y0: number,
|
|
785
|
+
x0: number,
|
|
786
|
+
radius: number,
|
|
787
|
+
border: number,
|
|
788
|
+
feat: number,
|
|
789
|
+
flag: number,
|
|
790
|
+
light: boolean,
|
|
791
|
+
): void {
|
|
792
|
+
let last = 0;
|
|
793
|
+
let k = radius;
|
|
794
|
+
let r2i2k2 = 0;
|
|
795
|
+
for (let i = 0; i <= radius; i++) {
|
|
796
|
+
let b = border;
|
|
797
|
+
if (border && last > k) b++;
|
|
798
|
+
fillXrange(c, y0 - i, x0 - k - b, x0 + k + b, feat, flag, light);
|
|
799
|
+
fillXrange(c, y0 + i, x0 - k - b, x0 + k + b, feat, flag, light);
|
|
800
|
+
fillYrange(c, x0 - i, y0 - k - b, y0 + k + b, feat, flag, light);
|
|
801
|
+
fillYrange(c, x0 + i, y0 - k - b, y0 + k + b, feat, flag, light);
|
|
802
|
+
last = k;
|
|
803
|
+
if (i < radius) {
|
|
804
|
+
r2i2k2 -= 2 * i + 1;
|
|
805
|
+
for (;;) {
|
|
806
|
+
const adj = 2 * k - 1;
|
|
807
|
+
if (Math.abs(r2i2k2 + adj) >= Math.abs(r2i2k2)) break;
|
|
808
|
+
k--;
|
|
809
|
+
r2i2k2 += adj;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/** generate_plus: fill the cross lines of a rectangle. */
|
|
816
|
+
export function generatePlus(
|
|
817
|
+
c: Chunk,
|
|
818
|
+
y1: number,
|
|
819
|
+
x1: number,
|
|
820
|
+
y2: number,
|
|
821
|
+
x2: number,
|
|
822
|
+
feat: number,
|
|
823
|
+
flag: number,
|
|
824
|
+
): void {
|
|
825
|
+
const y0 = Math.trunc((y1 + y2) / 2);
|
|
826
|
+
const x0 = Math.trunc((x1 + x2) / 2);
|
|
827
|
+
for (let y = y1; y <= y2; y++) c.setFeat(loc(x0, y), feat);
|
|
828
|
+
if (flag) generateMark(c, y1, x0, y2, x0, flag);
|
|
829
|
+
for (let x = x1; x <= x2; x++) c.setFeat(loc(x, y0), feat);
|
|
830
|
+
if (flag) generateMark(c, y0, x1, y0, x2, flag);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/** generate_open: open all four sides of a rectangle. */
|
|
834
|
+
export function generateOpen(
|
|
835
|
+
c: Chunk,
|
|
836
|
+
y1: number,
|
|
837
|
+
x1: number,
|
|
838
|
+
y2: number,
|
|
839
|
+
x2: number,
|
|
840
|
+
feat: number,
|
|
841
|
+
): void {
|
|
842
|
+
const y0 = Math.trunc((y1 + y2) / 2);
|
|
843
|
+
const x0 = Math.trunc((x1 + x2) / 2);
|
|
844
|
+
c.setFeat(loc(x0, y1), feat);
|
|
845
|
+
c.setFeat(loc(x1, y0), feat);
|
|
846
|
+
c.setFeat(loc(x0, y2), feat);
|
|
847
|
+
c.setFeat(loc(x2, y0), feat);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/** generate_hole: open one random side of a rectangle. */
|
|
851
|
+
export function generateHole(
|
|
852
|
+
rng: Rng,
|
|
853
|
+
c: Chunk,
|
|
854
|
+
y1: number,
|
|
855
|
+
x1: number,
|
|
856
|
+
y2: number,
|
|
857
|
+
x2: number,
|
|
858
|
+
feat: number,
|
|
859
|
+
): void {
|
|
860
|
+
const y0 = Math.trunc((y1 + y2) / 2);
|
|
861
|
+
const x0 = Math.trunc((x1 + x2) / 2);
|
|
862
|
+
switch (rng.randint0(4)) {
|
|
863
|
+
case 0:
|
|
864
|
+
c.setFeat(loc(x0, y1), feat);
|
|
865
|
+
break;
|
|
866
|
+
case 1:
|
|
867
|
+
c.setFeat(loc(x1, y0), feat);
|
|
868
|
+
break;
|
|
869
|
+
case 2:
|
|
870
|
+
c.setFeat(loc(x0, y2), feat);
|
|
871
|
+
break;
|
|
872
|
+
case 3:
|
|
873
|
+
c.setFeat(loc(x2, y0), feat);
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/** set_marked_granite: lay granite and optionally mark it. */
|
|
879
|
+
export function setMarkedGranite(c: Chunk, grid: Loc, flag: number): void {
|
|
880
|
+
c.setFeat(grid, FEAT.GRANITE);
|
|
881
|
+
if (flag) generateMark(c, grid.y, grid.x, grid.y, grid.x, flag);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* set_bordering_walls: convert floor grids on the edge of a room to outer
|
|
886
|
+
* walls so no floor is adjacent to a non-floor, non-outer-wall grid.
|
|
887
|
+
*/
|
|
888
|
+
export function setBorderingWalls(
|
|
889
|
+
c: Chunk,
|
|
890
|
+
y1: number,
|
|
891
|
+
x1: number,
|
|
892
|
+
y2: number,
|
|
893
|
+
x2: number,
|
|
894
|
+
): void {
|
|
895
|
+
const ry1 = Math.max(0, y1);
|
|
896
|
+
const ry2 = Math.min(c.height - 1, y2);
|
|
897
|
+
const rx1 = Math.max(0, x1);
|
|
898
|
+
const rx2 = Math.min(c.width - 1, x2);
|
|
899
|
+
const nx = rx2 - rx1 + 1;
|
|
900
|
+
const walls = new Array<boolean>(nx * (ry2 - ry1 + 1)).fill(false);
|
|
901
|
+
|
|
902
|
+
for (let y = ry1; y <= ry2; y++) {
|
|
903
|
+
const adjy1 = Math.max(0, y - 1);
|
|
904
|
+
const adjy2 = Math.min(c.height - 1, y + 1);
|
|
905
|
+
for (let x = rx1; x <= rx2; x++) {
|
|
906
|
+
if (!c.isFloor(loc(x, y))) continue;
|
|
907
|
+
const adjx1 = Math.max(0, x - 1);
|
|
908
|
+
const adjx2 = Math.min(c.width - 1, x + 1);
|
|
909
|
+
if (adjy2 - adjy1 !== 2 || adjx2 - adjx1 !== 2) {
|
|
910
|
+
walls[x - rx1 + nx * (y - ry1)] = true;
|
|
911
|
+
} else {
|
|
912
|
+
let nfloor = 0;
|
|
913
|
+
for (let ay = adjy1; ay <= adjy2; ay++) {
|
|
914
|
+
for (let ax = adjx1; ax <= adjx2; ax++) {
|
|
915
|
+
if (c.isFloor(loc(ax, ay))) nfloor++;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (nfloor !== 9) walls[x - rx1 + nx * (y - ry1)] = true;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
for (let y = ry1; y <= ry2; y++) {
|
|
924
|
+
for (let x = rx1; x <= rx2; x++) {
|
|
925
|
+
if (walls[x - rx1 + nx * (y - ry1)]) {
|
|
926
|
+
setMarkedGranite(c, loc(x, y), SQUARE.WALL_OUTER);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* generate_starburst_room (gen-room.c L569): carve a rounded "starburst" of
|
|
934
|
+
* `feat` inside the rectangle (y1,x1)-(y2,x2). Ported verbatim, including the
|
|
935
|
+
* long/narrow-room subdivision recursion, the per-arc RNG draws, the
|
|
936
|
+
* make-denser randint1 for non-floor passable terrain, and the outer-wall
|
|
937
|
+
* marking pass. RNG draws are reproduced in exact upstream order and count.
|
|
938
|
+
* Used by the town builder (a town-sized FEAT_FLOOR starburst) and available
|
|
939
|
+
* to any builder needing lakes/caverns. Occupancy checks read the Gen (no
|
|
940
|
+
* monsters/objects exist yet during town layout, matching upstream).
|
|
941
|
+
*/
|
|
942
|
+
export function generateStarburstRoom(
|
|
943
|
+
g: Gen,
|
|
944
|
+
y1: number,
|
|
945
|
+
x1: number,
|
|
946
|
+
y2: number,
|
|
947
|
+
x2: number,
|
|
948
|
+
light: boolean,
|
|
949
|
+
feat: number,
|
|
950
|
+
specialOk: boolean,
|
|
951
|
+
): boolean {
|
|
952
|
+
const c = g.c;
|
|
953
|
+
const rng = g.rng;
|
|
954
|
+
const reg = c.features;
|
|
955
|
+
|
|
956
|
+
/* Make certain the room does not cross the dungeon edge. */
|
|
957
|
+
if (!c.inBounds(loc(x1, y1)) || !c.inBounds(loc(x2, y2))) return false;
|
|
958
|
+
/* Robustness -- test sanity of input coordinates. */
|
|
959
|
+
if (y1 + 2 >= y2 || x1 + 2 >= x2) return false;
|
|
960
|
+
|
|
961
|
+
const height = 1 + y2 - y1;
|
|
962
|
+
const width = 1 + x2 - x1;
|
|
963
|
+
|
|
964
|
+
/* Handle long, narrow rooms by dividing them up. */
|
|
965
|
+
if (
|
|
966
|
+
height > Math.trunc((5 * width) / 2) ||
|
|
967
|
+
width > Math.trunc((5 * height) / 2)
|
|
968
|
+
) {
|
|
969
|
+
let tmpAy = y2;
|
|
970
|
+
let tmpAx = x2;
|
|
971
|
+
if (height > width) tmpAy = y1 + Math.trunc((2 * height) / 3);
|
|
972
|
+
else tmpAx = x1 + Math.trunc((2 * width) / 3);
|
|
973
|
+
generateStarburstRoom(g, y1, x1, tmpAy, tmpAx, light, feat, false);
|
|
974
|
+
|
|
975
|
+
let tmpBy = y1;
|
|
976
|
+
let tmpBx = x1;
|
|
977
|
+
if (height > width) tmpBy = y1 + Math.trunc((1 * height) / 3);
|
|
978
|
+
else tmpBx = x1 + Math.trunc((1 * width) / 3);
|
|
979
|
+
generateStarburstRoom(g, tmpBy, tmpBx, y2, x2, light, feat, false);
|
|
980
|
+
|
|
981
|
+
if (featIsFloor(reg, feat)) {
|
|
982
|
+
/* Extend a corridor between the two room centres. */
|
|
983
|
+
for (
|
|
984
|
+
let y = Math.trunc((y1 + tmpAy) / 2);
|
|
985
|
+
y <= Math.trunc((tmpBy + y2) / 2);
|
|
986
|
+
y++
|
|
987
|
+
) {
|
|
988
|
+
for (
|
|
989
|
+
let x = Math.trunc((x1 + tmpAx) / 2);
|
|
990
|
+
x <= Math.trunc((tmpBx + x2) / 2);
|
|
991
|
+
x++
|
|
992
|
+
) {
|
|
993
|
+
c.setFeat(loc(x, y), feat);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
} else {
|
|
997
|
+
/* Otherwise fill any gap between the two starbursts. */
|
|
998
|
+
let tmpCy1: number;
|
|
999
|
+
let tmpCx1: number;
|
|
1000
|
+
let tmpCy2: number;
|
|
1001
|
+
let tmpCx2: number;
|
|
1002
|
+
if (height > width) {
|
|
1003
|
+
tmpCy1 = y1 + Math.trunc((height - width) / 2);
|
|
1004
|
+
tmpCx1 = x1;
|
|
1005
|
+
tmpCy2 = tmpCy1 - Math.trunc((height - width) / 2);
|
|
1006
|
+
tmpCx2 = x2;
|
|
1007
|
+
} else {
|
|
1008
|
+
tmpCy1 = y1;
|
|
1009
|
+
tmpCx1 = x1 + Math.trunc((width - height) / 2);
|
|
1010
|
+
tmpCy2 = y2;
|
|
1011
|
+
tmpCx2 = tmpCx1 + Math.trunc((width - height) / 2);
|
|
1012
|
+
}
|
|
1013
|
+
generateStarburstRoom(g, tmpCy1, tmpCx1, tmpCy2, tmpCx2, light, feat, false);
|
|
1014
|
+
}
|
|
1015
|
+
return true;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/* Get a shrinkage ratio for large rooms, as the table is limited. */
|
|
1019
|
+
let distConv: number;
|
|
1020
|
+
if (width > 44 || height > 44) {
|
|
1021
|
+
if (width > height) distConv = Math.trunc((10 * width) / 44);
|
|
1022
|
+
else distConv = Math.trunc((10 * height) / 44);
|
|
1023
|
+
} else {
|
|
1024
|
+
distConv = 10;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/* arc[i] = [first degree of arc, maximum effect distance in arc]. */
|
|
1028
|
+
const arc: number[][] = [];
|
|
1029
|
+
let arcNum: number;
|
|
1030
|
+
let makeCloverleaf = false;
|
|
1031
|
+
|
|
1032
|
+
if (specialOk && height > 10 && rng.randint0(20) === 0) {
|
|
1033
|
+
arcNum = 12;
|
|
1034
|
+
makeCloverleaf = true;
|
|
1035
|
+
} else {
|
|
1036
|
+
arcNum = 8 + Math.trunc((height * width) / 80);
|
|
1037
|
+
arcNum = arcNum + 3 - rng.randint0(7);
|
|
1038
|
+
if (arcNum < 8) arcNum = 8;
|
|
1039
|
+
if (arcNum > 45) arcNum = 45;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
const y0 = y1 + Math.trunc(height / 2);
|
|
1043
|
+
const x0 = x1 + Math.trunc(width / 2);
|
|
1044
|
+
|
|
1045
|
+
let degreeFirst = 0;
|
|
1046
|
+
for (let i = 0; i < arcNum; i++) {
|
|
1047
|
+
/* Get the first degree for this arc (before advancing degreeFirst). */
|
|
1048
|
+
const arc0 = degreeFirst;
|
|
1049
|
+
|
|
1050
|
+
/* Get a slightly randomized start degree for the next arc. */
|
|
1051
|
+
degreeFirst += Math.trunc((180 + rng.randint0(arcNum)) / arcNum);
|
|
1052
|
+
if (degreeFirst < Math.trunc((180 * (i + 1)) / arcNum)) {
|
|
1053
|
+
degreeFirst = Math.trunc((180 * (i + 1)) / arcNum);
|
|
1054
|
+
}
|
|
1055
|
+
if (degreeFirst > Math.trunc(((180 + arcNum) * (i + 1)) / arcNum)) {
|
|
1056
|
+
degreeFirst = Math.trunc(((180 + arcNum) * (i + 1)) / arcNum);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
const centerOfArc = degreeFirst + arc0;
|
|
1060
|
+
|
|
1061
|
+
let arc1 = 0;
|
|
1062
|
+
if (
|
|
1063
|
+
(centerOfArc > 45 && centerOfArc < 135) ||
|
|
1064
|
+
(centerOfArc > 225 && centerOfArc < 315)
|
|
1065
|
+
) {
|
|
1066
|
+
arc1 = Math.trunc(height / 4) + rng.randint0(Math.trunc((height + 3) / 4));
|
|
1067
|
+
} else if (
|
|
1068
|
+
centerOfArc < 45 ||
|
|
1069
|
+
centerOfArc > 315 ||
|
|
1070
|
+
(centerOfArc < 225 && centerOfArc > 135)
|
|
1071
|
+
) {
|
|
1072
|
+
arc1 = Math.trunc(width / 4) + rng.randint0(Math.trunc((width + 3) / 4));
|
|
1073
|
+
} else if (i !== 0) {
|
|
1074
|
+
if (makeCloverleaf) arc1 = 0;
|
|
1075
|
+
else arc1 = (arc[i - 1] as number[])[1]! + 3 - rng.randint0(7);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/* Keep variability under control. */
|
|
1079
|
+
if (!makeCloverleaf && i !== 0 && i !== arcNum - 1) {
|
|
1080
|
+
const prev = (arc[i - 1] as number[])[1]!;
|
|
1081
|
+
if (featIsSmooth(reg, feat)) {
|
|
1082
|
+
if (arc1 > prev + 2) arc1 = prev + 2;
|
|
1083
|
+
if (arc1 > prev - 2) arc1 = prev - 2;
|
|
1084
|
+
} else {
|
|
1085
|
+
if (arc1 > Math.trunc((3 * (prev + 1)) / 2)) {
|
|
1086
|
+
arc1 = Math.trunc((3 * (prev + 1)) / 2);
|
|
1087
|
+
}
|
|
1088
|
+
if (arc1 < Math.trunc((2 * (prev - 1)) / 3)) {
|
|
1089
|
+
arc1 = Math.trunc((2 * (prev - 1)) / 3);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/* Neaten up the final arc by comparing it to the first. */
|
|
1095
|
+
if (i === arcNum - 1) {
|
|
1096
|
+
const first = (arc[0] as number[])[1]!;
|
|
1097
|
+
if (Math.abs(arc1 - first) > 3) {
|
|
1098
|
+
if (arc1 > first) arc1 -= rng.randint0(arc1 - first);
|
|
1099
|
+
else if (arc1 < first) arc1 += rng.randint0(first - arc1);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
arc[i] = [arc0, arc1];
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/* Precalculate check distance. */
|
|
1107
|
+
const distCheck = Math.trunc((21 * distConv) / 10);
|
|
1108
|
+
|
|
1109
|
+
/* Change grids between (and not including) the edges. */
|
|
1110
|
+
for (let y = y1 + 1; y < y2; y++) {
|
|
1111
|
+
for (let x = x1 + 1; x < x2; x++) {
|
|
1112
|
+
const grid = loc(x, y);
|
|
1113
|
+
|
|
1114
|
+
/* Do not touch vault grids or occupied grids. */
|
|
1115
|
+
if (squareIsVault(c, grid)) continue;
|
|
1116
|
+
if (c.mon(grid) !== 0) continue;
|
|
1117
|
+
if (g.hasObject(grid)) continue;
|
|
1118
|
+
|
|
1119
|
+
const dist = distance(loc(x0, y0), grid);
|
|
1120
|
+
if (dist >= distCheck) continue;
|
|
1121
|
+
|
|
1122
|
+
/* Convert and reorient the grid for table access. */
|
|
1123
|
+
const ny = 20 + Math.trunc((10 * (y - y0)) / distConv);
|
|
1124
|
+
const nx = 20 + Math.trunc((10 * (x - x0)) / distConv);
|
|
1125
|
+
if (ny < 0 || ny > 40 || nx < 0 || nx > 40) continue;
|
|
1126
|
+
|
|
1127
|
+
const degree = (GET_ANGLE_TO_GRID[ny] as readonly number[])[nx]!;
|
|
1128
|
+
|
|
1129
|
+
for (let i = arcNum - 1; i >= 0; i--) {
|
|
1130
|
+
if ((arc[i] as number[])[0]! <= degree) {
|
|
1131
|
+
const maxDist = (arc[i] as number[])[1]!;
|
|
1132
|
+
if (maxDist >= dist) {
|
|
1133
|
+
if (featIsFloor(reg, feat) || !featIsPassable(reg, feat)) {
|
|
1134
|
+
c.setFeat(grid, feat);
|
|
1135
|
+
if (featIsFloor(reg, feat)) c.sqinfoOn(grid, SQUARE.ROOM);
|
|
1136
|
+
else c.sqinfoOff(grid, SQUARE.ROOM);
|
|
1137
|
+
if (light) c.sqinfoOn(grid, SQUARE.GLOW);
|
|
1138
|
+
else if (!featIsBright(reg, c.feat(grid))) {
|
|
1139
|
+
c.sqinfoOff(grid, SQUARE.GLOW);
|
|
1140
|
+
}
|
|
1141
|
+
} else {
|
|
1142
|
+
/* Non-floor passable terrain: place only over floor. */
|
|
1143
|
+
if (featIsSmooth(reg, feat)) {
|
|
1144
|
+
if (c.isFloor(grid)) c.setFeat(grid, feat);
|
|
1145
|
+
} else if (c.isFloor(grid) && rng.randint1(maxDist + 5) >= dist + 5) {
|
|
1146
|
+
c.setFeat(grid, feat);
|
|
1147
|
+
}
|
|
1148
|
+
if (light) c.sqinfoOn(grid, SQUARE.GLOW);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
/* Arc found; end search. */
|
|
1152
|
+
break;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/*
|
|
1159
|
+
* If we placed floors or dungeon granite, all dungeon granite next to
|
|
1160
|
+
* floors becomes outer wall.
|
|
1161
|
+
*/
|
|
1162
|
+
if (featIsFloor(reg, feat) || feat === FEAT.GRANITE) {
|
|
1163
|
+
for (let y = y1 + 1; y < y2; y++) {
|
|
1164
|
+
for (let x = x1 + 1; x < x2; x++) {
|
|
1165
|
+
const grid = loc(x, y);
|
|
1166
|
+
if (!c.isFloor(grid)) continue;
|
|
1167
|
+
for (let d = 0; d < 8; d++) {
|
|
1168
|
+
const g1 = locSum(grid, DDGRID_DDD[d] as Loc);
|
|
1169
|
+
c.sqinfoOn(g1, SQUARE.ROOM);
|
|
1170
|
+
c.sqinfoOn(g1, SQUARE.NO_STAIRS);
|
|
1171
|
+
if (light) c.sqinfoOn(g1, SQUARE.GLOW);
|
|
1172
|
+
if (c.feat(g1) === FEAT.GRANITE) {
|
|
1173
|
+
setMarkedGranite(c, g1, SQUARE.WALL_OUTER);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
return true;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
/* ------------------------------------------------------------------ *
|
|
1184
|
+
* Feature placement (doors, rubble, stairs).
|
|
1185
|
+
* ------------------------------------------------------------------ */
|
|
1186
|
+
|
|
1187
|
+
export function placeRubble(g: Gen, grid: Loc): void {
|
|
1188
|
+
g.c.setFeat(grid, g.rng.oneIn(2) ? FEAT.RUBBLE : FEAT.PASS_RUBBLE);
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
export function placeSecretDoor(c: Chunk, grid: Loc): void {
|
|
1192
|
+
c.setFeat(grid, FEAT.SECRET);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/** place_closed_door: one in four doors is locked to power 1d7. */
|
|
1196
|
+
export function placeClosedDoor(g: Gen, grid: Loc): void {
|
|
1197
|
+
g.c.setFeat(grid, FEAT.CLOSED);
|
|
1198
|
+
/* square_set_door_lock: the lock is a trap on the live cave; record the
|
|
1199
|
+
* rolled power so the game state can place the lock at start. */
|
|
1200
|
+
if (g.rng.oneIn(4)) g.lockedDoors.push({ grid, power: g.rng.randint1(7) });
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
export function placeRandomDoor(g: Gen, grid: Loc): void {
|
|
1204
|
+
const tmp = g.rng.randint0(100);
|
|
1205
|
+
if (tmp < 30) g.c.setFeat(grid, FEAT.OPEN);
|
|
1206
|
+
else if (tmp < 40) g.c.setFeat(grid, FEAT.BROKEN);
|
|
1207
|
+
else placeClosedDoor(g, grid);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* square_player_trap_allowed at generation time (trap.c:255): no existing
|
|
1212
|
+
* trap, no object, and trap-holding terrain.
|
|
1213
|
+
*/
|
|
1214
|
+
function genPlayerTrapAllowed(g: Gen, grid: Loc): boolean {
|
|
1215
|
+
if (g.hasTrap(grid)) return false;
|
|
1216
|
+
if (g.hasObject(grid)) return false;
|
|
1217
|
+
return featIsTrapHolding(g.reg, g.c.feat(grid));
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* place_trap(c, grid, -1, c->depth) at generation time (trap.c:356): pick a
|
|
1222
|
+
* random player trap kind by rarity and roll its power, spending both RNG
|
|
1223
|
+
* draws in the generation stream (gap 9.2). Always records a GenTrap so
|
|
1224
|
+
* populate can materialize without a second draw. When the trap kind table is
|
|
1225
|
+
* not threaded in (bare unit-test Gen contexts only), records a grid marker
|
|
1226
|
+
* alone; the live boot path always supplies trapKinds and populate asserts
|
|
1227
|
+
* every marker has a descriptor.
|
|
1228
|
+
*/
|
|
1229
|
+
export function placeTrap(g: Gen, grid: Loc): void {
|
|
1230
|
+
if (!g.trapKinds) {
|
|
1231
|
+
g.markTrap(grid);
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/* The -1 index means "choose a random player trap", so the terrain must
|
|
1236
|
+
* be trap-allowed (trap.c:361-363). */
|
|
1237
|
+
if (!genPlayerTrapAllowed(g, grid)) return;
|
|
1238
|
+
|
|
1239
|
+
const tidx = pickTrapKind(g.rng, g.trapKinds, g.c.depth, {
|
|
1240
|
+
depth: g.c.depth,
|
|
1241
|
+
maxDepth: g.constants.maxDepth,
|
|
1242
|
+
isQuest: g.dun.quest,
|
|
1243
|
+
persist: g.dun.persist,
|
|
1244
|
+
});
|
|
1245
|
+
if (tidx < 0) return;
|
|
1246
|
+
|
|
1247
|
+
const kind = g.trapKinds[tidx]!;
|
|
1248
|
+
const power = g.rng.randcalc(kind.power, g.c.depth, "randomise");
|
|
1249
|
+
g.markTrap(grid);
|
|
1250
|
+
g.traps.push({ grid, tidx, power });
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/** place_stairs: choose the stair terrain honoring town / max-depth rules. */
|
|
1254
|
+
export function placeStairs(g: Gen, grid: Loc, quest: boolean, feat: number): void {
|
|
1255
|
+
if (!g.c.depth) {
|
|
1256
|
+
g.c.setFeat(grid, FEAT.MORE);
|
|
1257
|
+
} else if (quest || g.c.depth >= g.constants.maxDepth - 1) {
|
|
1258
|
+
g.c.setFeat(grid, FEAT.LESS);
|
|
1259
|
+
} else {
|
|
1260
|
+
g.c.setFeat(grid, feat);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
export function placeRandomStairs(g: Gen, grid: Loc, quest: boolean): void {
|
|
1265
|
+
const feat = g.rng.randint0(100) < 50 ? FEAT.LESS : FEAT.MORE;
|
|
1266
|
+
if (squareCanPutItem(g, grid)) placeStairs(g, grid, quest, feat);
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
/* ------------------------------------------------------------------ *
|
|
1270
|
+
* Object placement (place_object / place_gold), via ./obj.
|
|
1271
|
+
* ------------------------------------------------------------------ */
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* convert_depth_to_origin (obj-util.c L686): clamp a depth to a uint8
|
|
1275
|
+
* origin_depth.
|
|
1276
|
+
*/
|
|
1277
|
+
export function convertDepthToOrigin(depth: number): number {
|
|
1278
|
+
if (depth < 0) return 0;
|
|
1279
|
+
if (depth > 255) return 255;
|
|
1280
|
+
return depth;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/** place_object: make and place an object, if object deps are available. */
|
|
1284
|
+
export function placeObject(
|
|
1285
|
+
g: Gen,
|
|
1286
|
+
grid: Loc,
|
|
1287
|
+
level: number,
|
|
1288
|
+
good: boolean,
|
|
1289
|
+
great: boolean,
|
|
1290
|
+
tval: number,
|
|
1291
|
+
origin: number,
|
|
1292
|
+
): void {
|
|
1293
|
+
if (!g.c.inBounds(grid)) return;
|
|
1294
|
+
if (!squareCanPutItem(g, grid)) return;
|
|
1295
|
+
if (!g.objDeps) return;
|
|
1296
|
+
const rating: MakeObjectRating = { value: 0 };
|
|
1297
|
+
const obj = makeObject(
|
|
1298
|
+
g.rng,
|
|
1299
|
+
g.objDeps,
|
|
1300
|
+
level,
|
|
1301
|
+
good,
|
|
1302
|
+
great,
|
|
1303
|
+
false,
|
|
1304
|
+
tval,
|
|
1305
|
+
g.c.depth,
|
|
1306
|
+
rating,
|
|
1307
|
+
);
|
|
1308
|
+
if (!obj) return;
|
|
1309
|
+
/* gen-util.c L511-512: origin uses c->depth (the chunk depth), not level. */
|
|
1310
|
+
obj.origin = origin;
|
|
1311
|
+
obj.originDepth = convertDepthToOrigin(g.c.depth);
|
|
1312
|
+
g.addObject(grid, obj);
|
|
1313
|
+
|
|
1314
|
+
/* place_object's obj_rating accumulation (gen-util.c L509-540). Draws no
|
|
1315
|
+
* RNG: rating.value is a pure recomputation of make_object's *value. */
|
|
1316
|
+
if (obj.artifact) g.c.goodItem = true;
|
|
1317
|
+
let r = rating.value;
|
|
1318
|
+
if (r > 2_500_000) r = 2_500_000;
|
|
1319
|
+
else if (r < -2_500_000) r = -2_500_000;
|
|
1320
|
+
const scaled = Math.trunc(r / 100);
|
|
1321
|
+
g.c.addToObjRating(scaled * scaled);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/** place_gold: make and place a money object. */
|
|
1325
|
+
export function placeGold(g: Gen, grid: Loc, level: number, origin: number): void {
|
|
1326
|
+
if (!g.c.inBounds(grid)) return;
|
|
1327
|
+
if (!squareCanPutItem(g, grid)) return;
|
|
1328
|
+
if (!g.objDeps) return;
|
|
1329
|
+
const money = makeGold(g.rng, g.objDeps, level, "any");
|
|
1330
|
+
/* gen-util.c L560-561: gold origin_depth uses level, not c->depth. */
|
|
1331
|
+
money.origin = origin;
|
|
1332
|
+
money.originDepth = convertDepthToOrigin(level);
|
|
1333
|
+
g.addObject(grid, money);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/* SET_* and TYP_* constants (generate.h). */
|
|
1337
|
+
export const SET_CORR = 0x01;
|
|
1338
|
+
export const SET_ROOM = 0x02;
|
|
1339
|
+
export const SET_BOTH = 0x03;
|
|
1340
|
+
|
|
1341
|
+
export const TYP_RUBBLE = 0;
|
|
1342
|
+
export const TYP_TRAP = 1;
|
|
1343
|
+
export const TYP_GOLD = 2;
|
|
1344
|
+
export const TYP_OBJECT = 3;
|
|
1345
|
+
export const TYP_GOOD = 4;
|
|
1346
|
+
export const TYP_GREAT = 5;
|
|
1347
|
+
|
|
1348
|
+
/** alloc_object: place one random entity in a corridor/room/either. */
|
|
1349
|
+
export function allocObject(
|
|
1350
|
+
g: Gen,
|
|
1351
|
+
set: number,
|
|
1352
|
+
typ: number,
|
|
1353
|
+
depth: number,
|
|
1354
|
+
origin: number,
|
|
1355
|
+
): boolean {
|
|
1356
|
+
const finder = new CaveFinder(loc(1, 1), loc(g.c.width - 2, g.c.height - 2));
|
|
1357
|
+
for (;;) {
|
|
1358
|
+
const grid = finder.get(g.rng);
|
|
1359
|
+
if (!grid) return false;
|
|
1360
|
+
const inRoom = squareIsRoom(g.c, grid);
|
|
1361
|
+
const matched =
|
|
1362
|
+
(!!(set & SET_CORR) && !inRoom) || (!!(set & SET_ROOM) && inRoom);
|
|
1363
|
+
if (squareIsEmpty(g, grid) && matched) {
|
|
1364
|
+
switch (typ) {
|
|
1365
|
+
case TYP_RUBBLE:
|
|
1366
|
+
placeRubble(g, grid);
|
|
1367
|
+
break;
|
|
1368
|
+
case TYP_TRAP:
|
|
1369
|
+
placeTrap(g, grid);
|
|
1370
|
+
break;
|
|
1371
|
+
case TYP_GOLD:
|
|
1372
|
+
placeGold(g, grid, depth, origin);
|
|
1373
|
+
break;
|
|
1374
|
+
case TYP_OBJECT:
|
|
1375
|
+
placeObject(g, grid, depth, false, false, 0, origin);
|
|
1376
|
+
break;
|
|
1377
|
+
case TYP_GOOD:
|
|
1378
|
+
placeObject(g, grid, depth, true, false, 0, origin);
|
|
1379
|
+
break;
|
|
1380
|
+
case TYP_GREAT:
|
|
1381
|
+
placeObject(g, grid, depth, true, true, 0, origin);
|
|
1382
|
+
break;
|
|
1383
|
+
}
|
|
1384
|
+
return true;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
/** alloc_objects: place num entities, returning the number not placed. */
|
|
1390
|
+
export function allocObjects(
|
|
1391
|
+
g: Gen,
|
|
1392
|
+
set: number,
|
|
1393
|
+
typ: number,
|
|
1394
|
+
num: number,
|
|
1395
|
+
depth: number,
|
|
1396
|
+
origin: number,
|
|
1397
|
+
): number {
|
|
1398
|
+
let missed = 0;
|
|
1399
|
+
for (let k = 0; k < num; k++) {
|
|
1400
|
+
if (!allocObject(g, set, typ, depth, origin)) missed++;
|
|
1401
|
+
}
|
|
1402
|
+
return missed;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/* ------------------------------------------------------------------ *
|
|
1406
|
+
* Stairs (alloc_stairs) and player placement (new_player_spot).
|
|
1407
|
+
* ------------------------------------------------------------------ */
|
|
1408
|
+
|
|
1409
|
+
/** alloc_stairs: place num stairs of a type near walls, honoring minsep. */
|
|
1410
|
+
export function allocStairs(
|
|
1411
|
+
g: Gen,
|
|
1412
|
+
feat: number,
|
|
1413
|
+
num: number,
|
|
1414
|
+
minsep: number,
|
|
1415
|
+
sepany: boolean,
|
|
1416
|
+
avoidList: Connector[],
|
|
1417
|
+
quest: boolean,
|
|
1418
|
+
): void {
|
|
1419
|
+
const c = g.c;
|
|
1420
|
+
const av: Loc[] = [];
|
|
1421
|
+
|
|
1422
|
+
if (minsep > 0) {
|
|
1423
|
+
const tester = (grid: Loc): boolean => {
|
|
1424
|
+
if (sepany) return c.isStairs(grid);
|
|
1425
|
+
return feat === FEAT.MORE ? c.isDownstairs(grid) : c.isUpstairs(grid);
|
|
1426
|
+
};
|
|
1427
|
+
for (let y = 0; y < c.height; y++) {
|
|
1428
|
+
for (let x = 0; x < c.width; x++) {
|
|
1429
|
+
const grid = loc(x, y);
|
|
1430
|
+
if (tester(grid)) av.push(grid);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
for (const avc of avoidList) {
|
|
1434
|
+
if (avc.feat !== feat) av.push(avc.grid);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
const finder = new CaveFinder(loc(1, 1), loc(c.width - 2, c.height - 2));
|
|
1439
|
+
let i = 0;
|
|
1440
|
+
let walls = 3;
|
|
1441
|
+
while (i < num && walls >= 0) {
|
|
1442
|
+
for (;;) {
|
|
1443
|
+
if (i >= num) break;
|
|
1444
|
+
const grid = finder.get(g.rng);
|
|
1445
|
+
if (!grid) break;
|
|
1446
|
+
if (!squareIsEmpty(g, grid) || squareNumWallsAdjacent(c, grid) !== walls) {
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
if (minsep > 0) {
|
|
1450
|
+
let clash = false;
|
|
1451
|
+
for (const a of av) {
|
|
1452
|
+
if (Math.abs(grid.y - a.y) <= minsep && Math.abs(grid.x - a.x) <= minsep) {
|
|
1453
|
+
clash = true;
|
|
1454
|
+
break;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
if (clash) continue;
|
|
1458
|
+
av.push(grid);
|
|
1459
|
+
}
|
|
1460
|
+
placeStairs(g, grid, quest, feat);
|
|
1461
|
+
i++;
|
|
1462
|
+
}
|
|
1463
|
+
if (i < num) {
|
|
1464
|
+
walls--;
|
|
1465
|
+
finder.reset();
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
/** find_start: a good starting location for the player (or stairs). */
|
|
1471
|
+
export function findStart(g: Gen): Loc | null {
|
|
1472
|
+
const finder = new CaveFinder(loc(1, 1), loc(g.c.width - 2, g.c.height - 2));
|
|
1473
|
+
|
|
1474
|
+
let grid = scanFinder(finder, g.rng, (gr) => squareSuitsStairsWell(g, gr));
|
|
1475
|
+
if (grid) return grid;
|
|
1476
|
+
|
|
1477
|
+
finder.reset();
|
|
1478
|
+
grid = scanFinder(finder, g.rng, (gr) => squareSuitsStairsOk(g, gr));
|
|
1479
|
+
if (grid) return grid;
|
|
1480
|
+
|
|
1481
|
+
let walls = 6;
|
|
1482
|
+
while (walls >= 0) {
|
|
1483
|
+
finder.reset();
|
|
1484
|
+
grid = scanFinder(finder, g.rng, (gr) => {
|
|
1485
|
+
if (
|
|
1486
|
+
!squareIsEmpty(g, gr) ||
|
|
1487
|
+
squareIsVault(g.c, gr) ||
|
|
1488
|
+
squareIsNoStairs(g.c, gr)
|
|
1489
|
+
) {
|
|
1490
|
+
return false;
|
|
1491
|
+
}
|
|
1492
|
+
const total =
|
|
1493
|
+
squareNumWallsAdjacent(g.c, gr) + squareNumWallsDiagonal(g.c, gr);
|
|
1494
|
+
return total === walls;
|
|
1495
|
+
});
|
|
1496
|
+
if (grid) return grid;
|
|
1497
|
+
walls--;
|
|
1498
|
+
}
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
function scanFinder(
|
|
1503
|
+
finder: CaveFinder,
|
|
1504
|
+
rng: Rng,
|
|
1505
|
+
pred: (grid: Loc) => boolean,
|
|
1506
|
+
): Loc | null {
|
|
1507
|
+
for (;;) {
|
|
1508
|
+
const grid = finder.get(rng);
|
|
1509
|
+
if (!grid) return null;
|
|
1510
|
+
if (pred(grid)) return grid;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* new_player_spot: choose the player start. Returns the location, or null on
|
|
1516
|
+
* failure. createStair, if given, lays a stair on the start (the
|
|
1517
|
+
* birth_connect_stairs upstream behavior); depends on player state so it is
|
|
1518
|
+
* injected rather than read.
|
|
1519
|
+
*/
|
|
1520
|
+
export function newPlayerSpot(
|
|
1521
|
+
g: Gen,
|
|
1522
|
+
createStair: "down" | "up" | null = null,
|
|
1523
|
+
): Loc | null {
|
|
1524
|
+
const grid = findStart(g);
|
|
1525
|
+
if (!grid) {
|
|
1526
|
+
/* gen-util.c:422. NOT gated on cheat_room - upstream always tells the
|
|
1527
|
+
* player, then dumps the level (the dump is host-io) and re-rolls. */
|
|
1528
|
+
g.msg?.("Failed to place player; please report. Restarting generation.");
|
|
1529
|
+
return null;
|
|
1530
|
+
}
|
|
1531
|
+
if (createStair === "down") g.c.setFeat(grid, FEAT.MORE);
|
|
1532
|
+
else if (createStair === "up") g.c.setFeat(grid, FEAT.LESS);
|
|
1533
|
+
return grid;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
/* ------------------------------------------------------------------ *
|
|
1537
|
+
* NO REACHABILITY PROMISE - deliberately.
|
|
1538
|
+
*
|
|
1539
|
+
* Nothing here guarantees the player can walk to a staircase, because upstream
|
|
1540
|
+
* 4.2.6 does not: alloc_stairs (gen-util.c:629) picks any square_isempty grid
|
|
1541
|
+
* and does not exclude vault interiors, while ensure_connectedness runs with
|
|
1542
|
+
* allow_vault_disconnect = true at five of its six sites (gen-cave.c:1271, 2836,
|
|
1543
|
+
* 3083, 3693, 3953; only 3464 passes false), so a vault the tunneller never
|
|
1544
|
+
* joined can swallow a staircase. Measured on this port: 53 stranded levels in
|
|
1545
|
+
* 520 (10.2%), overwhelmingly the UP stair, because a level gets 3-4 down stairs
|
|
1546
|
+
* against only 1-2 up (gen-cave.c:958). 37 of the 53 had the orphaned stair
|
|
1547
|
+
* inside SQUARE_VAULT.
|
|
1548
|
+
*
|
|
1549
|
+
* This was briefly a core guarantee (owner ruling 2026-07-25) and was withdrawn
|
|
1550
|
+
* the next day once the owner learned the C really does strand floors:
|
|
1551
|
+
*
|
|
1552
|
+
* "We can't fix bugs in the port. Those will belong in the bug fixes mod. I
|
|
1553
|
+
* only said those couldn't exist because I thought that was how the C
|
|
1554
|
+
* version worked. Core must retain all warts of the reference code."
|
|
1555
|
+
*
|
|
1556
|
+
* A mod that wants the guarantee repairs the finished level through the
|
|
1557
|
+
* levelGenerated hook (mod/hooks.ts), which is handed the Gen and every
|
|
1558
|
+
* placement primitive above (placeStairs, squareIsEmpty, squareIsNoStairs,
|
|
1559
|
+
* squareNumWallsAdjacent) - so the repair needs nothing from core that a
|
|
1560
|
+
* third-party level mod would not also need. gen.test.ts' CONTROL test pins the
|
|
1561
|
+
* wart, and fails if the repair is ever moved back in here.
|
|
1562
|
+
* ------------------------------------------------------------------ */
|
|
1563
|
+
|
|
1564
|
+
/* ------------------------------------------------------------------ *
|
|
1565
|
+
* Vault helpers (vault_objects / vault_traps).
|
|
1566
|
+
* ------------------------------------------------------------------ */
|
|
1567
|
+
|
|
1568
|
+
export function vaultObjects(g: Gen, grid: Loc, depth: number, num: number): void {
|
|
1569
|
+
for (; num > 0; num--) {
|
|
1570
|
+
for (let i = 0; i < 11; i++) {
|
|
1571
|
+
const near = findNearbyGrid(g.c, g.rng, grid, 2, 3);
|
|
1572
|
+
if (!near) continue;
|
|
1573
|
+
if (!squareCanPutItem(g, near)) continue;
|
|
1574
|
+
/* vault_objects (gen-util.c L839/L841): objects SPECIAL, gold VAULT. */
|
|
1575
|
+
if (g.rng.randint0(100) < 75) placeObject(g, near, depth, false, false, 0, ORIGIN.SPECIAL);
|
|
1576
|
+
else placeGold(g, near, depth, ORIGIN.VAULT);
|
|
1577
|
+
break;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
export function vaultTraps(
|
|
1583
|
+
g: Gen,
|
|
1584
|
+
grid: Loc,
|
|
1585
|
+
yd: number,
|
|
1586
|
+
xd: number,
|
|
1587
|
+
num: number,
|
|
1588
|
+
): void {
|
|
1589
|
+
for (let i = 0; i < num; i++) {
|
|
1590
|
+
for (let tries = 0; tries <= 5; tries++) {
|
|
1591
|
+
const near = findNearbyGrid(g.c, g.rng, grid, yd, xd);
|
|
1592
|
+
if (!near) continue;
|
|
1593
|
+
if (!squareIsEmpty(g, near)) continue;
|
|
1594
|
+
placeTrap(g, near);
|
|
1595
|
+
break;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
/* ------------------------------------------------------------------ *
|
|
1601
|
+
* Monster placement (mon-make placement half + gen-monster helpers).
|
|
1602
|
+
*
|
|
1603
|
+
* The place_new_monster family (one monster, same-race groups, friends and
|
|
1604
|
+
* base-template escorts) is ported. Pit/nest monster theming (mon_restrict)
|
|
1605
|
+
* is still simplified to any depth-appropriate monster; placement RNG order
|
|
1606
|
+
* therefore diverges from upstream where theming would have restricted the
|
|
1607
|
+
* table, and structural invariants plus per-seed determinism are asserted
|
|
1608
|
+
* instead.
|
|
1609
|
+
* ------------------------------------------------------------------ */
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* place_new_monster_one, reduced to the generation-time subset: build the
|
|
1613
|
+
* monster and attach it if the grid is free. The live-cave concerns (drops,
|
|
1614
|
+
* update_mon) attach with their subsystems; object-mimic creation IS wired
|
|
1615
|
+
* here (see below).
|
|
1616
|
+
*/
|
|
1617
|
+
function placeNewMonsterOne(
|
|
1618
|
+
g: Gen,
|
|
1619
|
+
grid: Loc,
|
|
1620
|
+
race: MonsterRace,
|
|
1621
|
+
sleep: boolean,
|
|
1622
|
+
info: MonsterGroupInfo,
|
|
1623
|
+
origin: number = ORIGIN.DROP,
|
|
1624
|
+
): boolean {
|
|
1625
|
+
if (!g.c.inBounds(grid) || !squareIsEmpty(g, grid)) return false;
|
|
1626
|
+
if (g.uniqueAlreadyPlaced(race)) return false;
|
|
1627
|
+
|
|
1628
|
+
/* Add to level feeling (mon-make.c place_new_monster_one L1112-1126).
|
|
1629
|
+
* Draws no RNG. */
|
|
1630
|
+
g.c.addToMonsterRating(race.level * race.level);
|
|
1631
|
+
if (race.level > g.c.depth) {
|
|
1632
|
+
g.c.addToMonsterRating((race.level - g.c.depth) * race.level * race.level);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
const mon = createMonster(g.rng, race, {
|
|
1636
|
+
sleep,
|
|
1637
|
+
moveEnergy: g.constants.moveEnergy,
|
|
1638
|
+
groupIndex: info.index,
|
|
1639
|
+
groupRole: info.role,
|
|
1640
|
+
});
|
|
1641
|
+
g.attachMonster(grid, mon, g.nextMonIndex());
|
|
1642
|
+
|
|
1643
|
+
/* C bumps race->cur_num here (mon-make.c L1040-1041), and deliberately we do
|
|
1644
|
+
* NOT. C places monsters straight into the live cave, so that increment is
|
|
1645
|
+
* the only one; the port generates into a detached Gen and establishes the
|
|
1646
|
+
* shared count once at the populate boundary (countMonsterRaces, from the
|
|
1647
|
+
* level-change path). Incrementing here as well double-counts every monster
|
|
1648
|
+
* on a fresh level, and since wipe_mon_list decrements only once per live
|
|
1649
|
+
* monster on the way out, every descent leaks: a unique that reaches
|
|
1650
|
+
* cur_num >= max_num is refused by get_mon_num (mon-make.c L257-258) for the
|
|
1651
|
+
* rest of the game. The observable effect C gets from the early increment is
|
|
1652
|
+
* that get_mon_num stops OFFERING a placed unique, and that is reproduced
|
|
1653
|
+
* exactly by passing the level-local placed set to getMonNum instead.
|
|
1654
|
+
* Asserted by "cur_num tracks the live monster count" in session/game.test.ts. */
|
|
1655
|
+
|
|
1656
|
+
/* Create the monster's drop, if any (mon-make.c place_monster L1044-1046):
|
|
1657
|
+
* generation placement is the twin of place_new_monster_one -> place_monster,
|
|
1658
|
+
* which draws mon_create_drop here (before mon_create_mimicked_object) when
|
|
1659
|
+
* origin != 0. Every generation placement passes a nonzero origin, so the
|
|
1660
|
+
* gate reduces to having object-make deps. The generated held pile rides on
|
|
1661
|
+
* the Monster object through populateFromLevel into the live cave, where
|
|
1662
|
+
* monster_death later drops it. thefts come from the shared lore store when
|
|
1663
|
+
* the session threads it (g.monDeps.lore); absent, a never-stolen-from 0. */
|
|
1664
|
+
if (g.objDeps && origin !== ORIGIN.NONE) {
|
|
1665
|
+
createDrop(
|
|
1666
|
+
{
|
|
1667
|
+
rng: g.rng,
|
|
1668
|
+
depth: g.c.depth,
|
|
1669
|
+
makeDeps: g.objDeps,
|
|
1670
|
+
lore: g.monDeps?.lore ?? null,
|
|
1671
|
+
},
|
|
1672
|
+
mon,
|
|
1673
|
+
origin,
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
/* Make mimics start mimicking (mon-make.c place_monster L1048-1051): the
|
|
1678
|
+
* generation placement path is the twin of place_new_monster_one ->
|
|
1679
|
+
* place_monster, so the mimic object is created here, just after
|
|
1680
|
+
* mon_create_drop. Every vanilla mimic race carries no drops, so
|
|
1681
|
+
* mon_create_drop above draws zero RNG for them - the mimic object's draws
|
|
1682
|
+
* therefore land at the same generation-RNG position as upstream. Upstream's
|
|
1683
|
+
* `origin` gate is implicit: generation placement always passes a nonzero
|
|
1684
|
+
* origin (ORIGIN_DROP), so the gate reduces to a nonempty mimic_kinds. The
|
|
1685
|
+
* object is parked on the Gen side-table (no live floor yet); session/game.ts
|
|
1686
|
+
* populateFromLevel re-carries it via floor_carry and installs the monster
|
|
1687
|
+
* with its mimicked_obj link, the generation midx matching the live midx it
|
|
1688
|
+
* is re-assigned. Inert unless the generation supplies object-make deps. */
|
|
1689
|
+
if (g.objDeps && race.mimicKinds.length > 0) {
|
|
1690
|
+
createMimickedObject(
|
|
1691
|
+
{
|
|
1692
|
+
depth: g.c.depth,
|
|
1693
|
+
rng: g.rng,
|
|
1694
|
+
makeDeps: g.objDeps,
|
|
1695
|
+
/* floor_carry during generation: the mimic monster sits on an empty
|
|
1696
|
+
* floor grid (squareIsEmpty required no object), so the object parks
|
|
1697
|
+
* with no stacking. Fails only on a non-object-holding grid, exactly
|
|
1698
|
+
* as floor_carry's square_isobject_holding gate. */
|
|
1699
|
+
carry: (cgrid, obj) => {
|
|
1700
|
+
if (!g.c.isObjectHolding(cgrid)) return false;
|
|
1701
|
+
g.addObject(cgrid, obj);
|
|
1702
|
+
return true;
|
|
1703
|
+
},
|
|
1704
|
+
},
|
|
1705
|
+
mon,
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
return true;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* place_new_monster_group: puddle up to `total` monsters of one race around
|
|
1713
|
+
* grid, breadth first over the 8 neighbours of each placed monster.
|
|
1714
|
+
*/
|
|
1715
|
+
function placeNewMonsterGroup(
|
|
1716
|
+
g: Gen,
|
|
1717
|
+
grid: Loc,
|
|
1718
|
+
race: MonsterRace,
|
|
1719
|
+
sleep: boolean,
|
|
1720
|
+
info: MonsterGroupInfo,
|
|
1721
|
+
total: number,
|
|
1722
|
+
origin: number,
|
|
1723
|
+
): boolean {
|
|
1724
|
+
total = Math.min(total, g.constants.monsterGroupMax);
|
|
1725
|
+
|
|
1726
|
+
/* Start on the monster. */
|
|
1727
|
+
const locList: Loc[] = [grid];
|
|
1728
|
+
|
|
1729
|
+
/* Puddle monsters, breadth first, up to total. */
|
|
1730
|
+
for (let n = 0; n < locList.length && locList.length < total; n++) {
|
|
1731
|
+
for (let i = 0; i < 8 && locList.length < total; i++) {
|
|
1732
|
+
const tryGrid = locSum(locList[n] as Loc, DDGRID_DDD[i] as Loc);
|
|
1733
|
+
|
|
1734
|
+
/* Walls and monsters block flow. */
|
|
1735
|
+
if (!squareIsEmpty(g, tryGrid)) continue;
|
|
1736
|
+
|
|
1737
|
+
if (placeNewMonsterOne(g, tryGrid, race, sleep, info, origin)) {
|
|
1738
|
+
locList.push(tryGrid);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
return true;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
/** place_friends: place a friend or escort race near the original monster. */
|
|
1746
|
+
function placeFriends(
|
|
1747
|
+
g: Gen,
|
|
1748
|
+
grid: Loc,
|
|
1749
|
+
race: MonsterRace,
|
|
1750
|
+
friendsRace: MonsterRace,
|
|
1751
|
+
total: number,
|
|
1752
|
+
sleep: boolean,
|
|
1753
|
+
info: MonsterGroupInfo,
|
|
1754
|
+
origin: number,
|
|
1755
|
+
): boolean {
|
|
1756
|
+
/* Find the difference between current dungeon depth and monster level. */
|
|
1757
|
+
const levelDifference = g.c.depth - friendsRace.level + 5;
|
|
1758
|
+
|
|
1759
|
+
/* Handle unique monsters. */
|
|
1760
|
+
const isUnique = friendsRace.flags.has(RF.UNIQUE);
|
|
1761
|
+
|
|
1762
|
+
/* Make sure the unique hasn't been killed (or placed here) already. */
|
|
1763
|
+
if (isUnique) {
|
|
1764
|
+
if (friendsRace.curNum >= friendsRace.maxNum) return false;
|
|
1765
|
+
if (g.uniqueAlreadyPlaced(friendsRace)) return false;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
/* More than 4 levels OoD, no groups allowed. */
|
|
1769
|
+
if (levelDifference <= 0 && !isUnique) return false;
|
|
1770
|
+
|
|
1771
|
+
/* Reduce group size within 5 levels of natural depth. */
|
|
1772
|
+
if (levelDifference < 10 && !isUnique) {
|
|
1773
|
+
const extraChance = (total * levelDifference) % 10;
|
|
1774
|
+
total = Math.trunc((total * levelDifference) / 10);
|
|
1775
|
+
|
|
1776
|
+
/* Instead of flooring the group value, we use the decimal place
|
|
1777
|
+
* as a chance of an extra monster. */
|
|
1778
|
+
if (g.rng.randint0(10) > extraChance) total += 1;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
if (total > 0) {
|
|
1782
|
+
/* Handle friends same as original monster. */
|
|
1783
|
+
if (race.ridx === friendsRace.ridx) {
|
|
1784
|
+
return placeNewMonsterGroup(g, grid, race, sleep, info, total, origin);
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
/* Find a nearby place to put the other groups. */
|
|
1788
|
+
const spots = scatterExt(
|
|
1789
|
+
g.c,
|
|
1790
|
+
g.rng,
|
|
1791
|
+
1,
|
|
1792
|
+
grid,
|
|
1793
|
+
g.constants.monsterGroupDist,
|
|
1794
|
+
false,
|
|
1795
|
+
(_c, gr) => squareIsOpen(g, gr),
|
|
1796
|
+
);
|
|
1797
|
+
if (spots.length > 0) {
|
|
1798
|
+
const start = spots[0] as Loc;
|
|
1799
|
+
/* Place the monsters. */
|
|
1800
|
+
let success = placeNewMonsterOne(g, start, friendsRace, sleep, info, origin);
|
|
1801
|
+
if (total > 1) {
|
|
1802
|
+
success = placeNewMonsterGroup(
|
|
1803
|
+
g,
|
|
1804
|
+
start,
|
|
1805
|
+
friendsRace,
|
|
1806
|
+
sleep,
|
|
1807
|
+
info,
|
|
1808
|
+
total,
|
|
1809
|
+
origin,
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
return success;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
return false;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* place_new_monster: place a monster of the given race at the given location,
|
|
1821
|
+
* with its friends and escorts when `groupOk` is set. The first monster of a
|
|
1822
|
+
* fresh group is its leader.
|
|
1823
|
+
*/
|
|
1824
|
+
export function placeNewMonster(
|
|
1825
|
+
g: Gen,
|
|
1826
|
+
grid: Loc,
|
|
1827
|
+
race: MonsterRace,
|
|
1828
|
+
sleep: boolean,
|
|
1829
|
+
groupOk: boolean,
|
|
1830
|
+
groupInfo: MonsterGroupInfo,
|
|
1831
|
+
origin: number = ORIGIN.DROP,
|
|
1832
|
+
): boolean {
|
|
1833
|
+
if (!g.monDeps) return false;
|
|
1834
|
+
const info: MonsterGroupInfo = { ...groupInfo };
|
|
1835
|
+
|
|
1836
|
+
/* If we don't have a group index already, make one; our first monster
|
|
1837
|
+
* will be the leader. */
|
|
1838
|
+
if (!info.index) info.index = g.nextGroupIndex();
|
|
1839
|
+
|
|
1840
|
+
/* Place one monster, or fail. */
|
|
1841
|
+
if (!placeNewMonsterOne(g, grid, race, sleep, info, origin)) return false;
|
|
1842
|
+
|
|
1843
|
+
/* We're done unless the group flag is set. */
|
|
1844
|
+
if (!groupOk) return true;
|
|
1845
|
+
|
|
1846
|
+
/* Go through friends flags. */
|
|
1847
|
+
for (const friends of race.friends) {
|
|
1848
|
+
if (g.rng.randint0(100) >= friends.percentChance) continue;
|
|
1849
|
+
|
|
1850
|
+
/* Calculate the base number of monsters to place. */
|
|
1851
|
+
const total = g.rng.damroll(friends.numberDice, friends.numberSide);
|
|
1852
|
+
|
|
1853
|
+
/* Set group role. */
|
|
1854
|
+
info.role = friends.role;
|
|
1855
|
+
|
|
1856
|
+
/* Place them. */
|
|
1857
|
+
if (friends.race) {
|
|
1858
|
+
placeFriends(g, grid, race, friends.race, total, sleep, info, origin);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
/* Go through the friends_base flags. */
|
|
1863
|
+
for (const friendsBase of race.friendsBase) {
|
|
1864
|
+
/* Check if we pass chance for the monster appearing. */
|
|
1865
|
+
if (g.rng.randint0(100) >= friendsBase.percentChance) continue;
|
|
1866
|
+
|
|
1867
|
+
const total = g.rng.damroll(friendsBase.numberDice, friendsBase.numberSide);
|
|
1868
|
+
|
|
1869
|
+
/* Prepare allocation table for the escort base (no uniques). */
|
|
1870
|
+
g.monDeps.table.prep(
|
|
1871
|
+
(r) => r.base === friendsBase.base && !r.flags.has(RF.UNIQUE),
|
|
1872
|
+
);
|
|
1873
|
+
|
|
1874
|
+
/* Pick a random race, then reset the allocation table. */
|
|
1875
|
+
const friendsRace = g.monDeps.table.getMonNum(
|
|
1876
|
+
g.rng,
|
|
1877
|
+
race.level,
|
|
1878
|
+
g.c.depth,
|
|
1879
|
+
g.uniquePlaced,
|
|
1880
|
+
);
|
|
1881
|
+
g.monDeps.table.prep(null);
|
|
1882
|
+
|
|
1883
|
+
/* Handle failure. */
|
|
1884
|
+
if (!friendsRace) break;
|
|
1885
|
+
|
|
1886
|
+
/* Set group role. */
|
|
1887
|
+
info.role = friendsBase.role;
|
|
1888
|
+
|
|
1889
|
+
/* Place them. */
|
|
1890
|
+
placeFriends(g, grid, race, friendsRace, total, sleep, info, origin);
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
return true;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
/** pick_and_place_monster: place an appropriate monster (and group) at grid. */
|
|
1897
|
+
export function pickAndPlaceMonster(
|
|
1898
|
+
g: Gen,
|
|
1899
|
+
grid: Loc,
|
|
1900
|
+
depth: number,
|
|
1901
|
+
sleep: boolean,
|
|
1902
|
+
groupOkay = true,
|
|
1903
|
+
origin: number = ORIGIN.DROP,
|
|
1904
|
+
): boolean {
|
|
1905
|
+
if (!g.monDeps) return false;
|
|
1906
|
+
const race = g.monDeps.table.getMonNum(g.rng, depth, g.c.depth, g.uniquePlaced);
|
|
1907
|
+
if (!race) return false;
|
|
1908
|
+
const info: MonsterGroupInfo = { index: 0, role: MON_GROUP.LEADER };
|
|
1909
|
+
return placeNewMonster(g, grid, race, sleep, groupOkay, info, origin);
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
/** pick_and_place_distant_monster: place one monster far from the player. */
|
|
1913
|
+
export function pickAndPlaceDistantMonster(
|
|
1914
|
+
g: Gen,
|
|
1915
|
+
pgrid: Loc,
|
|
1916
|
+
dis: number,
|
|
1917
|
+
sleep: boolean,
|
|
1918
|
+
depth: number,
|
|
1919
|
+
): boolean {
|
|
1920
|
+
if (!g.monDeps) return false;
|
|
1921
|
+
const c = g.c;
|
|
1922
|
+
let attemptsLeft = 10_000;
|
|
1923
|
+
/* pick_and_place_distant_monster (mon-make.c L1483-1520): the initial
|
|
1924
|
+
* 10,000 is pre-decremented, giving exactly 9,999 location attempts. */
|
|
1925
|
+
while (--attemptsLeft) {
|
|
1926
|
+
const grid = loc(g.rng.randint0(c.width), g.rng.randint0(c.height));
|
|
1927
|
+
if (!squareIsEmpty(g, grid)) continue;
|
|
1928
|
+
if (c.info(grid).has(SQUARE.MON_RESTRICT)) continue;
|
|
1929
|
+
if (distance(grid, pgrid) <= dis) continue;
|
|
1930
|
+
return pickAndPlaceMonster(g, grid, depth, sleep);
|
|
1931
|
+
}
|
|
1932
|
+
return false;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
/** vault_monsters: place num sleeping monsters near a grid. */
|
|
1936
|
+
export function vaultMonsters(g: Gen, grid: Loc, depth: number, num: number): void {
|
|
1937
|
+
if (!g.c.inBounds(grid)) return;
|
|
1938
|
+
for (let k = 0; k < num; k++) {
|
|
1939
|
+
for (let i = 0; i < 9; i++) {
|
|
1940
|
+
const near = scatterExt(g.c, g.rng, 1, grid, 1, true, (cc, gr) =>
|
|
1941
|
+
squareIsEmpty(g, gr),
|
|
1942
|
+
);
|
|
1943
|
+
if (near.length === 0) continue;
|
|
1944
|
+
/* vault_monsters (gen-util.c L914): ORIGIN_DROP_SPECIAL. */
|
|
1945
|
+
pickAndPlaceMonster(g, near[0] as Loc, depth, true, true, ORIGIN.DROP_SPECIAL);
|
|
1946
|
+
break;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
/* spread_monsters lives in gen/gen-monster.ts (the faithful themed port); the
|
|
1952
|
+
* simplified copy that once shadowed it here has been removed (gap 9.8). */
|
|
1953
|
+
|
|
1954
|
+
/* ------------------------------------------------------------------ *
|
|
1955
|
+
* Shared helpers re-exported for builders.
|
|
1956
|
+
* ------------------------------------------------------------------ */
|
|
1957
|
+
|
|
1958
|
+
export { loc, locSum, locDiff, locEq, distance };
|