tiger_lib/ck3/data/
wars.rs1use std::path::PathBuf;
2
3use crate::block::Block;
4use crate::everything::Everything;
5use crate::fileset::{FileEntry, FileHandler};
6use crate::item::Item;
7use crate::parse::ParserMemory;
8use crate::pdxfile::PdxFile;
9use crate::report::{ErrorKey, err, warn};
10use crate::token::Token;
11use crate::validator::Validator;
12
13#[derive(Clone, Debug, Default)]
14pub struct Wars {
15 wars: Vec<War>,
16}
17
18impl Wars {
19 fn load_item(&mut self, key: Token, block: Block) {
20 if key.is("war") {
21 self.wars.push(War::new(block));
22 } else {
23 let msg = format!("unexpected key {key}, expected only `war`");
24 err(ErrorKey::History).msg(msg).loc(key).push();
25 }
26 }
27
28 pub fn validate(&self, data: &Everything) {
29 for item in &self.wars {
30 item.validate(data);
31 }
32 }
33}
34
35impl FileHandler<Block> for Wars {
36 fn subpath(&self) -> PathBuf {
37 PathBuf::from("history/wars")
38 }
39
40 fn load_file(&self, entry: &FileEntry, parser: &ParserMemory) -> Option<Block> {
41 if !entry.filename().to_string_lossy().ends_with(".txt") {
42 return None;
43 }
44
45 PdxFile::read_optional_bom(entry, parser)
46 }
47
48 fn handle_file(&mut self, _entry: &FileEntry, mut block: Block) {
49 for (key, block) in block.drain_definitions_warn() {
50 self.load_item(key, block);
51 }
52 }
53}
54
55#[derive(Clone, Debug)]
56pub struct War {
57 block: Block,
58}
59
60impl War {
61 pub fn new(block: Block) -> Self {
62 Self { block }
63 }
64
65 fn validate(&self, data: &Everything) {
66 let mut vd = Validator::new(&self.block, data);
67
68 vd.req_field("start_date");
71 vd.req_field("end_date");
72 vd.req_field("casus_belli");
73 vd.req_field("attackers");
74 vd.req_field("defenders");
75
76 vd.field_item("name", Item::Localization);
77
78 let mut start_date_token = None;
79 let mut end_date_token = None;
80 vd.field_validated_value("start_date", |_, mut vd| {
81 vd.date();
82 start_date_token = Some(vd.value().clone());
83 });
84 vd.field_validated_value("end_date", |_, mut vd| {
85 vd.date();
86 end_date_token = Some(vd.value().clone());
87 });
88
89 if let Some(start_date) = start_date_token.as_ref().and_then(Token::get_date) {
90 if let Some(end_date) = end_date_token.as_ref().and_then(Token::get_date) {
91 if start_date > end_date {
92 err(ErrorKey::Range)
93 .msg("start date is after end date")
94 .loc_msg(start_date_token.as_ref().unwrap(), "start date")
95 .loc_msg(end_date_token.as_ref().unwrap(), "end date")
96 .push();
97 }
98 }
99 }
100
101 vd.field_list_items("targeted_titles", Item::Title);
102 vd.field_item("casus_belli", Item::CasusBelli);
103 vd.field_list_items("attackers", Item::Character);
104 vd.field_list_items("defenders", Item::Character);
105 vd.field_item("claimant", Item::Character);
106
107 vd.unknown_block_fields(|key, block| {
108 if data.item_exists(Item::Character, key.as_str()) {
109 let mut vd = Validator::new(block, data);
110 vd.validate_history_blocks(|date, key, block, data| {
111 if let Some(start_date) = start_date_token.as_ref().and_then(Token::get_date) {
112 if date < start_date {
113 err(ErrorKey::Range)
114 .msg("date is before start date")
115 .loc(key)
116 .loc_msg(start_date_token.as_ref().unwrap(), "start date")
117 .push();
118 }
119 }
120 if let Some(end_date) = end_date_token.as_ref().and_then(Token::get_date) {
121 if date > end_date {
122 err(ErrorKey::Range)
123 .msg("date is after end date")
124 .loc(key)
125 .loc_msg(end_date_token.as_ref().unwrap(), "end date")
126 .push();
127 }
128 }
129 let mut vd = Validator::new(block, data);
130 vd.req_field("location");
131 vd.field_item("location", Item::Province);
132 });
133 } else {
134 let msg = format!("character id {key} not found in history");
135 warn(ErrorKey::MissingItem).msg(msg).loc(key).push();
136 }
137 });
138 }
139}