feat(civ): add shield waste mechanic and AI corruption triage
- Implement "waste" as corruption's production sibling: distant cities lose shields to waste (half the corruption decay rate), halved by courthouses. - Update city yields, UI summaries, and government screen to display waste alongside corruption and support costs. - AI now builds courthouses early when combined corruption + waste loss exceeds 4 per turn, preventing distant cities from becoming useless. - Refresh building effect tooltips and palace description to reflect waste.
This commit is contained in:
parent
aee3352efe
commit
b214f6b8bd
|
|
@ -319,6 +319,13 @@ function manageCityBuild(rules, state, civIdx, city, strategy) {
|
|||
setBuild(rules, state, city, 'unit', cvType);
|
||||
return;
|
||||
}
|
||||
// Corruption triage: distant cities bleed trade to corruption and shields
|
||||
// to waste — when the combined loss is worth a building's upkeep several
|
||||
// times over, jump the chain straight to a courthouse (halves both).
|
||||
if ((yields.corruption + yields.waste) >= 4 && avail.some((b) => b.id === 'courthouse')) {
|
||||
setBuild(rules, state, city, 'building', 'courthouse');
|
||||
return;
|
||||
}
|
||||
for (const id of DEVELOP_CHAIN) {
|
||||
if (avail.some((b) => b.id === id)) {
|
||||
// Skip aqueduct/sewer until the city is close to its cap.
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export function openCityScreen(scene, rules, state, city, onClose) {
|
|||
// Yields breakdown.
|
||||
const lines = [
|
||||
`Food ${y.food} (need ${y.foodNeed}) surplus ${y.foodSurplus >= 0 ? '+' : ''}${y.foodSurplus}`,
|
||||
`Shields ${y.shield}${y.supportShields ? ` (support −${y.supportShields})` : ''}`,
|
||||
`Shields ${y.shield}${y.waste ? ` waste −${y.waste}` : ''}${y.supportShields ? ` (support −${y.supportShields})` : ''}`,
|
||||
`Trade ${y.trade} corruption −${y.corruption}${y.routeTrade ? ` routes +${y.routeTrade}` : ''}`,
|
||||
`Gold +${y.gold} · Science +${y.science} · Upkeep −${y.upkeep}`,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -380,14 +380,21 @@ export function cityYields(rules, state, city) {
|
|||
}
|
||||
|
||||
const grossShield = Math.floor(shield * shieldMult);
|
||||
const netShield = Math.max(0, grossShield - supportShields);
|
||||
// Waste — corruption's production sibling: the same capital-distance decay
|
||||
// applied to shields, at half strength (full strength would zero out
|
||||
// distant cities' build boxes entirely under Despotism). Courthouse halves
|
||||
// it, same as corruption.
|
||||
let waste = Math.floor(grossShield * gov.corruptionFactor * Math.min(1, dist / 20) * 0.5);
|
||||
if (city.buildings.courthouse) waste = Math.floor(waste * 0.5);
|
||||
waste = Math.min(waste, grossShield);
|
||||
const netShield = Math.max(0, grossShield - waste - supportShields);
|
||||
const foodNeed = city.size * FOOD_PER_CITIZEN + settlerFood;
|
||||
const upkeep = Object.keys(city.buildings)
|
||||
.reduce((sum, id) => sum + (rules.buildings[id]?.upkeep ?? 0), 0);
|
||||
|
||||
return {
|
||||
food, foodNeed, foodSurplus: food - foodNeed,
|
||||
shield: netShield, grossShield, supportShields,
|
||||
shield: netShield, grossShield, waste, supportShields,
|
||||
trade, corruption, netTrade, routeTrade,
|
||||
gold: Math.floor(baseGold * goldMult), science: Math.floor(baseScience * sciMult),
|
||||
upkeep, supportGold,
|
||||
|
|
|
|||
|
|
@ -466,12 +466,12 @@ function govBullets(g) {
|
|||
const pro = (text) => out.push({ text, pro: true });
|
||||
const con = (text) => out.push({ text, pro: false });
|
||||
if (g.noScience) con('No research — science output is zero');
|
||||
if (g.corruptionFactor === 0) pro('No corruption at all');
|
||||
if (g.corruptionFactor === 0) pro('No corruption or waste at all');
|
||||
else if (g.corruptionFactor <= 0.4) {
|
||||
pro(g.flatCorruption ? 'Low corruption, the same across the whole empire' : 'Low corruption');
|
||||
} else if (g.corruptionFactor <= 0.7) pro('Reduced corruption');
|
||||
else if (g.corruptionFactor >= 1.5) con('Crippling corruption');
|
||||
else con('Heavy corruption, worse far from the capital');
|
||||
pro(g.flatCorruption ? 'Low corruption & waste, the same across the whole empire' : 'Low corruption & waste');
|
||||
} else if (g.corruptionFactor <= 0.7) pro('Reduced corruption & waste');
|
||||
else if (g.corruptionFactor >= 1.5) con('Crippling corruption & waste');
|
||||
else con('Heavy corruption & waste, worse far from the capital');
|
||||
if (g.tradeBonus) pro(`+${g.tradeBonus} trade on tiles already producing trade`);
|
||||
if (g.despotPenalty) con('−1 food/shield/trade on tiles yielding 3 or more');
|
||||
if (g.freeUnits > 0) pro(`${g.freeUnits} free units per city, then 1 ${g.unitUpkeep}/unit each turn`);
|
||||
|
|
@ -502,12 +502,12 @@ export function openGovernmentScreen(scene, rules, state, onClose) {
|
|||
// aggregated from the same cityYields the cities themselves run on.
|
||||
const cities = Logic.civCities(state, state.humanIndex);
|
||||
const sum = {
|
||||
gross: 0, support: 0, shield: 0, trade: 0, corruption: 0, netTrade: 0,
|
||||
gross: 0, waste: 0, support: 0, shield: 0, trade: 0, corruption: 0, netTrade: 0,
|
||||
gold: 0, upkeep: 0, supportGold: 0, science: 0, pop: 0,
|
||||
};
|
||||
for (const c of cities) {
|
||||
const y = Logic.cityYields(rules, state, c);
|
||||
sum.gross += y.grossShield; sum.support += y.supportShields; sum.shield += y.shield;
|
||||
sum.gross += y.grossShield; sum.waste += y.waste; sum.support += y.supportShields; sum.shield += y.shield;
|
||||
sum.trade += y.trade; sum.corruption += y.corruption; sum.netTrade += y.netTrade;
|
||||
sum.gold += y.gold; sum.upkeep += y.upkeep; sum.supportGold += y.supportGold;
|
||||
sum.science += y.science; sum.pop += c.size;
|
||||
|
|
@ -521,7 +521,7 @@ export function openGovernmentScreen(scene, rules, state, onClose) {
|
|||
}));
|
||||
const netGold = sum.gold - sum.upkeep - sum.supportGold;
|
||||
content.add(scene.add.text(left, top + 44,
|
||||
`Production: ${sum.shield} shields/turn (${sum.gross} gross − ${sum.support} unit support) `
|
||||
`Production: ${sum.shield} shields/turn (${sum.gross} gross − ${sum.waste} waste − ${sum.support} unit support) `
|
||||
+ `Trade: ${sum.netTrade}/turn (${sum.trade} − ${sum.corruption} corruption)`, {
|
||||
fontFamily: FONT, fontSize: '19px', color: COLORS.textHex,
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const EFFECT_TEXT = {
|
|||
farmfood: (b) => `+${Math.round(b.value * 100)}% food from farmland-improved tiles worked by this city.`,
|
||||
defenseair: (b) => `Multiplies this city's defense against air attacks by ${b.value}.`,
|
||||
power: (b) => `+${Math.round(b.value * 100)}% shield output from the city's Factory (requires a Factory).`,
|
||||
corruption: (b) => `Cuts this city's corruption by ${Math.round(b.value * 100)}%.`,
|
||||
corruption: (b) => `Cuts this city's corruption and waste by ${Math.round(b.value * 100)}%.`,
|
||||
gold: (b) => `+${Math.round(b.value * 100)}% gold income from this city's trade.`,
|
||||
veterans: () => 'Units built here start as veterans, with a combat bonus.',
|
||||
sizecap: (b) => (b.id === 'sewersystem'
|
||||
|
|
@ -52,7 +52,7 @@ const EFFECT_TEXT = {
|
|||
oceanfood: (b) => `+${b.value} food from every ocean tile this city works.`,
|
||||
shields: (b) => `+${Math.round(b.value * 100)}% shield (production) output from this city.`,
|
||||
oceanshield: (b) => `+${b.value} shield from every ocean tile this city works.`,
|
||||
palace: () => 'Makes this your capital — sharply reduces corruption and stores the seat of government.',
|
||||
palace: () => 'Makes this your capital — corruption and waste grow with distance from it.',
|
||||
defensesea: (b) => `Multiplies this city's defense against naval attacks by ${b.value}.`,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue