@v12-engine/create 0.0.0-stage → 0.1.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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -2
  3. package/base/_gitignore +10 -0
  4. package/base/index.html +20 -0
  5. package/base/package.json +23 -0
  6. package/base/src/ground.worker.ts +8 -0
  7. package/base/src/main.ts +61 -0
  8. package/base/tsconfig.json +14 -0
  9. package/base/vite.config.ts +25 -0
  10. package/bin.mjs +10 -0
  11. package/cli.mjs +381 -0
  12. package/index.mjs +286 -0
  13. package/layers/assets/package.json +5 -0
  14. package/layers/editor/package.json +8 -0
  15. package/layers/editor/src/editor.ts +13 -0
  16. package/layers/rooms/server.ts +69 -0
  17. package/layers/server/package.json +8 -0
  18. package/layers/server/server.ts +34 -0
  19. package/layers/source/package.json +12 -0
  20. package/layers/source/tsconfig.json +5 -0
  21. package/layers/source/vite.config.ts +45 -0
  22. package/layers/tests/package.json +8 -0
  23. package/package.json +45 -5
  24. package/starters/campaign/README.md +61 -0
  25. package/starters/campaign/files.txt +42 -0
  26. package/starters/campaign/layers/editor/src/editor.ts +18 -0
  27. package/starters/campaign/layers/rooms/server.ts +39 -0
  28. package/starters/campaign/layers/server/server.ts +33 -0
  29. package/starters/campaign/layers/tests/tests/rules.test.ts +320 -0
  30. package/starters/campaign/public/games/campaign/assets.json +1 -0
  31. package/starters/campaign/src/campaign/campaign.json +52 -0
  32. package/starters/campaign/src/campaign/carry.ts +47 -0
  33. package/starters/campaign/src/campaign/cinematics/intro.json +148 -0
  34. package/starters/campaign/src/campaign/cinematics/outro.json +92 -0
  35. package/starters/campaign/src/campaign/data.json +1 -0
  36. package/starters/campaign/src/campaign/fx.json +1 -0
  37. package/starters/campaign/src/campaign/game.ts +6 -0
  38. package/starters/campaign/src/campaign/ids.ts +77 -0
  39. package/starters/campaign/src/campaign/index.ts +121 -0
  40. package/starters/campaign/src/campaign/kills.ts +16 -0
  41. package/starters/campaign/src/campaign/looks.json +1 -0
  42. package/starters/campaign/src/campaign/maps.ts +34 -0
  43. package/starters/campaign/src/campaign/missions/homecoming.ts +160 -0
  44. package/starters/campaign/src/campaign/missions/siege.ts +91 -0
  45. package/starters/campaign/src/campaign/missions/warlord.ts +177 -0
  46. package/starters/campaign/src/campaign/prefabs/watchpost.prefab.json +18 -0
  47. package/starters/campaign/src/campaign/scenes.ts +46 -0
  48. package/starters/campaign/src/campaign/tiles.ts +8 -0
  49. package/starters/campaign/src/campaign/units.ts +390 -0
  50. package/starters/campaign/src/campaign/view/cinematics.ts +59 -0
  51. package/starters/campaign/src/campaign/view/fire.ts +115 -0
  52. package/starters/campaign/src/campaign/view/index.ts +334 -0
  53. package/starters/campaign/src/campaign/view/labels.ts +105 -0
  54. package/starters/campaign/src/campaign/view/rubble.ts +40 -0
  55. package/starters/campaign/src/campaign/view/waveLane.ts +88 -0
  56. package/starters/campaign/src/campaign/waves.json +36 -0
  57. package/starters/campaign/src/campaign/waves.ts +186 -0
  58. package/starters/campaign/src/campaign-editor.ts +43 -0
  59. package/starters/campaign/src/game.ts +2 -0
  60. package/starters/campaign/src/main.ts +70 -0
  61. package/starters/campaign/src/maps/fort.names.ts +31 -0
  62. package/starters/campaign/src/maps/fort.vgmap.json +1162 -0
  63. package/starters/campaign/src/maps/homestead.names.ts +36 -0
  64. package/starters/campaign/src/maps/homestead.vgmap.json +916 -0
  65. package/starters/campaign/src/maps/pass.names.ts +40 -0
  66. package/starters/campaign/src/maps/pass.vgmap.json +522 -0
  67. package/starters/campaign/src/maps.ts +2 -0
  68. package/starters/campaign/src/rules.ts +20 -0
  69. package/starters/campaign/src/waves-panel.ts +355 -0
  70. package/starters/empty/README.md +71 -0
  71. package/starters/empty/layers/tests/tests/rules.test.ts +31 -0
  72. package/starters/empty/src/game.ts +79 -0
  73. package/starters/empty/src/generate.worker.ts +9 -0
  74. package/starters/empty/src/maps.ts +44 -0
  75. package/starters/empty/src/rules.ts +67 -0
  76. package/starters/empty/src/tiles.ts +12 -0
  77. package/starters/melee/README.md +61 -0
  78. package/starters/melee/files.txt +60 -0
  79. package/starters/melee/layers/editor/src/editor.ts +13 -0
  80. package/starters/melee/layers/tests/tests/rules.test.ts +58 -0
  81. package/starters/melee/src/game.ts +2 -0
  82. package/starters/melee/src/maps/bay.names.ts +28 -0
  83. package/starters/melee/src/maps/bay.vgmap.json +3123 -0
  84. package/starters/melee/src/maps.ts +20 -0
  85. package/starters/melee/src/melee/abilities.ts +376 -0
  86. package/starters/melee/src/melee/bay.ts +319 -0
  87. package/starters/melee/src/melee/blight.ts +102 -0
  88. package/starters/melee/src/melee/cellLayers.json +11 -0
  89. package/starters/melee/src/melee/data.json +18 -0
  90. package/starters/melee/src/melee/floats.json +199 -0
  91. package/starters/melee/src/melee/formations.ts +46 -0
  92. package/starters/melee/src/melee/fx.json +1 -0
  93. package/starters/melee/src/melee/game.ts +6 -0
  94. package/starters/melee/src/melee/generator.ts +116 -0
  95. package/starters/melee/src/melee/heroSpells.ts +38 -0
  96. package/starters/melee/src/melee/hud.json +269 -0
  97. package/starters/melee/src/melee/index.ts +182 -0
  98. package/starters/melee/src/melee/items.ts +362 -0
  99. package/starters/melee/src/melee/languages/he.json +96 -0
  100. package/starters/melee/src/melee/looks.json +1 -0
  101. package/starters/melee/src/melee/maps.ts +53 -0
  102. package/starters/melee/src/melee/pings.json +16 -0
  103. package/starters/melee/src/melee/pings.ts +34 -0
  104. package/starters/melee/src/melee/quality.json +1 -0
  105. package/starters/melee/src/melee/saves.ts +12 -0
  106. package/starters/melee/src/melee/sounds.json +1 -0
  107. package/starters/melee/src/melee/undead.ts +683 -0
  108. package/starters/melee/src/melee/units.ts +785 -0
  109. package/starters/melee/src/melee/view/buildings.ts +33 -0
  110. package/starters/melee/src/melee/view/cheerLane.ts +42 -0
  111. package/starters/melee/src/melee/view/heroSpellLooks.ts +21 -0
  112. package/starters/melee/src/melee/view/index.ts +268 -0
  113. package/starters/melee/src/melee/view/languages.ts +10 -0
  114. package/starters/melee/src/melee/view/looks.ts +659 -0
  115. package/starters/melee/src/melee/view/undeadLooks.ts +220 -0
  116. package/starters/melee/src/melee/view/walls.ts +59 -0
  117. package/starters/melee/src/rules.ts +24 -0
  118. package/starters.mjs +35 -0
  119. package/v12.mjs +111 -0
