mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-11 00:08:58 +07:00
Improve AI city settling, science game, and belief picking (#12256)
* AI behaviour changes * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update ConstructionAutomation.kt * Update Automation.kt * Reverting some changes * Changes * revert changes * revert changes * revert changes * revert changes * Update CityLocationTileRanker.kt * Citizen assignment for stat conversion * Update CityLocationTileRanker.kt * Reduce AI settling * Avoid AI building units when in negative Supply * Update CityLocationTileRanker.kt * Update CityLocationTileRanker.kt * Update CityLocationTileRanker.kt * Update ConstructionAutomation.kt * Update build.gradle.kts * Update gradle-wrapper.properties * Update CityLocationTileRanker.kt * Update CityLocationTileRanker.kt * Update ConstructionAutomation.kt * Update CityLocationTileRanker.kt * AI changes for humans * Fix puppet focus * Update Automation.kt * Puppet focus * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Stats.kt * Update CityTurnManager.kt * Remove specialist science modifier * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update CivilianUnitAutomation.kt * Update ReligionAutomation.kt * Worker prioritization Workers are valuable in expand cities. * Update ConstructionAutomation.kt Food always important, it's rarely good to skip e.g. granary if we're on 6 pop. * Update ConstructionAutomation.kt Should achieve about the same with less lines of code. * Update Automation.kt * Update ConstructionAutomation.kt * Update Policies.json * Update Policies.json * Update Policies.json * Update ConstructionAutomation.kt * Update Policies.json * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Rename Crop Yield to Growth * Update worker usage * Update UnitAutomation.kt * Tutorials update * Update Tutorials.json * Fix spelling error * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * Update Tutorials.json * AI tech and policy choices * Update Techs.json * Update Policies.json * Update ConstructionAutomation.kt * Update UnitPromotions.json * Update * Update Policies.json * Update Tutorials.json * ReligionAutomation bugfix * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update AI city settling and science game * Update ReligionAutomation.kt * Maybe revert this now the belief picking has improved * Update ReligionAutomation.kt
This commit is contained in:
@ -38,6 +38,7 @@
|
|||||||
"name": "Archery",
|
"name": "Archery",
|
||||||
"row": 7,
|
"row": 7,
|
||||||
"prerequisites": ["Agriculture"],
|
"prerequisites": ["Agriculture"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'The haft of the arrow has been feathered with one of the eagle's own plumes, we often give our enemies the means of our own destruction' - Aesop"
|
"quote": "'The haft of the arrow has been feathered with one of the eagle's own plumes, we often give our enemies the means of our own destruction' - Aesop"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -101,6 +102,7 @@
|
|||||||
"name": "Bronze Working",
|
"name": "Bronze Working",
|
||||||
"row": 10,
|
"row": 10,
|
||||||
"prerequisites": ["Mining"],
|
"prerequisites": ["Mining"],
|
||||||
|
"uniques": ["[+50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Here Hector entered, with a spear eleven cubits long in his hand; the bronze point gleamed in front of him, and was fastened to the shaft of the spear by a ring of gold.' - Homer"
|
"quote": "'Here Hector entered, with a spear eleven cubits long in his hand; the bronze point gleamed in front of him, and was fastened to the shaft of the spear by a ring of gold.' - Homer"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -124,6 +126,7 @@
|
|||||||
"name": "Horseback Riding",
|
"name": "Horseback Riding",
|
||||||
"row": 5,
|
"row": 5,
|
||||||
"prerequisites": ["Trapping","The Wheel"],
|
"prerequisites": ["Trapping","The Wheel"],
|
||||||
|
"uniques": ["[+50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'A Horse! A Horse! My kingdom for a horse!' - Shakespeare (Richard III)"
|
"quote": "'A Horse! A Horse! My kingdom for a horse!' - Shakespeare (Richard III)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -178,6 +181,7 @@
|
|||||||
"name": "Iron Working",
|
"name": "Iron Working",
|
||||||
"row": 10,
|
"row": 10,
|
||||||
"prerequisites": ["Bronze Working"],
|
"prerequisites": ["Bronze Working"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Do not wait to strike til the iron is hot, but make it hot by striking.' - William Butler Yeats"
|
"quote": "'Do not wait to strike til the iron is hot, but make it hot by striking.' - William Butler Yeats"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -213,6 +217,7 @@
|
|||||||
"name": "Metal Casting",
|
"name": "Metal Casting",
|
||||||
"row": 9,
|
"row": 9,
|
||||||
"prerequisites": ["Engineering","Iron Working"],
|
"prerequisites": ["Engineering","Iron Working"],
|
||||||
|
"uniques": ["[+100]% weight to this choice for AI decisions"],
|
||||||
"quote": "'When pieces of bronze or gold or iron break, the metal-smith welds them together again in the fire, and the bond is established.' - Sri Guru Granth Sahib"
|
"quote": "'When pieces of bronze or gold or iron break, the metal-smith welds them together again in the fire, and the bond is established.' - Sri Guru Granth Sahib"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -229,6 +234,7 @@
|
|||||||
"cost": 375,
|
"cost": 375,
|
||||||
"row": 1,
|
"row": 1,
|
||||||
"prerequisites": ["Optics","Theology"],
|
"prerequisites": ["Optics","Theology"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'I find the great thing in this world is not so much where we stand, as in what direction we are moving.' - Oliver Wendell Holmes"
|
"quote": "'I find the great thing in this world is not so much where we stand, as in what direction we are moving.' - Oliver Wendell Holmes"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -262,6 +268,7 @@
|
|||||||
"name": "Steel",
|
"name": "Steel",
|
||||||
"row": 10,
|
"row": 10,
|
||||||
"prerequisites": ["Metal Casting"],
|
"prerequisites": ["Metal Casting"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'John Henry said to his Captain, / 'A man ain't nothin' but a man, / And before I'll let your steam drill beat me down, / I'll die with the hammer in my hand.'' - Anonymous: The Ballad of John Henry, the Steel-Drivin' Man"
|
"quote": "'John Henry said to his Captain, / 'A man ain't nothin' but a man, / And before I'll let your steam drill beat me down, / I'll die with the hammer in my hand.'' - Anonymous: The Ballad of John Henry, the Steel-Drivin' Man"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -276,7 +283,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Astronomy",
|
"name": "Astronomy",
|
||||||
"row": 2,
|
"row": 2,
|
||||||
"uniques": ["[+1] Movement <for [Embarked] units>","Enables [Embarked] units to enter ocean tiles"],
|
"uniques": ["[+1] Movement <for [Embarked] units>","Enables [Embarked] units to enter ocean tiles","[+50]% weight to this choice for AI decisions"],
|
||||||
"prerequisites": ["Compass","Education"],
|
"prerequisites": ["Compass","Education"],
|
||||||
"quote": "'Joyfully to the breeze royal Odysseus spread his sail, and with his rudder skillfully he steered.' - Homer"
|
"quote": "'Joyfully to the breeze royal Odysseus spread his sail, and with his rudder skillfully he steered.' - Homer"
|
||||||
},
|
},
|
||||||
@ -305,6 +312,7 @@
|
|||||||
"name": "Gunpowder",
|
"name": "Gunpowder",
|
||||||
"row": 10,
|
"row": 10,
|
||||||
"prerequisites": ["Physics","Steel"],
|
"prerequisites": ["Physics","Steel"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'The day when two army corps can annihilate each other in one second, all civilized nations, it is to be hoped, will recoil from war and discharge their troops.' - Alfred Nobel"
|
"quote": "'The day when two army corps can annihilate each other in one second, all civilized nations, it is to be hoped, will recoil from war and discharge their troops.' - Alfred Nobel"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -332,18 +340,21 @@
|
|||||||
"name": "Economics",
|
"name": "Economics",
|
||||||
"row": 6,
|
"row": 6,
|
||||||
"prerequisites": ["Banking","Printing Press"],
|
"prerequisites": ["Banking","Printing Press"],
|
||||||
|
"uniques": ["[+50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Compound interest is the most powerful force in the universe.' - Albert Einstein"
|
"quote": "'Compound interest is the most powerful force in the universe.' - Albert Einstein"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Metallurgy",
|
"name": "Metallurgy",
|
||||||
"row": 9,
|
"row": 9,
|
||||||
"prerequisites": ["Printing Press","Gunpowder"],
|
"prerequisites": ["Printing Press","Gunpowder"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'There never was a good knife made of bad steel.' - Benjamin Franklin"
|
"quote": "'There never was a good knife made of bad steel.' - Benjamin Franklin"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Chemistry",
|
"name": "Chemistry",
|
||||||
"row": 10,
|
"row": 10,
|
||||||
"prerequisites": ["Gunpowder"],
|
"prerequisites": ["Gunpowder"],
|
||||||
|
"uniques": ["[+100]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Wherever we look, the work of the chemist has raised the level of our civilization and has increased the productive capacity of the nation.' - Calvin Coolidge"
|
"quote": "'Wherever we look, the work of the chemist has raised the level of our civilization and has increased the productive capacity of the nation.' - Calvin Coolidge"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -359,6 +370,7 @@
|
|||||||
"name": "Archaeology",
|
"name": "Archaeology",
|
||||||
"row": 2,
|
"row": 2,
|
||||||
"prerequisites": ["Navigation","Architecture"],
|
"prerequisites": ["Navigation","Architecture"],
|
||||||
|
"uniques": ["[+50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Those who cannot remember the past are condemned to repeat it.' - George Santayana"
|
"quote": "'Those who cannot remember the past are condemned to repeat it.' - George Santayana"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -372,12 +384,14 @@
|
|||||||
"name": "Industrialization",
|
"name": "Industrialization",
|
||||||
"row": 6,
|
"row": 6,
|
||||||
"prerequisites": ["Economics"],
|
"prerequisites": ["Economics"],
|
||||||
|
"uniques": ["[+50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Industrialization based on machinery, already referred to as a characteristic of our age, is but one aspect of the revolution that is being wrought by technology.' - Emily Greene Balch"
|
"quote": "'Industrialization based on machinery, already referred to as a characteristic of our age, is but one aspect of the revolution that is being wrought by technology.' - Emily Greene Balch"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Rifling",
|
"name": "Rifling",
|
||||||
"row": 7,
|
"row": 7,
|
||||||
"prerequisites": ["Economics","Metallurgy"],
|
"prerequisites": ["Economics","Metallurgy"],
|
||||||
|
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
||||||
"quote": "'It is well that war is so terrible, or we should grow too fond of it.' - Robert E. Lee"
|
"quote": "'It is well that war is so terrible, or we should grow too fond of it.' - Robert E. Lee"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -442,19 +456,21 @@
|
|||||||
"name": "Refrigeration",
|
"name": "Refrigeration",
|
||||||
"row": 2,
|
"row": 2,
|
||||||
"prerequisites": ["Biology", "Electricity"], //todo: offshore platform should need this
|
"prerequisites": ["Biology", "Electricity"], //todo: offshore platform should need this
|
||||||
"uniques": ["[-50]% weight to this choice for AI decisions"],
|
"uniques": ["[-75]% weight to this choice for AI decisions"],
|
||||||
"quote": "'And homeless near a thousand homes I stood, and near a thousand tables pined and wanted food.' - William Wordsworth"
|
"quote": "'And homeless near a thousand homes I stood, and near a thousand tables pined and wanted food.' - William Wordsworth"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Radio",
|
"name": "Radio",
|
||||||
"row": 3,
|
"row": 3,
|
||||||
"prerequisites": ["Electricity"],
|
"prerequisites": ["Electricity"],
|
||||||
|
"uniques": ["[+100]% weight to this choice for AI decisions"],
|
||||||
"quote": "'The whole country was tied together by radio. We all experienced the same heroes and comedians and singers. They were giants.' - Woody Allen"
|
"quote": "'The whole country was tied together by radio. We all experienced the same heroes and comedians and singers. They were giants.' - Woody Allen"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Replaceable Parts",
|
"name": "Replaceable Parts",
|
||||||
"row": 4,
|
"row": 4,
|
||||||
"prerequisites": ["Electricity","Steam Power"],
|
"prerequisites": ["Electricity","Steam Power"],
|
||||||
|
"uniques": ["[+100]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Nothing is particularly hard if you divide it into small jobs.' - Henry Ford"
|
"quote": "'Nothing is particularly hard if you divide it into small jobs.' - Henry Ford"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -483,7 +499,7 @@
|
|||||||
"name": "Plastics",
|
"name": "Plastics",
|
||||||
"row": 3,
|
"row": 3,
|
||||||
"prerequisites": ["Radio","Replaceable Parts"],
|
"prerequisites": ["Radio","Replaceable Parts"],
|
||||||
"uniques": ["[+100]% weight to this choice for AI decisions"],
|
"uniques": ["[+200]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Ben, I want to say one word to you, just one word: plastics.' - Buck Henry and Calder Willingham, The Graduate"
|
"quote": "'Ben, I want to say one word to you, just one word: plastics.' - Buck Henry and Calder Willingham, The Graduate"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -531,6 +547,7 @@
|
|||||||
"name": "Radar",
|
"name": "Radar",
|
||||||
"row": 6,
|
"row": 6,
|
||||||
"prerequisites": ["Ballistics","Electronics"],
|
"prerequisites": ["Ballistics","Electronics"],
|
||||||
|
"uniques": ["[+100]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Vision is the art of seeing things invisible.' - Jonathan Swift"
|
"quote": "'Vision is the art of seeing things invisible.' - Jonathan Swift"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -604,7 +621,7 @@
|
|||||||
"name": "Satellites",
|
"name": "Satellites",
|
||||||
"row": 6,
|
"row": 6,
|
||||||
"prerequisites": ["Rocketry"],
|
"prerequisites": ["Rocketry"],
|
||||||
"uniques": ["Reveals the entire map","[+100]% weight to this choice for AI decisions"],
|
"uniques": ["Reveals the entire map","[+200]% weight to this choice for AI decisions"],
|
||||||
"quote": "'Now, somehow, in some new way, the sky seemed almost alien.' - Lyndon B. Johnson"
|
"quote": "'Now, somehow, in some new way, the sky seemed almost alien.' - Lyndon B. Johnson"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -259,7 +259,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
if (!civInfo.hasUnique(UniqueType.EnablesConstructionOfSpaceshipParts)) return
|
if (!civInfo.hasUnique(UniqueType.EnablesConstructionOfSpaceshipParts)) return
|
||||||
val spaceshipPart = (nonWonders + units).filter { it.name in spaceshipParts }.filterBuildable().firstOrNull()
|
val spaceshipPart = (nonWonders + units).filter { it.name in spaceshipParts }.filterBuildable().firstOrNull()
|
||||||
?: return
|
?: return
|
||||||
val modifier = 3f * personality.modifierFocus(PersonalityValue.Science, .4f)
|
val modifier = 20f //We're weighing Apollo program according to personality. If we decided to invest in that, we might as well commit to it.
|
||||||
addChoice(relativeCostEffectiveness, spaceshipPart.name, modifier)
|
addChoice(relativeCostEffectiveness, spaceshipPart.name, modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,17 +367,9 @@ object NextTurnAutomation {
|
|||||||
|
|
||||||
if (greatPeople.isEmpty()) return
|
if (greatPeople.isEmpty()) return
|
||||||
var greatPerson = greatPeople.random()
|
var greatPerson = greatPeople.random()
|
||||||
|
val scienceGP = greatPeople.firstOrNull { it.uniques.contains("Great Person - [Science]") }
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Culture)) {
|
if (scienceGP != null) greatPerson = scienceGP
|
||||||
val culturalGP =
|
// Humans would pick a prophet or engineer, but it'd require more sophistication on part of the AI - a scientist is the safest option for now
|
||||||
greatPeople.firstOrNull { it.uniques.contains("Great Person - [Culture]") }
|
|
||||||
if (culturalGP != null) greatPerson = culturalGP
|
|
||||||
}
|
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Science)) {
|
|
||||||
val scientificGP =
|
|
||||||
greatPeople.firstOrNull { it.uniques.contains("Great Person - [Science]") }
|
|
||||||
if (scientificGP != null) greatPerson = scientificGP
|
|
||||||
}
|
|
||||||
|
|
||||||
civInfo.units.addUnit(greatPerson, civInfo.cities.firstOrNull { it.isCapital() })
|
civInfo.units.addUnit(greatPerson, civInfo.cities.firstOrNull { it.isCapital() })
|
||||||
|
|
||||||
|
@ -33,16 +33,12 @@ object ReligionAutomation {
|
|||||||
|
|
||||||
if (civInfo.religionManager.remainingFoundableReligions() == 0 ) {
|
if (civInfo.religionManager.remainingFoundableReligions() == 0 ) {
|
||||||
buyGreatPerson(civInfo)
|
buyGreatPerson(civInfo)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't have a religion and no more change of getting it :(
|
|
||||||
if (civInfo.religionManager.religionState <= ReligionState.Pantheon) {
|
|
||||||
tryBuyAnyReligiousBuilding(civInfo)
|
tryBuyAnyReligiousBuilding(civInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have majority in all our own cities, build missionaries and inquisitors to solve this
|
// If we don't have majority in all our own cities, build missionaries and inquisitors to solve this
|
||||||
|
//TODO: in late game, this may not be worth it
|
||||||
val citiesWithoutOurReligion = civInfo.cities.filter { it.religion.getMajorityReligion() != civInfo.religionManager.religion!! }
|
val citiesWithoutOurReligion = civInfo.cities.filter { it.religion.getMajorityReligion() != civInfo.religionManager.religion!! }
|
||||||
// The original had a cap at 4 missionaries total, but 1/4 * the number of cities should be more appropriate imo
|
// The original had a cap at 4 missionaries total, but 1/4 * the number of cities should be more appropriate imo
|
||||||
if (citiesWithoutOurReligion.count() >
|
if (citiesWithoutOurReligion.count() >
|
||||||
@ -59,7 +55,6 @@ object ReligionAutomation {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get an inquisitor to defend our holy city
|
// Get an inquisitor to defend our holy city
|
||||||
val holyCity = civInfo.religionManager.getHolyCity()
|
val holyCity = civInfo.religionManager.getHolyCity()
|
||||||
if (holyCity != null
|
if (holyCity != null
|
||||||
@ -70,23 +65,13 @@ object ReligionAutomation {
|
|||||||
buyInquisitorNear(civInfo, holyCity)
|
buyInquisitorNear(civInfo, holyCity)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buy religious buildings in cities if possible
|
|
||||||
val citiesWithMissingReligiousBuildings = civInfo.cities.filter { city ->
|
|
||||||
city.religion.getMajorityReligion() != null
|
|
||||||
&& !city.cityConstructions.isAllBuilt(city.religion.getMajorityReligion()!!.buildingsPurchasableByBeliefs)
|
|
||||||
}
|
|
||||||
if (citiesWithMissingReligiousBuildings.any()) {
|
|
||||||
tryBuyAnyReligiousBuilding(civInfo)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just buy missionaries to spread our religion outside of our civ
|
// Just buy missionaries to spread our religion outside of our civ
|
||||||
if (civInfo.units.getCivUnits().count { it.hasUnique(UniqueType.CanSpreadReligion) } < 4) {
|
if (civInfo.units.getCivUnits().count { it.hasUnique(UniqueType.CanSpreadReligion) } < 4) {
|
||||||
buyMissionaryInAnyCity(civInfo)
|
buyMissionaryInAnyCity(civInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Todo: buy inquisitors for defence of other cities
|
// Todo: declare war if enemy missionaries enter our civ without permission
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryBuyAnyReligiousBuilding(civInfo: Civilization) {
|
private fun tryBuyAnyReligiousBuilding(civInfo: Civilization) {
|
||||||
@ -289,17 +274,17 @@ object ReligionAutomation {
|
|||||||
UniqueType.StatsFromObject ->
|
UniqueType.StatsFromObject ->
|
||||||
when {
|
when {
|
||||||
ruleSet.buildings.containsKey(unique.params[1]) -> {
|
ruleSet.buildings.containsKey(unique.params[1]) -> {
|
||||||
unique.stats.values.sum() /
|
unique.stats.values.sum() *
|
||||||
if (ruleSet.buildings[unique.params[1]]!!.isWonder) 2f
|
if (ruleSet.buildings[unique.params[1]]!!.isNationalWonder) 0.5f //there's at most 1 copy of each of these in our empire
|
||||||
else 1f
|
else 1.5f //yields for buildings are usually more desireable than faith-purchased buildings, as we might not need an upfront investment
|
||||||
|
|
||||||
}
|
}
|
||||||
ruleSet.specialists.containsKey(unique.params[1]) -> {
|
ruleSet.specialists.containsKey(unique.params[1]) -> {
|
||||||
unique.stats.values.sum() *
|
unique.stats.values.sum() *
|
||||||
if (city.population.population > 8f) 3f
|
if (city.population.population > 8f) 2f
|
||||||
else 1f
|
else 1f
|
||||||
}
|
}
|
||||||
else -> 0f
|
else -> unique.stats.values.sum() * 1f //should account for most edge cases here
|
||||||
}
|
}
|
||||||
UniqueType.StatsFromTradeRoute ->
|
UniqueType.StatsFromTradeRoute ->
|
||||||
unique.stats.values.sum() *
|
unique.stats.values.sum() *
|
||||||
@ -309,7 +294,7 @@ object ReligionAutomation {
|
|||||||
min(unique.params[0].toFloat() * city.population.population, unique.params[2].toFloat())
|
min(unique.params[0].toFloat() * city.population.population, unique.params[2].toFloat())
|
||||||
UniqueType.StatsPerCity ->
|
UniqueType.StatsPerCity ->
|
||||||
if (city.matchesFilter(unique.params[1]))
|
if (city.matchesFilter(unique.params[1]))
|
||||||
unique.stats.values.sum()
|
unique.stats.values.sum() * 2f //free yields
|
||||||
else 0f
|
else 0f
|
||||||
else -> 0f
|
else -> 0f
|
||||||
}
|
}
|
||||||
@ -359,7 +344,7 @@ object ReligionAutomation {
|
|||||||
// Some city-filters are modified by personality (non-enemy foreign cities)
|
// Some city-filters are modified by personality (non-enemy foreign cities)
|
||||||
score += modifier * when (unique.type) {
|
score += modifier * when (unique.type) {
|
||||||
UniqueType.KillUnitPlunderNearCity ->
|
UniqueType.KillUnitPlunderNearCity ->
|
||||||
unique.params[0].toFloat() * 4f *
|
unique.params[0].toFloat() * 0.5f * //can be very strong, but a low weight for now as the AI currently isn't farming barb camp
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Military)) 2f
|
if (civInfo.wantsToFocusOn(Victory.Focus.Military)) 2f
|
||||||
else 1f
|
else 1f
|
||||||
UniqueType.BuyUnitsForAmountStat, UniqueType.BuyBuildingsForAmountStat ->
|
UniqueType.BuyUnitsForAmountStat, UniqueType.BuyBuildingsForAmountStat ->
|
||||||
@ -368,39 +353,39 @@ object ReligionAutomation {
|
|||||||
) 0f
|
) 0f
|
||||||
// This is something completely different from the original, but I have no idea
|
// This is something completely different from the original, but I have no idea
|
||||||
// what happens over there
|
// what happens over there
|
||||||
else civInfo.stats.statsForNextTurn[Stat.valueOf(unique.params[2])] * 5f / unique.params[1].toFloat()
|
else civInfo.stats.statsForNextTurn[Stat.valueOf(unique.params[2])] * 200f / unique.params[1].toFloat() //the costs of these are probably similar to the baseUnitBuyCost
|
||||||
UniqueType.BuyUnitsWithStat, UniqueType.BuyBuildingsWithStat ->
|
UniqueType.BuyUnitsWithStat, UniqueType.BuyBuildingsWithStat ->
|
||||||
if (civInfo.religionManager.religion != null
|
if (civInfo.religionManager.religion != null
|
||||||
&& civInfo.religionManager.religion!!.followerBeliefUniqueMap.getUniques(unique.type).any()
|
&& civInfo.religionManager.religion!!.followerBeliefUniqueMap.getUniques(unique.type).any()
|
||||||
) 0f
|
) 0f
|
||||||
// This is something completely different from the original, but I have no idea
|
// This is something completely different from the original, but I have no idea
|
||||||
// what happens over there
|
// what happens over there
|
||||||
else civInfo.stats.statsForNextTurn[Stat.valueOf(unique.params[1])] * 10f / civInfo.getEra().baseUnitBuyCost
|
else civInfo.stats.statsForNextTurn[Stat.valueOf(unique.params[1])] * 200f / civInfo.getEra().baseUnitBuyCost //baseUnitBuyCost is 200 in Standard speed pre-Renaissance
|
||||||
UniqueType.BuyUnitsByProductionCost ->
|
UniqueType.BuyUnitsByProductionCost ->
|
||||||
15f * if (civInfo.wantsToFocusOn(Victory.Focus.Military)) 2f else 1f
|
0f //Holy Warriors is a waste if we don't buy units with it, and if we buy units with it'll cost us great persons
|
||||||
UniqueType.StatsWhenSpreading ->
|
UniqueType.StatsWhenSpreading ->
|
||||||
unique.params[0].toFloat() / 5f
|
unique.params[0].toFloat() / 10f
|
||||||
UniqueType.StatsWhenAdoptingReligion ->
|
UniqueType.StatsWhenAdoptingReligion ->
|
||||||
unique.stats.values.sum() / 50f
|
unique.stats.values.sum() / 50f
|
||||||
UniqueType.RestingPointOfCityStatesFollowingReligionChange ->
|
UniqueType.RestingPointOfCityStatesFollowingReligionChange ->
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.CityStates))
|
if (civInfo.wantsToFocusOn(Victory.Focus.CityStates))
|
||||||
unique.params[0].toFloat() / 3.5f
|
unique.params[0].toFloat() / 4f
|
||||||
else
|
else
|
||||||
unique.params[0].toFloat() / 7f
|
unique.params[0].toFloat() / 8f
|
||||||
UniqueType.StatsFromGlobalCitiesFollowingReligion ->
|
UniqueType.StatsFromGlobalCitiesFollowingReligion ->
|
||||||
unique.stats.values.sum()
|
unique.stats.values.sum() * 2f //free yields that are potentially more than our own number of cities would allow
|
||||||
UniqueType.StatsFromGlobalFollowers ->
|
UniqueType.StatsFromGlobalFollowers ->
|
||||||
4f * (unique.stats.values.sum() / unique.params[1].toFloat())
|
10f * (unique.stats.values.sum() / unique.params[1].toFloat())
|
||||||
UniqueType.Strength ->
|
UniqueType.Strength ->
|
||||||
unique.params[0].toFloat() / 4f
|
unique.params[0].toFloat() * 2f//combat strength from beliefs is very strong
|
||||||
UniqueType.ReligionSpreadDistance ->
|
UniqueType.ReligionSpreadDistance ->
|
||||||
(10f + unique.params[0].toFloat()) * goodEarlyModifier
|
(10f + unique.params[0].toFloat()) * goodEarlyModifier
|
||||||
UniqueType.NaturalReligionSpreadStrength ->
|
UniqueType.NaturalReligionSpreadStrength ->
|
||||||
unique.params[0].toFloat() * goodEarlyModifier / 5f
|
unique.params[0].toFloat() * goodEarlyModifier / 5f //We should weigh this according to cityFilter; Religious Texts is way stronger than Religious Unity
|
||||||
UniqueType.SpreadReligionStrength ->
|
UniqueType.SpreadReligionStrength ->
|
||||||
unique.params[0].toFloat() * goodLateModifier / 5f
|
unique.params[0].toFloat() * goodLateModifier / 5f
|
||||||
UniqueType.FaithCostOfGreatProphetChange ->
|
UniqueType.FaithCostOfGreatProphetChange ->
|
||||||
-unique.params[0].toFloat() * goodLateModifier / 2f
|
-unique.params[0].toFloat() * goodLateModifier / 10f //It's only about 1 more prophet, due to the increasing costs.
|
||||||
UniqueType.BuyBuildingsDiscount, UniqueType.BuyUnitsDiscount ->
|
UniqueType.BuyBuildingsDiscount, UniqueType.BuyUnitsDiscount ->
|
||||||
-unique.params[2].toFloat() * goodLateModifier / 5f
|
-unique.params[2].toFloat() * goodLateModifier / 5f
|
||||||
UniqueType.BuyItemsDiscount ->
|
UniqueType.BuyItemsDiscount ->
|
||||||
|
@ -96,25 +96,30 @@ object CityLocationTileRanker {
|
|||||||
if (onCoast) tileValue += 3
|
if (onCoast) tileValue += 3
|
||||||
// Hills are free production and defence
|
// Hills are free production and defence
|
||||||
if (onHill) tileValue += 7
|
if (onHill) tileValue += 7
|
||||||
// Observatories are good, but current implementation no mod-friendly
|
// Observatories are good, but current implementation not mod-friendly
|
||||||
if (isNextToMountain) tileValue += 5
|
if (isNextToMountain) tileValue += 5
|
||||||
if (newCityTile.isAdjacentToRiver()) tileValue += 14
|
// This bonus for settling on river is a bit outsized for the importance, but otherwise they have a habit of settling 1 tile away
|
||||||
if (newCityTile.terrainHasUnique(UniqueType.FreshWater)) tileValue += 5
|
if (newCityTile.isAdjacentToRiver()) tileValue += 20
|
||||||
// We want to found the city on an oasis because it can't be improved otherwise
|
// We want to found the city on an oasis because it can't be improved otherwise
|
||||||
if (newCityTile.terrainHasUnique(UniqueType.Unbuildable)) tileValue += 3
|
if (newCityTile.terrainHasUnique(UniqueType.Unbuildable)) tileValue += 3
|
||||||
// If we build the city on a resource tile, then we can't build any special improvements on it
|
// If we build the city on a resource tile, then we can't build any special improvements on it
|
||||||
if (newCityTile.resource != null) tileValue -= 4
|
if (newCityTile.resource != null) tileValue -= 4
|
||||||
|
if (newCityTile.resource != null && newCityTile.tileResource.resourceType == ResourceType.Bonus) tileValue -= 8
|
||||||
|
// Settling on bonus resources tends to waste a food
|
||||||
|
// Settling on luxuries generally speeds up our game, and settling on strategics as well, as the AI cheats and can see them.
|
||||||
|
|
||||||
var tiles = 0
|
var tiles = 0
|
||||||
for (i in 0..3) {
|
for (i in 0..3) {
|
||||||
|
//Ideally, we shouldn't really count the center tile, as it's converted into 1 production 2 food anyways with special cases treated above, but doing so can lead to AI moving settler back and forth until forever
|
||||||
for (nearbyTile in newCityTile.getTilesAtDistance(i)) {
|
for (nearbyTile in newCityTile.getTilesAtDistance(i)) {
|
||||||
tiles++
|
tiles++
|
||||||
tileValue += rankTile(nearbyTile, civ, onCoast, newUniqueLuxuryResources, baseTileMap, uniqueCache)
|
tileValue += rankTile(nearbyTile, civ, onCoast, newUniqueLuxuryResources, baseTileMap, uniqueCache) * (3 / (i + 1))
|
||||||
|
//Tiles close to the city can be worked more quickly, and thus should gain higher weight.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placing cities on the edge of the map is bad, we can't even build improvements on them!
|
// Placing cities on the edge of the map is bad, we can't even build improvements on them!
|
||||||
tileValue -= (HexMath.getNumberOfTilesInHexagon(3) - tiles) * 3
|
tileValue -= (HexMath.getNumberOfTilesInHexagon(3) - tiles) * 2.4f
|
||||||
return tileValue
|
return tileValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +155,7 @@ object CityLocationTileRanker {
|
|||||||
// Don't settle near but not on the coast
|
// Don't settle near but not on the coast
|
||||||
if (rankTile.isCoastalTile() && !onCoast) locationSpecificTileValue -= 2
|
if (rankTile.isCoastalTile() && !onCoast) locationSpecificTileValue -= 2
|
||||||
// Apply the effect of having a lighthouse, since we can probably assume that we will build it
|
// Apply the effect of having a lighthouse, since we can probably assume that we will build it
|
||||||
if (onCoast && rankTile.isOcean) locationSpecificTileValue += 1
|
if (onCoast && rankTile.isOcean) locationSpecificTileValue += 1.2f //food is ranked at 1.2 points
|
||||||
// Check if there are any new unique luxury resources
|
// Check if there are any new unique luxury resources
|
||||||
if (rankTile.resource != null && rankTile.tileResource.resourceType == ResourceType.Luxury
|
if (rankTile.resource != null && rankTile.tileResource.resourceType == ResourceType.Luxury
|
||||||
&& !(civ.hasResource(rankTile.resource!!) || newUniqueLuxuryResources.contains(rankTile.resource))) {
|
&& !(civ.hasResource(rankTile.resource!!) || newUniqueLuxuryResources.contains(rankTile.resource))) {
|
||||||
@ -170,9 +175,13 @@ object CityLocationTileRanker {
|
|||||||
rankTileValue += when (rankTile.tileResource.resourceType) {
|
rankTileValue += when (rankTile.tileResource.resourceType) {
|
||||||
ResourceType.Bonus -> 2f
|
ResourceType.Bonus -> 2f
|
||||||
ResourceType.Strategic -> 1.2f * rankTile.resourceAmount
|
ResourceType.Strategic -> 1.2f * rankTile.resourceAmount
|
||||||
ResourceType.Luxury -> 5f * rankTile.resourceAmount
|
ResourceType.Luxury -> 10f * rankTile.resourceAmount //very important for humans who might want to conquer the AI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (rankTile.terrainHasUnique(UniqueType.FreshWater)) rankTileValue += 0.5f
|
||||||
|
//Taking into account freshwater farm food, maybe less important in baseruleset mods
|
||||||
|
if (rankTile.terrainFeatures.isNotEmpty() && rankTile.lastTerrain.hasUnique(UniqueType.ProductionBonusWhenRemoved)) rankTileValue += 0.5f
|
||||||
|
//Taking into account yields from forest chopping
|
||||||
|
|
||||||
if (rankTile.isNaturalWonder()) rankTileValue += 10
|
if (rankTile.isNaturalWonder()) rankTileValue += 10
|
||||||
|
|
||||||
|
@ -85,6 +85,7 @@ object CivilianUnitAutomation {
|
|||||||
|
|
||||||
val hurriedPolicy = UnitActions.invokeUnitAction(unit, UnitActionType.HurryPolicy)
|
val hurriedPolicy = UnitActions.invokeUnitAction(unit, UnitActionType.HurryPolicy)
|
||||||
if (hurriedPolicy) return
|
if (hurriedPolicy) return
|
||||||
|
//TODO: save up great scientists/writers for late game (8 turns after research labs/broadcast towers resp.)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Great merchant -> Conduct trade mission if late game and if not at war.
|
// Great merchant -> Conduct trade mission if late game and if not at war.
|
||||||
@ -145,7 +146,7 @@ object CivilianUnitAutomation {
|
|||||||
private fun isLateGame(civ: Civilization): Boolean {
|
private fun isLateGame(civ: Civilization): Boolean {
|
||||||
val researchCompletePercent =
|
val researchCompletePercent =
|
||||||
(civ.tech.researchedTechnologies.size * 1.0f) / civ.gameInfo.ruleset.technologies.size
|
(civ.tech.researchedTechnologies.size * 1.0f) / civ.gameInfo.ruleset.technologies.size
|
||||||
return researchCompletePercent >= 0.7f
|
return researchCompletePercent >= 0.6f
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether the civilian spends its turn hiding and not moving */
|
/** Returns whether the civilian spends its turn hiding and not moving */
|
||||||
|
Reference in New Issue
Block a user