mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-25 21:03:15 -04:00
chore: Moved unit functions to UnitManager
This commit is contained in:
parent
1a64184600
commit
4488a6fe51
@ -6,9 +6,9 @@ import com.unciv.json.HashMapVector2
|
||||
import com.unciv.json.json
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.PerpetualConstruction
|
||||
import com.unciv.logic.civilization.managers.TechManager
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyManager
|
||||
import com.unciv.logic.civilization.managers.TechManager
|
||||
import com.unciv.models.ruleset.ModOptions
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
|
||||
@ -178,7 +178,7 @@ object BackwardCompatibility {
|
||||
fun GameInfo.convertFortify() {
|
||||
val reg = Regex("""^Fortify\s+(\d+)([\w\s]*)""")
|
||||
for (civInfo in civilizations) {
|
||||
for (unit in civInfo.getCivUnits()) {
|
||||
for (unit in civInfo.units.getCivUnits()) {
|
||||
if (unit.action != null && reg.matches(unit.action!!)) {
|
||||
val (turns, heal) = reg.find(unit.action!!)!!.destructured
|
||||
unit.turnsFortified = turns.toInt()
|
||||
|
@ -538,7 +538,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
||||
yieldAll(civilizations.filter { it.isCityState() })
|
||||
yieldAll(civilizations.filter { !it.isCityState() })
|
||||
}) {
|
||||
for (unit in civInfo.getCivUnits())
|
||||
for (unit in civInfo.units.getCivUnits())
|
||||
unit.updateVisibleTiles(false) // this needs to be done after all the units are assigned to their civs and all other transients are set
|
||||
civInfo.cache.updateSightAndResources() // only run ONCE and not for each unit - this is a huge performance saver!
|
||||
|
||||
|
@ -323,7 +323,7 @@ object GameStarter {
|
||||
}
|
||||
|
||||
fun placeNearStartingPosition(unitName: String) {
|
||||
civ.placeUnitNearTile(startingLocation.position, unitName)
|
||||
civ.units.placeUnitNearTile(startingLocation.position, unitName)
|
||||
}
|
||||
|
||||
// Determine starting units based on starting era
|
||||
|
@ -128,8 +128,8 @@ object Automation {
|
||||
}
|
||||
|
||||
val totalCarriableUnits =
|
||||
civInfo.getCivUnits().count { it.matchesFilter(carryFilter) }
|
||||
val totalCarryingSlots = civInfo.getCivUnits().sumOf { getCarryAmount(it) }
|
||||
civInfo.units.getCivUnits().count { it.matchesFilter(carryFilter) }
|
||||
val totalCarryingSlots = civInfo.units.getCivUnits().sumOf { getCarryAmount(it) }
|
||||
return totalCarriableUnits < totalCarryingSlots
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
|
||||
|
||||
private val units = cityInfo.getRuleset().units.values
|
||||
|
||||
private val civUnits = civInfo.getCivUnits()
|
||||
private val civUnits = civInfo.units.getCivUnits()
|
||||
private val militaryUnits = civUnits.count { it.baseUnit.isMilitary() }
|
||||
private val workers = civUnits.count { it.hasUniqueToBuildImprovements && it.isCivilian() }.toFloat()
|
||||
private val cities = civInfo.cities.size
|
||||
|
@ -10,9 +10,9 @@ class BarbarianAutomation(val civInfo: CivilizationInfo) {
|
||||
|
||||
fun automate() {
|
||||
// ranged go first, after melee and then everyone else
|
||||
civInfo.getCivUnits().filter { it.baseUnit.isRanged() }.forEach { automateUnit(it) }
|
||||
civInfo.getCivUnits().filter { it.baseUnit.isMelee() }.forEach { automateUnit(it) }
|
||||
civInfo.getCivUnits().filter { !it.baseUnit.isRanged() && !it.baseUnit.isMelee() }.forEach { automateUnit(it) }
|
||||
civInfo.units.getCivUnits().filter { it.baseUnit.isRanged() }.forEach { automateUnit(it) }
|
||||
civInfo.units.getCivUnits().filter { it.baseUnit.isMelee() }.forEach { automateUnit(it) }
|
||||
civInfo.units.getCivUnits().filter { !it.baseUnit.isRanged() && !it.baseUnit.isMelee() }.forEach { automateUnit(it) }
|
||||
}
|
||||
|
||||
private fun automateUnit(unit: MapUnit) {
|
||||
|
@ -16,11 +16,11 @@ import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.civilization.PopupAlert
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.map.BFS
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.trade.Trade
|
||||
@ -512,7 +512,7 @@ object NextTurnAutomation {
|
||||
if (resourceCount >= Automation.getReservedSpaceResourceAmount(civInfo))
|
||||
continue
|
||||
|
||||
val unitToDisband = civInfo.getCivUnits()
|
||||
val unitToDisband = civInfo.units.getCivUnits()
|
||||
.filter { it.baseUnit.requiresResource(resource) }
|
||||
.minByOrNull { it.getForceEvaluation() }
|
||||
unitToDisband?.disband()
|
||||
@ -710,7 +710,7 @@ object NextTurnAutomation {
|
||||
if (civInfo.cities.isEmpty() || civInfo.diplomacy.isEmpty()) return
|
||||
if (civInfo.isAtWar() || civInfo.getHappiness() <= 0) return
|
||||
|
||||
val ourMilitaryUnits = civInfo.getCivUnits().filter { !it.isCivilian() }.count()
|
||||
val ourMilitaryUnits = civInfo.units.getCivUnits().filter { !it.isCivilian() }.count()
|
||||
if (ourMilitaryUnits < civInfo.cities.size) return
|
||||
if (ourMilitaryUnits < 4) return // to stop AI declaring war at the beginning of games when everyone isn't set up well enough
|
||||
|
||||
@ -751,7 +751,7 @@ object NextTurnAutomation {
|
||||
val ourCity = closestCities.city1
|
||||
val theirCity = closestCities.city2
|
||||
|
||||
if (civInfo.getCivUnits().filter { it.isMilitary() }.none {
|
||||
if (civInfo.units.getCivUnits().filter { it.isMilitary() }.none {
|
||||
val damageRecievedWhenAttacking =
|
||||
BattleDamage.calculateDamageToAttacker(
|
||||
MapUnitCombatant(it),
|
||||
@ -875,7 +875,7 @@ object NextTurnAutomation {
|
||||
|
||||
|
||||
private fun automateUnits(civInfo: CivilizationInfo) {
|
||||
val sortedUnits = civInfo.getCivUnits().sortedBy { unit ->
|
||||
val sortedUnits = civInfo.units.getCivUnits().sortedBy { unit ->
|
||||
when {
|
||||
unit.baseUnit.isAirUnit() -> 2
|
||||
unit.baseUnit.isRanged() -> 3
|
||||
@ -915,7 +915,7 @@ object NextTurnAutomation {
|
||||
val settlerUnits = civInfo.gameInfo.ruleSet.units.values
|
||||
.filter { it.hasUnique(UniqueType.FoundCity) && it.isBuildable(civInfo) }
|
||||
if (settlerUnits.isEmpty()) return
|
||||
if (civInfo.getCivUnits().none { it.hasUnique(UniqueType.FoundCity) }
|
||||
if (civInfo.units.getCivUnits().none { it.hasUnique(UniqueType.FoundCity) }
|
||||
&& civInfo.cities.none {
|
||||
val currentConstruction = it.cityConstructions.getCurrentConstruction()
|
||||
currentConstruction is BaseUnit && currentConstruction.hasUnique(UniqueType.FoundCity)
|
||||
|
@ -41,7 +41,7 @@ object ReligionAutomation {
|
||||
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
|
||||
if (citiesWithoutOurReligion.count() >
|
||||
4 * civInfo.getCivUnits().count { it.canDoReligiousAction(Constants.spreadReligion) || it.canDoReligiousAction(Constants.removeHeresy) }
|
||||
4 * civInfo.units.getCivUnits().count { it.canDoReligiousAction(Constants.spreadReligion) || it.canDoReligiousAction(Constants.removeHeresy) }
|
||||
) {
|
||||
val (city, pressureDifference) = citiesWithoutOurReligion.map { city ->
|
||||
city to city.religion.getPressureDeficit(civInfo.religionManager.religion?.name)
|
||||
@ -57,7 +57,7 @@ object ReligionAutomation {
|
||||
val holyCity = civInfo.religionManager.getHolyCity()
|
||||
if (holyCity != null
|
||||
&& holyCity in civInfo.cities
|
||||
&& civInfo.getCivUnits().count { it.hasUnique(UniqueType.PreventSpreadingReligion) } == 0
|
||||
&& civInfo.units.getCivUnits().count { it.hasUnique(UniqueType.PreventSpreadingReligion) } == 0
|
||||
&& !holyCity.religion.isProtectedByInquisitor()
|
||||
) {
|
||||
buyInquisitorNear(civInfo, holyCity)
|
||||
@ -77,7 +77,7 @@ object ReligionAutomation {
|
||||
// Todo: buy Great People post industrial era
|
||||
|
||||
// Just buy missionaries to spread our religion outside of our civ
|
||||
if (civInfo.getCivUnits().count { it.canDoReligiousAction(Constants.spreadReligion) } < 4) {
|
||||
if (civInfo.units.getCivUnits().count { it.canDoReligiousAction(Constants.spreadReligion) } < 4) {
|
||||
buyMissionaryInAnyCity(civInfo)
|
||||
return
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ object SpecificUnitAutomation {
|
||||
if (unit.civInfo.gameInfo.turns == 0) { // Special case, we want AI to settle in place on turn 1.
|
||||
val foundCityAction = UnitActions.getFoundCityAction(unit, unit.getTile())
|
||||
// Depending on era and difficulty we might start with more than one settler. In that case settle the one with the best location
|
||||
val otherSettlers = unit.civInfo.getCivUnits().filter { it.currentMovement > 0 && it.baseUnit == unit.baseUnit }
|
||||
val otherSettlers = unit.civInfo.units.getCivUnits().filter { it.currentMovement > 0 && it.baseUnit == unit.baseUnit }
|
||||
if(foundCityAction?.action != null &&
|
||||
otherSettlers.none {
|
||||
rankTileAsCityCenter(it.getTile(), nearbyTileRankings, emptySequence()) > rankTileAsCityCenter(unit.getTile(), nearbyTileRankings, emptySequence())
|
||||
|
@ -10,8 +10,8 @@ import com.unciv.logic.battle.ICombatant
|
||||
import com.unciv.logic.battle.MapUnitCombatant
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -148,7 +148,7 @@ object UnitAutomation {
|
||||
if (tryRunAwayIfNeccessary(unit)) return
|
||||
|
||||
if (unit.currentTile.isCityCenter() && unit.currentTile.getCity()!!.isCapital()
|
||||
&& !unit.hasUnique(UniqueType.AddInCapital) && unit.civInfo.getCivUnits().any { unit.hasUnique(UniqueType.AddInCapital) }){
|
||||
&& !unit.hasUnique(UniqueType.AddInCapital) && unit.civInfo.units.getCivUnits().any { unit.hasUnique(UniqueType.AddInCapital) }){
|
||||
// First off get out of the way, then decide if you actually want to do something else
|
||||
val tilesCanMoveTo = unit.movement.getDistanceToTiles()
|
||||
.filter { unit.movement.canMoveTo(it.key) }
|
||||
@ -418,7 +418,7 @@ object UnitAutomation {
|
||||
}
|
||||
|
||||
private fun tryAccompanySettlerOrGreatPerson(unit: MapUnit): Boolean {
|
||||
val settlerOrGreatPersonToAccompany = unit.civInfo.getCivUnits()
|
||||
val settlerOrGreatPersonToAccompany = unit.civInfo.units.getCivUnits()
|
||||
.firstOrNull {
|
||||
val tile = it.currentTile
|
||||
it.isCivilian() &&
|
||||
|
@ -4,6 +4,7 @@ import com.badlogic.gdx.math.Vector2
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.automation.civilization.NextTurnAutomation
|
||||
import com.unciv.logic.automation.unit.AttackableTile
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.civilization.AlertType
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
@ -17,7 +18,6 @@ import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.RoadStatus
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.automation.unit.AttackableTile
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.models.helpers.UnitMovementMemoryType
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
@ -204,12 +204,8 @@ object Battle {
|
||||
if (defeatedUnitYieldSourceType == "Cost") unitCost else unitStr
|
||||
val yieldAmount = (yieldTypeSourceAmount * yieldPercent).toInt()
|
||||
|
||||
// This should be unnecessary as we check this for uniques when reading them in
|
||||
try {
|
||||
val stat = Stat.valueOf(unique.params[3])
|
||||
civUnit.getCivInfo().addStat(stat, yieldAmount)
|
||||
} catch (ex: Exception) {
|
||||
} // parameter is not a stat
|
||||
val stat = Stat.valueOf(unique.params[3])
|
||||
civUnit.getCivInfo().addStat(stat, yieldAmount)
|
||||
}
|
||||
|
||||
// CS friendship from killing barbarians
|
||||
@ -297,7 +293,7 @@ object Battle {
|
||||
/** Places a [unitName] unit near [tile] after being attacked by [attacker].
|
||||
* Adds a notification to [attacker]'s civInfo and returns whether the captured unit could be placed */
|
||||
private fun spawnCapturedUnit(unitName: String, attacker: ICombatant, tile: TileInfo): Boolean {
|
||||
val addedUnit = attacker.getCivInfo().placeUnitNearTile(tile.position, unitName) ?: return false
|
||||
val addedUnit = attacker.getCivInfo().units.placeUnitNearTile(tile.position, unitName) ?: return false
|
||||
addedUnit.currentMovement = 0f
|
||||
addedUnit.health = 50
|
||||
attacker.getCivInfo().addNotification("An enemy [${unitName}] has joined us!", addedUnit.getTile().position, NotificationCategory.War, unitName)
|
||||
@ -310,7 +306,7 @@ object Battle {
|
||||
return true
|
||||
}
|
||||
|
||||
private data class DamageDealt(val attackerDealt: Int, val defenderDealt: Int) {}
|
||||
private data class DamageDealt(val attackerDealt: Int, val defenderDealt: Int)
|
||||
|
||||
private fun takeDamage(attacker: ICombatant, defender: ICombatant): DamageDealt {
|
||||
var potentialDamageToDefender = BattleDamage.calculateDamageToDefender(attacker, defender)
|
||||
@ -631,7 +627,7 @@ object Battle {
|
||||
// This is so that future checks which check if a unit has been captured are caught give the right answer
|
||||
// For example, in postBattleMoveToAttackedTile
|
||||
capturedUnit.civInfo = attacker.getCivInfo()
|
||||
attacker.getCivInfo().placeUnitNearTile(capturedUnitTile.position, Constants.worker)
|
||||
attacker.getCivInfo().units.placeUnitNearTile(capturedUnitTile.position, Constants.worker)
|
||||
}
|
||||
else -> capturedUnit.capturedBy(attacker.getCivInfo())
|
||||
}
|
||||
@ -860,7 +856,7 @@ object Battle {
|
||||
var potentialInterceptors = sequence<MapUnit> { }
|
||||
for (interceptingCiv in UncivGame.Current.gameInfo!!.civilizations
|
||||
.filter {attacker.getCivInfo().isAtWarWith(it)}) {
|
||||
potentialInterceptors += interceptingCiv.getCivUnits()
|
||||
potentialInterceptors += interceptingCiv.units.getCivUnits()
|
||||
.filter { it.canIntercept(attackedTile) }
|
||||
}
|
||||
|
||||
@ -880,8 +876,6 @@ object Battle {
|
||||
interceptor.currentTile.position,
|
||||
attacker.unit.currentTile.position
|
||||
)
|
||||
val locationsAttackerUnknown =
|
||||
LocationAction(interceptor.currentTile.position, attackedTile.position)
|
||||
val locationsInterceptorUnknown =
|
||||
LocationAction(attackedTile.position, attacker.unit.currentTile.position)
|
||||
|
||||
@ -952,7 +946,7 @@ object Battle {
|
||||
if (attacker.unit.hasUnique(UniqueType.CannotBeIntercepted, StateForConditionals(attacker.getCivInfo(), ourCombatant = attacker, theirCombatant = defender, attackedTile = attackedTile)))
|
||||
return
|
||||
// Pick highest chance interceptor
|
||||
for (interceptor in interceptingCiv.getCivUnits()
|
||||
for (interceptor in interceptingCiv.units.getCivUnits()
|
||||
.filter { it.canIntercept(attackedTile) }
|
||||
.sortedByDescending { it.interceptChance() }
|
||||
) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.unciv.logic.battle
|
||||
|
||||
import com.unciv.logic.automation.unit.SpecificUnitAutomation
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.logic.automation.unit.SpecificUnitAutomation // for Kdoc
|
||||
|
||||
|
||||
object GreatGeneralImplementation {
|
||||
@ -27,7 +27,7 @@ object GreatGeneralImplementation {
|
||||
*/
|
||||
fun getGreatGeneralBonus(unit: MapUnit): Pair<String, Int> {
|
||||
val civInfo = unit.civInfo
|
||||
val allGenerals = civInfo.getCivUnits()
|
||||
val allGenerals = civInfo.units.getCivUnits()
|
||||
.filter { it.hasStrengthBonusInRadiusUnique }
|
||||
if (allGenerals.none()) return Pair("", 0)
|
||||
|
||||
|
@ -7,8 +7,6 @@ import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
class CivConstructions : IsPartOfGameInfoSerialization {
|
||||
|
||||
@ -132,7 +130,7 @@ class CivConstructions : IsPartOfGameInfoSerialization {
|
||||
it.cityConstructions.containsBuildingOrEquivalent(objectToCount.name)
|
||||
|| it.cityConstructions.isBeingConstructedOrEnqueued(objectToCount.name)
|
||||
}
|
||||
is BaseUnit -> civInfo.getCivUnits().count { it.name == objectToCount.name } +
|
||||
is BaseUnit -> civInfo.units.getCivUnits().count { it.name == objectToCount.name } +
|
||||
civInfo.cities.count { it.cityConstructions.isBeingConstructedOrEnqueued(objectToCount.name) }
|
||||
else -> 0
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import com.unciv.logic.civilization.managers.QuestManager
|
||||
import com.unciv.logic.civilization.managers.ReligionManager
|
||||
import com.unciv.logic.civilization.managers.RuinsManager
|
||||
import com.unciv.logic.civilization.managers.TechManager
|
||||
import com.unciv.logic.civilization.managers.UnitManager
|
||||
import com.unciv.logic.civilization.managers.VictoryManager
|
||||
import com.unciv.logic.civilization.transients.CivInfoStatsForNextTurn
|
||||
import com.unciv.logic.civilization.transients.CivInfoTransientCache
|
||||
@ -87,19 +88,8 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
@Transient
|
||||
lateinit var nation: Nation
|
||||
|
||||
/**
|
||||
* We never add or remove from here directly, could cause comodification problems.
|
||||
* Instead, we create a copy list with the change, and replace this list.
|
||||
* The other solution, casting toList() every "get", has a performance cost
|
||||
*/
|
||||
@Transient
|
||||
private var units = listOf<MapUnit>()
|
||||
|
||||
/**
|
||||
* Index in the unit list above of the unit that is potentially due and is next up for button "Next unit".
|
||||
*/
|
||||
@Transient
|
||||
private var nextPotentiallyDueAt = 0
|
||||
val units = UnitManager(this)
|
||||
|
||||
@Transient
|
||||
var viewableTiles = setOf<TileInfo>()
|
||||
@ -315,6 +305,8 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
return toReturn
|
||||
}
|
||||
|
||||
|
||||
|
||||
//region pure functions
|
||||
fun getDifficulty(): Difficulty {
|
||||
if (isHuman()) return gameInfo.getDifficulty()
|
||||
@ -495,79 +487,6 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
|
||||
//region Units
|
||||
fun getCivUnitsSize(): Int = units.size
|
||||
fun getCivUnits(): Sequence<MapUnit> = units.asSequence()
|
||||
fun getCivGreatPeople(): Sequence<MapUnit> = getCivUnits().filter { mapUnit -> mapUnit.isGreatPerson() }
|
||||
|
||||
// Similar to getCivUnits(), but the returned list is rotated so that the
|
||||
// 'nextPotentiallyDueAt' unit is first here.
|
||||
private fun getCivUnitsStartingAtNextDue(): Sequence<MapUnit> = sequenceOf(units.subList(nextPotentiallyDueAt, units.size) + units.subList(0, nextPotentiallyDueAt)).flatten()
|
||||
|
||||
fun addUnit(mapUnit: MapUnit, updateCivInfo: Boolean = true) {
|
||||
// Since we create a new list anyway (otherwise some concurrent modification
|
||||
// exception will happen), also rearrange existing units so that
|
||||
// 'nextPotentiallyDueAt' becomes 0. This way new units are always last to be due
|
||||
// (can be changed as wanted, just have a predictable place).
|
||||
val newList = getCivUnitsStartingAtNextDue().toMutableList()
|
||||
newList.add(mapUnit)
|
||||
units = newList
|
||||
nextPotentiallyDueAt = 0
|
||||
|
||||
if (updateCivInfo) {
|
||||
// Not relevant when updating TileInfo transients, since some info of the civ itself isn't yet available,
|
||||
// and in any case it'll be updated once civ info transients are
|
||||
updateStatsForNextTurn() // unit upkeep
|
||||
if (mapUnit.baseUnit.getResourceRequirements().isNotEmpty())
|
||||
cache.updateCivResources()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeUnit(mapUnit: MapUnit) {
|
||||
// See comment in addUnit().
|
||||
val newList = getCivUnitsStartingAtNextDue().toMutableList()
|
||||
newList.remove(mapUnit)
|
||||
units = newList
|
||||
nextPotentiallyDueAt = 0
|
||||
|
||||
updateStatsForNextTurn() // unit upkeep
|
||||
if (mapUnit.baseUnit.getResourceRequirements().isNotEmpty())
|
||||
cache.updateCivResources()
|
||||
}
|
||||
|
||||
fun getIdleUnits() = getCivUnits().filter { it.isIdle() }
|
||||
|
||||
fun getDueUnits(): Sequence<MapUnit> = getCivUnitsStartingAtNextDue().filter { it.due && it.isIdle() }
|
||||
|
||||
fun shouldGoToDueUnit() = UncivGame.Current.settings.checkForDueUnits && getDueUnits().any()
|
||||
|
||||
// Return the next due unit, but preferably not 'unitToSkip': this is returned only if it is the only remaining due unit.
|
||||
fun cycleThroughDueUnits(unitToSkip: MapUnit? = null): MapUnit? {
|
||||
if (units.none()) return null
|
||||
|
||||
var returnAt = nextPotentiallyDueAt
|
||||
var fallbackAt = -1
|
||||
|
||||
do {
|
||||
if (units[returnAt].due && units[returnAt].isIdle()) {
|
||||
if (units[returnAt] != unitToSkip) {
|
||||
nextPotentiallyDueAt = (returnAt + 1) % units.size
|
||||
return units[returnAt]
|
||||
}
|
||||
else fallbackAt = returnAt
|
||||
}
|
||||
|
||||
returnAt = (returnAt + 1) % units.size
|
||||
} while (returnAt != nextPotentiallyDueAt)
|
||||
|
||||
if (fallbackAt >= 0) {
|
||||
nextPotentiallyDueAt = (fallbackAt + 1) % units.size
|
||||
return units[fallbackAt]
|
||||
}
|
||||
else return null
|
||||
}
|
||||
//endregion
|
||||
|
||||
fun shouldOpenTechPicker(): Boolean {
|
||||
if (!tech.canResearchTech()) return false
|
||||
if (tech.freeTechs != 0) return true
|
||||
@ -661,7 +580,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
fun isDefeated() = when {
|
||||
isBarbarian() || isSpectator() -> false // Barbarians and voyeurs can't lose
|
||||
hasEverOwnedOriginalCapital == true -> cities.isEmpty()
|
||||
else -> getCivUnits().none()
|
||||
else -> units.getCivUnits().none()
|
||||
}
|
||||
|
||||
fun getEra(): Era = tech.era
|
||||
@ -757,7 +676,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
|
||||
private fun calculateMilitaryMight(): Int {
|
||||
var sum = 1 // minimum value, so we never end up with 0
|
||||
for (unit in units) {
|
||||
for (unit in units.getCivUnits()) {
|
||||
sum += if (unit.baseUnit.isWaterUnit())
|
||||
unit.getForceEvaluation() / 2 // Really don't value water units highly
|
||||
else
|
||||
@ -988,50 +907,6 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
if (action is LocationAction && action.locations.isEmpty()) null else action, category))
|
||||
}
|
||||
|
||||
fun addUnit(unitName: String, city: CityInfo? = null): MapUnit? {
|
||||
if (cities.isEmpty()) return null
|
||||
if (!gameInfo.ruleSet.units.containsKey(unitName)) return null
|
||||
|
||||
val cityToAddTo = city ?: cities.random()
|
||||
val unit = getEquivalentUnit(unitName)
|
||||
val placedUnit = placeUnitNearTile(cityToAddTo.location, unit.name)
|
||||
// silently bail if no tile to place the unit is found
|
||||
?: return null
|
||||
if (unit.isGreatPerson()) {
|
||||
addNotification("A [${unit.name}] has been born in [${cityToAddTo.name}]!", placedUnit.getTile().position, NotificationCategory.General, unit.name)
|
||||
}
|
||||
|
||||
if (placedUnit.hasUnique(UniqueType.ReligiousUnit) && gameInfo.isReligionEnabled()) {
|
||||
placedUnit.religion =
|
||||
when {
|
||||
placedUnit.hasUnique(UniqueType.TakeReligionOverBirthCity)
|
||||
&& religionManager.religion?.isMajorReligion() == true ->
|
||||
religionManager.religion!!.name
|
||||
city != null -> city.cityConstructions.cityInfo.religion.getMajorityReligionName()
|
||||
else -> religionManager.religion?.name
|
||||
}
|
||||
placedUnit.setupAbilityUses(cityToAddTo)
|
||||
}
|
||||
|
||||
for (unique in getMatchingUniques(UniqueType.LandUnitsCrossTerrainAfterUnitGained)) {
|
||||
if (unit.matchesFilter(unique.params[1])) {
|
||||
passThroughImpassableUnlocked = true // Update the cached Boolean
|
||||
passableImpassables.add(unique.params[0]) // Add to list of passable impassables
|
||||
}
|
||||
}
|
||||
|
||||
return placedUnit
|
||||
}
|
||||
|
||||
/** Tries to place the a [unitName] unit into the [TileInfo] closest to the given the [location]
|
||||
* @param location where to try to place the unit
|
||||
* @param unitName name of the [BaseUnit] to create and place
|
||||
* @return created [MapUnit] or null if no suitable location was found
|
||||
* */
|
||||
fun placeUnitNearTile(location: Vector2, unitName: String): MapUnit? {
|
||||
return gameInfo.tileMap.placeUnitNearTile(location, unitName, this)
|
||||
}
|
||||
|
||||
fun addCity(location: Vector2) {
|
||||
val newCity = CityInfo(this, location)
|
||||
newCity.cityConstructions.chooseNextConstruction()
|
||||
@ -1042,7 +917,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
else "The City-State of [$civName] has been destroyed!"
|
||||
for (civ in gameInfo.civilizations)
|
||||
civ.addNotification(destructionText, NotificationCategory.General, civName, NotificationIcon.Death)
|
||||
getCivUnits().forEach { it.destroy() }
|
||||
units.getCivUnits().forEach { it.destroy() }
|
||||
tradeRequests.clear() // if we don't do this then there could be resources taken by "pending" trades forever
|
||||
for (diplomacyManager in diplomacy.values) {
|
||||
diplomacyManager.trades.clear()
|
||||
|
@ -12,8 +12,8 @@ import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.civilization.PopupAlert
|
||||
import com.unciv.logic.civilization.Proximity
|
||||
import com.unciv.models.ruleset.nation.CityStateType
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.nation.CityStateType
|
||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
@ -78,7 +78,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
return
|
||||
val giftedUnit = giftableUnits.random()
|
||||
val cities = NextTurnAutomation.getClosestCities(receivingCiv, civInfo) ?: return
|
||||
val placedUnit = receivingCiv.placeUnitNearTile(cities.city1.location, giftedUnit.name)
|
||||
val placedUnit = receivingCiv.units.placeUnitNearTile(cities.city1.location, giftedUnit.name)
|
||||
?: return
|
||||
val locations = LocationAction(placedUnit.getTile().position, cities.city2.location)
|
||||
receivingCiv.addNotification( "[${civInfo.civName}] gave us a [${giftedUnit.name}] as a gift!", locations,
|
||||
@ -108,7 +108,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
?: return // That filter _can_ result in no candidates, if so, quit silently
|
||||
|
||||
// placing the unit may fail - in that case stay quiet
|
||||
val placedUnit = receivingCiv.placeUnitNearTile(city.location, militaryUnit.name) ?: return
|
||||
val placedUnit = receivingCiv.units.placeUnitNearTile(city.location, militaryUnit.name) ?: return
|
||||
|
||||
// The unit should have bonuses from Barracks, Alhambra etc as if it was built in the CS capital
|
||||
militaryUnit.addConstructionBonuses(placedUnit, civInfo.getCapital()!!.cityConstructions)
|
||||
@ -283,7 +283,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
// https://github.com/Gedemon/Civ5-DLL/blob/master/CvGameCoreDLL_Expansion1/CvMinorCivAI.cpp, line 7812
|
||||
var cost = (500 * civInfo.gameInfo.speed.goldCostModifier).toInt()
|
||||
// Plus disband value of all units
|
||||
for (unit in civInfo.getCivUnits()) {
|
||||
for (unit in civInfo.units.getCivUnits()) {
|
||||
cost += unit.baseUnit.getDisbandGold(civInfo)
|
||||
}
|
||||
// Round to lower multiple of 5
|
||||
@ -318,7 +318,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
civInfo.getCapital()!!.location,
|
||||
NotificationCategory.Diplomacy, civInfo.civName,
|
||||
NotificationIcon.Diplomacy, otherCiv.civName)
|
||||
for (unit in civInfo.getCivUnits())
|
||||
for (unit in civInfo.units.getCivUnits())
|
||||
unit.gift(otherCiv)
|
||||
|
||||
// Make sure this CS can never be liberated
|
||||
@ -435,7 +435,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
it.value.isCivilian() && it.value.isBuildable(civInfo)
|
||||
}
|
||||
if (buildableWorkerLikeUnits.isEmpty()) return // Bad luck?
|
||||
demandingCiv.placeUnitNearTile(civInfo.getCapital()!!.location, buildableWorkerLikeUnits.keys.random())
|
||||
demandingCiv.units.placeUnitNearTile(civInfo.getCapital()!!.location, buildableWorkerLikeUnits.keys.random())
|
||||
|
||||
civInfo.getDiplomacyManager(demandingCiv).addInfluence(-50f)
|
||||
cityStateBullied(demandingCiv)
|
||||
@ -462,7 +462,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
val diplomacy = civInfo.getDiplomacyManager(otherCiv)
|
||||
if (diplomacy.hasFlag(DiplomacyFlags.AngerFreeIntrusion)) continue // They recently helped us
|
||||
|
||||
val unitsInBorder = otherCiv.getCivUnits().count { !it.isCivilian() && it.getTile().getOwner() == civInfo }
|
||||
val unitsInBorder = otherCiv.units.getCivUnits().count { !it.isCivilian() && it.getTile().getOwner() == civInfo }
|
||||
if (unitsInBorder > 0 && diplomacy.relationshipLevel() < RelationshipLevel.Friend) {
|
||||
diplomacy.addInfluence(-10f)
|
||||
if (!diplomacy.hasFlag(DiplomacyFlags.BorderConflict)) {
|
||||
@ -489,7 +489,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
if (civInfo.gameInfo.gameParameters.noBarbarians) return 0
|
||||
val barbarianCiv = civInfo.gameInfo.civilizations.firstOrNull { it.isBarbarian() }
|
||||
?: return 0
|
||||
return barbarianCiv.getCivUnits().count { it.threatensCiv(civInfo) }
|
||||
return barbarianCiv.units.getCivUnits().count { it.threatensCiv(civInfo) }
|
||||
}
|
||||
|
||||
fun threateningBarbarianKilledBy(otherCiv: CivilizationInfo) {
|
||||
@ -651,7 +651,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
|
||||
|
||||
/** Asks all met majors that haven't yet declared wor on [attacker] to at least give some units */
|
||||
fun askForUnitGifts(attacker: CivilizationInfo) {
|
||||
if (attacker.isDefeated() || civInfo.isDefeated()) // nevermind, someone died
|
||||
if (attacker.isDefeated() || civInfo.isDefeated()) // never mind, someone died
|
||||
return
|
||||
if (civInfo.cities.isEmpty()) // Can't receive units with no cities
|
||||
return
|
||||
|
@ -419,7 +419,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
hasOpenBorders = newHasOpenBorders
|
||||
|
||||
if (bordersWereClosed) { // borders were closed, get out!
|
||||
for (unit in civInfo.getCivUnits()
|
||||
for (unit in civInfo.units.getCivUnits()
|
||||
.filter { it.currentTile.getOwner()?.civName == otherCivName }.toList()) {
|
||||
unit.movement.teleportToClosestMoveableTile()
|
||||
}
|
||||
@ -750,7 +750,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
diplomaticStatus = DiplomaticStatus.Peace
|
||||
val otherCiv = otherCiv()
|
||||
// Get out of others' territory
|
||||
for (unit in civInfo.getCivUnits().filter { it.getTile().getOwner() == otherCiv }.toList())
|
||||
for (unit in civInfo.units.getCivUnits().filter { it.getTile().getOwner() == otherCiv }.toList())
|
||||
unit.movement.teleportToClosestMoveableTile()
|
||||
|
||||
for (thirdCiv in civInfo.getKnownCivs()) {
|
||||
|
@ -5,7 +5,6 @@ import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
import com.unciv.logic.civilization.diplomacy.CityStatePersonality
|
||||
import com.unciv.logic.civilization.CivFlags
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.DiplomacyAction
|
||||
@ -13,6 +12,7 @@ import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.civilization.Proximity
|
||||
import com.unciv.logic.civilization.diplomacy.CityStatePersonality
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.map.TileInfo
|
||||
@ -407,7 +407,7 @@ class QuestManager : IsPartOfGameInfoSerialization {
|
||||
QuestName.Route.value -> assignee.isCapitalConnectedToCity(civInfo.getCapital()!!)
|
||||
QuestName.ConnectResource.value -> assignee.detailedCivResources.map { it.resource }.contains(civInfo.gameInfo.ruleSet.tileResources[assignedQuest.data1])
|
||||
QuestName.ConstructWonder.value -> assignee.cities.any { it.cityConstructions.isBuilt(assignedQuest.data1) }
|
||||
QuestName.GreatPerson.value -> assignee.getCivGreatPeople().any { it.baseUnit.getReplacedUnit(civInfo.gameInfo.ruleSet).name == assignedQuest.data1 }
|
||||
QuestName.GreatPerson.value -> assignee.units.getCivGreatPeople().any { it.baseUnit.getReplacedUnit(civInfo.gameInfo.ruleSet).name == assignedQuest.data1 }
|
||||
QuestName.FindPlayer.value -> assignee.hasMetCivTerritory(civInfo.gameInfo.getCivilization(assignedQuest.data1))
|
||||
QuestName.FindNaturalWonder.value -> assignee.naturalWonders.contains(assignedQuest.data1)
|
||||
QuestName.PledgeToProtect.value -> assignee in civInfo.cityStateFunctions.getProtectorCivs()
|
||||
@ -549,7 +549,7 @@ class QuestManager : IsPartOfGameInfoSerialization {
|
||||
/** Gets notified when we are attacked, for war with major pseudo-quest */
|
||||
fun wasAttackedBy(attacker: CivilizationInfo) {
|
||||
// Set target number units to kill
|
||||
val totalMilitaryUnits = attacker.getCivUnits().count { !it.isCivilian() }
|
||||
val totalMilitaryUnits = attacker.units.getCivUnits().count { !it.isCivilian() }
|
||||
val unitsToKill = max(3, totalMilitaryUnits / 4)
|
||||
unitsToKillForCiv[attacker.civName] = unitsToKill
|
||||
|
||||
@ -752,8 +752,8 @@ class QuestManager : IsPartOfGameInfoSerialization {
|
||||
private fun getGreatPersonForQuest(challenger: CivilizationInfo): BaseUnit? {
|
||||
val ruleSet = civInfo.gameInfo.ruleSet
|
||||
|
||||
val challengerGreatPeople = challenger.getCivGreatPeople().map { it.baseUnit.getReplacedUnit(ruleSet) }
|
||||
val cityStateGreatPeople = civInfo.getCivGreatPeople().map { it.baseUnit.getReplacedUnit(ruleSet) }
|
||||
val challengerGreatPeople = challenger.units.getCivGreatPeople().map { it.baseUnit.getReplacedUnit(ruleSet) }
|
||||
val cityStateGreatPeople = civInfo.units.getCivGreatPeople().map { it.baseUnit.getReplacedUnit(ruleSet) }
|
||||
|
||||
val greatPeople = challenger.greatPeople.getGreatPeople()
|
||||
.map { it.getReplacedUnit(ruleSet) }
|
||||
|
@ -178,7 +178,7 @@ class ReligionManager : IsPartOfGameInfoSerialization {
|
||||
val birthCity =
|
||||
if (religionState <= ReligionState.Pantheon) civInfo.getCapital()
|
||||
else civInfo.religionManager.getHolyCity()
|
||||
val prophet = civInfo.addUnit(prophetUnitName, birthCity) ?: return
|
||||
val prophet = civInfo.units.addUnit(prophetUnitName, birthCity) ?: return
|
||||
prophet.religion = religion!!.name
|
||||
storedFaith -= faithForNextGreatProphet()
|
||||
civInfo.civConstructions.boughtItemsWithIncreasingPrice.add(prophetUnitName, 1)
|
||||
@ -368,7 +368,7 @@ class ReligionManager : IsPartOfGameInfoSerialization {
|
||||
foundingCityId = null
|
||||
shouldChoosePantheonBelief = false
|
||||
|
||||
for (unit in civInfo.getCivUnits())
|
||||
for (unit in civInfo.units.getCivUnits())
|
||||
if (unit.hasUnique(UniqueType.ReligiousUnit) && unit.hasUnique(UniqueType.TakeReligionOverBirthCity))
|
||||
unit.religion = newReligion.name
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class TechManager : IsPartOfGameInfoSerialization {
|
||||
|
||||
/** When moving towards a certain tech, the user doesn't have to manually pick every one. */
|
||||
var techsToResearch = ArrayList<String>()
|
||||
var overflowScience = 0
|
||||
private var overflowScience = 0
|
||||
var techsInProgress = HashMap<String, Int>()
|
||||
|
||||
/** In civ IV, you can auto-convert a certain percentage of gold in cities to science */
|
||||
@ -340,7 +340,7 @@ class TechManager : IsPartOfGameInfoSerialization {
|
||||
|
||||
for (unique in civInfo.getMatchingUniques(UniqueType.ReceiveFreeUnitWhenDiscoveringTech)) {
|
||||
if (unique.params[1] != techName) continue
|
||||
civInfo.addUnit(unique.params[0])
|
||||
civInfo.units.addUnit(unique.params[0])
|
||||
}
|
||||
for (unique in civInfo.getMatchingUniques(UniqueType.MayanGainGreatPerson)) {
|
||||
if (unique.params[1] != techName) continue
|
||||
@ -385,7 +385,7 @@ class TechManager : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEra() {
|
||||
private fun updateEra() {
|
||||
val ruleset = civInfo.gameInfo.ruleSet
|
||||
if (ruleset.technologies.isEmpty() || researchedTechnologies.isEmpty())
|
||||
return
|
||||
|
@ -38,7 +38,7 @@ class TurnManager(val civInfo: CivilizationInfo) {
|
||||
if (civInfo.cities.isNotEmpty()) { //if no city available, addGreatPerson will throw exception
|
||||
val greatPerson = civInfo.greatPeople.getNewGreatPerson()
|
||||
if (greatPerson != null && civInfo.gameInfo.ruleSet.units.containsKey(greatPerson))
|
||||
civInfo.addUnit(greatPerson)
|
||||
civInfo.units.addUnit(greatPerson)
|
||||
civInfo.religionManager.startTurn()
|
||||
if (civInfo.isLongCountActive())
|
||||
MayaCalendar.startTurnForMaya(civInfo)
|
||||
@ -50,11 +50,11 @@ class TurnManager(val civInfo: CivilizationInfo) {
|
||||
updateRevolts()
|
||||
for (city in civInfo.cities) city.startTurn() // Most expensive part of startTurn
|
||||
|
||||
for (unit in civInfo.getCivUnits()) unit.startTurn()
|
||||
for (unit in civInfo.units.getCivUnits()) unit.startTurn()
|
||||
|
||||
if (civInfo.playerType == PlayerType.Human && UncivGame.Current.settings.automatedUnitsMoveOnTurnStart) {
|
||||
civInfo.hasMovedAutomatedUnits = true
|
||||
for (unit in civInfo.getCivUnits())
|
||||
for (unit in civInfo.units.getCivUnits())
|
||||
unit.doAction()
|
||||
} else civInfo.hasMovedAutomatedUnits = false
|
||||
|
||||
@ -228,7 +228,7 @@ class TurnManager(val civInfo: CivilizationInfo) {
|
||||
// disband units until there are none left OR the gold values are normal
|
||||
if (!civInfo.isBarbarian() && civInfo.gold < -100 && nextTurnStats.gold.toInt() < 0) {
|
||||
for (i in 1 until (civInfo.gold / -100)) {
|
||||
var civMilitaryUnits = civInfo.getCivUnits().filter { it.baseUnit.isMilitary() }
|
||||
var civMilitaryUnits = civInfo.units.getCivUnits().filter { it.baseUnit.isMilitary() }
|
||||
if (civMilitaryUnits.any()) {
|
||||
val unitToDisband = civMilitaryUnits.first()
|
||||
unitToDisband.disband()
|
||||
@ -263,7 +263,7 @@ class TurnManager(val civInfo: CivilizationInfo) {
|
||||
civInfo.temporaryUniques.endTurn()
|
||||
|
||||
civInfo.goldenAges.endTurn(civInfo.getHappiness())
|
||||
civInfo.getCivUnits().forEach { it.endTurn() } // This is the most expensive part of endTurn
|
||||
civInfo.units.getCivUnits().forEach { it.endTurn() } // This is the most expensive part of endTurn
|
||||
civInfo.diplomacy.values.toList().forEach { it.nextTurn() } // we copy the diplomacy values so if it changes in-loop we won't crash
|
||||
civInfo.cache.updateHasActiveEnemyMovementPenalty()
|
||||
|
||||
@ -272,7 +272,7 @@ class TurnManager(val civInfo: CivilizationInfo) {
|
||||
updateWinningCiv() // Maybe we did something this turn to win
|
||||
}
|
||||
|
||||
fun updateWinningCiv(){
|
||||
private fun updateWinningCiv(){
|
||||
if (civInfo.gameInfo.victoryData != null) return // Game already won
|
||||
|
||||
val victoryType = civInfo.victoryManager.getVictoryTypeAchieved()
|
||||
|
143
core/src/com/unciv/logic/civilization/managers/UnitManager.kt
Normal file
143
core/src/com/unciv/logic/civilization/managers/UnitManager.kt
Normal file
@ -0,0 +1,143 @@
|
||||
package com.unciv.logic.civilization.managers
|
||||
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
|
||||
class UnitManager(val civInfo:CivilizationInfo) {
|
||||
|
||||
/**
|
||||
* We never add or remove from here directly, could cause comodification problems.
|
||||
* Instead, we create a copy list with the change, and replace this list.
|
||||
* The other solution, casting toList() every "get", has a performance cost
|
||||
*/
|
||||
@Transient
|
||||
private var unitList = listOf<MapUnit>()
|
||||
|
||||
/**
|
||||
* Index in the unit list above of the unit that is potentially due and is next up for button "Next unit".
|
||||
*/
|
||||
@Transient
|
||||
private var nextPotentiallyDueAt = 0
|
||||
|
||||
fun addUnit(unitName: String, city: CityInfo? = null): MapUnit? {
|
||||
if (civInfo.cities.isEmpty()) return null
|
||||
if (!civInfo.gameInfo.ruleSet.units.containsKey(unitName)) return null
|
||||
|
||||
val cityToAddTo = city ?: civInfo.cities.random()
|
||||
val unit = civInfo.getEquivalentUnit(unitName)
|
||||
val placedUnit = placeUnitNearTile(cityToAddTo.location, unit.name)
|
||||
// silently bail if no tile to place the unit is found
|
||||
?: return null
|
||||
if (unit.isGreatPerson()) {
|
||||
civInfo.addNotification("A [${unit.name}] has been born in [${cityToAddTo.name}]!", placedUnit.getTile().position, NotificationCategory.General, unit.name)
|
||||
}
|
||||
|
||||
if (placedUnit.hasUnique(UniqueType.ReligiousUnit) && civInfo.gameInfo.isReligionEnabled()) {
|
||||
placedUnit.religion =
|
||||
when {
|
||||
placedUnit.hasUnique(UniqueType.TakeReligionOverBirthCity)
|
||||
&& civInfo.religionManager.religion?.isMajorReligion() == true ->
|
||||
civInfo.religionManager.religion!!.name
|
||||
city != null -> city.cityConstructions.cityInfo.religion.getMajorityReligionName()
|
||||
else -> civInfo.religionManager.religion?.name
|
||||
}
|
||||
placedUnit.setupAbilityUses(cityToAddTo)
|
||||
}
|
||||
|
||||
for (unique in civInfo.getMatchingUniques(UniqueType.LandUnitsCrossTerrainAfterUnitGained)) {
|
||||
if (unit.matchesFilter(unique.params[1])) {
|
||||
civInfo.passThroughImpassableUnlocked = true // Update the cached Boolean
|
||||
civInfo.passableImpassables.add(unique.params[0]) // Add to list of passable impassables
|
||||
}
|
||||
}
|
||||
|
||||
return placedUnit
|
||||
}
|
||||
|
||||
/** Tries to place the a [unitName] unit into the [TileInfo] closest to the given the [location]
|
||||
* @param location where to try to place the unit
|
||||
* @param unitName name of the [BaseUnit] to create and place
|
||||
* @return created [MapUnit] or null if no suitable location was found
|
||||
* */
|
||||
fun placeUnitNearTile(location: Vector2, unitName: String): MapUnit? {
|
||||
return civInfo.gameInfo.tileMap.placeUnitNearTile(location, unitName, civInfo)
|
||||
}
|
||||
fun getCivUnitsSize(): Int = unitList.size
|
||||
fun getCivUnits(): Sequence<MapUnit> = unitList.asSequence()
|
||||
fun getCivGreatPeople(): Sequence<MapUnit> = getCivUnits().filter { mapUnit -> mapUnit.isGreatPerson() }
|
||||
|
||||
// Similar to getCivUnits(), but the returned list is rotated so that the
|
||||
// 'nextPotentiallyDueAt' unit is first here.
|
||||
private fun getCivUnitsStartingAtNextDue(): Sequence<MapUnit> = sequenceOf(unitList.subList(nextPotentiallyDueAt, unitList.size) + unitList.subList(0, nextPotentiallyDueAt)).flatten()
|
||||
|
||||
fun addUnit(mapUnit: MapUnit, updateCivInfo: Boolean = true) {
|
||||
// Since we create a new list anyway (otherwise some concurrent modification
|
||||
// exception will happen), also rearrange existing units so that
|
||||
// 'nextPotentiallyDueAt' becomes 0. This way new units are always last to be due
|
||||
// (can be changed as wanted, just have a predictable place).
|
||||
val newList = getCivUnitsStartingAtNextDue().toMutableList()
|
||||
newList.add(mapUnit)
|
||||
unitList = newList
|
||||
nextPotentiallyDueAt = 0
|
||||
|
||||
if (updateCivInfo) {
|
||||
// Not relevant when updating TileInfo transients, since some info of the civ itself isn't yet available,
|
||||
// and in any case it'll be updated once civ info transients are
|
||||
civInfo.updateStatsForNextTurn() // unit upkeep
|
||||
if (mapUnit.baseUnit.getResourceRequirements().isNotEmpty())
|
||||
civInfo.cache.updateCivResources()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeUnit(mapUnit: MapUnit) {
|
||||
// See comment in addUnit().
|
||||
val newList = getCivUnitsStartingAtNextDue().toMutableList()
|
||||
newList.remove(mapUnit)
|
||||
unitList = newList
|
||||
nextPotentiallyDueAt = 0
|
||||
|
||||
civInfo.updateStatsForNextTurn() // unit upkeep
|
||||
if (mapUnit.baseUnit.getResourceRequirements().isNotEmpty())
|
||||
civInfo.cache.updateCivResources()
|
||||
}
|
||||
|
||||
fun getIdleUnits() = getCivUnits().filter { it.isIdle() }
|
||||
|
||||
fun getDueUnits(): Sequence<MapUnit> = getCivUnitsStartingAtNextDue().filter { it.due && it.isIdle() }
|
||||
|
||||
fun shouldGoToDueUnit() = UncivGame.Current.settings.checkForDueUnits && getDueUnits().any()
|
||||
|
||||
// Return the next due unit, but preferably not 'unitToSkip': this is returned only if it is the only remaining due unit.
|
||||
fun cycleThroughDueUnits(unitToSkip: MapUnit? = null): MapUnit? {
|
||||
if (unitList.none()) return null
|
||||
|
||||
var returnAt = nextPotentiallyDueAt
|
||||
var fallbackAt = -1
|
||||
|
||||
do {
|
||||
if (unitList[returnAt].due && unitList[returnAt].isIdle()) {
|
||||
if (unitList[returnAt] != unitToSkip) {
|
||||
nextPotentiallyDueAt = (returnAt + 1) % unitList.size
|
||||
return unitList[returnAt]
|
||||
}
|
||||
else fallbackAt = returnAt
|
||||
}
|
||||
|
||||
returnAt = (returnAt + 1) % unitList.size
|
||||
} while (returnAt != nextPotentiallyDueAt)
|
||||
|
||||
if (fallbackAt >= 0) {
|
||||
nextPotentiallyDueAt = (fallbackAt + 1) % unitList.size
|
||||
return unitList[fallbackAt]
|
||||
}
|
||||
else return null
|
||||
}
|
||||
|
||||
}
|
@ -35,7 +35,7 @@ class CivInfoStatsForNextTurn(val civInfo: CivilizationInfo) {
|
||||
freeUnits += unique.params[0].toInt()
|
||||
}
|
||||
|
||||
var unitsToPayFor = civInfo.getCivUnits()
|
||||
var unitsToPayFor = civInfo.units.getCivUnits()
|
||||
if (civInfo.hasUnique(UniqueType.UnitsInCitiesNoMaintenance))
|
||||
unitsToPayFor = unitsToPayFor.filterNot {
|
||||
it.getTile().isCityCenter() && it.canGarrison()
|
||||
@ -160,7 +160,7 @@ class CivInfoStatsForNextTurn(val civInfo: CivilizationInfo) {
|
||||
}
|
||||
return totalSupply.toInt()
|
||||
}
|
||||
fun getUnitSupplyDeficit(): Int = max(0,civInfo.getCivUnitsSize() - getUnitSupply())
|
||||
fun getUnitSupplyDeficit(): Int = max(0,civInfo.units.getCivUnitsSize() - getUnitSupply())
|
||||
|
||||
/** Per each supply missing, a player gets -10% production. Capped at -70%. */
|
||||
fun getUnitSupplyProductionPenalty(): Float = -min(getUnitSupplyDeficit() * 10f, 70f)
|
||||
@ -228,7 +228,6 @@ class CivInfoStatsForNextTurn(val civInfo: CivilizationInfo) {
|
||||
if (!containsKey(key)) put(key, value)
|
||||
else put(key, value+get(key)!!)
|
||||
}
|
||||
fun HashMap<String, Float>.add(key:String, value: Int) = add(key, value.toFloat())
|
||||
|
||||
statMap["Base happiness"] = civInfo.getDifficulty().baseHappiness.toFloat()
|
||||
|
||||
@ -289,7 +288,7 @@ class CivInfoStatsForNextTurn(val civInfo: CivilizationInfo) {
|
||||
return statMap
|
||||
}
|
||||
|
||||
fun getGlobalStatsFromUniques():StatMap {
|
||||
private fun getGlobalStatsFromUniques():StatMap {
|
||||
val statMap = StatMap()
|
||||
if (civInfo.religionManager.religion != null) {
|
||||
for (unique in civInfo.religionManager.religion!!.getFounderUniques()) {
|
||||
|
@ -69,7 +69,7 @@ class CivInfoTransientCache(val civInfo: CivilizationInfo) {
|
||||
|
||||
private fun updateViewableInvisibleTiles() {
|
||||
val newViewableInvisibleTiles = HashSet<TileInfo>()
|
||||
for (unit in civInfo.getCivUnits()) {
|
||||
for (unit in civInfo.units.getCivUnits()) {
|
||||
val invisibleUnitUniques = unit.getMatchingUniques(UniqueType.CanSeeInvisibleUnits)
|
||||
if (invisibleUnitUniques.none()) continue
|
||||
val visibleUnitTypes = invisibleUnitUniques.map { it.params[0] }
|
||||
@ -103,7 +103,7 @@ class CivInfoTransientCache(val civInfo: CivilizationInfo) {
|
||||
newViewableTiles.addAll(ownedTiles)
|
||||
val neighboringUnownedTiles = ownedTiles.flatMap { tile -> tile.neighbors.filter { it.getOwner() != civInfo } }
|
||||
newViewableTiles.addAll(neighboringUnownedTiles)
|
||||
newViewableTiles.addAll(civInfo.getCivUnits().flatMap { unit -> unit.viewableTiles.asSequence().filter { it.getOwner() != civInfo } })
|
||||
newViewableTiles.addAll(civInfo.units.getCivUnits().flatMap { unit -> unit.viewableTiles.asSequence().filter { it.getOwner() != civInfo } })
|
||||
|
||||
for (otherCiv in civInfo.getKnownCivs()) {
|
||||
if (otherCiv.getAllyCiv() == civInfo.civName || otherCiv.civName == civInfo.getAllyCiv()) {
|
||||
@ -229,7 +229,7 @@ class CivInfoTransientCache(val civInfo: CivilizationInfo) {
|
||||
for (diplomacyManager in civInfo.diplomacy.values)
|
||||
newDetailedCivResources.add(diplomacyManager.resourcesFromTrade())
|
||||
|
||||
for (unit in civInfo.getCivUnits())
|
||||
for (unit in civInfo.units.getCivUnits())
|
||||
newDetailedCivResources.subtractResourceRequirements(
|
||||
unit.baseUnit.getResourceRequirements(), civInfo.gameInfo.ruleSet, "Units")
|
||||
|
||||
|
@ -433,9 +433,6 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
fun isPreparingAirSweep() = action == UnitActionType.AirSweep.value
|
||||
fun isSetUpForSiege() = action == UnitActionType.SetUp.value
|
||||
|
||||
/** For display in Unit Overview */
|
||||
fun getActionLabel() = if (action == null) "" else if (isFortified()) UnitActionType.Fortify.value else if (isMoving()) "Moving" else action!!
|
||||
|
||||
fun isMilitary() = baseUnit.isMilitary()
|
||||
fun isCivilian() = baseUnit.isCivilian()
|
||||
|
||||
@ -552,9 +549,9 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
// and the civ currently has 0 horses, we need to see if the upgrade will be buildable
|
||||
// WHEN THE CURRENT UNIT IS NOT HERE
|
||||
// TODO redesign without kludge: Inform getRejectionReasons about 'virtually available' resources somehow
|
||||
civInfo.removeUnit(this)
|
||||
civInfo.units.removeUnit(this)
|
||||
val rejectionReasons = unitToUpgradeTo.getRejectionReasons(civInfo)
|
||||
civInfo.addUnit(this)
|
||||
civInfo.units.addUnit(this)
|
||||
|
||||
var relevantRejectionReasons = rejectionReasons.asSequence().filterNot { it.rejectionReason == RejectionReason.Unbuildable }
|
||||
if (ignoreRequirements)
|
||||
@ -912,7 +909,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
civInfo.attacksSinceTurnStart.addAll(attacksSinceTurnStart.asSequence().map { CivilizationInfo.HistoricalAttackMemory(this.name, currentPosition, it) })
|
||||
currentMovement = 0f
|
||||
removeFromTile()
|
||||
civInfo.removeUnit(this)
|
||||
civInfo.units.removeUnit(this)
|
||||
civInfo.cache.updateViewableTiles()
|
||||
if (destroyTransportedUnit) {
|
||||
// all transported units should be destroyed as well
|
||||
@ -924,7 +921,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
fun gift(recipient: CivilizationInfo) {
|
||||
civInfo.removeUnit(this)
|
||||
civInfo.units.removeUnit(this)
|
||||
civInfo.cache.updateViewableTiles()
|
||||
// all transported units should be destroyed as well
|
||||
currentTile.getUnits().filter { it.isTransported && isTransportTypeOf(it) }
|
||||
@ -1073,11 +1070,11 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
fun assignOwner(civInfo: CivilizationInfo, updateCivInfo: Boolean = true) {
|
||||
owner = civInfo.civName
|
||||
this.civInfo = civInfo
|
||||
civInfo.addUnit(this, updateCivInfo)
|
||||
civInfo.units.addUnit(this, updateCivInfo)
|
||||
}
|
||||
|
||||
fun capturedBy(captor: CivilizationInfo) {
|
||||
civInfo.removeUnit(this)
|
||||
civInfo.units.removeUnit(this)
|
||||
assignOwner(captor)
|
||||
currentMovement = 0f
|
||||
// It's possible that the unit can no longer stand on the tile it was captured on.
|
||||
|
@ -7,8 +7,8 @@ import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.map.mapgenerator.MapLandmassGenerator
|
||||
import com.unciv.models.metadata.Player
|
||||
import com.unciv.models.ruleset.nation.Nation
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.nation.Nation
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import java.lang.Integer.max
|
||||
@ -529,7 +529,7 @@ class TileMap : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
if (unitToPlaceTile == null) {
|
||||
civInfo.removeUnit(unit) // since we added it to the civ units in the previous assignOwner
|
||||
civInfo.units.removeUnit(unit) // since we added it to the civ units in the previous assignOwner
|
||||
return null // we didn't actually create a unit...
|
||||
}
|
||||
|
||||
|
@ -14,41 +14,6 @@ import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.BeliefType
|
||||
import com.unciv.models.ruleset.Victory
|
||||
import com.unciv.models.ruleset.unique.UniqueType.CityStateCanGiftGreatPeople
|
||||
import com.unciv.models.ruleset.unique.UniqueType.ConditionalTimedUnique
|
||||
import com.unciv.models.ruleset.unique.UniqueType.FoundCity
|
||||
import com.unciv.models.ruleset.unique.UniqueType.FreeSpecificBuildings
|
||||
import com.unciv.models.ruleset.unique.UniqueType.FreeStatBuildings
|
||||
import com.unciv.models.ruleset.unique.UniqueType.MayanGainGreatPerson
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeAmountFreePolicies
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeAmountFreeTechs
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeAmountFreeUnits
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeEnterGoldenAge
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreeBelief
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreeGreatPerson
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreePolicy
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreeTech
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreeTechRuins
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreeUnit
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeFreeUnitRuins
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGainPantheon
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGainPopulation
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGainPopulationRandomCity
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGainProphet
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGainStat
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGainStatRange
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeGlobalSpiesWhenEnteringEra
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeRevealCrudeMap
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeRevealEntireMap
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeRevealSpecificMapTiles
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeTriggerVoting
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeUnitGainPromotion
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeUnitGainXP
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeUnitHeal
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeUnitSpecialUpgrade
|
||||
import com.unciv.models.ruleset.unique.UniqueType.OneTimeUnitUpgrade
|
||||
import com.unciv.models.ruleset.unique.UniqueType.StrategicResourcesIncrease
|
||||
import com.unciv.models.ruleset.unique.UniqueType.UnitsGainPromotion
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.translations.fillPlaceholders
|
||||
import com.unciv.models.translations.hasPlaceholderParameters
|
||||
@ -66,7 +31,7 @@ object UniqueTriggerActivation {
|
||||
tile: TileInfo? = null,
|
||||
notification: String? = null
|
||||
): Boolean {
|
||||
val timingConditional = unique.conditionals.firstOrNull { it.type == ConditionalTimedUnique }
|
||||
val timingConditional = unique.conditionals.firstOrNull { it.type == UniqueType.ConditionalTimedUnique }
|
||||
if (timingConditional != null) {
|
||||
civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt()))
|
||||
return true
|
||||
@ -81,13 +46,13 @@ object UniqueTriggerActivation {
|
||||
val ruleSet = civInfo.gameInfo.ruleSet
|
||||
|
||||
when (unique.type) {
|
||||
OneTimeFreeUnit -> {
|
||||
UniqueType.OneTimeFreeUnit -> {
|
||||
val unitName = unique.params[0]
|
||||
val unit = ruleSet.units[unitName]
|
||||
if (chosenCity == null || unit == null || (unit.hasUnique(FoundCity) && civInfo.isOneCityChallenger()))
|
||||
if (chosenCity == null || unit == null || (unit.hasUnique(UniqueType.FoundCity) && civInfo.isOneCityChallenger()))
|
||||
return false
|
||||
|
||||
val placedUnit = civInfo.addUnit(unitName, chosenCity)
|
||||
val placedUnit = civInfo.units.addUnit(unitName, chosenCity)
|
||||
if (notification != null && placedUnit != null) {
|
||||
civInfo.addNotification(
|
||||
notification,
|
||||
@ -98,15 +63,15 @@ object UniqueTriggerActivation {
|
||||
}
|
||||
return true
|
||||
}
|
||||
OneTimeAmountFreeUnits -> {
|
||||
UniqueType.OneTimeAmountFreeUnits -> {
|
||||
val unitName = unique.params[1]
|
||||
val unit = ruleSet.units[unitName]
|
||||
if (chosenCity == null || unit == null || (unit.hasUnique(FoundCity) && civInfo.isOneCityChallenger()))
|
||||
if (chosenCity == null || unit == null || (unit.hasUnique(UniqueType.FoundCity) && civInfo.isOneCityChallenger()))
|
||||
return false
|
||||
|
||||
val tilesUnitsWerePlacedOn: MutableList<Vector2> = mutableListOf()
|
||||
for (i in 1..unique.params[0].toInt()) {
|
||||
val placedUnit = civInfo.addUnit(unitName, chosenCity)
|
||||
val placedUnit = civInfo.units.addUnit(unitName, chosenCity)
|
||||
if (placedUnit != null)
|
||||
tilesUnitsWerePlacedOn.add(placedUnit.getTile().position)
|
||||
}
|
||||
@ -120,7 +85,7 @@ object UniqueTriggerActivation {
|
||||
}
|
||||
return true
|
||||
}
|
||||
OneTimeFreeUnitRuins -> {
|
||||
UniqueType.OneTimeFreeUnitRuins -> {
|
||||
var unit = civInfo.getEquivalentUnit(unique.params[0])
|
||||
if ( unit.hasUnique(UniqueType.FoundCity) && civInfo.isOneCityChallenger()) {
|
||||
val replacementUnit = ruleSet.units.values.firstOrNull{it.getMatchingUniques(UniqueType.BuildImprovements)
|
||||
@ -131,7 +96,7 @@ object UniqueTriggerActivation {
|
||||
val placingTile =
|
||||
tile ?: civInfo.cities.random().getCenterTile()
|
||||
|
||||
val placedUnit = civInfo.placeUnitNearTile(placingTile.position, unit.name)
|
||||
val placedUnit = civInfo.units.placeUnitNearTile(placingTile.position, unit.name)
|
||||
if (notification != null && placedUnit != null) {
|
||||
val notificationText =
|
||||
if (notification.hasPlaceholderParameters())
|
||||
@ -148,7 +113,7 @@ object UniqueTriggerActivation {
|
||||
return placedUnit != null
|
||||
}
|
||||
|
||||
OneTimeFreePolicy -> {
|
||||
UniqueType.OneTimeFreePolicy -> {
|
||||
// spectators get all techs at start of game, and if (in a mod) a tech gives a free policy, the game gets stuck on the policy picker screen
|
||||
if (civInfo.isSpectator()) return false
|
||||
civInfo.policies.freePolicies++
|
||||
@ -157,7 +122,7 @@ object UniqueTriggerActivation {
|
||||
}
|
||||
return true
|
||||
}
|
||||
OneTimeAmountFreePolicies -> {
|
||||
UniqueType.OneTimeAmountFreePolicies -> {
|
||||
if (civInfo.isSpectator()) return false
|
||||
civInfo.policies.freePolicies += unique.params[0].toInt()
|
||||
if (notification != null) {
|
||||
@ -165,7 +130,7 @@ object UniqueTriggerActivation {
|
||||
}
|
||||
return true
|
||||
}
|
||||
OneTimeEnterGoldenAge -> {
|
||||
UniqueType.OneTimeEnterGoldenAge -> {
|
||||
civInfo.goldenAges.enterGoldenAge()
|
||||
if (notification != null) {
|
||||
civInfo.addNotification(notification, NotificationCategory.General, NotificationIcon.Happiness)
|
||||
@ -173,22 +138,22 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
OneTimeFreeGreatPerson, MayanGainGreatPerson -> {
|
||||
UniqueType.OneTimeFreeGreatPerson, UniqueType.MayanGainGreatPerson -> {
|
||||
if (civInfo.isSpectator()) return false
|
||||
val greatPeople = civInfo.greatPeople.getGreatPeople()
|
||||
if (unique.type == MayanGainGreatPerson && civInfo.greatPeople.longCountGPPool.isEmpty())
|
||||
if (unique.type == UniqueType.MayanGainGreatPerson && civInfo.greatPeople.longCountGPPool.isEmpty())
|
||||
civInfo.greatPeople.longCountGPPool = greatPeople.map { it.name }.toHashSet()
|
||||
if (civInfo.isHuman()) {
|
||||
civInfo.greatPeople.freeGreatPeople++
|
||||
// Anyone an idea for a good icon?
|
||||
if (unique.type == MayanGainGreatPerson) {
|
||||
if (unique.type == UniqueType.MayanGainGreatPerson) {
|
||||
civInfo.greatPeople.mayaLimitedFreeGP++
|
||||
civInfo.addNotification(notification!!, MayaLongCountAction(), NotificationCategory.General, MayaCalendar.notificationIcon)
|
||||
} else if (notification != null)
|
||||
civInfo.addNotification(notification, NotificationCategory.General)
|
||||
return true
|
||||
} else {
|
||||
if (unique.type == MayanGainGreatPerson)
|
||||
if (unique.type == UniqueType.MayanGainGreatPerson)
|
||||
greatPeople.removeAll { it.name !in civInfo.greatPeople.longCountGPPool }
|
||||
if (greatPeople.isEmpty()) return false
|
||||
var greatPerson = greatPeople.random()
|
||||
@ -204,13 +169,13 @@ object UniqueTriggerActivation {
|
||||
if (scientificGP != null) greatPerson = scientificGP
|
||||
}
|
||||
|
||||
if (unique.type == MayanGainGreatPerson)
|
||||
if (unique.type == UniqueType.MayanGainGreatPerson)
|
||||
civInfo.greatPeople.longCountGPPool.remove(greatPerson.name)
|
||||
return civInfo.addUnit(greatPerson.name, chosenCity) != null
|
||||
return civInfo.units.addUnit(greatPerson.name, chosenCity) != null
|
||||
}
|
||||
}
|
||||
|
||||
OneTimeGainPopulation -> {
|
||||
UniqueType.OneTimeGainPopulation -> {
|
||||
val applicableCities = when (unique.params[1]) {
|
||||
"in this city" -> sequenceOf(cityInfo!!)
|
||||
"in other cities" -> civInfo.cities.asSequence().filter { it != cityInfo }
|
||||
@ -228,7 +193,7 @@ object UniqueTriggerActivation {
|
||||
)
|
||||
return applicableCities.any()
|
||||
}
|
||||
OneTimeGainPopulationRandomCity -> {
|
||||
UniqueType.OneTimeGainPopulationRandomCity -> {
|
||||
if (civInfo.cities.isEmpty()) return false
|
||||
val randomCity = civInfo.cities.random(tileBasedRandom)
|
||||
randomCity.population.addPopulation(unique.params[0].toInt())
|
||||
@ -247,7 +212,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
OneTimeFreeTech -> {
|
||||
UniqueType.OneTimeFreeTech -> {
|
||||
if (civInfo.isSpectator()) return false
|
||||
civInfo.tech.freeTechs += 1
|
||||
if (notification != null) {
|
||||
@ -255,7 +220,7 @@ object UniqueTriggerActivation {
|
||||
}
|
||||
return true
|
||||
}
|
||||
OneTimeAmountFreeTechs -> {
|
||||
UniqueType.OneTimeAmountFreeTechs -> {
|
||||
if (civInfo.isSpectator()) return false
|
||||
civInfo.tech.freeTechs += unique.params[0].toInt()
|
||||
if (notification != null) {
|
||||
@ -263,7 +228,7 @@ object UniqueTriggerActivation {
|
||||
}
|
||||
return true
|
||||
}
|
||||
OneTimeFreeTechRuins -> {
|
||||
UniqueType.OneTimeFreeTechRuins -> {
|
||||
val researchableTechsFromThatEra = ruleSet.technologies.values
|
||||
.filter {
|
||||
(it.column!!.era == unique.params[1] || unique.params[1] == "any era")
|
||||
@ -289,7 +254,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
StrategicResourcesIncrease -> {
|
||||
UniqueType.StrategicResourcesIncrease -> {
|
||||
civInfo.cache.updateCivResources()
|
||||
if (notification != null) {
|
||||
civInfo.addNotification(
|
||||
@ -301,7 +266,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
OneTimeRevealEntireMap -> {
|
||||
UniqueType.OneTimeRevealEntireMap -> {
|
||||
if (notification != null) {
|
||||
civInfo.addNotification(notification, LocationAction(tile?.position), NotificationCategory.General, NotificationIcon.Scout)
|
||||
}
|
||||
@ -309,12 +274,12 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
UnitsGainPromotion -> {
|
||||
UniqueType.UnitsGainPromotion -> {
|
||||
val filter = unique.params[0]
|
||||
val promotion = unique.params[1]
|
||||
|
||||
val promotedUnitLocations: MutableList<Vector2> = mutableListOf()
|
||||
for (unit in civInfo.getCivUnits()) {
|
||||
for (unit in civInfo.units.getCivUnits()) {
|
||||
if (unit.matchesFilter(filter)
|
||||
&& ruleSet.unitPromotions.values.any {
|
||||
it.name == promotion && unit.type.name in it.unitTypes
|
||||
@ -336,7 +301,7 @@ object UniqueTriggerActivation {
|
||||
return promotedUnitLocations.isNotEmpty()
|
||||
}
|
||||
|
||||
CityStateCanGiftGreatPeople -> {
|
||||
UniqueType.CityStateCanGiftGreatPeople -> {
|
||||
civInfo.addFlag(
|
||||
CivFlags.CityStateGreatPersonGift.name,
|
||||
civInfo.cityStateFunctions.turnsForGreatPersonFromCityState() / 2
|
||||
@ -362,7 +327,7 @@ object UniqueTriggerActivation {
|
||||
// Note that the way this is implemented now, this unique does NOT stack
|
||||
// I could parametrize the [Allied], but eh.
|
||||
|
||||
OneTimeGainStat -> {
|
||||
UniqueType.OneTimeGainStat -> {
|
||||
val stat = Stat.safeValueOf(unique.params[1]) ?: return false
|
||||
|
||||
if (stat !in Stat.statsWithCivWideField
|
||||
@ -374,7 +339,7 @@ object UniqueTriggerActivation {
|
||||
civInfo.addNotification(notification, LocationAction(tile?.position), NotificationCategory.General, stat.notificationIcon)
|
||||
return true
|
||||
}
|
||||
OneTimeGainStatRange -> {
|
||||
UniqueType.OneTimeGainStatRange -> {
|
||||
val stat = Stat.safeValueOf(unique.params[2]) ?: return false
|
||||
|
||||
if (stat !in Stat.statsWithCivWideField
|
||||
@ -402,7 +367,7 @@ object UniqueTriggerActivation {
|
||||
|
||||
return true
|
||||
}
|
||||
OneTimeGainPantheon -> {
|
||||
UniqueType.OneTimeGainPantheon -> {
|
||||
if (civInfo.religionManager.religionState != ReligionState.None) return false
|
||||
val gainedFaith = civInfo.religionManager.faithForPantheon(2)
|
||||
if (gainedFaith == 0) return false
|
||||
@ -419,7 +384,7 @@ object UniqueTriggerActivation {
|
||||
|
||||
return true
|
||||
}
|
||||
OneTimeGainProphet -> {
|
||||
UniqueType.OneTimeGainProphet -> {
|
||||
if (civInfo.religionManager.getGreatProphetEquivalent() == null) return false
|
||||
val gainedFaith =
|
||||
(civInfo.religionManager.faithForNextGreatProphet() * (unique.params[0].toFloat() / 100f)).toInt()
|
||||
@ -437,7 +402,7 @@ object UniqueTriggerActivation {
|
||||
|
||||
return true
|
||||
}
|
||||
OneTimeFreeBelief -> {
|
||||
UniqueType.OneTimeFreeBelief -> {
|
||||
if (!civInfo.isMajorCiv()) return false
|
||||
val beliefType = BeliefType.valueOf(unique.params[0])
|
||||
val religionManager = civInfo.religionManager
|
||||
@ -454,7 +419,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
OneTimeRevealSpecificMapTiles -> {
|
||||
UniqueType.OneTimeRevealSpecificMapTiles -> {
|
||||
if (tile == null) return false
|
||||
val nearbyRevealableTiles = tile
|
||||
.getTilesInDistance(unique.params[2].toInt())
|
||||
@ -491,7 +456,7 @@ object UniqueTriggerActivation {
|
||||
|
||||
return true
|
||||
}
|
||||
OneTimeRevealCrudeMap -> {
|
||||
UniqueType.OneTimeRevealCrudeMap -> {
|
||||
if (tile == null) return false
|
||||
val revealCenter = tile.getTilesAtDistance(unique.params[0].toInt())
|
||||
.filter { !civInfo.hasExplored(it) }
|
||||
@ -514,7 +479,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
OneTimeTriggerVoting -> {
|
||||
UniqueType.OneTimeTriggerVoting -> {
|
||||
for (civ in civInfo.gameInfo.civilizations)
|
||||
if (!civ.isBarbarian() && !civ.isSpectator())
|
||||
civ.addFlag(
|
||||
@ -526,7 +491,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
OneTimeGlobalSpiesWhenEnteringEra -> {
|
||||
UniqueType.OneTimeGlobalSpiesWhenEnteringEra -> {
|
||||
if (!civInfo.isMajorCiv()) return false
|
||||
if (!civInfo.gameInfo.isEspionageEnabled()) return false
|
||||
val currentEra = civInfo.getEra().name
|
||||
@ -544,7 +509,7 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
FreeStatBuildings, FreeSpecificBuildings -> {
|
||||
UniqueType.FreeStatBuildings, UniqueType.FreeSpecificBuildings -> {
|
||||
civInfo.civConstructions.tryAddFreeBuildings()
|
||||
return true // not fully correct
|
||||
}
|
||||
@ -561,20 +526,20 @@ object UniqueTriggerActivation {
|
||||
notification: String? = null
|
||||
): Boolean {
|
||||
when (unique.type) {
|
||||
OneTimeUnitHeal -> {
|
||||
UniqueType.OneTimeUnitHeal -> {
|
||||
unit.healBy(unique.params[0].toInt())
|
||||
if (notification != null)
|
||||
unit.civInfo.addNotification(notification, unit.getTile().position, NotificationCategory.Units) // Do we have a heal icon?
|
||||
return true
|
||||
}
|
||||
OneTimeUnitGainXP -> {
|
||||
UniqueType.OneTimeUnitGainXP -> {
|
||||
if (!unit.baseUnit.isMilitary()) return false
|
||||
unit.promotions.XP += unique.params[0].toInt()
|
||||
if (notification != null)
|
||||
unit.civInfo.addNotification(notification, unit.getTile().position, NotificationCategory.Units)
|
||||
return true
|
||||
}
|
||||
OneTimeUnitUpgrade -> {
|
||||
UniqueType.OneTimeUnitUpgrade -> {
|
||||
val upgradeAction = UnitActions.getFreeUpgradeAction(unit)
|
||||
?: return false
|
||||
upgradeAction.action!!()
|
||||
@ -582,7 +547,7 @@ object UniqueTriggerActivation {
|
||||
unit.civInfo.addNotification(notification, unit.getTile().position, NotificationCategory.Units)
|
||||
return true
|
||||
}
|
||||
OneTimeUnitSpecialUpgrade -> {
|
||||
UniqueType.OneTimeUnitSpecialUpgrade -> {
|
||||
val upgradeAction = UnitActions.getAncientRuinsUpgradeAction(unit)
|
||||
?: return false
|
||||
upgradeAction.action!!()
|
||||
@ -590,7 +555,7 @@ object UniqueTriggerActivation {
|
||||
unit.civInfo.addNotification(notification, unit.getTile().position, NotificationCategory.Units)
|
||||
return true
|
||||
}
|
||||
OneTimeUnitGainPromotion -> {
|
||||
UniqueType.OneTimeUnitGainPromotion -> {
|
||||
val promotion = unit.civInfo.gameInfo.ruleSet.unitPromotions.keys
|
||||
.firstOrNull { it == unique.params[0] }
|
||||
?: return false
|
||||
|
@ -452,7 +452,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
|
||||
override fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat?): Boolean {
|
||||
val civInfo = cityConstructions.cityInfo.civInfo
|
||||
val unit = civInfo.placeUnitNearTile(cityConstructions.cityInfo.location, name)
|
||||
val unit = civInfo.units.placeUnitNearTile(cityConstructions.cityInfo.location, name)
|
||||
?: return false // couldn't place the unit, so there's actually no unit =(
|
||||
|
||||
//movement penalty
|
||||
@ -512,10 +512,6 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
}
|
||||
|
||||
|
||||
fun getDirectUpgradeUnit(civInfo: CivilizationInfo): BaseUnit {
|
||||
return civInfo.getEquivalentUnit(upgradesTo!!)
|
||||
}
|
||||
|
||||
fun getReplacedUnit(ruleset: Ruleset): BaseUnit {
|
||||
return if (replaces == null) this
|
||||
else ruleset.units[replaces!!]!!
|
||||
|
@ -3,8 +3,8 @@ package com.unciv.ui.overviewscreen
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.ui.utils.KeyCharAndCode
|
||||
import com.unciv.ui.overviewscreen.EmpireOverviewTab.EmpireOverviewTabPersistableData
|
||||
import com.unciv.ui.utils.KeyCharAndCode
|
||||
|
||||
private typealias FactoryType = (CivilizationInfo, EmpireOverviewScreen, EmpireOverviewTabPersistableData?) -> EmpireOverviewTab
|
||||
|
||||
@ -39,7 +39,7 @@ enum class EmpireOverviewCategories(
|
||||
Units("OtherIcons/Shield", 'U', Align.topLeft,
|
||||
fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?)
|
||||
= UnitOverviewTab(viewingPlayer, overviewScreen, persistedData),
|
||||
fun (viewingPlayer: CivilizationInfo) = viewingPlayer.getCivUnits().none().toState()),
|
||||
fun (viewingPlayer: CivilizationInfo) = viewingPlayer.units.getCivUnits().none().toState()),
|
||||
Politics("OtherIcons/Politics", 'P', Align.top,
|
||||
fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?)
|
||||
= GlobalPoliticsOverviewTable(viewingPlayer, overviewScreen, persistedData),
|
||||
@ -64,7 +64,7 @@ enum class EmpireOverviewCategories(
|
||||
fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?)
|
||||
= NotificationsOverviewTable(worldScreen = UncivGame.Current.worldScreen!!, viewingPlayer, overviewScreen, persistedData),
|
||||
fun (_: CivilizationInfo) = EmpireOverviewTabState.Normal)
|
||||
|
||||
|
||||
; //must be here
|
||||
|
||||
constructor(iconName: String, shortcutChar: Char, scrollAlign: Int, factory: FactoryType, stateTester: StateTesterType = { _ -> EmpireOverviewTabState.Normal })
|
||||
|
@ -9,6 +9,7 @@ import com.unciv.Constants
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.ui.audio.SoundPlayer
|
||||
import com.unciv.ui.images.IconTextButton
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
@ -120,7 +121,7 @@ class UnitOverviewTab(
|
||||
it.addLabeledValue("Population", stats.getUnitSupplyFromPop())
|
||||
it.addSeparator()
|
||||
it.addLabeledValue("Total Supply", stats.getUnitSupply())
|
||||
it.addLabeledValue("In Use", viewingPlayer.getCivUnitsSize())
|
||||
it.addLabeledValue("In Use", viewingPlayer.units.getCivUnitsSize())
|
||||
it.addSeparator()
|
||||
it.addLabeledValue("Supply Deficit", deficit)
|
||||
it.addLabeledValue("Production Penalty", "${stats.getUnitSupplyProductionPenalty().toInt()}%")
|
||||
@ -155,7 +156,7 @@ class UnitOverviewTab(
|
||||
val game = overviewScreen.game
|
||||
defaults().pad(5f)
|
||||
|
||||
for (unit in viewingPlayer.getCivUnits().sortedWith(
|
||||
for (unit in viewingPlayer.units.getCivUnits().sortedWith(
|
||||
compareBy({ it.displayName() },
|
||||
{ !it.due },
|
||||
{ it.currentMovement <= Constants.minimumMovementEpsilon },
|
||||
@ -184,7 +185,15 @@ class UnitOverviewTab(
|
||||
overviewScreen.game.replaceCurrentScreen(EmpireOverviewScreen(viewingPlayer, "", "")) })
|
||||
}
|
||||
add(editIcon)
|
||||
if (unit.action == null) add() else add(unit.getActionLabel().toLabel())
|
||||
|
||||
fun getActionLabel(unit:MapUnit) = when {
|
||||
unit.action == null -> ""
|
||||
unit.isFortified() -> UnitActionType.Fortify.value
|
||||
unit.isMoving() -> "Moving"
|
||||
else -> unit.action!!
|
||||
}
|
||||
|
||||
if (unit.action == null) add() else add(getActionLabel(unit).toLabel())
|
||||
if (baseUnit.strength > 0) add(baseUnit.strength.toLabel()) else add()
|
||||
if (baseUnit.rangedStrength > 0) add(baseUnit.rangedStrength.toLabel()) else add()
|
||||
add(unit.getMovementString().toLabel())
|
||||
|
@ -32,7 +32,7 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() {
|
||||
}
|
||||
|
||||
rightSideButton.onClick(UncivSound.Choir) {
|
||||
civInfo.addUnit(theChosenOne!!.name, civInfo.getCapital())
|
||||
civInfo.units.addUnit(theChosenOne!!.name, civInfo.getCapital())
|
||||
civInfo.greatPeople.freeGreatPeople--
|
||||
if (useMayaLongCount) {
|
||||
civInfo.greatPeople.mayaLimitedFreeGP--
|
||||
|
@ -61,7 +61,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
||||
return button
|
||||
}
|
||||
|
||||
fun addLeaderName(civInfo: CivilizationInfo) {
|
||||
private fun addLeaderName(civInfo: CivilizationInfo) {
|
||||
add(LeaderIntroTable(civInfo))
|
||||
addSeparator()
|
||||
}
|
||||
@ -350,7 +350,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
||||
originalOwner.cities.minByOrNull { it.getCenterTile().aerialDistanceTo(tile) }
|
||||
if (closestCity != null) {
|
||||
// Attempt to place the unit near their nearest city
|
||||
originalOwner.placeUnitNearTile(closestCity.location, unitName)
|
||||
originalOwner.units.placeUnitNearTile(closestCity.location, unitName)
|
||||
}
|
||||
|
||||
if (originalOwner.isCityState()) {
|
||||
@ -369,7 +369,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
||||
// This is so that future checks which check if a unit has been captured are caught give the right answer
|
||||
// For example, in postBattleMoveToAttackedTile
|
||||
capturedUnit.civInfo = captor
|
||||
captor.placeUnitNearTile(tile.position, Constants.worker)
|
||||
captor.units.placeUnitNearTile(tile.position, Constants.worker)
|
||||
} else
|
||||
capturedUnit.capturedBy(captor)
|
||||
}).row()
|
||||
|
@ -18,8 +18,8 @@ import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.UncivShowableException
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.civilization.managers.ReligionState
|
||||
import com.unciv.logic.event.EventBus
|
||||
import com.unciv.logic.map.MapVisualization
|
||||
import com.unciv.logic.multiplayer.MultiplayerGameUpdated
|
||||
@ -173,7 +173,7 @@ class WorldScreen(
|
||||
val tileToCenterOn: Vector2 =
|
||||
when {
|
||||
viewingCiv.cities.isNotEmpty() && viewingCiv.getCapital() != null -> viewingCiv.getCapital()!!.location
|
||||
viewingCiv.getCivUnits().any() -> viewingCiv.getCivUnits().first().getTile().position
|
||||
viewingCiv.units.getCivUnits().any() -> viewingCiv.units.getCivUnits().first().getTile().position
|
||||
else -> Vector2.Zero
|
||||
}
|
||||
|
||||
@ -411,7 +411,7 @@ class WorldScreen(
|
||||
|
||||
mapHolder.resetArrows()
|
||||
if (UncivGame.Current.settings.showUnitMovements) {
|
||||
val allUnits = gameInfo.civilizations.asSequence().flatMap { it.getCivUnits() }
|
||||
val allUnits = gameInfo.civilizations.asSequence().flatMap { it.units.getCivUnits() }
|
||||
val allAttacks = allUnits.map { unit -> unit.attacksSinceTurnStart.asSequence().map { attacked -> Triple(unit.civInfo, unit.getTile().position, attacked) } }.flatten() +
|
||||
gameInfo.civilizations.asSequence().flatMap { civInfo -> civInfo.attacksSinceTurnStart.asSequence().map { Triple(civInfo, it.source, it.target) } }
|
||||
mapHolder.updateMovementOverlay(
|
||||
@ -509,7 +509,7 @@ class WorldScreen(
|
||||
if (viewingCiv.isAtWar() && !completedTasks.contains("Conquer a city"))
|
||||
return "Conquer a city!\nBring an enemy city down to low health > " +
|
||||
"\nEnter the city with a melee unit"
|
||||
if (viewingCiv.getCivUnits().any { it.baseUnit.movesLikeAirUnits() } && !completedTasks.contains("Move an air unit"))
|
||||
if (viewingCiv.units.getCivUnits().any { it.baseUnit.movesLikeAirUnits() } && !completedTasks.contains("Move an air unit"))
|
||||
return "Move an air unit!\nSelect an air unit > select another city within range > " +
|
||||
"\nMove the unit to the other city"
|
||||
if (!completedTasks.contains("See your stats breakdown"))
|
||||
@ -537,10 +537,10 @@ class WorldScreen(
|
||||
}
|
||||
displayTutorial(TutorialTrigger.AfterConquering) { viewingCiv.cities.any { it.hasJustBeenConquered } }
|
||||
|
||||
displayTutorial(TutorialTrigger.InjuredUnits) { gameInfo.getCurrentPlayerCivilization().getCivUnits().any { it.health < 100 } }
|
||||
displayTutorial(TutorialTrigger.InjuredUnits) { gameInfo.getCurrentPlayerCivilization().units.getCivUnits().any { it.health < 100 } }
|
||||
|
||||
displayTutorial(TutorialTrigger.Workers) {
|
||||
gameInfo.getCurrentPlayerCivilization().getCivUnits().any {
|
||||
gameInfo.getCurrentPlayerCivilization().units.getCivUnits().any {
|
||||
it.hasUniqueToBuildImprovements && it.isCivilian() && !it.isGreatPerson()
|
||||
}
|
||||
}
|
||||
@ -642,7 +642,7 @@ class WorldScreen(
|
||||
// Try to select something new if we already have the next pending unit selected.
|
||||
if (bottomUnitTable.selectedUnit != null)
|
||||
bottomUnitTable.selectedUnit!!.due = false
|
||||
val nextDueUnit = viewingCiv.cycleThroughDueUnits(bottomUnitTable.selectedUnit)
|
||||
val nextDueUnit = viewingCiv.units.cycleThroughDueUnits(bottomUnitTable.selectedUnit)
|
||||
if (nextDueUnit != null) {
|
||||
mapHolder.setCenterPosition(
|
||||
nextDueUnit.currentTile.position,
|
||||
@ -774,11 +774,11 @@ class WorldScreen(
|
||||
game.pushScreen(DiplomaticVotePickerScreen(viewingCiv))
|
||||
}
|
||||
|
||||
viewingCiv.shouldGoToDueUnit() ->
|
||||
viewingCiv.units.shouldGoToDueUnit() ->
|
||||
NextTurnAction("Next unit", Color.LIGHT_GRAY,
|
||||
"NotificationIcons/NextUnit") { switchToNextUnit() }
|
||||
|
||||
!game.settings.automatedUnitsMoveOnTurnStart && !viewingCiv.hasMovedAutomatedUnits && viewingCiv.getCivUnits()
|
||||
!game.settings.automatedUnitsMoveOnTurnStart && !viewingCiv.hasMovedAutomatedUnits && viewingCiv.units.getCivUnits()
|
||||
.any { it.currentMovement > Constants.minimumMovementEpsilon && (it.isMoving() || it.isAutomated() || it.isExploring()) } ->
|
||||
NextTurnAction("Move automated units", Color.LIGHT_GRAY,
|
||||
"NotificationIcons/MoveAutomatedUnits") {
|
||||
@ -786,7 +786,7 @@ class WorldScreen(
|
||||
isPlayersTurn = false // Disable state changes
|
||||
nextTurnButton.disable()
|
||||
Concurrency.run("Move automated units") {
|
||||
for (unit in viewingCiv.getCivUnits())
|
||||
for (unit in viewingCiv.units.getCivUnits())
|
||||
unit.doAction()
|
||||
launchOnGLThread {
|
||||
shouldUpdate = true
|
||||
@ -857,7 +857,7 @@ class WorldScreen(
|
||||
.flatMap { it.cities.asSequence() }.any { viewingCiv.hasExplored(it.location) }
|
||||
}
|
||||
displayTutorial(TutorialTrigger.ApolloProgram) { viewingCiv.hasUnique(UniqueType.EnablesConstructionOfSpaceshipParts) }
|
||||
displayTutorial(TutorialTrigger.SiegeUnits) { viewingCiv.getCivUnits().any { it.baseUnit.isProbablySiegeUnit() } }
|
||||
displayTutorial(TutorialTrigger.SiegeUnits) { viewingCiv.units.getCivUnits().any { it.baseUnit.isProbablySiegeUnit() } }
|
||||
displayTutorial(TutorialTrigger.Embarking) { viewingCiv.hasUnique(UniqueType.LandUnitEmbarkation) }
|
||||
displayTutorial(TutorialTrigger.NaturalWonders) { viewingCiv.naturalWonders.size > 0 }
|
||||
displayTutorial(TutorialTrigger.WeLoveTheKingDay) { viewingCiv.cities.any { it.demandedResource != "" } }
|
||||
|
@ -29,7 +29,7 @@ class IdleUnitButton (
|
||||
enable()
|
||||
onClick {
|
||||
|
||||
val idleUnits = unitTable.worldScreen.viewingCiv.getIdleUnits()
|
||||
val idleUnits = unitTable.worldScreen.viewingCiv.units.getIdleUnits()
|
||||
if (idleUnits.none()) return@onClick
|
||||
|
||||
val unitToSelect: MapUnit
|
||||
|
@ -443,13 +443,13 @@ object UnitActions {
|
||||
title = title,
|
||||
action = {
|
||||
unit.destroy(destroyTransportedUnit = false)
|
||||
val newUnit = civInfo.placeUnitNearTile(unitTile.position, upgradedUnit.name)
|
||||
val newUnit = civInfo.units.placeUnitNearTile(unitTile.position, upgradedUnit.name)
|
||||
|
||||
/** We were UNABLE to place the new unit, which means that the unit failed to upgrade!
|
||||
* The only known cause of this currently is "land units upgrading to water units" which fail to be placed.
|
||||
*/
|
||||
if (newUnit == null) {
|
||||
val resurrectedUnit = civInfo.placeUnitNearTile(unitTile.position, unit.name)!!
|
||||
val resurrectedUnit = civInfo.units.placeUnitNearTile(unitTile.position, unit.name)!!
|
||||
unit.copyStatisticsTo(resurrectedUnit)
|
||||
} else { // Managed to upgrade
|
||||
if (!isFree) civInfo.addGold(-goldCostOfUpgrade)
|
||||
@ -476,8 +476,7 @@ object UnitActions {
|
||||
|
||||
private fun addTransformAction(
|
||||
unit: MapUnit,
|
||||
actionList: ArrayList<UnitAction>,
|
||||
maxSteps: Int = Int.MAX_VALUE
|
||||
actionList: ArrayList<UnitAction>
|
||||
) {
|
||||
val upgradeAction = getTransformAction(unit)
|
||||
if (upgradeAction != null) actionList += upgradeAction
|
||||
@ -516,13 +515,13 @@ object UnitActions {
|
||||
title = title,
|
||||
action = {
|
||||
unit.destroy()
|
||||
val newUnit = civInfo.placeUnitNearTile(unitTile.position, upgradedUnit.name)
|
||||
val newUnit = civInfo.units.placeUnitNearTile(unitTile.position, upgradedUnit.name)
|
||||
|
||||
/** We were UNABLE to place the new unit, which means that the unit failed to upgrade!
|
||||
* The only known cause of this currently is "land units upgrading to water units" which fail to be placed.
|
||||
*/
|
||||
if (newUnit == null) {
|
||||
val resurrectedUnit = civInfo.placeUnitNearTile(unitTile.position, unit.name)!!
|
||||
val resurrectedUnit = civInfo.units.placeUnitNearTile(unitTile.position, unit.name)!!
|
||||
unit.copyStatisticsTo(resurrectedUnit)
|
||||
} else { // Managed to upgrade
|
||||
unit.copyStatisticsTo(newUnit)
|
||||
@ -771,7 +770,7 @@ object UnitActions {
|
||||
}
|
||||
}
|
||||
|
||||
fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo) {
|
||||
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo) {
|
||||
if (!unit.civInfo.religionManager.maySpreadReligionAtAll(unit)) return
|
||||
actionList += UnitAction(UnitActionType.SpreadReligion,
|
||||
title = "Spread [${unit.getReligionDisplayName()!!}]",
|
||||
|
@ -61,10 +61,10 @@ class UnitTable(val worldScreen: WorldScreen) : Table() {
|
||||
|
||||
// This is so that not on every update(), we will update the unit table.
|
||||
// Most of the time it's the same unit with the same stats so why waste precious time?
|
||||
var selectedUnitHasChanged = false
|
||||
private var selectedUnitHasChanged = false
|
||||
val separator: Actor
|
||||
|
||||
var bg = Image(BaseScreen.skinStrings.getUiBackground("WorldScreen/UnitTable",
|
||||
private var bg = Image(BaseScreen.skinStrings.getUiBackground("WorldScreen/UnitTable",
|
||||
BaseScreen.skinStrings.roundedEdgeRectangleMidShape,
|
||||
BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f)))
|
||||
|
||||
@ -131,7 +131,7 @@ class UnitTable(val worldScreen: WorldScreen) : Table() {
|
||||
}
|
||||
}
|
||||
|
||||
if (worldScreen.viewingCiv.getIdleUnits().any()) { // more efficient to do this check once for both
|
||||
if (worldScreen.viewingCiv.units.getIdleUnits().any()) { // more efficient to do this check once for both
|
||||
prevIdleUnitButton.enable()
|
||||
nextIdleUnitButton.enable()
|
||||
} else {
|
||||
@ -323,16 +323,13 @@ class UnitTable(val worldScreen: WorldScreen) : Table() {
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (curUnit == null) {
|
||||
nextUnit = priorityUnit
|
||||
} else {
|
||||
|
||||
nextUnit = when {
|
||||
nextUnit = when {
|
||||
curUnit == null -> priorityUnit
|
||||
curUnit == civUnit && milUnit != null && milUnit.isEligible() -> {if (civUnit.isPrioritized()) milUnit else null}
|
||||
curUnit == milUnit && civUnit != null && civUnit.isEligible() -> {if (civUnit.isPrioritized()) null else civUnit}
|
||||
else -> priorityUnit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
when {
|
||||
forceSelectUnit != null ->
|
||||
|
@ -495,7 +495,7 @@ class UnitMovementAlgorithmsTests {
|
||||
unit.civInfo = civInfo
|
||||
unit.baseUnit.uniques.add("Can carry [2] [Aircraft] units")
|
||||
unit.updateUniques(ruleSet)
|
||||
civInfo.addUnit(unit, false)
|
||||
civInfo.units.addUnit(unit, false)
|
||||
|
||||
val fighters = ArrayList<MapUnit>()
|
||||
for (i in 0..1) {
|
||||
@ -507,14 +507,14 @@ class UnitMovementAlgorithmsTests {
|
||||
tile.airUnits += newFighter
|
||||
newFighter.name = "Fighter"
|
||||
newFighter.isTransported = true
|
||||
civInfo.addUnit(newFighter, false)
|
||||
civInfo.units.addUnit(newFighter, false)
|
||||
fighters += newFighter
|
||||
}
|
||||
|
||||
// simulate ejecting all units within foreign territory
|
||||
for (unit in civInfo.getCivUnits()) unit.movement.teleportToClosestMoveableTile()
|
||||
for (unit in civInfo.units.getCivUnits()) unit.movement.teleportToClosestMoveableTile()
|
||||
Assert.assertTrue("Transport and transported units must be teleported to the same tile",
|
||||
civInfo.getCivUnits().toList().size == 3 && civInfo.getCivUnits().all { it.getTile() == newTiles.last() })
|
||||
civInfo.units.getCivUnits().toList().size == 3 && civInfo.units.getCivUnits().all { it.getTile() == newTiles.last() })
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,17 +4,17 @@ import com.badlogic.gdx.Gdx
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.json.json
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.files.UncivFiles
|
||||
import com.unciv.logic.GameStarter
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.files.UncivFiles
|
||||
import com.unciv.logic.map.MapParameters
|
||||
import com.unciv.logic.map.MapSize
|
||||
import com.unciv.logic.map.MapSizeNew
|
||||
import com.unciv.models.metadata.GameParameters
|
||||
import com.unciv.models.metadata.GameSettings
|
||||
import com.unciv.models.metadata.GameSetupInfo
|
||||
import com.unciv.models.metadata.Player
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.models.metadata.GameSetupInfo
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.utils.debug
|
||||
import org.junit.After
|
||||
@ -71,7 +71,7 @@ class SerializationTests {
|
||||
|
||||
// Found a city otherwise too many classes have no instance and are not tested
|
||||
val civ = game.getCurrentPlayerCivilization()
|
||||
val unit = civ.getCivUnits().first { it.hasUnique(UniqueType.FoundCity) }
|
||||
val unit = civ.units.getCivUnits().first { it.hasUnique(UniqueType.FoundCity) }
|
||||
val tile = unit.getTile()
|
||||
unit.civInfo.addCity(tile.position)
|
||||
if (tile.ruleset.tileImprovements.containsKey("City center"))
|
||||
@ -108,7 +108,7 @@ class SerializationTests {
|
||||
return
|
||||
}
|
||||
|
||||
val pattern = """\{(\w+)\${'$'}delegate:\{class:kotlin.SynchronizedLazyImpl,"""
|
||||
val pattern = """\{(\w+)\\${'$'}delegate:\{class:kotlin.SynchronizedLazyImpl,"""
|
||||
val matches = Regex(pattern).findAll(json)
|
||||
matches.forEach {
|
||||
debug("Lazy missing `@delegate:Transient` annotation: %s", it.groups[1]!!.value)
|
||||
|
Loading…
x
Reference in New Issue
Block a user