- Add shotgun, machine gun, gatling gun, and plasma rifle weapons with
distinct fire modes (semi-auto, auto, burst) and damage profiles
- Refactor ammo from per-weapon pools to shared pools keyed by ammo type
(9mm, shells, plasma), allowing multiple weapons to share the same pool
- Add pickup system with 11 item types: 5 weapons, 4 ammo variants, and
2 health packs, all with spritesheet frames for rendering
- Update level editor with dynamic pickup dropdown populated from rules.json
- Generalize weapon viewmodel rendering to support multiple weapon images
with per-weapon bob/sway animation
- Add cosmetic pickup animations: vertical bobbing and orbiting sparkle
effects drawn in screen space around each pickup billboard
- Bump save version to v3 to invalidate old saves with incompatible ammo
structure
- Update keyboard bindings for weapon switching (keys 1-6)
- Add comprehensive test coverage for new weapons, burst fire mechanics,
ammo pooling, and pickup behavior
- Rename weapon_gattling.png to weapon_gatling.png to fix spelling
Introduces a new "Object" entity type that blocks movement but not sight/bullets, distinct from walls and pickups:
- **Data**: New `objects` array in level JSON (`{x, y, frame}`), with `data/wolfenstein-objects.json` as the frame registry (Tall Bush, Gold Eagle)
- **Artwork**: New `objects.png` spritesheet registered in `wolfenstein-artwork.json`; placeholder texture via `paintObject()` in WolfensteinArt.js
- **Logic**: Objects stored in `state.objects`, with a derived `map.objectBlocked` Set checked only by movement collision (`isWallCell`) — raycaster/sight/bullets never read it, so objects are see-through and shoot-through by construction
- **View**: Rendered as billboard sprites in `_drawSprites` with ground-anchored positioning (bottom edge on floor) and asymptotic depth sorting that stays below the weapon viewmodel
- **Editor**: New "Object" tool category with dynamic dropdown; click open floor to place/remove (toggle), click wall is a no-op; teal square indicator on board
- **Validation**: `validateLevel` checks objects sit on open floor; save/load round-trips with graceful degradation for pre-existing saves
- **Tests**: Verifies object blocks player movement but bullets pass through
**Analysis of the Diff:**
1. **Binary Files:** `walls.png` and `walls.psd` are updated. This suggests an asset update, likely related to the "wolfenstein" theme mentioned in the paths.
2. **JavaScript File:** `tools/verifyWolfenstein.js` is modified.
* A new test case is added under `section('4. Enemy AI');`.
* The test verifies that an enemy (guard) alerts when hit by a projectile, specifically in a scenario where:
* Visual detection (LOS+FOV) is blocked/blind (guard facing away).
* "Heard gunfire" alert path is blocked (different room/door logic).
* The test sets up a specific level layout, forces a door open, fires a pistol, and checks if the enemy's state changes from 'idle' to something else (alerted) and health drops.
* It explicitly mentions fixing an issue with `stepDoors` auto-close countdown underflow by setting `timer`.
**Synthesis:**
The primary functional change is adding a test case to ensure that direct hits alert enemies even when other alert mechanisms (vision, sound through doors) fail. The asset changes are likely incidental or part of the same feature branch (Wolfenstein theme).
**Drafting the Commit Message:**
* **Subject:** Add test for enemy alert on direct hit bypassing vision/sound checks
* **Body:**
* Update Wolfenstein wall assets (PNG/PSD).
* Add verification test in `verifyWolfenstein.js` ensuring enemies alert when shot, even if they cannot see the player or hear gunfire through doors.
* Fix door timer initialization in the test to prevent auto-close interference during projectile flight.
**Refining for Conciseness:**
Subject: Add enemy hit-alert test and update Wolfenstein assets
Body:
- Update `walls.png` and `walls.psd`.
- Add a test case in `verifyWolfenstein.js` verifying that direct hits alert enemies unconditionally, independent of vision cone or room-based sound alerts.
- Ensure door state is correctly initialized in the test to prevent auto-close interference with projectile simulation.
Let's make it standard conventional commit style if possible, or just clear and descriptive.
**Final Polish:**
Subject: Add test for unconditional enemy alert on direct hit
Body:
Update Wolfenstein wall assets (`walls.png`, `walls.psd`).
Add a new test case in `verifyWolfenstein.js` to verify that enemies alert when directly hit by a projectile, even when visual detection (LOS/FOV) and sound-based alerts (through doors) are inactive. This ensures the direct-hit alert path works independently.
Also fixes door timer initialization in the test setup to prevent auto-close logic from interfering with the projectile simulation.
This looks good. I will provide just the message as requested.
This refactors weapon/enemy combat systems to support per-weapon cooldowns,
fire modes (auto/semi), and data-driven damage rolls via ammo types. Guards
now use the pistol's stats for ranged attacks and can be stunned by non-lethal
hits. The level editor now includes a directional facing picker for newly placed
enemies and displays enemy orientation as arrows instead of dots.
Key changes:
- Logic: Replaced single weaponCooldownMs with per-weapon cooldowns map; added
prevFireHeld for semi-auto trigger-edge detection; guards now reference real
weapon definitions via rangedWeapon; projectiles carry ammoType and resolve
damage at hit time using rollDamage(); non-lethal ranged hits apply stunMs to
enemies, freezing their AI until it expires.
- Rules: Added ammoTypes array with damageMin/damageMax; weapons now specify
fireMode and ammoType (projectiles) or damage (melee); enemy definitions
include stunMs and reference weapon IDs instead of hardcoded projectile stats.
- Editor: Added FACING_DIRS constants and drawFacingPicker() overlay that lets
users click N/S/E/W neighbor cells to set a just-placed enemy's facing;
enemies now render as directional arrows showing their spawn orientation;
pendingFacingEnemy state tracks the in-progress pick across tool switches,
undo/redo, and level resets.
- View: Added GUARD_FRAME.stunned (frame 9) which takes visual priority over
all other states when e.stunMs > 0, ensuring the flinch pose displays even if
the enemy's internal state still reads 'attack' or 'chase'.
- Data: Expanded level-e1m1 to 19x21 grid with repositioned doors/enemies/exit;
bumped SAVE_VERSION to 2 since player.cooldowns and prevFireHeld are new
required fields absent from v1 saves.
- Tests: Added coverage for semi-auto trigger-edge behavior, stun application
and duration, melee non-stun behavior, damage roll range bounds, and guard
projectile ammo type/cooldown spacing; updated existing tests to use new
cooldowns/ammoType fields and toggle fireHeld for repeated shots.
Add computeRooms + alertEnemiesInPlayerRoom: a gunshot now alerts every
idle guard sharing the player's room regardless of range/LOS/cone. A
door cell is always treated as a room boundary for this purpose, even
when fully open — two rooms joined only by a doorway stay distinct
("gunfire carries through the room, not through doorways").
Fix _guardFacing side-walk/side-idle flip: was `rel > 0`, read
backwards in-game, now `rel < 0`.
Cover with three verifyWolfenstein cases: same-room alert fires,
behind-closed-door does not, through-open-door does not (door forced
slide=1 / wall zeroed to exercise the slide-independent path).
- Implement 90° field-of-view check for idle/patrolling guards (only alerts when player is within cone, in range, and has clear line of sight)
- Change patrol behavior: 0-1 waypoints ping-pong, 2+ waypoints form a one-way loop (home → nodes → home → ...)
- Reduce patrol speed to 50% of chase speed for natural movement
- Update editor to display loop closing line when 2+ patrol nodes exist
- Add new weapon sprite images (gattling, machinegun, plasma, rocket, shotgun)
- Extend map parser to support patrol route definitions via `opts.patrols`
- Add patrol routes to e1m1 (guard at 2.5,18.5) and e1m2 (guard at 9.5,8.5)
- Add comprehensive tests for vision cone (inside/outside edge cases) and patrol loop/ping-pong behavior
Movement & collision:
- stepSeparation (TALogic) replaces the hard "snap unit to nearest clear
tile centre" correction with a circle-vs-blocked-tile push proportional
to overlap, damped by separationStiffness — no more teleport-yank,
corner-bouncing, or stalling in exact-width corridors (caught as an
AI-vs-AI win-rate regression in testing).
- servicePathQueue now routes at a unit's exact required clearance instead
of padding +1, so traffic spreads across all passable tiles rather than
funneling into a few wide chokepoint corridors.
- TAArt's structure painter falls back to a generic spinning glyph for
topperFrame buildings.
Upgrades (new rule: upgradesFrom):
- A building may be placed directly on top of a friendly building it
names at the same tile/footprint, consuming it for a 50% refund of the
replaced building's OWN cost (not a price discount) — implemented via
TALogic.findUpgradeTarget and an army-aware canPlaceAt.
- New definitions: nuclearplant (upgrades energygen, frame 22) and
advancedmassgen (upgrades massgen, frame 24).
- compileRules (TARules) validates upgradesFrom references and topperFrame;
sprites.md documents the semantics.
- New map m06 "Annihilation" (medium, snowfields, Klaxon skill 5, seed
90123 — pre-vetted from the original sweep for early-economy balance).
Tests (tools/verifyTotalAnnihilation.js):
- Section 4d: pathfinding routes around obstacles and a unit threads a
corridor exactly its own width.
- Section 5b: obstacle push is a bounded per-tick nudge (not a
teleport), settles clear without oscillation, a unit ordered past an
obstacle arrives, and no stuck-give-up flagging.
- Upgrade suite: exact 50% refund credited in place, fresh-ground builds
still work, enemy-owned and mismatched-type targets rejected, reverse
nuclearplant/energygen pairing, and canPlaceAt without an army never
grants upgrade placements.
- New `upgradesFrom` rule: a building def (Nuclear Power Plant on the
Energy Generator, Advanced Metal Generator on the Mass Generator) may
be placed exactly on a friendly, finished building of the named type,
consuming it for a 50% refund of its build cost instead of needing
clear ground (TALogic findUpgradeTarget / consumeUpgrade / buildCommand)
- New `topperFrame`: a second sprite stacked on the finished structure
that spins continuously (the Advanced Metal Generator's centrifuge,
frame 26), hidden while under construction; TAArt sizes the sheet for
it and paints a generic spinner-glyph fallback
- New rules: Nuclear Power Plant (frames 22-23) and Advanced Metal
Generator (frames 24-26) in totalannihilation-rules.json
- TARules: validate topperFrame and upgradesFrom (real building with a
cost); TAWorldView renders/spins the topper; verifyTotalAnnihilation
checks topper frames fit and were painted
- Test section covering upgrade placement (ownership, type match, exact
footprint, refund amount, army-less fallback) and sprites.md updated
for frames 22-26
- 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
- Add morale bonus from buildings (e.g., Holo Simulator): flat +N% to total
colony production, uniformly boosting construction, defense, industry,
ecology, and research
- Add espionage restraint (offDrift): setting Intelligence to 'off' toward
an empire with neutral-or-better opinion drifts their attitude upward by
1/turn, giving a way to improve relations without gifting (gated on not
being at war and their opinion of you being >= 0)
- Display morale bonus in colony view when applicable
- Reduce planetShotDamageMult from 10 to 6
- Add verification tests for both new mechanics
- Starbases no longer count toward attacker power in holdsOrbit(), invade(),
resolveCombats(), pendingBattlesFor(), and prepareBattleAt(). A starbase
never leaves its home system, so it must never alone enable orbital
superiority or pick fights with neighbouring hostile colonies (Brian, 2026-08-15).
- VegaAI manageFleets 2a/2b now uses targetColonyAt() instead of colonyAt()
to resolve the colony it is actually at war with. At multi-colony stars
this fixes the bug where an idle fleet sitting on a hostile undefended
colony would silently check a different (not-at-war) colony sharing the
star and never bombard/invade (Brian, 2026-08-15).
- Add test suite 5f (starbases cannot attack alone) and 5g (AI bombard/invade
at contested multi-colony stars).
- defenseHp is now a pure per-battle ammo gauge (one full-strength
shot per planetDefensePerShot points, remainder as fractional shot)
instead of in-battle damage tracking; no longer written back after
battle outcome
- Planet now has a real range limit (planetRange, 1200) — previously
the only entity with no range check at all
- Per-shot damage scales with the defending empire's best known weapon
tech (weaponAvgDmg) instead of a flat HP-proportion curve
- defenseHp is only wiped to 0 when the planet is actually DESTROYED,
fixing the bug where a defeated planet could be re-attacked multiple
times in one turn with full strength each time
- Added combat config: planetDefensePerShot (5), planetShotDamageMult (1)
- Added combatV2 config: planetRange (1200)
- Comprehensive tests for range gating, shot formula, ammo exhaustion,
multi-battle-same-turn fix, and tech-scaled damage
Add siegeFreezesDefense mechanic (default true) that stops a colony's
passive defenseHp trickle and blocks defensive building completion at the
front of the build queue while a hostile warship fleet is present.
This fixes the recurring "Under Attack" notification loop reported by Brian
where defenseHp would regenerate each turn, re-arming the pendingBattlesFor
gate and triggering fresh popup notices for an already-beaten colony.
Also adds an AI dispatch throttle in manageFleets: idle fleets no longer
open redundant attack orders against colonies the empire already holds orbit
over with defenseHp beaten to 0. Excluded fleets fall through to rally logic
and naturally join the existing siege or find a fresh front.
New helpers: isDefensiveBuildingId, isHostileWarshipFleet, hasHostileWarshipFleet
— shared across processColony, pendingBattlesFor, and VegaAI to ensure a
single definition of "under active siege".
Includes tests (sections 5d, 5e) covering regen freeze, build queue freeze,
siegeFreezesDefense=false toggle, and AI throttle.
- **Visual Feedback**: Introduce VegaBombardScreen.js — a two-stage popup for
bombard/invasion results featuring JIT-loaded videos (per planet type or
invading species) and animated stat bars showing population, factory, and
building losses.
- **Expanded Consequences**: Factory and building destruction now scale with
the population kill ratio. On colony wipeout, weapon Mark gates planetary
ruin/ruination (toxic/radiated/dead/asteroids) via a weighted probability table.
- **AI & Tactics**: Ursaal now queue troop transports alongside warships for
invasion fleets. Added `bombardHoldFireChance` trait (0–1) to let species
defer bombing when invasion troops are staged, preserving intact colonies
without creating fortress-world stalemates.
- **Battle Logic Fixes**: Correct `prepareBattleAt` and `pendingBattlesFor` to
properly handle stars with multiple colonies, ignore transport-only fleets,
and suppress pending battles when planetary defenses are depleted.
- **UI/Reporting**: Wire player-initiated and AI-initiated attacks into the
new popup queue. Add `bombard` and `invasionFailed` to notable turn report
events with detailed outcome descriptions.
- **Testing & Tooling**: Add comprehensive verification tests for planet
destruction distribution, building damage rates, hold-fire chances, and
battle edge cases. Expose `window.game` for devtools debugging.
- Replace flat planetDefenseBase (20) with proportional planetDefenseScale
(0.06), so colony defense damage scales purely with current defenseHp.
A near-depleted colony now barely scratches attackers, while a fully
tech'd one still tops out ~110 damage — fixing "attacked with the
strength of a much-better-defended planet" (Brian, 2026-08-14).
- Add AI war memory: track consecutive losses per enemy and escalate
attackMultiplier up to 3x so repeated losing attacks stop dribbling
small fleets. A win resets the streak. Prevents permanent phoney wars
where both sides build to equal strength and nothing moves.
- Show "Under Attack" notice (one-button, no formation picker) when AI
attacks the player, since formation choice is meaningless for defense.
- Add planetary beam fire SFX for combat view.
- Add event `seq` cursor for war memory to survive event list trimming.
- Full test coverage for planet damage formula and AI escalation behavior.
- Add "Galactic Expansion" colony focus and "Expansion" allocation focus
for early-game land grab phase (one colony ship per discovered open world,
then 2 frigate escorts per colony ship)
- Introduce fleetUrgency() — sliding-scale fleet recommendation based on the
coldest contacted relationship, throttled pre-contact to avoid premature
militarization
- Hide Council menu button until the Council has actually convened (lastResult)
- Add tooltip to disabled population send button explaining why it's off
- Rename "Production" allocation preset to "Industrial Buildout"
- Expand Colony Improvement recommendation to fire when factories are well
below cap, not just near cap
- Add comprehensive tests for all new logic paths
- relationsRows now filters out empires the human hasn't contacted, matching
the existing contact-gating behavior of rankingRows (Brian, 2026-08-14)
- Expand GNN alert suppression from espionage-only to include tech breakthroughs
via new ALERT_STORY_KINDS set, skipping ranking/relations pages for these
one-off notifications
- Update verifyMasterOfVega tests to assert uncontacted empires are excluded
from relationsRows while confirming names can still appear in contacted
rows' war/trade/ally lists
- Add leader detail pop-over (VegaLeaderDetail.js) with portrait, bio, and
current posting bonuses displayed in fleet and colony views
- Add leader portrait click-to-zoom in the Leaders screen
- Add leader skill summary formatting (leaderSkillSummary) for readable
bonus descriptions across UI components
- Integrate leader skills into espionage power/defense and invasion attack
calculations in VegaLogic.js
- Cap bombard() at once per (attacker, colony) per turn via lastBombardTurn
tracking; fixes UI double-click and AI double-bombard bugs
- Contact-gate GNN breakthrough stories and ranking charts on first contact,
matching existing rankingRows behavior
- Round population displays throughout the UI (toFixed(1) → Math.round)
for cleaner presentation
- Bump colony ship and transport base costs in rules data
- Add leaders.png artwork reference to mastervega-artwork.json
- Add tests for bombard cap and GNN contact-gating in verifyMasterOfVega.js
- Add "peace request" diplomacy: player can ask an AI to end a war with a
third empire, and AIs can ask the player the same. Refusing costs attitude.
Implemented in VegaDiplomacy.js (wouldAcceptPeaceRequest/requestPeace/offerPeaceRequest),
VegaAudience.js (Demand Peace button + war picker), and full chat lines for
all species in VegaChat.js.
- Extract openFormationPicker to VegaScreens.js and wire it into
MasterOfVegaGame.js so the player chooses a formation before every battle.
AI opponents still pick silently.
- Fix Combat V2 planet positioning (fixed at worldWidth * 0.75 instead of
formation-relative), pass typeId for real planet art, and apply the
Planetary Shield building's shieldBonus (was hardcoded to 0).
- Add icon images to research screen tech field headers.
- Add comprehensive tests for peace requests and prepareBattleAt fixes.
Introduce a full-screen, click-advanced ceremony (VegaCouncilSession.js)
that replays runCouncil()'s result delegate-by-delegate instead of hiding
the tally behind the turn-report. Three fixed stages — Roster, Voting,
and Verdict — with a persistent 2:3 portrait anchor video, green-screen
ticker, live scoreboard with animated bars, and sting-then-loop audio.
Key changes:
- VegaLogic.js: expose per-voter `voters` breakdown and `pendingSession`
flag so the UI can replay the session before the victory check.
- MasterOfVegaGame.js: consume `pendingSession` in `runToHumanTurn()`
before `state.over`, ensuring a decisive council still gets its ceremony.
- VegaTurnReport.js: remove `council` from NOTABLE_TYPES (ceremony handles
it); keep `councilRefused` as a distinct war-declaration row.
- assetManifest.js / Sounds.js: register video + sting/loop audio cues.
- VegaScreens.js: add `D.council` depth value.
- verifyMasterOfVega.js: assert voter breakdown consistency and pending
session lifecycle.
Introduce a full-screen, click-advanced ceremony (VegaCouncilSession.js)
that replays runCouncil()'s result delegate-by-delegate instead of hiding
the tally behind the turn-report. Three fixed stages — Roster, Voting,
and Verdict — with a persistent 2:3 portrait anchor video, green-screen
ticker, live scoreboard with animated bars, and sting-then-loop audio.
Key changes:
- VegaLogic.js: expose per-voter `voters` breakdown and `pendingSession`
flag so the UI can replay the session before the victory check.
- MasterOfVegaGame.js: consume `pendingSession` in `runToHumanTurn()`
before `state.over`, ensuring a decisive council still gets its ceremony.
- VegaTurnReport.js: remove `council` from NOTABLE_TYPES (ceremony handles
it); keep `councilRefused` as a distinct war-declaration row.
- assetManifest.js / Sounds.js: register video + sting/loop audio cues.
- VegaScreens.js: add `D.council` depth value.
- verifyMasterOfVega.js: assert voter breakdown consistency and pending
session lifecycle.
Introduce GNN, a galaxy-wide news broadcast feature that reports major
events to the player via a full-screen takeover UI with anchor desk
video, story pages, MOO1-style animated rankings, and a diplomatic
relations reference.
Key changes:
- VegaGnn.js: headless event classification, anchor copywriting, and
ranking logic (Phaser-free, testable in Node)
- VegaGnnScreen.js: full-screen UI with looping anchor video,
green-screen ticker terminal, story renderers (diplomacy/tech/
territory/espionage), animated bar-chart rankings, and relations page
- HUD: new GNN button with unread bullet cue; auto-opens after turns
when stories are pending, on-demand via button
- VegaLogic.js: new `lastColony` event (reduced to single world),
`attacker` field on elimination events, `gnn` state with history
buffer, export empireFleetPower for multi-empire rankings
- VegaColoniesScreen.js: export and generalize createAdvisorTerminal
for reuse by GNN's ticker
- mastervega-rules.json: flag ~16 headline-worthy techs with
gnnHeadline (research-sourced only, not espionage-stolen)
- Assets: eager-load GNN anchor video, sting/loop audio, and populate
all 10 species colony advisor videos in mastervega-artwork.json
- verifyMasterOfVega.js: comprehensive 7b test section covering
classification, consumption, describeGnnStory, anchorLine, attacker
threading, ranking metrics, relationsRows, serialization, and AI soak
Introduce VegaColoniesScreen.js, a spreadsheet-style screen that displays
and manages all of the player's colonies at once, grouped by star and
sorted by population. Features include:
- JIT-loaded advisor video panel (one 1:1 muted loop per species, falling
back to the species portrait when no clip is recorded)
- Retro terminal with typing animation, scanlines, and glitch effects
that displays advisorColonyReport commentary for the selected colony
- Inline Colony Focus and Allocation Focus pills with dropdown pickers
showing the advisor's live recommendation outlined in yellow
- Population transfer (arm-and-target idiom matching fleet orders)
- Manage button delegating to the existing single-colony flyout
Refactor VegaColonyView.js to use shared applyColonyFocus and
applyAllocationFocus setters from VegaLogic.js so both the flyout and
inline pills apply identical side effects. Add empireColoniesByStar
grouping helper for the spreadsheet view. Wire a "Colonies" entry into
the Empire dropdown menu in MasterOfVegaGame.js. Add advisorVideos
entries to mastervega-artwork.json with JIT-loading helpers in VegaArt.js.
Update verifyMasterOfVega.js to validate the new assets, lazy-loading
behavior, and all new logic functions.
- Add VegaButton.js: a Master of Vega-local cyberpunk button with chamfered
panels, neon glow, scanline sweep, and corner-bracket hover animations.
Supports cyan/magenta/red/green schemes.
- Swap Button imports across 12 Vega modules to use VegaButton.js and add
scheme options (green for accept, red for reject/war, magenta for actions).
- Fix multi-colony targeting in VegaLogic.js: introduce targetColonyAt() to
resolve the correct colony by orbit when multiple exist at a star. Update
bombard(), invasionForecast(), and invade() to accept an optional orbit
parameter. Add immediate scene.log() feedback in VegaSystemView.js.
- Implement weighted 4:3:2:1 fleet mix (frigate:destroyer:cruiser:battleship)
in pickFleet(), replacing the old equal-count-per-hull diversity logic.
- Add BASELINE_WEAPON fallback in VegaShips.js so warships with zero weapon
tech still deal damage instead of silently doing nothing.
- Guard VegaDiplomacy.js proposeOrOffer calls with canNegotiate to prevent
diplomacy-incapable species (e.g., Lithox) from queuing peace offers the
human can never answer.
- Update verifyMasterOfVega.js with comprehensive tests for all new behavior.
- Hulls: frigate turnRateBase 150→340, brakeSeconds 11→1.0 (X-wing agility);
destroyer turnRateBase 100→230, brakeSeconds 2.8→1.35 (midpoint leaning frigate).
- Fix battleship (and all slow hulls) no longer holding position: added
anticipatory retrograde pre-turning in computeShipMove, comparing
worstTurnTime vs timeToRange so the nose begins flipping before braking
range, with urgency-blended facing to avoid "running away" appearance.
(Was accidentally crutched by strong avoidAccel collision avoidance.)
- Fix parked ships coasting indefinitely: velocity now starts from 0 when
hasTask is false instead of carrying residual velocity forever.
- V2 damageMultiplier (2.8): scales weapon raw output before shield
mitigation, V2-only, doesn't touch live engine balance. Shortens battle
duration meaningfully across test scenarios.
- V2 maxDurationSeconds (240) and disengageFraction (0.9): decoupled from
shared rules.combat.maxRounds. Counterintuitively, the old disengage
timer was an implicit duration cap; extending it let genuine fights play
out while damageMultiplier handles the shortening.
- Species-colored beams: VegaCombatViewV2.js now renders beams in a
vibrant, saturation-boosted version of the firing ship's species color,
memoized. Missiles keep fixed orange.
- Mirror-match bias tolerance widened 0.25→0.30 (expected variance cost
of lower TTK from higher damage multiplier).
- Frigate stationary-target check inverted: now asserts it CAN hold
position (alongside battleship/cruiser/destroyer). Added agility ordering
data-integrity checks on hulls block.
Implement continuous velocity vectors (vx/vy) replacing the old
kinematic position clamp. Each hull gets brakeSeconds-derived
linearAccel so stopping distance naturally falls under or over beamRange,
producing battleship hold-position vs frigate strafe-run behaviour
without hull-specific tactic branches.
Key mechanics:
- Thrust magnitude scaled by facing alignment (cos of angle to task
direction), honouring "turn and engage thrusters" without locking
thrust to facing (which caused battleships to never stop).
- GOLDEN_ANGLE-spaced approach points fan out ships sharing a target.
- avoidAccel (60) is a gentle, hull-independent collision avoidance
budget — ships can overlap when objectives require it.
- Target avoidance uses reduced radius (0.35×) so engagement isn't
fought by personal-space calculations.
Data: add brakeSeconds to all hulls, avoidAccel to combatV2 constants.
Verifier: rewrite turn-rate check to time-to-range metric, add hold-vs-
strafe gradient and max-delta-speed checks, relax cloak/singularity to
"doesn't hurt" invariant.
Introduce `VegaCombatV2.js`, a parallel headless combat engine that simulates
individual ships (not stack aggregates) in continuous time rather than discrete
rounds. Ships have per-hull `sizeScale`, `sizeSpeedMult`, and `turnRateBase`
fields; every entity tracks its own cooldown, position, facing, and angular
momentum. Damage and movement are banked per-tick to preserve fairness.
Accompanying files:
- `VegaCombatViewV2.js` — zoomable/pannable Phaser view with parallax starfield
- `VegaCombatCamera.js` — cursor-anchored zoom + drag-to-pan (listener cleanup
on destroy to avoid stacking across battles)
- `VegaFormations.js` — formation strategy plumbing (chosen per side, not yet
read by movement/targeting)
- Hull-specific destroy audio cues and vega buildings art
Wired behind `?movsim`'s Live/V2 toggle in `VegaCombatSim.js` — the live engine
and all real player battles are untouched.
Also fixes several latent bugs discovered during the rewrite:
- Trap 26: simultaneous wipe-out now checks draw before single-side wins
- Trap 27: movement is banked (two-phase) like damage
- Trap 28: weighted-random targeting tames chaotic nearest-neighbour sensitivity
- Trap 29: fleet gap clamped to 85% world width to prevent starvation
- Trap 30: `RANGE_EPS` tolerance prevents steering-induced standoffs
See `docs/mastervega-build-plan.md` for full design notes.
Move vega audio files into assets/fx/vega/ subdirectory and register them via
assetManifest.js. Add weapon and missile sound cues banded by ship Mark, with
staggered playback in VegaCombatView to prevent audio clipping during barrages.
Wire up two previously inert tech effects in combat:
- Stealth Field (cloaked): applies a flat accuracy malus via cloakEvasion rule.
- Black Hole Generator (singularity): adds passive shield pierce via
singularityShieldPierce rule on every weapon fired by the design.
Update tech descriptions, ship detail display, and designFor() to reflect
these effects. Fix a bug where singularity was never copied into the design
object.
Add vega-endturn cue to End Turn / Next Round buttons (no-op when busy),
remove hardcoded audio loads from PreloadScene, and add verification tests
that isolate each flag with A/B battle comparisons.
Introduce an advisor recommendation system that suggests colony focus
(improvement, research, fleet, growth, trade, defense) and allocation
slider presets (growth, production, military, research, default) for
each colony. Recommendations are computed by pure heuristics that
consider population levels, factory utilization, empire-wide fleet
strength, war status, and building availability.
UI changes:
- Colony Focus and Allocation Focus flyouts display "YOUR ADVISORS
RECOMMEND" banners with explanatory text and pulsing arrow indicators
pointing at the recommended row.
- Selecting a recommendation arms quiet-period tracking (15 turns) so
advisors don't nag immediately after the player makes a choice.
- `checkAdvisorRecommendations` fires once-a-turn `advisorRecommendation`
events when current settings diverge from live recommendations. Events
use dedup markers (`focusNotifiedValue`, `allocNotifiedKey`) that clear
on match, ensuring a persisting mismatch doesn't repeat every turn but
a later divergence is reported fresh.
- Turn report screen gains an "Advisor Recommendation" event type with a
"View Colony" shortcut button.
Performance change:
- Stop eager-loading `diplomacy.bySpecies` music tracks in
`assetManifest.js`. A playthrough may contact only a handful of the
nine species, so pre-fetching all nine at room entry wastes bandwidth.
`VegaMusic`'s own `new Audio()` at `setDiplomacy()` time is the actual
fetch — this manifest was only ever a race to get there first.
Logic changes:
- Extract shared building-ID lists and a `firstEligibleBuildingId` helper
to eliminate duplication between auto-queue pickers and the recommendation
heuristics.
- Add `advisor` tracking object to every colony (with migration in
`deserialize`).
- Introduce Colony Focus: a per-colony autopilot that auto-queues one
building/ship per turn when the queue is empty. Supports seven modes
(manual, improvement, research, fleet, growth, trade, defense) with
cost-aware affordability checks matching AI behaviour.
- Add Allocation Focus: one-time slider presets (default, research,
growth, production, military) that bulk-overwrite channel allocations.
- Refactor colony view flyout into a shared drawer supporting queue,
colony focus, and allocation focus modes with in-place swapping.
- Replace "Built here" text with hoverable building icon row and
tooltips on the colony screen.
- Add per-species audience music tracks and diplomacy music ducking when
seeking/planning an audience.
- Add sound effects for star selection, zoom in/out, and colony view
opening.
- Back-fill `focus: 'manual'` on old saves for forwards compatibility.
- Add verification tests exercising each focus mode in isolation.
- Add full diplomacy subsystem: tiered gifts (BC payments with diminishing returns), trade agreements (passive BC income, coexists with treaties, cancelled on war), and espionage mission toggles (Off/Steal/Sabotage) in the Audience screen.
- Implement whole-galaxy diplomacy passes: border and fleet proximity tension, fleet intrusion tracking with escalating penalties and force-opened Audience complaints, and "enemy of my enemy" attitude triangulation.
- Update Audience screen UI with new action buttons, gift picker, intelligence toggle, and species-specific chat dialogue for all diplomacy events.
- Add research choice prompts for ambiguous tech frontier picks, surfaced before the turn report.
- Improve star map: Delaunay triangulation for controlled-space range darkness, staggered docked fleet markers, expanded pan slack to clear UI chrome, and zoom-aware colony info labels.
- Backward-compatible save serialization for new diplomacy fields.
- Add comprehensive test coverage for all new logic, chat completeness, and AI soak validation.
- Add 21 new alternate techs across all 6 fields (computers, construction,
forcefields, planetology, propulsion, weapons), using icon frames 78-96
- Set research video paths for human and kestrelli species
- Expand tech sprite sheet from 8 to 10 rows to accommodate new frames
- Add fieldTechLevel() to VegaLogic: displays per-field level as highest
known tier × 5 plus extra known techs below the frontier
- Display field level in research screen headers
- Add verification tests for 3-way branching rungs, fieldTechLevel calculations,
and refine availability roll tests to measure unbranched rungs only
- Add branching tech alternatives across all six fields (computers,
construction, forcefields, planetology, propulsion, weapons). Each
branched tier has 2+ techs sharing the same rung; researching any one
clears the rung while leaving siblings researchable as side-picks.
- Correct racial skill to affect tech COST only (Poor 125%, Average 100%,
Good 80%, Excellent 60%), not availability. Availability is now a flat
50% roll per tech (75% for Cerebrai/psilon analogue), with a safety
net that no branched rung can end up with zero available options.
- Add techRungsByField data structure and rungCleared/canResearch/setResearchTarget
logic so the research screen lets players pick among open rung alternatives
without losing banked beakers.
- Update sprite sheet layout (+1 row, frames 66-77 for new tech icons).
- Add comprehensive verification tests for cost buckets, rung gating,
setResearchTarget behaviour, and statistical availability rates.
Introduce colony naming with a 50-name bank per species, shuffled
per-empire and displayed as defaults in naming prompts. Colony names
now appear across all UI layers (star map, side panel, colony view,
system view) with the astronomical designation as fallback.
Add three pure-flavor conversation topics to diplomacy: "Their People"
(neutral+), "Their Homeworld" (friendly), and "A Story" (friendly).
Each diplomacy-capable species receives unique lore-rich responses
(3 variants each) reflecting their culture, homeworld, and history.
Other changes:
- Switch ursaal videos from generic "human" assets to species-specific
- Widen diplomacy buttons to 200px; add auto-shrink for long labels
- Add ±5 population transport buttons to colony view
- Validate colonyNames (50+ entries, no duplicates)
- Enforce minimum lore variant counts in verification
- Add Colony Transport ('poptransport') hull, dispatched directly in transit
from a Send Population order rather than built from the queue. Shares the
Troop Transport's hull art and uses the colony ship's commander clip.
- Implement VegaLogic sendPopulation/deliverPopulation flow: clamped to
maxSendablePopulation (leaves 0.5 floor), creates poptransport fleet
immediately, auto-delivers on arrival capped at destination max pop.
- Add Send Population button and overlay picker in colony view with
destination list, ETA display, amount dial, and MAX button.
- Log populationSent/populationDelivered events in the turn report.
- Refactor VegaAudience mood visuals to play-once-and-hold-last-frame with
a clickable replay badge, mirroring VegaColonyIntro's video contract.
- Seed human audience mood clips (angry/neutral/happy) into artwork config
as placeholders for all diplomacy-capable species.
- Add verification tests for poptransport mechanics and video aliasing.
- Rewrite contact detection from proximity-based (parsec-range) to
star-scoped: empires now meet by sharing a system (colonies or fleets),
making first-contact a visible event rather than a silent background
check.
- Add full-screen Audience interface (VegaAudience.js) with species-specific
mood videos (or letterboxed portrait fallbacks), a typewriter chat log,
and contextual action buttons. Auto-opens on first contact via a queue
system in MasterOfVegaGame.
- Add VegaChat.js with unique dialogue pools for all 9 diplomacy-capable
species across 18+ situations (first contact, peace/alliance offers,
war declarations, tech trades, accept/reject responses, etc.).
- Introduce held diplomacy offers: AI proposals to the human are queued
(pendingOffers) instead of auto-resolved, with player Accept/Reject
buttons in the Audience screen and automatic expiry after 6 turns.
- Add audienceVideos config and JIT-loading infrastructure in VegaArt.js.
- Add ship videos for kkrix and mekhan species.
- Simplify openDiplomacyScreen to a single "Seek Audience" button.
- Fix colony view to filter out 'starbase' from building display list.
- Add comprehensive verification in tools/verifyMasterOfVega.js for
contact system, held offers, chat completeness, audience videos,
and serialization of new state fields.
- Remove obsolete contactRange rule from mastervega-rules.json.
Replace the turn-report "New Turn" popup row with a cinematic vignette that
plays the moment the player plants a colony: the soundtrack ducks, the world's
1920×1080 backdrop fills the screen, a 960×544 clip of this world being settled
plays in a framed window, and the founding numbers are read out underneath.
Key changes:
- Add `colonyVideos` block (15 clips, one per colonisable planet type) to
artwork JSON; clips are fetched just-in-time via ensureColonyVideo() when a
colony ship reaches a settleable world, keeping the set (~19 MB) out of the
eager manifest
- Add `vega-colony-cue` audio to the eager manifest for the founding soundtrack
- Remove `colonised` from NOTABLE_TYPES and TYPE_LABEL so the event is no longer
announced twice (once in the vignette, once in the turn report)
- Add `sourceWidth()` guard in VegaArt.js to fix a Phaser Video placeholder
width bug exposed by the non-square 960×544 colony clips (2.5× scale issue)
- Apply `sourceWidth()` to portrait and commander video scaling paths as well
- Add depth entry `intro: 78` to VegaScreens.js for the vignette overlay
- Add section 6b to the verifier: checks manifest exclusion, key conventions,
sourceWidth() behavior, turn-report classification, and colony stats
See build-plan trap #23 for the full sourceWidth() explanation.
Introduce looping commander videos (256×256) alongside ship thumbnails in
the side panel and colony catalogue. Each species×hull combination loads
its officer clip from shipVideos, falling back to portrait video → still →
procedural sheet. A scene-lifetime pool (VegaShipMedia.js) prevents decoder
thrash on every panel rebuild.
Add VegaShipDetail — a full-resolution pop-over (D.detail depth 76) showing
the commander at 256px, hull at 192px, derived stat block, and knapsack
loadout. Opens from both the side panel and colony screen without stacking
through openModal.
Add a "New Turn" popup (VegaTurnReportScreen) that interrupts the player
for notable events (discovery, first contact, diplomacy, eliminations).
Events are classified and sorted by consequence in VegaTurnReport.js.
Logic now emits 'discovered' events when fleets enter unexplored systems.
Update asset manifest to load nested shipVideos, extend verification to
validate shipVideoKey conventions, bump ships sheet to 192px frames, and
document the new art contract.
Move colony management (sliders, build queue, catalogue) from the
system-view modal into a dedicated full-screen colony view
(VegaColonyView.js). The system view now inspects worlds read-only
with a "View Colony" button to open the management screen.
Key changes:
- Add VegaColonyView.js with colony screen, build queue flyout,
scrolling catalogue, allocation sliders with padlocks, and
planet-type backdrops
- Add world backdrop artwork support (1920×1080, one per planet type)
declared in mastervega-artwork.json worldBackgrounds
- Add headless queue helpers to VegaLogic.js: collapseQueue,
moveQueueRun, colonyBuildRate, queueEtas, enqueueMany
- Fix star map pointer blocking (drags no longer pan map through modal)
- Move ORBIT constant to VegaScreens.js, add D.colony depth layer
- Update docs (build-plan, sprites) and verification suite
The colony screen stacks over the system view without requiring a
second modal, hiding the system layer and pausing the orrery while
open.
Introduce VegaSidePanel, a right-hand command panel with three modes:
star (system summary), fleet (ship count selectors), and order
(distance, ETA, Accept/Cancel). Replaces the inline fleet-order flow
with a callback-driven architecture where the scene owns selection
state and the panel only reads the engine and reports clicks.
Add fleet detachment logic to VegaLogic:
- splitFleet: carve a new idle fleet from an existing one
- sendDetachment: validate against actual stacks, normalize duplicates,
probe reachability on a copy, and rollback on refusal
- etaTo: compute ETA scoped to the selected detachment (slowest hull
in the selection, not the whole fleet)
VegaStarMap gains blockPointer (prevent pan/zoom over the panel),
onEmptyClick (dismiss panel by clicking void), and a rotating selection
reticle.
Section 4b adds ~32 verification checks covering ETA accuracy, ship
conservation, out-of-range refusals, duplicate normalization, star-base
immobility, and the idle-fleet merge rule.
Updates mastervega-build-plan.md to document the new panel and
verification section.
- Add VegaZoom.js with Phaser-free zoom ladder builder, verifiable headlessly
- Replace hardcoded ZOOMS array with galaxy-sized ladder anchored so the
bottom rung exactly covers the viewport
- Remove 160 px of pan slack in clampPan so empty space can never be dragged
into view
- Key semantic-zoom thresholds (isFarZoom / isNearZoom) to ladder index
instead of absolute scale, keeping behaviour consistent across galaxy sizes
- Add section 3b to verifyMasterOfVega.js with 163 new checks covering
ladder coverage, covering-zoom invariant, top-rung reach, and tiny-galaxy
single-step collapse
- Add video, still, and procedural three-tier portrait system for all 10 species
- Add species-specific speech clips and UI voiceover (SpeechQueue integration)
- Add landing screen with New Game / Resume / Return to Arcade buttons
- Add species detail pop-over with animated expand/collapse and auto-introduction
- Add game-specific soundtrack (masterofvega-music.json, 4 tracks)
- Add video asset type support in assetLoader and PreloadScene
- Add portraitVideos and portraitStills sections to artwork manifest
- Add verification for portraits, speech clips, and music tracks
- Update sprites.md with documentation for new assets and filenames