@v12-engine/engine 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/abilities/buffs.d.ts +83 -0
- package/dist/abilities/castTold.d.ts +12 -0
- package/dist/abilities/charges.d.ts +28 -0
- package/dist/abilities/dispel.d.ts +9 -0
- package/dist/abilities/effectFields.d.ts +10 -0
- package/dist/abilities/effects/buff.d.ts +8 -0
- package/dist/abilities/effects/core.d.ts +1 -0
- package/dist/abilities/effects/damage.d.ts +1 -0
- package/dist/abilities/effects/heal.d.ts +2 -0
- package/dist/abilities/effects/missile.d.ts +1 -0
- package/dist/abilities/effects/moves.d.ts +11 -0
- package/dist/abilities/effects/passives.d.ts +15 -0
- package/dist/abilities/effects/sight.d.ts +4 -0
- package/dist/abilities/effects/spawn.d.ts +2 -0
- package/dist/abilities/effects/timed.d.ts +4 -0
- package/dist/abilities/effects/trade.d.ts +1 -0
- package/dist/abilities/effects.d.ts +122 -0
- package/dist/abilities/land.d.ts +21 -0
- package/dist/abilities/scaled.d.ts +21 -0
- package/dist/abilities/text.d.ts +113 -0
- package/dist/ai/area.d.ts +53 -0
- package/dist/ai/brain.d.ts +528 -0
- package/dist/ai/budget.d.ts +67 -0
- package/dist/ai/checks.d.ts +115 -0
- package/dist/ai/computer.d.ts +166 -0
- package/dist/ai/defence.d.ts +108 -0
- package/dist/ai/define.d.ts +21 -0
- package/dist/ai/economy.d.ts +129 -0
- package/dist/ai/geometry.d.ts +35 -0
- package/dist/ai/goals.d.ts +360 -0
- package/dist/ai/index.d.ts +38 -0
- package/dist/ai/knowledge.d.ts +418 -0
- package/dist/ai/lanes.d.ts +232 -0
- package/dist/ai/melee/build.d.ts +61 -0
- package/dist/ai/melee/goals.d.ts +299 -0
- package/dist/ai/melee/heroes.d.ts +27 -0
- package/dist/ai/melee/index.d.ts +14 -0
- package/dist/ai/melee/production.d.ts +8 -0
- package/dist/ai/melee/surrender.d.ts +24 -0
- package/dist/ai/micro.d.ts +278 -0
- package/dist/ai/mission.d.ts +195 -0
- package/dist/ai/missionRules.d.ts +18 -0
- package/dist/ai/module.d.ts +116 -0
- package/dist/ai/options.d.ts +61 -0
- package/dist/ai/plans/build.d.ts +280 -0
- package/dist/ai/plans/placement.d.ts +82 -0
- package/dist/ai/plans/plans.d.ts +105 -0
- package/dist/ai/plans/production.d.ts +210 -0
- package/dist/ai/plans/purse.d.ts +73 -0
- package/dist/ai/plans/tech.d.ts +37 -0
- package/dist/ai/profiles.d.ts +204 -0
- package/dist/ai/reach.d.ts +4 -0
- package/dist/ai/report.d.ts +203 -0
- package/dist/ai/roles.d.ts +133 -0
- package/dist/ai/rules.d.ts +288 -0
- package/dist/ai/scouting.d.ts +98 -0
- package/dist/ai/settings.d.ts +73 -0
- package/dist/ai/squads.d.ts +429 -0
- package/dist/ai/strength.d.ts +167 -0
- package/dist/ai/task.d.ts +118 -0
- package/dist/ai/tasks/attack.d.ts +7 -0
- package/dist/ai/tasks/capture.d.ts +21 -0
- package/dist/ai/tasks/creep.d.ts +16 -0
- package/dist/ai/tasks/defend.d.ts +29 -0
- package/dist/ai/tasks/drop.d.ts +34 -0
- package/dist/ai/tasks/escort.d.ts +16 -0
- package/dist/ai/tasks/gather.d.ts +23 -0
- package/dist/ai/tasks/harass.d.ts +7 -0
- package/dist/ai/tasks/hold.d.ts +20 -0
- package/dist/ai/tasks/index.d.ts +32 -0
- package/dist/ai/tasks/move.d.ts +19 -0
- package/dist/ai/tasks/patrol.d.ts +8 -0
- package/dist/ai/tasks/retreat.d.ts +20 -0
- package/dist/ai/tasks/scout.d.ts +29 -0
- package/dist/ai/tasks/shared.d.ts +74 -0
- package/dist/ai/team.d.ts +155 -0
- package/dist/ai/threat.d.ts +91 -0
- package/dist/ai/view.d.ts +366 -0
- package/dist/ai/waves.d.ts +126 -0
- package/dist/ai.js +6239 -0
- package/dist/ai.js.map +1 -0
- package/dist/aiTesting.d.ts +179 -0
- package/dist/areas.d.ts +149 -0
- package/dist/attacks.d.ts +66 -0
- package/dist/attributes.d.ts +66 -0
- package/dist/brain-BvVdUhX8.js +7659 -0
- package/dist/brain-BvVdUhX8.js.map +1 -0
- package/dist/builds-C6LfgvEU.js +460 -0
- package/dist/builds-C6LfgvEU.js.map +1 -0
- package/dist/bytes.d.ts +6 -0
- package/dist/camps.d.ts +95 -0
- package/dist/capture.d.ts +131 -0
- package/dist/cellLayers.d.ts +75 -0
- package/dist/cinematics.d.ts +194 -0
- package/dist/clock.d.ts +32 -0
- package/dist/commands.d.ts +235 -0
- package/dist/components.d.ts +184 -0
- package/dist/computers.d.ts +108 -0
- package/dist/concealment.d.ts +61 -0
- package/dist/coreComponents-syuh2fPG.js +5149 -0
- package/dist/coreComponents-syuh2fPG.js.map +1 -0
- package/dist/coreComponents.d.ts +1 -0
- package/dist/dashing.d.ts +8 -0
- package/dist/debug.d.ts +36 -0
- package/dist/debug.js +3 -0
- package/dist/debugCommands-CzjrSm66.js +14739 -0
- package/dist/debugCommands-CzjrSm66.js.map +1 -0
- package/dist/debugCommands.d.ts +213 -0
- package/dist/debugging.d.ts +10 -0
- package/dist/definitions.d.ts +43 -0
- package/dist/defs.d.ts +1162 -0
- package/dist/denying.d.ts +81 -0
- package/dist/destructibles.d.ts +27 -0
- package/dist/determinism-BCymQwiE.js +518 -0
- package/dist/determinism-BCymQwiE.js.map +1 -0
- package/dist/determinism.d.ts +121 -0
- package/dist/dialog.d.ts +94 -0
- package/dist/effectRefs.d.ts +16 -0
- package/dist/effects.d.ts +80 -0
- package/dist/endings.d.ts +22 -0
- package/dist/engagement.d.ts +108 -0
- package/dist/engineEvents.d.ts +710 -0
- package/dist/entity.d.ts +409 -0
- package/dist/entityIndex.d.ts +50 -0
- package/dist/errors.d.ts +85 -0
- package/dist/events.d.ts +97 -0
- package/dist/exactMath.d.ts +63 -0
- package/dist/features.d.ts +10 -0
- package/dist/fields.d.ts +114 -0
- package/dist/fixture.d.ts +17 -0
- package/dist/fog.d.ts +110 -0
- package/dist/formation.d.ts +111 -0
- package/dist/friendlyFire.d.ts +26 -0
- package/dist/game-DiJEN-Ks.js +5800 -0
- package/dist/game-DiJEN-Ks.js.map +1 -0
- package/dist/game.d.ts +501 -0
- package/dist/gameData.d.ts +325 -0
- package/dist/gameFiles.d.ts +26 -0
- package/dist/gates.d.ts +28 -0
- package/dist/generate.d.ts +403 -0
- package/dist/generateWorker.d.ts +39 -0
- package/dist/grid.d.ts +53 -0
- package/dist/ground.d.ts +127 -0
- package/dist/groundSpeed.d.ts +22 -0
- package/dist/hero.d.ts +177 -0
- package/dist/home.d.ts +14 -0
- package/dist/hooks.d.ts +780 -0
- package/dist/hotReload.d.ts +76 -0
- package/dist/ids.d.ts +26 -0
- package/dist/index.d.ts +227 -0
- package/dist/index.js +4701 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect-D9dWHmZ0.js +491 -0
- package/dist/inspect-D9dWHmZ0.js.map +1 -0
- package/dist/inspect.d.ts +176 -0
- package/dist/inventory.d.ts +18 -0
- package/dist/items.d.ts +91 -0
- package/dist/lanes.d.ts +213 -0
- package/dist/life.d.ts +53 -0
- package/dist/local-Dkovq42k.js +1379 -0
- package/dist/local-Dkovq42k.js.map +1 -0
- package/dist/log.d.ts +140 -0
- package/dist/manaBurn.d.ts +39 -0
- package/dist/map/file.d.ts +114 -0
- package/dist/map/images.d.ts +18 -0
- package/dist/map/look.d.ts +47 -0
- package/dist/map/pathProfile.d.ts +13 -0
- package/dist/map/resize.d.ts +54 -0
- package/dist/map/schema.d.ts +10 -0
- package/dist/map/terrain.d.ts +32 -0
- package/dist/map/types.d.ts +613 -0
- package/dist/map.d.ts +7 -0
- package/dist/mapCheck/cells.d.ts +19 -0
- package/dist/mapCheck/rule.d.ts +30 -0
- package/dist/mapCheck/rules/names.d.ts +3 -0
- package/dist/mapCheck/rules/objects.d.ts +3 -0
- package/dist/mapCheck/rules/paths.d.ts +3 -0
- package/dist/mapCheck/rules/players.d.ts +3 -0
- package/dist/mapCheck/rules/races.d.ts +3 -0
- package/dist/mapCheck/rules/random.d.ts +3 -0
- package/dist/mapCheck/rules/regions.d.ts +3 -0
- package/dist/mapCheck/rules/targets.d.ts +3 -0
- package/dist/mapCheck/rules/walking.d.ts +3 -0
- package/dist/mapCheck.d.ts +23 -0
- package/dist/mapFields.d.ts +364 -0
- package/dist/mapFile.d.ts +23 -0
- package/dist/mapMeasure.d.ts +95 -0
- package/dist/mapMerge.d.ts +19 -0
- package/dist/mapObjectives.d.ts +82 -0
- package/dist/mapObjects.d.ts +1 -0
- package/dist/math.d.ts +44 -0
- package/dist/messages.d.ts +150 -0
- package/dist/missionRules-C-bGxm0Q.js +523 -0
- package/dist/missionRules-C-bGxm0Q.js.map +1 -0
- package/dist/missionRules.d.ts +179 -0
- package/dist/mods.d.ts +146 -0
- package/dist/names.d.ts +93 -0
- package/dist/navigation/agentParams.d.ts +4 -0
- package/dist/navigation/air.d.ts +89 -0
- package/dist/navigation/builds.d.ts +140 -0
- package/dist/navigation/groundAreas.d.ts +23 -0
- package/dist/navigation/navigation.d.ts +127 -0
- package/dist/navigation/recast.d.ts +214 -0
- package/dist/navigation/sidePaths.d.ts +69 -0
- package/dist/navigation/sized.d.ts +1 -0
- package/dist/navigation-worker.js +11 -0
- package/dist/navigation-worker.js.map +1 -0
- package/dist/nearest.d.ts +8 -0
- package/dist/noise.d.ts +12 -0
- package/dist/objectives.d.ts +93 -0
- package/dist/orders/basic.d.ts +96 -0
- package/dist/orders/build.d.ts +91 -0
- package/dist/orders/cast.d.ts +105 -0
- package/dist/orders/facts.d.ts +14 -0
- package/dist/orders/harvest.d.ts +94 -0
- package/dist/orders/idle.d.ts +7 -0
- package/dist/orders/items.d.ts +14 -0
- package/dist/orders/queue.d.ts +24 -0
- package/dist/pack.schema.json +6621 -0
- package/dist/packs/director/index.d.ts +81 -0
- package/dist/packs/heroes/campaign.d.ts +137 -0
- package/dist/packs/heroes/carry.d.ts +59 -0
- package/dist/packs/heroes/commands.d.ts +6 -0
- package/dist/packs/heroes/hire.d.ts +9 -0
- package/dist/packs/heroes/index.d.ts +12 -0
- package/dist/packs/heroes/making.d.ts +16 -0
- package/dist/packs/heroes/respawn.d.ts +42 -0
- package/dist/packs/moba/index.d.ts +34 -0
- package/dist/packs/pack.d.ts +84 -0
- package/dist/packs-g5thvmGn.js +3199 -0
- package/dist/packs-g5thvmGn.js.map +1 -0
- package/dist/packs.d.ts +84 -0
- package/dist/paths.d.ts +51 -0
- package/dist/plain.d.ts +17 -0
- package/dist/player.d.ts +117 -0
- package/dist/portals.d.ts +66 -0
- package/dist/prefabs.d.ts +139 -0
- package/dist/presetBuildings.d.ts +52 -0
- package/dist/presetGround.d.ts +22 -0
- package/dist/profiles-B3NS9jwk.js +335 -0
- package/dist/profiles-B3NS9jwk.js.map +1 -0
- package/dist/races.d.ts +136 -0
- package/dist/randomGroups.d.ts +2 -0
- package/dist/registry.d.ts +464 -0
- package/dist/remains.d.ts +119 -0
- package/dist/replication.d.ts +103 -0
- package/dist/rng.d.ts +17 -0
- package/dist/rules.d.ts +395 -0
- package/dist/rulesCheck.d.ts +37 -0
- package/dist/runes.d.ts +41 -0
- package/dist/save.d.ts +277 -0
- package/dist/scenario.d.ts +56 -0
- package/dist/scheduler.d.ts +67 -0
- package/dist/score.d.ts +306 -0
- package/dist/sequences.d.ts +132 -0
- package/dist/server/doorman.d.ts +21 -0
- package/dist/server/gameServer.d.ts +346 -0
- package/dist/server/index.d.ts +24 -0
- package/dist/server/lobby.d.ts +1 -0
- package/dist/server/log.d.ts +13 -0
- package/dist/server/match.d.ts +24 -0
- package/dist/server/mode.d.ts +168 -0
- package/dist/server/navigation-worker.d.ts +1 -0
- package/dist/server/navigation.d.ts +11 -0
- package/dist/server/ops.d.ts +78 -0
- package/dist/server/packs.d.ts +15 -0
- package/dist/server/ratings.d.ts +62 -0
- package/dist/server/relay.d.ts +34 -0
- package/dist/server/rooms.d.ts +162 -0
- package/dist/server/seat.d.ts +2 -0
- package/dist/server/seatSettings.d.ts +15 -0
- package/dist/server/secret.d.ts +5 -0
- package/dist/server/start.d.ts +54 -0
- package/dist/server/websocket.d.ts +74 -0
- package/dist/server.js +2861 -0
- package/dist/server.js.map +1 -0
- package/dist/session/can.d.ts +20 -0
- package/dist/session/commandReplay.d.ts +92 -0
- package/dist/session/debug.d.ts +65 -0
- package/dist/session/delay.d.ts +15 -0
- package/dist/session/delta.d.ts +98 -0
- package/dist/session/entityState.d.ts +1 -0
- package/dist/session/local.d.ts +214 -0
- package/dist/session/memory.d.ts +27 -0
- package/dist/session/protocol.d.ts +1155 -0
- package/dist/session/remote.d.ts +530 -0
- package/dist/session/replay.d.ts +114 -0
- package/dist/session/seed.d.ts +7 -0
- package/dist/session/share.d.ts +78 -0
- package/dist/session/socket.d.ts +8 -0
- package/dist/session/wire.d.ts +153 -0
- package/dist/session/worker.d.ts +227 -0
- package/dist/shared.d.ts +171 -0
- package/dist/sides.d.ts +75 -0
- package/dist/sight.d.ts +27 -0
- package/dist/simulate-oXBiw1Ff.js +167 -0
- package/dist/simulate-oXBiw1Ff.js.map +1 -0
- package/dist/simulate-worker.d.ts +1 -0
- package/dist/simulate-worker.js +28 -0
- package/dist/simulate-worker.js.map +1 -0
- package/dist/simulate.d.ts +154 -0
- package/dist/smart.d.ts +9 -0
- package/dist/spatial.d.ts +62 -0
- package/dist/spawning.d.ts +33 -0
- package/dist/stances.d.ts +76 -0
- package/dist/start.d.ts +71 -0
- package/dist/stats.d.ts +122 -0
- package/dist/summons.d.ts +63 -0
- package/dist/systems/abilities.d.ts +3 -0
- package/dist/systems/combat.d.ts +71 -0
- package/dist/systems/combatTold.d.ts +14 -0
- package/dist/systems/construction.d.ts +34 -0
- package/dist/systems/economy.d.ts +21 -0
- package/dist/systems/fog.d.ts +19 -0
- package/dist/systems/life.d.ts +3 -0
- package/dist/systems/movement.d.ts +105 -0
- package/dist/systems/orders.d.ts +7 -0
- package/dist/systems/production.d.ts +49 -0
- package/dist/systems/productionQueue.d.ts +40 -0
- package/dist/systems/victory.d.ts +14 -0
- package/dist/talk.d.ts +65 -0
- package/dist/tech.d.ts +62 -0
- package/dist/techTree.d.ts +38 -0
- package/dist/terrain.d.ts +173 -0
- package/dist/terrainSave.d.ts +29 -0
- package/dist/testing.d.ts +58 -0
- package/dist/testing.js +822 -0
- package/dist/testing.js.map +1 -0
- package/dist/tiles.d.ts +34 -0
- package/dist/timers.d.ts +146 -0
- package/dist/tomes.d.ts +48 -0
- package/dist/trade.d.ts +28 -0
- package/dist/transport.d.ts +76 -0
- package/dist/tunables.d.ts +45 -0
- package/dist/upkeep.d.ts +16 -0
- package/dist/veterancy.d.ts +80 -0
- package/dist/walls.d.ts +86 -0
- package/dist/world.d.ts +1118 -0
- package/package.json +80 -5
- package/README.md +0 -3
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the simulation tells a player, like "Not enough gold", is a key and some params, never words. The words are
|
|
3
|
+
* the business of the player's screen: the client has English for the engine's keys, and a game's view gives its own
|
|
4
|
+
* (`GameView.hud.messages`) or other words for the engine's. That keeps the engine free of any one language, and lets
|
|
5
|
+
* a game say "build more farms" where the engine only knows about supply.
|
|
6
|
+
*
|
|
7
|
+
* Params that name something are ids (a resource, a unit type, an upgrade), for the screen to find the name of.
|
|
8
|
+
*
|
|
9
|
+
* @beta
|
|
10
|
+
*/
|
|
11
|
+
export interface Message {
|
|
12
|
+
key: string;
|
|
13
|
+
params?: MessageParams;
|
|
14
|
+
}
|
|
15
|
+
/** @beta */
|
|
16
|
+
export type MessageParams = Record<string, string | number | string[]>;
|
|
17
|
+
/**
|
|
18
|
+
* A message, or a bare key for one without params. What hooks give as the reason something is called off
|
|
19
|
+
*
|
|
20
|
+
* @beta
|
|
21
|
+
*/
|
|
22
|
+
export type MessageRef = Message | string;
|
|
23
|
+
/** @beta */
|
|
24
|
+
export declare const toMessage: (message: MessageRef) => Message;
|
|
25
|
+
/**
|
|
26
|
+
* The messages the engine sends, and their params. The client has words for each of these.
|
|
27
|
+
* A game can send keys of its own as well.
|
|
28
|
+
*
|
|
29
|
+
* @beta
|
|
30
|
+
*/
|
|
31
|
+
export interface EngineMessages {
|
|
32
|
+
/** Cannot afford something: `resource` is the id of what is short */
|
|
33
|
+
notEnough: {
|
|
34
|
+
resource: string;
|
|
35
|
+
};
|
|
36
|
+
/** A prefab asked for by a name the game has not (`debug.spawnPrefab`) */
|
|
37
|
+
unknownPrefab: {
|
|
38
|
+
prefab: string;
|
|
39
|
+
};
|
|
40
|
+
/** The unit types the player still needs to build to make or research something, by id */
|
|
41
|
+
requires: {
|
|
42
|
+
units: string[];
|
|
43
|
+
};
|
|
44
|
+
queueFull: {};
|
|
45
|
+
alreadyHaveHero: {};
|
|
46
|
+
tooManyHeroes: {};
|
|
47
|
+
/** Out of supply, and could build more of what provides it. `pool` for one of the game's own (`GameRules.supply.pools`) */
|
|
48
|
+
supplyBlocked: {
|
|
49
|
+
pool?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Out of supply, and at the most anyone can have (`GameRules.supply.max`, a pool's `max`) */
|
|
52
|
+
supplyLimit: {
|
|
53
|
+
pool?: string;
|
|
54
|
+
};
|
|
55
|
+
alreadyResearching: {};
|
|
56
|
+
researchDone: {
|
|
57
|
+
upgrade: string;
|
|
58
|
+
};
|
|
59
|
+
/** `unit` is the id of the hero's type */
|
|
60
|
+
heroLevel: {
|
|
61
|
+
unit: string;
|
|
62
|
+
level: number;
|
|
63
|
+
};
|
|
64
|
+
defeated: {};
|
|
65
|
+
/** Another player gave up. `player` is their name */
|
|
66
|
+
surrendered: {
|
|
67
|
+
player: string;
|
|
68
|
+
};
|
|
69
|
+
/** Every pause of the player's is used */
|
|
70
|
+
noPausesLeft: {};
|
|
71
|
+
cannotBuildThere: {};
|
|
72
|
+
/** The navigation has no room for another building in the way (`RecastNavigationOptions.maxObstacles`) */
|
|
73
|
+
tooManyBuildings: {};
|
|
74
|
+
cannotReachSite: {};
|
|
75
|
+
cannotReach: {};
|
|
76
|
+
/** A worker with something to bring back and nowhere to bring it. `resource` is its id */
|
|
77
|
+
nowhereToReturn: {
|
|
78
|
+
resource: string;
|
|
79
|
+
};
|
|
80
|
+
cannotGather: {
|
|
81
|
+
resource: string;
|
|
82
|
+
};
|
|
83
|
+
buildOnResource: {
|
|
84
|
+
resource: string;
|
|
85
|
+
};
|
|
86
|
+
inventoryFull: {};
|
|
87
|
+
theirInventoryFull: {};
|
|
88
|
+
outOfStock: {};
|
|
89
|
+
/** Buying needs one of the player's heroes at the shop, with a free slot */
|
|
90
|
+
heroAtShop: {};
|
|
91
|
+
/** Hiring needs one of the player's units at the place that hires */
|
|
92
|
+
unitAtShop: {};
|
|
93
|
+
/** A hero is hired once: the player has it already. `unit` is its type */
|
|
94
|
+
alreadyHired: {
|
|
95
|
+
unit: string;
|
|
96
|
+
};
|
|
97
|
+
noShopNear: {};
|
|
98
|
+
cannotDoThat: {};
|
|
99
|
+
notReady: {};
|
|
100
|
+
notEnoughMana: {};
|
|
101
|
+
notEnoughHealth: {};
|
|
102
|
+
silenced: {};
|
|
103
|
+
/** An ability used on something it is not for */
|
|
104
|
+
cannotTargetThat: {};
|
|
105
|
+
cannotTargetFriends: {};
|
|
106
|
+
cannotTargetSelf: {};
|
|
107
|
+
cannotTargetAir: {};
|
|
108
|
+
mustTargetAir: {};
|
|
109
|
+
mustTargetHero: {};
|
|
110
|
+
/** An ability used on what is immune to spells */
|
|
111
|
+
targetSpellImmune: {};
|
|
112
|
+
/** Pinged too often: the rest go nowhere for a moment */
|
|
113
|
+
tooManyPings: {};
|
|
114
|
+
/** Said too much too quickly: the rest goes nowhere for a moment */
|
|
115
|
+
tooManyLines: {};
|
|
116
|
+
/** Sent commands faster than the game takes them (a server's rate, `World.commandLimit`): the rest went nowhere */
|
|
117
|
+
tooManyCommands: {};
|
|
118
|
+
/** Resources given to someone who is not an ally */
|
|
119
|
+
notAnAlly: {};
|
|
120
|
+
/** Resources given to an ally, and received from one (see `give`) */
|
|
121
|
+
sent: {
|
|
122
|
+
amount: number;
|
|
123
|
+
resource: string;
|
|
124
|
+
player: string;
|
|
125
|
+
};
|
|
126
|
+
received: {
|
|
127
|
+
amount: number;
|
|
128
|
+
resource: string;
|
|
129
|
+
player: string;
|
|
130
|
+
};
|
|
131
|
+
/** One resource traded for another at a rate (see `exchange`): `amount` of `resource` went, `received` of `for` came */
|
|
132
|
+
exchanged: {
|
|
133
|
+
amount: number;
|
|
134
|
+
resource: string;
|
|
135
|
+
received: number;
|
|
136
|
+
for: string;
|
|
137
|
+
};
|
|
138
|
+
/** A field of a definition the game does not let be changed, or a value it does not take (`debug.redefine`) */
|
|
139
|
+
dataRefused: {
|
|
140
|
+
why: string;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A message of the engine's own, with its params checked
|
|
145
|
+
*
|
|
146
|
+
* @beta
|
|
147
|
+
*/
|
|
148
|
+
export declare const engineMessage: <K extends keyof EngineMessages>(key: K, ...params: {} extends EngineMessages[K] ? [] | [EngineMessages[K]] : [EngineMessages[K]]) => Message;
|
|
149
|
+
/** A message, to whom it is for */
|
|
150
|
+
export declare const toldMessage: import("./replication").ReplicatedEvent;
|
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import { Nd as defineComponent, Qr as defineHook, Sr as defeat, To as defineTimer, lo as playCinematic, mu as gameOver, td as defineEvent } from "./debugCommands-CzjrSm66.js";
|
|
2
|
+
//#region src/mapObjectives.ts
|
|
3
|
+
/**
|
|
4
|
+
* The map objectives pack's id
|
|
5
|
+
*
|
|
6
|
+
* @beta
|
|
7
|
+
*/
|
|
8
|
+
var MAP_OBJECTIVES = "core.mapObjectives";
|
|
9
|
+
/**
|
|
10
|
+
* The key of the map's data its objectives are kept under (`GameMap.data.objectives`)
|
|
11
|
+
*
|
|
12
|
+
* @beta
|
|
13
|
+
*/
|
|
14
|
+
var MAP_OBJECTIVES_KEY = "objectives";
|
|
15
|
+
/** The words of an objective as a file may hold them: a key, or a key with params */
|
|
16
|
+
var isWords = (text) => typeof text === "string" ? text.trim() !== "" : typeof text === "object" && text !== null && typeof text.key === "string" && text.key !== "";
|
|
17
|
+
/**
|
|
18
|
+
* The objectives a map gives (`GameMap.data.objectives`), in the order it gives them: none for a map with none. What is
|
|
19
|
+
* 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
|
|
20
|
+
* it; the map's checks say so (`mapObjectives`)
|
|
21
|
+
*
|
|
22
|
+
* @beta
|
|
23
|
+
*/
|
|
24
|
+
function mapObjectivesOf(map) {
|
|
25
|
+
const kept = map.data[MAP_OBJECTIVES_KEY];
|
|
26
|
+
if (!Array.isArray(kept)) return [];
|
|
27
|
+
return kept.filter((each) => typeof each === "object" && each !== null && typeof each.id === "string" && each.id !== "" && isWords(each.text)).map((each) => ({
|
|
28
|
+
id: each.id,
|
|
29
|
+
text: each.text,
|
|
30
|
+
...each.detail !== void 0 && isWords(each.detail) && { detail: each.detail },
|
|
31
|
+
...each.required !== void 0 && { required: each.required !== false },
|
|
32
|
+
at: each.at === "rule" ? "rule" : "start"
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Who is given a map's objective when the rules do not say (`giveMapObjective`): the map's players a person plays, not
|
|
37
|
+
* those it says the computer plays or nobody does (`MapPlayer.controller`), in the order of their ids
|
|
38
|
+
*
|
|
39
|
+
* @beta
|
|
40
|
+
*/
|
|
41
|
+
function mapObjectivePlayers(world) {
|
|
42
|
+
return [...world.players.values()].filter((player) => !player.neutral && !player.creeps).filter((player) => {
|
|
43
|
+
const controller = world.map.player(player.id)?.controller;
|
|
44
|
+
return controller !== "computer" && controller !== "nobody";
|
|
45
|
+
}).map((player) => player.id).sort((a, b) => a - b);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Gives players an objective of the map's, by its id (`MapObjective`): those given by a rule (`at: 'rule'`), when the
|
|
49
|
+
* rules say. To every player a person plays when `players` is left out (`mapObjectivePlayers`); a player who has it
|
|
50
|
+
* already keeps theirs. Its words' params and its progress go with it, as `world.objectives.add`. Throws for an id the
|
|
51
|
+
* map does not have: an id in the code that is not on the map is a mistake
|
|
52
|
+
*
|
|
53
|
+
* @beta
|
|
54
|
+
*/
|
|
55
|
+
function giveMapObjective(world, id, options = {}) {
|
|
56
|
+
const def = mapObjectivesOf(world.map).find((objective) => objective.id === id);
|
|
57
|
+
if (!def) throw new Error(`The map${world.map.name ? ` "${world.map.name}"` : ""} has no objective "${id}"`);
|
|
58
|
+
const { at: _at, ...objective } = def;
|
|
59
|
+
const given = [];
|
|
60
|
+
for (const player of options.players ?? mapObjectivePlayers(world)) {
|
|
61
|
+
if (world.objectives.has(player, id)) continue;
|
|
62
|
+
given.push(world.objectives.add(player, objective, {
|
|
63
|
+
params: options.params,
|
|
64
|
+
progress: options.progress
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
return given;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What is wrong with a map's objectives (`GameMap.data.objectives`): one with no id or with another's, one with no
|
|
71
|
+
* words, a list that is not one. Each a click away in the Objectives panel
|
|
72
|
+
*
|
|
73
|
+
* @beta
|
|
74
|
+
*/
|
|
75
|
+
function checkMapObjectives(map) {
|
|
76
|
+
const kept = map.data[MAP_OBJECTIVES_KEY];
|
|
77
|
+
if (kept === void 0) return [];
|
|
78
|
+
if (!Array.isArray(kept)) return [{
|
|
79
|
+
message: "The map’s objectives are not a list",
|
|
80
|
+
error: true,
|
|
81
|
+
rule: "objectives"
|
|
82
|
+
}];
|
|
83
|
+
const problems = [];
|
|
84
|
+
const seen = /* @__PURE__ */ new Set();
|
|
85
|
+
kept.forEach((each, index) => {
|
|
86
|
+
const id = typeof each?.id === "string" ? each.id : "";
|
|
87
|
+
const reveal = {
|
|
88
|
+
panel: "objectives",
|
|
89
|
+
entry: id || String(index)
|
|
90
|
+
};
|
|
91
|
+
if (!id) problems.push({
|
|
92
|
+
message: `Objective ${index + 1} has no id`,
|
|
93
|
+
error: true,
|
|
94
|
+
rule: "objective-id",
|
|
95
|
+
reveal
|
|
96
|
+
});
|
|
97
|
+
else if (seen.has(id)) problems.push({
|
|
98
|
+
message: `Two objectives have the id "${id}"`,
|
|
99
|
+
error: true,
|
|
100
|
+
rule: "objective-id",
|
|
101
|
+
reveal
|
|
102
|
+
});
|
|
103
|
+
seen.add(id);
|
|
104
|
+
if (!isWords(each?.text)) problems.push({
|
|
105
|
+
message: `The objective "${id || index + 1}" has no words`,
|
|
106
|
+
error: true,
|
|
107
|
+
rule: "objective-text",
|
|
108
|
+
reveal
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
return problems;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Objectives as data on the map (campaign plan EQ3): a map's objectives (`MapObjective`, kept in `GameMap.data.objectives`,
|
|
115
|
+
* written by the editor's Objectives panel) given at the start to every player a person plays, as the world is made
|
|
116
|
+
* from the map; those given by a rule wait for the rules (`giveMapObjective(world, id)`). Done and failed as any
|
|
117
|
+
* objective is (`world.objectives.complete`, `fail`); a game that is won by them has `objectiveVictory` as its
|
|
118
|
+
* `victory`. The map's checks say what is wrong with them (`checkMapObjectives`)
|
|
119
|
+
*
|
|
120
|
+
* @beta
|
|
121
|
+
*/
|
|
122
|
+
function mapObjectives() {
|
|
123
|
+
return {
|
|
124
|
+
id: MAP_OBJECTIVES,
|
|
125
|
+
hooks: [defineHook({
|
|
126
|
+
hook: "mapStart",
|
|
127
|
+
id: MAP_OBJECTIVES,
|
|
128
|
+
run(world) {
|
|
129
|
+
for (const objective of mapObjectivesOf(world.map)) if (objective.at === "start") giveMapObjective(world, objective.id);
|
|
130
|
+
}
|
|
131
|
+
})],
|
|
132
|
+
check: (map) => checkMapObjectives(map)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/missionRules.ts
|
|
137
|
+
/**
|
|
138
|
+
* The mission rules pack's id
|
|
139
|
+
*
|
|
140
|
+
* @beta
|
|
141
|
+
*/
|
|
142
|
+
var MISSION_RULES = "core.missionRules";
|
|
143
|
+
/**
|
|
144
|
+
* The key of the map's data its rules are kept under (`GameMap.data.rules`)
|
|
145
|
+
*
|
|
146
|
+
* @beta
|
|
147
|
+
*/
|
|
148
|
+
var MAP_RULES_KEY = "rules";
|
|
149
|
+
/**
|
|
150
|
+
* What the mission rules remember: in the world's state, so that a save has it
|
|
151
|
+
*
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
var missionRulesState = defineComponent("core.missionRules", { default: () => ({
|
|
155
|
+
rules: {},
|
|
156
|
+
told: [],
|
|
157
|
+
timers: {}
|
|
158
|
+
}) });
|
|
159
|
+
/**
|
|
160
|
+
* A mission rule fired: its id. For a pack of the game's that does what the rules cannot
|
|
161
|
+
*
|
|
162
|
+
* @beta
|
|
163
|
+
*/
|
|
164
|
+
var ruleFired = defineEvent("core.ruleFired");
|
|
165
|
+
var ACTIONS = [
|
|
166
|
+
"objective",
|
|
167
|
+
"say",
|
|
168
|
+
"cinematic",
|
|
169
|
+
"spawn",
|
|
170
|
+
"tell",
|
|
171
|
+
"relation",
|
|
172
|
+
"timer",
|
|
173
|
+
"win",
|
|
174
|
+
"lose"
|
|
175
|
+
];
|
|
176
|
+
/** The form of an action, by its one key: none for data that is no action */
|
|
177
|
+
var actionKind = (action) => {
|
|
178
|
+
if (typeof action !== "object" || action === null) return void 0;
|
|
179
|
+
const keys = Object.keys(action);
|
|
180
|
+
return keys.length === 1 && ACTIONS.includes(keys[0]) ? keys[0] : void 0;
|
|
181
|
+
};
|
|
182
|
+
/** Whether data is a rule's condition: an object of one form */
|
|
183
|
+
var isCondition = (when) => typeof when === "object" && when !== null && Object.keys(when).length > 0;
|
|
184
|
+
/**
|
|
185
|
+
* The rules a map keeps (`GameMap.data.rules`), in their order: none for a map with none. What is kept there and is no
|
|
186
|
+
* 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
|
|
187
|
+
* say so (`checkMissionRules`). Actions that are of no form the pack knows are left out of a rule the same way
|
|
188
|
+
*
|
|
189
|
+
* @beta
|
|
190
|
+
*/
|
|
191
|
+
function missionRulesOf(map) {
|
|
192
|
+
const kept = map.data[MAP_RULES_KEY];
|
|
193
|
+
if (!Array.isArray(kept)) return [];
|
|
194
|
+
return kept.filter((each) => typeof each === "object" && each !== null && typeof each.id === "string" && each.id !== "" && isCondition(each.when)).map((each) => ({
|
|
195
|
+
id: each.id,
|
|
196
|
+
when: each.when,
|
|
197
|
+
do: Array.isArray(each.do) ? each.do.filter((action) => actionKind(action) !== void 0) : [],
|
|
198
|
+
...each.once !== void 0 && { once: each.once === true },
|
|
199
|
+
...typeof each.every === "number" && each.every > 0 && { every: each.every },
|
|
200
|
+
...typeof each.as === "number" && { as: each.as }
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Tells the mission rules a word, as the game's code does for what the rules cannot know on their own (the boss fell,
|
|
205
|
+
* the player chose): a rule `when: { told: word }` fires at the next check, and the word is heard no more after it.
|
|
206
|
+
* What a rule's timer does as it goes off
|
|
207
|
+
*
|
|
208
|
+
* @beta
|
|
209
|
+
*/
|
|
210
|
+
function tellRules(world, word, data) {
|
|
211
|
+
world.state(missionRulesState).told.push({
|
|
212
|
+
word,
|
|
213
|
+
...data !== void 0 && { data },
|
|
214
|
+
tick: world.tick
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* What a mission rule is now (`MissionRuleState`): none for a rule the world has not, or has not checked yet
|
|
219
|
+
*
|
|
220
|
+
* @beta
|
|
221
|
+
*/
|
|
222
|
+
function missionRuleState(world, id) {
|
|
223
|
+
if (!world.states.has(missionRulesState)) return void 0;
|
|
224
|
+
const kept = world.state(missionRulesState).rules[id];
|
|
225
|
+
return kept && {
|
|
226
|
+
holds: !!kept.was,
|
|
227
|
+
count: kept.count,
|
|
228
|
+
...kept.fired !== void 0 && { fired: kept.fired }
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/** The names of the regions a condition asks about, wherever it is in it */
|
|
232
|
+
function regionsNamed(when, out = []) {
|
|
233
|
+
if (typeof when !== "object" || when === null) return out;
|
|
234
|
+
const condition = when;
|
|
235
|
+
if ("region" in condition && typeof condition.region?.name === "string") out.push(condition.region.name);
|
|
236
|
+
for (const key of ["all", "any"]) if (Array.isArray(condition[key])) for (const each of condition[key]) regionsNamed(each, out);
|
|
237
|
+
if ("not" in condition) regionsNamed(condition.not, out);
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* What is wrong with a map's rules (`GameMap.data.rules`): one with no id or with another's, one with no condition, an
|
|
242
|
+
* action of no form the pack knows, a condition or an action naming what the map or the game has not (a region, an
|
|
243
|
+
* objective, a prefab, a player). Each a click away in the Rules panel
|
|
244
|
+
*
|
|
245
|
+
* @beta
|
|
246
|
+
*/
|
|
247
|
+
function checkMissionRules(map, registry) {
|
|
248
|
+
const kept = map.data[MAP_RULES_KEY];
|
|
249
|
+
if (kept === void 0) return [];
|
|
250
|
+
if (!Array.isArray(kept)) return [{
|
|
251
|
+
message: "The map’s rules are not a list",
|
|
252
|
+
error: true,
|
|
253
|
+
rule: "rules"
|
|
254
|
+
}];
|
|
255
|
+
const problems = [];
|
|
256
|
+
const seen = /* @__PURE__ */ new Set();
|
|
257
|
+
const regions = new Set(map.regions.map((region) => region.name));
|
|
258
|
+
const objectives = new Set(mapObjectivesOf(map).map((objective) => objective.id));
|
|
259
|
+
const players = new Set(map.players.map((player) => player.id));
|
|
260
|
+
kept.forEach((each, index) => {
|
|
261
|
+
const id = typeof each?.id === "string" ? each.id : "";
|
|
262
|
+
const name = id || String(index + 1);
|
|
263
|
+
const reveal = {
|
|
264
|
+
panel: "rules",
|
|
265
|
+
entry: id || String(index)
|
|
266
|
+
};
|
|
267
|
+
const problem = (message, rule, error = true) => problems.push({
|
|
268
|
+
message,
|
|
269
|
+
error,
|
|
270
|
+
rule,
|
|
271
|
+
reveal
|
|
272
|
+
});
|
|
273
|
+
if (!id) problem(`Rule ${index + 1} has no id`, "rule-id");
|
|
274
|
+
else if (seen.has(id)) problem(`Two rules have the id "${id}"`, "rule-id");
|
|
275
|
+
seen.add(id);
|
|
276
|
+
if (!isCondition(each?.when)) problem(`The rule "${name}" has no condition`, "rule-when");
|
|
277
|
+
else for (const region of regionsNamed(each.when)) if (!regions.has(region)) problem(`The rule "${name}" asks about a region "${region}" the map has not`, "rule-name");
|
|
278
|
+
if (each?.as !== void 0 && !players.has(each.as)) problem(`The rule "${name}" is asked as a player ${each.as} the map has not`, "rule-name");
|
|
279
|
+
const actions = Array.isArray(each?.do) ? each.do : [];
|
|
280
|
+
if (!actions.length) problem(`The rule "${name}" does nothing`, "rule-action", false);
|
|
281
|
+
for (const action of actions) {
|
|
282
|
+
const kind = actionKind(action);
|
|
283
|
+
if (!kind) {
|
|
284
|
+
problem(`The rule "${name}" has an action of no form the rules know (${Object.keys(action ?? {}).join(", ") || "nothing"})`, "rule-action");
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const data = action[kind];
|
|
288
|
+
const named = (player, what) => {
|
|
289
|
+
if (typeof player === "number" && !players.has(player)) problem(`The rule "${name}" ${what} a player ${player} the map has not`, "rule-name");
|
|
290
|
+
};
|
|
291
|
+
if (kind === "objective" && !objectives.has(String(data?.id ?? ""))) problem(`The rule "${name}" names an objective "${data?.id ?? ""}" the map has not`, "rule-name");
|
|
292
|
+
if (kind === "spawn" && registry && !registry.prefabs.has(String(data?.prefab ?? ""))) problem(`The rule "${name}" spawns a prefab "${data?.prefab ?? ""}" the game has not`, "rule-name");
|
|
293
|
+
if (kind === "spawn" && typeof data?.at === "string" && !placeNamed(map, data.at)) problem(`The rule "${name}" spawns at "${data.at}", which the map has not`, "rule-name");
|
|
294
|
+
if (kind === "spawn") named(data?.owner, "spawns for");
|
|
295
|
+
if (kind === "tell") named(data?.computer, "tells");
|
|
296
|
+
if (kind === "relation") {
|
|
297
|
+
named(data?.a, "sets");
|
|
298
|
+
named(data?.b, "sets");
|
|
299
|
+
}
|
|
300
|
+
if (typeof data === "object" && data !== null && Array.isArray(data.to)) for (const player of data.to) named(player, "is for");
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
return problems;
|
|
304
|
+
}
|
|
305
|
+
/** Whether a map has a place of this name: a point, a region, or something placed and named */
|
|
306
|
+
var placeNamed = (map, name) => map.points.some((point) => point.name === name) || map.regions.some((region) => region.name === name) || map.objects.some((object) => object.name === name);
|
|
307
|
+
/** Where a place is in the world: a point or a region of the map by name, a named thing, or the point given */
|
|
308
|
+
function placeOf(world, at) {
|
|
309
|
+
if (typeof at !== "string") return {
|
|
310
|
+
x: at.x,
|
|
311
|
+
z: at.z
|
|
312
|
+
};
|
|
313
|
+
const point = world.map.points.find((each) => each.name === at);
|
|
314
|
+
if (point) return {
|
|
315
|
+
x: point.x,
|
|
316
|
+
z: point.z
|
|
317
|
+
};
|
|
318
|
+
const region = world.map.regions.find((each) => each.name === at);
|
|
319
|
+
if (region) return {
|
|
320
|
+
x: region.shape.x,
|
|
321
|
+
z: region.shape.z
|
|
322
|
+
};
|
|
323
|
+
const named = world.named(at);
|
|
324
|
+
return named && {
|
|
325
|
+
x: named.pos.x,
|
|
326
|
+
z: named.pos.z
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* The players a rule's actions are for when they say none: the people, else everyone who can win or lose
|
|
331
|
+
*
|
|
332
|
+
* @internal
|
|
333
|
+
*/
|
|
334
|
+
function rulePlayers(world) {
|
|
335
|
+
const people = mapObjectivePlayers(world);
|
|
336
|
+
if (people.length) return people;
|
|
337
|
+
return [...world.players.values()].filter((player) => !player.neutral && !player.creeps).map((player) => player.id).sort((a, b) => a - b);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* The timer of a rule's `timer` action: as it goes off, the rules are told its id, and the screens stop counting it
|
|
341
|
+
*
|
|
342
|
+
* @internal
|
|
343
|
+
*/
|
|
344
|
+
var ruleTimer = defineTimer("core.missionRules.timer", (world, { word, to }, timer) => {
|
|
345
|
+
const state = world.state(missionRulesState);
|
|
346
|
+
if (state.timers[word] === timer.id) delete state.timers[word];
|
|
347
|
+
for (const player of to ?? []) world.timers.hide(player, timer.id);
|
|
348
|
+
tellRules(world, word);
|
|
349
|
+
});
|
|
350
|
+
/**
|
|
351
|
+
* Does one action of a rule, now
|
|
352
|
+
*
|
|
353
|
+
* @internal
|
|
354
|
+
*/
|
|
355
|
+
function doMissionAction(world, rule, action) {
|
|
356
|
+
const warn = (line) => world.log.warn("rules", `the rule "${rule.id}" ${line}`);
|
|
357
|
+
const people = rulePlayers(world);
|
|
358
|
+
if ("objective" in action) {
|
|
359
|
+
const { id, do: what = "give", to = people, reason } = action.objective;
|
|
360
|
+
if (what === "give") {
|
|
361
|
+
if (!mapObjectivesOf(world.map).some((objective) => objective.id === id)) return warn(`gives an objective "${id}" the map has not`);
|
|
362
|
+
giveMapObjective(world, id, { players: to });
|
|
363
|
+
} else for (const player of to) if (world.objectives.has(player, id)) what === "complete" ? world.objectives.complete(player, id) : world.objectives.fail(player, id, reason);
|
|
364
|
+
} else if ("say" in action) {
|
|
365
|
+
const { speaker, text, seconds, to = people } = action.say;
|
|
366
|
+
world.dialog.say(to, {
|
|
367
|
+
speaker,
|
|
368
|
+
text,
|
|
369
|
+
...seconds !== void 0 && { seconds }
|
|
370
|
+
});
|
|
371
|
+
} else if ("cinematic" in action) {
|
|
372
|
+
const { id, to, hold, skippable } = action.cinematic;
|
|
373
|
+
playCinematic(world, id, {
|
|
374
|
+
to: to ?? "everyone",
|
|
375
|
+
hold,
|
|
376
|
+
skippable
|
|
377
|
+
});
|
|
378
|
+
} else if ("spawn" in action) {
|
|
379
|
+
const { prefab, at, owner, facing } = action.spawn;
|
|
380
|
+
if (!world.registry.prefabs.has(prefab)) return warn(`spawns a prefab "${prefab}" the game has not`);
|
|
381
|
+
const place = placeOf(world, at);
|
|
382
|
+
if (!place) return warn(`spawns at "${String(at)}", which the map has not`);
|
|
383
|
+
world.spawnPrefab(prefab, {
|
|
384
|
+
at: place,
|
|
385
|
+
owner,
|
|
386
|
+
facing
|
|
387
|
+
});
|
|
388
|
+
} else if ("tell" in action) {
|
|
389
|
+
const { computer, word, data } = action.tell;
|
|
390
|
+
if (!world.computers.tell(computer, word, data)) warn(`tells player ${computer} "${word}", and the computer does not play them`);
|
|
391
|
+
} else if ("relation" in action) {
|
|
392
|
+
const { a, b, how } = action.relation;
|
|
393
|
+
world.sides.setRelation(a, b, how);
|
|
394
|
+
} else if ("timer" in action) {
|
|
395
|
+
const { id, seconds, label, to = people } = action.timer;
|
|
396
|
+
const state = world.state(missionRulesState);
|
|
397
|
+
if (state.timers[id] !== void 0) world.timers.cancel(state.timers[id]);
|
|
398
|
+
const shown = label === void 0 ? [] : to;
|
|
399
|
+
const timer = world.timers.after(seconds, ruleTimer, {
|
|
400
|
+
word: id,
|
|
401
|
+
...shown.length && { to: shown }
|
|
402
|
+
});
|
|
403
|
+
state.timers[id] = timer;
|
|
404
|
+
for (const player of shown) world.timers.show(player, timer, { label });
|
|
405
|
+
} else if ("win" in action) {
|
|
406
|
+
const to = action.win === true ? people : action.win.to ?? people;
|
|
407
|
+
if (world.winner !== null || !to.length) return;
|
|
408
|
+
const team = world.player(to[0]).team;
|
|
409
|
+
world.winner = team;
|
|
410
|
+
world.events.emit(gameOver, { winner: team });
|
|
411
|
+
} else if ("lose" in action) {
|
|
412
|
+
const to = action.lose === true ? people : action.lose.to ?? people;
|
|
413
|
+
for (const player of to) if (!world.player(player).defeated) defeat(world, player);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* The system that runs the rules: once a second, each watcher reads the picture, the words told since the last check
|
|
418
|
+
* are heard, and each rule's condition is asked and its actions done as it turns true. The watchers' memory is the
|
|
419
|
+
* system's to save
|
|
420
|
+
*/
|
|
421
|
+
function rulesSystem(world, own, watch) {
|
|
422
|
+
let read;
|
|
423
|
+
const rulesOf = () => {
|
|
424
|
+
if (read) return read;
|
|
425
|
+
read = [];
|
|
426
|
+
const ids = /* @__PURE__ */ new Set();
|
|
427
|
+
for (const rule of [...missionRulesOf(world.map), ...own]) {
|
|
428
|
+
if (ids.has(rule.id)) {
|
|
429
|
+
world.log.warn("rules", `two rules are called "${rule.id}": the second is left out`);
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
ids.add(rule.id);
|
|
433
|
+
read.push(rule);
|
|
434
|
+
}
|
|
435
|
+
return read;
|
|
436
|
+
};
|
|
437
|
+
const watchers = /* @__PURE__ */ new Map();
|
|
438
|
+
let restored;
|
|
439
|
+
const defaultPlayer = () => rulePlayers(world)[0];
|
|
440
|
+
const watcher = (player) => {
|
|
441
|
+
let made = watchers.get(player);
|
|
442
|
+
if (made) return made;
|
|
443
|
+
if (!world.players.has(player)) return void 0;
|
|
444
|
+
made = watch(world, player);
|
|
445
|
+
const memory = restored?.[player];
|
|
446
|
+
if (memory !== void 0) made.restore(memory);
|
|
447
|
+
watchers.set(player, made);
|
|
448
|
+
return made;
|
|
449
|
+
};
|
|
450
|
+
return {
|
|
451
|
+
name: "missionRules",
|
|
452
|
+
phase: "cleanup",
|
|
453
|
+
every: Math.max(1, Math.round(world.tickRate)),
|
|
454
|
+
offset: 3,
|
|
455
|
+
update() {
|
|
456
|
+
const rules = rulesOf();
|
|
457
|
+
if (!rules.length) return;
|
|
458
|
+
const state = world.state(missionRulesState);
|
|
459
|
+
const told = state.told.splice(0);
|
|
460
|
+
const asked = /* @__PURE__ */ new Set();
|
|
461
|
+
for (const rule of rules) {
|
|
462
|
+
const player = rule.as ?? defaultPlayer();
|
|
463
|
+
if (player !== void 0) asked.add(player);
|
|
464
|
+
}
|
|
465
|
+
for (const player of asked) {
|
|
466
|
+
const made = watcher(player);
|
|
467
|
+
if (!made) continue;
|
|
468
|
+
made.think();
|
|
469
|
+
for (const word of told) made.tell(word.word, word.data, word.tick);
|
|
470
|
+
}
|
|
471
|
+
for (const rule of rules) {
|
|
472
|
+
const kept = state.rules[rule.id] ??= { count: 0 };
|
|
473
|
+
if (rule.once && kept.count > 0) continue;
|
|
474
|
+
const player = rule.as ?? defaultPlayer();
|
|
475
|
+
const made = player === void 0 ? void 0 : watcher(player);
|
|
476
|
+
if (!made) {
|
|
477
|
+
if (kept.was === void 0) world.log.warn("rules", `the rule "${rule.id}" is asked as a player ${player} the world has not: it never fires`);
|
|
478
|
+
kept.was = false;
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
const holds = made.ask(rule.when);
|
|
482
|
+
const turned = holds && !kept.was;
|
|
483
|
+
kept.was = holds;
|
|
484
|
+
if (!holds) continue;
|
|
485
|
+
const again = rule.every !== void 0 && kept.fired !== void 0 && world.tick - kept.fired >= Math.round(rule.every * world.tickRate);
|
|
486
|
+
if (!turned && !again) continue;
|
|
487
|
+
kept.fired = world.tick;
|
|
488
|
+
kept.count++;
|
|
489
|
+
world.log.info("rules", `the rule "${rule.id}" fires`);
|
|
490
|
+
world.events.emit(ruleFired, { rule: rule.id });
|
|
491
|
+
for (const action of rule.do) doMissionAction(world, rule, action);
|
|
492
|
+
}
|
|
493
|
+
for (const made of watchers.values()) for (const word of new Set(told.map((each) => each.word))) made.takeTold(word);
|
|
494
|
+
},
|
|
495
|
+
save: () => ({ watchers: Object.fromEntries([...watchers].map(([player, made]) => [player, made.save()])) }),
|
|
496
|
+
restore: (_world, data) => {
|
|
497
|
+
restored = data?.watchers;
|
|
498
|
+
for (const [player, made] of watchers) if (restored?.[player] !== void 0) made.restore(restored[player]);
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* The mission rules pack, given what asks a rule's condition (`RulesWatcher`): what `missionRules` of `@v12-engine/engine/ai`
|
|
504
|
+
* makes, with a watcher of the computer players' kit. The map's rules and `rules` of the code's, run as the game plays
|
|
505
|
+
*
|
|
506
|
+
* @internal
|
|
507
|
+
*/
|
|
508
|
+
function missionRulesPack(options) {
|
|
509
|
+
const own = options.rules ?? [];
|
|
510
|
+
return {
|
|
511
|
+
id: MISSION_RULES,
|
|
512
|
+
components: [missionRulesState],
|
|
513
|
+
events: [ruleFired],
|
|
514
|
+
timers: [ruleTimer],
|
|
515
|
+
systems: [(world) => rulesSystem(world, own, options.watch)],
|
|
516
|
+
check: (map, registry) => checkMissionRules(map, registry),
|
|
517
|
+
...own.length && { options: { rules: own.map((rule) => rule.id) } }
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
//#endregion
|
|
521
|
+
export { missionRulesOf as a, tellRules as c, checkMapObjectives as d, giveMapObjective as f, mapObjectivesOf as h, missionRuleState as i, MAP_OBJECTIVES as l, mapObjectives as m, MISSION_RULES as n, missionRulesPack as o, mapObjectivePlayers as p, checkMissionRules as r, ruleFired as s, MAP_RULES_KEY as t, MAP_OBJECTIVES_KEY as u };
|
|
522
|
+
|
|
523
|
+
//# sourceMappingURL=missionRules-C-bGxm0Q.js.map
|