3.12.2-patch1

This commit is contained in:
Yair Morgenstern
2020-12-21 20:59:47 +02:00
parent 4e62d0b722
commit 43d9813ce1
8 changed files with 257 additions and 209 deletions

View File

@ -22,21 +22,27 @@ import kotlin.collections.ArrayList
class UncivShowableException(missingMods: String) : Exception(missingMods)
class GameInfo {
@Transient lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
@Transient lateinit var currentPlayerCiv:CivilizationInfo // this is called thousands of times, no reason to search for it with a find{} every time
@Transient
lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
@Transient
lateinit var currentPlayerCiv: CivilizationInfo // this is called thousands of times, no reason to search for it with a find{} every time
/** This is used in multiplayer games, where I may have a saved game state on my phone
* that is inconsistent with the saved game on the cloud */
@Transient var isUpToDate=false
@Transient lateinit var ruleSet:Ruleset
@Transient
var isUpToDate = false
@Transient
lateinit var ruleSet: Ruleset
var civilizations = mutableListOf<CivilizationInfo>()
var difficulty="Chieftain" // difficulty is game-wide, think what would happen if 2 human players could play on different difficulties?
var difficulty = "Chieftain" // difficulty is game-wide, think what would happen if 2 human players could play on different difficulties?
var tileMap: TileMap = TileMap()
var gameParameters= GameParameters()
var gameParameters = GameParameters()
var turns = 0
var oneMoreTurnMode=false
var currentPlayer=""
var oneMoreTurnMode = false
var currentPlayer = ""
var gameId = UUID.randomUUID().toString() // random string
@Volatile
var customSaveLocation: String? = null
@ -53,9 +59,9 @@ class GameInfo {
val toReturn = GameInfo()
toReturn.tileMap = tileMap.clone()
toReturn.civilizations.addAll(civilizations.map { it.clone() })
toReturn.currentPlayer=currentPlayer
toReturn.currentPlayer = currentPlayer
toReturn.turns = turns
toReturn.difficulty=difficulty
toReturn.difficulty = difficulty
toReturn.gameParameters = gameParameters
toReturn.gameId = gameId
toReturn.oneMoreTurnMode = oneMoreTurnMode
@ -66,11 +72,11 @@ class GameInfo {
fun getPlayerToViewAs(): CivilizationInfo {
if (!gameParameters.isOnlineMultiplayer) return currentPlayerCiv // non-online, play as human player
val userId = UncivGame.Current.settings.userId
if (civilizations.any { it.playerId == userId}) return civilizations.first { it.playerId == userId }
if (civilizations.any { it.playerId == userId }) return civilizations.first { it.playerId == userId }
else return getBarbarianCivilization()// you aren't anyone. How did you even get this game? Can you spectate?
}
fun getCivilization(civName:String) = civilizations.first { it.civName==civName }
fun getCivilization(civName: String) = civilizations.first { it.civName == civName }
fun getCurrentPlayerCivilization() = currentPlayerCiv
fun getBarbarianCivilization() = getCivilization(Constants.barbarians)
fun getDifficulty() = difficultyObject
@ -85,10 +91,10 @@ class GameInfo {
var currentPlayerIndex = civilizations.indexOf(thisPlayer)
fun switchTurn(){
fun switchTurn() {
thisPlayer.endTurn()
currentPlayerIndex = (currentPlayerIndex+1) % civilizations.size
if(currentPlayerIndex==0){
currentPlayerIndex = (currentPlayerIndex + 1) % civilizations.size
if (currentPlayerIndex == 0) {
turns++
}
thisPlayer = civilizations[currentPlayerIndex]
@ -98,7 +104,7 @@ class GameInfo {
switchTurn()
while (thisPlayer.playerType == PlayerType.AI
|| turns < UncivGame.Current.simulateUntilTurnForDebug
|| turns < UncivGame.Current.simulateUntilTurnForDebug
|| turns < simulateMaxTurns && simulateUntilWin
// For multiplayer, if there are 3+ players and one is defeated or spectator,
// we'll want to skip over their turn
@ -160,8 +166,7 @@ class GameInfo {
val unitName = tile.militaryUnit!!.name
thisPlayer.addNotification("An enemy [$unitName] was spotted $inOrNear our territory", tile.position, Color.RED)
}
}
else {
} else {
val positions = tiles.map { it.position }
thisPlayer.addNotification("[${positions.size}] enemy units were spotted $inOrNear our territory", Color.RED, LocationAction(positions))
}
@ -216,15 +221,15 @@ class GameInfo {
val barbarianCiv = getBarbarianCivilization()
barbarianCiv.tech.techsResearched = allResearchedTechs.toHashSet()
val unitList = ruleSet.units.values
.filter { !it.unitType.isCivilian()}
.filter { !it.unitType.isCivilian() }
.filter { it.isBuildable(barbarianCiv) }
val landUnits = unitList.filter { it.unitType.isLandUnit() }
val waterUnits = unitList.filter { it.unitType.isWaterUnit() }
val unit:String
if(waterUnits.isNotEmpty() && tileToPlace.isCoastalTile() && Random().nextBoolean())
unit=waterUnits.random().name
val unit: String
if (waterUnits.isNotEmpty() && tileToPlace.isCoastalTile() && Random().nextBoolean())
unit = waterUnits.random().name
else unit = landUnits.random().name
tileMap.placeUnitNearTile(tileToPlace.position, unit, getBarbarianCivilization())
@ -235,8 +240,10 @@ class GameInfo {
* adopted Honor policy and have explored the [tile] where the Barbarian Encampent has spawned.
*/
fun notifyCivsOfBarbarianEncampment(tile: TileInfo) {
civilizations.filter { it.hasUnique("Notified of new Barbarian encampments")
&& it.exploredTiles.contains(tile.position) }
civilizations.filter {
it.hasUnique("Notified of new Barbarian encampments")
&& it.exploredTiles.contains(tile.position)
}
.forEach { it.addNotification("A new barbarian encampment has spawned!", tile.position, Color.RED) }
}
@ -345,10 +352,10 @@ class GameInfo {
cityConstructions.builtBuildings.remove(oldBuildingName)
cityConstructions.builtBuildings.add(newBuildingName)
}
cityConstructions.constructionQueue.replaceAll { if(it==oldBuildingName) newBuildingName else it }
cityConstructions.constructionQueue.replaceAll { if (it == oldBuildingName) newBuildingName else it }
if (cityConstructions.inProgressConstructions.containsKey(oldBuildingName)) {
cityConstructions.inProgressConstructions[newBuildingName] = cityConstructions.inProgressConstructions[oldBuildingName]!!
cityConstructions.inProgressConstructions.remove(oldBuildingName)
}
}
}
}

View File

@ -26,9 +26,7 @@ object GameStarter {
gameInfo.tileMap = MapSaver.loadScenario(gameSetupInfo.mapParameters.name).tileMap
else if (gameSetupInfo.mapParameters.name != "") {
gameInfo.tileMap = MapSaver.loadMap(gameSetupInfo.mapFile!!)
}
else gameInfo.tileMap = MapGenerator(ruleset).generateMap(gameSetupInfo.mapParameters)
} else gameInfo.tileMap = MapGenerator(ruleset).generateMap(gameSetupInfo.mapParameters)
gameInfo.tileMap.mapParameters = gameSetupInfo.mapParameters
gameInfo.tileMap.gameInfo = gameInfo // need to set this transient before placing units in the map
@ -75,7 +73,7 @@ object GameStarter {
civInfo.tech.addTechnology(tech)
// generic start with technology unique
for(unique in civInfo.getMatchingUniques("Starts with []")) {
for (unique in civInfo.getMatchingUniques("Starts with []")) {
// get the parameter from the unique
val techName = unique.params[0]
@ -106,7 +104,7 @@ object GameStarter {
availableCivNames.removeAll(newGameParameters.players.map { it.chosenCiv })
availableCivNames.remove(Constants.barbarians)
if(!newGameParameters.noBarbarians && ruleset.nations.containsKey(Constants.barbarians)) {
if (!newGameParameters.noBarbarians && ruleset.nations.containsKey(Constants.barbarians)) {
val barbarianCivilization = CivilizationInfo(Constants.barbarians)
gameInfo.civilizations.add(barbarianCivilization)
}
@ -138,7 +136,7 @@ object GameStarter {
val civ = CivilizationInfo(cityStateName)
civ.cityStatePersonality = CityStatePersonality.values().random()
gameInfo.civilizations.add(civ)
for(tech in ruleset.technologies.values.filter { it.uniques.contains("Starting tech") })
for (tech in ruleset.technologies.values.filter { it.uniques.contains("Starting tech") })
civ.tech.techsResearched.add(tech.name) // can't be .addTechnology because the civInfo isn't assigned yet
}
}
@ -168,13 +166,14 @@ object GameStarter {
fun placeNearStartingPosition(unitName: String) {
civ.placeUnitNearTile(startingLocation.position, unitName)
}
val warriorEquivalent = getWarriorEquivalent(civ)
val startingUnits = when {
civ.isPlayerCivilization() -> gameInfo.getDifficulty().startingUnits
civ.isMajorCiv() -> gameInfo.getDifficulty().aiMajorCivStartingUnits
else -> gameInfo.getDifficulty().aiCityStateStartingUnits
}
for (unit in startingUnits) {
val unitToAdd = if (unit == "Warrior") warriorEquivalent else unit
if (unitToAdd != null) placeNearStartingPosition(unitToAdd)
@ -185,7 +184,7 @@ object GameStarter {
private fun getStartingLocations(civs: List<CivilizationInfo>, tileMap: TileMap): HashMap<CivilizationInfo, TileInfo> {
var landTiles = tileMap.values
// Games starting on snow might as well start over...
.filter { it.isLand && !it.isImpassible() && it.baseTerrain!=Constants.snow }
.filter { it.isLand && !it.isImpassible() && it.baseTerrain != Constants.snow }
val landTilesInBigEnoughGroup = ArrayList<TileInfo>()
while (landTiles.any()) {

View File

@ -32,12 +32,18 @@ import kotlin.math.min
import kotlin.math.roundToInt
class CityInfo {
@Transient lateinit var civInfo: CivilizationInfo
@Transient lateinit private var centerTileInfo:TileInfo // cached for better performance
@Transient val range = 2
@Transient lateinit var tileMap: TileMap
@Transient lateinit var tilesInRange:HashSet<TileInfo>
@Transient var hasJustBeenConquered = false // this is so that military units can enter the city, even before we decide what to do with it
@Transient
lateinit var civInfo: CivilizationInfo
@Transient
lateinit private var centerTileInfo: TileInfo // cached for better performance
@Transient
val range = 2
@Transient
lateinit var tileMap: TileMap
@Transient
lateinit var tilesInRange: HashSet<TileInfo>
@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 id: String = UUID.randomUUID().toString()
@ -55,14 +61,17 @@ class CityInfo {
/** All tiles that this city controls */
var tiles = HashSet<Vector2>()
/** Tiles that have population assigned to them */
var workedTiles = HashSet<Vector2>()
/** Tiles that the population in them won't be reassigned */
var lockedTiles = HashSet<Vector2>()
var isBeingRazed = false
var attackedThisTurn = false
var hasSoldBuildingThisTurn = false
var isPuppet = false
/** The very first found city is the _original_ capital,
* while the _current_ capital can be any other city after the original one is captured.
* It is important to distinct them since the original cannot be razed and defines the Domination Victory. */
@ -91,7 +100,7 @@ class CityInfo {
for (unique in civInfo.getMatchingUniques("Gain a free [] []")) {
val freeBuildingName = unique.params[0]
val cityFilter = unique.params[1]
if (cityFilter == "in every city" || (cityFilter == "in every coastal city" && getCenterTile().isCoastalTile()) ) {
if (cityFilter == "in every city" || (cityFilter == "in every coastal city" && getCenterTile().isCoastalTile())) {
if (!cityConstructions.isBuilt(freeBuildingName))
cityConstructions.addBuilding(freeBuildingName)
}
@ -154,7 +163,6 @@ class CityInfo {
}
fun getCenterTile(): TileInfo = centerTileInfo
fun getTiles(): Sequence<TileInfo> = tiles.asSequence().map { tileMap[it] }
fun getWorkableTiles() = tilesInRange.asSequence().filter { it.getOwner() == civInfo }
@ -163,10 +171,11 @@ class CityInfo {
fun isCapital(): Boolean = cityConstructions.builtBuildings.contains(capitalCityIndicator())
fun capitalCityIndicator(): String = getRuleset().buildings.values.first { it.uniques.contains("Indicates the capital city") }.name
fun isConnectedToCapital(connectionTypePredicate: (Set<String>) -> Boolean = {true}): Boolean {
fun isConnectedToCapital(connectionTypePredicate: (Set<String>) -> Boolean = { true }): Boolean {
val mediumTypes = civInfo.citiesConnectedToCapitalToMediums[this] ?: return false
return connectionTypePredicate(mediumTypes)
}
fun isInResistance() = resistanceCounter > 0
@ -193,10 +202,11 @@ class CityInfo {
val resource = getRuleset().tileResources[building.requiredResource]!!
cityResources.add(resource, -1, "Buildings")
}
for(unique in cityConstructions.builtBuildingUniqueMap.getUniques("Provides [] []")) { // E.G "Provides [1] [Iron]"
for (unique in cityConstructions.builtBuildingUniqueMap.getUniques("Provides [] []")) { // E.G "Provides [1] [Iron]"
val resource = getRuleset().tileResources[unique.params[1]]
if(resource!=null){
cityResources.add(resource, unique.params[0].toInt() * civInfo.getResourceModifier(resource), "Tiles") }
if (resource != null) {
cityResources.add(resource, unique.params[0].toInt() * civInfo.getResourceModifier(resource), "Tiles")
}
}
return cityResources
@ -205,17 +215,17 @@ class CityInfo {
fun getTileResourceAmount(tileInfo: TileInfo): Int {
if (tileInfo.resource == null) return 0
val resource = tileInfo.getTileResource()
if (resource.revealedBy!=null && !civInfo.tech.isResearched(resource.revealedBy!!)) return 0
if (resource.revealedBy != null && !civInfo.tech.isResearched(resource.revealedBy!!)) return 0
// Even if the improvement exists (we conquered an enemy city or somesuch) or we have a city on it, we won't get the resource until the correct tech is researched
if (resource.improvement!=null) {
if (resource.improvement != null) {
val improvement = getRuleset().tileImprovements[resource.improvement!!]!!
if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired!!)) return 0
}
if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter()
// Per https://gaming.stackexchange.com/questions/53155/do-manufactories-and-customs-houses-sacrifice-the-strategic-or-luxury-resources
|| (resource.resourceType==ResourceType.Strategic && tileInfo.containsGreatImprovement())) {
|| (resource.resourceType == ResourceType.Strategic && tileInfo.containsGreatImprovement())) {
var amountToAdd = 1
if (resource.resourceType == ResourceType.Strategic) {
amountToAdd = 2
@ -240,7 +250,7 @@ class CityInfo {
if (!isGrowing()) return null
val roundedFoodPerTurn = foodForNextTurn().toFloat()
val remainingFood = population.getFoodToNextPopulation() - population.foodStored
var turnsToGrowth = ceil( remainingFood / roundedFoodPerTurn).toInt()
var turnsToGrowth = ceil(remainingFood / roundedFoodPerTurn).toInt()
if (turnsToGrowth < 1) turnsToGrowth = 1
return turnsToGrowth
}
@ -251,11 +261,11 @@ class CityInfo {
return population.foodStored / -foodForNextTurn() + 1
}
fun containsBuildingUnique(unique:String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) }
fun containsBuildingUnique(unique: String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) }
fun getGreatPersonMap():StatMap {
fun getGreatPersonMap(): StatMap {
val stats = StatMap()
for((specialist, amount) in population.getNewSpecialists())
for ((specialist, amount) in population.getNewSpecialists())
if (getRuleset().specialists.containsKey(specialist)) // To solve problems in total remake mods
stats.add("Specialists", getRuleset().specialists[specialist]!!.greatPersonPoints.times(amount))
@ -275,7 +285,7 @@ class CityInfo {
val statName = greatUnitUnique.getPlaceholderParameters()[0]
val stat = Stat.values().firstOrNull { it.name == statName }
// this is not very efficient, and if it causes problems we can try and think of a way of improving it
if (stat != null) entry.value.add(stat, entry.value.get(stat) * unique.params[1].toFloat()/100)
if (stat != null) entry.value.add(stat, entry.value.get(stat) * unique.params[1].toFloat() / 100)
}
for (unique in civInfo.getMatchingUniques("+[]% great person generation in all cities")
@ -297,7 +307,9 @@ class CityInfo {
return 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth }
}
override fun toString(): String {return name} // for debug
override fun toString(): String {
return name
} // for debug
//endregion
//region state-changing functions
@ -313,7 +325,7 @@ class CityInfo {
cityConstructions.setTransients()
}
fun startTurn(){
fun startTurn() {
// Construct units at the beginning of the turn,
// so they won't be generated out in the open and vulnerable to enemy attacks before you can control them
cityConstructions.constructIfEnough()
@ -439,7 +451,7 @@ class CityInfo {
// How can you conquer a city but not know the civ you conquered it from?!
// I don't know either, but some of our players have managed this, and crashed their game!
if(!conqueringCiv.knows(oldCiv))
if (!conqueringCiv.knows(oldCiv))
conqueringCiv.meetCivilization(oldCiv)
oldCiv.getDiplomacyManager(conqueringCiv)
@ -498,10 +510,10 @@ class CityInfo {
val respecForLiberatingOurCity = 10f + percentageOfCivPopulationInThatCity.roundToInt()
// In order to get "plus points" in Diplomacy, you have to establish diplomatic relations if you haven't yet
if(!conqueringCiv.knows(foundingCiv))
if (!conqueringCiv.knows(foundingCiv))
conqueringCiv.meetCivilization(foundingCiv)
if(foundingCiv.isMajorCiv()) {
if (foundingCiv.isMajorCiv()) {
foundingCiv.getDiplomacyManager(conqueringCiv)
.addModifier(DiplomaticModifiers.CapturedOurCities, respecForLiberatingOurCity)
} else {
@ -570,23 +582,21 @@ class CityInfo {
tryUpdateRoadStatus()
}
private fun tryUpdateRoadStatus(){
if(getCenterTile().roadStatus==RoadStatus.None){
private fun tryUpdateRoadStatus() {
if (getCenterTile().roadStatus == RoadStatus.None) {
val roadImprovement = getRuleset().tileImprovements["Road"]
if(roadImprovement!=null && roadImprovement.techRequired in civInfo.tech.techsResearched)
getCenterTile().roadStatus=RoadStatus.Road
}
else if (getCenterTile().roadStatus != RoadStatus.Railroad) {
if (roadImprovement != null && roadImprovement.techRequired in civInfo.tech.techsResearched)
getCenterTile().roadStatus = RoadStatus.Road
} else if (getCenterTile().roadStatus != RoadStatus.Railroad) {
val railroadImprovement = getRuleset().tileImprovements["Railroad"]
if (railroadImprovement != null && railroadImprovement.techRequired in civInfo.tech.techsResearched)
getCenterTile().roadStatus = RoadStatus.Railroad
}
}
fun getGoldForSellingBuilding(buildingName:String) = getRuleset().buildings[buildingName]!!.cost / 10
fun getGoldForSellingBuilding(buildingName: String) = getRuleset().buildings[buildingName]!!.cost / 10
fun sellBuilding(buildingName:String) {
fun sellBuilding(buildingName: String) {
cityConstructions.removeBuilding(buildingName)
civInfo.gold += getGoldForSellingBuilding(buildingName)
hasSoldBuildingThisTurn = true
@ -617,19 +627,18 @@ class CityInfo {
But if they don't keep their promise they get a -20 that will only fully disappear in 160 turns.
There's a lot of triggering going on here.
*/
private fun triggerCitiesSettledNearOtherCiv(){
val citiesWithin6Tiles = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it!=civInfo }
private fun triggerCitiesSettledNearOtherCiv() {
val citiesWithin6Tiles = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != civInfo }
.flatMap { it.cities }
.filter { it.getCenterTile().aerialDistanceTo(getCenterTile()) <= 6 }
val civsWithCloseCities = citiesWithin6Tiles.map { it.civInfo }.distinct()
.filter { it.knows(civInfo) && it.exploredTiles.contains(location) }
for(otherCiv in civsWithCloseCities)
otherCiv.getDiplomacyManager(civInfo).setFlag(DiplomacyFlags.SettledCitiesNearUs,30)
for (otherCiv in civsWithCloseCities)
otherCiv.getDiplomacyManager(civInfo).setFlag(DiplomacyFlags.SettledCitiesNearUs, 30)
}
fun canPurchase(construction : IConstruction) : Boolean {
if (construction is BaseUnit)
{
fun canPurchase(construction: IConstruction): Boolean {
if (construction is BaseUnit) {
val tile = getCenterTile()
if (construction.unitType.isCivilian())
return tile.civilianUnit == null
@ -640,4 +649,4 @@ class CityInfo {
return true
}
//endregion
}
}

View File

@ -32,28 +32,40 @@ import kotlin.math.roundToInt
class CivilizationInfo {
@Transient lateinit var gameInfo: GameInfo
@Transient lateinit var nation:Nation
@Transient
lateinit var gameInfo: GameInfo
@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>()
@Transient var viewableTiles = setOf<TileInfo>()
@Transient var viewableInvisibleUnitsTiles = setOf<TileInfo>()
@Transient
private var units = listOf<MapUnit>()
@Transient
var viewableTiles = setOf<TileInfo>()
@Transient
var viewableInvisibleUnitsTiles = setOf<TileInfo>()
/** Contains mapping of cities to travel mediums from ALL civilizations connected by trade routes to the capital */
@Transient var citiesConnectedToCapitalToMediums = mapOf<CityInfo, Set<String>>()
@Transient
var citiesConnectedToCapitalToMediums = mapOf<CityInfo, Set<String>>()
/** This is for performance since every movement calculation depends on this, see MapUnit comment */
@Transient var hasActiveGreatWall = false
@Transient var statsForNextTurn = Stats()
@Transient var happinessForNextTurn = 0
@Transient var detailedCivResources = ResourceSupplyList()
@Transient
var hasActiveGreatWall = false
@Transient
var statsForNextTurn = Stats()
@Transient
var happinessForNextTurn = 0
@Transient
var detailedCivResources = ResourceSupplyList()
var playerType = PlayerType.AI
/** Used in online multiplayer for human players */ var playerId = ""
/** Used in online multiplayer for human players */
var playerId = ""
var gold = 0
var civName = ""
var tech = TechManager()
@ -61,7 +73,7 @@ class CivilizationInfo {
var questManager = QuestManager()
var goldenAges = GoldenAgeManager()
var greatPeople = GreatPersonManager()
var victoryManager=VictoryManager()
var victoryManager = VictoryManager()
var diplomacy = HashMap<String, DiplomacyManager>()
var notifications = ArrayList<Notification>()
val popupAlerts = ArrayList<PopupAlert>()
@ -115,24 +127,27 @@ class CivilizationInfo {
}
//region pure functions
fun getDifficulty():Difficulty {
fun getDifficulty(): Difficulty {
if (isPlayerCivilization()) return gameInfo.getDifficulty()
return gameInfo.ruleSet.difficulties["Chieftain"]!!
}
fun getDiplomacyManager(civInfo: CivilizationInfo) = getDiplomacyManager(civInfo.civName)
fun getDiplomacyManager(civName: String) = diplomacy[civName]!!
/** Returns only undefeated civs, aka the ones we care about */
fun getKnownCivs() = diplomacy.values.map { it.otherCiv() }.filter { !it.isDefeated() }
fun knows(otherCivName: String) = diplomacy.containsKey(otherCivName)
fun knows(otherCiv: CivilizationInfo) = knows(otherCiv.civName)
fun getCapital()= cities.first { it.isCapital() }
fun isPlayerCivilization() = playerType==PlayerType.Human
fun getCapital() = cities.first { it.isCapital() }
fun isPlayerCivilization() = playerType == PlayerType.Human
fun isOneCityChallenger() = (
playerType==PlayerType.Human &&
gameInfo.gameParameters.oneCityChallenge)
fun isCurrentPlayer() = gameInfo.getCurrentPlayerCivilization()==this
fun isBarbarian() = nation.isBarbarian()
playerType == PlayerType.Human &&
gameInfo.gameParameters.oneCityChallenge)
fun isCurrentPlayer() = gameInfo.getCurrentPlayerCivilization() == this
fun isBarbarian() = nation.isBarbarian()
fun isSpectator() = nation.isSpectator()
fun isCityState(): Boolean = nation.isCityState()
val cityStateType: CityStateType get() = nation.cityStateType!!
@ -144,10 +159,10 @@ class CivilizationInfo {
fun getCivTerritory() = cities.asSequence().flatMap { it.tiles.asSequence() }
fun victoryType(): VictoryType {
if(gameInfo.gameParameters.victoryTypes.size==1)
if (gameInfo.gameParameters.victoryTypes.size == 1)
return gameInfo.gameParameters.victoryTypes.first() // That is the most relevant one
val victoryType = nation.preferredVictoryType
if(gameInfo.gameParameters.victoryTypes.contains(victoryType)) return victoryType
if (gameInfo.gameParameters.victoryTypes.contains(victoryType)) return victoryType
else return VictoryType.Neutral
}
@ -163,9 +178,9 @@ class CivilizationInfo {
fun getCivResources(): ResourceSupplyList {
val newResourceSupplyList=ResourceSupplyList()
for(resourceSupply in detailedCivResources)
newResourceSupplyList.add(resourceSupply.resource,resourceSupply.amount,"All")
val newResourceSupplyList = ResourceSupplyList()
for (resourceSupply in detailedCivResources)
newResourceSupplyList.add(resourceSupply.resource, resourceSupply.amount, "All")
return newResourceSupplyList
}
@ -179,10 +194,10 @@ class CivilizationInfo {
/**
* Returns a dictionary of ALL resource names, and the amount that the civ has of each
*/
fun getCivResourcesByName():HashMap<String,Int> {
val hashMap = HashMap<String,Int>(gameInfo.ruleSet.tileResources.size)
for(resource in gameInfo.ruleSet.tileResources.keys) hashMap[resource]=0
for(entry in getCivResources())
fun getCivResourcesByName(): HashMap<String, Int> {
val hashMap = HashMap<String, Int>(gameInfo.ruleSet.tileResources.size)
for (resource in gameInfo.ruleSet.tileResources.keys) hashMap[resource] = 0
for (entry in getCivResources())
hashMap[entry.resource.name] = entry.amount
return hashMap
}
@ -199,11 +214,11 @@ class CivilizationInfo {
return resourceModifier
}
fun hasResource(resourceName:String): Boolean = getCivResourcesByName()[resourceName]!!>0
fun hasResource(resourceName: String): Boolean = getCivResourcesByName()[resourceName]!! > 0
fun getBuildingUniques(): Sequence<Unique> = cities.asSequence().flatMap { it.cityConstructions.builtBuildingUniqueMap.getAllUniques() }
fun hasUnique(unique:String) = getMatchingUniques(unique).any()
fun hasUnique(unique: String) = getMatchingUniques(unique).any()
fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> {
return nation.uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate } +
@ -215,12 +230,12 @@ class CivilizationInfo {
fun getCivUnits(): Sequence<MapUnit> = units.asSequence()
fun getCivGreatPeople(): Sequence<MapUnit> = getCivUnits().filter { mapUnit -> mapUnit.hasUnique("Great Person - []") }
fun addUnit(mapUnit: MapUnit, updateCivInfo:Boolean=true){
fun addUnit(mapUnit: MapUnit, updateCivInfo: Boolean = true) {
val newList = ArrayList(units)
newList.add(mapUnit)
units=newList
units = newList
if(updateCivInfo) {
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
@ -244,7 +259,7 @@ class CivilizationInfo {
fun getNextDueUnit(): MapUnit? {
val dueUnits = getDueUnits()
if(dueUnits.any()) {
if (dueUnits.any()) {
val unit = dueUnits.first()
unit.due = false
return unit
@ -260,17 +275,16 @@ class CivilizationInfo {
}
fun getEquivalentBuilding(buildingName:String): Building {
fun getEquivalentBuilding(buildingName: String): Building {
val baseBuilding = gameInfo.ruleSet.buildings[buildingName]!!.getBaseBuilding(gameInfo.ruleSet)
for(building in gameInfo.ruleSet.buildings.values)
if(building.replaces==baseBuilding.name && building.uniqueTo==civName)
for (building in gameInfo.ruleSet.buildings.values)
if (building.replaces == baseBuilding.name && building.uniqueTo == civName)
return building
return baseBuilding
}
fun getEquivalentUnit(baseUnitName:String):BaseUnit {
fun getEquivalentUnit(baseUnitName: String): BaseUnit {
for (unit in gameInfo.ruleSet.units.values)
if (unit.replaces == baseUnitName && unit.uniqueTo == civName)
return unit
@ -283,22 +297,23 @@ class CivilizationInfo {
diplomacy[otherCiv.civName] = DiplomacyManager(this, otherCiv.civName)
.apply { diplomaticStatus = DiplomaticStatus.Peace }
otherCiv.popupAlerts.add(PopupAlert(AlertType.FirstContact,civName))
otherCiv.popupAlerts.add(PopupAlert(AlertType.FirstContact, civName))
otherCiv.diplomacy[civName] = DiplomacyManager(otherCiv, civName)
.apply { diplomaticStatus = DiplomaticStatus.Peace }
popupAlerts.add(PopupAlert(AlertType.FirstContact,otherCiv.civName))
popupAlerts.add(PopupAlert(AlertType.FirstContact, otherCiv.civName))
if(isCurrentPlayer() || otherCiv.isCurrentPlayer())
if (isCurrentPlayer() || otherCiv.isCurrentPlayer())
UncivGame.Current.settings.addCompletedTutorialTask("Meet another civilization")
}
fun discoverNaturalWonder(naturalWonderName: String)
{
fun discoverNaturalWonder(naturalWonderName: String) {
naturalWonders.add(naturalWonderName)
}
override fun toString(): String {return civName} // for debug
override fun toString(): String {
return civName
} // for debug
/** Returns true if the civ was fully initialized and has no cities remaining */
fun isDefeated(): Boolean {
@ -314,9 +329,9 @@ class CivilizationInfo {
fun getEra(): String {
// For scenarios with no techs
if (gameInfo.ruleSet.technologies.isEmpty()) return "None"
if(tech.researchedTechnologies.isEmpty())
if (tech.researchedTechnologies.isEmpty())
return gameInfo.ruleSet.getEras().first()
val maxEraOfTech = tech.researchedTechnologies
val maxEraOfTech = tech.researchedTechnologies
.asSequence()
.map { it.column!! }
.maxBy { it.columnNumber }!!
@ -328,7 +343,7 @@ class CivilizationInfo {
return gameInfo.ruleSet.getEraNumber(getEra())
}
fun isAtWarWith(otherCiv:CivilizationInfo): Boolean {
fun isAtWarWith(otherCiv: CivilizationInfo): Boolean {
if (otherCiv.civName == civName) return false // never at war with itself
if (otherCiv.isBarbarian() || isBarbarian()) return true
val diplomacyManager = diplomacy[otherCiv.civName]
@ -336,7 +351,7 @@ class CivilizationInfo {
return diplomacyManager.diplomaticStatus == DiplomaticStatus.War
}
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus== DiplomaticStatus.War && !it.otherCiv().isDefeated() }
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus == DiplomaticStatus.War && !it.otherCiv().isDefeated() }
fun getLeaderDisplayName(): String {
var leaderName = nation.getLeaderDisplayName().tr()
@ -349,10 +364,10 @@ class CivilizationInfo {
}
fun canSignResearchAgreement(): Boolean {
if(!isMajorCiv()) return false
if(!tech.getTechUniques().contains("Enables Research agreements")) return false
if (!isMajorCiv()) return false
if (!tech.getTechUniques().contains("Enables Research agreements")) return false
if (gameInfo.ruleSet.technologies.values
.none { tech.canBeResearched(it.name) && !tech.isResearched(it.name) }) return false
.none { tech.canBeResearched(it.name) && !tech.isResearched(it.name) }) return false
return true
}
@ -366,8 +381,8 @@ class CivilizationInfo {
&& gold >= cost && otherCiv.gold >= cost
}
fun getStatForRanking(category: RankingType) : Int {
return when(category) {
fun getStatForRanking(category: RankingType): Int {
return when (category) {
RankingType.Population -> cities.sumBy { it.population.population }
RankingType.CropYield -> statsForNextTurn.food.roundToInt()
RankingType.Production -> statsForNextTurn.production.roundToInt()
@ -388,7 +403,7 @@ class CivilizationInfo {
* and the updateVisibleTiles tries to meet civs...
* And if they civs on't yet know who they are then they don;t know if they're barbarians =\
* */
fun setNationTransient(){
fun setNationTransient() {
nation = gameInfo.ruleSet.nations[civName]
?: throw java.lang.Exception("Nation $civName is not found!")
}
@ -397,25 +412,25 @@ class CivilizationInfo {
goldenAges.civInfo = this
policies.civInfo = this
if(policies.adoptedPolicies.size>0 && policies.numberOfAdoptedPolicies == 0)
if (policies.adoptedPolicies.size > 0 && policies.numberOfAdoptedPolicies == 0)
policies.numberOfAdoptedPolicies = policies.adoptedPolicies.count { !it.endsWith("Complete") }
policies.setTransients()
questManager.civInfo = this
questManager.setTransients()
if(citiesCreated==0 && cities.any())
if (citiesCreated == 0 && cities.any())
citiesCreated = cities.filter { it.name in nation.cities }.count()
tech.civInfo = this
tech.setTransients()
for (diplomacyManager in diplomacy.values) {
diplomacyManager.civInfo=this
diplomacyManager.civInfo = this
diplomacyManager.updateHasOpenBorders()
}
victoryManager.civInfo=this
victoryManager.civInfo = this
for (cityInfo in cities) {
cityInfo.civInfo = this // must be before the city's setTransients because it depends on the tilemap, that comes from the currentPlayerCivInfo
@ -452,9 +467,9 @@ class CivilizationInfo {
for (unit in getCivUnits()) unit.startTurn()
for(tradeRequest in tradeRequests.toList()) { // remove trade requests where one of the sides can no longer supply
for (tradeRequest in tradeRequests.toList()) { // remove trade requests where one of the sides can no longer supply
val offeringCiv = gameInfo.getCivilization(tradeRequest.requestingCiv)
if (offeringCiv.isDefeated() || !TradeEvaluation().isTradeValid(tradeRequest.trade,this, offeringCiv)) {
if (offeringCiv.isDefeated() || !TradeEvaluation().isTradeValid(tradeRequest.trade, this, offeringCiv)) {
tradeRequests.remove(tradeRequest)
// Yes, this is the right direction. I checked.
offeringCiv.addNotification("Our proposed trade is no longer relevant!", Color.GOLD)
@ -512,7 +527,7 @@ class CivilizationInfo {
}
fun canEnterTiles(otherCiv: CivilizationInfo): Boolean {
if (otherCiv==this) return true
if (otherCiv == this) return true
if (otherCiv.isBarbarian()) return true
if (nation.isBarbarian() && gameInfo.turns >= gameInfo.difficultyObject.turnBarbariansCanEnterPlayerTiles)
return true
@ -526,12 +541,12 @@ class CivilizationInfo {
addNotification(text, color, LocationAction(locations))
}
fun addNotification(text: String, color: Color, action: NotificationAction?=null) {
fun addNotification(text: String, color: Color, action: NotificationAction? = null) {
if (playerType == PlayerType.AI) return // no point in lengthening the saved game info if no one will read it
notifications.add(Notification(text, color, action))
}
fun addUnit(unitName:String, city: CityInfo?=null) {
fun addUnit(unitName: String, city: CityInfo? = null) {
if (cities.isEmpty()) return
val cityToAddTo = city ?: cities.random()
if (!gameInfo.ruleSet.units.containsKey(unitName)) return
@ -551,32 +566,32 @@ class CivilizationInfo {
}
fun destroy(){
val destructionText = if(isMajorCiv()) "The civilization of [$civName] has been destroyed!"
fun destroy() {
val destructionText = if (isMajorCiv()) "The civilization of [$civName] has been destroyed!"
else "The City-State of [$civName] has been destroyed!"
for(civ in gameInfo.civilizations)
for (civ in gameInfo.civilizations)
civ.addNotification(destructionText, null, Color.RED)
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){
for (diplomacyManager in diplomacy.values) {
diplomacyManager.trades.clear()
diplomacyManager.otherCiv().getDiplomacyManager(this).trades.clear()
for(tradeRequest in diplomacyManager.otherCiv().tradeRequests.filter { it.requestingCiv==civName })
for (tradeRequest in diplomacyManager.otherCiv().tradeRequests.filter { it.requestingCiv == civName })
diplomacyManager.otherCiv().tradeRequests.remove(tradeRequest) // it would be really weird to get a trade request from a dead civ
}
}
fun giveGoldGift(otherCiv: CivilizationInfo, giftAmount: Int) {
if(!otherCiv.isCityState()) throw Exception("You can only gain influence with City-States!")
if (!otherCiv.isCityState()) throw Exception("You can only gain influence with City-States!")
gold -= giftAmount
otherCiv.getDiplomacyManager(this).influence += giftAmount/10
otherCiv.getDiplomacyManager(this).influence += giftAmount / 10
otherCiv.updateAllyCivForCityState()
updateStatsForNextTurn()
}
fun getResearchAgreementCost(otherCiv: CivilizationInfo): Int {
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
val basicGoldCostOfSignResearchAgreement = when(getEra()){
val basicGoldCostOfSignResearchAgreement = when (getEra()) {
Constants.medievalEra, Constants.renaissanceEra -> 250
Constants.industrialEra -> 300
Constants.modernEra -> 350
@ -601,7 +616,7 @@ class CivilizationInfo {
var newAllyName = ""
if (!isCityState()) return
val maxInfluence = diplomacy
.filter{ !it.value.otherCiv().isCityState() && !it.value.otherCiv().isDefeated() }
.filter { !it.value.otherCiv().isCityState() && !it.value.otherCiv().isDefeated() }
.maxBy { it.value.influence }
if (maxInfluence != null && maxInfluence.value.influence >= 60) {
newAllyName = maxInfluence.key
@ -613,7 +628,7 @@ class CivilizationInfo {
// If the city-state is captured by a civ, it stops being the ally of the civ it was previously an ally of.
// This means that it will NOT HAVE a capital at that time, so if we run getCapital we'll get a crash!
val capitalLocation = if(cities.isNotEmpty()) getCapital().location else null
val capitalLocation = if (cities.isNotEmpty()) getCapital().location else null
if (newAllyName != "") {
val newAllyCiv = gameInfo.getCivilization(newAllyName)
@ -631,4 +646,4 @@ class CivilizationInfo {
}
//endregion
}
}

View File

@ -14,15 +14,22 @@ import com.unciv.ui.utils.Fonts
import kotlin.math.abs
open class TileInfo {
@Transient lateinit var tileMap: TileMap
@Transient lateinit var ruleset: Ruleset // a tile can be a tile with a ruleset, even without a map.
@Transient var owningCity:CityInfo?=null
@Transient private lateinit var baseTerrainObject:Terrain
@Transient
lateinit var tileMap: TileMap
@Transient
lateinit var ruleset: Ruleset // a tile can be a tile with a ruleset, even without a map.
@Transient
var owningCity: CityInfo? = null
@Transient
private lateinit var baseTerrainObject: Terrain
// These are for performance - checked with every tile movement and "canEnter" check, which makes them performance-critical
@Transient var isLand = false
@Transient var isWater = false
@Transient var isOcean = false
@Transient
var isLand = false
@Transient
var isWater = false
@Transient
var isOcean = false
// This will be called often - farm can be built on Hill and tundra if adjacent to fresh water
// and farms on adjacent to fresh water tiles will have +1 additional Food after researching Civil Service
@ -80,7 +87,7 @@ open class TileInfo {
}
fun containsUnfinishedGreatImprovement(): Boolean {
if(improvementInProgress==null) return false
if (improvementInProgress == null) return false
return ruleset.tileImprovements[improvementInProgress!!]!!.isGreatImprovement()
}
@ -298,7 +305,7 @@ open class TileInfo {
/** Without regards to what civinfo it is, a lot of the checks are just for the improvement on the tile.
* Doubles as a check for the map editor.
*/
fun canImprovementBeBuiltHere(improvement: TileImprovement, resourceIsVisible:Boolean = resource!=null): Boolean {
fun canImprovementBeBuiltHere(improvement: TileImprovement, resourceIsVisible: Boolean = resource != null): Boolean {
val topTerrain = getLastTerrain()
return when {
@ -325,7 +332,7 @@ open class TileInfo {
}
}
fun matchesUniqueFilter(filter:String): Boolean {
fun matchesUniqueFilter(filter: String): Boolean {
return filter == baseTerrain
|| filter == Constants.hill && isHill()
|| filter == "River" && isAdjacentToRiver()
@ -382,8 +389,8 @@ open class TileInfo {
}
/** The two tiles have a river between them */
fun isConnectedByRiver(otherTile:TileInfo): Boolean {
if(otherTile==this) throw Exception("Should not be called to compare to self!")
fun isConnectedByRiver(otherTile: TileInfo): Boolean {
if (otherTile == this) throw Exception("Should not be called to compare to self!")
val xDifference = this.position.x - otherTile.position.x
val yDifference = this.position.y - otherTile.position.y
@ -496,4 +503,4 @@ open class TileInfo {
&& (terrainFeature == Constants.jungle || terrainFeature == Constants.forest)
&& isFriendlyTerritory(civInfo)
//endregion
}
}

View File

@ -12,13 +12,20 @@ import kotlin.math.abs
class TileMap {
@Transient lateinit var gameInfo: GameInfo
@Transient var tileMatrix = ArrayList<ArrayList<TileInfo?>>() // this works several times faster than a hashmap, the performance difference is really astounding
@Transient var leftX = 0
@Transient var bottomY = 0
@delegate:Transient val maxLatitude: Float by lazy { if (values.isEmpty()) 0f else values.map { abs(it.latitude) }.max()!! }
@delegate:Transient val maxLongitude: Float by lazy { if (values.isEmpty()) 0f else values.map { abs(it.longitude) }.max()!! }
@delegate:Transient val naturalWonders: List<String> by lazy { tileList.asSequence().filter { it.isNaturalWonder() }.map { it.naturalWonder!! }.distinct().toList() }
@Transient
lateinit var gameInfo: GameInfo
@Transient
var tileMatrix = ArrayList<ArrayList<TileInfo?>>() // this works several times faster than a hashmap, the performance difference is really astounding
@Transient
var leftX = 0
@Transient
var bottomY = 0
@delegate:Transient
val maxLatitude: Float by lazy { if (values.isEmpty()) 0f else values.map { abs(it.latitude) }.max()!! }
@delegate:Transient
val maxLongitude: Float by lazy { if (values.isEmpty()) 0f else values.map { abs(it.longitude) }.max()!! }
@delegate:Transient
val naturalWonders: List<String> by lazy { tileList.asSequence().filter { it.isNaturalWonder() }.map { it.naturalWonder!! }.distinct().toList() }
var mapParameters = MapParameters()
@ -31,19 +38,20 @@ class TileMap {
constructor()
/** generates an hexagonal map of given radius */
constructor(radius:Int, ruleset: Ruleset){
for(vector in HexMath.getVectorsInDistance(Vector2.Zero, radius))
constructor(radius: Int, ruleset: Ruleset) {
for (vector in HexMath.getVectorsInDistance(Vector2.Zero, radius))
tileList.add(TileInfo().apply { position = vector; baseTerrain = Constants.grassland })
setTransients(ruleset)
}
/** generates a rectangular map of given width and height*/
constructor(width: Int, height: Int, ruleset: Ruleset) {
for(x in -width/2..width/2)
for (y in -height/2..height/2)
for (x in -width / 2..width / 2)
for (y in -height / 2..height / 2)
tileList.add(TileInfo().apply {
position = HexMath.evenQ2HexCoords(Vector2(x.toFloat(),y.toFloat()))
baseTerrain = Constants.grassland })
position = HexMath.evenQ2HexCoords(Vector2(x.toFloat(), y.toFloat()))
baseTerrain = Constants.grassland
})
setTransients(ruleset)
}
@ -58,17 +66,17 @@ class TileMap {
return contains(vector.x.toInt(), vector.y.toInt())
}
fun contains(x:Int, y:Int): Boolean {
val arrayXIndex = x-leftX
if(arrayXIndex<0 || arrayXIndex>=tileMatrix.size) return false
val arrayYIndex = y-bottomY
if(arrayYIndex<0 || arrayYIndex>=tileMatrix[arrayXIndex].size) return false
fun contains(x: Int, y: Int): Boolean {
val arrayXIndex = x - leftX
if (arrayXIndex < 0 || arrayXIndex >= tileMatrix.size) return false
val arrayYIndex = y - bottomY
if (arrayYIndex < 0 || arrayYIndex >= tileMatrix[arrayXIndex].size) return false
return tileMatrix[arrayXIndex][arrayYIndex] != null
}
operator fun get(x:Int, y:Int):TileInfo{
val arrayXIndex = x-leftX
val arrayYIndex = y-bottomY
operator fun get(x: Int, y: Int): TileInfo {
val arrayXIndex = x - leftX
val arrayYIndex = y - bottomY
return tileMatrix[arrayXIndex][arrayYIndex]!!
}
@ -134,7 +142,7 @@ class TileMap {
// both the civ name and actual civ need to be in here in order to calculate the canMoveTo...Darn
unit.assignOwner(civInfo, false)
var unitToPlaceTile : TileInfo? = null
var unitToPlaceTile: TileInfo? = null
// try to place at the original point (this is the most probable scenario)
val currentTile = get(position)
if (unit.movement.canMoveTo(currentTile)) unitToPlaceTile = currentTile
@ -145,7 +153,7 @@ class TileMap {
var potentialCandidates = getPassableNeighbours(currentTile)
while (unitToPlaceTile == null && tryCount++ < 10) {
unitToPlaceTile = potentialCandidates
.sortedByDescending { if(unit.type.isLandUnit()) it.isLand else true } // Land units should prefer to go into land tiles
.sortedByDescending { if (unit.type.isLandUnit()) it.isLand else true } // Land units should prefer to go into land tiles
.firstOrNull { unit.movement.canMoveTo(it) }
if (unitToPlaceTile != null) continue
// if it's not found yet, let's check their neighbours
@ -228,7 +236,7 @@ class TileMap {
* @return stripped clone of [TileMap]
*/
fun stripAllUnits(): TileMap {
return clone().apply { tileList.forEach {it.stripUnits()} }
return clone().apply { tileList.forEach { it.stripUnits() } }
}
/** Strips all units and starting location from [TileMap] for specified [Player]
@ -237,7 +245,9 @@ class TileMap {
*/
fun stripPlayer(player: Player) {
tileList.forEach {
if (it.improvement == "StartingLocation " + player.chosenCiv) { it.improvement = null }
if (it.improvement == "StartingLocation " + player.chosenCiv) {
it.improvement = null
}
for (unit in it.getUnits()) if (unit.owner == player.chosenCiv) unit.removeFromTile()
}
}
@ -249,33 +259,34 @@ class TileMap {
*/
fun switchPlayersNation(player: Player, newNation: Nation) {
tileList.forEach {
if (it.improvement == "StartingLocation " + player.chosenCiv) { it.improvement = "StartingLocation "+newNation.name }
if (it.improvement == "StartingLocation " + player.chosenCiv) {
it.improvement = "StartingLocation " + newNation.name
}
for (unit in it.getUnits()) if (unit.owner == player.chosenCiv) {
unit.owner = newNation.name
unit.civInfo = CivilizationInfo(newNation.name).apply { nation=newNation }
unit.civInfo = CivilizationInfo(newNation.name).apply { nation = newNation }
}
}
}
fun setTransients(ruleset: Ruleset, setUnitCivTransients:Boolean=true) { // In the map editor, no Civs or Game exist, so we won't set the unit transients
val topY= tileList.asSequence().map { it.position.y.toInt() }.max()!!
bottomY= tileList.asSequence().map { it.position.y.toInt() }.min()!!
val rightX= tileList.asSequence().map { it.position.x.toInt() }.max()!!
fun setTransients(ruleset: Ruleset, setUnitCivTransients: Boolean = true) { // In the map editor, no Civs or Game exist, so we won't set the unit transients
val topY = tileList.asSequence().map { it.position.y.toInt() }.max()!!
bottomY = tileList.asSequence().map { it.position.y.toInt() }.min()!!
val rightX = tileList.asSequence().map { it.position.x.toInt() }.max()!!
leftX = tileList.asSequence().map { it.position.x.toInt() }.min()!!
for(x in leftX..rightX){
for (x in leftX..rightX) {
val row = ArrayList<TileInfo?>()
for(y in bottomY..topY) row.add(null)
for (y in bottomY..topY) row.add(null)
tileMatrix.add(row)
}
for (tileInfo in values){
tileMatrix[tileInfo.position.x.toInt()-leftX][tileInfo.position.y.toInt()-bottomY] = tileInfo
for (tileInfo in values) {
tileMatrix[tileInfo.position.x.toInt() - leftX][tileInfo.position.y.toInt() - bottomY] = tileInfo
tileInfo.tileMap = this
tileInfo.ruleset = ruleset
tileInfo.setTerrainTransients()
tileInfo.setUnitTransients(setUnitCivTransients)
}
}
}
}