@maka/maka-cli 5.3.17 → 5.5.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 (245) hide show
  1. package/bundle/typescript/package.json +1 -1
  2. package/bundle/typescript/src/commands/game/sideQuest/archetypes.d.ts +62 -0
  3. package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +196 -0
  4. package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -0
  5. package/bundle/typescript/src/commands/game/sideQuest/commands/advance.d.ts +16 -0
  6. package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js +65 -0
  7. package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js.map +1 -0
  8. package/bundle/typescript/src/commands/game/sideQuest/commands/assense.d.ts +16 -0
  9. package/bundle/typescript/src/commands/game/sideQuest/commands/assense.js +122 -0
  10. package/bundle/typescript/src/commands/game/sideQuest/commands/assense.js.map +1 -0
  11. package/bundle/typescript/src/commands/game/sideQuest/commands/attack.d.ts +42 -0
  12. package/bundle/typescript/src/commands/game/sideQuest/commands/attack.js +243 -0
  13. package/bundle/typescript/src/commands/game/sideQuest/commands/attack.js.map +1 -0
  14. package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.d.ts +16 -0
  15. package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js +39 -0
  16. package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js.map +1 -0
  17. package/bundle/typescript/src/commands/game/sideQuest/commands/brandish.d.ts +21 -0
  18. package/bundle/typescript/src/commands/game/sideQuest/commands/brandish.js +82 -0
  19. package/bundle/typescript/src/commands/game/sideQuest/commands/brandish.js.map +1 -0
  20. package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.d.ts +28 -0
  21. package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.js +101 -0
  22. package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.js.map +1 -0
  23. package/bundle/typescript/src/commands/game/sideQuest/commands/call.d.ts +19 -0
  24. package/bundle/typescript/src/commands/game/sideQuest/commands/call.js +219 -0
  25. package/bundle/typescript/src/commands/game/sideQuest/commands/call.js.map +1 -0
  26. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.d.ts +58 -0
  27. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +397 -0
  28. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -0
  29. package/bundle/typescript/src/commands/game/sideQuest/commands/command-registry.d.ts +11 -1
  30. package/bundle/typescript/src/commands/game/sideQuest/commands/command-registry.js +8 -3
  31. package/bundle/typescript/src/commands/game/sideQuest/commands/command-registry.js.map +1 -1
  32. package/bundle/typescript/src/commands/game/sideQuest/commands/command.d.ts +6 -0
  33. package/bundle/typescript/src/commands/game/sideQuest/commands/command.js +4 -0
  34. package/bundle/typescript/src/commands/game/sideQuest/commands/command.js.map +1 -1
  35. package/bundle/typescript/src/commands/game/sideQuest/commands/drone.d.ts +15 -0
  36. package/bundle/typescript/src/commands/game/sideQuest/commands/drone.js +72 -0
  37. package/bundle/typescript/src/commands/game/sideQuest/commands/drone.js.map +1 -0
  38. package/bundle/typescript/src/commands/game/sideQuest/commands/drop.js +3 -0
  39. package/bundle/typescript/src/commands/game/sideQuest/commands/drop.js.map +1 -1
  40. package/bundle/typescript/src/commands/game/sideQuest/commands/edge.d.ts +13 -0
  41. package/bundle/typescript/src/commands/game/sideQuest/commands/edge.js +31 -0
  42. package/bundle/typescript/src/commands/game/sideQuest/commands/edge.js.map +1 -0
  43. package/bundle/typescript/src/commands/game/sideQuest/commands/end-call.d.ts +6 -0
  44. package/bundle/typescript/src/commands/game/sideQuest/commands/end-call.js +27 -0
  45. package/bundle/typescript/src/commands/game/sideQuest/commands/end-call.js.map +1 -0
  46. package/bundle/typescript/src/commands/game/sideQuest/commands/equip.d.ts +4 -0
  47. package/bundle/typescript/src/commands/game/sideQuest/commands/equip.js +59 -2
  48. package/bundle/typescript/src/commands/game/sideQuest/commands/equip.js.map +1 -1
  49. package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.d.ts +13 -0
  50. package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js +50 -0
  51. package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js.map +1 -0
  52. package/bundle/typescript/src/commands/game/sideQuest/commands/give.js +7 -1
  53. package/bundle/typescript/src/commands/game/sideQuest/commands/give.js.map +1 -1
  54. package/bundle/typescript/src/commands/game/sideQuest/commands/go.d.ts +13 -0
  55. package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +147 -4
  56. package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
  57. package/bundle/typescript/src/commands/game/sideQuest/commands/hack.d.ts +25 -0
  58. package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +199 -0
  59. package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -0
  60. package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.d.ts +15 -0
  61. package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js +75 -0
  62. package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js.map +1 -0
  63. package/bundle/typescript/src/commands/game/sideQuest/commands/inv.d.ts +12 -0
  64. package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js +43 -0
  65. package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js.map +1 -0
  66. package/bundle/typescript/src/commands/game/sideQuest/commands/jack.d.ts +17 -0
  67. package/bundle/typescript/src/commands/game/sideQuest/commands/jack.js +64 -0
  68. package/bundle/typescript/src/commands/game/sideQuest/commands/jack.js.map +1 -0
  69. package/bundle/typescript/src/commands/game/sideQuest/commands/kill.d.ts +10 -3
  70. package/bundle/typescript/src/commands/game/sideQuest/commands/kill.js +11 -33
  71. package/bundle/typescript/src/commands/game/sideQuest/commands/kill.js.map +1 -1
  72. package/bundle/typescript/src/commands/game/sideQuest/commands/look.js +47 -4
  73. package/bundle/typescript/src/commands/game/sideQuest/commands/look.js.map +1 -1
  74. package/bundle/typescript/src/commands/game/sideQuest/commands/map.d.ts +12 -0
  75. package/bundle/typescript/src/commands/game/sideQuest/commands/map.js +46 -0
  76. package/bundle/typescript/src/commands/game/sideQuest/commands/map.js.map +1 -0
  77. package/bundle/typescript/src/commands/game/sideQuest/commands/pan.d.ts +12 -0
  78. package/bundle/typescript/src/commands/game/sideQuest/commands/pan.js +55 -0
  79. package/bundle/typescript/src/commands/game/sideQuest/commands/pan.js.map +1 -0
  80. package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.d.ts +18 -0
  81. package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.js +100 -0
  82. package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.js.map +1 -0
  83. package/bundle/typescript/src/commands/game/sideQuest/commands/pick.d.ts +10 -0
  84. package/bundle/typescript/src/commands/game/sideQuest/commands/pick.js +33 -0
  85. package/bundle/typescript/src/commands/game/sideQuest/commands/pick.js.map +1 -0
  86. package/bundle/typescript/src/commands/game/sideQuest/commands/project.d.ts +19 -0
  87. package/bundle/typescript/src/commands/game/sideQuest/commands/project.js +54 -0
  88. package/bundle/typescript/src/commands/game/sideQuest/commands/project.js.map +1 -0
  89. package/bundle/typescript/src/commands/game/sideQuest/commands/read.js +6 -5
  90. package/bundle/typescript/src/commands/game/sideQuest/commands/read.js.map +1 -1
  91. package/bundle/typescript/src/commands/game/sideQuest/commands/reboot.d.ts +12 -0
  92. package/bundle/typescript/src/commands/game/sideQuest/commands/reboot.js +52 -0
  93. package/bundle/typescript/src/commands/game/sideQuest/commands/reboot.js.map +1 -0
  94. package/bundle/typescript/src/commands/game/sideQuest/commands/reload.d.ts +14 -0
  95. package/bundle/typescript/src/commands/game/sideQuest/commands/reload.js +40 -0
  96. package/bundle/typescript/src/commands/game/sideQuest/commands/reload.js.map +1 -0
  97. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.d.ts +15 -0
  98. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +59 -0
  99. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -0
  100. package/bundle/typescript/src/commands/game/sideQuest/commands/say.js +31 -2
  101. package/bundle/typescript/src/commands/game/sideQuest/commands/say.js.map +1 -1
  102. package/bundle/typescript/src/commands/game/sideQuest/commands/search.js +71 -7
  103. package/bundle/typescript/src/commands/game/sideQuest/commands/search.js.map +1 -1
  104. package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.d.ts +12 -0
  105. package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +58 -0
  106. package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js.map +1 -0
  107. package/bundle/typescript/src/commands/game/sideQuest/commands/silent.d.ts +13 -0
  108. package/bundle/typescript/src/commands/game/sideQuest/commands/silent.js +50 -0
  109. package/bundle/typescript/src/commands/game/sideQuest/commands/silent.js.map +1 -0
  110. package/bundle/typescript/src/commands/game/sideQuest/commands/sneak.d.ts +15 -0
  111. package/bundle/typescript/src/commands/game/sideQuest/commands/sneak.js +35 -0
  112. package/bundle/typescript/src/commands/game/sideQuest/commands/sneak.js.map +1 -0
  113. package/bundle/typescript/src/commands/game/sideQuest/commands/solve.js +32 -11
  114. package/bundle/typescript/src/commands/game/sideQuest/commands/solve.js.map +1 -1
  115. package/bundle/typescript/src/commands/game/sideQuest/commands/spells.d.ts +14 -0
  116. package/bundle/typescript/src/commands/game/sideQuest/commands/spells.js +86 -0
  117. package/bundle/typescript/src/commands/game/sideQuest/commands/spells.js.map +1 -0
  118. package/bundle/typescript/src/commands/game/sideQuest/commands/stance.d.ts +12 -0
  119. package/bundle/typescript/src/commands/game/sideQuest/commands/stance.js +41 -0
  120. package/bundle/typescript/src/commands/game/sideQuest/commands/stance.js.map +1 -0
  121. package/bundle/typescript/src/commands/game/sideQuest/commands/subdue.d.ts +21 -0
  122. package/bundle/typescript/src/commands/game/sideQuest/commands/subdue.js +43 -0
  123. package/bundle/typescript/src/commands/game/sideQuest/commands/subdue.js.map +1 -0
  124. package/bundle/typescript/src/commands/game/sideQuest/commands/surrender.d.ts +20 -0
  125. package/bundle/typescript/src/commands/game/sideQuest/commands/surrender.js +45 -0
  126. package/bundle/typescript/src/commands/game/sideQuest/commands/surrender.js.map +1 -0
  127. package/bundle/typescript/src/commands/game/sideQuest/commands/take.d.ts +8 -0
  128. package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +138 -2
  129. package/bundle/typescript/src/commands/game/sideQuest/commands/take.js.map +1 -1
  130. package/bundle/typescript/src/commands/game/sideQuest/commands/talk.js +8 -0
  131. package/bundle/typescript/src/commands/game/sideQuest/commands/talk.js.map +1 -1
  132. package/bundle/typescript/src/commands/game/sideQuest/commands/unequip.js +6 -3
  133. package/bundle/typescript/src/commands/game/sideQuest/commands/unequip.js.map +1 -1
  134. package/bundle/typescript/src/commands/game/sideQuest/commands/unlock.js +1 -0
  135. package/bundle/typescript/src/commands/game/sideQuest/commands/unlock.js.map +1 -1
  136. package/bundle/typescript/src/commands/game/sideQuest/commands/use.d.ts +24 -0
  137. package/bundle/typescript/src/commands/game/sideQuest/commands/use.js +102 -1
  138. package/bundle/typescript/src/commands/game/sideQuest/commands/use.js.map +1 -1
  139. package/bundle/typescript/src/commands/game/sideQuest/factories/item-factory.js +2 -1
  140. package/bundle/typescript/src/commands/game/sideQuest/factories/item-factory.js.map +1 -1
  141. package/bundle/typescript/src/commands/game/sideQuest/factories/npc-factory.js +7 -2
  142. package/bundle/typescript/src/commands/game/sideQuest/factories/npc-factory.js.map +1 -1
  143. package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.js +2 -1
  144. package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.js.map +1 -1
  145. package/bundle/typescript/src/commands/game/sideQuest/factories/room-factory.js +3 -0
  146. package/bundle/typescript/src/commands/game/sideQuest/factories/room-factory.js.map +1 -1
  147. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.d.ts +175 -0
  148. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +673 -0
  149. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js.map +1 -0
  150. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.d.ts +8 -1
  151. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js +139 -21
  152. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js.map +1 -1
  153. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.d.ts +174 -0
  154. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js +647 -0
  155. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js.map +1 -0
  156. package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +138 -9
  157. package/bundle/typescript/src/commands/game/sideQuest/game.js +757 -197
  158. package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
  159. package/bundle/typescript/src/commands/game/sideQuest/minigames/hack-minigame.d.ts +16 -0
  160. package/bundle/typescript/src/commands/game/sideQuest/minigames/hack-minigame.js +101 -0
  161. package/bundle/typescript/src/commands/game/sideQuest/minigames/hack-minigame.js.map +1 -0
  162. package/bundle/typescript/src/commands/game/sideQuest/minigames/lockpick-minigame.d.ts +15 -0
  163. package/bundle/typescript/src/commands/game/sideQuest/minigames/lockpick-minigame.js +95 -0
  164. package/bundle/typescript/src/commands/game/sideQuest/minigames/lockpick-minigame.js.map +1 -0
  165. package/bundle/typescript/src/commands/game/sideQuest/models/door.d.ts +10 -0
  166. package/bundle/typescript/src/commands/game/sideQuest/models/door.js +15 -2
  167. package/bundle/typescript/src/commands/game/sideQuest/models/door.js.map +1 -1
  168. package/bundle/typescript/src/commands/game/sideQuest/models/inventory.d.ts +10 -0
  169. package/bundle/typescript/src/commands/game/sideQuest/models/inventory.js +54 -4
  170. package/bundle/typescript/src/commands/game/sideQuest/models/inventory.js.map +1 -1
  171. package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +41 -0
  172. package/bundle/typescript/src/commands/game/sideQuest/models/item.js +106 -3
  173. package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
  174. package/bundle/typescript/src/commands/game/sideQuest/models/npc.d.ts +27 -0
  175. package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +312 -50
  176. package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
  177. package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +278 -0
  178. package/bundle/typescript/src/commands/game/sideQuest/models/player.js +661 -9
  179. package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
  180. package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.d.ts +75 -1
  181. package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js +199 -6
  182. package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js.map +1 -1
  183. package/bundle/typescript/src/commands/game/sideQuest/models/room.d.ts +24 -0
  184. package/bundle/typescript/src/commands/game/sideQuest/models/room.js +53 -18
  185. package/bundle/typescript/src/commands/game/sideQuest/models/room.js.map +1 -1
  186. package/bundle/typescript/src/commands/game/sideQuest/models/scene.d.ts +73 -0
  187. package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +208 -3
  188. package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
  189. package/bundle/typescript/src/commands/game/sideQuest/scenes/scene1.json +319 -70
  190. package/bundle/typescript/src/commands/game/sideQuest/scenes/scene2.json +661 -227
  191. package/bundle/typescript/src/commands/game/sideQuest/types/player-equipment.d.ts +1 -0
  192. package/bundle/typescript/src/commands/game/sideQuest/types/seed/exit-seed.d.ts +1 -0
  193. package/bundle/typescript/src/commands/game/sideQuest/types/seed/item-seed.d.ts +1 -0
  194. package/bundle/typescript/src/commands/game/sideQuest/types/seed/npc-seed.d.ts +1 -0
  195. package/bundle/typescript/src/commands/game/sideQuest/types/seed/player-seed.d.ts +42 -0
  196. package/bundle/typescript/src/commands/game/sideQuest/types/seed/puzzle-seed.d.ts +15 -1
  197. package/bundle/typescript/src/commands/game/sideQuest/types/seed/room-seed.d.ts +4 -0
  198. package/bundle/typescript/src/commands/game/sideQuest/types/seed/scene-seed.d.ts +8 -0
  199. package/bundle/typescript/src/commands/game/sideQuest/types/seed/win-condition-seed.d.ts +15 -0
  200. package/bundle/typescript/src/commands/game/sideQuest/types/seed/win-condition-seed.js +2 -0
  201. package/bundle/typescript/src/commands/game/sideQuest/types/seed/win-condition-seed.js.map +1 -0
  202. package/bundle/typescript/src/commands/game/sideQuest/types/shared/abstracts.d.ts +1 -0
  203. package/bundle/typescript/src/commands/game/sideQuest/types/shared/abstracts.js +5 -0
  204. package/bundle/typescript/src/commands/game/sideQuest/types/shared/abstracts.js.map +1 -1
  205. package/bundle/typescript/src/commands/game/sideQuest/types/shared/item-enum.d.ts +1 -0
  206. package/bundle/typescript/src/commands/game/sideQuest/types/shared/item-enum.js +1 -0
  207. package/bundle/typescript/src/commands/game/sideQuest/types/shared/item-enum.js.map +1 -1
  208. package/bundle/typescript/src/commands/game/sideQuest/ui.d.ts +3 -0
  209. package/bundle/typescript/src/commands/game/sideQuest/ui.js +95 -6
  210. package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
  211. package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.d.ts +60 -0
  212. package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.js +138 -0
  213. package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.js.map +1 -0
  214. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.d.ts +145 -0
  215. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +354 -0
  216. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -0
  217. package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.d.ts +2 -0
  218. package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.js +12 -0
  219. package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.js.map +1 -0
  220. package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.d.ts +22 -0
  221. package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js +34 -0
  222. package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js.map +1 -0
  223. package/bundle/typescript/src/commands/game/sideQuest/utilities/fuzzy-match.d.ts +36 -0
  224. package/bundle/typescript/src/commands/game/sideQuest/utilities/fuzzy-match.js +92 -0
  225. package/bundle/typescript/src/commands/game/sideQuest/utilities/fuzzy-match.js.map +1 -0
  226. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.d.ts +77 -0
  227. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +265 -0
  228. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -0
  229. package/bundle/typescript/src/commands/game/sideQuest/utilities/pursuit.d.ts +16 -0
  230. package/bundle/typescript/src/commands/game/sideQuest/utilities/pursuit.js +36 -0
  231. package/bundle/typescript/src/commands/game/sideQuest/utilities/pursuit.js.map +1 -0
  232. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +78 -7
  233. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
  234. package/bundle/typescript/src/commands/set/global.sub.cmd.js +59 -5
  235. package/bundle/typescript/src/commands/set/global.sub.cmd.js.map +1 -1
  236. package/bundle/typescript/src/tools/ai/ai.class.d.ts +42 -0
  237. package/bundle/typescript/src/tools/ai/ai.class.js +117 -0
  238. package/bundle/typescript/src/tools/ai/ai.class.js.map +1 -0
  239. package/bundle/typescript/src/tools/fsi/fsi.interfaces.d.ts +1 -0
  240. package/bundle/typescript/src/tools/fsi/fsi.interfaces.js.map +1 -1
  241. package/bundle/typescript/src/tools/https/https.class.d.ts +3 -2
  242. package/bundle/typescript/src/tools/https/https.class.js +51 -2
  243. package/bundle/typescript/src/tools/https/https.class.js.map +1 -1
  244. package/bundle/typescript/src/tools/https/https.interface.d.ts +10 -0
  245. package/package.json +1 -1
