@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,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the game looks and sounds (`GameView`): the client's, fetched as the page first plays the game
|
|
3
|
+
* (`game.view(() => import('./view'))` in `src/game.ts`): nothing of it is in what a server, a test or a worker reads
|
|
4
|
+
*/
|
|
5
|
+
import { type GameView, hotView, presetView } from '@v12-engine/client'
|
|
6
|
+
import type { Unit } from './rules'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The look: a unit type is drawn from `parts` (boxes, cylinders, cones, spheres, pyramids) until it has a model, a
|
|
10
|
+
* `.glb` in `public/models/` named by `model` (`{ src: 'scout.glb', scale: 1 }`). `color: 'team'` is its side's colour
|
|
11
|
+
// @if assets
|
|
12
|
+
*
|
|
13
|
+
* The shared art has models to start with: `import { characters } from '@v12-engine/assets'` and
|
|
14
|
+
* `model: { src: characters.models.knight, scale: 0.6 }` (played with its own clips)
|
|
15
|
+
// @end
|
|
16
|
+
*
|
|
17
|
+
* `presetView` lays in the client's ready-made looks, which it draws none of by itself: the rain and snow (its map has
|
|
18
|
+
* some), the abilities' styles, a building's rally flag, the glow over a unit with a buff and the looks of the engine's
|
|
19
|
+
* tiles, each under what the view says of its own
|
|
20
|
+
*/
|
|
21
|
+
export const view: GameView<Unit> = presetView({
|
|
22
|
+
world: {
|
|
23
|
+
// trees and scenery in front of the player's own units faded out (`seeThrough`): who for, how, how much
|
|
24
|
+
seeThrough: {},
|
|
25
|
+
/**
|
|
26
|
+
* Looks by name to start a map from: the map editor's Look panel puts one on a map (Preset), a scene plays a map with
|
|
27
|
+
* one (`gameScene({ environment: 'dusk' })`), the rules change to one (`world.setEnvironment(view.world.environments.storm,
|
|
28
|
+
* { over: 20 })`). Each is a `MapEnvironment`: sky, light, mist, wind, clouds, weather, water
|
|
29
|
+
*/
|
|
30
|
+
environments: {
|
|
31
|
+
dusk: {
|
|
32
|
+
sky: [0.55, 0.42, 0.5],
|
|
33
|
+
clouds: { cover: 0.4, color: [1, 0.8, 0.7] },
|
|
34
|
+
light: { sunUp: 12, sunAround: 250, sunColor: [1, 0.62, 0.42], sun: 1, ambient: 0.45, ambientColor: [0.8, 0.7, 0.9] },
|
|
35
|
+
fog: { start: 60, end: 200 },
|
|
36
|
+
mist: { ground: { base: 0, top: 2, density: 0.25 } }
|
|
37
|
+
},
|
|
38
|
+
storm: {
|
|
39
|
+
sky: [0.3, 0.33, 0.38],
|
|
40
|
+
clouds: { cover: 0.9, color: [0.55, 0.57, 0.6] },
|
|
41
|
+
cloudLayer: { height: 18, cover: 0.7, opacity: 0.55, shadows: 0.5 },
|
|
42
|
+
light: { sun: 0.7, ambient: 0.5 },
|
|
43
|
+
wind: { around: 70, strength: 0.8, gusts: 0.6 },
|
|
44
|
+
weather: { kind: 'rain', amount: 0.9, splashes: 0.6 },
|
|
45
|
+
fog: { start: 40, end: 140 }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
/*
|
|
50
|
+
* How hits feel (`feel`): the struck flashes and flinches, a pause on a critical strike or a kill, a streak behind a
|
|
51
|
+
* melee swing, a shake for what is big. On as it comes; each piece takes its own values or `false`, and `feel: false`
|
|
52
|
+
* turns it all off: `feel: { hitStop: false, trails: { color: [1, 0.9, 0.6] } }`
|
|
53
|
+
*/
|
|
54
|
+
units: {
|
|
55
|
+
looks: {
|
|
56
|
+
scout: {
|
|
57
|
+
// once it has a model with several attack clips, they take turns, never the same twice running:
|
|
58
|
+
// `attacks: [{ clip: ['Attack_1', 'Attack_2'], order: 'random', crit: 'Attack_Big' }]` (`UnitLook.attacks`)
|
|
59
|
+
height: 1.4,
|
|
60
|
+
shapes: [
|
|
61
|
+
{ shape: 'cylinder', size: [0.6, 1, 0.6], offset: [0, 0.5, 0], color: 'team' },
|
|
62
|
+
{ shape: 'sphere', size: [0.45, 0.45, 0.45], offset: [0, 1.2, 0], color: [0.9, 0.8, 0.65] }
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
ground: {
|
|
68
|
+
/**
|
|
69
|
+
* How each tile of the ground (`tiles` in src/rules.ts) looks: a colour (the minimap's, and the ground's until its picture comes)
|
|
70
|
+
* and a picture repeated over the ground. A picture is a file in `public/textures/` by its path there, or made in
|
|
71
|
+
* code with no file: `pattern: 'grass'` (grass, gravel, rock, cobbles, planks, ice, lava… fifteen), with a `recipe` (a second
|
|
72
|
+
* colour, specks, how strong, and the pattern's own parameters: `params: { seams: 1.2 }`), or a pattern of the
|
|
73
|
+
* game's own (`patterns: { cobbles: definePattern({ name, params, shade }) }` on the view, then `pattern: 'cobbles'`;
|
|
74
|
+
* the map editor offers it with a slider for each parameter)
|
|
75
|
+
*/
|
|
76
|
+
// the road as gravel of a colour of its own, over the client's looks of the engine's tiles (made in code, no files)
|
|
77
|
+
tiles: { road: { color: [0.55, 0.52, 0.47], pattern: 'gravel' } }
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// saved while it runs (npm run dev): the game and the editor open take its new look, with no new page
|
|
82
|
+
if (import.meta.hot) import.meta.hot.accept((module) => hotView(import.meta.hot, 'my-game', view, module?.view))
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# My game
|
|
2
|
+
|
|
3
|
+
What V12 can do, a small scene each, as [three.js's examples](https://threejs.org/examples/) are: the list down the left, searched and by category, and the example on the right, playing, with a card of its controls over it. Each is a few dozen lines to read, copy into a game of your own, and change.
|
|
4
|
+
|
|
5
|
+
| To | Run |
|
|
6
|
+
| ---------------------- | -------------------------------------------------------------------- |
|
|
7
|
+
| See the examples | `npm run dev`, and open the page it says: the list first |
|
|
8
|
+
| Open one straight | its id after the address: `/?mechanics-battle` |
|
|
9
|
+
<!-- @if editor -->
|
|
10
|
+
| Make maps | `npm run dev`, and open `/?editor`: Save writes them into `src/maps` |
|
|
11
|
+
| Check the maps | `npm run map check`: every map in `src/maps` against the game's rules |
|
|
12
|
+
<!-- @end -->
|
|
13
|
+
<!-- @if server -->
|
|
14
|
+
<!-- @if !rooms -->
|
|
15
|
+
| Play it on a server | `npm run server`, beside `npm run dev`, and open `/?server` |
|
|
16
|
+
<!-- @end -->
|
|
17
|
+
<!-- @if rooms -->
|
|
18
|
+
| Play it online | `npm run server`, beside `npm run dev`, and open `/?find-game` |
|
|
19
|
+
<!-- @end -->
|
|
20
|
+
<!-- @end -->
|
|
21
|
+
<!-- @if tests -->
|
|
22
|
+
| Test the examples | `npm test`: each one's world made, started and run with no page |
|
|
23
|
+
<!-- @end -->
|
|
24
|
+
| Check the types | `npm run typecheck` |
|
|
25
|
+
| Build the page to host | `npm run build`, into `dist/` |
|
|
26
|
+
<!-- @if desktop -->
|
|
27
|
+
| Play it as an app | `npm run app`: the page in a window of its own (Electron, fetched the first time) |
|
|
28
|
+
| Make the app to hand out | `npm run package`, into `out/` |
|
|
29
|
+
<!-- @end -->
|
|
30
|
+
|
|
31
|
+
## The categories
|
|
32
|
+
|
|
33
|
+
| Category | Folder |
|
|
34
|
+
| --------------------- | ----------------------------------- |
|
|
35
|
+
| Core mechanics | `src/examples/mechanics/` |
|
|
36
|
+
| Abilities | `src/examples/abilities/` |
|
|
37
|
+
| Like a MOBA | `src/examples/moba/` |
|
|
38
|
+
| Like an RTS | `src/examples/rts/` |
|
|
39
|
+
| Effects | `src/examples/fx/` |
|
|
40
|
+
| Your own effects | `src/examples/custom-fx/` |
|
|
41
|
+
| Animation | `src/examples/animation/` |
|
|
42
|
+
| Your own animation | `src/examples/custom-animation/` |
|
|
43
|
+
| Destruction | `src/examples/destruction/` |
|
|
44
|
+
| Construction | `src/examples/construction/` |
|
|
45
|
+
| Nature and weather | `src/examples/nature/` |
|
|
46
|
+
| Post-processing | `src/examples/post/` |
|
|
47
|
+
| A changing map | `src/examples/dynamic-map/` |
|
|
48
|
+
| Cinematics | `src/examples/cinematics/` |
|
|
49
|
+
| Dialogue | `src/examples/dialogs/` |
|
|
50
|
+
| Interfaces | `src/examples/gui/` |
|
|
51
|
+
| Showcase | `src/examples/showcase/` |
|
|
52
|
+
| Performance | `src/examples/performance/` |
|
|
53
|
+
|
|
54
|
+
## An example of your own
|
|
55
|
+
|
|
56
|
+
1. **Its rules.** In a category's `index.ts`, an entry in its `examples` (`ExampleDef`, `src/examples/define.ts`): an `id` starting with the category's (`fx-my-burst`), a `title`, a `summary`, and what it plays: a `map` (a flat field when left out, `exampleField`) and a `start` that puts units, buildings and scenery in the world. Units, abilities and commands it needs go in the category's `rules(game)`. The engine alone here (`@v12-engine/engine`): the server and the tests read it.
|
|
57
|
+
2. **Its look and controls.** In the category's `looks.ts`, by the example's id (`ExampleLook`, `src/shell/look.ts`): `view` changes the game's look for it, `controls` are the card's buttons, switches, sliders and choices (`button`, `toggle`, `slider`, `select`, `readout`), each run with the client, and `ready(client)` runs once it is drawn (the camera put where it should look). A control that changes the world sends a command of the category's (`client.session.send(command.make({ … }))`), as `src/examples/mechanics` does.
|
|
58
|
+
3. **A category of your own.** A folder with an `index.ts` and a `looks.ts`, its id in `CATEGORIES` (`src/examples/define.ts`), and its two files in `src/examples/catalog.ts` and `src/examples/looks.ts`.
|
|
59
|
+
|
|
60
|
+
## What is where
|
|
61
|
+
|
|
62
|
+
- `src/examples/<category>/index.ts`: a category's examples, their maps and starts, and the units, abilities and commands they add (`ExampleCategory`). The engine alone, so the page, the server, the editor and the tests play the same game
|
|
63
|
+
- `src/examples/<category>/looks.ts`: their looks and controls (`CategoryLooks`), fetched with the game's look, never with the list
|
|
64
|
+
- `src/examples/common/`: the units the examples share (a footman, an archer, a mage, a knight who is a hero, a training dummy) and their looks
|
|
65
|
+
- `src/examples/define.ts`: what an example is, the categories, and the field an example plays when it says no map
|
|
66
|
+
- `src/rules.ts`: the one game every example plays (`createGame`), each category's rules registered on it
|
|
67
|
+
- `src/game.ts`: the game whole, its look given (`game.view(() => import('./view'))`)
|
|
68
|
+
- `src/view.ts`: how it looks (`GameView`): the shared units', and each category's over them
|
|
69
|
+
- `src/shell/`: the list and the card (plain HTML: the list's page carries nothing of the client), and the scenes: the list's own page and one for each example
|
|
70
|
+
- `src/main.ts`: the page, the examples' scenes beside the usual ones `appScenes` makes (the start screen is `/?home`)
|
|
71
|
+
<!-- @if editor -->
|
|
72
|
+
- `src/editor.ts`: the map editor's own settings, for `appScenes`
|
|
73
|
+
<!-- @end -->
|
|
74
|
+
<!-- @if server -->
|
|
75
|
+
- `server.ts`: a server of the game, on its field
|
|
76
|
+
<!-- @end -->
|
|
77
|
+
<!-- @if tests -->
|
|
78
|
+
- `tests/`: every example's world made, started and run for five seconds with no page
|
|
79
|
+
<!-- @end -->
|
|
80
|
+
<!-- @if desktop -->
|
|
81
|
+
- `electron/`: the shell around the page, Electron's main process; `src/shell.ts` is all the page asks of it and `src/desktop.ts` what it does with that
|
|
82
|
+
<!-- @end -->
|
|
83
|
+
- `@v12-engine/assets`: the shared models the examples are drawn with (adventurers with their clips, buildings, trees and rocks, props, weapons), served by `assetsPackage()` in `vite.config.ts`. Whose each file is: its group's `CREDITS.md` in `node_modules/@v12-engine/assets/groups/`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** The examples, tested with no page: each one's world made and stepped here as it is in a page (`@v12-engine/engine/testing`) */
|
|
2
|
+
import { createWorldFromMap } from '@v12-engine/engine'
|
|
3
|
+
import { run } from '@v12-engine/engine/testing'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
import { examples, game } from '../src/game'
|
|
6
|
+
import { CATEGORIES, exampleField } from '../src/examples/define'
|
|
7
|
+
|
|
8
|
+
describe('the examples', () => {
|
|
9
|
+
it('fits together: every id it names is its own, every effect has a handler (check)', async () => {
|
|
10
|
+
expect((await game.check()).filter((problem) => problem.level === 'error')).toEqual([])
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('has an id of its own for each example, starting with its category', () => {
|
|
14
|
+
const ids = examples.map((each) => each.id)
|
|
15
|
+
expect(new Set(ids).size).toBe(ids.length)
|
|
16
|
+
for (const each of examples) {
|
|
17
|
+
expect(CATEGORIES.some((category) => category.id === each.category)).toBe(true)
|
|
18
|
+
expect(each.id.startsWith(`${each.category}-`), each.id).toBe(true)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
for (const example of examples)
|
|
23
|
+
it(`plays ${example.id}: its world made from its map, started and run for five seconds`, async () => {
|
|
24
|
+
const map = await (example.map?.() ?? exampleField())
|
|
25
|
+
const world = await createWorldFromMap({ map, rules: game.toRules(), seed: 1 })
|
|
26
|
+
await example.start?.(world, { map, player: map.players[0]?.id })
|
|
27
|
+
run(world, 5)
|
|
28
|
+
world.dispose()
|
|
29
|
+
})
|
|
30
|
+
})
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Areas and shapes: where an effect lands and what it covers. A cone, a ring, a cross and a crescent; ground that burns
|
|
3
|
+
* a while, a wall of fire, an edge that stuns who crosses it; a blast that falls a moment later; a channel; a ray aimed
|
|
4
|
+
* along two points; a zone the caster carries
|
|
5
|
+
*/
|
|
6
|
+
import type { AbilityDef, BuffDef } from '@v12-engine/engine'
|
|
7
|
+
import { exampleField } from '../define'
|
|
8
|
+
import type { Family } from './family'
|
|
9
|
+
import { caster, lineUp } from './kit'
|
|
10
|
+
|
|
11
|
+
const buffs: BuffDef[] = [{ id: 'abilitiesHorizonStun', name: 'Stunned', harmful: true, duration: 1.2, stun: true }]
|
|
12
|
+
|
|
13
|
+
const abilities: AbilityDef[] = [
|
|
14
|
+
{
|
|
15
|
+
// a quarter-circle from the caster toward the spot: drawn on the ground while aiming, flashed as it goes off
|
|
16
|
+
id: 'abilitiesBreath',
|
|
17
|
+
name: 'Breath of Fire',
|
|
18
|
+
description: 'A cone of fire, 7 cells long',
|
|
19
|
+
hotkey: 'Q',
|
|
20
|
+
target: 'point',
|
|
21
|
+
range: 7,
|
|
22
|
+
cooldown: 1,
|
|
23
|
+
castTime: 0.3,
|
|
24
|
+
effects: [{ type: 'damage', amount: 90, shape: 'cone', length: 7, angle: Math.PI / 2 }]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
// the outer ring hurts, the middle does not
|
|
28
|
+
id: 'abilitiesDecimate',
|
|
29
|
+
name: 'Decimate',
|
|
30
|
+
description: 'A ring around the caster: the outer 1.5 cells of a 5-cell circle',
|
|
31
|
+
hotkey: 'W',
|
|
32
|
+
target: 'none',
|
|
33
|
+
cooldown: 1,
|
|
34
|
+
castTime: 0.4,
|
|
35
|
+
effects: [{ type: 'damage', amount: 100, shape: 'ring', radius: 5, width: 1.5 }]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
// an X at the spot, 45° off the aim
|
|
39
|
+
id: 'abilitiesCross',
|
|
40
|
+
name: 'Death from Below',
|
|
41
|
+
description: 'An X of blades at the spot',
|
|
42
|
+
hotkey: 'E',
|
|
43
|
+
target: 'point',
|
|
44
|
+
range: 9,
|
|
45
|
+
cooldown: 1,
|
|
46
|
+
castTime: 0.4,
|
|
47
|
+
effects: [{ type: 'damage', amount: 110, shape: 'cross', length: 7, width: 0.7 }]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
// a crescent round the caster, centred on the aim
|
|
51
|
+
id: 'abilitiesCrescent',
|
|
52
|
+
name: 'Crescent Sweep',
|
|
53
|
+
description: 'A crescent swept round in front of the caster',
|
|
54
|
+
hotkey: 'R',
|
|
55
|
+
target: 'direction',
|
|
56
|
+
range: 6,
|
|
57
|
+
cooldown: 1,
|
|
58
|
+
castTime: 0.25,
|
|
59
|
+
effects: [{ type: 'damage', amount: 80, shape: 'arc', radius: 7, angle: Math.PI / 1.5, width: 2 }]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
// a zone: its effects run on those inside four times a second, for its duration
|
|
63
|
+
id: 'abilitiesFlameStrike',
|
|
64
|
+
name: 'Flame Strike',
|
|
65
|
+
description: 'Burns the ground for 5 seconds',
|
|
66
|
+
hotkey: 'T',
|
|
67
|
+
target: 'point',
|
|
68
|
+
range: 10,
|
|
69
|
+
cooldown: 1,
|
|
70
|
+
effects: [{ type: 'zone', radius: 2.5, duration: 5, effects: [{ type: 'damage', amount: 8 }] }]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
// a shaped zone keeps the way it was cast
|
|
74
|
+
id: 'abilitiesFireWall',
|
|
75
|
+
name: 'Wall of Fire',
|
|
76
|
+
description: 'A wall of fire across the way, for 6 seconds',
|
|
77
|
+
hotkey: 'D',
|
|
78
|
+
target: 'point',
|
|
79
|
+
range: 10,
|
|
80
|
+
cooldown: 1,
|
|
81
|
+
effects: [{ type: 'zone', duration: 6, shape: 'rect', length: 7, width: 0.5, effects: [{ type: 'damage', amount: 10 }] }]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
// whoever crosses its edge, in or out, is stunned
|
|
85
|
+
id: 'abilitiesEventHorizon',
|
|
86
|
+
name: 'Event Horizon',
|
|
87
|
+
description: 'A ring that stuns whoever crosses its edge, for 4 seconds',
|
|
88
|
+
hotkey: 'F',
|
|
89
|
+
target: 'point',
|
|
90
|
+
range: 10,
|
|
91
|
+
cooldown: 1,
|
|
92
|
+
effects: [{ type: 'zone', duration: 4, radius: 3, edge: [{ type: 'buff', buff: 'abilitiesHorizonStun' }] }]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
// lands a moment later where it was aimed: the screen marks the spot until then
|
|
96
|
+
id: 'abilitiesMeteor',
|
|
97
|
+
name: 'Meteor',
|
|
98
|
+
description: 'A star falls on the spot 1.2 seconds later',
|
|
99
|
+
hotkey: 'G',
|
|
100
|
+
target: 'point',
|
|
101
|
+
range: 10,
|
|
102
|
+
cooldown: 1,
|
|
103
|
+
effects: [{ type: 'after', delay: 1.2, effects: [{ type: 'damage', amount: 220, radius: 3 }] }]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
// a channel: the caster stands and keeps it up, its effects every second; another order breaks it
|
|
107
|
+
id: 'abilitiesBlizzard',
|
|
108
|
+
name: 'Blizzard',
|
|
109
|
+
description: 'Ice falls on the spot every second for 5 seconds, while the caster keeps it up',
|
|
110
|
+
hotkey: 'Z',
|
|
111
|
+
target: 'point',
|
|
112
|
+
range: 10,
|
|
113
|
+
cooldown: 1,
|
|
114
|
+
aim: { shape: 'circle', radius: 2.5 },
|
|
115
|
+
effects: [],
|
|
116
|
+
channel: { duration: 5, every: 1, effects: [{ type: 'damage', amount: 40, radius: 2.5 }] }
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
// two points: where it starts, then which way
|
|
120
|
+
id: 'abilitiesDeathRay',
|
|
121
|
+
name: 'Death Ray',
|
|
122
|
+
description: 'Aimed by two points, where it starts and which way: a ray across the line of enemies',
|
|
123
|
+
hotkey: 'X',
|
|
124
|
+
target: 'vector',
|
|
125
|
+
range: 10,
|
|
126
|
+
cooldown: 1,
|
|
127
|
+
effects: [{ type: 'missile', speed: 20, distance: 8, radius: 0.8, effects: [{ type: 'damage', amount: 90 }] }]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
// carried: it moves and turns with the caster
|
|
131
|
+
id: 'abilitiesFlamespitter',
|
|
132
|
+
name: 'Flamespitter',
|
|
133
|
+
description: 'A cone of fire in front of the caster for 3 seconds, wherever it walks',
|
|
134
|
+
hotkey: 'C',
|
|
135
|
+
target: 'none',
|
|
136
|
+
cooldown: 1,
|
|
137
|
+
effects: [
|
|
138
|
+
{ type: 'zone', duration: 3, follow: 'caster', effects: [{ type: 'damage', amount: 6, shape: 'cone', length: 5, angle: Math.PI / 2.5 }] }
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
export const areas: Family = {
|
|
144
|
+
abilities,
|
|
145
|
+
buffs,
|
|
146
|
+
units: [
|
|
147
|
+
caster(
|
|
148
|
+
'abilitiesShaper',
|
|
149
|
+
'Area mage',
|
|
150
|
+
abilities.map((each) => each.id)
|
|
151
|
+
)
|
|
152
|
+
],
|
|
153
|
+
example: {
|
|
154
|
+
id: 'abilities-areas',
|
|
155
|
+
category: 'abilities',
|
|
156
|
+
title: 'Areas and shapes',
|
|
157
|
+
summary:
|
|
158
|
+
'Cones, rings, crosses and crescents, burning ground, a wall of fire, a stunning edge, a falling star, a channel, a ray aimed by two points and a zone the caster carries. Each shows its shape on the ground as it goes off.',
|
|
159
|
+
tags: ['area', 'cone', 'line', 'ring', 'cross', 'arc', 'zone', 'channel', 'vector', 'delayed', 'telegraph'],
|
|
160
|
+
source: ['examples/abilities/areas.ts', 'examples/abilities/kit.ts'],
|
|
161
|
+
map: () => exampleField({ name: 'Areas', players: 2 }),
|
|
162
|
+
// the sparring footmen are the damage example's (`./damage.ts`)
|
|
163
|
+
start: (world) => lineUp(world, 'abilitiesShaper', 'abilitiesTarget', 5)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** How the areas example looks, and its card: a button for each shape (`./areas.ts`) */
|
|
2
|
+
import { sharedLooks } from '../common/looks'
|
|
3
|
+
import { areas } from './areas'
|
|
4
|
+
import type { FamilyLooks } from './looks'
|
|
5
|
+
import { castButton, look, readyOn, resetButton } from './lookKit'
|
|
6
|
+
|
|
7
|
+
export const areasLooks: FamilyLooks = {
|
|
8
|
+
units: { abilitiesShaper: sharedLooks.mage },
|
|
9
|
+
abilities: {
|
|
10
|
+
abilitiesBreath: look([1, 0.45, 0.1], 'burst'),
|
|
11
|
+
abilitiesDecimate: look([0.85, 0.15, 0.1], 'slam'),
|
|
12
|
+
abilitiesCross: look([0.3, 0.8, 0.75], 'smash'),
|
|
13
|
+
abilitiesCrescent: look([0.75, 0.85, 1], 'slam'),
|
|
14
|
+
// the fall a mark, then the zone burning for its life
|
|
15
|
+
abilitiesFlameStrike: look([1, 0.5, 0.1], 'mark', { options: { column: true, burst: 30 } }),
|
|
16
|
+
abilitiesFireWall: look([1, 0.35, 0.05], 'ring'),
|
|
17
|
+
abilitiesEventHorizon: look([0.6, 0.3, 1], 'ring'),
|
|
18
|
+
abilitiesMeteor: look([1, 0.55, 0.2], 'mark', { options: { lasts: 1.2, falls: 18, fill: true, burst: 40, sparks: 20 } }),
|
|
19
|
+
abilitiesBlizzard: look([0.7, 0.9, 1], 'barrage'),
|
|
20
|
+
abilitiesDeathRay: look([1, 0.3, 0.3], 'missile', { options: { shape: 'hawk' } }),
|
|
21
|
+
abilitiesFlamespitter: look([1, 0.5, 0.1], 'ring'),
|
|
22
|
+
abilitiesHorizonStun: look([0.6, 0.3, 1], undefined, { aura: 'glow', options: { shape: 'ring', at: 'head' } })
|
|
23
|
+
},
|
|
24
|
+
examples: {
|
|
25
|
+
'abilities-areas': {
|
|
26
|
+
ready: (client) => readyOn(client, 'abilitiesShaper'),
|
|
27
|
+
controls: [...areas.abilities.map((ability) => castButton(ability)), resetButton('abilities-areas')]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|