@v12-engine/engine 0.0.0-stage → 0.1.1

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 (341) hide show
  1. package/LICENSE +21 -0
  2. package/dist/abilities/buffs.d.ts +83 -0
  3. package/dist/abilities/castTold.d.ts +12 -0
  4. package/dist/abilities/charges.d.ts +28 -0
  5. package/dist/abilities/dispel.d.ts +9 -0
  6. package/dist/abilities/effectFields.d.ts +10 -0
  7. package/dist/abilities/effects/buff.d.ts +8 -0
  8. package/dist/abilities/effects/core.d.ts +1 -0
  9. package/dist/abilities/effects/damage.d.ts +1 -0
  10. package/dist/abilities/effects/heal.d.ts +2 -0
  11. package/dist/abilities/effects/missile.d.ts +1 -0
  12. package/dist/abilities/effects/moves.d.ts +11 -0
  13. package/dist/abilities/effects/passives.d.ts +15 -0
  14. package/dist/abilities/effects/sight.d.ts +4 -0
  15. package/dist/abilities/effects/spawn.d.ts +2 -0
  16. package/dist/abilities/effects/timed.d.ts +4 -0
  17. package/dist/abilities/effects/trade.d.ts +1 -0
  18. package/dist/abilities/effects.d.ts +122 -0
  19. package/dist/abilities/land.d.ts +21 -0
  20. package/dist/abilities/scaled.d.ts +21 -0
  21. package/dist/abilities/text.d.ts +113 -0
  22. package/dist/ai/area.d.ts +53 -0
  23. package/dist/ai/brain.d.ts +528 -0
  24. package/dist/ai/budget.d.ts +67 -0
  25. package/dist/ai/checks.d.ts +115 -0
  26. package/dist/ai/computer.d.ts +166 -0
  27. package/dist/ai/defence.d.ts +108 -0
  28. package/dist/ai/define.d.ts +21 -0
  29. package/dist/ai/economy.d.ts +129 -0
  30. package/dist/ai/geometry.d.ts +35 -0
  31. package/dist/ai/goals.d.ts +360 -0
  32. package/dist/ai/index.d.ts +38 -0
  33. package/dist/ai/knowledge.d.ts +418 -0
  34. package/dist/ai/lanes.d.ts +232 -0
  35. package/dist/ai/melee/build.d.ts +61 -0
  36. package/dist/ai/melee/goals.d.ts +299 -0
  37. package/dist/ai/melee/heroes.d.ts +27 -0
  38. package/dist/ai/melee/index.d.ts +14 -0
  39. package/dist/ai/melee/production.d.ts +8 -0
  40. package/dist/ai/melee/surrender.d.ts +24 -0
  41. package/dist/ai/micro.d.ts +278 -0
  42. package/dist/ai/mission.d.ts +195 -0
  43. package/dist/ai/missionRules.d.ts +18 -0
  44. package/dist/ai/module.d.ts +116 -0
  45. package/dist/ai/options.d.ts +61 -0
  46. package/dist/ai/plans/build.d.ts +280 -0
  47. package/dist/ai/plans/placement.d.ts +82 -0
  48. package/dist/ai/plans/plans.d.ts +105 -0
  49. package/dist/ai/plans/production.d.ts +210 -0
  50. package/dist/ai/plans/purse.d.ts +73 -0
  51. package/dist/ai/plans/tech.d.ts +37 -0
  52. package/dist/ai/profiles.d.ts +204 -0
  53. package/dist/ai/reach.d.ts +4 -0
  54. package/dist/ai/report.d.ts +203 -0
  55. package/dist/ai/roles.d.ts +133 -0
  56. package/dist/ai/rules.d.ts +288 -0
  57. package/dist/ai/scouting.d.ts +98 -0
  58. package/dist/ai/settings.d.ts +73 -0
  59. package/dist/ai/squads.d.ts +429 -0
  60. package/dist/ai/strength.d.ts +167 -0
  61. package/dist/ai/task.d.ts +118 -0
  62. package/dist/ai/tasks/attack.d.ts +7 -0
  63. package/dist/ai/tasks/capture.d.ts +21 -0
  64. package/dist/ai/tasks/creep.d.ts +16 -0
  65. package/dist/ai/tasks/defend.d.ts +29 -0
  66. package/dist/ai/tasks/drop.d.ts +34 -0
  67. package/dist/ai/tasks/escort.d.ts +16 -0
  68. package/dist/ai/tasks/gather.d.ts +23 -0
  69. package/dist/ai/tasks/harass.d.ts +7 -0
  70. package/dist/ai/tasks/hold.d.ts +20 -0
  71. package/dist/ai/tasks/index.d.ts +32 -0
  72. package/dist/ai/tasks/move.d.ts +19 -0
  73. package/dist/ai/tasks/patrol.d.ts +8 -0
  74. package/dist/ai/tasks/retreat.d.ts +20 -0
  75. package/dist/ai/tasks/scout.d.ts +29 -0
  76. package/dist/ai/tasks/shared.d.ts +74 -0
  77. package/dist/ai/team.d.ts +155 -0
  78. package/dist/ai/threat.d.ts +91 -0
  79. package/dist/ai/view.d.ts +366 -0
  80. package/dist/ai/waves.d.ts +126 -0
  81. package/dist/ai.js +6239 -0
  82. package/dist/ai.js.map +1 -0
  83. package/dist/aiTesting.d.ts +179 -0
  84. package/dist/areas.d.ts +149 -0
  85. package/dist/attacks.d.ts +66 -0
  86. package/dist/attributes.d.ts +66 -0
  87. package/dist/brain-BvVdUhX8.js +7659 -0
  88. package/dist/brain-BvVdUhX8.js.map +1 -0
  89. package/dist/builds-C6LfgvEU.js +460 -0
  90. package/dist/builds-C6LfgvEU.js.map +1 -0
  91. package/dist/bytes.d.ts +6 -0
  92. package/dist/camps.d.ts +95 -0
  93. package/dist/capture.d.ts +131 -0
  94. package/dist/cellLayers.d.ts +75 -0
  95. package/dist/cinematics.d.ts +194 -0
  96. package/dist/clock.d.ts +32 -0
  97. package/dist/commands.d.ts +235 -0
  98. package/dist/components.d.ts +184 -0
  99. package/dist/computers.d.ts +108 -0
  100. package/dist/concealment.d.ts +61 -0
  101. package/dist/coreComponents-syuh2fPG.js +5149 -0
  102. package/dist/coreComponents-syuh2fPG.js.map +1 -0
  103. package/dist/coreComponents.d.ts +1 -0
  104. package/dist/dashing.d.ts +8 -0
  105. package/dist/debug.d.ts +36 -0
  106. package/dist/debug.js +3 -0
  107. package/dist/debugCommands-CzjrSm66.js +14739 -0
  108. package/dist/debugCommands-CzjrSm66.js.map +1 -0
  109. package/dist/debugCommands.d.ts +213 -0
  110. package/dist/debugging.d.ts +10 -0
  111. package/dist/definitions.d.ts +43 -0
  112. package/dist/defs.d.ts +1162 -0
  113. package/dist/denying.d.ts +81 -0
  114. package/dist/destructibles.d.ts +27 -0
  115. package/dist/determinism-BCymQwiE.js +518 -0
  116. package/dist/determinism-BCymQwiE.js.map +1 -0
  117. package/dist/determinism.d.ts +121 -0
  118. package/dist/dialog.d.ts +94 -0
  119. package/dist/effectRefs.d.ts +16 -0
  120. package/dist/effects.d.ts +80 -0
  121. package/dist/endings.d.ts +22 -0
  122. package/dist/engagement.d.ts +108 -0
  123. package/dist/engineEvents.d.ts +710 -0
  124. package/dist/entity.d.ts +409 -0
  125. package/dist/entityIndex.d.ts +50 -0
  126. package/dist/errors.d.ts +85 -0
  127. package/dist/events.d.ts +97 -0
  128. package/dist/exactMath.d.ts +63 -0
  129. package/dist/features.d.ts +10 -0
  130. package/dist/fields.d.ts +114 -0
  131. package/dist/fixture.d.ts +17 -0
  132. package/dist/fog.d.ts +110 -0
  133. package/dist/formation.d.ts +111 -0
  134. package/dist/friendlyFire.d.ts +26 -0
  135. package/dist/game-DiJEN-Ks.js +5800 -0
  136. package/dist/game-DiJEN-Ks.js.map +1 -0
  137. package/dist/game.d.ts +501 -0
  138. package/dist/gameData.d.ts +325 -0
  139. package/dist/gameFiles.d.ts +26 -0
  140. package/dist/gates.d.ts +28 -0
  141. package/dist/generate.d.ts +403 -0
  142. package/dist/generateWorker.d.ts +39 -0
  143. package/dist/grid.d.ts +53 -0
  144. package/dist/ground.d.ts +127 -0
  145. package/dist/groundSpeed.d.ts +22 -0
  146. package/dist/hero.d.ts +177 -0
  147. package/dist/home.d.ts +14 -0
  148. package/dist/hooks.d.ts +780 -0
  149. package/dist/hotReload.d.ts +76 -0
  150. package/dist/ids.d.ts +26 -0
  151. package/dist/index.d.ts +227 -0
  152. package/dist/index.js +4701 -0
  153. package/dist/index.js.map +1 -0
  154. package/dist/inspect-D9dWHmZ0.js +491 -0
  155. package/dist/inspect-D9dWHmZ0.js.map +1 -0
  156. package/dist/inspect.d.ts +176 -0
  157. package/dist/inventory.d.ts +18 -0
  158. package/dist/items.d.ts +91 -0
  159. package/dist/lanes.d.ts +213 -0
  160. package/dist/life.d.ts +53 -0
  161. package/dist/local-Dkovq42k.js +1379 -0
  162. package/dist/local-Dkovq42k.js.map +1 -0
  163. package/dist/log.d.ts +140 -0
  164. package/dist/manaBurn.d.ts +39 -0
  165. package/dist/map/file.d.ts +114 -0
  166. package/dist/map/images.d.ts +18 -0
  167. package/dist/map/look.d.ts +47 -0
  168. package/dist/map/pathProfile.d.ts +13 -0
  169. package/dist/map/resize.d.ts +54 -0
  170. package/dist/map/schema.d.ts +10 -0
  171. package/dist/map/terrain.d.ts +32 -0
  172. package/dist/map/types.d.ts +613 -0
  173. package/dist/map.d.ts +7 -0
  174. package/dist/mapCheck/cells.d.ts +19 -0
  175. package/dist/mapCheck/rule.d.ts +30 -0
  176. package/dist/mapCheck/rules/names.d.ts +3 -0
  177. package/dist/mapCheck/rules/objects.d.ts +3 -0
  178. package/dist/mapCheck/rules/paths.d.ts +3 -0
  179. package/dist/mapCheck/rules/players.d.ts +3 -0
  180. package/dist/mapCheck/rules/races.d.ts +3 -0
  181. package/dist/mapCheck/rules/random.d.ts +3 -0
  182. package/dist/mapCheck/rules/regions.d.ts +3 -0
  183. package/dist/mapCheck/rules/targets.d.ts +3 -0
  184. package/dist/mapCheck/rules/walking.d.ts +3 -0
  185. package/dist/mapCheck.d.ts +23 -0
  186. package/dist/mapFields.d.ts +364 -0
  187. package/dist/mapFile.d.ts +23 -0
  188. package/dist/mapMeasure.d.ts +95 -0
  189. package/dist/mapMerge.d.ts +19 -0
  190. package/dist/mapObjectives.d.ts +82 -0
  191. package/dist/mapObjects.d.ts +1 -0
  192. package/dist/math.d.ts +44 -0
  193. package/dist/messages.d.ts +150 -0
  194. package/dist/missionRules-C-bGxm0Q.js +523 -0
  195. package/dist/missionRules-C-bGxm0Q.js.map +1 -0
  196. package/dist/missionRules.d.ts +179 -0
  197. package/dist/mods.d.ts +146 -0
  198. package/dist/names.d.ts +93 -0
  199. package/dist/navigation/agentParams.d.ts +4 -0
  200. package/dist/navigation/air.d.ts +89 -0
  201. package/dist/navigation/builds.d.ts +140 -0
  202. package/dist/navigation/groundAreas.d.ts +23 -0
  203. package/dist/navigation/navigation.d.ts +127 -0
  204. package/dist/navigation/recast.d.ts +214 -0
  205. package/dist/navigation/sidePaths.d.ts +69 -0
  206. package/dist/navigation/sized.d.ts +1 -0
  207. package/dist/navigation-worker.js +11 -0
  208. package/dist/navigation-worker.js.map +1 -0
  209. package/dist/nearest.d.ts +8 -0
  210. package/dist/noise.d.ts +12 -0
  211. package/dist/objectives.d.ts +93 -0
  212. package/dist/orders/basic.d.ts +96 -0
  213. package/dist/orders/build.d.ts +91 -0
  214. package/dist/orders/cast.d.ts +105 -0
  215. package/dist/orders/facts.d.ts +14 -0
  216. package/dist/orders/harvest.d.ts +94 -0
  217. package/dist/orders/idle.d.ts +7 -0
  218. package/dist/orders/items.d.ts +14 -0
  219. package/dist/orders/queue.d.ts +24 -0
  220. package/dist/pack.schema.json +6621 -0
  221. package/dist/packs/director/index.d.ts +81 -0
  222. package/dist/packs/heroes/campaign.d.ts +137 -0
  223. package/dist/packs/heroes/carry.d.ts +59 -0
  224. package/dist/packs/heroes/commands.d.ts +6 -0
  225. package/dist/packs/heroes/hire.d.ts +9 -0
  226. package/dist/packs/heroes/index.d.ts +12 -0
  227. package/dist/packs/heroes/making.d.ts +16 -0
  228. package/dist/packs/heroes/respawn.d.ts +42 -0
  229. package/dist/packs/moba/index.d.ts +34 -0
  230. package/dist/packs/pack.d.ts +84 -0
  231. package/dist/packs-g5thvmGn.js +3199 -0
  232. package/dist/packs-g5thvmGn.js.map +1 -0
  233. package/dist/packs.d.ts +84 -0
  234. package/dist/paths.d.ts +51 -0
  235. package/dist/plain.d.ts +17 -0
  236. package/dist/player.d.ts +117 -0
  237. package/dist/portals.d.ts +66 -0
  238. package/dist/prefabs.d.ts +139 -0
  239. package/dist/presetBuildings.d.ts +52 -0
  240. package/dist/presetGround.d.ts +22 -0
  241. package/dist/profiles-B3NS9jwk.js +335 -0
  242. package/dist/profiles-B3NS9jwk.js.map +1 -0
  243. package/dist/races.d.ts +136 -0
  244. package/dist/randomGroups.d.ts +2 -0
  245. package/dist/registry.d.ts +464 -0
  246. package/dist/remains.d.ts +119 -0
  247. package/dist/replication.d.ts +103 -0
  248. package/dist/rng.d.ts +17 -0
  249. package/dist/rules.d.ts +395 -0
  250. package/dist/rulesCheck.d.ts +37 -0
  251. package/dist/runes.d.ts +41 -0
  252. package/dist/save.d.ts +277 -0
  253. package/dist/scenario.d.ts +56 -0
  254. package/dist/scheduler.d.ts +67 -0
  255. package/dist/score.d.ts +306 -0
  256. package/dist/sequences.d.ts +132 -0
  257. package/dist/server/doorman.d.ts +21 -0
  258. package/dist/server/gameServer.d.ts +346 -0
  259. package/dist/server/index.d.ts +24 -0
  260. package/dist/server/lobby.d.ts +1 -0
  261. package/dist/server/log.d.ts +13 -0
  262. package/dist/server/match.d.ts +24 -0
  263. package/dist/server/mode.d.ts +168 -0
  264. package/dist/server/navigation-worker.d.ts +1 -0
  265. package/dist/server/navigation.d.ts +11 -0
  266. package/dist/server/ops.d.ts +78 -0
  267. package/dist/server/packs.d.ts +15 -0
  268. package/dist/server/ratings.d.ts +62 -0
  269. package/dist/server/relay.d.ts +34 -0
  270. package/dist/server/rooms.d.ts +162 -0
  271. package/dist/server/seat.d.ts +2 -0
  272. package/dist/server/seatSettings.d.ts +15 -0
  273. package/dist/server/secret.d.ts +5 -0
  274. package/dist/server/start.d.ts +54 -0
  275. package/dist/server/websocket.d.ts +74 -0
  276. package/dist/server.js +2861 -0
  277. package/dist/server.js.map +1 -0
  278. package/dist/session/can.d.ts +20 -0
  279. package/dist/session/commandReplay.d.ts +92 -0
  280. package/dist/session/debug.d.ts +65 -0
  281. package/dist/session/delay.d.ts +15 -0
  282. package/dist/session/delta.d.ts +98 -0
  283. package/dist/session/entityState.d.ts +1 -0
  284. package/dist/session/local.d.ts +214 -0
  285. package/dist/session/memory.d.ts +27 -0
  286. package/dist/session/protocol.d.ts +1155 -0
  287. package/dist/session/remote.d.ts +530 -0
  288. package/dist/session/replay.d.ts +114 -0
  289. package/dist/session/seed.d.ts +7 -0
  290. package/dist/session/share.d.ts +78 -0
  291. package/dist/session/socket.d.ts +8 -0
  292. package/dist/session/wire.d.ts +153 -0
  293. package/dist/session/worker.d.ts +227 -0
  294. package/dist/shared.d.ts +171 -0
  295. package/dist/sides.d.ts +75 -0
  296. package/dist/sight.d.ts +27 -0
  297. package/dist/simulate-oXBiw1Ff.js +167 -0
  298. package/dist/simulate-oXBiw1Ff.js.map +1 -0
  299. package/dist/simulate-worker.d.ts +1 -0
  300. package/dist/simulate-worker.js +28 -0
  301. package/dist/simulate-worker.js.map +1 -0
  302. package/dist/simulate.d.ts +154 -0
  303. package/dist/smart.d.ts +9 -0
  304. package/dist/spatial.d.ts +62 -0
  305. package/dist/spawning.d.ts +33 -0
  306. package/dist/stances.d.ts +76 -0
  307. package/dist/start.d.ts +71 -0
  308. package/dist/stats.d.ts +122 -0
  309. package/dist/summons.d.ts +63 -0
  310. package/dist/systems/abilities.d.ts +3 -0
  311. package/dist/systems/combat.d.ts +71 -0
  312. package/dist/systems/combatTold.d.ts +14 -0
  313. package/dist/systems/construction.d.ts +34 -0
  314. package/dist/systems/economy.d.ts +21 -0
  315. package/dist/systems/fog.d.ts +19 -0
  316. package/dist/systems/life.d.ts +3 -0
  317. package/dist/systems/movement.d.ts +105 -0
  318. package/dist/systems/orders.d.ts +7 -0
  319. package/dist/systems/production.d.ts +49 -0
  320. package/dist/systems/productionQueue.d.ts +40 -0
  321. package/dist/systems/victory.d.ts +14 -0
  322. package/dist/talk.d.ts +65 -0
  323. package/dist/tech.d.ts +62 -0
  324. package/dist/techTree.d.ts +38 -0
  325. package/dist/terrain.d.ts +173 -0
  326. package/dist/terrainSave.d.ts +29 -0
  327. package/dist/testing.d.ts +58 -0
  328. package/dist/testing.js +822 -0
  329. package/dist/testing.js.map +1 -0
  330. package/dist/tiles.d.ts +34 -0
  331. package/dist/timers.d.ts +146 -0
  332. package/dist/tomes.d.ts +48 -0
  333. package/dist/trade.d.ts +28 -0
  334. package/dist/transport.d.ts +76 -0
  335. package/dist/tunables.d.ts +45 -0
  336. package/dist/upkeep.d.ts +16 -0
  337. package/dist/veterancy.d.ts +80 -0
  338. package/dist/walls.d.ts +86 -0
  339. package/dist/world.d.ts +1118 -0
  340. package/package.json +80 -5
  341. package/README.md +0 -3
