civ/config.js

254 lines
6.3 KiB
JavaScript
Raw Normal View History

2026-05-14 20:15:23 +09:00
const Terrain = Object.freeze({
PLAINS: 0,
FOREST: 1,
MOUNTAIN: 2,
WATER: 3,
DESERT: 4
});
const terrainInfo = [
2026-09-16 20:53:17 +09:00
{ name: "平原", color: [82, 102, 74], move: 1.0, fertility: 0.55, mineral: 0.05, regen: 0.025 },
{ name: "森林", color: [58, 91, 68], move: 1.3, fertility: 0.62, mineral: 0.08, regen: 0.038 },
{ name: "山地", color: [104, 105, 101], move: 2.6, fertility: 0.18, mineral: 0.78, regen: 0.012 },
{ name: "水域", color: [52, 78, 103], move: 7.0, fertility: 0, mineral: 0.02, regen: 0.004 },
{ name: "砂漠", color: [139, 123, 86], move: 1.55, fertility: 0.16, mineral: 0.16, regen: 0.014 }
2026-05-14 20:15:23 +09:00
];
const WEEKS_PER_MONTH = 4;
const MONTHS_PER_YEAR = 12;
const WEEKS_PER_YEAR = MONTHS_PER_YEAR * WEEKS_PER_MONTH;
const SimConfig = Object.freeze({
2026-09-16 20:53:17 +09:00
world: Object.freeze({
initialPopulation: 50000,
defaultSize: 160
}),
2026-05-14 20:15:23 +09:00
population: Object.freeze({
2026-09-16 20:53:17 +09:00
populationScale: 10,
2026-05-14 20:15:23 +09:00
carryingCapacityBase: 2.4,
carryingCapacityFertility: 7.8,
carryingCapacityMineral: 1.8,
carryingCapacityFarmland: 5.5,
2026-09-17 22:32:25 +09:00
territoryExitPopulationLossRate: 0.12,
humanDataMinPopulation: 1.0
2026-05-14 20:15:23 +09:00
}),
city: Object.freeze({
2026-09-16 20:53:17 +09:00
maxCities: 1200,
initialPopulation: 400,
abandonmentPopulation: 200,
populationScale: 10,
foodProductionScale: 10,
postShockRecoveryGrowth: 0.045,
overCapacityAttrition: 0.020,
naturalFoundingMinDistance: 6,
naturalFoundingStartYears: 160,
naturalFoundingIntervalYears: 5,
naturalFoundingReferenceArea: 160 * 160,
naturalFoundingMaxPerCycle: 8,
foundingCompetitionRadius: 9,
2026-05-14 20:15:23 +09:00
}),
render: Object.freeze({
graphThrottleMs: 1400,
statsThrottleMs: 900,
historyWindowYears: 2000,
historySamplePaddingYears: 240
}),
technology: Object.freeze({
tradeDiffusion: 0.0032,
cityInnovation: 0.00045
}),
polity: Object.freeze({
minimumPerCapitaFood: 0.06,
2026-05-16 13:48:08 +09:00
logisticsDistance: 34,
charismaMin: 0.5,
2026-05-17 21:08:03 +09:00
charismaMax: 1.5,
charismaAverage: 1.0,
leaderTenureMinYears: 22,
2026-09-16 20:53:17 +09:00
leaderTenureMaxYears: 72,
foundingProtectionYears: 12,
warCapitalDistanceStart: 18,
warCapitalDistanceScale: 42,
warDisconnectedTerritoryFactor: 0.42,
institutionalAgingAnnualIncrease: 0.0015,
institutionalReformThreshold: 0.30,
institutionalReformBaseChance: 0.008,
institutionalReformChanceScale: 0.10,
institutionalReformMaxChance: 0.12,
institutionalReformCooldownYears: 50,
institutionalReformMinChange: -0.50,
institutionalReformMaxChange: 0.30,
treasuryCapPerPopulation: 0.30,
treasuryCityFoundingChance: 0.14,
treasuryCityFoundingCostRatio: 0.35,
treasuryCityPopulationPerCost: 0.18,
treasuryCityReservePerCost: 0.45,
treasuryCityFoundingSearchRadius: 20,
treasuryCitySiteScoreWindow: 6.0
}),
territory: Object.freeze({
baseCityReach: 9,
radiusScale: 0.5,
cityPowerWeight: 1.8,
capitalReachBonus: 1.5,
ownershipSwitchMargin: 1.5,
minimumInfluence: 2.4,
fullMaintenanceCityPopulation: 2400,
minimumPopulationSupport: 0.28,
maintenancePressure: 4,
supportSmoothing: 0.18,
smallStateSwitchPenalty: 2.5
}),
rebellion: Object.freeze({
participationLoyalty: 0.50,
automaticLoyalty: 0.30,
chanceScale: 0.20,
maxAnnualChance: 0.16,
conquestGraceYears: 20,
treasuryTransferRate: 0.65
2026-05-17 21:08:03 +09:00
}),
campaign: Object.freeze({
checkIntervalYears: 3,
baseChance: 0.18,
minCooldownYears: 12,
maxCooldownYears: 45,
maxActiveCampaigns: 12,
frontierTargetChance: 0.35,
nonStateTargetChance: 0.30,
independentCityTargetChance: 0.20,
2026-09-16 20:53:17 +09:00
polityTargetChance: 0,
independentCityPeacefulShare: 0.4,
2026-05-17 21:08:03 +09:00
baseDurationYears: 8,
maxDurationYears: 25,
claimRadius: 8,
maxTargetDistance: 48
2026-05-14 20:15:23 +09:00
}),
2026-09-16 13:51:43 +09:00
nomad: Object.freeze({
enabled: true,
maxBands: 24,
enabledAfterYears: 120,
spawnCheckIntervalYears: 25,
baseSpawnChance: 0.28,
minPopulation: 80,
maxPopulation: 420,
minRadius: 5,
maxRadius: 14,
movementIntervalYears: 2,
maxMoveDistance: 9,
grazingGain: 0.035,
overgrazingDamage: 0.018,
resourceConsumption: 0.012,
herdSoftCapPerPop: 2.4,
herdHardCapPerPop: 4.0,
resourceSoftCapPerPop: 1.2,
resourceHardCapPerPop: 2.5,
grazingDiminishingPower: 1.35,
urbanAbsorptionControl: 0.55,
cityInteractionRadius: 8,
tradeChance: 0.22,
raidChance: 0.14,
invasionChance: 0.025,
confederationPopulation: 900,
confederationPrestige: 1.8,
splitPopulation: 1200,
sedentarizationChance: 0.035,
collapseCohesion: 0.12,
influenceCulturalTrace: 0.006,
influenceMobilePopulationTrace: 0.004,
visualDurationYears: 20
}),
2026-05-14 20:15:23 +09:00
polityAccess: Object.freeze({
enabled: true,
2026-05-17 21:08:03 +09:00
maxSearchDepth: 8,
indirectPenalty: 0.012,
perHopPenalty: 0.006,
noAccessPenalty: 0.045,
lowLoyaltyTransitPenalty: 0.012,
foreignTransitPenalty: 0.008
2026-05-14 20:15:23 +09:00
}),
culture: Object.freeze({
2026-09-16 20:53:17 +09:00
minimumInfluence: 0.18,
divergenceRateMultiplier: 0.25,
absorptionPopulationThreshold: 30,
urbanSpreadRadius: 5,
cityBlendRate: 0.045,
routeBlendRate: 0.035,
routeNeighborFactor: 0.35,
cityTradeBlendRate: 0.015
2026-05-14 20:15:23 +09:00
}),
route: Object.freeze({
maxRouteLength: 42,
2026-09-16 13:51:43 +09:00
adaptiveMaxRouteLength: 72,
isolatedCityBootstrap: true,
isolatedRouteSearchLimit: 8,
isolatedRouteRadius: 4,
newRoutePheromoneSeed: 2.5,
newRouteGraceBoost: 18,
isolatedRouteMinStrength: 0.12,
2026-05-14 20:15:23 +09:00
pheromoneDecay: 0.996,
pheromoneDiffusion: 0.045,
maxPheromone: 18,
routePheromoneBuild: 0.18,
routePheromoneMaintain: 0.12,
routeUpkeepPerTile: 0.018,
routeWeakThreshold: 8,
2026-09-16 13:51:43 +09:00
routeUnsupportedDecay: 3,
2026-09-16 20:53:17 +09:00
routeMaintainedBoost: 10,
manualProtectionYears: 25,
manualProtectedStrength: 32,
manualRouteMaxLength: 120,
desertTraversalCostFactor: 0.68,
desertRouteLengthBonus: 30,
desertAdaptiveMaxRouteLength: 96,
desertPheromoneThresholdFactor: 0.45,
desertConstructionCostFactor: 0.72
2026-05-14 20:15:23 +09:00
}),
2026-09-16 13:51:43 +09:00
war: Object.freeze({
2026-09-16 20:53:17 +09:00
damageMultiplier: 0.65,
tickWeeks: 4,
startChanceMultiplier: 3,
maxActiveWars: 12,
maxStartsPerTick: 4,
minDurationWeeks: 12,
idleEndWeeks: 24,
cooldownWeeks: 24,
decisiveScore: 6,
2026-09-16 13:51:43 +09:00
pressureMemoryDecay: 0.88,
2026-09-17 22:32:25 +09:00
captureChanceMultiplier: 0.50,
occupationPopulationLossRadius: 4,
occupationPopulationLossRate: 0.08,
2026-09-16 20:53:17 +09:00
cityDamageMinRate: 0.025,
cityDamageMaxRate: 0.30,
captureLossBase: 0.22,
captureLossMax: 0.40,
exhaustionPopulationLossBase: 0.003,
exhaustionPopulationLossMax: 0.03,
warZoneTileLossRate: 0.025,
2026-09-16 13:51:43 +09:00
majorSettlementThreshold: 1.25
}),
2026-05-14 20:15:23 +09:00
disaster: Object.freeze({
damageScale: 1.5,
majorLossRate: 0.05,
2026-09-17 22:32:25 +09:00
regionalPopulationLossRate: 0.42,
regionalPopulationLossMax: 0.65,
2026-05-14 20:15:23 +09:00
checkIntervalYears: 8,
baseChance: 0.76,
minRadius: 6,
maxRadius: 34,
rareLargeChance: 0.10,
largeRadiusMin: 28,
largeRadiusMax: 54,
minIntensity: 0.25,
maxIntensity: 0.95,
visualDurationYears: 18,
maxActiveVisuals: 12,
maxHistory: 160
}),
frontierWave: Object.freeze({
enabledAfterYears: 300,
intervalYears: 80,
chance: 0.45,
2026-09-16 13:51:43 +09:00
minPopulation: 60,
maxPopulation: 140,
edgeBand: 4
2026-05-14 20:15:23 +09:00
})
});
function years(value) {
return value * WEEKS_PER_YEAR;
}