Great person points come from the json! The only things that still happen directly to the specialists stats is the assign/unassign, this is as close as we'll get without changing the rest of it!

This commit is contained in:
Yair Morgenstern 2020-09-30 20:18:52 +03:00
parent e39d3e89da
commit aa2486c896
8 changed files with 95 additions and 70 deletions

View File

@ -2,21 +2,25 @@
{ {
"name":"Scientist", "name":"Scientist",
"science":3, "science":3,
"greatPersonPoints": {"science":3}
"color": [0,0,255] "color": [0,0,255]
}, },
{ {
"name":"Merchant", "name":"Merchant",
"gold":3, "gold":3,
"greatPersonPoints": {"gold":3}
"color": [255,215,0] "color": [255,215,0]
}, },
{ {
"name":"Artist", "name":"Artist",
"culture":2, "culture":2,
"greatPersonPoints": {"culture":3}
"color": [160,32,240] "color": [160,32,240]
}, },
{ {
"name":"Engineer", "name":"Engineer",
"production":2, "production":2,
"greatPersonPoints": {"production":3}
"color": [139,69,19] "color": [139,69,19]
} }
] ]

View File

@ -253,16 +253,17 @@ class GameInfo {
throw UncivShowableException("Missing mods: [$missingMods]") throw UncivShowableException("Missing mods: [$missingMods]")
} }
// TODO: Scheduled for removal 3.10.14
// Renames as of version 3.1.8, because of translation conflicts with the property "Range" and the difficulty "Immortal" // Renames as of version 3.1.8, because of translation conflicts with the property "Range" and the difficulty "Immortal"
// Needs to be BEFORE tileMap.setTransients, because the units' setTransients is called from there // Needs to be BEFORE tileMap.setTransients, because the units' setTransients is called from there
for (tile in tileMap.values) // for (tile in tileMap.values)
for (unit in tile.getUnits()) { // for (unit in tile.getUnits()) {
if (unit.name == "Immortal") unit.name = "Persian Immortal" // if (unit.name == "Immortal") unit.name = "Persian Immortal"
if (unit.promotions.promotions.contains("Range")) { // if (unit.promotions.promotions.contains("Range")) {
unit.promotions.promotions.remove("Range") // unit.promotions.promotions.remove("Range")
unit.promotions.promotions.add("Extended Range") // unit.promotions.promotions.add("Extended Range")
} // }
} // }
tileMap.setTransients(ruleSet) tileMap.setTransients(ruleSet)
@ -285,67 +286,72 @@ class GameInfo {
civInfo.policies.adoptedPolicies.remove("Facism") civInfo.policies.adoptedPolicies.remove("Facism")
civInfo.policies.adoptedPolicies.add("Fascism") civInfo.policies.adoptedPolicies.add("Fascism")
} }
}
// This doesn't HAVE to go here, but why not. // This doesn't HAVE to go here, but why not.
// As of version 3.1.3, trade offers of "Declare war on X" and "Introduction to X" were changed to X, // As of version 3.1.3, trade offers of "Declare war on X" and "Introduction to X" were changed to X,
// with the extra text being added only on UI display (solved a couple of problems). // with the extra text being added only on UI display (solved a couple of problems).
for (trade in civInfo.tradeRequests.map { it.trade }) { // TODO: Scheduled for removal 3.10.14
for (offer in trade.theirOffers.union(trade.ourOffers)) { // for (trade in civInfo.tradeRequests.map { it.trade }) {
offer.name = offer.name.removePrefix("Declare war on ") // for (offer in trade.theirOffers.union(trade.ourOffers)) {
offer.name = offer.name.removePrefix("Introduction to ") // offer.name = offer.name.removePrefix("Declare war on ")
} // offer.name = offer.name.removePrefix("Introduction to ")
} // }
// }
// TODO: Scheduled for removal 3.10.14
// As of 3.4.9 cities are referenced by id, not by name // As of 3.4.9 cities are referenced by id, not by name
// So try to update every tradeRequest (if there are no conflicting names) // So try to update every tradeRequest (if there are no conflicting names)
for (tradeRequest in civInfo.tradeRequests) { // for (tradeRequest in civInfo.tradeRequests) {
val trade = tradeRequest.trade // val trade = tradeRequest.trade
val toRemove = ArrayList<TradeOffer>() // val toRemove = ArrayList<TradeOffer>()
for (offer in trade.ourOffers) { // for (offer in trade.ourOffers) {
if (offer.type == TradeType.City) { // if (offer.type == TradeType.City) {
val countNames = civInfo.cities.count { it.name == offer.name } // val countNames = civInfo.cities.count { it.name == offer.name }
//
if (countNames == 1) // if (countNames == 1)
offer.name = civInfo.cities.first { it.name == offer.name }.id // offer.name = civInfo.cities.first { it.name == offer.name }.id
// There are conflicting names: we can't guess what city was being offered // // There are conflicting names: we can't guess what city was being offered
else if (countNames > 1) // else if (countNames > 1)
toRemove.add(offer) // toRemove.add(offer)
} // }
} // }
//
trade.ourOffers.removeAll(toRemove) // trade.ourOffers.removeAll(toRemove)
toRemove.clear() // toRemove.clear()
//
val themCivInfo = getCivilization(tradeRequest.requestingCiv) // val themCivInfo = getCivilization(tradeRequest.requestingCiv)
for (offer in trade.theirOffers) { // for (offer in trade.theirOffers) {
if (offer.type == TradeType.City) { // if (offer.type == TradeType.City) {
val countNames = themCivInfo.cities.count { it.name == offer.name } // val countNames = themCivInfo.cities.count { it.name == offer.name }
//
if (countNames == 1) // if (countNames == 1)
offer.name = themCivInfo.cities.first { it.name == offer.name }.id // offer.name = themCivInfo.cities.first { it.name == offer.name }.id
// There are conflicting names: we can't guess what city was being offered // // There are conflicting names: we can't guess what city was being offered
else if (countNames > 1) // else if (countNames > 1)
toRemove.add(offer) // toRemove.add(offer)
} // }
} // }
//
trade.theirOffers.removeAll(toRemove) // trade.theirOffers.removeAll(toRemove)
} // }
// TODO: Scheduled for removal 3.10.14
// As of 3.4.9 cities are referenced by id, not by name // As of 3.4.9 cities are referenced by id, not by name
val toRemove = ArrayList<PopupAlert>() // val toRemove = ArrayList<PopupAlert>()
for (popupAlert in civInfo.popupAlerts.filter { it.type == AlertType.CityConquered }) { // for (popupAlert in civInfo.popupAlerts.filter { it.type == AlertType.CityConquered }) {
val countNames = getCities().count { it.name == popupAlert.value } // val countNames = getCities().count { it.name == popupAlert.value }
//
if (countNames == 1) // if (countNames == 1)
popupAlert.value = getCities().first { it.name == popupAlert.value }.id // popupAlert.value = getCities().first { it.name == popupAlert.value }.id
else if (countNames > 1) { // else if (countNames > 1) {
// Sorry again, conflicting names: who knows what city you conquered? // // Sorry again, conflicting names: who knows what city you conquered?
toRemove.add(popupAlert) // toRemove.add(popupAlert)
} // }
} // }
civInfo.popupAlerts.removeAll(toRemove) // civInfo.popupAlerts.removeAll(toRemove)
} // }
for (civInfo in civilizations) civInfo.setNationTransient() for (civInfo in civilizations) civInfo.setNationTransient()
for (civInfo in civilizations) civInfo.setTransients() for (civInfo in civilizations) civInfo.setTransients()
@ -364,7 +370,7 @@ class GameInfo {
for (cityInfo in civInfo.cities) cityInfo.cityStats.updateCityHappiness() for (cityInfo in civInfo.cities) cityInfo.cityStats.updateCityHappiness()
for (cityInfo in civInfo.cities) { for (cityInfo in civInfo.cities) {
if(cityInfo.cityConstructions.currentConstruction!="") { // move it to the top of the queue if (cityInfo.cityConstructions.currentConstruction != "") { // move it to the top of the queue
val constructionQueue = cityInfo.cityConstructions.constructionQueue val constructionQueue = cityInfo.cityConstructions.constructionQueue
val itemsInQueue = constructionQueue.toList() val itemsInQueue = constructionQueue.toList()
constructionQueue.clear() constructionQueue.clear()
@ -372,6 +378,13 @@ class GameInfo {
constructionQueue.addAll(itemsInQueue) constructionQueue.addAll(itemsInQueue)
cityInfo.cityConstructions.currentConstruction = "" cityInfo.cityConstructions.currentConstruction = ""
} }
// As of 3.10.14, specialists are saved by name not by stat
// for((key, value) in cityInfo.population.specialists.toHashMap())
// cityInfo.population.specialistAllocations.add(
// cityInfo.population.specialistNameByStat(key), value.toInt())
// cityInfo.population.specialists.clear()
cityInfo.cityStats.update() cityInfo.cityStats.update()
} }
} }

