diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 744a652b5e..8f97ea4c90 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -279,7 +279,7 @@ object UnitAutomation { .firstOrNull { val tile = it.currentTile it.type == UnitType.Civilian && - (it.hasUnique(Constants.settlerUnique) || unit.name in GreatPersonManager().statToGreatPersonMapping.values) + (it.hasUnique(Constants.settlerUnique) || unit.isGreatPerson()) && tile.militaryUnit == null && unit.movement.canMoveTo(tile) && unit.movement.canReach(tile) } if (settlerOrGreatPersonToAccompany == null) return false diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index b25e494a55..5046048507 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -235,7 +235,7 @@ class CivilizationInfo { //region Units fun getCivUnits(): Sequence = units.asSequence() - fun getCivGreatPeople(): Sequence = getCivUnits().filter { mapUnit -> mapUnit.hasUnique("Great Person - []") } + fun getCivGreatPeople(): Sequence = getCivUnits().filter { mapUnit -> mapUnit.isGreatPerson() } fun addUnit(mapUnit: MapUnit, updateCivInfo: Boolean = true) { val newList = ArrayList(units) @@ -402,6 +402,10 @@ class CivilizationInfo { } } + + fun getGreatPeople() = gameInfo.ruleSet.units.values.asSequence() + .filter { it.isGreatPerson() }.map { getEquivalentUnit(it.name) }.toHashSet() + //endregion //region state-changing functions @@ -559,7 +563,7 @@ class CivilizationInfo { if (!gameInfo.ruleSet.units.containsKey(unitName)) return val unit = getEquivalentUnit(unitName) placeUnitNearTile(cityToAddTo.location, unit.name) - if (unit.uniques.any { it.equalsPlaceholderText("Great Person - []") }) + if (unit.isGreatPerson()) addNotification("A [${unit.name}] has been born in [${cityToAddTo.name}]!", cityToAddTo.location, Color.GOLD) } diff --git a/core/src/com/unciv/logic/civilization/QuestManager.kt b/core/src/com/unciv/logic/civilization/QuestManager.kt index fe5f8d697c..942768f3c2 100644 --- a/core/src/com/unciv/logic/civilization/QuestManager.kt +++ b/core/src/com/unciv/logic/civilization/QuestManager.kt @@ -502,7 +502,7 @@ class QuestManager { val greatPeople = ruleSet.units.values .asSequence() - .filter { baseUnit -> baseUnit.uniques.any { it.equalsPlaceholderText("Great Person - []") } } + .filter { it.isGreatPerson() } .map { it.getReplacedUnit(ruleSet) } .distinct() .filter { !challengerGreatPeople.contains(it) && !cityStateGreatPeople.contains(it) } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 48eefceaf4..033afa460e 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -304,6 +304,8 @@ class MapUnit { fun canGarrison() = type.isMilitary() && type.isLandUnit() + fun isGreatPerson() = baseUnit.isGreatPerson() + //endregion //region state-changing functions diff --git a/core/src/com/unciv/models/ruleset/Unique.kt b/core/src/com/unciv/models/ruleset/Unique.kt index eccca4c50c..d07a6a87f7 100644 --- a/core/src/com/unciv/models/ruleset/Unique.kt +++ b/core/src/com/unciv/models/ruleset/Unique.kt @@ -1,6 +1,5 @@ package com.unciv.models.ruleset -import com.unciv.Constants import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.stats.Stats @@ -59,14 +58,21 @@ object UniqueTriggerActivation { "Free Great Person" -> { if (civInfo.isPlayerCivilization()) civInfo.greatPeople.freeGreatPeople++ else { + val greatPeople = civInfo.getGreatPeople() + if (greatPeople.isEmpty()) return + var greatPerson = civInfo.getGreatPeople().random() + val preferredVictoryType = civInfo.victoryType() - val greatPerson = when (preferredVictoryType) { - VictoryType.Cultural -> "Great Artist" - VictoryType.Scientific -> "Great Scientist" - else -> civInfo.gameInfo.ruleSet.units.values - .filter { it.uniqueObjects.any { it.placeholderText == "Great Person - []" } }.map { it.name }.random() + if (preferredVictoryType == VictoryType.Cultural) { + val culturalGP = greatPeople.firstOrNull { it.uniques.contains("Great Person - [Culture]") } + if (culturalGP != null) greatPerson = culturalGP } - civInfo.addUnit(greatPerson, chosenCity) + if (preferredVictoryType == VictoryType.Scientific) { + val scientificGP = greatPeople.firstOrNull { it.uniques.contains("Great Person - [Science]") } + if (scientificGP != null) greatPerson = scientificGP + } + + civInfo.addUnit(greatPerson.name, chosenCity) } } "+1 population in each city" -> diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 6507ca2eac..cd075f8647 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -23,21 +23,21 @@ class BaseUnit : INamed, IConstruction { var cost: Int = 0 var hurryCostModifier: Int = 0 var movement: Int = 0 - var strength:Int = 0 - var rangedStrength:Int = 0 - var range:Int = 2 + var strength: Int = 0 + var rangedStrength: Int = 0 + var range: Int = 2 var interceptRange = 0 lateinit var unitType: UnitType - var requiredTech:String? = null - var requiredResource:String? = null - var uniques =HashSet() + var requiredTech: String? = null + var requiredResource: String? = null + var uniques = HashSet() val uniqueObjects: List by lazy { uniques.map { Unique(it) } } - var promotions =HashSet() - var obsoleteTech:String?=null - var upgradesTo:String? = null - var replaces:String?=null - var uniqueTo:String?=null - var attackSound:String?=null + var promotions = HashSet() + var obsoleteTech: String? = null + var upgradesTo: String? = null + var replaces: String? = null + var uniqueTo: String? = null + var attackSound: String? = null fun getShortDescription(): String { val infoList = mutableListOf() @@ -51,28 +51,28 @@ class BaseUnit : INamed, IConstruction { return infoList.joinToString() } - fun getDescription(forPickerScreen:Boolean): String { + fun getDescription(forPickerScreen: Boolean): String { val sb = StringBuilder() - if(requiredResource!=null) sb.appendln("Consumes 1 [{$requiredResource}]".tr()) - if(!forPickerScreen) { - if(uniqueTo!=null) sb.appendln("Unique to [$uniqueTo], replaces [$replaces]".tr()) + if (requiredResource != null) sb.appendln("Consumes 1 [{$requiredResource}]".tr()) + if (!forPickerScreen) { + if (uniqueTo != null) sb.appendln("Unique to [$uniqueTo], replaces [$replaces]".tr()) else sb.appendln("{Cost}: $cost".tr()) - if(requiredTech!=null) sb.appendln("Required tech: [$requiredTech]".tr()) - if(upgradesTo!=null) sb.appendln("Upgrades to [$upgradesTo]".tr()) - if(obsoleteTech!=null) sb.appendln("Obsolete with [$obsoleteTech]".tr()) + if (requiredTech != null) sb.appendln("Required tech: [$requiredTech]".tr()) + if (upgradesTo != null) sb.appendln("Upgrades to [$upgradesTo]".tr()) + if (obsoleteTech != null) sb.appendln("Obsolete with [$obsoleteTech]".tr()) } - if(strength!=0) { + if (strength != 0) { sb.append("$strength${Fonts.strength}, ") if (rangedStrength != 0) sb.append("$rangedStrength${Fonts.rangedStrength}, ") if (rangedStrength != 0) sb.append("$range${Fonts.range}, ") } sb.appendln("$movement${Fonts.movement}") - for(unique in uniques) + for (unique in uniques) sb.appendln(Translations.translateBonusOrPenalty(unique)) if (promotions.isNotEmpty()) { - sb.append((if (promotions.size==1) "Free promotion:" else "Free promotions:").tr()) + sb.append((if (promotions.size == 1) "Free promotion:" else "Free promotions:").tr()) sb.appendln(promotions.joinToString(", ", " ") { it.tr() }) } @@ -110,11 +110,11 @@ class BaseUnit : INamed, IConstruction { return (cost / 10).toInt() * 10 // rounded down o nearest ten } - fun getDisbandGold() = getBaseGoldCost().toInt()/20 + fun getDisbandGold() = getBaseGoldCost().toInt() / 20 override fun shouldBeDisplayed(construction: CityConstructions): Boolean { val rejectionReason = getRejectionReason(construction) - return rejectionReason=="" + return rejectionReason == "" || rejectionReason.startsWith("Requires") || rejectionReason.startsWith("Consumes") } @@ -122,7 +122,7 @@ class BaseUnit : INamed, IConstruction { fun getRejectionReason(construction: CityConstructions): String { if (unitType.isWaterUnit() && !construction.cityInfo.getCenterTile().isCoastalTile()) return "Can only build water units in coastal cities" - for (unique in uniqueObjects.filter { it.placeholderText == "Not displayed as an available construction without []"}) { + for (unique in uniqueObjects.filter { it.placeholderText == "Not displayed as an available construction without []" }) { val filter = unique.params[0] if ((filter in construction.cityInfo.civInfo.gameInfo.ruleSet.tileResources && !construction.cityInfo.civInfo.hasResource(filter)) || (filter in construction.cityInfo.civInfo.gameInfo.ruleSet.buildings && !construction.containsBuildingOrEquivalent(filter))) @@ -135,10 +135,10 @@ class BaseUnit : INamed, IConstruction { fun getRejectionReason(civInfo: CivilizationInfo): String { if (uniques.contains("Unbuildable")) return "Unbuildable" - if (requiredTech!=null && !civInfo.tech.isResearched(requiredTech!!)) return "$requiredTech not researched" - if (obsoleteTech!=null && civInfo.tech.isResearched(obsoleteTech!!)) return "Obsolete by $obsoleteTech" - if (uniqueTo!=null && uniqueTo!=civInfo.civName) return "Unique to $uniqueTo" - if (civInfo.gameInfo.ruleSet.units.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return "Our unique unit replaces this" + if (requiredTech != null && !civInfo.tech.isResearched(requiredTech!!)) return "$requiredTech not researched" + if (obsoleteTech != null && civInfo.tech.isResearched(obsoleteTech!!)) return "Obsolete by $obsoleteTech" + if (uniqueTo != null && uniqueTo != civInfo.civName) return "Unique to $uniqueTo" + if (civInfo.gameInfo.ruleSet.units.values.any { it.uniqueTo == civInfo.civName && it.replaces == name }) return "Our unique unit replaces this" if (!civInfo.gameInfo.gameParameters.nuclearWeaponsEnabled && uniques.contains("Nuclear weapon")) return "Disabled by setting" for (unique in uniqueObjects.filter { it.placeholderText == "Requires []" }) { @@ -147,13 +147,13 @@ class BaseUnit : INamed, IConstruction { if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) }) return unique.text // Wonder is not built } else if (!civInfo.policies.adoptedPolicies.contains(filter)) return "Policy is not adopted" } - if (requiredResource!=null && !civInfo.hasResource(requiredResource!!) && !civInfo.gameInfo.gameParameters.godMode) return "Consumes 1 [$requiredResource]" + if (requiredResource != null && !civInfo.hasResource(requiredResource!!) && !civInfo.gameInfo.gameParameters.godMode) return "Consumes 1 [$requiredResource]" if (uniques.contains(Constants.settlerUnique) && civInfo.isCityState()) return "No settler for city-states" if (uniques.contains(Constants.settlerUnique) && civInfo.isOneCityChallenger()) return "No settler for players in One City Challenge" return "" } - fun isBuildable(civInfo: CivilizationInfo) = getRejectionReason(civInfo)=="" + fun isBuildable(civInfo: CivilizationInfo) = getRejectionReason(civInfo) == "" override fun isBuildable(cityConstructions: CityConstructions): Boolean { return getRejectionReason(cityConstructions) == "" @@ -192,8 +192,8 @@ class BaseUnit : INamed, IConstruction { } // This is to be deprecated and converted to "All newly-trained [] in this city receive the [] promotion" - keeping it here to that mods with this can still work for now - if (unit.type in listOf(UnitType.Melee,UnitType.Mounted,UnitType.Armor) - && construction.cityInfo.containsBuildingUnique("All newly-trained melee, mounted, and armored units in this city receive the Drill I promotion")) + if (unit.type in listOf(UnitType.Melee, UnitType.Mounted, UnitType.Armor) + && construction.cityInfo.containsBuildingUnique("All newly-trained melee, mounted, and armored units in this city receive the Drill I promotion")) unit.promotions.addPromotion("Drill I", isFree = true) return true @@ -201,7 +201,7 @@ class BaseUnit : INamed, IConstruction { override fun getResource(): String? = requiredResource - fun getDirectUpgradeUnit(civInfo: CivilizationInfo):BaseUnit{ + fun getDirectUpgradeUnit(civInfo: CivilizationInfo): BaseUnit { return civInfo.getEquivalentUnit(upgradesTo!!) } @@ -212,7 +212,7 @@ class BaseUnit : INamed, IConstruction { else ruleset.units[replaces!!]!! } - fun matchesFilter(filter:String):Boolean { + fun matchesFilter(filter: String): Boolean { if (filter == unitType.name) return true if (filter == name) return true if (filter == "All") return true @@ -223,4 +223,6 @@ class BaseUnit : INamed, IConstruction { if ((filter == "military" || filter == "Military" || filter == "military units") && unitType.isMilitary()) return true return false } + + fun isGreatPerson() = uniqueObjects.any { it.placeholderText == "Great Person - []" } } diff --git a/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt index 77adcbcef3..5290c45366 100644 --- a/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt @@ -18,9 +18,7 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() { closeButton.isVisible=false rightSideButton.setText("Choose a free great person".tr()) - val greatPersonNames = GreatPersonManager().statToGreatPersonMapping.values - .union(listOf("Great General")) - val greatPersonUnits = greatPersonNames.map { civInfo.getEquivalentUnit(it) } + val greatPersonUnits = civInfo.getGreatPeople() for (unit in greatPersonUnits) { val button = Button(skin)