civ units are now cached and not calculated every time

This commit is contained in:
Yair Morgenstern
2018-08-17 14:45:48 +03:00
parent 1957c4ca80
commit 06091d640d
6 changed files with 123 additions and 113 deletions

View File

@ -120,7 +120,7 @@ class Battle(val gameInfo:GameInfo=UnCivGame.Current.gameInfo) {
if(enemyCiv.isDefeated()) { if(enemyCiv.isDefeated()) {
gameInfo.getPlayerCivilization() gameInfo.getPlayerCivilization()
.addNotification("The civilization of [${enemyCiv.civName}] has been destroyed!", null, Color.RED) .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()){ else if(enemyCiv.cities.isNotEmpty()){
enemyCiv.cities.first().cityConstructions.builtBuildings.add("Palace") // relocate palace 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 val capturedUnit = (defender as MapUnitCombatant).unit
capturedUnit.civInfo.addNotification("An enemy ["+attacker.getName()+"] has captured our ["+defender.getName()+"]", capturedUnit.civInfo.addNotification("An enemy ["+attacker.getName()+"] has captured our ["+defender.getName()+"]",
defender.getTile().position, Color.RED) defender.getTile().position, Color.RED)
capturedUnit.civInfo = attacker.getCivilization()
capturedUnit.owner = capturedUnit.civInfo.civName capturedUnit.civInfo.units.remove(capturedUnit)
capturedUnit.assignOwner(attacker.getCivilization())
} }
} }

View File

