feat(totalannihilation): add Megatank unit with multi-barrel weapons and rebalance combat
- Introduce Megatank: medium commander with Twin 150mm Cannon and Side Rocket Pods - Implement multi-barrel weapon system (barrels + barrelSpacing) in TALogic and TARules - Lower DEFENCE_MIN_SKILL from 4 to 3; make first Laser Tower proactive, not reactive - Rebalance unit triangle: Tank now counters Rocket Tank; rockets weak vs vehicle armour - Re-seed campaign missions m05 (67890) and m06 (80808) with updated maps and briefings - Skirmish default theme uses rules default (tropics) instead of hardcoded grasslands - Add intro video before main menu - Update sprite docs and verification tests for new balance
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 287 KiB After Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 258 KiB After Width: | Height: | Size: 288 KiB |
|
|
@ -67,7 +67,7 @@
|
|||
},
|
||||
"icons": {
|
||||
"key": "ta-icons", "path": null, "kind": "icon",
|
||||
"frameWidth": 44, "frameHeight": 44, "cols": 10,
|
||||
"frameWidth": 64, "frameHeight": 64, "cols": 10,
|
||||
"rows": 4
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -273,6 +273,9 @@ export default class TAHud {
|
|||
this._clearGrid();
|
||||
const s = this.scene;
|
||||
const army = this.state.armies[this.playerArmy];
|
||||
// Real art or the procedural fallback (TAArt.js always supplies one or the other), so this
|
||||
// is only null for a def that predates the `icon` field — see the fallback layout below.
|
||||
const iconKey = this.view.sheetKeys?.icons;
|
||||
options.forEach((def, i) => {
|
||||
const col = i % GRID_COLS, row = Math.floor(i / GRID_COLS);
|
||||
// The container is placed at the button's CENTRE, not its top-left — see below.
|
||||
|
|
@ -286,13 +289,23 @@ export default class TAHud {
|
|||
// child here is centred on (0,0) so the visual and the hit area coincide.
|
||||
const box = s.add.rectangle(0, 0, BTN_W, BTN_H, affordable ? 0x22304a : 0x1a2130, 1)
|
||||
.setStrokeStyle(2, affordable ? EDGE : 0x2a3244);
|
||||
const label = s.add.text(0, -BTN_H / 2 + 12, shortName(def.name), {
|
||||
fontFamily: FONT, fontSize: '20px', color: affordable ? TEXT : '#5d6b80',
|
||||
const children = [box];
|
||||
const hasIcon = iconKey != null && def.icon != null;
|
||||
// The icon carries the button's identity at a glance once one exists; name and cost drop
|
||||
// underneath it rather than owning the whole button the way they did before icons.
|
||||
if (hasIcon) {
|
||||
const icon = s.add.image(0, -18, iconKey, def.icon).setDisplaySize(36, 36);
|
||||
if (!affordable) icon.setAlpha(0.5);
|
||||
children.push(icon);
|
||||
}
|
||||
const label = s.add.text(0, hasIcon ? 2 : -BTN_H / 2 + 12, shortName(def.name), {
|
||||
fontFamily: FONT, fontSize: hasIcon ? '14px' : '20px', color: affordable ? TEXT : '#5d6b80',
|
||||
}).setOrigin(0.5, 0);
|
||||
const cost = s.add.text(0, -BTN_H / 2 + 44, `${def.cost.mass}m ${def.cost.energy}e`, {
|
||||
fontFamily: FONT, fontSize: '15px', color: affordable ? DIM : '#4e5a6d',
|
||||
const cost = s.add.text(0, hasIcon ? 18 : -BTN_H / 2 + 44, `${def.cost.mass}m ${def.cost.energy}e`, {
|
||||
fontFamily: FONT, fontSize: hasIcon ? '12px' : '15px', color: affordable ? DIM : '#4e5a6d',
|
||||
}).setOrigin(0.5, 0);
|
||||
c.add([box, label, cost]);
|
||||
children.push(label, cost);
|
||||
c.add(children);
|
||||
c.setSize(BTN_W, BTN_H);
|
||||
c.setInteractive({ useHandCursor: true });
|
||||
c.on('pointerover', () => box.setFillStyle(affordable ? 0x2e3f5f : 0x1a2130, 1));
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ capacity the verify script holds every `frame` index to, and it is measured off
|
|||
|
||||
| Sheet name (JSON key) | Texture key | Cell | Cols | Contents |
|
||||
|---|---|---|---|---|
|
||||
| `arm-units` | `ta-arm-units` | 64×64 | 8 | ARM mobile units |
|
||||
| `core-units` | `ta-core-units` | 64×64 | 8 | CORE mobile units |
|
||||
| `arm-units` | `ta-arm-units` | 128×128 | 8 | ARM mobile units |
|
||||
| `core-units` | `ta-core-units` | 128×128 | 8 | CORE mobile units |
|
||||
| `arm-structures` | `ta-arm-structures` | 192×192 | 6×4 | ARM buildings |
|
||||
| `core-structures` | `ta-core-structures` | 192×192 | 6×4 | CORE buildings |
|
||||
| `terrain-grasslands` | `ta-terrain-grasslands` | 64×64 | 9 | Grassland tiles |
|
||||
| `terrain-snowfields` | `ta-terrain-snowfields` | 64×64 | 9 | Snow tiles |
|
||||
| `terrain-tropics` | `ta-terrain-tropics` | 64×64 | 9 | Jungle tiles |
|
||||
| `icons` | `ta-icons` | 44×44 | 10 | Command/build glyphs |
|
||||
| `icons` | `ta-icons` | 64×64 | 10 | Command/build glyphs — shared, NOT per-army |
|
||||
|
||||
Frames are numbered **left to right, then top to bottom**, starting at 0.
|
||||
|
||||
|
|
@ -228,24 +228,69 @@ The theme then appears in the skirmish setup screen automatically.
|
|||
|
||||
---
|
||||
|
||||
## Icons (44×44 cells, 10 per row)
|
||||
## Icons (64×64 cells, 10 per row)
|
||||
|
||||
Build-menu and command glyphs. Frame numbers come from each def's `icon` in the rules JSON
|
||||
and from `commandIcons`, so this table is a reflection of that file, not a second source of
|
||||
truth. Purely decorative today — the build menu labels itself from unit names — so this sheet
|
||||
is the lowest priority of the eight.
|
||||
truth.
|
||||
|
||||
**Shared across both armies — this is the one sheet that does NOT get the "paint every army's
|
||||
sheet in its own finished colours" treatment** from the top of this doc. There's a single
|
||||
`icons` entry in the artwork JSON, not an `arm-icons`/`core-icons` pair, and the same frame
|
||||
renders in either player's build menu. Paint it in a neutral palette (dark plate + light
|
||||
linework is what the procedural fallback already does) rather than ARM blue or CORE red/orange.
|
||||
|
||||
**Wired into the build menu** (`TAHud._drawGrid`, since 2026-08-16): every button in the
|
||||
build/production grid — buildings AND units — now draws this sheet's `def.icon` frame above the
|
||||
shortened name and cost, at a **36×36 display size**. The command bar (Move/Attack/Patrol/…)
|
||||
still renders text-only for now; its glyphs (frames 20–29) only exist for the procedural
|
||||
fallback painter today.
|
||||
|
||||
**The 64×64 source is intentionally bigger than that 36×36 display size.** Painting at exactly
|
||||
the display size (the old 44×44 spec was already close to that trap) means every icon gets
|
||||
upscaled a little and softens; painting bigger and letting Phaser scale down is what keeps it
|
||||
crisp. Draw at the full 64×64 canvas — don't pre-shrink your art to "look right" at a smaller
|
||||
preview size.
|
||||
|
||||
| Frames | Contents |
|
||||
|---|---|
|
||||
| 0–9 | Units: commander, infantry, sniper, jeep, tank, rocket tank, rocket trooper, construction vehicle, fighter, bomber |
|
||||
| 10–16 | Buildings: energy gen, mass gen, barracks, vehicle plant, laser tower, missile launcher, advanced vehicle plant |
|
||||
| 17–19 | Overflow: hover constructor (unit), airfield, radar tower |
|
||||
| 30–31 | Advanced radar, radar jammer |
|
||||
| 20–29 | Commands: move, attack, attack-move, stop, hold, patrol, guard, assist, repair, rally |
|
||||
| 30–31 | Advanced radar, radar jammer |
|
||||
| 32 | Megatank (unit) |
|
||||
|
||||
Row 0 filled up before the Airfield units were added, which is why the hover constructor sits
|
||||
next to the buildings at 17 rather than with the other units. Nothing reads a row as a
|
||||
category — only the `icon` numbers matter.
|
||||
category — only the `icon` numbers matter. Frames 33–39 are free.
|
||||
|
||||
### Painting priority: buildings the Commander and Construction Vehicle put up
|
||||
|
||||
This is the set that actually appears in the build-menu grid during a normal game — the union
|
||||
of everything `commander`, `constructor` and `hoverconstructor` can build — in a sensible
|
||||
painting order (the 8 the Commander itself can queue from turn one, then the 3 that need a
|
||||
Construction Vehicle or Hover Constructor first):
|
||||
|
||||
| Frame | Building | Also needs a Constructor? | Footprint |
|
||||
|---|---|---|---|
|
||||
| 10 | Energy Generator | no — Commander builds it too | 2×2 |
|
||||
| 11 | Mass Generator | no | 2×2 |
|
||||
| 12 | Barracks | no | 3×3 |
|
||||
| 13 | Vehicle Plant | no | 3×3 |
|
||||
| 14 | Laser Tower | no | 1×1 |
|
||||
| 15 | Missile Launcher | no | 2×2 |
|
||||
| 18 | Airfield | no | 3×3 |
|
||||
| 19 | Radar Tower | no | 2×2 |
|
||||
| 16 | Advanced Vehicle Plant | **yes** | 4×4 |
|
||||
| 30 | Advanced Radar | **yes** | 2×2 |
|
||||
| 31 | Radar Jammer | **yes** | 2×2 |
|
||||
|
||||
Draw each as a simplified, high-contrast read of its full structure-sheet art (see Structure
|
||||
sheets below), not a literal crop of it — a 128–192px building shrunk straight down to 64px
|
||||
loses its silhouette to surface detail. Keep the same silhouette and colour language (Laser
|
||||
Tower's plinth-and-emitter, the Radar family's dish/mast/broken-rings distinction, etc.) so an
|
||||
icon and its full-size building are still recognisably the same thing at a glance.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||