@@ -0,0 +1,429 @@
1
+ import type { OrderInit } from '#engine/registry';
2
+ import type { AiArea } from './area';
3
+ import { type Vec2 } from '#engine/math';
4
+ import type { EntityState } from '#engine/session/protocol';
5
+ import { type Brain } from './brain';
6
+ import { type AiModuleDef } from './module';
7
+ import { UnitSet } from './view';
8
+ import type { TaskCommon, TaskData, TaskDef, TaskDone, TaskOrder, TaskState } from './task';
9
+ /**
10
+ * How a squad behaves around its task (`SquadsOptions`, `ai.squads.make(name, units, options)`): when it regroups,
11
+ * reinforces, retreats. Plain data, kept in a save
12
+ *
13
+ * @beta
14
+ */
15
+ export interface SquadOptions {
16
+ /**
17
+ * How far from its middle a unit may be before it counts as strayed: what a regroup brings in. Grows with the squad
18
+ * when left out (8, and three times the square root of its size above that: 12 for sixteen units)
19
+ */
20
+ spread?: number;
21
+ /** 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 */
22
+ regroupWhen?: number | false;
23
+ /** Whether it makes up what it lost since its task began from the pool (the idle fighters nothing holds): no when left out */
24
+ reinforce?: boolean;
25
+ /**
26
+ * Its odds in a fight (`Strength.odds`) under which it falls back home, away from home: 0.3. `false` fights on to the
27
+ * last (a mission's guards)
28
+ */
29
+ retreatAt?: number | false;
30
+ /** How near home it fights on whatever the odds: there is nowhere to fall back to. 20 when left out */
31
+ home?: number;
32
+ /**
33
+ * Whether the micro module (`micro()`, C2) fights for it once it is in a fight: focus fire, kiting, fleeing, siege.
34
+ * 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)
35
+ */
36
+ micro?: boolean;
37
+ }
38
+ /**
39
+ * How a brain's squads behave, where a squad says nothing for itself (`BrainDef.squads`, the seat's `AiOptions.squads`
40
+ * over it); and the tasks of the game's own (`defineTask`) a save of the brain may name
41
+ *
42
+ * @beta
43
+ */
44
+ export interface SquadsOptions extends SquadOptions {
45
+ /** Tasks of the game's own: registered with the brain, so that a squad on one is carried on after a load */
46
+ tasks?: TaskDef[];
47
+ }
48
+ /**
49
+ * A squad as the brain remembers it: plain data, kept in a save
50
+ *
51
+ * @beta
52
+ */
53
+ export interface SquadData {
54
+ /** Unique among the brain's squads */
55
+ name: string;
56
+ /** Who it belongs to: a goal's id, a rule's or a module's hold (`squad:<name>` for one of its own) */
57
+ owner: string;
58
+ /** Its units, by id, in the picture's order */
59
+ units: number[];
60
+ /** How it behaves: its own, over the brain's */
61
+ options: SquadOptions;
62
+ /** What it is doing. None for a squad told nothing yet */
63
+ task?: TaskState;
64
+ /** How many units its task began with, or was given since: what reinforcements make up */
65
+ size: number;
66
+ /** The tick it was made at */
67
+ made: number;
68
+ /** How many times it fell back from a fight it was losing */
69
+ retreats: number;
70
+ /** The last time its units or its task changed, and why, in words */
71
+ changed?: {
72
+ tick: number;
73
+ why: string;
74
+ };
75
+ /** The tick it may next call for reinforcements */
76
+ nextReinforce?: number;
77
+ }
78
+ /**
79
+ * What the squads remember between thinks, for a save
80
+ *
81
+ * @beta
82
+ */
83
+ export interface SquadsMemory {
84
+ v: 1;
85
+ squads: SquadData[];
86
+ }
87
+ /**
88
+ * 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
89
+ *
90
+ * @beta
91
+ */
92
+ export interface SquadReport {
93
+ name: string;
94
+ owner: string;
95
+ units: number[];
96
+ strength: number;
97
+ /** Its middle */
98
+ at?: [number, number];
99
+ size: number;
100
+ task?: {
101
+ kind: string;
102
+ phase: string;
103
+ since: number;
104
+ at?: [number, number];
105
+ done?: TaskDone;
106
+ };
107
+ retreats: number;
108
+ changed?: {
109
+ tick: number;
110
+ why: string;
111
+ };
112
+ }
113
+ /**
114
+ * A squad of the brain (`ai.squads.make`, `named`, `all`): a handle over its data, with the task methods. A squad's
115
+ * units are as of the think's picture: the dead and those its owner no longer holds are dropped as the squads module
116
+ * looks at it
117
+ *
118
+ * @beta
119
+ */
120
+ export declare class Squad {
121
+ /** The squads it is one of */
122
+ readonly squads: Squads;
123
+ /** What it is, as plain data: what a save keeps */
124
+ readonly data: SquadData;
125
+ constructor(
126
+ /** The squads it is one of */
127
+ squads: Squads,
128
+ /** What it is, as plain data: what a save keeps */
129
+ data: SquadData);
130
+ /** Its name: unique among the brain's squads */
131
+ get name(): string;
132
+ /** Who it belongs to: the goal, rule or module that made it */
133
+ get owner(): string;
134
+ /** What it is doing: none for a squad told nothing yet */
135
+ get current(): TaskState | undefined;
136
+ /** How its task ended: none while it goes on, or while it has none */
137
+ get done(): TaskDone | undefined;
138
+ /** Whether it has nothing to do: no task, or its task is over */
139
+ get idle(): boolean;
140
+ /** Whether it is still one of the brain's squads: not once disbanded */
141
+ get alive(): boolean;
142
+ /** How it behaves: its own options over the brain's */
143
+ get options(): SquadOptions;
144
+ /** Its units, as of the think's picture: those alive and the player's */
145
+ units(): UnitSet;
146
+ /** How many units it has */
147
+ get length(): number;
148
+ /** How strong it is together (`UnitSet.strength`) */
149
+ strength(): number;
150
+ /** Its middle: none with no unit left */
151
+ centre(): Vec2 | undefined;
152
+ /**
153
+ * How far from its middle a unit may be before it counts as strayed (`SquadOptions.spread`): grows with the squad
154
+ * when not given
155
+ */
156
+ spread(): number;
157
+ /** Adds units: what its owner may have (see `Squads.make`), taken out of any other squad */
158
+ add(units: Iterable<EntityState | number>, why?: string): this;
159
+ /** Takes units out: they go back to the pool (its owner lets go of them) */
160
+ remove(units: Iterable<EntityState | number>, why?: string): this;
161
+ /** Disbands it: its units go back to its owner (a goal's), or to the pool (a squad of its own) */
162
+ disband(why?: string): void;
163
+ /** Writes down the last change of its units or task, for the report */
164
+ changed(why: string): void;
165
+ /**
166
+ * 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).
167
+ * What it was doing is over. Its first orders go at once; the squads module watches it from then on
168
+ */
169
+ task<D extends object, M extends object>(def: TaskDef<D, M>, data: D & TaskCommon): this;
170
+ task(kind: string, data?: TaskData): this;
171
+ /** Ends its task, saying how: what a task's `think` calls once it is over */
172
+ finish(done: TaskDone): void;
173
+ /**
174
+ * Goes to fight at a place or a target (an entity, or its id): attack-moves there, fighting what it meets, regroups
175
+ * on the way, retreats on the odds. Done `cleared` once there with nothing left to fight, `lost` when the target is
176
+ * gone. `avoid: 'army'` goes round where their strength is on the way (the threat map and their army as last seen),
177
+ * 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
178
+ */
179
+ attack(target: Vec2 | EntityState | number, options?: {
180
+ avoid?: 'army' | false;
181
+ via?: Vec2;
182
+ then?: TaskOrder;
183
+ }): this;
184
+ /** Attack-moves to a place, as a group of units would on a click: the squad's attack without its regroup */
185
+ attackMove(at: Vec2, options?: {
186
+ then?: TaskOrder;
187
+ }): this;
188
+ /**
189
+ * Holds a place against what comes within `radius` of it (16 when left out): fights what comes, goes back once it is
190
+ * gone. Never over by itself: its owner says when
191
+ */
192
+ defend(at: Vec2, radius?: number): this;
193
+ /** Goes to a place (where it stands when left out) and holds it: stands, fighting only what comes within reach */
194
+ hold(at?: Vec2): this;
195
+ /** Walks to a place, fighting nothing on the way. Done `arrived` */
196
+ move(at: Vec2, options?: {
197
+ then?: TaskOrder;
198
+ }): this;
199
+ /** Goes with a unit of the player's or an ally's, fighting what comes near it. Done `lost` when it is gone */
200
+ escort(target: EntityState | number): this;
201
+ /**
202
+ * Goes for the workers at a place, round where their army is (`avoid: 'army'` unless told otherwise), the workers
203
+ * first once there. Done `cleared`
204
+ */
205
+ harass(at: Vec2, options?: {
206
+ avoid?: 'army' | false;
207
+ then?: TaskOrder;
208
+ }): this;
209
+ /** 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` */
210
+ scout(points: readonly Vec2[]): this;
211
+ /**
212
+ * Gathers at a rally point before going on (`then`): until `minForces` of it (a share, 1 when left out) is there,
213
+ * or `seconds` have gone by. Done `arrived`, and on to `then`
214
+ */
215
+ gather(at: Vec2, options?: {
216
+ minForces?: number;
217
+ seconds?: number;
218
+ then?: TaskOrder;
219
+ }): this;
220
+ /** Falls back to a place (home when left out), fighting nothing on the way. Done `retreated` */
221
+ retreat(to?: Vec2, why?: string): this;
222
+ /**
223
+ * Walks a round of places, one after the other and back to the first, fighting what it meets on the way (an
224
+ * attack-move to each): a mission's guards on the road, a watch round the walls. Never over by itself: its owner
225
+ * says when
226
+ */
227
+ patrol(points: readonly Vec2[]): this;
228
+ /** Takes a camp of creeps: fights there until the camp is cleared. Done `cleared` */
229
+ creep(camp: Vec2): this;
230
+ /**
231
+ * Carried by transports to a place it cannot walk to, let out on the land nearest it (the `drop` task): done
232
+ * `landed`, then what `then` says (an attack where it landed)
233
+ */
234
+ drop(at: Vec2, transports: readonly number[], options?: {
235
+ then?: TaskOrder;
236
+ }): this;
237
+ /** Sends its units an order (`move`, `hold`, the game's), all or some of them: counted as the task's last */
238
+ order(order: OrderInit, units?: readonly number[], queue?: boolean): void;
239
+ /**
240
+ * Puts its units, all or some, in a stance, where the game has stances (`withStances`): those not in it already. A
241
+ * squad that holds is defensive, one sent to fight aggressive
242
+ */
243
+ setStance(id: string, units?: readonly number[]): void;
244
+ /**
245
+ * Sends its units to take a capture point of the game's (`withCapture`), by its id: they fight their way in and
246
+ * stand in it until it is theirs (`captured`), or it is gone (`lost`)
247
+ */
248
+ capture(id: string): this;
249
+ /** Sends its units, all or some, to fight at a place, or a target there: an attack-move, or an attack */
250
+ fight(at: Vec2, units?: readonly number[], target?: number, queue?: boolean): void;
251
+ /**
252
+ * 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
253
+ * goal before the `squads()` module ran) is no one to order
254
+ */
255
+ private living;
256
+ /** Its units that stand with nothing to do: what lost its order, or never had one */
257
+ idleUnits(): EntityState[];
258
+ /** 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 */
259
+ mayResend(): boolean;
260
+ private sent;
261
+ }
262
+ /**
263
+ * Some squads together (`ai.squads.all()`, `idle()`): read as a list, told as one (`ai.squads.all().defend(home)`:
264
+ * each squad is given the task)
265
+ *
266
+ * @beta
267
+ */
268
+ export declare class SquadGroup implements Iterable<Squad> {
269
+ /** The brain they are of */
270
+ readonly ai: Brain;
271
+ /** The squads */
272
+ readonly squads: readonly Squad[];
273
+ constructor(
274
+ /** The brain they are of */
275
+ ai: Brain,
276
+ /** The squads */
277
+ squads: readonly Squad[]);
278
+ [Symbol.iterator](): Iterator<Squad>;
279
+ /** How many squads */
280
+ get length(): number;
281
+ /** Their units together, as a set */
282
+ units(): UnitSet;
283
+ /** How strong they are together */
284
+ strength(): number;
285
+ /** Each given the same task */
286
+ task<D extends object, M extends object>(def: TaskDef<D, M>, data: D & TaskCommon): this;
287
+ task(kind: string, data?: TaskData): this;
288
+ attack(target: Vec2 | EntityState | number, options?: {
289
+ avoid?: 'army' | false;
290
+ then?: TaskOrder;
291
+ }): this;
292
+ defend(at: Vec2 | undefined, radius?: number): this;
293
+ hold(at?: Vec2): this;
294
+ move(at: Vec2): this;
295
+ retreat(to?: Vec2): this;
296
+ /** Each disbanded */
297
+ disband(why?: string): void;
298
+ }
299
+ /**
300
+ * A brain's squads (`ai.squads`): made by its goals, rules and modules, watched by the `squads()` module each think
301
+ * (`think`): the dead dropped, what the owner let go of let go of, each task looked at, regroups, retreats and
302
+ * reinforcements seen to. Kept in the brain's memory (`BrainMemory.squads`)
303
+ *
304
+ * @beta
305
+ */
306
+ export declare class Squads implements AiArea {
307
+ /** The brain they are the squads of */
308
+ readonly ai: Brain;
309
+ /** Its id among the brain's areas: what its memory and its report are kept under */
310
+ readonly id = "squads";
311
+ /** What the log says where a save's memory of it is of a shape it does not read */
312
+ readonly afresh = "the save remembers the computer player\u2019s squads in a shape this brain does not read: they are let go of";
313
+ private list;
314
+ private readonly tasks;
315
+ private thoughtAt;
316
+ /** How a squad behaves where it says nothing and the brain's settings say nothing either: the `squads()` module's */
317
+ private moduleOptions;
318
+ constructor(
319
+ /** The brain they are the squads of */
320
+ ai: Brain,
321
+ /** The tasks of the game's own its squads may be on (`AiSettings.squads.tasks`) */
322
+ tasks?: readonly TaskDef[]);
323
+ /** Puts the `squads()` module's options under the brain's settings */
324
+ configure(options: SquadOptions): void;
325
+ /** How a squad behaves where it says nothing: the module's options, the brain's settings over them (`ai.settings.squads`) */
326
+ get defaults(): SquadOptions;
327
+ /** 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` */
328
+ define(def: TaskDef): void;
329
+ /** A kind of task by its id: the kit's, or one registered */
330
+ taskDef(id: string): TaskDef | undefined;
331
+ /**
332
+ * Makes a squad of units under a name (one of that name already is disbanded first), with how it behaves where it
333
+ * is not the brain's way. Whose it is (`owner`): what `options.owner` names (a goal makes its own with
334
+ * `claimed.squad`), else its own (`squad:<name>`). A goal's squad is made of what the goal holds, and what
335
+ * nothing holds is given to it; a squad of a rule or a module takes its units from whatever holds them (the goal
336
+ * told: `stop('told')`) and holds them until it is disbanded. A unit in another squad leaves it
337
+ */
338
+ make(name: string, units: Iterable<EntityState | number>, options?: SquadOptions & {
339
+ owner?: string;
340
+ }): Squad;
341
+ /**
342
+ * 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
343
+ * or a module's), out of any other squad. Those put in, by id
344
+ */
345
+ enlist(squad: Squad, wanted: number[]): number[];
346
+ /** A squad by name: none for one there is not */
347
+ named(name: string): Squad | undefined;
348
+ /** Every squad, as made */
349
+ all(): SquadGroup;
350
+ /** The squads with nothing to do: told nothing, or their task over */
351
+ idle(): SquadGroup;
352
+ /** The squads a goal, rule or module owns */
353
+ of(owner: string): SquadGroup;
354
+ /** The squad a unit is in, by the unit or its id: none for a unit in none */
355
+ squadOf(unit: EntityState | number): Squad | undefined;
356
+ /** The player's units nothing holds (`ai.goals.pool`, buildings left out): what a squad is made of, or reinforced from */
357
+ pool(): UnitSet;
358
+ /** Disbands a squad: a squad that held its units itself lets them go back to the pool */
359
+ disband(squad: Squad, why?: string, letGo?: boolean): void;
360
+ /**
361
+ * 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
362
+ * reinforcements make up to from then on (`SquadData.size`), but for a task it goes on to by itself (`going on`: a
363
+ * task's `then`, a fall back on the odds), which keeps what the task before was given. The task it is on given
364
+ * again changes nothing, its `size` kept: what it lost since is what reinforcements make up
365
+ */
366
+ give(squad: Squad, kind: string | TaskDef, data: TaskData, goingOn?: boolean): void;
367
+ /**
368
+ * Looks at every squad, once a think: its units (the dead, and what its owner let go of, dropped; a squad of a goal
369
+ * that stopped disbanded), then its task (retreat on the odds, the task's own look, regroup, reinforcements). What the
370
+ * `squads()` module runs; a module may call it sooner
371
+ */
372
+ think(): void;
373
+ /** The squads still to be looked at this think, where a pass stopped for the tick's budget, and the next of them */
374
+ private advancing;
375
+ private cursor;
376
+ /** 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 */
377
+ private prune;
378
+ /** One squad's think: retreat on the odds, the task's own look, then on to the next task, regroup, reinforcements */
379
+ private advance;
380
+ /**
381
+ * Whether a squad in a fight away from home is losing it (its odds under `retreatAt`), and so falls back: its task
382
+ * becomes `retreat`, home, and it is said why
383
+ */
384
+ private losing;
385
+ /**
386
+ * Regroups a squad that is strung out on its way: too many of its units (`regroupWhen`) further than `spread` from its
387
+ * middle, and no fight near. It gathers on its middle and goes on once together, or once it has waited long enough
388
+ */
389
+ private regroup;
390
+ /**
391
+ * Makes up what a squad lost since its task began from the pool: the idle fighters nothing holds, the nearest
392
+ * first, given to its owner and sent to join it. Never a hero: one crossing the map alone to a fight dies on the
393
+ * way, and heroes are sent with a squad, not after it. Not while it falls back, nor more often than every few seconds
394
+ */
395
+ private reinforce;
396
+ /** The place a squad's task is about: none for a task about no place */
397
+ whereOf(squad: Squad): Vec2 | undefined;
398
+ /**
399
+ * The way to a place round where the enemy is strong (`avoid: 'army'`): the waypoint to go by, where the straight way
400
+ * crosses their strength (the threat map, with what is remembered of their towers, and their army as last seen) and a
401
+ * way round is less hot, tried on either side and then further out, twice at most. A heuristic, not a safe route:
402
+ * none where the straight way is cool enough, or where there is no way round (`note` says so)
403
+ */
404
+ route(from: Vec2, to: Vec2, squad: Squad): {
405
+ waypoints: Vec2[];
406
+ note?: string;
407
+ };
408
+ /** Every squad as the report shows it */
409
+ report(): SquadReport[];
410
+ /** What the squads are, for a save: copies */
411
+ /** Whether it has anything to remember now: one that does not is left out of a save */
412
+ remembers(): boolean;
413
+ save(): SquadsMemory;
414
+ /** Takes back what `save` gave: whether it was read. A squad on a task the brain does not know is kept, and does nothing */
415
+ restore(memory: unknown): boolean;
416
+ }
417
+ /**
418
+ * The squads module: looks at every squad of the brain each think (`ai.squads.think`), after the goals, the rules and
419
+ * the words that make them: their units, their tasks, regroups, retreats, reinforcements. With how they behave where the
420
+ * brain's definition and the seat's options say nothing
421
+ *
422
+ * @beta
423
+ */
424
+ export declare const squads: (options?: SquadsOptions) => AiModuleDef;
425
+ declare module './area' {
426
+ interface AreaMemories {
427
+ squads?: SquadsMemory;
428
+ }
429
+ }
@@ -0,0 +1,167 @@
1
+ import { type Stats, type UnitTypeDef } from '#engine/defs';
2
+ import type { Registry } from '#engine/registry';
3
+ import type { EntityState } from '#engine/session/protocol';
4
+ import type { AiView, UnitSet } from './view';
5
+ /**
6
+ * A force to weigh: a set of entities as the view gives them (`view.enemies.fighters()`), a plain array of them, or
7
+ * types with counts (`{ footman: 6, gryphon: 2 }`), as the knowledge keeps an army it saw (`ArmySighting.types`,
8
+ * `TypeSeen`): those are taken at full health with the stats their type starts with
9
+ *
10
+ * @beta
11
+ */
12
+ export type Force = UnitSet | readonly EntityState[] | Readonly<Record<string, number>>;
13
+ /**
14
+ * What a strength formula is given of one unit or type: its definition, its stats as they stand (the type's, with what
15
+ * the snapshot shows of a seen unit's own: upgrades, items, levels, buffs), the entity where there is one (its health,
16
+ * its level) and the view, for the roles and the registry
17
+ *
18
+ * @beta
19
+ */
20
+ export interface StrengthInput {
21
+ /** The unit type */
22
+ def: UnitTypeDef;
23
+ /** The stats as they stand: the type's, with a seen unit's own over them */
24
+ stats: Readonly<Stats>;
25
+ /** The unit, where one is weighed; none for a type */
26
+ entity?: EntityState;
27
+ /** 0..1: the health it has left, as a part of its most; 1 for a type */
28
+ health: number;
29
+ /** The picture it is weighed in: for the roles (`view.roles`) and the definitions (`view.registry`) */
30
+ view: AiView;
31
+ }
32
+ /**
33
+ * How strong a unit or a type is, as a number that adds up over a group: the kit's formula (`defaultStrength`), or a
34
+ * game's own in its place (`AiOptions.strength`, `BrainDef.strength`). Given the unit's definition and stats as they
35
+ * stand, the entity where there is one, and the health it has left as a part of its most. Must give a finite number,
36
+ * 0 for what does not fight
37
+ *
38
+ * @beta
39
+ */
40
+ export type StrengthFormula = (input: StrengthInput) => number;
41
+ /**
42
+ * What one side of a matchup is worth against the other, with how (`Strength.matchup`): the strength of each of its
43
+ * units against the opponent, summed
44
+ *
45
+ * @beta
46
+ */
47
+ export interface Matchup {
48
+ /** The side's strength against the opponent: 0 where none of it can hit any of them */
49
+ strength: number;
50
+ /** The side's strength on its own, against no one in particular */
51
+ plain: number;
52
+ /** How many fought: units with health left and an attack */
53
+ count: number;
54
+ }
55
+ /**
56
+ * How well a type answers a force (`Strength.counterFor`): its strength against them over its plain strength. 1 is as
57
+ * good as it is against anyone, 0 is useless (it cannot hit them), above 1 it is the answer
58
+ *
59
+ * @beta
60
+ */
61
+ export interface Counter {
62
+ /** The type ranked */
63
+ def: UnitTypeDef;
64
+ /** Its strength against the force over its plain strength */
65
+ score: number;
66
+ }
67
+ /**
68
+ * What a game declares a type good against (`UnitTypeDef.ai.counters`): a tag (`'air'`), a role (`'siege'`) or a type
69
+ * id, as a word, or with how much it counts (`weight`, 0.5 when left out: a unit whose whole opponent it counters is
70
+ * worth half again)
71
+ *
72
+ * @beta
73
+ */
74
+ export type CounterHint = string | {
75
+ target: string;
76
+ weight?: number;
77
+ };
78
+ /**
79
+ * The kit's formula for how strong a unit is, under a square root so that it adds up over a group (Lanchester):
80
+ *
81
+ * `sqrt(toughness × offence) × hero`, where
82
+ *
83
+ * - `toughness` is the health it has left, more by its armour and magic resist (the middle of the two, since no
84
+ * opponent is in question: 100 of armour doubles it, as the engine's `mitigation` halves what arrives),
85
+ * - `offence` is its damage a second (`attackDamage × attackSpeed`), up to a quarter more for reach (at 10 of range)
86
+ * and a tenth for speed (at 8),
87
+ * - `hero` is 1 for a unit, and `1.1 + 0.1 × (level − 1)` for a hero: its spells, and more as they level.
88
+ *
89
+ * 0 for what has no attack: a building that does not shoot, a worker with no weapon. A declared strength
90
+ * (`UnitTypeDef.ai.strength`) is taken in its place by `Strength`, before this is asked
91
+ *
92
+ * @beta
93
+ */
94
+ export declare const defaultStrength: StrengthFormula;
95
+ /**
96
+ * How strong things are, to a brain (`AiView.strength`, `Brain.strength`): one unit or type (`of`), a group (`sum`,
97
+ * what `UnitSet.strength()` asks), one force against another (`matchup`, `odds`), and what to train against what was
98
+ * seen (`counterFor`). The formula is the kit's (`defaultStrength`) unless the brain was given one
99
+ * (`AiOptions.strength`, `BrainDef.strength`); a type's declared strength (`UnitTypeDef.ai.strength`) goes before
100
+ * either. What a type's numbers come to is worked out once and kept across thinks; a seen unit's own stats
101
+ * (`EntityState.stats`: its upgrades, items, levels, buffs) are read each time
102
+ *
103
+ * @beta
104
+ */
105
+ export declare class Strength {
106
+ /** The game's definitions */
107
+ readonly registry: Registry;
108
+ /** The formula a unit's strength comes from: the kit's unless the brain was given one */
109
+ readonly formula: StrengthFormula;
110
+ private readonly profiles;
111
+ private readonly plainByType;
112
+ constructor(
113
+ /** The game's definitions */
114
+ registry: Registry,
115
+ /** The formula a unit's strength comes from: the kit's unless the brain was given one */
116
+ formula?: StrengthFormula);
117
+ /**
118
+ * 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
119
+ * health with the stats it starts with. 0 for what does not fight. A finite number always
120
+ */
121
+ of(what: EntityState | UnitTypeDef | string): number;
122
+ /** A type at full health: worked out once */
123
+ private ofType;
124
+ /** The formula asked, the declared strength first; whatever comes back made finite */
125
+ private evaluate;
126
+ /** The stats of a seen unit as they stand: its type's, with its own over them (`EntityState.stats`: upgrades, items, levels, buffs) */
127
+ statsOf(entity: EntityState, def?: UnitTypeDef): Readonly<Stats>;
128
+ /** How strong a group is: the strength of each, summed */
129
+ sum(force: Force): number;
130
+ /**
131
+ * One force against another: the strength of each of `a`'s units against `b` (what it cannot hit counts for nothing
132
+ * of its damage; its damage meets their armour, theirs meets its; what it is declared to counter weighs it up),
133
+ * summed. `matchup(a, b).strength / matchup(b, a).strength` is how `a` compares; `odds` turns it into a chance
134
+ */
135
+ matchup(a: Force, b: Force): Matchup;
136
+ /**
137
+ * The chance that `a` beats `b` in a fight to the end, 0..1: `A² / (A² + B²)` of the two matchups (Lanchester's
138
+ * square law: numbers count twice, since each unit both deals and takes). 0.5 for a mirror, and when neither can hit
139
+ * the other. **An estimate**: it reads stats, layers, armour and declared counters, and knows nothing of spells,
140
+ * terrain, focus fire, who shoots first or who runs; the plan's E3 checks it against fights played out, and a game
141
+ * that knows better gives its own formula (`AiOptions.strength`)
142
+ */
143
+ odds(a: Force, b: Force): number;
144
+ /**
145
+ * What answers a force best among some types: each with its strength against them over its plain strength (1 is as
146
+ * good as against anyone, 0 cannot hit them, above 1 is the answer), the best first, equals in the order given.
147
+ * Against nothing, every type scores 1
148
+ */
149
+ counterFor(enemies: Force, candidates: readonly (UnitTypeDef | string)[]): Counter[];
150
+ /** What a game declares a type good against, as `{ target, weight }` each */
151
+ countersOf(type: UnitTypeDef | string): readonly {
152
+ target: string;
153
+ weight: number;
154
+ }[];
155
+ /**
156
+ * A profile's strength against a force over its plain strength: what its damage comes to against them (what it can
157
+ * hit, through their armour) and what theirs comes to against it (through its armour), each as a part of the
158
+ * plain, under the same square root, times what it is declared to counter. 1 against nothing
159
+ */
160
+ private edge;
161
+ /** Whether a declared counter's word is one of a profile's: its type, a role or a tag of it */
162
+ private matches;
163
+ /** What a type comes to for a matchup, kept */
164
+ private profile;
165
+ /** A force as groups: a profile and how many, those with health left and an attack. Units with stats of their own stand apart */
166
+ private groups;
167
+ }