tiger_lib/ck3/data/
ai_war_stances.rs

1use crate::block::Block;
2use crate::db::{Db, DbKind};
3use crate::everything::Everything;
4use crate::game::GameFlags;
5use crate::item::{Item, ItemLoader};
6use crate::report::{ErrorKey, err};
7use crate::scopes::Scopes;
8use crate::token::Token;
9use crate::tooltipped::Tooltipped;
10use crate::validator::Validator;
11
12// LAST UPDATED CK3 VERSION 1.11.5
13// Taken from common/ai_war_stances/_ai_war_stances.info
14//
15// TODO: find a way to warn if any of these are missing.
16// The main problem is we have no Loc to attach the warning to.
17const AI_WAR_STANCES: &[&str] = &[
18    "attacker_offensive",
19    "attacker_defensive",
20    "defender_offensive",
21    "defender_defensive",
22    "defender_desperate",
23    "great_holy_war_attacker",
24    "great_holy_war_defender",
25];
26
27// LAST UPDATED CK3 VERSION 1.11.5
28// Taken from common/ai_war_stances/_ai_war_stances.info
29const AI_WAR_OBJECTIVES: &[&str] = &[
30    "wargoal_province",
31    "enemy_unit_province",
32    "enemy_capital_province",
33    "capital_province",
34    "enemy_province",
35    "enemy_ally_province",
36    "province",
37    "defend_wargoal_province",
38];
39
40// LAST UPDATED CK3 VERSION 1.11.5
41// Taken from common/ai_war_stances/_ai_war_stances.info
42const AI_WAR_AREAS: &[&str] = &[
43    "wargoal",
44    "primary_attacker",
45    "primary_attacker_ally",
46    "primary_defender",
47    "primary_defender_ally",
48];
49
50#[derive(Clone, Debug)]
51pub struct AiWarStance {}
52
53inventory::submit! {
54    ItemLoader::Normal(GameFlags::Ck3, Item::AiWarStance, AiWarStance::add)
55}
56
57impl AiWarStance {
58    pub fn add(db: &mut Db, key: Token, block: Block) {
59        db.add(Item::AiWarStance, key, block, Box::new(Self {}));
60    }
61}
62
63impl DbKind for AiWarStance {
64    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
65        let mut vd = Validator::new(block, data);
66
67        if !AI_WAR_STANCES.contains(&key.as_str()) {
68            let msg = format!("unknown war stance `{key}`");
69            err(ErrorKey::Validation).msg(msg).loc(key).push();
70        }
71
72        vd.field_choice("side", &["attacker", "defender"]);
73        vd.field_integer_range("enemy_unit_priority", 1..=1000);
74
75        vd.field_validated_block("behaviour_attributes", |block, data| {
76            let mut vd = Validator::new(block, data);
77            vd.field_bool("stronger");
78            vd.field_bool("weaker");
79            vd.field_bool("desperate");
80        });
81
82        vd.field_trigger_rooted("can_be_picked", Tooltipped::No, Scopes::War);
83        vd.field_script_value_no_breakdown_rooted("ai_will_do", Scopes::War);
84
85        vd.multi_field_validated_block("objectives", |block, data| {
86            let mut vd = Validator::new(block, data);
87            // TODO: "enemy_unit_province areas may not overlap"
88            vd.multi_field_validated_block("enemy_unit_province", |block, data| {
89                let mut vd = Validator::new(block, data);
90                vd.field_integer_range("priority", 1..=1000);
91                vd.multi_field_choice("area", AI_WAR_AREAS);
92            });
93            for &objective in AI_WAR_OBJECTIVES {
94                if objective != "enemy_unit_province" {
95                    vd.field_integer_range(objective, 1..=1000);
96                }
97            }
98        });
99    }
100}