mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 20:55:44 +00:00
Label strategically retreating armies in battle progress (#8707)
* Label strategically retreating battle armies * Show strategic retreats in initial battle progress
This commit is contained in:
@@ -34,6 +34,6 @@ message ShardokBattleView {
|
||||
.google.protobuf.Int32Value winning_faction_id = 10; // set when battle ended and result is revealed
|
||||
bool can_fight = 11; // true only for this viewer's highest fightable battle
|
||||
bool can_observe = 12; // true if this viewer can currently observe this battle
|
||||
bool defender_retreating = 13; // true once any defending unit has fled
|
||||
bool attacker_retreating = 14; // true once any attacking unit has fled
|
||||
bool defender_retreating = 13; // true for an army already retreating or once a defending unit has fled
|
||||
bool attacker_retreating = 14; // true for an army already retreating or once an attacking unit has fled
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ object BattleFilter {
|
||||
val total = defTroops + atkTroops
|
||||
val ratio = if total == 0 then 0.5f else defTroops.toFloat / total
|
||||
val showCounts = fid.exists(f => isParticipantOrAlly(f, battle, factions))
|
||||
val defenderRetreating = sideHasRetreatingArmy(battle, isDefender = true)
|
||||
val attackerRetreating = sideHasRetreatingArmy(battle, isDefender = false)
|
||||
|
||||
val shardokPlayer =
|
||||
battle.players.find(sp => fid.contains(sp.eagleFid))
|
||||
@@ -46,7 +48,9 @@ object BattleFilter {
|
||||
attackerTroopCount = Option.when(showCounts)(atkTroops),
|
||||
winningFactionId = None,
|
||||
canFight = false,
|
||||
canObserve = false
|
||||
canObserve = false,
|
||||
defenderRetreating = defenderRetreating,
|
||||
attackerRetreating = attackerRetreating
|
||||
)
|
||||
}.getOrElse {
|
||||
ShardokBattleView(
|
||||
@@ -63,11 +67,22 @@ object BattleFilter {
|
||||
attackerTroopCount = Option.when(showCounts)(atkTroops),
|
||||
winningFactionId = None,
|
||||
canFight = false,
|
||||
canObserve = false
|
||||
canObserve = false,
|
||||
defenderRetreating = defenderRetreating,
|
||||
attackerRetreating = attackerRetreating
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def sideHasRetreatingArmy(
|
||||
battle: ShardokBattle,
|
||||
isDefender: Boolean
|
||||
): Boolean =
|
||||
battle.players.exists { player =>
|
||||
player.isDefender == isDefender &&
|
||||
player.armyGroup.exists(_.armies.exists(_.army.isRetreating))
|
||||
}
|
||||
|
||||
private def initialTroopCounts(
|
||||
battle: ShardokBattle,
|
||||
battalions: Map[BattalionId, BattalionT]
|
||||
|
||||
@@ -571,22 +571,28 @@ object GameController {
|
||||
val currentRound = battleUpdate.currentRound
|
||||
|
||||
// Determine which player IDs are defenders from the battle's player list
|
||||
val defenderPlayerIds = battleUpdate.battle.players.zipWithIndex
|
||||
val defenderPlayerIds = battleUpdate.battle.players.zipWithIndex
|
||||
.filter(_._1.isDefender)
|
||||
.map(_._2)
|
||||
.toSet
|
||||
val defenderTroops = battleUpdate.playerTroopCounts
|
||||
val retreatingArmyPlayerIds = battleUpdate.battle.players.zipWithIndex.collect {
|
||||
case (player, playerId) if player.armyGroup.exists(_.armies.exists(_.army.exists(_.isRetreating))) =>
|
||||
playerId
|
||||
}.toSet
|
||||
val defenderTroops = battleUpdate.playerTroopCounts
|
||||
.filter(ptc => defenderPlayerIds.contains(ptc.playerId))
|
||||
.map(_.troopCount)
|
||||
.sum
|
||||
val attackerTroops = battleUpdate.playerTroopCounts
|
||||
val attackerTroops = battleUpdate.playerTroopCounts
|
||||
.filterNot(ptc => defenderPlayerIds.contains(ptc.playerId))
|
||||
.map(_.troopCount)
|
||||
.sum
|
||||
val defenderRetreating = battleUpdate.playerTroopCounts
|
||||
.exists(ptc => defenderPlayerIds.contains(ptc.playerId) && ptc.isRetreating)
|
||||
val attackerRetreating = battleUpdate.playerTroopCounts
|
||||
.exists(ptc => !defenderPlayerIds.contains(ptc.playerId) && ptc.isRetreating)
|
||||
val defenderRetreating = battleUpdate.playerTroopCounts
|
||||
.exists(ptc => defenderPlayerIds.contains(ptc.playerId) && ptc.isRetreating) ||
|
||||
retreatingArmyPlayerIds.exists(defenderPlayerIds.contains)
|
||||
val attackerRetreating = battleUpdate.playerTroopCounts
|
||||
.exists(ptc => !defenderPlayerIds.contains(ptc.playerId) && ptc.isRetreating) ||
|
||||
retreatingArmyPlayerIds.exists(playerId => !defenderPlayerIds.contains(playerId))
|
||||
|
||||
val snapshot = BattleProgressSnapshot(
|
||||
defenderTroops,
|
||||
@@ -645,8 +651,8 @@ object GameController {
|
||||
defenderRatio = snapshot.defenderRatio,
|
||||
defenderTroopCount = Option.when(isAllied)(snapshot.defenderTroops),
|
||||
attackerTroopCount = Option.when(isAllied)(snapshot.attackerTroops),
|
||||
defenderRetreating = snapshot.defenderRetreating,
|
||||
attackerRetreating = snapshot.attackerRetreating,
|
||||
defenderRetreating = view.defenderRetreating || snapshot.defenderRetreating,
|
||||
attackerRetreating = view.attackerRetreating || snapshot.attackerRetreating,
|
||||
winningFactionId =
|
||||
// Only reveal winner when the gated round has caught up to the end round
|
||||
tracker.endedAtRound.filter(_ <= gatedRound).flatMap(_ => tracker.winningFactionId)
|
||||
|
||||
@@ -211,6 +211,29 @@ class BattleFilterTest extends AnyFlatSpec with Matchers {
|
||||
view.defenderRatio shouldBe (50f / 150f +- 0.001f)
|
||||
}
|
||||
|
||||
it `should` "mark an attacker that was already retreating in the initial battle view" in {
|
||||
val originalBattle = battleWithBattalions
|
||||
val retreatingAttacker = originalBattle
|
||||
.players(1)
|
||||
.copy(
|
||||
armyGroup = originalBattle.players(1).armyGroup.map { group =>
|
||||
group.copy(
|
||||
armies = group.armies.map { movingArmy =>
|
||||
movingArmy.copy(army = movingArmy.army.copy(isRetreating = true))
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
val battleWithRetreating = originalBattle.copy(
|
||||
players = originalBattle.players.updated(1, retreatingAttacker)
|
||||
)
|
||||
|
||||
val view = BattleFilter.filterBattle(battleWithRetreating, factions, Some(1), testBattalions)
|
||||
|
||||
view.attackerRetreating shouldBe true
|
||||
view.defenderRetreating shouldBe false
|
||||
}
|
||||
|
||||
it `should` "show correct ratio but no troop counts for non-participants" in {
|
||||
val view = BattleFilter.filterBattle(battleWithBattalions, factionsWithThird, Some(3), testBattalions)
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ scala_test(
|
||||
name = "battle_progress_test",
|
||||
srcs = ["BattleProgressTest.scala"],
|
||||
deps = [
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:army_scala_proto",
|
||||
"//src/main/protobuf/net/eagle0/eagle/internal:shardok_battle_scala_proto",
|
||||
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
|
||||
"//src/main/scala/net/eagle0/eagle/service/controller:battle_progress_tracker",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.eagle0.eagle.service.controller
|
||||
|
||||
import net.eagle0.common.shardok_internal_interface.PlayerTroopCount
|
||||
import net.eagle0.eagle.internal.army.{Army, HostileArmyGroup, MovingArmy}
|
||||
import net.eagle0.eagle.internal.shardok_battle.{ShardokBattle, ShardokPlayer}
|
||||
import net.eagle0.eagle.shardok_interface.BattleUpdate
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
@@ -143,6 +144,37 @@ class BattleProgressTest extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
}
|
||||
|
||||
it should "mark an attacker whose strategic army was already retreating" in {
|
||||
val retreatingAttacker = attacker.copy(
|
||||
armyGroup = Some(
|
||||
HostileArmyGroup(
|
||||
armies = Seq(
|
||||
MovingArmy(
|
||||
army = Some(Army(isRetreating = true))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
val update = makeBattleUpdate(
|
||||
currentRound = 1,
|
||||
playerTroopCounts = Seq(
|
||||
PlayerTroopCount(playerId = 0, troopCount = 500),
|
||||
PlayerTroopCount(playerId = 1, troopCount = 300)
|
||||
),
|
||||
battle = twoPlayerBattle.copy(players = Seq(defender, retreatingAttacker))
|
||||
)
|
||||
|
||||
val result = GameController.updatedBattleProgress(Map.empty, "test-battle-1", update)
|
||||
|
||||
result("test-battle-1").latestSnapshot shouldBe BattleProgressSnapshot(
|
||||
defenderTroops = 500,
|
||||
attackerTroops = 300,
|
||||
defenderRetreating = false,
|
||||
attackerRetreating = true
|
||||
)
|
||||
}
|
||||
|
||||
it should "default to zero when defender has no troop count entry" in {
|
||||
val update = makeBattleUpdate(
|
||||
currentRound = 1,
|
||||
|
||||
Reference in New Issue
Block a user