@ -14,7 +14,7 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant {
override fun takeDamage(damage: Int) { override fun takeDamage(damage: Int) {
unit.health -= damage unit.health -= damage
if(isDefeated()) unit.removeFromTile() if(isDefeated()) unit.destroy()
} }
override fun getAttackingStrength(defender: ICombatant): Int { // todo remove defender override fun getAttackingStrength(defender: ICombatant): Int { // todo remove defender

View File

@ -23,6 +23,7 @@ import kotlin.math.roundToInt
class CivilizationInfo { class CivilizationInfo {
@Transient lateinit var gameInfo: GameInfo @Transient lateinit var gameInfo: GameInfo
@Transient var units=ArrayList<MapUnit>()
var gold = 0 var gold = 0
var happiness = 15 var happiness = 15
@ -174,7 +175,7 @@ class CivilizationInfo {
fun getBuildingUniques(): List<String> = cities.flatMap { it.cityConstructions.getBuiltBuildings().map { it.unique }.filterNotNull() }.distinct() fun getBuildingUniques(): List<String> = cities.flatMap { it.cityConstructions.getBuiltBuildings().map { it.unique }.filterNotNull() }.distinct()
fun getCivUnits(): List<MapUnit> { fun getCivUnits(): List<MapUnit> {
return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName } return units
} }
fun getViewableTiles(): List<TileInfo> { fun getViewableTiles(): List<TileInfo> {
@ -232,12 +233,11 @@ class CivilizationInfo {
tech.civInfo = this tech.civInfo = this
diplomacy.values.forEach { it.civInfo=this} diplomacy.values.forEach { it.civInfo=this}
for (unit in getCivUnits()) { for (unit in gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName }) {
unit.civInfo=this unit.assignOwner(this)
unit.setTransients() unit.setTransients()
} }
for (cityInfo in cities) { for (cityInfo in cities) {
cityInfo.setTransients() cityInfo.setTransients()
cityInfo.civInfo = this cityInfo.civInfo = this
@ -255,7 +255,7 @@ class CivilizationInfo {
var civMilitaryUnits = getCivUnits().filter { it.baseUnit().unitType != UnitType.Civilian } var civMilitaryUnits = getCivUnits().filter { it.baseUnit().unitType != UnitType.Civilian }
if (civMilitaryUnits.isNotEmpty()) { if (civMilitaryUnits.isNotEmpty()) {
val unitToDisband = civMilitaryUnits.first() val unitToDisband = civMilitaryUnits.first()
unitToDisband.removeFromTile() unitToDisband.destroy()
civMilitaryUnits -= unitToDisband civMilitaryUnits -= unitToDisband
addNotification("Cannot provide unit upkeep for " + unitToDisband.name + " - unit has been disbanded!".tr(), null, Color.RED) addNotification("Cannot provide unit upkeep for " + unitToDisband.name + " - unit has been disbanded!".tr(), null, Color.RED)
} }

View File

@ -9,8 +9,9 @@ import com.unciv.models.gamebasics.unit.UnitType
import java.text.DecimalFormat import java.text.DecimalFormat
class MapUnit { class MapUnit {
@Transient @Transient lateinit var civInfo: CivilizationInfo
lateinit var civInfo: CivilizationInfo @Transient lateinit var baseUnit: BaseUnit
@Transient internal lateinit var currentTile :TileInfo
lateinit var owner: String lateinit var owner: String
lateinit var name: String lateinit var name: String
@ -20,12 +21,21 @@ class MapUnit {
var attacksThisTurn = 0 var attacksThisTurn = 0
var promotions = UnitPromotions() 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 baseUnit(): BaseUnit = baseUnit
fun getMovementString(): String = DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + getMaxMovement() fun getMovementString(): String = DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + getMaxMovement()
@Transient
internal lateinit var currentTile :TileInfo
fun getTile(): TileInfo = currentTile fun getTile(): TileInfo = currentTile
fun getMaxMovement() = baseUnit.movement fun getMaxMovement() = baseUnit.movement
@ -34,6 +44,83 @@ class MapUnit {
return movementAlgs().getDistanceToTilesWithinTurn(tile.position,currentMovement) return movementAlgs().getDistanceToTilesWithinTurn(tile.position,currentMovement)
} }
fun getSpecialAbilities(): MutableList<String> {
val abilities = mutableListOf<String>()
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<TileInfo> {
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() { fun doPreTurnAction() {
val currentTile = getTile() val currentTile = getTile()
if (currentMovement == 0f) return // We've already done stuff this turn, and can't do any more stuff 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 tile.improvementInProgress = null
} }
/**
* @return The tile that we reached this turn
*/
private fun heal(){ private fun heal(){
val tile = getTile() val tile = getTile()
health += when{ health += when{
@ -107,6 +190,9 @@ class MapUnit {
if(health>100) health=100 if(health>100) health=100
} }
/**
* @return The tile that we reached this turn
*/
fun moveToTile(otherTile: TileInfo) { fun moveToTile(otherTile: TileInfo) {
if(otherTile==getTile()) return // already here! if(otherTile==getTile()) return // already here!
val distanceToTiles = getDistanceToTiles() val distanceToTiles = getDistanceToTiles()
@ -139,40 +225,9 @@ class MapUnit {
doPreTurnAction() doPreTurnAction()
} }
fun getSpecialAbilities(): MutableList<String> { fun destroy(){
val abilities = mutableListOf<String>() removeFromTile()
val baseUnit = baseUnit() civInfo.units.remove(this)
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<TileInfo> {
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 removeFromTile(){ fun removeFromTile(){
@ -188,54 +243,10 @@ class MapUnit {
currentTile = tile currentTile = tile
} }
/** fun assignOwner(civInfo:CivilizationInfo){
* Designates whether we can walk to the tile - without attacking owner=civInfo.civName
*/ this.civInfo=civInfo
fun canMoveTo(tile: TileInfo): Boolean { civInfo.units.add(this)
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
} }
//endregion
} }

View File

@ -41,11 +41,9 @@ class TileMap {
} }
fun placeUnitNearTile(position: Vector2, unitName: String, civInfo: CivilizationInfo): MapUnit { fun placeUnitNearTile(position: Vector2, unitName: String, civInfo: CivilizationInfo): MapUnit {
val unit = GameBasics.Units[unitName]!!.getMapUnit() val unit = GameBasics.Units[unitName]!!.getMapUnit()
unit.owner = civInfo.civName unit.assignOwner(civInfo)
unit.civInfo = civInfo
val tilesInDistance = getTilesInDistance(position, 2) val tilesInDistance = getTilesInDistance(position, 2)
val unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) } val unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) }
if(unitToPlaceTile!=null) unit.putInTile(unitToPlaceTile) if(unitToPlaceTile!=null) unit.putInTile(unitToPlaceTile)

View File

@ -22,7 +22,7 @@ class UnitActions {
private fun constructImprovementAndDestroyUnit(unit:MapUnit, improvementName: String): () -> Unit { private fun constructImprovementAndDestroyUnit(unit:MapUnit, improvementName: String): () -> Unit {
return { return {
unit.getTile().improvement = improvementName unit.getTile().improvement = improvementName
unit.removeFromTile() unit.destroy()
} }
} }
@ -71,7 +71,7 @@ class UnitActions {
{ {
unit.civInfo.gold -= goldCostOfUpgrade unit.civInfo.gold -= goldCostOfUpgrade
val unitTile = unit.getTile() val unitTile = unit.getTile()
unit.removeFromTile() unit.destroy()
val newunit = unit.civInfo.placeUnitNearTile(unitTile.position, upgradedUnit.name) val newunit = unit.civInfo.placeUnitNearTile(unitTile.position, upgradedUnit.name)
newunit.health = unit.health newunit.health = unit.health
newunit.promotions = unit.promotions newunit.promotions = unit.promotions
@ -95,7 +95,7 @@ class UnitActions {
unit.civInfo.addCity(tile.position) unit.civInfo.addCity(tile.position)
tile.improvement=null 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 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 && unit.currentMovement != 0f &&
!tile.getTilesInDistance(2).any { it.isCityCenter() }) !tile.getTilesInDistance(2).any { it.isCityCenter() })
@ -126,7 +126,7 @@ class UnitActions {
actionList += UnitAction( "Discover Technology", actionList += UnitAction( "Discover Technology",
{ {
unit.civInfo.tech.freeTechs += 1 unit.civInfo.tech.freeTechs += 1
unit.removeFromTile() unit.destroy()
worldScreen.game.screen = TechPickerScreen(true, unit.civInfo) worldScreen.game.screen = TechPickerScreen(true, unit.civInfo)
},unit.currentMovement != 0f) },unit.currentMovement != 0f)
@ -139,7 +139,7 @@ class UnitActions {
actionList += UnitAction( "Start Golden Age", actionList += UnitAction( "Start Golden Age",
{ {
unit.civInfo.goldenAges.enterGoldenAge() unit.civInfo.goldenAges.enterGoldenAge()
unit.removeFromTile() unit.destroy()
},unit.currentMovement != 0f },unit.currentMovement != 0f
) )
actionList += UnitAction("Construct Landmark", actionList += UnitAction("Construct Landmark",
@ -151,7 +151,7 @@ class UnitActions {
actionList += UnitAction( "Hurry Wonder", actionList += UnitAction( "Hurry Wonder",
{ {
tile.getCity()!!.cityConstructions.addConstruction(300 + 30 * tile.getCity()!!.population.population) //http://civilization.wikia.com/wiki/Great_engineer_(Civ5) 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 && unit.currentMovement != 0f &&
tile.isCityCenter() && tile.isCityCenter() &&
@ -167,7 +167,7 @@ class UnitActions {
actionList += UnitAction("Conduct Trade Mission", actionList += UnitAction("Conduct Trade Mission",
{ {
unit.civInfo.gold += 350 // + 50 * era_number - todo! unit.civInfo.gold += 350 // + 50 * era_number - todo!
unit.removeFromTile() unit.destroy()
},unit.currentMovement != 0f) },unit.currentMovement != 0f)
actionList += UnitAction( "Construct Customs House", actionList += UnitAction( "Construct Customs House",
constructImprovementAndDestroyUnit(unit, "Customs house"), constructImprovementAndDestroyUnit(unit, "Customs house"),
@ -177,7 +177,7 @@ class UnitActions {
actionList += UnitAction("Disband unit", actionList += UnitAction("Disband unit",
{ {
YesNoPopupTable("Do you really want to disband this unit?".tr(), YesNoPopupTable("Do you really want to disband this unit?".tr(),
{unit.removeFromTile(); worldScreen.update()} ) {unit.destroy(); worldScreen.update()} )
},unit.currentMovement != 0f) },unit.currentMovement != 0f)
return actionList return actionList