@@ -0,0 +1,145 @@
1
+ import { Player } from '../models/player.js';
2
+ import { NPC } from '../models/npc.js';
3
+ import { Scene } from '../models/scene.js';
4
+ import { Logger } from './logger.js';
5
+ /**
6
+ * What one directed strike looks like mechanically -- defaults come from
7
+ * the attacker's equipped weapon (see weaponProfile()), but a spell attack
8
+ * supplies its own: a casting pool instead of Agility+skill, and a soak
9
+ * pool that ignores armor (magic's whole niche -- see commands/cast.ts).
10
+ */
11
+ export interface IStrikeProfile {
12
+ /** e.g. "with Ares Light Fire 75", "with a manabolt" */
13
+ label: string;
14
+ pool: number;
15
+ damageBase: number;
16
+ soakPool: number;
17
+ /** The physical weapon behind the strike, when there is one -- lets
18
+ * resolveStrike() spend a round of its ammunition. */
19
+ weaponItem?: import('../models/item.js').Item;
20
+ /** Subdual (see subdue.ts): damage lands on the STUN track instead of
21
+ * physical -- knockouts, not kills (though stun overflow still bleeds
22
+ * into the body). */
23
+ dealStun?: boolean;
24
+ }
25
+ /**
26
+ * The shared combat-exchange engine, extracted from AttackCommand so spell
27
+ * combat (cast.ts) rides the exact same rails: progressive block-by-block
28
+ * narration with beats, opposed strike resolution, death handling through
29
+ * the flows that already exist (removeActor for NPCs, endGame for the
30
+ * player), and the NPC follow-up pause that gives the player a window to
31
+ * act between an NPC's exchanges. See AttackCommand's class doc for the
32
+ * full rationale on pacing and self-announcement -- all of it lives here
33
+ * now, unchanged in behavior.
34
+ */
35
+ export declare class CombatExchange {
36
+ private scene;
37
+ private logger;
38
+ private actor;
39
+ /** Pause between narration blocks so a fight reads as a fight. */
40
+ static readonly BEAT_MS = 900;
41
+ /**
42
+ * Extra breathing room tacked onto the END of an NPC-initiated exchange,
43
+ * before the command returns to the NPC's AI reflect loop (which awaits
44
+ * it, so delaying the return directly throttles its next swing). This is
45
+ * the player's window to heal or flee. Player-typed actions skip it.
46
+ */
47
+ static readonly NPC_FOLLOWUP_PAUSE_MS = 2500;
48
+ constructor(scene: Scene, logger: Logger, actor: Player | NPC);
49
+ /**
50
+ * Call once combat is actually joined (gates passed, target resolved).
51
+ * While an exchange involving the player is resolving, the player can't
52
+ * "go" (see go.ts) -- you don't get to walk out from between an
53
+ * attacker's narration beats mid-exchange. finishExchange() releases the
54
+ * lock BEFORE the between-exchanges pause, which remains the legitimate
55
+ * window to flee or heal. Safe to call for NPC-vs-NPC fights too: the
56
+ * lock only engages when the player is one of the combatants.
57
+ */
58
+ private _combatants;
59
+ beginExchange(target: Player | NPC, opts?: {
60
+ aggressorDraws?: boolean;
61
+ }): string[];
62
+ /** Clears the per-combatant serialization flags. Safe to call twice. */
63
+ releaseExchange(): void;
64
+ /**
65
+ * Parks an NPC-driven action until every listed combatant's in-flight
66
+ * exchange settles, so the action fires in the lull instead of being
67
+ * discarded. Without this, an NPC's whole turn evaporated: its AI reacts
68
+ * to the player's attack within a second or two -- always mid-exchange --
69
+ * so every counterattack AND every wounded-NPC flee attempt was refused
70
+ * into its private history. Two real sessions of Krow talking trash while
71
+ * never once shooting back or making the door he was trying to flee
72
+ * through, which read to the player as the game stalling out.
73
+ *
74
+ * Resolves true when the flags clear (caller must revalidate everything:
75
+ * the waiter or its target may have died in the very exchange it sat
76
+ * out); false on timeout, meaning something is stuck and the caller
77
+ * should fall back to a plain refusal.
78
+ */
79
+ static waitForLull(combatants: (Player | NPC)[], timeoutMs?: number): Promise<boolean>;
80
+ /**
81
+ * The initiative roll-off that opens an exchange: Reaction + Intuition
82
+ * (+ live commlink AR bonus, see Player.getInitiativePool). The winner
83
+ * acts first -- attacking someone faster than you means eating their
84
+ * strike before yours lands -- with ties going to the aggressor. Winning
85
+ * by 3+ net hits earns an INITIATIVE PASS: one extra strike at the end
86
+ * of the exchange (the wired-reflexes speed fantasy, without a full
87
+ * action-economy system).
88
+ */
89
+ rollInitiative(aggressor: Player | NPC, defender: Player | NPC): {
90
+ first: Player | NPC;
91
+ second: Player | NPC;
92
+ extraStriker: Player | NPC | null;
93
+ lines: string[];
94
+ };
95
+ /**
96
+ * The player should see a fight's blow-by-blow only when they're actually
97
+ * there for it -- as a combatant or as a bystander in the same room. A
98
+ * brawl between two NPCs elsewhere in the scene stays off-screen, and
99
+ * skips the narration beats entirely.
100
+ */
101
+ playerWitnesses(): boolean;
102
+ /**
103
+ * Pushes one narration block to the player's screen (when they're present
104
+ * for it) and holds a beat before whatever happens next. Only results of
105
+ * commands the PLAYER typed flow through ui.ts's response pipeline; an
106
+ * NPC's command result goes solely into that NPC's own AI history, so
107
+ * without self-announcing here the player would never see the dice of a
108
+ * fight an NPC started. The status box refreshes with every block so the
109
+ * condition monitor visibly ticks as damage lands.
110
+ */
111
+ announce(lines: string[]): Promise<void>;
112
+ /**
113
+ * The default, weapon-based strike profile. A firearm with a dry
114
+ * magazine automatically falls back to bare fists -- this covers the
115
+ * involuntary strikes (retaliation) where refusing to swing at all would
116
+ * make no sense; a deliberately INITIATED attack with a dry gun is
117
+ * blocked with a reload prompt before ever reaching here (attack.ts).
118
+ */
119
+ weaponProfile(attacker: Player | NPC, defender: Player | NPC): IStrikeProfile;
120
+ /** One directed strike: attack vs defense, then soak. Mutates the defender. */
121
+ resolveStrike(attacker: Player | NPC, defender: Player | NPC, profile?: IStrikeProfile): string[];
122
+ /**
123
+ * Death/knockout narration is announced BEFORE the removal side effects
124
+ * run -- removeActor() fires the "drops what they carried" observer line
125
+ * straight to the screen, so running it first would put the gear hitting
126
+ * the floor before the kill itself. `fallLine`/`gameOverLine` let a caller replace
127
+ * the default gunned-down flavor; `fatal: false` marks a knockout (a
128
+ * full STUN track -- see cast.ts drain) rather than a death: same
129
+ * out-of-the-run consequences, honestly narrated as unconsciousness.
130
+ */
131
+ resolveDeath(fallen: Player | NPC, killer: Player | NPC, opts?: {
132
+ fallLine?: string;
133
+ gameOverLine?: string;
134
+ fatal?: boolean;
135
+ }): Promise<string[]>;
136
+ /**
137
+ * The screen already got everything block-by-block, so the player-typed
138
+ * path returns '' (ui.ts prints the return value -- a second copy would
139
+ * double-display). An NPC actor gets the full report back instead: that
140
+ * return value is what lands in the NPC's AI history, which is how it
141
+ * knows how its own fight went -- but only after the follow-up pause,
142
+ * which is the player's window to act before the NPC's next exchange.
143
+ */
144
+ finishExchange(report: string[]): Promise<string>;
145
+ }
@@ -0,0 +1,354 @@
1
+ import { rollPool, formatRoll } from './dice.js';
2
+ import { leaveMatrix } from './planes.js';
3
+ /**
4
+ * The shared combat-exchange engine, extracted from AttackCommand so spell
5
+ * combat (cast.ts) rides the exact same rails: progressive block-by-block
6
+ * narration with beats, opposed strike resolution, death handling through
7
+ * the flows that already exist (removeActor for NPCs, endGame for the
8
+ * player), and the NPC follow-up pause that gives the player a window to
9
+ * act between an NPC's exchanges. See AttackCommand's class doc for the
10
+ * full rationale on pacing and self-announcement -- all of it lives here
11
+ * now, unchanged in behavior.
12
+ */
13
+ export class CombatExchange {
14
+ scene;
15
+ logger;
16
+ actor;
17
+ /** Pause between narration blocks so a fight reads as a fight. */
18
+ static BEAT_MS = 900;
19
+ /**
20
+ * Extra breathing room tacked onto the END of an NPC-initiated exchange,
21
+ * before the command returns to the NPC's AI reflect loop (which awaits
22
+ * it, so delaying the return directly throttles its next swing). This is
23
+ * the player's window to heal or flee. Player-typed actions skip it.
24
+ */
25
+ static NPC_FOLLOWUP_PAUSE_MS = 2500;
26
+ constructor(scene, logger, actor) {
27
+ this.scene = scene;
28
+ this.logger = logger;
29
+ this.actor = actor;
30
+ }
31
+ /**
32
+ * Call once combat is actually joined (gates passed, target resolved).
33
+ * While an exchange involving the player is resolving, the player can't
34
+ * "go" (see go.ts) -- you don't get to walk out from between an
35
+ * attacker's narration beats mid-exchange. finishExchange() releases the
36
+ * lock BEFORE the between-exchanges pause, which remains the legitimate
37
+ * window to flee or heal. Safe to call for NPC-vs-NPC fights too: the
38
+ * lock only engages when the player is one of the combatants.
39
+ */
40
+ _combatants = [];
41
+ beginExchange(target, opts = {}) {
42
+ const player = this.scene.getPlayer();
43
+ if (this.actor === player || target === player) {
44
+ this.scene.beginPlayerExchange();
45
+ }
46
+ // Fight or flight: holstered steel comes OUT when an exchange opens
47
+ // (see Player.weaponDrawn) -- the defender's counter is always their
48
+ // lethal weapon, and the aggressor's default profile is theirs, so
49
+ // neither side should ever punch because they forgot to "brandish".
50
+ // The aggressor skips the draw when their attack isn't weapon-driven
51
+ // (a subdual hold, a spell) -- their hands are already busy.
52
+ const drawLines = [];
53
+ const shouldDraw = (c) => c.plane === 'meat' && (c !== this.actor || opts.aggressorDraws !== false);
54
+ for (const combatant of [this.actor, target]) {
55
+ if (!shouldDraw(combatant))
56
+ continue;
57
+ const drawn = combatant.drawWeapon();
58
+ if (drawn) {
59
+ this.logger.write(`${combatant.name} draws ${drawn.name} as the exchange opens.`);
60
+ drawLines.push(`${combatant.name} draws ${drawn.name}.`);
61
+ }
62
+ }
63
+ // Serialize combat per combatant (see Player.inExchange) -- callers
64
+ // gate on these flags BEFORE calling beginExchange.
65
+ this._combatants = [this.actor, target];
66
+ this.actor.inExchange = true;
67
+ target.inExchange = true;
68
+ // Initiating violence revokes your own surrender -- hands up means
69
+ // hands up (see commands/surrender.ts). The TARGET's surrender flag
70
+ // stays: being attacked while surrendered doesn't un-surrender you.
71
+ this.actor.surrendered = false;
72
+ // Both sides remember the fight -- this is what a parting shot keys
73
+ // off when either of them tries to walk away (see go.ts).
74
+ const now = Date.now();
75
+ this.actor.combatOpponent = target;
76
+ this.actor.lastExchangeAt = now;
77
+ target.combatOpponent = this.actor;
78
+ target.lastExchangeAt = now;
79
+ return drawLines;
80
+ }
81
+ /** Clears the per-combatant serialization flags. Safe to call twice. */
82
+ releaseExchange() {
83
+ for (const combatant of this._combatants) {
84
+ combatant.inExchange = false;
85
+ }
86
+ }
87
+ /**
88
+ * Parks an NPC-driven action until every listed combatant's in-flight
89
+ * exchange settles, so the action fires in the lull instead of being
90
+ * discarded. Without this, an NPC's whole turn evaporated: its AI reacts
91
+ * to the player's attack within a second or two -- always mid-exchange --
92
+ * so every counterattack AND every wounded-NPC flee attempt was refused
93
+ * into its private history. Two real sessions of Krow talking trash while
94
+ * never once shooting back or making the door he was trying to flee
95
+ * through, which read to the player as the game stalling out.
96
+ *
97
+ * Resolves true when the flags clear (caller must revalidate everything:
98
+ * the waiter or its target may have died in the very exchange it sat
99
+ * out); false on timeout, meaning something is stuck and the caller
100
+ * should fall back to a plain refusal.
101
+ */
102
+ static async waitForLull(combatants, timeoutMs = 15000) {
103
+ const busy = () => combatants.some(c => c.inExchange);
104
+ const deadline = Date.now() + timeoutMs;
105
+ while (busy()) {
106
+ if (Date.now() >= deadline)
107
+ return false;
108
+ await new Promise(resolve => setTimeout(resolve, 250));
109
+ }
110
+ return true;
111
+ }
112
+ /**
113
+ * The initiative roll-off that opens an exchange: Reaction + Intuition
114
+ * (+ live commlink AR bonus, see Player.getInitiativePool). The winner
115
+ * acts first -- attacking someone faster than you means eating their
116
+ * strike before yours lands -- with ties going to the aggressor. Winning
117
+ * by 3+ net hits earns an INITIATIVE PASS: one extra strike at the end
118
+ * of the exchange (the wired-reflexes speed fantasy, without a full
119
+ * action-economy system).
120
+ */
121
+ rollInitiative(aggressor, defender) {
122
+ const aggRoll = rollPool(aggressor.getInitiativePool());
123
+ const defRoll = rollPool(defender.getInitiativePool());
124
+ const aggressorFirst = aggRoll.hits >= defRoll.hits;
125
+ const first = aggressorFirst ? aggressor : defender;
126
+ const second = aggressorFirst ? defender : aggressor;
127
+ const net = Math.abs(aggRoll.hits - defRoll.hits);
128
+ const extraStriker = net >= 3 ? first : null;
129
+ this.logger.write(`Initiative: ${aggressor.name} ${aggRoll.hits} vs ${defender.name} ${defRoll.hits} -- ${first.name} first${extraStriker ? ' with an extra strike' : ''}.`);
130
+ const lines = [
131
+ `Initiative: ${aggressor.name} ${formatRoll(aggRoll)} vs ${defender.name} ${formatRoll(defRoll)}`,
132
+ ` ${first.name} moves first.${extraStriker ? ` And they're FAST -- an extra strike this exchange.` : ''}`,
133
+ ];
134
+ return { first, second, extraStriker, lines };
135
+ }
136
+ /**
137
+ * The player should see a fight's blow-by-blow only when they're actually
138
+ * there for it -- as a combatant or as a bystander in the same room. A
139
+ * brawl between two NPCs elsewhere in the scene stays off-screen, and
140
+ * skips the narration beats entirely.
141
+ */
142
+ playerWitnesses() {
143
+ // Same room AND perceivable plane (see Player.canPerceive): a Matrix
144
+ // brawl is invisible static to a meat bystander in the same room; an
145
+ // astral observer sees a meat fight below, dimly.
146
+ const player = this.scene.getPlayer();
147
+ return player.currentLocation === this.actor.currentLocation && player.canPerceive(this.actor);
148
+ }
149
+ /**
150
+ * Pushes one narration block to the player's screen (when they're present
151
+ * for it) and holds a beat before whatever happens next. Only results of
152
+ * commands the PLAYER typed flow through ui.ts's response pipeline; an
153
+ * NPC's command result goes solely into that NPC's own AI history, so
154
+ * without self-announcing here the player would never see the dice of a
155
+ * fight an NPC started. The status box refreshes with every block so the
156
+ * condition monitor visibly ticks as damage lands.
157
+ */
158
+ async announce(lines) {
159
+ if (lines.length === 0 || !this.playerWitnesses())
160
+ return;
161
+ this.logger.log(lines.join('\n'));
162
+ this.scene.updateStatus();
163
+ await new Promise(resolve => setTimeout(resolve, CombatExchange.BEAT_MS));
164
+ }
165
+ /**
166
+ * The default, weapon-based strike profile. A firearm with a dry
167
+ * magazine automatically falls back to bare fists -- this covers the
168
+ * involuntary strikes (retaliation) where refusing to swing at all would
169
+ * make no sense; a deliberately INITIATED attack with a dry gun is
170
+ * blocked with a reload prompt before ever reaching here (attack.ts).
171
+ */
172
+ weaponProfile(attacker, defender) {
173
+ const weapon = attacker.getWeaponProfile();
174
+ // The physical weapon only backs a MEAT-plane strike by someone who
175
+ // has it DRAWN (see Player.weaponDrawn) -- a holstered gun never
176
+ // speaks (or spends ammo), and off-plane strikes are attack programs /
177
+ // astral will, so a dry or jammed meat-side gun must not degrade them
178
+ // to "bare fists" nor burn rounds. In practice beginExchange has
179
+ // already drawn for every meat combatant.
180
+ const weaponItem = (attacker.plane === 'meat' && attacker.weaponDrawn)
181
+ ? attacker.equipment.rightHand?.weapon ?? attacker.equipment.leftHand?.weapon ?? undefined
182
+ : undefined;
183
+ // An armed edge boost (see edge.ts) lands on whichever strike this
184
+ // builds -- the attacker's next swing.
185
+ const edgeBoost = attacker.consumeEdgeBoost();
186
+ if (weaponItem?.isFirearm() && (weaponItem.ammo <= 0 || weaponItem.jammed)) {
187
+ return {
188
+ label: `with bare fists -- ${weaponItem.name} is ${weaponItem.jammed ? 'locked (smartlink hacked)' : 'dry'}`,
189
+ pool: Math.max(0, attacker.getAttackPool() - weapon.poolBonus + edgeBoost),
190
+ damageBase: 2,
191
+ soakPool: defender.getSoakPool(),
192
+ };
193
+ }
194
+ return {
195
+ label: `with ${weapon.name}`,
196
+ pool: attacker.getAttackPool() + edgeBoost,
197
+ damageBase: weapon.damage,
198
+ soakPool: defender.getSoakPool(),
199
+ weaponItem: weaponItem ?? undefined,
200
+ };
201
+ }
202
+ /** One directed strike: attack vs defense, then soak. Mutates the defender. */
203
+ resolveStrike(attacker, defender, profile) {
204
+ const strike = profile ?? this.weaponProfile(attacker, defender);
205
+ const lines = [];
206
+ // Firing costs a round; the last one gets a warning line.
207
+ if (strike.weaponItem?.isFirearm()) {
208
+ strike.weaponItem.fireRound();
209
+ this.logger.write(`${attacker.name} fired ${strike.weaponItem.name} (${strike.weaponItem.ammo} rounds left).`);
210
+ }
211
+ const attack = rollPool(strike.pool);
212
+ const defense = rollPool(defender.getDefensePool());
213
+ lines.push(`${attacker.name} attacks ${defender.name} ${strike.label}:`);
214
+ lines.push(` Attack: ${formatRoll(attack)}`);
215
+ lines.push(` Defense: ${formatRoll(defense)}`);
216
+ const dryWarning = strike.weaponItem?.isFirearm() && strike.weaponItem.ammo === 0
217
+ ? [` ${attacker.name}'s ${strike.weaponItem.name} clicks empty -- that was the last round.`]
218
+ : [];
219
+ const netHits = attack.hits - defense.hits;
220
+ if (attack.criticalGlitch) {
221
+ lines.push(` ${attacker.name}'s attack goes catastrophically wrong -- a clean miss, and everyone nearby heard it.`);
222
+ return [...lines, ...dryWarning];
223
+ }
224
+ if (netHits <= 0) {
225
+ lines.push(` ${defender.name} evades the attack.`);
226
+ return [...lines, ...dryWarning];
227
+ }
228
+ const incoming = strike.damageBase + netHits;
229
+ const soak = rollPool(strike.soakPool);
230
+ const dealt = Math.max(0, incoming - soak.hits);
231
+ lines.push(` Hit! ${netHits} net -- ${incoming} damage incoming.`);
232
+ lines.push(` Soak: ${formatRoll(soak)}`);
233
+ if (dealt === 0) {
234
+ lines.push(` ${defender.name} shrugs it off -- no damage gets through.`);
235
+ return [...lines, ...dryWarning];
236
+ }
237
+ // A jacked-in visitor takes MATRIX damage (only visitors have a
238
+ // simMode -- native ice's normal track IS its integrity, so it takes
239
+ // damage the ordinary way below). Matrix damage is HARDWARE damage:
240
+ // deck rider -- every box lands on the deck's device monitor; a
241
+ // full track BRICKS it: forced dump, dumpshock, fight
242
+ // over. Hot-sim ADDITIONALLY bleeds half the hit
243
+ // (rounded up) into the rider's real stun track.
244
+ // technomancer (no deck) -- a living persona has no hardware to
245
+ // sacrifice: EVERY box is real stun, both sim modes.
246
+ if (defender.plane === 'matrix' && defender.simMode) {
247
+ const deck = defender.activeDeck;
248
+ if (deck) {
249
+ deck.takeDeckDamage(dealt);
250
+ this.logger.write(`${attacker.name} dealt ${dealt} MATRIX damage to ${defender.name}'s ${deck.name} (${deck.deckDamage}/${deck.maxDeckBoxes}).`);
251
+ lines.push(` ${defender.name}'s ${deck.name} takes ${dealt} box${dealt === 1 ? '' : 'es'}: ${deck.deckSummary()}`);
252
+ if (defender.simMode === 'hot') {
253
+ const bio = Math.ceil(dealt / 2);
254
+ const { stun, overflow } = defender.takeStun(bio);
255
+ lines.push(` Biofeedback claws through the hot-sim link -- ${stun} stun: ${defender.stunSummary()}`);
256
+ if (overflow > 0) {
257
+ lines.push(` It's more than a mind can hold -- ${overflow} box${overflow === 1 ? '' : 'es'} spill physical: ${defender.conditionSummary()}`);
258
+ }
259
+ }
260
+ if (deck.isBricked) {
261
+ lines.push(` ${deck.name} BRICKS -- the persona collapses into static --`);
262
+ lines.push(...leaveMatrix(this.scene, defender, { forced: true, reason: `The ice burns your deck out from under you.` }));
263
+ }
264
+ return [...lines, ...dryWarning];
265
+ }
266
+ // Deckless: the living persona. Fall through to the stun branch.
267
+ }
268
+ const asStun = strike.dealStun || (defender.plane === 'matrix' && !!defender.simMode);
269
+ if (asStun) {
270
+ const { stun, overflow } = defender.takeStun(dealt);
271
+ this.logger.write(`${attacker.name} dealt ${dealt} STUN to ${defender.name} (stun ${defender.stunTaken}/${defender.maxStunBoxes}, overflow ${overflow}).`);
272
+ const bioNote = !strike.dealStun ? ' (biofeedback)' : '';
273
+ lines.push(` ${defender.name} takes ${stun} stun${bioNote}: ${defender.stunSummary()}`);
274
+ if (overflow > 0) {
275
+ lines.push(` The beating goes past unconsciousness -- ${overflow} box${overflow === 1 ? '' : 'es'} spill into their body: ${defender.conditionSummary()}`);
276
+ }
277
+ }
278
+ else {
279
+ defender.takeDamage(dealt);
280
+ this.logger.write(`${attacker.name} dealt ${dealt} boxes to ${defender.name} (${defender.damageTaken}/${defender.maxConditionBoxes}).`);
281
+ lines.push(` ${defender.name} takes ${dealt} box${dealt === 1 ? '' : 'es'}: ${defender.conditionSummary()}`);
282
+ }
283
+ return [...lines, ...dryWarning];
284
+ }
285
+ /**
286
+ * Death/knockout narration is announced BEFORE the removal side effects
287
+ * run -- removeActor() fires the "drops what they carried" observer line
288
+ * straight to the screen, so running it first would put the gear hitting
289
+ * the floor before the kill itself. `fallLine`/`gameOverLine` let a caller replace
290
+ * the default gunned-down flavor; `fatal: false` marks a knockout (a
291
+ * full STUN track -- see cast.ts drain) rather than a death: same
292
+ * out-of-the-run consequences, honestly narrated as unconsciousness.
293
+ */
294
+ async resolveDeath(fallen, killer, opts) {
295
+ const room = fallen.currentLocation;
296
+ const isPlayer = fallen === this.scene.getPlayer();
297
+ // Idempotence: if this NPC was already removed (a concurrent exchange
298
+ // beat us to the kill), don't narrate a second death or re-drop gear.
299
+ if (!isPlayer && this.scene.getActor(fallen.name) !== fallen) {
300
+ this.logger.write(`CombatExchange: ${fallen.name} already resolved as down -- skipping duplicate death.`);
301
+ return [];
302
+ }
303
+ const verb = (opts?.fatal ?? true) ? 'killed' : 'knocked out';
304
+ this.logger.write(`CombatExchange: ${killer.name} ${verb} ${fallen.name} in ${room.name}.`);
305
+ this.scene.addWorldEvent(`${killer.name} ${verb} ${fallen.name} in ${room.name}.`);
306
+ if (isPlayer) {
307
+ const lines = [opts?.fallLine ?? `You collapse. The last thing you see is ${killer.name} standing over you.`];
308
+ await this.announce(lines);
309
+ // Same flow as kill.ts and a fatal bypass: freeze input, self-announce
310
+ // so the reason stays on screen, and wait for ctrl-c ("You died!").
311
+ const gameOverLine = opts?.gameOverLine ?? `💀 GAME OVER: ${fallen.name} was gunned down by ${killer.name}.`;
312
+ void this.scene.endGame().then(() => {
313
+ this.logger.logWithColor(gameOverLine, 'red');
314
+ this.logger.logWithColor(`Press ctrl-c to quit.`, 'red');
315
+ });
316
+ return ['', ...lines];
317
+ }
318
+ const npcFall = (opts?.fatal ?? true)
319
+ ? `${fallen.name} goes down -- dead before they hit the floor. Their gear scatters across ${room.name}.`
320
+ : `${fallen.name} collapses, out cold -- down for the count. Their gear scatters across ${room.name}.`;
321
+ const lines = [opts?.fallLine ?? npcFall];
322
+ await this.announce(lines);
323
+ // scene.removeActor drops everything they carried AND wore where they
324
+ // fell -- its observer lines now correctly land after the kill above.
325
+ this.scene.removeActor(fallen.name);
326
+ return ['', ...lines];
327
+ }
328
+ /**
329
+ * The screen already got everything block-by-block, so the player-typed
330
+ * path returns '' (ui.ts prints the return value -- a second copy would
331
+ * double-display). An NPC actor gets the full report back instead: that
332
+ * return value is what lands in the NPC's AI history, which is how it
333
+ * knows how its own fight went -- but only after the follow-up pause,
334
+ * which is the player's window to act before the NPC's next exchange.
335
+ */
336
+ async finishExchange(report) {
337
+ // The exchange is resolved -- movement unlocks BEFORE the follow-up
338
+ // pause below, so the pause stays the window to flee or heal.
339
+ this.scene.endPlayerExchange();
340
+ this.releaseExchange();
341
+ this.scene.updateStatus();
342
+ // The fight autopilot's trigger: a settled exchange involving the
343
+ // player schedules their next auto action (see utilities/auto-fight.ts).
344
+ this.scene.notifyExchangeSettled(this._combatants);
345
+ if (this.actor === this.scene.getPlayer()) {
346
+ return '';
347
+ }
348
+ if (this.playerWitnesses()) {
349
+ await new Promise(resolve => setTimeout(resolve, CombatExchange.NPC_FOLLOWUP_PAUSE_MS));
350
+ }
351
+ return report.join('\n');
352
+ }
353
+ }
354
+ //# sourceMappingURL=combat-exchange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"combat-exchange.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/combat-exchange.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const CALL_ICON = "\uD83D\uDCDE";
2
+ export declare const CALL_COLOR = "cyan";
@@ -0,0 +1,12 @@
1
+ // Visual styling for commlink/AR-context messages. A call stays in the main
2
+ // log window (it's not a separate view -- it's augmented reality laid over
3
+ // wherever the player already is), but is tagged with a distinct icon and
4
+ // color so it visibly reads as a different "space" than in-person dialogue.
5
+ //
6
+ // Future contexts (the Astral Plane, VR hot-sim/cold-sim) are expected to
7
+ // follow the same shape: their own icon/color pair, applied the same way --
8
+ // not a bigger context system, just more constants like this one, until
9
+ // there's an actual second context to justify one.
10
+ export const CALL_ICON = '📞';
11
+ export const CALL_COLOR = 'cyan';
12
+ //# sourceMappingURL=comm-style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comm-style.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/comm-style.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,4EAA4E;AAC5E,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,wEAAwE;AACxE,mDAAmD;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC;AAC9B,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shadowrun-style d6 dice pools: roll N six-siders, every 5 or 6 is a hit.
3
+ * A "glitch" is rolling 1s on more than half the pool (something went ugly
4
+ * even if you succeeded); a "critical glitch" is glitching with zero hits
5
+ * (it went ugly AND you failed). Pure functions, no game-state knowledge --
6
+ * combat resolution lives in commands/attack.ts.
7
+ */
8
+ export interface IDiceRoll {
9
+ pool: number;
10
+ rolls: number[];
11
+ hits: number;
12
+ glitch: boolean;
13
+ criticalGlitch: boolean;
14
+ }
15
+ export declare function rollPool(pool: number): IDiceRoll;
16
+ /**
17
+ * One-line render of a roll for the game log, e.g.:
18
+ * "8d6 [6 5 5 3 2 1 4 6] -> 4 hits"
19
+ * The raw dice faces are shown on purpose -- watching the pool land is
20
+ * most of the fun of dice-pool combat.
21
+ */
22
+ export declare function formatRoll(roll: IDiceRoll): string;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Shadowrun-style d6 dice pools: roll N six-siders, every 5 or 6 is a hit.
3
+ * A "glitch" is rolling 1s on more than half the pool (something went ugly
4
+ * even if you succeeded); a "critical glitch" is glitching with zero hits
5
+ * (it went ugly AND you failed). Pure functions, no game-state knowledge --
6
+ * combat resolution lives in commands/attack.ts.
7
+ */
8
+ export function rollPool(pool) {
9
+ const size = Math.max(0, Math.floor(pool));
10
+ const rolls = Array.from({ length: size }, () => 1 + Math.floor(Math.random() * 6));
11
+ const hits = rolls.filter(r => r >= 5).length;
12
+ const ones = rolls.filter(r => r === 1).length;
13
+ const glitch = size > 0 && ones > size / 2;
14
+ return {
15
+ pool: size,
16
+ rolls,
17
+ hits,
18
+ glitch,
19
+ criticalGlitch: glitch && hits === 0,
20
+ };
21
+ }
22
+ /**
23
+ * One-line render of a roll for the game log, e.g.:
24
+ * "8d6 [6 5 5 3 2 1 4 6] -> 4 hits"
25
+ * The raw dice faces are shown on purpose -- watching the pool land is
26
+ * most of the fun of dice-pool combat.
27
+ */
28
+ export function formatRoll(roll) {
29
+ if (roll.pool === 0)
30
+ return '0d6 -> no dice to roll';
31
+ const glitchTag = roll.criticalGlitch ? ' -- CRITICAL GLITCH' : roll.glitch ? ' -- glitch' : '';
32
+ return `${roll.pool}d6 [${roll.rolls.join(' ')}] -> ${roll.hits} hit${roll.hits === 1 ? '' : 's'}${glitchTag}`;
33
+ }
34
+ //# sourceMappingURL=dice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dice.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/dice.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACpF,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;IAE3C,OAAO;QACL,IAAI,EAAE,IAAI;QACV,KAAK;QACL,IAAI;QACJ,MAAM;QACN,cAAc,EAAE,MAAM,IAAI,IAAI,KAAK,CAAC;KACrC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,IAAe;IACxC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,wBAAwB,CAAC;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,OAAO,GAAG,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,SAAS,EAAE,CAAC;AACjH,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared fuzzy name-matching, extracted from Inventory's item resolution so
3
+ * actor targeting (attack.ts, cast.ts) behaves the same way "take" does --
4
+ * found via a real session where "cast manabolt at mr krow" failed against
5
+ * "Mr. Krow" over a missing period. Three tiers, in order of confidence:
6
+ *
7
+ * 1. Exact match on the loosely-normalized strings (case, punctuation,
8
+ * and extra whitespace ignored -- "mr krow" == "Mr. Krow").
9
+ * 2. Substring containment, either direction -- short aliases ("krow"),
10
+ * or extra/missing words at the edges.
11
+ * 3. Word-overlap with light per-word typo tolerance (Levenshtein <= 1
12
+ * on words longer than 3 chars, stopwords ignored) -- misspellings
13
+ * and reordered/inserted words.
14
+ *
15
+ * A tier only matches when it produces exactly ONE candidate (or a clear
16
+ * best score) -- an ambiguous guess deliberately misses rather than
17
+ * picking someone at random.
18
+ */
19
+ export declare const STOPWORDS: Set<string>;
20
+ /** Lowercase, strip punctuation, collapse whitespace. */
21
+ export declare function normalizeLoose(s: string): string;
22
+ export declare function significantWords(s: string): string[];
23
+ export declare function wordsAreCloseEnough(a: string, b: string): boolean;
24
+ /**
25
+ * Damerau-Levenshtein (OSA variant): like plain Levenshtein but a swap of
26
+ * two adjacent letters counts as ONE edit, not two -- transpositions
27
+ * ("jhonson" for "johnson", "teh" for "the") are the single most common
28
+ * typo class, and plain Levenshtein prices them out of the <=1 tolerance.
29
+ */
30
+ export declare function levenshteinDistance(a: string, b: string): number;
31
+ /**
32
+ * Picks the single name from `names` that `input` most plausibly refers
33
+ * to, or undefined when nothing (or more than one thing) qualifies.
34
+ * Returns the ORIGINAL name string, not the normalized form.
35
+ */
36
+ export declare function fuzzyPickName(input: string, names: string[]): string | undefined;