Compare commits

...
Author SHA1 Message Date
adminandClaude Opus 4.5 45d35cccea Add hostility and originProvinceId to ArmyStats
The client was crashing with KeyNotFoundException because ArmyStats
didn't include originProvinceId. The protobuf already had these fields
but they weren't populated from the Scala model.

Changes:
- Add hostility and originProvinceId fields to Scala ArmyStats
- Update AvailableAttackDecisionCommandFactory to populate new fields
- Update AvailableFreeForAllDecisionCommandFactory to populate new fields
- Update AvailableCommandConverter to include fields in protobuf
- Add necessary BUILD.bazel dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 19:45:38 -08:00
6 changed files with 29 additions and 12 deletions
@@ -62,11 +62,13 @@ object AvailableAttackDecisionCommandFactory extends ScalaAvailableCommandsFacto
.takeRight(heroCount)
.sum
province.rulingFactionId.map { _ =>
province.rulingFactionId.map { defenderFid =>
ArmyStats(
factionId = province.rulingFactionId.get,
factionId = defenderFid,
heroCount = heroCount,
troopCount = troopCount
troopCount = troopCount,
hostility = FactionUtils.hostilityStatus(attackerFid, defenderFid, gs.factions.values.toVector),
originProvinceId = Some(pid)
)
}
}
@@ -76,22 +78,26 @@ object AvailableAttackDecisionCommandFactory extends ScalaAvailableCommandsFacto
pid: ProvinceId,
gs: GameState
): Vector[ArmyStats] =
relevantArmies(pid, gs).map(ma => stats(ma.army, gs)) ++ defendingArmyStats(
relevantArmies(pid, gs).map(ma => stats(toFid, ma, gs)) ++ defendingArmyStats(
toFid,
pid,
gs
)
private def stats(
army: Army,
viewerFid: FactionId,
movingArmy: MovingArmy,
gs: GameState
): ArmyStats = {
val army = movingArmy.army
val battalions = army.units.flatMap(_.battalionId).map(gs.battalions)
val troopCount = battalions.map(_.size).sum
ArmyStats(
factionId = army.factionId,
heroCount = army.units.size,
troopCount = troopCount
troopCount = troopCount,
hostility = FactionUtils.hostilityStatus(viewerFid, army.factionId, gs.factions.values.toVector),
originProvinceId = Some(movingArmy.originProvinceId)
)
}
@@ -1,6 +1,7 @@
package net.eagle0.eagle.library.actions.availability
import net.eagle0.eagle.{FactionId, ProvinceId}
import net.eagle0.eagle.library.util.faction_utils.FactionUtils
import net.eagle0.eagle.library.util.IncomingArmyUtils
import net.eagle0.eagle.model.state.{Army, HostileArmyGroupStatus, MovingArmy}
import net.eagle0.eagle.model.state.command.available.AvailableCommand
@@ -53,19 +54,22 @@ object AvailableFreeForAllDecisionCommandFactory extends ScalaAvailableCommandsF
pid: ProvinceId,
gs: GameState
): Vector[ArmyStats] =
relevantArmies(pid, gs).map(ma => stats(toFid, ma.army, gs))
relevantArmies(pid, gs).map(ma => stats(toFid, ma, gs))
private def stats(
toFid: FactionId,
army: Army,
viewerFid: FactionId,
movingArmy: MovingArmy,
gs: GameState
): ArmyStats = {
val army = movingArmy.army
val battalions = army.units.flatMap(_.battalionId).map(gs.battalions)
val troopCount = battalions.map(_.size).sum
ArmyStats(
factionId = army.factionId,
heroCount = army.units.size,
troopCount = troopCount
troopCount = troopCount,
hostility = FactionUtils.hostilityStatus(viewerFid, army.factionId, gs.factions.values.toVector),
originProvinceId = Some(movingArmy.originProvinceId)
)
}
@@ -316,6 +316,7 @@ scala_library(
":scala_available_commands_factory",
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
"//src/main/scala/net/eagle0/eagle/library/util:incoming_army_utils",
"//src/main/scala/net/eagle0/eagle/library/util/faction_utils",
"//src/main/scala/net/eagle0/eagle/model/state:army",
"//src/main/scala/net/eagle0/eagle/model/state:round_phase",
"//src/main/scala/net/eagle0/eagle/model/state/command/available",
@@ -499,7 +499,9 @@ object AvailableCommandConverter {
net.eagle0.eagle.api.command.util.army_stats.ArmyStats(
factionId = stats.factionId,
heroCount = stats.heroCount,
troopCount = stats.troopCount
troopCount = stats.troopCount,
hostility = stats.hostility,
originProvinceId = stats.originProvinceId.getOrElse(0)
)
private def expandedCombatUnitToProto(
@@ -1,5 +1,6 @@
package net.eagle0.eagle.model.state.command.available
import net.eagle0.common.hostility.Hostility
import net.eagle0.eagle.{BattalionId, FactionId, HeroId, ProvinceId}
import net.eagle0.eagle.model.state.command.common.*
import net.eagle0.eagle.model.state.diplomacy_offer.status.Status
@@ -199,7 +200,9 @@ object AvailableCommand:
case class ArmyStats(
factionId: FactionId,
heroCount: Int,
troopCount: Int
troopCount: Int,
hostility: Hostility = Hostility.ENEMY_HOSTILITY,
originProvinceId: Option[ProvinceId] = None
)
case class ExpandedCombatUnit(
@@ -18,6 +18,7 @@ scala_library(
"//src/test/scala/net/eagle0/eagle/model/state/command:__subpackages__",
],
deps = [
"//src/main/protobuf/net/eagle0/common:hostility_scala_proto",
"//src/main/scala/net/eagle0/eagle:eagle_pkg",
"//src/main/scala/net/eagle0/eagle/model/state/command/common",
"//src/main/scala/net/eagle0/eagle/model/state/diplomacy_offer/status",