use crate::import::{BattleSize, Roster, RosterUnit};
use super::helpers::{displayed_unit_points, title_case_id, total_army_points};
use super::{ExportFormat, RosterSerializer};
fn battle_size_label(roster: &Roster) -> Option<String> {
match roster.battle_size? {
BattleSize::StrikeForce => Some(format!(
"Strike Force ({} Point limit)",
roster.points.declared_limit.unwrap_or(2000)
)),
BattleSize::Incursion => Some(format!(
"Incursion ({} Point limit)",
roster.points.declared_limit.unwrap_or(1000)
)),
}
}
fn wargear_text(u: &RosterUnit, per_model_divisor: u64) -> String {
let mut parts: Vec<String> = Vec::new();
if let Some(enh) = &u.enhancement {
let pts_tag = match u.enhancement_points {
Some(p) => format!(" [{p} pts]"),
None => String::new(),
};
parts.push(format!("{}{pts_tag}", enh.raw_name));
}
if u.is_warlord {
parts.push("Warlord".to_string());
}
for w in &u.wargear {
let c = if per_model_divisor > 0 {
w.count / per_model_divisor
} else {
w.count
};
if c > 1 {
parts.push(format!("{c}x {}", w.ref_.raw_name));
} else {
parts.push(w.ref_.raw_name.clone());
}
}
parts.join(", ")
}
fn unit_text(u: &RosterUnit) -> Vec<String> {
let pts = displayed_unit_points(u);
let pts_text = match pts {
Some(p) => format!("{p} pts"),
None => String::new(),
};
if u.model_count <= 1 {
return vec![format!(
"{} [{pts_text}]: {}",
u.ref_.raw_name,
wargear_text(u, 1)
)];
}
let divisible = u
.wargear
.iter()
.all(|w| u.model_count > 0 && w.count % u.model_count == 0);
if divisible {
return vec![
format!("{} [{pts_text}]:", u.ref_.raw_name),
format!(
"• {}x {}: {}",
u.model_count,
u.ref_.raw_name,
wargear_text(u, u.model_count)
),
];
}
vec![
format!("{} [{pts_text}]:", u.ref_.raw_name),
format!(
"• {}x {}: {}",
u.model_count,
u.ref_.raw_name,
wargear_text(u, 1)
),
]
}
pub struct NewRecruitSimpleSerializer;
impl RosterSerializer for NewRecruitSimpleSerializer {
fn id(&self) -> ExportFormat {
ExportFormat::NewrecruitSimple
}
fn serialize(&self, roster: &Roster) -> String {
let faction =
title_case_id(roster.faction_id.as_deref()).unwrap_or_else(|| "Unknown".to_string());
let detachment = title_case_id(roster.detachment_id.as_deref());
let battle = battle_size_label(roster);
let total = total_army_points(roster);
let limit = roster.points.declared_limit.unwrap_or(total);
let mut lines: Vec<String> = Vec::new();
lines.push(format!("{faction} - {} - [{limit} pts]", roster.name));
lines.push(String::new());
lines.push(format!("# ++ Army Roster ++ [{total} pts]"));
lines.push("## Configuration".to_string());
if let Some(b) = battle {
lines.push(format!("Battle Size: {b}"));
}
if let Some(d) = detachment {
lines.push(format!("Detachment: {d}"));
}
lines.push(String::new());
let section_total: u64 = roster
.units
.iter()
.map(|u| u.points.unwrap_or(0) + u.enhancement_points.unwrap_or(0))
.sum();
lines.push(format!("## Battleline [{section_total} pts]"));
for u in &roster.units {
lines.extend(unit_text(u));
}
let mut out = lines.join("\n");
out.push('\n');
out
}
}