@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
|
@@ -0,0 +1,1560 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* process_monster and the mon-move.c monster AI, ported from
|
|
3
|
+
* reference/src/mon-move.c (Angband 4.2.6) as faithfully as the ported
|
|
4
|
+
* subset of the world allows.
|
|
5
|
+
*
|
|
6
|
+
* PORTED:
|
|
7
|
+
* - get_move_find_range: min_range / best_range (fear flight distance, the
|
|
8
|
+
* level/health comparison that scares weak monsters, the never-move /
|
|
9
|
+
* never-blow stand-off bonus, turn_range "nearby monsters won't run").
|
|
10
|
+
* - get_move_advance: pass-wall beeline, line-of-sight beeline, then sound
|
|
11
|
+
* (the cave->noise flow heatmap from world/flow) with the cardinal-first
|
|
12
|
+
* 8-direction scan, then scent. This is the flow-following core.
|
|
13
|
+
* - get_move: advance vs. the tracking fallback / random step, the afraid
|
|
14
|
+
* flee branch, get_move_choose_direction (the vertical/horizontal/diagonal
|
|
15
|
+
* preference with the turn-parity tie-break), MFLAG_TRACKING.
|
|
16
|
+
* - monster_turn_should_stagger: RAND_25 / RAND_50 erratic movement and the
|
|
17
|
+
* confusion staggers (CONF_ERRATIC_CHANCE per confusion grade).
|
|
18
|
+
* - monster_turn: the 5-step side_dirs movement loop, the tracking early-out,
|
|
19
|
+
* NEVER_MOVE, attack the player via combat.monMeleeAttack, push past / kill
|
|
20
|
+
* a blocking monster, and the "paralysed by fear" fallback.
|
|
21
|
+
* - process_monster_timed (sleep/wake, timer decrement, hold/stun miss) and
|
|
22
|
+
* monster_check_active.
|
|
23
|
+
*
|
|
24
|
+
* NOW WIRED (was deferred): make_ranged_attack via the state.monsterCast
|
|
25
|
+
* hook, monster_group_rouse before it, and group_monster_tracking in
|
|
26
|
+
* get_move's fallback branch.
|
|
27
|
+
*
|
|
28
|
+
* NOW PORTED (this pass, one coherent RNG-order-preserving change):
|
|
29
|
+
* - Fleeing geometry: get_move_find_safety (the dist_offsets ring scan for a
|
|
30
|
+
* reachable out-of-view grid) and the swerving get_move_flee, wired into the
|
|
31
|
+
* afraid branch of get_move exactly as upstream (find_safety -> flee for a
|
|
32
|
+
* course, else leg it away). Both draw no RNG.
|
|
33
|
+
* - Terrain manipulation in monster_turn_can_move: OPEN_DOOR / BASH_DOOR
|
|
34
|
+
* (with the confused one_in_(3) bash chance, the one_in_(2) open-vs-bash
|
|
35
|
+
* choice, and the locked-door randint0(hp/10) strength test seamed to the
|
|
36
|
+
* trap system) and KILL_WALL / SMASH_WALL (square_smash_wall's per-adjacent
|
|
37
|
+
* granite/quartz/magma survival rolls) / PASS_WALL, plus the confused-move
|
|
38
|
+
* self-stun. The "can move here" predicate stays distinct from "did the
|
|
39
|
+
* terrain action" (the did-something flag that spends the turn).
|
|
40
|
+
* - Reproduction: monster_turn_multiply (the num_repro cap, arena block, the
|
|
41
|
+
* 3x3 neighbour count and the one_in_(k * repro_monster_rate) chance) calling
|
|
42
|
+
* multiply_monster through the state.monsterMultiply hook. Runs before the
|
|
43
|
+
* ranged attack, matching upstream's process_monster order.
|
|
44
|
+
* - Item pickup/crush: monster_turn_grab_objects (TAKE_ITEM copies the floor
|
|
45
|
+
* object into the monster's held pile, KILL_ITEM crushes it; gold, mimics and
|
|
46
|
+
* artifacts are left; draws no RNG).
|
|
47
|
+
* - Aggravation: monster_reduce_sleep consults player OF_AGGRAVATE first and
|
|
48
|
+
* wakes the monster (drawing monster_wake's randint0(100) instead of the
|
|
49
|
+
* notice roll), matching the upstream if/else.
|
|
50
|
+
* - Camouflage/mimic reveal: monster_turn_try_push reveals a camouflaged
|
|
51
|
+
* blocker before it is trampled (mon-move.c L1352), and monster_turn itself
|
|
52
|
+
* reveals a camouflaged mon that did_something on its turn (L1680), both via
|
|
53
|
+
* the injected state.becomeAware hook (game/known.ts becomeAware, installed
|
|
54
|
+
* by session/game.ts). monster_turn_multiply's "reveal a camouflaged child
|
|
55
|
+
* of an already-revealed breeder" (L1002-1011) is ported alongside it in
|
|
56
|
+
* game/mon-place.ts multiplyMonster. Draws no RNG.
|
|
57
|
+
*
|
|
58
|
+
* NOW PORTED (this pass):
|
|
59
|
+
* - Group AI: get_move_bodyguard (a bodyguard stays adjacent to its group
|
|
60
|
+
* leader, wired into the top of get_move_advance) and the RF_GROUP_AI pack
|
|
61
|
+
* ambush branch of get_move (the open-grid count around the player, then
|
|
62
|
+
* get_move_find_hiding - the flow/projectable ring scan that finds a hidden
|
|
63
|
+
* grid to lie in wait). Both draw no RNG.
|
|
64
|
+
* - Damaging terrain (square_isdamaging is feat_is_fiery / lava in 4.2.6, and
|
|
65
|
+
* lava with resist-flag IM_FIRE IS modelled): monster_hates_grid (avoid it in
|
|
66
|
+
* advance/random/find_safety/bodyguard/can_move) and monster_taking_terrain_
|
|
67
|
+
* damage (the get_move terrain-flight branch, the get_move_flee early-out, and
|
|
68
|
+
* the monster_check_active activation). All draw no RNG.
|
|
69
|
+
* - Glyph: monster_turn_attack_glyph (a monster on a warded grid rolls
|
|
70
|
+
* randint1(glyph_hardness) < level to break the ward). Decoy: monster is
|
|
71
|
+
* decoyed -> target the decoy (get_move_advance / get_move), attack-allowed in
|
|
72
|
+
* can_move, and square_destroy_decoy when stepped on (draws no RNG; the decoy
|
|
73
|
+
* is disambiguated from a glyph of warding by cave->decoy since both traps
|
|
74
|
+
* share the GLYPH flag). Web: a webbed monster passes / clears / is stuck by
|
|
75
|
+
* RF_PASS_WEB / RF_CLEAR_WEB / pass-walls (draws no RNG).
|
|
76
|
+
*
|
|
77
|
+
* DEFERRED (ledgered in parity/ledger/game-monster-ai.yaml):
|
|
78
|
+
* - monster_take_terrain_damage (the actual lava damage after the turn, called
|
|
79
|
+
* from process_monster, not monster_turn): needs mon_take_nonplayer_hit
|
|
80
|
+
* (monster_death / delete_monster_idx), which is not ported; only the
|
|
81
|
+
* movement-driving predicate is ported here.
|
|
82
|
+
* - react_to_slay pickup safety, the confused-move / door-burst / glyph-break /
|
|
83
|
+
* decoy-destroy UI messages and disturb, and the remaining monster-lore
|
|
84
|
+
* updates. None of these draw RNG until taken, so the RNG order for the ported
|
|
85
|
+
* paths is unaffected.
|
|
86
|
+
*/
|
|
87
|
+
import { DDD, DDGRID, DDGRID_DDD, SIDE_DIRS, distance, loc, locDiff, locEq, locIsZero, locSum, } from "../loc.js";
|
|
88
|
+
import { FEAT, MFLAG, MON_TMD, MSG, OF, RF, SQUARE, TF, TMD, TRF } from "../generated/index.js";
|
|
89
|
+
import { MON_GROUP } from "../mon/types.js";
|
|
90
|
+
import { monsterBreathes, monsterIsCamouflaged, monsterIsInView, monsterIsObvious, monsterIsUnique, monsterIsVisible, monsterLovesArchery, monsterPassesWalls, } from "../mon/predicate.js";
|
|
91
|
+
import { MDESC, monsterDesc } from "../mon/desc.js";
|
|
92
|
+
import { getLore, loreCountU16, loreCountU8, loreLearnFlagIfVisible, loreUpdate, } from "../mon/lore.js";
|
|
93
|
+
import { monsterRevertShape } from "./mon-shape.js";
|
|
94
|
+
import { monsterCarry } from "../mon/make.js";
|
|
95
|
+
import { monsterWake } from "../mon/take-hit.js";
|
|
96
|
+
import { MON_TMD_FLG_NOMESSAGE, MON_TMD_FLG_NOTIFY, monClearTimed, monDecTimed, monIncTimed, monsterEffectLevel, } from "../mon/timed.js";
|
|
97
|
+
import { formatMonsterMessageByName } from "./mon-message.js";
|
|
98
|
+
import { tvalIsMoney } from "../obj/object.js";
|
|
99
|
+
import { monMeleeAttack } from "../combat/mon-melee.js";
|
|
100
|
+
import { reactToSlay } from "../combat/brand-slay.js";
|
|
101
|
+
import { equipLearnOnDefend } from "../obj/knowledge.js";
|
|
102
|
+
import { updatePlayerObjectKnowledge } from "./known.js";
|
|
103
|
+
import { los, squareIsSeen, squareIsView } from "../world/view.js";
|
|
104
|
+
import { PROJECT, projectPath, projectable } from "../world/project.js";
|
|
105
|
+
import { deleteMonster, monsterSwap, squareIsPlayer, squareMonster, } from "./context.js";
|
|
106
|
+
import { disturb } from "./player-path.js";
|
|
107
|
+
import { floorExcise, floorPile } from "./floor.js";
|
|
108
|
+
import { describeObject } from "./describe.js";
|
|
109
|
+
import { ODESC } from "../obj/desc.js";
|
|
110
|
+
import { squareIsEmptyLive } from "./mon-place.js";
|
|
111
|
+
import { squareIsPlayerTrap, squareIsWarded, squareIsWebbed, squareRemoveAllTraps, squareTrap, } from "./trap.js";
|
|
112
|
+
import { groupMonsterTracking, monsterGroupLeader, monsterGroupRouse, } from "./mon-group.js";
|
|
113
|
+
/** enum monster_stagger. */
|
|
114
|
+
export const STAGGER = {
|
|
115
|
+
NO: 0,
|
|
116
|
+
CONFUSED: 1,
|
|
117
|
+
INNATE: 2,
|
|
118
|
+
};
|
|
119
|
+
/** mon-timed.h CONF_ERRATIC_CHANCE / STUN_MISS_CHANCE. */
|
|
120
|
+
const CONF_ERRATIC_CHANCE = 30;
|
|
121
|
+
const STUN_MISS_CHANCE = 10;
|
|
122
|
+
/** PRIMARY_GROUP index (monster.h). */
|
|
123
|
+
const PRIMARY_GROUP = 0;
|
|
124
|
+
/**
|
|
125
|
+
* dist_offsets_y / dist_offsets_x (cave.c): for each distance d (1..9), the
|
|
126
|
+
* offsets of every grid exactly distance d from a centre, terminated by the
|
|
127
|
+
* (0,0) sentinel. Copied verbatim so get_move_find_safety's ring scan order -
|
|
128
|
+
* and therefore its tie-break (first grid at the maximum distance wins) - match
|
|
129
|
+
* upstream exactly.
|
|
130
|
+
*/
|
|
131
|
+
const D_OFF_Y = [
|
|
132
|
+
[0],
|
|
133
|
+
[-1, -1, -1, 0, 0, 1, 1, 1, 0],
|
|
134
|
+
[-1, -1, -2, -2, -2, 0, 0, 1, 1, 2, 2, 2, 0],
|
|
135
|
+
[-1, -1, -2, -2, -3, -3, -3, 0, 0, 1, 1, 2, 2, 3, 3, 3, 0],
|
|
136
|
+
[
|
|
137
|
+
-1, -1, -2, -2, -3, -3, -3, -3, -4, -4, -4, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4,
|
|
138
|
+
4, 4, 0,
|
|
139
|
+
],
|
|
140
|
+
[
|
|
141
|
+
-1, -1, -2, -2, -3, -3, -4, -4, -4, -4, -5, -5, -5, 0, 0, 1, 1, 2, 2, 3, 3,
|
|
142
|
+
4, 4, 4, 4, 5, 5, 5, 0,
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
-1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -5, -5, -6, -6, -6, 0, 0, 1, 1, 2, 2,
|
|
146
|
+
3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 0,
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
-1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -5, -5, -6, -6, -6, -6, -7, -7, -7,
|
|
150
|
+
0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 0,
|
|
151
|
+
],
|
|
152
|
+
[
|
|
153
|
+
-1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -6, -6, -7, -7, -7, -7, -8,
|
|
154
|
+
-8, -8, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
|
|
155
|
+
0,
|
|
156
|
+
],
|
|
157
|
+
[
|
|
158
|
+
-1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -7, -7, -8, -8, -8,
|
|
159
|
+
-8, -9, -9, -9, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8,
|
|
160
|
+
8, 8, 9, 9, 9, 0,
|
|
161
|
+
],
|
|
162
|
+
];
|
|
163
|
+
const D_OFF_X = [
|
|
164
|
+
[0],
|
|
165
|
+
[-1, 0, 1, -1, 1, -1, 0, 1, 0],
|
|
166
|
+
[-2, 2, -1, 0, 1, -2, 2, -2, 2, -1, 0, 1, 0],
|
|
167
|
+
[-3, 3, -2, 2, -1, 0, 1, -3, 3, -3, 3, -2, 2, -1, 0, 1, 0],
|
|
168
|
+
[
|
|
169
|
+
-4, 4, -3, 3, -2, -3, 2, 3, -1, 0, 1, -4, 4, -4, 4, -3, 3, -2, -3, 2, 3, -1,
|
|
170
|
+
0, 1, 0,
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
-5, 5, -4, 4, -4, 4, -2, -3, 2, 3, -1, 0, 1, -5, 5, -5, 5, -4, 4, -4, 4, -2,
|
|
174
|
+
-3, 2, 3, -1, 0, 1, 0,
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
-6, 6, -5, 5, -5, 5, -4, 4, -2, -3, 2, 3, -1, 0, 1, -6, 6, -6, 6, -5, 5, -5,
|
|
178
|
+
5, -4, 4, -2, -3, 2, 3, -1, 0, 1, 0,
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
-7, 7, -6, 6, -6, 6, -5, 5, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0, 1, -7, 7, -7,
|
|
182
|
+
7, -6, 6, -6, 6, -5, 5, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0, 1, 0,
|
|
183
|
+
],
|
|
184
|
+
[
|
|
185
|
+
-8, 8, -7, 7, -7, 7, -6, 6, -6, 6, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0, 1, -8,
|
|
186
|
+
8, -8, 8, -7, 7, -7, 7, -6, 6, -6, 6, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0, 1,
|
|
187
|
+
0,
|
|
188
|
+
],
|
|
189
|
+
[
|
|
190
|
+
-9, 9, -8, 8, -8, 8, -7, 7, -7, 7, -6, 6, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0,
|
|
191
|
+
1, -9, 9, -9, 9, -8, 8, -8, 8, -7, 7, -7, 7, -6, 6, -4, -5, 4, 5, -2, -3, 2,
|
|
192
|
+
3, -1, 0, 1, 0,
|
|
193
|
+
],
|
|
194
|
+
];
|
|
195
|
+
/** The (0,0)-terminated ring of offsets at each distance d (1..9). */
|
|
196
|
+
const DIST_OFFSETS = D_OFF_Y.map((ys, d) => {
|
|
197
|
+
const xs = D_OFF_X[d];
|
|
198
|
+
const ring = [];
|
|
199
|
+
for (let i = 0; (xs[i] ?? 0) !== 0 || (ys[i] ?? 0) !== 0; i++) {
|
|
200
|
+
ring.push(loc(xs[i], ys[i]));
|
|
201
|
+
}
|
|
202
|
+
return ring;
|
|
203
|
+
});
|
|
204
|
+
function noiseAt(state, grid) {
|
|
205
|
+
return state.chunk.noise[grid.y * state.chunk.width + grid.x] ?? 0;
|
|
206
|
+
}
|
|
207
|
+
function scentAt(state, grid) {
|
|
208
|
+
return state.chunk.scent[grid.y * state.chunk.width + grid.x] ?? 0;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* monster_can_see_player (mon-move.c L92): the monster's grid is in the
|
|
212
|
+
* player's view, and a player covering tracks (TMD_COVERTRACKS) is unseen
|
|
213
|
+
* beyond max_sight / 4.
|
|
214
|
+
*/
|
|
215
|
+
function monsterCanSeePlayer(mon, state) {
|
|
216
|
+
if (!squareIsView(state.chunk, mon.grid))
|
|
217
|
+
return false;
|
|
218
|
+
if ((state.actor.player.timed[TMD.COVERTRACKS] ?? 0) > 0 &&
|
|
219
|
+
mon.cdis > Math.trunc(state.z.maxSight / 4)) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* The PROJECT_SHORT projection range (project.c L370-373): max_range, quartered
|
|
226
|
+
* while the player covers tracks (TMD_COVERTRACKS). The port's projectable takes
|
|
227
|
+
* the range from the caller, so PROJECT.SHORT callers pass this.
|
|
228
|
+
*/
|
|
229
|
+
export function shortRange(state) {
|
|
230
|
+
return (state.actor.player.timed[TMD.COVERTRACKS] ?? 0) > 0
|
|
231
|
+
? Math.trunc(state.z.maxRange / 4)
|
|
232
|
+
: state.z.maxRange;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* monster_near_permwall (mon-move.c L65): whether a PASS_WALL / KILL_WALL
|
|
236
|
+
* monster should use the flow code instead of beelining - the player is out of
|
|
237
|
+
* (short) projection range and the direct PROJECT_ROCK path hits a permanent
|
|
238
|
+
* wall before reaching the player. Draws randint0(99) for the "occasionally
|
|
239
|
+
* flow for a turn anyway" 5% branch, exactly at the upstream stream position.
|
|
240
|
+
*/
|
|
241
|
+
export function monsterNearPermwall(mon, state) {
|
|
242
|
+
const c = state.chunk;
|
|
243
|
+
/* If player is in LOS, there's no need to go around walls. */
|
|
244
|
+
if (projectable(c, mon.grid, state.actor.grid, PROJECT.SHORT, shortRange(state))) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
/* PASS_WALL & KILL_WALL monsters occasionally flow for a turn anyway. */
|
|
248
|
+
if (state.rng.randint0(99) < 5)
|
|
249
|
+
return true;
|
|
250
|
+
/* Find the shortest path. */
|
|
251
|
+
const path = projectPath(c, state.z.maxSight, mon.grid, state.actor.grid, PROJECT.ROCK);
|
|
252
|
+
/* See if we can "see" the player without hitting permanent wall. */
|
|
253
|
+
for (const g of path) {
|
|
254
|
+
if (c.isPerm(g))
|
|
255
|
+
return true;
|
|
256
|
+
if (squareIsPlayer(state, g))
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
/** monster_can_hear: race hearing beats the local noise (minus stealth/3). */
|
|
262
|
+
function monsterCanHear(mon, state) {
|
|
263
|
+
const baseHearing = mon.race.hearing - Math.trunc(state.actor.stealth / 3);
|
|
264
|
+
const n = noiseAt(state, mon.grid);
|
|
265
|
+
if (n === 0)
|
|
266
|
+
return false;
|
|
267
|
+
return baseHearing > n;
|
|
268
|
+
}
|
|
269
|
+
/** monster_can_smell: race smell beats the local scent age. */
|
|
270
|
+
function monsterCanSmell(mon, state) {
|
|
271
|
+
const s = scentAt(state, mon.grid);
|
|
272
|
+
if (s === 0)
|
|
273
|
+
return false;
|
|
274
|
+
return mon.race.smell > s;
|
|
275
|
+
}
|
|
276
|
+
/** compare_monsters: -1 / 0 / 1 by (original) race experience value. */
|
|
277
|
+
function compareMonsters(a, b) {
|
|
278
|
+
const ma = (a.originalRace ?? a.race).mexp;
|
|
279
|
+
const mb = (b.originalRace ?? b.race).mexp;
|
|
280
|
+
if (ma < mb)
|
|
281
|
+
return -1;
|
|
282
|
+
if (ma > mb)
|
|
283
|
+
return 1;
|
|
284
|
+
return 0;
|
|
285
|
+
}
|
|
286
|
+
/** monster_can_kill: trample a weaker, non-unique monster (KILL_BODY). */
|
|
287
|
+
function monsterCanKill(state, mon, grid) {
|
|
288
|
+
const other = squareMonster(state, grid);
|
|
289
|
+
if (!other)
|
|
290
|
+
return true;
|
|
291
|
+
if (monsterIsUnique(other))
|
|
292
|
+
return false;
|
|
293
|
+
return mon.race.flags.has(RF.KILL_BODY) && compareMonsters(mon, other) > 0;
|
|
294
|
+
}
|
|
295
|
+
/** monster_can_move: swap with a weaker monster (MOVE_BODY). */
|
|
296
|
+
function monsterCanMoveInto(state, mon, grid) {
|
|
297
|
+
const other = squareMonster(state, grid);
|
|
298
|
+
if (!other)
|
|
299
|
+
return true;
|
|
300
|
+
return mon.race.flags.has(RF.MOVE_BODY) && compareMonsters(mon, other) > 0;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* square_isdamaging (cave-square.c L730) && the monster lacks the feature's
|
|
304
|
+
* resist_flag: the shared predicate behind monster_hates_grid and
|
|
305
|
+
* monster_taking_terrain_damage. square_isdamaging is feat_is_fiery in 4.2.6
|
|
306
|
+
* (lava only), so this is chunk.isFiery gated by the feature's resistFlag.
|
|
307
|
+
*/
|
|
308
|
+
function damagingTerrainHurts(state, mon, grid) {
|
|
309
|
+
if (!state.chunk.isFiery(grid))
|
|
310
|
+
return false;
|
|
311
|
+
return !mon.race.flags.has(state.chunk.feature(grid).resistFlag);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* monster_hates_grid (mon-move.c L188): damaging terrain the monster can't
|
|
315
|
+
* survive. Draws no RNG.
|
|
316
|
+
*/
|
|
317
|
+
function monsterHatesGrid(state, mon, grid) {
|
|
318
|
+
return damagingTerrainHurts(state, mon, grid);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* monster_taking_terrain_damage (mon-util.c L1347): the monster is standing on
|
|
322
|
+
* damaging terrain it does not resist. Draws no RNG. NOTE: the actual damage
|
|
323
|
+
* application (monster_take_terrain_damage, mon-util.c L1327, called from
|
|
324
|
+
* process_monster after monster_turn) is DEFERRED - it needs mon_take_nonplayer_hit
|
|
325
|
+
* (monster_death / delete_monster_idx), which is not ported yet; this predicate
|
|
326
|
+
* only drives movement (flight / avoidance / activation).
|
|
327
|
+
*/
|
|
328
|
+
function monsterTakingTerrainDamage(state, mon) {
|
|
329
|
+
return damagingTerrainHurts(state, mon, mon.grid);
|
|
330
|
+
}
|
|
331
|
+
/** cave->decoy is set and this grid holds it (square_isdecoyed, cave-square.c L757). */
|
|
332
|
+
function squareIsDecoyed(state, grid) {
|
|
333
|
+
const d = state.decoy;
|
|
334
|
+
return !!d && !locIsZero(d) && locEq(d, grid);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* monster_is_decoyed (mon-predicate.c L308): a live decoy exists and the monster
|
|
338
|
+
* has line of sight to it. Draws no RNG.
|
|
339
|
+
*/
|
|
340
|
+
export function monsterIsDecoyed(mon, state) {
|
|
341
|
+
const d = state.decoy;
|
|
342
|
+
if (!d || locIsZero(d))
|
|
343
|
+
return false;
|
|
344
|
+
return los(state.chunk, mon.grid, d);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* square_remove_all_traps_of_type by trap flag: remove every trap at `grid` that
|
|
348
|
+
* carries `flag` (glyph of warding / web / decoy all being distinguished only by
|
|
349
|
+
* their tidx, which we recover from the first matching trap). Uses the existing
|
|
350
|
+
* trap.ts helpers (squareTrap / squareRemoveAllTraps); draws no RNG.
|
|
351
|
+
*/
|
|
352
|
+
function removeTrapsWithFlag(state, grid, flag) {
|
|
353
|
+
for (const t of squareTrap(state, grid)) {
|
|
354
|
+
if (t.flags.has(flag)) {
|
|
355
|
+
squareRemoveAllTraps(state, grid, t.tidx);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* get_move_find_range (mon-move.c L207): set mon.minRange (flee distance) and
|
|
362
|
+
* mon.bestRange (preferred combat distance) - archers sit back +3, breathers
|
|
363
|
+
* with high innate frequency like point blank, other frequent casters sit back
|
|
364
|
+
* +3 (mon-move.c L287-300).
|
|
365
|
+
*/
|
|
366
|
+
export function getMoveFindRange(mon, state) {
|
|
367
|
+
const p = state.actor.player;
|
|
368
|
+
const fleeRange = state.z.maxSight + state.z.fleeRange;
|
|
369
|
+
if ((mon.mTimed[MON_TMD.FEAR] ?? 0) ||
|
|
370
|
+
mon.race.flags.has(RF.FRIGHTENED)) {
|
|
371
|
+
mon.minRange = fleeRange;
|
|
372
|
+
}
|
|
373
|
+
else if (mon.groupInfo[PRIMARY_GROUP]?.role === MON_GROUP.BODYGUARD) {
|
|
374
|
+
mon.minRange = 1;
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
mon.minRange = 1;
|
|
378
|
+
/* mon-move.c L232: taunt forces close-in movement and returns before
|
|
379
|
+
* level/health range heuristics or preferred-range selection. */
|
|
380
|
+
if ((p.timed[TMD.TAUNT] ?? 0) > 0)
|
|
381
|
+
return;
|
|
382
|
+
const pLev = p.lev;
|
|
383
|
+
const mLev = mon.race.level + (mon.midx & 0x08) + 25;
|
|
384
|
+
if (mLev + 3 < pLev) {
|
|
385
|
+
mon.minRange = fleeRange;
|
|
386
|
+
}
|
|
387
|
+
else if (mLev - 5 < pLev) {
|
|
388
|
+
const pChp = p.chp;
|
|
389
|
+
const pMhp = p.mhp;
|
|
390
|
+
const mChp = mon.hp;
|
|
391
|
+
const mMhp = mon.maxhp;
|
|
392
|
+
const pVal = pLev * pMhp + (pChp << 2);
|
|
393
|
+
const mVal = mLev * mMhp + (mChp << 2);
|
|
394
|
+
/* Strong players scare strong monsters. */
|
|
395
|
+
if (pVal * mMhp > mVal * pMhp)
|
|
396
|
+
mon.minRange = fleeRange;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (mon.minRange < fleeRange) {
|
|
400
|
+
if (mon.race.flags.has(RF.NEVER_MOVE))
|
|
401
|
+
mon.minRange += 3;
|
|
402
|
+
if (mon.race.flags.has(RF.NEVER_BLOW))
|
|
403
|
+
mon.minRange += 3;
|
|
404
|
+
}
|
|
405
|
+
if (!(mon.minRange < fleeRange)) {
|
|
406
|
+
mon.minRange = fleeRange;
|
|
407
|
+
}
|
|
408
|
+
else if (mon.cdis < state.z.turnRange) {
|
|
409
|
+
mon.minRange = 1;
|
|
410
|
+
}
|
|
411
|
+
/* Now find the preferred range (mon-move.c L285-300). */
|
|
412
|
+
mon.bestRange = mon.minRange;
|
|
413
|
+
/* Archers are quite happy at a good distance. */
|
|
414
|
+
if (monsterLovesArchery(mon)) {
|
|
415
|
+
mon.bestRange += 3;
|
|
416
|
+
}
|
|
417
|
+
if (mon.race.freqInnate > 24) {
|
|
418
|
+
/* Breathers like point blank range. */
|
|
419
|
+
if (monsterBreathes(mon) && mon.hp > Math.trunc(mon.maxhp / 2)) {
|
|
420
|
+
mon.bestRange = Math.max(1, mon.bestRange);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
else if (mon.race.freqSpell > 24) {
|
|
424
|
+
/* Other spell casters will sit back and cast. */
|
|
425
|
+
mon.bestRange += 3;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* get_move_bodyguard (mon-move.c L309): a bodyguard stays close to its group
|
|
430
|
+
* leader, but takes a step that is also closer to the player when it can. Sets
|
|
431
|
+
* mon.target.grid and returns true on success. Draws no RNG - the scan order is
|
|
432
|
+
* ddgrid_ddd and the tie-break is upstream's (first closer-to-leader grid, and a
|
|
433
|
+
* grid that is also closer to the player short-circuits the scan).
|
|
434
|
+
*/
|
|
435
|
+
export function getMoveBodyguard(mon, state) {
|
|
436
|
+
const leader = monsterGroupLeader(state, mon);
|
|
437
|
+
if (!leader)
|
|
438
|
+
return false;
|
|
439
|
+
const dist = distance(mon.grid, leader.grid);
|
|
440
|
+
/* If currently adjacent to the leader, we can afford a move. */
|
|
441
|
+
if (dist <= 1)
|
|
442
|
+
return false;
|
|
443
|
+
/* If the leader's too out of sight and far away, save yourself. */
|
|
444
|
+
if (!los(state.chunk, mon.grid, leader.grid) && dist > 10)
|
|
445
|
+
return false;
|
|
446
|
+
let best = loc(0, 0);
|
|
447
|
+
let found = false;
|
|
448
|
+
for (let i = 0; i < 8; i++) {
|
|
449
|
+
const grid = locSum(mon.grid, DDGRID_DDD[i]);
|
|
450
|
+
const newDist = distance(grid, leader.grid);
|
|
451
|
+
const charDist = distance(grid, state.actor.grid);
|
|
452
|
+
if (!state.chunk.inBounds(grid))
|
|
453
|
+
continue;
|
|
454
|
+
/* There's a monster blocking that we can't deal with. */
|
|
455
|
+
if (!monsterCanKill(state, mon, grid) && !monsterCanMoveInto(state, mon, grid)) {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
/* There's damaging terrain. */
|
|
459
|
+
if (monsterHatesGrid(state, mon, grid))
|
|
460
|
+
continue;
|
|
461
|
+
/* Closer to the leader is always better. */
|
|
462
|
+
if (newDist < dist) {
|
|
463
|
+
best = grid;
|
|
464
|
+
found = true;
|
|
465
|
+
/* If there's a grid that's also closer to the player, that wins. */
|
|
466
|
+
if (charDist < mon.cdis)
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (found) {
|
|
471
|
+
mon.target = { grid: best, midx: mon.target.midx };
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* get_move_advance: set mon.target.grid to the grid to move toward and
|
|
478
|
+
* return whether a good advance was found. `track` is set when the target
|
|
479
|
+
* came from sound/scent tracking (a one-step goal).
|
|
480
|
+
*/
|
|
481
|
+
function getMoveAdvance(mon, state, track) {
|
|
482
|
+
const target = monsterIsDecoyed(mon, state) && state.decoy ? state.decoy : state.actor.grid;
|
|
483
|
+
/* Bodyguards are special. */
|
|
484
|
+
if (mon.groupInfo[PRIMARY_GROUP]?.role === MON_GROUP.BODYGUARD) {
|
|
485
|
+
if (getMoveBodyguard(mon, state))
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
/* If the monster can pass through nearby walls, do that (mon-move.c
|
|
489
|
+
* L416): beeline unless a permanent wall blocks the direct path. */
|
|
490
|
+
if (monsterPassesWalls(mon) && !monsterNearPermwall(mon, state)) {
|
|
491
|
+
mon.target = { grid: target, midx: mon.target.midx };
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
/* If the monster can see the player, beeline. */
|
|
495
|
+
if (monsterCanSeePlayer(mon, state)) {
|
|
496
|
+
mon.target = { grid: target, midx: mon.target.midx };
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
const baseHearing = mon.race.hearing - Math.trunc(state.actor.stealth / 3);
|
|
500
|
+
const currentNoise = baseHearing - noiseAt(state, mon.grid);
|
|
501
|
+
let best = null;
|
|
502
|
+
let backup = null;
|
|
503
|
+
/* Try to use sound, cardinal directions first (ddd order). */
|
|
504
|
+
if (monsterCanHear(mon, state)) {
|
|
505
|
+
for (let i = 0; i < 8; i++) {
|
|
506
|
+
const dir = DDGRID_DDD[i];
|
|
507
|
+
const grid = locSum(mon.grid, dir);
|
|
508
|
+
if (!state.chunk.inBounds(grid))
|
|
509
|
+
continue;
|
|
510
|
+
if (noiseAt(state, grid) === 0)
|
|
511
|
+
continue;
|
|
512
|
+
if (!monsterCanKill(state, mon, grid) && !monsterCanMoveInto(state, mon, grid)) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (monsterHatesGrid(state, mon, grid))
|
|
516
|
+
continue;
|
|
517
|
+
const heardNoise = baseHearing - noiseAt(state, grid);
|
|
518
|
+
if (heardNoise > currentNoise) {
|
|
519
|
+
best = grid;
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
else if (heardNoise === currentNoise) {
|
|
523
|
+
backup = grid;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
/* Failing sound, use scent. */
|
|
528
|
+
if (monsterCanSmell(mon, state) && !best) {
|
|
529
|
+
let bestScent = 0;
|
|
530
|
+
for (let i = 0; i < 8; i++) {
|
|
531
|
+
const dir = DDGRID_DDD[i];
|
|
532
|
+
const grid = locSum(mon.grid, dir);
|
|
533
|
+
if (!state.chunk.inBounds(grid))
|
|
534
|
+
continue;
|
|
535
|
+
const smelled = mon.race.smell - scentAt(state, grid);
|
|
536
|
+
if (smelled > bestScent && scentAt(state, grid) !== 0) {
|
|
537
|
+
bestScent = smelled;
|
|
538
|
+
best = grid;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (best) {
|
|
543
|
+
mon.target = { grid: best, midx: mon.target.midx };
|
|
544
|
+
track.value = true;
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
else if (backup) {
|
|
548
|
+
mon.target = { grid: backup, midx: mon.target.midx };
|
|
549
|
+
track.value = true;
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
/** get_move_random: a random passable adjacent step, or (0,0). */
|
|
555
|
+
function getMoveRandom(mon, state) {
|
|
556
|
+
const attempts = [0, 1, 2, 3, 4, 5, 6, 7];
|
|
557
|
+
let nleft = 8;
|
|
558
|
+
while (nleft > 0) {
|
|
559
|
+
const itry = state.rng.randint0(nleft);
|
|
560
|
+
const dir = DDGRID_DDD[attempts[itry]];
|
|
561
|
+
const tryGrid = locSum(mon.grid, dir);
|
|
562
|
+
if (state.chunk.inBounds(tryGrid) &&
|
|
563
|
+
state.chunk.isMonsterWalkable(tryGrid) &&
|
|
564
|
+
!monsterHatesGrid(state, mon, tryGrid)) {
|
|
565
|
+
return dir;
|
|
566
|
+
}
|
|
567
|
+
const tmp = attempts[itry];
|
|
568
|
+
nleft--;
|
|
569
|
+
attempts[itry] = attempts[nleft];
|
|
570
|
+
attempts[nleft] = tmp;
|
|
571
|
+
}
|
|
572
|
+
return loc(0, 0);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* get_move_choose_direction: keypad direction (as a side_dirs row index)
|
|
576
|
+
* from an offset, with the turn-parity tie-break exactly as upstream.
|
|
577
|
+
*/
|
|
578
|
+
export function getMoveChooseDirection(offset, turn) {
|
|
579
|
+
let dir = 0;
|
|
580
|
+
const dx = offset.x;
|
|
581
|
+
const dy = offset.y;
|
|
582
|
+
const ay = Math.abs(dy);
|
|
583
|
+
const ax = Math.abs(dx);
|
|
584
|
+
if (ay > ax * 2) {
|
|
585
|
+
if (dy > 0) {
|
|
586
|
+
dir = 2;
|
|
587
|
+
if (dx > 0 || (dx === 0 && turn % 2 === 0))
|
|
588
|
+
dir += 10;
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
dir = 8;
|
|
592
|
+
if (dx < 0 || (dx === 0 && turn % 2 === 0))
|
|
593
|
+
dir += 10;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
else if (ax > ay * 2) {
|
|
597
|
+
if (dx > 0) {
|
|
598
|
+
dir = 6;
|
|
599
|
+
if (dy < 0 || (dy === 0 && turn % 2 === 0))
|
|
600
|
+
dir += 10;
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
dir = 4;
|
|
604
|
+
if (dy > 0 || (dy === 0 && turn % 2 === 0))
|
|
605
|
+
dir += 10;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
else if (dy > 0) {
|
|
609
|
+
if (dx > 0) {
|
|
610
|
+
dir = 3;
|
|
611
|
+
if (ay < ax || (ay === ax && turn % 2 === 0))
|
|
612
|
+
dir += 10;
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
dir = 1;
|
|
616
|
+
if (ay > ax || (ay === ax && turn % 2 === 0))
|
|
617
|
+
dir += 10;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
if (dx > 0) {
|
|
622
|
+
dir = 9;
|
|
623
|
+
if (ay > ax || (ay === ax && turn % 2 === 0))
|
|
624
|
+
dir += 10;
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
dir = 7;
|
|
628
|
+
if (ay < ax || (ay === ax && turn % 2 === 0))
|
|
629
|
+
dir += 10;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return dir;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* get_move_find_safety (mon-move.c L545): choose a reachable grid the player
|
|
636
|
+
* cannot fire into (out of view) that is as far from the player as possible,
|
|
637
|
+
* spreading outward a distance ring at a time. Sets mon.target.grid and returns
|
|
638
|
+
* true on success. Pure scan - draws no RNG. The dist_offsets ring order fixes
|
|
639
|
+
* the tie-break: the FIRST grid at the maximum player-distance wins.
|
|
640
|
+
*/
|
|
641
|
+
function getMoveFindSafety(mon, state) {
|
|
642
|
+
const c = state.chunk;
|
|
643
|
+
let gdis = 0;
|
|
644
|
+
let best = loc(0, 0);
|
|
645
|
+
for (let d = 1; d < 10; d++) {
|
|
646
|
+
const ring = DIST_OFFSETS[d];
|
|
647
|
+
for (const off of ring) {
|
|
648
|
+
const grid = locSum(mon.grid, off);
|
|
649
|
+
/* Skip illegal / walled locations. */
|
|
650
|
+
if (!c.inBoundsFully(grid))
|
|
651
|
+
continue;
|
|
652
|
+
if (!c.isPassable(grid))
|
|
653
|
+
continue;
|
|
654
|
+
/* Ignore too-distant grids (noise heatmap gate). */
|
|
655
|
+
if (noiseAt(state, grid) > noiseAt(state, mon.grid) + 2 * d)
|
|
656
|
+
continue;
|
|
657
|
+
/* Ignore damaging terrain (DEFERRED: monsterHatesGrid is false). */
|
|
658
|
+
if (monsterHatesGrid(state, mon, grid))
|
|
659
|
+
continue;
|
|
660
|
+
/* Check for absence of shot (more or less). */
|
|
661
|
+
if (!squareIsView(c, grid)) {
|
|
662
|
+
const dis = distance(grid, state.actor.grid);
|
|
663
|
+
if (dis > gdis) {
|
|
664
|
+
best = grid;
|
|
665
|
+
gdis = dis;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (gdis > 0) {
|
|
670
|
+
mon.target = { grid: best, midx: mon.target.midx };
|
|
671
|
+
return true;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return false;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* get_move_flee (mon-move.c L675): provide a swerving course toward the current
|
|
678
|
+
* target (a safe grid) that gives the player a wide berth. Sets mon.target.grid
|
|
679
|
+
* and returns true, or returns false (leaving the target as find_safety set it)
|
|
680
|
+
* when the monster is too far to bother. Diagonals are scanned first. Draws no
|
|
681
|
+
* RNG.
|
|
682
|
+
*/
|
|
683
|
+
function getMoveFlee(mon, state) {
|
|
684
|
+
let best = loc(0, 0);
|
|
685
|
+
let bestScore = -1;
|
|
686
|
+
/* Taking damage from terrain makes moving vital; otherwise the two early-outs
|
|
687
|
+
* apply (player too far, or the monster can neither hear nor smell). */
|
|
688
|
+
if (!monsterTakingTerrainDamage(state, mon)) {
|
|
689
|
+
if (mon.cdis >= mon.bestRange)
|
|
690
|
+
return false;
|
|
691
|
+
if (!monsterCanHear(mon, state) && !monsterCanSmell(mon, state))
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
/* Check nearby grids, diagonals first. */
|
|
695
|
+
for (let i = 7; i >= 0; i--) {
|
|
696
|
+
const grid = locSum(mon.grid, DDGRID_DDD[i]);
|
|
697
|
+
if (!state.chunk.inBounds(grid))
|
|
698
|
+
continue;
|
|
699
|
+
/* Distance of this grid from our target. */
|
|
700
|
+
const dis = distance(grid, mon.target.grid);
|
|
701
|
+
/* Inversely proportional to distance, less the grid's closeness to the
|
|
702
|
+
* player (the noise heatmap). Integer division, as upstream. */
|
|
703
|
+
let score = Math.trunc(5000 / (dis + 3)) - Math.trunc(500 / (noiseAt(state, grid) + 1));
|
|
704
|
+
if (score < 0)
|
|
705
|
+
score = 0;
|
|
706
|
+
if (score < bestScore)
|
|
707
|
+
continue;
|
|
708
|
+
bestScore = score;
|
|
709
|
+
best = grid;
|
|
710
|
+
}
|
|
711
|
+
mon.target = { grid: best, midx: mon.target.midx };
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* get_move_find_hiding (mon-move.c L613): a pack monster looks for a hidden grid
|
|
716
|
+
* (out of the player's view but projectable from the monster) to lie in wait and
|
|
717
|
+
* lure the player into the open. Prefers the closest such grid that is still at
|
|
718
|
+
* least `min` away from the player, spreading outward a distance ring at a time.
|
|
719
|
+
* Sets mon.target.grid and returns true on success. Pure scan - draws no RNG.
|
|
720
|
+
* `gdis` persists across rings (as upstream) but the per-ring success return
|
|
721
|
+
* makes that moot; the dist_offsets ring order fixes the tie-break.
|
|
722
|
+
*/
|
|
723
|
+
export function getMoveFindHiding(mon, state) {
|
|
724
|
+
const c = state.chunk;
|
|
725
|
+
/* square_isempty on the live cave (no player trap / web). */
|
|
726
|
+
const preds = {
|
|
727
|
+
isPlayerTrap: (g) => squareIsPlayerTrap(state, g),
|
|
728
|
+
isWebbed: (g) => squareIsWebbed(state, g),
|
|
729
|
+
isWarded: (g) => squareIsWarded(state, g),
|
|
730
|
+
};
|
|
731
|
+
/* Closest distance to get. */
|
|
732
|
+
const min = Math.trunc((distance(state.actor.grid, mon.grid) * 3) / 4) + 2;
|
|
733
|
+
let gdis = 999;
|
|
734
|
+
for (let d = 1; d < 10; d++) {
|
|
735
|
+
let best = loc(0, 0);
|
|
736
|
+
const ring = DIST_OFFSETS[d];
|
|
737
|
+
for (const off of ring) {
|
|
738
|
+
const grid = locSum(mon.grid, off);
|
|
739
|
+
/* Skip illegal / occupied locations. */
|
|
740
|
+
if (!c.inBoundsFully(grid))
|
|
741
|
+
continue;
|
|
742
|
+
if (!squareIsEmptyLive(state, grid, preds))
|
|
743
|
+
continue;
|
|
744
|
+
/* Check for a hidden, available grid. */
|
|
745
|
+
if (!squareIsView(c, grid) &&
|
|
746
|
+
projectable(c, mon.grid, grid, PROJECT.STOP, state.z.maxRange)) {
|
|
747
|
+
const dis = distance(grid, state.actor.grid);
|
|
748
|
+
if (dis < gdis && dis >= min) {
|
|
749
|
+
best = grid;
|
|
750
|
+
gdis = dis;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
if (gdis < 999) {
|
|
755
|
+
mon.target = { grid: best, midx: mon.target.midx };
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* get_move: decide whether and where the monster wants to step. Returns the
|
|
763
|
+
* side_dirs row index for the movement loop. The RF_GROUP_AI pack-ambush branch
|
|
764
|
+
* (get_move_find_hiding) and the group-surround branch (mon-move.c L932, which
|
|
765
|
+
* draws randint0(8)) are both ported, so the RNG draw order matches upstream.
|
|
766
|
+
*/
|
|
767
|
+
export function getMove(mon, state) {
|
|
768
|
+
const fleeRange = state.z.maxSight + state.z.fleeRange;
|
|
769
|
+
const target = monsterIsDecoyed(mon, state) && state.decoy ? state.decoy : state.actor.grid;
|
|
770
|
+
const groupAi = mon.race.flags.has(RF.GROUP_AI);
|
|
771
|
+
let grid = loc(0, 0);
|
|
772
|
+
const track = { value: false };
|
|
773
|
+
let done = false;
|
|
774
|
+
getMoveFindRange(mon, state);
|
|
775
|
+
if (getMoveAdvance(mon, state, track)) {
|
|
776
|
+
grid = locDiff(mon.target.grid, mon.grid);
|
|
777
|
+
mon.mflag.on(MFLAG.TRACKING);
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
/* Try to follow someone who knows where they're going. */
|
|
781
|
+
const tracker = groupMonsterTracking(state, mon);
|
|
782
|
+
if (tracker && los(state.chunk, mon.grid, tracker.grid)) {
|
|
783
|
+
grid = locDiff(tracker.grid, mon.grid);
|
|
784
|
+
/* No longer tracking. */
|
|
785
|
+
mon.mflag.off(MFLAG.TRACKING);
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
if (mon.mflag.has(MFLAG.TRACKING)) {
|
|
789
|
+
/* Keep heading to the most recent goal. */
|
|
790
|
+
grid = locDiff(mon.target.grid, mon.grid);
|
|
791
|
+
}
|
|
792
|
+
if (locIsZero(grid)) {
|
|
793
|
+
/* Try a random move and no longer track. */
|
|
794
|
+
grid = getMoveRandom(mon, state);
|
|
795
|
+
mon.mflag.off(MFLAG.TRACKING);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/* Monster is taking damage from terrain - flee to safety (draws no RNG:
|
|
800
|
+
* find_safety and flee are pure scans). */
|
|
801
|
+
if (monsterTakingTerrainDamage(state, mon)) {
|
|
802
|
+
if (getMoveFindSafety(mon, state)) {
|
|
803
|
+
getMoveFlee(mon, state);
|
|
804
|
+
grid = locDiff(mon.target.grid, mon.grid);
|
|
805
|
+
done = true;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
/* Normal animal packs try to get the player out of corridors: if the player
|
|
809
|
+
* is not in the open and is healthy, find a hiding place for an ambush
|
|
810
|
+
* (get_move_find_hiding draws no RNG). */
|
|
811
|
+
if (!done && groupAi && !monsterPassesWalls(mon)) {
|
|
812
|
+
let open = 0;
|
|
813
|
+
for (let i = 0; i < 8; i++) {
|
|
814
|
+
const test = locSum(target, DDGRID_DDD[i]);
|
|
815
|
+
if (!state.chunk.inBounds(test))
|
|
816
|
+
continue;
|
|
817
|
+
if (state.chunk.isPassable(test) ||
|
|
818
|
+
state.chunk.sqinfoHas(test, SQUARE.ROOM)) {
|
|
819
|
+
open++;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
const p = state.actor.player;
|
|
823
|
+
if (open < 5 && p.chp > Math.trunc(p.mhp / 2)) {
|
|
824
|
+
if (getMoveFindHiding(mon, state)) {
|
|
825
|
+
done = true;
|
|
826
|
+
grid = locDiff(mon.target.grid, mon.grid);
|
|
827
|
+
mon.mflag.off(MFLAG.TRACKING);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
/* Not hiding and monster is afraid. */
|
|
832
|
+
if (!done && mon.minRange === fleeRange) {
|
|
833
|
+
/* Try to find a safe place. */
|
|
834
|
+
if (getMoveFindSafety(mon, state)) {
|
|
835
|
+
/* Set a course for the safe place (flee's return is ignored: on a
|
|
836
|
+
* false early-out the target stays as find_safety set it). */
|
|
837
|
+
getMoveFlee(mon, state);
|
|
838
|
+
grid = locDiff(mon.target.grid, mon.grid);
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
/* Just leg it away from the player. */
|
|
842
|
+
grid = locDiff(loc(0, 0), grid);
|
|
843
|
+
}
|
|
844
|
+
/* No longer tracking. */
|
|
845
|
+
mon.mflag.off(MFLAG.TRACKING);
|
|
846
|
+
done = true;
|
|
847
|
+
}
|
|
848
|
+
/* Monster groups try to surround the player if they're in sight
|
|
849
|
+
* (mon-move.c L932). When not already adjacent (cdis > 1) it draws
|
|
850
|
+
* randint0(8) to pick a pseudo-random starting direction, then fills the
|
|
851
|
+
* first empty grid near the player from there; if none is empty grid1 keeps
|
|
852
|
+
* the last computed offset (matching the C loop's fall-through). */
|
|
853
|
+
if (!done && groupAi && squareIsView(state.chunk, mon.grid)) {
|
|
854
|
+
let grid1 = mon.target.grid;
|
|
855
|
+
if (mon.cdis > 1) {
|
|
856
|
+
const preds = {
|
|
857
|
+
isPlayerTrap: (g) => squareIsPlayerTrap(state, g),
|
|
858
|
+
isWebbed: (g) => squareIsWebbed(state, g),
|
|
859
|
+
isWarded: (g) => squareIsWarded(state, g),
|
|
860
|
+
};
|
|
861
|
+
const tmp = state.rng.randint0(8);
|
|
862
|
+
for (let i = 0; i < 8; i++) {
|
|
863
|
+
grid1 = locSum(target, DDGRID_DDD[(tmp + i) % 8]);
|
|
864
|
+
if (!squareIsEmptyLive(state, grid1, preds))
|
|
865
|
+
continue;
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
grid = locDiff(grid1, mon.grid);
|
|
870
|
+
}
|
|
871
|
+
if (locIsZero(grid))
|
|
872
|
+
return { move: false, dir: 0, tracking: track.value };
|
|
873
|
+
return {
|
|
874
|
+
move: true,
|
|
875
|
+
dir: getMoveChooseDirection(grid, state.turn),
|
|
876
|
+
tracking: track.value,
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* monster_turn_should_stagger: whether the monster steps at random this turn
|
|
881
|
+
* (confusion staggers, then the cumulative RAND_25 / RAND_50 chances).
|
|
882
|
+
*/
|
|
883
|
+
export function monsterTurnShouldStagger(mon, state) {
|
|
884
|
+
let chance = 0;
|
|
885
|
+
let confLevel = monsterEffectLevel(mon, MON_TMD.CONF);
|
|
886
|
+
while (confLevel) {
|
|
887
|
+
let accuracy = 100 - chance;
|
|
888
|
+
accuracy *= 100 - CONF_ERRATIC_CHANCE;
|
|
889
|
+
accuracy = Math.trunc(accuracy / 100);
|
|
890
|
+
chance = 100 - accuracy;
|
|
891
|
+
confLevel--;
|
|
892
|
+
}
|
|
893
|
+
const confusedChance = chance;
|
|
894
|
+
if (mon.race.flags.has(RF.RAND_25))
|
|
895
|
+
chance += 25;
|
|
896
|
+
if (mon.race.flags.has(RF.RAND_50))
|
|
897
|
+
chance += 50;
|
|
898
|
+
const roll = state.rng.randint0(100);
|
|
899
|
+
if (roll < confusedChance)
|
|
900
|
+
return STAGGER.CONFUSED;
|
|
901
|
+
return roll < chance ? STAGGER.INNATE : STAGGER.NO;
|
|
902
|
+
}
|
|
903
|
+
/** square_issecretdoor: a door still disguised as rock (cave-square.c L304). */
|
|
904
|
+
function squareIsSecretDoor(state, grid) {
|
|
905
|
+
const f = state.chunk.feature(grid).flags;
|
|
906
|
+
return f.has(TF.DOOR_ANY) && f.has(TF.ROCK);
|
|
907
|
+
}
|
|
908
|
+
/** square_destroy_wall (cave-square.c L1419): turn a wall to floor. */
|
|
909
|
+
function squareDestroyWall(state, grid) {
|
|
910
|
+
state.chunk.setFeat(grid, FEAT.FLOOR);
|
|
911
|
+
}
|
|
912
|
+
/** square_open_door (cave-square.c L1351): remove the lock, open the door. */
|
|
913
|
+
function squareOpenDoor(state, grid) {
|
|
914
|
+
state.removeDoorLock?.(grid);
|
|
915
|
+
state.chunk.setFeat(grid, FEAT.OPEN);
|
|
916
|
+
}
|
|
917
|
+
/** square_smash_door (cave-square.c L1367): remove the lock, break the door. */
|
|
918
|
+
function squareSmashDoor(state, grid) {
|
|
919
|
+
state.removeDoorLock?.(grid);
|
|
920
|
+
state.chunk.setFeat(grid, FEAT.BROKEN);
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* square_smash_wall (cave-square.c L1424): reduce the wall and much of what is
|
|
924
|
+
* next to it to floor. Each adjacent granite / quartz / magma grid gets a
|
|
925
|
+
* survival roll (one_in_ 4 / 10 / 20) - the RNG draws happen in ddgrid_ddd
|
|
926
|
+
* order, exactly once per mineral neighbour. (Decoy destruction on adjacent
|
|
927
|
+
* floors is DEFERRED and draws no RNG.)
|
|
928
|
+
*/
|
|
929
|
+
function squareSmashWall(state, grid) {
|
|
930
|
+
const c = state.chunk;
|
|
931
|
+
c.setFeat(grid, FEAT.FLOOR);
|
|
932
|
+
for (let i = 0; i < 8; i++) {
|
|
933
|
+
const adj = locSum(grid, DDGRID_DDD[i]);
|
|
934
|
+
if (!c.inBoundsFully(adj))
|
|
935
|
+
continue;
|
|
936
|
+
if (c.isPerm(adj))
|
|
937
|
+
continue;
|
|
938
|
+
/* Ignore floors (adjacent-decoy destruction DEFERRED). */
|
|
939
|
+
if (c.isFloor(adj))
|
|
940
|
+
continue;
|
|
941
|
+
/* Give this grid a chance to survive. */
|
|
942
|
+
if ((c.isGranite(adj) && state.rng.oneIn(4)) ||
|
|
943
|
+
(c.isQuartz(adj) && state.rng.oneIn(10)) ||
|
|
944
|
+
(c.isMagma(adj) && state.rng.oneIn(20))) {
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
c.setFeat(adj, FEAT.FLOOR);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* monster_slightly_stun_by_move (mon-move.c L1127): a confused monster that
|
|
952
|
+
* bumbles into something may lightly stun itself (one_in_(3), then a normal
|
|
953
|
+
* mon_inc_timed which itself may draw the STUN resist save).
|
|
954
|
+
*/
|
|
955
|
+
function monsterSlightlyStunByMove(mon, state) {
|
|
956
|
+
if ((mon.mTimed[MON_TMD.STUN] ?? 0) < 5 && state.rng.oneIn(3)) {
|
|
957
|
+
monIncTimed(state.rng, mon, MON_TMD.STUN, 3, 0);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* monster_turn_can_move (mon-move.c L1141): whether the monster can move
|
|
962
|
+
* through `next`, opening / bashing doors or smashing / boring walls in the
|
|
963
|
+
* way. `did` is set true when the monster spent its turn on a terrain action
|
|
964
|
+
* (or a confused bump) even though it did not move - the caller keeps the
|
|
965
|
+
* "can move here" result distinct from "did the terrain action".
|
|
966
|
+
*/
|
|
967
|
+
/**
|
|
968
|
+
* monster_desc for a movement/behaviour message: m_name as upstream builds it
|
|
969
|
+
* (MDESC_CAPITAL | MDESC_IND_HID | MDESC_COMMA), e.g. "The kobold". Pure, no RNG.
|
|
970
|
+
*/
|
|
971
|
+
function monMoveName(mon) {
|
|
972
|
+
return monsterDesc(mon, MDESC.CAPITAL | MDESC.IND_HID | MDESC.COMMA);
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* monster_display_confused_move_msg (mon-move.c L1111): a confused monster that
|
|
976
|
+
* bumps an obstacle stumbles - "%s %s." with the terrain's confused_msg, or
|
|
977
|
+
* "stumbles" when the feature defines none. Only shown for a monster both
|
|
978
|
+
* visible and in view. Draws no RNG.
|
|
979
|
+
*/
|
|
980
|
+
function displayConfusedMoveMsg(mon, state, next) {
|
|
981
|
+
if (monsterIsVisible(mon) && monsterIsInView(mon)) {
|
|
982
|
+
const m = state.chunk.feature(next).confusedMsg;
|
|
983
|
+
state.msg?.(`${monMoveName(mon)} ${m || "stumbles"}.`);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
function monsterTurnCanMove(mon, state, next, confused, did) {
|
|
987
|
+
const lore = getLore(state.lore, mon.race);
|
|
988
|
+
/* Always allow an attack upon the player or decoy. */
|
|
989
|
+
if (squareIsPlayer(state, next) || squareIsDecoyed(state, next))
|
|
990
|
+
return true;
|
|
991
|
+
/* Dangerous terrain in the way (monsterHatesGrid is DEFERRED: false). */
|
|
992
|
+
if (!confused && monsterHatesGrid(state, mon, next))
|
|
993
|
+
return false;
|
|
994
|
+
/* Floor is open? */
|
|
995
|
+
if (state.chunk.isPassable(next))
|
|
996
|
+
return true;
|
|
997
|
+
/* Permanent wall in the way. */
|
|
998
|
+
if (state.chunk.isPerm(next)) {
|
|
999
|
+
if (confused) {
|
|
1000
|
+
did.value = true;
|
|
1001
|
+
displayConfusedMoveMsg(mon, state, next);
|
|
1002
|
+
monsterSlightlyStunByMove(mon, state);
|
|
1003
|
+
}
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
/* Normal wall, door, or secret door in the way - learn kill / pass-wall. */
|
|
1007
|
+
if (monsterIsVisible(mon)) {
|
|
1008
|
+
lore.flags.on(RF.PASS_WALL);
|
|
1009
|
+
lore.flags.on(RF.KILL_WALL);
|
|
1010
|
+
lore.flags.on(RF.SMASH_WALL);
|
|
1011
|
+
}
|
|
1012
|
+
if (mon.race.flags.has(RF.PASS_WALL)) {
|
|
1013
|
+
return true;
|
|
1014
|
+
}
|
|
1015
|
+
else if (mon.race.flags.has(RF.SMASH_WALL)) {
|
|
1016
|
+
squareSmashWall(state, next);
|
|
1017
|
+
return true;
|
|
1018
|
+
}
|
|
1019
|
+
else if (mon.race.flags.has(RF.KILL_WALL)) {
|
|
1020
|
+
squareDestroyWall(state, next);
|
|
1021
|
+
return true;
|
|
1022
|
+
}
|
|
1023
|
+
else if (state.chunk.isClosedDoor(next) || squareIsSecretDoor(state, next)) {
|
|
1024
|
+
/* Don't allow a confused move to open a door. */
|
|
1025
|
+
const canOpen = mon.race.flags.has(RF.OPEN_DOOR) && !confused;
|
|
1026
|
+
/* During a confused move, a monster only bashes sometimes. */
|
|
1027
|
+
const canBash = mon.race.flags.has(RF.BASH_DOOR) && (!confused || state.rng.oneIn(3));
|
|
1028
|
+
let willBash = false;
|
|
1029
|
+
/* Take a turn. */
|
|
1030
|
+
if (canOpen || canBash)
|
|
1031
|
+
did.value = true;
|
|
1032
|
+
/* Learn about door abilities. */
|
|
1033
|
+
if (!confused && monsterIsVisible(mon)) {
|
|
1034
|
+
lore.flags.on(RF.OPEN_DOOR);
|
|
1035
|
+
lore.flags.on(RF.BASH_DOOR);
|
|
1036
|
+
}
|
|
1037
|
+
/* If creature can open or bash doors, make a choice. */
|
|
1038
|
+
if (canOpen) {
|
|
1039
|
+
/* Sometimes bash anyway (impatient). */
|
|
1040
|
+
if (canBash)
|
|
1041
|
+
willBash = state.rng.oneIn(2);
|
|
1042
|
+
}
|
|
1043
|
+
else if (canBash) {
|
|
1044
|
+
/* Only choice. */
|
|
1045
|
+
willBash = true;
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
/* Door is an insurmountable obstacle. */
|
|
1049
|
+
if (confused) {
|
|
1050
|
+
did.value = true;
|
|
1051
|
+
displayConfusedMoveMsg(mon, state, next);
|
|
1052
|
+
monsterSlightlyStunByMove(mon, state);
|
|
1053
|
+
}
|
|
1054
|
+
return false;
|
|
1055
|
+
}
|
|
1056
|
+
/* Now outcome depends on type of door. */
|
|
1057
|
+
const lockPower = state.doorLockPower?.(next) ?? 0;
|
|
1058
|
+
if (lockPower > 0) {
|
|
1059
|
+
/* Locked door -- test monster strength against door strength. */
|
|
1060
|
+
if (state.rng.randint0(Math.trunc(mon.hp / 10)) > lockPower) {
|
|
1061
|
+
state.msg?.(willBash
|
|
1062
|
+
? `${monMoveName(mon)} slams against the door.`
|
|
1063
|
+
: `${monMoveName(mon)} fiddles with the lock.`);
|
|
1064
|
+
/* Reduce the power of the door by one. */
|
|
1065
|
+
state.setDoorLock?.(next, lockPower - 1);
|
|
1066
|
+
}
|
|
1067
|
+
if (confused) {
|
|
1068
|
+
if (monsterIsVisible(mon))
|
|
1069
|
+
lore.flags.on(RF.BASH_DOOR);
|
|
1070
|
+
monsterSlightlyStunByMove(mon, state);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
/* Closed or secret door -- always open or bash. */
|
|
1075
|
+
if (willBash) {
|
|
1076
|
+
squareSmashDoor(state, next);
|
|
1077
|
+
/* mon-move.c L1269-1270: the burst is heard everywhere, then disturb()
|
|
1078
|
+
* stops the player running / resting. Neither draws RNG. */
|
|
1079
|
+
state.msg?.("You hear a door burst open!");
|
|
1080
|
+
disturb(state);
|
|
1081
|
+
if (confused) {
|
|
1082
|
+
if (monsterIsVisible(mon))
|
|
1083
|
+
lore.flags.on(RF.BASH_DOOR);
|
|
1084
|
+
monsterSlightlyStunByMove(mon, state);
|
|
1085
|
+
}
|
|
1086
|
+
/* Fall into doorway. */
|
|
1087
|
+
return true;
|
|
1088
|
+
}
|
|
1089
|
+
else {
|
|
1090
|
+
squareOpenDoor(state, next);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
else if (confused) {
|
|
1095
|
+
did.value = true;
|
|
1096
|
+
displayConfusedMoveMsg(mon, state, next);
|
|
1097
|
+
monsterSlightlyStunByMove(mon, state);
|
|
1098
|
+
}
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
/** monster_turn_try_push: trample or swap a blocking monster. */
|
|
1102
|
+
function monsterTurnTryPush(mon, state, next) {
|
|
1103
|
+
const killOk = monsterCanKill(state, mon, next);
|
|
1104
|
+
const moveOk = monsterCanMoveInto(state, mon, next) && state.chunk.isPassable(mon.grid);
|
|
1105
|
+
if (!killOk && !moveOk)
|
|
1106
|
+
return false;
|
|
1107
|
+
/* Reveal a camouflaged blocker (mon-move.c L1352) before it is potentially
|
|
1108
|
+
* trampled. */
|
|
1109
|
+
const victim = squareMonster(state, next);
|
|
1110
|
+
if (victim && monsterIsCamouflaged(victim)) {
|
|
1111
|
+
state.becomeAware?.(victim);
|
|
1112
|
+
}
|
|
1113
|
+
/* Note if visible (mon-move.c L1355-1358): "%s tramples over / pushes past
|
|
1114
|
+
* %s." n_name is monster_desc(mon1, MDESC_IND_HID). No RNG. */
|
|
1115
|
+
if (victim && monsterIsVisible(mon) && monsterIsInView(mon)) {
|
|
1116
|
+
state.msg?.(`${monMoveName(mon)} ${killOk ? "tramples over" : "pushes past"} ` +
|
|
1117
|
+
`${monsterDesc(victim, MDESC.IND_HID)}.`);
|
|
1118
|
+
}
|
|
1119
|
+
if (killOk) {
|
|
1120
|
+
if (victim) {
|
|
1121
|
+
/* mon-move.c L1360: delete_monster_idx clears groups, targets,
|
|
1122
|
+
* tracking, occupancy and the held/drop bookkeeping seam. */
|
|
1123
|
+
deleteMonster(state, victim.midx);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
monsterSwap(state, mon.grid, next);
|
|
1127
|
+
return true;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* monster_turn_multiply (mon-move.c L1025): every monster is checked here so
|
|
1131
|
+
* the RF_MULTIPLY lore is learnt when the crowd roll passes; only breeders that
|
|
1132
|
+
* find room actually reproduce. Returns true if reproduction spent the turn.
|
|
1133
|
+
*
|
|
1134
|
+
* RNG order is exact: the level cap and arena gate draw nothing, then the 3x3
|
|
1135
|
+
* neighbour count (k, which always includes the monster itself so k >= 1), then
|
|
1136
|
+
* one_in_(k * repro_monster_rate) - and only on a passing roll does the breeder
|
|
1137
|
+
* gate and multiply_monster (via the state.monsterMultiply hook) run.
|
|
1138
|
+
*/
|
|
1139
|
+
export function monsterTurnMultiply(mon, state) {
|
|
1140
|
+
/* Too many breeders on the level already. */
|
|
1141
|
+
if ((state.numRepro ?? 0) >= state.z.reproMonsterMax)
|
|
1142
|
+
return false;
|
|
1143
|
+
/* No breeding in single combat. */
|
|
1144
|
+
if (state.arenaLevel)
|
|
1145
|
+
return false;
|
|
1146
|
+
/* Count the adjacent monsters (the 3x3 includes the monster itself). */
|
|
1147
|
+
let k = 0;
|
|
1148
|
+
for (let y = mon.grid.y - 1; y <= mon.grid.y + 1; y++) {
|
|
1149
|
+
for (let x = mon.grid.x - 1; x <= mon.grid.x + 1; x++) {
|
|
1150
|
+
const g = loc(x, y);
|
|
1151
|
+
if (state.chunk.inBounds(g) && state.chunk.mon(g) > 0)
|
|
1152
|
+
k++;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
/* Multiply slower in crowded areas. */
|
|
1156
|
+
if (k < 4 && (k === 0 || state.rng.oneIn(k * state.z.reproMonsterRate))) {
|
|
1157
|
+
/* Successful breeding attempt, learn about that now. */
|
|
1158
|
+
const lore = getLore(state.lore, mon.race);
|
|
1159
|
+
loreLearnFlagIfVisible(lore, mon, RF.MULTIPLY);
|
|
1160
|
+
/* Leave now if not a breeder. */
|
|
1161
|
+
if (!mon.race.flags.has(RF.MULTIPLY))
|
|
1162
|
+
return false;
|
|
1163
|
+
/* Try to multiply. */
|
|
1164
|
+
if (state.monsterMultiply?.(mon)) {
|
|
1165
|
+
/* Make a sound. */
|
|
1166
|
+
if (monsterIsVisible(mon))
|
|
1167
|
+
state.sound?.(MSG.MULTIPLY);
|
|
1168
|
+
/* Multiplying takes energy. */
|
|
1169
|
+
return true;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* monster_turn_grab_objects (mon-move.c L1374): pick up (TAKE_ITEM) or crush
|
|
1176
|
+
* (KILL_ITEM) the floor objects at `next`. Gold, mimicked objects and artifacts
|
|
1177
|
+
* are left alone. Draws no RNG. The lore learn, the react_to_slay pickup-safety
|
|
1178
|
+
* check and the seen/ignore message gating are handled as noted (react_to_slay
|
|
1179
|
+
* is DEFERRED - it draws no RNG; messages ride presentation).
|
|
1180
|
+
*/
|
|
1181
|
+
function monsterTurnGrabObjects(mon, state, next) {
|
|
1182
|
+
const lore = getLore(state.lore, mon.race);
|
|
1183
|
+
const visible = monsterIsVisible(mon);
|
|
1184
|
+
/* Learn about item pickup behaviour. */
|
|
1185
|
+
for (const obj of floorPile(state, next)) {
|
|
1186
|
+
if (!tvalIsMoney(obj.tval) && visible) {
|
|
1187
|
+
lore.flags.on(RF.TAKE_ITEM);
|
|
1188
|
+
lore.flags.on(RF.KILL_ITEM);
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
/* Abort if can't pick up / kill. */
|
|
1193
|
+
if (!mon.race.flags.has(RF.TAKE_ITEM) &&
|
|
1194
|
+
!mon.race.flags.has(RF.KILL_ITEM)) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
/* Take or kill objects on the floor (snapshot: the pile is mutated). */
|
|
1198
|
+
for (const obj of [...floorPile(state, next)]) {
|
|
1199
|
+
/* Skip gold. */
|
|
1200
|
+
if (tvalIsMoney(obj.tval))
|
|
1201
|
+
continue;
|
|
1202
|
+
/* Skip mimicked objects. */
|
|
1203
|
+
if (obj.mimickingMIdx)
|
|
1204
|
+
continue;
|
|
1205
|
+
/* o_name (mon-move.c L1416) is object_desc(PREFIX|FULL); computed lazily so
|
|
1206
|
+
* an unseen pickup/crush - the common case - never pays for the describe.
|
|
1207
|
+
* !ignore_item_ok(player, obj): a message is suppressed for items the player
|
|
1208
|
+
* has chosen to ignore. state.isIgnored is the wired equivalent; absent
|
|
1209
|
+
* (worldless), nothing is ignored so the message shows. */
|
|
1210
|
+
const oName = () => describeObject(state, obj, ODESC.PREFIX | ODESC.FULL);
|
|
1211
|
+
const notIgnored = !(state.isIgnored?.(obj) ?? false);
|
|
1212
|
+
/* Artifacts are "safe" - a monster cannot pick them up; so are objects
|
|
1213
|
+
* that would hurt the monster (react_to_slay, mon-move.c L1420). */
|
|
1214
|
+
const safe = (obj.artifact ? true : false) || reactToSlay(obj, mon, state.slays);
|
|
1215
|
+
if (safe) {
|
|
1216
|
+
/* Only give a message for "take_item" (mon-move.c L1424-1432). */
|
|
1217
|
+
if (mon.race.flags.has(RF.TAKE_ITEM) &&
|
|
1218
|
+
visible &&
|
|
1219
|
+
squareIsView(state.chunk, next) &&
|
|
1220
|
+
notIgnored) {
|
|
1221
|
+
state.msg?.(`${monMoveName(mon)} tries to pick up ${oName()}, but fails.`);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
else if (mon.race.flags.has(RF.TAKE_ITEM)) {
|
|
1225
|
+
/* Pick it up: move the floor object into the monster's held pile. The
|
|
1226
|
+
* player-cave placeholder copy rides the knowledge subsystem (DEFERRED);
|
|
1227
|
+
* here the object simply leaves the floor and joins the monster. */
|
|
1228
|
+
if (floorExcise(state, next, obj)) {
|
|
1229
|
+
monsterCarry(mon.heldObj, obj, mon.midx);
|
|
1230
|
+
/* Describe observable situations (mon-move.c L1452-1454). */
|
|
1231
|
+
if (squareIsSeen(state.chunk, next) && notIgnored) {
|
|
1232
|
+
state.msg?.(`${monMoveName(mon)} picks up ${oName()}.`);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
else {
|
|
1237
|
+
/* Crush it (mon-move.c L1466-1468). */
|
|
1238
|
+
if (squareIsSeen(state.chunk, next) && notIgnored) {
|
|
1239
|
+
state.msg?.(`${monMoveName(mon)} crushes ${oName()}.`, MSG.DESTROY);
|
|
1240
|
+
state.sound?.(MSG.DESTROY);
|
|
1241
|
+
}
|
|
1242
|
+
floorExcise(state, next, obj);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* monster_turn_attack_glyph (mon-move.c L1299): a monster on a warded grid tries
|
|
1248
|
+
* to break the glyph of warding. Draws exactly one randint1(glyph_hardness); on
|
|
1249
|
+
* a roll below the monster's level the ward breaks (the glyph trap is removed)
|
|
1250
|
+
* and it returns true, else the ward holds and it returns false. The
|
|
1251
|
+
* "rune of protection is broken!" message is UI (DEFERRED, no RNG).
|
|
1252
|
+
*/
|
|
1253
|
+
function monsterTurnAttackGlyph(mon, state, next) {
|
|
1254
|
+
if (state.rng.randint1(state.z.glyphHardness) < mon.race.level) {
|
|
1255
|
+
/* Describe observable breakage (mon-move.c L1308). */
|
|
1256
|
+
if (squareIsSeen(state.chunk, next)) {
|
|
1257
|
+
state.msg?.("The rune of protection is broken!");
|
|
1258
|
+
}
|
|
1259
|
+
removeTrapsWithFlag(state, next, TRF.GLYPH);
|
|
1260
|
+
return true;
|
|
1261
|
+
}
|
|
1262
|
+
return false;
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* monster_turn: the monster acts. A ranged attack (spell / breath) is attempted
|
|
1266
|
+
* first through the injected state.monsterCast hook (make_ranged_attack, wired by
|
|
1267
|
+
* game/mon-ranged.ts installMonsterCasting); when it spends the turn we stop
|
|
1268
|
+
* here, exactly as upstream's `if (make_ranged_attack(mon)) return;`.
|
|
1269
|
+
* Item pickup, group behaviour and lore are partially DEFERRED (see the module
|
|
1270
|
+
* header); this ports the movement/attack core plus web/glyph/decoy handling.
|
|
1271
|
+
*/
|
|
1272
|
+
export function monsterTurn(mon, state) {
|
|
1273
|
+
/* W2.2 mod seam: a trusted plugin may take this monster's turn over entirely.
|
|
1274
|
+
* Absent (the default) this is a no-op and the ported AI runs unchanged. The
|
|
1275
|
+
* hook runs before any AI RNG is drawn, so a mod that skips the turn leaves
|
|
1276
|
+
* the seeded stream exactly where a "do nothing" monster would. */
|
|
1277
|
+
if (state.monsterTurnHook?.(mon, state))
|
|
1278
|
+
return;
|
|
1279
|
+
let didSomething = false;
|
|
1280
|
+
/* If we're in a web, deal with that (mon-move.c L1519). Draws no RNG. */
|
|
1281
|
+
if (squareIsWebbed(state, mon.grid)) {
|
|
1282
|
+
const lore = getLore(state.lore, mon.race);
|
|
1283
|
+
if (monsterIsVisible(mon)) {
|
|
1284
|
+
lore.flags.on(RF.CLEAR_WEB);
|
|
1285
|
+
lore.flags.on(RF.PASS_WEB);
|
|
1286
|
+
}
|
|
1287
|
+
/* If we can pass, no need to clear. */
|
|
1288
|
+
if (!mon.race.flags.has(RF.PASS_WEB)) {
|
|
1289
|
+
if (monsterIsVisible(mon)) {
|
|
1290
|
+
lore.flags.on(RF.PASS_WALL);
|
|
1291
|
+
lore.flags.on(RF.KILL_WALL);
|
|
1292
|
+
}
|
|
1293
|
+
if (mon.race.flags.has(RF.PASS_WALL)) {
|
|
1294
|
+
/* Insubstantial monsters go right through. */
|
|
1295
|
+
}
|
|
1296
|
+
else if (monsterPassesWalls(mon)) {
|
|
1297
|
+
/* If you can destroy a wall, you can destroy a web. */
|
|
1298
|
+
removeTrapsWithFlag(state, mon.grid, TRF.WEB);
|
|
1299
|
+
}
|
|
1300
|
+
else if (mon.race.flags.has(RF.CLEAR_WEB)) {
|
|
1301
|
+
/* Clearing costs a turn. */
|
|
1302
|
+
removeTrapsWithFlag(state, mon.grid, TRF.WEB);
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
else {
|
|
1306
|
+
/* Stuck. */
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
/* Let other group monsters know about the player. */
|
|
1312
|
+
monsterGroupRouse(state, mon);
|
|
1313
|
+
/* Try to multiply - this can use up a turn (mon-move.c L1564, BEFORE the
|
|
1314
|
+
* ranged attack, so its cap / chance rolls precede make_ranged_attack in the
|
|
1315
|
+
* RNG stream). */
|
|
1316
|
+
if (monsterTurnMultiply(mon, state))
|
|
1317
|
+
return;
|
|
1318
|
+
/* Attempt a ranged attack (spell / breath) before moving. */
|
|
1319
|
+
if (state.monsterCast?.(mon, state))
|
|
1320
|
+
return;
|
|
1321
|
+
const stagger = monsterTurnShouldStagger(mon, state);
|
|
1322
|
+
let dir = 0;
|
|
1323
|
+
let tracking = false;
|
|
1324
|
+
if (stagger === STAGGER.NO) {
|
|
1325
|
+
const decision = getMove(mon, state);
|
|
1326
|
+
if (!decision.move)
|
|
1327
|
+
return;
|
|
1328
|
+
dir = decision.dir;
|
|
1329
|
+
tracking = decision.tracking;
|
|
1330
|
+
}
|
|
1331
|
+
for (let i = 0; i < 5 && !didSomething; i++) {
|
|
1332
|
+
const d = stagger !== STAGGER.NO
|
|
1333
|
+
? DDD[state.rng.randint0(8)]
|
|
1334
|
+
: SIDE_DIRS[dir]?.[i];
|
|
1335
|
+
const next = locSum(mon.grid, DDGRID[d]);
|
|
1336
|
+
/* Tracking monsters commit to their best direction. */
|
|
1337
|
+
if (i > 0 &&
|
|
1338
|
+
stagger === STAGGER.NO &&
|
|
1339
|
+
!squareIsView(state.chunk, mon.grid) &&
|
|
1340
|
+
tracking) {
|
|
1341
|
+
break;
|
|
1342
|
+
}
|
|
1343
|
+
if (!state.chunk.inBounds(next))
|
|
1344
|
+
continue;
|
|
1345
|
+
/* "can move here" (return) is kept distinct from "did the terrain action"
|
|
1346
|
+
* (canDid) which spends the turn even when the monster does not step. */
|
|
1347
|
+
const canDid = { value: false };
|
|
1348
|
+
const canMove = monsterTurnCanMove(mon, state, next, stagger === STAGGER.CONFUSED, canDid);
|
|
1349
|
+
if (canDid.value)
|
|
1350
|
+
didSomething = true;
|
|
1351
|
+
if (!canMove)
|
|
1352
|
+
continue;
|
|
1353
|
+
/* Try to break the glyph if there is one. This can happen multiple times
|
|
1354
|
+
* per turn because failure does not break the loop. A decoy grid also
|
|
1355
|
+
* carries the GLYPH trap flag, so exclude it here (it is handled next). */
|
|
1356
|
+
if (squareIsWarded(state, next) &&
|
|
1357
|
+
!squareIsDecoyed(state, next) &&
|
|
1358
|
+
!monsterTurnAttackGlyph(mon, state, next)) {
|
|
1359
|
+
continue;
|
|
1360
|
+
}
|
|
1361
|
+
/* Break a decoy if there is one. */
|
|
1362
|
+
if (squareIsDecoyed(state, next)) {
|
|
1363
|
+
const lore = getLore(state.lore, mon.race);
|
|
1364
|
+
if (monsterIsVisible(mon))
|
|
1365
|
+
lore.flags.on(RF.NEVER_BLOW);
|
|
1366
|
+
/* Some monsters never attack. */
|
|
1367
|
+
if (mon.race.flags.has(RF.NEVER_BLOW))
|
|
1368
|
+
continue;
|
|
1369
|
+
/* Destroy the decoy (square_destroy_decoy, cave-square.c L1402): remove
|
|
1370
|
+
* the decoy trap and clear cave->decoy. The "decoy is destroyed!" message
|
|
1371
|
+
* is UI (DEFERRED, no RNG). */
|
|
1372
|
+
removeTrapsWithFlag(state, next, TRF.GLYPH);
|
|
1373
|
+
state.decoy = null;
|
|
1374
|
+
didSomething = true;
|
|
1375
|
+
break;
|
|
1376
|
+
}
|
|
1377
|
+
if (squareIsPlayer(state, next)) {
|
|
1378
|
+
if (mon.race.flags.has(RF.NEVER_BLOW))
|
|
1379
|
+
continue;
|
|
1380
|
+
const result = monMeleeAttack(state.rng, mon, state.actor.player, state.actor.defense, state.monBlowEnv ? { env: state.monBlowEnv(mon) } : {});
|
|
1381
|
+
/* Being attacked teaches the to-armor rune (mon-attack.c L530). Its
|
|
1382
|
+
* player_learn_rune tail-calls update_player_object_knowledge (L1373), so
|
|
1383
|
+
* sweep carried/floor objects for any awareness the new rune completes. */
|
|
1384
|
+
equipLearnOnDefend(state.actor.player, state.runeEnv);
|
|
1385
|
+
updatePlayerObjectKnowledge(state);
|
|
1386
|
+
if (result.playerDied || state.actor.player.chp < 0) {
|
|
1387
|
+
state.isDead = true;
|
|
1388
|
+
state.playing = false;
|
|
1389
|
+
}
|
|
1390
|
+
/* Analyze "visible" monsters only: count obvious or damaging blows
|
|
1391
|
+
* (mon-attack.c L727), notice the cause of death, refresh lore. */
|
|
1392
|
+
const lore = getLore(state.lore, mon.race);
|
|
1393
|
+
if (monsterIsVisible(mon)) {
|
|
1394
|
+
result.blows.forEach((blow, i) => {
|
|
1395
|
+
if (blow.obvious || blow.damage || (lore.blowTimesSeen[i] ?? 0) > 10) {
|
|
1396
|
+
if ((lore.blowTimesSeen[i] ?? 0) < 255)
|
|
1397
|
+
lore.blowTimesSeen[i]++;
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
if (state.isDead)
|
|
1402
|
+
loreCountU16(lore, "deaths");
|
|
1403
|
+
loreUpdate(mon.race, lore);
|
|
1404
|
+
didSomething = true;
|
|
1405
|
+
break;
|
|
1406
|
+
}
|
|
1407
|
+
if (mon.race.flags.has(RF.NEVER_MOVE))
|
|
1408
|
+
return;
|
|
1409
|
+
if (squareMonster(state, next)) {
|
|
1410
|
+
didSomething = monsterTurnTryPush(mon, state, next);
|
|
1411
|
+
}
|
|
1412
|
+
else {
|
|
1413
|
+
monsterSwap(state, mon.grid, next);
|
|
1414
|
+
didSomething = true;
|
|
1415
|
+
}
|
|
1416
|
+
/* Scan all objects in the grid, if we reached it. */
|
|
1417
|
+
if (squareMonster(state, next) === mon) {
|
|
1418
|
+
monsterTurnGrabObjects(mon, state, next);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
/* Possible disturb (mon-move.c L1661-1670): a visible monster that acted in
|
|
1422
|
+
* the player's view stops the player running / resting, gated by the
|
|
1423
|
+
* disturb_near option (shipped default true). The did_something NEVER_MOVE
|
|
1424
|
+
* lore learn rides the lore layer; disturb draws no RNG. */
|
|
1425
|
+
if (didSomething &&
|
|
1426
|
+
monsterIsVisible(mon) &&
|
|
1427
|
+
mon.mflag.has(MFLAG.VIEW) &&
|
|
1428
|
+
(state.options?.get("disturb_near") ?? true)) {
|
|
1429
|
+
disturb(state);
|
|
1430
|
+
}
|
|
1431
|
+
/* Out of options - monster is paralysed by fear (converts fear to hold). */
|
|
1432
|
+
if (!didSomething && (mon.mTimed[MON_TMD.FEAR] ?? 0)) {
|
|
1433
|
+
const amount = mon.mTimed[MON_TMD.FEAR] ?? 0;
|
|
1434
|
+
const sink = monsterTimedMessage(state);
|
|
1435
|
+
monClearTimed(state.rng, mon, MON_TMD.FEAR, MON_TMD_FLG_NOMESSAGE);
|
|
1436
|
+
monIncTimed(state.rng, mon, MON_TMD.HOLD, amount, MON_TMD_FLG_NOTIFY, sink);
|
|
1437
|
+
}
|
|
1438
|
+
/* If we see an unaware monster do something, become aware of it
|
|
1439
|
+
* (mon-move.c L1680). */
|
|
1440
|
+
if (didSomething && monsterIsCamouflaged(mon)) {
|
|
1441
|
+
state.becomeAware?.(mon);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* monster_reduce_sleep (mon-move.c L1729): wake a monster (or reduce its sleep)
|
|
1446
|
+
* from player noise. The notice roll is drawn unconditionally (matching
|
|
1447
|
+
* upstream), then aggravation is checked first: an aggravating player wakes the
|
|
1448
|
+
* monster outright via monster_wake (which draws its own randint0(100)); only
|
|
1449
|
+
* otherwise does the noise-notice reduction run.
|
|
1450
|
+
*/
|
|
1451
|
+
function monsterTimedMessage(state) {
|
|
1452
|
+
return (mon, note) => {
|
|
1453
|
+
const text = formatMonsterMessageByName(mon, note);
|
|
1454
|
+
if (text)
|
|
1455
|
+
state.msg?.(text);
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
function monsterReduceSleep(mon, state) {
|
|
1459
|
+
const stealth = state.actor.stealth;
|
|
1460
|
+
const playerNoise = Math.pow(2, 30 - stealth);
|
|
1461
|
+
const notice = state.rng.randint0(1024);
|
|
1462
|
+
const aggravate = state.playerState?.flags.has(OF.AGGRAVATE) ?? false;
|
|
1463
|
+
if (aggravate) {
|
|
1464
|
+
/* Wake the monster, make it aware. */
|
|
1465
|
+
monsterWake(state.rng, mon, false, 100);
|
|
1466
|
+
/* Notify the player if aware (mon-move.c L1748-1750). equip_learn_flag(
|
|
1467
|
+
* OF_AGGRAVATE) is lore (DEFERRED). No RNG. */
|
|
1468
|
+
if (monsterIsObvious(mon)) {
|
|
1469
|
+
state.msg?.(`${monMoveName(mon)} wakes up.`);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
else if (notice * notice * notice <= playerNoise) {
|
|
1473
|
+
let sleepReduction = 1;
|
|
1474
|
+
const localNoise = noiseAt(state, mon.grid);
|
|
1475
|
+
if (localNoise > 0 && localNoise < 50) {
|
|
1476
|
+
sleepReduction = Math.trunc(100 / localNoise);
|
|
1477
|
+
}
|
|
1478
|
+
monDecTimed(state.rng, mon, MON_TMD.SLEEP, sleepReduction, MON_TMD_FLG_NOTIFY, monsterTimedMessage(state));
|
|
1479
|
+
const next = mon.mTimed[MON_TMD.SLEEP] ?? 0;
|
|
1480
|
+
/* Update knowledge (mon-move.c L1771): a watched sleeper that stirs
|
|
1481
|
+
* is "ignored", one that wakes is "woken". */
|
|
1482
|
+
if (monsterIsObvious(mon)) {
|
|
1483
|
+
const lore = getLore(state.lore, mon.race);
|
|
1484
|
+
loreCountU8(lore, next > 0 ? "ignore" : "wake");
|
|
1485
|
+
loreUpdate(mon.race, lore);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* process_monster_timed: decrement timed effects, wake sleepers. Returns
|
|
1491
|
+
* true if the monster skips its turn (asleep, held, commanded, or a stunned
|
|
1492
|
+
* miss). Message plumbing and lore are DEFERRED.
|
|
1493
|
+
*/
|
|
1494
|
+
export function processMonsterTimed(mon, state) {
|
|
1495
|
+
if (mon.mTimed[MON_TMD.SLEEP] ?? 0) {
|
|
1496
|
+
monsterReduceSleep(mon, state);
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
if (state.rng.oneIn(10) && mon.mflag.has(MFLAG.ACTIVE)) {
|
|
1500
|
+
mon.mflag.on(MFLAG.AWARE);
|
|
1501
|
+
}
|
|
1502
|
+
const sink = monsterTimedMessage(state);
|
|
1503
|
+
const shape = {
|
|
1504
|
+
change: () => false,
|
|
1505
|
+
revert: (m) => monsterRevertShape(state, m),
|
|
1506
|
+
};
|
|
1507
|
+
/* mon-move.c L1800-1826: flag-0 decrements precede the notifying
|
|
1508
|
+
* stun/confusion/shape decrements, all through mon_dec_timed. */
|
|
1509
|
+
for (const idx of [MON_TMD.FAST, MON_TMD.SLOW, MON_TMD.HOLD, MON_TMD.DISEN]) {
|
|
1510
|
+
if ((mon.mTimed[idx] ?? 0) > 0)
|
|
1511
|
+
monDecTimed(state.rng, mon, idx, 1);
|
|
1512
|
+
}
|
|
1513
|
+
for (const idx of [MON_TMD.STUN, MON_TMD.CONF]) {
|
|
1514
|
+
if ((mon.mTimed[idx] ?? 0) > 0) {
|
|
1515
|
+
monDecTimed(state.rng, mon, idx, 1, MON_TMD_FLG_NOTIFY, sink);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
if ((mon.mTimed[MON_TMD.CHANGED] ?? 0) > 0) {
|
|
1519
|
+
monDecTimed(state.rng, mon, MON_TMD.CHANGED, 1, MON_TMD_FLG_NOTIFY, sink, shape);
|
|
1520
|
+
}
|
|
1521
|
+
if (mon.mTimed[MON_TMD.FEAR] ?? 0) {
|
|
1522
|
+
const d = state.rng.randint1(Math.trunc(mon.race.level / 10) + 1);
|
|
1523
|
+
monDecTimed(state.rng, mon, MON_TMD.FEAR, d, MON_TMD_FLG_NOTIFY, sink);
|
|
1524
|
+
}
|
|
1525
|
+
if ((mon.mTimed[MON_TMD.HOLD] ?? 0) || (mon.mTimed[MON_TMD.COMMAND] ?? 0)) {
|
|
1526
|
+
return true;
|
|
1527
|
+
}
|
|
1528
|
+
if (mon.mTimed[MON_TMD.STUN] ?? 0) {
|
|
1529
|
+
return state.rng.oneIn(STUN_MISS_CHANCE);
|
|
1530
|
+
}
|
|
1531
|
+
return false;
|
|
1532
|
+
}
|
|
1533
|
+
/** monster_check_active: set/clear MFLAG_ACTIVE, return whether active. */
|
|
1534
|
+
export function monsterCheckActive(mon, state) {
|
|
1535
|
+
let active = false;
|
|
1536
|
+
if (mon.cdis <= mon.race.hearing && monsterPassesWalls(mon)) {
|
|
1537
|
+
active = true;
|
|
1538
|
+
}
|
|
1539
|
+
else if (mon.hp < mon.maxhp) {
|
|
1540
|
+
active = true;
|
|
1541
|
+
}
|
|
1542
|
+
else if (squareIsView(state.chunk, mon.grid)) {
|
|
1543
|
+
active = true;
|
|
1544
|
+
}
|
|
1545
|
+
else if (monsterCanHear(mon, state)) {
|
|
1546
|
+
active = true;
|
|
1547
|
+
}
|
|
1548
|
+
else if (monsterCanSmell(mon, state)) {
|
|
1549
|
+
active = true;
|
|
1550
|
+
}
|
|
1551
|
+
else if (monsterTakingTerrainDamage(state, mon)) {
|
|
1552
|
+
active = true;
|
|
1553
|
+
}
|
|
1554
|
+
if (active)
|
|
1555
|
+
mon.mflag.on(MFLAG.ACTIVE);
|
|
1556
|
+
else
|
|
1557
|
+
mon.mflag.off(MFLAG.ACTIVE);
|
|
1558
|
+
return active;
|
|
1559
|
+
}
|
|
1560
|
+
//# sourceMappingURL=monster-turn.js.map
|