@v12-engine/create 0.1.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +1 -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
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Buffs and auras: something lasting on a unit, put on by the `buff` effect or kept on everyone near by an `aura`.
3
+ * Stats, a shield, stacks that go off at five, an immolation turned on and off, a bomb that goes off when its time is
4
+ * up, untouchable and unkillable, walking through units, cleaving blows, healing past full kept as a shield, and a
5
+ * doom that leaves a demon where its carrier dies
6
+ */
7
+ import type { AbilityDef, BuffDef } from '@v12-engine/engine'
8
+ import { exampleField } from '../define'
9
+ import { ENEMY, PLAYER } from '../common/units'
10
+ import type { Family } from './family'
11
+ import { caster, put, sparring } from './kit'
12
+
13
+ const buffs: BuffDef[] = [
14
+ // flat and percent stats
15
+ {
16
+ id: 'abilitiesInnerFire',
17
+ name: 'Inner Fire',
18
+ description: '+10 armor, +40% attack damage',
19
+ duration: 20,
20
+ stats: { armor: 10 },
21
+ percent: { attackDamage: 0.4 }
22
+ },
23
+ // a shield takes damage first; its amount set by the cast
24
+ { id: 'abilitiesBarrier', name: 'Barrier', description: 'A shield', duration: 8, shield: 150 },
25
+ // an aura's buff has no duration: it stays while its carrier is near the one with the aura
26
+ { id: 'abilitiesDevotion', name: 'Devotion Aura', description: '+8 armor while near the paladin', stats: { armor: 8 } },
27
+ // stacks: at five, a stun, and the stacks spent
28
+ {
29
+ id: 'abilitiesRend',
30
+ name: 'Rend',
31
+ description: 'Bleeds; at five stacks, a stun',
32
+ harmful: true,
33
+ duration: 6,
34
+ maxStacks: 5,
35
+ stacking: 'refresh',
36
+ onTick: { every: 1, effects: [{ type: 'damage', amount: 10 }] },
37
+ onMaxStacks: [
38
+ { type: 'buff', buff: 'abilitiesRendStun' },
39
+ { type: 'removeBuff', buff: 'abilitiesRend' }
40
+ ]
41
+ },
42
+ { id: 'abilitiesRendStun', name: 'Ruptured', harmful: true, duration: 1.5, stun: true },
43
+ // kept on until cast again, taking mana every second
44
+ {
45
+ id: 'abilitiesImmolating',
46
+ name: 'Immolation',
47
+ description: 'Burns everyone near, 8 mana a second',
48
+ drain: { mana: 8 },
49
+ onTick: { every: 1, effects: [{ type: 'damage', amount: 20, radius: 3 }] }
50
+ },
51
+ // goes off when its time is up
52
+ { id: 'abilitiesTimeBomb', name: 'Time Bomb', harmful: true, duration: 3, onEnd: [{ type: 'damage', amount: 200, radius: 3 }] },
53
+ // no damage, no enemy casts or attacks
54
+ { id: 'abilitiesDivineShield', name: 'Divine Shield', description: 'Takes no damage', duration: 5, invulnerable: true },
55
+ // out of everyone's reach, still seen, and held
56
+ { id: 'abilitiesStasis', name: 'Stasis', description: 'Untouchable and held', duration: 2.5, invulnerable: true, untargetable: true, stun: true },
57
+ // damage never takes it under 100
58
+ { id: 'abilitiesUndying', name: 'Undying Rage', description: 'Can not fall below 100 health', duration: 6, minHealth: 100 },
59
+ // walks through units, and they through it
60
+ { id: 'abilitiesGhost', name: 'Ghost', description: 'Walks through units, 40% faster', duration: 6, phasing: true, percent: { moveSpeed: 0.4 } },
61
+ // its blows strike the enemies around their target too, 60% of their damage
62
+ {
63
+ id: 'abilitiesCleaving',
64
+ name: 'Cleaving Blows',
65
+ description: 'Blows strike those around the target too',
66
+ duration: 10,
67
+ cleave: { part: 0.6, radius: 2.5 }
68
+ },
69
+ // healing it gives past full health becomes a shield on the one healed
70
+ {
71
+ id: 'abilitiesMercy',
72
+ name: 'Mercy’s Echo',
73
+ description: 'Healing past full health becomes a shield',
74
+ duration: 20,
75
+ overheal: { buff: 'abilitiesEcho', part: 1, most: 0.5 }
76
+ },
77
+ { id: 'abilitiesEcho', name: 'Echo', description: 'A shield of healing past full', duration: 6 },
78
+ // where its carrier dies carrying it, a demon of whoever put it on
79
+ {
80
+ id: 'abilitiesDoom',
81
+ name: 'Doom',
82
+ harmful: true,
83
+ duration: 30,
84
+ silence: true,
85
+ onTick: { every: 0.5, effects: [{ type: 'damage', amount: 60 }] },
86
+ onCarrierDeath: [{ type: 'spawn', unit: 'abilitiesDemon' }]
87
+ }
88
+ ]
89
+
90
+ const abilities: AbilityDef[] = [
91
+ {
92
+ id: 'abilitiesCastInnerFire',
93
+ name: 'Inner Fire',
94
+ description: 'An ally: +10 armor and +40% attack damage for 20 seconds',
95
+ hotkey: 'Q',
96
+ target: 'unit',
97
+ targets: { allies: true, self: true },
98
+ range: 8,
99
+ cooldown: 0.5,
100
+ effects: [{ type: 'buff', buff: 'abilitiesInnerFire' }]
101
+ },
102
+ {
103
+ // the buff's shield, sized by the cast
104
+ id: 'abilitiesCastBarrier',
105
+ name: 'Shield',
106
+ description: 'An ally: a shield of 300 for 8 seconds, taken before its health',
107
+ hotkey: 'W',
108
+ target: 'unit',
109
+ targets: { allies: true, self: true },
110
+ range: 8,
111
+ cooldown: 0.5,
112
+ effects: [{ type: 'buff', buff: 'abilitiesBarrier', amount: 300 }]
113
+ },
114
+ {
115
+ id: 'abilitiesCastRend',
116
+ name: 'Rend',
117
+ description: 'A stack of bleeding; at five, a stun, the stacks spent',
118
+ hotkey: 'E',
119
+ target: 'unit',
120
+ targets: { enemies: true },
121
+ range: 8,
122
+ cooldown: 0.2,
123
+ effects: [{ type: 'buff', buff: 'abilitiesRend', stack: true }]
124
+ },
125
+ {
126
+ // `toggle`: on, then off when cast again
127
+ id: 'abilitiesImmolation',
128
+ name: 'Immolation',
129
+ description: 'Turned on and off: burns everyone within 3, for mana every second',
130
+ hotkey: 'R',
131
+ target: 'none',
132
+ effects: [{ type: 'toggle', buff: 'abilitiesImmolating' }]
133
+ },
134
+ {
135
+ id: 'abilitiesCastTimeBomb',
136
+ name: 'Time Bomb',
137
+ description: 'A bomb on an enemy, going off around it in 3 seconds',
138
+ hotkey: 'T',
139
+ target: 'unit',
140
+ targets: { enemies: true },
141
+ range: 8,
142
+ cooldown: 0.5,
143
+ effects: [{ type: 'buff', buff: 'abilitiesTimeBomb' }]
144
+ },
145
+ {
146
+ id: 'abilitiesCastDivineShield',
147
+ name: 'Divine Shield',
148
+ description: 'The caster takes no damage for 5 seconds',
149
+ hotkey: 'D',
150
+ target: 'none',
151
+ cooldown: 0.5,
152
+ effects: [{ type: 'buff', buff: 'abilitiesDivineShield', on: 'caster' }]
153
+ },
154
+ {
155
+ id: 'abilitiesCastStasis',
156
+ name: 'Stasis',
157
+ description: 'The caster is untouchable, by anyone, and held for 2.5 seconds',
158
+ hotkey: 'F',
159
+ target: 'none',
160
+ cooldown: 0.5,
161
+ effects: [{ type: 'buff', buff: 'abilitiesStasis', on: 'caster' }]
162
+ },
163
+ {
164
+ id: 'abilitiesCastUndying',
165
+ name: 'Undying Rage',
166
+ description: 'An ally can not fall below 100 health for 6 seconds',
167
+ hotkey: 'G',
168
+ target: 'unit',
169
+ targets: { allies: true, self: true },
170
+ range: 8,
171
+ cooldown: 0.5,
172
+ effects: [{ type: 'buff', buff: 'abilitiesUndying' }]
173
+ },
174
+ {
175
+ id: 'abilitiesCastGhost',
176
+ name: 'Ghost',
177
+ description: 'The caster walks through units, faster, for 6 seconds',
178
+ hotkey: 'Z',
179
+ target: 'none',
180
+ cooldown: 0.5,
181
+ effects: [{ type: 'buff', buff: 'abilitiesGhost', on: 'caster' }]
182
+ },
183
+ {
184
+ id: 'abilitiesCastCleave',
185
+ name: 'Cleaving Blows',
186
+ description: 'An ally’s blows strike the enemies round its target too',
187
+ hotkey: 'X',
188
+ target: 'unit',
189
+ targets: { allies: true },
190
+ range: 8,
191
+ cooldown: 0.5,
192
+ effects: [{ type: 'buff', buff: 'abilitiesCleaving' }]
193
+ },
194
+ {
195
+ // with Mercy's Echo on the caster, a heal past full health leaves a shield on the healed
196
+ id: 'abilitiesCastMercy',
197
+ name: 'Overheal',
198
+ description: 'The caster’s healing past full becomes a shield; then it heals an ally for 400',
199
+ hotkey: 'C',
200
+ target: 'unit',
201
+ targets: { allies: true, self: true },
202
+ range: 8,
203
+ cooldown: 0.5,
204
+ effects: [
205
+ { type: 'buff', buff: 'abilitiesMercy', on: 'caster' },
206
+ { type: 'heal', amount: 400 }
207
+ ]
208
+ },
209
+ {
210
+ id: 'abilitiesCastDoom',
211
+ name: 'Doom',
212
+ description: 'An enemy is silenced and burns; where it dies a demon of yours stands',
213
+ hotkey: 'V',
214
+ target: 'unit',
215
+ targets: { enemies: true },
216
+ range: 8,
217
+ cooldown: 0.5,
218
+ effects: [{ type: 'buff', buff: 'abilitiesDoom' }]
219
+ },
220
+ {
221
+ // takes stacks or a whole buff off: here every bomb and bleed off everyone near
222
+ id: 'abilitiesDefuse',
223
+ name: 'Remove buffs',
224
+ description: 'Takes every Time Bomb, Rend and Doom off the enemies within 12',
225
+ hotkey: 'B',
226
+ target: 'none',
227
+ cooldown: 0.5,
228
+ effects: [
229
+ { type: 'removeBuff', buff: 'abilitiesTimeBomb', radius: 12, affects: 'enemies' },
230
+ { type: 'removeBuff', buff: 'abilitiesRend', radius: 12, affects: 'enemies' },
231
+ { type: 'removeBuff', buff: 'abilitiesDoom', radius: 12, affects: 'enemies' }
232
+ ]
233
+ }
234
+ ]
235
+
236
+ /** The paladin's aura: a passive that keeps its buff on every ally within 7 */
237
+ const devotionAura: AbilityDef = {
238
+ id: 'abilitiesDevotionAura',
239
+ name: 'Devotion Aura',
240
+ description: 'Allies within 7: +8 armor',
241
+ target: 'passive',
242
+ effects: [{ type: 'aura', buff: 'abilitiesDevotion', radius: 7, affects: 'allies' }]
243
+ }
244
+
245
+ export const buffsFamily: Family = {
246
+ abilities,
247
+ more: [devotionAura],
248
+ buffs,
249
+ units: [
250
+ caster('abilitiesPaladin', 'Paladin', [...abilities.map((each) => each.id), devotionAura.id]),
251
+ // an ally that fights: what Inner Fire and Cleaving Blows make stronger
252
+ sparring('abilitiesSoldier', 'Footman', {
253
+ stats: { health: 900, healthRegen: 3, attackDamage: 20, attackSpeed: 1.1, attackRange: 0.5, armor: 5, moveSpeed: 4 },
254
+ attacks: [{ damagePoint: 0.45, acquisitionRange: 6 }]
255
+ }),
256
+ // what Doom leaves where its carrier dies
257
+ sparring('abilitiesDemon', 'Doom Guard', {
258
+ radius: 0.6,
259
+ stats: { health: 1400, attackDamage: 40, attackSpeed: 1, attackRange: 0.6, armor: 8, moveSpeed: 3.6 },
260
+ attacks: [{ damagePoint: 0.4, acquisitionRange: 8 }],
261
+ lifetime: 30
262
+ })
263
+ ],
264
+ example: {
265
+ id: 'abilities-buffs',
266
+ category: 'abilities',
267
+ title: 'Buffs and auras',
268
+ summary:
269
+ 'Stats, shields, stacks, an aura, a toggle that drains mana, a bomb on a timer, invulnerable and untargetable, a health floor, walking through units, cleaving blows, overheal and a doom. Your footman fights a pack of training footmen while you buff it.',
270
+ tags: ['buff', 'debuff', 'aura', 'shield', 'stacks', 'toggle', 'invulnerable', 'untargetable', 'cleave', 'overheal', 'phasing', 'doom'],
271
+ source: ['examples/abilities/buffs.ts', 'examples/abilities/kit.ts'],
272
+ map: () => exampleField({ name: 'Buffs', players: 2 }),
273
+ start: (world) => {
274
+ put(world, 'abilitiesPaladin', PLAYER, { x: 24, z: 17 }, 'caster')
275
+ put(world, 'abilitiesSoldier', PLAYER, { x: 24, z: 21 }, 'ally')
276
+ // the pack the footman fights: close enough for its blows to cleave
277
+ for (const [i, [x, z]] of [
278
+ [23, 24],
279
+ [25, 24],
280
+ [24, 25.3],
281
+ [22.4, 25.6],
282
+ [25.6, 25.6]
283
+ ].entries())
284
+ put(world, 'abilitiesTarget', ENEMY, { x, z }, `enemy${i + 1}`, Math.PI)
285
+ }
286
+ }
287
+ }
@@ -0,0 +1,46 @@
1
+ /** How the buffs example looks, and its card: a button for each buff (`./buffs.ts`) */
2
+ import { sharedLooks } from '../common/looks'
3
+ import { buffsFamily } from './buffs'
4
+ import type { FamilyLooks } from './looks'
5
+ import { castButton, look, readyOn, resetButton } from './lookKit'
6
+
7
+ /** A buff's look on its carrier: sparks of `shape` in its colour (`glow`) */
8
+ const glow = (color: [number, number, number], shape: string, more: Record<string, unknown> = {}) =>
9
+ look(color, undefined, { aura: 'glow', options: { shape, ...more } })
10
+
11
+ export const buffsLooks: FamilyLooks = {
12
+ units: {
13
+ abilitiesPaladin: { ...sharedLooks.knight, model: { ...sharedLooks.knight.model!, scale: 0.8 } },
14
+ abilitiesSoldier: sharedLooks.footman,
15
+ abilitiesDemon: { ...sharedLooks.knight, model: { ...sharedLooks.knight.model!, scale: 1.25 } }
16
+ },
17
+ abilities: {
18
+ abilitiesCastInnerFire: look([1, 0.55, 0.2], 'burst'),
19
+ abilitiesCastBarrier: look([0.5, 0.8, 1], 'burst'),
20
+ abilitiesImmolation: look([1, 0.45, 0.1], 'burst'),
21
+ abilitiesCastDoom: look([0.6, 0.05, 0.1], 'burst'),
22
+ abilitiesDefuse: look([1, 1, 1], 'sonar'),
23
+ abilitiesInnerFire: glow([1, 0.55, 0.2], 'rise'),
24
+ abilitiesBarrier: glow([0.5, 0.8, 1], 'shell'),
25
+ abilitiesDevotion: glow([1, 0.85, 0.4], 'ring'),
26
+ // a pip a stack over the carrier
27
+ abilitiesRend: look([0.9, 0.1, 0.1], undefined, { counter: { max: 5 }, aura: 'glow', options: { shape: 'fall', solid: true } }),
28
+ abilitiesRendStun: glow([1, 0.3, 0.3], 'ring', { at: 'head' }),
29
+ abilitiesImmolating: glow([1, 0.45, 0.1], 'column', { streaks: true }),
30
+ abilitiesTimeBomb: glow([1, 0.2, 0.1], 'ring', { at: 'head' }),
31
+ abilitiesDivineShield: glow([1, 0.95, 0.6], 'shell'),
32
+ abilitiesStasis: glow([0.95, 0.85, 0.3], 'shell'),
33
+ abilitiesUndying: glow([0.9, 0.2, 0.15], 'rise'),
34
+ abilitiesGhost: glow([0.7, 0.8, 1], 'dust'),
35
+ abilitiesCleaving: glow([0.9, 0.9, 0.9], 'about', { streaks: true }),
36
+ abilitiesMercy: glow([0.6, 1, 0.7], 'rise'),
37
+ abilitiesEcho: glow([0.6, 1, 0.7], 'shell'),
38
+ abilitiesDoom: glow([0.7, 0.05, 0.1], 'rise')
39
+ },
40
+ examples: {
41
+ 'abilities-buffs': {
42
+ ready: (client) => readyOn(client, 'abilitiesPaladin', { minX: 18, minZ: 14, maxX: 30, maxZ: 28 }),
43
+ controls: [...buffsFamily.abilities.map((ability) => castButton(ability)), resetButton('abilities-buffs')]
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Changing abilities while the game runs (the ability changes pack, `abilityChangesPack`): one granted for a while,
3
+ * one swapped for a stronger one for a cast, an enemy's ultimate stolen, an enemy taken over, one upgraded for good;
4
+ * and forms (`morph`): a demon form for a while, a cougar form turned on and off, each with abilities of its own
5
+ */
6
+ import { type AbilityDef, type BuffDef, defineCommand, upgradeAbility } from '@v12-engine/engine'
7
+ import { exampleField } from '../define'
8
+ import { ENEMY, PLAYER } from '../common/units'
9
+ import type { Family } from './family'
10
+ import { caster, put, sparring } from './kit'
11
+
12
+ const buffs: BuffDef[] = [{ id: 'abilitiesSiphoned', name: 'Siphoned', harmful: true, duration: 3, percent: { moveSpeed: -0.5 } }]
13
+
14
+ const abilities: AbilityDef[] = [
15
+ {
16
+ // added after the caster's others, for 20 seconds
17
+ id: 'abilitiesGift',
18
+ name: 'Gift',
19
+ description: 'Holy Nova, added to the card for 20 seconds',
20
+ hotkey: 'Q',
21
+ target: 'none',
22
+ cooldown: 1,
23
+ effects: [{ type: 'grantAbility', ability: 'abilitiesHolyNova', atLevel: 1, duration: 20, on: 'caster' }]
24
+ },
25
+ {
26
+ // Wildfire gives way to its awakened form for one cast, then comes back
27
+ id: 'abilitiesAwaken',
28
+ name: 'Awaken',
29
+ description: 'Wildfire becomes Wildfire Awakened for one cast',
30
+ hotkey: 'W',
31
+ target: 'none',
32
+ cooldown: 1,
33
+ effects: [{ type: 'swapAbility', from: 'abilitiesWildfire', ability: 'abilitiesWildfireAwakened', uses: 1, on: 'caster' }]
34
+ },
35
+ {
36
+ id: 'abilitiesWildfire',
37
+ name: 'Wildfire',
38
+ description: 'Burns round the nearest enemy for 60',
39
+ hotkey: 'E',
40
+ target: 'point',
41
+ range: 9,
42
+ cooldown: 0.5,
43
+ effects: [{ type: 'damage', amount: 60, radius: 1.5 }]
44
+ },
45
+ {
46
+ // the target's ultimate in the place of Hijack, for one cast
47
+ id: 'abilitiesHijack',
48
+ name: 'Hijack',
49
+ description: 'Takes the warlock’s ultimate, Cataclysm, for one cast in its place',
50
+ hotkey: 'R',
51
+ target: 'unit',
52
+ targets: { enemies: true },
53
+ range: 12,
54
+ cooldown: 1,
55
+ effects: [{ type: 'stealAbility', pick: 'ultimate' }]
56
+ },
57
+ {
58
+ id: 'abilitiesTakeOver',
59
+ name: 'Take over',
60
+ description: 'An enemy footman is yours for 15 seconds',
61
+ hotkey: 'T',
62
+ target: 'unit',
63
+ targets: { enemies: true },
64
+ range: 12,
65
+ cooldown: 1,
66
+ effects: [{ type: 'convert', duration: 15 }]
67
+ },
68
+ {
69
+ // what it may be made into for good (`upgrades`): the Upgrade button picks it
70
+ id: 'abilitiesSiphon',
71
+ name: 'Siphon Power',
72
+ description: 'A blow of 60; upgraded, it slows and heals the caster too',
73
+ hotkey: 'D',
74
+ target: 'unit',
75
+ targets: { enemies: true },
76
+ range: 9,
77
+ cooldown: 0.5,
78
+ upgrades: ['abilitiesSiphonAugmented'],
79
+ effects: [{ type: 'damage', amount: 60 }]
80
+ },
81
+ {
82
+ // another unit type where it stands, for 15 seconds: its stats and its abilities
83
+ id: 'abilitiesMetamorphosis',
84
+ name: 'Metamorphosis',
85
+ description: 'A demon for 15 seconds, with a demon’s strength and spells',
86
+ hotkey: 'F',
87
+ target: 'none',
88
+ cooldown: 1,
89
+ effects: [{ type: 'morph', into: 'abilitiesDemonForm', duration: 15 }]
90
+ },
91
+ {
92
+ // cast again (the cougar has it too) to turn back
93
+ id: 'abilitiesAspect',
94
+ name: 'Aspect of the Cougar',
95
+ description: 'A cougar until cast again, with a pounce of its own',
96
+ hotkey: 'G',
97
+ target: 'none',
98
+ cooldown: 1,
99
+ effects: [{ type: 'morph', into: 'abilitiesCougar', toggle: true }]
100
+ }
101
+ ]
102
+
103
+ const more: AbilityDef[] = [
104
+ {
105
+ id: 'abilitiesHolyNova',
106
+ name: 'Holy Nova',
107
+ description: 'Heals allies and burns enemies within 4',
108
+ hotkey: 'Z',
109
+ target: 'none',
110
+ cooldown: 0.5,
111
+ effects: [
112
+ { type: 'heal', amount: 100, radius: 4 },
113
+ { type: 'damage', amount: 60, radius: 4 }
114
+ ]
115
+ },
116
+ {
117
+ id: 'abilitiesWildfireAwakened',
118
+ name: 'Wildfire Awakened',
119
+ description: 'Burns round the nearest enemy for 250',
120
+ hotkey: 'E',
121
+ target: 'point',
122
+ range: 9,
123
+ cooldown: 0.5,
124
+ effects: [{ type: 'damage', amount: 250, radius: 3 }]
125
+ },
126
+ {
127
+ id: 'abilitiesSiphonAugmented',
128
+ name: 'Siphon Power+',
129
+ description: 'A blow of 60 that slows, and heals the caster as much',
130
+ hotkey: 'D',
131
+ target: 'unit',
132
+ targets: { enemies: true },
133
+ range: 9,
134
+ cooldown: 0.5,
135
+ effects: [
136
+ { type: 'damage', amount: 60 },
137
+ { type: 'buff', buff: 'abilitiesSiphoned' },
138
+ { type: 'heal', amount: 60, on: 'caster' }
139
+ ]
140
+ },
141
+ {
142
+ id: 'abilitiesCataclysm',
143
+ name: 'Cataclysm',
144
+ description: 'The warlock’s ultimate: fire falls round the spot',
145
+ target: 'point',
146
+ range: 12,
147
+ ultimate: true,
148
+ cooldown: 30,
149
+ effects: [{ type: 'after', delay: 0.8, effects: [{ type: 'damage', amount: 200, radius: 3.5 }] }]
150
+ },
151
+ {
152
+ id: 'abilitiesChaosBolt',
153
+ name: 'Chaos Bolt',
154
+ description: 'A demon’s bolt for 160',
155
+ hotkey: 'Q',
156
+ target: 'unit',
157
+ targets: { enemies: true },
158
+ range: 9,
159
+ cooldown: 0.5,
160
+ effects: [{ type: 'missile', homing: true, speed: 16, effects: [{ type: 'damage', amount: 160 }] }]
161
+ },
162
+ {
163
+ id: 'abilitiesPounce',
164
+ name: 'Pounce',
165
+ description: 'Leaps at the spot, clawing round where it lands',
166
+ hotkey: 'W',
167
+ target: 'point',
168
+ range: 5,
169
+ cooldown: 0.5,
170
+ effects: [{ type: 'dash', distance: 5, speed: 16, leap: 1, effects: [{ type: 'damage', amount: 80, radius: 1.5 }] }]
171
+ }
172
+ ]
173
+
174
+ /** Makes Siphon Power into Siphon Power+ for good: what a player's pick of an upgrade does (`upgradeAbility`) */
175
+ export const upgrade = defineCommand('abilities.upgrade', {}, (world, player) => {
176
+ const unit = world.named('caster')
177
+ if (unit && unit.owner === player) upgradeAbility(world, unit, 'abilitiesSiphon', 'abilitiesSiphonAugmented')
178
+ })
179
+
180
+ export const changing: Family = {
181
+ abilities,
182
+ more,
183
+ buffs,
184
+ commands: [upgrade],
185
+ units: [
186
+ caster(
187
+ 'abilitiesShifter',
188
+ 'Shifter',
189
+ abilities.map((each) => each.id)
190
+ ),
191
+ // the forms: unit types of their own, with what they cast
192
+ caster('abilitiesDemonForm', 'Demon form', ['abilitiesChaosBolt'], {
193
+ radius: 0.6,
194
+ stats: {
195
+ health: 2000,
196
+ healthRegen: 10,
197
+ mana: 1000,
198
+ manaRegen: 60,
199
+ attackDamage: 60,
200
+ attackSpeed: 1,
201
+ attackRange: 0.7,
202
+ moveSpeed: 4.6,
203
+ armor: 15
204
+ }
205
+ }),
206
+ caster('abilitiesCougar', 'Cougar', ['abilitiesPounce', 'abilitiesAspect'], {
207
+ radius: 0.45,
208
+ stats: { health: 1200, healthRegen: 4, mana: 1000, manaRegen: 60, attackDamage: 45, attackSpeed: 1.4, attackRange: 0.5, moveSpeed: 5.5 }
209
+ }),
210
+ // an enemy with an ultimate to steal
211
+ sparring('abilitiesWarlock', 'Warlock', { abilities: ['abilitiesCataclysm'] })
212
+ ],
213
+ example: {
214
+ id: 'abilities-changing',
215
+ category: 'abilities',
216
+ title: 'Changing abilities and forms',
217
+ summary:
218
+ 'An ability granted for a while, one swapped for a stronger cast, the warlock’s ultimate stolen, a footman taken over, an upgrade for good, a demon form and a cougar form. Watch the card below change.',
219
+ tags: ['grant', 'swap', 'steal', 'convert', 'upgrade', 'morph', 'form', 'transform', 'shapeshift'],
220
+ source: ['examples/abilities/changing.ts', 'examples/abilities/kit.ts'],
221
+ map: () => exampleField({ name: 'Changing', players: 2 }),
222
+ start: (world) => {
223
+ put(world, 'abilitiesShifter', PLAYER, { x: 24, z: 18 }, 'caster')
224
+ put(world, 'abilitiesWarlock', ENEMY, { x: 28, z: 25 }, 'warlock', Math.PI)
225
+ for (const [i, x] of [20, 23].entries()) put(world, 'abilitiesTarget', ENEMY, { x, z: 25 }, `enemy${i + 1}`, Math.PI)
226
+ }
227
+ }
228
+ }
@@ -0,0 +1,61 @@
1
+ /** How the changing abilities example looks, and its card: what changes the card, and what the changes give */
2
+ import { button } from '../../shell/look'
3
+ import { character, hold, person, sharedLooks, TWO_HANDED } from '../common/looks'
4
+ import { changing, upgrade } from './changing'
5
+ import type { FamilyLooks } from './looks'
6
+ import { castButton, look, readyOn, resetButton } from './lookKit'
7
+
8
+ /** What the changes put on the card, cast by name: each is refused while the caster does not have it */
9
+ const given = ['abilitiesHolyNova', 'abilitiesWildfireAwakened', 'abilitiesCataclysm', 'abilitiesChaosBolt', 'abilitiesPounce']
10
+
11
+ export const changingLooks: FamilyLooks = {
12
+ units: {
13
+ abilitiesShifter: sharedLooks.mage,
14
+ abilitiesDemonForm: {
15
+ height: 2.6,
16
+ model: character('barbarian', 1.1, { hold: [hold('axe_2handed')] }),
17
+ attacks: [TWO_HANDED],
18
+ shapes: person(2.6, [0.5, 0.05, 0.1])
19
+ },
20
+ // the shared art has no animals: a cougar of parts, a long body and a head
21
+ abilitiesCougar: {
22
+ height: 1,
23
+ shapes: [
24
+ { shape: 'sphere', size: [0.7, 0.6, 1.4], offset: [0, 0.6, 0], color: [0.75, 0.55, 0.3] },
25
+ { shape: 'sphere', size: [0.45, 0.45, 0.5], offset: [0, 0.85, 0.75], color: [0.7, 0.5, 0.28] }
26
+ ]
27
+ },
28
+ abilitiesWarlock: { ...sharedLooks.mage, model: character('skeleton_mage', 0.72, { hold: [hold('staff')] }) }
29
+ },
30
+ abilities: {
31
+ abilitiesGift: look([1, 0.95, 0.6], 'burst'),
32
+ abilitiesAwaken: look([1, 0.5, 0.1], 'burst'),
33
+ abilitiesWildfire: look([1, 0.5, 0.1], 'smash'),
34
+ abilitiesWildfireAwakened: look([1, 0.3, 0.05], 'smash'),
35
+ abilitiesHijack: look([0.4, 0.8, 1], 'tether'),
36
+ abilitiesTakeOver: look([1, 0.4, 0.8], 'tether'),
37
+ abilitiesSiphon: look([0.5, 0.3, 1], 'burst'),
38
+ abilitiesSiphonAugmented: look([0.3, 1, 0.8], 'burst'),
39
+ abilitiesMetamorphosis: look([0.6, 0.05, 0.1], 'tornado'),
40
+ abilitiesAspect: look([0.9, 0.7, 0.3], 'burst'),
41
+ abilitiesHolyNova: look([1, 0.95, 0.6], 'slam'),
42
+ abilitiesCataclysm: look([1, 0.35, 0.1], 'mark', { options: { lasts: 0.8, falls: 16, burst: 40 } }),
43
+ abilitiesChaosBolt: look([0.5, 1, 0.3], 'missile', { options: { shape: 'ball' } }),
44
+ abilitiesPounce: look([0.9, 0.7, 0.3], 'slam'),
45
+ abilitiesSiphoned: look([0.3, 1, 0.8], undefined, { aura: 'glow', options: { shape: 'fall' } })
46
+ },
47
+ examples: {
48
+ 'abilities-changing': {
49
+ ready: (client) => readyOn(client, 'abilitiesShifter'),
50
+ controls: [
51
+ ...changing.abilities.map((ability) => castButton(ability, ability.id === 'abilitiesHijack' ? { at: 'warlock' } : {})),
52
+ button('Upgrade Siphon Power', (client) => client.session.send(upgrade.make({})), 'Makes Siphon Power into Siphon Power+ for good'),
53
+ ...given.map((id) => {
54
+ const ability = changing.more!.find((each) => each.id === id)!
55
+ return castButton(ability, { label: `${ability.name} (given)` })
56
+ }),
57
+ resetButton('abilities-changing')
58
+ ]
59
+ }
60
+ }
61
+ }