mirror of
https://github.com/yairm210/Unciv.git
synced 2025-08-02 16:19:41 +07:00
Save attacks per civ for arrows for cities, missiles, dead units. (#5855)
* Save attacks per civ for arrows for cities, missiles, dead units. * Tweak docs.
This commit is contained in:
@ -61,6 +61,12 @@ object Battle {
|
||||
val attackedTile = defender.getTile()
|
||||
if (attacker is MapUnitCombatant) {
|
||||
attacker.unit.attacksSinceTurnStart.add(Vector2(attackedTile.position))
|
||||
} else {
|
||||
attacker.getCivInfo().attacksSinceTurnStart.add(CivilizationInfo.HistoricalAttackMemory(
|
||||
null,
|
||||
Vector2(attacker.getTile().position),
|
||||
Vector2(attackedTile.position)
|
||||
))
|
||||
}
|
||||
|
||||
if (attacker is MapUnitCombatant && attacker.unit.baseUnit.isAirUnit()) {
|
||||
@ -634,6 +640,8 @@ object Battle {
|
||||
}
|
||||
if (attacker.isDefeated()) return
|
||||
|
||||
attacker.unit.attacksSinceTurnStart.add(Vector2(targetTile.position))
|
||||
|
||||
// Destroy units on the target tile
|
||||
// Needs the toList() because if we're destroying the units, they're no longer part of the sequence
|
||||
for (defender in targetTile.getUnits().filter { it != attacker.unit }.toList()) {
|
||||
|
@ -178,6 +178,33 @@ class CivilizationInfo {
|
||||
var totalCultureForContests = 0
|
||||
var totalFaithForContests = 0
|
||||
|
||||
/**
|
||||
* Container class to represent a historical attack recently performed by this civilization.
|
||||
*
|
||||
* @property attackingUnit Name key of [BaseUnit] type that performed the attack, or null (E.G. for city bombardments).
|
||||
* @property source Position of the tile from which the attack was made.
|
||||
* @property target Position of the tile targetted by the attack.
|
||||
* @see [MapUnit.UnitMovementMemory], [attacksSinceTurnStart]
|
||||
*/
|
||||
class HistoricalAttackMemory() {
|
||||
constructor(attackingUnit: String?, source: Vector2, target: Vector2): this() {
|
||||
this.attackingUnit = attackingUnit
|
||||
this.source = source
|
||||
this.target = target
|
||||
}
|
||||
var attackingUnit: String? = null
|
||||
lateinit var source: Vector2
|
||||
lateinit var target: Vector2
|
||||
fun clone() = HistoricalAttackMemory(attackingUnit, Vector2(source), Vector2(target))
|
||||
}
|
||||
/** Deep clone an ArrayList of [HistoricalAttackMemory]s. */
|
||||
private fun ArrayList<HistoricalAttackMemory>.copy() = ArrayList(this.map { it.clone() })
|
||||
/**
|
||||
* List of attacks that this civilization has performed since the start of its most recent turn. Does not include attacks already tracked in [MapUnit.attacksSinceTurnStart] of living units. Used in movement arrow overlay.
|
||||
* @see [MapUnit.attacksSinceTurnStart]
|
||||
*/
|
||||
var attacksSinceTurnStart = ArrayList<HistoricalAttackMemory>()
|
||||
|
||||
var hasMovedAutomatedUnits = false
|
||||
|
||||
@Transient
|
||||
@ -230,6 +257,7 @@ class CivilizationInfo {
|
||||
toReturn.numMinorCivsAttacked = numMinorCivsAttacked
|
||||
toReturn.totalCultureForContests = totalCultureForContests
|
||||
toReturn.totalFaithForContests = totalFaithForContests
|
||||
toReturn.attacksSinceTurnStart = attacksSinceTurnStart.copy()
|
||||
toReturn.hasMovedAutomatedUnits = hasMovedAutomatedUnits
|
||||
return toReturn
|
||||
}
|
||||
@ -782,6 +810,7 @@ class CivilizationInfo {
|
||||
|
||||
fun startTurn() {
|
||||
civConstructions.startTurn()
|
||||
attacksSinceTurnStart.clear()
|
||||
updateStatsForNextTurn() // for things that change when turn passes e.g. golden age, city state influence
|
||||
|
||||
// Generate great people at the start of the turn,
|
||||
|
@ -177,6 +177,7 @@ class MapUnit {
|
||||
*
|
||||
* @property position Position on the map at this instant.
|
||||
* @property type Category of the last change in position that brought the unit to this position.
|
||||
* @see [movementMemories]
|
||||
* */
|
||||
class UnitMovementMemory() {
|
||||
constructor(position: Vector2, type: UnitMovementMemoryType): this() {
|
||||
@ -827,6 +828,8 @@ class MapUnit {
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
val currentPosition = Vector2(getTile().position)
|
||||
civInfo.attacksSinceTurnStart.addAll(attacksSinceTurnStart.asSequence().map { CivilizationInfo.HistoricalAttackMemory(this.name, currentPosition, it) })
|
||||
removeFromTile()
|
||||
civInfo.removeUnit(this)
|
||||
civInfo.updateViewableTiles()
|
||||
|
@ -22,6 +22,6 @@ class MapVisualization(val gameInfo: GameInfo, val viewingCiv: CivilizationInfo)
|
||||
// Plans should be visible always for own units and never for foreign units.
|
||||
|
||||
/** @return Whether an attack by a unit to a target should be visible to the player. */
|
||||
fun isAttackVisible(attacker: MapUnit, target: Vector2) = (attacker.civInfo == viewingCiv || attacker.getTile() in viewingCiv.viewableTiles || gameInfo.tileMap[target] in viewingCiv.viewableTiles)
|
||||
fun isAttackVisible(attacker: CivilizationInfo, source: Vector2, target: Vector2) = (attacker == viewingCiv || gameInfo.tileMap[source] in viewingCiv.viewableTiles || gameInfo.tileMap[target] in viewingCiv.viewableTiles)
|
||||
// Attacks by the player civ should always be visible, and attacks by foreign civs should be visible if either the tile they targeted or the attacker's tile are visible. E.G. Civ V shows bombers coming out of the Fog of War.
|
||||
}
|
||||
|
@ -455,9 +455,9 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
*
|
||||
* @param pastVisibleUnits Sequence of [MapUnit]s for which the last turn's movement history can be displayed.
|
||||
* @param targetVisibleUnits Sequence of [MapUnit]s for which the active movement target can be displayed.
|
||||
* @param visibleAttacks Sequence of pairs of MapUnits to the target coordinates of attacks that they have done and can be displayed.
|
||||
* @param visibleAttacks Sequence of pairs of [Vector2] positions of the sources and the targets of all attacks that can be displayed.
|
||||
* */
|
||||
internal fun updateMovementOverlay(pastVisibleUnits: Sequence<MapUnit>, targetVisibleUnits: Sequence<MapUnit>, visibleAttacks: Sequence<Pair<MapUnit, Vector2>>) {
|
||||
internal fun updateMovementOverlay(pastVisibleUnits: Sequence<MapUnit>, targetVisibleUnits: Sequence<MapUnit>, visibleAttacks: Sequence<Pair<Vector2, Vector2>>) {
|
||||
if (!UncivGame.Current.settings.showUnitMovements) {
|
||||
return
|
||||
}
|
||||
@ -481,7 +481,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
addArrow(unit.getTile(), toTile, MiscArrowTypes.UnitMoving)
|
||||
}
|
||||
for ((from, to) in visibleAttacks) {
|
||||
addArrow(tileMap[from.getTile().position], tileMap[to], MiscArrowTypes.UnitHasAttacked)
|
||||
addArrow(tileMap[from], tileMap[to], MiscArrowTypes.UnitHasAttacked)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@ import com.unciv.logic.GameSaver
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.ReligionState
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.MapVisualization
|
||||
import com.unciv.logic.trade.TradeEvaluation
|
||||
import com.unciv.models.Tutorial
|
||||
@ -405,11 +404,13 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
|
||||
|
||||
mapHolder.resetArrows()
|
||||
val allUnits = gameInfo.civilizations.asSequence().flatMap { it.getCivUnits() }
|
||||
val allAttacks = allUnits.map { unit -> unit.attacksSinceTurnStart.asSequence().map { attacked -> unit to attacked } }.flatten()
|
||||
val allAttacks = allUnits.map { unit -> unit.attacksSinceTurnStart.asSequence().map { attacked -> Triple(unit.civInfo, unit.getTile().position, attacked) } }.flatten() +
|
||||
gameInfo.civilizations.asSequence().flatMap { civInfo -> civInfo.attacksSinceTurnStart.asSequence().map { Triple(civInfo, it.source, it.target) } }
|
||||
mapHolder.updateMovementOverlay(
|
||||
allUnits.filter(mapVisualization::isUnitPastVisible),
|
||||
allUnits.filter(mapVisualization::isUnitFutureVisible),
|
||||
allAttacks.filter { (attacker, target) -> mapVisualization.isAttackVisible(attacker, target) }
|
||||
allAttacks.filter { (attacker, source, target) -> mapVisualization.isAttackVisible(attacker, source, target) }
|
||||
.map { (attacker, source, target) -> source to target }
|
||||
)
|
||||
|
||||
// if we use the clone, then when we update viewable tiles
|
||||
|
Reference in New Issue
Block a user