mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-25 21:03:15 -04:00
Cities referenced by UUID (#1638)
* Cities referenced by UUID * UUID defaulted in CityInfo Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
parent
065e944896
commit
036d4058f1
@ -5,16 +5,17 @@ import com.unciv.Constants
|
|||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.automation.NextTurnAutomation
|
import com.unciv.logic.automation.NextTurnAutomation
|
||||||
import com.unciv.logic.city.CityConstructions
|
import com.unciv.logic.city.CityConstructions
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.*
|
||||||
import com.unciv.logic.civilization.LocationAction
|
|
||||||
import com.unciv.logic.civilization.PlayerType
|
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.logic.map.TileMap
|
import com.unciv.logic.map.TileMap
|
||||||
|
import com.unciv.logic.trade.TradeOffer
|
||||||
|
import com.unciv.logic.trade.TradeType
|
||||||
import com.unciv.models.metadata.GameParameters
|
import com.unciv.models.metadata.GameParameters
|
||||||
import com.unciv.models.ruleset.Difficulty
|
import com.unciv.models.ruleset.Difficulty
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class GameInfo {
|
class GameInfo {
|
||||||
@Transient lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
|
@Transient lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
|
||||||
@ -58,6 +59,7 @@ class GameInfo {
|
|||||||
fun getCurrentPlayerCivilization() = currentPlayerCiv
|
fun getCurrentPlayerCivilization() = currentPlayerCiv
|
||||||
fun getBarbarianCivilization() = getCivilization("Barbarians")
|
fun getBarbarianCivilization() = getCivilization("Barbarians")
|
||||||
fun getDifficulty() = difficultyObject
|
fun getDifficulty() = difficultyObject
|
||||||
|
fun getCities() = civilizations.flatMap { it.cities }
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
fun nextTurn() {
|
fun nextTurn() {
|
||||||
@ -265,11 +267,62 @@ class GameInfo {
|
|||||||
// This doesn't HAVE to go here, but why not.
|
// This doesn't HAVE to go here, but why not.
|
||||||
// As of version 3.1.3, trade offers of "Declare war on X" and "Introduction to X" were changed to X,
|
// As of version 3.1.3, trade offers of "Declare war on X" and "Introduction to X" were changed to X,
|
||||||
// with the extra text being added only on UI display (solved a couple of problems).
|
// with the extra text being added only on UI display (solved a couple of problems).
|
||||||
for(trade in civInfo.tradeRequests.map { it.trade })
|
for(trade in civInfo.tradeRequests.map { it.trade }) {
|
||||||
for(offer in trade.theirOffers.union(trade.ourOffers)){
|
for (offer in trade.theirOffers.union(trade.ourOffers)) {
|
||||||
offer.name = offer.name.removePrefix("Declare war on ")
|
offer.name = offer.name.removePrefix("Declare war on ")
|
||||||
offer.name = offer.name.removePrefix("Introduction to ")
|
offer.name = offer.name.removePrefix("Introduction to ")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// As of 3.4.9 cities are referenced by id, not by name
|
||||||
|
// So try to update every tradeRequest (if there are no conflicting names)
|
||||||
|
for(tradeRequest in civInfo.tradeRequests) {
|
||||||
|
val trade = tradeRequest.trade
|
||||||
|
val toRemove = ArrayList<TradeOffer>()
|
||||||
|
for (offer in trade.ourOffers) {
|
||||||
|
if (offer.type == TradeType.City) {
|
||||||
|
val countNames = civInfo.cities.count { it.name == offer.name}
|
||||||
|
|
||||||
|
if (countNames == 1)
|
||||||
|
offer.name = civInfo.cities.first { it.name == offer.name}.id
|
||||||
|
// There are conflicting names: we can't guess what city was being offered
|
||||||
|
else if (countNames > 1)
|
||||||
|
toRemove.add(offer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trade.ourOffers.removeAll(toRemove)
|
||||||
|
toRemove.clear()
|
||||||
|
|
||||||
|
val themCivInfo = getCivilization(tradeRequest.requestingCiv)
|
||||||
|
for (offer in trade.theirOffers) {
|
||||||
|
if (offer.type == TradeType.City) {
|
||||||
|
val countNames = themCivInfo.cities.count { it.name == offer.name}
|
||||||
|
|
||||||
|
if (countNames == 1)
|
||||||
|
offer.name = themCivInfo.cities.first { it.name == offer.name}.id
|
||||||
|
// There are conflicting names: we can't guess what city was being offered
|
||||||
|
else if (countNames > 1)
|
||||||
|
toRemove.add(offer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trade.theirOffers.removeAll(toRemove)
|
||||||
|
}
|
||||||
|
|
||||||
|
// As of 3.4.9 cities are referenced by id, not by name
|
||||||
|
val toRemove = ArrayList<PopupAlert>()
|
||||||
|
for (popupAlert in civInfo.popupAlerts.filter { it.type == AlertType.CityConquered }) {
|
||||||
|
val countNames = getCities().count { it.name == popupAlert.value }
|
||||||
|
|
||||||
|
if (countNames == 1)
|
||||||
|
popupAlert.value = getCities().first { it.name == popupAlert.value }.id
|
||||||
|
else if (countNames > 1) {
|
||||||
|
// Sorry again, conflicting names: who knows what city you conquered?
|
||||||
|
toRemove.add(popupAlert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
civInfo.popupAlerts.removeAll(toRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (civInfo in civilizations) civInfo.setNationTransient()
|
for (civInfo in civilizations) civInfo.setNationTransient()
|
||||||
|
@ -93,7 +93,7 @@ class SpecificUnitAutomation{
|
|||||||
fun automateSettlerActions(unit: MapUnit) {
|
fun automateSettlerActions(unit: MapUnit) {
|
||||||
if(unit.getTile().militaryUnit==null) return // Don't move until you're accompanied by a military unit
|
if(unit.getTile().militaryUnit==null) return // Don't move until you're accompanied by a military unit
|
||||||
|
|
||||||
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }
|
val tilesNearCities = unit.civInfo.gameInfo.getCities()
|
||||||
.flatMap {
|
.flatMap {
|
||||||
val distanceAwayFromCity =
|
val distanceAwayFromCity =
|
||||||
if (unit.civInfo.knows(it.civInfo)
|
if (unit.civInfo.knows(it.civInfo)
|
||||||
|
@ -45,14 +45,14 @@ class WorkerAutomation(val unit: MapUnit) {
|
|||||||
|
|
||||||
val citiesToNumberOfUnimprovedTiles = HashMap<String, Int>()
|
val citiesToNumberOfUnimprovedTiles = HashMap<String, Int>()
|
||||||
for (city in unit.civInfo.cities) {
|
for (city in unit.civInfo.cities) {
|
||||||
citiesToNumberOfUnimprovedTiles[city.name] =
|
citiesToNumberOfUnimprovedTiles[city.id] =
|
||||||
city.getTiles().count { it.isLand && it.civilianUnit == null
|
city.getTiles().count { it.isLand && it.civilianUnit == null
|
||||||
&& tileCanBeImproved(it, unit.civInfo) }
|
&& tileCanBeImproved(it, unit.civInfo) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val mostUndevelopedCity = unit.civInfo.cities
|
val mostUndevelopedCity = unit.civInfo.cities
|
||||||
.filter { citiesToNumberOfUnimprovedTiles[it.name]!! > 0 }
|
.filter { citiesToNumberOfUnimprovedTiles[it.id]!! > 0 }
|
||||||
.sortedByDescending { citiesToNumberOfUnimprovedTiles[it.name] }
|
.sortedByDescending { citiesToNumberOfUnimprovedTiles[it.id] }
|
||||||
.firstOrNull { unit.movement.canReach(it.getCenterTile()) } //goto most undeveloped city
|
.firstOrNull { unit.movement.canReach(it.getCenterTile()) } //goto most undeveloped city
|
||||||
if (mostUndevelopedCity != null && mostUndevelopedCity != unit.currentTile.owningCity) {
|
if (mostUndevelopedCity != null && mostUndevelopedCity != unit.currentTile.owningCity) {
|
||||||
val reachedTile = unit.movement.headTowards(mostUndevelopedCity.getCenterTile())
|
val reachedTile = unit.movement.headTowards(mostUndevelopedCity.getCenterTile())
|
||||||
|
@ -256,7 +256,7 @@ class Battle(val gameInfo:GameInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attackerCiv.isPlayerCivilization()) {
|
if (attackerCiv.isPlayerCivilization()) {
|
||||||
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.name))
|
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.id))
|
||||||
UncivGame.Current.settings.addCompletedTutorialTask("Conquer a city")
|
UncivGame.Current.settings.addCompletedTutorialTask("Conquer a city")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -19,8 +19,10 @@ import com.unciv.models.ruleset.tile.ResourceSupplyList
|
|||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.utils.withoutItem
|
import com.unciv.ui.utils.withoutItem
|
||||||
import kotlin.math.*
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
import kotlin.collections.HashSet
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
class CityInfo {
|
class CityInfo {
|
||||||
@Transient lateinit var civInfo: CivilizationInfo
|
@Transient lateinit var civInfo: CivilizationInfo
|
||||||
@ -31,6 +33,7 @@ class CityInfo {
|
|||||||
@Transient var hasJustBeenConquered = false // this is so that military units can enter the city, even before we decide what to do with it
|
@Transient var hasJustBeenConquered = false // this is so that military units can enter the city, even before we decide what to do with it
|
||||||
|
|
||||||
var location: Vector2 = Vector2.Zero
|
var location: Vector2 = Vector2.Zero
|
||||||
|
var id: String = UUID.randomUUID().toString()
|
||||||
var name: String = ""
|
var name: String = ""
|
||||||
var foundingCiv = ""
|
var foundingCiv = ""
|
||||||
var turnAcquired = 0
|
var turnAcquired = 0
|
||||||
@ -99,15 +102,16 @@ class CityInfo {
|
|||||||
//region pure functions
|
//region pure functions
|
||||||
fun clone(): CityInfo {
|
fun clone(): CityInfo {
|
||||||
val toReturn = CityInfo()
|
val toReturn = CityInfo()
|
||||||
toReturn.location=location
|
toReturn.location = location
|
||||||
toReturn.name=name
|
toReturn.id = id
|
||||||
toReturn.health=health
|
toReturn.name = name
|
||||||
|
toReturn.health = health
|
||||||
toReturn.population = population.clone()
|
toReturn.population = population.clone()
|
||||||
toReturn.cityConstructions=cityConstructions.clone()
|
toReturn.cityConstructions = cityConstructions.clone()
|
||||||
toReturn.expansion = expansion.clone()
|
toReturn.expansion = expansion.clone()
|
||||||
toReturn.tiles = tiles
|
toReturn.tiles = tiles
|
||||||
toReturn.workedTiles = workedTiles
|
toReturn.workedTiles = workedTiles
|
||||||
toReturn.isBeingRazed=isBeingRazed
|
toReturn.isBeingRazed = isBeingRazed
|
||||||
toReturn.attackedThisTurn = attackedThisTurn
|
toReturn.attackedThisTurn = attackedThisTurn
|
||||||
toReturn.resistanceCounter = resistanceCounter
|
toReturn.resistanceCounter = resistanceCounter
|
||||||
toReturn.foundingCiv = foundingCiv
|
toReturn.foundingCiv = foundingCiv
|
||||||
|
@ -128,7 +128,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
|
|||||||
val citiesReachedToMediums = HashMap<CityInfo, ArrayList<String>>()
|
val citiesReachedToMediums = HashMap<CityInfo, ArrayList<String>>()
|
||||||
var citiesToCheck = mutableListOf(civInfo.getCapital())
|
var citiesToCheck = mutableListOf(civInfo.getCapital())
|
||||||
citiesReachedToMediums[civInfo.getCapital()] = arrayListOf("Start")
|
citiesReachedToMediums[civInfo.getCapital()] = arrayListOf("Start")
|
||||||
val allCivCities = civInfo.gameInfo.civilizations.flatMap { it.cities }
|
val allCivCities = civInfo.gameInfo.getCities()
|
||||||
|
|
||||||
val theWheelIsResearched = civInfo.tech.isResearched("The Wheel")
|
val theWheelIsResearched = civInfo.tech.isResearched("The Wheel")
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class TradeEvaluation{
|
|||||||
TradeType.Technology -> return true
|
TradeType.Technology -> return true
|
||||||
TradeType.Introduction -> return true
|
TradeType.Introduction -> return true
|
||||||
TradeType.WarDeclaration -> return true
|
TradeType.WarDeclaration -> return true
|
||||||
TradeType.City -> return offerer.cities.any { it.name==tradeOffer.name }
|
TradeType.City -> return offerer.cities.any { it.id == tradeOffer.name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ class TradeEvaluation{
|
|||||||
else return 0 // why should we pay you to go fight someone...?
|
else return 0 // why should we pay you to go fight someone...?
|
||||||
}
|
}
|
||||||
TradeType.City -> {
|
TradeType.City -> {
|
||||||
val city = tradePartner.cities.first { it.name==offer.name }
|
val city = tradePartner.cities.first { it.id==offer.name }
|
||||||
val stats = city.cityStats.currentCityStats
|
val stats = city.cityStats.currentCityStats
|
||||||
if(civInfo.getHappiness() + city.cityStats.happinessList.values.sum() < 0)
|
if(civInfo.getHappiness() + city.cityStats.happinessList.values.sum() < 0)
|
||||||
return 0 // we can't really afford to go into negative happiness because of buying a city
|
return 0 // we can't really afford to go into negative happiness because of buying a city
|
||||||
@ -204,7 +204,7 @@ class TradeEvaluation{
|
|||||||
}
|
}
|
||||||
|
|
||||||
TradeType.City -> {
|
TradeType.City -> {
|
||||||
val city = civInfo.cities.first { it.name==offer.name }
|
val city = civInfo.cities.first { it.id == offer.name }
|
||||||
val stats = city.cityStats.currentCityStats
|
val stats = city.cityStats.currentCityStats
|
||||||
val sumOfStats = stats.culture+stats.gold+stats.science+stats.production+stats.happiness+stats.food
|
val sumOfStats = stats.culture+stats.gold+stats.science+stats.production+stats.happiness+stats.food
|
||||||
return sumOfStats.toInt() * 100
|
return sumOfStats.toInt() * 100
|
||||||
|
@ -48,7 +48,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
|
|||||||
if (!civInfo.isOneCityChallenger() && !otherCivilization.isOneCityChallenger()
|
if (!civInfo.isOneCityChallenger() && !otherCivilization.isOneCityChallenger()
|
||||||
&& !civInfo.isCityState() && !otherCivilization.isCityState()) {
|
&& !civInfo.isCityState() && !otherCivilization.isCityState()) {
|
||||||
for (city in civInfo.cities.filterNot { it.isCapital() })
|
for (city in civInfo.cities.filterNot { it.isCapital() })
|
||||||
offers.add(TradeOffer(city.name, TradeType.City, 0))
|
offers.add(TradeOffer(city.id, TradeType.City, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
val otherCivsWeKnow = civInfo.getKnownCivs()
|
val otherCivsWeKnow = civInfo.getKnownCivs()
|
||||||
@ -94,7 +94,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
|
|||||||
to.tech.addTechnology(offer.name)
|
to.tech.addTechnology(offer.name)
|
||||||
}
|
}
|
||||||
if (offer.type == TradeType.City) {
|
if (offer.type == TradeType.City) {
|
||||||
val city = from.cities.first { it.name == offer.name }
|
val city = from.cities.first { it.id == offer.name }
|
||||||
city.moveToCiv(to)
|
city.moveToCiv(to)
|
||||||
city.getCenterTile().getUnits().forEach { it.movement.teleportToClosestMoveableTile() }
|
city.getCenterTile().getUnits().forEach { it.movement.teleportToClosestMoveableTile() }
|
||||||
to.updateViewableTiles()
|
to.updateViewableTiles()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.unciv.logic.trade
|
package com.unciv.logic.trade
|
||||||
|
|
||||||
|
import com.unciv.UncivGame
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
|
||||||
data class TradeOffer(var name:String, var type: TradeType,
|
data class TradeOffer(var name:String, var type: TradeType,
|
||||||
@ -18,6 +19,7 @@ data class TradeOffer(var name:String, var type: TradeType,
|
|||||||
var offerText = when(type){
|
var offerText = when(type){
|
||||||
TradeType.WarDeclaration -> "Declare war on [$name]"
|
TradeType.WarDeclaration -> "Declare war on [$name]"
|
||||||
TradeType.Introduction -> "Introduction to [$name]"
|
TradeType.Introduction -> "Introduction to [$name]"
|
||||||
|
TradeType.City -> UncivGame.Current.gameInfo.getCities().first{ it.id == name }.name
|
||||||
else -> name
|
else -> name
|
||||||
}.tr()
|
}.tr()
|
||||||
if (type !in tradesToNotHaveNumbers) offerText += " ($amount)"
|
if (type !in tradesToNotHaveNumbers) offerText += " ($amount)"
|
||||||
|
@ -256,7 +256,7 @@ class Building : NamedStats(), IConstruction{
|
|||||||
|
|
||||||
// Regular wonders
|
// Regular wonders
|
||||||
if (isWonder){
|
if (isWonder){
|
||||||
if(civInfo.gameInfo.civilizations.flatMap { it.cities }
|
if(civInfo.gameInfo.getCities()
|
||||||
.any {it.cityConstructions.isBuilt(name)})
|
.any {it.cityConstructions.isBuilt(name)})
|
||||||
return "Wonder is already built"
|
return "Wonder is already built"
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AlertType.CityConquered -> {
|
AlertType.CityConquered -> {
|
||||||
val city = worldScreen.gameInfo.civilizations.flatMap { it.cities }.first { it.name == popupAlert.value}
|
val city = worldScreen.gameInfo.getCities().first { it.id == popupAlert.value }
|
||||||
addGoodSizedLabel("What would you like to do with the city?",24)
|
addGoodSizedLabel("What would you like to do with the city?",24)
|
||||||
.padBottom(20f).row()
|
.padBottom(20f).row()
|
||||||
val conqueringCiv = worldScreen.gameInfo.currentPlayerCiv
|
val conqueringCiv = worldScreen.gameInfo.currentPlayerCiv
|
||||||
|
Loading…
x
Reference in New Issue
Block a user