@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.
Files changed (263) hide show
  1. package/README.md +4 -1
  2. package/base/_gitignore +5 -0
  3. package/base/package.json +3 -3
  4. package/base/src/main.ts +36 -10
  5. package/base/src/navigation.worker.ts +7 -0
  6. package/base/vite.config.ts +24 -2
  7. package/cli.mjs +21 -6
  8. package/index.mjs +27 -7
  9. package/layers/desktop/electron/app.mjs +237 -0
  10. package/layers/desktop/electron/config.mjs +16 -0
  11. package/layers/desktop/electron/dev.mjs +63 -0
  12. package/layers/desktop/electron/files.mjs +86 -0
  13. package/layers/desktop/electron/icons/icon.icns +0 -0
  14. package/layers/desktop/electron/icons/icon.png +0 -0
  15. package/layers/desktop/electron/main.mjs +12 -0
  16. package/layers/desktop/electron/package.mjs +75 -0
  17. package/layers/desktop/electron/preload.cjs +41 -0
  18. package/layers/desktop/electron/presentation.m +87 -0
  19. package/layers/desktop/electron/serve.mjs +76 -0
  20. package/layers/desktop/electron/tools.mjs +63 -0
  21. package/layers/desktop/electron/updates.mjs +71 -0
  22. package/layers/desktop/package.json +13 -0
  23. package/layers/desktop/src/desktop.ts +175 -0
  24. package/layers/desktop/src/shell.ts +279 -0
  25. package/layers/desktop/tests/main.test.ts +189 -0
  26. package/layers/desktop/tests/shell.test.ts +152 -0
  27. package/layers/rooms/server.ts +13 -10
  28. package/layers/server/server.ts +4 -5
  29. package/layers/source/vite.config.ts +21 -1
  30. package/package.json +2 -1
  31. package/starters/campaign/README.md +9 -2
  32. package/starters/campaign/layers/rooms/server.ts +3 -3
  33. package/starters/campaign/layers/server/server.ts +3 -5
  34. package/starters/campaign/layers/tests/tests/rules.test.ts +40 -21
  35. package/starters/campaign/src/campaign/game.ts +26 -5
  36. package/starters/campaign/src/campaign/index.ts +104 -68
  37. package/starters/campaign/src/campaign/kills.ts +1 -1
  38. package/starters/campaign/src/campaign/missions/homecoming.ts +7 -7
  39. package/starters/campaign/src/campaign/missions/siege.ts +6 -6
  40. package/starters/campaign/src/campaign/missions/warlord.ts +13 -14
  41. package/starters/campaign/src/campaign/scenes.ts +8 -7
  42. package/starters/campaign/src/campaign/units.ts +59 -20
  43. package/starters/campaign/src/campaign/view/attacks.ts +19 -0
  44. package/starters/campaign/src/campaign/view/fire.ts +2 -2
  45. package/starters/campaign/src/campaign/view/index.ts +54 -43
  46. package/starters/campaign/src/campaign/waves.ts +18 -17
  47. package/starters/campaign/src/game.ts +8 -1
  48. package/starters/campaign/src/main.ts +38 -19
  49. package/starters/campaign/src/maps/fort.names.ts +2 -2
  50. package/starters/campaign/src/maps/fort.vgmap.json +102 -2
  51. package/starters/campaign/src/maps/homestead.names.ts +2 -2
  52. package/starters/campaign/src/maps/homestead.vgmap.json +85 -1
  53. package/starters/campaign/src/maps/pass.names.ts +2 -2
  54. package/starters/campaign/src/maps/pass.vgmap.json +69 -1
  55. package/starters/campaign/src/waves-panel.ts +2 -1
  56. package/starters/empty/README.md +18 -10
  57. package/starters/empty/layers/tests/tests/rules.test.ts +16 -17
  58. package/starters/empty/src/game.ts +11 -75
  59. package/starters/empty/src/generate.worker.ts +5 -5
  60. package/starters/empty/src/rules.ts +83 -25
  61. package/starters/empty/src/view.ts +82 -0
  62. package/starters/examples/README.md +83 -0
  63. package/starters/examples/layers/tests/tests/examples.test.ts +30 -0
  64. package/starters/examples/package.json +5 -0
  65. package/starters/examples/src/examples/abilities/areas.ts +165 -0
  66. package/starters/examples/src/examples/abilities/areasLooks.ts +30 -0
  67. package/starters/examples/src/examples/abilities/buffs.ts +287 -0
  68. package/starters/examples/src/examples/abilities/buffsLooks.ts +46 -0
  69. package/starters/examples/src/examples/abilities/changing.ts +228 -0
  70. package/starters/examples/src/examples/abilities/changingLooks.ts +61 -0
  71. package/starters/examples/src/examples/abilities/control.ts +158 -0
  72. package/starters/examples/src/examples/abilities/controlLooks.ts +78 -0
  73. package/starters/examples/src/examples/abilities/damage.ts +156 -0
  74. package/starters/examples/src/examples/abilities/damageLooks.ts +37 -0
  75. package/starters/examples/src/examples/abilities/family.ts +29 -0
  76. package/starters/examples/src/examples/abilities/index.ts +32 -0
  77. package/starters/examples/src/examples/abilities/kit.ts +179 -0
  78. package/starters/examples/src/examples/abilities/lookKit.ts +71 -0
  79. package/starters/examples/src/examples/abilities/looks.ts +47 -0
  80. package/starters/examples/src/examples/abilities/missiles.ts +203 -0
  81. package/starters/examples/src/examples/abilities/missilesLooks.ts +38 -0
  82. package/starters/examples/src/examples/abilities/moves.ts +206 -0
  83. package/starters/examples/src/examples/abilities/movesLooks.ts +52 -0
  84. package/starters/examples/src/examples/abilities/recasts.ts +181 -0
  85. package/starters/examples/src/examples/abilities/recastsLooks.ts +41 -0
  86. package/starters/examples/src/examples/abilities/resources.ts +166 -0
  87. package/starters/examples/src/examples/abilities/resourcesLooks.ts +42 -0
  88. package/starters/examples/src/examples/abilities/summons.ts +296 -0
  89. package/starters/examples/src/examples/abilities/summonsLooks.ts +115 -0
  90. package/starters/examples/src/examples/abilities/triggers.ts +204 -0
  91. package/starters/examples/src/examples/abilities/triggersLooks.ts +53 -0
  92. package/starters/examples/src/examples/abilities/vision.ts +137 -0
  93. package/starters/examples/src/examples/abilities/visionLooks.ts +50 -0
  94. package/starters/examples/src/examples/animation/index.ts +235 -0
  95. package/starters/examples/src/examples/animation/looks.ts +444 -0
  96. package/starters/examples/src/examples/catalog.ts +52 -0
  97. package/starters/examples/src/examples/cinematics/index.ts +217 -0
  98. package/starters/examples/src/examples/cinematics/looks.ts +476 -0
  99. package/starters/examples/src/examples/cinematics/tour.json +43 -0
  100. package/starters/examples/src/examples/cinematics/village.ts +88 -0
  101. package/starters/examples/src/examples/common/looks.ts +65 -0
  102. package/starters/examples/src/examples/common/units.ts +70 -0
  103. package/starters/examples/src/examples/construction/index.ts +329 -0
  104. package/starters/examples/src/examples/construction/looks.ts +275 -0
  105. package/starters/examples/src/examples/custom-animation/bones.ts +92 -0
  106. package/starters/examples/src/examples/custom-animation/index.ts +190 -0
  107. package/starters/examples/src/examples/custom-animation/looks.ts +523 -0
  108. package/starters/examples/src/examples/custom-animation/runes.ts +82 -0
  109. package/starters/examples/src/examples/custom-fx/glaive.look.ts +110 -0
  110. package/starters/examples/src/examples/custom-fx/glaive.ts +40 -0
  111. package/starters/examples/src/examples/custom-fx/gpu.look.ts +145 -0
  112. package/starters/examples/src/examples/custom-fx/gpu.ts +22 -0
  113. package/starters/examples/src/examples/custom-fx/index.ts +25 -0
  114. package/starters/examples/src/examples/custom-fx/lights.look.ts +144 -0
  115. package/starters/examples/src/examples/custom-fx/lights.ts +25 -0
  116. package/starters/examples/src/examples/custom-fx/looks.ts +36 -0
  117. package/starters/examples/src/examples/custom-fx/meteor.look.ts +133 -0
  118. package/starters/examples/src/examples/custom-fx/meteor.ts +26 -0
  119. package/starters/examples/src/examples/custom-fx/parts.look.ts +193 -0
  120. package/starters/examples/src/examples/custom-fx/parts.ts +21 -0
  121. package/starters/examples/src/examples/custom-fx/portal.look.ts +193 -0
  122. package/starters/examples/src/examples/custom-fx/portal.ts +48 -0
  123. package/starters/examples/src/examples/custom-fx/renderer.look.ts +139 -0
  124. package/starters/examples/src/examples/custom-fx/renderer.ts +18 -0
  125. package/starters/examples/src/examples/custom-fx/ribbons.look.ts +151 -0
  126. package/starters/examples/src/examples/custom-fx/ribbons.ts +22 -0
  127. package/starters/examples/src/examples/custom-fx/shader.ts +42 -0
  128. package/starters/examples/src/examples/custom-fx/shield.look.ts +226 -0
  129. package/starters/examples/src/examples/custom-fx/shield.ts +43 -0
  130. package/starters/examples/src/examples/define.ts +86 -0
  131. package/starters/examples/src/examples/destruction/index.ts +570 -0
  132. package/starters/examples/src/examples/destruction/looks.ts +447 -0
  133. package/starters/examples/src/examples/dialogs/index.ts +383 -0
  134. package/starters/examples/src/examples/dialogs/looks.ts +546 -0
  135. package/starters/examples/src/examples/dynamic-map/index.ts +603 -0
  136. package/starters/examples/src/examples/dynamic-map/looks.ts +301 -0
  137. package/starters/examples/src/examples/fx/blood.look.ts +62 -0
  138. package/starters/examples/src/examples/fx/blood.ts +59 -0
  139. package/starters/examples/src/examples/fx/feel.look.ts +86 -0
  140. package/starters/examples/src/examples/fx/feel.ts +57 -0
  141. package/starters/examples/src/examples/fx/fight.ts +28 -0
  142. package/starters/examples/src/examples/fx/floats.look.ts +108 -0
  143. package/starters/examples/src/examples/fx/floats.ts +24 -0
  144. package/starters/examples/src/examples/fx/gallery.look.ts +168 -0
  145. package/starters/examples/src/examples/fx/gallery.ts +23 -0
  146. package/starters/examples/src/examples/fx/index.ts +30 -0
  147. package/starters/examples/src/examples/fx/links.look.ts +83 -0
  148. package/starters/examples/src/examples/fx/links.ts +49 -0
  149. package/starters/examples/src/examples/fx/looks.ts +55 -0
  150. package/starters/examples/src/examples/fx/map.look.ts +93 -0
  151. package/starters/examples/src/examples/fx/map.ts +33 -0
  152. package/starters/examples/src/examples/fx/marks.look.ts +100 -0
  153. package/starters/examples/src/examples/fx/marks.ts +36 -0
  154. package/starters/examples/src/examples/fx/shots.look.ts +92 -0
  155. package/starters/examples/src/examples/fx/shots.ts +71 -0
  156. package/starters/examples/src/examples/fx/spells.look.ts +87 -0
  157. package/starters/examples/src/examples/fx/spells.ts +122 -0
  158. package/starters/examples/src/examples/fx/stage.ts +31 -0
  159. package/starters/examples/src/examples/gui/babylonScreen.ts +167 -0
  160. package/starters/examples/src/examples/gui/babylonWorld.ts +191 -0
  161. package/starters/examples/src/examples/gui/htmlPart.ts +95 -0
  162. package/starters/examples/src/examples/gui/index.ts +143 -0
  163. package/starters/examples/src/examples/gui/keys.ts +91 -0
  164. package/starters/examples/src/examples/gui/layout.ts +42 -0
  165. package/starters/examples/src/examples/gui/looks.ts +270 -0
  166. package/starters/examples/src/examples/gui/minimap.ts +127 -0
  167. package/starters/examples/src/examples/gui/ownInterface.ts +129 -0
  168. package/starters/examples/src/examples/gui/plates.ts +87 -0
  169. package/starters/examples/src/examples/gui/radial.ts +104 -0
  170. package/starters/examples/src/examples/gui/solidPart.ts +107 -0
  171. package/starters/examples/src/examples/looks.ts +45 -0
  172. package/starters/examples/src/examples/mechanics/battle.ts +51 -0
  173. package/starters/examples/src/examples/mechanics/damage.ts +80 -0
  174. package/starters/examples/src/examples/mechanics/flying.ts +93 -0
  175. package/starters/examples/src/examples/mechanics/formations.ts +58 -0
  176. package/starters/examples/src/examples/mechanics/highGround.ts +82 -0
  177. package/starters/examples/src/examples/mechanics/index.ts +44 -0
  178. package/starters/examples/src/examples/mechanics/looks.ts +289 -0
  179. package/starters/examples/src/examples/mechanics/maze.ts +119 -0
  180. package/starters/examples/src/examples/mechanics/orders.ts +68 -0
  181. package/starters/examples/src/examples/mechanics/selection.ts +30 -0
  182. package/starters/examples/src/examples/moba/index.ts +377 -0
  183. package/starters/examples/src/examples/moba/looks.ts +349 -0
  184. package/starters/examples/src/examples/moba/maps.ts +69 -0
  185. package/starters/examples/src/examples/moba/spells.ts +34 -0
  186. package/starters/examples/src/examples/moba/units.ts +196 -0
  187. package/starters/examples/src/examples/nature/camera.ts +15 -0
  188. package/starters/examples/src/examples/nature/grass.ts +64 -0
  189. package/starters/examples/src/examples/nature/index.ts +327 -0
  190. package/starters/examples/src/examples/nature/land.ts +173 -0
  191. package/starters/examples/src/examples/nature/looks.ts +577 -0
  192. package/starters/examples/src/examples/nature/maps.ts +370 -0
  193. package/starters/examples/src/examples/nature/skies.ts +324 -0
  194. package/starters/examples/src/examples/nature/weather.ts +80 -0
  195. package/starters/examples/src/examples/performance/index.ts +263 -0
  196. package/starters/examples/src/examples/performance/looks.ts +372 -0
  197. package/starters/examples/src/examples/performance/meter.ts +158 -0
  198. package/starters/examples/src/examples/post/grades.ts +86 -0
  199. package/starters/examples/src/examples/post/index.ts +202 -0
  200. package/starters/examples/src/examples/post/looks.ts +884 -0
  201. package/starters/examples/src/examples/post/passes.ts +213 -0
  202. package/starters/examples/src/examples/rts/ai.ts +49 -0
  203. package/starters/examples/src/examples/rts/airlift.ts +43 -0
  204. package/starters/examples/src/examples/rts/base.ts +129 -0
  205. package/starters/examples/src/examples/rts/build.ts +65 -0
  206. package/starters/examples/src/examples/rts/camps.ts +36 -0
  207. package/starters/examples/src/examples/rts/carry.ts +103 -0
  208. package/starters/examples/src/examples/rts/creeps.ts +61 -0
  209. package/starters/examples/src/examples/rts/data.ts +406 -0
  210. package/starters/examples/src/examples/rts/ferry.ts +41 -0
  211. package/starters/examples/src/examples/rts/garrison.ts +50 -0
  212. package/starters/examples/src/examples/rts/harvest.ts +29 -0
  213. package/starters/examples/src/examples/rts/hero.ts +67 -0
  214. package/starters/examples/src/examples/rts/index.ts +77 -0
  215. package/starters/examples/src/examples/rts/looks.ts +721 -0
  216. package/starters/examples/src/examples/rts/shop.ts +46 -0
  217. package/starters/examples/src/examples/rts/tech.ts +39 -0
  218. package/starters/examples/src/examples/rts/train.ts +48 -0
  219. package/starters/examples/src/examples/rts/waterside.ts +185 -0
  220. package/starters/examples/src/examples/showcase/index.ts +714 -0
  221. package/starters/examples/src/examples/showcase/looks.ts +238 -0
  222. package/starters/examples/src/game.ts +17 -0
  223. package/starters/examples/src/main.ts +82 -0
  224. package/starters/examples/src/rules.ts +31 -0
  225. package/starters/examples/src/shell/look.ts +79 -0
  226. package/starters/examples/src/shell/registry.ts +7 -0
  227. package/starters/examples/src/shell/scenes.ts +178 -0
  228. package/starters/examples/src/shell/shell.ts +290 -0
  229. package/starters/examples/src/shell/style.ts +202 -0
  230. package/starters/examples/src/view.ts +50 -0
  231. package/starters/melee/README.md +12 -3
  232. package/starters/melee/layers/tests/tests/heroes.test.ts +402 -0
  233. package/starters/melee/layers/tests/tests/rules.test.ts +10 -8
  234. package/starters/melee/src/game.ts +32 -2
  235. package/starters/melee/src/maps/bay.names.ts +2 -2
  236. package/starters/melee/src/maps/bay.vgmap.json +198 -1
  237. package/starters/melee/src/maps.ts +11 -9
  238. package/starters/melee/src/melee/abilities.ts +1 -194
  239. package/starters/melee/src/melee/blight.ts +7 -7
  240. package/starters/melee/src/melee/cellLayers.json +3 -3
  241. package/starters/melee/src/melee/data.json +1 -18
  242. package/starters/melee/src/melee/game.ts +6 -4
  243. package/starters/melee/src/melee/heroes.ts +1025 -0
  244. package/starters/melee/src/melee/index.ts +64 -61
  245. package/starters/melee/src/melee/items.ts +15 -362
  246. package/starters/melee/src/melee/languages/he.json +14 -2
  247. package/starters/melee/src/melee/pings.ts +5 -6
  248. package/starters/melee/src/melee/saves.ts +1 -1
  249. package/starters/melee/src/melee/undead.ts +15 -230
  250. package/starters/melee/src/melee/units.ts +37 -171
  251. package/starters/melee/src/melee/view/attacks.ts +19 -0
  252. package/starters/melee/src/melee/view/heroSpellLooks.ts +39 -8
  253. package/starters/melee/src/melee/view/index.ts +56 -52
  254. package/starters/melee/src/melee/view/looks.ts +86 -63
  255. package/starters/melee/src/melee/view/undeadLooks.ts +70 -31
  256. package/starters/melee/src/melee/view/walls.ts +1 -1
  257. package/starters.mjs +6 -0
  258. package/v12.mjs +14 -15
  259. package/starters/campaign/src/rules.ts +0 -20
  260. package/starters/empty/src/maps.ts +0 -44
  261. package/starters/empty/src/tiles.ts +0 -12
  262. package/starters/melee/src/melee/heroSpells.ts +0 -38
  263. package/starters/melee/src/rules.ts +0 -24
