@v12-engine/create 0.1.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/base/_gitignore +5 -0
- package/base/package.json +3 -3
- package/base/src/main.ts +36 -10
- package/base/src/navigation.worker.ts +7 -0
- package/base/vite.config.ts +24 -2
- package/cli.mjs +21 -6
- package/index.mjs +27 -7
- package/layers/desktop/electron/app.mjs +237 -0
- package/layers/desktop/electron/config.mjs +16 -0
- package/layers/desktop/electron/dev.mjs +63 -0
- package/layers/desktop/electron/files.mjs +86 -0
- package/layers/desktop/electron/icons/icon.icns +0 -0
- package/layers/desktop/electron/icons/icon.png +0 -0
- package/layers/desktop/electron/main.mjs +12 -0
- package/layers/desktop/electron/package.mjs +75 -0
- package/layers/desktop/electron/preload.cjs +41 -0
- package/layers/desktop/electron/presentation.m +87 -0
- package/layers/desktop/electron/serve.mjs +76 -0
- package/layers/desktop/electron/tools.mjs +63 -0
- package/layers/desktop/electron/updates.mjs +71 -0
- package/layers/desktop/package.json +13 -0
- package/layers/desktop/src/desktop.ts +175 -0
- package/layers/desktop/src/shell.ts +279 -0
- package/layers/desktop/tests/main.test.ts +189 -0
- package/layers/desktop/tests/shell.test.ts +152 -0
- package/layers/rooms/server.ts +13 -10
- package/layers/server/server.ts +4 -5
- package/layers/source/vite.config.ts +21 -1
- package/package.json +1 -1
- package/starters/campaign/README.md +9 -2
- package/starters/campaign/layers/rooms/server.ts +3 -3
- package/starters/campaign/layers/server/server.ts +3 -5
- package/starters/campaign/layers/tests/tests/rules.test.ts +40 -21
- package/starters/campaign/src/campaign/game.ts +26 -5
- package/starters/campaign/src/campaign/index.ts +104 -68
- package/starters/campaign/src/campaign/kills.ts +1 -1
- package/starters/campaign/src/campaign/missions/homecoming.ts +7 -7
- package/starters/campaign/src/campaign/missions/siege.ts +6 -6
- package/starters/campaign/src/campaign/missions/warlord.ts +13 -14
- package/starters/campaign/src/campaign/scenes.ts +8 -7
- package/starters/campaign/src/campaign/units.ts +59 -20
- package/starters/campaign/src/campaign/view/attacks.ts +19 -0
- package/starters/campaign/src/campaign/view/fire.ts +2 -2
- package/starters/campaign/src/campaign/view/index.ts +54 -43
- package/starters/campaign/src/campaign/waves.ts +18 -17
- package/starters/campaign/src/game.ts +8 -1
- package/starters/campaign/src/main.ts +38 -19
- package/starters/campaign/src/maps/fort.names.ts +2 -2
- package/starters/campaign/src/maps/fort.vgmap.json +102 -2
- package/starters/campaign/src/maps/homestead.names.ts +2 -2
- package/starters/campaign/src/maps/homestead.vgmap.json +85 -1
- package/starters/campaign/src/maps/pass.names.ts +2 -2
- package/starters/campaign/src/maps/pass.vgmap.json +69 -1
- package/starters/campaign/src/waves-panel.ts +2 -1
- package/starters/empty/README.md +18 -10
- package/starters/empty/layers/tests/tests/rules.test.ts +16 -17
- package/starters/empty/src/game.ts +11 -75
- package/starters/empty/src/generate.worker.ts +5 -5
- package/starters/empty/src/rules.ts +83 -25
- package/starters/empty/src/view.ts +82 -0
- package/starters/examples/README.md +83 -0
- package/starters/examples/layers/tests/tests/examples.test.ts +30 -0
- package/starters/examples/package.json +5 -0
- package/starters/examples/src/examples/abilities/areas.ts +165 -0
- package/starters/examples/src/examples/abilities/areasLooks.ts +30 -0
- package/starters/examples/src/examples/abilities/buffs.ts +287 -0
- package/starters/examples/src/examples/abilities/buffsLooks.ts +46 -0
- package/starters/examples/src/examples/abilities/changing.ts +228 -0
- package/starters/examples/src/examples/abilities/changingLooks.ts +61 -0
- package/starters/examples/src/examples/abilities/control.ts +158 -0
- package/starters/examples/src/examples/abilities/controlLooks.ts +78 -0
- package/starters/examples/src/examples/abilities/damage.ts +156 -0
- package/starters/examples/src/examples/abilities/damageLooks.ts +37 -0
- package/starters/examples/src/examples/abilities/family.ts +29 -0
- package/starters/examples/src/examples/abilities/index.ts +32 -0
- package/starters/examples/src/examples/abilities/kit.ts +179 -0
- package/starters/examples/src/examples/abilities/lookKit.ts +71 -0
- package/starters/examples/src/examples/abilities/looks.ts +47 -0
- package/starters/examples/src/examples/abilities/missiles.ts +203 -0
- package/starters/examples/src/examples/abilities/missilesLooks.ts +38 -0
- package/starters/examples/src/examples/abilities/moves.ts +206 -0
- package/starters/examples/src/examples/abilities/movesLooks.ts +52 -0
- package/starters/examples/src/examples/abilities/recasts.ts +181 -0
- package/starters/examples/src/examples/abilities/recastsLooks.ts +41 -0
- package/starters/examples/src/examples/abilities/resources.ts +166 -0
- package/starters/examples/src/examples/abilities/resourcesLooks.ts +42 -0
- package/starters/examples/src/examples/abilities/summons.ts +296 -0
- package/starters/examples/src/examples/abilities/summonsLooks.ts +115 -0
- package/starters/examples/src/examples/abilities/triggers.ts +204 -0
- package/starters/examples/src/examples/abilities/triggersLooks.ts +53 -0
- package/starters/examples/src/examples/abilities/vision.ts +137 -0
- package/starters/examples/src/examples/abilities/visionLooks.ts +50 -0
- package/starters/examples/src/examples/animation/index.ts +235 -0
- package/starters/examples/src/examples/animation/looks.ts +444 -0
- package/starters/examples/src/examples/catalog.ts +52 -0
- package/starters/examples/src/examples/cinematics/index.ts +217 -0
- package/starters/examples/src/examples/cinematics/looks.ts +476 -0
- package/starters/examples/src/examples/cinematics/tour.json +43 -0
- package/starters/examples/src/examples/cinematics/village.ts +88 -0
- package/starters/examples/src/examples/common/looks.ts +65 -0
- package/starters/examples/src/examples/common/units.ts +70 -0
- package/starters/examples/src/examples/construction/index.ts +329 -0
- package/starters/examples/src/examples/construction/looks.ts +275 -0
- package/starters/examples/src/examples/custom-animation/bones.ts +92 -0
- package/starters/examples/src/examples/custom-animation/index.ts +190 -0
- package/starters/examples/src/examples/custom-animation/looks.ts +523 -0
- package/starters/examples/src/examples/custom-animation/runes.ts +82 -0
- package/starters/examples/src/examples/custom-fx/glaive.look.ts +110 -0
- package/starters/examples/src/examples/custom-fx/glaive.ts +40 -0
- package/starters/examples/src/examples/custom-fx/gpu.look.ts +145 -0
- package/starters/examples/src/examples/custom-fx/gpu.ts +22 -0
- package/starters/examples/src/examples/custom-fx/index.ts +25 -0
- package/starters/examples/src/examples/custom-fx/lights.look.ts +144 -0
- package/starters/examples/src/examples/custom-fx/lights.ts +25 -0
- package/starters/examples/src/examples/custom-fx/looks.ts +36 -0
- package/starters/examples/src/examples/custom-fx/meteor.look.ts +133 -0
- package/starters/examples/src/examples/custom-fx/meteor.ts +26 -0
- package/starters/examples/src/examples/custom-fx/parts.look.ts +193 -0
- package/starters/examples/src/examples/custom-fx/parts.ts +21 -0
- package/starters/examples/src/examples/custom-fx/portal.look.ts +193 -0
- package/starters/examples/src/examples/custom-fx/portal.ts +48 -0
- package/starters/examples/src/examples/custom-fx/renderer.look.ts +139 -0
- package/starters/examples/src/examples/custom-fx/renderer.ts +18 -0
- package/starters/examples/src/examples/custom-fx/ribbons.look.ts +151 -0
- package/starters/examples/src/examples/custom-fx/ribbons.ts +22 -0
- package/starters/examples/src/examples/custom-fx/shader.ts +42 -0
- package/starters/examples/src/examples/custom-fx/shield.look.ts +226 -0
- package/starters/examples/src/examples/custom-fx/shield.ts +43 -0
- package/starters/examples/src/examples/define.ts +86 -0
- package/starters/examples/src/examples/destruction/index.ts +570 -0
- package/starters/examples/src/examples/destruction/looks.ts +447 -0
- package/starters/examples/src/examples/dialogs/index.ts +383 -0
- package/starters/examples/src/examples/dialogs/looks.ts +546 -0
- package/starters/examples/src/examples/dynamic-map/index.ts +603 -0
- package/starters/examples/src/examples/dynamic-map/looks.ts +301 -0
- package/starters/examples/src/examples/fx/blood.look.ts +62 -0
- package/starters/examples/src/examples/fx/blood.ts +59 -0
- package/starters/examples/src/examples/fx/feel.look.ts +86 -0
- package/starters/examples/src/examples/fx/feel.ts +57 -0
- package/starters/examples/src/examples/fx/fight.ts +28 -0
- package/starters/examples/src/examples/fx/floats.look.ts +108 -0
- package/starters/examples/src/examples/fx/floats.ts +24 -0
- package/starters/examples/src/examples/fx/gallery.look.ts +168 -0
- package/starters/examples/src/examples/fx/gallery.ts +23 -0
- package/starters/examples/src/examples/fx/index.ts +30 -0
- package/starters/examples/src/examples/fx/links.look.ts +83 -0
- package/starters/examples/src/examples/fx/links.ts +49 -0
- package/starters/examples/src/examples/fx/looks.ts +55 -0
- package/starters/examples/src/examples/fx/map.look.ts +93 -0
- package/starters/examples/src/examples/fx/map.ts +33 -0
- package/starters/examples/src/examples/fx/marks.look.ts +100 -0
- package/starters/examples/src/examples/fx/marks.ts +36 -0
- package/starters/examples/src/examples/fx/shots.look.ts +92 -0
- package/starters/examples/src/examples/fx/shots.ts +71 -0
- package/starters/examples/src/examples/fx/spells.look.ts +87 -0
- package/starters/examples/src/examples/fx/spells.ts +122 -0
- package/starters/examples/src/examples/fx/stage.ts +31 -0
- package/starters/examples/src/examples/gui/babylonScreen.ts +167 -0
- package/starters/examples/src/examples/gui/babylonWorld.ts +191 -0
- package/starters/examples/src/examples/gui/htmlPart.ts +95 -0
- package/starters/examples/src/examples/gui/index.ts +143 -0
- package/starters/examples/src/examples/gui/keys.ts +91 -0
- package/starters/examples/src/examples/gui/layout.ts +42 -0
- package/starters/examples/src/examples/gui/looks.ts +270 -0
- package/starters/examples/src/examples/gui/minimap.ts +127 -0
- package/starters/examples/src/examples/gui/ownInterface.ts +129 -0
- package/starters/examples/src/examples/gui/plates.ts +87 -0
- package/starters/examples/src/examples/gui/radial.ts +104 -0
- package/starters/examples/src/examples/gui/solidPart.ts +107 -0
- package/starters/examples/src/examples/looks.ts +45 -0
- package/starters/examples/src/examples/mechanics/battle.ts +51 -0
- package/starters/examples/src/examples/mechanics/damage.ts +80 -0
- package/starters/examples/src/examples/mechanics/flying.ts +93 -0
- package/starters/examples/src/examples/mechanics/formations.ts +58 -0
- package/starters/examples/src/examples/mechanics/highGround.ts +82 -0
- package/starters/examples/src/examples/mechanics/index.ts +44 -0
- package/starters/examples/src/examples/mechanics/looks.ts +289 -0
- package/starters/examples/src/examples/mechanics/maze.ts +119 -0
- package/starters/examples/src/examples/mechanics/orders.ts +68 -0
- package/starters/examples/src/examples/mechanics/selection.ts +30 -0
- package/starters/examples/src/examples/moba/index.ts +377 -0
- package/starters/examples/src/examples/moba/looks.ts +349 -0
- package/starters/examples/src/examples/moba/maps.ts +69 -0
- package/starters/examples/src/examples/moba/spells.ts +34 -0
- package/starters/examples/src/examples/moba/units.ts +196 -0
- package/starters/examples/src/examples/nature/camera.ts +15 -0
- package/starters/examples/src/examples/nature/grass.ts +64 -0
- package/starters/examples/src/examples/nature/index.ts +327 -0
- package/starters/examples/src/examples/nature/land.ts +173 -0
- package/starters/examples/src/examples/nature/looks.ts +577 -0
- package/starters/examples/src/examples/nature/maps.ts +370 -0
- package/starters/examples/src/examples/nature/skies.ts +324 -0
- package/starters/examples/src/examples/nature/weather.ts +80 -0
- package/starters/examples/src/examples/performance/index.ts +263 -0
- package/starters/examples/src/examples/performance/looks.ts +372 -0
- package/starters/examples/src/examples/performance/meter.ts +158 -0
- package/starters/examples/src/examples/post/grades.ts +86 -0
- package/starters/examples/src/examples/post/index.ts +202 -0
- package/starters/examples/src/examples/post/looks.ts +884 -0
- package/starters/examples/src/examples/post/passes.ts +213 -0
- package/starters/examples/src/examples/rts/ai.ts +49 -0
- package/starters/examples/src/examples/rts/airlift.ts +43 -0
- package/starters/examples/src/examples/rts/base.ts +129 -0
- package/starters/examples/src/examples/rts/build.ts +65 -0
- package/starters/examples/src/examples/rts/camps.ts +36 -0
- package/starters/examples/src/examples/rts/carry.ts +103 -0
- package/starters/examples/src/examples/rts/creeps.ts +61 -0
- package/starters/examples/src/examples/rts/data.ts +406 -0
- package/starters/examples/src/examples/rts/ferry.ts +41 -0
- package/starters/examples/src/examples/rts/garrison.ts +50 -0
- package/starters/examples/src/examples/rts/harvest.ts +29 -0
- package/starters/examples/src/examples/rts/hero.ts +67 -0
- package/starters/examples/src/examples/rts/index.ts +77 -0
- package/starters/examples/src/examples/rts/looks.ts +721 -0
- package/starters/examples/src/examples/rts/shop.ts +46 -0
- package/starters/examples/src/examples/rts/tech.ts +39 -0
- package/starters/examples/src/examples/rts/train.ts +48 -0
- package/starters/examples/src/examples/rts/waterside.ts +185 -0
- package/starters/examples/src/examples/showcase/index.ts +714 -0
- package/starters/examples/src/examples/showcase/looks.ts +238 -0
- package/starters/examples/src/game.ts +17 -0
- package/starters/examples/src/main.ts +82 -0
- package/starters/examples/src/rules.ts +31 -0
- package/starters/examples/src/shell/look.ts +79 -0
- package/starters/examples/src/shell/registry.ts +7 -0
- package/starters/examples/src/shell/scenes.ts +178 -0
- package/starters/examples/src/shell/shell.ts +290 -0
- package/starters/examples/src/shell/style.ts +202 -0
- package/starters/examples/src/view.ts +50 -0
- package/starters/melee/README.md +12 -3
- package/starters/melee/layers/tests/tests/heroes.test.ts +402 -0
- package/starters/melee/layers/tests/tests/rules.test.ts +10 -8
- package/starters/melee/src/game.ts +32 -2
- package/starters/melee/src/maps/bay.names.ts +2 -2
- package/starters/melee/src/maps/bay.vgmap.json +198 -1
- package/starters/melee/src/maps.ts +11 -9
- package/starters/melee/src/melee/abilities.ts +1 -194
- package/starters/melee/src/melee/blight.ts +7 -7
- package/starters/melee/src/melee/cellLayers.json +3 -3
- package/starters/melee/src/melee/data.json +1 -18
- package/starters/melee/src/melee/game.ts +6 -4
- package/starters/melee/src/melee/heroes.ts +1025 -0
- package/starters/melee/src/melee/index.ts +64 -61
- package/starters/melee/src/melee/items.ts +15 -362
- package/starters/melee/src/melee/languages/he.json +14 -2
- package/starters/melee/src/melee/pings.ts +5 -6
- package/starters/melee/src/melee/saves.ts +1 -1
- package/starters/melee/src/melee/undead.ts +15 -230
- package/starters/melee/src/melee/units.ts +37 -171
- package/starters/melee/src/melee/view/attacks.ts +19 -0
- package/starters/melee/src/melee/view/heroSpellLooks.ts +39 -8
- package/starters/melee/src/melee/view/index.ts +56 -52
- package/starters/melee/src/melee/view/looks.ts +86 -63
- package/starters/melee/src/melee/view/undeadLooks.ts +70 -31
- package/starters/melee/src/melee/view/walls.ts +1 -1
- package/starters.mjs +6 -0
- package/v12.mjs +14 -15
- package/starters/campaign/src/rules.ts +0 -20
- package/starters/empty/src/maps.ts +0 -44
- package/starters/empty/src/tiles.ts +0 -12
- package/starters/melee/src/melee/heroSpells.ts +0 -38
- package/starters/melee/src/rules.ts +0 -24
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cinematics.tour",
|
|
3
|
+
"name": "A tour of Elmbrook",
|
|
4
|
+
"length": 18,
|
|
5
|
+
"lanes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "camera",
|
|
8
|
+
"kind": "camera",
|
|
9
|
+
"items": [
|
|
10
|
+
{ "at": 0, "value": { "x": 24, "z": 6, "distance": 40, "yaw": 0, "pitch": 0.8 } },
|
|
11
|
+
{ "at": 6, "value": { "x": 24, "z": 22, "distance": 20, "yaw": 0.6, "pitch": 0.5 }, "path": "smooth", "ease": "inOutCubic" },
|
|
12
|
+
{ "at": 12, "value": { "x": 24, "z": 30, "distance": 18, "yaw": 2.8, "pitch": 0.45 }, "path": "smooth", "ease": "inOutSine" },
|
|
13
|
+
{ "at": 16, "value": { "x": 24, "z": 26, "distance": 42, "yaw": 3.6, "pitch": 0.9 }, "ease": "inOutSine" }
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "screen",
|
|
18
|
+
"kind": "screen",
|
|
19
|
+
"items": [
|
|
20
|
+
{ "at": 0, "for": 18, "letterbox": 2.39, "vignette": 0.3, "in": 0.6, "out": 0.8 },
|
|
21
|
+
{ "at": 0, "for": 1.5, "fade": 1, "in": 0, "out": 1.5 }
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "ui",
|
|
26
|
+
"kind": "ui",
|
|
27
|
+
"items": [{ "at": 0.5, "for": 4, "ui": "title", "title": "Elmbrook", "subtitle": "made in a file", "in": 0.6, "out": 0.8 }]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "dialog",
|
|
31
|
+
"kind": "dialog",
|
|
32
|
+
"items": [
|
|
33
|
+
{ "at": 1.5, "for": 4.5, "speaker": "cinematics.narrator", "text": "In the north there is a village where the road ends." },
|
|
34
|
+
{ "at": 7.5, "for": 4.5, "speaker": "cinematics.narrator", "text": "Its people keep the fire lit, and the bell rung." }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"markers": [
|
|
39
|
+
{ "at": 0, "name": "road", "kind": "section" },
|
|
40
|
+
{ "at": 6, "name": "square", "kind": "section" },
|
|
41
|
+
{ "at": 12, "name": "bell", "kind": "section" }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A village to stage scenes in: a field with houses round a bonfire, a well, a market, carts and hay, a dirt road in
|
|
3
|
+
* from the south and woods round the edge. Scenery only (`MapDoodad`): the rules never see it. The cinematics and the
|
|
4
|
+
* dialogue examples play here, each with its own name for the map (`world.map.name`), which their rules check to know
|
|
5
|
+
* the example is theirs
|
|
6
|
+
*/
|
|
7
|
+
import { exactMath, type GameMap, type MapDoodad } from '@v12-engine/engine'
|
|
8
|
+
import { exampleField } from '../define'
|
|
9
|
+
|
|
10
|
+
/** The middle of the village: the bonfire */
|
|
11
|
+
export const SQUARE = { x: 24, z: 26 }
|
|
12
|
+
/** Where the road comes in, at the south edge */
|
|
13
|
+
export const ROAD_END = { x: 24, z: 4 }
|
|
14
|
+
|
|
15
|
+
/** A few houses, the well, the market and what lies about, round the square: [model, x, z, facing] */
|
|
16
|
+
const BUILDINGS: [string, number, number, number][] = [
|
|
17
|
+
['village/bonfire.glb', SQUARE.x, SQUARE.z, 0],
|
|
18
|
+
['village/fantasy_house.glb', 15, 33, 2.4],
|
|
19
|
+
['village/fantasy_house_2.glb', 33, 34, -2.4],
|
|
20
|
+
['village/fantasy_inn.glb', 14, 21, 1.6],
|
|
21
|
+
['village/fantasy_house_3.glb', 34, 20, -1.6],
|
|
22
|
+
['village/well.glb', 29.5, 28.5, 0],
|
|
23
|
+
['village/market_stand.glb', 19.5, 27, 1.2],
|
|
24
|
+
['village/cart.glb', 28.5, 22, 0.4],
|
|
25
|
+
['village/hay.glb', 31, 25.5, 0],
|
|
26
|
+
['village/barrel.glb', 20, 31, 0],
|
|
27
|
+
['village/crate.glb', 21, 30.2, 0.5],
|
|
28
|
+
['village/bench.glb', 25.5, 29.5, 0],
|
|
29
|
+
['village/fence.glb', 21, 14, 0],
|
|
30
|
+
['village/fence.glb', 27, 14, 0],
|
|
31
|
+
['village/bell_tower.glb', 24, 40, Math.PI],
|
|
32
|
+
// the old stones north of the fire, in a ring
|
|
33
|
+
...[0, 1, 2, 3, 4, 5].map((i): [string, number, number, number] => [
|
|
34
|
+
'village/rocks.glb',
|
|
35
|
+
24 + exactMath.cos(i * 1.047) * 2.6,
|
|
36
|
+
33 + exactMath.sin(i * 1.047) * 2.6,
|
|
37
|
+
i * 1.3
|
|
38
|
+
])
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
/** The woods round the edge: trees in a ring, a little off from even, the same on every map made */
|
|
42
|
+
function woods(): MapDoodad[] {
|
|
43
|
+
const trees: MapDoodad[] = []
|
|
44
|
+
const models = ['trees/oak_1.glb', 'trees/oak_2.glb', 'trees/columnar_1.glb', 'trees/columnar_3.glb']
|
|
45
|
+
for (let i = 0; i < 44; i++) {
|
|
46
|
+
const angle = (i / 44) * Math.PI * 2
|
|
47
|
+
// a gap where the road comes in
|
|
48
|
+
if (Math.abs(angle - Math.PI * 1.5) < 0.22) continue
|
|
49
|
+
const away = 19 + ((i * 7) % 5)
|
|
50
|
+
const x = 24 + exactMath.cos(angle) * away
|
|
51
|
+
const z = 24 + exactMath.sin(angle) * away
|
|
52
|
+
const size = 0.9 + ((i * 13) % 7) / 14
|
|
53
|
+
trees.push({ id: 100 + i, model: models[i % models.length], x, z, yaw: i * 1.7, scale: [size, size, size] })
|
|
54
|
+
}
|
|
55
|
+
return trees
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The village, called `name` (what the example's rules know it by), with `players` players */
|
|
59
|
+
export function villageMap(name: string, players = 2): GameMap {
|
|
60
|
+
const map = exampleField({ name, players })
|
|
61
|
+
const dirt = map.tileset.indexOf('dirt') + 1
|
|
62
|
+
const darkGrass = map.tileset.indexOf('darkGrass') + 1
|
|
63
|
+
// the road in from the south, and the trodden square round the bonfire
|
|
64
|
+
for (let z = 0; z < map.depth; z++)
|
|
65
|
+
for (let x = 0; x < map.width; x++) {
|
|
66
|
+
const square = exactMath.hypot(x + 0.5 - SQUARE.x, z + 0.5 - SQUARE.z)
|
|
67
|
+
const road = Math.abs(x + 0.5 - 24) < 1.6 && z < SQUARE.z
|
|
68
|
+
if (square < 5.5 || road) map.tiles[z * map.width + x] = dirt
|
|
69
|
+
else if (square > 17) map.tiles[z * map.width + x] = darkGrass
|
|
70
|
+
}
|
|
71
|
+
map.doodads = [...BUILDINGS.map(([model, x, z, yaw], i): MapDoodad => ({ id: i + 1, model, x, z, yaw, scale: [1, 1, 1] })), ...woods()]
|
|
72
|
+
// the road as a line the cinematics can run the camera along (`cut.rail('road')`)
|
|
73
|
+
map.paths = [
|
|
74
|
+
{
|
|
75
|
+
id: 1,
|
|
76
|
+
name: 'road',
|
|
77
|
+
width: 3,
|
|
78
|
+
points: [
|
|
79
|
+
{ x: 24, z: 2 },
|
|
80
|
+
{ x: 24, z: 14 },
|
|
81
|
+
{ x: 20, z: 22 },
|
|
82
|
+
{ x: 24, z: 31 },
|
|
83
|
+
{ x: 30, z: 27 }
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
return map
|
|
88
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the shared units look (`./units.ts`): the shared art's adventurers with their clips and their gear in hand,
|
|
3
|
+
* drawn as their parts while the model loads. A category's own units' looks go in its `looks.ts`
|
|
4
|
+
*/
|
|
5
|
+
import type { AttackLook, ModelDef, UnitLook } from '@v12-engine/client'
|
|
6
|
+
|
|
7
|
+
/** A character of the shared art, `scale` times its size, with what it holds in its hands */
|
|
8
|
+
export const character = (name: string, scale: number, own: Partial<ModelDef> = {}): ModelDef => ({ src: `characters/${name}.glb`, scale, ...own })
|
|
9
|
+
/** A piece of the adventurers' gear in a hand: the right one when not said */
|
|
10
|
+
export const hold = (name: string, hand: 'l' | 'r' = 'r') => ({ src: `gear/${name}.glb`, at: `handslot.${hand}` })
|
|
11
|
+
|
|
12
|
+
const SKIN: [number, number, number] = [0.87, 0.68, 0.53]
|
|
13
|
+
|
|
14
|
+
/** A person, as parts: a body in a colour and a head */
|
|
15
|
+
export const person = (height: number, body: [number, number, number] | 'team' = 'team'): UnitLook['shapes'] => [
|
|
16
|
+
{ shape: 'cylinder', size: [0.5, height * 0.6, 0.5], offset: [0, height * 0.3, 0], color: body },
|
|
17
|
+
{ shape: 'sphere', size: [0.4, 0.4, 0.4], offset: [0, height * 0.75, 0], color: SKIN }
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
/** A one-handed weapon's swings, in turn at random, a big slice on a critical strike */
|
|
21
|
+
export const ONE_HANDED: AttackLook = {
|
|
22
|
+
clip: ['Melee_1H_Attack_Chop', 'Melee_1H_Attack_Slice_Diagonal', 'Melee_1H_Attack_Stab'],
|
|
23
|
+
order: 'random',
|
|
24
|
+
crit: 'Melee_2H_Attack_Slice'
|
|
25
|
+
}
|
|
26
|
+
/** A two-handed weapon's: a chop and a slice */
|
|
27
|
+
export const TWO_HANDED: AttackLook = { clip: ['Melee_2H_Attack_Chop', 'Melee_2H_Attack_Slice'], crit: 'Melee_2H_Attack_Chop' }
|
|
28
|
+
|
|
29
|
+
/** The shared units' looks, by id */
|
|
30
|
+
export const sharedLooks: Record<string, UnitLook> = {
|
|
31
|
+
footman: {
|
|
32
|
+
height: 1.8,
|
|
33
|
+
model: character('knight', 0.7, { hold: [hold('sword_1handed'), hold('shield_round', 'l')] }),
|
|
34
|
+
attacks: [ONE_HANDED],
|
|
35
|
+
shapes: person(1.8)
|
|
36
|
+
},
|
|
37
|
+
archer: {
|
|
38
|
+
height: 1.7,
|
|
39
|
+
model: character('ranger', 0.68, { hold: [hold('bow')], animations: { attack: 'Ranged_2H_Shoot' } }),
|
|
40
|
+
shot: { color: [0.85, 0.75, 0.55], size: 0.2 },
|
|
41
|
+
shapes: person(1.7)
|
|
42
|
+
},
|
|
43
|
+
mage: {
|
|
44
|
+
height: 1.8,
|
|
45
|
+
model: character('mage', 0.72, { hold: [hold('staff')] }),
|
|
46
|
+
shot: { color: [0.4, 0.6, 1], size: 0.3 },
|
|
47
|
+
shapes: person(1.8)
|
|
48
|
+
},
|
|
49
|
+
knight: {
|
|
50
|
+
height: 2.2,
|
|
51
|
+
model: character('knight', 0.9, { hold: [hold('sword_2handed')], animations: { attack: 'Melee_2H_Attack_Chop' } }),
|
|
52
|
+
attacks: [TWO_HANDED],
|
|
53
|
+
shapes: person(2.2)
|
|
54
|
+
},
|
|
55
|
+
dummy: {
|
|
56
|
+
height: 1.9,
|
|
57
|
+
// the shared art's training dummy, 1.86 high as it is; the parts below show until it has loaded
|
|
58
|
+
model: { src: 'props/dummy.glb', scale: 1 },
|
|
59
|
+
shapes: [
|
|
60
|
+
{ shape: 'cylinder', size: [0.15, 1.9, 0.15], offset: [0, 0.95, 0], color: [0.45, 0.31, 0.18] },
|
|
61
|
+
{ shape: 'cylinder', size: [0.7, 0.9, 0.7], offset: [0, 1.2, 0], color: [0.78, 0.68, 0.45] },
|
|
62
|
+
{ shape: 'sphere', size: [0.45, 0.45, 0.45], offset: [0, 1.85, 0], color: [0.78, 0.68, 0.45] }
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The units the examples share: a footman, an archer, a mage, a knight who is a hero, and a dummy to hit. Each is
|
|
3
|
+
* data (`UnitTypeDef`); how each looks is `./looks.ts`. A category with units of its own registers them in its
|
|
4
|
+
* `index.ts`, its ids starting with the category's (`fx.target`)
|
|
5
|
+
*/
|
|
6
|
+
import { defineIds, type Game, type IdOf, type UnitTypeDef } from '@v12-engine/engine'
|
|
7
|
+
|
|
8
|
+
/** The shared units' ids: `UNIT.footman` everywhere else */
|
|
9
|
+
export const UNIT = defineIds('footman', 'archer', 'mage', 'knight', 'dummy')
|
|
10
|
+
export type SharedUnit = IdOf<typeof UNIT>
|
|
11
|
+
|
|
12
|
+
/** The two sides an example sets against each other: the player, and the one it fights */
|
|
13
|
+
export const PLAYER = 1
|
|
14
|
+
export const ENEMY = 2
|
|
15
|
+
|
|
16
|
+
const units: UnitTypeDef[] = [
|
|
17
|
+
{
|
|
18
|
+
id: UNIT.footman,
|
|
19
|
+
name: 'Footman',
|
|
20
|
+
kind: 'unit',
|
|
21
|
+
radius: 0.45,
|
|
22
|
+
stats: { health: 420, attackDamage: 14, attackSpeed: 1.1, attackRange: 0.5, armor: 12, moveSpeed: 4 },
|
|
23
|
+
sight: 10,
|
|
24
|
+
attacks: [{ damagePoint: 0.45, acquisitionRange: 8 }]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: UNIT.archer,
|
|
28
|
+
name: 'Archer',
|
|
29
|
+
kind: 'unit',
|
|
30
|
+
radius: 0.42,
|
|
31
|
+
stats: { health: 260, attackDamage: 18, attackSpeed: 1, attackRange: 7, moveSpeed: 4.2 },
|
|
32
|
+
sight: 11,
|
|
33
|
+
attacks: [{ damagePoint: 0.5, acquisitionRange: 8, projectileSpeed: 26 }]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: UNIT.mage,
|
|
37
|
+
name: 'Mage',
|
|
38
|
+
kind: 'unit',
|
|
39
|
+
radius: 0.42,
|
|
40
|
+
stats: { health: 300, mana: 400, manaRegen: 4, attackDamage: 16, attackSpeed: 0.9, attackRange: 6, moveSpeed: 4 },
|
|
41
|
+
sight: 11,
|
|
42
|
+
attacks: [{ damagePoint: 0.5, acquisitionRange: 7, projectileSpeed: 18 }]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: UNIT.knight,
|
|
46
|
+
name: 'Knight',
|
|
47
|
+
kind: 'unit',
|
|
48
|
+
radius: 0.5,
|
|
49
|
+
stats: { health: 900, healthRegen: 2, mana: 500, manaRegen: 5, attackDamage: 42, attackSpeed: 0.8, attackRange: 0.6, armor: 30, moveSpeed: 4.4 },
|
|
50
|
+
sight: 12,
|
|
51
|
+
attacks: [{ damagePoint: 0.4, acquisitionRange: 8 }],
|
|
52
|
+
hero: { learns: [], growth: { stats: { health: 80, mana: 30, attackDamage: 3, armor: 3 } }, maxLevel: 10 },
|
|
53
|
+
inventory: 6,
|
|
54
|
+
level: 1
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
// stands where it is put and takes what it is given: what an effect or an ability is tried on
|
|
58
|
+
id: UNIT.dummy,
|
|
59
|
+
name: 'Training dummy',
|
|
60
|
+
kind: 'unit',
|
|
61
|
+
radius: 0.5,
|
|
62
|
+
stats: { health: 5000, healthRegen: 50, moveSpeed: 0 },
|
|
63
|
+
sight: 4
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
/** Registers the shared units on the game */
|
|
68
|
+
export function sharedUnits(game: Game<any>): void {
|
|
69
|
+
for (const unit of units) game.unit(unit)
|
|
70
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The construction examples on the rules' side: workers who build, buildings that go up as they work (`construction:
|
|
3
|
+
* 'builder'`), a speed for all of it, sites paused, called off and repaired, a hall upgraded where it stands, a town
|
|
4
|
+
* laid out and built. How each building looks as it rises (grows, rises, fades in, is revealed, stands in scaffolding)
|
|
5
|
+
* is its look's `construction` (`./looks.ts`)
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
cancelConstructionCommand,
|
|
9
|
+
defineCommand,
|
|
10
|
+
defineComponent,
|
|
11
|
+
defineTimer,
|
|
12
|
+
type Entity,
|
|
13
|
+
type Game,
|
|
14
|
+
number,
|
|
15
|
+
text,
|
|
16
|
+
underConstruction,
|
|
17
|
+
type UnitTypeDef,
|
|
18
|
+
upgradeBuildingCommand,
|
|
19
|
+
type Vec2,
|
|
20
|
+
type World
|
|
21
|
+
} from '@v12-engine/engine'
|
|
22
|
+
import { PLAYER } from '../common/units'
|
|
23
|
+
import { type ExampleCategory, type ExampleDef, exampleField } from '../define'
|
|
24
|
+
|
|
25
|
+
/** The construction examples' own unit types */
|
|
26
|
+
export const C = {
|
|
27
|
+
worker: 'constructionWorker',
|
|
28
|
+
hall: 'constructionHall',
|
|
29
|
+
keep: 'constructionKeep',
|
|
30
|
+
castle: 'constructionCastle',
|
|
31
|
+
barracks: 'constructionBarracks',
|
|
32
|
+
tower: 'constructionTower',
|
|
33
|
+
house: 'constructionHouse',
|
|
34
|
+
temple: 'constructionTemple',
|
|
35
|
+
farm: 'constructionFarm',
|
|
36
|
+
mill: 'constructionMill',
|
|
37
|
+
fortress: 'constructionFortress'
|
|
38
|
+
} as const
|
|
39
|
+
|
|
40
|
+
/** How fast everything goes up, 1 as its `buildTime` says: what the Build speed slider sets */
|
|
41
|
+
const speed = defineComponent<{ factor: number }>({ id: 'construction.speed', default: () => ({ factor: 1 }) })
|
|
42
|
+
|
|
43
|
+
/** How fast a site goes up with so many builders: the first counts whole, every other one half, times the example's speed */
|
|
44
|
+
const rate = (builders: number, world: World) => (builders > 0 ? 1 + (builders - 1) * 0.5 : 0) * world.state(speed).factor
|
|
45
|
+
|
|
46
|
+
const building = (id: string, name: string, size: number, buildTime: number, health: number, own: Partial<UnitTypeDef> = {}): UnitTypeDef => ({
|
|
47
|
+
id,
|
|
48
|
+
name,
|
|
49
|
+
kind: 'building',
|
|
50
|
+
radius: size / 2,
|
|
51
|
+
footprint: { w: size, d: size },
|
|
52
|
+
sight: 6,
|
|
53
|
+
stats: { health, armor: 3 },
|
|
54
|
+
// a worker stays and works on it; more workers, faster
|
|
55
|
+
construction: 'builder',
|
|
56
|
+
buildTime,
|
|
57
|
+
buildRate: rate,
|
|
58
|
+
...own
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const types: UnitTypeDef[] = [
|
|
62
|
+
{
|
|
63
|
+
id: C.worker,
|
|
64
|
+
name: 'Worker',
|
|
65
|
+
kind: 'unit',
|
|
66
|
+
radius: 0.4,
|
|
67
|
+
sight: 8,
|
|
68
|
+
stats: { health: 220, moveSpeed: 4.5 },
|
|
69
|
+
// what it puts down: every building here. A unit that builds can repair too
|
|
70
|
+
builds: [C.hall, C.barracks, C.tower, C.house, C.temple, C.farm, C.mill, C.fortress]
|
|
71
|
+
},
|
|
72
|
+
building(C.hall, 'Town hall', 4, 30, 2000, { upgradesTo: C.keep }),
|
|
73
|
+
building(C.keep, 'Keep', 4, 10, 2600, { upgradesTo: C.castle }),
|
|
74
|
+
building(C.castle, 'Castle', 4, 12, 3400),
|
|
75
|
+
building(C.barracks, 'Barracks', 3, 18, 1200),
|
|
76
|
+
building(C.tower, 'Watch tower', 2, 14, 700),
|
|
77
|
+
building(C.house, 'House', 2, 10, 500),
|
|
78
|
+
building(C.temple, 'Temple', 3, 24, 1400),
|
|
79
|
+
building(C.farm, 'Farm', 3, 12, 600),
|
|
80
|
+
building(C.mill, 'Windmill', 3, 16, 800),
|
|
81
|
+
building(C.fortress, 'Fortress', 4, 28, 2400)
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
// ---- helpers the examples share
|
|
85
|
+
|
|
86
|
+
/** A worker of the player's, put down beside a point */
|
|
87
|
+
const worker = (world: World, at: Vec2): Entity => world.spawn(C.worker, { at, owner: PLAYER })
|
|
88
|
+
|
|
89
|
+
/** A site of the player's, put down at a point: at `progress` of the way already, nobody working on it yet */
|
|
90
|
+
function site(world: World, type: string, at: Vec2, progress = 0): Entity {
|
|
91
|
+
const made = world.spawn(type, { at, owner: PLAYER, underConstruction: true })
|
|
92
|
+
if (progress > 0) setProgress(world, made, progress)
|
|
93
|
+
return made
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Puts a site at a share of the way, and its health with it: what it would be had it been built so far */
|
|
97
|
+
function setProgress(world: World, entity: Entity, progress: number): void {
|
|
98
|
+
const state = underConstruction(entity)
|
|
99
|
+
if (!state) return
|
|
100
|
+
state.progress = Math.min(0.999, Math.max(0, progress))
|
|
101
|
+
const start = world.settings.production.constructionHealth
|
|
102
|
+
entity.health = Math.max(1, entity.maxHealth * (start + (1 - start) * state.progress))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The sites still going up, left to right */
|
|
106
|
+
const sites = (world: World) =>
|
|
107
|
+
world
|
|
108
|
+
.query({ kinds: ['building'], owner: PLAYER })
|
|
109
|
+
.filter((each) => underConstruction(each))
|
|
110
|
+
.sort((a, b) => a.pos.x - b.pos.x)
|
|
111
|
+
|
|
112
|
+
/** Takes away everything an example put down */
|
|
113
|
+
function clear(world: World): void {
|
|
114
|
+
for (const each of [...world.entities.values()]) if (each.alive) world.kill(each, undefined, false, 'removed')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ---- the examples' layouts
|
|
118
|
+
|
|
119
|
+
/** Five sites in a row, each going up its own way, a worker at each */
|
|
120
|
+
function row(world: World): void {
|
|
121
|
+
const kinds = [C.barracks, C.tower, C.house, C.temple, C.fortress]
|
|
122
|
+
kinds.forEach((type, i) => {
|
|
123
|
+
const x = 8 + i * 8
|
|
124
|
+
const made = site(world, type, { x, z: 24 })
|
|
125
|
+
worker(world, { x: x - 1, z: 20.5 }).order('construct', made)
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** A hall to be, and six workers waiting by it */
|
|
130
|
+
function yard(world: World): void {
|
|
131
|
+
site(world, C.fortress, { x: 24, z: 26 })
|
|
132
|
+
for (let i = 0; i < 6; i++) worker(world, { x: 19 + i * 2, z: 17 })
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** The same building six times, each further along: 0, a fifth, two fifths… and one finished */
|
|
136
|
+
function stages(world: World): void {
|
|
137
|
+
for (let i = 0; i < 6; i++) {
|
|
138
|
+
const at = { x: 6 + i * 7.2, z: 24 }
|
|
139
|
+
if (i === 5) world.spawn(C.fortress, { at, owner: PLAYER })
|
|
140
|
+
else site(world, C.fortress, at, i * 0.2)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** A barracks that is burning, and three workers to mend it */
|
|
145
|
+
function burning(world: World): void {
|
|
146
|
+
world.spawn(C.barracks, { at: { x: 24.5, z: 26.5 }, owner: PLAYER })
|
|
147
|
+
for (let i = 0; i < 3; i++) worker(world, { x: 21 + i * 3, z: 19 })
|
|
148
|
+
// set alight a moment after it stands: the screen has drawn it by then, to put the fire on
|
|
149
|
+
world.timers.after(1.5, alight)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Every building of the player's hurt to an eighth of its health, with a blast on it */
|
|
153
|
+
const alight = defineTimer({ id: 'construction.alight', run: (world) => hurtTo(world, 0.12) })
|
|
154
|
+
|
|
155
|
+
function hurtTo(world: World, share: number): void {
|
|
156
|
+
for (const each of world.query({ kinds: ['building'], owner: PLAYER })) {
|
|
157
|
+
each.health = Math.max(1, Math.min(each.health, each.maxHealth * share))
|
|
158
|
+
world.fx('explosion', { at: each.pos, params: { size: 0.6, scorch: false } })
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** A town hall, standing, to upgrade into a keep and then a castle */
|
|
163
|
+
function hall(world: World): void {
|
|
164
|
+
world.spawn(C.hall, { at: { x: 24, z: 26 }, owner: PLAYER })
|
|
165
|
+
for (let i = 0; i < 2; i++) worker(world, { x: 22 + i * 3, z: 20 })
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Where the town's buildings go, in the order they are built: a hall in the middle, the rest round it */
|
|
169
|
+
const TOWN: [string, number, number][] = [
|
|
170
|
+
[C.hall, 24, 24],
|
|
171
|
+
[C.house, 18, 19],
|
|
172
|
+
[C.house, 30, 19],
|
|
173
|
+
[C.farm, 15.5, 27.5],
|
|
174
|
+
[C.farm, 32.5, 27.5],
|
|
175
|
+
[C.barracks, 18.5, 32.5],
|
|
176
|
+
[C.house, 24, 33],
|
|
177
|
+
[C.temple, 29.5, 33.5],
|
|
178
|
+
[C.tower, 13, 18],
|
|
179
|
+
[C.tower, 35, 18],
|
|
180
|
+
[C.mill, 10.5, 32.5],
|
|
181
|
+
[C.house, 36, 24],
|
|
182
|
+
[C.house, 12, 24],
|
|
183
|
+
[C.tower, 13, 38],
|
|
184
|
+
[C.tower, 35, 38],
|
|
185
|
+
[C.fortress, 37, 33]
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
/** Workers in the middle of an empty field, a town to be laid out round them */
|
|
189
|
+
function town(world: World): void {
|
|
190
|
+
for (let i = 0; i < 10; i++) worker(world, { x: 20 + (i % 5) * 2, z: 12 + Math.floor(i / 5) * 1.6 })
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Each example's layout, by its id */
|
|
194
|
+
const LAYOUTS: Record<string, (world: World) => void> = {
|
|
195
|
+
'construction-motions': row,
|
|
196
|
+
'construction-workers': yard,
|
|
197
|
+
'construction-stages': stages,
|
|
198
|
+
'construction-repair': burning,
|
|
199
|
+
'construction-upgrade': hall,
|
|
200
|
+
'construction-town': town
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ---- commands, sent by the examples' buttons
|
|
204
|
+
|
|
205
|
+
/** How fast everything goes up, from a quarter to eight times */
|
|
206
|
+
export const setSpeed = defineCommand('construction.speed', { factor: number }, (world, _player, { factor }) => {
|
|
207
|
+
world.setState(speed, { factor: Math.min(8, Math.max(0.1, factor)) })
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
/** Workers sent to the first site still going up: `count` more of those idle, or all (0) */
|
|
211
|
+
export const sendWorkers = defineCommand('construction.send', { count: number }, (world, _player, { count }) => {
|
|
212
|
+
const target = sites(world)[0]
|
|
213
|
+
if (!target) return
|
|
214
|
+
const idle = world.query({ type: C.worker, owner: PLAYER, sort: 'nearest', near: target }).filter((each) => each.currentOrder?.type !== 'construct')
|
|
215
|
+
for (const each of count > 0 ? idle.slice(0, count) : idle) each.order('construct', target)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
/** Every worker stops: the sites stand where they got to */
|
|
219
|
+
export const stopWork = defineCommand('construction.stop', {}, (world) => {
|
|
220
|
+
for (const each of world.query({ type: C.worker, owner: PLAYER })) each.order('stop')
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
/** The first site called off, as its Cancel button would (the engine's `cancelConstruction`): it folds into the ground */
|
|
224
|
+
export const callOff = defineCommand('construction.cancel', {}, (world, player) => {
|
|
225
|
+
const target = sites(world)[0]
|
|
226
|
+
if (target) cancelConstructionCommand.execute(world, player, { building: target.id })
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
/** Every site put at a share of the way (the Progress slider) */
|
|
230
|
+
export const progressAll = defineCommand('construction.progress', { share: number }, (world, _player, { share }) => {
|
|
231
|
+
for (const each of sites(world)) setProgress(world, each, share)
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
/** The workers told to mend every hurt building of the player's */
|
|
235
|
+
export const repairAll = defineCommand('construction.repair', {}, (world) => {
|
|
236
|
+
const hurt = world.query({ kinds: ['building'], owner: PLAYER }).filter((each) => !underConstruction(each) && each.health < each.maxHealth)
|
|
237
|
+
if (!hurt.length) return
|
|
238
|
+
for (const each of world.query({ type: C.worker, owner: PLAYER })) each.order('repair', hurt[0])
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
/** Every building of the player's hurt down to a share of its health */
|
|
242
|
+
export const hurtAll = defineCommand('construction.hurt', { share: number }, (world, _player, { share }) => hurtTo(world, share))
|
|
243
|
+
|
|
244
|
+
/** The hall upgraded into a keep, the keep into a castle, as its card's button would (the engine's `upgradeBuilding`) */
|
|
245
|
+
export const upgrade = defineCommand('construction.upgrade', {}, (world, player) => {
|
|
246
|
+
const standing = world.query({ type: [C.hall, C.keep], owner: PLAYER, limit: 1 })[0]
|
|
247
|
+
if (standing) upgradeBuildingCommand.execute(world, player, { building: standing.id, into: undefined })
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
/** The town laid out: each worker given its share of the plan, one after another (queued `build` orders) */
|
|
251
|
+
export const buildTown = defineCommand('construction.town', {}, (world) => {
|
|
252
|
+
const workers = world.query({ type: C.worker, owner: PLAYER })
|
|
253
|
+
if (!workers.length) return
|
|
254
|
+
// each its share of the plan, in turn: the first the hall, the others a house, a farm… and on to the next
|
|
255
|
+
TOWN.forEach(([type, x, z], i) => {
|
|
256
|
+
const builder = workers[i % workers.length]
|
|
257
|
+
builder.order('build', { unitType: type, point: { x, z } }, { queue: true })
|
|
258
|
+
})
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
/** Takes everything away and lays the example out again */
|
|
262
|
+
export const relay = defineCommand('construction.relay', { example: text }, (world, _player, { example }) => {
|
|
263
|
+
const layout = LAYOUTS[example]
|
|
264
|
+
if (!layout) return
|
|
265
|
+
clear(world)
|
|
266
|
+
layout(world)
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const example = (id: string, title: string, summary: string, tags: string[]): ExampleDef => ({
|
|
270
|
+
id,
|
|
271
|
+
category: 'construction',
|
|
272
|
+
title,
|
|
273
|
+
summary,
|
|
274
|
+
tags,
|
|
275
|
+
map: () => exampleField({ name: title }),
|
|
276
|
+
start: (world) => {
|
|
277
|
+
world.setState(speed, { factor: 1 })
|
|
278
|
+
LAYOUTS[id]?.(world)
|
|
279
|
+
},
|
|
280
|
+
source: ['examples/construction/index.ts', 'examples/construction/looks.ts']
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
export const category: ExampleCategory = {
|
|
284
|
+
rules: (game: Game<any>) => {
|
|
285
|
+
for (const type of types) game.unit(type)
|
|
286
|
+
game.component(speed)
|
|
287
|
+
game.timer(alight)
|
|
288
|
+
for (const command of [setSpeed, sendWorkers, stopWork, callOff, progressAll, repairAll, hurtAll, upgrade, buildTown, relay])
|
|
289
|
+
game.command(command)
|
|
290
|
+
},
|
|
291
|
+
examples: [
|
|
292
|
+
example(
|
|
293
|
+
'construction-motions',
|
|
294
|
+
'Five ways to go up',
|
|
295
|
+
'Five buildings going up side by side, a worker hammering at each: one grows out of the ground, one rises, one fades in, one is revealed by a glowing cut, and one stands in scaffolding until it is done.',
|
|
296
|
+
['construction', 'build', 'grow', 'rise', 'fade', 'reveal', 'scaffold', 'stages', 'speed']
|
|
297
|
+
),
|
|
298
|
+
example(
|
|
299
|
+
'construction-workers',
|
|
300
|
+
'Workers at a site',
|
|
301
|
+
'A fortress to be built and six workers. Send them one at a time and watch it go faster with each; stop them and it waits where it got to; cancel it and it folds back into the ground.',
|
|
302
|
+
['construction', 'workers', 'builders', 'pause', 'cancel', 'refund']
|
|
303
|
+
),
|
|
304
|
+
example(
|
|
305
|
+
'construction-stages',
|
|
306
|
+
'Every stage at once',
|
|
307
|
+
'The same fortress six times, each further along: dug earth, low scaffolding, high scaffolding, the building rising inside it, and finished. Drag Progress to move them all.',
|
|
308
|
+
['construction', 'stages', 'scaffold', 'progress']
|
|
309
|
+
),
|
|
310
|
+
example(
|
|
311
|
+
'construction-repair',
|
|
312
|
+
'Repair a burning barracks',
|
|
313
|
+
'A barracks is burning down. Send the workers to repair it: its health comes back as they hammer, the fire goes out under a quarter and the smoke over a half.',
|
|
314
|
+
['repair', 'damaged', 'fire', 'smoke', 'workers']
|
|
315
|
+
),
|
|
316
|
+
example(
|
|
317
|
+
'construction-upgrade',
|
|
318
|
+
'Hall, keep, castle',
|
|
319
|
+
'A town hall upgraded where it stands: scaffolding goes up round it, and it comes out a keep; upgrade again for a castle. It keeps working all the while.',
|
|
320
|
+
['upgrade', 'morph', 'hall', 'keep', 'castle', 'scaffold']
|
|
321
|
+
),
|
|
322
|
+
example(
|
|
323
|
+
'construction-town',
|
|
324
|
+
'A whole town',
|
|
325
|
+
'Ten workers lay out a town: a hall first, then houses, farms, a barracks, a temple, towers and a mill, each worker going from one to the next. Speed it up to watch it all rise.',
|
|
326
|
+
['town', 'build order', 'workers', 'queue', 'city', 'construction']
|
|
327
|
+
)
|
|
328
|
+
]
|
|
329
|
+
}
|