fix Vega game: reset fleet selection on show, offset fleet animations, add building queue UI
- Reset fleet selection when showing a new fleet so it starts at full strength - Offset moving fleet sprites by (-26, -22) to prevent blocking star click targets - Track newly unlocked building IDs in research completion events - Add one-click bulk-queue buttons in turn report for newly researched buildings - "All Colonies" queues at every colony - "Colonies with positive BC" filters by net income (trade minus upkeep)
This commit is contained in:
parent
2f99d5ce68
commit
a7c3ef20e4
|
|
@ -135,6 +135,9 @@ export default class VegaSidePanel {
|
|||
showFleet(fleet) {
|
||||
this.mode = 'fleet';
|
||||
this.fleet = fleet;
|
||||
// A fresh selection always starts at full strength: any dial-down from a
|
||||
// prior selection (this fleet or another) must not carry over here.
|
||||
this.sel = [];
|
||||
this.syncSelection();
|
||||
this.rebuild();
|
||||
this.open();
|
||||
|
|
@ -507,9 +510,12 @@ export default class VegaSidePanel {
|
|||
|
||||
/**
|
||||
* Rebuild the per-stack selection, keeping whatever the player had already
|
||||
* dialled in where the stack still exists. Immobile hulls (star bases) are
|
||||
* excluded outright rather than shown at zero: they defend the system they
|
||||
* were built in and can never be part of a move order.
|
||||
* dialled in where the stack still exists. This carry-over only matters for
|
||||
* refresh() (same selection, engine state changed under us); showFleet()
|
||||
* clears this.sel first so a fresh selection always starts at full
|
||||
* strength. Immobile hulls (star bases) are excluded outright rather than
|
||||
* shown at zero: they defend the system they were built in and can never
|
||||
* be part of a move order.
|
||||
*/
|
||||
syncSelection() {
|
||||
const fleet = this.fleet;
|
||||
|
|
|
|||
|
|
@ -335,8 +335,10 @@ export default class VegaStarMap {
|
|||
if (!a || !b) continue;
|
||||
if (viewer && !own && !viewer.explored[fleet.toStar]) continue;
|
||||
const t = fleet.total > 0 ? Phaser.Math.Clamp(fleet.progress / fleet.total, 0, 1) : 0;
|
||||
x = a.x + (b.x - a.x) * t;
|
||||
y = a.y + (b.y - a.y) * t;
|
||||
// Offset up-left of the lane so a fleet just leaving its origin star
|
||||
// doesn't sit directly on top of it and block the star's own click target.
|
||||
x = a.x + (b.x - a.x) * t - 26;
|
||||
y = a.y + (b.y - a.y) * t - 22;
|
||||
}
|
||||
|
||||
const colour = Phaser.Display.Color.HexStringToColor(emp.color).color;
|
||||
|
|
@ -501,8 +503,8 @@ export default class VegaStarMap {
|
|||
const from = this.state.galaxy.stars[f.fromStar];
|
||||
if (!from) return null;
|
||||
const t = f.total > 0 ? Phaser.Math.Clamp(f.progress / f.total, 0, 1) : 0;
|
||||
ax = from.x + (dest.x - from.x) * t;
|
||||
ay = from.y + (dest.y - from.y) * t;
|
||||
ax = from.x + (dest.x - from.x) * t - 26;
|
||||
ay = from.y + (dest.y - from.y) * t - 22;
|
||||
}
|
||||
return {
|
||||
ax, ay, bx: dest.x, by: dest.y,
|
||||
|
|
|
|||
|
|
@ -103,16 +103,20 @@ function describeTechDone(rules, state, ev) {
|
|||
if (effects.length) {
|
||||
lines.push(line(`Effects: ${effects.map(([k, v]) => `${k} ${v > 0 ? '+' : ''}${v}`).join(', ')}`, '#7fd8a0'));
|
||||
}
|
||||
const newBuildings = gate.buildings.map((id) => rules.buildings[id]?.name).filter(Boolean);
|
||||
const newBuildingIds = gate.buildings.filter((id) => rules.buildings[id]);
|
||||
const newTechs = gate.prereqOf
|
||||
.filter((id) => emp.available[id] && !emp.known[id])
|
||||
.map((id) => rules.techs[id]?.name)
|
||||
.filter(Boolean);
|
||||
const unlocks = [...newBuildings, ...newTechs];
|
||||
const unlocks = [...newBuildingIds.map((id) => rules.buildings[id].name), ...newTechs];
|
||||
if (unlocks.length) {
|
||||
lines.push(line(`Now available: ${unlocks.join(', ')}`, '#ffd88a'));
|
||||
}
|
||||
return { headline: `Research completed: ${tech.name}.`, lines };
|
||||
return {
|
||||
headline: `Research completed: ${tech.name}.`,
|
||||
lines,
|
||||
buildingUnlocks: newBuildingIds.map((id) => ({ id, name: rules.buildings[id].name })),
|
||||
};
|
||||
}
|
||||
|
||||
function describeBuildingDone(rules, state, ev) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,16 @@ import { buildingFrame } from './VegaArt.js';
|
|||
import { turnToYear } from './VegaRules.js';
|
||||
import { Button } from '../../ui/Button.js';
|
||||
import { describeEvent, categoryWeight } from './VegaTurnReport.js';
|
||||
import { enqueue, empireColonies, colonyTrade } from './VegaLogic.js';
|
||||
|
||||
// A colony's own trade minus what its existing buildings already cost to run
|
||||
// — there's no per-colony BC in this economy (only the empire-wide pool), so
|
||||
// this is the closest local stand-in for "can this colony carry one more
|
||||
// building's upkeep on its own income."
|
||||
function colonyNetIncome(rules, state, colony) {
|
||||
const upkeep = colony.buildings.reduce((s, bid) => s + (rules.buildings[bid]?.upkeep ?? 0), 0);
|
||||
return colonyTrade(rules, state, colony) - upkeep;
|
||||
}
|
||||
|
||||
const ACCENT = 0x6fc4ff;
|
||||
const ROW_BG = 0x142238;
|
||||
|
|
@ -96,6 +106,45 @@ export function openTurnReportScreen(scene, rules, state, events, onClose) {
|
|||
}
|
||||
cy += 4;
|
||||
|
||||
// A newly-researched tech that unlocks a colony building gets a
|
||||
// one-click bulk-queue offer right in the report — the whole reason
|
||||
// to interrupt the player for research news instead of leaving it in
|
||||
// the ticker log.
|
||||
if (ev.type === 'techDone') {
|
||||
for (const bu of (desc.buildingUnlocks ?? [])) {
|
||||
const label = scene.add.text(16, cy, `Build ${bu.name}:`, {
|
||||
fontFamily: FONT, fontSize: '15px', color: '#ffd88a',
|
||||
});
|
||||
col.content.add(label);
|
||||
cy += label.height + 8;
|
||||
|
||||
const status = scene.add.text(16, cy + 34, '', {
|
||||
fontFamily: FONT, fontSize: '13px', color: '#7fd8a0', wordWrap: { width: w - 32 },
|
||||
});
|
||||
|
||||
const queueAt = (colonies) => {
|
||||
let n = 0;
|
||||
for (const c of colonies) if (enqueue(rules, state, c, 'building', bu.id)) n += 1;
|
||||
status.setText(n > 0
|
||||
? `Queued at ${n} colon${n === 1 ? 'y' : 'ies'}.`
|
||||
: 'Already built or queued at every colony.');
|
||||
};
|
||||
|
||||
const allBtn = new Button(scene, 16 + 84, cy + 14, 'All Colonies', () => {
|
||||
queueAt(empireColonies(state, ev.empire));
|
||||
}, { width: 168, height: 28, fontSize: 13 });
|
||||
col.content.add(allBtn);
|
||||
|
||||
const bcBtn = new Button(scene, 16 + 168 + 16 + 105, cy + 14, 'Colonies with positive BC', () => {
|
||||
queueAt(empireColonies(state, ev.empire).filter((c) => colonyNetIncome(rules, state, c) > 0));
|
||||
}, { width: 210, height: 28, fontSize: 13 });
|
||||
col.content.add(bcBtn);
|
||||
|
||||
col.content.add(status);
|
||||
cy += 28 + 14 + status.height + 10;
|
||||
}
|
||||
}
|
||||
|
||||
// The built item's picture, right-aligned against the synopsis text
|
||||
// it sits beside. Reserving mediaW off the wrap width above (rather
|
||||
// than overlaying it) keeps long descriptions from running under it.
|
||||
|
|
|
|||
Loading…
Reference in New Issue