@@ -14,19 +14,16 @@ import {
14
14
  HUD_FILE,
15
15
  layFiles,
16
16
  PINGS_FILE,
17
- presetBuffMarker,
18
17
  presetFloats,
18
+ presetFoliage,
19
19
  presetFx,
20
20
  presetPings,
21
- presetRallyFlag,
22
- presetSpellStyles,
23
- presetWeather,
21
+ presetView,
24
22
  QUALITY_FILE,
25
23
  SOUNDS_FILE,
26
24
  stanceButtons,
27
- TILE_LOOKS,
28
25
  veterancyRank,
29
- withHeroesView
26
+ heroesViewPack
30
27
  } from '@v12-engine/client'
31
28
  import { LOOKS_FILE } from '@v12-engine/client/looks-file'
32
29
  import looksFile from '../looks.json'
@@ -52,15 +49,18 @@ const buffColor = ({ params }: FloatInput): string => {
52
49
 
53
50
  /** How melee looks. The rules are in `../index.ts`; this part only runs on a player's screen */
54
51
  export const meleeView: GameView = layFiles(
55
- {
52
+ // the client's ready-made looks it draws none of by itself: the rain and snow, the abilities' styles, a building's
53
+ // rally flag, the glow over a unit with a buff and the looks of the engine's tiles (grass, dirt, road, sand, rock,
54
+ // snow), under what the view says of its own
55
+ presetView({
56
56
  // the languages it is played in, the setting `language` choosing one: English, and Hebrew right to left
57
57
  languages: meleeLanguages,
58
58
  hud: {
59
- parts: [capturePanel()],
60
- // the stances of the pack the rules turn on (`withStances`): a button a stance for the selected fighters; and a
61
- // gate of the player's opened and shut (`withWalls`)
59
+ widgets: [capturePanel()],
60
+ // the stances of the pack the rules turn on (`stancesPack`): a button a stance for the selected fighters; and a
61
+ // gate of the player's opened and shut (`wallsPack`)
62
62
  cardButtons: cardButtons(stanceButtons(), gateButtons),
63
- // the capture points of the pack the rules turn on (`withCapture`): a dot each on the minimap, a bar each on the
63
+ // the capture points of the pack the rules turn on (`capturePack`): a dot each on the minimap, a bar each on the
64
64
  // HUD; and the Restless' blight under them as it spreads
65
65
  minimap: { layers: [blightMinimapLayer(), captureMinimapLayer()] },
66
66
  // the debug panel's AI tab can draw what the computer it inspects is thinking over the ground: its squads, its threat
@@ -99,10 +99,24 @@ export const meleeView: GameView = layFiles(
99
99
  night: 'Night: units see less far, and creeps sleep until attacked',
100
100
  needsBlight: 'Must be built on blight',
101
101
  needsHauntedMine: 'Acolytes gather gold at a cursed mine of yours'
102
+ },
103
+ // the ready-made floating text for every kind: damage dealt and taken, crits, healing, experience, mana, gold, levels,
104
+ // buffs; the damage dealt white, as made; a buff's name in its own colour (`effects`, a function: code); the others in
105
+ // melee's colours, outlined dark brown, as the editor's Words panel wrote them over the ready-made ones (`floats.json`)
106
+ // and a unit's rank of veterancy reached, its name in gold over it (`veterancyPack`'s `core.rankedUp`)
107
+ floats: {
108
+ ...presetFloats(undefined, { buff: { style: { color: buffColor } } }),
109
+ 'core.rankedUp': {
110
+ text: '{name}!',
111
+ style: { color: '#e7b94a', size: 18, background: { color: 'rgba(20, 14, 4, 0.7)', padding: 3, radius: 5 } },
112
+ motion: [{ pop: { from: 0.4, seconds: 0.3, ease: 'outBack' } }, { rise: 0.6, ease: 'outQuad' }],
113
+ offset: { y: -30 },
114
+ seconds: 2
115
+ }
102
116
  }
103
117
  },
104
- // the HUD's half of the heroes the rules take (`withHeroes`): the hero's panel, the heroes' portraits, the shop
105
- packs: [withHeroesView()],
118
+ // the HUD's half of the heroes the rules take (`heroesPack`): the hero's panel, the heroes' portraits, the shop
119
+ packs: [heroesViewPack()],
106
120
  cinematics: {
107
121
  // a lane of its own for its cinematics, beside the client's: everyone of a side cheers (see `cheerLane.ts`)
108
122
  lanes: [cheerLane]
@@ -112,18 +126,27 @@ export const meleeView: GameView = layFiles(
112
126
  // the looks of its units (`looks.ts`): what the editor's model setup wrote is laid over them (`looks.json`), and the
113
127
  // HUD over its units the Unit HUD panel wrote (`hud.json`) over the heroes' plates
114
128
  looks,
115
- rallyFlag: presetRallyFlag(),
116
- buffMarker: presetBuffMarker(),
117
129
  // a line around what the pointer is over, a unit or a building: none on the neutral (camps, mines)
118
- hover: (entity) => (entity.owner === 0 ? undefined : { color: [1, 0.85, 0.4], width: 2 })
130
+ hover: (entity) => (entity.owner === 0 ? undefined : { color: [1, 0.85, 0.4], width: 2 }),
131
+ // items on the ground: draughts in their colours, the blades and the shield as what they are, a chest for the rest
132
+ items: {
133
+ looks: {
134
+ healingDraught: { color: [0.85, 0.15, 0.15], size: 0.6 },
135
+ manaDraught: { color: [0.2, 0.35, 0.95], size: 0.6 },
136
+ ironSword: { model: { src: 'items/sword.glb', scale: 1 } },
137
+ quickDagger: { model: { src: 'gear/dagger.glb', scale: 1 } },
138
+ squiresBlade: { model: { src: 'items/sword_2.glb', scale: 1 } },
139
+ squiresShield: { model: { src: 'items/shield_round.glb', scale: 1 } }
140
+ }
141
+ }
119
142
  },
120
- scene: {
143
+ world: {
121
144
  // what drawing asks of the device: the client's presets, the most pixels a preset draws and each preset's resolution
122
145
  // and edges as the editor's Look panel wrote them over them (`quality.json`)
123
146
  quality: {},
124
147
  // the bushes: tall grass that sways, bends and rustles as units go through, see-through around one's own
125
- // the ready-made rain and snow, and a weather of melee's own beside them: ash drifting down, for a map of burnt lands
126
- weather: { ...presetWeather(), ash: { rate: 700, speed: 1.6, lifetime: 12, size: [0.1, 0.18], color: [0.32, 0.3, 0.3, 0.85] } },
148
+ // a weather of melee's own beside the ready-made rain and snow: ash drifting down, for a map of burnt lands
149
+ weather: { ash: { rate: 700, speed: 1.6, lifetime: 12, size: [0.1, 0.18], color: [0.32, 0.3, 0.3, 0.85] } },
127
150
  // the sky and the mist with the hour, as the client has them: dark blue at night, warm at dawn and dusk
128
151
  daylight: DAYLIGHT_COLORS,
129
152
  // the trees, the buildings and the armies of the shared art lighter from far, as their levels are made (`npm run lod`)
@@ -162,22 +185,6 @@ export const meleeView: GameView = layFiles(
162
185
  }
163
186
  }
164
187
  },
165
- // the ready-made effects its buildings smoke, burn, go up and come down with, and what the editor's FX panel wrote
166
- // over them (and of its own)
167
- // the ready-made floating text for every kind: damage dealt and taken, crits, healing, experience, mana, gold, levels,
168
- // buffs; the damage dealt white, as made; a buff's name in its own colour (`effects`, a function: code); the others in
169
- // melee's colours, outlined dark brown, as the editor's Words panel wrote them over the ready-made ones (`floats.json`)
170
- // and a unit's rank of veterancy reached, its name in gold over it (`withVeterancy`'s `core.rankedUp`)
171
- floats: {
172
- ...presetFloats(undefined, { buff: { style: { color: buffColor } } }),
173
- 'core.rankedUp': {
174
- text: '{name}!',
175
- style: { color: '#e7b94a', size: 18, background: { color: 'rgba(20, 14, 4, 0.7)', padding: 3, radius: 5 } },
176
- motion: [{ pop: { from: 0.4, seconds: 0.3, ease: 'outBack' } }, { rise: 0.6, ease: 'outQuad' }],
177
- offset: { y: -30 },
178
- seconds: 2
179
- }
180
- },
181
188
  pings: {
182
189
  // the pings of the rules (`../pings`), the ready-made ones: the six of the wheel (Ctrl and the left button) in this
183
190
  // order, the others sent from code alone; and what the editor's Pings fold wrote over them and of the wheel
@@ -185,6 +192,8 @@ export const meleeView: GameView = layFiles(
185
192
  kinds: presetPings([...PINGS], Object.fromEntries(OFF_WHEEL_PINGS.map((kind) => [kind, { wheel: { hidden: true } }]))),
186
193
  wheel: {}
187
194
  },
195
+ // the ready-made effects its buildings smoke, burn, go up and come down with, and what the editor's FX panel wrote
196
+ // over them (and of its own)
188
197
  fx: {
189
198
  defs: presetFx([
190
199
  'smoke',
@@ -211,10 +220,7 @@ export const meleeView: GameView = layFiles(
211
220
  'leaves'
212
221
  ]),
213
222
  abilities: {
214
- looks: effects,
215
- // the ready-made styles of what abilities look like, a building's rally flag, the glow over a unit with a buff:
216
- // the client draws none of them by itself
217
- styles: presetSpellStyles()
223
+ looks: effects
218
224
  }
219
225
  },
220
226
  ground: {
@@ -227,29 +233,27 @@ export const meleeView: GameView = layFiles(
227
233
  // the devil's sword was made to shine: it glows past its edges, a little by day and fully at night
228
234
  'weapons/devils_sword.glb': { glow: { day: 0.1, night: 1 } }
229
235
  },
230
- // its tiles in the client's looks of grass, dirt, road, sand, rock and snow: taken, not given
231
- tiles: TILE_LOOKS,
232
236
  // with what the editor's Terrain panel wrote of a layer's look (its own models, colours, how it shakes) over them
233
237
  cellLayers: {
234
- // the bushes: the client's tall grass, shaken as units go in, leaves flying
235
- bush: foliage({ color: [0.16, 0.36, 0.1], tip: [0.5, 0.68, 0.24], height: 1.4, leaves: 'leaves' }),
238
+ // the bushes: the client's tall grass, shaken as units go in, leaves flying, laid down where they walk; the dry
239
+ // grass (style 2) as the client's ready-made one of that name
240
+ bush: foliage({
241
+ color: [0.16, 0.36, 0.1],
242
+ tip: [0.5, 0.68, 0.24],
243
+ height: 1.4,
244
+ leaves: 'leaves',
245
+ walked: { flatten: 0.5, recover: 10 },
246
+ styles: { 2: presetFoliage.dryGrass }
247
+ }),
236
248
  // the Restless' blight: the client's, the shared art's spoiled ground and green gases rising off it
237
249
  blight: blightLook()
238
250
  }
239
251
  },
240
- // items on the ground: potions in their colours, the blade and the shield as what they are, a chest for the rest
241
- items: {
242
- healingPotion: { color: [0.85, 0.15, 0.15], size: 0.6 },
243
- manaPotion: { color: [0.2, 0.35, 0.95], size: 0.6 },
244
- longSword: { model: { src: 'items/sword.glb', scale: 1 } },
245
- squiresBlade: { model: { src: 'items/sword_2.glb', scale: 1 } },
246
- squiresShield: { model: { src: 'items/shield_round.glb', scale: 1 } }
247
- },
248
252
  input: {
249
253
  // a hero arena game's keys for heroes (its hero panel's stats are the client's eight)
250
254
  keys: { abilities: ['Q', 'W', 'E', 'R'], spells: ['D', 'F'], shop: 'P' }
251
255
  }
252
- },
256
+ }),
253
257
  // the files the editor writes next to the code, each laid over what the code says above, in this order (`hud.json`
254
258
  // over the looks `looks.json` made)
255
259
  [
@@ -1,7 +1,8 @@
1
- import type { AbilityLooks, EntityView, ModelDef, Nameplate, UnitHudDef, UnitLook, UnitLooks } from '@v12-engine/client'
1
+ import type { AbilityLooks, EntityView, ModelDef, UnitHudPlate, UnitHudDef, UnitLook, UnitLooks } from '@v12-engine/client'
2
2
  import { units } from '../units'
3
+ import { ONE_HANDED, TWO_HANDED } from './attacks'
3
4
  import { building } from './buildings'
4
- import { heroSpellEffects } from './heroSpellLooks'
5
+ import { heroSpellEffects, kingdomHeroEffects } from './heroSpellLooks'
5
6
  import { undeadEffects, undeadLooks } from './undeadLooks'
6
7
 
7
8
  export const effects: AbilityLooks = {
@@ -13,24 +14,15 @@ export const effects: AbilityLooks = {
13
14
  mirrorImage: { color: [0.45, 0.65, 1], style: 'burst', options: { count: 40, ring: 1.6, shape: 'about' } },
14
15
  slow: { color: [0.6, 0.4, 1] },
15
16
  arcaneBlast: { color: [0.45, 0.8, 1] },
16
- holyLight: { color: [1, 0.95, 0.45] },
17
- stomp: { color: [0.85, 0.7, 0.45] },
18
17
  stunned: { color: [1, 1, 0.3] },
19
- avatar: { color: [1, 0.85, 0.3] },
20
- blessedSprint: { color: [1, 0.95, 0.6] },
21
- flameStrike: { color: [1, 0.45, 0.1] },
22
- frostBolt: { color: [0.55, 0.85, 1] },
23
- cataclysm: { color: [1, 0.3, 0.1] },
24
18
  clap: { color: [0.85, 0.7, 0.45] },
25
- tornado: { color: [0.78, 0.86, 0.92], style: 'tornado' },
26
- groundSmash: { color: [0.8, 0.6, 0.35], style: 'smash' },
27
- lasso: { color: [0.62, 0.47, 0.27], style: 'tether', until: 'lassoed' },
28
- lassoed: { color: [0.62, 0.47, 0.27] },
29
19
  knockedUp: { color: [0.78, 0.86, 0.92] },
30
- revealArea: { color: [0.55, 0.85, 1] },
31
- plantWard: { color: [0.95, 0.9, 0.55] },
32
- sweep: { color: [0.55, 1, 0.75], style: 'sonar' },
20
+ // what the default items do (`defaultItemSet`)
21
+ plantSightWard: { color: [0.95, 0.9, 0.55] },
22
+ scatterSeersDust: { color: [0.55, 1, 0.75], style: 'sonar' },
23
+ rallyingHorn: { color: [1, 0.85, 0.4], style: 'burst' },
33
24
  ...heroSpellEffects,
25
+ ...kingdomHeroEffects,
34
26
  ...undeadEffects
35
27
  }
36
28
 
@@ -73,7 +65,7 @@ const TREE_MIX = FOREST.map((_, i) => String(i + 1).padStart(3, '0'))
73
65
  const GHOST = { seconds: 0.6 }
74
66
 
75
67
  /** A hero's plate: with its health's points on the bar where `points` */
76
- const heroPlate = (points: boolean): Nameplate => ({
68
+ const heroPlate = (points: boolean): UnitHudPlate => ({
77
69
  show: 'always',
78
70
  gap: 1,
79
71
  items: [
@@ -165,7 +157,8 @@ export const looks: UnitLooks = {
165
157
  peasant: {
166
158
  height: 1.5,
167
159
  model: character('barbarian', 0.58, { hold: [hold('axe_1handed')] }),
168
- parts: [
160
+ attacks: [ONE_HANDED],
161
+ shapes: [
169
162
  { shape: 'cylinder', size: [0.5, 0.8, 0.5], offset: [0, 0.4, 0], color: 'team' },
170
163
  { shape: 'sphere', size: [0.38, 0.38, 0.38], offset: [0, 0.98, 0], color: SKIN },
171
164
  { shape: 'cone', size: [0.5, 0.22, 0.5], offset: [0, 1.22, 0], color: STRAW },
@@ -185,9 +178,10 @@ export const looks: UnitLooks = {
185
178
  footman: {
186
179
  height: 1.8,
187
180
  model: character('knight', 0.7, { hold: [hold('sword_1handed'), hold('shield_round', 'l')] }),
181
+ attacks: [ONE_HANDED],
188
182
  // armies of them: drawn as copies of one mesh, their animations baked (S41)
189
183
  baked: true,
190
- parts: [
184
+ shapes: [
191
185
  { shape: 'box', size: [0.62, 1, 0.42], offset: [0, 0.5, 0], color: 'team' },
192
186
  { shape: 'sphere', size: [0.42, 0.42, 0.42], offset: [0, 1.22, 0], color: STEEL },
193
187
  { shape: 'box', size: [0.1, 0.6, 0.5], offset: [-0.4, 0.65, 0.12], color: STEEL },
@@ -196,8 +190,12 @@ export const looks: UnitLooks = {
196
190
  },
197
191
  rifleman: {
198
192
  height: 1.8,
199
- model: character('ranger', 0.7, { hold: [hold('crossbow_2handed')], animations: { attack: 'Ranged_2H_Shoot' }, hitAt: 0.3 }),
200
- parts: [
193
+ model: character('ranger', 0.7, {
194
+ hold: [hold('crossbow_2handed')],
195
+ animations: { attack: 'Ranged_2H_Shoot' },
196
+ clips: { Ranged_2H_Shoot: { marks: [{ name: 'hit', at: 0.3 }] } }
197
+ }),
198
+ shapes: [
201
199
  { shape: 'cylinder', size: [0.56, 0.95, 0.56], offset: [0, 0.48, 0], color: 'team' },
202
200
  { shape: 'sphere', size: [0.4, 0.4, 0.4], offset: [0, 1.17, 0], color: SKIN },
203
201
  { shape: 'cylinder', size: [0.5, 0.12, 0.5], offset: [0, 1.36, 0], color: WOOD },
@@ -210,7 +208,7 @@ export const looks: UnitLooks = {
210
208
  height: 2.4,
211
209
  // its shots are rocks, thrown high
212
210
  shot: { color: STONE, size: 0.5, arc: 0.4 },
213
- parts: [
211
+ shapes: [
214
212
  { shape: 'box', size: [1.1, 0.3, 1.7], offset: [0, 0.5, 0], color: WOOD },
215
213
  { shape: 'box', size: [1.2, 0.12, 0.5], offset: [0, 0.72, -0.4], color: 'team' },
216
214
  { shape: 'cylinder', size: [0.6, 0.16, 0.6], offset: [0.64, 0.3, 0.55], color: DARK, tilt: Math.PI / 2, turn: Math.PI / 2 },
@@ -228,7 +226,7 @@ export const looks: UnitLooks = {
228
226
  height: 1.9,
229
227
  altitude: 3.2,
230
228
  shot: { color: [0.55, 0.8, 1], size: 0.3 },
231
- parts: [
229
+ shapes: [
232
230
  { shape: 'sphere', size: [0.8, 0.7, 1.5], offset: [0, 0.7, 0], color: [0.72, 0.58, 0.36] },
233
231
  { shape: 'sphere', size: [0.5, 0.5, 0.6], offset: [0, 1.05, 0.85], color: [0.93, 0.91, 0.84] },
234
232
  { shape: 'cone', size: [0.2, 0.4, 0.2], offset: [0, 0.98, 1.25], color: GOLD, tilt: Math.PI / 2 },
@@ -242,7 +240,7 @@ export const looks: UnitLooks = {
242
240
  goblinShipyard: {
243
241
  height: 3,
244
242
  model: building('rts/dock.glb', 3),
245
- parts: [
243
+ shapes: [
246
244
  { shape: 'box', size: [3, 0.4, 3], offset: [0, 0.2, 0], color: WOOD },
247
245
  { shape: 'box', size: [1.6, 1.4, 1.6], offset: [-0.6, 1.1, -0.6], color: WOOD },
248
246
  { shape: 'pyramid', size: [1.9, 0.8, 1.9], offset: [-0.6, 2.2, -0.6], color: 'team' },
@@ -252,7 +250,7 @@ export const looks: UnitLooks = {
252
250
  // a hull, a deck house and a sail in the side's colour: drawn of parts, there is no boat among the shared art
253
251
  transportShip: {
254
252
  height: 2.6,
255
- parts: [
253
+ shapes: [
256
254
  { shape: 'box', size: [1.4, 0.6, 2.8], offset: [0, 0.3, 0], color: WOOD },
257
255
  { shape: 'cone', size: [1.4, 0.8, 0.6], offset: [0, 0.3, 1.6], color: WOOD, tilt: Math.PI / 2 },
258
256
  { shape: 'box', size: [0.9, 0.6, 0.9], offset: [0, 0.9, -0.6], color: STRAW },
@@ -263,7 +261,7 @@ export const looks: UnitLooks = {
263
261
  aviary: {
264
262
  height: 4,
265
263
  model: building('rts/stone_tower.glb', 2.6),
266
- parts: [
264
+ shapes: [
267
265
  { shape: 'cylinder', size: [2.6, 1.2, 2.6], offset: [0, 0.6, 0], color: STONE },
268
266
  { shape: 'cylinder', size: [0.4, 2.6, 0.4], offset: [0.9, 2.2, 0.9], color: WOOD },
269
267
  { shape: 'cylinder', size: [0.4, 2.6, 0.4], offset: [-0.9, 2.2, 0.9], color: WOOD },
@@ -276,7 +274,7 @@ export const looks: UnitLooks = {
276
274
  priest: {
277
275
  height: 1.8,
278
276
  model: character('mage', 0.7, { hold: [hold('staff')], animations: { attack: 'Ranged_Magic_Shoot' } }),
279
- parts: [
277
+ shapes: [
280
278
  { shape: 'cone', size: [0.8, 1.05, 0.8], offset: [0, 0.52, 0], color: [0.93, 0.91, 0.84] },
281
279
  { shape: 'box', size: [0.3, 0.5, 0.3], offset: [0, 0.75, 0], color: 'team' },
282
280
  { shape: 'sphere', size: [0.38, 0.38, 0.38], offset: [0, 1.2, 0], color: SKIN },
@@ -287,22 +285,25 @@ export const looks: UnitLooks = {
287
285
  sorceress: {
288
286
  height: 1.9,
289
287
  model: character('mage', 0.72, { hold: [hold('wand')], animations: { attack: 'Ranged_Magic_Shoot' } }),
290
- parts: [
288
+ shapes: [
291
289
  { shape: 'cone', size: [0.85, 1.05, 0.85], offset: [0, 0.52, 0], color: 'team' },
292
290
  { shape: 'sphere', size: [0.38, 0.38, 0.38], offset: [0, 1.2, 0], color: SKIN },
293
291
  { shape: 'cone', size: [0.5, 0.55, 0.5], offset: [0, 1.6, 0], color: [0.4, 0.25, 0.6] },
294
292
  { shape: 'sphere', size: [0.22, 0.22, 0.22], offset: [0.4, 0.95, 0.2], color: [0.6, 0.85, 1] }
295
293
  ]
296
294
  },
297
- paladin: {
295
+ // ---- the Kingdom's heroes (`heroes.ts`)
296
+ oathbreaker: {
298
297
  height: 2.3,
299
298
  model: character('knight', 0.9, {
300
299
  hold: [hold('sword_2handed')],
301
300
  animations: { attack: 'Melee_2H_Attack_Chop', work: 'Melee_2H_Attack_Chop' },
302
- // the sprint goes off without a gesture: the Paladin keeps running
303
- casts: { blessedSprint: '' }
301
+ // the charge goes off without a gesture: he keeps running
302
+ casts: { oathCharge: '' }
304
303
  }),
305
- parts: [
304
+ // a hero's blade: a golden streak behind it
305
+ attacks: [{ ...TWO_HANDED, trail: { color: [1, 0.85, 0.4], width: 0.16 } }],
306
+ shapes: [
306
307
  { shape: 'box', size: [0.8, 1.25, 0.55], offset: [0, 0.62, 0], color: 'team' },
307
308
  { shape: 'box', size: [1.1, 0.3, 0.6], offset: [0, 1.25, 0], color: GOLD },
308
309
  { shape: 'sphere', size: [0.48, 0.48, 0.48], offset: [0, 1.62, 0], color: STEEL },
@@ -311,22 +312,24 @@ export const looks: UnitLooks = {
311
312
  { shape: 'box', size: [0.1, 1.1, 0.75], offset: [0, 0.8, -0.34], color: GOLD }
312
313
  ]
313
314
  },
314
- archmage: {
315
+ dawnPriest: {
315
316
  height: 2.4,
316
317
  model: character('mage', 0.92, { hold: [hold('staff')], animations: { attack: 'Ranged_Magic_Shoot' } }),
317
- parts: [
318
- { shape: 'cone', size: [1, 1.35, 1], offset: [0, 0.67, 0], color: 'team' },
318
+ shot: { color: [1, 0.92, 0.55], size: 0.3 },
319
+ shapes: [
320
+ { shape: 'cone', size: [1, 1.35, 1], offset: [0, 0.67, 0], color: [0.95, 0.92, 0.82] },
321
+ { shape: 'box', size: [0.34, 0.6, 0.34], offset: [0, 0.9, 0], color: 'team' },
319
322
  { shape: 'sphere', size: [0.44, 0.44, 0.44], offset: [0, 1.5, 0], color: SKIN },
320
323
  { shape: 'cone', size: [0.7, 0.8, 0.7], offset: [0, 1.98, 0], color: GOLD },
321
324
  { shape: 'box', size: [0.07, 1.9, 0.07], offset: [0.5, 0.95, 0.15], color: WOOD },
322
- { shape: 'sphere', size: [0.3, 0.3, 0.3], offset: [0.5, 1.95, 0.15], color: [0.5, 0.85, 1] }
325
+ { shape: 'sphere', size: [0.3, 0.3, 0.3], offset: [0.5, 1.95, 0.15], color: [1, 0.9, 0.5] }
323
326
  ]
324
327
  },
325
- testiro: {
328
+ stormcaller: {
326
329
  height: 2.6,
327
330
  model: character('mage', 1, { hold: [hold('spellbook_open', 'l')], animations: { attack: 'Ranged_Magic_Shoot' } }),
328
331
  shot: { color: [0.75, 0.9, 1], size: 0.26 },
329
- parts: [
332
+ shapes: [
330
333
  { shape: 'cone', size: [0.95, 1.2, 0.95], offset: [0, 0.6, 0], color: 'team' },
331
334
  { shape: 'cylinder', size: [0.5, 0.5, 0.5], offset: [0, 1.15, 0], color: [0.78, 0.86, 0.92] },
332
335
  { shape: 'sphere', size: [0.42, 0.42, 0.42], offset: [0, 1.55, 0], color: SKIN },
@@ -337,11 +340,28 @@ export const looks: UnitLooks = {
337
340
  { shape: 'cone', size: [0.3, 0.35, 0.3], offset: [-0.45, 1.85, 0.15], color: [0.78, 0.86, 0.92] }
338
341
  ]
339
342
  },
343
+ galeHunter: {
344
+ height: 2.3,
345
+ model: character('ranger', 0.9, {
346
+ hold: [hold('crossbow_2handed')],
347
+ animations: { attack: 'Ranged_2H_Shoot' },
348
+ clips: { Ranged_2H_Shoot: { marks: [{ name: 'hit', at: 0.3 }] } },
349
+ // the roll goes off without a gesture
350
+ casts: { tumble: '' }
351
+ }),
352
+ shot: { color: [0.85, 0.95, 0.8], size: 0.18, trail: { color: [0.8, 1, 0.85], count: 30 } },
353
+ shapes: [
354
+ { shape: 'cylinder', size: [0.62, 1.15, 0.62], offset: [0, 0.58, 0], color: 'team' },
355
+ { shape: 'sphere', size: [0.44, 0.44, 0.44], offset: [0, 1.42, 0], color: SKIN },
356
+ { shape: 'cone', size: [0.55, 0.5, 0.55], offset: [0, 1.75, 0], color: [0.3, 0.45, 0.25] },
357
+ { shape: 'box', size: [0.08, 0.08, 1.3], offset: [0.32, 1, 0.5], color: DARK }
358
+ ]
359
+ },
340
360
  ward: {
341
361
  // a flag on a stick: no blood
342
362
  blood: false,
343
363
  height: 1.4,
344
- parts: [
364
+ shapes: [
345
365
  { shape: 'cylinder', size: [0.06, 1.3, 0.06], offset: [0, 0.65, 0], color: WOOD },
346
366
  { shape: 'box', size: [0.04, 0.35, 0.5], offset: [0, 1.1, 0.25], color: 'team' }
347
367
  ]
@@ -351,7 +371,8 @@ export const looks: UnitLooks = {
351
371
  blood: false,
352
372
  height: 1.6,
353
373
  model: character('skeleton_minion', 0.62, { hold: [{ src: 'skeleton-gear/blade.glb', at: 'handslot.r' }] }),
354
- parts: [
374
+ attacks: [ONE_HANDED],
375
+ shapes: [
355
376
  { shape: 'cylinder', size: [0.5, 1, 0.5], offset: [0, 0.5, 0], color: [0.86, 0.83, 0.74] },
356
377
  { shape: 'sphere', size: [0.4, 0.4, 0.4], offset: [0, 1.2, 0], color: [0.86, 0.83, 0.74] }
357
378
  ]
@@ -359,7 +380,7 @@ export const looks: UnitLooks = {
359
380
  altar: {
360
381
  height: 3.2,
361
382
  model: building('rts/temple_3.glb', 2.9),
362
- parts: [
383
+ shapes: [
363
384
  { shape: 'box', size: [2.8, 0.5, 2.8], offset: [0, 0.25, 0], color: STONE },
364
385
  { shape: 'box', size: [2, 0.5, 2], offset: [0, 0.75, 0], color: STONE },
365
386
  { shape: 'cylinder', size: [0.35, 1.8, 0.35], offset: [1, 1.4, 1], color: STONE },
@@ -374,7 +395,7 @@ export const looks: UnitLooks = {
374
395
  // straw: no blood
375
396
  blood: false,
376
397
  height: 2,
377
- parts: [
398
+ shapes: [
378
399
  { shape: 'cylinder', size: [0.16, 1.1, 0.16], offset: [0, 0.55, 0], color: WOOD },
379
400
  { shape: 'cylinder', size: [0.7, 0.85, 0.55], offset: [0, 1.2, 0], color: [0.78, 0.66, 0.42] },
380
401
  { shape: 'box', size: [1.25, 0.12, 0.12], offset: [0, 1.4, 0], color: WOOD },
@@ -386,7 +407,8 @@ export const looks: UnitLooks = {
386
407
  gnoll: {
387
408
  height: 1.6,
388
409
  model: character('rogue_hooded', 0.62, { hold: [hold('axe_1handed')] }),
389
- parts: [
410
+ attacks: [ONE_HANDED],
411
+ shapes: [
390
412
  { shape: 'box', size: [0.6, 0.85, 0.5], offset: [0, 0.5, 0], color: [0.5, 0.38, 0.22], tilt: 0.25 },
391
413
  { shape: 'sphere', size: [0.42, 0.4, 0.5], offset: [0, 1.05, 0.15], color: [0.62, 0.48, 0.3] },
392
414
  { shape: 'cone', size: [0.14, 0.3, 0.14], offset: [0.14, 1.32, 0.1], color: [0.62, 0.48, 0.3] },
@@ -399,9 +421,9 @@ export const looks: UnitLooks = {
399
421
  model: character('skeleton_rogue', 0.72, {
400
422
  hold: [{ src: 'skeleton-gear/crossbow.glb', at: 'handslot.r' }],
401
423
  animations: { attack: 'Ranged_2H_Shoot' },
402
- hitAt: 0.3
424
+ clips: { Ranged_2H_Shoot: { marks: [{ name: 'hit', at: 0.3 }] } }
403
425
  }),
404
- parts: [
426
+ shapes: [
405
427
  { shape: 'cylinder', size: [0.55, 1.1, 0.55], offset: [0, 0.55, 0], color: [0.3, 0.5, 0.34] },
406
428
  { shape: 'sphere', size: [0.4, 0.42, 0.4], offset: [0, 1.3, 0], color: [0.36, 0.58, 0.4] },
407
429
  { shape: 'cone', size: [0.2, 0.5, 0.2], offset: [0, 1.7, -0.05], color: [0.8, 0.3, 0.2] },
@@ -416,7 +438,8 @@ export const looks: UnitLooks = {
416
438
  { src: 'skeleton-gear/shield_large_a.glb', at: 'handslot.l' }
417
439
  ]
418
440
  }),
419
- parts: [
441
+ attacks: [ONE_HANDED],
442
+ shapes: [
420
443
  { shape: 'sphere', size: [1.5, 1.6, 1.3], offset: [0, 1, 0], color: [0.62, 0.52, 0.4] },
421
444
  { shape: 'sphere', size: [0.7, 0.7, 0.7], offset: [0, 2.1, 0.1], color: [0.68, 0.57, 0.44] },
422
445
  { shape: 'box', size: [1.2, 0.35, 1], offset: [0, 0.75, 0], color: [0.35, 0.25, 0.18] },
@@ -427,7 +450,7 @@ export const looks: UnitLooks = {
427
450
  townhall: {
428
451
  height: 4.6,
429
452
  model: building('rts/castle.glb', 3.9),
430
- parts: [
453
+ shapes: [
431
454
  { shape: 'box', size: [3.6, 1.9, 3.6], offset: [0, 0.95, 0], color: STONE },
432
455
  { shape: 'pyramid', size: [4.4, 1.7, 4.4], offset: [0, 2.75, 0], color: 'team' },
433
456
  { shape: 'box', size: [1, 1.2, 0.2], offset: [0, 0.6, -1.76], color: WOOD },
@@ -437,7 +460,7 @@ export const looks: UnitLooks = {
437
460
  keep: {
438
461
  height: 5.6,
439
462
  model: building('rts/castle_2.glb', 4),
440
- parts: [
463
+ shapes: [
441
464
  { shape: 'box', size: [3.7, 2.4, 3.7], offset: [0, 1.2, 0], color: STONE },
442
465
  { shape: 'pyramid', size: [4.4, 1.7, 4.4], offset: [0, 3.25, 0], color: 'team' },
443
466
  { shape: 'box', size: [1, 1.2, 0.2], offset: [0, 0.6, -1.81], color: WOOD },
@@ -448,7 +471,7 @@ export const looks: UnitLooks = {
448
471
  castle: {
449
472
  height: 6.6,
450
473
  model: building('rts/castle_fortress.glb', 4.2),
451
- parts: [
474
+ shapes: [
452
475
  { shape: 'box', size: [3.8, 2.8, 3.8], offset: [0, 1.4, 0], color: STONE },
453
476
  { shape: 'pyramid', size: [4.4, 1.9, 4.4], offset: [0, 3.75, 0], color: 'team' },
454
477
  { shape: 'box', size: [1.1, 1.4, 0.2], offset: [0, 0.7, -1.86], color: WOOD },
@@ -465,7 +488,7 @@ export const looks: UnitLooks = {
465
488
  farm: {
466
489
  height: 2.3,
467
490
  model: building('rts/small_farm.glb', 2.1),
468
- parts: [
491
+ shapes: [
469
492
  { shape: 'box', size: [1.7, 0.9, 1.7], offset: [0, 0.45, 0], color: WOOD },
470
493
  { shape: 'pyramid', size: [2.1, 0.95, 2.1], offset: [0, 1.37, 0], color: STRAW },
471
494
  { shape: 'box', size: [0.5, 0.12, 0.5], offset: [0, 1.9, 0], color: 'team' }
@@ -474,7 +497,7 @@ export const looks: UnitLooks = {
474
497
  barracks: {
475
498
  height: 3.4,
476
499
  model: building('rts/barracks.glb', 3),
477
- parts: [
500
+ shapes: [
478
501
  { shape: 'box', size: [2.7, 1.6, 2.7], offset: [0, 0.8, 0], color: STONE },
479
502
  { shape: 'box', size: [2.9, 0.35, 2.9], offset: [0, 1.75, 0], color: 'team' },
480
503
  { shape: 'box', size: [0.5, 0.7, 0.5], offset: [1.15, 2.2, 1.15], color: STONE },
@@ -488,7 +511,7 @@ export const looks: UnitLooks = {
488
511
  height: 4.4,
489
512
  // its arrows leave from its top, not from its middle
490
513
  model: building('rts/watch_tower.glb', 1.7, { points: { launch: { offset: [0, 3.6, 0] } } }),
491
- parts: [
514
+ shapes: [
492
515
  { shape: 'cylinder', size: [1.5, 2.8, 1.5], offset: [0, 1.4, 0], color: STONE },
493
516
  { shape: 'cylinder', size: [1.9, 0.5, 1.9], offset: [0, 3.05, 0], color: STONE },
494
517
  { shape: 'cone', size: [2, 1, 2], offset: [0, 3.8, 0], color: 'team' }
@@ -506,7 +529,7 @@ export const looks: UnitLooks = {
506
529
  tee: building('rts/stone_wall_towers.glb', 1),
507
530
  cross: building('rts/stone_wall_towers.glb', 1)
508
531
  },
509
- parts: [{ shape: 'box', size: [1, 1.8, 0.8], offset: [0, 0.9, 0], color: STONE }]
532
+ shapes: [{ shape: 'box', size: [1, 1.8, 0.8], offset: [0, 0.9, 0], color: STONE }]
510
533
  },
511
534
  // a gate of the wall, shut or open (the arch without its door: the way through is clear)
512
535
  stoneGate: {
@@ -516,12 +539,12 @@ export const looks: UnitLooks = {
516
539
  shut: building('rts/castle_gate.glb', 3),
517
540
  open: building('dungeon-kit/wall_gate.glb', 3)
518
541
  },
519
- parts: [{ shape: 'box', size: [3, 1.8, 0.6], offset: [0, 0.9, 0], color: STONE }]
542
+ shapes: [{ shape: 'box', size: [3, 1.8, 0.6], offset: [0, 0.9, 0], color: STONE }]
520
543
  },
521
544
  blacksmith: {
522
545
  height: 3.3,
523
546
  model: building('village/blacksmith.glb', 2.9),
524
- parts: [
547
+ shapes: [
525
548
  { shape: 'box', size: [2.7, 1.4, 2.7], offset: [0, 0.7, 0], color: STONE },
526
549
  { shape: 'pyramid', size: [3.1, 1, 3.1], offset: [0, 1.9, 0], color: DARK },
527
550
  { shape: 'box', size: [0.6, 1.5, 0.6], offset: [-0.8, 2.2, 0.8], color: STONE },
@@ -535,7 +558,7 @@ export const looks: UnitLooks = {
535
558
  `ruins${size}`,
536
559
  {
537
560
  height: 0.8,
538
- parts: [
561
+ shapes: [
539
562
  { shape: 'box', size: [size * 0.9, 0.25, size * 0.9], offset: [0, 0.12, 0], color: [0.33, 0.3, 0.27] },
540
563
  { shape: 'box', size: [size * 0.6, 0.3, 0.25], offset: [0, 0.35, size * 0.15], color: DARK, turn: 0.4 },
541
564
  { shape: 'box', size: [0.25, 0.35, size * 0.5], offset: [size * 0.2, 0.4, 0], color: [0.28, 0.2, 0.12], turn: -0.3 },
@@ -547,7 +570,7 @@ export const looks: UnitLooks = {
547
570
  tavern: {
548
571
  height: 3.4,
549
572
  model: building('rts/houses_2.glb', 3),
550
- parts: [
573
+ shapes: [
551
574
  { shape: 'box', size: [2.8, 1.6, 2.6], offset: [0, 0.8, 0], color: WOOD },
552
575
  { shape: 'pyramid', size: [3.2, 1.2, 3], offset: [0, 2.2, 0], color: STRAW },
553
576
  { shape: 'box', size: [0.8, 1, 0.2], offset: [0, 0.5, -1.35], color: DARK },
@@ -557,7 +580,7 @@ export const looks: UnitLooks = {
557
580
  alchemist: {
558
581
  height: 3.6,
559
582
  model: building('rts/tower_house.glb', 2.8),
560
- parts: [
583
+ shapes: [
561
584
  { shape: 'cylinder', size: [2.6, 1.5, 2.6], offset: [0, 0.75, 0], color: [0.78, 0.74, 0.66] },
562
585
  { shape: 'cone', size: [3, 1.5, 3], offset: [0, 2.25, 0], color: 'team' },
563
586
  { shape: 'sphere', size: [0.55, 0.55, 0.55], offset: [0, 3.15, 0], color: [0.45, 0.95, 0.5] },
@@ -567,7 +590,7 @@ export const looks: UnitLooks = {
567
590
  armory: {
568
591
  height: 3.4,
569
592
  model: building('rts/archery_building.glb', 2.9),
570
- parts: [
593
+ shapes: [
571
594
  { shape: 'box', size: [2.7, 1.5, 2.7], offset: [0, 0.75, 0], color: STONE },
572
595
  { shape: 'pyramid', size: [3.1, 1.1, 3.1], offset: [0, 2.05, 0], color: 'team' },
573
596
  { shape: 'box', size: [0.9, 1.1, 0.2], offset: [0, 0.55, -1.32], color: WOOD },
@@ -582,7 +605,7 @@ export const looks: UnitLooks = {
582
605
  looks: TREE_LOOKS,
583
606
  mix: TREE_MIX,
584
607
  vary: { scale: 0.25, lean: 0.07 },
585
- parts: [
608
+ shapes: [
586
609
  { shape: 'cylinder', size: [0.3, 1, 0.3], offset: [0, 0.5, 0], color: [0.36, 0.25, 0.15] },
587
610
  { shape: 'cone', size: [1.5, 1.5, 1.5], offset: [0, 1.5, 0], color: [0.14, 0.36, 0.17] },
588
611
  { shape: 'cone', size: [1.1, 1.3, 1.1], offset: [0, 2.4, 0], color: [0.17, 0.42, 0.2] }
@@ -591,7 +614,7 @@ export const looks: UnitLooks = {
591
614
  lumbermill: {
592
615
  height: 3,
593
616
  model: building('village/fantasy_sawmill.glb', 2.9),
594
- parts: [
617
+ shapes: [
595
618
  { shape: 'box', size: [2.7, 1.3, 2.4], offset: [0, 0.65, 0], color: WOOD },
596
619
  { shape: 'pyramid', size: [3.1, 1.2, 2.8], offset: [0, 1.9, 0], color: 'team' },
597
620
  { shape: 'cylinder', size: [0.4, 2.2, 0.4], offset: [-1.1, 0.25, -1.45], color: [0.36, 0.25, 0.15], tilt: Math.PI / 2, turn: Math.PI / 2 },
@@ -607,7 +630,7 @@ export const looks: UnitLooks = {
607
630
  { shape: 'box', size: [0.5, 0.4, 0.45], color: [0.3, 0.28, 0.26], count: 8 },
608
631
  { shape: 'sphere', size: [0.3, 0.25, 0.3], color: GOLD, count: 6 }
609
632
  ],
610
- parts: [
633
+ shapes: [
611
634
  { shape: 'pyramid', size: [3.9, 2.6, 3.9], offset: [0, 1.3, 0], color: [0.36, 0.33, 0.3] },
612
635
  { shape: 'box', size: [1.1, 1.2, 0.4], offset: [0, 0.6, -1.85], color: DARK },
613
636
  { shape: 'sphere', size: [0.6, 0.5, 0.6], offset: [1.4, 0.25, -1.9], color: GOLD },
@@ -639,7 +662,7 @@ for (const visual of Object.values(looks)) {
639
662
  }
640
663
 
641
664
  // the casters carry a soft light at night, at the hand that holds the staff: it moves with their clips
642
- for (const caster of ['priest', 'sorceress', 'archmage']) {
665
+ for (const caster of ['priest', 'sorceress', 'dawnPriest']) {
643
666
  const visual = looks[caster]
644
667
  if (visual?.model)
645
668
  visual.model = {