@v12-engine/create 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +26 -2
- package/base/_gitignore +10 -0
- package/base/index.html +20 -0
- package/base/package.json +23 -0
- package/base/src/ground.worker.ts +8 -0
- package/base/src/main.ts +61 -0
- package/base/tsconfig.json +14 -0
- package/base/vite.config.ts +25 -0
- package/bin.mjs +10 -0
- package/cli.mjs +381 -0
- package/index.mjs +286 -0
- package/layers/assets/package.json +5 -0
- package/layers/editor/package.json +8 -0
- package/layers/editor/src/editor.ts +13 -0
- package/layers/rooms/server.ts +69 -0
- package/layers/server/package.json +8 -0
- package/layers/server/server.ts +34 -0
- package/layers/source/package.json +12 -0
- package/layers/source/tsconfig.json +5 -0
- package/layers/source/vite.config.ts +45 -0
- package/layers/tests/package.json +8 -0
- package/package.json +46 -5
- package/starters/campaign/README.md +61 -0
- package/starters/campaign/files.txt +42 -0
- package/starters/campaign/layers/editor/src/editor.ts +18 -0
- package/starters/campaign/layers/rooms/server.ts +39 -0
- package/starters/campaign/layers/server/server.ts +33 -0
- package/starters/campaign/layers/tests/tests/rules.test.ts +320 -0
- package/starters/campaign/public/games/campaign/assets.json +1 -0
- package/starters/campaign/src/campaign/campaign.json +52 -0
- package/starters/campaign/src/campaign/carry.ts +47 -0
- package/starters/campaign/src/campaign/cinematics/intro.json +148 -0
- package/starters/campaign/src/campaign/cinematics/outro.json +92 -0
- package/starters/campaign/src/campaign/data.json +1 -0
- package/starters/campaign/src/campaign/fx.json +1 -0
- package/starters/campaign/src/campaign/game.ts +6 -0
- package/starters/campaign/src/campaign/ids.ts +77 -0
- package/starters/campaign/src/campaign/index.ts +121 -0
- package/starters/campaign/src/campaign/kills.ts +16 -0
- package/starters/campaign/src/campaign/looks.json +1 -0
- package/starters/campaign/src/campaign/maps.ts +34 -0
- package/starters/campaign/src/campaign/missions/homecoming.ts +160 -0
- package/starters/campaign/src/campaign/missions/siege.ts +91 -0
- package/starters/campaign/src/campaign/missions/warlord.ts +177 -0
- package/starters/campaign/src/campaign/prefabs/watchpost.prefab.json +18 -0
- package/starters/campaign/src/campaign/scenes.ts +46 -0
- package/starters/campaign/src/campaign/tiles.ts +8 -0
- package/starters/campaign/src/campaign/units.ts +390 -0
- package/starters/campaign/src/campaign/view/cinematics.ts +59 -0
- package/starters/campaign/src/campaign/view/fire.ts +115 -0
- package/starters/campaign/src/campaign/view/index.ts +334 -0
- package/starters/campaign/src/campaign/view/labels.ts +105 -0
- package/starters/campaign/src/campaign/view/rubble.ts +40 -0
- package/starters/campaign/src/campaign/view/waveLane.ts +88 -0
- package/starters/campaign/src/campaign/waves.json +36 -0
- package/starters/campaign/src/campaign/waves.ts +186 -0
- package/starters/campaign/src/campaign-editor.ts +43 -0
- package/starters/campaign/src/game.ts +2 -0
- package/starters/campaign/src/main.ts +70 -0
- package/starters/campaign/src/maps/fort.names.ts +31 -0
- package/starters/campaign/src/maps/fort.vgmap.json +1162 -0
- package/starters/campaign/src/maps/homestead.names.ts +36 -0
- package/starters/campaign/src/maps/homestead.vgmap.json +916 -0
- package/starters/campaign/src/maps/pass.names.ts +40 -0
- package/starters/campaign/src/maps/pass.vgmap.json +522 -0
- package/starters/campaign/src/maps.ts +2 -0
- package/starters/campaign/src/rules.ts +20 -0
- package/starters/campaign/src/waves-panel.ts +355 -0
- package/starters/empty/README.md +71 -0
- package/starters/empty/layers/tests/tests/rules.test.ts +31 -0
- package/starters/empty/src/game.ts +79 -0
- package/starters/empty/src/generate.worker.ts +9 -0
- package/starters/empty/src/maps.ts +44 -0
- package/starters/empty/src/rules.ts +67 -0
- package/starters/empty/src/tiles.ts +12 -0
- package/starters/melee/README.md +61 -0
- package/starters/melee/files.txt +60 -0
- package/starters/melee/layers/editor/src/editor.ts +13 -0
- package/starters/melee/layers/tests/tests/rules.test.ts +58 -0
- package/starters/melee/src/game.ts +2 -0
- package/starters/melee/src/maps/bay.names.ts +28 -0
- package/starters/melee/src/maps/bay.vgmap.json +3123 -0
- package/starters/melee/src/maps.ts +20 -0
- package/starters/melee/src/melee/abilities.ts +376 -0
- package/starters/melee/src/melee/bay.ts +319 -0
- package/starters/melee/src/melee/blight.ts +102 -0
- package/starters/melee/src/melee/cellLayers.json +11 -0
- package/starters/melee/src/melee/data.json +18 -0
- package/starters/melee/src/melee/floats.json +199 -0
- package/starters/melee/src/melee/formations.ts +46 -0
- package/starters/melee/src/melee/fx.json +1 -0
- package/starters/melee/src/melee/game.ts +6 -0
- package/starters/melee/src/melee/generator.ts +116 -0
- package/starters/melee/src/melee/heroSpells.ts +38 -0
- package/starters/melee/src/melee/hud.json +269 -0
- package/starters/melee/src/melee/index.ts +182 -0
- package/starters/melee/src/melee/items.ts +362 -0
- package/starters/melee/src/melee/languages/he.json +96 -0
- package/starters/melee/src/melee/looks.json +1 -0
- package/starters/melee/src/melee/maps.ts +53 -0
- package/starters/melee/src/melee/pings.json +16 -0
- package/starters/melee/src/melee/pings.ts +34 -0
- package/starters/melee/src/melee/quality.json +1 -0
- package/starters/melee/src/melee/saves.ts +12 -0
- package/starters/melee/src/melee/sounds.json +1 -0
- package/starters/melee/src/melee/undead.ts +683 -0
- package/starters/melee/src/melee/units.ts +785 -0
- package/starters/melee/src/melee/view/buildings.ts +33 -0
- package/starters/melee/src/melee/view/cheerLane.ts +42 -0
- package/starters/melee/src/melee/view/heroSpellLooks.ts +21 -0
- package/starters/melee/src/melee/view/index.ts +268 -0
- package/starters/melee/src/melee/view/languages.ts +10 -0
- package/starters/melee/src/melee/view/looks.ts +659 -0
- package/starters/melee/src/melee/view/undeadLooks.ts +220 -0
- package/starters/melee/src/melee/view/walls.ts +59 -0
- package/starters/melee/src/rules.ts +24 -0
- package/starters.mjs +35 -0
- package/v12.mjs +111 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Melee's buildings drawn with the shared art (@v12-engine/assets): a model of its packs made as wide as the building
|
|
3
|
+
* stands, by the size the package says it has (its `sizes.json`), with a lamp over its door at night
|
|
4
|
+
*/
|
|
5
|
+
import sizesByPath from '@v12-engine/assets/sizes.json'
|
|
6
|
+
import type { ModelDef, ModelLightDef } from '@v12-engine/client'
|
|
7
|
+
|
|
8
|
+
/** Every model of the package by its path in `models/`, with its size in its own units: across, up, deep */
|
|
9
|
+
const sizes = new Map<string, number[]>(Object.entries(sizesByPath as Record<string, number[]>))
|
|
10
|
+
|
|
11
|
+
/** The size a model of the package has, in its own units, or nothing for one it does not have */
|
|
12
|
+
export const sizeOf = (src: string): number[] | undefined => sizes.get(src)
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A model of the package (`rts/barracks.glb`) made `width` across at its widest, its lamp over the door: a third of
|
|
16
|
+
* the way up its front (the packs' buildings face +z)
|
|
17
|
+
*/
|
|
18
|
+
export function building(src: string, width: number, own: Partial<ModelDef> = {}): ModelDef {
|
|
19
|
+
const size = sizes.get(src)
|
|
20
|
+
if (!size) throw new Error(`@v12-engine/assets has no model ${src}`)
|
|
21
|
+
const lamp: ModelLightDef = {
|
|
22
|
+
name: 'door',
|
|
23
|
+
offset: [0, size[1] * 0.3, size[2] / 2 + 0.12],
|
|
24
|
+
color: [1, 0.74, 0.45],
|
|
25
|
+
intensity: 1.3,
|
|
26
|
+
range: 5,
|
|
27
|
+
flicker: 0.06
|
|
28
|
+
}
|
|
29
|
+
const scale = width / Math.max(size[0], size[2])
|
|
30
|
+
// over its roof, where it smokes and burns when hurt (`damaged` in looks.ts)
|
|
31
|
+
const roof = { offset: [0, size[1] * 0.8, 0] as [number, number, number] }
|
|
32
|
+
return { src, scale, lights: [lamp], ...own, points: { roof, ...own.points } }
|
|
33
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Clip, defineLane } from '@v12-engine/client'
|
|
2
|
+
import { oneOf, text } from '@v12-engine/engine'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A lane of melee's own for its cinematics: everyone of a side cheers at a moment (`who`: `me`, `enemy` or
|
|
6
|
+
* `everyone`), for a victory, a taunt. Made the way the client's own lanes are (`defineLane`), listed on the view
|
|
7
|
+
* (`lanes`), so it plays from a cinematic file and the Cinematic panel draws it like any other
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface CheerClip extends Clip {
|
|
11
|
+
who: 'me' | 'enemy' | 'everyone'
|
|
12
|
+
/** The clip they play: `cheer` when left out */
|
|
13
|
+
clip?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const cheerLane = defineLane<CheerClip>({
|
|
17
|
+
kind: 'melee.cheer',
|
|
18
|
+
name: 'Cheer',
|
|
19
|
+
read: (item, what) => ({
|
|
20
|
+
...item,
|
|
21
|
+
who: oneOf('me', 'enemy', 'everyone')(item.who ?? 'everyone', `${what}.who`),
|
|
22
|
+
...(item.clip !== undefined && { clip: text(item.clip, `${what}.clip`) })
|
|
23
|
+
}),
|
|
24
|
+
run(cut, item, from) {
|
|
25
|
+
// a cheer seeked into is not cheered again: it is a burst, not a stretch
|
|
26
|
+
if (from > 0) return
|
|
27
|
+
const state = cut.lane('melee.cheer').state as { cheered?: number }
|
|
28
|
+
state.cheered = (state.cheered ?? 0) + 1
|
|
29
|
+
const side = cut.stage.units?.(item.who) ?? []
|
|
30
|
+
for (const id of side) cut.stage.playClip(id, item.clip ?? 'cheer')
|
|
31
|
+
},
|
|
32
|
+
editor: {
|
|
33
|
+
color: '#f0c040',
|
|
34
|
+
icon: 'cheer',
|
|
35
|
+
hint: 'A side of the game’s units cheers at a moment: each plays its cheer clip (or the one said)',
|
|
36
|
+
fields: [
|
|
37
|
+
{ key: 'who', kind: 'choice', label: 'Who', options: ['me', 'enemy', 'everyone'] },
|
|
38
|
+
{ key: 'clip', kind: 'clip', label: 'Clip' }
|
|
39
|
+
],
|
|
40
|
+
label: (item) => `${item.who} cheer`
|
|
41
|
+
}
|
|
42
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AbilityLooks } from '@v12-engine/client'
|
|
2
|
+
|
|
3
|
+
type Rgb = [number, number, number]
|
|
4
|
+
|
|
5
|
+
/** The spells every hero brings along */
|
|
6
|
+
const GOLD: Rgb = [1, 0.85, 0.35]
|
|
7
|
+
const LIFE: Rgb = [0.5, 1, 0.55]
|
|
8
|
+
/** What falls from the sky is gold */
|
|
9
|
+
const STARLIGHT: Rgb = [1, 0.92, 0.5]
|
|
10
|
+
|
|
11
|
+
/** How the spells every hero brings along and what an item calls down look, by their id */
|
|
12
|
+
export const heroSpellEffects: AbilityLooks = {
|
|
13
|
+
// ---- the spells every hero brings along
|
|
14
|
+
flash: { color: GOLD, style: 'burst', options: { where: 'point', rise: 0, count: 40 } },
|
|
15
|
+
secondWind: { color: LIFE, style: 'burst', options: { count: 50 } },
|
|
16
|
+
healHaste: { color: LIFE, aura: 'glow', options: { shape: 'rise', streaks: true } },
|
|
17
|
+
barrier: { color: GOLD, style: 'burst', aura: 'glow', options: { count: 36, shape: 'shell' } },
|
|
18
|
+
|
|
19
|
+
// ---- what an item calls down
|
|
20
|
+
intervention: { color: [0.7, 1, 0.8], style: 'mark', options: { lasts: 2.5, radius: 6.9, sparks: 12, column: true, burst: 80, tint: STARLIGHT } }
|
|
21
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import {
|
|
2
|
+
aiOverlay,
|
|
3
|
+
blightLook,
|
|
4
|
+
captureMinimapLayer,
|
|
5
|
+
capturePanel,
|
|
6
|
+
CELL_LAYERS_FILE,
|
|
7
|
+
DAYLIGHT_COLORS,
|
|
8
|
+
type FloatInput,
|
|
9
|
+
FLOATS_FILE,
|
|
10
|
+
foliage,
|
|
11
|
+
FX_FILE,
|
|
12
|
+
type GameView,
|
|
13
|
+
hotView,
|
|
14
|
+
HUD_FILE,
|
|
15
|
+
layFiles,
|
|
16
|
+
PINGS_FILE,
|
|
17
|
+
presetBuffMarker,
|
|
18
|
+
presetFloats,
|
|
19
|
+
presetFx,
|
|
20
|
+
presetPings,
|
|
21
|
+
presetRallyFlag,
|
|
22
|
+
presetSpellStyles,
|
|
23
|
+
presetWeather,
|
|
24
|
+
QUALITY_FILE,
|
|
25
|
+
SOUNDS_FILE,
|
|
26
|
+
stanceButtons,
|
|
27
|
+
TILE_LOOKS,
|
|
28
|
+
veterancyRank,
|
|
29
|
+
withHeroesView
|
|
30
|
+
} from '@v12-engine/client'
|
|
31
|
+
import { LOOKS_FILE } from '@v12-engine/client/looks-file'
|
|
32
|
+
import looksFile from '../looks.json'
|
|
33
|
+
import fxFile from '../fx.json'
|
|
34
|
+
import hudFile from '../hud.json'
|
|
35
|
+
import floatsFile from '../floats.json'
|
|
36
|
+
import pingsFile from '../pings.json'
|
|
37
|
+
import qualityFile from '../quality.json'
|
|
38
|
+
import cellLayersFile from '../cellLayers.json'
|
|
39
|
+
import soundsFile from '../sounds.json'
|
|
40
|
+
import { effects, looks } from './looks'
|
|
41
|
+
import { cheerLane } from './cheerLane'
|
|
42
|
+
import { blightMinimapLayer, cardButtons, gateButtons } from './walls'
|
|
43
|
+
import { OFF_WHEEL_PINGS, PINGS } from '../pings'
|
|
44
|
+
import { meleeLanguages } from './languages'
|
|
45
|
+
import { VETERANCY_RANKS } from '@v12-engine/engine'
|
|
46
|
+
|
|
47
|
+
/** A buff's name floats in the colour its effect has (`effects`), a light one where it has none */
|
|
48
|
+
const buffColor = ({ params }: FloatInput): string => {
|
|
49
|
+
const color = effects[String(params?.buff)]?.color
|
|
50
|
+
return color ? `rgb(${color.map((part) => Math.round(160 + part * 95)).join(', ')})` : '#e8e2c8'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** How melee looks. The rules are in `../index.ts`; this part only runs on a player's screen */
|
|
54
|
+
export const meleeView: GameView = layFiles(
|
|
55
|
+
{
|
|
56
|
+
// the languages it is played in, the setting `language` choosing one: English, and Hebrew right to left
|
|
57
|
+
languages: meleeLanguages,
|
|
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`)
|
|
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
|
|
64
|
+
// HUD; and the Restless' blight under them as it spreads
|
|
65
|
+
minimap: { layers: [blightMinimapLayer(), captureMinimapLayer()] },
|
|
66
|
+
// the debug panel's AI tab can draw what the computer it inspects is thinking over the ground: its squads, its threat
|
|
67
|
+
// map, what it knows (Show on the map)
|
|
68
|
+
debug: { ai: aiOverlay() },
|
|
69
|
+
// a unit's rank of veterancy among its stats, once it has one
|
|
70
|
+
stats: (entity, lines) => {
|
|
71
|
+
const rank = veterancyRank(entity)
|
|
72
|
+
if (!rank) return lines
|
|
73
|
+
return [
|
|
74
|
+
...lines,
|
|
75
|
+
{
|
|
76
|
+
id: 'rank',
|
|
77
|
+
label: 'Rank',
|
|
78
|
+
value: `${VETERANCY_RANKS[rank - 1].name} ${'✦'.repeat(rank)}`,
|
|
79
|
+
hint: 'Earned by its kills: each rank more damage and health'
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
resources: {
|
|
84
|
+
gold: {
|
|
85
|
+
chip: 'background: radial-gradient(circle at 35% 30%, #fff3b8, var(--vg-gold) 45%, #9c6f12)',
|
|
86
|
+
color: '#ffd23c'
|
|
87
|
+
},
|
|
88
|
+
lumber: {
|
|
89
|
+
chip: 'width: 14px; height: 10px; border-radius: 5px; background: linear-gradient(180deg, #c8935a, #7a4a22); box-shadow: inset -4px 0 0 #e2c08c',
|
|
90
|
+
color: '#1f4d25'
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
// supply comes from farms here, and from bone spires for the Restless
|
|
94
|
+
messages: {
|
|
95
|
+
supplyBlocked: (_params, _registry, { race }) =>
|
|
96
|
+
race === 'undead' ? 'Not enough food, build more bone spires' : 'Not enough food, build more farms',
|
|
97
|
+
gatherHint: 'Gather: click a gold mine or a tree',
|
|
98
|
+
gatherTarget: 'Must target a gold mine or a tree',
|
|
99
|
+
night: 'Night: units see less far, and creeps sleep until attacked',
|
|
100
|
+
needsBlight: 'Must be built on blight',
|
|
101
|
+
needsHauntedMine: 'Acolytes gather gold at a cursed mine of yours'
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
// the HUD's half of the heroes the rules take (`withHeroes`): the hero's panel, the heroes' portraits, the shop
|
|
105
|
+
packs: [withHeroesView()],
|
|
106
|
+
cinematics: {
|
|
107
|
+
// a lane of its own for its cinematics, beside the client's: everyone of a side cheers (see `cheerLane.ts`)
|
|
108
|
+
lanes: [cheerLane]
|
|
109
|
+
},
|
|
110
|
+
units: {
|
|
111
|
+
// its cinematics, made in the editor's Cinematic panel: none yet (`GameView.cinematics.defs`, by id)
|
|
112
|
+
// the looks of its units (`looks.ts`): what the editor's model setup wrote is laid over them (`looks.json`), and the
|
|
113
|
+
// HUD over its units the Unit HUD panel wrote (`hud.json`) over the heroes' plates
|
|
114
|
+
looks,
|
|
115
|
+
rallyFlag: presetRallyFlag(),
|
|
116
|
+
buffMarker: presetBuffMarker(),
|
|
117
|
+
// 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 })
|
|
119
|
+
},
|
|
120
|
+
scene: {
|
|
121
|
+
// what drawing asks of the device: the client's presets, the most pixels a preset draws and each preset's resolution
|
|
122
|
+
// and edges as the editor's Look panel wrote them over them (`quality.json`)
|
|
123
|
+
quality: {},
|
|
124
|
+
// 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] } },
|
|
127
|
+
// the sky and the mist with the hour, as the client has them: dark blue at night, warm at dawn and dusk
|
|
128
|
+
daylight: DAYLIGHT_COLORS,
|
|
129
|
+
// the trees, the buildings and the armies of the shared art lighter from far, as their levels are made (`npm run lod`)
|
|
130
|
+
detail: { levels: [{}, { ratio: 0.4, from: 40 }, { ratio: 0.15, from: 80 }], shadowBias: 1 },
|
|
131
|
+
// trees and scenery in front of the player's own units faded out, so a unit behind a tree is never lost
|
|
132
|
+
seeThrough: {},
|
|
133
|
+
// the picture as drawn by day; at night a little colder and less coloured, the lamps blooming (nothing is done to
|
|
134
|
+
// the picture, and it costs nothing, while it is day)
|
|
135
|
+
picture: { night: { tint: [0.55, 0.65, 1], tintAmount: 0.18, saturation: 0.85, bloom: 0.35, bloomThreshold: 0.75 } },
|
|
136
|
+
// looks to start a map from: the editor's Look panel puts one on a map, the rules can change to one
|
|
137
|
+
environments: {
|
|
138
|
+
winter: {
|
|
139
|
+
sky: [0.7, 0.76, 0.84],
|
|
140
|
+
clouds: { cover: 0.7, color: [0.95, 0.96, 1] },
|
|
141
|
+
light: { sunUp: 28, sunColor: [0.92, 0.95, 1], ambientColor: [0.85, 0.9, 1] },
|
|
142
|
+
wind: { around: 200, strength: 0.4 },
|
|
143
|
+
weather: { kind: 'snow', amount: 0.6, settle: 0.6 },
|
|
144
|
+
fog: { start: 70, end: 220, color: [0.82, 0.86, 0.92] },
|
|
145
|
+
picture: { tone: 'neutral', exposure: 1.05, tint: [0.85, 0.92, 1], tintAmount: 0.12, bloom: 0.25, bloomThreshold: 0.85 }
|
|
146
|
+
},
|
|
147
|
+
swamp: {
|
|
148
|
+
sky: [0.5, 0.56, 0.5],
|
|
149
|
+
clouds: { cover: 0.6, color: [0.85, 0.88, 0.82] },
|
|
150
|
+
light: { sun: 1, ambientColor: [0.85, 0.95, 0.8] },
|
|
151
|
+
mist: { ground: { base: 0, top: 2.5, density: 0.5, color: [0.6, 0.68, 0.58] } },
|
|
152
|
+
water: { shallow: [0.3, 0.42, 0.28], deep: [0.15, 0.22, 0.14], opacity: 0.9 },
|
|
153
|
+
fog: { start: 40, end: 150, color: [0.55, 0.62, 0.52] },
|
|
154
|
+
picture: { saturation: 0.75, tint: [0.75, 0.9, 0.6], tintAmount: 0.15, contrast: 1.05, vignette: 0.3, vignetteColor: [0.05, 0.1, 0.04] }
|
|
155
|
+
},
|
|
156
|
+
dusk: {
|
|
157
|
+
sky: [0.55, 0.42, 0.5],
|
|
158
|
+
clouds: { cover: 0.4, color: [1, 0.8, 0.7] },
|
|
159
|
+
light: { sunUp: 12, sunAround: 250, sunColor: [1, 0.62, 0.42], sun: 1, ambient: 0.45, ambientColor: [0.8, 0.7, 0.9] },
|
|
160
|
+
fog: { start: 60, end: 200 },
|
|
161
|
+
picture: { tone: 'aces', exposure: 1.15, tint: [1, 0.75, 0.55], tintAmount: 0.15, bloom: 0.4, vignette: 0.25, occlusion: 1 }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
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
|
+
pings: {
|
|
182
|
+
// the pings of the rules (`../pings`), the ready-made ones: the six of the wheel (Ctrl and the left button) in this
|
|
183
|
+
// order, the others sent from code alone; and what the editor's Pings fold wrote over them and of the wheel
|
|
184
|
+
// (`pings.json`: a ring of six; the rules read it for their kinds too)
|
|
185
|
+
kinds: presetPings([...PINGS], Object.fromEntries(OFF_WHEEL_PINGS.map((kind) => [kind, { wheel: { hidden: true } }]))),
|
|
186
|
+
wheel: {}
|
|
187
|
+
},
|
|
188
|
+
fx: {
|
|
189
|
+
defs: presetFx([
|
|
190
|
+
'smoke',
|
|
191
|
+
'fire',
|
|
192
|
+
'dust',
|
|
193
|
+
'spark-burst',
|
|
194
|
+
'explosion',
|
|
195
|
+
'shockwave',
|
|
196
|
+
'ground-crack',
|
|
197
|
+
'burning-ground',
|
|
198
|
+
'rubble-fall',
|
|
199
|
+
'lightning',
|
|
200
|
+
// the detailed ones, for its abilities and the debug panel to play by name
|
|
201
|
+
'heal',
|
|
202
|
+
'impact-ring',
|
|
203
|
+
'fire-trail',
|
|
204
|
+
'essence',
|
|
205
|
+
'sunburst',
|
|
206
|
+
'gas-cloud',
|
|
207
|
+
'fireball',
|
|
208
|
+
'blood-burst',
|
|
209
|
+
'blood-splatter',
|
|
210
|
+
// leaves flung up as a unit pushes into the bushes
|
|
211
|
+
'leaves'
|
|
212
|
+
]),
|
|
213
|
+
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()
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
ground: {
|
|
221
|
+
// what scenery gives besides its model: the dungeon pack's torch lights the ground around it at night, from its
|
|
222
|
+
// flame (in the model's own units, scaled with it)
|
|
223
|
+
scenery: {
|
|
224
|
+
'dungeon/torch.glb': {
|
|
225
|
+
lights: [{ name: 'flame', offset: [0, 0.85, 0], color: [1, 0.72, 0.42], intensity: 1.4, range: 9, flicker: 0.08 }]
|
|
226
|
+
},
|
|
227
|
+
// the devil's sword was made to shine: it glows past its edges, a little by day and fully at night
|
|
228
|
+
'weapons/devils_sword.glb': { glow: { day: 0.1, night: 1 } }
|
|
229
|
+
},
|
|
230
|
+
// its tiles in the client's looks of grass, dirt, road, sand, rock and snow: taken, not given
|
|
231
|
+
tiles: TILE_LOOKS,
|
|
232
|
+
// with what the editor's Terrain panel wrote of a layer's look (its own models, colours, how it shakes) over them
|
|
233
|
+
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' }),
|
|
236
|
+
// the Restless' blight: the client's, the shared art's spoiled ground and green gases rising off it
|
|
237
|
+
blight: blightLook()
|
|
238
|
+
}
|
|
239
|
+
},
|
|
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
|
+
input: {
|
|
249
|
+
// a hero arena game's keys for heroes (its hero panel's stats are the client's eight)
|
|
250
|
+
keys: { abilities: ['Q', 'W', 'E', 'R'], spells: ['D', 'F'], shop: 'P' }
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
// the files the editor writes next to the code, each laid over what the code says above, in this order (`hud.json`
|
|
254
|
+
// over the looks `looks.json` made)
|
|
255
|
+
[
|
|
256
|
+
[LOOKS_FILE, looksFile],
|
|
257
|
+
[HUD_FILE, hudFile],
|
|
258
|
+
[QUALITY_FILE, qualityFile],
|
|
259
|
+
[FLOATS_FILE, floatsFile],
|
|
260
|
+
[PINGS_FILE, pingsFile],
|
|
261
|
+
[FX_FILE, fxFile],
|
|
262
|
+
[CELL_LAYERS_FILE, cellLayersFile],
|
|
263
|
+
[SOUNDS_FILE, soundsFile]
|
|
264
|
+
]
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
// saved while it runs in the dev server: the games and editors of the page take its new looks (hot reload)
|
|
268
|
+
if (import.meta.hot) import.meta.hot.accept((module) => hotView(import.meta.hot, 'my-game', meleeView, module?.meleeView))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Languages, MessagesFile } from '@v12-engine/client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The languages melee is played in (`GameView.languages`, `docs/languages.md`): English, which the game is written in,
|
|
5
|
+
* and Hebrew, written right to left, a table fetched as it is chosen. What Hebrew has no words for is said in English
|
|
6
|
+
*/
|
|
7
|
+
export const meleeLanguages: Languages = {
|
|
8
|
+
en: {},
|
|
9
|
+
he: () => import('../languages/he.json').then((file) => file.default as MessagesFile)
|
|
10
|
+
}
|