From f6ca98b1d721406f147828344319e8d843425b51 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Thu, 31 May 2018 17:23:46 +0300 Subject: [PATCH] Massive change - Unit in TileInfo now spit to CivilianUnit and MilitaryUnit! --- core/src/com/unciv/GameStarter.kt | 1 + core/src/com/unciv/logic/GameInfo.kt | 10 ++-- .../com/unciv/logic/automation/Automation.kt | 2 +- .../unciv/logic/automation/UnitAutomation.kt | 40 ++++---------- .../logic/automation/WorkerAutomation.kt | 4 +- core/src/com/unciv/logic/battle/Battle.kt | 23 ++++++-- .../unciv/logic/battle/MapUnitCombatant.kt | 2 +- .../logic/civilization/CivilizationInfo.kt | 7 ++- core/src/com/unciv/logic/map/MapUnit.kt | 49 ++++++++++++----- core/src/com/unciv/logic/map/TileInfo.kt | 25 ++++----- core/src/com/unciv/logic/map/TileMap.kt | 12 +++-- .../unciv/logic/map/UnitMovementAlgorithms.kt | 8 +-- .../com/unciv/ui/cityscreen/CityTileGroup.kt | 7 --- core/src/com/unciv/ui/tilegroups/TileGroup.kt | 52 +++++++++---------- .../com/unciv/ui/tilegroups/WorldTileGroup.kt | 31 +++++------ .../com/unciv/ui/worldscreen/BattleTable.kt | 15 ++---- .../com/unciv/ui/worldscreen/TileMapHolder.kt | 20 ++++--- .../ui/worldscreen/unit/IdleUnitButton.kt | 2 +- .../unciv/ui/worldscreen/unit/UnitActions.kt | 31 ++++++----- .../unciv/ui/worldscreen/unit/UnitTable.kt | 10 ++-- 20 files changed, 187 insertions(+), 164 deletions(-) diff --git a/core/src/com/unciv/GameStarter.kt b/core/src/com/unciv/GameStarter.kt index 6a33065b76..713ef73ded 100644 --- a/core/src/com/unciv/GameStarter.kt +++ b/core/src/com/unciv/GameStarter.kt @@ -12,6 +12,7 @@ class GameStarter(){ val gameInfo = GameInfo() gameInfo.tileMap = TileMap(mapRadius) + gameInfo.tileMap.gameInfo = gameInfo // need to set this transient before placing units in the map gameInfo.civilizations.add(CivilizationInfo(civilization, Vector2.Zero, gameInfo)) // first one is player civ val freeTiles = gameInfo.tileMap.values.toMutableList() diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 9f4c17da2e..962059b02c 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -57,7 +57,7 @@ class GameInfo { var tile = tileToPlace if(tileToPlace==null) { val playerViewableTiles = getPlayerCivilization().getViewableTiles().toHashSet() - val viableTiles = tileMap.values.filterNot { playerViewableTiles.contains(it) || it.unit != null } + val viableTiles = tileMap.values.filterNot { playerViewableTiles.contains(it) || it.militaryUnit != null || it.civilianUnit!=null} tile=viableTiles.getRandom() } tileMap.placeUnitNearTile(tile!!.position,"Warrior",getBarbarianCivilization()) @@ -72,8 +72,12 @@ class GameInfo { civInfo.setTransients() } - for (tile in tileMap.values.filter { it.unit!=null }) - tile.unit!!.civInfo = civilizations.first { it.civName == tile.unit!!.owner } + val civNameToCiv = civilizations.associateBy ({ it.civName},{it}) + + for (tile in tileMap.values) { + if (tile.militaryUnit != null) tile.militaryUnit!!.civInfo = civNameToCiv[tile.militaryUnit!!.owner]!! + if (tile.civilianUnit!= null) tile.civilianUnit!!.civInfo = civNameToCiv[tile.civilianUnit!!.owner]!! + } for (civInfo in civilizations) diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index d2f963524b..ff5ca60bc6 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -68,7 +68,7 @@ class Automation { private fun trainCombatUnit(city: CityInfo) { val combatUnits = city.cityConstructions.getConstructableUnits().filter { it.unitType != UnitType.Civilian } val chosenUnit:Unit - if(city.civInfo.cities.any { it.getCenterTile().unit==null} + if(city.civInfo.cities.any { it.getCenterTile().militaryUnit==null} && combatUnits.any { it.unitType==UnitType.Archery }) // this is for city defence so get an archery unit if we can chosenUnit = combatUnits.filter { it.unitType==UnitType.Archery }.maxBy { it.cost }!! diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 48bea3ee8a..bc830553c8 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -1,15 +1,11 @@ package com.unciv.logic.automation -import com.badlogic.gdx.graphics.Color import com.unciv.UnCivGame import com.unciv.logic.battle.Battle -import com.unciv.logic.battle.CityCombatant -import com.unciv.logic.battle.ICombatant import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo -import com.unciv.logic.map.UnitType import com.unciv.ui.utils.getRandom import com.unciv.ui.worldscreen.unit.UnitActions @@ -22,14 +18,14 @@ class UnitAutomation{ val unitTile = unit.getTile() // Go to friendly tile if within distance - better healing! - val friendlyTile = tilesInDistance.firstOrNull { it.getOwner()?.civName == unit.owner && it.unit == null } + val friendlyTile = tilesInDistance.firstOrNull { it.getOwner()?.civName == unit.owner && unit.canMoveTo(it) } if (unitTile.getOwner()?.civName != unit.owner && friendlyTile != null) { unit.moveToTile(friendlyTile) return } // Or at least get out of enemy territory yaknow - val neutralTile = tilesInDistance.firstOrNull { it.getOwner() == null && it.unit == null } + val neutralTile = tilesInDistance.firstOrNull { it.getOwner() == null && unit.canMoveTo(it)} if (unitTile.getOwner()?.civName != unit.owner && unitTile.getOwner() != null && neutralTile != null) { unit.moveToTile(neutralTile) return @@ -37,8 +33,9 @@ class UnitAutomation{ } fun containsAttackableEnemy(tile: TileInfo, civInfo: CivilizationInfo): Boolean { - return (tile.unit != null && tile.unit!!.owner != civInfo.civName) - || (tile.isCityCenter() && tile.getCity()!!.civInfo!=civInfo) + val tileCombatant = Battle().getMapCombatantOfTile(tile) + if(tileCombatant==null) return false + return tileCombatant.getCivilization()!=civInfo } fun getAttackableEnemies(unit: MapUnit): List { @@ -53,7 +50,7 @@ class UnitAutomation{ return attackableTiles.filter { it.neighbors.any { unit.getTile()==it || // We're already right nearby - it.unit == null + unit.canMoveTo(it) && distanceToTiles.containsKey(it) && distanceToTiles[it]!! < unit.currentMovement // We can get there } @@ -89,23 +86,7 @@ class UnitAutomation{ val enemyTileToAttack = getAttackableEnemies(unit).firstOrNull() if (enemyTileToAttack != null) { - - val enemy:ICombatant - if(enemyTileToAttack.isCityCenter()){ - enemy = CityCombatant(enemyTileToAttack.getCity()!!) - } - - else { - val unitToAttack = enemyTileToAttack.unit!! - if (unitToAttack.getBaseUnit().unitType == UnitType.Civilian) { // kill - unitToAttack.civInfo.addNotification("Our " + unitToAttack.name + " was destroyed by an enemy " + unit.name + "!", enemyTileToAttack.position, Color.RED) - enemyTileToAttack.unit = null - unit.movementAlgs().headTowards(enemyTileToAttack) - return - } - enemy=MapUnitCombatant(unitToAttack) - } - + val enemy = Battle().getMapCombatantOfTile(enemyTileToAttack)!! val damageToAttacker = Battle(unit.civInfo.gameInfo).calculateDamageToAttacker(MapUnitCombatant(unit), enemy) if (damageToAttacker < unit.health) { // don't attack if we'll die from the attack @@ -118,7 +99,8 @@ class UnitAutomation{ if(unit.getTile().isCityCenter()) return // It's always good to have a unit in the city center, so if you havn't found annyonw aroud to attack, forget it. - val reachableCitiesWithoutUnits = unit.civInfo.cities.filter { it.getCenterTile().unit==null + val reachableCitiesWithoutUnits = unit.civInfo.cities.filter { + unit.canMoveTo(it.getCenterTile()) && unit.movementAlgs().canReach(it.getCenterTile()) } if(reachableCitiesWithoutUnits.isNotEmpty()){ val closestCityWithoutUnit = reachableCitiesWithoutUnits @@ -153,7 +135,7 @@ class UnitAutomation{ // else, go to a random space val reachableTiles = unit.getDistanceToTiles() - .filter { it.key.unit == null} // at edge of walking distance + .filter { unit.canMoveTo(it.key)} val reachableTilesMaxWalkingDistance = reachableTiles.filter { it.value==unit.currentMovement} if(reachableTilesMaxWalkingDistance.any()) unit.moveToTile(reachableTilesMaxWalkingDistance.toList().getRandom().first) else if(reachableTiles.any()) unit.moveToTile(reachableTiles.toList().getRandom().first) @@ -184,7 +166,7 @@ class UnitAutomation{ if(possibleTiles.isEmpty()) // We got a badass over here, all tiles within 5 are taken? Screw it, random walk. { unit.moveToTile(unit.getDistanceToTiles() - .filter { it.key.unit == null && it.value==unit.currentMovement } // at edge of walking distance + .filter { unit.canMoveTo(it.key) && it.value==unit.currentMovement } // at edge of walking distance .toList().getRandom().first) return } diff --git a/core/src/com/unciv/logic/automation/WorkerAutomation.kt b/core/src/com/unciv/logic/automation/WorkerAutomation.kt index c26cd1c4e3..7d8bc542f2 100644 --- a/core/src/com/unciv/logic/automation/WorkerAutomation.kt +++ b/core/src/com/unciv/logic/automation/WorkerAutomation.kt @@ -10,7 +10,7 @@ class WorkerAutomation { fun automateWorkerAction(unit: MapUnit) { val enemyUnitsInWalkingDistance = unit.getDistanceToTiles().keys - .filter { it.unit!=null && it.unit!!.civInfo!=unit.civInfo } + .filter { it.militaryUnit!=null && it.militaryUnit!!.civInfo!=unit.civInfo } if(enemyUnitsInWalkingDistance.isNotEmpty()) return // Don't you dare move. @@ -33,7 +33,7 @@ class WorkerAutomation { val currentTile=worker.getTile() val workableTiles = currentTile.getTilesInDistance(4) .filter { - (it.unit == null || it == currentTile) + (it.civilianUnit== null || it == currentTile) && it.improvement == null && it.canBuildImprovement(chooseImprovement(it), worker.civInfo) && {val city=it.getCity(); city==null || it.getCity()?.civInfo == worker.civInfo}() // don't work tiles belonging to another civ diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index a39cbf25a6..c39eb1df49 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -1,6 +1,7 @@ package com.unciv.logic.battle import com.badlogic.gdx.graphics.Color +import com.unciv.UnCivGame import com.unciv.logic.GameInfo import com.unciv.logic.city.CityInfo import com.unciv.logic.map.TileInfo @@ -12,7 +13,7 @@ import kotlin.math.max /** * Damage calculations according to civ v wiki and https://steamcommunity.com/sharedfiles/filedetails/?id=170194443 */ -class Battle(val gameInfo:GameInfo) { +class Battle(val gameInfo:GameInfo=UnCivGame.Current.gameInfo) { private fun getGeneralModifiers(combatant: ICombatant, enemy: ICombatant): HashMap { val modifiers = HashMap() @@ -47,9 +48,9 @@ class Battle(val gameInfo:GameInfo) { val modifiers = getGeneralModifiers(attacker, defender) if (attacker.isMelee()) { val numberOfAttackersSurroundingDefender = defender.getTile().neighbors.count { - it.unit != null - && it.unit!!.owner == attacker.getCivilization().civName - && MapUnitCombatant(it.unit!!).isMelee() + it.militaryUnit != null + && it.militaryUnit!!.owner == attacker.getCivilization().civName + && MapUnitCombatant(it.militaryUnit!!).isMelee() } if (numberOfAttackersSurroundingDefender > 1) modifiers["Flanking"] = 0.1f * (numberOfAttackersSurroundingDefender-1) //https://www.carlsguides.com/strategy/civilization5/war/combatbonuses.php @@ -101,6 +102,7 @@ class Battle(val gameInfo:GameInfo) { fun calculateDamageToAttacker(attacker: ICombatant, defender: ICombatant): Int { if(attacker.isRanged()) return 0 + if(defender.getUnitType()==UnitType.Civilian) return 0 val ratio = getDefendingStrength(attacker,defender) / getAttackingStrength(attacker,defender) return (ratio * 30 * getHealthDependantDamageRatio(defender)).toInt() } @@ -180,7 +182,11 @@ class Battle(val gameInfo:GameInfo) { attacker.getCivilization().cities.add(city) city.civInfo = attacker.getCivilization() city.health = city.getMaxHealth() / 2 // I think that cities recover to half health? - city.getCenterTile().unit = null + city.getCenterTile().apply { + militaryUnit = null + civilianUnit=null + } + city.expansion.cultureStored = 0 city.expansion.reset() @@ -201,4 +207,11 @@ class Battle(val gameInfo:GameInfo) { (attacker as MapUnitCombatant).unit.moveToTile(city.getCenterTile()) city.civInfo.gameInfo.updateTilesToCities() } + + fun getMapCombatantOfTile(tile:TileInfo): ICombatant? { + if(tile.isCityCenter()) return CityCombatant(tile.getCity()!!) + if(tile.militaryUnit!=null) return MapUnitCombatant(tile.militaryUnit!!) + if(tile.civilianUnit!=null) return MapUnitCombatant(tile.civilianUnit!!) + return null + } } \ 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 1b0140180f..76da92dede 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.getTile().unit=null + if(isDefeated()) unit.removeFromTile() } override fun getAttackingStrength(defender: ICombatant): Int { diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index f43d9f0004..7b10cc1efe 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -174,16 +174,15 @@ class CivilizationInfo { } fun getCivUnits(): List { - return gameInfo.tileMap.values.filter { it.unit!=null && it.unit!!.owner==civName }.map { it.unit!! } + return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.civInfo==this } } fun getViewableTiles(): List { var viewablePositions = emptyList() viewablePositions += cities.flatMap { it.getTiles() } .flatMap { it.neighbors } // tiles adjacent to city tiles - viewablePositions += gameInfo.tileMap.values - .filter { it.unit != null && it.unit!!.owner == civName } - .flatMap { it.getViewableTiles(it.unit!!.getVisibilityRange())} // Tiles within 2 tiles of units + viewablePositions += getCivUnits() + .flatMap { it.getViewableTiles()} // Tiles within 2 tiles of units viewablePositions.map { it.position }.filterNot { exploredTiles.contains(it) }.toCollection(exploredTiles) return viewablePositions } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index ca00eeb693..f3d9739791 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -21,7 +21,7 @@ class MapUnit { fun getBaseUnit(): Unit = GameBasics.Units[name]!! fun getMovementString(): String = DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + maxMovement fun getTile(): TileInfo { - return civInfo.gameInfo.tileMap.values.first{it.unit==this} + return civInfo.gameInfo.tileMap.values.first{it.militaryUnit==this || it.civilianUnit==this} } fun getDistanceToTiles(): HashMap { @@ -34,7 +34,7 @@ class MapUnit { if (currentMovement == 0f) return // We've already done stuff this turn, and can't do any more stuff val enemyUnitsInWalkingDistance = getDistanceToTiles().keys - .filter { it.unit!=null && it.unit!!.civInfo!=civInfo } + .filter { it.militaryUnit!=null && it.militaryUnit!!.civInfo!=civInfo } if(enemyUnitsInWalkingDistance.isNotEmpty()) return // Don't you dare move. if (action != null && action!!.startsWith("moveTo")) { @@ -88,23 +88,17 @@ class MapUnit { if(health>100) health=100 } - fun canMove(tile: TileInfo): Boolean { - if(tile.unit!=null) return false - if(tile.isCityCenter() && tile.getOwner()!=civInfo) return false - return true - } - fun moveToTile(otherTile: TileInfo) { val distanceToTiles = getDistanceToTiles() if (!distanceToTiles.containsKey(otherTile)) throw Exception("You can't get there from here!") - if (otherTile.unit != null ) throw Exception("Tile already contains a unit!") + if(!canMoveTo(otherTile)) throw Exception("Can't enter this tile!") if(otherTile.isCityCenter() && otherTile.getOwner()!=civInfo) throw Exception("This is an enemy city, you can't go here!") currentMovement -= distanceToTiles[otherTile]!! if (currentMovement < 0.1) currentMovement = 0f // silly floats which are "almost zero" - getTile().unit = null - otherTile.unit = this + removeFromTile() + putInTile(otherTile) } fun endTurn() { @@ -130,10 +124,10 @@ class MapUnit { return "$name - $owner" } - fun getVisibilityRange(): Int { + fun getViewableTiles(): MutableList { var visibilityRange = 2 if(hasUnique("Limited Visibility")) visibilityRange-=1 - return visibilityRange + return getTile().getViewableTiles(visibilityRange) } fun isFortified(): Boolean { @@ -144,4 +138,33 @@ class MapUnit { if(!isFortified()) return 0 return action!!.split(" ")[1].toInt() } + + fun removeFromTile(){ + if (getBaseUnit().unitType==UnitType.Civilian) getTile().civilianUnit=null + else getTile().militaryUnit=null + } + + fun putInTile(tile:TileInfo){ + if(!canMoveTo(tile)) throw Exception("I can't go there!") + if(getBaseUnit().unitType==UnitType.Civilian) + tile.civilianUnit=this + else tile.militaryUnit=this + } + + /** + * Designates whether we can walk to the tile - without attacking + */ + fun canMoveTo(tile: TileInfo): Boolean { + if(tile.isCityCenter() && tile.getOwner()!!.civName!=owner) return false + if (getBaseUnit().unitType==UnitType.Civilian) + return tile.civilianUnit==null && (tile.militaryUnit==null || tile.militaryUnit!!.owner==owner) + else return tile.militaryUnit==null + } + + fun isIdle(): Boolean { + if (currentMovement == 0f) return false + if (name == "Worker" && getTile().improvementInProgress != null) return false + if (isFortified()) return false + return true + } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index 4396c66c4c..7a5f021428 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -10,10 +10,14 @@ import com.unciv.models.gamebasics.TileImprovement import com.unciv.models.gamebasics.TileResource import com.unciv.models.stats.Stats -class TileInfo { +open class TileInfo { @Transient lateinit var tileMap: TileMap - var unit: MapUnit? = null + var unit:MapUnit?=null + var militaryUnit:MapUnit?=null + var civilianUnit:MapUnit?=null + fun getUnits()= listOf(militaryUnit,civilianUnit).filterNotNull() + var position: Vector2 = Vector2.Zero var baseTerrain: String? = null var terrainFeature: String? = null @@ -153,10 +157,12 @@ class TileInfo { if (roadStatus !== RoadStatus.None && !isCityCenter()) SB.appendln(roadStatus) if (improvement != null) SB.appendln(improvement!!) if (improvementInProgress != null) SB.appendln("$improvementInProgress in ${this.turnsToImprovement} turns") - if (unit != null && UnCivGame.Current.gameInfo.getPlayerCivilization().getViewableTiles().contains(this)){ - var unitString = unit!!.name - if(unit!!.getBaseUnit().unitType!=UnitType.Civilian && unit!!.health<100) unitString += "(" + unit!!.health + ")" - SB.appendln(unitString) + val isViewableToPlayer = UnCivGame.Current.gameInfo.getPlayerCivilization().getViewableTiles().contains(this) + if (civilianUnit != null && isViewableToPlayer) SB.appendln(civilianUnit!!.name) + if(militaryUnit!=null && isViewableToPlayer){ + var milUnitString = militaryUnit!!.name + if(militaryUnit!!.health<100) milUnitString += "(" + militaryUnit!!.health + ")" + SB.appendln(milUnitString) } return SB.toString().trim() } @@ -166,11 +172,7 @@ class TileInfo { } fun hasIdleUnit(): Boolean { - if (unit == null) return false - if (unit!!.currentMovement == 0f) return false - if (unit!!.name == "Worker" && improvementInProgress != null) return false - if (unit!!.isFortified()) return false - return true + return getUnits().any{it.isIdle()} } fun getViewableTiles(distance:Int): MutableList { @@ -191,5 +193,4 @@ class TileInfo { val city = getCity() return city!=null && city.workedTiles.contains(position) } - } \ 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 68ffc5b2fe..6450ae63a3 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -47,8 +47,8 @@ class TileMap { unit.owner = civInfo.civName unit.civInfo = civInfo val tilesInDistance = getTilesInDistance(position, 2) - val unitToPlaceTile = tilesInDistance.firstOrNull { it.unit == null } - if(unitToPlaceTile!=null) unitToPlaceTile.unit = unit // And if there's none, then kill me. + val unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) } + if(unitToPlaceTile!=null) unit.putInTile(unitToPlaceTile) return unit } @@ -65,7 +65,13 @@ class TileMap { } fun setTransients() { - for (tileInfo in values) tileInfo.tileMap = this + for (tileInfo in values){ + tileInfo.tileMap = this + if(tileInfo.unit!=null){ + tileInfo.unit!!.putInTile(tileInfo) + tileInfo.unit=null + } + } } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 0a69c8164e..7b5c098dd0 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -37,7 +37,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { var totalDistanceToTile:Float if ((neighbor.getOwner() != unit.civInfo && neighbor.isCityCenter())// Enemy city, - || neighbor.unit!=null && neighbor.unit!!.civInfo!=unit.civInfo) // Enemy unit + || neighbor.getUnits().isNotEmpty() && neighbor.getUnits().first().civInfo!=unit.civInfo) // Enemy unit totalDistanceToTile = unitMovement // can't move through it - we'll be "stuck" there else { @@ -80,7 +80,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { distanceToDestination[tileToCheck] = distanceToTilesThisTurn[reachableTile]!! else { if (movementTreeParents.containsKey(reachableTile)) continue // We cannot be faster than anything existing... - if (!unit.canMove(reachableTile)) continue // This is a tile that we can''t actually enter - either an intermediary tile containing our unit, or an enemy unit/city + if (!unit.canMoveTo(reachableTile)) continue // This is a tile that we can''t actually enter - either an intermediary tile containing our unit, or an enemy unit/city movementTreeParents[reachableTile] = tileToCheck newTilesToCheck.add(reachableTile) } @@ -121,7 +121,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { val destinationTileThisTurn: TileInfo if (distanceToTiles.containsKey(destination)) { // we can get there this turn - if (unit.canMove(destination)) + if (unit.canMoveTo(destination)) destinationTileThisTurn = destination else // Someone is blocking to the path to the final tile... { @@ -130,7 +130,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { return currentTile val reachableDestinationNeighbors = destinationNeighbors - .filter { distanceToTiles.containsKey(it) && unit.canMove(it)} + .filter { distanceToTiles.containsKey(it) && unit.canMoveTo(it)} if (reachableDestinationNeighbors.isEmpty()) // We can't get closer... return currentTile diff --git a/core/src/com/unciv/ui/cityscreen/CityTileGroup.kt b/core/src/com/unciv/ui/cityscreen/CityTileGroup.kt index aa0c53026a..61dae6db9b 100644 --- a/core/src/com/unciv/ui/cityscreen/CityTileGroup.kt +++ b/core/src/com/unciv/ui/cityscreen/CityTileGroup.kt @@ -6,7 +6,6 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.map.TileInfo import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.utils.ImageGetter -import com.unciv.ui.utils.center import com.unciv.ui.utils.centerX class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo) : TileGroup(tileInfo) { @@ -25,12 +24,6 @@ class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo) : TileGroup( fun update() { super.update(true) - updateUnitImage(true) - if(unitImage!=null) { - unitImage!!.center(this) - unitImage!!.y += 20 // top - } - updatePopulationImage() if (improvementImage != null) improvementImage!!.setColor(1f, 1f, 1f, 0.5f) if (resourceImage != null) resourceImage!!.setColor(1f, 1f, 1f, 0.5f) diff --git a/core/src/com/unciv/ui/tilegroups/TileGroup.kt b/core/src/com/unciv/ui/tilegroups/TileGroup.kt index f363dfbb4f..83fd6d05c3 100644 --- a/core/src/com/unciv/ui/tilegroups/TileGroup.kt +++ b/core/src/com/unciv/ui/tilegroups/TileGroup.kt @@ -29,7 +29,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() { var populationImage: Image? = null private val roadImages = HashMap() private val borderImages = ArrayList() - protected var unitImage: Group? = null + protected var civilianUnitImage: Group? = null + protected var militaryUnitImage: Group? = null private val circleImage = ImageGetter.getImage("OtherIcons/Circle.png") // for blue and red circles on the tile private val fogImage = ImageGetter.getImage("TerrainIcons/Fog.png") @@ -71,8 +72,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() { populationImage!!.run { setSize(20f, 20f) center(this@TileGroup) - y -= 20 - } // top left + x += 20 // right + } addActor(populationImage) } @@ -96,6 +97,9 @@ open class TileGroup(var tileInfo: TileInfo) : Group() { updateResourceImage(isViewable) updateImprovementImage(isViewable) + civilianUnitImage = newUnitImage(tileInfo.civilianUnit,civilianUnitImage,isViewable,-20f) + militaryUnitImage = newUnitImage(tileInfo.militaryUnit,militaryUnitImage,isViewable,20f) + updateRoadImages() updateBorderImages() @@ -202,7 +206,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() { improvementImage!!.run { setSize(20f, 20f) center(this@TileGroup) - this.x+=20 // right + this.x -= 22 // left + this.y -= 10 // bottom } improvementType = tileInfo.improvement } @@ -218,7 +223,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() { resourceImage = ImageGetter.getImage(fileName) resourceImage!!.setSize(20f, 20f) resourceImage!!.center(this) - resourceImage!!.x -= 20 // left + resourceImage!!.x -= 22 // left + resourceImage!!.y += 10 // top addActor(resourceImage!!) } if(resourceImage!=null){ @@ -228,41 +234,35 @@ open class TileGroup(var tileInfo: TileInfo) : Group() { } - protected fun updateUnitImage(isViewable: Boolean) { - if (unitImage != null) { // The unit can change within one update - for instance, when attacking, the attacker replaces the defender! - unitImage!!.remove() - unitImage = null + protected fun newUnitImage(unit:MapUnit?, currentImage:Group?, isViewable: Boolean, yFromCenter:Float): Group? { + var newImage:Group? = null + if (currentImage!= null) { // The unit can change within one update - for instance, when attacking, the attacker replaces the defender! + currentImage.remove() } - if (tileInfo.unit != null && (isViewable || viewEntireMapForDebug)) { // Tile is visible - val unit = tileInfo.unit!! - unitImage = getUnitImage(unit, unit.civInfo.getCivilization().getColor()) - addActor(unitImage!!) - unitImage!!.setSize(20f, 20f) - } - - - if (unitImage != null) { - if (!tileInfo.hasIdleUnit()) - unitImage!!.color = Color(1f, 1f, 1f, 0.5f) - else - unitImage!!.color = Color.WHITE + if (unit != null && (isViewable || viewEntireMapForDebug)) { // Tile is visible + newImage = getUnitImage(unit, unit.civInfo.getCivilization().getColor(), 25f) + addActor(newImage) + newImage.center(this) + newImage.y+=yFromCenter + if(!unit.isIdle()) newImage.color = Color(1f, 1f, 1f, 0.5f) } + return newImage } - private fun getUnitImage(unit: MapUnit, color:Color): Group { + private fun getUnitImage(unit: MapUnit, color: Color, size: Float): Group { val unitBaseImage = ImageGetter.getUnitIcon(unit.name) - .apply { setSize(15f,15f) } + .apply { setSize(20f,20f) } val background = if(unit.isFortified()) ImageGetter.getImage("OtherIcons/Shield.png") else ImageGetter.getImage("OtherIcons/Circle.png") background.apply { this.color = color - setSize(20f,20f) + setSize(size,size) } val group = Group().apply { - setSize(background.width,background.height) + setSize(size,size) addActor(background) } unitBaseImage.center(group) diff --git a/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt b/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt index a0ba0b99f1..d2e6282368 100644 --- a/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt +++ b/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt @@ -7,7 +7,9 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.UnCivGame import com.unciv.logic.city.CityInfo +import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo +import com.unciv.logic.map.UnitType import com.unciv.ui.cityscreen.CityScreen import com.unciv.ui.cityscreen.addClickListener import com.unciv.ui.utils.CameraStageBaseScreen @@ -19,33 +21,28 @@ import com.unciv.ui.utils.setFontColor class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) { var cityButton: Table? = null - fun addWhiteHaloAroundUnit(){ - val whiteHalo = if(tileInfo.unit!!.isFortified()) ImageGetter.getImage("OtherIcons/Shield.png") + fun addWhiteHaloAroundUnit(unit: MapUnit) { + val whiteHalo = if(unit.isFortified()) ImageGetter.getImage("OtherIcons/Shield.png") else ImageGetter.getImage("OtherIcons/Circle.png") - whiteHalo.setSize(25f,25f) - whiteHalo.center(unitImage!!) - unitImage!!.addActor(whiteHalo) + whiteHalo.setSize(30f,30f) + val unitImage = if(unit.getBaseUnit().unitType==UnitType.Civilian) civilianUnitImage!! + else militaryUnitImage!! + whiteHalo.center(unitImage) + unitImage.addActor(whiteHalo) whiteHalo.toBack() } override fun update(isViewable: Boolean) { - super.update(isViewable) - if (!tileInfo.tileMap.gameInfo.getPlayerCivilization().exploredTiles.contains(tileInfo.position) - && !viewEntireMapForDebug) return - - if (populationImage != null) removePopulationIcon() val city = tileInfo.getCity() - if (tileInfo.isWorked() && city!!.civInfo.isPlayerCivilization() && populationImage == null) + if (isViewable && tileInfo.isWorked() && city!!.civInfo.isPlayerCivilization() && populationImage == null) addPopulationIcon() - updateCityButton(city) - updateUnitImage(isViewable) - if(unitImage!=null) { - unitImage!!.center(this) - unitImage!!.y += 20 // top - } + if (tileInfo.tileMap.gameInfo.getPlayerCivilization().exploredTiles.contains(tileInfo.position) + || viewEntireMapForDebug) updateCityButton(city) // needs to be before the update so the units will be above the city button + + super.update(isViewable) } private fun updateCityButton(city: CityInfo?) { diff --git a/core/src/com/unciv/ui/worldscreen/BattleTable.kt b/core/src/com/unciv/ui/worldscreen/BattleTable.kt index fea5e109ce..2c1ab44654 100644 --- a/core/src/com/unciv/ui/worldscreen/BattleTable.kt +++ b/core/src/com/unciv/ui/worldscreen/BattleTable.kt @@ -5,7 +5,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.logic.automation.UnitAutomation import com.unciv.logic.battle.Battle -import com.unciv.logic.battle.CityCombatant import com.unciv.logic.battle.ICombatant import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.map.UnitType @@ -42,15 +41,11 @@ class BattleTable(val worldScreen: WorldScreen): Table() { if (worldScreen.tileMapHolder.selectedTile == null) return val selectedTile = worldScreen.tileMapHolder.selectedTile!! - val defender: ICombatant - if (attacker.getCivilization().exploredTiles.contains(selectedTile.position) - && selectedTile.isCityCenter() && selectedTile.getOwner() != worldScreen.civInfo) - defender = CityCombatant(selectedTile.getCity()!!) - else if (selectedTile.unit != null - && selectedTile.unit!!.owner != worldScreen.civInfo.civName // enemy unit on selected tile, - && worldScreen.civInfo.getViewableTiles().contains(selectedTile)) - defender = MapUnitCombatant(selectedTile.unit!!) - else { + + val defender: ICombatant? = Battle().getMapCombatantOfTile(selectedTile) + + if(defender==null || defender.getCivilization()==worldScreen.civInfo + || !attacker.getCivilization().exploredTiles.contains(selectedTile.position)) { hide() return } diff --git a/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt b/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt index 4284452068..71bbb7b5e8 100644 --- a/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt +++ b/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt @@ -93,20 +93,26 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap: if(worldScreen.bottomBar.unitTable.selectedUnit!=null){ val unit = worldScreen.bottomBar.unitTable.selectedUnit!! - tileGroups[unit.getTile()]!!.addWhiteHaloAroundUnit() - + tileGroups[unit.getTile()]!!.addWhiteHaloAroundUnit(unit) + + for(tile: TileInfo in unit.getDistanceToTiles().keys) + tileGroups[tile]!!.showCircle(colorFromRGB(0, 120, 215)) + val attackableTiles: List = when(unit.getBaseUnit().unitType){ - UnitType.Civilian -> listOf() + UnitType.Civilian -> unit.getDistanceToTiles().keys.toList() UnitType.Melee, UnitType.Mounted -> unit.getDistanceToTiles().keys.toList() UnitType.Archery, UnitType.Siege -> unit.getTile().getTilesInDistance(2) UnitType.City -> throw Exception("A unit shouldn't have a City unittype!") } - for(tile: TileInfo in unit.getDistanceToTiles().keys) - tileGroups[tile]!!.showCircle(colorFromRGB(0, 120, 215)) - for (tile in attackableTiles.filter { it.unit!=null && it.unit!!.owner != unit.owner && civViewableTiles.contains(it)}) - tileGroups[tile]!!.showCircle(colorFromRGB(237, 41, 57)) + for (tile in attackableTiles.filter { + it.getUnits().isNotEmpty() + && it.getUnits().first().owner != unit.owner + && civViewableTiles.contains(it)}) { + if(unit.getBaseUnit().unitType==UnitType.Civilian) tileGroups[tile]!!.hideCircle() + else tileGroups[tile]!!.showCircle(colorFromRGB(237, 41, 57)) + } } if(selectedTile!=null) diff --git a/core/src/com/unciv/ui/worldscreen/unit/IdleUnitButton.kt b/core/src/com/unciv/ui/worldscreen/unit/IdleUnitButton.kt index c64cbeb699..5b8e78cd73 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/IdleUnitButton.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/IdleUnitButton.kt @@ -13,7 +13,7 @@ class IdleUnitButton internal constructor(internal val unitTable: UnitTable, : TextButton(if(previous)"<" else ">", CameraStageBaseScreen.skin) { fun getTilesWithIdleUnits() = tileMapHolder.tileMap.values - .filter { it.hasIdleUnit() && it.unit!!.owner == unitTable.worldScreen.civInfo.civName } + .filter { it.hasIdleUnit() && it.getUnits().first().owner == unitTable.worldScreen.civInfo.civName } init { addClickListener { val tilesWithIdleUnits = getTilesWithIdleUnits() diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 9c513f71a5..e4dc2cf092 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -2,7 +2,6 @@ package com.unciv.ui.worldscreen.unit import com.unciv.logic.automation.WorkerAutomation import com.unciv.logic.map.MapUnit -import com.unciv.logic.map.TileInfo import com.unciv.logic.map.UnitType import com.unciv.models.gamebasics.Building import com.unciv.models.gamebasics.GameBasics @@ -15,10 +14,10 @@ class UnitAction(var name: String, var action:()->Unit, var canAct:Boolean) class UnitActions { - private fun constructImprovementAndDestroyUnit(tileInfo: TileInfo, improvementName: String): () -> Unit { + private fun constructImprovementAndDestroyUnit(unit:MapUnit, improvementName: String): () -> Unit { return { - tileInfo.improvement = improvementName - tileInfo.unit = null// destroy! + unit.getTile().improvement = improvementName + unit.removeFromTile() } } @@ -56,7 +55,7 @@ class UnitActions { { unit.civInfo.gold -= goldCostOfUpgrade val unitTile = unit.getTile() - unitTile.unit = null + unit.removeFromTile() val newunit = unit.civInfo.placeUnitNearTile(unitTile.position, upgradedUnit.name) newunit.health = unit.health newunit.currentMovement=0f @@ -74,7 +73,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 - tile.unit = null // Remove settler! + unit.removeFromTile() }, unit.currentMovement != 0f && !tile.getTilesInDistance(2).any { it.isCityCenter() }) @@ -94,8 +93,8 @@ class UnitActions { else { actionList += UnitAction("Automate", { - tile.unit!!.action = "automation" - WorkerAutomation().automateWorkerAction(tile.unit!!) + unit.action = "automation" + WorkerAutomation().automateWorkerAction(unit) },unit.currentMovement != 0f ) } @@ -105,30 +104,30 @@ class UnitActions { actionList += UnitAction( "Discover Technology", { unit.civInfo.tech.freeTechs += 1 - tile.unit = null// destroy! + unit.removeFromTile() worldScreen.game.screen = TechPickerScreen(true, unit.civInfo) },unit.currentMovement != 0f) actionList += UnitAction("Construct Academy", - constructImprovementAndDestroyUnit(tile, "Academy"),unit.currentMovement != 0f) + constructImprovementAndDestroyUnit(unit, "Academy"),unit.currentMovement != 0f) } if (unit.name == "Great Artist") { actionList += UnitAction( "Start Golden Age", { unit.civInfo.goldenAges.enterGoldenAge() - tile.unit = null// destroy! + unit.removeFromTile() },unit.currentMovement != 0f ) actionList += UnitAction("Construct Landmark", - constructImprovementAndDestroyUnit(tile, "Landmark"),unit.currentMovement != 0f) + constructImprovementAndDestroyUnit(unit, "Landmark"),unit.currentMovement != 0f) } if (unit.name == "Great Engineer") { actionList += UnitAction( "Hurry Wonder", { tile.getCity()!!.cityConstructions.addConstruction(300 + 30 * tile.getCity()!!.population.population) //http://civilization.wikia.com/wiki/Great_engineer_(Civ5) - tile.unit = null // destroy! + unit.removeFromTile() }, unit.currentMovement != 0f && tile.isCityCenter() && @@ -136,17 +135,17 @@ class UnitActions { (tile.getCity()!!.cityConstructions.getCurrentConstruction() as Building).isWonder) actionList += UnitAction("Construct Manufactory", - constructImprovementAndDestroyUnit(tile, "Manufactory"),unit.currentMovement != 0f) + constructImprovementAndDestroyUnit(unit, "Manufactory"),unit.currentMovement != 0f) } if (unit.name == "Great Merchant") { actionList += UnitAction("Conduct Trade Mission", { unit.civInfo.gold += 350 // + 50 * era_number - todo! - tile.unit = null // destroy! + unit.removeFromTile() },unit.currentMovement != 0f) actionList += UnitAction( "Construct Customs House", - constructImprovementAndDestroyUnit(tile, "Customs house"), + constructImprovementAndDestroyUnit(unit, "Customs house"), unit.currentMovement != 0f) } diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt index e8777cdc37..8d1dd1fb2b 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt @@ -73,7 +73,6 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){ fun tileSelected(selectedTile: TileInfo) { if(currentlyExecutingAction=="moveTo"){ - if(selectedUnit!!.movementAlgs() .getShortestPath(selectedTile).isEmpty()) return // can't reach there with the selected unit, watcha want me to do? @@ -86,8 +85,13 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){ currentlyExecutingAction = null } - if(selectedTile.unit!=null && selectedTile.unit!!.civInfo == worldScreen.civInfo) - selectedUnit= selectedTile.unit + if(selectedTile.militaryUnit!=null && selectedTile.militaryUnit!!.civInfo == worldScreen.civInfo + && selectedUnit!=selectedTile.militaryUnit) + selectedUnit = selectedTile.militaryUnit + + else if (selectedTile.civilianUnit!=null && selectedTile.civilianUnit!!.civInfo == worldScreen.civInfo + && selectedUnit!=selectedTile.civilianUnit) + selectedUnit = selectedTile.civilianUnit } }