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