@v12-engine/create 0.1.0 → 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 +2 -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,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Items and a shop: a building that `sells` items sells them to whoever has a hero near it, for the item's cost. An
|
|
3
|
+
* item gives what it gives while carried (`bonus`), or is used for its ability, a charge a use (`charges`). A creep
|
|
4
|
+
* can drop one when it dies (`drops`): the brute by the shop carries a salve
|
|
5
|
+
*/
|
|
6
|
+
import { defineCommand, heroesOf, oneOf, type World } from '@v12-engine/engine'
|
|
7
|
+
import { PLAYER } from '../common/units'
|
|
8
|
+
import { type ExampleDef, exampleField } from '../define'
|
|
9
|
+
import { clear, ownedOf, purse } from './base'
|
|
10
|
+
import { camps, type CampSpot, withCamps } from './camps'
|
|
11
|
+
import { RTS, rtsItems } from './data'
|
|
12
|
+
|
|
13
|
+
/** A camp of one: the brute, with its salve */
|
|
14
|
+
const BRUTE: readonly CampSpot[] = [{ name: 'brute', at: { x: 35, z: 14 }, types: [RTS.brute] }]
|
|
15
|
+
|
|
16
|
+
/** The merchant, the paladin by it with a purse to spend, and a brute that drops a salve */
|
|
17
|
+
function layOut(world: World): void {
|
|
18
|
+
clear(world)
|
|
19
|
+
purse(world, PLAYER, 1500, 0)
|
|
20
|
+
world.spawn(RTS.shop, { at: { x: 24.5, z: 26.5 }, owner: 0 })
|
|
21
|
+
world.spawn(RTS.paladin, { at: { x: 24, z: 22 }, owner: PLAYER, facing: 0 })
|
|
22
|
+
// the supply the hero takes
|
|
23
|
+
world.spawn(RTS.farm, { at: { x: 19, z: 21 }, owner: PLAYER })
|
|
24
|
+
camps(world, BRUTE)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The player's hero buys an item at the merchant, as a click on its card's item does */
|
|
28
|
+
export const buy = defineCommand('rts.buy', { item: oneOf(...rtsItems.map((each) => each.id)) }, (world, player, { item }) => {
|
|
29
|
+
const [shop] = ownedOf(world, 0, RTS.shop)
|
|
30
|
+
const [hero] = heroesOf(world, player)
|
|
31
|
+
if (shop && hero) world.issue({ type: 'buy', player, shop: shop.id, item, hero: hero.id })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
export const resetShop = defineCommand('rts.resetShop', {}, (world) => layOut(world))
|
|
35
|
+
|
|
36
|
+
export const shopExample: ExampleDef = {
|
|
37
|
+
id: 'rts-shop',
|
|
38
|
+
category: 'rts',
|
|
39
|
+
title: 'Items and a shop',
|
|
40
|
+
summary:
|
|
41
|
+
'A goblin merchant sells to a hero standing by it. Buy claws, a ring or gloves and watch the paladin’s numbers go up; a salve is drunk from the inventory. The gnoll brute drops a salve when it dies.',
|
|
42
|
+
tags: ['items', 'shop', 'inventory', 'buy', 'merchant', 'drops', 'loot', 'hero'],
|
|
43
|
+
map: () => withCamps(exampleField({ name: 'Market', size: 44 }), BRUTE),
|
|
44
|
+
start: (world) => layOut(world),
|
|
45
|
+
source: ['examples/rts/shop.ts', 'examples/rts/data.ts', 'examples/rts/looks.ts']
|
|
46
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tech: a blacksmith `researches` upgrades, each level of one paid and studied in its own time, and what it gives goes
|
|
3
|
+
* on every footman at once, and on every one trained after. Forged Swords' second level asks for a keep: the town hall
|
|
4
|
+
* becomes one in place (`upgradesTo`), still a hall to everything that asks for one (`provides`)
|
|
5
|
+
*/
|
|
6
|
+
import { defineCommand, type World } from '@v12-engine/engine'
|
|
7
|
+
import { PLAYER } from '../common/units'
|
|
8
|
+
import { type ExampleDef, exampleField } from '../define'
|
|
9
|
+
import { base, clear, ownedOf, purse } from './base'
|
|
10
|
+
import { RTS } from './data'
|
|
11
|
+
|
|
12
|
+
/** A base with a barracks and a blacksmith up, six footmen drilling in front of them */
|
|
13
|
+
function layOut(world: World): void {
|
|
14
|
+
clear(world)
|
|
15
|
+
purse(world, PLAYER, 3000, 1500)
|
|
16
|
+
base(world, PLAYER, { x: 22, z: 26 }, { workers: 0 })
|
|
17
|
+
world.spawn(RTS.barracks, { at: { x: 30.5, z: 26.5 }, owner: PLAYER })
|
|
18
|
+
world.spawn(RTS.blacksmith, { at: { x: 30.5, z: 21.5 }, owner: PLAYER })
|
|
19
|
+
world.spawn(RTS.farm, { at: { x: 34, z: 30 }, owner: PLAYER })
|
|
20
|
+
for (let i = 0; i < 6; i++) world.spawn(RTS.footman, { at: { x: 21 + (i % 3) * 1.5, z: 17 - Math.floor(i / 3) * 1.5 }, owner: PLAYER, facing: 0 })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The town hall becomes a keep, as its card's button does: paid, and built over its own time in place */
|
|
24
|
+
export const toKeep = defineCommand('rts.toKeep', {}, (world, player) => {
|
|
25
|
+
const [hall] = ownedOf(world, player, RTS.townhall)
|
|
26
|
+
if (hall) world.issue({ type: 'upgradeBuilding', player, building: hall.id })
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export const tech: ExampleDef = {
|
|
30
|
+
id: 'rts-tech',
|
|
31
|
+
category: 'rts',
|
|
32
|
+
title: 'Upgrades and tech',
|
|
33
|
+
summary:
|
|
34
|
+
'The blacksmith researches Forged Swords and Iron Plating; each level lands on every footman at once. The second level of swords needs a keep: upgrade the town hall in place, then research again.',
|
|
35
|
+
tags: ['research', 'upgrade', 'tech', 'tech tree', 'requires', 'blacksmith', 'keep', 'morph'],
|
|
36
|
+
map: () => exampleField({ name: 'Smithy', size: 44 }),
|
|
37
|
+
start: (world) => layOut(world),
|
|
38
|
+
source: ['examples/rts/tech.ts', 'examples/rts/base.ts', 'examples/rts/data.ts', 'examples/rts/looks.ts']
|
|
39
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Training: a building `trains` unit types, a queue of them at a time, each paid for as it is queued and made in its
|
|
3
|
+
* `buildTime`. Supply caps the army: each unit takes some (`supply`), halls and farms give it (`supplyGiven`). A
|
|
4
|
+
* rally point sends what comes out where the player says. The rifleman asks for a blacksmith first (`requires`)
|
|
5
|
+
*/
|
|
6
|
+
import { defineCommand, type World } from '@v12-engine/engine'
|
|
7
|
+
import { PLAYER } from '../common/units'
|
|
8
|
+
import { type ExampleDef, exampleField } from '../define'
|
|
9
|
+
import { base, clear, ownedOf, purse } from './base'
|
|
10
|
+
import { RTS } from './data'
|
|
11
|
+
|
|
12
|
+
/** Where the rally button sends the new units: the field in front of the barracks */
|
|
13
|
+
export const RALLY = { x: 31, z: 28 }
|
|
14
|
+
|
|
15
|
+
/** A hall, a barracks, two farms and plenty of gold: all there is to train with */
|
|
16
|
+
function layOut(world: World): void {
|
|
17
|
+
clear(world)
|
|
18
|
+
purse(world, PLAYER, 2000, 500)
|
|
19
|
+
base(world, PLAYER, { x: 26, z: 26 }, { workers: 0 })
|
|
20
|
+
world.spawn(RTS.barracks, { at: { x: 32.5, z: 20.5 }, owner: PLAYER })
|
|
21
|
+
world.spawn(RTS.farm, { at: { x: 20, z: 18 }, owner: PLAYER })
|
|
22
|
+
world.spawn(RTS.farm, { at: { x: 23, z: 18 }, owner: PLAYER })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The barracks' rally point, out on the field: what it trains walks there as it comes out */
|
|
26
|
+
export const rally = defineCommand('rts.rally', {}, (world, player) => {
|
|
27
|
+
const barracks = ownedOf(world, player, RTS.barracks)
|
|
28
|
+
world.issue({ type: 'rally', player, buildings: barracks.map((each) => each.id), point: RALLY })
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
/** A blacksmith put down, built at once: the rifleman's requirement */
|
|
32
|
+
export const smithy = defineCommand('rts.smithy', {}, (world, player) => {
|
|
33
|
+
if (!ownedOf(world, player, RTS.blacksmith).length) world.spawn(RTS.blacksmith, { at: { x: 36.5, z: 26.5 }, owner: player })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export const resetTrain = defineCommand('rts.resetTrain', {}, (world) => layOut(world))
|
|
37
|
+
|
|
38
|
+
export const training: ExampleDef = {
|
|
39
|
+
id: 'rts-train',
|
|
40
|
+
category: 'rts',
|
|
41
|
+
title: 'Training and supply',
|
|
42
|
+
summary:
|
|
43
|
+
'A barracks trains footmen, a queue of five at a time, each paid as it is queued. Farms give the supply the army takes; riflemen need a blacksmith first. Set a rally point and new units walk there.',
|
|
44
|
+
tags: ['train', 'queue', 'production', 'supply', 'food', 'rally', 'barracks', 'requires', 'tech'],
|
|
45
|
+
map: () => exampleField({ name: 'Barracks', size: 44 }),
|
|
46
|
+
start: (world) => layOut(world),
|
|
47
|
+
source: ['examples/rts/train.ts', 'examples/rts/base.ts', 'examples/rts/data.ts', 'examples/rts/looks.ts']
|
|
48
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The land the transport examples are played on, made in code: a river across a field to ferry over, and a plateau
|
|
3
|
+
* behind a cliff wall to fly up onto. Each is a map (`GameMap`): its ground, its cliff levels, its water (deep where
|
|
4
|
+
* boats go and nothing walks, shallow where it is waded), its paint and its scenery
|
|
5
|
+
*/
|
|
6
|
+
import { createMap, exactMath, type GameMap, type MapDoodad, type Vec2, WATER_DEEP, WATER_SHALLOW } from '@v12-engine/engine'
|
|
7
|
+
import { tiles } from '../define'
|
|
8
|
+
|
|
9
|
+
/** A test of a cell, by its middle */
|
|
10
|
+
type Where = (x: number, z: number) => boolean
|
|
11
|
+
|
|
12
|
+
/** A small hash of a whole cell, 0 to 1: the wobble of a bank, where a tree goes. The same on every machine */
|
|
13
|
+
export function hash(x: number, z: number, seed = 1): number {
|
|
14
|
+
const n = exactMath.sin(Math.floor(x) * 127.1 + Math.floor(z) * 311.7 + seed * 74.7) * 43758.5453
|
|
15
|
+
return n - Math.floor(n)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A smooth wobble along a line, -1 to 1: what makes a bank or a cliff's edge look grown, not drawn */
|
|
19
|
+
export const wobble = (along: number, seed = 1): number => exactMath.sin(along * 0.31 + seed) * 0.6 + exactMath.sin(along * 0.73 + seed * 2.1) * 0.4
|
|
20
|
+
|
|
21
|
+
/** A field of grass `width` by `depth`, a player for each start given, starting there */
|
|
22
|
+
export function land(name: string, width: number, depth: number, ...starts: Vec2[]): GameMap {
|
|
23
|
+
const map = createMap({ name, width, depth, players: starts.length, game: 'examples', tileset: tiles.map((each) => each.id) })
|
|
24
|
+
map.tiles.fill(map.tileset.indexOf('grass') + 1)
|
|
25
|
+
starts.forEach((start, i) => (map.players[i].start = start))
|
|
26
|
+
return map
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Every cell `where` says, given to `set` by its index */
|
|
30
|
+
function eachCell(map: GameMap, where: Where, set: (cell: number) => void): void {
|
|
31
|
+
for (let z = 0; z < map.depth; z++) for (let x = 0; x < map.width; x++) if (where(x + 0.5, z + 0.5)) set(z * map.width + x)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Paints a tile of the game's (`grass`, `darkGrass`, `dirt`, `road`, `sand`, `rock`, `snow`) where it says */
|
|
35
|
+
export function paint(map: GameMap, tile: string, where: Where): void {
|
|
36
|
+
const value = map.tileset.indexOf(tile) + 1
|
|
37
|
+
if (value > 0) eachCell(map, where, (cell) => (map.tiles[cell] = value))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Water where `where` says: deep where `deep` says too, shallow (waded through) elsewhere */
|
|
41
|
+
export function pour(map: GameMap, where: Where, deep: Where): void {
|
|
42
|
+
eachCell(map, where, (cell) => (map.water[cell] = deep((cell % map.width) + 0.5, Math.floor(cell / map.width) + 0.5) ? WATER_DEEP : WATER_SHALLOW))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Raises the cells it says to a cliff level: the cliffs round them have no ramp, so nothing walks up */
|
|
46
|
+
export function raise(map: GameMap, level: number, where: Where): void {
|
|
47
|
+
eachCell(map, where, (cell) => (map.levels[cell] = level))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The ground's height at every vertex, from a function of where it is */
|
|
51
|
+
export function sculpt(map: GameMap, height: (x: number, z: number) => number): void {
|
|
52
|
+
const row = map.width + 1
|
|
53
|
+
for (let z = 0; z <= map.depth; z++) for (let x = 0; x <= map.width; x++) map.ground[z * row + x] = height(x, z)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Puts a model of the shared art down as scenery, turned `yaw` and scaled; `blocks` keeps walkers off it */
|
|
57
|
+
export function place(map: GameMap, model: string, at: Vec2, options: { yaw?: number; scale?: number; blocks?: number } = {}): void {
|
|
58
|
+
const { yaw = 0, scale = 1, blocks } = options
|
|
59
|
+
const doodad: MapDoodad = { id: map.doodads.length + 1, model, x: at.x, z: at.z, yaw, scale: [scale, scale, scale] }
|
|
60
|
+
if (blocks) Object.assign(doodad, { blocks: 'walk', radius: blocks })
|
|
61
|
+
map.doodads.push(doodad)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The trees of the shared art the woods are made of: pines and columnar trees, an oak now and then */
|
|
65
|
+
const TREES = ['trees/pine_1.glb', 'trees/pine_3.glb', 'trees/columnar_1.glb', 'trees/pine_4.glb', 'trees/columnar_2.glb', 'trees/oak_5.glb']
|
|
66
|
+
|
|
67
|
+
/** Trees, as scenery, on the cells `where` says, about one in `every` of them, each kind and size and turn its own */
|
|
68
|
+
export function wood(map: GameMap, where: Where, every: number, seed: number): void {
|
|
69
|
+
eachCell(map, where, (cell) => {
|
|
70
|
+
const x = (cell % map.width) + 0.5
|
|
71
|
+
const z = Math.floor(cell / map.width) + 0.5
|
|
72
|
+
if (hash(x, z, seed) * every >= 1) return
|
|
73
|
+
const kind = TREES[Math.floor(hash(z, x, seed + 1) * TREES.length)]
|
|
74
|
+
const scale = (kind.includes('oak') ? 0.6 : 1) * (0.8 + hash(x, z, seed + 2) * 0.45)
|
|
75
|
+
place(
|
|
76
|
+
map,
|
|
77
|
+
kind,
|
|
78
|
+
{ x: x + (hash(x, z, seed + 3) - 0.5) * 0.6, z: z + (hash(x, z, seed + 4) - 0.5) * 0.6 },
|
|
79
|
+
{ yaw: hash(x, z, seed + 5) * 6.28, scale }
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Rocks of the shared art scattered on the cells `where` says, about one in `every` */
|
|
85
|
+
export function rocks(map: GameMap, where: Where, every: number, seed: number): void {
|
|
86
|
+
eachCell(map, where, (cell) => {
|
|
87
|
+
const x = (cell % map.width) + 0.5
|
|
88
|
+
const z = Math.floor(cell / map.width) + 0.5
|
|
89
|
+
if (hash(x, z, seed) * every >= 1) return
|
|
90
|
+
const kind = `forest/rock_medium_${1 + Math.floor(hash(z, x, seed) * 3)}.glb`
|
|
91
|
+
place(map, kind, { x, z }, { yaw: hash(x, z, seed + 1) * 6.28, scale: 0.6 + hash(x, z, seed + 2) * 0.6 })
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ---- a river to ferry over
|
|
96
|
+
|
|
97
|
+
/** The river's middle runs north to south along this x, its deep water `RIVER_DEEP` either side of it */
|
|
98
|
+
export const RIVER_X = 24
|
|
99
|
+
const RIVER_DEEP = 5.5
|
|
100
|
+
const RIVER_BANK = 7
|
|
101
|
+
|
|
102
|
+
/** The river's middle at a row: it bends a little as it goes */
|
|
103
|
+
export const riverAt = (z: number): number => RIVER_X + wobble(z, 3) * 1.6
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* A field of 48 by 40 cells cut north to south by a river eleven cells of deep water across, a fringe of shallows and
|
|
107
|
+
* sand on either bank, woods along the far edges. Nothing that walks crosses it
|
|
108
|
+
*/
|
|
109
|
+
export function riverMap(): GameMap {
|
|
110
|
+
const map = land('River crossing', 48, 40, { x: 12, z: 20 })
|
|
111
|
+
sculpt(map, (x, z) => 1 + wobble(x * 0.7 + z * 0.4, 5) * 0.25)
|
|
112
|
+
const from = (x: number, z: number) => Math.abs(x - riverAt(z))
|
|
113
|
+
pour(
|
|
114
|
+
map,
|
|
115
|
+
(x, z) => from(x, z) < RIVER_BANK + wobble(z, 7) * 0.5,
|
|
116
|
+
(x, z) => from(x, z) < RIVER_DEEP
|
|
117
|
+
)
|
|
118
|
+
paint(map, 'sand', (x, z) => from(x, z) < RIVER_BANK + 1.4 + wobble(z, 9) * 0.6)
|
|
119
|
+
paint(map, 'darkGrass', (x, z) => from(x, z) > RIVER_BANK + 6 && hash(x, z, 4) > 0.45)
|
|
120
|
+
paint(map, 'dirt', (x, z) => Math.abs(z - 20) < 1.2 + wobble(x, 2) * 0.3 && from(x, z) > RIVER_BANK + 1 && from(x, z) < RIVER_BANK + 12)
|
|
121
|
+
wood(map, (x, z) => (x < 4 || x > 44 || z < 4 || z > 36) && from(x, z) > RIVER_BANK + 2, 2.2, 11)
|
|
122
|
+
rocks(map, (x, z) => from(x, z) > RIVER_BANK + 1.5 && from(x, z) < RIVER_BANK + 2.5 && Math.abs(z - 20) > 4, 9, 12)
|
|
123
|
+
// a jetty on each bank, out over the shallows where the ship comes in
|
|
124
|
+
place(map, 'rts/dock_2.glb', { x: riverAt(20) - RIVER_BANK + 0.4, z: 20 }, { yaw: Math.PI / 2, scale: 1.2 })
|
|
125
|
+
place(map, 'rts/dock_2.glb', { x: riverAt(20) + RIVER_BANK - 0.4, z: 20 }, { yaw: -Math.PI / 2, scale: 1.2 })
|
|
126
|
+
// the harbour the west bank sails from, and crates and barrels by the far jetty
|
|
127
|
+
place(map, 'rts/port.glb', { x: riverAt(28) - RIVER_BANK - 4, z: 28 }, { yaw: Math.PI / 2, scale: 1, blocks: 2.6 })
|
|
128
|
+
place(map, 'props/barrel.glb', { x: riverAt(22) + RIVER_BANK + 2, z: 23 }, { scale: 1.2 })
|
|
129
|
+
place(map, 'props/crate_wooden.glb', { x: riverAt(22) + RIVER_BANK + 2.8, z: 23.6 }, { yaw: 0.4, scale: 1.2 })
|
|
130
|
+
place(map, 'props/crate_wooden.glb', { x: riverAt(22) + RIVER_BANK + 2.4, z: 24.6 }, { yaw: 1.1, scale: 1 })
|
|
131
|
+
return map
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---- a plateau behind a cliff wall
|
|
135
|
+
|
|
136
|
+
/** The plateau: from this x east, one level up behind a cliff with no ramp, to the map's east edge */
|
|
137
|
+
export const PLATEAU_X = 26
|
|
138
|
+
/** The plateau's cliff edge at a row: it wanders a little */
|
|
139
|
+
export const edgeAt = (z: number): number => PLATEAU_X + wobble(z, 6) * 1.5
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A field of 48 by 40 cells, its east half a plateau two cliff levels up: a wall of rock all along it with no ramp, so
|
|
143
|
+
* nothing that walks gets up. A pond and woods below, rocks and pines up top
|
|
144
|
+
*/
|
|
145
|
+
export function plateauMap(): GameMap {
|
|
146
|
+
const map = land('Cliff wall', 48, 40, { x: 12, z: 20 })
|
|
147
|
+
sculpt(map, (x, z) => 1 + wobble(x * 0.6 + z * 0.5, 2) * 0.3)
|
|
148
|
+
const up = (x: number, z: number) => x > edgeAt(z)
|
|
149
|
+
raise(map, 2, up)
|
|
150
|
+
paint(map, 'rock', (x, z) => up(x, z) && x < edgeAt(z) + 1.5)
|
|
151
|
+
paint(map, 'darkGrass', (x, z) => up(x, z) && hash(x, z, 8) > 0.5)
|
|
152
|
+
paint(map, 'dirt', (x, z) => !up(x, z) && x > edgeAt(z) - 2.5)
|
|
153
|
+
paint(map, 'dirt', (x, z) => up(x, z) && exactMath.hypot(x - 36, z - 20) < 3.5 + wobble(x + z, 4) * 0.6)
|
|
154
|
+
// a pond below the wall, to the south
|
|
155
|
+
const pond = (x: number, z: number) => exactMath.hypot(x - 10, z - 7) < 4 + wobble(x - z, 3) * 0.8
|
|
156
|
+
pour(map, pond, () => false)
|
|
157
|
+
paint(map, 'sand', (x, z) => exactMath.hypot(x - 10, z - 7) < 5.2 + wobble(x - z, 3) * 0.8)
|
|
158
|
+
wood(map, (x, z) => !up(x, z) && (x < 3 || z > 35) && !pond(x, z), 2.2, 21)
|
|
159
|
+
wood(map, (x, z) => up(x, z) && x > edgeAt(z) + 3 && (z < 8 || z > 31 || x > 43), 2.4, 22)
|
|
160
|
+
rocks(map, (x, z) => up(x, z) && x > edgeAt(z) + 1.5 && x < edgeAt(z) + 3 && Math.abs(z - 20) > 5, 5, 23)
|
|
161
|
+
rocks(map, (x, z) => !up(x, z) && x > edgeAt(z) - 2 && hash(x, z, 30) > 0.5 && Math.abs(z - 20) > 6, 6, 24)
|
|
162
|
+
return map
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ---- a watch post on a road
|
|
166
|
+
|
|
167
|
+
/** The road's middle at a row: it winds down from the north to the hall */
|
|
168
|
+
export const roadAt = (z: number): number => 24 + wobble(z * 0.5, 1) * 2
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A field of 48 cells a side for two players, a dirt road winding down it from the north to the hall in the south,
|
|
172
|
+
* woods either side of the road and rocks along it: the way the gnolls come
|
|
173
|
+
*/
|
|
174
|
+
export function outpostMap(): GameMap {
|
|
175
|
+
const map = land('Watch post', 48, 48, { x: 24, z: 13 }, { x: 24, z: 42 })
|
|
176
|
+
sculpt(map, (x, z) => 1 + wobble(x * 0.5 + z * 0.3, 4) * 0.3)
|
|
177
|
+
const from = (x: number, z: number) => Math.abs(x - roadAt(z))
|
|
178
|
+
paint(map, 'darkGrass', (x, z) => from(x, z) > 6 && hash(x, z, 3) > 0.4)
|
|
179
|
+
paint(map, 'dirt', (x, z) => z > 9 && from(x, z) < 1.6 + wobble(z, 5) * 0.3)
|
|
180
|
+
paint(map, 'road', (x, z) => z > 9 && z < 17 && from(x, z) < 3.5 && hash(x, z, 6) > 0.5)
|
|
181
|
+
wood(map, (x, z) => z > 26 && from(x, z) > 7 + wobble(z, 8) * 1.5, 1.6, 31)
|
|
182
|
+
wood(map, (x, z) => z <= 26 && (x < 6 || x > 42), 2, 32)
|
|
183
|
+
rocks(map, (x, z) => z > 24 && from(x, z) > 3 && from(x, z) < 5, 8, 33)
|
|
184
|
+
return map
|
|
185
|
+
}
|