use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum BattleSize {
Incursion,
StrikeForce,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum RosterFormat {
Listforge,
NewrecruitJson,
NewrecruitWtcCompact,
NewrecruitWtcFull,
NewrecruitSimple,
Rosterizer,
Gw,
ListforgeText,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum WarningCode {
FactionUnresolved,
UnitUnresolved,
WeaponUnresolved,
EnhancementUnresolved,
DetachmentUnresolved,
BattleSizeUnmapped,
PointsMismatch,
LeaderAttachmentInferred,
MultiForce,
UnknownField,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Candidate {
pub id: String,
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ResolvedRef {
pub id: Option<String>,
pub raw_name: String,
pub resolved: bool,
pub candidates: Vec<Candidate>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RosterWargear {
#[serde(rename = "ref")]
pub ref_: ResolvedRef,
pub count: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RosterLeaderAttachment {
pub bodyguard_ref: ResolvedRef,
pub provisional: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RosterUnit {
#[serde(rename = "ref")]
pub ref_: ResolvedRef,
pub model_count: u64,
pub points: Option<u64>,
pub is_warlord: bool,
pub enhancement: Option<ResolvedRef>,
pub enhancement_points: Option<u64>,
pub wargear: Vec<RosterWargear>,
pub leader_attachment: Option<RosterLeaderAttachment>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RosterSource {
pub format: RosterFormat,
pub generated_by: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RosterPoints {
pub declared_limit: Option<u64>,
pub total_reported: Option<u64>,
pub total_computed: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Warning {
pub code: WarningCode,
pub message: String,
pub raw_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Diagnostics {
pub resolved_units: u64,
pub unresolved_units: u64,
pub resolved_weapons: u64,
pub unresolved_weapons: u64,
pub warnings: Vec<Warning>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GameVersionRef {
pub edition: String,
pub dataslate: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Roster {
pub name: String,
pub source: RosterSource,
pub faction_id: Option<String>,
pub detachment_id: Option<String>,
pub battle_size: Option<BattleSize>,
pub points: RosterPoints,
pub units: Vec<RosterUnit>,
pub game_version: GameVersionRef,
pub diagnostics: Diagnostics,
}
impl Roster {
pub fn attached_leader_for(&self, bodyguard_unit_id: &str) -> Option<&RosterUnit> {
self.units.iter().find(|u| {
u.leader_attachment
.as_ref()
.and_then(|la| la.bodyguard_ref.id.as_deref())
== Some(bodyguard_unit_id)
})
}
pub fn attachment_partners_for(&self, unit_id: &str) -> Vec<&RosterUnit> {
let mut out: Vec<&RosterUnit> = Vec::new();
for u in &self.units {
if u.leader_attachment
.as_ref()
.and_then(|la| la.bodyguard_ref.id.as_deref())
== Some(unit_id)
&& !out.iter().any(|q| std::ptr::eq(*q, u))
{
out.push(u);
}
if u.ref_.id.as_deref() == Some(unit_id) {
if let Some(la) = u.leader_attachment.as_ref() {
if let Some(bodyguard) = self
.units
.iter()
.find(|b| b.ref_.id.as_deref() == la.bodyguard_ref.id.as_deref())
{
if !out.iter().any(|q| std::ptr::eq(*q, bodyguard)) {
out.push(bodyguard);
}
}
}
}
}
out
}
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ParsedWargear {
pub raw_name: String,
pub count: u64,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ParsedUnit {
pub raw_name: String,
pub is_character: bool,
pub model_count: u64,
pub points: Option<u64>,
pub is_warlord: bool,
pub enhancement_raw_name: Option<String>,
pub enhancement_points: Option<u64>,
pub wargear: Vec<ParsedWargear>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ParsedRoster {
pub name: String,
pub generated_by: Option<String>,
pub faction_raw_name: Option<String>,
pub detachment_raw_name: Option<String>,
pub battle_size_raw: Option<String>,
pub declared_limit: Option<u64>,
pub total_reported: Option<u64>,
pub total_computed: u64,
pub units: Vec<ParsedUnit>,
pub multi_force: bool,
}