@@ -0,0 +1,785 @@
1
+ import { rubbleType, type UnitTypeDef, type UpgradeDef } from '@v12-engine/engine'
2
+ import { catalogue } from './items'
3
+ import { undeadUnits, undeadUpgrades } from './undead'
4
+
5
+ export const peasant: UnitTypeDef = {
6
+ id: 'peasant',
7
+ armourType: 'medium',
8
+ race: 'human',
9
+ name: 'Peasant',
10
+ kind: 'unit',
11
+ radius: 0.4,
12
+ stats: { health: 250, attackDamage: 8, attackSpeed: 0.6, attackRange: 0.4, moveSpeed: 4.05 },
13
+ sight: 8,
14
+ attacks: [{ attackType: 'normal', damagePoint: 0.4, acquisitionRange: 0, targets: ['unit', 'building'] }],
15
+ cost: { gold: 75 },
16
+ supply: 1,
17
+ buildTime: 10,
18
+ harvester: { capacity: 10, gatherTime: 1.5 },
19
+ builds: ['townhall', 'farm', 'barracks', 'altar', 'lumbermill', 'tower', 'blacksmith', 'alchemist', 'armory', 'aviary', 'stoneWall', 'stoneGate'],
20
+ hotkey: 'P',
21
+ threat: 1
22
+ }
23
+
24
+ export const footman: UnitTypeDef = {
25
+ id: 'footman',
26
+ armourType: 'heavy',
27
+ race: 'human',
28
+ name: 'Footman',
29
+ kind: 'unit',
30
+ radius: 0.45,
31
+ stats: { health: 480, attackDamage: 12, attackSpeed: 1.25, attackRange: 0.5, armor: 10, moveSpeed: 4.05 },
32
+ sight: 10,
33
+ attacks: [{ attackType: 'normal', damagePoint: 0.45, acquisitionRange: 8 }],
34
+ cost: { gold: 135 },
35
+ supply: 2,
36
+ buildTime: 14,
37
+ abilities: ['defend'],
38
+ hotkey: 'F'
39
+ }
40
+
41
+ export const rifleman: UnitTypeDef = {
42
+ id: 'rifleman',
43
+ armourType: 'medium',
44
+ race: 'human',
45
+ name: 'Rifleman',
46
+ kind: 'unit',
47
+ radius: 0.45,
48
+ stats: { health: 300, attackDamage: 23, attackSpeed: 0.667, attackRange: 6.9, moveSpeed: 4.05 },
49
+ sight: 11,
50
+ attacks: [{ attackType: 'pierce', damagePoint: 0.35, acquisitionRange: 9, projectileSpeed: 22, targets: ['ground', 'air'] }],
51
+ cost: { gold: 205, lumber: 30 },
52
+ supply: 3,
53
+ buildTime: 18,
54
+ requires: ['blacksmith'],
55
+ hotkey: 'R'
56
+ }
57
+
58
+ export const catapult: UnitTypeDef = {
59
+ id: 'catapult',
60
+ armourType: 'heavy',
61
+ race: 'human',
62
+ name: 'Catapult',
63
+ kind: 'unit',
64
+ radius: 0.7,
65
+ stats: { health: 900, attackDamage: 60, attackSpeed: 0.28, attackRange: 13, armor: 15, armorPenetration: 0.4, moveSpeed: 2.6 },
66
+ sight: 10,
67
+ turnRate: 2.5,
68
+ attacks: [
69
+ {
70
+ attackType: 'siege',
71
+ damagePoint: 0.6,
72
+ acquisitionRange: 11,
73
+ projectileSpeed: 11,
74
+ splash: 2.2,
75
+ ground: true,
76
+ fells: true
77
+ }
78
+ ],
79
+ cost: { gold: 220, lumber: 120 },
80
+ supply: 4,
81
+ buildTime: 30,
82
+ requires: ['blacksmith', 'lumbermill'],
83
+ hotkey: 'C'
84
+ }
85
+
86
+ export const gryphon: UnitTypeDef = {
87
+ id: 'gryphon',
88
+ armourType: 'medium',
89
+ race: 'human',
90
+ name: 'Gryphon Rider',
91
+ kind: 'unit',
92
+ radius: 0.6,
93
+ flying: true,
94
+ stats: { health: 700, attackDamage: 45, attackSpeed: 0.5, attackRange: 4.5, armor: 10, magicResist: 20, moveSpeed: 5 },
95
+ sight: 12,
96
+ turnRate: 6,
97
+ attacks: [{ attackType: 'normal', damageType: 'magic', damagePoint: 0.5, acquisitionRange: 8, projectileSpeed: 14, targets: ['ground', 'air'] }],
98
+ cost: { gold: 280, lumber: 70 },
99
+ supply: 4,
100
+ buildTime: 35,
101
+ hotkey: 'G'
102
+ }
103
+
104
+ export const priest: UnitTypeDef = {
105
+ id: 'priest',
106
+ armourType: 'light',
107
+ race: 'human',
108
+ name: 'Priest',
109
+ kind: 'unit',
110
+ radius: 0.4,
111
+ stats: { health: 290, mana: 200, manaRegen: 0.7, attackDamage: 10, attackSpeed: 0.6, attackRange: 6, moveSpeed: 4.05 },
112
+ initialMana: 75,
113
+ sight: 10,
114
+ attacks: [{ attackType: 'magic', damageType: 'magic', damagePoint: 0.4, acquisitionRange: 7, projectileSpeed: 16, targets: ['ground', 'air'] }],
115
+ abilities: ['heal', 'innerFire', 'raiseDead', 'dispelMagic'],
116
+ cost: { gold: 145, lumber: 10 },
117
+ supply: 2,
118
+ buildTime: 18,
119
+ requires: ['keep'],
120
+ hotkey: 'T'
121
+ }
122
+
123
+ export const sorceress: UnitTypeDef = {
124
+ id: 'sorceress',
125
+ armourType: 'light',
126
+ race: 'human',
127
+ name: 'Sorceress',
128
+ kind: 'unit',
129
+ radius: 0.4,
130
+ stats: { health: 325, mana: 200, manaRegen: 0.7, attackDamage: 12, attackSpeed: 0.6, attackRange: 6, moveSpeed: 4.05 },
131
+ initialMana: 75,
132
+ sight: 10,
133
+ attacks: [{ attackType: 'magic', damageType: 'magic', damagePoint: 0.4, acquisitionRange: 7, projectileSpeed: 16, targets: ['ground', 'air'] }],
134
+ abilities: ['slow', 'arcaneBlast', 'manaShield', 'mirrorImage'],
135
+ cost: { gold: 165, lumber: 20 },
136
+ supply: 2,
137
+ buildTime: 20,
138
+ requires: ['keep'],
139
+ hotkey: 'S'
140
+ }
141
+
142
+ export const paladin: UnitTypeDef = {
143
+ id: 'paladin',
144
+ armourType: 'hero',
145
+ race: 'human',
146
+ name: 'Paladin',
147
+ kind: 'unit',
148
+ radius: 0.5,
149
+ stats: {
150
+ health: 645,
151
+ healthRegen: 1.2,
152
+ mana: 300,
153
+ manaRegen: 1.7,
154
+ attackDamage: 55,
155
+ attackSpeed: 0.625,
156
+ attackRange: 0.6,
157
+ armor: 40,
158
+ magicResist: 32,
159
+ moveSpeed: 4.25
160
+ },
161
+ sight: 12,
162
+ attacks: [{ attackType: 'hero', damagePoint: 0.45, acquisitionRange: 8 }],
163
+ hero: {
164
+ growth: {
165
+ stats: { health: 99, healthRegen: 0.1, mana: 60, manaRegen: 0.2, attackDamage: 3.5, armor: 4.3, magicResist: 2.05 },
166
+ percent: { attackSpeed: 0.02 }
167
+ },
168
+ learns: ['holyLight', 'stomp', 'devotionAura', 'blessedSprint', 'avatar'],
169
+ spells: ['barrier', 'flash']
170
+ },
171
+ inventory: 6,
172
+ cost: { gold: 425, lumber: 100 },
173
+ supply: 5,
174
+ buildTime: 45,
175
+ hotkey: 'P',
176
+ threat: 3
177
+ }
178
+
179
+ export const archmage: UnitTypeDef = {
180
+ id: 'archmage',
181
+ armourType: 'hero',
182
+ race: 'human',
183
+ name: 'Archmage',
184
+ kind: 'unit',
185
+ radius: 0.5,
186
+ stats: {
187
+ health: 580,
188
+ healthRegen: 1.1,
189
+ mana: 480,
190
+ manaRegen: 1.6,
191
+ attackDamage: 54,
192
+ attackSpeed: 0.669,
193
+ attackRange: 6.9,
194
+ armor: 21,
195
+ magicResist: 30,
196
+ moveSpeed: 4.1
197
+ },
198
+ sight: 12,
199
+ attacks: [{ attackType: 'hero', damageType: 'magic', damagePoint: 0.4, acquisitionRange: 8, projectileSpeed: 18, targets: ['ground', 'air'] }],
200
+ hero: {
201
+ growth: {
202
+ stats: { health: 99, healthRegen: 0.11, mana: 24, manaRegen: 0.16, attackDamage: 3.3, armor: 5.2, magicResist: 1.3 },
203
+ percent: { attackSpeed: 0.03 }
204
+ },
205
+ learns: ['flameStrike', 'frostBolt', 'clarityAura', 'cataclysm'],
206
+ spells: ['secondWind', 'flash']
207
+ },
208
+ inventory: 6,
209
+ cost: { gold: 425, lumber: 100 },
210
+ supply: 5,
211
+ buildTime: 45,
212
+ hotkey: 'A',
213
+ threat: 3
214
+ }
215
+
216
+ export const testiro: UnitTypeDef = {
217
+ id: 'testiro',
218
+ armourType: 'hero',
219
+ race: 'human',
220
+ name: 'Testiro',
221
+ kind: 'unit',
222
+ radius: 0.5,
223
+ stats: {
224
+ health: 570,
225
+ healthRegen: 1.1,
226
+ mana: 360,
227
+ manaRegen: 2.3,
228
+ attackDamage: 52,
229
+ attackSpeed: 0.625,
230
+ attackRange: 6.9,
231
+ armor: 28,
232
+ magicResist: 30,
233
+ moveSpeed: 4.1
234
+ },
235
+ sight: 12,
236
+ attacks: [{ attackType: 'hero', damageType: 'magic', damagePoint: 0.4, acquisitionRange: 8, projectileSpeed: 18, targets: ['ground', 'air'] }],
237
+ hero: {
238
+ growth: {
239
+ stats: { health: 90, healthRegen: 0.1, mana: 64, manaRegen: 0.08, attackDamage: 3, armor: 4.5, magicResist: 1.3 },
240
+ percent: { attackSpeed: 0.025 }
241
+ },
242
+ learns: ['tornado', 'groundSmash', 'lasso'],
243
+ spells: ['secondWind', 'flash']
244
+ },
245
+ inventory: 6,
246
+ cost: { gold: 425, lumber: 100 },
247
+ supply: 5,
248
+ buildTime: 45,
249
+ hotkey: 'E',
250
+ threat: 3
251
+ }
252
+
253
+ export const altar: UnitTypeDef = {
254
+ id: 'altar',
255
+ armourType: 'fortified',
256
+ race: 'human',
257
+ name: 'Hero Altar',
258
+ kind: 'building',
259
+ radius: 1.5,
260
+ footprint: { w: 3, d: 3 },
261
+ stats: { health: 1350, armor: 40, magicResist: 40 },
262
+ sight: 9,
263
+ cost: { gold: 180, lumber: 50 },
264
+ buildTime: 30,
265
+ trains: ['paladin', 'archmage', 'testiro'],
266
+ revives: true,
267
+ hotkey: 'L'
268
+ }
269
+
270
+ /** Put down by a hero from the Sentry Ward item: sees around it for a minute, and enemies only see it being put down */
271
+ export const ward: UnitTypeDef = {
272
+ id: 'ward',
273
+ armourType: 'unarmored',
274
+ name: 'Sentry Ward',
275
+ kind: 'unit',
276
+ radius: 0.3,
277
+ stats: { health: 3 },
278
+ sight: 12,
279
+ sightNight: 12,
280
+ lifetime: 60,
281
+ invisible: { after: 2 },
282
+ hits: 3,
283
+ bounty: [15, 15],
284
+ xp: 15
285
+ }
286
+
287
+ /** Raised from a corpse by a priest's Raise Dead: weak, and gone after a while */
288
+ export const skeleton: UnitTypeDef = {
289
+ id: 'skeleton',
290
+ armourType: 'light',
291
+ name: 'Skeleton Warrior',
292
+ kind: 'unit',
293
+ radius: 0.4,
294
+ stats: { health: 180, attackDamage: 9, attackSpeed: 0.75, attackRange: 1, moveSpeed: 3.5, armor: 5 },
295
+ sight: 8,
296
+ attacks: [{ attackType: 'normal', damagePoint: 0.4, acquisitionRange: 6 }],
297
+ // bones leave no corpse to raise again
298
+ corpse: false,
299
+ abilities: ['burrow'],
300
+ xp: 10
301
+ }
302
+
303
+ // ---- creeps
304
+
305
+ export const gnoll: UnitTypeDef = {
306
+ id: 'gnoll',
307
+ armourType: 'medium',
308
+ name: 'Gnoll',
309
+ kind: 'unit',
310
+ radius: 0.42,
311
+ stats: { health: 400, attackDamage: 16, attackSpeed: 0.7, attackRange: 0.5, moveSpeed: 4 },
312
+ sight: 8,
313
+ attacks: [{ attackType: 'normal', damagePoint: 0.4, acquisitionRange: 5 }],
314
+ level: 1,
315
+ bounty: [8, 12],
316
+ xp: 25
317
+ }
318
+
319
+ export const troll: UnitTypeDef = {
320
+ id: 'troll',
321
+ armourType: 'medium',
322
+ name: 'Forest Troll',
323
+ kind: 'unit',
324
+ radius: 0.45,
325
+ stats: { health: 500, attackDamage: 25, attackSpeed: 0.6, attackRange: 6, armor: 10, magicResist: 10, moveSpeed: 4 },
326
+ sight: 9,
327
+ attacks: [{ attackType: 'normal', damagePoint: 0.4, acquisitionRange: 5, projectileSpeed: 18, targets: ['ground', 'air'] }],
328
+ level: 2,
329
+ bounty: [14, 20],
330
+ xp: 40,
331
+ drops: [{ item: 'healingPotion', chance: 0.25 }]
332
+ }
333
+
334
+ export const ogre: UnitTypeDef = {
335
+ id: 'ogre',
336
+ armourType: 'heavy',
337
+ name: 'Ogre Lord',
338
+ kind: 'unit',
339
+ radius: 0.75,
340
+ stats: {
341
+ health: 1800,
342
+ healthRegen: 1,
343
+ magicResist: 20,
344
+ tenacity: 0.3,
345
+ mana: 200,
346
+ manaRegen: 0.8,
347
+ attackDamage: 60,
348
+ attackSpeed: 0.5,
349
+ attackRange: 0.7,
350
+ armor: 20,
351
+ moveSpeed: 3.6
352
+ },
353
+ sight: 9,
354
+ attacks: [{ attackType: 'normal', damagePoint: 0.55, acquisitionRange: 5 }],
355
+ abilities: ['clap'],
356
+ level: 5,
357
+ bounty: [45, 60],
358
+ xp: 115,
359
+ threat: 3,
360
+ drops: [
361
+ { item: 'longSword', chance: 0.5 },
362
+ { item: 'clothArmor', chance: 0.5 },
363
+ { item: 'manaPotion', chance: 0.5 }
364
+ ]
365
+ }
366
+
367
+ export const creeps = [gnoll, troll, ogre]
368
+
369
+ export const townhall: UnitTypeDef = {
370
+ id: 'townhall',
371
+ armourType: 'fortified',
372
+ race: 'human',
373
+ name: 'Town Hall',
374
+ kind: 'building',
375
+ radius: 2,
376
+ footprint: { w: 4, d: 4 },
377
+ stats: { health: 2250, armor: 40, magicResist: 40 },
378
+ sight: 12,
379
+ cost: { gold: 385, lumber: 205 },
380
+ buildTime: 45,
381
+ supplyProvided: 12,
382
+ trains: ['peasant'],
383
+ dropOff: true,
384
+ upgradesTo: 'keep',
385
+ hotkey: 'H'
386
+ }
387
+
388
+ export const keep: UnitTypeDef = {
389
+ id: 'keep',
390
+ armourType: 'fortified',
391
+ race: 'human',
392
+ name: 'Keep',
393
+ kind: 'building',
394
+ radius: 2,
395
+ footprint: { w: 4, d: 4 },
396
+ stats: { health: 3000, armor: 40, magicResist: 40 },
397
+ sight: 12,
398
+ cost: { gold: 320, lumber: 210 },
399
+ buildTime: 50,
400
+ supplyProvided: 12,
401
+ trains: ['peasant'],
402
+ dropOff: true,
403
+ provides: ['townhall'],
404
+ upgradesTo: 'castle',
405
+ hotkey: 'U'
406
+ }
407
+
408
+ export const castle: UnitTypeDef = {
409
+ id: 'castle',
410
+ armourType: 'fortified',
411
+ race: 'human',
412
+ name: 'Castle',
413
+ kind: 'building',
414
+ radius: 2,
415
+ footprint: { w: 4, d: 4 },
416
+ stats: { health: 3750, armor: 40, magicResist: 40 },
417
+ sight: 12,
418
+ cost: { gold: 360, lumber: 210 },
419
+ buildTime: 60,
420
+ supplyProvided: 12,
421
+ trains: ['peasant'],
422
+ dropOff: true,
423
+ provides: ['townhall', 'keep'],
424
+ hotkey: 'U'
425
+ }
426
+
427
+ export const farm: UnitTypeDef = {
428
+ id: 'farm',
429
+ armourType: 'fortified',
430
+ race: 'human',
431
+ name: 'Farm',
432
+ kind: 'building',
433
+ radius: 1,
434
+ footprint: { w: 2, d: 2 },
435
+ stats: { health: 750, armor: 40, magicResist: 40, attackSpeed: 0.8, attackRange: 7 },
436
+ sight: 6,
437
+ cost: { gold: 80, lumber: 20 },
438
+ buildTime: 12,
439
+ supplyProvided: 6,
440
+ hotkey: 'F',
441
+ // up to four peasants take cover in it, and shoot out of it: it attacks only with them inside, as an orc burrow does
442
+ transport: { capacity: 4, takes: (def) => def.id === 'peasant', armed: 9 },
443
+ attacks: [{ damagePoint: 0.3, acquisitionRange: 7, projectileSpeed: 24, targets: ['ground', 'air'] }]
444
+ }
445
+
446
+ export const barracks: UnitTypeDef = {
447
+ id: 'barracks',
448
+ armourType: 'fortified',
449
+ race: 'human',
450
+ name: 'Barracks',
451
+ kind: 'building',
452
+ radius: 1.5,
453
+ footprint: { w: 3, d: 3 },
454
+ stats: { health: 2250, armor: 40, magicResist: 40 },
455
+ sight: 9,
456
+ cost: { gold: 160, lumber: 60 },
457
+ buildTime: 25,
458
+ trains: ['footman', 'rifleman', 'priest', 'sorceress', 'catapult'],
459
+ hotkey: 'B'
460
+ }
461
+
462
+ export const tower: UnitTypeDef = {
463
+ id: 'tower',
464
+ armourType: 'fortified',
465
+ race: 'human',
466
+ name: 'Guard Tower',
467
+ kind: 'building',
468
+ radius: 1,
469
+ footprint: { w: 2, d: 2 },
470
+ stats: { health: 1500, attackDamage: 60, attackSpeed: 0.83, attackRange: 8, armor: 40, magicResist: 40 },
471
+ sight: 12,
472
+ attacks: [{ attackType: 'pierce', damagePoint: 0.3, acquisitionRange: 8, projectileSpeed: 24, targets: ['ground', 'air'] }],
473
+ cost: { gold: 110, lumber: 50 },
474
+ buildTime: 20,
475
+ requires: ['barracks'],
476
+ hotkey: 'T'
477
+ }
478
+
479
+ /**
480
+ * A piece of stone wall: a cell of it, laid in a line by a drag (`withWalls`), each piece joined with those beside it
481
+ * and drawn by the shape that makes (its look: `stoneWallLooks`)
482
+ */
483
+ export const stoneWall: UnitTypeDef = {
484
+ id: 'stoneWall',
485
+ armourType: 'fortified',
486
+ race: 'human',
487
+ name: 'Stone Wall',
488
+ kind: 'building',
489
+ radius: 0.5,
490
+ footprint: { w: 1, d: 1 },
491
+ stats: { health: 400, armor: 40, magicResist: 40 },
492
+ sight: 2,
493
+ cost: { gold: 5, lumber: 10 },
494
+ buildTime: 4,
495
+ requires: ['barracks'],
496
+ wall: { family: 'stone' },
497
+ // nobody picks a fight with a wall on their own
498
+ ignored: true,
499
+ hotkey: 'W'
500
+ }
501
+
502
+ /**
503
+ * A gate of stone wall: a gatehouse of 3 by 3 in a line of the wall, joined and turned along it, that its owner opens
504
+ * and shuts for everyone (`withWalls`' `wallGateCommand`): open, whoever walks goes through. A cell's gap would let
505
+ * nobody by
506
+ */
507
+ export const stoneGate: UnitTypeDef = {
508
+ id: 'stoneGate',
509
+ armourType: 'fortified',
510
+ race: 'human',
511
+ name: 'Stone Gate',
512
+ kind: 'building',
513
+ radius: 1.5,
514
+ footprint: { w: 3, d: 3 },
515
+ stats: { health: 600, armor: 40, magicResist: 40 },
516
+ sight: 2,
517
+ cost: { gold: 20, lumber: 30 },
518
+ buildTime: 6,
519
+ requires: ['barracks'],
520
+ wall: { family: 'stone', gate: true },
521
+ ignored: true,
522
+ hotkey: 'Q'
523
+ }
524
+
525
+ export const blacksmith: UnitTypeDef = {
526
+ id: 'blacksmith',
527
+ armourType: 'fortified',
528
+ race: 'human',
529
+ name: 'Blacksmith',
530
+ kind: 'building',
531
+ radius: 1.5,
532
+ footprint: { w: 3, d: 3 },
533
+ stats: { health: 1800, armor: 40, magicResist: 40 },
534
+ sight: 9,
535
+ cost: { gold: 140, lumber: 60 },
536
+ buildTime: 25,
537
+ requires: ['barracks'],
538
+ researches: ['swords', 'gunpowder', 'plating'],
539
+ hotkey: 'S'
540
+ }
541
+
542
+ export const alchemist: UnitTypeDef = {
543
+ id: 'alchemist',
544
+ armourType: 'fortified',
545
+ race: 'human',
546
+ name: 'Alchemist',
547
+ kind: 'building',
548
+ radius: 1.5,
549
+ footprint: { w: 3, d: 3 },
550
+ stats: { health: 1350, armor: 40, magicResist: 40 },
551
+ sight: 9,
552
+ cost: { gold: 130, lumber: 30 },
553
+ buildTime: 22,
554
+ requires: ['keep'],
555
+ sells: catalogue,
556
+ hotkey: 'A'
557
+ }
558
+
559
+ /**
560
+ * A transport ship: it sails the deep water alone (`naval`), and carries up to eight of its side across (`transport`):
561
+ * they board it from the shore, and it lets them out on the land it comes to. Of no race: a goblin shipyard hires it out
562
+ */
563
+ export const transportShip: UnitTypeDef = {
564
+ id: 'transportShip',
565
+ armourType: 'heavy',
566
+ name: 'Transport Ship',
567
+ kind: 'unit',
568
+ radius: 1,
569
+ naval: true,
570
+ transport: { capacity: 8 },
571
+ stats: { health: 600, armor: 20, moveSpeed: 5 },
572
+ sight: 9,
573
+ cost: { gold: 170, lumber: 50 },
574
+ supply: 2,
575
+ hotkey: 'T'
576
+ }
577
+
578
+ /**
579
+ * A goblin shipyard: neutral and indestructible, by the water, hiring out transport ships to whoever has
580
+ * someone by it (`hires`): each comes out onto the deep water nearest it
581
+ */
582
+ export const goblinShipyard: UnitTypeDef = {
583
+ id: 'goblinShipyard',
584
+ name: 'Goblin Shipyard',
585
+ kind: 'building',
586
+ radius: 1.5,
587
+ footprint: { w: 3, d: 3 },
588
+ stats: { health: 1300, armor: 40, magicResist: 40 },
589
+ sight: 9,
590
+ invulnerable: true,
591
+ hires: ['transportShip']
592
+ }
593
+
594
+ export const armory: UnitTypeDef = {
595
+ id: 'armory',
596
+ armourType: 'fortified',
597
+ race: 'human',
598
+ name: 'Armory',
599
+ kind: 'building',
600
+ radius: 1.5,
601
+ footprint: { w: 3, d: 3 },
602
+ stats: { health: 1350, armor: 40, magicResist: 40 },
603
+ sight: 9,
604
+ cost: { gold: 150, lumber: 40 },
605
+ buildTime: 25,
606
+ requires: ['blacksmith'],
607
+ sells: catalogue,
608
+ hotkey: 'R'
609
+ }
610
+
611
+ export const aviary: UnitTypeDef = {
612
+ id: 'aviary',
613
+ armourType: 'fortified',
614
+ race: 'human',
615
+ name: 'Aviary',
616
+ kind: 'building',
617
+ radius: 1.5,
618
+ footprint: { w: 3, d: 3 },
619
+ stats: { health: 1800, armor: 40, magicResist: 40 },
620
+ sight: 9,
621
+ cost: { gold: 140, lumber: 150 },
622
+ buildTime: 35,
623
+ requires: ['keep', 'lumbermill'],
624
+ trains: ['gryphon'],
625
+ hotkey: 'G'
626
+ }
627
+
628
+ export const lumbermill: UnitTypeDef = {
629
+ id: 'lumbermill',
630
+ armourType: 'fortified',
631
+ race: 'human',
632
+ name: 'Lumber Mill',
633
+ kind: 'building',
634
+ radius: 1.5,
635
+ footprint: { w: 3, d: 3 },
636
+ stats: { health: 1350, armor: 40, magicResist: 40 },
637
+ sight: 9,
638
+ cost: { gold: 120 },
639
+ buildTime: 20,
640
+ dropOff: ['lumber'],
641
+ hotkey: 'M'
642
+ }
643
+
644
+ export const tree: UnitTypeDef = {
645
+ id: 'tree',
646
+ name: 'Tree',
647
+ kind: 'resource',
648
+ radius: 0.5,
649
+ footprint: { w: 1, d: 1 },
650
+ stats: { health: 1 },
651
+ sight: 0,
652
+ invulnerable: true,
653
+ fellable: true,
654
+ resource: { kind: 'lumber', amount: 50, slots: 1, gatherTime: 8 }
655
+ }
656
+
657
+ export const goldmine: UnitTypeDef = {
658
+ id: 'goldmine',
659
+ name: 'Gold Mine',
660
+ kind: 'resource',
661
+ radius: 2,
662
+ footprint: { w: 4, d: 4 },
663
+ stats: { health: 1 },
664
+ sight: 0,
665
+ invulnerable: true,
666
+ resource: { kind: 'gold', amount: 12500, slots: 1, entered: true }
667
+ }
668
+
669
+ /**
670
+ * A tavern: neutral, and it cannot be destroyed. It hires out no one yet: heroes of no race given to it (`hires`) would
671
+ * go to whoever has someone of theirs by it, once each
672
+ */
673
+ export const tavern: UnitTypeDef = {
674
+ id: 'tavern',
675
+ name: 'Tavern',
676
+ kind: 'building',
677
+ radius: 1.5,
678
+ footprint: { w: 3, d: 3 },
679
+ stats: { health: 1500, armor: 40, magicResist: 40 },
680
+ sight: 9,
681
+ invulnerable: true
682
+ }
683
+
684
+ /**
685
+ * The ruins a fallen building leaves where it stood, by its size (`withRemains`): they block the way until workers clear
686
+ * them, gathering their timber as lumber
687
+ */
688
+ export const ruins = [2, 3, 4].map((size) =>
689
+ rubbleType({ id: `ruins${size}`, name: 'Ruins', footprint: { w: size, d: size }, kind: 'lumber', amount: size * 25 })
690
+ )
691
+
692
+ /** Something to try abilities on. It stands where it is put, cannot die, and is whole again a moment after it was last hit */
693
+ export const dummy: UnitTypeDef = {
694
+ id: 'dummy',
695
+ name: 'Training Dummy',
696
+ kind: 'unit',
697
+ radius: 0.5,
698
+ stats: { health: 3000, moveSpeed: 3 },
699
+ sight: 2,
700
+ undying: true,
701
+ recovers: 3,
702
+ ignored: true,
703
+ threat: 0
704
+ }
705
+
706
+ export const units = [
707
+ peasant,
708
+ footman,
709
+ rifleman,
710
+ priest,
711
+ sorceress,
712
+ catapult,
713
+ gryphon,
714
+ paladin,
715
+ archmage,
716
+ testiro,
717
+ dummy,
718
+ ward,
719
+ skeleton,
720
+ altar,
721
+ townhall,
722
+ keep,
723
+ castle,
724
+ farm,
725
+ barracks,
726
+ tower,
727
+ stoneWall,
728
+ stoneGate,
729
+ goblinShipyard,
730
+ transportShip,
731
+ blacksmith,
732
+ alchemist,
733
+ armory,
734
+ aviary,
735
+ tavern,
736
+ ...ruins,
737
+ goldmine,
738
+ tree,
739
+ lumbermill,
740
+ ...undeadUnits,
741
+ ...creeps
742
+ ]
743
+
744
+ export const upgrades: UpgradeDef[] = [
745
+ {
746
+ id: 'swords',
747
+ race: 'human',
748
+ // the second level asks for a keep, the third for a castle
749
+ requires: [[], ['keep'], ['castle']],
750
+ name: 'Forged Swords',
751
+ description: '+2 damage for footmen and peasants',
752
+ cost: { gold: 100, lumber: 50 },
753
+ researchTime: 20,
754
+ maxLevel: 3,
755
+ hotkey: 'W',
756
+ effects: [{ units: ['footman', 'peasant'], stats: { attackDamage: 2 } }]
757
+ },
758
+ {
759
+ id: 'gunpowder',
760
+ race: 'human',
761
+ // the second level asks for a keep, the third for a castle
762
+ requires: [[], ['keep'], ['castle']],
763
+ name: 'Black Gunpowder',
764
+ description: '+3 damage for riflemen and guard towers',
765
+ cost: { gold: 120, lumber: 50 },
766
+ researchTime: 20,
767
+ maxLevel: 3,
768
+ hotkey: 'G',
769
+ effects: [{ units: ['rifleman', 'tower'], stats: { attackDamage: 3 } }]
770
+ },
771
+ {
772
+ id: 'plating',
773
+ race: 'human',
774
+ // the second level asks for a keep, the third for a castle
775
+ requires: [[], ['keep'], ['castle']],
776
+ name: 'Iron Plating',
777
+ description: '+12 armor for footmen and riflemen',
778
+ cost: { gold: 125, lumber: 75 },
779
+ researchTime: 25,
780
+ maxLevel: 3,
781
+ hotkey: 'P',
782
+ effects: [{ units: ['footman', 'rifleman'], stats: { armor: 12 } }]
783
+ },
784
+ ...undeadUpgrades
785
+ ]