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
251
252
253
254
use df_ls_core::{Reference, ReferenceTo};
use df_ls_diagnostics::DiagnosticsInfo;
use df_ls_syntax_analysis::{Token, TokenDeserialize, TryFromArgumentGroup};
use serde::{Deserialize, Serialize};
use crate::BodyToken;
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum BodyPartTypeEnum {
/// Marks the body part as an opening in the body. If it is `[EMBEDDED]`, it cannot be gouged.
#[token_de(token = "APERTURE")]
Aperture,
/// Body part is used to breathe. If all body parts with `[BREATHE]` are damaged or destroyed,
/// the creature will suffocate unless it has the `[NOBREATHE]` tag. Note that bruising counts
/// as (fast-healing) damage.
#[token_de(token = "BREATHE")]
Breathe,
/// Body part is responsible for blood circulation. Exact effects not known.
#[token_de(token = "CIRCULATION")]
Circulation,
/// Body part is used to connect other body parts together. Used for the neck and lower spine.
#[token_de(token = "CONNECTOR")]
Connector,
/// Defines part as a digit. Body parts that are digits, or have them as direct sub-parts, can
/// perform gouging attacks within a wrestling hold.
#[token_de(token = "DIGIT")]
Digit,
/// Body part with this tag is embedded on the surface of parent body part. i.e.: eyes and mouth
/// on head. It cannot be chopped off, can't be used to wrestle enemies and can't be grabbed by
/// them.
#[token_de(token = "EMBEDDED")]
Embedded,
/// Flags the body part as being needed for flight. Damage to a certain number of `FLIER` body
/// parts will prevent the creature from flying.
///
/// Note that a creature can only fly if the creature has the `[FLIER]` tag in its creature
/// definition, and that a flying creature does not actually need any `FLIER` body parts.
/// This tag's only purpose is to identify body parts which will cause a creature to lose the
/// ability to fly when damaged.
#[token_de(token = "FLIER")]
Flier,
/// Creature can wield a picked-up weapon with the body part, and can use the part to initiate
/// almost all wrestling moves.
///
/// When creatures are spawned with a weapon and shield, one `GRASP` part will hold a weapon
/// while all others will hold shields.
///
/// A grasp-able bodypart is needed for Grasp-attacks, which are in turn needed to start a fist
/// fight. Creatures throwing a tantrum, but missing a bodypart with the grasp-property, will
/// be cancelling their fist fight, due to being 'too injured'.
#[token_de(token = "GRASP")]
Grasp,
/// Body part is susceptible to low blows. Used for guts. Damage to this body part causes nausea
/// and may make the creature lose turns, vomiting uncontrollably.
#[token_de(token = "GUTS")]
Guts,
/// Flags the body part as being able to wear head clothing like hats, helms, etc. If all heads
/// are chopped off, the creature dies. Multiple heads are redundant - for example, hydras can
/// survive with several missing heads.
#[token_de(token = "HEAD")]
Head,
/// Body part is used to hear. May be a requirement for the body part to wear earrings.
#[token_de(token = "HEAR")]
Hear,
/// Marks the body part as being inside the body. It is behind all the other tissues of the body
/// part, cannot be severed, nor used for wrestling. It cannot be targeted directly in combat,
/// but can be damaged by attacks to the parent body part.
#[token_de(token = "INTERNAL")]
Internal,
/// Body part is a joint. If the limb it's in is grabbed in a wrestling hold, it can be broken
/// with bending force, disabling the parent limb. If the joint is modded to sit outside the
/// body, grabbing and breaking it snaps the entire limb right off.
#[token_de(token = "JOINT")]
Joint,
/// Marks body part as on the left side of the body and vulnerable to attacks from the left.
/// Used in conjunction with tags in the `b_detail_plan_default` raw.
#[token_de(token = "LEFT")]
Left,
/// Body part is a limb. It can be used to initiate most wrestling moves.
///
/// If it is located between an `[UPPERBODY]` part and a `[GRASP]` body part, it is eligible to
/// be covered by certain types of armor (body armors and gauntlets).
///
/// If it is located between a `[LOWERBODY]` part and a `[STANCE]` body part, it is eligible to
/// be covered by other types of armor (Leg armors like pants, etc.; trailing body armors like
/// mail shirts and robes; and high boots).
#[token_de(token = "LIMB")]
Limb,
/// Flags the body part as being able to wear lower body clothing like skirts, pants, etc.
///
/// If all parts with this token are chopped off or pulped, the creature dies. If the creature
/// has multiple parts with this token, they will not die until all parts with this token have
/// been pulped or severed. No such creature exists in the base game, however.
#[token_de(token = "LOWERBODY")]
Lowerbody,
/// Body part is a mouth. Implication unknown.
#[token_de(token = "MOUTH")]
Mouth,
/// Body part is the hub of nervous function. Used for the parts of the spine. Damage disables
/// everything in the parent bodypart and what's below it, causing death by suffocation in most
/// cases.
#[token_de(token = "NERVOUS")]
Nervous,
/// Marks body part as on the right side of the body and vulnerable to attacks from the right.
/// Used in conjunction with tags in the `b_detail_plan_default` raw.
#[token_de(token = "RIGHT")]
Right,
/// Body part is used to see with. If the creature has no `SIGHT` body parts, or if all its
/// sight body parts are damaged or destroyed, it can't see unless it has the `[EXTRAVISION]`
/// tag in its creature definition.
#[token_de(token = "SIGHT")]
Sight,
/// Body part is part of the creature's skeleton.
#[token_de(token = "SKELETON")]
Skeleton,
/// "`SMALL` means that the part isn't displayed as part of the overall displayed body part lists.
/// They can't be splinted. They are more often targeted for torture (although those situations
/// might not occur anymore). They are removed in skeletons if they aren't specifically
/// skeletons/joints/digits/apertures. They are more easily lost in world gen duels. They are
/// the only gougable/pinchable parts (note: at least this is no longer the case.). `SMALL` is
/// an old tag, so it has accumulated some weird functions which'll get split off over time. "
///
/// --Toady
#[token_de(token = "SMALL")]
Small,
/// Body part is used to smell. No known function. (could possibly control reactions to miasma
/// in fortress mode?)
#[token_de(token = "SMELL")]
Smell,
/// Body part breaks off and goes flying if broken, even with blunt force. Used on teeth to make
/// them easy to knock out. Rendered invalid by `[INTERNAL]`.
#[token_de(token = "SOCKET")]
Socket,
/// Allows the creature to stand. Damage or loss of these body parts will cause creature to fall
/// over. Loss of one `STANCE` part can be substituted with a crutch. Does not give the body
/// part an ability to initiate wrestling moves, unlike `[GRASP]` or `[LIMB]`.
#[token_de(token = "STANCE")]
Stance,
/// The central core of the body. Used with the brain. Damage causes instant death unless the
/// creature has `[NO_THOUGHT_CENTER_FOR_MOVEMENT]`/`[NOTHOUGHT]`.
#[token_de(token = "THOUGHT")]
Thought,
/// Body part can be strangled. Latching bites that hit the head have a chance to target this
/// instead. Note: this tag doesn't control any bleeding behavior.
#[token_de(token = "THROAT")]
Throat,
/// This bodypart can be turned into a totem by craftsmen. Always drops from slaughtered
/// creatures, no matter how small.
#[token_de(token = "TOTEMABLE")]
Totemable,
/// Makes the body part pop out of the body when cut through. Used on guts. Body part shows up
/// as "~" and drags behind the victim when spilled.
#[token_de(token = "UNDER_PRESSURE")]
UnderPressure,
/// Flags the body part as being able to wear upper body clothing like coats, breastplates etc.
///
/// If all parts with this token are pulped or chopped off, the creature dies. Multiple
/// `UPPERBODY` parts are redundant, but no such creatures exist in the base game.
/// All default creatures with bodies have the upper body as the root of the body tree, making
/// it impossible to chop off.
#[token_de(token = "UPPERBODY")]
Upperbody,
/// Allows the item to be obtained from butchered or rotted vermin. Used with shells.
#[token_de(token = "VERMIN_BUTCHER_ITEM")]
VerminButcherItem,
/// Creatures with a body part containing this token may be gelded, which prevents them
/// reproducing. Gelding may also occur during combat if this body part is damaged sufficiently.
#[token_de(token = "GELDABLE")]
Geldable,
}
impl Default for BodyPartTypeEnum {
fn default() -> Self {
Self::Aperture
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum BpCriteriaTokenArg {
/// Select body parts by their `CATEGORY`, as defined in a `[CATEGORY:...]` body token.
ByCategory(Reference), // TODO: ref is a CATEGORY from inside BodyToken
/// Select body parts by their type (for example, `GRASP`, or `BREATHE`).
///
/// Most tokens applied to a given body part count as "types".
ByType(BodyPartTypeEnum),
/// Select specific body parts by their token ID/reference.
ByToken(ReferenceTo<BodyToken>),
}
impl Default for BpCriteriaTokenArg {
fn default() -> Self {
Self::ByCategory(Reference::default())
}
}
// Deserialize a token with following pattern: `[REF:bp_criteria_token_args:...]`
df_ls_syntax_analysis::token_deserialize_unary_token!(BpCriteriaTokenArg);
impl TryFromArgumentGroup for BpCriteriaTokenArg {
fn try_from_argument_group(
token: &mut Token,
source: &str,
diagnostics: &mut DiagnosticsInfo,
add_diagnostics_on_err: bool,
) -> Result<Self, ()> {
// Safe first argument (is not token_name) for error case
let arg0 = match token.get_current_arg() {
Ok(arg) => Ok(arg.clone()),
Err(err) => Err(err),
};
let reference_arg0 =
Reference::try_from_argument_group(token, source, diagnostics, add_diagnostics_on_err)?;
let bp_criteria = match reference_arg0.0.as_ref() {
"BY_CATEGORY" => {
// Arg 1
let by_category = Reference::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
BpCriteriaTokenArg::ByCategory(by_category)
}
"BY_TYPE" => {
let by_type = BodyPartTypeEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
BpCriteriaTokenArg::ByType(by_type)
}
"BY_TOKEN" => {
let by_token = ReferenceTo::<BodyToken>::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
BpCriteriaTokenArg::ByToken(by_token)
}
_ => {
Self::diagnostics_wrong_enum_type(
&arg0?,
vec!["BY_CATEGORY", "BY_TYPE", "BY_TOKEN"],
source,
diagnostics,
add_diagnostics_on_err,
);
return Err(());
}
};
Ok(bp_criteria)
}
}