This commit is contained in:
yairm210 2021-09-02 20:48:29 +03:00
parent e418f1b8ca
commit c116b9ba94
2 changed files with 109 additions and 62 deletions

View File

@ -5,6 +5,7 @@ import com.unciv.logic.map.RoadStatus
import com.unciv.models.metadata.BASE_GAME_DURATION_TURNS
import com.unciv.models.ruleset.BeliefType
import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.Unique
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.StatMap
@ -24,7 +25,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
for (unique in civInfo.getMatchingUniques("[] units cost no maintenance")) {
freeUnits += unique.params[0].toInt()
}
var unitsToPayFor = civInfo.getCivUnits()
if (civInfo.hasUnique("Units in cities cost no Maintenance"))
// Only land military units can truly "garrison"
@ -37,12 +38,17 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
for (unique in civInfo.getMatchingUniques("-[]% [] unit maintenance costs")) {
val numberOfUnitsWithDiscount = min(numberOfUnitsToPayFor, unitsToPayFor.count { it.matchesFilter(unique.params[1]) }.toFloat())
val numberOfUnitsWithDiscount = min(
numberOfUnitsToPayFor,
unitsToPayFor.count { it.matchesFilter(unique.params[1]) }.toFloat()
)
numberOfUnitsToPayFor -= numberOfUnitsWithDiscount * unique.params[0].toFloat() / 100f
}
val turnLimit = BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier
val gameProgress = min(civInfo.gameInfo.turns / turnLimit, 1f) // as game progresses Maintenance cost rises
val turnLimit =
BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier
val gameProgress =
min(civInfo.gameInfo.turns / turnLimit, 1f) // as game progresses Maintenance cost rises
var cost = baseUnitCost * numberOfUnitsToPayFor * (1 + gameProgress)
cost = cost.pow(1 + gameProgress / 3) // Why 3? To spread 1 to 1.33
if (!civInfo.isPlayerCivilization())
@ -51,7 +57,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
for (unique in civInfo.getMatchingUniques("-[]% unit upkeep costs")) {
cost *= 1f - unique.params[0].toFloat() / 100f
}
return cost.toInt()
}
@ -60,8 +66,9 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
// we no longer use .flatMap, because there are a lot of tiles and keeping them all in a list
// just to go over them once is a waste of memory - there are low-end phones who don't have much ram
val ignoredTileTypes = civInfo.getMatchingUniques("No Maintenance costs for improvements in [] tiles")
.map { it.params[0] }.toHashSet() // needs to be .toHashSet()ed,
val ignoredTileTypes =
civInfo.getMatchingUniques("No Maintenance costs for improvements in [] tiles")
.map { it.params[0] }.toHashSet() // needs to be .toHashSet()ed,
// Because we go over every tile in every city and check if it's in this list, which can get real heavy.
for (city in civInfo.cities) {
@ -74,7 +81,8 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
}
}
for (unique in civInfo.getMatchingUniques("Maintenance on roads & railroads reduced by []%"))
transportationUpkeep = (transportationUpkeep * (100f - unique.params[0].toInt()) / 100).toInt()
transportationUpkeep =
(transportationUpkeep * (100f - unique.params[0].toInt()) / 100).toInt()
return transportationUpkeep
}
@ -88,23 +96,29 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
//City-States bonuses
for (otherCiv in civInfo.getKnownCivs()) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() >= RelationshipLevel.Friend) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo.civName)
.relationshipLevel() >= RelationshipLevel.Friend
) {
val cityStateBonus = Stats()
val eraInfo = civInfo.getEraObject()
val relevantBonuses =
when {
eraInfo == null -> null
otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() == RelationshipLevel.Friend ->
otherCiv.getDiplomacyManager(civInfo.civName)
.relationshipLevel() == RelationshipLevel.Friend ->
eraInfo.friendBonus[otherCiv.cityStateType.name]
else -> eraInfo.allyBonus[otherCiv.cityStateType.name]
}
if (relevantBonuses != null) {
for (bonus in relevantBonuses) {
if (bonus.getPlaceholderText() == "Provides [] [] per turn") {
cityStateBonus.add(Stat.valueOf(bonus.getPlaceholderParameters()[1]), bonus.getPlaceholderParameters()[0].toFloat())
}
val unique = Unique(bonus)
if (unique.placeholderText == "Provides [] [] per turn")
cityStateBonus.add(
Stat.valueOf(unique.params[1]),
unique.params[0].toFloat()
)
}
} else {
// Deprecated, assume Civ V values for compatibility
@ -130,7 +144,9 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
if (otherCiv.isCityState())
for (unique in civInfo.getMatchingUniques("Allied City-States provide [] equal to []% of what they produce for themselves")) {
if (otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() != RelationshipLevel.Ally) continue
if (otherCiv.getDiplomacyManager(civInfo.civName)
.relationshipLevel() != RelationshipLevel.Ally
) continue
statMap.add(
"City-States",
Stats().add(
@ -145,23 +161,27 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
statMap["Unit upkeep"] = Stats(gold = -getUnitMaintenance().toFloat())
if (civInfo.religionManager.religion != null) {
for (unique in civInfo.religionManager.religion!!.getBeliefs(BeliefType.Founder).flatMap { it.uniqueObjects }) {
for (unique in civInfo.religionManager.religion!!.getBeliefs(BeliefType.Founder)
.flatMap { it.uniqueObjects }) {
if (unique.placeholderText == "[] for each global city following this religion") {
statMap.add(
"Religion",
"Religion",
unique.stats.times(civInfo.religionManager.numberOfCitiesFollowingThisReligion())
)
}
}
for (unique in civInfo.religionManager.religion!!.getFounderUniques())
if (unique.placeholderText == "[] for every [] global followers []")
statMap.add("Religion",
statMap.add(
"Religion",
unique.stats *
civInfo.religionManager.numberOfFollowersFollowingThisReligion(unique.params[2]).toFloat() /
unique.params[1].toFloat()
civInfo.religionManager.numberOfFollowersFollowingThisReligion(
unique.params[2]
).toFloat() /
unique.params[1].toFloat()
)
}
if (civInfo.hasUnique("50% of excess happiness added to culture towards policies")) {
val happiness = civInfo.getHappiness()
@ -173,7 +193,8 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
// will show a negative number of turns and int.max, respectively
if (statMap.values.map { it.gold }.sum() < 0 && civInfo.gold < 0) {
val scienceDeficit = max(statMap.values.map { it.gold }.sum(),
1 - statMap.values.map { it.science }.sum())// Leave at least 1
1 - statMap.values.map { it.science }.sum()
)// Leave at least 1
statMap["Treasury deficit"] = Stats(science = scienceDeficit)
}
val goldDifferenceFromTrade = civInfo.diplomacy.values.sumBy { it.goldPerTurn() }
@ -191,33 +212,39 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
var happinessPerUniqueLuxury = 4f + civInfo.getDifficulty().extraHappinessPerLuxury
for (unique in civInfo.getMatchingUniques("+[] happiness from each type of luxury resource"))
happinessPerUniqueLuxury += unique.params[0].toInt()
val ownedLuxuries = civInfo.getCivResources().map { it.resource }.filter { it.resourceType == ResourceType.Luxury }
val ownedLuxuries = civInfo.getCivResources().map { it.resource }
.filter { it.resourceType == ResourceType.Luxury }
statMap["Luxury resources"] = civInfo.getCivResources()
.map { it.resource }
.count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury
val happinessBonusForCityStateProvidedLuxuries =
civInfo.getMatchingUniques("Happiness from Luxury Resources gifted by City-States increased by []%")
.sumBy { it.params[0].toInt() } / 100f
val luxuriesProvidedByCityStates = civInfo.getKnownCivs().asSequence()
.filter { it.isCityState() && it.getAllyCiv() == civInfo.civName }
.flatMap { it.getCivResources().map { res -> res.resource } }
.distinct()
.count { it.resourceType === ResourceType.Luxury && ownedLuxuries.contains(it) }
statMap["City-State Luxuries"] = happinessPerUniqueLuxury * luxuriesProvidedByCityStates * happinessBonusForCityStateProvidedLuxuries
statMap["City-State Luxuries"] =
happinessPerUniqueLuxury * luxuriesProvidedByCityStates * happinessBonusForCityStateProvidedLuxuries
val luxuriesAllOfWhichAreTradedAway = civInfo.detailedCivResources
.filter { it.amount < 0 && it.resource.resourceType == ResourceType.Luxury
&& (it.origin == "Trade" || it.origin == "Trade request")}
.filter {
it.amount < 0 && it.resource.resourceType == ResourceType.Luxury
&& (it.origin == "Trade" || it.origin == "Trade request")
}
.map { it.resource }
.filter { !ownedLuxuries.contains(it) }
statMap["Traded Luxuries"] = luxuriesAllOfWhichAreTradedAway.count() * happinessPerUniqueLuxury *
civInfo.getMatchingUniques("Retain []% of the happiness from a luxury after the last copy has been traded away").sumBy { it.params[0].toInt() } / 100f
statMap["Traded Luxuries"] =
luxuriesAllOfWhichAreTradedAway.count() * happinessPerUniqueLuxury *
civInfo.getMatchingUniques("Retain []% of the happiness from a luxury after the last copy has been traded away")
.sumBy { it.params[0].toInt() } / 100f
for (city in civInfo.cities) {
// There appears to be a concurrency problem? In concurrent thread in ConstructionsTable.getConstructionButtonDTOs
@ -233,7 +260,8 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
if (civInfo.hasUnique("Provides 1 happiness per 2 additional social policies adopted")) {
if (!statMap.containsKey("Policies")) statMap["Policies"] = 0f
statMap["Policies"] = statMap["Policies"]!! +
civInfo.policies.getAdoptedPolicies().count { !Policy.isBranchCompleteByName(it) } / 2
civInfo.policies.getAdoptedPolicies()
.count { !Policy.isBranchCompleteByName(it) } / 2
}
var happinessPerNaturalWonder = 1f
@ -244,32 +272,39 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
if (civInfo.religionManager.religion != null) {
statMap["Religion"] = 0f
for (unique in civInfo.religionManager.religion!!.getBeliefs(BeliefType.Founder).flatMap { it.uniqueObjects }) {
for (unique in civInfo.religionManager.religion!!.getBeliefs(BeliefType.Founder)
.flatMap { it.uniqueObjects }) {
if (unique.placeholderText == "[] for each global city following this religion") {
statMap["Religion"] =
statMap["Religion"] =
statMap["Religion"]!! +
unique.stats.happiness * civInfo.religionManager.numberOfCitiesFollowingThisReligion().toFloat()
unique.stats.happiness * civInfo.religionManager.numberOfCitiesFollowingThisReligion()
.toFloat()
}
if (unique.placeholderText == "[] for every [] global followers []") {
statMap["Religion"] =
statMap["Religion"]!! +
unique.stats.happiness *
civInfo.religionManager.numberOfFollowersFollowingThisReligion(unique.params[2]).toFloat() /
unique.params[1].toFloat()
unique.stats.happiness *
civInfo.religionManager.numberOfFollowersFollowingThisReligion(
unique.params[2]
).toFloat() /
unique.params[1].toFloat()
}
}
if (statMap["Religion"] == 0f)
if (statMap["Religion"] == 0f)
statMap.remove("Religion")
}
//From city-states
for (otherCiv in civInfo.getKnownCivs()) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo).relationshipLevel() >= RelationshipLevel.Friend) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo)
.relationshipLevel() >= RelationshipLevel.Friend
) {
val eraInfo = civInfo.getEraObject()
val relevantBonuses =
val relevantBonuses =
when {
eraInfo == null -> null
otherCiv.getDiplomacyManager(civInfo).relationshipLevel() == RelationshipLevel.Friend ->
otherCiv.getDiplomacyManager(civInfo)
.relationshipLevel() == RelationshipLevel.Friend ->
eraInfo.friendBonus[otherCiv.cityStateType.name]
else ->
eraInfo.allyBonus[otherCiv.cityStateType.name]
@ -279,15 +314,17 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
for (bonus in relevantBonuses) {
if (bonus.getPlaceholderText() == "Provides [] Happiness") {
if (statMap.containsKey("City-States"))
statMap["City-States"] = statMap["City-States"]!! + bonus.getPlaceholderParameters()[0].toFloat()
statMap["City-States"] =
statMap["City-States"]!! + bonus.getPlaceholderParameters()[0].toFloat()
else
statMap["City-States"] = bonus.getPlaceholderParameters()[0].toFloat()
statMap["City-States"] =
bonus.getPlaceholderParameters()[0].toFloat()
}
}
} else {
// Deprecated, assume Civ V values for compatibility
if (otherCiv.cityStateType == CityStateType.Mercantile) {
val happinessBonus = if(civInfo.getEraNumber() in 0..1) 2f else 3f
val happinessBonus = if (civInfo.getEraNumber() in 0..1) 2f else 3f
if (statMap.containsKey("City-States"))
statMap["City-States"] = statMap["City-States"]!! + happinessBonus
else

View File

@ -26,9 +26,9 @@ class Era : INamed {
fun getStartingUnits(): List<String> {
val startingUnits = mutableListOf<String>()
repeat(startingSettlerCount) {startingUnits.add(startingSettlerUnit)}
repeat(startingWorkerCount) {startingUnits.add(startingWorkerUnit)}
repeat(startingMilitaryUnitCount) {startingUnits.add(startingMilitaryUnit)}
repeat(startingSettlerCount) { startingUnits.add(startingSettlerUnit) }
repeat(startingWorkerCount) { startingUnits.add(startingWorkerUnit) }
repeat(startingMilitaryUnitCount) { startingUnits.add(startingMilitaryUnit) }
return startingUnits
}
@ -37,21 +37,31 @@ class Era : INamed {
return colorFromRGB(iconRGB!![0], iconRGB!![1], iconRGB!![2])
}
fun getHexColor() = "#" + getColor().toString().substring(0,6)
fun getHexColor() = "#" + getColor().toString().substring(0, 6)
companion object {
// User for CS bonuses in case the Eras file is missing (legacy mods)
fun getLegacyCityStateBonusEra(eraNumber: Int) = Era().apply {
val cultureBonus = if(eraNumber in 0..1) 3 else if (eraNumber in 2..3) 6 else 13
val happinessBonus = if(eraNumber in 0..1) 2 else 3
friendBonus[CityStateType.Militaristic.name] = arrayListOf("Provides military units every [20] turns")
friendBonus[CityStateType.Cultured.name] = arrayListOf("Provides [$cultureBonus] [Culture] per turn")
friendBonus[CityStateType.Mercantile.name] = arrayListOf("Provides [$happinessBonus] Happiness")
friendBonus[CityStateType.Maritime.name] = arrayListOf("Provides [2] [Food] [in capital]")
allyBonus[CityStateType.Militaristic.name] = arrayListOf("Provides military units every [17] turns")
allyBonus[CityStateType.Cultured.name] = arrayListOf("Provides [${cultureBonus*2}] [Culture] per turn")
allyBonus[CityStateType.Mercantile.name] = arrayListOf("Provides [$happinessBonus] Happiness", "Provides a unique luxury")
allyBonus[CityStateType.Maritime.name] = arrayListOf("Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]")
val cultureBonus = if (eraNumber in 0..1) 3 else if (eraNumber in 2..3) 6 else 13
val happinessBonus = if (eraNumber in 0..1) 2 else 3
friendBonus[CityStateType.Militaristic.name] =
arrayListOf("Provides military units every [20] turns")
friendBonus[CityStateType.Cultured.name] =
arrayListOf("Provides [$cultureBonus] [Culture] per turn")
friendBonus[CityStateType.Mercantile.name] =
arrayListOf("Provides [$happinessBonus] Happiness")
friendBonus[CityStateType.Maritime.name] =
arrayListOf("Provides [2] [Food] [in capital]")
allyBonus[CityStateType.Militaristic.name] =
arrayListOf("Provides military units every [17] turns")
allyBonus[CityStateType.Cultured.name] =
arrayListOf("Provides [${cultureBonus * 2}] [Culture] per turn")
allyBonus[CityStateType.Mercantile.name] =
arrayListOf("Provides [$happinessBonus] Happiness", "Provides a unique luxury")
allyBonus[CityStateType.Maritime.name] = arrayListOf(
"Provides [2] [Food] [in capital]",
"Provides [1] [Food] [in all cities]"
)
}
}
}