@v12-engine/engine 0.1.1 → 0.4.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 (951) hide show
  1. package/dist/abilities/amounts.d.ts +28 -0
  2. package/dist/abilities/amounts.js +74 -0
  3. package/dist/abilities/amounts.js.map +1 -0
  4. package/dist/abilities/buffs.d.ts +106 -6
  5. package/dist/abilities/buffs.js +443 -0
  6. package/dist/abilities/buffs.js.map +1 -0
  7. package/dist/abilities/castTold.d.ts +2 -0
  8. package/dist/abilities/castTold.js +66 -0
  9. package/dist/abilities/castTold.js.map +1 -0
  10. package/dist/abilities/chance.d.ts +38 -0
  11. package/dist/abilities/chance.js +77 -0
  12. package/dist/abilities/chance.js.map +1 -0
  13. package/dist/abilities/charges.d.ts +18 -0
  14. package/dist/abilities/charges.js +101 -0
  15. package/dist/abilities/charges.js.map +1 -0
  16. package/dist/abilities/control.d.ts +28 -0
  17. package/dist/abilities/control.js +113 -0
  18. package/dist/abilities/control.js.map +1 -0
  19. package/dist/abilities/dispel.js +51 -0
  20. package/dist/abilities/dispel.js.map +1 -0
  21. package/dist/abilities/effectFields.d.ts +1 -1
  22. package/dist/abilities/effectFields.js +676 -0
  23. package/dist/abilities/effectFields.js.map +1 -0
  24. package/dist/abilities/effectIndex.d.ts +27 -0
  25. package/dist/abilities/effectIndex.js +64 -0
  26. package/dist/abilities/effectIndex.js.map +1 -0
  27. package/dist/abilities/effects/buff.d.ts +9 -3
  28. package/dist/abilities/effects/buff.js +84 -0
  29. package/dist/abilities/effects/buff.js.map +1 -0
  30. package/dist/abilities/effects/conditions.d.ts +2 -0
  31. package/dist/abilities/effects/conditions.js +41 -0
  32. package/dist/abilities/effects/conditions.js.map +1 -0
  33. package/dist/abilities/effects/core.js +54 -0
  34. package/dist/abilities/effects/core.js.map +1 -0
  35. package/dist/abilities/effects/damage.d.ts +1 -1
  36. package/dist/abilities/effects/damage.js +43 -0
  37. package/dist/abilities/effects/damage.js.map +1 -0
  38. package/dist/abilities/effects/heal.d.ts +2 -2
  39. package/dist/abilities/effects/heal.js +51 -0
  40. package/dist/abilities/effects/heal.js.map +1 -0
  41. package/dist/abilities/effects/missile.d.ts +13 -1
  42. package/dist/abilities/effects/missile.js +104 -0
  43. package/dist/abilities/effects/missile.js.map +1 -0
  44. package/dist/abilities/effects/morph.d.ts +5 -0
  45. package/dist/abilities/effects/morph.js +43 -0
  46. package/dist/abilities/effects/morph.js.map +1 -0
  47. package/dist/abilities/effects/moves.d.ts +16 -4
  48. package/dist/abilities/effects/moves.js +212 -0
  49. package/dist/abilities/effects/moves.js.map +1 -0
  50. package/dist/abilities/effects/passives.d.ts +19 -9
  51. package/dist/abilities/effects/passives.js +131 -0
  52. package/dist/abilities/effects/passives.js.map +1 -0
  53. package/dist/abilities/effects/proxy.d.ts +5 -0
  54. package/dist/abilities/effects/proxy.js +60 -0
  55. package/dist/abilities/effects/proxy.js.map +1 -0
  56. package/dist/abilities/effects/sight.d.ts +2 -2
  57. package/dist/abilities/effects/sight.js +39 -0
  58. package/dist/abilities/effects/sight.js.map +1 -0
  59. package/dist/abilities/effects/spawn.d.ts +5 -2
  60. package/dist/abilities/effects/spawn.js +40 -0
  61. package/dist/abilities/effects/spawn.js.map +1 -0
  62. package/dist/abilities/effects/timed.d.ts +2 -2
  63. package/dist/abilities/effects/timed.js +96 -0
  64. package/dist/abilities/effects/timed.js.map +1 -0
  65. package/dist/abilities/effects/trade.d.ts +1 -1
  66. package/dist/abilities/effects/trade.js +25 -0
  67. package/dist/abilities/effects/trade.js.map +1 -0
  68. package/dist/abilities/effects.d.ts +97 -23
  69. package/dist/abilities/effects.js +860 -0
  70. package/dist/abilities/effects.js.map +1 -0
  71. package/dist/abilities/land.d.ts +38 -4
  72. package/dist/abilities/land.js +189 -0
  73. package/dist/abilities/land.js.map +1 -0
  74. package/dist/abilities/recast.d.ts +45 -0
  75. package/dist/abilities/recast.js +118 -0
  76. package/dist/abilities/recast.js.map +1 -0
  77. package/dist/abilities/scaled.js +40 -0
  78. package/dist/abilities/scaled.js.map +1 -0
  79. package/dist/abilities/screen.d.ts +6 -0
  80. package/dist/abilities/screen.js +83 -0
  81. package/dist/abilities/screen.js.map +1 -0
  82. package/dist/abilities/shapes.d.ts +66 -0
  83. package/dist/abilities/shapes.js +122 -0
  84. package/dist/abilities/shapes.js.map +1 -0
  85. package/dist/abilities/text.d.ts +14 -2
  86. package/dist/abilities/text.js +204 -0
  87. package/dist/abilities/text.js.map +1 -0
  88. package/dist/abilities/triggers.d.ts +98 -0
  89. package/dist/abilities/triggers.js +351 -0
  90. package/dist/abilities/triggers.js.map +1 -0
  91. package/dist/abilityChanges.d.ts +131 -0
  92. package/dist/abilityChanges.js +345 -0
  93. package/dist/abilityChanges.js.map +1 -0
  94. package/dist/ai/area.d.ts +4 -1
  95. package/dist/ai/brain.d.ts +4 -1
  96. package/dist/ai/brain.js +844 -0
  97. package/dist/ai/brain.js.map +1 -0
  98. package/dist/ai/budget.js +74 -0
  99. package/dist/ai/budget.js.map +1 -0
  100. package/dist/ai/checks.d.ts +9 -1
  101. package/dist/ai/checks.js +242 -0
  102. package/dist/ai/checks.js.map +1 -0
  103. package/dist/ai/computer.d.ts +11 -4
  104. package/dist/ai/computer.js +251 -0
  105. package/dist/ai/computer.js.map +1 -0
  106. package/dist/ai/defence.d.ts +4 -0
  107. package/dist/ai/defence.js +430 -0
  108. package/dist/ai/defence.js.map +1 -0
  109. package/dist/ai/define.d.ts +3 -2
  110. package/dist/ai/define.js +31 -0
  111. package/dist/ai/define.js.map +1 -0
  112. package/dist/ai/economy.d.ts +10 -7
  113. package/dist/ai/economy.js +780 -0
  114. package/dist/ai/economy.js.map +1 -0
  115. package/dist/ai/geometry.js +38 -0
  116. package/dist/ai/geometry.js.map +1 -0
  117. package/dist/ai/goals.d.ts +1 -0
  118. package/dist/ai/goals.js +560 -0
  119. package/dist/ai/goals.js.map +1 -0
  120. package/dist/ai/knowledge.d.ts +72 -7
  121. package/dist/ai/knowledge.js +804 -0
  122. package/dist/ai/knowledge.js.map +1 -0
  123. package/dist/ai/lanes.d.ts +10 -2
  124. package/dist/ai/lanes.js +715 -0
  125. package/dist/ai/lanes.js.map +1 -0
  126. package/dist/ai/melee/build.js +264 -0
  127. package/dist/ai/melee/build.js.map +1 -0
  128. package/dist/ai/melee/goals.d.ts +7 -0
  129. package/dist/ai/melee/goals.js +720 -0
  130. package/dist/ai/melee/goals.js.map +1 -0
  131. package/dist/ai/melee/heroes.js +68 -0
  132. package/dist/ai/melee/heroes.js.map +1 -0
  133. package/dist/ai/melee/index.d.ts +1 -1
  134. package/dist/ai/melee/index.js +51 -0
  135. package/dist/ai/melee/index.js.map +1 -0
  136. package/dist/ai/melee/production.js +29 -0
  137. package/dist/ai/melee/production.js.map +1 -0
  138. package/dist/ai/melee/surrender.js +64 -0
  139. package/dist/ai/melee/surrender.js.map +1 -0
  140. package/dist/ai/micro.d.ts +9 -0
  141. package/dist/ai/micro.js +1316 -0
  142. package/dist/ai/micro.js.map +1 -0
  143. package/dist/ai/mission.d.ts +9 -2
  144. package/dist/ai/mission.js +538 -0
  145. package/dist/ai/mission.js.map +1 -0
  146. package/dist/ai/missionRules.d.ts +1 -1
  147. package/dist/ai/missionRules.js +26 -0
  148. package/dist/ai/missionRules.js.map +1 -0
  149. package/dist/ai/module.d.ts +6 -2
  150. package/dist/ai/module.js +37 -0
  151. package/dist/ai/module.js.map +1 -0
  152. package/dist/ai/options.d.ts +3 -3
  153. package/dist/ai/plans/build.d.ts +20 -1
  154. package/dist/ai/plans/build.js +608 -0
  155. package/dist/ai/plans/build.js.map +1 -0
  156. package/dist/ai/plans/placement.d.ts +4 -1
  157. package/dist/ai/plans/placement.js +295 -0
  158. package/dist/ai/plans/placement.js.map +1 -0
  159. package/dist/ai/plans/plans.d.ts +9 -0
  160. package/dist/ai/plans/plans.js +110 -0
  161. package/dist/ai/plans/plans.js.map +1 -0
  162. package/dist/ai/plans/production.d.ts +14 -2
  163. package/dist/ai/plans/production.js +434 -0
  164. package/dist/ai/plans/production.js.map +1 -0
  165. package/dist/ai/plans/purse.d.ts +6 -3
  166. package/dist/ai/plans/purse.js +139 -0
  167. package/dist/ai/plans/purse.js.map +1 -0
  168. package/dist/ai/plans/tech.d.ts +6 -0
  169. package/dist/ai/plans/tech.js +122 -0
  170. package/dist/ai/plans/tech.js.map +1 -0
  171. package/dist/ai/profiles.d.ts +4 -4
  172. package/dist/{profiles-B3NS9jwk.js → ai/profiles.js} +3 -98
  173. package/dist/ai/profiles.js.map +1 -0
  174. package/dist/ai/reach.js +54 -0
  175. package/dist/ai/reach.js.map +1 -0
  176. package/dist/ai/report.d.ts +8 -0
  177. package/dist/ai/report.js +87 -0
  178. package/dist/ai/report.js.map +1 -0
  179. package/dist/ai/roles.d.ts +4 -0
  180. package/dist/ai/roles.js +207 -0
  181. package/dist/ai/roles.js.map +1 -0
  182. package/dist/ai/rules.d.ts +8 -2
  183. package/dist/ai/rules.js +416 -0
  184. package/dist/ai/rules.js.map +1 -0
  185. package/dist/ai/scouting.d.ts +6 -0
  186. package/dist/ai/scouting.js +324 -0
  187. package/dist/ai/scouting.js.map +1 -0
  188. package/dist/ai/settings.js +99 -0
  189. package/dist/ai/settings.js.map +1 -0
  190. package/dist/ai/squads.d.ts +21 -2
  191. package/dist/ai/squads.js +916 -0
  192. package/dist/ai/squads.js.map +1 -0
  193. package/dist/ai/strength.js +320 -0
  194. package/dist/ai/strength.js.map +1 -0
  195. package/dist/ai/task.d.ts +3 -1
  196. package/dist/ai/task.js +17 -0
  197. package/dist/ai/task.js.map +1 -0
  198. package/dist/ai/tasks/attack.js +24 -0
  199. package/dist/ai/tasks/attack.js.map +1 -0
  200. package/dist/ai/tasks/capture.d.ts +3 -3
  201. package/dist/ai/tasks/capture.js +37 -0
  202. package/dist/ai/tasks/capture.js.map +1 -0
  203. package/dist/ai/tasks/creep.js +29 -0
  204. package/dist/ai/tasks/creep.js.map +1 -0
  205. package/dist/ai/tasks/defend.js +61 -0
  206. package/dist/ai/tasks/defend.js.map +1 -0
  207. package/dist/ai/tasks/drop.js +81 -0
  208. package/dist/ai/tasks/drop.js.map +1 -0
  209. package/dist/ai/tasks/escort.js +59 -0
  210. package/dist/ai/tasks/escort.js.map +1 -0
  211. package/dist/ai/tasks/gather.js +48 -0
  212. package/dist/ai/tasks/gather.js.map +1 -0
  213. package/dist/ai/tasks/harass.js +39 -0
  214. package/dist/ai/tasks/harass.js.map +1 -0
  215. package/dist/ai/tasks/hold.js +32 -0
  216. package/dist/ai/tasks/hold.js.map +1 -0
  217. package/dist/ai/tasks/index.js +34 -0
  218. package/dist/ai/tasks/index.js.map +1 -0
  219. package/dist/ai/tasks/move.js +26 -0
  220. package/dist/ai/tasks/move.js.map +1 -0
  221. package/dist/ai/tasks/patrol.js +59 -0
  222. package/dist/ai/tasks/patrol.js.map +1 -0
  223. package/dist/ai/tasks/retreat.js +28 -0
  224. package/dist/ai/tasks/retreat.js.map +1 -0
  225. package/dist/ai/tasks/scout.js +73 -0
  226. package/dist/ai/tasks/scout.js.map +1 -0
  227. package/dist/ai/tasks/shared.d.ts +1 -1
  228. package/dist/ai/tasks/shared.js +137 -0
  229. package/dist/ai/tasks/shared.js.map +1 -0
  230. package/dist/ai/team.d.ts +18 -1
  231. package/dist/ai/team.js +492 -0
  232. package/dist/ai/team.js.map +1 -0
  233. package/dist/ai/threat.d.ts +6 -0
  234. package/dist/ai/threat.js +206 -0
  235. package/dist/ai/threat.js.map +1 -0
  236. package/dist/ai/view.d.ts +21 -7
  237. package/dist/ai/view.js +677 -0
  238. package/dist/ai/view.js.map +1 -0
  239. package/dist/ai/waves.d.ts +6 -0
  240. package/dist/ai/waves.js +410 -0
  241. package/dist/ai/waves.js.map +1 -0
  242. package/dist/ai.js +54 -6239
  243. package/dist/aiTesting.d.ts +6 -3
  244. package/dist/aiTesting.js +229 -0
  245. package/dist/aiTesting.js.map +1 -0
  246. package/dist/areas.d.ts +4 -1
  247. package/dist/areas.js +295 -0
  248. package/dist/areas.js.map +1 -0
  249. package/dist/attacks.d.ts +3 -3
  250. package/dist/attacks.js +127 -0
  251. package/dist/attacks.js.map +1 -0
  252. package/dist/burning.d.ts +267 -0
  253. package/dist/burning.js +795 -0
  254. package/dist/burning.js.map +1 -0
  255. package/dist/bytes.js +21 -0
  256. package/dist/bytes.js.map +1 -0
  257. package/dist/callings.d.ts +71 -0
  258. package/dist/callings.js +157 -0
  259. package/dist/callings.js.map +1 -0
  260. package/dist/cameraOrders.d.ts +78 -0
  261. package/dist/cameraOrders.js +114 -0
  262. package/dist/cameraOrders.js.map +1 -0
  263. package/dist/camps.d.ts +70 -4
  264. package/dist/camps.js +501 -0
  265. package/dist/camps.js.map +1 -0
  266. package/dist/capture.d.ts +15 -3
  267. package/dist/capture.js +304 -0
  268. package/dist/capture.js.map +1 -0
  269. package/dist/cellLayers.d.ts +78 -13
  270. package/dist/cellLayers.js +275 -0
  271. package/dist/cellLayers.js.map +1 -0
  272. package/dist/cellPatches.d.ts +24 -0
  273. package/dist/cellPatches.js +73 -0
  274. package/dist/cellPatches.js.map +1 -0
  275. package/dist/cinematics.d.ts +10 -5
  276. package/dist/cinematics.js +161 -0
  277. package/dist/cinematics.js.map +1 -0
  278. package/dist/clock.d.ts +2 -2
  279. package/dist/clock.js +78 -0
  280. package/dist/clock.js.map +1 -0
  281. package/dist/commands.d.ts +36 -4
  282. package/dist/commands.js +636 -0
  283. package/dist/commands.js.map +1 -0
  284. package/dist/components.d.ts +31 -10
  285. package/dist/components.js +74 -0
  286. package/dist/components.js.map +1 -0
  287. package/dist/computers.d.ts +4 -4
  288. package/dist/computers.js +194 -0
  289. package/dist/computers.js.map +1 -0
  290. package/dist/concealment.d.ts +25 -2
  291. package/dist/concealment.js +409 -0
  292. package/dist/concealment.js.map +1 -0
  293. package/dist/coreComponents.js +130 -0
  294. package/dist/coreComponents.js.map +1 -0
  295. package/dist/createGame.d.ts +306 -0
  296. package/dist/createGame.js +405 -0
  297. package/dist/createGame.js.map +1 -0
  298. package/dist/dashing.d.ts +18 -2
  299. package/dist/dashing.js +41 -0
  300. package/dist/dashing.js.map +1 -0
  301. package/dist/debug.d.ts +8 -0
  302. package/dist/debug.js +5 -3
  303. package/dist/debug2.js +76 -0
  304. package/dist/debug2.js.map +1 -0
  305. package/dist/debugCommands.d.ts +6 -6
  306. package/dist/debugCommands.js +537 -0
  307. package/dist/debugCommands.js.map +1 -0
  308. package/dist/debugging.d.ts +1 -0
  309. package/dist/defaultSets.d.ts +183 -0
  310. package/dist/defaultSets.js +216 -0
  311. package/dist/defaultSets.js.map +1 -0
  312. package/dist/definitions.d.ts +6 -0
  313. package/dist/definitions.js +78 -0
  314. package/dist/definitions.js.map +1 -0
  315. package/dist/defs.d.ts +1895 -165
  316. package/dist/defs.js +380 -0
  317. package/dist/defs.js.map +1 -0
  318. package/dist/denying.d.ts +4 -4
  319. package/dist/denying.js +106 -0
  320. package/dist/denying.js.map +1 -0
  321. package/dist/destructibles.d.ts +2 -2
  322. package/dist/destructibles.js +36 -0
  323. package/dist/destructibles.js.map +1 -0
  324. package/dist/determinism.d.ts +4 -4
  325. package/dist/determinism.js +247 -0
  326. package/dist/determinism.js.map +1 -0
  327. package/dist/dialog.d.ts +17 -2
  328. package/dist/dialog.js +108 -0
  329. package/dist/dialog.js.map +1 -0
  330. package/dist/effectRefs.js +28 -0
  331. package/dist/effectRefs.js.map +1 -0
  332. package/dist/effects.d.ts +27 -11
  333. package/dist/effects.js +110 -0
  334. package/dist/effects.js.map +1 -0
  335. package/dist/endings.d.ts +1 -1
  336. package/dist/endings.js +78 -0
  337. package/dist/endings.js.map +1 -0
  338. package/dist/engagement.d.ts +40 -6
  339. package/dist/engagement.js +530 -0
  340. package/dist/engagement.js.map +1 -0
  341. package/dist/engineEvents.d.ts +72 -9
  342. package/dist/engineEvents.js +520 -0
  343. package/dist/engineEvents.js.map +1 -0
  344. package/dist/entity.d.ts +275 -26
  345. package/dist/entity.js +441 -0
  346. package/dist/entity.js.map +1 -0
  347. package/dist/entityIndex.d.ts +10 -3
  348. package/dist/entityIndex.js +149 -0
  349. package/dist/entityIndex.js.map +1 -0
  350. package/dist/errors.d.ts +6 -2
  351. package/dist/errors.js +59 -0
  352. package/dist/errors.js.map +1 -0
  353. package/dist/events.d.ts +11 -5
  354. package/dist/events.js +158 -0
  355. package/dist/events.js.map +1 -0
  356. package/dist/exactMath.js +273 -0
  357. package/dist/exactMath.js.map +1 -0
  358. package/dist/features.d.ts +1 -1
  359. package/dist/features.js +127 -0
  360. package/dist/features.js.map +1 -0
  361. package/dist/fields.d.ts +25 -5
  362. package/dist/fields.js +140 -0
  363. package/dist/fields.js.map +1 -0
  364. package/dist/fixture.d.ts +3 -3
  365. package/dist/fixture.js +512 -0
  366. package/dist/fixture.js.map +1 -0
  367. package/dist/fog.d.ts +26 -3
  368. package/dist/fog.js +333 -0
  369. package/dist/fog.js.map +1 -0
  370. package/dist/foliage.d.ts +476 -0
  371. package/dist/foliage.js +1478 -0
  372. package/dist/foliage.js.map +1 -0
  373. package/dist/foliageDebug.d.ts +57 -0
  374. package/dist/foliageDebug.js +172 -0
  375. package/dist/foliageDebug.js.map +1 -0
  376. package/dist/foliageRegrowth.d.ts +20 -0
  377. package/dist/foliageRegrowth.js +332 -0
  378. package/dist/foliageRegrowth.js.map +1 -0
  379. package/dist/formState.d.ts +67 -0
  380. package/dist/formState.js +65 -0
  381. package/dist/formState.js.map +1 -0
  382. package/dist/formation.d.ts +46 -8
  383. package/dist/formation.js +297 -0
  384. package/dist/formation.js.map +1 -0
  385. package/dist/forms.d.ts +58 -0
  386. package/dist/forms.js +146 -0
  387. package/dist/forms.js.map +1 -0
  388. package/dist/friendlyFire.d.ts +2 -2
  389. package/dist/friendlyFire.js +37 -0
  390. package/dist/friendlyFire.js.map +1 -0
  391. package/dist/game.d.ts +141 -48
  392. package/dist/game.js +834 -0
  393. package/dist/game.js.map +1 -0
  394. package/dist/gameData.d.ts +96 -22
  395. package/dist/gameData.js +1690 -0
  396. package/dist/gameData.js.map +1 -0
  397. package/dist/gameFiles.d.ts +3 -3
  398. package/dist/gameFiles.js +14 -0
  399. package/dist/gameFiles.js.map +1 -0
  400. package/dist/gates.js +92 -0
  401. package/dist/gates.js.map +1 -0
  402. package/dist/generate.d.ts +28 -1
  403. package/dist/generate.js +1062 -0
  404. package/dist/generate.js.map +1 -0
  405. package/dist/generateWorker.d.ts +7 -3
  406. package/dist/generateWorker.js +86 -0
  407. package/dist/generateWorker.js.map +1 -0
  408. package/dist/grid.d.ts +9 -0
  409. package/dist/grid.js +102 -0
  410. package/dist/grid.js.map +1 -0
  411. package/dist/ground.d.ts +17 -1
  412. package/dist/ground.js +375 -0
  413. package/dist/ground.js.map +1 -0
  414. package/dist/groundObjects.d.ts +70 -0
  415. package/dist/groundObjects.js +371 -0
  416. package/dist/groundObjects.js.map +1 -0
  417. package/dist/groundSpeed.d.ts +20 -3
  418. package/dist/groundSpeed.js +117 -0
  419. package/dist/groundSpeed.js.map +1 -0
  420. package/dist/hero.d.ts +126 -10
  421. package/dist/hero.js +432 -0
  422. package/dist/hero.js.map +1 -0
  423. package/dist/holds.d.ts +94 -0
  424. package/dist/holds.js +305 -0
  425. package/dist/holds.js.map +1 -0
  426. package/dist/home.d.ts +1 -1
  427. package/dist/home.js +30 -0
  428. package/dist/home.js.map +1 -0
  429. package/dist/hooks.d.ts +339 -57
  430. package/dist/hooks.js +105 -0
  431. package/dist/hooks.js.map +1 -0
  432. package/dist/hotReload.d.ts +6 -5
  433. package/dist/hotReload.js +145 -0
  434. package/dist/hotReload.js.map +1 -0
  435. package/dist/ids.d.ts +3 -3
  436. package/dist/ids.js +30 -0
  437. package/dist/ids.js.map +1 -0
  438. package/dist/idsFile.d.ts +36 -0
  439. package/dist/idsFile.js +134 -0
  440. package/dist/idsFile.js.map +1 -0
  441. package/dist/index.d.ts +105 -68
  442. package/dist/index.js +194 -4701
  443. package/dist/inspect.d.ts +29 -2
  444. package/dist/{inspect-D9dWHmZ0.js → inspect.js} +21 -12
  445. package/dist/inspect.js.map +1 -0
  446. package/dist/inventory.d.ts +14 -1
  447. package/dist/inventory.js +84 -0
  448. package/dist/inventory.js.map +1 -0
  449. package/dist/items.d.ts +136 -8
  450. package/dist/items.js +585 -0
  451. package/dist/items.js.map +1 -0
  452. package/dist/lanes.d.ts +12 -3
  453. package/dist/lanes.js +496 -0
  454. package/dist/lanes.js.map +1 -0
  455. package/dist/life.d.ts +6 -2
  456. package/dist/life.js +287 -0
  457. package/dist/life.js.map +1 -0
  458. package/dist/log.d.ts +26 -3
  459. package/dist/log.js +192 -0
  460. package/dist/log.js.map +1 -0
  461. package/dist/manaBurn.d.ts +2 -2
  462. package/dist/manaBurn.js +75 -0
  463. package/dist/manaBurn.js.map +1 -0
  464. package/dist/map/file.d.ts +56 -3
  465. package/dist/map/file.js +264 -0
  466. package/dist/map/file.js.map +1 -0
  467. package/dist/map/images.js +61 -0
  468. package/dist/map/images.js.map +1 -0
  469. package/dist/map/look.d.ts +1 -1
  470. package/dist/map/look.js +30 -0
  471. package/dist/map/look.js.map +1 -0
  472. package/dist/map/pathProfile.js +183 -0
  473. package/dist/map/pathProfile.js.map +1 -0
  474. package/dist/map/resize.d.ts +4 -0
  475. package/dist/map/resize.js +136 -0
  476. package/dist/map/resize.js.map +1 -0
  477. package/dist/map/schema.js +257 -0
  478. package/dist/map/schema.js.map +1 -0
  479. package/dist/map/terrain.js +214 -0
  480. package/dist/map/terrain.js.map +1 -0
  481. package/dist/map/types.d.ts +92 -13
  482. package/dist/map/types.js +251 -0
  483. package/dist/map/types.js.map +1 -0
  484. package/dist/mapCheck/cells.js +94 -0
  485. package/dist/mapCheck/cells.js.map +1 -0
  486. package/dist/mapCheck/rules/foliage.d.ts +9 -0
  487. package/dist/mapCheck/rules/foliage.js +83 -0
  488. package/dist/mapCheck/rules/foliage.js.map +1 -0
  489. package/dist/mapCheck/rules/names.js +39 -0
  490. package/dist/mapCheck/rules/names.js.map +1 -0
  491. package/dist/mapCheck/rules/objects.d.ts +1 -1
  492. package/dist/mapCheck/rules/objects.js +56 -0
  493. package/dist/mapCheck/rules/objects.js.map +1 -0
  494. package/dist/mapCheck/rules/paths.js +32 -0
  495. package/dist/mapCheck/rules/paths.js.map +1 -0
  496. package/dist/mapCheck/rules/players.js +20 -0
  497. package/dist/mapCheck/rules/players.js.map +1 -0
  498. package/dist/mapCheck/rules/races.js +56 -0
  499. package/dist/mapCheck/rules/races.js.map +1 -0
  500. package/dist/mapCheck/rules/random.js +47 -0
  501. package/dist/mapCheck/rules/random.js.map +1 -0
  502. package/dist/mapCheck/rules/regions.js +30 -0
  503. package/dist/mapCheck/rules/regions.js.map +1 -0
  504. package/dist/mapCheck/rules/targets.js +31 -0
  505. package/dist/mapCheck/rules/targets.js.map +1 -0
  506. package/dist/mapCheck/rules/walking.js +45 -0
  507. package/dist/mapCheck/rules/walking.js.map +1 -0
  508. package/dist/mapCheck.d.ts +2 -2
  509. package/dist/mapCheck.js +63 -0
  510. package/dist/mapCheck.js.map +1 -0
  511. package/dist/mapFields.d.ts +25 -2
  512. package/dist/mapFields.js +134 -0
  513. package/dist/mapFields.js.map +1 -0
  514. package/dist/mapFile.js +176 -0
  515. package/dist/mapFile.js.map +1 -0
  516. package/dist/mapMeasure.d.ts +8 -0
  517. package/dist/mapMeasure.js +283 -0
  518. package/dist/mapMeasure.js.map +1 -0
  519. package/dist/mapMerge.d.ts +1 -0
  520. package/dist/mapMerge.js +172 -0
  521. package/dist/mapMerge.js.map +1 -0
  522. package/dist/mapObjectives.js +138 -0
  523. package/dist/mapObjectives.js.map +1 -0
  524. package/dist/mapObjects.js +80 -0
  525. package/dist/mapObjects.js.map +1 -0
  526. package/dist/math.d.ts +37 -7
  527. package/dist/math.js +155 -0
  528. package/dist/math.js.map +1 -0
  529. package/dist/messages.d.ts +71 -4
  530. package/dist/messages.js +29 -0
  531. package/dist/messages.js.map +1 -0
  532. package/dist/missionRules.d.ts +10 -2
  533. package/dist/{missionRules-C-bGxm0Q.js → missionRules.js} +30 -150
  534. package/dist/missionRules.js.map +1 -0
  535. package/dist/mods.d.ts +39 -20
  536. package/dist/mods.js +271 -0
  537. package/dist/mods.js.map +1 -0
  538. package/dist/moves.d.ts +87 -0
  539. package/dist/moves.js +539 -0
  540. package/dist/moves.js.map +1 -0
  541. package/dist/names.d.ts +7 -0
  542. package/dist/names.js +122 -0
  543. package/dist/names.js.map +1 -0
  544. package/dist/navigation/agentParams.js +14 -0
  545. package/dist/navigation/agentParams.js.map +1 -0
  546. package/dist/navigation/air.d.ts +7 -3
  547. package/dist/navigation/air.js +401 -0
  548. package/dist/navigation/air.js.map +1 -0
  549. package/dist/navigation/builds.d.ts +34 -2
  550. package/dist/navigation/builds.js +287 -0
  551. package/dist/navigation/builds.js.map +1 -0
  552. package/dist/navigation/groundAreas.d.ts +59 -1
  553. package/dist/navigation/groundAreas.js +407 -0
  554. package/dist/navigation/groundAreas.js.map +1 -0
  555. package/dist/navigation/navigation.d.ts +98 -9
  556. package/dist/navigation/recast.d.ts +194 -18
  557. package/dist/navigation/recast.js +1379 -0
  558. package/dist/navigation/recast.js.map +1 -0
  559. package/dist/navigation/sidePaths.d.ts +8 -3
  560. package/dist/navigation/sidePaths.js +241 -0
  561. package/dist/navigation/sidePaths.js.map +1 -0
  562. package/dist/navigation/sized.js +243 -0
  563. package/dist/navigation/sized.js.map +1 -0
  564. package/dist/nearest.js +32 -0
  565. package/dist/nearest.js.map +1 -0
  566. package/dist/noise.js +59 -0
  567. package/dist/noise.js.map +1 -0
  568. package/dist/objectives.d.ts +12 -3
  569. package/dist/objectives.js +144 -0
  570. package/dist/objectives.js.map +1 -0
  571. package/dist/orders/basic.d.ts +5 -5
  572. package/dist/orders/basic.js +417 -0
  573. package/dist/orders/basic.js.map +1 -0
  574. package/dist/orders/build.js +278 -0
  575. package/dist/orders/build.js.map +1 -0
  576. package/dist/orders/cast.d.ts +13 -3
  577. package/dist/orders/cast.js +558 -0
  578. package/dist/orders/cast.js.map +1 -0
  579. package/dist/orders/facts.js +16 -0
  580. package/dist/orders/facts.js.map +1 -0
  581. package/dist/orders/harvest.d.ts +21 -5
  582. package/dist/orders/harvest.js +540 -0
  583. package/dist/orders/harvest.js.map +1 -0
  584. package/dist/orders/idle.d.ts +3 -1
  585. package/dist/orders/idle.js +234 -0
  586. package/dist/orders/idle.js.map +1 -0
  587. package/dist/orders/items.js +92 -0
  588. package/dist/orders/items.js.map +1 -0
  589. package/dist/orders/queue.js +108 -0
  590. package/dist/orders/queue.js.map +1 -0
  591. package/dist/orders/waiting.d.ts +39 -0
  592. package/dist/orders/waiting.js +149 -0
  593. package/dist/orders/waiting.js.map +1 -0
  594. package/dist/pack.schema.js +13 -0
  595. package/dist/pack.schema.js.map +1 -0
  596. package/dist/pack.schema.json +7622 -841
  597. package/dist/packs/director/index.d.ts +13 -5
  598. package/dist/packs/director/index.js +204 -0
  599. package/dist/packs/director/index.js.map +1 -0
  600. package/dist/packs/heroes/campaign.d.ts +3 -2
  601. package/dist/packs/heroes/campaign.js +241 -0
  602. package/dist/packs/heroes/campaign.js.map +1 -0
  603. package/dist/packs/heroes/carry.d.ts +6 -0
  604. package/dist/packs/heroes/carry.js +112 -0
  605. package/dist/packs/heroes/carry.js.map +1 -0
  606. package/dist/packs/heroes/commands.js +115 -0
  607. package/dist/packs/heroes/commands.js.map +1 -0
  608. package/dist/packs/heroes/fallen.d.ts +43 -0
  609. package/dist/packs/heroes/fallen.js +61 -0
  610. package/dist/packs/heroes/fallen.js.map +1 -0
  611. package/dist/packs/heroes/hire.js +60 -0
  612. package/dist/packs/heroes/hire.js.map +1 -0
  613. package/dist/packs/heroes/index.d.ts +7 -6
  614. package/dist/packs/heroes/index.js +130 -0
  615. package/dist/packs/heroes/index.js.map +1 -0
  616. package/dist/packs/heroes/loop.d.ts +95 -0
  617. package/dist/packs/heroes/loop.js +250 -0
  618. package/dist/packs/heroes/loop.js.map +1 -0
  619. package/dist/packs/heroes/making.d.ts +6 -3
  620. package/dist/packs/heroes/making.js +55 -0
  621. package/dist/packs/heroes/making.js.map +1 -0
  622. package/dist/packs/heroes/respawn.d.ts +3 -3
  623. package/dist/packs/heroes/respawn.js +87 -0
  624. package/dist/packs/heroes/respawn.js.map +1 -0
  625. package/dist/packs/heroes/sets.d.ts +32 -0
  626. package/dist/packs/heroes/sets.js +51 -0
  627. package/dist/packs/heroes/sets.js.map +1 -0
  628. package/dist/packs/heroes/spells.d.ts +16 -0
  629. package/dist/packs/heroes/spells.js +269 -0
  630. package/dist/packs/heroes/spells.js.map +1 -0
  631. package/dist/packs/items/defaults.d.ts +43 -0
  632. package/dist/packs/items/defaults.js +1504 -0
  633. package/dist/packs/items/defaults.js.map +1 -0
  634. package/dist/packs/items/index.d.ts +27 -0
  635. package/dist/packs/items/index.js +214 -0
  636. package/dist/packs/items/index.js.map +1 -0
  637. package/dist/packs/moba/index.d.ts +3 -3
  638. package/dist/packs/moba/index.js +174 -0
  639. package/dist/packs/moba/index.js.map +1 -0
  640. package/dist/packs/pack.d.ts +15 -15
  641. package/dist/packs/pack.js +14 -0
  642. package/dist/packs/pack.js.map +1 -0
  643. package/dist/packs.d.ts +15 -7
  644. package/dist/packs.js +222 -0
  645. package/dist/packs.js.map +1 -0
  646. package/dist/paths.d.ts +2 -0
  647. package/dist/paths.js +109 -0
  648. package/dist/paths.js.map +1 -0
  649. package/dist/plain.js +57 -0
  650. package/dist/plain.js.map +1 -0
  651. package/dist/player.d.ts +33 -10
  652. package/dist/player.js +159 -0
  653. package/dist/player.js.map +1 -0
  654. package/dist/portals.d.ts +1 -1
  655. package/dist/portals.js +194 -0
  656. package/dist/portals.js.map +1 -0
  657. package/dist/prefabs.d.ts +25 -2
  658. package/dist/prefabs.js +239 -0
  659. package/dist/prefabs.js.map +1 -0
  660. package/dist/presetBuildings.js +58 -0
  661. package/dist/presetBuildings.js.map +1 -0
  662. package/dist/presetFoliage.d.ts +27 -0
  663. package/dist/presetFoliage.js +98 -0
  664. package/dist/presetFoliage.js.map +1 -0
  665. package/dist/presetGround.js +65 -0
  666. package/dist/presetGround.js.map +1 -0
  667. package/dist/proxies.d.ts +12 -0
  668. package/dist/proxies.js +79 -0
  669. package/dist/proxies.js.map +1 -0
  670. package/dist/query.d.ts +56 -0
  671. package/dist/query.js +88 -0
  672. package/dist/query.js.map +1 -0
  673. package/dist/races.d.ts +15 -14
  674. package/dist/races.js +172 -0
  675. package/dist/races.js.map +1 -0
  676. package/dist/randomGroups.js +91 -0
  677. package/dist/randomGroups.js.map +1 -0
  678. package/dist/registry.d.ts +117 -53
  679. package/dist/registry.js +323 -0
  680. package/dist/registry.js.map +1 -0
  681. package/dist/remains.d.ts +11 -9
  682. package/dist/remains.js +188 -0
  683. package/dist/remains.js.map +1 -0
  684. package/dist/replication.d.ts +12 -7
  685. package/dist/replication.js +100 -0
  686. package/dist/replication.js.map +1 -0
  687. package/dist/rng.d.ts +2 -0
  688. package/dist/rng.js +40 -0
  689. package/dist/rng.js.map +1 -0
  690. package/dist/rules.d.ts +186 -99
  691. package/dist/rules.js +179 -0
  692. package/dist/rules.js.map +1 -0
  693. package/dist/rulesCheck.d.ts +5 -4
  694. package/dist/rulesCheck.js +693 -0
  695. package/dist/rulesCheck.js.map +1 -0
  696. package/dist/runes.d.ts +2 -2
  697. package/dist/runes.js +80 -0
  698. package/dist/runes.js.map +1 -0
  699. package/dist/save.d.ts +37 -12
  700. package/dist/save.js +532 -0
  701. package/dist/save.js.map +1 -0
  702. package/dist/scenario.d.ts +2 -2
  703. package/dist/scenario.js +99 -0
  704. package/dist/scenario.js.map +1 -0
  705. package/dist/scheduler.d.ts +3 -0
  706. package/dist/scheduler.js +156 -0
  707. package/dist/scheduler.js.map +1 -0
  708. package/dist/score.d.ts +19 -19
  709. package/dist/score.js +709 -0
  710. package/dist/score.js.map +1 -0
  711. package/dist/sequences.d.ts +10 -6
  712. package/dist/sequences.js +206 -0
  713. package/dist/sequences.js.map +1 -0
  714. package/dist/server/doorman.js +154 -0
  715. package/dist/server/doorman.js.map +1 -0
  716. package/dist/server/gameServer.d.ts +16 -1
  717. package/dist/server/gameServer.js +643 -0
  718. package/dist/server/gameServer.js.map +1 -0
  719. package/dist/server/index.d.ts +1 -1
  720. package/dist/server/lobby.js +199 -0
  721. package/dist/server/lobby.js.map +1 -0
  722. package/dist/server/log.js +18 -0
  723. package/dist/server/log.js.map +1 -0
  724. package/dist/server/match.js +267 -0
  725. package/dist/server/match.js.map +1 -0
  726. package/dist/server/mode.d.ts +18 -9
  727. package/dist/server/mode.js +220 -0
  728. package/dist/server/mode.js.map +1 -0
  729. package/dist/{navigation-worker.js → server/navigation-worker.js} +1 -1
  730. package/dist/server/navigation-worker.js.map +1 -0
  731. package/dist/server/navigation.js +39 -0
  732. package/dist/server/navigation.js.map +1 -0
  733. package/dist/server/ops.d.ts +4 -0
  734. package/dist/server/ops.js +137 -0
  735. package/dist/server/ops.js.map +1 -0
  736. package/dist/server/packs.d.ts +3 -3
  737. package/dist/server/packs.js +32 -0
  738. package/dist/server/packs.js.map +1 -0
  739. package/dist/server/ratings.d.ts +5 -0
  740. package/dist/server/ratings.js +104 -0
  741. package/dist/server/ratings.js.map +1 -0
  742. package/dist/server/relay.d.ts +12 -2
  743. package/dist/server/relay.js +144 -0
  744. package/dist/server/relay.js.map +1 -0
  745. package/dist/server/rooms.d.ts +9 -2
  746. package/dist/server/rooms.js +442 -0
  747. package/dist/server/rooms.js.map +1 -0
  748. package/dist/server/seat.js +116 -0
  749. package/dist/server/seat.js.map +1 -0
  750. package/dist/server/seatSettings.d.ts +3 -3
  751. package/dist/server/seatSettings.js +63 -0
  752. package/dist/server/seatSettings.js.map +1 -0
  753. package/dist/server/secret.js +13 -0
  754. package/dist/server/secret.js.map +1 -0
  755. package/dist/server/start.d.ts +13 -6
  756. package/dist/server/start.js +76 -0
  757. package/dist/server/start.js.map +1 -0
  758. package/dist/server/websocket.d.ts +9 -1
  759. package/dist/server/websocket.js +306 -0
  760. package/dist/server/websocket.js.map +1 -0
  761. package/dist/server.js +15 -2861
  762. package/dist/session/can.js +26 -0
  763. package/dist/session/can.js.map +1 -0
  764. package/dist/session/commandReplay.d.ts +8 -2
  765. package/dist/session/commandReplay.js +293 -0
  766. package/dist/session/commandReplay.js.map +1 -0
  767. package/dist/session/debug.js +151 -0
  768. package/dist/session/debug.js.map +1 -0
  769. package/dist/session/delay.js +62 -0
  770. package/dist/session/delay.js.map +1 -0
  771. package/dist/session/delta.d.ts +14 -1
  772. package/dist/session/delta.js +407 -0
  773. package/dist/session/delta.js.map +1 -0
  774. package/dist/session/entityState.js +415 -0
  775. package/dist/session/entityState.js.map +1 -0
  776. package/dist/session/local.d.ts +47 -5
  777. package/dist/session/local.js +670 -0
  778. package/dist/session/local.js.map +1 -0
  779. package/dist/session/memory.d.ts +20 -2
  780. package/dist/session/memory.js +131 -0
  781. package/dist/session/memory.js.map +1 -0
  782. package/dist/session/protocol.d.ts +325 -31
  783. package/dist/session/protocol.js +55 -0
  784. package/dist/session/protocol.js.map +1 -0
  785. package/dist/session/remote.d.ts +74 -12
  786. package/dist/session/remote.js +1394 -0
  787. package/dist/session/remote.js.map +1 -0
  788. package/dist/session/replay.d.ts +11 -2
  789. package/dist/session/replay.js +160 -0
  790. package/dist/session/replay.js.map +1 -0
  791. package/dist/session/seed.js +12 -0
  792. package/dist/session/seed.js.map +1 -0
  793. package/dist/session/share.d.ts +5 -1
  794. package/dist/session/share.js +94 -0
  795. package/dist/session/share.js.map +1 -0
  796. package/dist/session/socket.d.ts +1 -1
  797. package/dist/session/socket.js +29 -0
  798. package/dist/session/socket.js.map +1 -0
  799. package/dist/session/wire.d.ts +5 -0
  800. package/dist/session/wire.js +84 -0
  801. package/dist/session/wire.js.map +1 -0
  802. package/dist/session/worker.d.ts +77 -12
  803. package/dist/session/worker.js +499 -0
  804. package/dist/session/worker.js.map +1 -0
  805. package/dist/shared.d.ts +31 -5
  806. package/dist/shared.js +166 -0
  807. package/dist/shared.js.map +1 -0
  808. package/dist/sides.d.ts +9 -3
  809. package/dist/sides.js +149 -0
  810. package/dist/sides.js.map +1 -0
  811. package/dist/sight.js +85 -0
  812. package/dist/sight.js.map +1 -0
  813. package/dist/simulate-worker.js +1 -1
  814. package/dist/simulate.d.ts +12 -8
  815. package/dist/{simulate-oXBiw1Ff.js → simulate.js} +10 -11
  816. package/dist/simulate.js.map +1 -0
  817. package/dist/smart.js +77 -0
  818. package/dist/smart.js.map +1 -0
  819. package/dist/spatial.d.ts +32 -16
  820. package/dist/spatial.js +234 -0
  821. package/dist/spatial.js.map +1 -0
  822. package/dist/spawning.d.ts +1 -0
  823. package/dist/spawning.js +224 -0
  824. package/dist/spawning.js.map +1 -0
  825. package/dist/stances.d.ts +6 -3
  826. package/dist/stances.js +169 -0
  827. package/dist/stances.js.map +1 -0
  828. package/dist/start.d.ts +10 -10
  829. package/dist/start.js +75 -0
  830. package/dist/start.js.map +1 -0
  831. package/dist/stats.d.ts +42 -16
  832. package/dist/stats.js +290 -0
  833. package/dist/stats.js.map +1 -0
  834. package/dist/summoned.d.ts +52 -0
  835. package/dist/summoned.js +38 -0
  836. package/dist/summoned.js.map +1 -0
  837. package/dist/summons.d.ts +10 -13
  838. package/dist/summons.js +271 -0
  839. package/dist/summons.js.map +1 -0
  840. package/dist/systems/abilities.js +224 -0
  841. package/dist/systems/abilities.js.map +1 -0
  842. package/dist/systems/combat.d.ts +35 -1
  843. package/dist/systems/combat.js +677 -0
  844. package/dist/systems/combat.js.map +1 -0
  845. package/dist/systems/combatTold.d.ts +3 -1
  846. package/dist/systems/combatTold.js +85 -0
  847. package/dist/systems/combatTold.js.map +1 -0
  848. package/dist/systems/construction.js +80 -0
  849. package/dist/systems/construction.js.map +1 -0
  850. package/dist/systems/economy.d.ts +0 -6
  851. package/dist/systems/economy.js +128 -0
  852. package/dist/systems/economy.js.map +1 -0
  853. package/dist/systems/fog.d.ts +1 -1
  854. package/dist/systems/fog.js +120 -0
  855. package/dist/systems/fog.js.map +1 -0
  856. package/dist/systems/life.js +32 -0
  857. package/dist/systems/life.js.map +1 -0
  858. package/dist/systems/movement.d.ts +24 -12
  859. package/dist/systems/movement.js +1247 -0
  860. package/dist/systems/movement.js.map +1 -0
  861. package/dist/systems/orders.js +64 -0
  862. package/dist/systems/orders.js.map +1 -0
  863. package/dist/systems/production.js +322 -0
  864. package/dist/systems/production.js.map +1 -0
  865. package/dist/systems/productionQueue.js +120 -0
  866. package/dist/systems/productionQueue.js.map +1 -0
  867. package/dist/systems/victory.d.ts +1 -1
  868. package/dist/systems/victory.js +56 -0
  869. package/dist/systems/victory.js.map +1 -0
  870. package/dist/talk.d.ts +6 -6
  871. package/dist/talk.js +153 -0
  872. package/dist/talk.js.map +1 -0
  873. package/dist/targeting.d.ts +142 -0
  874. package/dist/targeting.js +49 -0
  875. package/dist/targeting.js.map +1 -0
  876. package/dist/tech.d.ts +20 -3
  877. package/dist/tech.js +239 -0
  878. package/dist/tech.js.map +1 -0
  879. package/dist/techTree.d.ts +7 -0
  880. package/dist/techTree.js +90 -0
  881. package/dist/techTree.js.map +1 -0
  882. package/dist/terrain.d.ts +59 -7
  883. package/dist/terrain.js +389 -0
  884. package/dist/terrain.js.map +1 -0
  885. package/dist/terrainSave.d.ts +6 -0
  886. package/dist/terrainSave.js +74 -0
  887. package/dist/terrainSave.js.map +1 -0
  888. package/dist/testing.d.ts +8 -7
  889. package/dist/testing.js +13 -739
  890. package/dist/testing.js.map +1 -1
  891. package/dist/tiles.d.ts +1 -1
  892. package/dist/tiles.js +43 -0
  893. package/dist/tiles.js.map +1 -0
  894. package/dist/timers.d.ts +29 -4
  895. package/dist/timers.js +242 -0
  896. package/dist/timers.js.map +1 -0
  897. package/dist/tomes.d.ts +4 -4
  898. package/dist/tomes.js +94 -0
  899. package/dist/tomes.js.map +1 -0
  900. package/dist/trade.js +103 -0
  901. package/dist/trade.js.map +1 -0
  902. package/dist/transport.d.ts +6 -1
  903. package/dist/transport.js +281 -0
  904. package/dist/transport.js.map +1 -0
  905. package/dist/tunables.d.ts +10 -3
  906. package/dist/tunables.js +56 -0
  907. package/dist/tunables.js.map +1 -0
  908. package/dist/unitResources.d.ts +67 -0
  909. package/dist/unitResources.js +266 -0
  910. package/dist/unitResources.js.map +1 -0
  911. package/dist/upkeep.d.ts +6 -1
  912. package/dist/upkeep.js +26 -0
  913. package/dist/upkeep.js.map +1 -0
  914. package/dist/veterancy.d.ts +8 -3
  915. package/dist/veterancy.js +131 -0
  916. package/dist/veterancy.js.map +1 -0
  917. package/dist/vision.d.ts +36 -0
  918. package/dist/vision.js +133 -0
  919. package/dist/vision.js.map +1 -0
  920. package/dist/walls.d.ts +1 -1
  921. package/dist/walls.js +278 -0
  922. package/dist/walls.js.map +1 -0
  923. package/dist/world.d.ts +606 -88
  924. package/dist/world.js +1263 -0
  925. package/dist/world.js.map +1 -0
  926. package/package.json +2 -2
  927. package/dist/ai.js.map +0 -1
  928. package/dist/attributes.d.ts +0 -66
  929. package/dist/brain-BvVdUhX8.js +0 -7659
  930. package/dist/brain-BvVdUhX8.js.map +0 -1
  931. package/dist/builds-C6LfgvEU.js +0 -460
  932. package/dist/builds-C6LfgvEU.js.map +0 -1
  933. package/dist/coreComponents-syuh2fPG.js +0 -5149
  934. package/dist/coreComponents-syuh2fPG.js.map +0 -1
  935. package/dist/debugCommands-CzjrSm66.js +0 -14739
  936. package/dist/debugCommands-CzjrSm66.js.map +0 -1
  937. package/dist/determinism-BCymQwiE.js +0 -518
  938. package/dist/determinism-BCymQwiE.js.map +0 -1
  939. package/dist/game-DiJEN-Ks.js +0 -5800
  940. package/dist/game-DiJEN-Ks.js.map +0 -1
  941. package/dist/index.js.map +0 -1
  942. package/dist/inspect-D9dWHmZ0.js.map +0 -1
  943. package/dist/local-Dkovq42k.js +0 -1379
  944. package/dist/local-Dkovq42k.js.map +0 -1
  945. package/dist/missionRules-C-bGxm0Q.js.map +0 -1
  946. package/dist/navigation-worker.js.map +0 -1
  947. package/dist/packs-g5thvmGn.js +0 -3199
  948. package/dist/packs-g5thvmGn.js.map +0 -1
  949. package/dist/profiles-B3NS9jwk.js.map +0 -1
  950. package/dist/server.js.map +0 -1
  951. package/dist/simulate-oXBiw1Ff.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"squads.js","names":[],"sources":["../../src/ai/squads.ts"],"sourcesContent":["import type { Layer } from '#engine/defs'\nimport type { OrderInit } from '#engine/registry'\nimport type { AiArea } from './area'\nimport { distSq, type Vec2 } from '#engine/math'\nimport type { EntityState } from '#engine/session/protocol'\nimport { DEFAULT_STANCE, stance, stanceCommand } from '#engine/stances'\nimport { type Brain } from './brain'\nimport { type AiModule, type AiModuleDef, defineModule } from './module'\nimport { UnitSet } from './view'\nimport { ATTACK, CAPTURE, CREEP, DEFEND_TASK, DROP, ESCORT, GATHER, HARASS, HOLD, MOVE, PATROL, RETREAT, SCOUT_TASK, TASKS } from './tasks'\nimport type { TaskCommon, TaskData, TaskDef, TaskDone, TaskOrder, TaskState } from './task'\nimport { capturePointsOf } from './tasks/shared'\nimport { heroOfState } from '#engine/hero'\nimport { pair, plural, point, where } from './geometry'\nimport { ENGAGED, FIGHT_REACH, RESEND } from './reach'\n\n/*\n * Squads and their tasks (AI plan, C1): the unit of command. A goal that holds units (B1) used to send them all one\n * order and hope; two goals could send one unit two ways in a think, and nothing watched an order once it was sent.\n * A **squad** is a named group of the player's units with one **task** (attack there, defend here, gather at the rally\n * and then go): the goal, rule or module that made it says what, once, and the squads module (`squads()`) sees it\n * done, think after think:\n *\n * - **An order is sent once and watched.** A unit told to attack-move every second never arrives: it stops and\n * starts. A task sends its orders as it begins, then each think looks at how it goes (where the squad is, whether a\n * unit stands idle short of where it was sent, whether its target is still there) and sends again only what was lost.\n * - **A squad regroups when spread.** Units walk at different speeds: a column of footmen and knights arrives one by\n * one and is beaten one by one. When too many of its units (`regroupWhen`, four tenths) are further than `spread`\n * from its middle, on its way and out of a fight, the squad gathers on its middle, then goes on.\n * - **A squad retreats when it is losing.** In a fight away from home, with its odds (`Strength.odds`, A4) under\n * `retreatAt` (three tenths), it falls back home (the classic Groups Flee): the task becomes `retreat`, done\n * (`retreated`) once home. Whoever made it decides what next.\n * - **A squad is reinforced** (`reinforce`): what it lost since its task began is made up from the pool (the fighters\n * nothing holds, idle), the nearest first, sent to join it.\n *\n * **Who may move a unit.** The goals' holds are the one place that says (B1): a unit is held by one goal, rule or\n * module at a time (`ai.goals.holder`), and a squad is made of what its **owner** holds. A squad made in a goal's\n * `run` with `claimed.squad` is the goal's: when the goal stops, its squads go; a unit another goal took leaves the squad\n * that think. A squad made anywhere else (a rule, a module) holds its units itself, until it is disbanded (`take`\n * with `seconds: Infinity`, under `squad:<name>` or the owner it names), taking them from whatever goal had them,\n * which is told (`stop('told')`). A unit is in one squad at a time: a squad made of units of another takes them out\n * of it.\n *\n * Tasks are plain data (`TaskState`: its kind, what it was given, its phase, when it began, its own memory), kept in\n * the brain's memory with the squads, so that a save keeps the army on its way. The kit's tasks (`attack`, `defend`,\n * `hold`, `move`, `escort`, `harass`, `scout`, `gather`, `retreat`, `creep`, `patrol`) send the engine's orders; a game's own is\n * `defineTask` (a capture, a garrison, an order of the game's), run with the same regroup, reinforce and retreat\n * around it unless it says it `handles` them.\n */\n\n/** Seconds a squad waits for its stragglers at most, regrouping, before it goes on with what it has */\nconst REGROUP_FOR = 10\n/** Seconds between two calls for reinforcements */\nconst REINFORCE_EVERY = 5\n/** How far aside of the hottest place on its way a squad that avoids looks for a way round, then half as far again */\nconst DETOUR = 24\n/** Seconds a sighting of their army counts as where it is, for a squad that avoids it */\nconst AVOID_SEEN = 60\n\n/**\n * How a squad behaves around its task (`SquadsOptions`, `ai.squads.make(name, units, options)`): when it regroups,\n * reinforces, retreats. Plain data, kept in a save\n *\n * @beta\n */\nexport interface SquadOptions {\n\t/**\n\t * How far from its middle a unit may be before it counts as strayed: what a regroup brings in. Grows with the squad\n\t * when left out (8, and three times the square root of its size above that: 12 for sixteen units)\n\t */\n\tspread?: number\n\t/** The share of its units strayed (`spread`) at which it stops to regroup, on its way and out of a fight: 0.4. `false` never */\n\tregroupWhen?: number | false\n\t/** Whether it makes up what it lost since its task began from the pool (the idle fighters nothing holds): no when left out */\n\treinforce?: boolean\n\t/**\n\t * Its odds in a fight (`Strength.odds`) under which it falls back home, away from home: 0.3. `false` fights on to the\n\t * last (a mission's guards)\n\t */\n\tretreatAt?: number | false\n\t/** How near home it fights on whatever the odds: there is nowhere to fall back to. 20 when left out */\n\thome?: number\n\t/**\n\t * Whether the micro module (`micro()`, C2) fights for it once it is in a fight: focus fire, kiting, fleeing, siege.\n\t * Yes when left out; `false` for a squad left to its units (a scout, a mission's guards on an order of the game's)\n\t */\n\tmicro?: boolean\n}\n\n/**\n * How a brain's squads behave, where a squad says nothing for itself (`BrainDef.squads`, the seat's `AiOptions.squads`\n * over it); and the tasks of the game's own (`defineTask`) a save of the brain may name\n *\n * @beta\n */\nexport interface SquadsOptions extends SquadOptions {\n\t/** Tasks of the game's own: registered with the brain, so that a squad on one is carried on after a load */\n\ttasks?: TaskDef[]\n}\n\n/**\n * A squad as the brain remembers it: plain data, kept in a save\n *\n * @beta\n */\nexport interface SquadData {\n\t/** Unique among the brain's squads */\n\tname: string\n\t/** Who it belongs to: a goal's id, a rule's or a module's hold (`squad:<name>` for one of its own) */\n\towner: string\n\t/** Its units, by id, in the picture's order */\n\tunits: number[]\n\t/** How it behaves: its own, over the brain's */\n\toptions: SquadOptions\n\t/** What it is doing. None for a squad told nothing yet */\n\ttask?: TaskState\n\t/** How many units its task began with, or was given since: what reinforcements make up */\n\tsize: number\n\t/** The tick it was made at */\n\tmade: number\n\t/** How many times it fell back from a fight it was losing */\n\tretreats: number\n\t/** The last time its units or its task changed, and why, in words */\n\tchanged?: { tick: number; why: string }\n\t/** The tick it may next call for reinforcements */\n\tnextReinforce?: number\n}\n\n/**\n * What the squads remember between thinks, for a save\n *\n * @beta\n */\nexport interface SquadsMemory {\n\t/** The version of the memory's format: 1 so far */\n\tv: 1\n\t/** Each squad's data */\n\tsquads: SquadData[]\n}\n\n/**\n * A squad as the report shows it: who it belongs to, its units and their strength, where it is, its task and how it goes\n *\n * @beta\n */\nexport interface SquadReport {\n\t/** The squad's name, by which it is found (`ai.squads.named`) */\n\tname: string\n\t/** What holds the squad: the module or goal that made it */\n\towner: string\n\t/** The entity ids of its units */\n\tunits: number[]\n\t/** How strong its units are together */\n\tstrength: number\n\t/** Its middle */\n\tat?: [number, number]\n\t/** How many units it has */\n\tsize: number\n\t/** Its task: the kind, the phase it is in, since when, where, and how it ended once done */\n\ttask?: { kind: string; phase: string; since: number; at?: [number, number]; done?: TaskDone }\n\t/** How many times it retreated */\n\tretreats: number\n\t/** The tick its task last changed and why */\n\tchanged?: { tick: number; why: string }\n}\n\n/**\n * A squad of the brain (`ai.squads.make`, `named`, `all`): a handle over its data, with the task methods. A squad's\n * units are as of the think's picture: the dead and those its owner no longer holds are dropped as the squads module\n * looks at it\n *\n * @beta\n */\nexport class Squad {\n\tconstructor(\n\t\t/** The squads it is one of */\n\t\treadonly squads: Squads,\n\t\t/** What it is, as plain data: what a save keeps */\n\t\treadonly data: SquadData\n\t) {}\n\n\t/** Its name: unique among the brain's squads */\n\tget name(): string {\n\t\treturn this.data.name\n\t}\n\n\t/** Who it belongs to: the goal, rule or module that made it */\n\tget owner(): string {\n\t\treturn this.data.owner\n\t}\n\n\t/** What it is doing: none for a squad told nothing yet */\n\tget current(): TaskState | undefined {\n\t\treturn this.data.task\n\t}\n\n\t/** How its task ended: none while it goes on, or while it has none */\n\tget done(): TaskDone | undefined {\n\t\treturn this.data.task?.done\n\t}\n\n\t/** Whether it has nothing to do: no task, or its task is over */\n\tget idle(): boolean {\n\t\treturn !this.data.task || this.data.task.done !== undefined\n\t}\n\n\t/** Whether it is still one of the brain's squads: not once disbanded */\n\tget alive(): boolean {\n\t\treturn this.squads.named(this.data.name) === this\n\t}\n\n\t/** How it behaves: its own options over the brain's */\n\tget options(): SquadOptions {\n\t\treturn this.data.options\n\t}\n\n\t/** Its units, as of the think's picture: those alive and the player's */\n\tunits(): UnitSet {\n\t\tconst { view } = this.squads.ai\n\t\treturn new UnitSet(\n\t\t\tview,\n\t\t\tthis.data.units.map((id) => view.byId(id)).filter((unit): unit is EntityState => !!unit && unit.health > 0)\n\t\t)\n\t}\n\n\t/** How many units it has */\n\tget length(): number {\n\t\treturn this.data.units.length\n\t}\n\n\t/** How strong it is together (`UnitSet.strength`) */\n\tstrength(): number {\n\t\treturn this.units().strength()\n\t}\n\n\t/** Its middle: none with no unit left */\n\tcentre(): Vec2 | undefined {\n\t\treturn this.units().centre()\n\t}\n\n\t/**\n\t * How far from its middle a unit may be before it counts as strayed (`SquadOptions.spread`): grows with the squad\n\t * when not given\n\t */\n\tspread(): number {\n\t\treturn this.data.options.spread ?? Math.max(8, 3 * Math.sqrt(this.data.units.length))\n\t}\n\n\t/** Adds units: what its owner may have (see `Squads.make`), taken out of any other squad */\n\tadd(units: Iterable<EntityState | number>, why = 'given'): this {\n\t\tconst added = this.squads.enlist(this, ids(units))\n\t\tif (added.length) {\n\t\t\tthis.data.size = Math.max(this.data.size, this.data.units.length)\n\t\t\tthis.changed(`${why}: ${plural(added.length)}`)\n\t\t}\n\t\treturn this\n\t}\n\n\t/** Takes units out: they go back to the pool (its owner lets go of them) */\n\tremove(units: Iterable<EntityState | number>, why = 'taken out'): this {\n\t\tconst gone = new Set(ids(units))\n\t\tconst removed = this.data.units.filter((id) => gone.has(id))\n\t\tif (!removed.length) return this\n\t\tthis.data.units = this.data.units.filter((id) => !gone.has(id))\n\t\tthis.squads.ai.goals.drop(this.data.owner, removed)\n\t\tthis.changed(`${why}: ${plural(removed.length)}`)\n\t\treturn this\n\t}\n\n\t/** Disbands it: its units go back to its owner (a goal's), or to the pool (a squad of its own) */\n\tdisband(why = 'disbanded'): void {\n\t\tthis.squads.disband(this, why)\n\t}\n\n\t/** Writes down the last change of its units or task, for the report */\n\tchanged(why: string): void {\n\t\tthis.data.changed = { tick: this.squads.ai.tick, why }\n\t}\n\n\t/**\n\t * Gives it a task: one of the kit's by its word (`attack`), or of the game's (`defineTask`, by its def or its id).\n\t * What it was doing is over. Its first orders go at once; the squads module watches it from then on\n\t */\n\ttask<D extends object, M extends object>(def: TaskDef<D, M>, data: D & TaskCommon): this\n\t/** Gives the squad a task of a game's own, by its definition and data; what it was doing is over and the squad is returned */\n\ttask(kind: string, data?: TaskData): this\n\ttask(kind: string | TaskDef, data: TaskData = {}): this {\n\t\tthis.squads.give(this, kind, data)\n\t\treturn this\n\t}\n\n\t/** Ends its task, saying how: what a task's `think` calls once it is over */\n\tfinish(done: TaskDone): void {\n\t\tconst state = this.data.task\n\t\tif (!state || state.done !== undefined) return\n\t\tstate.done = done\n\t\tstate.doneAt = this.squads.ai.tick\n\t\tstate.phase = 'done'\n\t\tstate.phaseSince = this.squads.ai.tick\n\t}\n\n\t/**\n\t * Goes to fight at a place or a target (an entity, or its id): attack-moves there, fighting what it meets, regroups\n\t * on the way, retreats on the odds. Done `cleared` once there with nothing left to fight, `lost` when the target is\n\t * gone. `avoid: 'army'` goes round where their strength is on the way (the threat map and their army as last seen),\n\t * when there is a way round. `via`: a place to go by on the way (a way of its own: Random Paths). `then`: the task after it\n\t */\n\tattack(target: Vec2 | EntityState | number, options: { avoid?: 'army' | false; via?: Vec2; then?: TaskOrder } = {}): this {\n\t\treturn this.task(ATTACK, { ...targetOf(this.squads.ai, target), ...options })\n\t}\n\n\t/** Attack-moves to a place, as a group of units would on a click: the squad's attack without its regroup */\n\tattackMove(at: Vec2, options: { then?: TaskOrder } = {}): this {\n\t\treturn this.task(ATTACK, { at: point(at), regroup: false, ...options })\n\t}\n\n\t/**\n\t * Holds a place against what comes within `radius` of it (16 when left out): fights what comes, goes back once it is\n\t * gone. Never over by itself: its owner says when\n\t */\n\tdefend(at: Vec2, radius = 16): this {\n\t\treturn this.task(DEFEND_TASK, { at: point(at), radius })\n\t}\n\n\t/** Goes to a place (where it stands when left out) and holds it: stands, fighting only what comes within reach */\n\thold(at?: Vec2): this {\n\t\tconst there = at ?? this.centre()\n\t\treturn this.task(HOLD, there ? { at: point(there) } : {})\n\t}\n\n\t/** Walks to a place, fighting nothing on the way. Done `arrived` */\n\tmove(at: Vec2, options: { then?: TaskOrder } = {}): this {\n\t\treturn this.task(MOVE, { at: point(at), ...options })\n\t}\n\n\t/** Goes with a unit of the player's or an ally's, fighting what comes near it. Done `lost` when it is gone */\n\tescort(target: EntityState | number): this {\n\t\treturn this.task(ESCORT, { target: typeof target === 'number' ? target : target.id })\n\t}\n\n\t/**\n\t * Goes for the workers at a place, round where their army is (`avoid: 'army'` unless told otherwise), the workers\n\t * first once there. Done `cleared`\n\t */\n\tharass(at: Vec2, options: { avoid?: 'army' | false; then?: TaskOrder } = {}): this {\n\t\treturn this.task(HARASS, { at: point(at), avoid: 'army', ...options })\n\t}\n\n\t/** Goes to look at places, one after the other: each is looked at once in sight, or reached as near as the ground lets. Done `arrived` */\n\tscout(points: readonly Vec2[]): this {\n\t\treturn this.task(SCOUT_TASK, { points: points.map(point) })\n\t}\n\n\t/**\n\t * Gathers at a rally point before going on (`then`): until `minForces` of it (a share, 1 when left out) is there,\n\t * or `seconds` have gone by. Done `arrived`, and on to `then`\n\t */\n\tgather(at: Vec2, options: { minForces?: number; seconds?: number; then?: TaskOrder } = {}): this {\n\t\treturn this.task(GATHER, { at: point(at), ...options })\n\t}\n\n\t/** Falls back to a place (home when left out), fighting nothing on the way. Done `retreated` */\n\tretreat(to?: Vec2, why?: string): this {\n\t\tconst home = to ?? this.squads.ai.view.home()\n\t\treturn this.task(RETREAT, { ...(home && { at: point(home) }), ...(why && { why }) })\n\t}\n\n\t/**\n\t * Walks a round of places, one after the other and back to the first, fighting what it meets on the way (an\n\t * attack-move to each): a mission's guards on the road, a watch round the walls. Never over by itself: its owner\n\t * says when\n\t */\n\tpatrol(points: readonly Vec2[]): this {\n\t\treturn this.task(PATROL, { points: points.map(point) })\n\t}\n\n\t/** Takes a camp of creeps: fights there until the camp is cleared. Done `cleared` */\n\tcreep(camp: Vec2): this {\n\t\treturn this.task(CREEP, { at: point(camp) })\n\t}\n\n\t/**\n\t * Carried by transports to a place it cannot walk to, let out on the land nearest it (the `drop` task): done\n\t * `landed`, then what `then` says (an attack where it landed)\n\t */\n\tdrop(at: Vec2, transports: readonly number[], options: { then?: TaskOrder } = {}): this {\n\t\treturn this.task(DROP, { at: point(at), transports: [...transports], ...(options.then && { then: options.then }) })\n\t}\n\n\t/** Sends its units an order (`move`, `hold`, the game's), all or some of them: counted as the task's last */\n\torder(order: OrderInit, units: readonly number[] = this.data.units, queue = false): void {\n\t\tunits = this.living(units)\n\t\tif (!units.length) return\n\t\tthis.squads.ai.send({ type: 'order', entities: [...units], order, ...(queue && { queue: true }) })\n\t\tthis.sent()\n\t}\n\n\t/**\n\t * Puts its units, all or some, in a stance, where the game has stances (`stancesPack`): those not in it already. A\n\t * squad that holds is defensive, one sent to fight aggressive\n\t */\n\tsetStance(id: string, units: readonly number[] = this.data.units): void {\n\t\tif (!this.squads.ai.registry.command('stance')) return\n\t\tconst change: number[] = []\n\t\tfor (const unit of this.units()) {\n\t\t\tif (!units.includes(unit.id)) continue\n\t\t\tconst now = (unit.components?.[stance.id] as string | undefined) ?? DEFAULT_STANCE\n\t\t\tif (now !== id) change.push(unit.id)\n\t\t}\n\t\tif (change.length) this.squads.ai.send(stanceCommand.make({ entities: change, stance: id }))\n\t}\n\n\t/**\n\t * Sends its units to take a capture point of the game's (`capturePack`), by its id: they fight their way in and\n\t * stand in it until it is theirs (`captured`), or it is gone (`lost`)\n\t */\n\tcapture(id: string): this {\n\t\tconst found = capturePointsOf(this.squads.ai).find((each) => each.id === id)\n\t\treturn this.task(CAPTURE, { point: id, ...(found && { at: point({ x: found.x, z: found.z }) }) })\n\t}\n\n\t/** Sends its units, all or some, to fight at a place, or a target there: an attack-move, or an attack */\n\tfight(at: Vec2, units: readonly number[] = this.data.units, target?: number, queue = false): void {\n\t\tunits = this.living(units)\n\t\tif (!units.length) return\n\t\tthis.setStance(DEFAULT_STANCE, units)\n\t\tthis.squads.ai.send({\n\t\t\ttype: 'attack',\n\t\t\tentities: [...units],\n\t\t\tpoint: point(at),\n\t\t\t...(target !== undefined && { target }),\n\t\t\t...(queue && { queue: true })\n\t\t})\n\t\tthis.sent()\n\t}\n\n\t/**\n\t * Of some of its units, those the picture has: a unit that died since the squads were last looked at (a task given by a\n\t * goal before the `squads()` module ran) is no one to order\n\t */\n\tprivate living(units: readonly number[]): readonly number[] {\n\t\tconst { mine } = this.squads.ai.view\n\t\treturn units.every((id) => mine.has(id)) ? units : units.filter((id) => mine.has(id))\n\t}\n\n\t/** Its units that stand with nothing to do: what lost its order, or never had one */\n\tidleUnits(): EntityState[] {\n\t\treturn this.units().filter((unit) => !!unit.own && !unit.own.order && !unit.own.hidden)\n\t}\n\n\t/** Whether its last order was sent long enough ago to send one again (`RESEND` seconds): what keeps a stuck unit from being told every think */\n\tmayResend(): boolean {\n\t\tconst state = this.data.task\n\t\tconst { ai } = this.squads\n\t\treturn !state || state.sent === undefined || ai.tick - state.sent >= RESEND * ai.session.tickRate\n\t}\n\n\tprivate sent(): void {\n\t\tif (this.data.task) this.data.task.sent = this.squads.ai.tick\n\t}\n}\n\n/**\n * Some squads together (`ai.squads.all()`, `idle()`): read as a list, told as one (`ai.squads.all().defend(home)`:\n * each squad is given the task)\n *\n * @beta\n */\nexport class SquadGroup implements Iterable<Squad> {\n\tconstructor(\n\t\t/** The brain they are of */\n\t\treadonly ai: Brain,\n\t\t/** The squads */\n\t\treadonly squads: readonly Squad[]\n\t) {}\n\n\t/** Iterates the squads, so that the set reads as a list */\n\t[Symbol.iterator](): Iterator<Squad> {\n\t\treturn this.squads[Symbol.iterator]()\n\t}\n\n\t/** How many squads */\n\tget length(): number {\n\t\treturn this.squads.length\n\t}\n\n\t/** Their units together, as a set */\n\tunits(): UnitSet {\n\t\tconst { view } = this.ai\n\t\tconst all = this.squads.flatMap((squad) => squad.units().items)\n\t\tall.sort((a, b) => view.indexOf(a) - view.indexOf(b))\n\t\treturn new UnitSet(view, all)\n\t}\n\n\t/** How strong they are together */\n\tstrength(): number {\n\t\treturn this.units().strength()\n\t}\n\n\t/** Each given the same task */\n\ttask<D extends object, M extends object>(def: TaskDef<D, M>, data: D & TaskCommon): this\n\t/** Gives each squad the same task, by its kind and data, and returns the set */\n\ttask(kind: string, data?: TaskData): this\n\ttask(kind: string | TaskDef, data: TaskData = {}): this {\n\t\tfor (const squad of this.squads) squad.squads.give(squad, kind, data)\n\t\treturn this\n\t}\n\n\t/** Tells each squad to attack a point, an entity or an entity id, as `Squad.attack` does, and returns the set */\n\tattack(target: Vec2 | EntityState | number, options: { avoid?: 'army' | false; then?: TaskOrder } = {}): this {\n\t\tfor (const squad of this.squads) squad.attack(target, options)\n\t\treturn this\n\t}\n\n\t/** Tells each squad to defend a place within a radius as `Squad.defend` does; does nothing without a place; returns the set */\n\tdefend(at: Vec2 | undefined, radius?: number): this {\n\t\tif (at) for (const squad of this.squads) squad.defend(at, radius)\n\t\treturn this\n\t}\n\n\t/** Tells each squad to hold at a place, or where it is, as `Squad.hold` does, and returns the set */\n\thold(at?: Vec2): this {\n\t\tfor (const squad of this.squads) squad.hold(at)\n\t\treturn this\n\t}\n\n\t/** Tells each squad to move to a point as `Squad.move` does, and returns the set */\n\tmove(at: Vec2): this {\n\t\tfor (const squad of this.squads) squad.move(at)\n\t\treturn this\n\t}\n\n\t/** Tells each squad to retreat to a point, or home when left out, as `Squad.retreat` does, and returns the set */\n\tretreat(to?: Vec2): this {\n\t\tfor (const squad of this.squads) squad.retreat(to)\n\t\treturn this\n\t}\n\n\t/** Each disbanded */\n\tdisband(why?: string): void {\n\t\tfor (const squad of [...this.squads]) squad.disband(why)\n\t}\n}\n\n/** The ids of units given as entities or ids, each once */\nfunction ids(units: Iterable<EntityState | number>): number[] {\n\tconst result: number[] = []\n\tfor (const unit of units) {\n\t\tconst id = typeof unit === 'number' ? unit : unit.id\n\t\tif (!result.includes(id)) result.push(id)\n\t}\n\treturn result\n}\n\n/** A target as an attack's data: a place, or an entity and where it is */\nfunction targetOf(ai: Brain, target: Vec2 | EntityState | number): { target?: number; at?: Vec2 } {\n\tif (typeof target === 'number') {\n\t\tconst entity = ai.view.byId(target)\n\t\treturn { target, ...(entity && { at: point(entity) }) }\n\t}\n\tif ('id' in target && typeof (target as EntityState).id === 'number') return { target: (target as EntityState).id, at: point(target) }\n\treturn { at: point(target) }\n}\n\n/**\n * A brain's squads (`ai.squads`): made by its goals, rules and modules, watched by the `squads()` module each think\n * (`think`): the dead dropped, what the owner let go of let go of, each task looked at, regroups, retreats and\n * reinforcements seen to. Kept in the brain's memory (`BrainMemory.squads`)\n *\n * @beta\n */\nexport class Squads implements AiArea {\n\t/** Its id among the brain's areas: what its memory and its report are kept under */\n\treadonly id = 'squads'\n\t/** What the log says where a save's memory of it is of a shape it does not read */\n\treadonly afresh = 'the save remembers the computer player’s squads in a shape this brain does not read: they are let go of'\n\n\tprivate list: Squad[] = []\n\tprivate readonly tasks = new Map<string, TaskDef>()\n\tprivate thoughtAt = -1\n\t/** How a squad behaves where it says nothing and the brain's settings say nothing either: the `squads()` module's */\n\tprivate moduleOptions: SquadOptions = {}\n\n\tconstructor(\n\t\t/** The brain they are the squads of */\n\t\treadonly ai: Brain,\n\t\t/** The tasks of the game's own its squads may be on (`AiSettings.squads.tasks`) */\n\t\ttasks: readonly TaskDef[] = []\n\t) {\n\t\tfor (const def of TASKS) this.tasks.set(def.id, def)\n\t\tfor (const def of tasks) this.define(def)\n\t}\n\n\t/** Puts the `squads()` module's options under the brain's settings */\n\tconfigure(options: SquadOptions): void {\n\t\tthis.moduleOptions = options\n\t}\n\n\t/** How a squad behaves where it says nothing: the module's options, the brain's settings over them (`ai.settings.squads`) */\n\tget defaults(): SquadOptions {\n\t\tconst { tasks: _tasks, ...settings } = this.ai.settings.squads ?? {}\n\t\treturn { ...this.moduleOptions, ...settings }\n\t}\n\n\t/** Registers a task of the game's own, so that a squad on it is carried on after a load. Given by `BrainDef.squads.tasks` */\n\tdefine(def: TaskDef): void {\n\t\tconst known = this.tasks.get(def.id)\n\t\tif (known && known !== def && TASKS.includes(known))\n\t\t\tthrow new Error(`\"${def.id}\" is a task of the kit's: a task of the game's needs a name of its own`)\n\t\tthis.tasks.set(def.id, def)\n\t}\n\n\t/** A kind of task by its id: the kit's, or one registered */\n\ttaskDef(id: string): TaskDef | undefined {\n\t\treturn this.tasks.get(id)\n\t}\n\n\t/**\n\t * Makes a squad of units under a name (one of that name already is disbanded first), with how it behaves where it\n\t * is not the brain's way. Whose it is (`owner`): what `options.owner` names (a goal makes its own with\n\t * `claimed.squad`), else its own (`squad:<name>`). A goal's squad is made of what the goal holds, and what\n\t * nothing holds is given to it; a squad of a rule or a module takes its units from whatever holds them (the goal\n\t * told: `stop('told')`) and holds them until it is disbanded. A unit in another squad leaves it\n\t */\n\tmake(name: string, units: Iterable<EntityState | number>, options: SquadOptions & { owner?: string } = {}): Squad {\n\t\tif (!name) throw new Error('A squad needs a name')\n\t\tconst { ai } = this\n\t\tconst { owner: named, ...own } = options\n\t\tconst owner = named ?? `squad:${name}`\n\t\tconst old = this.named(name)\n\t\tif (old) this.disband(old, 'made anew', old.owner !== owner)\n\t\t// the brain's settings (Groups Flee, the odds it falls back at), the squad's own over them\n\t\tconst behaves = { ...this.defaults, ...own }\n\t\tconst squad = new Squad(this, { name, owner, units: [], options: behaves, size: 0, made: ai.tick, retreats: 0 })\n\t\tthis.list.push(squad)\n\t\tthis.enlist(squad, ids(units))\n\t\tsquad.data.size = squad.data.units.length\n\t\tsquad.changed(`made by ${owner === `squad:${name}` ? 'itself' : owner}: ${plural(squad.data.units.length)}`)\n\t\treturn squad\n\t}\n\n\t/**\n\t * Puts units in a squad: those its owner may have (held by it, or given from the pool for a goal; taken for a rule's\n\t * or a module's), out of any other squad. Those put in, by id\n\t */\n\tenlist(squad: Squad, wanted: number[]): number[] {\n\t\tconst { goals, view, session, tick } = this.ai\n\t\tconst owner = squad.data.owner\n\t\tconst units = wanted.filter((id) => view.mine.has(id) && !squad.data.units.includes(id))\n\t\tif (!units.length) return []\n\t\tlet put: number[]\n\t\tif (goals.get(owner)) {\n\t\t\t// a goal's: what it holds, and what nothing holds given to it; what another holds is not its to have\n\t\t\tgoals.give(owner, units)\n\t\t\tput = units.filter((id) => goals.holder(id) === owner)\n\t\t} else {\n\t\t\t// a rule's, a module's, its own: taken from whoever holds them, for as long as the hold it is under lasts\n\t\t\tconst hold = goals.held(owner)\n\t\t\tconst seconds = !hold || hold.kept ? Infinity : Math.max(1, (hold.until - tick) / session.tickRate)\n\t\t\tgoals.take(units, 'told', { id: owner, seconds })\n\t\t\tput = units.filter((id) => goals.held(owner)?.units.includes(id))\n\t\t}\n\t\tif (!put.length) return put\n\t\t// in one squad at a time\n\t\tfor (const other of [...this.list]) {\n\t\t\tif (other === squad || !other.data.units.some((id) => put.includes(id))) continue\n\t\t\tother.data.units = other.data.units.filter((id) => !put.includes(id))\n\t\t\tother.changed(`${plural(put.length)} went to ${squad.name}`)\n\t\t\tif (!other.data.units.length) this.disband(other, `its units went to ${squad.name}`)\n\t\t}\n\t\t// what died since the squads module last looked is dropped as the new come in: the order is the picture's\n\t\tsquad.data.units = squad.data.units.filter((id) => view.mine.has(id))\n\t\tsquad.data.units.push(...put)\n\t\tsquad.data.units.sort((a, b) => view.indexOf(view.byId(a)!) - view.indexOf(view.byId(b)!))\n\t\treturn put\n\t}\n\n\t/** A squad by name: none for one there is not */\n\tnamed(name: string): Squad | undefined {\n\t\treturn this.list.find((squad) => squad.data.name === name)\n\t}\n\n\t/** Every squad, as made */\n\tall(): SquadGroup {\n\t\treturn new SquadGroup(this.ai, this.list)\n\t}\n\n\t/** The squads with nothing to do: told nothing, or their task over */\n\tidle(): SquadGroup {\n\t\treturn new SquadGroup(\n\t\t\tthis.ai,\n\t\t\tthis.list.filter((squad) => squad.idle)\n\t\t)\n\t}\n\n\t/** The squads a goal, rule or module owns */\n\tof(owner: string): SquadGroup {\n\t\treturn new SquadGroup(\n\t\t\tthis.ai,\n\t\t\tthis.list.filter((squad) => squad.data.owner === owner)\n\t\t)\n\t}\n\n\t/** The squad a unit is in, by the unit or its id: none for a unit in none */\n\tsquadOf(unit: EntityState | number): Squad | undefined {\n\t\tconst id = typeof unit === 'number' ? unit : unit.id\n\t\treturn this.list.find((squad) => squad.data.units.includes(id))\n\t}\n\n\t/** The player's units nothing holds (`ai.goals.pool`, buildings left out): what a squad is made of, or reinforced from */\n\tpool(): UnitSet {\n\t\treturn this.ai.goals.pool().units()\n\t}\n\n\t/** Disbands a squad: a squad that held its units itself lets them go back to the pool */\n\tdisband(squad: Squad, why = 'disbanded', letGo = true): void {\n\t\tconst index = this.list.indexOf(squad)\n\t\tif (index < 0) return\n\t\tthis.list.splice(index, 1)\n\t\tconst { goals } = this.ai\n\t\tif (letGo && !goals.get(squad.data.owner) && goals.held(squad.data.owner)) {\n\t\t\t// what it held is let go of; a hold it shares with other squads of its owner keeps theirs\n\t\t\tconst others = new Set(this.list.filter((other) => other.data.owner === squad.data.owner).flatMap((other) => other.data.units))\n\t\t\tgoals.drop(\n\t\t\t\tsquad.data.owner,\n\t\t\t\tsquad.data.units.filter((id) => !others.has(id))\n\t\t\t)\n\t\t}\n\t\tif (squad.data.units.length || why !== 'made anew') this.ai.decide(`squad ${squad.name} disbanded: ${why}`, { kind: 'squad' })\n\t}\n\n\t/**\n\t * Gives a squad a task: what it was doing is over, and the new one's first orders go at once. What it has now is what\n\t * reinforcements make up to from then on (`SquadData.size`), but for a task it goes on to by itself (`going on`: a\n\t * task's `then`, a fall back on the odds), which keeps what the task before was given. The task it is on given\n\t * again changes nothing, its `size` kept: what it lost since is what reinforcements make up\n\t */\n\tgive(squad: Squad, kind: string | TaskDef, data: TaskData, goingOn = false): void {\n\t\tconst { ai } = this\n\t\tconst def = typeof kind === 'string' ? this.tasks.get(kind) : kind\n\t\tif (!def)\n\t\t\tthrow new Error(\n\t\t\t\t`The squad \"${squad.name}\" was given a task \"${String(kind)}\" the brain does not know: list it in its squads' tasks (defineTask)`\n\t\t\t)\n\t\tif (typeof kind !== 'string' && !this.tasks.has(def.id)) this.define(def)\n\t\tconst before = squad.data.task\n\t\t// the task it is on already, given again (a goal's run each think): it goes on as it is, and nothing is sent again\n\t\tif (before && before.done === undefined && before.kind === def.id && sameData(before.data, data)) return\n\t\tconst state: TaskState = { kind: def.id, data: { ...data }, since: ai.tick, phase: 'starting', phaseSince: ai.tick, memory: {} }\n\t\tsquad.data.task = state\n\t\tif (!goingOn) squad.data.size = squad.data.units.length\n\t\tsquad.changed(before && before.done === undefined ? `${before.kind} → ${def.id}` : `on to ${def.id}`)\n\t\tif (squad.data.units.length) def.start(ai, squad, state)\n\t}\n\n\t/**\n\t * Looks at every squad, once a think: its units (the dead, and what its owner let go of, dropped; a squad of a goal\n\t * that stopped disbanded), then its task (retreat on the odds, the task's own look, regroup, reinforcements). What the\n\t * `squads()` module runs; a module may call it sooner\n\t */\n\tthink(): void {\n\t\tconst { ai } = this\n\t\tif (this.thoughtAt !== ai.tick) {\n\t\t\tthis.thoughtAt = ai.tick\n\t\t\tthis.prune()\n\t\t\tthis.advancing = [...this.list]\n\t\t\tthis.cursor = 0\n\t\t} else if (!this.advancing) return\n\t\t// each squad looked at in turn, as many as the tick's budget has room for (F2, `ai.budget`): a think sliced over\n\t\t// ticks goes on from the next squad at the next tick, over the same picture\n\t\tconst squads = this.advancing\n\t\tfor (; this.cursor < squads.length; this.cursor++) {\n\t\t\tconst squad = squads[this.cursor]\n\t\t\tthis.advance(squad)\n\t\t\tif (!ai.budget.spent(squad.data.units.length || 1) && this.cursor + 1 < squads.length) {\n\t\t\t\tthis.cursor++\n\t\t\t\treturn ai.budget.later()\n\t\t\t}\n\t\t}\n\t\tthis.advancing = undefined\n\t}\n\n\t/** The squads still to be looked at this think, where a pass stopped for the tick's budget, and the next of them */\n\tprivate advancing: Squad[] | undefined\n\tprivate cursor = 0\n\n\t/** Every squad's units looked at, as a think begins: the dead and what its owner let go of dropped, a squad with none left disbanded */\n\tprivate prune(): void {\n\t\tconst { ai } = this\n\t\tconst { goals, view } = ai\n\t\tfor (const squad of [...this.list]) {\n\t\t\tconst hold = goals.held(squad.data.owner)\n\t\t\tif (!hold) {\n\t\t\t\tthis.disband(squad, `${squad.data.owner} let go`, false)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// what a rule's or a module's hold has that is gone is let go of: with no goals in the brain, nothing else does\n\t\t\tif (!goals.get(squad.data.owner) && hold.units.some((id) => !view.mine.has(id))) hold.units = hold.units.filter((id) => view.mine.has(id))\n\t\t\tconst kept = squad.data.units.filter((id) => hold.units.includes(id) && view.mine.has(id) && view.byId(id)!.health > 0)\n\t\t\tif (kept.length !== squad.data.units.length) squad.data.units = kept\n\t\t\tif (!kept.length) {\n\t\t\t\tsquad.finish('wiped')\n\t\t\t\tthis.disband(squad, 'none of its units left', false)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** One squad's think: retreat on the odds, the task's own look, then on to the next task, regroup, reinforcements */\n\tprivate advance(squad: Squad): void {\n\t\tconst { ai } = this\n\t\tconst state = squad.data.task\n\t\tconst def = state && this.tasks.get(state.kind)\n\t\tconst handles = def?.handles ?? []\n\t\tif (state && def && state.done === undefined) {\n\t\t\tif (!handles.includes('retreat') && this.losing(squad)) return\n\t\t\tconst over = def.done?.(ai, squad, state)\n\t\t\tif (over) squad.finish(over)\n\t\t\telse def.think(ai, squad, state)\n\t\t\tif (state.done === undefined && !handles.includes('regroup') && state.data.regroup !== false) this.regroup(squad, state, def)\n\t\t\tconst then = state.data.then as TaskOrder | undefined\n\t\t\tif (state.done !== undefined && state.done !== 'lost' && state.done !== 'wiped' && then?.kind && this.tasks.has(then.kind)) {\n\t\t\t\tthis.give(squad, then.kind, then.data ?? {}, true)\n\t\t\t}\n\t\t}\n\t\tif (squad.data.options.reinforce && !handles.includes('reinforce')) this.reinforce(squad)\n\t}\n\n\t/**\n\t * Whether a squad in a fight away from home is losing it (its odds under `retreatAt`), and so falls back: its task\n\t * becomes `retreat`, home, and it is said why\n\t */\n\tprivate losing(squad: Squad): boolean {\n\t\tconst { ai } = this\n\t\tconst { view } = ai\n\t\tconst at = squad.data.options.retreatAt ?? 0.3\n\t\tif (at === false || !(at > 0)) return false\n\t\tconst units = squad.units()\n\t\tconst middle = units.centre()\n\t\tconst home = view.home()\n\t\tif (!middle || !home) return false\n\t\tconst safe = squad.data.options.home ?? 20\n\t\tif (distSq(middle, home) < safe * safe) return false\n\t\tconst foes = view.hostile.units().alive().near(middle, FIGHT_REACH)\n\t\tif (!foes.length || !foes.some((foe) => units.some((unit) => distSq(unit, foe) <= ENGAGED * ENGAGED))) return false\n\t\tconst odds = view.strength.odds(units.near(middle, FIGHT_REACH), foes)\n\t\tif (odds >= at) return false\n\t\tconst was = squad.data.task?.kind ?? 'nothing'\n\t\tsquad.data.retreats++\n\t\tthis.give(squad, 'retreat', { at: point(home), why: 'odds' }, true)\n\t\tai.decide(`squad ${squad.name} falls back home with ${plural(units.length)}: ${was} lost (odds ${odds.toFixed(2)} under ${at})`, {\n\t\t\tkind: 'squad'\n\t\t})\n\t\treturn true\n\t}\n\n\t/**\n\t * Regroups a squad that is strung out on its way: too many of its units (`regroupWhen`) further than `spread` from its\n\t * middle, and no fight near. It gathers on its middle and goes on once together, or once it has waited long enough\n\t */\n\tprivate regroup(squad: Squad, state: TaskState, def: TaskDef): void {\n\t\tconst { ai } = this\n\t\tconst units = squad.units()\n\t\tif (units.length < 3) return\n\t\tconst middle = units.centre()!\n\t\tconst spread = squad.spread()\n\t\tif (state.phase === 'regrouping') {\n\t\t\tconst together = units.every((unit) => distSq(unit, middle) <= spread * spread * 0.36)\n\t\t\tif (together || ai.tick - state.phaseSince >= REGROUP_FOR * ai.session.tickRate) {\n\t\t\t\t// on its way again: the task sends what it sends as it begins\n\t\t\t\tdef.start(ai, squad, state)\n\t\t\t\tai.decide(`squad ${squad.name} regrouped${together ? '' : ' as much as it waits for'}: on with ${state.kind}`, { kind: 'squad' })\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (state.phase !== 'going') return\n\t\tconst when = squad.data.options.regroupWhen ?? 0.4\n\t\tif (when === false) return\n\t\tconst strayed = units.filter((unit) => distSq(unit, middle) > spread * spread).length\n\t\tif (strayed <= units.length * when) return\n\t\tif (ai.view.hostile.alive().near(middle, FIGHT_REACH).length) return\n\t\tstate.phase = 'regrouping'\n\t\tstate.phaseSince = ai.tick\n\t\tsquad.order({ type: 'move', point: point(middle) })\n\t\tai.decide(`squad ${squad.name} regroups at ${where(middle)}: ${strayed} of ${units.length} strung out`, { kind: 'squad' })\n\t}\n\n\t/**\n\t * Makes up what a squad lost since its task began from the pool: the idle fighters nothing holds, the nearest\n\t * first, given to its owner and sent to join it. Never a hero: one crossing the map alone to a fight dies on the\n\t * way, and heroes are sent with a squad, not after it. Not while it falls back, nor more often than every few seconds\n\t */\n\tprivate reinforce(squad: Squad): void {\n\t\tconst { ai } = this\n\t\tconst { data } = squad\n\t\tconst missing = data.size - data.units.length\n\t\tif (missing <= 0 || (data.task?.kind === 'retreat' && data.task.done === undefined)) return\n\t\tif (data.nextReinforce !== undefined && ai.tick < data.nextReinforce) return\n\t\tdata.nextReinforce = ai.tick + REINFORCE_EVERY * ai.session.tickRate\n\t\tconst join = squad.centre() ?? this.whereOf(squad) ?? ai.view.home()\n\t\tif (!join) return\n\t\t// not a hero (sent with a squad, never after it), nor the wounded (one walking alone into the fight it fled dies there)\n\t\tconst { strength } = ai.view\n\t\tconst free = [...this.pool().fighters().idle()]\n\t\t\t.filter((unit) => !heroOfState(unit) && unit.health >= WOUNDED * (unit.maxHealth ?? strength.statsOf(unit).health))\n\t\t\t.sort((a, b) => distSq(a, join) - distSq(b, join) || a.id - b.id)\n\t\tconst chosen = free.slice(0, missing).map((unit) => unit.id)\n\t\tif (!chosen.length) return\n\t\tconst size = data.size\n\t\tsquad.add(chosen, 'reinforced')\n\t\tdata.size = size\n\t\tconst added = chosen.filter((id) => data.units.includes(id))\n\t\tif (!added.length) return\n\t\t// to where it is, fighting what they meet on the way\n\t\tai.send({ type: 'attack', entities: added, point: point(join) })\n\t\tai.decide(`squad ${squad.name} reinforced with ${plural(added.length)}`, { kind: 'squad' })\n\t}\n\n\t/** The place a squad's task is about: none for a task about no place */\n\twhereOf(squad: Squad): Vec2 | undefined {\n\t\tconst state = squad.data.task\n\t\tconst def = state && this.tasks.get(state.kind)\n\t\treturn state && def?.where?.(this.ai, squad, state)\n\t}\n\n\t/**\n\t * The way to a place round where the enemy is strong (`avoid: 'army'`): the waypoint to go by, where the straight way\n\t * crosses their strength (the threat map, with what is remembered of their towers, and their army as last seen) and a\n\t * way round is less hot, tried on either side and then further out, twice at most. A heuristic, not a safe route:\n\t * none where the straight way is cool enough, or where there is no way round (`note` says so)\n\t */\n\troute(from: Vec2, to: Vec2, squad: Squad): { waypoints: Vec2[]; note?: string } {\n\t\tconst { ai } = this\n\t\tconst { view } = ai\n\t\tconst units = squad.units()\n\t\tconst flying = units.length > 0 && units.every((unit) => !!view.def(unit).flying)\n\t\tconst layer: Layer = flying ? 'air' : 'ground'\n\t\tconst seen = ai.def.knowledge === false ? [] : ai.knowledge.enemy.armySeen(AVOID_SEEN)\n\t\tconst danger = (at: Vec2) => {\n\t\t\tlet enemy = view.threat.at(at, { layer, remembered: true }).enemy\n\t\t\tfor (const army of seen) if (distSq(army.at, at) < 12 * 12) enemy += army.strength\n\t\t\treturn enemy\n\t\t}\n\t\t// the hottest place along a way, looked at every few units of it\n\t\tconst hottest = (path: readonly Vec2[]) => {\n\t\t\tlet worst = { at: path[0] ?? from, enemy: 0 }\n\t\t\tfor (let i = 1; i < path.length; i++) {\n\t\t\t\tconst a = path[i - 1]\n\t\t\t\tconst b = path[i]\n\t\t\t\tconst steps = Math.max(1, Math.ceil(Math.sqrt(distSq(a, b)) / 6))\n\t\t\t\tfor (let s = 1; s <= steps; s++) {\n\t\t\t\t\tconst at = { x: a.x + ((b.x - a.x) * s) / steps, z: a.z + ((b.z - a.z) * s) / steps }\n\t\t\t\t\tconst enemy = danger(at)\n\t\t\t\t\tif (enemy > worst.enemy) worst = { at, enemy }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn worst\n\t\t}\n\t\tconst straight = view.findPath(from, to, flying) ?? [from, to]\n\t\tconst worst = hottest([from, ...straight])\n\t\t// what the squad would rather not walk into: half its own strength\n\t\tconst bearable = Math.max(1e-9, units.strength() * 0.5)\n\t\tif (worst.enemy <= bearable) return { waypoints: [] }\n\t\tconst { width, depth } = view.session.terrain\n\t\tconst dx = to.x - from.x\n\t\tconst dz = to.z - from.z\n\t\tconst length = Math.sqrt(dx * dx + dz * dz) || 1\n\t\tconst aside = { x: -dz / length, z: dx / length }\n\t\tlet best: { at: Vec2; enemy: number } | undefined\n\t\tfor (let attempt = 0; attempt < 2; attempt++) {\n\t\t\tconst far = DETOUR * (1 + attempt / 2)\n\t\t\tfor (const side of [1, -1]) {\n\t\t\t\tconst at = {\n\t\t\t\t\tx: Math.min(width - 1, Math.max(1, worst.at.x + aside.x * far * side)),\n\t\t\t\t\tz: Math.min(depth - 1, Math.max(1, worst.at.z + aside.z * far * side))\n\t\t\t\t}\n\t\t\t\tconst there = view.findPath(from, at, flying)\n\t\t\t\tconst on = there && view.findPath(at, to, flying)\n\t\t\t\tif (!there || !on) continue\n\t\t\t\tconst enemy = Math.max(hottest([from, ...there]).enemy, hottest([at, ...on]).enemy)\n\t\t\t\tif (!best || enemy < best.enemy) best = { at, enemy }\n\t\t\t}\n\t\t\tif (best && best.enemy <= bearable) return { waypoints: [point(best.at)], note: `round ${where(worst.at)} by ${where(best.at)}` }\n\t\t}\n\t\tif (best && best.enemy < worst.enemy)\n\t\t\treturn { waypoints: [point(best.at)], note: `no way round ${where(worst.at)} that is safe: by ${where(best.at)}, the least hot` }\n\t\treturn { waypoints: [], note: `no way round ${where(worst.at)}: straight` }\n\t}\n\n\t/** Every squad as the report shows it */\n\treport(): SquadReport[] {\n\t\treturn this.list.map((squad) => {\n\t\t\tconst { data } = squad\n\t\t\tconst units = squad.units()\n\t\t\tconst middle = units.centre()\n\t\t\tconst state = data.task\n\t\t\tconst at = this.whereOf(squad)\n\t\t\treturn {\n\t\t\t\tname: data.name,\n\t\t\t\towner: data.owner,\n\t\t\t\tunits: [...data.units],\n\t\t\t\tstrength: units.strength(),\n\t\t\t\t...(middle && { at: pair(middle) }),\n\t\t\t\tsize: data.size,\n\t\t\t\t...(state && {\n\t\t\t\t\ttask: {\n\t\t\t\t\t\tkind: state.kind,\n\t\t\t\t\t\tphase: state.phase,\n\t\t\t\t\t\tsince: state.since,\n\t\t\t\t\t\t...(at && { at: pair(at) }),\n\t\t\t\t\t\t...(state.done !== undefined && { done: state.done })\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\tretreats: data.retreats,\n\t\t\t\t...(data.changed && { changed: { ...data.changed } })\n\t\t\t}\n\t\t})\n\t}\n\n\t/** What the squads are, for a save: copies */\n\t/** Whether it has anything to remember now: one that does not is left out of a save */\n\tremembers(): boolean {\n\t\treturn this.all().length > 0\n\t}\n\n\t/** Gives the squads' data as plain data for a save of the brain */\n\tsave(): SquadsMemory {\n\t\treturn { v: 1, squads: this.list.map((squad) => structuredClone(squad.data)) }\n\t}\n\n\t/** Takes back what `save` gave: whether it was read. A squad on a task the brain does not know is kept, and does nothing */\n\trestore(memory: unknown): boolean {\n\t\tconst given = memory as SquadsMemory | undefined\n\t\tif (!given || typeof given !== 'object' || given.v !== 1 || !Array.isArray(given.squads)) return false\n\t\tthis.list = given.squads\n\t\t\t.filter((data) => data && typeof data.name === 'string' && Array.isArray(data.units))\n\t\t\t.map((data) => new Squad(this, structuredClone(data)))\n\t\tfor (const squad of this.list) {\n\t\t\tconst kind = squad.data.task?.kind\n\t\t\tif (kind && !this.tasks.has(kind))\n\t\t\t\tthis.ai.log.info('ai', `the squad \"${squad.name}\" is on a task \"${kind}\" this brain does not know: it waits`, { squad: squad.name })\n\t\t}\n\t\treturn true\n\t}\n}\n\n/** The share of its health under which a unit is not sent as a reinforcement */\nconst WOUNDED = 0.5\n\n/** Whether two tasks' data say the same: plain data, field by field */\nfunction sameData(a: unknown, b: unknown): boolean {\n\tif (a === b) return true\n\tif (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false\n\tif (Array.isArray(a) !== Array.isArray(b)) return false\n\tconst keys = Object.keys(a).filter((key) => (a as Record<string, unknown>)[key] !== undefined)\n\tconst others = Object.keys(b).filter((key) => (b as Record<string, unknown>)[key] !== undefined)\n\treturn keys.length === others.length && keys.every((key) => sameData((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]))\n}\n\n/**\n * The squads module: looks at every squad of the brain each think (`ai.squads.think`), after the goals, the rules and\n * the words that make them: their units, their tasks, regroups, retreats, reinforcements. With how they behave where the\n * brain's definition and the seat's options say nothing\n *\n * @beta\n */\nexport const squads = (options: SquadsOptions = {}): AiModuleDef =>\n\tdefineModule({ id: 'squads', make: (ai: Brain): AiModule => {\n\t\tfor (const def of options.tasks ?? []) ai.squads.define(def)\n\t\tconst { tasks: _tasks, ...defaults } = options\n\t\tai.squads.configure(defaults)\n\t\treturn {\n\t\t\tid: 'squads',\n\t\t\tphase: 'act',\n\t\t\tafter: ['goals'],\n\t\t\tthink: () => ai.squads.think()\n\t\t}\n\t} })\n\ndeclare module './area' {\n\tinterface AreaMemories {\n\t\tsquads?: SquadsMemory\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,320 @@
1
+ import { baseStats } from "../defs.js";
2
+ import { heroOfState } from "../hero.js";
3
+ import { attackStat, farthestReach } from "../attacks.js";
4
+ //#region src/ai/strength.ts
5
+ /** How much a hero is worth over its numbers at level 1, and what each level adds: the spells and the items it brings */
6
+ var HERO = 1.1;
7
+ var HERO_LEVEL = .1;
8
+ /** How far reach counts, and how much: a unit that shoots this far deals a quarter more, for the first hits are its */
9
+ var REACH = 10;
10
+ var REACH_WORTH = .25;
11
+ /** The same for speed: it picks its fights and leaves them */
12
+ var SPEED = 8;
13
+ var SPEED_WORTH = .1;
14
+ /** What a declared counter is worth when its weight is left out */
15
+ var COUNTER_WEIGHT = .5;
16
+ /**
17
+ * The kit's formula for how strong a unit is, under a square root so that it adds up over a group (Lanchester):
18
+ *
19
+ * `sqrt(toughness × offence) × hero`, where
20
+ *
21
+ * - `toughness` is the health it has left, more by its armour and magic resist (the middle of the two, since no
22
+ * opponent is in question: 100 of armour doubles it, as the engine's `mitigation` halves what arrives),
23
+ * - `offence` is its damage a second (`attackDamage × attackSpeed`), up to a quarter more for reach (at 10 of range)
24
+ * and a tenth for speed (at 8),
25
+ * - `hero` is 1 for a unit, and `1.1 + 0.1 × (level − 1)` for a hero: its spells, and more as they level.
26
+ *
27
+ * 0 for what has no attack: a building that does not shoot, a worker with no weapon. A declared strength
28
+ * (`UnitTypeDef.ai.strength`) is taken in its place by `Strength`, before this is asked
29
+ *
30
+ * @beta
31
+ */
32
+ var defaultStrength = ({ def, stats, entity, health }) => {
33
+ if (!def.attacks?.length) return 0;
34
+ let dps = 0;
35
+ for (const attack of def.attacks) dps = Math.max(dps, attackStat(stats, attack, "damage") * attackStat(stats, attack, "speed"));
36
+ if (dps <= 0 || stats.health <= 0) return 0;
37
+ const resist = Math.max(0, (stats.armor + stats.magicResist) / 2);
38
+ const toughness = stats.health * health * (1 + resist / 100);
39
+ const offence = dps * reachFactor(def, stats);
40
+ let strength = Math.sqrt(toughness * offence);
41
+ if (def.hero) strength *= HERO + HERO_LEVEL * (((entity && heroOfState(entity)?.level) ?? def.level ?? 1) - 1);
42
+ return strength;
43
+ };
44
+ /** What reach (of its farthest attack) and speed add to what a unit deals: the first hits, the fights it picks */
45
+ var reachFactor = (def, stats) => (1 + Math.min(farthestReach(def, stats), REACH) / REACH * REACH_WORTH) * (1 + Math.min(stats.moveSpeed, SPEED) / SPEED * SPEED_WORTH);
46
+ var KINDS = [
47
+ "unit",
48
+ "building",
49
+ "resource"
50
+ ];
51
+ /** The first of an attacker's attacks that reaches something where it is and of its kind: the engine's `reaches` and `defaultPickAttack`, over profiles */
52
+ function hits(attacker, target) {
53
+ for (const weapon of attacker.weapons) {
54
+ if (target.layer === "air" ? !weapon.hitsAir : !weapon.hitsGround) continue;
55
+ if (!weapon.kinds || weapon.kinds.includes(target.kind)) return weapon;
56
+ }
57
+ }
58
+ /**
59
+ * How strong things are, to a brain (`AiView.strength`, `Brain.strength`): one unit or type (`of`), a group (`sum`,
60
+ * what `UnitSet.strength()` asks), one force against another (`matchup`, `odds`), and what to train against what was
61
+ * seen (`counterFor`). The formula is the kit's (`defaultStrength`) unless the brain was given one
62
+ * (`AiOptions.strength`, `BrainDef.strength`); a type's declared strength (`UnitTypeDef.ai.strength`) goes before
63
+ * either. What a type's numbers come to is worked out once and kept across thinks; a seen unit's own stats
64
+ * (`EntityState.stats`: its upgrades, items, levels, buffs) are read each time
65
+ *
66
+ * @beta
67
+ */
68
+ var Strength = class {
69
+ registry;
70
+ formula;
71
+ profiles = /* @__PURE__ */ new Map();
72
+ plainByType = /* @__PURE__ */ new Map();
73
+ constructor(registry, formula = defaultStrength) {
74
+ this.registry = registry;
75
+ this.formula = formula;
76
+ }
77
+ /** @internal The view the questions are asked through: set by the view that holds this, each think */
78
+ view;
79
+ /**
80
+ * How strong a unit is, with the health it has left and its own stats as the snapshot shows them; or a type at full
81
+ * health with the stats it starts with. 0 for what does not fight. A finite number always
82
+ */
83
+ of(what) {
84
+ if (typeof what === "string") return this.ofType(this.registry.unit(what));
85
+ if ("id" in what && typeof what.id === "string") return this.ofType(what);
86
+ const entity = what;
87
+ const def = this.registry.unit(entity.type);
88
+ if (!def.attacks?.length) return 0;
89
+ const stats = this.statsOf(entity, def);
90
+ return this.evaluate(def, stats, entity, healthOf(entity, stats));
91
+ }
92
+ /** A type at full health: worked out once */
93
+ ofType(def) {
94
+ let found = this.plainByType.get(def.id);
95
+ if (found === void 0) this.plainByType.set(def.id, found = this.evaluate(def, baseStats(def, this.registry), void 0, 1));
96
+ return found;
97
+ }
98
+ /** The formula asked, the declared strength first; whatever comes back made finite */
99
+ evaluate(def, stats, entity, health) {
100
+ const declared = def.ai?.strength;
101
+ const strength = declared !== void 0 ? declared * Math.sqrt(health) : this.formula({
102
+ def,
103
+ stats,
104
+ entity,
105
+ health,
106
+ view: this.view
107
+ });
108
+ return Number.isFinite(strength) && strength > 0 ? strength : 0;
109
+ }
110
+ /** The stats of a seen unit as they stand: its type's, with its own over them (`EntityState.stats`: upgrades, items, levels, buffs) */
111
+ statsOf(entity, def = this.registry.unit(entity.type)) {
112
+ const base = baseStats(def, this.registry);
113
+ return entity.stats ? {
114
+ ...base,
115
+ ...entity.stats
116
+ } : base;
117
+ }
118
+ /** How strong a group is: the strength of each, summed */
119
+ sum(force) {
120
+ let total = 0;
121
+ if (isCounts(force)) {
122
+ for (const type in force) if (this.registry.units.has(type)) total += this.of(type) * force[type];
123
+ return total;
124
+ }
125
+ for (const entity of force) total += this.of(entity);
126
+ return total;
127
+ }
128
+ /**
129
+ * One force against another: the strength of each of `a`'s units against `b` (what it cannot hit counts for nothing
130
+ * of its damage; its damage meets their armour, theirs meets its; what it is declared to counter weighs it up),
131
+ * summed. `matchup(a, b).strength / matchup(b, a).strength` is how `a` compares; `odds` turns it into a chance
132
+ */
133
+ matchup(a, b) {
134
+ const mine = this.groups(a);
135
+ const theirs = this.groups(b);
136
+ let strength = 0;
137
+ let plain = 0;
138
+ let count = 0;
139
+ for (const group of mine) {
140
+ count += group.count;
141
+ plain += group.strength;
142
+ if (group.strength > 0) strength += group.strength * this.edge(group.profile, theirs);
143
+ }
144
+ return {
145
+ strength,
146
+ plain,
147
+ count
148
+ };
149
+ }
150
+ /**
151
+ * The chance that `a` beats `b` in a fight to the end, 0..1: `A² / (A² + B²)` of the two matchups (Lanchester's
152
+ * square law: numbers count twice, since each unit both deals and takes). 0.5 for a mirror, and when neither can hit
153
+ * the other. **An estimate**: it reads stats, layers, armour and declared counters, and knows nothing of spells,
154
+ * terrain, focus fire, who shoots first or who runs; the plan's E3 checks it against fights played out, and a game
155
+ * that knows better gives its own formula (`AiOptions.strength`)
156
+ */
157
+ odds(a, b) {
158
+ const mine = this.matchup(a, b).strength;
159
+ const theirs = this.matchup(b, a).strength;
160
+ const total = mine * mine + theirs * theirs;
161
+ return total > 0 ? mine * mine / total : .5;
162
+ }
163
+ /**
164
+ * What answers a force best among some types: each with its strength against them over its plain strength (1 is as
165
+ * good as against anyone, 0 cannot hit them, above 1 is the answer), the best first, equals in the order given.
166
+ * Against nothing, every type scores 1
167
+ */
168
+ counterFor(enemies, candidates) {
169
+ const theirs = this.groups(enemies);
170
+ return candidates.map((candidate) => {
171
+ const def = typeof candidate === "string" ? this.registry.unit(candidate) : candidate;
172
+ const profile = this.profile(def);
173
+ return {
174
+ def,
175
+ score: this.ofType(def) > 0 ? theirs.length ? this.edge(profile, theirs) : 1 : 0
176
+ };
177
+ }).sort((x, y) => y.score - x.score);
178
+ }
179
+ /** What a game declares a type good against, as `{ target, weight }` each */
180
+ countersOf(type) {
181
+ return this.profile(typeof type === "string" ? this.registry.unit(type) : type).counters;
182
+ }
183
+ /**
184
+ * A profile's strength against a force over its plain strength: what its damage comes to against them (what it can
185
+ * hit, through their armour) and what theirs comes to against it (through its armour), each as a part of the
186
+ * plain, under the same square root, times what it is declared to counter. 1 against nothing
187
+ */
188
+ edge(profile, theirs) {
189
+ if (!theirs.length) return 1;
190
+ const { settings: rules } = this.registry;
191
+ let health = 0;
192
+ let hittable = 0;
193
+ let countered = 0;
194
+ let dps = 0;
195
+ let through = 0;
196
+ for (const group of theirs) {
197
+ const other = group.profile;
198
+ const weight = other.stats.health * group.health;
199
+ health += weight;
200
+ const mine = hits(profile, other);
201
+ if (mine) {
202
+ hittable += weight * rules.combat.mitigation(mine.damageType, other.stats, profile.stats);
203
+ for (const counter of profile.counters) if (this.matches(counter.target, other)) countered += weight * counter.weight;
204
+ }
205
+ const theirs = hits(other, profile);
206
+ if (theirs && theirs.dps > 0) {
207
+ const theirDps = theirs.dps * group.count;
208
+ dps += theirDps;
209
+ through += theirDps * rules.combat.mitigation(theirs.damageType, profile.stats, other.stats);
210
+ }
211
+ }
212
+ if (!health) return 1;
213
+ const plainResist = Math.max(0, (profile.stats.armor + profile.stats.magicResist) / 2);
214
+ const offence = hittable / health;
215
+ const toughness = dps > 0 ? 1 / (through / dps) / (1 + plainResist / 100) : 1;
216
+ return Math.sqrt(offence * toughness) * (1 + countered / health);
217
+ }
218
+ /** Whether a declared counter's word is one of a profile's: its type, a role or a tag of it */
219
+ matches(target, profile) {
220
+ const { roles } = this.view;
221
+ return profile.def.id === target || roles.has(profile.def.id, target) || roles.hasTag(profile.def.id, target);
222
+ }
223
+ /** What a type comes to for a matchup, kept */
224
+ profile(def, stats) {
225
+ const own = stats !== void 0;
226
+ if (!own) {
227
+ const found = this.profiles.get(def.id);
228
+ if (found) return found;
229
+ }
230
+ const read = stats ?? baseStats(def, this.registry);
231
+ const profile = {
232
+ def,
233
+ stats: read,
234
+ layer: def.flying ? "air" : "ground",
235
+ kind: def.kind,
236
+ weapons: (def.attacks ?? []).map((attack) => {
237
+ const { targets } = attack;
238
+ const kinds = targets?.filter((entry) => KINDS.includes(entry));
239
+ return {
240
+ hitsGround: !targets || targets.some((entry) => entry !== "air"),
241
+ hitsAir: !!targets?.includes("air"),
242
+ kinds: kinds?.length ? kinds : void 0,
243
+ damageType: attack.damageType ?? "physical",
244
+ dps: attackStat(read, attack, "damage") * attackStat(read, attack, "speed")
245
+ };
246
+ }),
247
+ counters: (def.ai?.counters ?? []).map((hint) => typeof hint === "string" ? {
248
+ target: hint,
249
+ weight: COUNTER_WEIGHT
250
+ } : {
251
+ target: hint.target,
252
+ weight: hint.weight ?? COUNTER_WEIGHT
253
+ })
254
+ };
255
+ if (!own) this.profiles.set(def.id, profile);
256
+ return profile;
257
+ }
258
+ /** A force as groups: a profile and how many, those with health left and an attack. Units with stats of their own stand apart */
259
+ groups(force) {
260
+ const groups = [];
261
+ if (isCounts(force)) {
262
+ for (const type in force) {
263
+ const count = force[type];
264
+ if (!(count > 0) || !this.registry.units.has(type)) continue;
265
+ const def = this.registry.unit(type);
266
+ if (def.attacks?.length) groups.push({
267
+ profile: this.profile(def),
268
+ count,
269
+ health: count,
270
+ strength: this.ofType(def) * count
271
+ });
272
+ }
273
+ return groups;
274
+ }
275
+ const byType = /* @__PURE__ */ new Map();
276
+ for (const entity of force) {
277
+ if (entity.health <= 0) continue;
278
+ const def = this.registry.unit(entity.type);
279
+ if (!def.attacks?.length) continue;
280
+ if (entity.stats) {
281
+ const stats = this.statsOf(entity, def);
282
+ const health = healthOf(entity, stats);
283
+ groups.push({
284
+ profile: this.profile(def, stats),
285
+ count: 1,
286
+ health,
287
+ strength: this.evaluate(def, stats, entity, health)
288
+ });
289
+ continue;
290
+ }
291
+ let group = byType.get(def.id);
292
+ if (!group) {
293
+ byType.set(def.id, group = {
294
+ profile: this.profile(def),
295
+ count: 0,
296
+ health: 0,
297
+ strength: 0
298
+ });
299
+ groups.push(group);
300
+ }
301
+ const health = healthOf(entity, group.profile.stats);
302
+ group.count++;
303
+ group.health += health;
304
+ group.strength += this.evaluate(def, group.profile.stats, entity, health);
305
+ }
306
+ return groups;
307
+ }
308
+ };
309
+ /** Whether a force is given as types with counts */
310
+ var isCounts = (force) => !(Symbol.iterator in force);
311
+ /** The health a seen unit has left, as a part of its most: 1 for one at full health or whose most is not known */
312
+ function healthOf(entity, stats) {
313
+ const most = entity.maxHealth ?? stats.health;
314
+ if (!(most > 0)) return 1;
315
+ return Math.max(0, Math.min(1, entity.health / most));
316
+ }
317
+ //#endregion
318
+ export { Strength, defaultStrength };
319
+
320
+ //# sourceMappingURL=strength.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strength.js","names":[],"sources":["../../src/ai/strength.ts"],"sourcesContent":["import { baseStats, type DamageType, type EntityKind, type Layer, type Stats, type UnitTypeDef } from '#engine/defs'\nimport type { Registry } from '#engine/registry'\nimport type { EntityState } from '#engine/session/protocol'\nimport type { AiView, UnitSet } from './view'\nimport { heroOfState } from '#engine/hero'\nimport { attackStat, farthestReach } from '#engine/attacks'\n\n/*\n * How strong things are, to a computer player (AI plan, A4). A brain asks three questions of a fight: how strong is this\n * unit, how strong is this group, and who would win. The old melee player answered the first two with health alone and\n * the third with three ifs; this file answers them from the definitions, one documented formula a game can replace.\n *\n * The idea, in plain words. A unit's **strength** is how much it can take times how much it deals, under a square root\n * so that the number adds up: two footmen are twice one. That is Lanchester's square law in a form a brain can sum: when\n * two groups of linear strength A and B fight to the end, the odds of A are A² / (A² + B²), and the mirror is 0.5. What\n * a unit can take is its health, more of it where its armour turns damage away (the engine's `mitigation`); what it\n * deals is its damage a second, a little more where it reaches farther and moves faster (it picks fights and leaves\n * them). A hero is worth more than its numbers for the spells it brings, and more as it levels. Nothing here is of\n * one game: the numbers are the engine's stats as the definitions give them, with what the snapshot shows of a seen\n * unit's own (its upgrades, items, levels and buffs are in `EntityState.stats`), scaled by the health it has left.\n *\n * A **matchup** reads the same numbers against an opponent: what a unit cannot hit (footmen under gryphons) counts for\n * nothing of its damage; what its damage meets is the opponent's armour or magic resist, by the engine's own formula;\n * what hits it is the opponent's mix of damage, against its own armour; and what a game declares a type good against\n * (`UnitTypeDef.ai.counters`) weighs it up. `odds(a, b)` turns two matchups into a chance of winning, an **estimate**\n * said so in its doc: it knows nothing of spells, terrain, focus fire or who shoots first (E3 checks it against fights\n * played out; a game that knows better replaces the formula with `AiOptions.strength`, or declares a type's strength\n * with `UnitTypeDef.ai.strength`). `counterFor` ranks what to train against what was seen, by the same arithmetic\n */\n\n/**\n * A force to weigh: a set of entities as the view gives them (`view.enemies.fighters()`), a plain array of them, or\n * types with counts (`{ footman: 6, gryphon: 2 }`), as the knowledge keeps an army it saw (`ArmySighting.types`,\n * `TypeSeen`): those are taken at full health with the stats their type starts with\n *\n * @beta\n */\nexport type Force = UnitSet | readonly EntityState[] | Readonly<Record<string, number>>\n\n/**\n * What a strength formula is given of one unit or type: its definition, its stats as they stand (the type's, with what\n * the snapshot shows of a seen unit's own: upgrades, items, levels, buffs), the entity where there is one (its health,\n * its level) and the view, for the roles and the registry\n *\n * @beta\n */\nexport interface StrengthInput {\n\t/** The unit type */\n\tdef: UnitTypeDef\n\t/** The stats as they stand: the type's, with a seen unit's own over them */\n\tstats: Readonly<Stats>\n\t/** The unit, where one is weighed; none for a type */\n\tentity?: EntityState\n\t/** 0..1: the health it has left, as a part of its most; 1 for a type */\n\thealth: number\n\t/** The picture it is weighed in: for the roles (`view.roles`) and the definitions (`view.registry`) */\n\tview: AiView\n}\n\n/**\n * How strong a unit or a type is, as a number that adds up over a group: the kit's formula (`defaultStrength`), or a\n * game's own in its place (`AiOptions.strength`, `BrainDef.strength`). Given the unit's definition and stats as they\n * stand, the entity where there is one, and the health it has left as a part of its most. Must give a finite number,\n * 0 for what does not fight\n *\n * @beta\n */\nexport type StrengthFormula = (input: StrengthInput) => number\n\n/**\n * What one side of a matchup is worth against the other, with how (`Strength.matchup`): the strength of each of its\n * units against the opponent, summed\n *\n * @beta\n */\nexport interface Matchup {\n\t/** The side's strength against the opponent: 0 where none of it can hit any of them */\n\tstrength: number\n\t/** The side's strength on its own, against no one in particular */\n\tplain: number\n\t/** How many fought: units with health left and an attack */\n\tcount: number\n}\n\n/**\n * How well a type answers a force (`Strength.counterFor`): its strength against them over its plain strength. 1 is as\n * good as it is against anyone, 0 is useless (it cannot hit them), above 1 it is the answer\n *\n * @beta\n */\nexport interface Counter {\n\t/** The type ranked */\n\tdef: UnitTypeDef\n\t/** Its strength against the force over its plain strength */\n\tscore: number\n}\n\n/**\n * What a game declares a type good against (`UnitTypeDef.ai.counters`): a tag (`'air'`), a role (`'siege'`) or a type\n * id, as a word, or with how much it counts (`weight`, 0.5 when left out: a unit whose whole opponent it counters is\n * worth half again)\n *\n * @beta\n */\nexport type CounterHint = string | { target: string; weight?: number }\n\n/** How much a hero is worth over its numbers at level 1, and what each level adds: the spells and the items it brings */\nconst HERO = 1.1\nconst HERO_LEVEL = 0.1\n/** How far reach counts, and how much: a unit that shoots this far deals a quarter more, for the first hits are its */\nconst REACH = 10\nconst REACH_WORTH = 0.25\n/** The same for speed: it picks its fights and leaves them */\nconst SPEED = 8\nconst SPEED_WORTH = 0.1\n/** What a declared counter is worth when its weight is left out */\nconst COUNTER_WEIGHT = 0.5\n\n/**\n * The kit's formula for how strong a unit is, under a square root so that it adds up over a group (Lanchester):\n *\n * `sqrt(toughness × offence) × hero`, where\n *\n * - `toughness` is the health it has left, more by its armour and magic resist (the middle of the two, since no\n * opponent is in question: 100 of armour doubles it, as the engine's `mitigation` halves what arrives),\n * - `offence` is its damage a second (`attackDamage × attackSpeed`), up to a quarter more for reach (at 10 of range)\n * and a tenth for speed (at 8),\n * - `hero` is 1 for a unit, and `1.1 + 0.1 × (level − 1)` for a hero: its spells, and more as they level.\n *\n * 0 for what has no attack: a building that does not shoot, a worker with no weapon. A declared strength\n * (`UnitTypeDef.ai.strength`) is taken in its place by `Strength`, before this is asked\n *\n * @beta\n */\nexport const defaultStrength: StrengthFormula = ({ def, stats, entity, health }) => {\n\tif (!def.attacks?.length) return 0\n\t// of its attacks, the one that deals the most\n\tlet dps = 0\n\tfor (const attack of def.attacks) dps = Math.max(dps, attackStat(stats, attack, 'damage') * attackStat(stats, attack, 'speed'))\n\tif (dps <= 0 || stats.health <= 0) return 0\n\tconst resist = Math.max(0, (stats.armor + stats.magicResist) / 2)\n\tconst toughness = stats.health * health * (1 + resist / 100)\n\tconst offence = dps * reachFactor(def, stats)\n\tlet strength = Math.sqrt(toughness * offence)\n\tif (def.hero) strength *= HERO + HERO_LEVEL * (((entity && heroOfState(entity)?.level) ?? def.level ?? 1) - 1)\n\treturn strength\n}\n\n/** What reach (of its farthest attack) and speed add to what a unit deals: the first hits, the fights it picks */\nconst reachFactor = (def: UnitTypeDef, stats: Readonly<Stats>): number =>\n\t(1 + (Math.min(farthestReach(def, stats), REACH) / REACH) * REACH_WORTH) * (1 + (Math.min(stats.moveSpeed, SPEED) / SPEED) * SPEED_WORTH)\n\nconst KINDS: readonly EntityKind[] = ['unit', 'building', 'resource']\n\n/** What of a type a matchup reads, worked out once a type and kept (`Strength`): where it is, what it hits, how */\ninterface Profile {\n\tdef: UnitTypeDef\n\tstats: Readonly<Stats>\n\tlayer: Layer\n\tkind: EntityKind\n\t/** Its attacks, in the order of its type's: none for what does not fight */\n\tweapons: readonly Weapon[]\n\t/** What the game declares it good against, by target word */\n\tcounters: readonly { target: string; weight: number }[]\n}\n\n/** One of a profile's attacks, for a matchup */\ninterface Weapon {\n\t/** Whether it reaches the ground, the air */\n\thitsGround: boolean\n\thitsAir: boolean\n\t/** The kinds it names, where it names any: a worker that hits units and buildings, not trees */\n\tkinds: readonly EntityKind[] | undefined\n\tdamageType: DamageType\n\t/** Damage a second */\n\tdps: number\n}\n\n/** One group of a force: a profile, how many of it, their health left as a part of their most, summed, and their strength */\ninterface Group {\n\tprofile: Profile\n\tcount: number\n\t/** Σ health left, 0..1 each: what the group can take, as a part of `count` */\n\thealth: number\n\t/** Σ strength by the formula: with the health each has left and its own stats */\n\tstrength: number\n}\n\n/** The first of an attacker's attacks that reaches something where it is and of its kind: the engine's `reaches` and `defaultPickAttack`, over profiles */\nfunction hits(attacker: Profile, target: Profile): Weapon | undefined {\n\tfor (const weapon of attacker.weapons) {\n\t\tif (target.layer === 'air' ? !weapon.hitsAir : !weapon.hitsGround) continue\n\t\tif (!weapon.kinds || weapon.kinds.includes(target.kind)) return weapon\n\t}\n\treturn undefined\n}\n\n/**\n * How strong things are, to a brain (`AiView.strength`, `Brain.strength`): one unit or type (`of`), a group (`sum`,\n * what `UnitSet.strength()` asks), one force against another (`matchup`, `odds`), and what to train against what was\n * seen (`counterFor`). The formula is the kit's (`defaultStrength`) unless the brain was given one\n * (`AiOptions.strength`, `BrainDef.strength`); a type's declared strength (`UnitTypeDef.ai.strength`) goes before\n * either. What a type's numbers come to is worked out once and kept across thinks; a seen unit's own stats\n * (`EntityState.stats`: its upgrades, items, levels, buffs) are read each time\n *\n * @beta\n */\nexport class Strength {\n\tprivate readonly profiles = new Map<string, Profile>()\n\tprivate readonly plainByType = new Map<string, number>()\n\n\tconstructor(\n\t\t/** The game's definitions */\n\t\treadonly registry: Registry,\n\t\t/** The formula a unit's strength comes from: the kit's unless the brain was given one */\n\t\treadonly formula: StrengthFormula = defaultStrength\n\t) {}\n\n\t/** @internal The view the questions are asked through: set by the view that holds this, each think */\n\tview!: AiView\n\n\t/**\n\t * How strong a unit is, with the health it has left and its own stats as the snapshot shows them; or a type at full\n\t * health with the stats it starts with. 0 for what does not fight. A finite number always\n\t */\n\tof(what: EntityState | UnitTypeDef | string): number {\n\t\tif (typeof what === 'string') return this.ofType(this.registry.unit(what))\n\t\tif ('id' in what && typeof what.id === 'string') return this.ofType(what as UnitTypeDef)\n\t\tconst entity = what as EntityState\n\t\tconst def = this.registry.unit(entity.type)\n\t\tif (!def.attacks?.length) return 0\n\t\tconst stats = this.statsOf(entity, def)\n\t\treturn this.evaluate(def, stats, entity, healthOf(entity, stats))\n\t}\n\n\t/** A type at full health: worked out once */\n\tprivate ofType(def: UnitTypeDef): number {\n\t\tlet found = this.plainByType.get(def.id)\n\t\tif (found === undefined) this.plainByType.set(def.id, (found = this.evaluate(def, baseStats(def, this.registry), undefined, 1)))\n\t\treturn found\n\t}\n\n\t/** The formula asked, the declared strength first; whatever comes back made finite */\n\tprivate evaluate(def: UnitTypeDef, stats: Readonly<Stats>, entity: EntityState | undefined, health: number): number {\n\t\tconst declared = def.ai?.strength\n\t\tconst strength = declared !== undefined ? declared * Math.sqrt(health) : this.formula({ def, stats, entity, health, view: this.view })\n\t\treturn Number.isFinite(strength) && strength > 0 ? strength : 0\n\t}\n\n\t/** The stats of a seen unit as they stand: its type's, with its own over them (`EntityState.stats`: upgrades, items, levels, buffs) */\n\tstatsOf(entity: EntityState, def = this.registry.unit(entity.type)): Readonly<Stats> {\n\t\tconst base = baseStats(def, this.registry)\n\t\treturn entity.stats ? ({ ...base, ...entity.stats } as Stats) : base\n\t}\n\n\t/** How strong a group is: the strength of each, summed */\n\tsum(force: Force): number {\n\t\tlet total = 0\n\t\tif (isCounts(force)) {\n\t\t\tfor (const type in force) if (this.registry.units.has(type)) total += this.of(type) * force[type]\n\t\t\treturn total\n\t\t}\n\t\tfor (const entity of force) total += this.of(entity)\n\t\treturn total\n\t}\n\n\t/**\n\t * One force against another: the strength of each of `a`'s units against `b` (what it cannot hit counts for nothing\n\t * of its damage; its damage meets their armour, theirs meets its; what it is declared to counter weighs it up),\n\t * summed. `matchup(a, b).strength / matchup(b, a).strength` is how `a` compares; `odds` turns it into a chance\n\t */\n\tmatchup(a: Force, b: Force): Matchup {\n\t\tconst mine = this.groups(a)\n\t\tconst theirs = this.groups(b)\n\t\tlet strength = 0\n\t\tlet plain = 0\n\t\tlet count = 0\n\t\tfor (const group of mine) {\n\t\t\tcount += group.count\n\t\t\tplain += group.strength\n\t\t\tif (group.strength > 0) strength += group.strength * this.edge(group.profile, theirs)\n\t\t}\n\t\treturn { strength, plain, count }\n\t}\n\n\t/**\n\t * The chance that `a` beats `b` in a fight to the end, 0..1: `A² / (A² + B²)` of the two matchups (Lanchester's\n\t * square law: numbers count twice, since each unit both deals and takes). 0.5 for a mirror, and when neither can hit\n\t * the other. **An estimate**: it reads stats, layers, armour and declared counters, and knows nothing of spells,\n\t * terrain, focus fire, who shoots first or who runs; the plan's E3 checks it against fights played out, and a game\n\t * that knows better gives its own formula (`AiOptions.strength`)\n\t */\n\todds(a: Force, b: Force): number {\n\t\tconst mine = this.matchup(a, b).strength\n\t\tconst theirs = this.matchup(b, a).strength\n\t\tconst total = mine * mine + theirs * theirs\n\t\treturn total > 0 ? (mine * mine) / total : 0.5\n\t}\n\n\t/**\n\t * What answers a force best among some types: each with its strength against them over its plain strength (1 is as\n\t * good as against anyone, 0 cannot hit them, above 1 is the answer), the best first, equals in the order given.\n\t * Against nothing, every type scores 1\n\t */\n\tcounterFor(enemies: Force, candidates: readonly (UnitTypeDef | string)[]): Counter[] {\n\t\tconst theirs = this.groups(enemies)\n\t\tconst ranked = candidates.map((candidate) => {\n\t\t\tconst def = typeof candidate === 'string' ? this.registry.unit(candidate) : candidate\n\t\t\tconst profile = this.profile(def)\n\t\t\tconst score = this.ofType(def) > 0 ? (theirs.length ? this.edge(profile, theirs) : 1) : 0\n\t\t\treturn { def, score }\n\t\t})\n\t\treturn ranked.sort((x, y) => y.score - x.score)\n\t}\n\n\t/** What a game declares a type good against, as `{ target, weight }` each */\n\tcountersOf(type: UnitTypeDef | string): readonly { target: string; weight: number }[] {\n\t\treturn this.profile(typeof type === 'string' ? this.registry.unit(type) : type).counters\n\t}\n\n\t/**\n\t * A profile's strength against a force over its plain strength: what its damage comes to against them (what it can\n\t * hit, through their armour) and what theirs comes to against it (through its armour), each as a part of the\n\t * plain, under the same square root, times what it is declared to counter. 1 against nothing\n\t */\n\tprivate edge(profile: Profile, theirs: readonly Group[]): number {\n\t\tif (!theirs.length) return 1\n\t\tconst { settings: rules } = this.registry\n\t\t// what its damage meets: the share of them it can hit, each through their armour, weighted by the health to chew\n\t\tlet health = 0\n\t\tlet hittable = 0\n\t\tlet countered = 0\n\t\t// what hits it: their damage, each through its armour, as a part of all their damage\n\t\tlet dps = 0\n\t\tlet through = 0\n\t\tfor (const group of theirs) {\n\t\t\tconst other = group.profile\n\t\t\tconst weight = other.stats.health * group.health\n\t\t\thealth += weight\n\t\t\tconst mine = hits(profile, other)\n\t\t\tif (mine) {\n\t\t\t\thittable += weight * rules.combat.mitigation(mine.damageType, other.stats, profile.stats)\n\t\t\t\tfor (const counter of profile.counters) if (this.matches(counter.target, other)) countered += weight * counter.weight\n\t\t\t}\n\t\t\tconst theirs = hits(other, profile)\n\t\t\tif (theirs && theirs.dps > 0) {\n\t\t\t\tconst theirDps = theirs.dps * group.count\n\t\t\t\tdps += theirDps\n\t\t\t\tthrough += theirDps * rules.combat.mitigation(theirs.damageType, profile.stats, other.stats)\n\t\t\t}\n\t\t}\n\t\tif (!health) return 1\n\t\t// its damage against them, as a part of the plain (the plain met the middle of armour and magic resist)\n\t\tconst plainResist = Math.max(0, (profile.stats.armor + profile.stats.magicResist) / 2)\n\t\tconst offence = hittable / health\n\t\t// what it can take against them, as a part of the plain: what they get through, against the middle it was read at\n\t\tconst toughness = dps > 0 ? 1 / (through / dps) / (1 + plainResist / 100) : 1\n\t\treturn Math.sqrt(offence * toughness) * (1 + countered / health)\n\t}\n\n\t/** Whether a declared counter's word is one of a profile's: its type, a role or a tag of it */\n\tprivate matches(target: string, profile: Profile): boolean {\n\t\tconst { roles } = this.view\n\t\treturn profile.def.id === target || roles.has(profile.def.id, target) || roles.hasTag(profile.def.id, target)\n\t}\n\n\t/** What a type comes to for a matchup, kept */\n\tprivate profile(def: UnitTypeDef, stats?: Readonly<Stats>): Profile {\n\t\tconst own = stats !== undefined\n\t\tif (!own) {\n\t\t\tconst found = this.profiles.get(def.id)\n\t\t\tif (found) return found\n\t\t}\n\t\tconst read = stats ?? baseStats(def, this.registry)\n\t\tconst profile: Profile = {\n\t\t\tdef,\n\t\t\tstats: read,\n\t\t\tlayer: def.flying ? 'air' : 'ground',\n\t\t\tkind: def.kind,\n\t\t\tweapons: (def.attacks ?? []).map((attack) => {\n\t\t\t\tconst { targets } = attack\n\t\t\t\tconst kinds = targets?.filter((entry): entry is EntityKind => KINDS.includes(entry as EntityKind))\n\t\t\t\treturn {\n\t\t\t\t\thitsGround: !targets || targets.some((entry) => entry !== 'air'),\n\t\t\t\t\thitsAir: !!targets?.includes('air'),\n\t\t\t\t\tkinds: kinds?.length ? kinds : undefined,\n\t\t\t\t\tdamageType: attack.damageType ?? 'physical',\n\t\t\t\t\tdps: attackStat(read, attack, 'damage') * attackStat(read, attack, 'speed')\n\t\t\t\t}\n\t\t\t}),\n\t\t\tcounters: (def.ai?.counters ?? []).map((hint) =>\n\t\t\t\ttypeof hint === 'string' ? { target: hint, weight: COUNTER_WEIGHT } : { target: hint.target, weight: hint.weight ?? COUNTER_WEIGHT }\n\t\t\t)\n\t\t}\n\t\tif (!own) this.profiles.set(def.id, profile)\n\t\treturn profile\n\t}\n\n\t/** A force as groups: a profile and how many, those with health left and an attack. Units with stats of their own stand apart */\n\tprivate groups(force: Force): Group[] {\n\t\tconst groups: Group[] = []\n\t\tif (isCounts(force)) {\n\t\t\tfor (const type in force) {\n\t\t\t\tconst count = force[type]\n\t\t\t\tif (!(count > 0) || !this.registry.units.has(type)) continue\n\t\t\t\tconst def = this.registry.unit(type)\n\t\t\t\tif (def.attacks?.length) groups.push({ profile: this.profile(def), count, health: count, strength: this.ofType(def) * count })\n\t\t\t}\n\t\t\treturn groups\n\t\t}\n\t\tconst byType = new Map<string, Group>()\n\t\tfor (const entity of force) {\n\t\t\tif (entity.health <= 0) continue\n\t\t\tconst def = this.registry.unit(entity.type)\n\t\t\tif (!def.attacks?.length) continue\n\t\t\tif (entity.stats) {\n\t\t\t\tconst stats = this.statsOf(entity, def)\n\t\t\t\tconst health = healthOf(entity, stats)\n\t\t\t\tgroups.push({ profile: this.profile(def, stats), count: 1, health, strength: this.evaluate(def, stats, entity, health) })\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlet group = byType.get(def.id)\n\t\t\tif (!group) {\n\t\t\t\tbyType.set(def.id, (group = { profile: this.profile(def), count: 0, health: 0, strength: 0 }))\n\t\t\t\tgroups.push(group)\n\t\t\t}\n\t\t\tconst health = healthOf(entity, group.profile.stats)\n\t\t\tgroup.count++\n\t\t\tgroup.health += health\n\t\t\tgroup.strength += this.evaluate(def, group.profile.stats, entity, health)\n\t\t}\n\t\treturn groups\n\t}\n}\n\n/** Whether a force is given as types with counts */\nconst isCounts = (force: Force): force is Readonly<Record<string, number>> => !(Symbol.iterator in force)\n\n/** The health a seen unit has left, as a part of its most: 1 for one at full health or whose most is not known */\nfunction healthOf(entity: EntityState, stats: Readonly<Stats>): number {\n\tconst most = entity.maxHealth ?? stats.health\n\tif (!(most > 0)) return 1\n\treturn Math.max(0, Math.min(1, entity.health / most))\n}\n"],"mappings":"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"}
package/dist/ai/task.d.ts CHANGED
@@ -20,7 +20,9 @@ export type TaskDone = 'arrived' | 'cleared' | 'lost' | 'retreated' | 'wiped' |
20
20
  * @beta
21
21
  */
22
22
  export interface TaskOrder {
23
+ /** The kind of task: one of the kit's by its word or the id of a game's (`defineTask`) */
23
24
  kind: string;
25
+ /** What the task is given, beside its kind */
24
26
  data?: TaskData;
25
27
  }
26
28
  /**
@@ -115,4 +117,4 @@ export interface TaskDef<D extends object = TaskData, M extends object = TaskMem
115
117
  *
116
118
  * @beta
117
119
  */
118
- export declare function defineTask<D extends object = TaskData, M extends object = TaskMemory>(id: string, def: Omit<TaskDef<D, M>, 'id'>): TaskDef<D, M>;
120
+ export declare function defineTask<D extends object = TaskData, M extends object = TaskMemory>(def: TaskDef<D, M>): TaskDef<D, M>;
@@ -0,0 +1,17 @@
1
+ //#region src/ai/task.ts
2
+ /**
3
+ * Defines a task: a kind of thing a squad can be told to do (`squad.task(def, data)`, its data typed by the task), the
4
+ * kit's and a game's own. List a game's in the brain's `settings.squads.tasks`, so that a squad on it goes on after a
5
+ * load
6
+ *
7
+ * @beta
8
+ */
9
+ function defineTask(def) {
10
+ if (!def.id) throw new Error("A task needs an id");
11
+ if (typeof def.start !== "function" || typeof def.think !== "function") throw new Error(`The task "${def.id}" needs a start and a think`);
12
+ return def;
13
+ }
14
+ //#endregion
15
+ export { defineTask };
16
+
17
+ //# sourceMappingURL=task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task.js","names":[],"sources":["../../src/ai/task.ts"],"sourcesContent":["/**\n * A kind of task a squad is on (design review B10): its definition (`TaskDef`, `defineTask`), typed by what it is given\n * (`TaskData`) and what it remembers (`TaskMemory`), and its state as the brain keeps it (`TaskState`). Apart from the\n * squads (`squads.ts`), so that the kit's tasks (`tasks/`) and a game's define theirs without loading the squads\n */\nimport type { Vec2 } from '#engine/math'\nimport type { Brain } from './brain'\nimport type { Squad } from './squads'\n\n/**\n * How a task ended (`TaskState.done`): `arrived` where it was sent, `cleared` with nothing left to fight where it went,\n * `lost` its target (gone from sight: killed, or out of it), `retreated` home after a fight it was losing, `wiped`\n * with none of its units left; or a game's own word\n *\n * @beta\n */\nexport type TaskDone = 'arrived' | 'cleared' | 'lost' | 'retreated' | 'wiped' | (string & {})\n\n/**\n * A task to give next (`then`): its kind (the kit's `attack`, a game's `defineTask` id) and what it is given\n *\n * @beta\n */\nexport interface TaskOrder {\n\t/** The kind of task: one of the kit's by its word or the id of a game's (`defineTask`) */\n\tkind: string\n\t/** What the task is given, beside its kind */\n\tdata?: TaskData\n}\n\n/**\n * What any task may be given beside its own (`TaskState.data`): the task after it (`then`), and `regroup: false` for one\n * not stopped for its stragglers\n *\n * @beta\n */\nexport type TaskCommon = {\n\tthen?: TaskOrder\n\tregroup?: boolean\n}\n\n/**\n * What a task is given, as plain data (`TaskState.data`): each task says its own shape (`defineTask<Data>`)\n *\n * @beta\n */\nexport type TaskData = Record<string, unknown>\n\n/**\n * What a task remembers of its own, as plain data (`TaskState.memory`): each task says its own shape\n * (`defineTask<Data, Memory>`)\n *\n * @beta\n */\nexport type TaskMemory = Record<string, unknown>\n\n/**\n * What a squad is doing, as plain data kept in the brain's memory: the kind of task, what it was given, where it is in\n * it (`phase`: `going`, `regrouping`, `fighting`, `gathering`, `holding`, the task's own words), since when, the last\n * order it sent, and how it ended\n *\n * @beta\n */\nexport interface TaskState<D extends object = TaskData, M extends object = TaskMemory> {\n\t/** The kind of task: the kit's (`attack`) or a game's (`defineTask`) */\n\tkind: string\n\t/** What it was given: a point (`at`), a target, a radius, what to do next (`then`). Plain data, of the task's shape */\n\tdata: D & TaskCommon\n\t/** The tick it began at */\n\tsince: number\n\t/** Where it is in it, in a word */\n\tphase: string\n\t/** The tick its phase began at */\n\tphaseSince: number\n\t/** The tick it last sent an order */\n\tsent?: number\n\t/** How it ended: none while it goes on */\n\tdone?: TaskDone\n\t/** The tick it ended at */\n\tdoneAt?: number\n\t/** What the task remembers of its own, plain data of the task's shape: the point of a scout's round it is at */\n\tmemory: M\n}\n\n/**\n * A kind of task (`defineTask`): what it sends as it begins (`start`), what it looks at each think (`think`), and the\n * place it is about (`where`, for the squads module's regroup and reinforcements and for the report). The squads\n * module runs it with its own regroup, reinforce and retreat around it, but for what it `handles` itself\n *\n * @beta\n */\nexport interface TaskDef<D extends object = TaskData, M extends object = TaskMemory> {\n\t/** Unique among the brain's tasks: what a save names it by. The kit's are words (`attack`); a game's prefixed (`ctf.capture`) */\n\tid: string\n\t/**\n\t * Sends what puts the squad on its way: called as the task is given, and again as the squad goes on after a regroup.\n\t * Sets `state.phase`\n\t */\n\tstart(ai: Brain, squad: Squad, state: TaskState<D, M>): void\n\t/** Each think, after the squads module looked at the squad: watches how it goes, sends what was lost, `squad.finish(done)` when it is over */\n\tthink(ai: Brain, squad: Squad, state: TaskState<D, M>): void\n\t/** Whether it is over, asked each think before `think`: how it ended, or nothing while it goes on */\n\tdone?(ai: Brain, squad: Squad, state: TaskState<D, M>): TaskDone | undefined | false\n\t/** The place it is about: where reinforcements are sent, what the report shows. None for a task about no place */\n\twhere?(ai: Brain, squad: Squad, state: TaskState<D, M>): Vec2 | undefined\n\t/** What the squads module leaves to it: a task that regroups in its own way, or retreats never */\n\thandles?: readonly ('retreat' | 'regroup' | 'reinforce')[]\n\t/**\n\t * Whether it is a standing duty, going on as long as its squad has it (a hero walking a lane with its waves): never\n\t * stuck, whatever its phase, for the `ends` invariant (`checkBrain`). No when left out\n\t */\n\tstanding?: boolean\n\t/**\n\t * Whether a squad on it is in a fight it means to win, which the micro fights for (`ai.area(Micro)`): yes when left\n\t * out. No for a task that goes somewhere, looks, stands, gathers or falls back (the kit's `move`, `scout`, `hold`,\n\t * `gather`, `retreat`, and the micro's own `flee`)\n\t */\n\tfighting?: boolean\n}\n\n/**\n * Defines a task: a kind of thing a squad can be told to do (`squad.task(def, data)`, its data typed by the task), the\n * kit's and a game's own. List a game's in the brain's `settings.squads.tasks`, so that a squad on it goes on after a\n * load\n *\n * @beta\n */\nexport function defineTask<D extends object = TaskData, M extends object = TaskMemory>(def: TaskDef<D, M>): TaskDef<D, M> {\n\tif (!def.id) throw new Error('A task needs an id')\n\tif (typeof def.start !== 'function' || typeof def.think !== 'function') throw new Error(`The task \"${def.id}\" needs a start and a think`)\n\treturn def\n}\n"],"mappings":";;;;;;;;AA+HA,SAAgB,WAAuE,KAAmC;CACzH,IAAI,CAAC,IAAI,IAAI,MAAM,IAAI,MAAM,oBAAoB;CACjD,IAAI,OAAO,IAAI,UAAU,cAAc,OAAO,IAAI,UAAU,YAAY,MAAM,IAAI,MAAM,aAAa,IAAI,GAAG,4BAA4B;CACxI,OAAO;AACR"}
@@ -0,0 +1,24 @@
1
+ import { defineTask } from "../task.js";
2
+ import { goFight, placeOf, planRoute, watchFight } from "./shared.js";
3
+ //#region src/ai/tasks/attack.ts
4
+ /**
5
+ * The kit's `attack` task (design review B10): attacks a place or a target, by a way round where told: done `cleared` with nothing left to fight there, `lost` with its target gone
6
+ */
7
+ /**
8
+ * Attacks a place or a target, by a way round where told: done `cleared` with nothing left to fight there, `lost` with its target gone
9
+ *
10
+ * @beta
11
+ */
12
+ var ATTACK = defineTask({
13
+ id: "attack",
14
+ start(ai, squad, state) {
15
+ planRoute(ai, squad, state);
16
+ goFight(ai, squad, state);
17
+ },
18
+ think: watchFight,
19
+ where: (ai, _squad, state) => placeOf(ai, state)
20
+ });
21
+ //#endregion
22
+ export { ATTACK };
23
+
24
+ //# sourceMappingURL=attack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attack.js","names":[],"sources":["../../../src/ai/tasks/attack.ts"],"sourcesContent":["/**\n * The kit's `attack` task (design review B10): attacks a place or a target, by a way round where told: done `cleared` with nothing left to fight there, `lost` with its target gone\n */\nimport { defineTask } from '../task'\nimport { type FightData, type FightMemory, goFight, placeOf, planRoute, watchFight } from './shared'\n\n/**\n * Attacks a place or a target, by a way round where told: done `cleared` with nothing left to fight there, `lost` with its target gone\n *\n * @beta\n */\nexport const ATTACK = defineTask<FightData, FightMemory>({ id: 'attack', start(ai, squad, state) {\n\t\tplanRoute(ai, squad, state)\n\t\tgoFight(ai, squad, state)\n\t},\n\tthink: watchFight,\n\twhere: (ai, _squad, state) => placeOf(ai, state) })\n"],"mappings":";;;;;;;;;;;AAWA,IAAa,SAAS,WAAmC;CAAE,IAAI;CAAU,MAAM,IAAI,OAAO,OAAO;EAC/F,UAAU,IAAI,OAAO,KAAK;EAC1B,QAAQ,IAAI,OAAO,KAAK;CACzB;CACA,OAAO;CACP,QAAQ,IAAI,QAAQ,UAAU,QAAQ,IAAI,KAAK;AAAE,CAAC"}