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) {
|
showFleet(fleet) {
|
||||||
this.mode = 'fleet';
|
this.mode = 'fleet';
|
||||||
this.fleet = 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.syncSelection();
|
||||||
this.rebuild();
|
this.rebuild();
|
||||||
this.open();
|
this.open();
|
||||||
|
|
@ -507,9 +510,12 @@ export default class VegaSidePanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuild the per-stack selection, keeping whatever the player had already
|
* Rebuild the per-stack selection, keeping whatever the player had already
|
||||||
* dialled in where the stack still exists. Immobile hulls (star bases) are
|
* dialled in where the stack still exists. This carry-over only matters for
|
||||||
* excluded outright rather than shown at zero: they defend the system they
|
* refresh() (same selection, engine state changed under us); showFleet()
|
||||||
* were built in and can never be part of a move order.
|
* 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() {
|
syncSelection() {
|
||||||
const fleet = this.fleet;
|
const fleet = this.fleet;
|
||||||
|
|
|
||||||
|
|
@ -335,8 +335,10 @@ export default class VegaStarMap {
|
||||||
if (!a || !b) continue;
|
if (!a || !b) continue;
|
||||||
if (viewer && !own && !viewer.explored[fleet.toStar]) continue;
|
if (viewer && !own && !viewer.explored[fleet.toStar]) continue;
|
||||||
const t = fleet.total > 0 ? Phaser.Math.Clamp(fleet.progress / fleet.total, 0, 1) : 0;
|
const t = fleet.total > 0 ? Phaser.Math.Clamp(fleet.progress / fleet.total, 0, 1) : 0;
|
||||||
x = a.x + (b.x - a.x) * t;
|
// Offset up-left of the lane so a fleet just leaving its origin star
|
||||||
y = a.y + (b.y - a.y) * t;
|
// 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;
|
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];
|
const from = this.state.galaxy.stars[f.fromStar];
|
||||||
if (!from) return null;
|
if (!from) return null;
|
||||||
const t = f.total > 0 ? Phaser.Math.Clamp(f.progress / f.total, 0, 1) : 0;
|
const t = f.total > 0 ? Phaser.Math.Clamp(f.progress / f.total, 0, 1) : 0;
|
||||||
ax = from.x + (dest.x - from.x) * t;
|
ax = from.x + (dest.x - from.x) * t - 26;
|
||||||
ay = from.y + (dest.y - from.y) * t;
|
ay = from.y + (dest.y - from.y) * t - 22;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ax, ay, bx: dest.x, by: dest.y,
|
ax, ay, bx: dest.x, by: dest.y,
|
||||||
|
|
|
||||||
|
|
@ -103,16 +103,20 @@ function describeTechDone(rules, state, ev) {
|
||||||
if (effects.length) {
|
if (effects.length) {
|
||||||
lines.push(line(`Effects: ${effects.map(([k, v]) => `${k} ${v > 0 ? '+' : ''}${v}`).join(', ')}`, '#7fd8a0'));
|
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
|
const newTechs = gate.prereqOf
|
||||||
.filter((id) => emp.available[id] && !emp.known[id])
|
.filter((id) => emp.available[id] && !emp.known[id])
|
||||||
.map((id) => rules.techs[id]?.name)
|
.map((id) => rules.techs[id]?.name)
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const unlocks = [...newBuildings, ...newTechs];
|
const unlocks = [...newBuildingIds.map((id) => rules.buildings[id].name), ...newTechs];
|
||||||
if (unlocks.length) {
|
if (unlocks.length) {
|
||||||
lines.push(line(`Now available: ${unlocks.join(', ')}`, '#ffd88a'));
|
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) {
|
function describeBuildingDone(rules, state, ev) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,16 @@ import { buildingFrame } from './VegaArt.js';
|
||||||
import { turnToYear } from './VegaRules.js';
|
import { turnToYear } from './VegaRules.js';
|
||||||
import { Button } from '../../ui/Button.js';
|
import { Button } from '../../ui/Button.js';
|
||||||
import { describeEvent, categoryWeight } from './VegaTurnReport.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 ACCENT = 0x6fc4ff;
|
||||||
const ROW_BG = 0x142238;
|
const ROW_BG = 0x142238;
|
||||||
|
|
@ -96,6 +106,45 @@ export function openTurnReportScreen(scene, rules, state, events, onClose) {
|
||||||
}
|
}
|
||||||
cy += 4;
|
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
|
// The built item's picture, right-aligned against the synopsis text
|
||||||
// it sits beside. Reserving mediaW off the wrap width above (rather
|
// it sits beside. Reserving mediaW off the wrap width above (rather
|
||||||
// than overlaying it) keeps long descriptions from running under it.
|
// than overlaying it) keeps long descriptions from running under it.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue