From 7182d6da1ace628a048096d396c55e2cd5bc0592 Mon Sep 17 00:00:00 2001 From: Cyan Date: Fri, 15 May 2026 15:04:25 +0200 Subject: [PATCH 1/5] Extract trade route count calculation into separate function --- src/functions.js | 87 +++++++++++++++++++++++++++++++++++++++++++++++- src/main.js | 65 +++--------------------------------- 2 files changed, 91 insertions(+), 61 deletions(-) diff --git a/src/functions.js b/src/functions.js index 502a3faa2..4b978e476 100644 --- a/src/functions.js +++ b/src/functions.js @@ -1,7 +1,7 @@ import { global, save, message_logs, message_filters, webWorker, keyMultiplier, intervals, resizeGame, atrack, p_on, quantum_level, tmp_vars } from './vars.js'; import { loc } from './locale.js'; import { races, traits, genus_def, traitSkin, fathomCheck } from './races.js'; -import { actions, actionDesc } from './actions.js'; +import { actions, actionDesc, structName } from './actions.js'; import { jobScale } from './jobs.js'; import { universe_affixes } from './space.js'; import { arpaAdjustCosts, arpaProjectCosts } from './arpa.js'; @@ -13,6 +13,7 @@ import { universeLevel, universeAffix, alevel } from './achieve.js'; import { astrologySign, astroVal } from './seasons.js'; import { shipCosts, TPShipDesc } from './truepath.js'; import { mechCost, mechDesc } from './portal.js'; +import { faithTempleCount } from './resources.js'; var popperRef = false; export function popover(id,content,opts){ @@ -1756,6 +1757,90 @@ export function calcPrestige(type,inputs){ return gains; } +export function getTradeRouteCount(getBreakdown = false){ + let count = 0; + let breakdown = {}; + + if (global.race['banana']){ + count++; + if (getBreakdown) + breakdown[loc('base')] = 1; + } + + if (global.city['trade']){ + let routes = global.race['nomadic'] || global.race['xenophobic'] ? global.tech.trade : global.tech.trade + 1; + if (global.tech['trade'] && global.tech['trade'] >= 3){ + routes--; + } + if (global.race['flier']){ + routes += traits.flier.vars()[1]; + } + + const r_count = routes * global.city.trade.count; + count += r_count; + if (getBreakdown) + breakdown[loc('city_trade')] = r_count; + } + + if (global.city['trade'] && global.tech['fanaticism'] && global.tech['fanaticism'] >= 3){ + const r_count = faithTempleCount(); + count += r_count; + if (getBreakdown) + breakdown[global.race['cataclysm'] ? loc('space_red_ziggurat_title') : structName('temple')] = r_count; + } + + if (global.city['wharf']){ + const r_count = global.city.wharf.count * 2; + count += r_count; + if (getBreakdown) + breakdown[loc('city_wharf')] = r_count; + } + + if (global.space['gps'] && global.space.gps.count >= 4){ + const r_count = global.space.gps.count * 2; + count += r_count; + if (getBreakdown) + breakdown[loc('space_home_gps_title')] = r_count; + } + + if (global.city['storage_yard'] && global.tech['trade'] && global.tech['trade'] >= 3){ + const r_count = global.city.storage_yard.count; + count += r_count; + if (getBreakdown) + breakdown[loc('city_storage_yard')] = r_count; + } + + if (global.portal['bazaar'] && global.portal['spire']){ + const r_count = global.portal.bazaar.count * global.portal.spire.count; + count += r_count; + if (getBreakdown) + breakdown[loc('portal_bazaar_title')] = r_count; + } + + if (global.tech['railway']){ + let routes = 0; + if (global.race['cataclysm'] || global.race['orbit_decayed']){ + routes = global.space['gps'] ? Math.floor(global.space.gps.count / 3) : 0; + } + else if (global.race['warlord']){ + routes = 5; + } + else { + routes = global.city['storage_yard'] ? Math.floor(global.city.storage_yard.count / 6) : 0; + } + if (global.stats.achieve['banana'] && global.stats.achieve.banana.l >= 2){ + routes++; + } + + const r_count = global.tech['railway'] * routes + count += r_count; + if (getBreakdown) + breakdown[loc('arpa_projects_railway_title')] = r_count; + } + + return getBreakdown ? {count: count, breakdown: breakdown} : {count: count}; +} + export function adjustCosts(c_action, offset, wiki){ let costs = c_action.cost || {}; if ((costs['RNA'] || costs['DNA']) && global.genes['evolve']){ diff --git a/src/main.js b/src/main.js index a7f7ee0f6..c13151ad2 100644 --- a/src/main.js +++ b/src/main.js @@ -1,7 +1,7 @@ import { global, save, seededRandom, webWorker, intervals, keyMap, atrack, resizeGame, breakdown, sizeApproximation, keyMultiplier, power_generated, p_on, support_on, int_on, gal_on, spire_on, set_qlevel, quantum_level, callback_queue, active_rituals } from './vars.js'; import { loc } from './locale.js'; import { unlockAchieve, checkAchievements, drawAchieve, alevel, universeAffix, challengeIcon, unlockFeat, checkAdept } from './achieve.js'; -import { gameLoop, vBind, popover, clearPopper, flib, tagEvent, timeCheck, arpaTimeCheck, timeFormat, powerModifier, resetResBuffer, modRes, initMessageQueue, messageQueue, calc_mastery, calcPillar, darkEffect, calcQueueMax, calcRQueueMax, buildQueue, shrineBonusActive, getShrineBonus, eventActive, easterEggBind, trickOrTreatBind, powerGrid, deepClone, addATime, exceededATimeThreshold, loopTimers, calcQuantumLevel, drawPet } from './functions.js'; +import { gameLoop, vBind, popover, clearPopper, flib, tagEvent, timeCheck, arpaTimeCheck, timeFormat, powerModifier, resetResBuffer, modRes, initMessageQueue, messageQueue, calc_mastery, calcPillar, darkEffect, calcQueueMax, calcRQueueMax, buildQueue, shrineBonusActive, getShrineBonus, eventActive, easterEggBind, trickOrTreatBind, powerGrid, deepClone, addATime, exceededATimeThreshold, loopTimers, calcQuantumLevel, drawPet, getTradeRouteCount } from './functions.js'; import { races, traits, racialTrait, orbitLength, servantTrait, randomMinorTrait, biomes, planetTraits, shapeShift, fathomCheck, blubberFill, cleanRemoveTrait } from './races.js'; import { defineResources, resource_values, spatialReasoning, craftCost, plasmidBonus, faithBonus, faithTempleCount, tradeRatio, craftingRatio, crateValue, containerValue, tradeSellPrice, tradeBuyPrice, atomic_mass, supplyValue, galaxyOffers } from './resources.js'; import { defineJobs, job_desc, loadFoundry, farmerValue, jobName, jobScale, workerScale, limitCraftsmen, loadServants} from './jobs.js'; @@ -9858,65 +9858,10 @@ function midLoop(){ breakdown.c.Asphodel_Powder[loc('eden_encampment_title')] = powder+'v'; } - breakdown['t_route'] = {}; - global.city.market.mtrade = 0; - if (global.race['banana']){ - global.city.market.mtrade++; - breakdown.t_route[loc('base')] = 1; - } - if (global.city['trade']){ - let routes = global.race['nomadic'] || global.race['xenophobic'] ? global.tech.trade : global.tech.trade + 1; - if (global.tech['trade'] && global.tech['trade'] >= 3){ - routes--; - } - if (global.race['flier']){ - routes += traits.flier.vars()[1]; - } - global.city.market.mtrade += routes * global.city.trade.count; - breakdown.t_route[loc('city_trade')] = routes * global.city.trade.count; - if (global.tech['fanaticism'] && global.tech['fanaticism'] >= 3){ - let r_count = faithTempleCount(); - global.city.market.mtrade += r_count; - breakdown.t_route[global.race['cataclysm'] ? loc('space_red_ziggurat_title') : structName('temple')] = r_count; - } - } - if (global.city['wharf']){ - let r_count = global.city.wharf.count * 2; - global.city.market.mtrade += r_count; - breakdown.t_route[loc('city_wharf')] = r_count; - } - if (global.space['gps'] && global.space.gps.count >= 4){ - let r_count = global.space.gps.count * 2; - global.city.market.mtrade += global.space.gps.count * 2; - breakdown.t_route[loc('space_home_gps_title')] = r_count; - } - if (global.city['storage_yard'] && global.tech['trade'] && global.tech['trade'] >= 3){ - let r_count = global.city.storage_yard.count; - global.city.market.mtrade += r_count; - breakdown.t_route[loc('city_storage_yard')] = r_count; - } - if (global.portal['bazaar'] && global.portal['spire']){ - let r_count = global.portal.bazaar.count * global.portal.spire.count; - global.city.market.mtrade += r_count; - breakdown.t_route[loc('portal_bazaar_title')] = r_count; - } - if (global.tech['railway']){ - let routes = 0; - if (global.race['cataclysm'] || global.race['orbit_decayed']){ - routes = global.space['gps'] ? Math.floor(global.space.gps.count / 3) : 0; - } - else if (global.race['warlord']){ - routes = 5; - } - else { - routes = global.city['storage_yard'] ? Math.floor(global.city.storage_yard.count / 6) : 0; - } - if (global.stats.achieve['banana'] && global.stats.achieve.banana.l >= 2){ - routes++; - } - global.city.market.mtrade += global.tech['railway'] * routes; - breakdown.t_route[loc('arpa_projects_railway_title')] = global.tech['railway'] * routes; - } + var routes = getTradeRouteCount(true); + breakdown['t_route'] = routes.breakdown; + global.city.market.mtrade = routes.count; + if (p_on['titan_spaceport']){ let water = p_on['titan_spaceport'] * spatialReasoning(250); caps['Water'] += water; From d12dfb485a517ba68df2f98dbf549a6c15a268c5 Mon Sep 17 00:00:00 2001 From: Cyan Date: Fri, 15 May 2026 15:04:52 +0200 Subject: [PATCH 2/5] Fix nomadic not unassigning excess routes when gained --- src/races.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/races.js b/src/races.js index 20098de8d..b37817c85 100644 --- a/src/races.js +++ b/src/races.js @@ -2,7 +2,7 @@ import { global, seededRandom, save, webWorker, power_generated, keyMultiplier, import { loc } from './locale.js'; import { defineIndustry } from './industry.js'; import { setJobName, jobScale, loadFoundry } from './jobs.js'; -import { vBind, clearElement, popover, removeFromQueue, removeFromRQueue, calc_mastery, gameLoop, getEaster, getHalloween, randomKey, modRes, messageQueue } from './functions.js'; +import { vBind, clearElement, popover, removeFromQueue, removeFromRQueue, calc_mastery, gameLoop, getEaster, getHalloween, randomKey, modRes, messageQueue, getTradeRouteCount } from './functions.js'; import { setResourceName, drawResourceTab, atomic_mass } from './resources.js'; import { buildGarrison, govEffect, govTitle, armyRating, govCivics } from './civics.js'; import { govActive, removeTask, defineGovernor } from './governor.js'; @@ -7321,6 +7321,29 @@ export function cleanAddTrait(trait){ } calc_mastery(true); break; + case 'nomadic': + const routes = Object.keys(global.resource) + .filter(res => !isNaN(global.resource[res].trade) && global.resource[res].trade != 0) + + const usedRoutes = routes.map(res => global.resource[res].trade) + .reduce((val, agg) => Math.abs(val) + agg); + + const maxRoutes = getTradeRouteCount().count; + let lostRoutes = usedRoutes - maxRoutes; + + let ix = 0; + while (lostRoutes > 0) { + const res = routes[ix]; + const cnt = Math.min(Math.abs(global.resource[res].trade), lostRoutes); + if (global.resource[res].trade > 0) + global.resource[res].trade -= cnt; + else + global.resource[res].trade += cnt; + + lostRoutes -= cnt; + ix++; + } + break; default: break; } From 95769be46ba0e11e880d595db5c1cec0ba1652b8 Mon Sep 17 00:00:00 2001 From: Cyan Date: Fri, 15 May 2026 15:32:56 +0200 Subject: [PATCH 3/5] Code clarity --- src/functions.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/functions.js b/src/functions.js index 4b978e476..600bba234 100644 --- a/src/functions.js +++ b/src/functions.js @@ -1768,13 +1768,13 @@ export function getTradeRouteCount(getBreakdown = false){ } if (global.city['trade']){ - let routes = global.race['nomadic'] || global.race['xenophobic'] ? global.tech.trade : global.tech.trade + 1; - if (global.tech['trade'] && global.tech['trade'] >= 3){ + let routes = 2; + if (global.tech.trade >= 2) //Diplomacy + routes++; + if (global.race['nomadic'] || global.race['xenophobic']) routes--; - } - if (global.race['flier']){ + if (global.race['flier']) routes += traits.flier.vars()[1]; - } const r_count = routes * global.city.trade.count; count += r_count; From 4e5e3f473cb471edda6e71b24d4094b909eb6cad Mon Sep 17 00:00:00 2001 From: Cyan Date: Mon, 18 May 2026 09:32:32 +0200 Subject: [PATCH 4/5] Additionally fix flier and xenophobic --- src/races.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/races.js b/src/races.js index b37817c85..71671f48f 100644 --- a/src/races.js +++ b/src/races.js @@ -7322,6 +7322,7 @@ export function cleanAddTrait(trait){ calc_mastery(true); break; case 'nomadic': + case 'xenophobic': const routes = Object.keys(global.resource) .filter(res => !isNaN(global.resource[res].trade) && global.resource[res].trade != 0) @@ -7429,6 +7430,28 @@ export function cleanRemoveTrait(trait,rank){ global.resource.Cement.display = true; global.civic.cement_worker.display = true; } + + const routes = Object.keys(global.resource) + .filter(res => !isNaN(global.resource[res].trade) && global.resource[res].trade != 0) + + const usedRoutes = routes.map(res => global.resource[res].trade) + .reduce((val, agg) => Math.abs(val) + agg); + + const maxRoutes = getTradeRouteCount().count; + let lostRoutes = usedRoutes - maxRoutes; + + let ix = 0; + while (lostRoutes > 0) { + const res = routes[ix]; + const cnt = Math.min(Math.abs(global.resource[res].trade), lostRoutes); + if (global.resource[res].trade > 0) + global.resource[res].trade -= cnt; + else + global.resource[res].trade += cnt; + + lostRoutes -= cnt; + ix++; + } break; case 'sappy': setResourceName('Stone'); From 4302b668acc9a49534b03330755d62b96f23f53d Mon Sep 17 00:00:00 2001 From: Cyan Date: Mon, 18 May 2026 10:32:33 +0200 Subject: [PATCH 5/5] Bugfix --- src/races.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/races.js b/src/races.js index 71671f48f..b0ec5cfc1 100644 --- a/src/races.js +++ b/src/races.js @@ -7327,7 +7327,7 @@ export function cleanAddTrait(trait){ .filter(res => !isNaN(global.resource[res].trade) && global.resource[res].trade != 0) const usedRoutes = routes.map(res => global.resource[res].trade) - .reduce((val, agg) => Math.abs(val) + agg); + .reduce((agg, val) => agg + Math.abs(val), 0); const maxRoutes = getTradeRouteCount().count; let lostRoutes = usedRoutes - maxRoutes; @@ -7435,9 +7435,9 @@ export function cleanRemoveTrait(trait,rank){ .filter(res => !isNaN(global.resource[res].trade) && global.resource[res].trade != 0) const usedRoutes = routes.map(res => global.resource[res].trade) - .reduce((val, agg) => Math.abs(val) + agg); + .reduce((agg, val) => agg + Math.abs(val), 0); - const maxRoutes = getTradeRouteCount().count; + const maxRoutes = getTradeRouteCount().count; let lostRoutes = usedRoutes - maxRoutes; let ix = 0;