mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-08 23:08:35 +07:00
Split off properties of era's to another JSON file (#4336)
* Added Era.json and imported the data to the ruleset * Units at start are now also determined by eras.json * Research agreement costs now determined by json file * Gold and Culture provided at the start are now awarded * Can no longer build wonders that are more than two eras older than the starting era * Default population and buildings for settlers can now be added * Added checks for validity of eras.json file in mods * Colors for the icons of technologies are no also saved in eras.json * Removed constants for all era's as they have been generalized away by this PR * Removed spurios println's * Added compatibility for mods * Updated the military unit you get from ruines to be the military unit you received at the start of the game
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
"policyCostModifier": 0.5,
|
||||
"unhappinessModifier": 0.4,
|
||||
"barbarianBonus": 0.75,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [], // Note that the units from Eras.json are added to this pool. This should only contain bonus starting units.
|
||||
"aiCityGrowthModifier": 1.6, // that is to say it'll take them 1.6 times as long to grow the city
|
||||
"aiUnitCostModifier": 1.75,
|
||||
"aiBuildingCostModifier": 1.6,
|
||||
@ -17,8 +17,8 @@
|
||||
"aiBuildingMaintenanceModifier": 1,
|
||||
"aiUnitMaintenanceModifier": 1,
|
||||
"aiFreeTechs": [],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": [],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 1,
|
||||
"aisExchangeTechs": false,
|
||||
"turnBarbariansCanEnterPlayerTiles": 10000,
|
||||
@ -34,7 +34,7 @@
|
||||
"policyCostModifier": 0.67,
|
||||
"unhappinessModifier": 0.6,
|
||||
"barbarianBonus": 0.5,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 1.3,
|
||||
"aiUnitCostModifier": 1.3,
|
||||
"aiBuildingCostModifier": 1.3,
|
||||
@ -42,8 +42,8 @@
|
||||
"aiBuildingMaintenanceModifier": 1,
|
||||
"aiUnitMaintenanceModifier": 1,
|
||||
"aiFreeTechs": [],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": [],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 1,
|
||||
"aisExchangeTechs": false,
|
||||
"turnBarbariansCanEnterPlayerTiles": 60,
|
||||
@ -59,7 +59,7 @@
|
||||
"policyCostModifier": 0.85,
|
||||
"unhappinessModifier": 0.75,
|
||||
"barbarianBonus": 0.4,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 1.1,
|
||||
"aiUnitCostModifier": 1.1,
|
||||
"aiBuildingCostModifier": 1.1,
|
||||
@ -67,8 +67,8 @@
|
||||
"aiBuildingMaintenanceModifier": 1,
|
||||
"aiUnitMaintenanceModifier": 1,
|
||||
"aiFreeTechs": [],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": [],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 1,
|
||||
"aisExchangeTechs": false,
|
||||
"turnBarbariansCanEnterPlayerTiles": 20,
|
||||
@ -84,7 +84,7 @@
|
||||
"policyCostModifier": 1,
|
||||
"unhappinessModifier": 1,
|
||||
"barbarianBonus": 0.33,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 1,
|
||||
"aiUnitCostModifier": 1,
|
||||
"aiBuildingCostModifier": 1,
|
||||
@ -92,8 +92,8 @@
|
||||
"aiBuildingMaintenanceModifier": 1,
|
||||
"aiUnitMaintenanceModifier": 0.85,
|
||||
"aiFreeTechs": [],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": [],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 1,
|
||||
"aisExchangeTechs": true,
|
||||
"turnBarbariansCanEnterPlayerTiles": 0,
|
||||
@ -109,7 +109,7 @@
|
||||
"policyCostModifier": 1,
|
||||
"unhappinessModifier": 1,
|
||||
"barbarianBonus": 0.25,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 0.9,
|
||||
"aiUnitCostModifier": 0.85,
|
||||
"aiBuildingCostModifier": 0.85,
|
||||
@ -117,8 +117,8 @@
|
||||
"aiBuildingMaintenanceModifier": 0.85,
|
||||
"aiUnitMaintenanceModifier": 0.8,
|
||||
"aiFreeTechs": ["Pottery"],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior", "Warrior"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": ["Era Starting Unit"],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 0.9,
|
||||
"aisExchangeTechs": true,
|
||||
"turnBarbariansCanEnterPlayerTiles": 0,
|
||||
@ -134,7 +134,7 @@
|
||||
"policyCostModifier": 1,
|
||||
"unhappinessModifier": 1,
|
||||
"barbarianBonus": 0.2,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 0.85,
|
||||
"aiUnitCostModifier": 0.8,
|
||||
"aiBuildingCostModifier": 0.8,
|
||||
@ -142,8 +142,8 @@
|
||||
"aiBuildingMaintenanceModifier": 0.8,
|
||||
"aiUnitMaintenanceModifier": 0.75,
|
||||
"aiFreeTechs": ["Pottery","Animal Husbandry"],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior", "Warrior", "Scout"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": ["Era Starting Unit", "Scout"],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 0.85,
|
||||
"aisExchangeTechs": true,
|
||||
"turnBarbariansCanEnterPlayerTiles": 0,
|
||||
@ -159,7 +159,7 @@
|
||||
"policyCostModifier": 1,
|
||||
"unhappinessModifier": 1,
|
||||
"barbarianBonus": 0.1,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 0.75,
|
||||
"aiUnitCostModifier": 0.65,
|
||||
"aiBuildingCostModifier": 0.65,
|
||||
@ -167,8 +167,8 @@
|
||||
"aiBuildingMaintenanceModifier": 0.65,
|
||||
"aiUnitMaintenanceModifier": 0.65,
|
||||
"aiFreeTechs": ["Pottery","Animal Husbandry","Mining"],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior", "Warrior", "Warrior", "Worker", "Scout"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": ["Era Starting Unit", "Era Starting Unit", "Worker", "Scout"],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 0.75,
|
||||
"aisExchangeTechs": true,
|
||||
"turnBarbariansCanEnterPlayerTiles": 0,
|
||||
@ -184,7 +184,7 @@
|
||||
"policyCostModifier": 1,
|
||||
"unhappinessModifier": 1,
|
||||
"barbarianBonus": 0,
|
||||
"startingUnits": ["Settler", "Warrior"],
|
||||
"playerBonusStartingUnits": [],
|
||||
"aiCityGrowthModifier": 0.6,
|
||||
"aiUnitCostModifier": 0.5,
|
||||
"aiBuildingCostModifier": 0.5,
|
||||
@ -192,8 +192,8 @@
|
||||
"aiBuildingMaintenanceModifier": 0.5,
|
||||
"aiUnitMaintenanceModifier": 0.5,
|
||||
"aiFreeTechs": ["Pottery","Animal Husbandry","Mining","The Wheel"],
|
||||
"aiMajorCivStartingUnits": ["Settler", "Warrior", "Settler", "Warrior", "Warrior", "Worker", "Worker", "Scout"],
|
||||
"aiCityStateStartingUnits": ["Settler", "Warrior"],
|
||||
"aiMajorCivBonusStartingUnits": ["Settler", "Era Starting Unit", "Era Starting Unit", "Era Starting Unit", "Worker", "Scout"],
|
||||
"aiCityStateBonusStartingUnits": [],
|
||||
"aiUnhappinessModifier": 0.6,
|
||||
"aisExchangeTechs": true,
|
||||
"turnBarbariansCanEnterPlayerTiles": 0,
|
||||
|
150
android/assets/jsons/Civ V - Vanilla/Eras.json
Normal file
150
android/assets/jsons/Civ V - Vanilla/Eras.json
Normal file
@ -0,0 +1,150 @@
|
||||
[
|
||||
// Source: the fandom, so take these with a grain of salt
|
||||
// I also did some testing in the official version, but by far not all
|
||||
|
||||
{
|
||||
"name": "Ancient era",
|
||||
"researchAgreementCost": 150,
|
||||
"startingSettlerCount": 1, // These values should not include the values given in Difficulties.json
|
||||
"startingWorkerCount": 0,
|
||||
"startingMilitaryUnitCount": 1,
|
||||
"startingMilitaryUnit": "Warrior",
|
||||
"settlerPopulation": 1,
|
||||
"iconRGB": [255, 87, 35]
|
||||
},
|
||||
{
|
||||
"name": "Classical era",
|
||||
"researchAgreementCost": 150,
|
||||
"startingSettlerCount": 1,
|
||||
"startingWorkerCount": 0,
|
||||
"startingMilitaryUnitCount": 2,
|
||||
"startingMilitaryUnit": "Spearman",
|
||||
"startingGold": 10,
|
||||
"startingCulture": 100,
|
||||
"settlerPopulation": 1,
|
||||
"iconRGB": [233, 31, 99]
|
||||
},
|
||||
{
|
||||
"name": "Medieval era",
|
||||
"researchAgreementCost": 250,
|
||||
"startingSettlerCount": 2,
|
||||
"startingWorkerCount": 1,
|
||||
"startingMilitaryUnitCount": 3,
|
||||
"startingMilitaryUnit": "Spearman",
|
||||
"startingGold": 25,
|
||||
"startingCulture": 200,
|
||||
"settlerPopulation": 1,
|
||||
"settlerBuildings": ["Shrine","Monument"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus"],
|
||||
"iconRGB": [157, 39, 176]
|
||||
},
|
||||
{
|
||||
"name": "Renaissance era",
|
||||
"researchAgreementCost": 250,
|
||||
"startingSettlerCount": 2,
|
||||
"startingWorkerCount": 1,
|
||||
"startingMilitaryUnitCount": 3,
|
||||
"startingMilitaryUnit": "Pikeman",
|
||||
"startingGold": 50,
|
||||
"startingCulture": 300,
|
||||
"settlerPopulation": 2,
|
||||
"settlerBuildings": ["Shrine","Monument","Granary","Lighthouse"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus"],
|
||||
"iconRGB": [104, 58, 183]
|
||||
},
|
||||
{
|
||||
"name": "Industrial era",
|
||||
"researchAgreementCost": 300,
|
||||
"startingSettlerCount": 3,
|
||||
"startingWorkerCount": 2,
|
||||
"startingMilitaryUnitCount": 5,
|
||||
"startingMilitaryUnit": "Musketman",
|
||||
"startingGold": 100,
|
||||
"startingCulture": 400,
|
||||
"settlerPopulation": 3,
|
||||
"settlerBuildings": ["Monument","Granary","Lighthouse","Market","Workshop","Amphitheater","Barracks","Library","Colosseum"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame"],
|
||||
"iconRGB": [63, 81, 182]
|
||||
},
|
||||
{
|
||||
"name": "Modern era",
|
||||
"researchAgreementCost": 350,
|
||||
"startingSettlerCount": 3,
|
||||
"startingWorkerCount": 2,
|
||||
"startingMilitaryUnitCount": 5,
|
||||
"startingMilitaryUnit": "Rifleman",
|
||||
"startingGold": 200,
|
||||
"startingCulture": 500,
|
||||
"settlerPopulation": 3,
|
||||
"settlerBuildings": ["Monument","Granary","Lighthouse","Market","Workshop","Amphitheater","Barracks","Library","Colosseum"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame",
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin"],
|
||||
"iconRGB": [33, 150, 243]
|
||||
},
|
||||
{
|
||||
"name": "Atomic era",
|
||||
"researchAgreementCost": 400,
|
||||
"startingSettlerCount": 3,
|
||||
"startingWorkerCount": 2,
|
||||
"startingMilitaryUnitCount": 5,
|
||||
"startingMilitaryUnit": "Infantry",
|
||||
"startingGold": 200,
|
||||
"startingCulture": 500,
|
||||
"settlerPopulation": 4,
|
||||
"settlerBuildings": ["Monument","Granary","Lighthouse","Market","Workshop","Amphitheater","Barracks","Library","Colosseum"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame",
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin",
|
||||
"The Louvre", "Big Ben", "Brandenburg Gate"],
|
||||
"iconRGB": [0, 150, 136]
|
||||
},
|
||||
{
|
||||
"name": "Information era",
|
||||
"researchAgreementCost": 400,
|
||||
"startingSettlerCount": 3,
|
||||
"startingWorkerCount": 3,
|
||||
"startingMilitaryUnitCount": 5,
|
||||
"startingMilitaryUnit": "Marine",
|
||||
"startingGold": 400,
|
||||
"startingCulture": 600,
|
||||
"settlerPopulation": 5,
|
||||
"settlerBuildings": ["Monument","Granary","Lighthouse","Market","Workshop","Amphitheater","Barracks","Library","Colosseum","Theatre","Bank"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame",
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin",
|
||||
"The Louvre", "Big Ben", "Brandenburg Gate",
|
||||
"Eiffel Tower", "Statue of Liberty", "Neuschwanstein", "Cristo Redentor"],
|
||||
// So theoretically this is always just all the wonders at least 2 eras old. So we could just use that.
|
||||
// But where is the modularity? The excluding of very specific wonders? That is no fun.
|
||||
// So we just write down the entire long list (sorted by era!) instead.
|
||||
"iconRGB": [76, 176, 81]
|
||||
},
|
||||
{ // Technically, this Era doesn't exist in the original game.
|
||||
// But as it is _really_ usefull to have for testing, I'd like to keep it.
|
||||
// The stats are just copy-pasted from the information era.
|
||||
"name": "Future era",
|
||||
"researchAgreementCost": 400,
|
||||
"startingSettlerCount": 3,
|
||||
"startingWorkerCount": 3,
|
||||
"startingMilitaryUnitCount": 5,
|
||||
"startingMilitaryUnit": "Marine",
|
||||
"startingGold": 400,
|
||||
"startingCulture": 600,
|
||||
"settlerPopulation": 5,
|
||||
"settlerBuildings": ["Monument","Granary","Lighthouse","Market","Workshop","Amphitheater","Barracks","Library","Colosseum","Theatre","Bank"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame",
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin",
|
||||
"The Louvre", "Big Ben", "Brandenburg Gate",
|
||||
"Eiffel Tower", "Statue of Liberty", "Neuschwanstein", "Cristo Redentor"],
|
||||
"iconRGB": [76, 176, 81]
|
||||
}
|
||||
]
|
@ -8,6 +8,7 @@ object Constants {
|
||||
//
|
||||
const val settler = "Settler"
|
||||
const val settlerUnique = "Founds a new city"
|
||||
const val eraSpecificUnit = "Era Starting Unit"
|
||||
|
||||
const val impassable = "Impassable"
|
||||
const val ocean = "Ocean"
|
||||
@ -71,14 +72,6 @@ object Constants {
|
||||
const val disabled = "disabled"
|
||||
const val enabled = "enabled"
|
||||
|
||||
const val ancientEra = "Ancient era"
|
||||
const val classicalEra = "Classical era"
|
||||
const val medievalEra = "Medieval era"
|
||||
const val renaissanceEra = "Renaissance era"
|
||||
const val industrialEra = "Industrial era"
|
||||
const val modernEra = "Modern era"
|
||||
const val informationEra = "Information era"
|
||||
const val futureEra = "Future era"
|
||||
const val barbarians = "Barbarians"
|
||||
const val spectator = "Spectator"
|
||||
const val custom = "Custom"
|
||||
|
@ -8,10 +8,12 @@ import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.map.TileMap
|
||||
import com.unciv.logic.map.mapgenerator.MapGenerator
|
||||
import com.unciv.models.metadata.GameParameters
|
||||
import com.unciv.models.ruleset.Era
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.ui.newgamescreen.GameSetupInfo
|
||||
import java.util.*
|
||||
import kotlin.NoSuchElementException
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.max
|
||||
|
||||
@ -53,6 +55,8 @@ object GameStarter {
|
||||
|
||||
addCivTechs(gameInfo, ruleset, gameSetupInfo)
|
||||
|
||||
addCivStats(gameInfo)
|
||||
|
||||
// and only now do we add units for everyone, because otherwise both the gameInfo.setTransients() and the placeUnit will both add the unit to the civ's unit list!
|
||||
addCivStartingUnits(gameInfo)
|
||||
|
||||
@ -111,6 +115,21 @@ object GameStarter {
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCivStats(gameInfo: GameInfo) {
|
||||
val ruleSet = gameInfo.ruleSet
|
||||
val startingEra = gameInfo.gameParameters.startingEra
|
||||
val era =
|
||||
if (startingEra in ruleSet.eras.keys) {
|
||||
ruleSet.eras[startingEra]!!
|
||||
} else {
|
||||
Era()
|
||||
}
|
||||
for (civInfo in gameInfo.civilizations.filter { !it.isBarbarian() }) {
|
||||
civInfo.addGold((era.startingGold * gameInfo.gameParameters.gameSpeed.modifier).toInt())
|
||||
civInfo.policies.addCulture((era.startingCulture * gameInfo.gameParameters.gameSpeed.modifier).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCivilizations(newGameParameters: GameParameters, gameInfo: GameInfo, ruleset: Ruleset) {
|
||||
val availableCivNames = Stack<String>()
|
||||
// CityState or Spectator civs are not available for Random pick
|
||||
@ -161,15 +180,7 @@ object GameStarter {
|
||||
gameInfo.civilizations.filter { !it.isBarbarian() },
|
||||
gameInfo.tileMap)
|
||||
|
||||
// For later starting eras, or for civs like Polynesia with a different Warrior, we need different starting units
|
||||
fun getWarriorEquivalent(civ: CivilizationInfo): String? {
|
||||
val availableMilitaryUnits = gameInfo.ruleSet.units.values.filter {
|
||||
it.isBuildable(civ)
|
||||
&& it.unitType.isLandUnit()
|
||||
&& !it.unitType.isCivilian()
|
||||
}
|
||||
return availableMilitaryUnits.maxByOrNull { max(it.strength, it.rangedStrength) }?.name
|
||||
}
|
||||
|
||||
// no starting units for Barbarians and Spectators
|
||||
for (civ in gameInfo.civilizations.filter { !it.isBarbarian() && !it.isSpectator() }) {
|
||||
val startingLocation = startingLocations[civ]!!
|
||||
@ -181,15 +192,75 @@ object GameStarter {
|
||||
civ.placeUnitNearTile(startingLocation.position, unitName)
|
||||
}
|
||||
|
||||
val warriorEquivalent = getWarriorEquivalent(civ)
|
||||
val startingUnits = when {
|
||||
civ.isPlayerCivilization() -> gameInfo.getDifficulty().startingUnits
|
||||
civ.isMajorCiv() -> gameInfo.getDifficulty().aiMajorCivStartingUnits
|
||||
else -> gameInfo.getDifficulty().aiCityStateStartingUnits
|
||||
|
||||
// Determine starting units based on starting era
|
||||
val ruleSet = gameInfo.ruleSet
|
||||
val startingEra = gameInfo.gameParameters.startingEra
|
||||
var startingUnits: MutableList<String>
|
||||
var eraUnitReplacement: String
|
||||
|
||||
if (ruleSet.eras.isEmpty()) { // We are using an older mod, so we only look at the difficulty file
|
||||
startingUnits = (when {
|
||||
civ.isPlayerCivilization() -> gameInfo.getDifficulty().startingUnits
|
||||
civ.isMajorCiv() -> gameInfo.getDifficulty().aiMajorCivStartingUnits
|
||||
else -> gameInfo.getDifficulty().aiCityStateStartingUnits
|
||||
}).toMutableList()
|
||||
|
||||
val warriorEquivalent = ruleSet.units
|
||||
.filter { it.value.unitType.isLandUnit() && it.value.unitType.isMilitary() && it.value.isBuildable(civ) }
|
||||
.maxByOrNull {max(it.value.strength, it.value.rangedStrength)}
|
||||
?.key
|
||||
|
||||
for (unit in startingUnits) {
|
||||
val unitToAdd = if (unit == "Warrior") warriorEquivalent else unit
|
||||
if (unitToAdd != null) placeNearStartingPosition(unitToAdd)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
if (startingEra in ruleSet.eras.keys) {
|
||||
startingUnits = ruleSet.eras[startingEra]!!.getStartingUnits().toMutableList()
|
||||
eraUnitReplacement = ruleSet.eras[startingEra]!!.startingMilitaryUnit
|
||||
} else {
|
||||
startingUnits = Era().getStartingUnits().toMutableList()
|
||||
eraUnitReplacement = Era().startingMilitaryUnit
|
||||
}
|
||||
|
||||
// Add extra units granted by difficulty
|
||||
startingUnits.addAll(when {
|
||||
civ.isPlayerCivilization() -> gameInfo.getDifficulty().playerBonusStartingUnits
|
||||
civ.isMajorCiv() -> gameInfo.getDifficulty().aiMajorCivBonusStartingUnits
|
||||
else -> gameInfo.getDifficulty().aiCityStateBonusStartingUnits
|
||||
})
|
||||
|
||||
fun getEquivalentUnit(civ: CivilizationInfo, unitParam: String): String? {
|
||||
var unit = unitParam // We want to change it and this is the easiest way to do so
|
||||
if (unit == Constants.eraSpecificUnit) unit = eraUnitReplacement
|
||||
if (unit == "Settler" && "Settler" !in ruleSet.units) {
|
||||
val settlerLikeUnits = ruleSet.units.filter {
|
||||
it.value.uniqueObjects.any { it.placeholderText == Constants.settlerUnique }
|
||||
&& it.value.isBuildable(civ)
|
||||
&& it.value.unitType.isCivilian()
|
||||
}
|
||||
if (settlerLikeUnits.isEmpty()) return null // No settlers in this mod
|
||||
return civ.getEquivalentUnit(settlerLikeUnits.keys.random()).name
|
||||
}
|
||||
if (unit == "Worker" && "Worker" !in ruleSet.units) {
|
||||
val workerLikeUnits = ruleSet.units.filter {
|
||||
it.value.uniqueObjects.any { it.placeholderText == Constants.canBuildImprovements }
|
||||
&& it.value.isBuildable(civ)
|
||||
&& it.value.unitType.isCivilian()
|
||||
}
|
||||
if (workerLikeUnits.isEmpty()) return null // No workers in this mod
|
||||
return civ.getEquivalentUnit(workerLikeUnits.keys.random()).name
|
||||
}
|
||||
return civ.getEquivalentUnit(unit).name
|
||||
}
|
||||
|
||||
for (unit in startingUnits) {
|
||||
val unitToAdd = if (unit == "Warrior") warriorEquivalent else unit
|
||||
val unitToAdd = getEquivalentUnit(civ, unit)
|
||||
if (unitToAdd != null) placeNearStartingPosition(unitToAdd)
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,18 @@ class CityInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Add buildings and pop we get from starting in this era
|
||||
val ruleset = civInfo.gameInfo.ruleSet
|
||||
val startingEra = civInfo.gameInfo.gameParameters.startingEra
|
||||
if (startingEra in ruleset.eras) {
|
||||
population.setPopulation(ruleset.eras[startingEra]!!.settlerPopulation)
|
||||
for (building in ruleset.eras[startingEra]!!.settlerBuildings) {
|
||||
if (ruleset.buildings[building]!!.isBuildable(cityConstructions)) {
|
||||
cityConstructions.addBuilding(building)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expansion.reset()
|
||||
|
||||
|
||||
|
@ -717,14 +717,8 @@ class CivilizationInfo {
|
||||
|
||||
fun getResearchAgreementCost(): Int {
|
||||
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
|
||||
val basicGoldCostOfSignResearchAgreement = when (getEra()) {
|
||||
Constants.medievalEra, Constants.renaissanceEra -> 250
|
||||
Constants.industrialEra -> 300
|
||||
Constants.modernEra -> 350
|
||||
Constants.informationEra, Constants.futureEra -> 400
|
||||
else -> 0
|
||||
}
|
||||
return (basicGoldCostOfSignResearchAgreement * gameInfo.gameParameters.gameSpeed.modifier).toInt()
|
||||
val era = if (getEra() in gameInfo.ruleSet.eras) gameInfo.ruleSet.eras[getEra()]!! else Era()
|
||||
return (era.researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier).toInt()
|
||||
}
|
||||
|
||||
fun gainMilitaryUnitFromCityState(otherCiv: CivilizationInfo) {
|
||||
|
@ -749,15 +749,15 @@ class MapUnit {
|
||||
)
|
||||
}
|
||||
|
||||
val researchableAncientEraTechs = tile.tileMap.gameInfo.ruleSet.technologies.values
|
||||
val researchableFirstEraTechs = tile.tileMap.gameInfo.ruleSet.technologies.values
|
||||
.filter {
|
||||
!civInfo.tech.isResearched(it.name)
|
||||
&& civInfo.tech.canBeResearched(it.name)
|
||||
&& it.era() == Constants.ancientEra
|
||||
&& civInfo.gameInfo.ruleSet.getEraNumber(it.era()) == 1
|
||||
}
|
||||
if (researchableAncientEraTechs.isNotEmpty())
|
||||
if (researchableFirstEraTechs.isNotEmpty())
|
||||
actions.add {
|
||||
val tech = researchableAncientEraTechs.random(tileBasedRandom).name
|
||||
val tech = researchableFirstEraTechs.random(tileBasedRandom).name
|
||||
civInfo.tech.addTechnology(tech)
|
||||
civInfo.addNotification(
|
||||
"We have discovered the lost technology of [$tech] in the ruins!",
|
||||
@ -767,10 +767,13 @@ class MapUnit {
|
||||
)
|
||||
}
|
||||
|
||||
val militaryUnit =
|
||||
if (civInfo.gameInfo.gameParameters.startingEra !in civInfo.gameInfo.ruleSet.eras) "Warrior"
|
||||
else civInfo.gameInfo.ruleSet.eras[civInfo.gameInfo.gameParameters.startingEra]!!.startingMilitaryUnit
|
||||
val possibleUnits = (
|
||||
//City-States and OCC don't get settler from ruins
|
||||
listOf(Constants.settler).filterNot { civInfo.isCityState() || civInfo.isOneCityChallenger() }
|
||||
+ listOf(Constants.worker, "Warrior")
|
||||
+ listOf(Constants.worker, militaryUnit)
|
||||
).filter { civInfo.gameInfo.ruleSet.units.containsKey(it) }
|
||||
if (possibleUnits.isNotEmpty())
|
||||
actions.add {
|
||||
|
@ -24,7 +24,7 @@ class GameParameters { // Default values are the default new game
|
||||
var religionEnabled = false
|
||||
|
||||
var victoryTypes: ArrayList<VictoryType> = arrayListOf(VictoryType.Cultural, VictoryType.Domination, VictoryType.Scientific) // By default, all victory types
|
||||
var startingEra = Constants.ancientEra
|
||||
var startingEra = "Ancient Era"
|
||||
|
||||
var isOnlineMultiplayer = false
|
||||
var baseRuleset: BaseRuleset = BaseRuleset.Civ_V_Vanilla
|
||||
|
@ -309,6 +309,11 @@ class Building : NamedStats(), IConstruction {
|
||||
|
||||
if (civInfo.isCityState())
|
||||
return "No world wonders for city-states"
|
||||
|
||||
val ruleSet = civInfo.gameInfo.ruleSet
|
||||
val startingEra = civInfo.gameInfo.gameParameters.startingEra
|
||||
if (startingEra in ruleSet.eras && name in ruleSet.eras[startingEra]!!.startingObsoleteWonders)
|
||||
return "Wonder is disabled when starting in this era"
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,7 +14,8 @@ class Difficulty: INamed {
|
||||
var policyCostModifier:Float = 1f
|
||||
var unhappinessModifier:Float = 1f
|
||||
var barbarianBonus:Float = 0f
|
||||
var startingUnits = ArrayList<String>()
|
||||
var startingUnits = ArrayList<String>() // Deprecated since 3.15.8
|
||||
var playerBonusStartingUnits = ArrayList<String>()
|
||||
|
||||
var aiCityGrowthModifier:Float = 1f
|
||||
var aiUnitCostModifier:Float = 1f
|
||||
@ -23,22 +24,14 @@ class Difficulty: INamed {
|
||||
var aiBuildingMaintenanceModifier:Float = 1f
|
||||
var aiUnitMaintenanceModifier = 1f
|
||||
var aiFreeTechs = ArrayList<String>()
|
||||
var aiMajorCivStartingUnits = ArrayList<String>()
|
||||
var aiCityStateStartingUnits = ArrayList<String>()
|
||||
var aiMajorCivStartingUnits = ArrayList<String>() // Deprecated since 3.15.8
|
||||
var aiMajorCivBonusStartingUnits = ArrayList<String>()
|
||||
var aiCityStateStartingUnits = ArrayList<String>() // Deprecated since 3.15.8
|
||||
var aiCityStateBonusStartingUnits = ArrayList<String>()
|
||||
var aiUnhappinessModifier = 1f
|
||||
var turnBarbariansCanEnterPlayerTiles = 0
|
||||
var clearBarbarianCampReward = 25
|
||||
|
||||
init {
|
||||
// For compatibility with old mods that use deprecated var aiFreeUnits and do not have startingUnits, aiCityStateStartingUnits, aiMajorCivStartingUnits
|
||||
if (startingUnits.isEmpty()) {
|
||||
startingUnits.add(Constants.settler)
|
||||
startingUnits.add("Warrior")
|
||||
aiCityStateStartingUnits.addAll(startingUnits)
|
||||
aiMajorCivStartingUnits.addAll(startingUnits)
|
||||
}
|
||||
}
|
||||
|
||||
fun getDescription(): String {
|
||||
val lines = ArrayList<String>()
|
||||
lines += "Player settings"
|
||||
|
35
core/src/com/unciv/models/ruleset/Era.kt
Normal file
35
core/src/com/unciv/models/ruleset/Era.kt
Normal file
@ -0,0 +1,35 @@
|
||||
package com.unciv.models.ruleset
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.ui.utils.colorFromRGB
|
||||
|
||||
class Era : INamed {
|
||||
override var name: String = ""
|
||||
var researchAgreementCost = 300
|
||||
var startingSettlerCount = 1
|
||||
var startingSettlerUnit = "Settler" // For mods which have differently named settlers
|
||||
var startingWorkerCount = 0
|
||||
var startingWorkerUnit = "Worker"
|
||||
var startingMilitaryUnitCount = 1
|
||||
var startingMilitaryUnit = "Warrior"
|
||||
var startingGold = 0
|
||||
var startingCulture = 0
|
||||
var settlerPopulation = 1
|
||||
var settlerBuildings = ArrayList<String>()
|
||||
var startingObsoleteWonders = ArrayList<String>()
|
||||
var iconRGB: List<Int>? = null
|
||||
|
||||
fun getStartingUnits(): List<String> {
|
||||
val startingUnits = mutableListOf<String>()
|
||||
repeat(startingSettlerCount) {startingUnits.add(startingSettlerUnit)}
|
||||
repeat(startingWorkerCount) {startingUnits.add(startingWorkerUnit)}
|
||||
repeat(startingMilitaryUnitCount) {startingUnits.add(startingMilitaryUnit)}
|
||||
return startingUnits
|
||||
}
|
||||
|
||||
fun getColor(): Color {
|
||||
if (iconRGB == null) return Color.WHITE.cpy()
|
||||
return colorFromRGB(iconRGB!![0], iconRGB!![1], iconRGB!![2])
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ class Ruleset {
|
||||
val tileResources = LinkedHashMap<String, TileResource>()
|
||||
val tileImprovements = LinkedHashMap<String, TileImprovement>()
|
||||
val technologies = LinkedHashMap<String, Technology>()
|
||||
val eras = LinkedHashMap<String, Era>()
|
||||
val units = LinkedHashMap<String, BaseUnit>()
|
||||
val unitPromotions = LinkedHashMap<String, Promotion>()
|
||||
val nations = LinkedHashMap<String, Nation>()
|
||||
@ -79,6 +80,7 @@ class Ruleset {
|
||||
buildings.putAll(ruleset.buildings)
|
||||
for (buildingToRemove in ruleset.modOptions.buildingsToRemove) buildings.remove(buildingToRemove)
|
||||
difficulties.putAll(ruleset.difficulties)
|
||||
eras.putAll(ruleset.eras)
|
||||
nations.putAll(ruleset.nations)
|
||||
policyBranches.putAll(ruleset.policyBranches)
|
||||
policies.putAll(ruleset.policies)
|
||||
@ -99,22 +101,22 @@ class Ruleset {
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
beliefs.clear()
|
||||
buildings.clear()
|
||||
difficulties.clear()
|
||||
nations.clear()
|
||||
eras.clear()
|
||||
policyBranches.clear()
|
||||
specialists.clear()
|
||||
mods.clear()
|
||||
nations.clear()
|
||||
policies.clear()
|
||||
beliefs.clear()
|
||||
quests.clear()
|
||||
technologies.clear()
|
||||
buildings.clear()
|
||||
terrains.clear()
|
||||
tileImprovements.clear()
|
||||
tileResources.clear()
|
||||
unitPromotions.clear()
|
||||
specialists.clear()
|
||||
units.clear()
|
||||
mods.clear()
|
||||
modWithReligionLoaded = false
|
||||
}
|
||||
|
||||
@ -153,6 +155,8 @@ class Ruleset {
|
||||
val improvementsFile = folderHandle.child("TileImprovements.json")
|
||||
if (improvementsFile.exists()) tileImprovements += createHashmap(jsonParser.getFromJson(Array<TileImprovement>::class.java, improvementsFile))
|
||||
|
||||
val erasFile = folderHandle.child("Eras.json")
|
||||
if (erasFile.exists()) eras += createHashmap(jsonParser.getFromJson(Array<Era>::class.java, erasFile))
|
||||
val unitsFile = folderHandle.child("Units.json")
|
||||
if (unitsFile.exists()) units += createHashmap(jsonParser.getFromJson(Array<BaseUnit>::class.java, unitsFile))
|
||||
|
||||
@ -371,8 +375,27 @@ class Ruleset {
|
||||
warningCount++
|
||||
}
|
||||
}
|
||||
// eras.isNotEmpty() is only for mod compatibility, it should be removed at some point.
|
||||
if (eras.isNotEmpty() && tech.era() !in eras)
|
||||
lines += "Unknown era ${tech.era()} referenced in column of tech ${tech.name}"
|
||||
}
|
||||
|
||||
for (era in eras) {
|
||||
for (wonder in era.value.startingObsoleteWonders)
|
||||
if (wonder !in buildings)
|
||||
lines += "Nonexistent wonder ${wonder} obsoleted when starting in ${era.key}!"
|
||||
for (building in era.value.settlerBuildings)
|
||||
if (building !in buildings)
|
||||
lines += "Nonexistent building ${building} built by settlers when starting in ${era.key}"
|
||||
if (era.value.startingMilitaryUnit !in units)
|
||||
lines += "Nonexistent unit ${era.value.startingMilitaryUnit} marked as starting unit when starting in ${era.key}"
|
||||
if (era.value.researchAgreementCost < 0 || era.value.startingSettlerCount < 0 || era.value.startingWorkerCount < 0 || era.value.startingMilitaryUnitCount < 0 || era.value.startingGold < 0 || era.value.startingCulture < 0)
|
||||
lines += "Unexpected negative number found while parsing era ${era.key}"
|
||||
if (era.value.settlerPopulation <= 0)
|
||||
lines += "Population in cities from settlers must be strictly positive! Found value ${era.value.settlerPopulation} for era ${era.key}"
|
||||
}
|
||||
|
||||
|
||||
return CheckModLinksResult(warningCount, lines)
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +137,7 @@ class GameOptionsTable(val previousScreen: IPreviousScreen, val updatePlayerPick
|
||||
|
||||
private fun Table.addEraSelectBox() {
|
||||
if (ruleset.technologies.isEmpty()) return // mod with no techs
|
||||
// Should eventually be changed to use eras.json, but we'll keep it like this for now for mod compatibility
|
||||
val eras = ruleset.technologies.values.filter { !it.uniques.contains("Starting tech") }.map { it.era() }.distinct()
|
||||
addSelectBox("{Starting Era}:", eras, gameParameters.startingEra)
|
||||
{ gameParameters.startingEra = it }
|
||||
|
@ -16,6 +16,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.ruleset.Era
|
||||
import com.unciv.models.ruleset.Nation
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
@ -319,17 +320,10 @@ object ImageGetter {
|
||||
fun getTechIconGroup(techName: String, circleSize: Float) = getTechIcon(techName).surroundWithCircle(circleSize)
|
||||
|
||||
fun getTechIcon(techName: String): Image {
|
||||
val techIconColor = when (ruleset.technologies[techName]!!.era()) {
|
||||
Constants.ancientEra -> colorFromRGB(255, 87, 35)
|
||||
Constants.classicalEra -> colorFromRGB(233, 31, 99)
|
||||
Constants.medievalEra -> colorFromRGB(157, 39, 176)
|
||||
Constants.renaissanceEra -> colorFromRGB(104, 58, 183)
|
||||
Constants.industrialEra -> colorFromRGB(63, 81, 182)
|
||||
Constants.modernEra -> colorFromRGB(33, 150, 243)
|
||||
Constants.informationEra -> colorFromRGB(0, 150, 136)
|
||||
Constants.futureEra -> colorFromRGB(76, 176, 81)
|
||||
else -> Color.WHITE.cpy()
|
||||
}
|
||||
val era = ruleset.technologies[techName]!!.era()
|
||||
val techIconColor =
|
||||
if (era !in ruleset.eras) Era().getColor()
|
||||
else ruleset.eras[ruleset.technologies[techName]!!.era()]!!.getColor()
|
||||
return getImage("TechIcons/$techName").apply { color = techIconColor.lerp(Color.BLACK, 0.6f) }
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user