@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 @@
1
+ {"version":3,"file":"missionRules-C-bGxm0Q.js","names":[],"sources":["../src/mapObjectives.ts","../src/missionRules.ts"],"sourcesContent":["import type { PlayerId } from './entity'\nimport { defineHook } from './hooks'\nimport type { GameMap } from './map'\nimport type { MapProblem } from './mapFields'\nimport type { Message } from './messages'\nimport type { ObjectiveDef, ObjectiveState } from './objectives'\nimport type { GamePack } from './packs/pack'\nimport type { World } from './world'\n\n/*\n * Objectives as data on the map (campaign plan EQ3): a list kept in the map's data (`GameMap.data.objectives`), which\n * the editor's Objectives panel writes, and which the map objectives pack reads (`mapObjectives`): those given at the\n * start are each player's as the world is made from the map, the rest are given by the rules by id\n * (`giveMapObjective`). What becomes of them, done or failed, is the rules' as for any objective (`world.objectives`)\n */\n\n/**\n * The map objectives pack's id\n *\n * @beta\n */\nexport const MAP_OBJECTIVES = 'core.mapObjectives'\n\n/**\n * The key of the map's data its objectives are kept under (`GameMap.data.objectives`)\n *\n * @beta\n */\nexport const MAP_OBJECTIVES_KEY = 'objectives'\n\n/**\n * An objective a map gives, as it keeps it: an objective (`ObjectiveDef`: its id, its words, whether the mission needs\n * it, more about it) and when it is given\n *\n * @beta\n */\nexport interface MapObjective extends ObjectiveDef {\n\t/**\n\t * When it is given: as the game starts (`start`), to every player a person plays (`mapObjectivePlayers`), or when\n\t * the rules say (`rule`: `giveMapObjective(world, id)`). Anything but `rule` is the start\n\t */\n\tat: 'start' | 'rule'\n}\n\n/** The words of an objective as a file may hold them: a key, or a key with params */\nconst isWords = (text: unknown): boolean =>\n\ttypeof text === 'string'\n\t\t? text.trim() !== ''\n\t\t: typeof text === 'object' && text !== null && typeof (text as Message).key === 'string' && (text as Message).key !== ''\n\n/**\n * The objectives a map gives (`GameMap.data.objectives`), in the order it gives them: none for a map with none. What is\n * kept there and is no objective (no id, no words) is left out, so that a file changed by hand breaks no rule that reads\n * it; the map's checks say so (`mapObjectives`)\n *\n * @beta\n */\nexport function mapObjectivesOf(map: { readonly data: Readonly<Record<string, unknown>> }): MapObjective[] {\n\tconst kept = map.data[MAP_OBJECTIVES_KEY]\n\tif (!Array.isArray(kept)) return []\n\treturn kept\n\t\t.filter(\n\t\t\t(each): each is MapObjective => typeof each === 'object' && each !== null && typeof each.id === 'string' && each.id !== '' && isWords(each.text)\n\t\t)\n\t\t.map((each) => ({\n\t\t\tid: each.id,\n\t\t\ttext: each.text,\n\t\t\t...(each.detail !== undefined && isWords(each.detail) && { detail: each.detail }),\n\t\t\t...(each.required !== undefined && { required: each.required !== false }),\n\t\t\tat: each.at === 'rule' ? 'rule' : 'start'\n\t\t}))\n}\n\n/**\n * Who is given a map's objective when the rules do not say (`giveMapObjective`): the map's players a person plays, not\n * those it says the computer plays or nobody does (`MapPlayer.controller`), in the order of their ids\n *\n * @beta\n */\nexport function mapObjectivePlayers(world: World): PlayerId[] {\n\treturn [...world.players.values()]\n\t\t.filter((player) => !player.neutral && !player.creeps)\n\t\t.filter((player) => {\n\t\t\tconst controller = world.map.player(player.id)?.controller\n\t\t\treturn controller !== 'computer' && controller !== 'nobody'\n\t\t})\n\t\t.map((player) => player.id)\n\t\t.sort((a, b) => a - b)\n}\n\n/**\n * Gives players an objective of the map's, by its id (`MapObjective`): those given by a rule (`at: 'rule'`), when the\n * rules say. To every player a person plays when `players` is left out (`mapObjectivePlayers`); a player who has it\n * already keeps theirs. Its words' params and its progress go with it, as `world.objectives.add`. Throws for an id the\n * map does not have: an id in the code that is not on the map is a mistake\n *\n * @beta\n */\nexport function giveMapObjective(\n\tworld: World,\n\tid: string,\n\toptions: { players?: readonly PlayerId[]; params?: Message['params']; progress?: { value: number; max: number } } = {}\n): ObjectiveState[] {\n\tconst def = mapObjectivesOf(world.map).find((objective) => objective.id === id)\n\tif (!def) throw new Error(`The map${world.map.name ? ` \"${world.map.name}\"` : ''} has no objective \"${id}\"`)\n\tconst { at: _at, ...objective } = def\n\tconst given: ObjectiveState[] = []\n\tfor (const player of options.players ?? mapObjectivePlayers(world)) {\n\t\tif (world.objectives.has(player, id)) continue\n\t\tgiven.push(world.objectives.add(player, objective, { params: options.params, progress: options.progress }))\n\t}\n\treturn given\n}\n\n/**\n * What is wrong with a map's objectives (`GameMap.data.objectives`): one with no id or with another's, one with no\n * words, a list that is not one. Each a click away in the Objectives panel\n *\n * @beta\n */\nexport function checkMapObjectives(map: GameMap): MapProblem[] {\n\tconst kept = map.data[MAP_OBJECTIVES_KEY]\n\tif (kept === undefined) return []\n\tif (!Array.isArray(kept)) return [{ message: 'The map’s objectives are not a list', error: true, rule: 'objectives' }]\n\tconst problems: MapProblem[] = []\n\tconst seen = new Set<string>()\n\tkept.forEach((each: Partial<MapObjective> | null, index) => {\n\t\tconst id = typeof each?.id === 'string' ? each.id : ''\n\t\tconst reveal = { panel: 'objectives', entry: id || String(index) }\n\t\tif (!id) problems.push({ message: `Objective ${index + 1} has no id`, error: true, rule: 'objective-id', reveal })\n\t\telse if (seen.has(id)) problems.push({ message: `Two objectives have the id \"${id}\"`, error: true, rule: 'objective-id', reveal })\n\t\tseen.add(id)\n\t\tif (!isWords(each?.text))\n\t\t\tproblems.push({ message: `The objective \"${id || index + 1}\" has no words`, error: true, rule: 'objective-text', reveal })\n\t})\n\treturn problems\n}\n\n/**\n * Objectives as data on the map (campaign plan EQ3): a map's objectives (`MapObjective`, kept in `GameMap.data.objectives`,\n * written by the editor's Objectives panel) given at the start to every player a person plays, as the world is made\n * from the map; those given by a rule wait for the rules (`giveMapObjective(world, id)`). Done and failed as any\n * objective is (`world.objectives.complete`, `fail`); a game that is won by them has `objectiveVictory` as its\n * `victory`. The map's checks say what is wrong with them (`checkMapObjectives`)\n *\n * @beta\n */\nexport function mapObjectives(): GamePack {\n\tconst atStart = defineHook({\n\t\thook: 'mapStart',\n\t\tid: MAP_OBJECTIVES,\n\t\trun(world) {\n\t\t\tfor (const objective of mapObjectivesOf(world.map)) if (objective.at === 'start') giveMapObjective(world, objective.id)\n\t\t}\n\t})\n\treturn { id: MAP_OBJECTIVES, hooks: [atStart], check: (map) => checkMapObjectives(map) }\n}\n","import type { AiConditionData } from './ai/rules'\nimport { playCinematic } from './cinematics'\nimport { defineComponent } from './components'\nimport type { PlayerId } from './entity'\nimport { gameOver } from './engineEvents'\nimport { defineEvent } from './events'\nimport type { GameMap } from './map'\nimport type { MapProblem } from './mapFields'\nimport { giveMapObjective, mapObjectivePlayers, mapObjectivesOf } from './mapObjectives'\nimport type { Vec2 } from './math'\nimport type { MessageRef } from './messages'\nimport type { GamePack } from './packs/pack'\nimport type { Registry, System } from './registry'\nimport { defeat } from './systems/victory'\nimport { defineTimer } from './timers'\nimport type { PlayerRelation, World } from './world'\n\n/*\n * Mission rules as data (campaign plan MS1): what a mission scripts without code, kept on the map (`GameMap.data.rules`),\n * written in the editor's Rules panel, and run by the mission rules pack (`missionRules` of `@v12-engine/engine/ai`, where the\n * computer players' kit it asks the conditions of lives: `ai/missionRules.ts`). A rule is `when` a\n * condition of the computer players' language (`AiConditionData`, `docs/ai.md`: the hero nears the camp, a region has\n * units in it, an objective is done, a word was told, so many seconds went by) and `do` a list of actions from a closed\n * set: give, complete or fail an objective of the map's, say a line, play a cinematic, spawn a prefab, tell a computer\n * player a word, set what two players are to each other, start a timer, win, lose. No variables and no code by name:\n * what needs code is a pack of the game's, which the rules reach through the words they are told (`tellRules`) and\n * the event each firing is (`ruleFired`).\n *\n * The conditions are asked of a watcher: a brain with no modules of its own, seated at the player the rule is `as`\n * (the first person playing when it says none), which sees the whole map (an observer's session) and reads it as a\n * computer player does (`Brain.view`, `knowledge`), once a second. So `{ units: { of: 'enemy' } }` means that\n * player's enemies, and every form of the table in `docs/ai.md` works as it does for a brain. A rule fires as its\n * condition turns true, once (`once`) or each time, or again every so many seconds while it holds (`every`), as a\n * brain's rules do. What the rules remember (whether each held, when and how often it fired, the words told and not yet\n * heard, the timers started) is in the world's state, and the watchers' memory in the system's: a save mid-mission has\n * it all, and a game loaded from one goes on where it was\n */\n\n/**\n * The mission rules pack's id\n *\n * @beta\n */\nexport const MISSION_RULES = 'core.missionRules'\n\n/**\n * The key of the map's data its rules are kept under (`GameMap.data.rules`)\n *\n * @beta\n */\nexport const MAP_RULES_KEY = 'rules'\n\n/**\n * What a mission rule does, as plain data: one of a closed set of actions. Each takes who it is for (`to`) where that\n * matters: every player a person plays when left out (`mapObjectivePlayers`), as the map's objectives are given\n *\n * @beta\n */\nexport type MissionActionData =\n\t/** An objective of the map's (`MapObjective`), by id: given (`give`, the default), done or failed (with why) */\n\t| { objective: { id: string; do?: 'give' | 'complete' | 'fail'; to?: PlayerId[]; reason?: MessageRef } }\n\t/** A line said (`world.dialog.say`): who speaks (a speaker of the view's), what (a message key, or the words), for how long */\n\t| { say: { speaker: string; text: MessageRef; seconds?: number; to?: PlayerId[] } }\n\t/** A cinematic of the view's played (`playCinematic`), to everyone when `to` is left out */\n\t| { cinematic: { id: string; to?: PlayerId[]; hold?: boolean; skippable?: boolean } }\n\t/**\n\t * A prefab of the game's spawned (`world.spawnPrefab`) at a place: a point or a region of the map by name, a named\n\t * thing of the map, or a point; for a player, or neutral\n\t */\n\t| { spawn: { prefab: string; at: string | Vec2; owner?: PlayerId; facing?: number } }\n\t/** A word told to a computer player (`world.computers.tell`), with what goes with it */\n\t| { tell: { computer: PlayerId; word: string; data?: unknown } }\n\t/** What two players are to each other from now on (`world.sides.setRelation`) */\n\t| { relation: { a: PlayerId; b: PlayerId; how: PlayerRelation } }\n\t/**\n\t * A timer started: so many seconds on, the rules are told its id as a word (a rule `when: { told: id }` fires), and\n\t * with `label` it counts down on the players' screens meanwhile (`world.timers.show`). Started again, it starts over\n\t */\n\t| { timer: { id: string; seconds: number; label?: MessageRef; to?: PlayerId[] } }\n\t/** The game is won by the players' team */\n\t| { win: true | { to?: PlayerId[] } }\n\t/** The players are out of the game (`defeat`) */\n\t| { lose: true | { to?: PlayerId[] } }\n\n/**\n * A rule of a mission, as the map keeps it and the mission rules pack runs it: `when` a condition of the computer\n * players' language holds, `do` its actions. Fires as the condition turns true; `once` the first time only, ever; with\n * `every`, again while it holds, at most so often. Asked `as` a player: whose the units of `of: 'mine'` are, whose\n * objectives `{ objective }` reads; the first player a person plays when left out\n *\n * @beta\n */\nexport interface MissionRule {\n\t/** What the log, the checks and the editor know it by; no two the same */\n\tid: string\n\t/** When it fires: plain data (`docs/ai.md`, \"Conditions\") */\n\twhen: AiConditionData\n\t/** What it does, in order */\n\tdo: MissionActionData[]\n\t/** The first time only, ever */\n\tonce?: boolean\n\t/** Seconds: fired again while its condition holds, at most so often */\n\tevery?: number\n\t/** The player the condition is asked for */\n\tas?: PlayerId\n}\n\n/** What the rules remember of one rule, in the world's state */\ninterface RuleMemory {\n\t/** Whether its condition held at the last check: a rule fires as it turns true */\n\twas?: boolean\n\t/** The tick it last fired at */\n\tfired?: number\n\t/** How many times it fired */\n\tcount: number\n}\n\n/** A word the rules were told and have not heard yet */\ninterface ToldWord {\n\tword: string\n\tdata?: unknown\n\ttick: number\n}\n\n/** What the rules keep in the world: plain data, into a save */\ninterface RulesState {\n\trules: Record<string, RuleMemory>\n\ttold: ToldWord[]\n\t/** The timers the rules started and have not heard yet, by their id in the rules, as the world numbers them */\n\ttimers: Record<string, number>\n}\n\n/**\n * What the mission rules remember: in the world's state, so that a save has it\n *\n * @internal\n */\nexport const missionRulesState = defineComponent<RulesState>('core.missionRules', { default: () => ({ rules: {}, told: [], timers: {} }) })\n\n/**\n * A mission rule fired: its id. For a pack of the game's that does what the rules cannot\n *\n * @beta\n */\nexport const ruleFired = defineEvent<{ rule: string }>('core.ruleFired')\n\n/**\n * What a mission rule is now, for the report and the tests: whether its condition held at the last check, how often it\n * fired and when it last did\n *\n * @beta\n */\nexport interface MissionRuleState {\n\tholds: boolean\n\tcount: number\n\tfired?: number\n}\n\nconst ACTIONS = ['objective', 'say', 'cinematic', 'spawn', 'tell', 'relation', 'timer', 'win', 'lose'] as const\n\n/** The form of an action, by its one key: none for data that is no action */\nconst actionKind = (action: unknown): (typeof ACTIONS)[number] | undefined => {\n\tif (typeof action !== 'object' || action === null) return undefined\n\tconst keys = Object.keys(action)\n\treturn keys.length === 1 && (ACTIONS as readonly string[]).includes(keys[0]) ? (keys[0] as (typeof ACTIONS)[number]) : undefined\n}\n\n/** Whether data is a rule's condition: an object of one form */\nconst isCondition = (when: unknown): when is AiConditionData => typeof when === 'object' && when !== null && Object.keys(when).length > 0\n\n/**\n * The rules a map keeps (`GameMap.data.rules`), in their order: none for a map with none. What is kept there and is no\n * rule (no id, no condition) is left out, so that a file changed by hand breaks no game that reads it; the map's checks\n * say so (`checkMissionRules`). Actions that are of no form the pack knows are left out of a rule the same way\n *\n * @beta\n */\nexport function missionRulesOf(map: { readonly data: Readonly<Record<string, unknown>> }): MissionRule[] {\n\tconst kept = map.data[MAP_RULES_KEY]\n\tif (!Array.isArray(kept)) return []\n\treturn kept\n\t\t.filter(\n\t\t\t(each): each is MissionRule =>\n\t\t\t\ttypeof each === 'object' && each !== null && typeof each.id === 'string' && each.id !== '' && isCondition(each.when)\n\t\t)\n\t\t.map((each) => ({\n\t\t\tid: each.id,\n\t\t\twhen: each.when,\n\t\t\tdo: Array.isArray(each.do) ? each.do.filter((action) => actionKind(action) !== undefined) : [],\n\t\t\t...(each.once !== undefined && { once: each.once === true }),\n\t\t\t...(typeof each.every === 'number' && each.every > 0 && { every: each.every }),\n\t\t\t...(typeof each.as === 'number' && { as: each.as })\n\t\t}))\n}\n\n/**\n * Tells the mission rules a word, as the game's code does for what the rules cannot know on their own (the boss fell,\n * the player chose): a rule `when: { told: word }` fires at the next check, and the word is heard no more after it.\n * What a rule's timer does as it goes off\n *\n * @beta\n */\nexport function tellRules(world: World, word: string, data?: unknown): void {\n\tworld.state(missionRulesState).told.push({ word, ...(data !== undefined && { data }), tick: world.tick })\n}\n\n/**\n * What a mission rule is now (`MissionRuleState`): none for a rule the world has not, or has not checked yet\n *\n * @beta\n */\nexport function missionRuleState(world: World, id: string): MissionRuleState | undefined {\n\tif (!world.states.has(missionRulesState)) return undefined\n\tconst kept = world.state(missionRulesState).rules[id]\n\treturn kept && { holds: !!kept.was, count: kept.count, ...(kept.fired !== undefined && { fired: kept.fired }) }\n}\n\n/** The names of the regions a condition asks about, wherever it is in it */\nfunction regionsNamed(when: unknown, out: string[] = []): string[] {\n\tif (typeof when !== 'object' || when === null) return out\n\tconst condition = when as Record<string, unknown>\n\tif ('region' in condition && typeof (condition.region as { name?: unknown })?.name === 'string')\n\t\tout.push((condition.region as { name: string }).name)\n\tfor (const key of ['all', 'any'] as const)\n\t\tif (Array.isArray(condition[key])) for (const each of condition[key] as unknown[]) regionsNamed(each, out)\n\tif ('not' in condition) regionsNamed(condition.not, out)\n\treturn out\n}\n\n/**\n * What is wrong with a map's rules (`GameMap.data.rules`): one with no id or with another's, one with no condition, an\n * action of no form the pack knows, a condition or an action naming what the map or the game has not (a region, an\n * objective, a prefab, a player). Each a click away in the Rules panel\n *\n * @beta\n */\nexport function checkMissionRules(map: GameMap, registry?: Registry): MapProblem[] {\n\tconst kept = map.data[MAP_RULES_KEY]\n\tif (kept === undefined) return []\n\tif (!Array.isArray(kept)) return [{ message: 'The map’s rules are not a list', error: true, rule: 'rules' }]\n\tconst problems: MapProblem[] = []\n\tconst seen = new Set<string>()\n\tconst regions = new Set(map.regions.map((region) => region.name))\n\tconst objectives = new Set(mapObjectivesOf(map).map((objective) => objective.id))\n\tconst players = new Set(map.players.map((player) => player.id))\n\tkept.forEach((each: Partial<MissionRule> | null, index) => {\n\t\tconst id = typeof each?.id === 'string' ? each.id : ''\n\t\tconst name = id || String(index + 1)\n\t\tconst reveal = { panel: 'rules', entry: id || String(index) }\n\t\tconst problem = (message: string, rule: string, error = true) => problems.push({ message, error, rule, reveal })\n\t\tif (!id) problem(`Rule ${index + 1} has no id`, 'rule-id')\n\t\telse if (seen.has(id)) problem(`Two rules have the id \"${id}\"`, 'rule-id')\n\t\tseen.add(id)\n\t\tif (!isCondition(each?.when)) problem(`The rule \"${name}\" has no condition`, 'rule-when')\n\t\telse\n\t\t\tfor (const region of regionsNamed(each!.when))\n\t\t\t\tif (!regions.has(region)) problem(`The rule \"${name}\" asks about a region \"${region}\" the map has not`, 'rule-name')\n\t\tif (each?.as !== undefined && !players.has(each.as)) problem(`The rule \"${name}\" is asked as a player ${each.as} the map has not`, 'rule-name')\n\t\tconst actions = Array.isArray(each?.do) ? each.do : []\n\t\tif (!actions.length) problem(`The rule \"${name}\" does nothing`, 'rule-action', false)\n\t\tfor (const action of actions as unknown[]) {\n\t\t\tconst kind = actionKind(action)\n\t\t\tif (!kind) {\n\t\t\t\tproblem(`The rule \"${name}\" has an action of no form the rules know (${Object.keys(action ?? {}).join(', ') || 'nothing'})`, 'rule-action')\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst data = (action as Record<string, Record<string, unknown>>)[kind]\n\t\t\tconst named = (player: unknown, what: string) => {\n\t\t\t\tif (typeof player === 'number' && !players.has(player)) problem(`The rule \"${name}\" ${what} a player ${player} the map has not`, 'rule-name')\n\t\t\t}\n\t\t\tif (kind === 'objective' && !objectives.has(String(data?.id ?? '')))\n\t\t\t\tproblem(`The rule \"${name}\" names an objective \"${data?.id ?? ''}\" the map has not`, 'rule-name')\n\t\t\tif (kind === 'spawn' && registry && !registry.prefabs.has(String(data?.prefab ?? '')))\n\t\t\t\tproblem(`The rule \"${name}\" spawns a prefab \"${data?.prefab ?? ''}\" the game has not`, 'rule-name')\n\t\t\tif (kind === 'spawn' && typeof data?.at === 'string' && !placeNamed(map, data.at))\n\t\t\t\tproblem(`The rule \"${name}\" spawns at \"${data.at}\", which the map has not`, 'rule-name')\n\t\t\tif (kind === 'spawn') named(data?.owner, 'spawns for')\n\t\t\tif (kind === 'tell') named(data?.computer, 'tells')\n\t\t\tif (kind === 'relation') {\n\t\t\t\tnamed(data?.a, 'sets')\n\t\t\t\tnamed(data?.b, 'sets')\n\t\t\t}\n\t\t\tif (typeof data === 'object' && data !== null && Array.isArray(data.to)) for (const player of data.to) named(player, 'is for')\n\t\t}\n\t})\n\treturn problems\n}\n\n/** Whether a map has a place of this name: a point, a region, or something placed and named */\nconst placeNamed = (map: GameMap, name: string): boolean =>\n\tmap.points.some((point) => point.name === name) ||\n\tmap.regions.some((region) => region.name === name) ||\n\tmap.objects.some((object) => object.name === name)\n\n/** Where a place is in the world: a point or a region of the map by name, a named thing, or the point given */\nfunction placeOf(world: World, at: string | Vec2): Vec2 | undefined {\n\tif (typeof at !== 'string') return { x: at.x, z: at.z }\n\tconst point = world.map.points.find((each) => each.name === at)\n\tif (point) return { x: point.x, z: point.z }\n\tconst region = world.map.regions.find((each) => each.name === at)\n\tif (region) return { x: region.shape.x, z: region.shape.z }\n\tconst named = world.named(at)\n\treturn named && { x: named.pos.x, z: named.pos.z }\n}\n\n/**\n * The players a rule's actions are for when they say none: the people, else everyone who can win or lose\n *\n * @internal\n */\nexport function rulePlayers(world: World): PlayerId[] {\n\tconst people = mapObjectivePlayers(world)\n\tif (people.length) return people\n\treturn [...world.players.values()]\n\t\t.filter((player) => !player.neutral && !player.creeps)\n\t\t.map((player) => player.id)\n\t\t.sort((a, b) => a - b)\n}\n\n/**\n * The timer of a rule's `timer` action: as it goes off, the rules are told its id, and the screens stop counting it\n *\n * @internal\n */\nexport const ruleTimer = defineTimer<{ word: string; to?: PlayerId[] }>('core.missionRules.timer', (world, { word, to }, timer) => {\n\tconst state = world.state(missionRulesState)\n\tif (state.timers[word] === timer.id) delete state.timers[word]\n\tfor (const player of to ?? []) world.timers.hide(player, timer.id)\n\ttellRules(world, word)\n})\n\n/**\n * Does one action of a rule, now\n *\n * @internal\n */\nexport function doMissionAction(world: World, rule: MissionRule, action: MissionActionData): void {\n\tconst warn = (line: string) => world.log.warn('rules', `the rule \"${rule.id}\" ${line}`)\n\tconst people = rulePlayers(world)\n\tif ('objective' in action) {\n\t\tconst { id, do: what = 'give', to = people, reason } = action.objective\n\t\tif (what === 'give') {\n\t\t\tif (!mapObjectivesOf(world.map).some((objective) => objective.id === id)) return warn(`gives an objective \"${id}\" the map has not`)\n\t\t\tgiveMapObjective(world, id, { players: to })\n\t\t} else\n\t\t\tfor (const player of to)\n\t\t\t\tif (world.objectives.has(player, id)) what === 'complete' ? world.objectives.complete(player, id) : world.objectives.fail(player, id, reason)\n\t} else if ('say' in action) {\n\t\tconst { speaker, text, seconds, to = people } = action.say\n\t\tworld.dialog.say(to, { speaker, text, ...(seconds !== undefined && { seconds }) })\n\t} else if ('cinematic' in action) {\n\t\tconst { id, to, hold, skippable } = action.cinematic\n\t\tplayCinematic(world, id, { to: to ?? 'everyone', hold, skippable })\n\t} else if ('spawn' in action) {\n\t\tconst { prefab, at, owner, facing } = action.spawn\n\t\tif (!world.registry.prefabs.has(prefab)) return warn(`spawns a prefab \"${prefab}\" the game has not`)\n\t\tconst place = placeOf(world, at)\n\t\tif (!place) return warn(`spawns at \"${String(at)}\", which the map has not`)\n\t\tworld.spawnPrefab(prefab, { at: place, owner, facing })\n\t} else if ('tell' in action) {\n\t\tconst { computer, word, data } = action.tell\n\t\tif (!world.computers.tell(computer, word, data)) warn(`tells player ${computer} \"${word}\", and the computer does not play them`)\n\t} else if ('relation' in action) {\n\t\tconst { a, b, how } = action.relation\n\t\tworld.sides.setRelation(a, b, how)\n\t} else if ('timer' in action) {\n\t\tconst { id, seconds, label, to = people } = action.timer\n\t\tconst state = world.state(missionRulesState)\n\t\tif (state.timers[id] !== undefined) world.timers.cancel(state.timers[id])\n\t\tconst shown = label === undefined ? [] : to\n\t\tconst timer = world.timers.after(seconds, ruleTimer, { word: id, ...(shown.length && { to: shown }) })\n\t\tstate.timers[id] = timer\n\t\tfor (const player of shown) world.timers.show(player, timer, { label: label! })\n\t} else if ('win' in action) {\n\t\tconst to = action.win === true ? people : (action.win.to ?? people)\n\t\tif (world.winner !== null || !to.length) return\n\t\tconst team = world.player(to[0]).team\n\t\tworld.winner = team\n\t\tworld.events.emit(gameOver, { winner: team })\n\t} else if ('lose' in action) {\n\t\tconst to = action.lose === true ? people : (action.lose.to ?? people)\n\t\tfor (const player of to) if (!world.player(player).defeated) defeat(world, player)\n\t}\n}\n\n/**\n * What a rule's condition is asked of: a watcher seated as a player, which reads the game as a computer player does\n * (`ai/computer.ts`'s `ruleWatcher`: a brain with no modules of its own, on an observer's session). The engine itself\n * carries none of the computer players' kit, so the pack that runs the rules is the kit's (`missionRules` of\n * `@v12-engine/engine/ai`), and hands this to `missionRulesPack`\n *\n * @internal\n */\nexport interface RulesWatcher {\n\t/** Reads the picture of the game anew */\n\tthink(): void\n\t/** Whether a condition holds for it now */\n\task(condition: AiConditionData): boolean\n\t/** A word told to the rules, for `{ told }` to see */\n\ttell(word: string, data: unknown, tick: number): void\n\t/** The word heard: taken, it is seen no more */\n\ttakeTold(word: string): void\n\t/** What it remembers, for a save, and back */\n\tsave(): unknown\n\trestore(memory: unknown): void\n}\n\n/**\n * The system that runs the rules: once a second, each watcher reads the picture, the words told since the last check\n * are heard, and each rule's condition is asked and its actions done as it turns true. The watchers' memory is the\n * system's to save\n */\nfunction rulesSystem(world: World, own: readonly MissionRule[], watch: (world: World, player: PlayerId) => RulesWatcher): System {\n\t// the map's rules and the code's, read as the first check comes: the system is made before the world has its map\n\tlet read: MissionRule[] | undefined\n\tconst rulesOf = (): MissionRule[] => {\n\t\tif (read) return read\n\t\tread = []\n\t\tconst ids = new Set<string>()\n\t\tfor (const rule of [...missionRulesOf(world.map), ...own]) {\n\t\t\tif (ids.has(rule.id)) {\n\t\t\t\tworld.log.warn('rules', `two rules are called \"${rule.id}\": the second is left out`)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tids.add(rule.id)\n\t\t\tread.push(rule)\n\t\t}\n\t\treturn read\n\t}\n\tconst watchers = new Map<PlayerId, RulesWatcher>()\n\tlet restored: Record<string, unknown> | undefined\n\tconst defaultPlayer = (): PlayerId | undefined => rulePlayers(world)[0]\n\tconst watcher = (player: PlayerId): RulesWatcher | undefined => {\n\t\tlet made = watchers.get(player)\n\t\tif (made) return made\n\t\tif (!world.players.has(player)) return undefined\n\t\tmade = watch(world, player)\n\t\tconst memory = restored?.[player]\n\t\tif (memory !== undefined) made.restore(memory)\n\t\twatchers.set(player, made)\n\t\treturn made\n\t}\n\treturn {\n\t\tname: 'missionRules',\n\t\tphase: 'cleanup',\n\t\tevery: Math.max(1, Math.round(world.tickRate)),\n\t\toffset: 3,\n\t\tupdate() {\n\t\t\tconst rules = rulesOf()\n\t\t\tif (!rules.length) return\n\t\t\tconst state = world.state(missionRulesState)\n\t\t\t// the words told since the last check: heard by every watcher this once\n\t\t\tconst told = state.told.splice(0)\n\t\t\tconst asked = new Set<PlayerId>()\n\t\t\tfor (const rule of rules) {\n\t\t\t\tconst player = rule.as ?? defaultPlayer()\n\t\t\t\tif (player !== undefined) asked.add(player)\n\t\t\t}\n\t\t\tfor (const player of asked) {\n\t\t\t\tconst made = watcher(player)\n\t\t\t\tif (!made) continue\n\t\t\t\tmade.think()\n\t\t\t\tfor (const word of told) made.tell(word.word, word.data, word.tick)\n\t\t\t}\n\t\t\tfor (const rule of rules) {\n\t\t\t\tconst kept = (state.rules[rule.id] ??= { count: 0 })\n\t\t\t\tif (rule.once && kept.count > 0) continue\n\t\t\t\tconst player = rule.as ?? defaultPlayer()\n\t\t\t\tconst made = player === undefined ? undefined : watcher(player)\n\t\t\t\tif (!made) {\n\t\t\t\t\tif (kept.was === undefined)\n\t\t\t\t\t\tworld.log.warn('rules', `the rule \"${rule.id}\" is asked as a player ${player} the world has not: it never fires`)\n\t\t\t\t\tkept.was = false\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst holds = made.ask(rule.when)\n\t\t\t\tconst turned = holds && !kept.was\n\t\t\t\tkept.was = holds\n\t\t\t\tif (!holds) continue\n\t\t\t\tconst again = rule.every !== undefined && kept.fired !== undefined && world.tick - kept.fired >= Math.round(rule.every * world.tickRate)\n\t\t\t\tif (!turned && !again) continue\n\t\t\t\tkept.fired = world.tick\n\t\t\t\tkept.count++\n\t\t\t\tworld.log.info('rules', `the rule \"${rule.id}\" fires`)\n\t\t\t\tworld.events.emit(ruleFired, { rule: rule.id })\n\t\t\t\tfor (const action of rule.do) doMissionAction(world, rule, action)\n\t\t\t}\n\t\t\tfor (const made of watchers.values()) for (const word of new Set(told.map((each) => each.word))) made.takeTold(word)\n\t\t},\n\t\tsave: () => ({ watchers: Object.fromEntries([...watchers].map(([player, made]) => [player, made.save()])) }),\n\t\trestore: (_world, data) => {\n\t\t\trestored = (data as { watchers?: Record<string, unknown> } | undefined)?.watchers\n\t\t\tfor (const [player, made] of watchers) if (restored?.[player] !== undefined) made.restore(restored[player])\n\t\t}\n\t}\n}\n\n/**\n * The mission rules pack, given what asks a rule's condition (`RulesWatcher`): what `missionRules` of `@v12-engine/engine/ai`\n * makes, with a watcher of the computer players' kit. The map's rules and `rules` of the code's, run as the game plays\n *\n * @internal\n */\nexport function missionRulesPack(options: { rules?: MissionRule[]; watch: (world: World, player: PlayerId) => RulesWatcher }): GamePack {\n\tconst own = options.rules ?? []\n\treturn {\n\t\tid: MISSION_RULES,\n\t\tcomponents: [missionRulesState],\n\t\tevents: [ruleFired],\n\t\ttimers: [ruleTimer],\n\t\tsystems: [(world) => rulesSystem(world, own, options.watch)],\n\t\tcheck: (map, registry) => checkMissionRules(map, registry),\n\t\t...(own.length && { options: { rules: own.map((rule) => rule.id) } })\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,179 @@
1
+ import type { AiConditionData } from './ai/rules';
2
+ import type { PlayerId } from './entity';
3
+ import type { GameMap } from './map';
4
+ import type { MapProblem } from './mapFields';
5
+ import type { Vec2 } from './math';
6
+ import type { MessageRef } from './messages';
7
+ import type { Registry } from './registry';
8
+ import type { PlayerRelation, World } from './world';
9
+ /**
10
+ * The mission rules pack's id
11
+ *
12
+ * @beta
13
+ */
14
+ export declare const MISSION_RULES = "core.missionRules";
15
+ /**
16
+ * The key of the map's data its rules are kept under (`GameMap.data.rules`)
17
+ *
18
+ * @beta
19
+ */
20
+ export declare const MAP_RULES_KEY = "rules";
21
+ /**
22
+ * What a mission rule does, as plain data: one of a closed set of actions. Each takes who it is for (`to`) where that
23
+ * matters: every player a person plays when left out (`mapObjectivePlayers`), as the map's objectives are given
24
+ *
25
+ * @beta
26
+ */
27
+ export type MissionActionData =
28
+ /** An objective of the map's (`MapObjective`), by id: given (`give`, the default), done or failed (with why) */
29
+ {
30
+ objective: {
31
+ id: string;
32
+ do?: 'give' | 'complete' | 'fail';
33
+ to?: PlayerId[];
34
+ reason?: MessageRef;
35
+ };
36
+ }
37
+ /** A line said (`world.dialog.say`): who speaks (a speaker of the view's), what (a message key, or the words), for how long */
38
+ | {
39
+ say: {
40
+ speaker: string;
41
+ text: MessageRef;
42
+ seconds?: number;
43
+ to?: PlayerId[];
44
+ };
45
+ }
46
+ /** A cinematic of the view's played (`playCinematic`), to everyone when `to` is left out */
47
+ | {
48
+ cinematic: {
49
+ id: string;
50
+ to?: PlayerId[];
51
+ hold?: boolean;
52
+ skippable?: boolean;
53
+ };
54
+ }
55
+ /**
56
+ * A prefab of the game's spawned (`world.spawnPrefab`) at a place: a point or a region of the map by name, a named
57
+ * thing of the map, or a point; for a player, or neutral
58
+ */
59
+ | {
60
+ spawn: {
61
+ prefab: string;
62
+ at: string | Vec2;
63
+ owner?: PlayerId;
64
+ facing?: number;
65
+ };
66
+ }
67
+ /** A word told to a computer player (`world.computers.tell`), with what goes with it */
68
+ | {
69
+ tell: {
70
+ computer: PlayerId;
71
+ word: string;
72
+ data?: unknown;
73
+ };
74
+ }
75
+ /** What two players are to each other from now on (`world.sides.setRelation`) */
76
+ | {
77
+ relation: {
78
+ a: PlayerId;
79
+ b: PlayerId;
80
+ how: PlayerRelation;
81
+ };
82
+ }
83
+ /**
84
+ * A timer started: so many seconds on, the rules are told its id as a word (a rule `when: { told: id }` fires), and
85
+ * with `label` it counts down on the players' screens meanwhile (`world.timers.show`). Started again, it starts over
86
+ */
87
+ | {
88
+ timer: {
89
+ id: string;
90
+ seconds: number;
91
+ label?: MessageRef;
92
+ to?: PlayerId[];
93
+ };
94
+ }
95
+ /** The game is won by the players' team */
96
+ | {
97
+ win: true | {
98
+ to?: PlayerId[];
99
+ };
100
+ }
101
+ /** The players are out of the game (`defeat`) */
102
+ | {
103
+ lose: true | {
104
+ to?: PlayerId[];
105
+ };
106
+ };
107
+ /**
108
+ * A rule of a mission, as the map keeps it and the mission rules pack runs it: `when` a condition of the computer
109
+ * players' language holds, `do` its actions. Fires as the condition turns true; `once` the first time only, ever; with
110
+ * `every`, again while it holds, at most so often. Asked `as` a player: whose the units of `of: 'mine'` are, whose
111
+ * objectives `{ objective }` reads; the first player a person plays when left out
112
+ *
113
+ * @beta
114
+ */
115
+ export interface MissionRule {
116
+ /** What the log, the checks and the editor know it by; no two the same */
117
+ id: string;
118
+ /** When it fires: plain data (`docs/ai.md`, "Conditions") */
119
+ when: AiConditionData;
120
+ /** What it does, in order */
121
+ do: MissionActionData[];
122
+ /** The first time only, ever */
123
+ once?: boolean;
124
+ /** Seconds: fired again while its condition holds, at most so often */
125
+ every?: number;
126
+ /** The player the condition is asked for */
127
+ as?: PlayerId;
128
+ }
129
+ /**
130
+ * A mission rule fired: its id. For a pack of the game's that does what the rules cannot
131
+ *
132
+ * @beta
133
+ */
134
+ export declare const ruleFired: import("./events").EventKey<{
135
+ rule: string;
136
+ }>;
137
+ /**
138
+ * What a mission rule is now, for the report and the tests: whether its condition held at the last check, how often it
139
+ * fired and when it last did
140
+ *
141
+ * @beta
142
+ */
143
+ export interface MissionRuleState {
144
+ holds: boolean;
145
+ count: number;
146
+ fired?: number;
147
+ }
148
+ /**
149
+ * The rules a map keeps (`GameMap.data.rules`), in their order: none for a map with none. What is kept there and is no
150
+ * rule (no id, no condition) is left out, so that a file changed by hand breaks no game that reads it; the map's checks
151
+ * say so (`checkMissionRules`). Actions that are of no form the pack knows are left out of a rule the same way
152
+ *
153
+ * @beta
154
+ */
155
+ export declare function missionRulesOf(map: {
156
+ readonly data: Readonly<Record<string, unknown>>;
157
+ }): MissionRule[];
158
+ /**
159
+ * Tells the mission rules a word, as the game's code does for what the rules cannot know on their own (the boss fell,
160
+ * the player chose): a rule `when: { told: word }` fires at the next check, and the word is heard no more after it.
161
+ * What a rule's timer does as it goes off
162
+ *
163
+ * @beta
164
+ */
165
+ export declare function tellRules(world: World, word: string, data?: unknown): void;
166
+ /**
167
+ * What a mission rule is now (`MissionRuleState`): none for a rule the world has not, or has not checked yet
168
+ *
169
+ * @beta
170
+ */
171
+ export declare function missionRuleState(world: World, id: string): MissionRuleState | undefined;
172
+ /**
173
+ * What is wrong with a map's rules (`GameMap.data.rules`): one with no id or with another's, one with no condition, an
174
+ * action of no form the pack knows, a condition or an action naming what the map or the game has not (a region, an
175
+ * objective, a prefab, a player). Each a click away in the Rules panel
176
+ *
177
+ * @beta
178
+ */
179
+ export declare function checkMissionRules(map: GameMap, registry?: Registry): MapProblem[];
package/dist/mods.d.ts ADDED
@@ -0,0 +1,146 @@
1
+ import type { RaceDef } from './races';
2
+ import type { Component } from './components';
3
+ import type { EventKey } from './events';
4
+ import type { EffectKind } from './abilities/effects';
5
+ import type { CommandDef } from './commands';
6
+ import type { AbilityDef, BuffDef, ItemDef, ResourceDef, StatDef, UnitTypeDef, UpgradeDef } from './defs';
7
+ import type { GameModule } from './game';
8
+ import type { AreaDef } from './areas';
9
+ import type { ListenerDef } from './events';
10
+ import type { SequenceDef } from './sequences';
11
+ import type { TimerDef } from './timers';
12
+ import type { HookDef } from './hooks';
13
+ import type { OrderBehavior, SystemDef } from './registry';
14
+ import { type RulesInit } from './rules';
15
+ import type { GamePack } from './packs/pack';
16
+ /**
17
+ * A mod: changes to a game, made on top of it instead of on a copy of it. A new hero, other numbers, a rule of its
18
+ * own. `composeGame` applies mods to a game in the order they need each other, and tells about two mods that change
19
+ * the same thing without one knowing of the other, before anyone plays.
20
+ *
21
+ * @beta
22
+ */
23
+ export interface ModDef {
24
+ id: string;
25
+ /** `major.minor.patch`. Mods that need this one say which versions they work with */
26
+ version: string;
27
+ name?: string;
28
+ /**
29
+ * The game and the mods it is made for, each `id`, `id@1.2.3` (that version only) or `id@^1.2` (that major version,
30
+ * from 1.2 on). The game counts as one of them, by its id and `GameModule.version`
31
+ */
32
+ requires?: string[];
33
+ /** Makes the changes, through the builder */
34
+ apply(game: GameBuilder): void;
35
+ }
36
+ /**
37
+ * Typed help for writing a mod
38
+ *
39
+ * @beta
40
+ */
41
+ export declare const defineMod: (def: ModDef) => ModDef;
42
+ /**
43
+ * Definitions of one kind, by id: what a mod adds, changes or takes out
44
+ *
45
+ * @beta
46
+ */
47
+ export interface Collection<T> {
48
+ get(id: string): T | undefined;
49
+ has(id: string): boolean;
50
+ /** Throws when there is one of that id already: that is `override` */
51
+ add(def: T): void;
52
+ /** Changes one that is there: a new definition, or the fields that are different. Throws when there is none */
53
+ override(id: string, change: Partial<T> | ((def: T) => T)): void;
54
+ /** Throws when there is none of that id */
55
+ remove(id: string): void;
56
+ all(): readonly T[];
57
+ }
58
+ /**
59
+ * The game a mod is applied to, as it stands after the mods before it
60
+ *
61
+ * @beta
62
+ */
63
+ export interface GameBuilder {
64
+ /** What the game is so far: to read, not to change. Changes go through the rest of the builder */
65
+ readonly current: Readonly<GameModule>;
66
+ units: Collection<UnitTypeDef>;
67
+ abilities: Collection<AbilityDef>;
68
+ buffs: Collection<BuffDef>;
69
+ items: Collection<ItemDef>;
70
+ upgrades: Collection<UpgradeDef>;
71
+ /** The sides players can play (`GameModule.races`) */
72
+ races: Collection<RaceDef>;
73
+ stats: Collection<StatDef>;
74
+ resources: Collection<ResourceDef>;
75
+ /** Kinds of ability effects, by their type (`defineEffect`) */
76
+ effects: Collection<EffectKind>;
77
+ orders: Collection<OrderBehavior>;
78
+ commands: Collection<CommandDef>;
79
+ /** The game's hook handlers, by id. `withoutHook` takes out one of the engine's */
80
+ hooks: Collection<HookDef>;
81
+ /** How the game reacts to events, by id */
82
+ listeners: Collection<ListenerDef>;
83
+ /** The state of its own the game keeps, by id: a mod's own components are added here */
84
+ components: Collection<Component<any>>;
85
+ /** The events of its own the game emits, by id */
86
+ events: Collection<EventKey<any>>;
87
+ /** The parts of the map the rules watch, by id */
88
+ areas: Collection<AreaDef>;
89
+ /** What the game can set to go off later, by id */
90
+ timers: Collection<TimerDef>;
91
+ /** The game's scripts of steps, by id */
92
+ sequences: Collection<SequenceDef>;
93
+ withoutHook(id: string): void;
94
+ /** The parts of the rules the game opts into (`GameModule.packs`), by id: `packs.add(withHeroes())` @beta */
95
+ packs: Collection<GamePack>;
96
+ /** Takes out a command of the engine's or a pack's, by its type (`GameModule.withoutCommands`) @beta */
97
+ withoutCommand(type: string): void;
98
+ /** Takes out an order of the engine's or a pack's, by its type (`GameModule.withoutOrders`) @beta */
99
+ withoutOrder(type: string): void;
100
+ /** Adds a system of the mod's own, or one in place of the engine's of the same name */
101
+ addSystem(system: SystemDef): void;
102
+ /** Takes out a system: one of the engine's, or one the game gave as an object, by name */
103
+ withoutSystem(name: string): void;
104
+ /** Changes rules of the game (`GameRules`): any of them, a group in part (`{ supply: { max: 200 } }`) */
105
+ rules(changes: RulesInit): void;
106
+ /** Changes one of the game's settings that are one thing, not a list */
107
+ set<K extends Setting>(key: K, value: GameModule[K]): void;
108
+ }
109
+ /** The parts of a game a mod can only put something else in the place of */
110
+ type Setting = 'name' | 'currency' | 'upkeep' | 'day' | 'victory' | 'start' | 'report' | 'ai';
111
+ /**
112
+ * Throws when a requirement is not met, or two mods change the same thing without one requiring the other
113
+ *
114
+ * @beta
115
+ */
116
+ export declare class ModError extends Error {
117
+ }
118
+ /**
119
+ * A game with mods on it: a new `GameModule`, which `createWorld` takes like any other. Its id names the game and
120
+ * the mods (`melee+goldRush`), and `mods` lists them with their versions. Mods are applied after the ones they
121
+ * require, otherwise in the order given. Neither the game nor the mods are changed
122
+ *
123
+ * @beta
124
+ */
125
+ export declare function composeGame(base: GameModule, mods: ModDef[]): GameModule;
126
+ /**
127
+ * A game made by `composeGame` made again, of its base and its mods as they are now (a base made of mods made again
128
+ * too): what a game played with mods takes as one of them, or its base, is saved while it runs (hot reload). A game not
129
+ * made so is itself. Throws as `composeGame` does: mods that no longer go together
130
+ *
131
+ * @beta
132
+ */
133
+ export declare function recompose(game: GameModule): GameModule;
134
+ /**
135
+ * Whether a game is made of this game or mod: is it, or has it as its base or one of its mods, at any depth
136
+ *
137
+ * @beta
138
+ */
139
+ export declare function isMadeOf(game: GameModule, part: GameModule | ModDef): boolean;
140
+ /**
141
+ * Whether a version is in a range: `1.2.3` exactly, or `^1.2` for 1.2 and later of major version 1
142
+ *
143
+ * @beta
144
+ */
145
+ export declare function satisfies(have: string, range: string): boolean;
146
+ export {};
@@ -0,0 +1,93 @@
1
+ import type { GameData } from './gameData';
2
+ import type { MapCamera, MapDoodad, MapEnvironment, MapForce, MapItemTable, MapPath, MapPlayer, MapPoint, MapRegion } from './map';
3
+ import { type MapFieldDef, type MapThing } from './mapFields';
4
+ import { Path, type Spot } from './paths';
5
+ /**
6
+ * Entities by the names they were given: on a map, where the editor names what the rules have to find (`MapObject.name`),
7
+ * or in code (`SpawnOptions.name`, `world.setName`). The rules ask for "the gate", never for a number or a spot on
8
+ * the map. Kept in the world, so that a save has them
9
+ */
10
+ export declare const names: import("./components").Component<Record<string, number>, Record<string, number>>;
11
+ /**
12
+ * What the map a world was made from says that is not an entity, as it is kept in the world: plain data, for a save
13
+ *
14
+ * @beta
15
+ */
16
+ export interface MapInfo {
17
+ name: string;
18
+ data: Record<string, unknown>;
19
+ points: MapPoint[];
20
+ paths: MapPath[];
21
+ /** What the map looks like, for the screens (`GameSession.environment`) */
22
+ environment?: MapEnvironment;
23
+ /** Its scenery, for the screens (`GameSession.doodads`) */
24
+ doodads?: MapDoodad[];
25
+ /** Its regions, for the screens (`GameSession.regions`): what mist in places lies over by name. The rules know them as areas */
26
+ regions?: MapRegion[];
27
+ /** Its views saved under names, for the screens (`GameSession.cameras`) */
28
+ cameras?: MapCamera[];
29
+ /** Who plays each player, and the game's own fields of each (with what they are when not set) */
30
+ players?: MapPlayerInfo[];
31
+ /** Its teams, named, and what they share */
32
+ forces?: MapForce[];
33
+ /** What things placed on it drop when they die (`MapObject.drops`) */
34
+ itemTables?: MapItemTable[];
35
+ /** The map's own definitions (`GameMap.definitions`): what a load of the world lays over the game again */
36
+ definitions?: GameData;
37
+ }
38
+ /**
39
+ * What the map says of a player beyond what the world has of them: who plays them, and the game's own fields
40
+ *
41
+ * @beta
42
+ */
43
+ export interface MapPlayerInfo {
44
+ id: number;
45
+ controller?: MapPlayer['controller'];
46
+ data: Record<string, unknown>;
47
+ }
48
+ export declare const mapInfo: import("./components").Component<MapInfo, MapInfo>;
49
+ /**
50
+ * What the map a world was made from says that is not an entity (`World.map`): its name, what the game kept with it,
51
+ * and its points and paths by name. A game can say which names there are: `world.map.path<RoadPaths>('road')`
52
+ *
53
+ * @beta
54
+ */
55
+ export declare class WorldMap {
56
+ private readonly info;
57
+ constructor(info: MapInfo);
58
+ /** The name of the map. Empty for a world made without one */
59
+ get name(): string;
60
+ /** What the game kept with the map (`GameMap.data`): a difficulty, the waves of this level */
61
+ get data(): Record<string, unknown>;
62
+ /**
63
+ * The things of a kind of the game's own that were put on the map (`MapThing`): a tower defense's ground kept clear,
64
+ * a MOBA's lanes. None for a kind the map has nothing of. With `fields`, each thing's own (`data`) has what was not
65
+ * set at its default: `world.map.things('td.clearings', clearingFields)`
66
+ */
67
+ things(kind: string, fields?: readonly Pick<MapFieldDef, 'id' | 'default'>[]): MapThing[];
68
+ /** Whether the map has a point or a path of this name */
69
+ has(name: string): boolean;
70
+ /** A point of the map. Throws for one it does not have: a name in the code that is not on the map is a mistake */
71
+ point<Name extends string = string>(name: Name): Spot;
72
+ /** A path of the map, to ask how long it is, where along it, what is on it. Throws for one it does not have */
73
+ path<Name extends string = string>(name: Name): Path;
74
+ /** What the map looks like, for the screens: its water. Nothing for a world made without a map */
75
+ get environment(): MapEnvironment | undefined;
76
+ /** The regions of the map, for the screens: what mist in places lies over by name. The rules know them as areas */
77
+ get regions(): readonly MapRegion[];
78
+ /** The scenery of the map, for the screens: the rules never see it, but where it blocks, which the terrain has */
79
+ get doodads(): readonly MapDoodad[];
80
+ /** What the map says of a player: who plays them (a person, the computer, nobody) and the game's own fields */
81
+ player(id: number): MapPlayerInfo | undefined;
82
+ /** An item table of the map, by name: what something placed on it drops when it dies */
83
+ itemTable(name: string): MapItemTable | undefined;
84
+ /** The teams of the map, named, and what their players share */
85
+ get forces(): readonly MapForce[];
86
+ /** The views of the map saved under names, for the screens */
87
+ get cameras(): readonly MapCamera[];
88
+ /** The points of the map, as it has them. None in a world saved before maps had points */
89
+ get points(): readonly MapPoint[];
90
+ /** The paths of the map, as it has them */
91
+ get paths(): readonly MapPath[];
92
+ private get named();
93
+ }
@@ -0,0 +1,4 @@
1
+ import type { Entity } from '#engine/entity';
2
+ import type { AgentParams } from './navigation';
3
+ /** What the navigation is told of a unit when it takes it on as an agent: one place for every site that adds one again */
4
+ export declare function agentParamsOf(entity: Entity, speed: number): AgentParams;
@@ -0,0 +1,89 @@
1
+ import type { Rect, Vec2 } from '#engine/math';
2
+ import type { AgentParams, AgentSave, AgentState, NavDebugGeometry, Navigation } from './navigation';
3
+ /**
4
+ * Where flyers move. There is nothing in the way up there but other flyers and the edge of the map,
5
+ * so they go straight to where they are sent and only keep from flying inside one another.
6
+ */
7
+ export declare class AirNavigation implements Navigation {
8
+ private readonly width;
9
+ private readonly depth;
10
+ readonly version = 0;
11
+ private readonly flyers;
12
+ constructor(width: number, depth: number);
13
+ private inside;
14
+ addAgent(id: number, position: Vec2, params: AgentParams): void;
15
+ removeAgent(id: number): void;
16
+ saveAgent(id: number): AgentSave | undefined;
17
+ reseat(agents: readonly (readonly [id: number, save: AgentSave])[]): void;
18
+ restoreAgent(id: number, save: AgentSave): void;
19
+ settle(): void;
20
+ hasAgent(id: number): boolean;
21
+ setDestination(id: number, target: Vec2): boolean;
22
+ clearDestination(id: number): void;
23
+ teleport(id: number, position: Vec2): void;
24
+ setAnchored(id: number, anchored: boolean): void;
25
+ setGhost(id: number, ghost: boolean): void;
26
+ setSpeed(id: number, speed: number): void;
27
+ readAgent(id: number, out: AgentState): boolean;
28
+ update(dt: number): void;
29
+ /**
30
+ * The flyers that push (all but ghosts), by cells twice the widest one's radius across: two that overlap are in the
31
+ * same cell or next to each other, so each looks at its own cell and the eight about it, not at every flyer
32
+ */
33
+ private cellsOf;
34
+ addObstacle(_key: number, _rect: Rect): boolean;
35
+ obstacleRoom(): number;
36
+ removeObstacle(_key: number): void;
37
+ closestPoint(point: Vec2): Vec2;
38
+ findPath(from: Vec2, to: Vec2): Vec2[];
39
+ debugGeometry(): NavDebugGeometry;
40
+ dispose(): void;
41
+ }
42
+ /**
43
+ * The ground, the air and the water as one: agents are told apart when they are added and find their own layer from
44
+ * then on. Everything that is not about an agent, like obstacles and looking for walkable ground, is about the ground.
45
+ * Boats go on the ground where the map has no water to go on (`water` is left out)
46
+ */
47
+ export declare class LayeredNavigation implements Navigation {
48
+ readonly ground: Navigation;
49
+ readonly air: Navigation;
50
+ readonly water?: Navigation | undefined;
51
+ private readonly flying;
52
+ private readonly naval;
53
+ constructor(ground: Navigation, air: Navigation, water?: Navigation | undefined);
54
+ get version(): number;
55
+ private of;
56
+ /** The layer of a kind of agent: for finding where one can be put */
57
+ layer(kind: {
58
+ flying?: boolean;
59
+ naval?: boolean;
60
+ }): Navigation;
61
+ addAgent(id: number, position: Vec2, params: AgentParams): void;
62
+ removeAgent(id: number): void;
63
+ hasAgent(id: number): boolean;
64
+ setDestination(id: number, target: Vec2): boolean;
65
+ clearDestination(id: number): void;
66
+ teleport(id: number, position: Vec2): void;
67
+ setAnchored(id: number, anchored: boolean): void;
68
+ setGhost(id: number, ghost: boolean): void;
69
+ setSpeed(id: number, speed: number): void;
70
+ readAgent(id: number, out: AgentState): boolean;
71
+ saveAgent(id: number): AgentSave | undefined;
72
+ restoreAgent(id: number, save: AgentSave): void;
73
+ reseat(agents: readonly (readonly [id: number, save: AgentSave])[]): void;
74
+ settle(version: number): void;
75
+ /** Slow ground is the ground's: what flies or sails goes at one speed (EN2) */
76
+ groundChanged(cells: readonly number[]): void;
77
+ /** The ground's and the water's cut again of the ground as it is now: what flies goes over it all the same */
78
+ reshape(): boolean;
79
+ update(dt: number): void;
80
+ addObstacle(key: number, rect: Rect): boolean;
81
+ obstacleRoom(): number;
82
+ holdObstacles(hold: boolean): void;
83
+ removeObstacle(key: number): void;
84
+ sameCrowd(a: number, b: number): boolean;
85
+ closestPoint(point: Vec2, searchRadius?: number): Vec2 | null;
86
+ findPath(from: Vec2, to: Vec2): Vec2[] | null;
87
+ debugGeometry(): NavDebugGeometry;
88
+ dispose(): void;
89
+ }