1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
use crate::{ItemReferenceArg, KeyBindEnum, LaborEnum, MaterialTokenArgWithNoneNone};
use df_ls_core::{Choose, Clamp, DFChar, Reference, ReferenceTo, Referenceable};
use df_ls_syntax_analysis::TokenDeserialize;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq, Referenceable)]
pub enum BuildingToken {
#[token_de(token = "BUILDING_WORKSHOP")]
Workshop(BuildingGeneralToken),
#[token_de(token = "BUILDING_FURNACE")]
Furnace(BuildingGeneralToken),
}
impl Default for BuildingToken {
fn default() -> Self {
Self::Workshop(BuildingGeneralToken::default())
}
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct BuildingGeneralToken {
/// Argument 1 of `[BUILDING_WORKSHOP:...]` or `[BUILDING_FURNACE:...]`
#[token_de(
token = "BUILDING_WORKSHOP",
alias = "BUILDING_FURNACE", // TODO should not give alias warning
on_duplicate_to_parent,
primary_token
)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// The name of the custom building.
#[token_de(token = "NAME")]
pub name: Option<String>,
/// The color of the building's name when querying it.
/// Seemingly ignored for furnaces, which are hardcoded to 4:0:1.
///
/// Arguments: `[NAME_COLOR:fg:bg:bright]`
#[token_de(token = "NAME_COLOR")]
pub name_color: Option<(u8, u8, u8)>,
/// The size of the custom building, in number of tiles.
///
/// Arguments: `[DIM:width:height]`
/// Defaults to 3x3.
/// Maximum possible size is 31x31.
#[token_de(token = "DIM")]
pub dim: Option<(Clamp<u8, 0, 31>, Clamp<u8, 0, 31>)>,
/// The tile (1:1 for upper-left) in which dwarves will stand when they are performing tasks.
///
/// Arguments: `[WORK_LOCATION:x:y]`
/// Defaults to 3:3 (bottom-right).
#[token_de(token = "WORK_LOCATION")]
pub work_location: Option<(Clamp<u8, 1, 31>, Clamp<u8, 1, 31>)>,
/// The labor required to construct the custom building.
/// If multiple `BUILD_LABOR` tokens are specified, then any of the indicated labors can
/// be used to construct the building; if none are specified, then no labors are required.
/// For furnaces, this labor does not come into play until after the
/// workshop has been designed by an architect.
#[token_de(token = "BUILD_LABOR")]
pub build_labor: Vec<LaborEnum>,
/// The shortcut key used in the Build menu for selecting the custom building.
#[token_de(token = "BUILD_KEY")]
pub build_key: Option<KeyBindEnum>,
/// Specifies whether or not each workshop tile blocks movement.
/// The first parameter is the row (1 = top), and each subsequent parameter
/// is a 0 (nonblocking) or 1 (blocking) for each column, left to right.
///
/// Arguments: `[BLOCK:row_nr:blocking_args]`
#[token_de(token = "BLOCK")]
pub block: Vec<(u8, bool, Vec<bool>)>,
/// Specifies the characters used to represent the custom building.
/// The first parameter is the building stage, varying from 0 (awaiting construction)
/// to N (completed) where N is between 1 and 3, the 2nd parameter is the row number,
/// and each subsequent parameter is a character number
/// (or literal character enclosed in 'quotes').
///
/// Arguments: `[TILE:building_stage:row_nr:df_chars]`
#[token_de(token = "TILE")]
pub tile: Vec<(
Clamp<u8, 0, 3>, // Building stage
u8, // Row number
DFChar, // Building characters (at least 1 required)
Vec<DFChar>, // Building characters
)>,
/// Specifies the colors in which the custom building's tiles will be displayed.
/// The first parameter is the building stage, the 2nd parameter is the row number,
/// and subsequent parameters are either sets of 3 numbers (`foreground:background:brightness`)
/// or the token `MAT` to use the color of the primary building material.
/// `MAT` may not be available on `BUILDING_FURNACE`s.
///
/// Arguments: `[COLOR:building_stage:row_nr:colors]`
#[token_de(token = "COLOR")]
pub color: Vec<(
Clamp<u8, 0, 3>, // Building stage
u8, // Row number
Choose<MatEnum, (u8, u8, u8)>, // Building color (at least 1 required)
Vec<Choose<MatEnum, (u8, u8, u8)>>, // Building color
)>,
/// Specifies one of the objects necessary to construct the custom building.
/// Each `BUILD_ITEM` can be followed by zero or more modifiers.
///
/// Arguments: `[BUILD_ITEM:quantity:item_token:material_token]`
#[token_de(token = "BUILD_ITEM")]
pub build_item: Vec<BuildItemToken>,
/// Specifies that one of the building's tiles (other than the `WORK_LOCATION`)
/// must be hanging over magma in order for the building to function.
/// Buildings with this token also ignore the `[FUEL]` token in their reactions.
#[token_de(token = "NEEDS_MAGMA")]
pub needs_magma: Option<()>,
}
#[derive(Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq)]
pub struct BuildItemToken {
/// Argument 1 of `[BUILD_ITEM:...]`
#[token_de(token = "BUILD_ITEM", on_duplicate_to_parent, primary_token)]
pub build_item: Option<(
u32, // quantity
ItemReferenceArg, // Item token
MaterialTokenArgWithNoneNone, // Material token
)>,
//-------------------------------------------------------------
// All tokens below are similar or the same as `ReagentToken`.
//-------------------------------------------------------------
/// Item material must have the `[BONE]` token.
#[token_de(token = "ANY_BONE_MATERIAL")]
pub any_bone_material: Option<()>,
/// Item material must have the `[HORN]` token.
#[token_de(token = "ANY_HORN_MATERIAL")]
pub any_horn_material: Option<()>,
/// Item material must have the `[LEATHER]` token.
#[token_de(token = "ANY_LEATHER_MATERIAL")]
pub any_leather_material: Option<()>,
/// Item material must have the `[PEARL]` token.
#[token_de(token = "ANY_PEARL_MATERIAL")]
pub any_pearl_material: Option<()>,
/// Item material must be subordinate to a `PLANT` object.
#[token_de(token = "ANY_PLANT_MATERIAL")]
pub any_plant_material: Option<()>,
/// Item material must have the `[SHELL]` token.
#[token_de(token = "ANY_SHELL_MATERIAL")]
pub any_shell_material: Option<()>,
/// Item material must have the `[SILK]` token.
#[token_de(token = "ANY_SILK_MATERIAL")]
pub any_silk_material: Option<()>,
/// Item material must have the `[SOAP]` token.
#[token_de(token = "ANY_SOAP_MATERIAL")]
pub any_soap_material: Option<()>,
/// Item is made of a tissue having `[TISSUE_SHAPE:STRANDS]`,
/// intended for matching hair and wool.
/// Must be used with `[USE_BODY_COMPONENT]`.
#[token_de(token = "ANY_STRAND_TISSUE")]
pub any_strand_tissue: Option<()>,
/// Item material must have the `[TOOTH]` token.
#[token_de(token = "ANY_TOOTH_MATERIAL")]
pub any_tooth_material: Option<()>,
/// Item material must have the `[YARN]` token.
#[token_de(token = "ANY_YARN_MATERIAL")]
pub any_yarn_material: Option<()>,
/// Item has to be a bag. Intended to be used with an item type of `BOX`,
/// to prevent chests, coffers, and other containers from being used instead.
#[token_de(token = "BAG")]
pub bag: Option<()>,
/// Item is able to be used to build structures (Stone, Wood, Blocks, Bars?).
#[token_de(token = "BUILDMAT")]
pub build_material: Option<()>,
/// Item can be an Artifact.
#[token_de(token = "CAN_USE_ARTIFACT")]
pub can_use_artifact: Option<()>,
/// Item must be a `BARREL` or `TOOL` which contains at least one item of
/// type `LIQUID_MISC` made of `LYE`.
#[token_de(token = "CONTAINS_LYE", alias = "POTASHABLE")]
pub contains_lye: Option<Reference>,
/// If the item is a container, it must be empty.
#[token_de(token = "EMPTY")]
pub empty: Option<()>,
/// Item material must be considered fire-safe (stable temperature below 11000 °U ).
/// Only works with items of type `BAR`, `BLOCKS`, `BOULDER`, `WOOD`, and `ANVIL` -
/// all others are considered unsafe.
#[token_de(token = "FIRE_BUILD_SAFE")]
pub fire_build_safe: Option<()>,
/// Item material has `[IS_GLASS]`. All 3 types of glass have this token hardcoded.
#[token_de(token = "GLASS_MATERIAL")]
pub glass_material: Option<()>,
/// Similar to `REACTION_CLASS`, but requires the reagents material to have a matching
/// `MATERIAL_REACTION_PRODUCT` entry. Intended for reactions which transform one class of
/// material into another, such as skin->leather and fat->tallow.
#[token_de(token = "HAS_MATERIAL_REACTION_PRODUCT")]
pub has_material_reaction_product: Option<Reference>, // TODO See REACTION_CLASS in MaterialDefinitionToken
/// Item must be a tool with the specific `TOOL_USE` value.
/// The item type must be `TOOL:NONE` for this to make any sense.
pub has_tool_use: Option<Reference>, // TODO reference to Item ToolToken (must have `TOOL_USE`)
/// Item material must be considered fire-safe (stable temperature below 12000 °U ).
/// Only works with items of type `BAR`, `BLOCKS`, `BOULDER`, `WOOD`, and `ANVIL` -
/// all others are considered unsafe.
#[token_de(token = "MAGMA_BUILD_SAFE")]
pub magma_build_safe: Option<()>,
/// Item material must be an ore of the specified metal.
#[token_de(token = "METAL_ORE")]
pub metal_ore: Option<Reference>, // TODO reference to Inorganic material
/// Item's item dimension must be at least this large. The reagent's item type must be
/// `BAR`, `POWDER_MISC`, `LIQUID_MISC`, `DRINK`, `THREAD`, `CLOTH`, or `GLOB` for this to work.
#[token_de(token = "MIN_DIMENSION")]
pub min_dimension: Option<u32>,
/// Item must not have an edge, so must be blunt.
/// Sharp stones (produced using knapping) and most types of weapon/ammo
/// can not be used with this token.
#[token_de(token = "NO_EDGE_ALLOWED")]
pub no_edge_allowed: Option<()>,
/// If the item is a container, it must not contain lye or milk.
/// Not necessary if specifying `[EMPTY]`.
#[token_de(token = "NOT_CONTAIN_BARREL_ITEM")]
pub not_contain_barrel_item: Option<()>,
/// Item can not be engraved. For example, a memorial slab can not be engraved.
#[token_de(token = "NOT_ENGRAVED")]
pub not_engraved: Option<()>,
/// Item must be "collected" - used with `THREAD:NONE` to exclude webs.
#[token_de(token = "NOT_WEB")]
pub not_web: Option<()>,
/// Requires the reagents material to have a matching `REACTION_CLASS` entry.
/// Intended for reactions which accept a variety of materials but where the input material
/// does not determine the output material, such as `FLUX` (for making pig iron and steel)
/// and `GYPSUM` (for producing plaster powder).
#[token_de(token = "REACTION_CLASS")]
pub reaction_class: Option<Reference>, // TODO reference to Reaction token
/// Item must not be rotten, mainly for organic materials.
#[token_de(token = "UNROTTEN")]
pub unrotten: Option<()>,
/// Item material must come off a creature's body (`CORPSE` or `CORPSEPIECE`).
#[token_de(token = "USE_BODY_COMPONENT")]
pub use_body_component: Option<()>,
/// Item must be "undisturbed" - used with `THREAD:NONE` to gather webs.
#[token_de(token = "WEB_ONLY")]
pub web_only: Option<()>,
/// Item is made of an non-economic stone.
#[token_de(token = "WORTHLESS_STONE_ONLY")]
pub worthless_stone_only: Option<()>,
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum MatEnum {
#[token_de(token = "MAT")]
Mat,
}
impl Default for MatEnum {
fn default() -> Self {
Self::Mat
}
}