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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
use df_ls_core::{Choose, Clamp, Reference, ReferenceTo};
use df_ls_syntax_analysis::TokenDeserialize;
use serde::{Deserialize, Serialize};
use crate::CreatureToken;
use crate::{AllEnum, MaleOrFemaleEnum, WeaponSkillEnum};
/// Defines a leader/noble position for a civilization. These replace previous tags such as
/// `[MAYOR]` and `[CAN_HAVE_SITE_LEADER]` and so on.
#[derive(Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq)]
pub struct EntityPosition {
/// argument 1 of `POSITION`
#[token_de(token = "POSITION", on_duplicate_to_parent, primary_token)]
pub reference: Option<Reference>,
/// A list of responsibilties this position has.
#[token_de(token = "RESPONSIBILITY")]
pub responsibility: Vec<Responsibility>,
/// The position holder is not subjected to the economy. Less than relevant right now.
#[token_de(token = "ACCOUNT_EXEMPT")]
pub account_exempt: Option<()>,
/// Only creatures with the specified class token can be appointed to this position.
#[token_de(token = "ALLOWED_CLASS")]
pub allowed_class: Option<Reference>, // TODO: ref is creature class
/// Restricts the position to only the defined caste. Only works with a caste of the entity's
/// current race. (If the entity had multiple `CREATURE` tokens)
#[token_de(token = "ALLOWED_CREATURE")]
pub allowed_creature: Vec<(ReferenceTo<CreatureToken>, Option<Reference>)>, // TODO ref is caste
/// This position can only be chosen for the task from the nobles screen, and is available only
/// if there is an *argument* present. For example, the `GENERAL` is `[APPOINTED_BY:MONARCH]`.
/// Contrast `[ELECTED]`. Being appointed by a `MONARCH` seems to handle a lot of worldgen
/// stuff, and interferes with fort mode titles.
#[token_de(token = "APPOINTED_BY")]
pub appointed_by: Vec<Reference>, // TODO: ref here is EntityPosition
/// A creature that kills a member of this position will be sure to talk about it a lot.
#[token_de(token = "BRAG_ON_KILL")]
pub brag_on_kill: Option<()>,
/// In adventure mode, when referencing locations, an `NPC` may mention this position holder
/// living there or having done some deed there, it also means that the position exists in
/// world-gen, rather than being created only at the end of world-gen.
///
/// Dark Fortress civs cannot have this tag on anybody but their Law Maker, or the game will
/// crash without leaving an errorlog.
#[token_de(token = "CHAT_WORTHY")]
pub chat_worthy: Option<()>,
/// Creatures of this position will have this color, instead of their profession color, e.g.
/// `[COLOR:5:0:1]`.
#[token_de(token = "COLOR")]
pub color: Option<(u8, u8, u8)>,
/// This position will act as a commander of the specified position (presumably).
/// E.g. `GENERAL` is `[COMMANDER:LIEUTENANT:ALL]`. Unknown if values other than `ALL` work.
#[token_de(token = "COMMANDER")]
pub commander: Option<(Reference, AllEnum)>, // TODO: ref here is an EntityPosition
/// This position is a puppet ruler left behind in a conquered site.
#[token_de(token = "CONQUERED_SITE")]
pub conquered_site: Option<()>,
/// How many demands the position can make of the population at one time.
#[token_de(token = "DEMAND_MAX")]
pub demand_max: Option<Clamp<u8, 0, 100>>,
/// The site's (or civ's) minted coins, if any, will have images that reflect the personality of
/// this position holder.
#[token_de(token = "DETERMINES_COIN_DESIGN")]
pub determines_coin_design: Option<()>,
/// The position won't be culled from Legends as "unimportant" during world generation.
#[token_de(token = "DO_NOT_CULL")]
pub do_not_cull: Option<()>,
/// Members of this position will never agree to 'join' your character during adventure mode.
#[token_de(token = "DUTY_BOUND")]
pub duty_bound: Option<()>,
/// The population will periodically select the most skill-eligible creature to fill this
/// position. Contrast `[APPOINTED_BY]`.
#[token_de(token = "ELECTED")]
pub elected: Option<()>,
/// The various members who have filled this role will be listed in the civilisation's history.
#[token_de(token = "EXPORTED_IN_LEGENDS")]
pub exported_in_legends: Option<()>,
/// The creature holding this position will visibly flash, like legendary citizens. Represents a
/// properly noble station by default.
#[token_de(token = "FLASHES")]
pub flashes: Option<()>,
/// The position can only be held by the specified gender. Currently bugged:
/// [Bug:2714](https://www.bay12games.com/dwarves/mantisbt/view.php?id=2714).
#[token_de(token = "GENDER")]
pub gender: Option<MaleOrFemaleEnum>,
/// The position can assign quests to adventurers.
#[token_de(token = "KILL_QUEST")]
pub kill_quest: Option<()>,
/// This is an alternative to `SITE`. What it does is allow positions to be created at civ-level
/// 'as needed' for all sites that meet the requirements to have them, which are the values set
/// in `LAND_HOLDER_TRIGGER`. The character is tied permanently to a particular site but also
/// operates at the civ-level.
#[token_de(token = "LAND_HOLDER")]
pub land_holder: Option<Clamp<u8, 1, 3>>,
/// The name the area takes on when under the control of a `LAND_HOLDER`. E.g. for the `DUKE`,
/// `[LAND_NAME:a duchy]`.
#[token_de(token = "LAND_NAME")]
pub land_name: Option<String>,
/// The maximum number of mandates the position can make at once.
#[token_de(token = "MANDATE_MAX")]
pub mandate_max: Option<u8>,
/// The position holder cannot be assigned labors. Currently nonfunctional.
/// [Bug:3721](https://www.bay12games.com/dwarves/mantisbt/view.php?id=3721).
#[token_de(token = "MENIAL_WORK_EXEMPTION")]
pub menial_work_exemption: Option<()>,
/// The spouse of the position holder doesn't have to work/cannot be assigned labors.
/// Currently nonfunctional.
/// [Bug:3721](https://www.bay12games.com/dwarves/mantisbt/view.php?id=3721).
#[token_de(token = "MENIAL_WORK_EXEMPTION_SPOUSE")]
pub menial_work_exemption_spouse: Option<()>,
/// This position cannot be appointed from the nobles screen. Intended for militia captains and
/// other squad leaders to reduce clutter. Currently nonfunctional:
/// [Bug:8965](https://www.bay12games.com/dwarves/mantisbt/view.php?id=8965).
#[token_de(token = "MILITARY_SCREEN_ONLY")]
pub military_screen_only: Option<()>,
/// The name of the position.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// If the creature holding the position is male, this is the position's name. E.g. for
/// `MONARCH`, `[NAME_MALE:king:kings]`.
#[token_de(token = "NAME_MALE")]
pub name_male: Option<(String, String)>,
/// If the creature holding the position is female, this is the position's name. E.g. for
/// `MONARCH`, `[NAME_FEMALE:queen:queens]`.
#[token_de(token = "NAME_FEMALE")]
pub name_female: Option<(String, String)>,
/// How many of the position there should be. If the `[SITE]` token exists, this is per site,
/// otherwise this is per civilisation.
#[token_de(token = "NUMBER")]
pub number: Option<Choose<u8, AsNeededEnum>>,
/// How important the position is in society; a lower number is more important and displayed
/// higher in the Nobles menu. For `MONARCH` it's 1, for `MILITIA_CAPTAIN` it's 200.
#[token_de(token = "PRECEDENCE")]
pub precedence: Option<Clamp<u32, 0, 30_000>>,
/// The position holder will not be held accountable for his or her crimes. Currently
/// nonfunctional. [Bug:4589](http://www.bay12games.com/dwarves/mantisbt/view.php?id=4589).
#[token_de(token = "PUNISHMENT_EXEMPTION")]
pub punishment_exemption: Option<()>,
/// The position holder can give quests in Adventure mode. Functionality in 0.31.13 and later is
/// uncertain.
#[token_de(token = "QUEST_GIVER")]
pub quest_giver: Option<()>,
/// Creatures of the specified class cannot be appointed to this position.
#[token_de(token = "REJECTED_CLASS")]
pub rejected_class: Vec<Reference>, // TODO: ref is creature class
/// Restricts position holders by `CREATURE` type.
#[token_de(token = "REJECTED_CREATURE")]
pub rejected_creature: Vec<(ReferenceTo<CreatureToken>, Option<Reference>)>, // TODO ref is caste
/// This position is absorbed by another down the line. For example, expedition leader is
/// `[REPLACED_BY:MAYOR]`.
#[token_de(token = "REPLACED_BY")]
pub replaced_by: Option<Reference>, // TODO: semantic check; this should be a POSITION
/// The position holder requires a bedroom with at least this value.
#[token_de(token = "REQUIRED_BEDROOM")]
pub required_bedroom: Option<Clamp<u32, 0, 1_000_000>>,
/// The position holder requires at least this many boxes.
#[token_de(token = "REQUIRED_BOXES")]
pub required_boxes: Option<Clamp<u8, 0, 100>>,
/// The position holder requires at least this many cabinets.
#[token_de(token = "REQUIRED_CABINETS")]
pub required_cabinets: Option<Clamp<u8, 0, 100>>,
/// The position holder requires a dining room with at least this value.
#[token_de(token = "REQUIRED_DINING")]
pub required_dining: Option<Clamp<u32, 0, 1_000_000>>,
/// The position holder requires an office with at least this value.
#[token_de(token = "REQUIRED_OFFICE")]
pub required_office: Option<Clamp<u32, 0, 1_000_000>>,
/// The position holder requires at least this many weapon racks.
#[token_de(token = "REQUIRED_RACKS")]
pub required_racks: Option<Clamp<u8, 0, 100>>,
/// The position holder requires at least this many armour stands.
#[token_de(token = "REQUIRED_STANDS")]
pub required_stands: Option<Clamp<u8, 0, 100>>,
/// The position holder requires a tomb with at least this value.
#[token_de(token = "REQUIRED_TOMB")]
pub required_tomb: Option<Clamp<u32, 0, 1_000_000>>,
/// Does not have anything directly to do with markets. It means that in minor sites (such as
/// hillocks) the position will not appear, while in major sites (such as dwarf fortresses) it
/// will.
#[token_de(token = "REQUIRES_MARKET")]
pub requires_market: Option<()>,
/// The position requires the population to be at least this number before it becomes available,
/// or before the position holder will move in.
#[token_de(token = "REQUIRES_POPULATION")]
pub requires_population: Option<u32>,
/// If there is a special location set aside for rulers, such as a human castle/mead hall, the
/// position holder will always be found at that particular location. Does nothing for dwarven
/// nobles, because at present, dwarves have no such special locations.
#[token_de(token = "RULES_FROM_LOCATION")]
pub rules_from_location: Option<()>,
/// Every site government will have the defined number of this position instead of the whole
/// civilization; provided that other criteria (if any) are met. Unless `LAND_HOLDER` is present
/// instead, the defined number of the position will be created only for the civilization as a
/// whole.
#[token_de(token = "SITE")]
pub site: Option<()>,
/// The position holder will get upset if someone with a higher `PRECEDENCE` holds quarters with
/// a greater value than their own.
#[token_de(token = "SLEEP_PRETENSION")]
pub sleep_pretension: Option<()>,
/// The civilization will inter the corpse of the position holder in a special grave, either in
/// catacombs or in monuments. If that grave is disturbed, the position holder can return as a
/// mummy (unverified).
#[token_de(token = "SPECIAL_BURIAL")]
pub special_burial: Option<()>,
/// The name of the position holder's spouse.
#[token_de(token = "SPOUSE")]
pub spouse: Option<(String, String)>,
/// If the spouse of the creature holding the position is female, this is the spouse's position
/// name.
#[token_de(token = "SPOUSE_FEMALE")]
pub spouse_female: Option<(String, String)>,
/// If the spouse of the creature holding the position is male, this is the spouse's position
/// name.
#[token_de(token = "SPOUSE_MALE")]
pub spouse_male: Option<(String, String)>,
/// The position holder is authorized to form a military squad, led by themselves.
///
/// The number denotes the maximum headcount. The noun used to describe the subordinates
/// (e.g. royal guard) is used in adventure mode for the adventurer.
#[token_de(token = "SQUAD")]
pub squad: Option<(Clamp<u8, 0, 10>, String, String)>,
/// How a new position holder is chosen. A single position can have multiple `BY_POSITION`
/// tokens. If the type is `BY_POSITION`, the position must be specified.
#[token_de(token = "SUCCESSION")]
pub succession: Option<(SuccessionTypeEnum, Option<Reference>)>, // TODO: ref is position
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum SuccessionTypeEnum {
#[token_de(token = "BY_HEIR")]
ByHeir,
#[token_de(token = "BY_POSITION")]
ByPosition,
}
impl Default for SuccessionTypeEnum {
fn default() -> Self {
Self::ByHeir
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum AsNeededEnum {
#[token_de(token = "AS_NEEDED")]
AsNeeded,
}
impl Default for AsNeededEnum {
fn default() -> Self {
Self::AsNeeded
}
}
/// The position holder does a thing. See each enum value for what each responsibility does.
#[derive(Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq)]
pub struct Responsibility {
/// argument 1 of `Responsibility`
#[token_de(token = "RESPONSIBILITY", on_duplicate_to_parent, primary_token)]
pub reference: Option<ResponsibilityEnum>,
/// A mandatory sub-tag of `[RESPONSIBILITY:EXECUTIONS]`. Determines the weapon chosen by the
/// executioner for their work.
#[token_de(token = "EXECUTION_SKILL")]
pub execution_skill: Option<WeaponSkillEnum>,
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum ResponsibilityEnum {
/// Found on bookkeeper. Position will use record keeper skill to keep track of stocks.
#[token_de(token = "ACCOUNTING")]
Accounting,
///
#[token_de(token = "ADVISE_LEADERS")]
AdviseLeaders,
/// Found on elven ranger captain and human warrior. Effect unknown.
#[token_de(token = "ATTACK_ENEMIES")]
AttackEnemies,
/// Found on champion. Position will lead military training exercises.
#[token_de(token = "BUILD_MORALE")]
BuildMorale,
///
#[token_de(token = "BUILDING_SAFETY")]
BuildingSafety,
/// Currently unused - was originally assigned to the tax collector.
#[token_de(token = "COLLECT_TAXES")]
CollectTaxes,
///
#[token_de(token = "CONSTRUCTION_PERMITS")]
ConstructionPermits,
/// Currently unused - was originally assigned to the arsenal dwarf.
#[token_de(token = "EQUIPMENT_MANIFESTS")]
EquipmentManifests,
/// Currently unused - was originally assigned to the Royal Guards (squad members beneath the
/// Hammerer).
#[token_de(token = "ESCORT_TAX_COLLECTOR")]
EscortTaxCollector,
/// Found on dungeon master and princess.
#[token_de(token = "ESPIONAGE")]
Espionage,
/// Found on outpost liaison. Position travels with the caravan to make trade agreements with
/// any settlements that it visits, provided they are domestic, report the news and promote
/// `LAND_HOLDER` positions. Also reports recent news. Presumably has no effect at site level.
///
/// Crucially, it does not visit foreign settlements, but the civ-level `TRADE` position does
/// the exact same thing in its position.
#[token_de(token = "ESTABLISH_COLONY_TRADE_AGREEMENTS")]
EstablishColonyTradeAgreements,
/// Found on hammerer. Position executes death penalty judgements with a weapon of the
/// appropriate skill.
#[token_de(token = "EXECUTIONS")]
Executions,
///
#[token_de(token = "FIRE_SAFETY")]
FireSafety,
///
#[token_de(token = "FOOD_SUPPLY")]
FoodSupply,
/// Found on chief medical dwarf. Position will use diagnostician skill to enable the z-menu
/// health screen.
#[token_de(token = "HEALTH_MANAGEMENT")]
HealthManagement,
///
#[token_de(token = "JUDGE")]
Judge,
/// Found on sheriff/captain of the guard. Position and its subordinates are in charge of
/// punishing criminals.
///
/// A position holding this responsibility plus the `SQUAD` token (or allowing the entity to
/// have a `SITE_VARIABLE_POSITION` with this responsibility) is required for an adventurer
/// from a given civilization to start as a hearthperson, fortress guard, etc.
#[token_de(token = "LAW_ENFORCEMENT")]
LawEnforcement,
/// Found on monarch/landholders. Will be referred to as the leader of the site in adventure
/// mode and they may be informed as to the site being the capital city for civ-level positions.
#[token_de(token = "LAW_MAKING")]
LawMaking,
///
#[token_de(token = "MAINTAIN_BRIDGES")]
MaintainBridges,
///
#[token_de(token = "MAINTAIN_ROADS")]
MaintainRoads,
///
#[token_de(token = "MAINTAIN_SEWERS")]
MaintainSewers,
///
#[token_de(token = "MAINTAIN_TUNNELS")]
MaintainTunnels,
/// Position will make a 'social call' to an established foreign settlement, complimenting or
/// insulting them depending on relations and reporting the news.
#[token_de(token = "MAKE_INTRODUCTIONS")]
MakeIntroductions,
/// Found on diplomat. Position negotiates peace treaties in order to end wars.
#[token_de(token = "MAKE_PEACE_AGREEMENTS")]
MakePeaceAgreements,
/// Found on diplomat. Position negotiates special agreements, such as tree cutting quotas.
#[token_de(token = "MAKE_TOPIC_AGREEMENTS")]
MakeTopicAgreements,
/// Found on dungeon master.
#[token_de(token = "MANAGE_ANIMALS")]
ManageAnimals,
///
#[token_de(token = "MANAGE_LEADER_HOUSEHOLD_CLEANLINESS")]
ManageLeaderHouseholdCleanliness,
///
#[token_de(token = "MANAGE_LEADER_HOUSEHOLD_DRINKS")]
ManageLeaderHouseholdDrinks,
///
#[token_de(token = "MANAGE_LEADER_HOUSEHOLD_FOOD")]
ManageLeaderHouseholdFood,
/// Found on manager. Position enables the use of workshop profiles and uses the organizer skill
/// to process work orders entered in the job manager after the fortress population reaches 20.
#[token_de(token = "MANAGE_PRODUCTION")]
ManageProduction,
/// Found on expedition leader/mayor. Position uses the various social skills to hold meetings
/// with unhappy citizens and try to pacify them with happy thoughts.
#[token_de(token = "MEET_WORKERS")]
MeetWorkers,
/// Found on monarch/landholder/leaders. Character is in charge of going to war and making peace
/// for the government they work for.
///
/// Without a position with this responsibility at civ level the civilization will not be able
/// to make peace and its sites will wage war on each other constantly, and as a result, all
/// viable civilizations must have one leader with this tag at civ level. This appears not to
/// be a problem for kobolds, presumably due to either the `SKULKING` or the `UTTERANCES` tokens.
#[token_de(token = "MILITARY_GOALS")]
MilitaryGoals,
/// Found on general/militia commander. During worldgen, position will go on expeditions to tame
/// exotic creatures. Means that they will command the armies of their site or civilization.
///
/// Issues the orders for the teams conducting raids or other operations away from the
/// fortress.
#[token_de(token = "MILITARY_STRATEGY")]
MilitaryStrategy,
///
#[token_de(token = "OVERSEE_LEADER_HOUSEHOLD")]
OverseeLeaderHousehold,
/// Found on elven ranger captain. Effect unknown.
#[token_de(token = "PATROL_TERRITORY")]
PatrolTerritory,
///
#[token_de(token = "PREPARE_LEADER_MEALS")]
PrepareLeaderMeals,
/// Found on monarch/landholder/leaders. Position uses the various social skills to hold
/// meetings with incoming diplomats and liaisons.
#[token_de(token = "RECEIVE_DIPLOMATS")]
ReceiveDiplomats,
/// Found on elven druid. Position informs you about worship cults.
#[token_de(token = "RELIGION")]
Religion,
/// Currently unused - was originally assigned to the arsenal dwarf.
#[token_de(token = "SORT_AMMUNITION")]
SortAmmunition,
/// Position will tame animals with the `[PET_EXOTIC]` token. Currently unused - was originally
/// assigned to the dungeon master.
#[token_de(token = "TAME_EXOTICS")]
TameExotics,
/// Found on broker. Position will use Appraisal skill to display value estimates and the
/// various Social skills to trade at the depot.
///
/// When applied to other civilizations, this position will arrive with the caravan to make
/// trade agreements (like the Human Guild Representative from older versions) and behaves
/// otherwise like the civ's own `ESTABLISH_COLONY_TRADE_AGREEMENTS` position holder.
#[token_de(token = "TRADE")]
Trade,
/// Currently unused - was originally assigned to the arsenal dwarf.
#[token_de(token = "UPGRADE_SQUAD_EQUIPMENT")]
UpgradeSquadEquipment,
}
impl Default for ResponsibilityEnum {
fn default() -> Self {
Self::Accounting
}
}