|
1 | 1 | (function () { |
2 | 2 | const STORAGE_KEY = "aggs-operations-state-v4"; |
| 3 | + const TRADE_V4_FORMULA_VERSION = "trade2028"; |
3 | 4 |
|
4 | 5 | const HEALTH_GROWTH = { Depression: -3, Recession: -2, Slowdown: -1, Recovery: 1, Expansion: 2, Prosperity: 3 }; |
5 | 6 | const HEALTH_DEMOGRAPHICS = { |
|
149 | 150 | return Number(number(value, 0).toFixed(2)); |
150 | 151 | } |
151 | 152 |
|
| 153 | + function budgetBalanceMigrationTarget(national = {}) { |
| 154 | + const storedBalance = number(national.budgetBalance, null); |
| 155 | + if (Number.isFinite(storedBalance)) return roundCurrency(storedBalance); |
| 156 | + return roundCurrency(number(national.budgetCapacity, 0) - number(national.budgetExpenditure, 0)); |
| 157 | + } |
| 158 | + |
| 159 | + function captureTradeV4BudgetBalanceTargets(data, previousTradeFormulaVersion) { |
| 160 | + if (previousTradeFormulaVersion === TRADE_V4_FORMULA_VERSION || data.meta.tradeV4BudgetBalanceTargets) return; |
| 161 | + const nationalRows = data.national && typeof data.national === "object" && !Array.isArray(data.national) |
| 162 | + ? data.national |
| 163 | + : {}; |
| 164 | + const targets = Object.fromEntries( |
| 165 | + Object.entries(nationalRows) |
| 166 | + .map(([id, national]) => [id, budgetBalanceMigrationTarget(national)]) |
| 167 | + .filter(([, target]) => Number.isFinite(target)) |
| 168 | + ); |
| 169 | + if (Object.keys(targets).length) data.meta.tradeV4BudgetBalanceTargets = targets; |
| 170 | + } |
| 171 | + |
152 | 172 | function ensureState(data = {}) { |
153 | 173 | data.meta = data.meta || {}; |
| 174 | + const previousTradeFormulaVersion = data.meta.tradeFormulaVersion; |
154 | 175 | data.meta.title = data.meta.title || "AG-GS Global Ledger"; |
155 | 176 | data.meta.currentYear = number(data.meta.currentYear, 2021); |
156 | 177 | data.meta.worldEconomicHealth = data.meta.worldEconomicHealth || "Expansion"; |
157 | 178 | data.meta.budgetFormulaVersion = data.meta.budgetFormulaVersion || "legacy"; |
158 | 179 | data.meta.tariffFormulaVersion = TARIFF_FORMULAS[data.meta.tariffFormulaVersion] ? data.meta.tariffFormulaVersion : "legacy"; |
159 | | - data.meta.tradeFormulaVersion = "trade2028"; |
160 | 180 | data.meta.populationFormulaVersion = POPULATION_FORMULAS[data.meta.populationFormulaVersion] ? data.meta.populationFormulaVersion : "population2026"; |
161 | 181 | delete data.meta.tradeV3Enabled; |
162 | 182 | data.meta.archivedNationIds = Array.isArray(data.meta.archivedNationIds) ? data.meta.archivedNationIds : []; |
|
170 | 190 | ["populationColumns", "equipmentCosts", "eraMultipliers", "costAdditionModifiers", "costReductionModifiers"].forEach((key) => { |
171 | 191 | data[key] = Array.isArray(data[key]) ? data[key] : []; |
172 | 192 | }); |
| 193 | + captureTradeV4BudgetBalanceTargets(data, previousTradeFormulaVersion); |
| 194 | + data.meta.tradeFormulaVersion = TRADE_V4_FORMULA_VERSION; |
173 | 195 | data.tradeNetwork = data.tradeNetwork && typeof data.tradeNetwork === "object" && !Array.isArray(data.tradeNetwork) ? data.tradeNetwork : {}; |
174 | 196 | data.tradeNetwork.targetedTariffs = data.tradeNetwork.targetedTariffs && typeof data.tradeNetwork.targetedTariffs === "object" && !Array.isArray(data.tradeNetwork.targetedTariffs) |
175 | 197 | ? data.tradeNetwork.targetedTariffs |
|
230 | 252 | return true; |
231 | 253 | } |
232 | 254 |
|
| 255 | + function hasTradeV4BudgetBalanceTargets(data) { |
| 256 | + const targets = data.meta?.tradeV4BudgetBalanceTargets; |
| 257 | + return Boolean(targets && typeof targets === "object" && !Array.isArray(targets) && Object.keys(targets).length); |
| 258 | + } |
| 259 | + |
| 260 | + function budgetMigrationSignature(data) { |
| 261 | + return Object.keys(data.national || {}) |
| 262 | + .sort() |
| 263 | + .map((id) => { |
| 264 | + const national = data.national[id] || {}; |
| 265 | + return [ |
| 266 | + id, |
| 267 | + roundCurrency(national.budgetCapacity), |
| 268 | + roundCurrency(national.budgetExpenditure), |
| 269 | + roundCurrency(national.budgetBalance) |
| 270 | + ].join(":"); |
| 271 | + }) |
| 272 | + .join("|"); |
| 273 | + } |
| 274 | + |
233 | 275 | function load(baseData) { |
234 | 276 | const saved = localStorage.getItem(STORAGE_KEY); |
235 | 277 | if (saved) { |
|
729 | 771 |
|
730 | 772 | function recalculateAll(data, options = {}) { |
731 | 773 | ensureTradeV4State(data); |
| 774 | + if (hasTradeV4BudgetBalanceTargets(data)) { |
| 775 | + const migrationOptions = { ...options, keepTradeV4BudgetBalanceTargets: true }; |
| 776 | + let previousSignature = ""; |
| 777 | + for (let attempt = 0; attempt < 6; attempt++) { |
| 778 | + recalculateTrade(data, options); |
| 779 | + recalculateBudgets(data, migrationOptions); |
| 780 | + const nextSignature = budgetMigrationSignature(data); |
| 781 | + if (attempt > 0 && nextSignature === previousSignature) break; |
| 782 | + previousSignature = nextSignature; |
| 783 | + } |
| 784 | + delete data.meta.tradeV4BudgetBalanceTargets; |
| 785 | + return data; |
| 786 | + } |
732 | 787 | recalculateTrade(data, options); |
733 | 788 | recalculateBudgets(data, options); |
734 | 789 | recalculateTrade(data, options); |
|
767 | 822 | function ensureTradeV4State(data) { |
768 | 823 | ensureState(data); |
769 | 824 | ensureTradeNetworkState(data); |
770 | | - data.meta.tradeFormulaVersion = "trade2028"; |
| 825 | + data.meta.tradeFormulaVersion = TRADE_V4_FORMULA_VERSION; |
771 | 826 | delete data.meta.tradeV3Enabled; |
772 | 827 | return data; |
773 | 828 | } |
|
0 commit comments