mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -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 settler = "Settler"
|
||||||
const val eraSpecificUnit = "Era Starting Unit"
|
const val eraSpecificUnit = "Era Starting Unit"
|
||||||
val all = setOf("All", "all")
|
val all = setOf("All", "all")
|
||||||
|
const val NO_ID = -1
|
||||||
|
|
||||||
const val english = "English"
|
const val english = "English"
|
||||||
|
|
||||||
|
@ -200,4 +200,12 @@ object BackwardCompatibility {
|
|||||||
}
|
}
|
||||||
historyStartTurn = turns
|
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.UncivGame.Version
|
||||||
import com.unciv.json.json
|
import com.unciv.json.json
|
||||||
import com.unciv.logic.BackwardCompatibility.convertFortify
|
import com.unciv.logic.BackwardCompatibility.convertFortify
|
||||||
|
import com.unciv.logic.BackwardCompatibility.ensureUnitIds
|
||||||
import com.unciv.logic.BackwardCompatibility.guaranteeUnitPromotions
|
import com.unciv.logic.BackwardCompatibility.guaranteeUnitPromotions
|
||||||
import com.unciv.logic.BackwardCompatibility.migrateGreatGeneralPools
|
import com.unciv.logic.BackwardCompatibility.migrateGreatGeneralPools
|
||||||
import com.unciv.logic.BackwardCompatibility.migrateToTileHistory
|
import com.unciv.logic.BackwardCompatibility.migrateToTileHistory
|
||||||
@ -115,6 +116,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
|||||||
var currentTurnStartTime = 0L
|
var currentTurnStartTime = 0L
|
||||||
var gameId = UUID.randomUUID().toString() // random string
|
var gameId = UUID.randomUUID().toString() // random string
|
||||||
var checksum = ""
|
var checksum = ""
|
||||||
|
var lastUnitId = 0
|
||||||
|
|
||||||
var victoryData: VictoryData? = null
|
var victoryData: VictoryData? = null
|
||||||
|
|
||||||
@ -679,10 +681,9 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
|||||||
cityDistances.game = this
|
cityDistances.game = this
|
||||||
|
|
||||||
guaranteeUnitPromotions()
|
guaranteeUnitPromotions()
|
||||||
|
|
||||||
migrateToTileHistory()
|
migrateToTileHistory()
|
||||||
|
|
||||||
migrateGreatGeneralPools()
|
migrateGreatGeneralPools()
|
||||||
|
ensureUnitIds()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCivilizationState() {
|
private fun updateCivilizationState() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.logic.automation.unit
|
package com.unciv.logic.automation.unit
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.city.City
|
import com.unciv.logic.city.City
|
||||||
import com.unciv.logic.civilization.Civilization
|
import com.unciv.logic.civilization.Civilization
|
||||||
@ -82,7 +83,9 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, cachedForTurn: Int,
|
|||||||
return roadsToBuildByCitiesCache[city]!!
|
return roadsToBuildByCitiesCache[city]!!
|
||||||
}
|
}
|
||||||
// TODO: some better worker representative needs to be used here
|
// 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()
|
val roadToCapitalStatus = city.cityStats.getRoadTypeOfConnectionToCapital()
|
||||||
|
|
||||||
fun rankRoadCapitalPriority(roadStatus: RoadStatus): Float {
|
fun rankRoadCapitalPriority(roadStatus: RoadStatus): Float {
|
||||||
|
@ -219,7 +219,7 @@ object BattleUnitCapture {
|
|||||||
.firstOrNull { it.isCivilian() && it.getMatchingUniques(UniqueType.BuildImprovements)
|
.firstOrNull { it.isCivilian() && it.getMatchingUniques(UniqueType.BuildImprovements)
|
||||||
.any { unique -> unique.params[0] == "Land" } }
|
.any { unique -> unique.params[0] == "Land" } }
|
||||||
?: return null
|
?: return null
|
||||||
return capturingCiv.units.placeUnitNearTile(capturedUnit.currentTile.position, workerTypeUnit)
|
return capturingCiv.units.placeUnitNearTile(capturedUnit.currentTile.position, workerTypeUnit, capturedUnit.id)
|
||||||
?.currentTile?.position
|
?.currentTile?.position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +90,8 @@ class UnitManager(val civInfo: Civilization) {
|
|||||||
* @param baseUnit [BaseUnit] to create and place
|
* @param baseUnit [BaseUnit] to create and place
|
||||||
* @return created [MapUnit] or null if no suitable location was found
|
* @return created [MapUnit] or null if no suitable location was found
|
||||||
* */
|
* */
|
||||||
fun placeUnitNearTile(location: Vector2, baseUnit: BaseUnit): MapUnit? {
|
fun placeUnitNearTile(location: Vector2, baseUnit: BaseUnit, unitId: Int? = null): MapUnit? {
|
||||||
val unit = civInfo.gameInfo.tileMap.placeUnitNearTile(location, baseUnit, civInfo)
|
val unit = civInfo.gameInfo.tileMap.placeUnitNearTile(location, baseUnit, civInfo, unitId)
|
||||||
|
|
||||||
if (unit != null) {
|
if (unit != null) {
|
||||||
val triggerNotificationText = "due to gaining a [${unit.name}]"
|
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 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.
|
// 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? {
|
fun cycleThroughDueUnits(unitToSkip: MapUnit? = null): MapUnit? {
|
||||||
if (unitList.none()) return null
|
if (unitList.none()) return null
|
||||||
|
@ -530,10 +530,11 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
|||||||
fun placeUnitNearTile(
|
fun placeUnitNearTile(
|
||||||
position: Vector2,
|
position: Vector2,
|
||||||
unitName: String,
|
unitName: String,
|
||||||
civInfo: Civilization
|
civInfo: Civilization,
|
||||||
|
unitId: Int? = null
|
||||||
): MapUnit? {
|
): MapUnit? {
|
||||||
val unit = gameInfo.ruleset.units[unitName]!!
|
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]
|
/** 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(
|
fun placeUnitNearTile(
|
||||||
position: Vector2,
|
position: Vector2,
|
||||||
baseUnit: BaseUnit,
|
baseUnit: BaseUnit,
|
||||||
civInfo: Civilization
|
civInfo: Civilization,
|
||||||
|
unitId: Int? = null
|
||||||
): MapUnit? {
|
): MapUnit? {
|
||||||
val unit = baseUnit.getMapUnit(civInfo)
|
val unit = baseUnit.getMapUnit(civInfo, unitId)
|
||||||
|
|
||||||
fun getPassableNeighbours(tile: Tile): Set<Tile> =
|
fun getPassableNeighbours(tile: Tile): Set<Tile> =
|
||||||
tile.neighbors.filter { unit.movement.canPassThrough(it) }.toSet()
|
tile.neighbors.filter { unit.movement.canPassThrough(it) }.toSet()
|
||||||
|
@ -56,6 +56,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
var currentMovement: Float = 0f
|
var currentMovement: Float = 0f
|
||||||
var health: Int = 100
|
var health: Int = 100
|
||||||
|
var id: Int = Constants.NO_ID
|
||||||
|
|
||||||
// work, automation, fortifying, ...
|
// work, automation, fortifying, ...
|
||||||
// Connect roads implies automated is true. It is specified by the action type.
|
// 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)
|
unit.destroy(destroyTransportedUnit = false)
|
||||||
val civ = unit.civ
|
val civ = unit.civ
|
||||||
val position = unit.currentTile.position
|
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!
|
/** 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.
|
* 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)
|
civInfo.units.addUnit(civUnit, chosenCity)
|
||||||
// Else set the unit at the given tile
|
// Else set the unit at the given tile
|
||||||
tile != null -> civInfo.units.placeUnitNearTile(tile.position, civUnit)
|
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.getCivUnits().any() ->
|
||||||
civInfo.units.placeUnitNearTile(civInfo.units.getCivUnits().first().currentTile.position, civUnit)
|
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()
|
val unit = MapUnit()
|
||||||
unit.name = name
|
unit.name = name
|
||||||
unit.civ = civInfo
|
unit.civ = civInfo
|
||||||
unit.owner = civInfo.civName
|
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
|
// 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
|
// 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())
|
if (isWaterUnit() && !cityConstructions.city.isCoastal())
|
||||||
yield(RejectionReasonType.WaterUnitsInCoastalCities.toInstance())
|
yield(RejectionReasonType.WaterUnitsInCoastalCities.toInstance())
|
||||||
if (isAirUnit()) {
|
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())
|
val canUnitEnterTile = fakeUnit.movement.canMoveTo(cityConstructions.city.getCenterTile())
|
||||||
if (!canUnitEnterTile)
|
if (!canUnitEnterTile)
|
||||||
yield(RejectionReasonType.NoPlaceToPutUnit.toInstance())
|
yield(RejectionReasonType.NoPlaceToPutUnit.toInstance())
|
||||||
|
fakeUnit.destroy()
|
||||||
}
|
}
|
||||||
val civInfo = cityConstructions.city.civ
|
val civInfo = cityConstructions.city.civ
|
||||||
|
|
||||||
|
@ -370,14 +370,14 @@ object UnitActionsFromUniques {
|
|||||||
val oldMovement = unit.currentMovement
|
val oldMovement = unit.currentMovement
|
||||||
unit.destroy()
|
unit.destroy()
|
||||||
val newUnit =
|
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!
|
/** 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.
|
* The only known cause of this currently is "land units upgrading to water units" which fail to be placed.
|
||||||
*/
|
*/
|
||||||
if (newUnit == null) {
|
if (newUnit == null) {
|
||||||
val resurrectedUnit =
|
val resurrectedUnit =
|
||||||
civInfo.units.placeUnitNearTile(unitTile.position, unit.baseUnit)!!
|
civInfo.units.placeUnitNearTile(unitTile.position, unit.baseUnit, unit.id)!!
|
||||||
unit.copyStatisticsTo(resurrectedUnit)
|
unit.copyStatisticsTo(resurrectedUnit)
|
||||||
} else { // Managed to upgrade
|
} else { // Managed to upgrade
|
||||||
unit.copyStatisticsTo(newUnit)
|
unit.copyStatisticsTo(newUnit)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user