From 06091d640dfd4b26167a9729e1569f8bc58a5ba3 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Fri, 17 Aug 2018 14:45:48 +0300 Subject: [PATCH] civ units are now cached and not calculated every time --- core/src/com/unciv/logic/battle/Battle.kt | 7 +- .../unciv/logic/battle/MapUnitCombatant.kt | 2 +- .../logic/civilization/CivilizationInfo.kt | 10 +- core/src/com/unciv/logic/map/MapUnit.kt | 197 +++++++++--------- core/src/com/unciv/logic/map/TileMap.kt | 4 +- .../unciv/ui/worldscreen/unit/UnitActions.kt | 16 +- 6 files changed, 123 insertions(+), 113 deletions(-) diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 91e1480285..0438b1e819 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -120,7 +120,7 @@ class Battle(val gameInfo:GameInfo=UnCivGame.Current.gameInfo) { if(enemyCiv.isDefeated()) { gameInfo.getPlayerCivilization() .addNotification("The civilization of [${enemyCiv.civName}] has been destroyed!", null, Color.RED) - enemyCiv.getCivUnits().forEach { it.removeFromTile() } + enemyCiv.getCivUnits().forEach { it.destroy() } } else if(enemyCiv.cities.isNotEmpty()){ enemyCiv.cities.first().cityConstructions.builtBuildings.add("Palace") // relocate palace @@ -145,7 +145,8 @@ class Battle(val gameInfo:GameInfo=UnCivGame.Current.gameInfo) { val capturedUnit = (defender as MapUnitCombatant).unit capturedUnit.civInfo.addNotification("An enemy ["+attacker.getName()+"] has captured our ["+defender.getName()+"]", defender.getTile().position, Color.RED) - capturedUnit.civInfo = attacker.getCivilization() - capturedUnit.owner = capturedUnit.civInfo.civName + + capturedUnit.civInfo.units.remove(capturedUnit) + capturedUnit.assignOwner(attacker.getCivilization()) } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/battle/MapUnitCombatant.kt b/core/src/com/unciv/logic/battle/MapUnitCombatant.kt index d8da3bdb7d..6477d63b9a 100644 --- a/core/src/com/unciv/logic/battle/MapUnitCombatant.kt +++ b/core/src/com/unciv/logic/battle/MapUnitCombatant.kt @@ -14,7 +14,7 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant { override fun takeDamage(damage: Int) { unit.health -= damage - if(isDefeated()) unit.removeFromTile() + if(isDefeated()) unit.destroy() } override fun getAttackingStrength(defender: ICombatant): Int { // todo remove defender diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index e950bc6236..e3b3de68a6 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -23,6 +23,7 @@ import kotlin.math.roundToInt class CivilizationInfo { @Transient lateinit var gameInfo: GameInfo + @Transient var units=ArrayList() var gold = 0 var happiness = 15 @@ -174,7 +175,7 @@ class CivilizationInfo { fun getBuildingUniques(): List = cities.flatMap { it.cityConstructions.getBuiltBuildings().map { it.unique }.filterNotNull() }.distinct() fun getCivUnits(): List { - return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName } + return units } fun getViewableTiles(): List { @@ -232,12 +233,11 @@ class CivilizationInfo { tech.civInfo = this diplomacy.values.forEach { it.civInfo=this} - for (unit in getCivUnits()) { - unit.civInfo=this + for (unit in gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName }) { + unit.assignOwner(this) unit.setTransients() } - for (cityInfo in cities) { cityInfo.setTransients() cityInfo.civInfo = this @@ -255,7 +255,7 @@ class CivilizationInfo { var civMilitaryUnits = getCivUnits().filter { it.baseUnit().unitType != UnitType.Civilian } if (civMilitaryUnits.isNotEmpty()) { val unitToDisband = civMilitaryUnits.first() - unitToDisband.removeFromTile() + unitToDisband.destroy() civMilitaryUnits -= unitToDisband addNotification("Cannot provide unit upkeep for " + unitToDisband.name + " - unit has been disbanded!".tr(), null, Color.RED) } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index a1b5486041..7d639773f0 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -9,8 +9,9 @@ import com.unciv.models.gamebasics.unit.UnitType import java.text.DecimalFormat class MapUnit { - @Transient - lateinit var civInfo: CivilizationInfo + @Transient lateinit var civInfo: CivilizationInfo + @Transient lateinit var baseUnit: BaseUnit + @Transient internal lateinit var currentTile :TileInfo lateinit var owner: String lateinit var name: String @@ -20,12 +21,21 @@ class MapUnit { var attacksThisTurn = 0 var promotions = UnitPromotions() - @Transient lateinit var baseUnit: BaseUnit + //region pure functions + fun clone(): MapUnit { + val toReturn = MapUnit() + toReturn.action=action + toReturn.currentMovement=currentMovement + toReturn.name=name + toReturn.promotions=promotions.clone() + toReturn.health=health + toReturn.attacksThisTurn=attacksThisTurn + toReturn.owner=owner + return toReturn + } + fun baseUnit(): BaseUnit = baseUnit fun getMovementString(): String = DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + getMaxMovement() - - @Transient - internal lateinit var currentTile :TileInfo fun getTile(): TileInfo = currentTile fun getMaxMovement() = baseUnit.movement @@ -34,6 +44,83 @@ class MapUnit { return movementAlgs().getDistanceToTilesWithinTurn(tile.position,currentMovement) } + fun getSpecialAbilities(): MutableList { + val abilities = mutableListOf() + val baseUnit = baseUnit() + if(baseUnit.uniques!=null) abilities.addAll(baseUnit.uniques!!) + abilities.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect }) + return abilities + } + + fun hasUnique(unique:String): Boolean { + return getSpecialAbilities().contains(unique) + } + + fun getViewableTiles(): MutableList { + var visibilityRange = 2 + visibilityRange += getSpecialAbilities().count{it=="+1 Visibility Range"} + if(hasUnique("Limited Visibility")) visibilityRange-=1 + val tile = getTile() + if (tile.baseTerrain == "Hill") visibilityRange += 1 + return tile.getViewableTiles(visibilityRange) + } + + fun isFortified(): Boolean { + return action!=null && action!!.startsWith("Fortify") + } + + fun getFortificationTurns(): Int { + if(!isFortified()) return 0 + return action!!.split(" ")[1].toInt() + } + + fun movementAlgs() = UnitMovementAlgorithms(this) + + override fun toString(): String { + return "$name - $owner" + } + + /** + * Designates whether we can walk to the tile - without attacking + */ + fun canMoveTo(tile: TileInfo): Boolean { + val tileOwner = tile.getOwner() + if(tileOwner!=null && tileOwner.civName!=owner + && (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false + + if (baseUnit().unitType== UnitType.Civilian) + return tile.civilianUnit==null && (tile.militaryUnit==null || tile.militaryUnit!!.owner==owner) + else return tile.militaryUnit==null && (tile.civilianUnit==null || tile.civilianUnit!!.owner==owner) + } + + fun isIdle(): Boolean { + if (currentMovement == 0f) return false + if (name == "Worker" && getTile().improvementInProgress != null) return false + if (isFortified()) return false + return true + } + + fun canAttack(): Boolean { + if(currentMovement==0f) return false + if(attacksThisTurn>0) return false + if(hasUnique("Must set up to ranged attack") && action != "Set Up") return false + return true + } + + fun getRange(): Int { + if(baseUnit().unitType.isMelee()) return 1 + var range = baseUnit().range + if(hasUnique("+1 Range")) range++ + return range + } + + //endregion + + //region state-changing functions + fun setTransients(){ + promotions.unit=this + baseUnit=GameBasics.Units[name]!! + } fun doPreTurnAction() { val currentTile = getTile() if (currentMovement == 0f) return // We've already done stuff this turn, and can't do any more stuff @@ -92,10 +179,6 @@ class MapUnit { tile.improvementInProgress = null } - /** - * @return The tile that we reached this turn - */ - private fun heal(){ val tile = getTile() health += when{ @@ -107,6 +190,9 @@ class MapUnit { if(health>100) health=100 } + /** + * @return The tile that we reached this turn + */ fun moveToTile(otherTile: TileInfo) { if(otherTile==getTile()) return // already here! val distanceToTiles = getDistanceToTiles() @@ -139,40 +225,9 @@ class MapUnit { doPreTurnAction() } - fun getSpecialAbilities(): MutableList { - val abilities = mutableListOf() - val baseUnit = baseUnit() - if(baseUnit.uniques!=null) abilities.addAll(baseUnit.uniques!!) - abilities.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect }) - return abilities - } - - fun hasUnique(unique:String): Boolean { - return getSpecialAbilities().contains(unique) - } - - fun movementAlgs() = UnitMovementAlgorithms(this) - - override fun toString(): String { - return "$name - $owner" - } - - fun getViewableTiles(): MutableList { - var visibilityRange = 2 - visibilityRange += getSpecialAbilities().count{it=="+1 Visibility Range"} - if(hasUnique("Limited Visibility")) visibilityRange-=1 - val tile = getTile() - if (tile.baseTerrain == "Hill") visibilityRange += 1 - return tile.getViewableTiles(visibilityRange) - } - - fun isFortified(): Boolean { - return action!=null && action!!.startsWith("Fortify") - } - - fun getFortificationTurns(): Int { - if(!isFortified()) return 0 - return action!!.split(" ")[1].toInt() + fun destroy(){ + removeFromTile() + civInfo.units.remove(this) } fun removeFromTile(){ @@ -188,54 +243,10 @@ class MapUnit { currentTile = tile } - /** - * Designates whether we can walk to the tile - without attacking - */ - fun canMoveTo(tile: TileInfo): Boolean { - val tileOwner = tile.getOwner() - if(tileOwner!=null && tileOwner.civName!=owner - && (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false - - if (baseUnit().unitType== UnitType.Civilian) - return tile.civilianUnit==null && (tile.militaryUnit==null || tile.militaryUnit!!.owner==owner) - else return tile.militaryUnit==null && (tile.civilianUnit==null || tile.civilianUnit!!.owner==owner) - } - - fun isIdle(): Boolean { - if (currentMovement == 0f) return false - if (name == "Worker" && getTile().improvementInProgress != null) return false - if (isFortified()) return false - return true - } - - fun canAttack(): Boolean { - if(currentMovement==0f) return false - if(attacksThisTurn>0) return false - if(hasUnique("Must set up to ranged attack") && action != "Set Up") return false - return true - } - - fun setTransients(){ - promotions.unit=this - baseUnit=GameBasics.Units[name]!! - } - - fun getRange(): Int { - if(baseUnit().unitType.isMelee()) return 1 - var range = baseUnit().range - if(hasUnique("+1 Range")) range++ - return range - } - - fun clone(): MapUnit { - val toReturn = MapUnit() - toReturn.action=action - toReturn.currentMovement=currentMovement - toReturn.name=name - toReturn.promotions=promotions.clone() - toReturn.health=health - toReturn.attacksThisTurn=attacksThisTurn - toReturn.owner=owner - return toReturn + fun assignOwner(civInfo:CivilizationInfo){ + owner=civInfo.civName + this.civInfo=civInfo + civInfo.units.add(this) } + //endregion } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index bc333ec17c..634e96a973 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -41,11 +41,9 @@ class TileMap { } - fun placeUnitNearTile(position: Vector2, unitName: String, civInfo: CivilizationInfo): MapUnit { val unit = GameBasics.Units[unitName]!!.getMapUnit() - unit.owner = civInfo.civName - unit.civInfo = civInfo + unit.assignOwner(civInfo) val tilesInDistance = getTilesInDistance(position, 2) val unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) } if(unitToPlaceTile!=null) unit.putInTile(unitToPlaceTile) diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index d2dabb20c7..303d9fb4fe 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -22,7 +22,7 @@ class UnitActions { private fun constructImprovementAndDestroyUnit(unit:MapUnit, improvementName: String): () -> Unit { return { unit.getTile().improvement = improvementName - unit.removeFromTile() + unit.destroy() } } @@ -71,7 +71,7 @@ class UnitActions { { unit.civInfo.gold -= goldCostOfUpgrade val unitTile = unit.getTile() - unit.removeFromTile() + unit.destroy() val newunit = unit.civInfo.placeUnitNearTile(unitTile.position, upgradedUnit.name) newunit.health = unit.health newunit.promotions = unit.promotions @@ -95,7 +95,7 @@ class UnitActions { unit.civInfo.addCity(tile.position) tile.improvement=null unitTable.currentlyExecutingAction = null // In case the settler was in the middle of doing something and we then founded a city with it - unit.removeFromTile() + unit.destroy() }, unit.currentMovement != 0f && !tile.getTilesInDistance(2).any { it.isCityCenter() }) @@ -126,7 +126,7 @@ class UnitActions { actionList += UnitAction( "Discover Technology", { unit.civInfo.tech.freeTechs += 1 - unit.removeFromTile() + unit.destroy() worldScreen.game.screen = TechPickerScreen(true, unit.civInfo) },unit.currentMovement != 0f) @@ -139,7 +139,7 @@ class UnitActions { actionList += UnitAction( "Start Golden Age", { unit.civInfo.goldenAges.enterGoldenAge() - unit.removeFromTile() + unit.destroy() },unit.currentMovement != 0f ) actionList += UnitAction("Construct Landmark", @@ -151,7 +151,7 @@ class UnitActions { actionList += UnitAction( "Hurry Wonder", { tile.getCity()!!.cityConstructions.addConstruction(300 + 30 * tile.getCity()!!.population.population) //http://civilization.wikia.com/wiki/Great_engineer_(Civ5) - unit.removeFromTile() + unit.destroy() }, unit.currentMovement != 0f && tile.isCityCenter() && @@ -167,7 +167,7 @@ class UnitActions { actionList += UnitAction("Conduct Trade Mission", { unit.civInfo.gold += 350 // + 50 * era_number - todo! - unit.removeFromTile() + unit.destroy() },unit.currentMovement != 0f) actionList += UnitAction( "Construct Customs House", constructImprovementAndDestroyUnit(unit, "Customs house"), @@ -177,7 +177,7 @@ class UnitActions { actionList += UnitAction("Disband unit", { YesNoPopupTable("Do you really want to disband this unit?".tr(), - {unit.removeFromTile(); worldScreen.update()} ) + {unit.destroy(); worldScreen.update()} ) },unit.currentMovement != 0f) return actionList