View File

@ -19,12 +19,12 @@ import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat import com.unciv.models.stats.Stat
import com.unciv.models.stats.StatMap
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.equalsPlaceholderText import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.ui.utils.withoutItem import com.unciv.ui.utils.withoutItem
import java.util.* import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.HashSet import kotlin.collections.HashSet
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
@ -243,16 +243,16 @@ class CityInfo {
fun containsBuildingUnique(unique:String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) } fun containsBuildingUnique(unique:String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) }
fun getGreatPersonMap():HashMap<String,Stats> { fun getGreatPersonMap():StatMap {
val stats = HashMap<String, Stats>() val stats = StatMap()
if (population.specialists.toString() != "") for((specialist, amount) in population.getNewSpecialists())
stats["Specialists"] = population.specialists.times(3f) stats.add("Specialists", getRuleset().specialists[specialist]!!.greatPersonPoints.times(amount))
val buildingStats = Stats() val buildingStats = Stats()
for (building in cityConstructions.getBuiltBuildings()) for (building in cityConstructions.getBuiltBuildings())
if (building.greatPersonPoints != null) if (building.greatPersonPoints != null)
buildingStats.add(building.greatPersonPoints!!) buildingStats.add(building.greatPersonPoints!!)
if (buildingStats.toString() != "") if (!buildingStats.isEmpty())
stats["Buildings"] = buildingStats stats["Buildings"] = buildingStats
for (entry in stats) { for (entry in stats) {

View File

@ -5,6 +5,7 @@ import com.unciv.UncivGame
import com.unciv.logic.civilization.CityStateType import com.unciv.logic.civilization.CityStateType
import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.RoadStatus
import com.unciv.models.Counter
import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.Unique import com.unciv.models.ruleset.Unique
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
@ -260,10 +261,10 @@ class CityStats {
return stats return stats
} }
private fun getStatsFromSpecialists(specialists: HashMap<String, Int>): Stats { private fun getStatsFromSpecialists(specialists: Counter<String>): Stats {
val stats = Stats() val stats = Stats()
for (entry in specialists.filter { it.value > 0 }) for (entry in specialists.filter { it.value > 0 })
stats.add(getStatsOfSpecialist(entry.key) * entry.value.toFloat()) stats.add(getStatsOfSpecialist(entry.key) * entry.value)
return stats return stats
} }

View File

@ -20,6 +20,8 @@ class PopulationManager {
// Being deprecated out // Being deprecated out
val specialists = Stats() val specialists = Stats()
// In favor of this bad boy
val specialistAllocations = Counter<String>()
fun getNewSpecialists() = convertStatsToSpecialistHashmap(specialists) fun getNewSpecialists() = convertStatsToSpecialistHashmap(specialists)

View File

@ -85,7 +85,7 @@ class Building : NamedStats(), IConstruction {
if (providesFreeBuilding != null) if (providesFreeBuilding != null)
stringBuilder.appendln("Provides a free [$providesFreeBuilding] in the city".tr()) stringBuilder.appendln("Provides a free [$providesFreeBuilding] in the city".tr())
if(uniques.isNotEmpty()) stringBuilder.appendln(uniques.asSequence().map { it.tr() }.joinToString("\n")) if(uniques.isNotEmpty()) stringBuilder.appendln(uniques.asSequence().map { it.tr() }.joinToString("\n"))
if (stats.toString() != "") if (!stats.isEmpty())
stringBuilder.appendln(stats) stringBuilder.appendln(stats)
val percentStats = getStatPercentageBonuses(civInfo) val percentStats = getStatPercentageBonuses(civInfo)

View File

@ -317,4 +317,5 @@ object RulesetCache :HashMap<String,Ruleset>() {
class Specialist: NamedStats() { class Specialist: NamedStats() {
var color = ArrayList<Int>() var color = ArrayList<Int>()
val colorObject by lazy { colorFromRGB(color) } val colorObject by lazy { colorFromRGB(color) }
var greatPersonPoints= Stats()
} }

View File

@ -57,12 +57,16 @@ open class Stats() {
return stats return stats
} }
operator fun times(number: Int) = times(number.toFloat())
operator fun times(number: Float): Stats { operator fun times(number: Float): Stats {
val hashMap = toHashMap() val hashMap = toHashMap()
for (stat in Stat.values()) hashMap[stat] = number * hashMap[stat]!! for (stat in Stat.values()) hashMap[stat] = number * hashMap[stat]!!
return Stats(hashMap) return Stats(hashMap)
} }
fun isEmpty() = equals(Stats())
override fun toString(): String { override fun toString(): String {
return toHashMap().filter { it.value != 0f } return toHashMap().filter { it.value != 0f }
.map { (if (it.value > 0) "+" else "") + it.value.toInt() + " " + it.key.toString().tr() }.joinToString() .map { (if (it.value > 0) "+" else "") + it.value.toInt() + " " + it.key.toString().tr() }.joinToString()