mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-15 18:28:42 +07:00
Add Air Sweep (#7484)
* Add Air Sweep Unique Enable Dogfighting Promotion Add Air Sweep mode button and crosshair overlay * Adding Air Sweep Battle Table * Add airSweep to Battle Remove double XP While in AirSweep can't select other units on tile * initial airsweep code * Implement airSweep * BattleTable indicates tile you're AirSweeping * some notifications * Clean up notifications. Add icons * Revert game.atlas and game.png * Fix selection properly * Update Vanilla UnitPromotions.json * Better handling of movement use comment cleanup * missing credit * Proper code so that Seas units also deal no damage Adding Tutorials! * Remove Intercept Bonus Damage/Protection * Remove chance of Interceptor missing * Battle Table a bit more consistent * Defender also gets Air Sweep Modifiers * Defender doesn't get bonus * Remove unused getInterceptBonus Combine logic * Show damage in notifications for Air Sweep * Randomize intercepting Civ and prioritize Air Units * Remove debug code * Updated atlas * Clean up Uniques * Object-ify DamageDealt for ease of reference * code clean up Co-authored-by: itanasi <spellman23@gmail.com>
This commit is contained in:
@ -72,11 +72,18 @@ object BattleHelper {
|
||||
.asSequence()
|
||||
|
||||
for (tile in tilesInAttackRange) {
|
||||
if (tile in tilesWithEnemies) attackableTiles += AttackableTile(reachableTile, tile, movementLeft)
|
||||
if (tile in tilesWithEnemies) attackableTiles += AttackableTile(
|
||||
reachableTile,
|
||||
tile,
|
||||
movementLeft
|
||||
)
|
||||
else if (tile in tilesWithoutEnemies) continue // avoid checking the same empty tile multiple times
|
||||
else if (checkTile(unit, tile, tilesToCheck)) {
|
||||
tilesWithEnemies += tile
|
||||
attackableTiles += AttackableTile(reachableTile, tile, movementLeft)
|
||||
} else if (unit.isPreparingAirSweep()){
|
||||
tilesWithEnemies += tile
|
||||
attackableTiles += AttackableTile(reachableTile, tile, movementLeft)
|
||||
} else {
|
||||
tilesWithoutEnemies += tile
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.civilization.PopupAlert
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.RoadStatus
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.AttackableTile
|
||||
@ -305,10 +306,13 @@ object Battle {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun takeDamage(attacker: ICombatant, defender: ICombatant) {
|
||||
private data class DamageDealt(val attackerDealt: Int, val defenderDealt: Int) {}
|
||||
|
||||
private fun takeDamage(attacker: ICombatant, defender: ICombatant): DamageDealt {
|
||||
var potentialDamageToDefender = BattleDamage.calculateDamageToDefender(attacker, defender)
|
||||
var potentialDamageToAttacker = BattleDamage.calculateDamageToAttacker(attacker, defender)
|
||||
|
||||
val attackerHealthBefore = attacker.getHealth()
|
||||
val defenderHealthBefore = defender.getHealth()
|
||||
|
||||
if (defender is MapUnitCombatant && defender.unit.isCivilian() && attacker.isMelee()) {
|
||||
@ -332,7 +336,11 @@ object Battle {
|
||||
}
|
||||
}
|
||||
|
||||
plunderFromDamage(attacker, defender, defenderHealthBefore - defender.getHealth())
|
||||
val defenderDamageDealt = attackerHealthBefore - attacker.getHealth()
|
||||
val attackerDamageDealt = defenderHealthBefore - defender.getHealth()
|
||||
|
||||
plunderFromDamage(attacker, defender, attackerDamageDealt)
|
||||
return DamageDealt(attackerDamageDealt, defenderDamageDealt)
|
||||
}
|
||||
|
||||
private fun plunderFromDamage(
|
||||
@ -810,6 +818,153 @@ object Battle {
|
||||
if (targetedCity.population.population < 1) targetedCity.population.setPopulation(1)
|
||||
}
|
||||
|
||||
// Should draw an Interception if available on the tile from any Civ
|
||||
// Land Units deal 0 damage, and no XP for either party
|
||||
// Air Interceptors do Air Combat as if Melee (mutual damage) but using Ranged Strength. 5XP to both
|
||||
// But does not use the Interception mechanic bonuses/promotions
|
||||
// Counts as an Attack for both units
|
||||
// Will always draw out an Interceptor's attack (they cannot miss)
|
||||
// This means the combat against Air Units will execute and always deal damage
|
||||
// Random Civ at War will Intercept, prioritizing Air Units,
|
||||
// sorted by highest Intercept chance (same as regular Intercept)
|
||||
fun airSweep(attacker: MapUnitCombatant, attackedTile: TileInfo) {
|
||||
// Air Sweep counts as an attack, even if nothing else happens
|
||||
attacker.unit.attacksThisTurn++
|
||||
// copied and modified from reduceAttackerMovementPointsAndAttacks()
|
||||
// use up movement
|
||||
if (attacker.unit.hasUnique(UniqueType.CanMoveAfterAttacking) || attacker.unit.maxAttacksPerTurn() > attacker.unit.attacksThisTurn) {
|
||||
// if it was a melee attack and we won, then the unit ALREADY got movement points deducted,
|
||||
// for the movement to the enemy's tile!
|
||||
// and if it's an air unit, it only has 1 movement anyway, so...
|
||||
if (!attacker.unit.baseUnit.movesLikeAirUnits())
|
||||
attacker.unit.useMovementPoints(1f)
|
||||
} else attacker.unit.currentMovement = 0f
|
||||
val attackerName = attacker.getName()
|
||||
|
||||
// Make giant sequence of all potential Interceptors from all Civs isAtWarWith()
|
||||
var potentialInterceptors = sequence<MapUnit> { }
|
||||
for (interceptingCiv in UncivGame.Current.gameInfo!!.civilizations
|
||||
.filter {attacker.getCivInfo().isAtWarWith(it)}) {
|
||||
potentialInterceptors += interceptingCiv.getCivUnits()
|
||||
.filter { it.canIntercept(attackedTile) }
|
||||
}
|
||||
|
||||
// first priority, only Air Units
|
||||
if (potentialInterceptors.any { it.baseUnit.isAirUnit() })
|
||||
potentialInterceptors = potentialInterceptors.filter { it.baseUnit.isAirUnit() }
|
||||
|
||||
// Pick highest chance interceptor
|
||||
for (interceptor in potentialInterceptors
|
||||
.shuffled() // randomize Civ
|
||||
.sortedByDescending { it.interceptChance() }) {
|
||||
// No chance of Interceptor to miss (unlike regular Interception). Always want to deal damage
|
||||
val interceptingCiv = interceptor.civInfo
|
||||
val interceptorName = interceptor.name
|
||||
// pairs of LocationAction for Notification
|
||||
val locations = LocationAction(
|
||||
interceptor.currentTile.position,
|
||||
attacker.unit.currentTile.position
|
||||
)
|
||||
val locationsAttackerUnknown =
|
||||
LocationAction(interceptor.currentTile.position, attackedTile.position)
|
||||
val locationsInterceptorUnknown =
|
||||
LocationAction(attackedTile.position, attacker.unit.currentTile.position)
|
||||
|
||||
interceptor.attacksThisTurn++ // even if you miss, you took the shot
|
||||
val damageDealt: DamageDealt
|
||||
if (!interceptor.baseUnit.isAirUnit()) {
|
||||
// Deal no damage (moddable in future?) and no XP
|
||||
val attackerText =
|
||||
"Our [$attackerName] (0) was attacked by an intercepting [$interceptorName] (0)"
|
||||
val interceptorText =
|
||||
"Our [$interceptorName] (0) intercepted and attacked an enemy [$attackerName] (0)"
|
||||
attacker.getCivInfo().addNotification(
|
||||
attackerText, locations,
|
||||
attackerName, NotificationIcon.War, interceptorName
|
||||
)
|
||||
interceptingCiv.addNotification(
|
||||
interceptorText, locations,
|
||||
interceptorName, NotificationIcon.War, attackerName
|
||||
)
|
||||
attacker.unit.action = null
|
||||
return
|
||||
} else {
|
||||
// Damage if Air v Air should work similar to Melee
|
||||
damageDealt = takeDamage(attacker, MapUnitCombatant(interceptor))
|
||||
|
||||
// 5 XP to both
|
||||
addXp(MapUnitCombatant(interceptor), 5, attacker)
|
||||
addXp(attacker, 5, MapUnitCombatant(interceptor))
|
||||
}
|
||||
|
||||
if (attacker.isDefeated()) {
|
||||
if (interceptor.getTile() in attacker.getCivInfo().viewableTiles) {
|
||||
val attackerText =
|
||||
"Our [$attackerName] (${damageDealt.attackerDealt}) was destroyed by an intercepting [$interceptorName] (${damageDealt.defenderDealt})"
|
||||
attacker.getCivInfo().addNotification(
|
||||
attackerText, locations,
|
||||
attackerName, NotificationIcon.War, interceptorName
|
||||
)
|
||||
} else {
|
||||
val attackerText =
|
||||
"Our [$attackerName] (${damageDealt.attackerDealt}) was destroyed by an unknown interceptor"
|
||||
attacker.getCivInfo().addNotification(
|
||||
attackerText, locationsInterceptorUnknown,
|
||||
attackerName, NotificationIcon.War, NotificationIcon.Question
|
||||
)
|
||||
}
|
||||
val interceptorText =
|
||||
"Our [$interceptorName] (${damageDealt.defenderDealt}) intercepted and destroyed an enemy [$attackerName] (${damageDealt.attackerDealt})"
|
||||
interceptingCiv.addNotification(
|
||||
interceptorText, locations,
|
||||
interceptorName, NotificationIcon.War, attackerName
|
||||
)
|
||||
} else if (MapUnitCombatant(interceptor).isDefeated()) {
|
||||
val attackerText =
|
||||
"Our [$attackerName] (${damageDealt.attackerDealt}) destroyed an intercepting [$interceptorName] (${damageDealt.defenderDealt})"
|
||||
attacker.getCivInfo().addNotification(
|
||||
attackerText, locations,
|
||||
attackerName, NotificationIcon.War, interceptorName
|
||||
)
|
||||
if (attacker.getTile() in interceptingCiv.viewableTiles) {
|
||||
val interceptorText =
|
||||
"Our [$interceptorName] (${damageDealt.defenderDealt}) intercepted and was destroyed by an enemy [$attackerName](${damageDealt.attackerDealt}) "
|
||||
interceptingCiv.addNotification(
|
||||
interceptorText, locations,
|
||||
interceptorName, NotificationIcon.War, attackerName
|
||||
)
|
||||
} else {
|
||||
val interceptorText =
|
||||
"Our [$interceptorName] (${damageDealt.defenderDealt}) intercepted and was destroyed by an unknown enemy"
|
||||
interceptingCiv.addNotification(
|
||||
interceptorText, locationsAttackerUnknown,
|
||||
interceptorName, NotificationIcon.War, NotificationIcon.Question
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val attackerText =
|
||||
"Our [$attackerName] (${damageDealt.attackerDealt}) was attacked by an intercepting [$interceptorName] (${damageDealt.defenderDealt})"
|
||||
val interceptorText =
|
||||
"Our [$interceptorName] (${damageDealt.defenderDealt}) intercepted and attacked an enemy [$attackerName] (${damageDealt.attackerDealt})"
|
||||
attacker.getCivInfo().addNotification(
|
||||
attackerText, locations,
|
||||
attackerName, NotificationIcon.War, interceptorName
|
||||
)
|
||||
interceptingCiv.addNotification(
|
||||
interceptorText, locations,
|
||||
interceptorName, NotificationIcon.War, attackerName
|
||||
)
|
||||
}
|
||||
attacker.unit.action = null
|
||||
return
|
||||
}
|
||||
|
||||
// No Interceptions available
|
||||
val attackerText = "Nothing tried to intercept our [$attackerName]"
|
||||
attacker.getCivInfo().addNotification(attackerText, attackerName)
|
||||
attacker.unit.action = null
|
||||
}
|
||||
|
||||
private fun tryInterceptAirAttack(attacker: MapUnitCombatant, attackedTile: TileInfo, interceptingCiv: CivilizationInfo, defender: ICombatant?) {
|
||||
if (attacker.unit.hasUnique(UniqueType.CannotBeIntercepted, StateForConditionals(attacker.getCivInfo(), ourCombatant = attacker, theirCombatant = defender, attackedTile = attackedTile)))
|
||||
return
|
||||
|
@ -122,6 +122,9 @@ object BattleDamage {
|
||||
if (attacker.unit.type.isWaterUnit() && attacker.isMelee() && !defender.getTile().isWater
|
||||
&& !attacker.unit.hasUnique(UniqueType.AttackAcrossCoast) && !defender.isCity())
|
||||
modifiers["Landing"] = -50
|
||||
// Air unit attacking with Air Sweep
|
||||
if (attacker.unit.isPreparingAirSweep())
|
||||
modifiers.add(getAirSweepAttackModifiers(attacker))
|
||||
|
||||
if (attacker.isMelee()) {
|
||||
val numberOfAttackersSurroundingDefender = defender.getTile().neighbors.count {
|
||||
@ -155,6 +158,20 @@ object BattleDamage {
|
||||
return modifiers
|
||||
}
|
||||
|
||||
fun getAirSweepAttackModifiers(
|
||||
attacker: ICombatant
|
||||
): Counter<String> {
|
||||
val modifiers = Counter<String>()
|
||||
|
||||
if (attacker is MapUnitCombatant) {
|
||||
for (unique in attacker.unit.getUniques().filter{it.isOfType(UniqueType.StrengthWhenAirsweep)}) {
|
||||
modifiers.add(getModifierStringFromUnique(unique), unique.params[0].toInt())
|
||||
}
|
||||
}
|
||||
|
||||
return modifiers
|
||||
}
|
||||
|
||||
fun getDefenceModifiers(attacker: ICombatant, defender: ICombatant): Counter<String> {
|
||||
val modifiers = getGeneralModifiers(defender, attacker, CombatAction.Defend)
|
||||
val tile = defender.getTile()
|
||||
|
@ -56,4 +56,5 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant {
|
||||
fun hasUnique(uniqueType: UniqueType, conditionalState: StateForConditionals? = null): Boolean =
|
||||
if (conditionalState == null) unit.hasUnique(uniqueType)
|
||||
else unit.hasUnique(uniqueType, conditionalState)
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ object NotificationIcon {
|
||||
const val Scout = "UnitIcons/Scout"
|
||||
const val Ruins = "ImprovementIcons/Ancient ruins"
|
||||
const val Barbarians = "ImprovementIcons/Barbarian encampment"
|
||||
const val Question = "OtherIcons/Question"
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -440,6 +440,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
fun isAutomated() = action == UnitActionType.Automate.value
|
||||
fun isExploring() = action == UnitActionType.Explore.value
|
||||
fun isPreparingParadrop() = action == UnitActionType.Paradrop.value
|
||||
fun isPreparingAirSweep() = action == UnitActionType.AirSweep.value
|
||||
fun isSetUpForSiege() = action == UnitActionType.SetUp.value
|
||||
|
||||
/** For display in Unit Overview */
|
||||
@ -858,7 +859,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
action = null // wake up when healed
|
||||
}
|
||||
|
||||
if (isPreparingParadrop())
|
||||
if (isPreparingParadrop() || isPreparingAirSweep())
|
||||
action = null
|
||||
|
||||
if (hasUnique(UniqueType.ReligiousUnit)
|
||||
@ -1302,7 +1303,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
|
||||
fun actionsOnDeselect() {
|
||||
showAdditionalActions = false
|
||||
if (isPreparingParadrop()) action = null
|
||||
if (isPreparingParadrop() || isPreparingAirSweep()) action = null
|
||||
}
|
||||
|
||||
fun getForceEvaluation(): Int {
|
||||
|
@ -101,6 +101,8 @@ enum class UnitActionType(
|
||||
{ ImageGetter.getImage("OtherIcons/Pillage") }, 'p'),
|
||||
Paradrop("Paradrop",
|
||||
{ ImageGetter.getUnitIcon("Paratrooper") }, 'p'),
|
||||
AirSweep("Air Sweep",
|
||||
{ ImageGetter.getImage("OtherIcons/AirSweep") }, 'a'),
|
||||
SetUp("Set up",
|
||||
{ ImageGetter.getUnitIcon("Catapult") }, 't', UncivSound.Setup),
|
||||
FoundCity("Found city",
|
||||
|
@ -430,6 +430,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
ExtraInterceptionsPerTurn("[amount] extra interceptions may be made per turn", UniqueTarget.Unit),
|
||||
CannotBeIntercepted("Cannot be intercepted", UniqueTarget.Unit),
|
||||
CannotInterceptUnits("Cannot intercept [mapUnitFilter] units", UniqueTarget.Unit),
|
||||
CanAirsweep("Can perform Air Sweep", UniqueTarget.Unit),
|
||||
StrengthWhenAirsweep("[relativeAmount]% Strength when performing Air Sweep", UniqueTarget.Unit),
|
||||
|
||||
UnitMaintenanceDiscount("[relativeAmount]% maintenance costs", UniqueTarget.Unit, UniqueTarget.Global),
|
||||
UnitUpgradeCost("[relativeAmount]% Gold cost of upgrading", UniqueTarget.Unit, UniqueTarget.Global),
|
||||
|
@ -190,7 +190,7 @@ class WorldMapHolder(
|
||||
it.movement.canMoveTo(tileInfo) ||
|
||||
it.movement.isUnknownTileWeShouldAssumeToBePassable(tileInfo) && !it.baseUnit.movesLikeAirUnits()
|
||||
}
|
||||
)) {
|
||||
) && previousSelectedUnits.any { !it.isPreparingAirSweep()}) {
|
||||
if (previousSelectedUnitIsSwapping) {
|
||||
addTileOverlaysWithUnitSwapping(previousSelectedUnits.first(), tileInfo)
|
||||
}
|
||||
@ -647,7 +647,7 @@ class WorldMapHolder(
|
||||
|
||||
for (tile in tilesInMoveRange) {
|
||||
for (tileToColor in tileGroups[tile]!!) {
|
||||
if (isAirUnit)
|
||||
if (isAirUnit && !unit.isPreparingAirSweep()) {
|
||||
if (tile.aerialDistanceTo(unit.getTile()) <= unit.getRange()) {
|
||||
// The tile is within attack range
|
||||
tileToColor.showHighlight(Color.RED, 0.3f)
|
||||
@ -655,6 +655,7 @@ class WorldMapHolder(
|
||||
// The tile is within move range
|
||||
tileToColor.showHighlight(Color.BLUE, 0.3f)
|
||||
}
|
||||
}
|
||||
if (unit.movement.canMoveTo(tile) ||
|
||||
unit.movement.isUnknownTileWeShouldAssumeToBePassable(tile) && !unit.baseUnit.movesLikeAirUnits())
|
||||
tileToColor.showHighlight(moveTileOverlayColor,
|
||||
|
@ -60,6 +60,10 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
val selectedTile = worldScreen.mapHolder.selectedTile
|
||||
?: return hide() // no selected tile
|
||||
simulateNuke(attacker, selectedTile)
|
||||
} else if (attacker is MapUnitCombatant && attacker.unit.isPreparingAirSweep()) {
|
||||
val selectedTile = worldScreen.mapHolder.selectedTile
|
||||
?: return hide() // no selected tile
|
||||
simulateAirsweep(attacker, selectedTile)
|
||||
} else {
|
||||
val defender = tryGetDefender() ?: return hide()
|
||||
if (attacker is CityCombatant && defender is CityCombatant) return hide()
|
||||
@ -113,6 +117,21 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
if (combatant is MapUnitCombatant) UnitGroup(combatant.unit,25f)
|
||||
else ImageGetter.getNationIndicator(combatant.getCivInfo().nation, 25f)
|
||||
|
||||
private val quarterScreen = worldScreen.stage.width / 4
|
||||
|
||||
private fun getModifierTable(key: String, value: Int) = Table().apply {
|
||||
val description = if (key.startsWith("vs "))
|
||||
("vs [" + key.drop(3) + "]").tr()
|
||||
else key.tr()
|
||||
val percentage = (if (value > 0) "+" else "") + value + "%"
|
||||
val upOrDownLabel = if (value > 0f) "⬆".toLabel(Color.GREEN)
|
||||
else "⬇".toLabel(Color.RED)
|
||||
|
||||
add(upOrDownLabel)
|
||||
val modifierLabel = "$percentage $description".toLabel(fontSize = 14).apply { wrap = true }
|
||||
add(modifierLabel).width(quarterScreen - upOrDownLabel.minWidth)
|
||||
}
|
||||
|
||||
private fun simulateBattle(attacker: ICombatant, defender: ICombatant){
|
||||
clear()
|
||||
|
||||
@ -139,21 +158,6 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
add(attacker.getAttackingStrength().toString() + attackIcon)
|
||||
add(defender.getDefendingStrength(attacker.isRanged()).toString() + defenceIcon).row()
|
||||
|
||||
|
||||
val quarterScreen = worldScreen.stage.width / 4
|
||||
|
||||
fun getModifierTable(key: String, value: Int) = Table().apply {
|
||||
val description = if (key.startsWith("vs "))
|
||||
("vs [" + key.drop(3) + "]").tr()
|
||||
else key.tr()
|
||||
val percentage = (if (value > 0) "+" else "") + value + "%"
|
||||
val upOrDownLabel = if (value > 0f) "⬆".toLabel(Color.GREEN)
|
||||
else "⬇".toLabel(Color.RED)
|
||||
|
||||
add(upOrDownLabel)
|
||||
val modifierLabel = "$percentage $description".toLabel(fontSize = 14).apply { wrap = true }
|
||||
add(modifierLabel).width(quarterScreen - upOrDownLabel.minWidth)
|
||||
}
|
||||
val attackerModifiers =
|
||||
BattleDamage.getAttackModifiers(attacker, defender).map {
|
||||
getModifierTable(it.key, it.value)
|
||||
@ -323,4 +327,63 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
|
||||
setPosition(worldScreen.stage.width / 2 - width / 2, 5f)
|
||||
}
|
||||
|
||||
private fun simulateAirsweep(attacker: MapUnitCombatant, targetTile: TileInfo)
|
||||
{
|
||||
clear()
|
||||
|
||||
val attackerNameWrapper = Table()
|
||||
val attackerLabel = attacker.getName().toLabel()
|
||||
attackerNameWrapper.add(getIcon(attacker)).padRight(5f)
|
||||
attackerNameWrapper.add(attackerLabel)
|
||||
add(attackerNameWrapper)
|
||||
|
||||
val canAttack = attacker.canAttack()
|
||||
|
||||
val defenderLabel = Label("???", skin)
|
||||
add(defenderLabel).row()
|
||||
|
||||
addSeparator().pad(0f)
|
||||
|
||||
val attackIcon = Fonts.rangedStrength
|
||||
add(attacker.getAttackingStrength().toString() + attackIcon)
|
||||
add("???$attackIcon").row()
|
||||
|
||||
val attackerModifiers =
|
||||
BattleDamage.getAirSweepAttackModifiers(attacker).map {
|
||||
getModifierTable(it.key, it.value)
|
||||
}
|
||||
|
||||
for (modifier in attackerModifiers) {
|
||||
add(modifier)
|
||||
add()
|
||||
row().pad(2f)
|
||||
}
|
||||
|
||||
add(getHealthBar(attacker.getHealth(), attacker.getMaxHealth(), 0))
|
||||
add(getHealthBar(attacker.getMaxHealth(), attacker.getMaxHealth(), 0))
|
||||
row().pad(5f)
|
||||
|
||||
val attackButton = "Air Sweep".toTextButton().apply { color = Color.RED }
|
||||
|
||||
val canReach = attacker.unit.currentTile.getTilesInDistance(attacker.unit.getRange()).contains(targetTile)
|
||||
|
||||
if (!worldScreen.isPlayersTurn || !attacker.canAttack() || !canReach || !canAttack) {
|
||||
attackButton.disable()
|
||||
attackButton.label.color = Color.GRAY
|
||||
}
|
||||
else {
|
||||
attackButton.onClick(attacker.getAttackSound()) {
|
||||
Battle.airSweep(attacker, targetTile)
|
||||
worldScreen.mapHolder.removeUnitActionOverlay() // the overlay was one of attacking
|
||||
worldScreen.shouldUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
add(attackButton).colspan(2)
|
||||
|
||||
pack()
|
||||
|
||||
setPosition(worldScreen.stage.width / 2 - width / 2, 5f)
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ object UnitActions {
|
||||
addUnitUpgradeAction(unit, actionList)
|
||||
addPillageAction(unit, actionList, worldScreen)
|
||||
addParadropAction(unit, actionList)
|
||||
addAirSweepAction(unit, actionList)
|
||||
addSetupAction(unit, actionList)
|
||||
addFoundCityAction(unit, actionList, tile)
|
||||
addBuildingImprovementsAction(unit, actionList, tile, worldScreen, unitTable)
|
||||
@ -267,6 +268,21 @@ object UnitActions {
|
||||
})
|
||||
}
|
||||
|
||||
private fun addAirSweepAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val airsweepUniques =
|
||||
unit.getMatchingUniques(UniqueType.CanAirsweep)
|
||||
if (!airsweepUniques.any()) return
|
||||
actionList += UnitAction(UnitActionType.AirSweep,
|
||||
isCurrentAction = unit.isPreparingAirSweep(),
|
||||
action = {
|
||||
if (unit.isPreparingAirSweep()) unit.action = null
|
||||
else unit.action = UnitActionType.AirSweep.value
|
||||
}.takeIf {
|
||||
unit.canAttack()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun addPillageAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) {
|
||||
val pillageAction = getPillageAction(unit)
|
||||
?: return
|
||||
|
@ -255,6 +255,8 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||
|
||||
// Do not select a different unit or city center if we click on it to swap our current unit to it
|
||||
if (selectedUnitIsSwapping && selectedUnit != null && selectedUnit!!.movement.canUnitSwapTo(selectedTile)) return
|
||||
// Do no select a different unit while in Air Sweep mode
|
||||
if (selectedUnit != null && selectedUnit!!.isPreparingAirSweep()) return
|
||||
|
||||
when {
|
||||
forceSelectUnit != null ->
|
||||
|
Reference in New Issue
Block a user