use std::fmt::Display;
use bitflags::Flags;
use crate::block::Block;
use crate::everything::Everything;
use crate::game::Game;
#[cfg(feature = "hoi4")]
use crate::hoi4::tables::modifs::modif_loc_hoi4;
#[cfg(any(feature = "ck3", feature = "vic3", feature = "hoi4"))]
use crate::item::Item;
use crate::report::{err, ErrorKey, Severity};
#[cfg(feature = "jomini")]
use crate::script_value::validate_non_dynamic_script_value;
use crate::token::Token;
use crate::validator::Validator;
#[cfg(feature = "vic3")]
use crate::vic3::tables::modifs::modif_loc_vic3;
pub trait ModifKinds: Display + Flags + Copy {
fn require(self, other: Self, token: &Token) {
if !self.intersects(other) {
let msg = format!("`{token}` is a modifier for {other} but expected {self}");
err(ErrorKey::Modifiers).msg(msg).loc(token).push();
}
}
fn lookup_modif(name: &Token, data: &Everything, warn: Option<Severity>) -> Option<Self>;
}
pub fn validate_modifs<'a, MK: ModifKinds>(
_block: &Block,
data: &'a Everything,
kinds: MK,
mut vd: Validator<'a>,
) {
#[cfg(feature = "hoi4")]
vd.field_validated_block("hidden_modifier", |block, data| {
let mut vd = Validator::new(block, data);
vd.unknown_fields(|key, bv| {
if let Some(mk) = MK::lookup_modif(key, data, Some(Severity::Error)) {
kinds.require(mk, key);
let _ = &bv;
} else {
let msg = format!("unknown modifier `{key}`");
err(ErrorKey::UnknownField).msg(msg).loc(key).push();
}
});
});
#[cfg(feature = "hoi4")]
vd.field_item("custom_modifier_tooltip", Item::Localization);
vd.unknown_fields(|key, bv| {
#[cfg(feature = "hoi4")]
if Game::is_hoi4()
&& (key.is("fort") || key.is("river") || data.item_exists(Item::Terrain, key.as_str()))
{
if let Some(block) = bv.expect_block() {
let mut vd = Validator::new(block, data);
vd.field_numeric("attack");
vd.field_numeric("movement");
vd.field_numeric("defence");
}
return;
}
if let Some(mk) = MK::lookup_modif(key, data, Some(Severity::Error)) {
kinds.require(mk, key);
if Game::is_jomini() {
#[cfg(feature = "jomini")]
validate_non_dynamic_script_value(bv, data);
} else {
let _ = &bv;
}
#[cfg(feature = "ck3")]
if Game::is_ck3()
&& !key.is("health")
&& !key.is("elderly_health")
&& !key.is("child_health")
&& !key.is("negate_health_penalty_add")
{
data.verify_exists(Item::ModifierFormat, key);
}
#[cfg(feature = "vic3")]
if Game::is_vic3() {
let (loca_key, loca_desc_key) = modif_loc_vic3(key, data);
data.verify_exists_implied(Item::Localization, &loca_key, key);
data.verify_exists_implied(Item::Localization, &loca_desc_key, key);
}
#[cfg(feature = "hoi4")]
if Game::is_hoi4() {
let loca_key = modif_loc_hoi4(key, data);
data.verify_exists_implied(Item::Localization, &loca_key, key);
}
}
else if !Game::is_vic3() {
let msg = format!("unknown modifier `{key}`");
err(ErrorKey::UnknownField).msg(msg).loc(key).push();
}
});
}
pub fn verify_modif_exists<MK: ModifKinds>(
key: &Token,
data: &Everything,
kinds: MK,
sev: Severity,
) {
if let Some(mk) = MK::lookup_modif(key, data, Some(sev)) {
kinds.require(mk, key);
}
else if !Game::is_vic3() {
let msg = format!("unknown modifier `{key}`");
err(ErrorKey::UnknownField).msg(msg).loc(key).push();
}
}