@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
|
@@ -3,6 +3,7 @@ import { Color3 } from '@babylonjs/core/Maths/math.color.js'
|
|
|
3
3
|
import { CreateCylinder } from '@babylonjs/core/Meshes/Builders/cylinderBuilder.js'
|
|
4
4
|
import type { AbilityLooks, ModelDef, ShotContext, ShotDrawing, UnitLooks } from '@v12-engine/client'
|
|
5
5
|
import { building } from './buildings'
|
|
6
|
+
import { DUAL_WIELD, ONE_HANDED } from './attacks'
|
|
6
7
|
|
|
7
8
|
/*
|
|
8
9
|
* How the Restless looks (features-plan C4): the shared art's skeletons with their own gear, and its Fantasy RTS
|
|
@@ -68,7 +69,7 @@ export const undeadLooks: UnitLooks = {
|
|
|
68
69
|
blood: false,
|
|
69
70
|
height: 1.5,
|
|
70
71
|
model: skeleton('characters/skeleton_minion.glb', 0.6, 'skeleton-gear/staff.glb'),
|
|
71
|
-
|
|
72
|
+
shapes: [
|
|
72
73
|
...bones(1.5),
|
|
73
74
|
{ shape: 'sphere', size: [0.42, 0.36, 0.42], offset: [0, 0.75, -0.34], color: GOLD, carrying: 'gold' },
|
|
74
75
|
{ shape: 'cylinder', size: [0.22, 0.9, 0.22], offset: [0, 0.8, -0.34], color: WOOD, tilt: Math.PI / 2, turn: Math.PI / 2, carrying: 'lumber' }
|
|
@@ -78,9 +79,10 @@ export const undeadLooks: UnitLooks = {
|
|
|
78
79
|
blood: false,
|
|
79
80
|
height: 1.6,
|
|
80
81
|
model: skeleton('characters/skeleton_minion.glb', 0.68, 'skeleton-gear/blade.glb', 'skeleton-gear/blade.glb'),
|
|
82
|
+
attacks: [DUAL_WIELD],
|
|
81
83
|
// packs of them: drawn as copies of one mesh, their animations baked (S41)
|
|
82
84
|
baked: true,
|
|
83
|
-
|
|
85
|
+
shapes: bones(1.6)
|
|
84
86
|
},
|
|
85
87
|
cryptCrawler: {
|
|
86
88
|
blood: false,
|
|
@@ -88,23 +90,24 @@ export const undeadLooks: UnitLooks = {
|
|
|
88
90
|
model: {
|
|
89
91
|
...skeleton('characters/skeleton_rogue.glb', 0.75, 'skeleton-gear/crossbow.glb'),
|
|
90
92
|
animations: { attack: 'Ranged_2H_Shoot' },
|
|
91
|
-
|
|
93
|
+
clips: { Ranged_2H_Shoot: { marks: [{ name: 'hit', at: 0.3 }] } }
|
|
92
94
|
},
|
|
93
95
|
shot: { color: [0.55, 0.85, 0.45], size: 0.25 },
|
|
94
|
-
|
|
96
|
+
shapes: bones(1.7)
|
|
95
97
|
},
|
|
96
98
|
abomination: {
|
|
97
99
|
blood: false,
|
|
98
100
|
height: 2.6,
|
|
99
101
|
model: skeleton('characters/skeleton_warrior.glb', 1.2, 'skeleton-gear/axe.glb', 'skeleton-gear/shield_large_a.glb'),
|
|
100
|
-
|
|
102
|
+
attacks: [ONE_HANDED],
|
|
103
|
+
shapes: bones(2.6)
|
|
101
104
|
},
|
|
102
105
|
necromancer: {
|
|
103
106
|
blood: false,
|
|
104
107
|
height: 1.8,
|
|
105
108
|
model: { ...skeleton('characters/skeleton_mage.glb', 0.75, 'skeleton-gear/staff.glb'), animations: { attack: 'Ranged_Magic_Shoot' } },
|
|
106
109
|
shot: { color: [0.55, 0.85, 0.45], size: 0.3 },
|
|
107
|
-
|
|
110
|
+
shapes: bones(1.8)
|
|
108
111
|
},
|
|
109
112
|
gargoyle: {
|
|
110
113
|
blood: false,
|
|
@@ -112,40 +115,58 @@ export const undeadLooks: UnitLooks = {
|
|
|
112
115
|
model: skeleton('characters/skeleton_minion.glb', 0.75, 'skeleton-gear/axe.glb'),
|
|
113
116
|
altitude: 3.2,
|
|
114
117
|
shot: { color: [0.6, 0.6, 0.65], size: 0.3 },
|
|
115
|
-
|
|
118
|
+
shapes: bones(1.6)
|
|
116
119
|
},
|
|
117
|
-
|
|
120
|
+
// ---- the Restless' heroes (`heroes.ts`)
|
|
121
|
+
gravelord: {
|
|
118
122
|
blood: false,
|
|
119
123
|
height: 2.3,
|
|
120
124
|
model: skeleton('characters/skeleton_warrior.glb', 0.95, 'skeleton-gear/blade.glb', 'skeleton-gear/shield_small_a.glb'),
|
|
121
|
-
|
|
125
|
+
// a hero's blade: a streak of blood behind it
|
|
126
|
+
attacks: [{ ...ONE_HANDED, trail: { color: [0.8, 0.15, 0.2], width: 0.16 } }],
|
|
127
|
+
shapes: bones(2.3)
|
|
122
128
|
},
|
|
123
|
-
|
|
129
|
+
rimeWitch: {
|
|
124
130
|
blood: false,
|
|
125
131
|
height: 2.2,
|
|
126
132
|
model: { ...skeleton('characters/skeleton_mage.glb', 1, 'skeleton-gear/staff.glb'), animations: { attack: 'Ranged_Magic_Shoot' } },
|
|
127
133
|
shot: { color: [0.55, 0.85, 1], size: 0.35 },
|
|
128
|
-
|
|
134
|
+
shapes: bones(2.2)
|
|
129
135
|
},
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
duskblade: {
|
|
137
|
+
blood: false,
|
|
138
|
+
height: 2.1,
|
|
139
|
+
model: skeleton('characters/skeleton_rogue.glb', 0.9, 'skeleton-gear/blade.glb', 'skeleton-gear/blade.glb'),
|
|
140
|
+
// two blades: both together, and each alone, with a dusk-violet streak
|
|
141
|
+
attacks: [{ ...DUAL_WIELD, trail: { color: [0.6, 0.35, 0.9], width: 0.12 } }],
|
|
142
|
+
shapes: bones(2.1)
|
|
143
|
+
},
|
|
144
|
+
boneReaver: {
|
|
145
|
+
blood: false,
|
|
146
|
+
height: 2.6,
|
|
147
|
+
model: skeleton('characters/skeleton_warrior.glb', 1.1, 'skeleton-gear/axe.glb'),
|
|
148
|
+
attacks: [{ ...ONE_HANDED, trail: { color: [0.9, 0.85, 0.7], width: 0.18 } }],
|
|
149
|
+
shapes: bones(2.6)
|
|
150
|
+
},
|
|
151
|
+
gravehold: { height: 4.6, model: building('rts/wooden_temple.glb', 3.6), shapes: crypt(3.6, 4.6) },
|
|
152
|
+
hallOfBones: { height: 5.6, model: building('rts/fortress.glb', 3.7), shapes: crypt(3.7, 5.6) },
|
|
153
|
+
duskCitadel: { height: 6.6, model: building('rts/wooden_fortress.glb', 3.9), shapes: crypt(3.8, 6.6) },
|
|
133
154
|
// over the gold mine's own model, a little bigger
|
|
134
|
-
cursedMine: { height: 3.4, model: building('rts/mine.glb', 4),
|
|
135
|
-
boneSpire: { height: 2.4, model: building('rts/wooden_monument.glb', 1.9),
|
|
136
|
-
crypt: { height: 3.2, model: building('rts/storage_house.glb', 2.7),
|
|
137
|
-
graveyard: { height: 3, model: building('rts/houses.glb', 2.7),
|
|
138
|
-
darkAltar: { height: 3.6, model: building('rts/temple.glb', 2.8),
|
|
139
|
-
slaughterhouse: { height: 3.4, model: building('rts/storage_shed.glb', 2.7),
|
|
140
|
-
temple: { height: 3.6, model: building('rts/temple_2.glb', 2.6),
|
|
155
|
+
cursedMine: { height: 3.4, model: building('rts/mine.glb', 4), shapes: crypt(4, 3.4) },
|
|
156
|
+
boneSpire: { height: 2.4, model: building('rts/wooden_monument.glb', 1.9), shapes: crypt(1.7, 2.4) },
|
|
157
|
+
crypt: { height: 3.2, model: building('rts/storage_house.glb', 2.7), shapes: crypt(2.7, 3.2) },
|
|
158
|
+
graveyard: { height: 3, model: building('rts/houses.glb', 2.7), shapes: crypt(2.7, 3) },
|
|
159
|
+
darkAltar: { height: 3.6, model: building('rts/temple.glb', 2.8), shapes: crypt(2.8, 3.6) },
|
|
160
|
+
slaughterhouse: { height: 3.4, model: building('rts/storage_shed.glb', 2.7), shapes: crypt(2.7, 3.4) },
|
|
161
|
+
temple: { height: 3.6, model: building('rts/temple_2.glb', 2.6), shapes: crypt(2.6, 3.6) },
|
|
141
162
|
spiritTower: {
|
|
142
163
|
height: 4.4,
|
|
143
164
|
model: building('rts/stone_tower_2.glb', 1.9, { points: { launch: { offset: [0, 3, 0] } } }),
|
|
144
165
|
// a beam of the dead's green from the tower's top to where the shot is: drawn by melee, not the client
|
|
145
166
|
shot: { draw: beam([0.55, 0.95, 0.45]) },
|
|
146
|
-
|
|
167
|
+
shapes: crypt(1.5, 4.4)
|
|
147
168
|
},
|
|
148
|
-
tomb: { height: 3.2, model: building('rts/archery_towers.glb', 2.7),
|
|
169
|
+
tomb: { height: 3.2, model: building('rts/archery_towers.glb', 2.7), shapes: crypt(2.7, 3.2) }
|
|
149
170
|
}
|
|
150
171
|
|
|
151
172
|
/** What the Restless' buildings are darkened with */
|
|
@@ -173,14 +194,32 @@ for (const id of [
|
|
|
173
194
|
}
|
|
174
195
|
|
|
175
196
|
export const undeadEffects: AbilityLooks = {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
197
|
+
// the Restless' heroes
|
|
198
|
+
graveLash: { color: [0.75, 0.15, 0.2] },
|
|
199
|
+
graveChill: { color: [0.55, 0.3, 0.45] },
|
|
200
|
+
siphon: { color: [0.8, 0.1, 0.2], style: 'tether' },
|
|
201
|
+
deathless: { color: [0.55, 0.85, 0.45] },
|
|
202
|
+
armyOfTheGrave: { color: [0.55, 0.85, 0.45], style: 'burst', options: { count: 80, rise: 2.5, shape: 'rise' } },
|
|
203
|
+
graveRallied: { color: [0.8, 0.2, 0.25] },
|
|
204
|
+
bloodTithe: { color: [0.7, 0.1, 0.15] },
|
|
205
|
+
rimeBolt: { color: [0.55, 0.85, 1] },
|
|
206
|
+
frozen: { color: [0.62, 0.86, 1] },
|
|
207
|
+
grasp: { color: [0.62, 0.86, 1], style: 'burst', options: { count: 60, ring: 2.5, shape: 'about' } },
|
|
208
|
+
iceRooted: { color: [0.62, 0.86, 1] },
|
|
209
|
+
frostbitten: { color: [0.62, 0.86, 1] },
|
|
210
|
+
whiteout: { color: [0.85, 0.93, 1], style: 'mark', options: { lasts: 5, radius: 4.5, sparks: 30 } },
|
|
211
|
+
whiteoutChill: { color: [0.85, 0.93, 1] },
|
|
212
|
+
duskMark: { color: [0.6, 0.35, 0.9] },
|
|
213
|
+
faded: { color: [0.45, 0.35, 0.6] },
|
|
214
|
+
shadowed: { color: [0.35, 0.25, 0.5] },
|
|
215
|
+
hushed: { color: [0.6, 0.35, 0.9] },
|
|
216
|
+
eclipse: { color: [0.4, 0.2, 0.6], style: 'burst', options: { count: 50, shape: 'about' } },
|
|
217
|
+
eclipsed: { color: [0.4, 0.2, 0.6] },
|
|
218
|
+
boneCleaver: { color: [0.9, 0.85, 0.7], style: 'burst', options: { count: 50, ring: 3, shape: 'about' } },
|
|
219
|
+
gorge: { color: [0.75, 0.15, 0.2] },
|
|
220
|
+
bonePit: { color: [0.9, 0.85, 0.7], style: 'mark', options: { lasts: 4, radius: 4.5, sparks: 24 } },
|
|
221
|
+
bonePitFrenzy: { color: [0.9, 0.85, 0.7] },
|
|
222
|
+
harvest: { color: [0.75, 0.15, 0.2] },
|
|
184
223
|
unholyFrenzy: { color: [0.9, 0.3, 0.25] },
|
|
185
224
|
crippled: { color: [0.5, 0.35, 0.6] },
|
|
186
225
|
webbed: { color: [0.9, 0.9, 0.85] },
|
|
@@ -6,7 +6,7 @@ import { blightLayer } from '../blight'
|
|
|
6
6
|
type CardButtons = NonNullable<NonNullable<GameView['hud']>['cardButtons']>
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* The button of a gate of the player's (`
|
|
9
|
+
* The button of a gate of the player's (`wallsPack`, `wall.gate`): Open while it is shut, Shut while it is open, for
|
|
10
10
|
* everyone (`wallGateCommand`). On the card of the gate picked first, once it stands
|
|
11
11
|
*/
|
|
12
12
|
export const gateButtons: CardButtons = ({ primary }) => {
|
package/starters.mjs
CHANGED
|
@@ -21,6 +21,12 @@ export const starters = [
|
|
|
21
21
|
title: 'A campaign',
|
|
22
22
|
summary: 'three missions with a hero carried between them: a base to defend, a siege of waves at night, a warlord to face',
|
|
23
23
|
needs: ['assets']
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'examples',
|
|
27
|
+
title: 'Examples',
|
|
28
|
+
summary: "what the engine can do, a small scene each, browsed from a list as three.js's examples are: to read, copy and change",
|
|
29
|
+
needs: ['assets']
|
|
24
30
|
}
|
|
25
31
|
]
|
|
26
32
|
|
package/v12.mjs
CHANGED
|
@@ -6,22 +6,22 @@
|
|
|
6
6
|
* | merge <base> <ours> <theirs> | generate <game> <name> [--generator id] [--seed N] …
|
|
7
7
|
* v12 save diff <a> <b>
|
|
8
8
|
*
|
|
9
|
-
* The project is read as its page reads it, through its own Vite, so its game (`src/game.ts`: every game
|
|
10
|
-
* `
|
|
9
|
+
* The project is read as its page reads it, through its own Vite, so its game (`src/game.ts`: every game made there,
|
|
10
|
+
* `createGame`) and a script for `map run` are TypeScript with nothing built first. Its maps are in `src/maps`
|
|
11
11
|
*/
|
|
12
|
-
import { readFileSync } from 'node:fs'
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
13
13
|
import { createRequire } from 'node:module'
|
|
14
14
|
import { join, resolve } from 'node:path'
|
|
15
15
|
import { pathToFileURL } from 'node:url'
|
|
16
16
|
|
|
17
17
|
const [command, ...args] = process.argv.slice(2)
|
|
18
18
|
|
|
19
|
-
/** The project's games: every game
|
|
20
|
-
function gamesOf(module) {
|
|
19
|
+
/** The project's games: every game made in its `src/game.ts` (what `createGame` gives), its rules and its view fetched */
|
|
20
|
+
async function gamesOf(module) {
|
|
21
21
|
const games = {}
|
|
22
22
|
for (const value of Object.values(module)) {
|
|
23
|
-
if (value && typeof value === 'object' && typeof value.id === 'string' && value.
|
|
24
|
-
games[value.id] = { module: value.
|
|
23
|
+
if (value && typeof value === 'object' && typeof value.id === 'string' && typeof value.toRules === 'function' && value.hasView) {
|
|
24
|
+
games[value.id] = { module: value.toRules(), view: await value.toView() }
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
return games
|
|
@@ -38,14 +38,13 @@ async function map(project) {
|
|
|
38
38
|
logLevel: 'error'
|
|
39
39
|
})
|
|
40
40
|
try {
|
|
41
|
-
const games = gamesOf(await server.ssrLoadModule('/src/game.ts'))
|
|
42
|
-
if (!Object.keys(games).length) throw new Error('src/game.ts
|
|
43
|
-
// the map editor's: a project made without the editor has no map command
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
41
|
+
const games = await gamesOf(await server.ssrLoadModule('/src/game.ts'))
|
|
42
|
+
if (!Object.keys(games).length) throw new Error('src/game.ts makes no game (`export const game = createGame({ id, name })`, with its view)')
|
|
43
|
+
// the map editor's: a project made without the editor has no map command. Whether the package is there, not whether
|
|
44
|
+
// its command resolves: in the library's own repository the packages are read as they are written, nothing built,
|
|
45
|
+
// and the command's file resolves through Vite below, not through Node
|
|
46
|
+
const editor = (require.resolve.paths('@v12-engine/editor') ?? []).some((dir) => existsSync(join(dir, '@v12-engine/editor/package.json')))
|
|
47
|
+
if (!editor) throw new Error("v12 map is the map editor's: this project has none. npm install @v12-engine/editor")
|
|
49
48
|
const { mapCommand } = await server.ssrLoadModule('@v12-engine/editor/map-command')
|
|
50
49
|
return await mapCommand(args, {
|
|
51
50
|
games,
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The rules: the campaign's, in `src/campaign`. Its units, its missions and its waves are in that folder; this is the
|
|
3
|
-
* name every part of the project knows them by
|
|
4
|
-
*/
|
|
5
|
-
import type { GameMap, World } from '@v12-engine/engine'
|
|
6
|
-
import { campaign, startMission } from './campaign'
|
|
7
|
-
|
|
8
|
-
export { ENEMY, PLAYER, UNIT } from './campaign'
|
|
9
|
-
|
|
10
|
-
export const rules = campaign
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* What the game does once a world is made from a map, before anyone plays: the map's mission is given (each map is
|
|
14
|
-
* a mission's; a map of none plays on with no objectives). The page's free play, the server, the tests and the
|
|
15
|
-
* editor's Play here each call it with the map; the campaign's own scene gives the mission itself, knowing whether
|
|
16
|
-
* the game is new or loaded from a save
|
|
17
|
-
*/
|
|
18
|
-
export function start(world: World, { map }: { map?: GameMap }): void {
|
|
19
|
-
startMission(world, map)
|
|
20
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The maps of the game. There is one, made here in code: a flat field with a player on it and a road across it.
|
|
3
|
-
// @if editor
|
|
4
|
-
* The map editor (`npm run dev`, then `/?editor`) opens it, and Save writes it into `src/maps/field.vgmap.json`. From
|
|
5
|
-
* then on the file is the map: import it here in its place, as the lines below say, and `flatField` can go
|
|
6
|
-
// @end
|
|
7
|
-
*/
|
|
8
|
-
import { createMap, type GameMap } from '@v12-engine/engine'
|
|
9
|
-
import { tiles } from './tiles'
|
|
10
|
-
// @if editor
|
|
11
|
-
// import { mapsFrom } from '@v12-engine/engine'
|
|
12
|
-
// import field from './maps/field.vgmap.json'
|
|
13
|
-
// @end
|
|
14
|
-
|
|
15
|
-
/** A flat field of 32 cells a side, a player with a start in its middle, and a road across it */
|
|
16
|
-
function flatField(): GameMap {
|
|
17
|
-
const map = createMap({ name: 'Field', width: 32, depth: 32, players: 1, game: 'my-game', tileset: tiles.map((tile) => tile.id) })
|
|
18
|
-
map.players[0].start = { x: 16, z: 16 }
|
|
19
|
-
// a cell's paint is the place of its tile in the map's tileset, from 1 (0 is none: the ground's own colour)
|
|
20
|
-
const road = map.tileset.indexOf('road') + 1
|
|
21
|
-
for (let z = 20; z < 22; z++) for (let x = 0; x < map.width; x++) map.tiles[z * map.width + x] = road
|
|
22
|
-
return map
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** The maps by name */
|
|
26
|
-
// @if editor
|
|
27
|
-
// once the editor has saved the field: mapsFrom({ './maps/field.vgmap.json': field })
|
|
28
|
-
// @end
|
|
29
|
-
export const maps: Readonly<Record<string, GameMap>> = { field: flatField() }
|
|
30
|
-
|
|
31
|
-
// @if editor
|
|
32
|
-
/** The map a game is on when nothing says which, and the one the editor opens first */
|
|
33
|
-
// @end
|
|
34
|
-
// @if !editor
|
|
35
|
-
/** The map a game is on when nothing says which */
|
|
36
|
-
// @end
|
|
37
|
-
export const DEFAULT_MAP = 'field'
|
|
38
|
-
|
|
39
|
-
/** A map by name, as a copy: a game changes nothing of what the next one starts from */
|
|
40
|
-
export function mapNamed(name = DEFAULT_MAP): GameMap {
|
|
41
|
-
const map = maps[name]
|
|
42
|
-
if (!map) throw new Error(`There is no map "${name}": the maps are ${Object.keys(maps).join(', ')}`)
|
|
43
|
-
return structuredClone(map)
|
|
44
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What the ground can be painted with: the rules' names for it, which the map editor's Paint offers and the rules read
|
|
3
|
-
* (`world.registry.tile('road')`). How each looks is the game's look's (`tiles` in `src/game.ts`). A new one is a line
|
|
4
|
-
* here and one there; a map keeps its paint by these names, so their order can change
|
|
5
|
-
*/
|
|
6
|
-
import { presetTiles } from '@v12-engine/engine'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The engine's tiles of an RTS (grass, dark grass, dirt, road, sand, rock, snow), drawn with the client's `TILE_LOOKS`.
|
|
10
|
-
* A game's own goes beside them: `defineTile({ id: 'lava', name: 'Lava' })` here, its look in `src/game.ts`
|
|
11
|
-
*/
|
|
12
|
-
export const tiles = [...presetTiles]
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { AbilityDef, BuffDef } from '@v12-engine/engine'
|
|
2
|
-
|
|
3
|
-
/** The spells every hero brings along (`HeroDef.spells`): learned from the start, one point each, on long cooldowns */
|
|
4
|
-
|
|
5
|
-
export const heroSpellBuffs: BuffDef[] = [
|
|
6
|
-
{ id: 'healHaste', name: 'Second Wind', description: 'Moves 30% faster', duration: 1, percent: { moveSpeed: 0.3 } },
|
|
7
|
-
{ id: 'barrier', name: 'Barrier', description: 'A shield takes the damage', duration: 2.5, shield: 120, shieldScaling: { level: 21.2 } }
|
|
8
|
-
]
|
|
9
|
-
|
|
10
|
-
export const heroSpells: AbilityDef[] = [
|
|
11
|
-
{
|
|
12
|
-
id: 'flash',
|
|
13
|
-
name: 'Flash',
|
|
14
|
-
description: 'At once a short way towards the pointer, through whatever is in between',
|
|
15
|
-
target: 'direction',
|
|
16
|
-
cooldown: 300,
|
|
17
|
-
effects: [{ type: 'blink', distance: 5.3 }]
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
id: 'secondWind',
|
|
21
|
-
name: 'Second Wind',
|
|
22
|
-
description: 'The hero and allied heroes nearby regain 80 to 318 health, more with every level, and run 30% faster for a second',
|
|
23
|
-
target: 'none',
|
|
24
|
-
cooldown: 240,
|
|
25
|
-
effects: [
|
|
26
|
-
{ type: 'heal', amount: 80, scaling: { level: 14 }, radius: 10.9, only: 'heroes' },
|
|
27
|
-
{ type: 'buff', buff: 'healHaste', radius: 10.9, only: 'heroes' }
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: 'barrier',
|
|
32
|
-
name: 'Barrier',
|
|
33
|
-
description: 'A shield for 2.5 seconds that takes 120 to 480 damage, more with every level',
|
|
34
|
-
target: 'none',
|
|
35
|
-
cooldown: 180,
|
|
36
|
-
effects: [{ type: 'buff', buff: 'barrier', on: 'caster' }]
|
|
37
|
-
}
|
|
38
|
-
]
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The rules: melee's, in `src/melee`. Its races, heroes, units, buildings and the generator of its random maps are
|
|
3
|
-
* in that folder; this is the name every part of the project knows them by
|
|
4
|
-
*/
|
|
5
|
-
import type { GameMap, PlayerId, World } from '@v12-engine/engine'
|
|
6
|
-
import { melee } from './melee'
|
|
7
|
-
|
|
8
|
-
export const rules = melee
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* What the game does once a world is made from a map, before anyone plays. Every player with a start is given a hall
|
|
12
|
-
* and five workers by the rules themselves; in the page, the computer plays everyone but you, each against the other
|
|
13
|
-
* teams' starts. A server seats its computers itself (`server.ts`), so there is no one to seat here
|
|
14
|
-
*/
|
|
15
|
-
export function start(world: World, { map, player }: { map?: GameMap; player?: PlayerId }): void {
|
|
16
|
-
if (!map || player === undefined) return
|
|
17
|
-
const players = map.players.filter((other) => other.start)
|
|
18
|
-
for (const other of players) {
|
|
19
|
-
if (other.id === player) continue
|
|
20
|
-
const enemyBases = players.filter((rival) => rival.team !== other.team).map((rival) => rival.start!)
|
|
21
|
-
// remembered, so that a game loaded from a save of this one plays on against them
|
|
22
|
-
world.computers.seat(other.id, { enemyBases, settings: { army: { firstAttack: 360, waveSize: 6 } } })
|
|
23
|
-
}
|
|
24
|
-
}
|