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