tiger_lib/vic3/data/
themes.rs1use std::path::PathBuf;
2
3use crate::block::Block;
4use crate::context::ScopeContext;
5use crate::db::{Db, DbKind};
6use crate::everything::Everything;
7use crate::game::GameFlags;
8use crate::item::{Item, ItemLoader, LoadAsFile, Recursive};
9use crate::pdxfile::PdxEncoding;
10use crate::report::{ErrorKey, warn};
11use crate::scopes::Scopes;
12use crate::token::Token;
13use crate::tooltipped::Tooltipped;
14use crate::validator::Validator;
15
16#[derive(Clone, Debug)]
17pub struct Theme {}
18
19inventory::submit! {
20 ItemLoader::Normal(GameFlags::Vic3, Item::Theme, Theme::add)
21}
22
23impl Theme {
24 pub fn add(db: &mut Db, key: Token, block: Block) {
25 db.add(Item::Theme, key, block, Box::new(Self {}));
26 }
27}
28
29impl DbKind for Theme {
30 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
31 let mut vd = Validator::new(block, data);
32
33 data.verify_exists(Item::Localization, key);
34 let loca = format!("{key}_desc");
35 data.verify_exists_implied(Item::Localization, &loca, key);
36
37 vd.req_field("category");
38 vd.field_choice("category", THEME_CATEGORIES);
39 if let Some(category) = block.get_field_value("category") {
40 data.verify_exists(Item::Localization, category);
41 let loca = format!("{category}_desc");
42 data.verify_exists_implied(Item::Localization, &loca, category);
43
44 vd.advice_field(
45 "map_textures",
46 "docs say map_textures, but it's papermap_textures_file",
47 );
48 if category.is("papermap_theme") {
49 vd.field_item("papermap_textures_file", Item::File);
50 } else {
51 vd.ban_field("papermap_textures_file", || "category papermap_theme");
52 }
53 }
54
55 vd.field_trigger_rooted("selectable", Tooltipped::No, Scopes::None);
56
57 vd.advice_field("skin", "docs say skin, but it's ui_skin");
58 vd.field_validated_value("ui_skin", |_, mut vd| {
59 vd.maybe_is("default");
60 vd.item(Item::Skin);
61 });
62
63 vd.advice_field("theme_object", "docs say theme_object, but it's map_object");
64 vd.multi_field_validated_block("map_object", |block, data| {
65 let mut vd = Validator::new(block, data);
66 vd.req_field_one_of(&["pdxmesh", "entity"]);
67 vd.field_item("pdxmesh", Item::Pdxmesh);
68 vd.field_item("entity", Item::Entity);
69 vd.req_field("locator");
70 vd.field_value("locator"); });
72
73 vd.field_item("dlc", Item::Dlc);
74 vd.field_value("bulk_selection_group");
75 let mut sc = ScopeContext::new(Scopes::Country, key);
76 vd.field_script_value_no_breakdown("dynamic_weight", &mut sc);
77
78 vd.field_item("video", Item::File);
82 }
83}
84
85#[derive(Clone, Debug)]
86pub struct Skin {}
87
88inventory::submit! {
89 ItemLoader::Full(GameFlags::Vic3, Item::Skin, PdxEncoding::Utf8Bom, ".skin", LoadAsFile::Yes, Recursive::No, Skin::add)
90}
91
92impl Skin {
93 pub fn add(db: &mut Db, key: Token, block: Block) {
94 if let Some(name) = block.get_field_value("name") {
95 db.add(Item::Skin, name.clone(), block, Box::new(Self {}));
96 } else {
97 let msg = "skin file with no name field";
98 warn(ErrorKey::FieldMissing).msg(msg).loc(key).push();
99 }
100 }
101}
102
103impl DbKind for Skin {
104 fn validate(&self, _key: &Token, block: &Block, data: &Everything) {
105 let mut vd = Validator::new(block, data);
106
107 vd.field_value("name");
108 vd.field_item("folder", Item::Directory);
109
110 if let Some(folder) = block.get_field_value("folder") {
111 for entry in data.fileset.get_files_under(&PathBuf::from(folder.as_str())) {
112 let path = entry.path().to_string_lossy();
113 let base_path = format!("gfx/interface{}", &path[folder.as_str().len()..]);
115 if !data.item_exists(Item::File, &base_path) {
116 let msg = format!("file {base_path} does not exist");
117 let info = "every skin file must override an existing interface file";
118 warn(ErrorKey::ExtraFile).msg(msg).info(info).loc(entry).push();
119 }
120 }
121 }
122 }
123}
124
125const THEME_CATEGORIES: &[&str] = &[
126 "ui_skin_theme",
127 "papermap_theme",
128 "table_top_theme",
129 "table_asset_1_theme",
130 "table_asset_2_theme",
131 "table_asset_3_theme",
132 "table_asset_4_theme",
133 "table_asset_cloth_theme",
134 "building_sets_themes",
135 "main_menu_image_theme",
137];