mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-27 13:55:54 -04:00
Add unique for Personality to avoid building object (#11160)
* Add unique for Personality to avoid building object * Switch civInfo with city * Missed a spot * baseUnitFilter instead of "unitFilter"
This commit is contained in:
parent
b80ab2d3e6
commit
17abf7840b
@ -10,6 +10,7 @@ import com.unciv.logic.civilization.NotificationIcon
|
|||||||
import com.unciv.logic.civilization.PlayerType
|
import com.unciv.logic.civilization.PlayerType
|
||||||
import com.unciv.logic.map.BFS
|
import com.unciv.logic.map.BFS
|
||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
|
import com.unciv.models.ruleset.IConstruction
|
||||||
import com.unciv.models.ruleset.INonPerpetualConstruction
|
import com.unciv.models.ruleset.INonPerpetualConstruction
|
||||||
import com.unciv.models.ruleset.MilestoneType
|
import com.unciv.models.ruleset.MilestoneType
|
||||||
import com.unciv.models.ruleset.PerpetualConstruction
|
import com.unciv.models.ruleset.PerpetualConstruction
|
||||||
@ -17,6 +18,7 @@ import com.unciv.models.ruleset.Victory
|
|||||||
import com.unciv.models.ruleset.nation.PersonalityValue
|
import com.unciv.models.ruleset.nation.PersonalityValue
|
||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
@ -25,6 +27,20 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
|
|
||||||
private val city = cityConstructions.city
|
private val city = cityConstructions.city
|
||||||
private val civInfo = city.civ
|
private val civInfo = city.civ
|
||||||
|
|
||||||
|
private val personality = civInfo.getPersonality()
|
||||||
|
|
||||||
|
private val constructionsToAvoid = personality.getMatchingUniques(UniqueType.WillNotBuild, StateForConditionals(city))
|
||||||
|
.map{ it.params[0] }
|
||||||
|
private fun shouldAvoidConstruction (construction: IConstruction): Boolean {
|
||||||
|
for (toAvoid in constructionsToAvoid) {
|
||||||
|
if (construction is Building && construction.matchesFilter(toAvoid))
|
||||||
|
return true
|
||||||
|
if (construction is BaseUnit && construction.matchesFilter(toAvoid))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private val disabledAutoAssignConstructions: Set<String> =
|
private val disabledAutoAssignConstructions: Set<String> =
|
||||||
if (civInfo.isHuman()) GUI.getSettings().disabledAutoAssignConstructions
|
if (civInfo.isHuman()) GUI.getSettings().disabledAutoAssignConstructions
|
||||||
@ -33,7 +49,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
private val buildableBuildings = hashMapOf<String, Boolean>()
|
private val buildableBuildings = hashMapOf<String, Boolean>()
|
||||||
private val buildableUnits = hashMapOf<String, Boolean>()
|
private val buildableUnits = hashMapOf<String, Boolean>()
|
||||||
private val buildings = city.getRuleset().buildings.values.asSequence()
|
private val buildings = city.getRuleset().buildings.values.asSequence()
|
||||||
.filterNot { it.name in disabledAutoAssignConstructions }
|
.filterNot { it.name in disabledAutoAssignConstructions || shouldAvoidConstruction(it) }
|
||||||
|
|
||||||
private val nonWonders = buildings.filterNot { it.isAnyWonder() }
|
private val nonWonders = buildings.filterNot { it.isAnyWonder() }
|
||||||
.filterNot { buildableBuildings[it.name] == false } // if we already know that this building can't be built here then don't even consider it
|
.filterNot { buildableBuildings[it.name] == false } // if we already know that this building can't be built here then don't even consider it
|
||||||
@ -41,8 +57,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
private val wonders = buildings.filter { it.isAnyWonder() }
|
private val wonders = buildings.filter { it.isAnyWonder() }
|
||||||
|
|
||||||
private val units = city.getRuleset().units.values.asSequence()
|
private val units = city.getRuleset().units.values.asSequence()
|
||||||
.filterNot { buildableUnits[it.name] == false } // if we already know that this unit can't be built here then don't even consider it
|
.filterNot { buildableUnits[it.name] == false || // if we already know that this unit can't be built here then don't even consider it
|
||||||
.filterNot { it.name in disabledAutoAssignConstructions }
|
it.name in disabledAutoAssignConstructions || shouldAvoidConstruction(it) }
|
||||||
|
|
||||||
private val civUnits = civInfo.units.getCivUnits()
|
private val civUnits = civInfo.units.getCivUnits()
|
||||||
private val militaryUnits = civUnits.count { it.baseUnit.isMilitary() }
|
private val militaryUnits = civUnits.count { it.baseUnit.isMilitary() }
|
||||||
@ -151,7 +167,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
modifier = 5f // there's a settler just sitting here, doing nothing - BAD
|
modifier = 5f // there's a settler just sitting here, doing nothing - BAD
|
||||||
|
|
||||||
if (civInfo.playerType == PlayerType.Human) modifier /= 2 // Players prefer to make their own unit choices usually
|
if (civInfo.playerType == PlayerType.Human) modifier /= 2 // Players prefer to make their own unit choices usually
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Military)
|
modifier *= personality.scaledFocus(PersonalityValue.Military)
|
||||||
addChoice(relativeCostEffectiveness, militaryUnit, modifier)
|
addChoice(relativeCostEffectiveness, militaryUnit, modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +231,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
if (city.cityStats.currentCityStats.culture == 0f) // It won't grow if we don't help it
|
if (city.cityStats.currentCityStats.culture == 0f) // It won't grow if we don't help it
|
||||||
modifier = 0.8f
|
modifier = 0.8f
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Culture)) modifier = 1.6f
|
if (civInfo.wantsToFocusOn(Victory.Focus.Culture)) modifier = 1.6f
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Culture)
|
modifier *= personality.scaledFocus(PersonalityValue.Culture)
|
||||||
addChoice(relativeCostEffectiveness, cultureBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, cultureBuilding.name, modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,12 +306,12 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
.filterBuildable()
|
.filterBuildable()
|
||||||
.minByOrNull { it.cost } ?: return
|
.minByOrNull { it.cost } ?: return
|
||||||
if ((isAtWar ||
|
if ((isAtWar ||
|
||||||
!civInfo.wantsToFocusOn(Victory.Focus.Culture) || !city.civ.getPersonality().isNeutralPersonality)) {
|
!civInfo.wantsToFocusOn(Victory.Focus.Culture) || !personality.isNeutralPersonality)) {
|
||||||
var modifier = if (cityIsOverAverageProduction) 0.5f else 0.1f // You shouldn't be cranking out units anytime soon
|
var modifier = if (cityIsOverAverageProduction) 0.5f else 0.1f // You shouldn't be cranking out units anytime soon
|
||||||
if (isAtWar) modifier *= 2
|
if (isAtWar) modifier *= 2
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Military))
|
if (civInfo.wantsToFocusOn(Victory.Focus.Military))
|
||||||
modifier *= 1.3f
|
modifier *= 1.3f
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Military)
|
modifier *= personality.scaledFocus(PersonalityValue.Military)
|
||||||
addChoice(relativeCostEffectiveness, unitTrainingBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, unitTrainingBuilding.name, modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,7 +345,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
if (civHappiness > 5) modifier = 1 / 2f // less desperate
|
if (civHappiness > 5) modifier = 1 / 2f // less desperate
|
||||||
if (civHappiness < 0) modifier = 3f // more desperate
|
if (civHappiness < 0) modifier = 3f // more desperate
|
||||||
else if (happinessBuilding.hasUnique(UniqueType.RemoveAnnexUnhappiness)) modifier = 2f // building courthouse is always important
|
else if (happinessBuilding.hasUnique(UniqueType.RemoveAnnexUnhappiness)) modifier = 2f // building courthouse is always important
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Happiness)
|
modifier *= personality.scaledFocus(PersonalityValue.Happiness)
|
||||||
addChoice(relativeCostEffectiveness, happinessBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, happinessBuilding.name, modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +359,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
var modifier = 1.1f
|
var modifier = 1.1f
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Science))
|
if (civInfo.wantsToFocusOn(Victory.Focus.Science))
|
||||||
modifier *= 1.4f
|
modifier *= 1.4f
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Science)
|
modifier *= personality.scaledFocus(PersonalityValue.Science)
|
||||||
addChoice(relativeCostEffectiveness, scienceBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, scienceBuilding.name, modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +368,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
.filterBuildable()
|
.filterBuildable()
|
||||||
.minByOrNull { it.cost } ?: return
|
.minByOrNull { it.cost } ?: return
|
||||||
var modifier = if (civInfo.stats.statsForNextTurn.gold < 0) 3f else 1.2f
|
var modifier = if (civInfo.stats.statsForNextTurn.gold < 0) 3f else 1.2f
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Gold)
|
modifier *= personality.scaledFocus(PersonalityValue.Gold)
|
||||||
addChoice(relativeCostEffectiveness, goldBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, goldBuilding.name, modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +377,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
.filter { it.isStatRelated(Stat.Production) }
|
.filter { it.isStatRelated(Stat.Production) }
|
||||||
.filterBuildable()
|
.filterBuildable()
|
||||||
.minByOrNull { it.cost } ?: return
|
.minByOrNull { it.cost } ?: return
|
||||||
val modifier = city.civ.getPersonality().scaledFocus(PersonalityValue.Production)
|
val modifier = personality.scaledFocus(PersonalityValue.Production)
|
||||||
addChoice(relativeCostEffectiveness, productionBuilding.name, 1.5f * modifier)
|
addChoice(relativeCostEffectiveness, productionBuilding.name, 1.5f * modifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +391,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
}.filterBuildable().minByOrNull { it.cost } ?: return
|
}.filterBuildable().minByOrNull { it.cost } ?: return
|
||||||
var modifier = 1f
|
var modifier = 1f
|
||||||
if (city.population.population < 5) modifier = 1.3f
|
if (city.population.population < 5) modifier = 1.3f
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Food)
|
modifier *= personality.scaledFocus(PersonalityValue.Food)
|
||||||
addChoice(relativeCostEffectiveness, foodBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, foodBuilding.name, modifier)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -388,7 +404,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
.minByOrNull { it.cost } ?: return
|
.minByOrNull { it.cost } ?: return
|
||||||
var modifier = 0.5f
|
var modifier = 0.5f
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Faith)) modifier = 1f
|
if (civInfo.wantsToFocusOn(Victory.Focus.Faith)) modifier = 1f
|
||||||
modifier *= city.civ.getPersonality().scaledFocus(PersonalityValue.Faith)
|
modifier *= personality.scaledFocus(PersonalityValue.Faith)
|
||||||
addChoice(relativeCostEffectiveness, faithBuilding.name, modifier)
|
addChoice(relativeCostEffectiveness, faithBuilding.name, modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,6 +458,7 @@ object NextTurnAutomation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun trainSettler(civInfo: Civilization) {
|
private fun trainSettler(civInfo: Civilization) {
|
||||||
|
val personality = civInfo.getPersonality()
|
||||||
if (civInfo.isCityState()) return
|
if (civInfo.isCityState()) return
|
||||||
if (civInfo.isAtWar()) return // don't train settlers when you could be training troops.
|
if (civInfo.isAtWar()) return // don't train settlers when you could be training troops.
|
||||||
if (civInfo.wantsToFocusOn(Victory.Focus.Culture) && civInfo.cities.size > 3 &&
|
if (civInfo.wantsToFocusOn(Victory.Focus.Culture) && civInfo.cities.size > 3 &&
|
||||||
@ -467,7 +468,9 @@ object NextTurnAutomation {
|
|||||||
if (civInfo.getHappiness() <= civInfo.cities.size) return
|
if (civInfo.getHappiness() <= civInfo.cities.size) return
|
||||||
|
|
||||||
val settlerUnits = civInfo.gameInfo.ruleset.units.values
|
val settlerUnits = civInfo.gameInfo.ruleset.units.values
|
||||||
.filter { it.isCityFounder() && it.isBuildable(civInfo) }
|
.filter { it.isCityFounder() && it.isBuildable(civInfo) &&
|
||||||
|
personality.getMatchingUniques(UniqueType.WillNotBuild, StateForConditionals(civInfo))
|
||||||
|
.none { unique -> it.matchesFilter(unique.params[0]) } }
|
||||||
if (settlerUnits.isEmpty()) return
|
if (settlerUnits.isEmpty()) return
|
||||||
if (!civInfo.units.getCivUnits().none { it.hasUnique(UniqueType.FoundCity) }) return
|
if (!civInfo.units.getCivUnits().none { it.hasUnique(UniqueType.FoundCity) }) return
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ enum class UniqueTarget(
|
|||||||
|
|
||||||
// Civilization-specific
|
// Civilization-specific
|
||||||
Nation(inheritsFrom = Global),
|
Nation(inheritsFrom = Global),
|
||||||
|
Personality,
|
||||||
Era(inheritsFrom = Global),
|
Era(inheritsFrom = Global),
|
||||||
Tech(inheritsFrom = Global),
|
Tech(inheritsFrom = Global),
|
||||||
Policy(inheritsFrom = Global),
|
Policy(inheritsFrom = Global),
|
||||||
@ -57,7 +58,6 @@ enum class UniqueTarget(
|
|||||||
Tutorial,
|
Tutorial,
|
||||||
CityState(inheritsFrom = Global),
|
CityState(inheritsFrom = Global),
|
||||||
ModOptions,
|
ModOptions,
|
||||||
Personality,
|
|
||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
Conditional("Modifiers that can be added to other uniques to limit when they will be active", modifierType = ModifierType.Conditional),
|
Conditional("Modifiers that can be added to other uniques to limit when they will be active", modifierType = ModifierType.Conditional),
|
||||||
|
@ -600,7 +600,11 @@ enum class UniqueType(
|
|||||||
AutomatedWorkersWillReplace("Will be replaced by automated workers", UniqueTarget.Improvement),
|
AutomatedWorkersWillReplace("Will be replaced by automated workers", UniqueTarget.Improvement),
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
///////////////////////////////////////// region 07 CONDITIONALS /////////////////////////////////////////
|
/////////////////////////////////// region 07 PERSONALITY UNIQUES ////////////////////////////////////////
|
||||||
|
|
||||||
|
WillNotBuild("Will not build [baseUnitFilter/buildingFilter]", UniqueTarget.Personality),
|
||||||
|
|
||||||
|
///////////////////////////////////////// region 08 CONDITIONALS /////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
/////// general conditionals
|
/////// general conditionals
|
||||||
@ -708,7 +712,7 @@ enum class UniqueType(
|
|||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
///////////////////////////////////////// region 08 TRIGGERED ONE-TIME /////////////////////////////////////////
|
///////////////////////////////////////// region 09 TRIGGERED ONE-TIME /////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
OneTimeFreeUnit("Free [unit] appears", UniqueTarget.Triggerable), // used in Policies, Buildings
|
OneTimeFreeUnit("Free [unit] appears", UniqueTarget.Triggerable), // used in Policies, Buildings
|
||||||
@ -762,7 +766,7 @@ enum class UniqueType(
|
|||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////// region 09 TRIGGERS /////////////////////////////////////////
|
///////////////////////////////////////// region 10 TRIGGERS /////////////////////////////////////////
|
||||||
|
|
||||||
TriggerUponResearch("upon discovering [tech]", UniqueTarget.TriggerCondition),
|
TriggerUponResearch("upon discovering [tech]", UniqueTarget.TriggerCondition),
|
||||||
TriggerUponEnteringEra("upon entering the [era]", UniqueTarget.TriggerCondition),
|
TriggerUponEnteringEra("upon entering the [era]", UniqueTarget.TriggerCondition),
|
||||||
@ -789,7 +793,7 @@ enum class UniqueType(
|
|||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////// region 10 UNIT TRIGGERS /////////////////////////////////////////
|
///////////////////////////////////////// region 11 UNIT TRIGGERS /////////////////////////////////////////
|
||||||
|
|
||||||
TriggerUponDefeatingUnit("upon defeating a [mapUnitFilter] unit", UniqueTarget.UnitTriggerCondition),
|
TriggerUponDefeatingUnit("upon defeating a [mapUnitFilter] unit", UniqueTarget.UnitTriggerCondition),
|
||||||
TriggerUponDefeat("upon being defeated", UniqueTarget.UnitTriggerCondition),
|
TriggerUponDefeat("upon being defeated", UniqueTarget.UnitTriggerCondition),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user