fix: cap city shields at build cost to prevent overflow display
When a city cannot complete a build (e.g., size < 2 for settlers), shields were accumulating past the build cost, showing confusing values like "60/40 shields" or negative turn counts. - Cap shieldBox at buildCost each turn in processCity - Clamp displayed shields to min(shieldBox, cost) in city screen - Add tests verifying shield capping and stalled build completion
This commit is contained in:
parent
325692fa35
commit
4d864503f2
|
|
@ -114,9 +114,10 @@ export function openCityScreen(scene, rules, state, city, onClose) {
|
||||||
const rx = px + 60;
|
const rx = px + 60;
|
||||||
const cost = Logic.buildCost(rules, city);
|
const cost = Logic.buildCost(rules, city);
|
||||||
const cur = city.build.type === 'unit' ? rules.units[city.build.id] : rules.buildings[city.build.id];
|
const cur = city.build.type === 'unit' ? rules.units[city.build.id] : rules.buildings[city.build.id];
|
||||||
const turns = y.shield > 0 ? Math.ceil((cost - city.shieldBox) / y.shield) : '∞';
|
const shownShields = Math.min(city.shieldBox, cost);
|
||||||
|
const turns = y.shield > 0 ? Math.max(0, Math.ceil((cost - shownShields) / y.shield)) : '∞';
|
||||||
dynamic.add(scene.add.text(rx, top + 64,
|
dynamic.add(scene.add.text(rx, top + 64,
|
||||||
`Building: ${cur.name} ${city.shieldBox}/${cost} shields (${turns} turns)`, {
|
`Building: ${cur.name} ${shownShields}/${cost} shields (${turns} turns)`, {
|
||||||
fontFamily: FONT, fontSize: '22px', color: COLORS.textHex,
|
fontFamily: FONT, fontSize: '22px', color: COLORS.textHex,
|
||||||
}));
|
}));
|
||||||
const buyPrice = Logic.buyCost(rules, city);
|
const buyPrice = Logic.buyCost(rules, city);
|
||||||
|
|
|
||||||
|
|
@ -548,8 +548,11 @@ function processCity(rules, state, city) {
|
||||||
if (city.size <= 0) { destroyCity(rules, state, city); return; }
|
if (city.size <= 0) { destroyCity(rules, state, city); return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shields.
|
// Shields. Capped at cost — a settler build stalled on city.size < 2
|
||||||
city.shieldBox += y.shield;
|
// (see completeBuild) would otherwise keep banking shields turn after
|
||||||
|
// turn with nowhere to go, showing e.g. "60/40 shields" and a negative
|
||||||
|
// turn count once shields overshot the cost.
|
||||||
|
city.shieldBox = Math.min(city.shieldBox + y.shield, buildCost(rules, city));
|
||||||
if (city.shieldBox >= buildCost(rules, city)) completeBuild(rules, state, city);
|
if (city.shieldBox >= buildCost(rules, city)) completeBuild(rules, state, city);
|
||||||
city.boughtThisTurn = false;
|
city.boughtThisTurn = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -336,6 +336,33 @@ if (RULES) {
|
||||||
check('granary keeps half box', city.foodBox >= Math.floor(((sizeBefore + 1) * Logic.FOODBOX_PER_SIZE) / 2));
|
check('granary keeps half box', city.foodBox >= Math.floor(((sizeBefore + 1) * Logic.FOODBOX_PER_SIZE) / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Settler-hold: a size-1 city building a settler must not bank shields
|
||||||
|
// past cost turn after turn while it waits for the city to spare a
|
||||||
|
// citizen (used to show e.g. "60/40 shields (-5 turns)").
|
||||||
|
{
|
||||||
|
const st = makeFlatState({ terrain: 'plains' });
|
||||||
|
const city = Logic.foundCity(RULES, st, Logic.spawnUnit(RULES, st, 0, 'settlers', 5, 5, null));
|
||||||
|
city.build = { type: 'unit', id: 'settlers' };
|
||||||
|
const cost = Logic.buildCost(RULES, city);
|
||||||
|
city.size = 1;
|
||||||
|
city.shieldBox = cost + 20; // as if it had banked well past cost over many stalled turns
|
||||||
|
city.foodBox = 0;
|
||||||
|
Logic.beginCivTurn(RULES, st, 0);
|
||||||
|
check('shieldBox re-capped at cost on a stalled turn', city.shieldBox <= cost,
|
||||||
|
`${city.shieldBox}/${cost}`);
|
||||||
|
|
||||||
|
// Once the city can spare a citizen, the stalled build completes
|
||||||
|
// immediately. foodBox=2 keeps this turn's -1 deficit (size-2 plains
|
||||||
|
// under despotism) from also triggering a famine shrink, which would
|
||||||
|
// confound the size assertion below.
|
||||||
|
const unitsBefore = st.units.length;
|
||||||
|
city.size = 2;
|
||||||
|
city.foodBox = 2;
|
||||||
|
Logic.beginCivTurn(RULES, st, 0);
|
||||||
|
check('stalled settler completes once city can spare population',
|
||||||
|
st.units.length === unitsBefore + 1 && city.size === 1 && city.shieldBox === 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Despotism penalty & government trade bonus on tile yields.
|
// Despotism penalty & government trade bonus on tile yields.
|
||||||
{
|
{
|
||||||
const st = makeFlatState({ terrain: 'plains' });
|
const st = makeFlatState({ terrain: 'plains' });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue