@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,92 @@
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 const STOPWORDS = new Set(['a', 'an', 'the', 'of', 'on', 'in', 'at', 'to', 'with']);
20
+ /** Lowercase, strip punctuation, collapse whitespace. */
21
+ export function normalizeLoose(s) {
22
+ return s.toLowerCase().replace(/[^\w\s]/g, '').replace(/\s+/g, ' ').trim();
23
+ }
24
+ export function significantWords(s) {
25
+ return s.split(/\s+/).filter(w => w.length > 0 && !STOPWORDS.has(w));
26
+ }
27
+ export function wordsAreCloseEnough(a, b) {
28
+ if (a === b)
29
+ return true;
30
+ if (a.length <= 3 || b.length <= 3)
31
+ return false; // too short for typo tolerance to be safe
32
+ return levenshteinDistance(a, b) <= 1;
33
+ }
34
+ /**
35
+ * Damerau-Levenshtein (OSA variant): like plain Levenshtein but a swap of
36
+ * two adjacent letters counts as ONE edit, not two -- transpositions
37
+ * ("jhonson" for "johnson", "teh" for "the") are the single most common
38
+ * typo class, and plain Levenshtein prices them out of the <=1 tolerance.
39
+ */
40
+ export function levenshteinDistance(a, b) {
41
+ const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
42
+ for (let i = 0; i <= a.length; i++)
43
+ dp[i][0] = i;
44
+ for (let j = 0; j <= b.length; j++)
45
+ dp[0][j] = j;
46
+ for (let i = 1; i <= a.length; i++) {
47
+ for (let j = 1; j <= b.length; j++) {
48
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
49
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
50
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
51
+ dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + cost);
52
+ }
53
+ }
54
+ }
55
+ return dp[a.length][b.length];
56
+ }
57
+ /**
58
+ * Picks the single name from `names` that `input` most plausibly refers
59
+ * to, or undefined when nothing (or more than one thing) qualifies.
60
+ * Returns the ORIGINAL name string, not the normalized form.
61
+ */
62
+ export function fuzzyPickName(input, names) {
63
+ const normalized = normalizeLoose(input);
64
+ if (normalized.length === 0)
65
+ return undefined;
66
+ const candidates = names.map(name => ({ name, norm: normalizeLoose(name) }));
67
+ const exact = candidates.filter(c => c.norm === normalized);
68
+ if (exact.length === 1)
69
+ return exact[0].name;
70
+ if (exact.length > 1)
71
+ return undefined;
72
+ const substring = candidates.filter(c => c.norm.includes(normalized) || normalized.includes(c.norm));
73
+ if (substring.length === 1)
74
+ return substring[0].name;
75
+ const inputWords = significantWords(normalized);
76
+ if (inputWords.length === 0)
77
+ return undefined;
78
+ const scored = candidates
79
+ .map(c => {
80
+ const nameWords = significantWords(c.norm);
81
+ const matched = inputWords.filter(iw => nameWords.some(nw => wordsAreCloseEnough(iw, nw))).length;
82
+ return { name: c.name, score: matched / inputWords.length };
83
+ })
84
+ .filter(s => s.score >= 0.6)
85
+ .sort((a, b) => b.score - a.score);
86
+ if (scored.length === 1)
87
+ return scored[0].name;
88
+ if (scored.length > 1 && scored[0].score > scored[1].score)
89
+ return scored[0].name; // clear winner
90
+ return undefined;
91
+ }
92
+ //# sourceMappingURL=fuzzy-match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy-match.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/fuzzy-match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAE3F,yDAAyD;AACzD,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAS;IACxC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,CAAS;IACtD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,0CAA0C;IAC5F,OAAO,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,CAAS;IACtD,MAAM,EAAE,GAAe,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3G,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YACjF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,KAAe;IAC1D,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7E,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAEvC,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrG,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAErD,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE9C,MAAM,MAAM,GAAG,UAAU;SACtB,GAAG,CAAC,CAAC,CAAC,EAAE;QACP,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAClG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;IAC9D,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC;SAC3B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAErC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe;IAElG,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { Player, SimMode, Plane } from '../models/player.js';
2
+ import { Item } from '../models/item.js';
3
+ import { NPC } from '../models/npc.js';
4
+ import { Scene } from '../models/scene.js';
5
+ import { Room } from '../models/room.js';
6
+ /**
7
+ * Plane transitions and their tolls -- the one place that moves an actor
8
+ * between meat, Matrix, and astral (see Player.plane for the model).
9
+ *
10
+ * The invariant every transition preserves: while off the meat plane, the
11
+ * actor's empty body slumps in `bodyRoom`, visible and attackable
12
+ * (resolveBodyAttack); snapping back -- voluntarily or forced -- returns
13
+ * the actor there and settles the toll:
14
+ *
15
+ * Matrix -- voluntary jack-out is clean; a forced dump is DUMPSHOCK,
16
+ * resisted with Willpower: stun in cold-sim, PHYSICAL in
17
+ * hot-sim. The persona's Matrix track resets either way (a
18
+ * rebooted persona comes back clean).
19
+ * Astral -- the longer you were out (astralTicks, one per room-move),
20
+ * the harder the snap-back: resist ceil(ticks/2) stun with
21
+ * Willpower + half Magic; a forced return adds +2 before the
22
+ * resist.
23
+ */
24
+ export declare function planeLabel(actor: Player): string;
25
+ /** Every off-plane actor whose empty body lies in this room. */
26
+ export declare function shellsInRoom(scene: Scene, room: Room): (Player | NPC)[];
27
+ export declare function enterMatrix(scene: Scene, actor: Player, mode: SimMode): string[];
28
+ export declare function leaveMatrix(scene: Scene, actor: Player, opts?: {
29
+ forced?: boolean;
30
+ reason?: string;
31
+ }): string[];
32
+ export declare function projectAstral(scene: Scene, actor: Player): string[];
33
+ /**
34
+ * Whether this actor's jacked-in persona can touch the host in `room`.
35
+ * A wireless host (the default) is on the grid -- any persona standing in
36
+ * the room's overlay reaches it. A WIRED host is air-gapped: it only
37
+ * opens to a hard line, meaning the actor's BODY is in this room (they
38
+ * jacked in here). Movement is never gated -- the grid overlays every
39
+ * room -- only the host itself (hacking it, and its vaulted files).
40
+ */
41
+ export declare function canReachHost(actor: Player, room: Room): boolean;
42
+ /**
43
+ * An item name tinted for the plane it lives on -- the game's plane
44
+ * palette (matrix cyan, astral magenta, same as the HUD) applied to item
45
+ * listings so WHAT a thing is reads at a glance. A real session's decker
46
+ * found matrix paydata via a jacked-in search and didn't realize it was
47
+ * takeable right there: the name looked exactly like every meat item, so
48
+ * they jacked out and walked the whole map hunting for it physically.
49
+ * `viewerPlane` drives the astral cross-plane annotation (they see meat
50
+ * items, dimly, but can't carry them -- see take.ts).
51
+ */
52
+ export declare function planeTintItemName(item: Item, viewerPlane: Plane): string;
53
+ /**
54
+ * The "you can see them, but you can't touch them" refusal. When a target
55
+ * name matches someone in the room on a plane the actor perceives but
56
+ * can't reach (today: an astral projector eyeing a meat body), returns a
57
+ * line naming the actual rule -- because "Present: no one" right after
58
+ * "look" listed that very person's aura reads as a bug, not a boundary
59
+ * (real session: three attempts on a visible Mr. Krow, all told "no one").
60
+ * Returns null when no cross-plane match, so callers fall through to
61
+ * their normal miss handling. `deed` picks the phrasing: a weapon strike,
62
+ * a combat spell, or touch-range support magic.
63
+ */
64
+ export declare function crossPlaneRefusal(scene: Scene, actor: Player, room: Room, targetName: string, deed: 'strike' | 'spell' | 'touch'): string | null;
65
+ export declare function returnToBody(scene: Scene, actor: Player, opts?: {
66
+ forced?: boolean;
67
+ reason?: string;
68
+ }): string[];
69
+ /**
70
+ * A meat-plane attack on an empty body: one UNANSWERED strike -- no
71
+ * defense roll (nobody's home), meat soak only (Body + worn armor; the
72
+ * plane-aware getSoakPool would wrongly price the persona's firewall) --
73
+ * then the owner is slammed back into a body under attack, paying the
74
+ * forced-return toll on top of whatever got through. Returns the full
75
+ * narration; the caller announces it.
76
+ */
77
+ export declare function resolveBodyAttack(scene: Scene, attacker: Player | NPC, victim: Player | NPC): string[];
@@ -0,0 +1,265 @@
1
+ import { Logger } from './logger.js';
2
+ import { rollPool, formatRoll } from './dice.js';
3
+ import { fuzzyPickName } from './fuzzy-match.js';
4
+ /**
5
+ * Plane transitions and their tolls -- the one place that moves an actor
6
+ * between meat, Matrix, and astral (see Player.plane for the model).
7
+ *
8
+ * The invariant every transition preserves: while off the meat plane, the
9
+ * actor's empty body slumps in `bodyRoom`, visible and attackable
10
+ * (resolveBodyAttack); snapping back -- voluntarily or forced -- returns
11
+ * the actor there and settles the toll:
12
+ *
13
+ * Matrix -- voluntary jack-out is clean; a forced dump is DUMPSHOCK,
14
+ * resisted with Willpower: stun in cold-sim, PHYSICAL in
15
+ * hot-sim. The persona's Matrix track resets either way (a
16
+ * rebooted persona comes back clean).
17
+ * Astral -- the longer you were out (astralTicks, one per room-move),
18
+ * the harder the snap-back: resist ceil(ticks/2) stun with
19
+ * Willpower + half Magic; a forced return adds +2 before the
20
+ * resist.
21
+ */
22
+ export function planeLabel(actor) {
23
+ if (actor.plane === 'matrix')
24
+ return `MATRIX (${actor.simMode ?? 'cold'}-sim)`;
25
+ if (actor.plane === 'astral')
26
+ return 'ASTRAL';
27
+ return 'MEAT';
28
+ }
29
+ /** Every off-plane actor whose empty body lies in this room. */
30
+ export function shellsInRoom(scene, room) {
31
+ return scene.allActors.filter(a => a.plane !== 'meat' && a.bodyRoom === room);
32
+ }
33
+ export function enterMatrix(scene, actor, mode) {
34
+ actor.bodyRoom = actor.currentLocation;
35
+ actor.plane = 'matrix';
36
+ actor.simMode = mode;
37
+ // The deck you ride in on is the deck that takes the damage (see
38
+ // Item's device condition monitor). Its existing dents come with it --
39
+ // hardware doesn't heal between runs.
40
+ actor.activeDeck = actor.getCyberdeck();
41
+ actor.performAction('jacks in', `slumping where they stand, eyes flickering (${mode}-sim)`);
42
+ scene.addWorldEvent(`${actor.name} jacked into the Matrix in ${actor.bodyRoom.name}.`);
43
+ Logger.getInstance().write(`${actor.name} entered the Matrix (${mode}-sim, ${actor.activeDeck?.name ?? (actor.isTechnomancer() ? 'living persona' : 'no deck?!')}) from ${actor.bodyRoom.name}.`);
44
+ const hotWarning = mode === 'hot'
45
+ ? ` Hot-sim: everything is faster and hits harder -- including what hits YOU. Ice biofeedback bleeds into your real stun track.`
46
+ : actor.isTechnomancer()
47
+ ? ` There is no deck between you and the ice -- every hit out here is YOUR mind taking it.`
48
+ : ` Cold-sim: the ice can only chew on your deck, not your brain.`;
49
+ const deckNote = actor.activeDeck && actor.activeDeck.deckDamage > 0
50
+ ? ` Your ${actor.activeDeck.name} is already scarred: ${actor.activeDeck.deckSummary()}.`
51
+ : '';
52
+ const entry = actor.isTechnomancer()
53
+ ? `You close your eyes and the Matrix is simply THERE -- no deck, no interface, just the resonance singing. Your body slumps where you stood in ${actor.bodyRoom.name}, empty.`
54
+ : `Your ${actor.activeDeck?.name ?? 'deck'} spins up and the room dissolves into geometry -- you're in. Your body slumps where you stood in ${actor.bodyRoom.name}, empty.`;
55
+ return [
56
+ `${entry}${hotWarning}${deckNote}`,
57
+ `Move with "go" (the grid overlays the world), "hack" inside a host node, "jack out" to return.`,
58
+ ];
59
+ }
60
+ export function leaveMatrix(scene, actor, opts) {
61
+ const lines = [];
62
+ const body = actor.bodyRoom;
63
+ const wasHot = actor.simMode === 'hot';
64
+ if (opts?.forced) {
65
+ // Dumpshock: 4 boxes resisted with Willpower -- stun in cold-sim,
66
+ // physical in hot-sim (your brain was IN there).
67
+ const resist = rollPool(actor.willpower);
68
+ const dealt = Math.max(0, 4 - resist.hits);
69
+ lines.push(opts.reason ?? `The connection is severed from the other side.`);
70
+ lines.push(` DUMPSHOCK -- resist: ${formatRoll(resist)}`);
71
+ if (dealt > 0) {
72
+ if (wasHot) {
73
+ actor.takeDamage(dealt);
74
+ lines.push(` The world tears loose -- ${dealt} box${dealt === 1 ? '' : 'es'} PHYSICAL (hot-sim): ${actor.conditionSummary()}`);
75
+ }
76
+ else {
77
+ actor.takeStun(dealt);
78
+ lines.push(` Your head rings like a struck bell -- ${dealt} stun: ${actor.stunSummary()}`);
79
+ }
80
+ }
81
+ else {
82
+ lines.push(` You ride it out -- no damage.`);
83
+ }
84
+ }
85
+ else {
86
+ lines.push(`You back out clean and unplug.`);
87
+ }
88
+ // Deck damage STAYS -- it's hardware, not a session variable. A bricked
89
+ // deck refuses the next jack-in until repaired (rest.ts).
90
+ if (actor.activeDeck?.isBricked) {
91
+ lines.push(`Your ${actor.activeDeck.name} is BRICKED -- dead boards, burnt trace. It repairs while you rest somewhere safe.`);
92
+ }
93
+ actor.plane = 'meat';
94
+ actor.simMode = undefined;
95
+ actor.activeDeck = undefined;
96
+ if (body) {
97
+ actor.currentLocation = body;
98
+ actor.bodyRoom = undefined;
99
+ lines.push(`You're back in your body in ${body.name}.`);
100
+ }
101
+ actor.performAction('jacks out', 'stirring awake');
102
+ scene.addWorldEvent(`${actor.name} jacked out of the Matrix.`);
103
+ scene.updateStatus();
104
+ return lines;
105
+ }
106
+ export function projectAstral(scene, actor) {
107
+ actor.bodyRoom = actor.currentLocation;
108
+ actor.plane = 'astral';
109
+ actor.astralTicks = 0;
110
+ // Projection IS full astral senses -- the sustained half-sight toggle
111
+ // (and its -2) makes no sense out here.
112
+ actor.astralPerceiving = false;
113
+ actor.performAction('projects', 'body going slack, something vast leaving their eyes');
114
+ scene.addWorldEvent(`${actor.name} projected astrally from ${actor.bodyRoom.name}.`);
115
+ Logger.getInstance().write(`${actor.name} projected astrally from ${actor.bodyRoom.name}.`);
116
+ return [
117
+ `You slip free of your flesh. The world stays -- shifted: auras where faces were, glass-bright emotion, the meat world dim and untouchable below. Your body slumps in ${actor.bodyRoom.name}, empty.`,
118
+ `Move with "go" (locked doors mean nothing; wards do), "assense" what you see, "return" to your body. Every move out here is a debt the snap-back collects.`,
119
+ `The meat world is READ-ONLY from out here: you can watch and assense it, nothing more. No touching, no taking, no talking to the living, no spells or strikes across the veil -- astral combat only finds spirits and other projections. To act on flesh, go back to yours.`,
120
+ ];
121
+ }
122
+ /**
123
+ * Whether this actor's jacked-in persona can touch the host in `room`.
124
+ * A wireless host (the default) is on the grid -- any persona standing in
125
+ * the room's overlay reaches it. A WIRED host is air-gapped: it only
126
+ * opens to a hard line, meaning the actor's BODY is in this room (they
127
+ * jacked in here). Movement is never gated -- the grid overlays every
128
+ * room -- only the host itself (hacking it, and its vaulted files).
129
+ */
130
+ export function canReachHost(actor, room) {
131
+ if (!room.hasNode)
132
+ return false;
133
+ if (room.nodeAccess !== 'wired')
134
+ return true;
135
+ return actor.bodyRoom === room;
136
+ }
137
+ /**
138
+ * An item name tinted for the plane it lives on -- the game's plane
139
+ * palette (matrix cyan, astral magenta, same as the HUD) applied to item
140
+ * listings so WHAT a thing is reads at a glance. A real session's decker
141
+ * found matrix paydata via a jacked-in search and didn't realize it was
142
+ * takeable right there: the name looked exactly like every meat item, so
143
+ * they jacked out and walked the whole map hunting for it physically.
144
+ * `viewerPlane` drives the astral cross-plane annotation (they see meat
145
+ * items, dimly, but can't carry them -- see take.ts).
146
+ */
147
+ export function planeTintItemName(item, viewerPlane) {
148
+ if (item.plane === 'matrix') {
149
+ return `{cyan-fg}${item.name} [data]{/cyan-fg}`;
150
+ }
151
+ if (item.plane === 'astral') {
152
+ return `{magenta-fg}${item.name} [astral]{/magenta-fg}`;
153
+ }
154
+ if (viewerPlane === 'astral') {
155
+ return `${item.name} (physical -- look, don't touch)`;
156
+ }
157
+ return item.name;
158
+ }
159
+ /**
160
+ * The "you can see them, but you can't touch them" refusal. When a target
161
+ * name matches someone in the room on a plane the actor perceives but
162
+ * can't reach (today: an astral projector eyeing a meat body), returns a
163
+ * line naming the actual rule -- because "Present: no one" right after
164
+ * "look" listed that very person's aura reads as a bug, not a boundary
165
+ * (real session: three attempts on a visible Mr. Krow, all told "no one").
166
+ * Returns null when no cross-plane match, so callers fall through to
167
+ * their normal miss handling. `deed` picks the phrasing: a weapon strike,
168
+ * a combat spell, or touch-range support magic.
169
+ */
170
+ export function crossPlaneRefusal(scene, actor, room, targetName, deed) {
171
+ const visible = scene.getActorsInRoom(room)
172
+ .filter(a => a !== actor && a.plane !== actor.plane && actor.canPerceive(a));
173
+ const picked = fuzzyPickName(targetName, visible.map(a => a.name));
174
+ if (!picked)
175
+ return null;
176
+ const other = visible.find(a => a.name === picked);
177
+ if (actor.plane === 'astral' && other.plane === 'meat') {
178
+ switch (deed) {
179
+ case 'strike':
180
+ return `${other.name} is right there -- but only in the meat. From the astral you're a ghost: watch them, "assense" them, and that's all. Astral strikes only land on astral things (spirits, other projections). "return" to your body if you want to lay hands on them.`;
181
+ case 'spell':
182
+ return `${other.name}'s aura burns right below you, but mana can't cross back into the meat from out here. Spells cast while projecting only touch astral targets (spirits, projections). "return" to your body, then cast with flesh behind it.`;
183
+ case 'touch':
184
+ return `${other.name} is meat and right now you're not -- touch-range magic needs your hands. "return" to your body first.`;
185
+ }
186
+ }
187
+ return `${other.name} is on a plane your hands can't reach -- you can see them, not touch them.`;
188
+ }
189
+ export function returnToBody(scene, actor, opts) {
190
+ const lines = [];
191
+ const body = actor.bodyRoom;
192
+ const debt = Math.ceil(actor.astralTicks / 2) + (opts?.forced ? 2 : 0);
193
+ if (opts?.reason)
194
+ lines.push(opts.reason);
195
+ if (debt > 0) {
196
+ const resist = rollPool(actor.willpower + Math.floor(actor.magic / 2));
197
+ const dealt = Math.max(0, debt - resist.hits);
198
+ lines.push(` The snap-back (${debt}) -- resist: ${formatRoll(resist)}`);
199
+ if (dealt > 0) {
200
+ actor.takeStun(dealt);
201
+ lines.push(` Re-entry burns -- ${dealt} stun: ${actor.stunSummary()}`);
202
+ }
203
+ else {
204
+ lines.push(` You settle back into your flesh without a tremor.`);
205
+ }
206
+ }
207
+ else {
208
+ lines.push(`You flow back down the silver thread.`);
209
+ }
210
+ actor.plane = 'meat';
211
+ actor.astralTicks = 0;
212
+ if (body) {
213
+ actor.currentLocation = body;
214
+ actor.bodyRoom = undefined;
215
+ lines.push(`You open your own eyes in ${body.name}.`);
216
+ }
217
+ actor.performAction('returns to their body', 'drawing a sharp breath');
218
+ scene.addWorldEvent(`${actor.name} returned to their body.`);
219
+ scene.updateStatus();
220
+ return lines;
221
+ }
222
+ /**
223
+ * A meat-plane attack on an empty body: one UNANSWERED strike -- no
224
+ * defense roll (nobody's home), meat soak only (Body + worn armor; the
225
+ * plane-aware getSoakPool would wrongly price the persona's firewall) --
226
+ * then the owner is slammed back into a body under attack, paying the
227
+ * forced-return toll on top of whatever got through. Returns the full
228
+ * narration; the caller announces it.
229
+ */
230
+ export function resolveBodyAttack(scene, attacker, victim) {
231
+ const logger = Logger.getInstance();
232
+ const lines = [];
233
+ const wasPlane = victim.plane;
234
+ const weapon = attacker.getWeaponProfile();
235
+ const attack = rollPool(attacker.getAttackPool());
236
+ const soakPool = Math.max(0, victim.body + victim.getArmorValue());
237
+ lines.push(`${attacker.name} attacks ${victim.name}'s empty body with ${weapon.name} -- nobody's home to dodge:`);
238
+ lines.push(` Attack: ${formatRoll(attack)}`);
239
+ if (attack.hits === 0) {
240
+ lines.push(` Somehow, the blow goes wide of even a motionless target.`);
241
+ }
242
+ else {
243
+ const incoming = weapon.damage + attack.hits;
244
+ const soak = rollPool(soakPool);
245
+ const dealt = Math.max(0, incoming - soak.hits);
246
+ lines.push(` Hit! ${incoming} damage incoming.`);
247
+ lines.push(` Soak: ${formatRoll(soak)}`);
248
+ if (dealt === 0) {
249
+ lines.push(` The armor holds -- the body doesn't even rock.`);
250
+ }
251
+ else {
252
+ victim.takeDamage(dealt);
253
+ lines.push(` ${dealt} box${dealt === 1 ? '' : 'es'} into the defenseless flesh.`);
254
+ }
255
+ }
256
+ logger.write(`${attacker.name} attacked ${victim.name}'s empty body (${wasPlane}).`);
257
+ // The owner feels it and snaps back -- into a room with an attacker.
258
+ const reason = `Something is happening to your BODY --`;
259
+ const back = wasPlane === 'matrix'
260
+ ? leaveMatrix(scene, victim, { forced: true, reason })
261
+ : returnToBody(scene, victim, { forced: true, reason });
262
+ lines.push('', ...back);
263
+ return lines;
264
+ }
265
+ //# sourceMappingURL=planes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planes.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/planes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Scene } from '../models/scene.js';
2
+ import { Room } from '../models/room.js';
3
+ /**
4
+ * When a combat target isn't in the room, work out where they actually are
5
+ * and phrase it as something actionable -- found via a real session where a
6
+ * player ping-ponged between two rooms and the hostile NPC's AI loop just
7
+ * spammed dozens of failed "attack" commands at the empty room instead of
8
+ * chasing. The failed command's RESULT string is the one thing guaranteed
9
+ * to land in an NPC's AI history, so putting the literal next command in it
10
+ * ("go west" to chase) is what converts flailing into pursuit. Works for
11
+ * the player too: attacking someone who just fled tells you where they ran.
12
+ *
13
+ * Returns undefined when the name matches nobody in the scene at all --
14
+ * the caller keeps its ordinary "no such person" message for that.
15
+ */
16
+ export declare function describeFledTarget(scene: Scene, fromRoom: Room, targetName: string): string | undefined;
@@ -0,0 +1,36 @@
1
+ import { Door } from '../models/door.js';
2
+ import { fuzzyPickName } from './fuzzy-match.js';
3
+ /**
4
+ * When a combat target isn't in the room, work out where they actually are
5
+ * and phrase it as something actionable -- found via a real session where a
6
+ * player ping-ponged between two rooms and the hostile NPC's AI loop just
7
+ * spammed dozens of failed "attack" commands at the empty room instead of
8
+ * chasing. The failed command's RESULT string is the one thing guaranteed
9
+ * to land in an NPC's AI history, so putting the literal next command in it
10
+ * ("go west" to chase) is what converts flailing into pursuit. Works for
11
+ * the player too: attacking someone who just fled tells you where they ran.
12
+ *
13
+ * Returns undefined when the name matches nobody in the scene at all --
14
+ * the caller keeps its ordinary "no such person" message for that.
15
+ */
16
+ export function describeFledTarget(scene, fromRoom, targetName) {
17
+ const elsewhere = scene.allActors.filter(a => a.currentLocation !== fromRoom);
18
+ const pickedName = fuzzyPickName(targetName, elsewhere.map(a => a.name));
19
+ if (!pickedName)
20
+ return undefined;
21
+ const target = elsewhere.find(a => a.name === pickedName);
22
+ if (!target || !target.currentLocation)
23
+ return undefined;
24
+ const theirRoom = target.currentLocation;
25
+ // Adjacent? Name the direction and whether the way is open.
26
+ for (const [direction, exit] of fromRoom.exits.entries()) {
27
+ if (exit instanceof Door && exit.getOtherSide(fromRoom) === theirRoom) {
28
+ if (exit.checkIfLocked()) {
29
+ return `${target.name} isn't here -- they're through the ${direction} door in ${theirRoom.name}, but it's locked.`;
30
+ }
31
+ return `${target.name} isn't here -- they went ${direction}, to ${theirRoom.name}. ("go ${direction}" to chase them.)`;
32
+ }
33
+ }
34
+ return `${target.name} isn't here -- they're somewhere else (${theirRoom.name}), not within reach of this room.`;
35
+ }
36
+ //# sourceMappingURL=pursuit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pursuit.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/pursuit.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,QAAc,EAAE,UAAkB;IACjF,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;IAC9E,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAElC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe;QAAE,OAAO,SAAS,CAAC;IAEzD,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,CAAC;IAEzC,4DAA4D;IAC5D,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QACzD,IAAI,IAAI,YAAY,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE,CAAC;YACtE,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;gBACzB,OAAO,GAAG,MAAM,CAAC,IAAI,sCAAsC,SAAS,YAAY,SAAS,CAAC,IAAI,oBAAoB,CAAC;YACrH,CAAC;YACD,OAAO,GAAG,MAAM,CAAC,IAAI,4BAA4B,SAAS,QAAQ,SAAS,CAAC,IAAI,UAAU,SAAS,mBAAmB,CAAC;QACzH,CAAC;IACH,CAAC;IAED,OAAO,GAAG,MAAM,CAAC,IAAI,0CAA0C,SAAS,CAAC,IAAI,mCAAmC,CAAC;AACnH,CAAC"}
@@ -6,6 +6,12 @@ import PlayCommand from './play.command.js';
6
6
  import { Command } from '../../command.js';
7
7
  import { Actions } from '../../tools/actions/actions.class.js';
8
8
  import { Log } from '../../tools/log/log.class.js';
9
+ import { SceneSeedGenerator } from './sideQuest/factories/scene-seed-generator.js';
10
+ import { ARCHETYPES, getArchetype, outfitArchetype } from './sideQuest/archetypes.js';
11
+ import { Player } from './sideQuest/models/player.js';
12
+ import { Room } from './sideQuest/models/room.js';
13
+ import { Logger } from './sideQuest/utilities/logger.js';
14
+ import { AI } from '../../tools/ai/ai.class.js';
9
15
  const shadowrunConfig1 = require('./sideQuest/scenes/scene1.json');
10
16
  const shadowrunConfig2 = require('./sideQuest/scenes/scene2.json');
11
17
  import { fileURLToPath } from 'url';
@@ -24,20 +30,85 @@ Command.create({
24
30
  }, async function (args, opts) {
25
31
  try {
26
32
  const makaDir = this.fsi.getGlobalMakaDir();
27
- const logFilePath = path.join(makaDir, 'side-quest.log');
33
+ // Each play session gets its own directory (timestamp-named) instead of
34
+ // appending to one ever-growing log file. Generated AI scenes are saved
35
+ // alongside the log for that same session -- see SceneSeedGenerator.
36
+ const sessionId = new Date().toISOString().replace(/[:.]/g, '-');
37
+ const sessionDir = path.join(makaDir, 'side-quest-sessions', sessionId);
38
+ const logFilePath = path.join(sessionDir, 'game.log');
28
39
  const playerName = (opts.player) ? opts.player : await Actions.ask('What is your name? [Maka]') || 'Maka';
40
+ // Pick who you are before what the job is -- the archetype spread
41
+ // becomes the player's full attribute sheet (see archetypes.ts), and
42
+ // the mage archetypes are the road to playing Awakened.
43
+ const archetypeName = await Actions.select({
44
+ message: 'Who are you on the street?',
45
+ name: 'archetypeName',
46
+ choices: ARCHETYPES.map(a => ({ name: `${a.name} -- ${a.description}`, value: a.name })),
47
+ });
29
48
  const gameOptions = {
30
49
  ...opts,
31
- logFilePath
50
+ logFilePath,
51
+ // Matches the convention NPC dialogue already uses elsewhere in this
52
+ // game: AI features turn on automatically whenever a key is
53
+ // configured, with no separate flag for the player to remember.
54
+ // AI.isConfigured() picks whichever provider is set up (OpenAI or
55
+ // Anthropic -- see tools/ai/ai.class.ts).
56
+ useAi: AI.isConfigured(),
57
+ archetype: archetypeName
32
58
  };
33
- const sideQuestAnswer = await Actions.select({
59
+ const GENERATE_NEW_RUN = 'GENERATE_NEW_RUN';
60
+ // The hub (Tacoma Purple Haze) leads the list -- it's the intended
61
+ // starting ground: live there, call the fixer for runs, come home
62
+ // between them. Seattle Underground stays as the compact smoke-test
63
+ // scene (and the generation-failure fallback below).
64
+ const choices = [
65
+ { name: shadowrunConfig2.name, value: shadowrunConfig2 },
66
+ { name: shadowrunConfig1.name, value: shadowrunConfig1 },
67
+ ];
68
+ if (gameOptions.useAi) {
69
+ choices.push({ name: 'Generate a new Run (AI)', value: GENERATE_NEW_RUN });
70
+ }
71
+ let sideQuestAnswer = await Actions.select({
34
72
  message: 'Which Run would you like to play?',
35
73
  name: 'sideQuestAnswer',
36
- choices: [
37
- { name: shadowrunConfig1.name, value: shadowrunConfig1 },
38
- { name: shadowrunConfig2.name, value: shadowrunConfig2 },
39
- ]
74
+ choices
40
75
  });
76
+ if (sideQuestAnswer === GENERATE_NEW_RUN) {
77
+ const spinner = Log.withSpinner();
78
+ spinner.start('Generating a new Run');
79
+ // A throwaway player built from the picked archetype, purely as the
80
+ // generation dossier source (see buildPlayerDossier) -- the REAL
81
+ // player is constructed in the spawned ui.js child from the same
82
+ // archetype options, so this one is never played. Without it, the
83
+ // first run of a session was archetype-blind: a real Decker session
84
+ // drew a job with no Matrix content anywhere. The Logger singleton
85
+ // must be primed first -- Player's constructor grabs it, and its
86
+ // first getInstance() call demands a screen (the same headless stub
87
+ // SceneSeedGenerator itself uses).
88
+ Logger.getInstance(logFilePath, { children: [], render: () => { } });
89
+ const archetype = getArchetype(gameOptions.archetype);
90
+ const dossierPlayer = new Player({
91
+ playerName,
92
+ startLocation: new Room({ name: 'Nexus', description: 'A featureless room where lost souls drift.', roomType: 'void' }),
93
+ combat: archetype.combat,
94
+ });
95
+ outfitArchetype(dossierPlayer, archetype);
96
+ const generated = await SceneSeedGenerator.generate(logFilePath, 1, undefined, dossierPlayer);
97
+ if (generated) {
98
+ spinner.success(`-- "${generated.name}" is ready.`);
99
+ sideQuestAnswer = generated;
100
+ }
101
+ else {
102
+ // The blessed UI takes over the terminal's alternate screen buffer
103
+ // as soon as the child process starts, so a spinner message printed
104
+ // here would be swallowed before the player ever sees it -- carry
105
+ // it into the game itself instead.
106
+ const notice = 'Could not generate a new AI run this time (after 3 attempts) -- starting "Seattle Underground" instead.';
107
+ spinner.failure(notice);
108
+ sideQuestAnswer = shadowrunConfig1;
109
+ gameOptions.generationNotice = notice;
110
+ }
111
+ }
41
112
  if (playerName && sideQuestAnswer) {
42
113
  // Spawn a new process to run your main function
43
114
  const child = spawn('node', [path.resolve(__dirname, './sideQuest/ui.js'), playerName, JSON.stringify(sideQuestAnswer), JSON.stringify(gameOptions)], {