mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 19:08:48 -04:00
Adds unique IDs to units (#11745)
* Adds unique IDs to units * Add IDs to units in existing games * civ.getUnitById function * Fix 'no units' case
This commit is contained in:
parent
3b40820bf2
commit
255e6c7fc9
@ -4,6 +4,7 @@ object Constants {
|
||||
const val settler = "Settler"
|
||||
const val eraSpecificUnit = "Era Starting Unit"
|
||||
val all = setOf("All", "all")
|
||||
const val NO_ID = -1
|
||||
|
||||
const val english = "English"
|
||||
|
||||
|
@ -200,4 +200,12 @@ object BackwardCompatibility {
|
||||
}
|
||||
historyStartTurn = turns
|
||||
}
|
||||
|
||||
fun GameInfo.ensureUnitIds(){
|
||||
if (lastUnitId == 0) lastUnitId = tileMap.values.asSequence()
|
||||
.flatMap { it.getUnits() }.maxOfOrNull { it.id } ?: 0
|
||||
for (unit in tileMap.values.flatMap { it.getUnits() }) {
|
||||
if (unit.id == 0) unit.id = ++lastUnitId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.unciv.UncivGame
|
||||
import com.unciv.UncivGame.Version
|
||||
import com.unciv.json.json
|
||||
import com.unciv.logic.BackwardCompatibility.convertFortify
|
||||
import com.unciv.logic.BackwardCompatibility.ensureUnitIds
|
||||
import com.unciv.logic.BackwardCompatibility.guaranteeUnitPromotions
|
||||
import com.unciv.logic.BackwardCompatibility.migrateGreatGeneralPools
|
||||
import com.unciv.logic.BackwardCompatibility.migrateToTileHistory
|
||||
@ -115,6 +116,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
||||
var currentTurnStartTime = 0L
|
||||
var gameId = UUID.randomUUID().toString() // random string
|
||||
var checksum = ""
|
||||
var lastUnitId = 0
|
||||
|
||||
var victoryData: VictoryData? = null
|
||||
|
||||
@ -679,10 +681,9 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
||||
cityDistances.game = this
|
||||
|
||||
guaranteeUnitPromotions()
|
||||
|
||||
migrateToTileHistory()
|
||||
|
||||
migrateGreatGeneralPools()
|
||||
ensureUnitIds()
|
||||
}
|
||||
|
||||
private fun updateCivilizationState() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic.automation.unit
|
||||
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.city.City
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
@ -82,7 +83,9 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, cachedForTurn: Int,
|
||||
return roadsToBuildByCitiesCache[city]!!
|
||||
}
|
||||
// TODO: some better worker representative needs to be used here
|
||||
val workerUnit = civInfo.gameInfo.ruleset.units.map { it.value }.firstOrNull { it.hasUnique(UniqueType.BuildImprovements) }?.getMapUnit(civInfo) ?: return listOf()
|
||||
val workerUnit = civInfo.gameInfo.ruleset.units.map { it.value }.firstOrNull { it.hasUnique(UniqueType.BuildImprovements) }
|
||||
// This is a temporary unit only for AI purposes so it doesn't get a unique ID
|
||||
?.getMapUnit(civInfo, Constants.NO_ID) ?: return listOf()
|
||||
val roadToCapitalStatus = city.cityStats.getRoadTypeOfConnectionToCapital()
|
||||
|
||||
fun rankRoadCapitalPriority(roadStatus: RoadStatus): Float {
|
||||
|
@ -219,7 +219,7 @@ object BattleUnitCapture {
|
||||
.firstOrNull { it.isCivilian() && it.getMatchingUniques(UniqueType.BuildImprovements)
|
||||
.any { unique -> unique.params[0] == "Land" } }
|
||||
?: return null
|
||||
return capturingCiv.units.placeUnitNearTile(capturedUnit.currentTile.position, workerTypeUnit)
|
||||
return capturingCiv.units.placeUnitNearTile(capturedUnit.currentTile.position, workerTypeUnit, capturedUnit.id)
|
||||
?.currentTile?.position
|
||||
}
|
||||
|
||||
|
@ -90,8 +90,8 @@ class UnitManager(val civInfo: Civilization) {
|
||||
* @param baseUnit [BaseUnit] to create and place
|
||||
* @return created [MapUnit] or null if no suitable location was found
|
||||
* */
|
||||
fun placeUnitNearTile(location: Vector2, baseUnit: BaseUnit): MapUnit? {
|
||||
val unit = civInfo.gameInfo.tileMap.placeUnitNearTile(location, baseUnit, civInfo)
|
||||
fun placeUnitNearTile(location: Vector2, baseUnit: BaseUnit, unitId: Int? = null): MapUnit? {
|
||||
val unit = civInfo.gameInfo.tileMap.placeUnitNearTile(location, baseUnit, civInfo, unitId)
|
||||
|
||||
if (unit != null) {
|
||||
val triggerNotificationText = "due to gaining a [${unit.name}]"
|
||||
@ -168,6 +168,8 @@ class UnitManager(val civInfo: Civilization) {
|
||||
|
||||
fun shouldGoToDueUnit() = UncivGame.Current.settings.checkForDueUnits && getDueUnits().any()
|
||||
|
||||
fun getUnitById(id: Int) = getCivUnits().firstOrNull { it.id == id }
|
||||
|
||||
// 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
|
||||
|
@ -530,10 +530,11 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
||||
fun placeUnitNearTile(
|
||||
position: Vector2,
|
||||
unitName: String,
|
||||
civInfo: Civilization
|
||||
civInfo: Civilization,
|
||||
unitId: Int? = null
|
||||
): MapUnit? {
|
||||
val unit = gameInfo.ruleset.units[unitName]!!
|
||||
return placeUnitNearTile(position, unit, civInfo)
|
||||
return placeUnitNearTile(position, unit, civInfo, unitId)
|
||||
}
|
||||
|
||||
/** Tries to place the [baseUnit] into the [Tile] closest to the given [position]
|
||||
@ -545,9 +546,10 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
||||
fun placeUnitNearTile(
|
||||
position: Vector2,
|
||||
baseUnit: BaseUnit,
|
||||
civInfo: Civilization
|
||||
civInfo: Civilization,
|
||||
unitId: Int? = null
|
||||
): MapUnit? {
|
||||
val unit = baseUnit.getMapUnit(civInfo)
|
||||
val unit = baseUnit.getMapUnit(civInfo, unitId)
|
||||
|
||||
fun getPassableNeighbours(tile: Tile): Set<Tile> =
|
||||
tile.neighbors.filter { unit.movement.canPassThrough(it) }.toSet()
|
||||
|
@ -56,6 +56,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
|
||||
var currentMovement: Float = 0f
|
||||
var health: Int = 100
|
||||
var id: Int = Constants.NO_ID
|
||||
|
||||
// work, automation, fortifying, ...
|
||||
// Connect roads implies automated is true. It is specified by the action type.
|
||||
|
@ -87,7 +87,7 @@ class UnitUpgradeManager(val unit: MapUnit) {
|
||||
unit.destroy(destroyTransportedUnit = false)
|
||||
val civ = unit.civ
|
||||
val position = unit.currentTile.position
|
||||
val newUnit = civ.units.placeUnitNearTile(position, upgradedUnit)
|
||||
val newUnit = civ.units.placeUnitNearTile(position, upgradedUnit, unit.id)
|
||||
|
||||
/** 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.
|
||||
|
@ -201,7 +201,7 @@ object UniqueTriggerActivation {
|
||||
civInfo.units.addUnit(civUnit, chosenCity)
|
||||
// Else set the unit at the given tile
|
||||
tile != null -> civInfo.units.placeUnitNearTile(tile.position, civUnit)
|
||||
// Else set unit unit near other units if we have no cities
|
||||
// Else set new unit near other units if we have no cities
|
||||
civInfo.units.getCivUnits().any() ->
|
||||
civInfo.units.placeUnitNearTile(civInfo.units.getCivUnits().first().currentTile.position, civUnit)
|
||||
|
||||
|
@ -101,11 +101,12 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
}
|
||||
}
|
||||
|
||||
fun getMapUnit(civInfo: Civilization): MapUnit {
|
||||
fun getMapUnit(civInfo: Civilization, unitId: Int? = null): MapUnit {
|
||||
val unit = MapUnit()
|
||||
unit.name = name
|
||||
unit.civ = civInfo
|
||||
unit.owner = civInfo.civName
|
||||
unit.id = unitId ?: ++civInfo.gameInfo.lastUnitId
|
||||
|
||||
// must be after setting name & civInfo because it sets the baseUnit according to the name
|
||||
// and the civInfo is required for using `hasUnique` when determining its movement options
|
||||
@ -174,10 +175,11 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
if (isWaterUnit() && !cityConstructions.city.isCoastal())
|
||||
yield(RejectionReasonType.WaterUnitsInCoastalCities.toInstance())
|
||||
if (isAirUnit()) {
|
||||
val fakeUnit = getMapUnit(cityConstructions.city.civ)
|
||||
val fakeUnit = getMapUnit(cityConstructions.city.civ, Constants.NO_ID)
|
||||
val canUnitEnterTile = fakeUnit.movement.canMoveTo(cityConstructions.city.getCenterTile())
|
||||
if (!canUnitEnterTile)
|
||||
yield(RejectionReasonType.NoPlaceToPutUnit.toInstance())
|
||||
fakeUnit.destroy()
|
||||
}
|
||||
val civInfo = cityConstructions.city.civ
|
||||
|
||||
|
@ -370,14 +370,14 @@ object UnitActionsFromUniques {
|
||||
val oldMovement = unit.currentMovement
|
||||
unit.destroy()
|
||||
val newUnit =
|
||||
civInfo.units.placeUnitNearTile(unitTile.position, unitToTransformTo)
|
||||
civInfo.units.placeUnitNearTile(unitTile.position, unitToTransformTo, unit.id)
|
||||
|
||||
/** 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.units.placeUnitNearTile(unitTile.position, unit.baseUnit)!!
|
||||
civInfo.units.placeUnitNearTile(unitTile.position, unit.baseUnit, unit.id)!!
|
||||
unit.copyStatisticsTo(resurrectedUnit)
|
||||
} else { // Managed to upgrade
|
||||
unit.copyStatisticsTo(newUnit)
|
||||
|
Loading…
x
Reference in New Issue
Block a user