use df_ls_core::{Choose, Clamp, DFChar, Reference, ReferenceTo, Referenceable};
use df_ls_diagnostics::DiagnosticsInfo;
use df_ls_syntax_analysis::{Token, TokenDeserialize, TryFromArgumentGroup};
use serde::{Deserialize, Serialize};
use crate::{MusicSkillEnum, SkillEnum};
#[allow(clippy::large_enum_variant)]
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
pub enum ItemToken {
#[token_de(token = "ITEM_AMMO")]
AmmoToken(AmmoToken),
#[token_de(token = "ITEM_ARMOR")]
ArmorToken(ArmorToken),
#[token_de(token = "ITEM_FOOD")]
FoodToken(FoodToken),
#[token_de(token = "ITEM_GLOVES")]
GlovesToken(GlovesToken),
#[token_de(token = "ITEM_HELM")]
HelmToken(HelmToken),
#[token_de(token = "ITEM_INSTRUMENT")]
InstrumentToken(InstrumentToken),
#[token_de(token = "ITEM_PANTS")]
PantsToken(PantsToken),
#[token_de(token = "ITEM_SHIELD")]
ShieldToken(ShieldToken),
#[token_de(token = "ITEM_SHOES")]
ShoesToken(ShoesToken),
#[token_de(token = "ITEM_SIEGEAMMO")]
SiegeAmmoToken(SiegeAmmoToken),
#[token_de(token = "ITEM_TOOL")]
ToolToken(ToolToken),
#[token_de(token = "ITEM_TOY")]
ToyToken(ToyToken),
#[token_de(token = "ITEM_TRAPCOMP")]
TrapCompToken(TrapCompToken),
#[token_de(token = "ITEM_WEAPON")]
WeaponToken(WeaponToken),
}
impl Default for ItemToken {
fn default() -> Self {
Self::AmmoToken(AmmoToken::default())
}
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct AmmoToken {
/// Argument 1 of `[ITEM_AMMO:...]`
#[token_de(token = "ITEM_AMMO", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// This ammo can be fired from a weapon that is set to fire the same ammo type.
/// Defaults to `BOLT`.
#[token_de(token = "CLASS")]
pub class: Option<Reference>,
/// How large the ammunition is.
#[token_de(token = "SIZE")] // Required token
pub size: Option<u32>,
/// The attack used by this ammo when used as a melee weapon.
#[token_de(token = "ATTACK")]
pub attack: Option<ItemAttack>, // TODO: test ingame if WeaponAttack could be used instead here
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct ArmorToken {
/// Argument 1 of `[ITEM_ARMOR:...]`
#[token_de(token = "ITEM_ARMOR", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// Length of the sleeves, counted in `[LIMB]` body parts towards the hands. A value of 0 only
/// protects both halves of the torso, 1 extends over the upper arms and so on. Regardless of
/// the value, body armor can never extend to cover the hands or head.
///
/// Currently bugged, high values of `UBSTEP` will result in the item protecting
/// facial features, fingers, and toes, while leaving those parts that it cannot protect
/// unprotected (but still counting them as steps).
/// [Bug:1821](http://www.bay12games.com/dwarves/mantisbt/view.php?id=1821)
#[token_de(token = "UBSTEP")]
pub ubstep: Option<Choose<u8, MaxEnum>>,
// region: Shared by garments/shields/trapcomp/weapons; are all required ======================
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Most important with bars. The number of bars
/// required to make the item is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
// endregion ==================================================================================
// region: Shared by all garments =============================================================
/// Adjective preceding the material name (e.g. "large copper dagger").
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// Metal versions of this item count as one `ARMORLEVEL` higher and thus won't be worn by
/// random peasants. This tag will not work unless `ARMORLEVEL` is explicitly declared: if you
/// leave out `ARMORLEVEL`, even metal armor will default to level 0.
#[token_de(token = "METAL_ARMOR_LEVELS")]
pub metal_armor_levels: Option<()>,
/// Metal versions of this item will have "chain" added between the material and item name.
#[token_de(token = "CHAIN_METAL_TEXT")]
pub chain_metal_text: Option<()>,
/// Clothiers can make this item from all kinds of cloth. If paired with `[LEATHER]`, the item
/// has an equal chance of being either in randomly generated outfits. Further uses of this tag
/// are unknown.
#[token_de(token = "SOFT")]
pub soft: Option<()>,
/// Default state in the absence of a `[SOFT]` token. Actual effects unknown.
#[token_de(token = "HARD")]
pub hard: Option<()>,
/// Item can be made from metal. Overrides `[SOFT]` and `[LEATHER]` in randomly generated
/// outfits, if the `ARMORLEVEL` permits. Civilizations with `[WOOD_ARMOR]` will make this
/// item out of wood instead.
#[token_de(token = "METAL")]
pub metal: Option<()>,
/// Craftsmen can make this item from bones. Randomly generated outfits don't include bone
/// armor.
#[token_de(token = "BARRED")]
pub barred: Option<()>,
/// Craftsmen can make this item from shells. Randomly generated outfits don't include shell
/// armor.
#[token_de(token = "SCALED")]
pub scaled: Option<()>,
/// Leatherworkers can make this item from leather. If paired with `[SOFT]`, this item has an
/// equal chance of being either in randomly generated outfits.
#[token_de(token = "LEATHER")]
pub leather: Option<()>,
/// Only one shaped piece of clothing can be worn on a single body slot at a time.
#[token_de(token = "SHAPED")]
pub shaped: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, if lower.
/// This makes the garment flex and give way instead of shattering under force. Strong materials
/// that resist cutting will blunt edged attacks into bone-crushing hits instead.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_ALL")]
pub structural_elasticity_chain_all: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, but only if
/// the garment is made from metal.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_METAL")]
pub structural_elasticity_chain_metal: Option<()>,
/// Reduces the armor material's `SHEAR_YIELD` to 20000, `SHEAR_FRACTURE` to 30000 and increases
/// the `*_STRAIN_AT_YIELD` properties to 50000, but only if the garment is made from cloth.
/// This makes the item very weak against edged attacks, even if the thread material is
/// normally very strong.
#[token_de(token = "STRUCTURAL_ELASTICITY_WOVEN_THREAD")]
pub structural_elasticity_woven_thread: Option<()>,
/// The item's bulkiness when worn. Aside from the layer limitations, it's a big contributor to
/// the thickness and weight (and therefore price) of the garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_SIZE")]
pub layer_size: Option<u32>,
/// The maximum amount of garments that can fit underneath this garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_PERMIT")]
pub layer_permit: Option<u32>,
/// Where the item goes in relation to other clothes. Socks cannot be worn on top of boots!
///
/// The `LAYER_PERMIT` of the highest layer is used on a given section of the body - you can fit
/// a lot of shirts and other undergarments underneath a robe, but not if you wear a leather
/// jerkin on top of it, and you can still wear a cloak over the whole ensemble. Defaults to
/// `UNDER`.
#[token_de(token = "LAYER")]
pub layer: Option<LayerEnum>,
/// How often the garment gets in the way of a contaminant or an attack. Armor with a 5%
/// coverage value, for example, will be near useless because 95% of attacks will bypass it
/// completely. Temperature effects and armor thickness are also influenced. Defaults to 100.
#[token_de(token = "COVERAGE")]
pub coverage: Option<u8>,
/// The garment's general purpose. Defaults to 1 for shields, 0 for everything else. Class 0
/// items are claimed and used by civilians as ordinary clothing and are subject to wear.
#[token_de(token = "ARMORLEVEL")]
pub armorlevel: Option<u8>, // shared by all garments, and shields
// endregion ==================================================================================
// region: Shared by ARMOR and PANTS ==========================================================
/// Changes the plural form of this item to "`phrase of` item". Primarily pertains to the stock
/// screens.
///
/// Example, "suits of" platemail, "pairs of" trousers, etc.
#[token_de(token = "PREPLURAL")]
pub preplural: Option<String>,
/// If the item has no material associated with it (e.g. stockpile menus and trade
/// negotiations), this will be displayed in its place. Used for leather armor in vanilla.
#[token_de(token = "MATERIAL_PLACEHOLDER")]
pub material_placeholder: Option<String>,
/// Length of the legs/hem, counted in `[LIMB]` body parts towards the feet. A value of 0 only
/// covers the lower body, 1 extends over the upper legs and so on. Regardless of the value,
/// body armor or pants can never extend to cover the feet.
#[token_de(token = "LBSTEP")]
pub lbstep: Option<Choose<u8, MaxEnum>>,
// endregion ==================================================================================
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct FoodToken {
/// Argument 1 of `[ITEM_FOOD:...]`
#[token_de(token = "ITEM_FOOD", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<String>,
/// Specifies the number of ingredients that are used in this type of prepared meal:
/// - 2 for Easy. (default)
/// - 3 for Fine.
/// - 4 for Lavish.
#[token_de(token = "LEVEL")]
pub level: Option<Clamp<u8, 2, 4>>,
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct GlovesToken {
/// Argument 1 of `[ITEM_GLOVES:...]`
#[token_de(token = "ITEM_GLOVES", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// Length of gloves or footwear, counted in `[LIMB]` body parts towards the torso. A value of 1
/// lets gloves cover the lower arms, a value of 2 stretches a boot all the way over the upper
/// leg and so on.
///
/// Regardless of the value, none of these items can ever extend to cover the upper or lower
/// body. Shields also have this token, but it only seems to affect weight.
#[token_de(token = "UPSTEP")]
pub upstep: Option<Choose<u8, MaxEnum>>, // shared by glove, shield, shoes
// region: Shared by garments/shields/trapcomp/weapons; are all required ======================
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Most important with bars. The number of bars
/// required to make the item is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
// endregion ==================================================================================
// region: Shared by all garments =============================================================
/// Adjective preceding the material name (e.g. "large copper dagger").
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// Metal versions of this item count as one `ARMORLEVEL` higher and thus won't be worn by
/// random peasants. This tag will not work unless `ARMORLEVEL` is explicitly declared: if you
/// leave out `ARMORLEVEL`, even metal armor will default to level 0.
#[token_de(token = "METAL_ARMOR_LEVELS")]
pub metal_armor_levels: Option<()>,
/// Metal versions of this item will have "chain" added between the material and item name.
#[token_de(token = "CHAIN_METAL_TEXT")]
pub chain_metal_text: Option<()>,
/// Clothiers can make this item from all kinds of cloth. If paired with `[LEATHER]`, the item
/// has an equal chance of being either in randomly generated outfits. Further uses of this tag
/// are unknown.
#[token_de(token = "SOFT")]
pub soft: Option<()>,
/// Default state in the absence of a `[SOFT]` token. Actual effects unknown.
#[token_de(token = "HARD")]
pub hard: Option<()>,
/// Item can be made from metal. Overrides `[SOFT]` and `[LEATHER]` in randomly generated
/// outfits, if the `ARMORLEVEL` permits. Civilizations with `[WOOD_ARMOR]` will make this
/// item out of wood instead.
#[token_de(token = "METAL")]
pub metal: Option<()>,
/// Craftsmen can make this item from bones. Randomly generated outfits don't include bone
/// armor.
#[token_de(token = "BARRED")]
pub barred: Option<()>,
/// Craftsmen can make this item from shells. Randomly generated outfits don't include shell
/// armor.
#[token_de(token = "SCALED")]
pub scaled: Option<()>,
/// Leatherworkers can make this item from leather. If paired with `[SOFT]`, this item has an
/// equal chance of being either in randomly generated outfits.
#[token_de(token = "LEATHER")]
pub leather: Option<()>,
/// Only one shaped piece of clothing can be worn on a single body slot at a time.
#[token_de(token = "SHAPED")]
pub shaped: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, if lower.
/// This makes the garment flex and give way instead of shattering under force. Strong materials
/// that resist cutting will blunt edged attacks into bone-crushing hits instead.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_ALL")]
pub structural_elasticity_chain_all: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, but only if
/// the garment is made from metal.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_METAL")]
pub structural_elasticity_chain_metal: Option<()>,
/// Reduces the armor material's `SHEAR_YIELD` to 20000, `SHEAR_FRACTURE` to 30000 and increases
/// the `*_STRAIN_AT_YIELD` properties to 50000, but only if the garment is made from cloth.
/// This makes the item very weak against edged attacks, even if the thread material is
/// normally very strong.
#[token_de(token = "STRUCTURAL_ELASTICITY_WOVEN_THREAD")]
pub structural_elasticity_woven_thread: Option<()>,
/// The item's bulkiness when worn. Aside from the layer limitations, it's a big contributor to
/// the thickness and weight (and therefore price) of the garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_SIZE")]
pub layer_size: Option<u32>,
/// The maximum amount of garments that can fit underneath this garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_PERMIT")]
pub layer_permit: Option<u32>,
/// Where the item goes in relation to other clothes. Socks cannot be worn on top of boots!
///
/// The `LAYER_PERMIT` of the highest layer is used on a given section of the body - you can fit
/// a lot of shirts and other undergarments underneath a robe, but not if you wear a leather
/// jerkin on top of it, and you can still wear a cloak over the whole ensemble. Defaults to
/// `UNDER`.
#[token_de(token = "LAYER")]
pub layer: Option<LayerEnum>,
/// How often the garment gets in the way of a contaminant or an attack. Armor with a 5%
/// coverage value, for example, will be near useless because 95% of attacks will bypass it
/// completely. Temperature effects and armor thickness are also influenced. Defaults to 100.
#[token_de(token = "COVERAGE")]
pub coverage: Option<u8>,
/// The garment's general purpose. Defaults to 1 for shields, 0 for everything else. Class 0
/// items are claimed and used by civilians as ordinary clothing and are subject to wear.
#[token_de(token = "ARMORLEVEL")] // shared by all garments, and shields
pub armorlevel: Option<u8>,
// endregion ==================================================================================
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct HelmToken {
/// Argument 1 of `[ITEM_HELM:...]`
#[token_de(token = "ITEM_HELM", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
// region: Shared by garments/shields/trapcomp/weapons; are all required ======================
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Most important with bars. The number of bars
/// required to make the item is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
// endregion ==================================================================================
// region: Shared by all garments =============================================================
/// Adjective preceding the material name (e.g. "large copper dagger").
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// Metal versions of this item count as one `ARMORLEVEL` higher and thus won't be worn by
/// random peasants. This tag will not work unless `ARMORLEVEL` is explicitly declared: if you
/// leave out `ARMORLEVEL`, even metal armor will default to level 0.
#[token_de(token = "METAL_ARMOR_LEVELS")]
pub metal_armor_levels: Option<()>,
/// Metal versions of this item will have "chain" added between the material and item name.
#[token_de(token = "CHAIN_METAL_TEXT")]
pub chain_metal_text: Option<()>,
/// Clothiers can make this item from all kinds of cloth. If paired with `[LEATHER]`, the item
/// has an equal chance of being either in randomly generated outfits. Further uses of this tag
/// are unknown.
#[token_de(token = "SOFT")]
pub soft: Option<()>,
/// Default state in the absence of a `[SOFT]` token. Actual effects unknown.
#[token_de(token = "HARD")]
pub hard: Option<()>,
/// Item can be made from metal. Overrides `[SOFT]` and `[LEATHER]` in randomly generated
/// outfits, if the `ARMORLEVEL` permits. Civilizations with `[WOOD_ARMOR]` will make this
/// item out of wood instead.
#[token_de(token = "METAL")]
pub metal: Option<()>,
/// Craftsmen can make this item from bones. Randomly generated outfits don't include bone
/// armor.
#[token_de(token = "BARRED")]
pub barred: Option<()>,
/// Craftsmen can make this item from shells. Randomly generated outfits don't include shell
/// armor.
#[token_de(token = "SCALED")]
pub scaled: Option<()>,
/// Leatherworkers can make this item from leather. If paired with `[SOFT]`, this item has an
/// equal chance of being either in randomly generated outfits.
#[token_de(token = "LEATHER")]
pub leather: Option<()>,
/// Only one shaped piece of clothing can be worn on a single body slot at a time.
#[token_de(token = "SHAPED")]
pub shaped: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, if lower.
/// This makes the garment flex and give way instead of shattering under force. Strong materials
/// that resist cutting will blunt edged attacks into bone-crushing hits instead.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_ALL")]
pub structural_elasticity_chain_all: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, but only if
/// the garment is made from metal.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_METAL")]
pub structural_elasticity_chain_metal: Option<()>,
/// Reduces the armor material's `SHEAR_YIELD` to 20000, `SHEAR_FRACTURE` to 30000 and increases
/// the `*_STRAIN_AT_YIELD` properties to 50000, but only if the garment is made from cloth.
/// This makes the item very weak against edged attacks, even if the thread material is
/// normally very strong.
#[token_de(token = "STRUCTURAL_ELASTICITY_WOVEN_THREAD")]
pub structural_elasticity_woven_thread: Option<()>,
/// The item's bulkiness when worn. Aside from the layer limitations, it's a big contributor to
/// the thickness and weight (and therefore price) of the garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_SIZE")]
pub layer_size: Option<u32>,
/// The maximum amount of garments that can fit underneath this garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_PERMIT")]
pub layer_permit: Option<u32>,
/// Where the item goes in relation to other clothes. Socks cannot be worn on top of boots!
///
/// The `LAYER_PERMIT` of the highest layer is used on a given section of the body - you can fit
/// a lot of shirts and other undergarments underneath a robe, but not if you wear a leather
/// jerkin on top of it, and you can still wear a cloak over the whole ensemble. Defaults to
/// `UNDER`.
#[token_de(token = "LAYER")]
pub layer: Option<LayerEnum>,
/// How often the garment gets in the way of a contaminant or an attack. Armor with a 5%
/// coverage value, for example, will be near useless because 95% of attacks will bypass it
/// completely. Temperature effects and armor thickness are also influenced. Defaults to 100.
#[token_de(token = "COVERAGE")]
pub coverage: Option<u8>,
/// The garment's general purpose. Defaults to 1 for shields, 0 for everything else. Class 0
/// items are claimed and used by civilians as ordinary clothing and are subject to wear.
#[token_de(token = "ARMORLEVEL")] // shared by all garments, and shields
pub armorlevel: Option<u8>,
// endregion ==================================================================================
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct InstrumentToken {
/// Argument 1 of `[ITEM_INSTRUMENT:...]`
#[token_de(token = "ITEM_INSTRUMENT", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
// region: Unique to instruments ==============================================================
/// Makes the instrument stationary.
#[token_de(token = "PLACED_AS_BUILDING")]
pub placed_as_building: Option<()>,
/// Sets a piece as the central part of the instrument.
#[token_de(token = "DOMINANT_MATERIAL_PIECE")]
pub dominant_material_piece: Option<Reference>,
/// Defines an instrument piece. The 1st argument is the identifier that can be used in other
/// raw tags to refer to this instrument piece. The 2nd is the tool which is required
/// (and consumed) during the construction process to create this instrument piece.
///
/// If an instrument does not have any pieces, `SELF` can be used for any argument which needs
/// to be an instrument piece.
#[token_de(token = "INSTRUMENT_PIECE")]
pub instrument_piece: Vec<(
Reference,
ReferenceTo<ToolToken>,
String,
String,
NameTypeEnum,
)>,
/// The instrument's volume range, in millibels (100 mB = 1 dB).
#[token_de(token = "VOLUME_mB")]
pub volume_mb: Option<(u32, u32)>,
/// Defines how a musician can produce sound when using this instrument. Can be used multiple
/// times.
#[token_de(token = "SOUND_PRODUCTION")]
pub sound_production: Vec<(SoundProductionEnum, Reference, Option<Reference>)>,
/// Defines how the pitch can be varied by the musician. Can be used multiple times.
#[token_de(token = "PITCH_CHOICE")]
pub pitch_choice: Vec<(PitchMethodEnum, Reference, Option<Reference>)>,
/// Defines how the instrument may be tuned. Can be used multiple times.
#[token_de(token = "TUNING")]
pub tuning: Vec<(TuningMethodEnum, Reference)>,
/// Pitch is `min`:`max` in cents with middle C at zero. There are 1200 cents in an octave.
///
/// The game verbally differentiates values from -4200 to 4200, but you can go outside
/// that if you like. The in-game generated instruments will range from roughly C0 to C8
/// (-4800 to 4800), sometimes beyond for really unusual ones.
///
/// You can also use `[INDEFINITE_PITCH]` instead.
#[token_de(token = "PITCH_RANGE")]
pub pitch_range: Option<(i32, i32)>,
/// You can add as many timbre words as you want. The generated timbres have a series of
/// checks for conflicts, but they don't apply to the raws, so how you use them is up to you.
#[token_de(token = "TIMBRE")]
pub timbre: Option<(TimbreEnum, Vec<TimbreEnum>)>,
/// The pitch range overrides the global pitch for a register, but the register timbres are
/// added to the global ones. You can add as many timbre words as you want.
///
/// Pitch is `min`:`max` in cents with middle C at zero. There are 1200 cents in an octave.
///
/// The game verbally differentiates values from -4200 to 4200, but you can go outside
/// that if you like. The in-game generated instruments will range from roughly C0 to C8
/// (-4800 to 4800), sometimes beyond for really unusual ones.
///
/// You can also use `[INDEFINITE_PITCH]` instead.
#[token_de(token = "REGISTER")]
pub register: Vec<(i32, i32, TimbreEnum, Vec<TimbreEnum>)>,
/// The skill used for playing this instrument.
#[token_de(token = "MUSIC_SKILL")]
pub music_skill: Option<MusicSkillEnum>,
/// Can be used instead of either `REGISTER` or `PITCH_RANGE`.
#[token_de(token = "INDEFINITE_PITCH")]
pub indefinite_pitch: Option<()>,
// endregion ==================================================================================
// TODO: prune the following list/region of shared tokens, these aren't all actually shared.
// The following 3 links may be useful for figuring out which are truly shared:
// - https://github.com/DFHack/df-structures/blob/master/df.items.xml
// - https://github.com/DFHack/df-structures/blob/master/df.item-raws.xml
// - https://github.com/DFHack/df-structures/blob/master/df.item-vectors.xml
// Also, the descriptions for most of them are almost definitely inapplicable for instruments.
// region: Shared by tools and instruments ====================================================
/// Volume of tool in mL or cubic centimeters. Required.
#[token_de(token = "SIZE")]
pub size: Option<u32>,
/// Name of the tool. Required.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// Defines the item value of the tool. Required.
#[token_de(token = "VALUE")]
pub value: Option<u32>,
/// Defines the tile used to represent the tool. Required.
#[token_de(token = "TILE")]
pub tile: Option<DFChar>,
/// Permits the tool to be made from any bone.
#[token_de(token = "BONE_MAT")]
pub bone_mat: Option<()>,
/// Permits the tool to be made from any ceramic material.
#[token_de(token = "CERAMIC_MAT")]
pub ceramic_mat: Option<()>,
/// Allows a string to describe the tool when viewed. The text box can accommodate up to 325
/// characters until it cuts off, but the spacing of actual sentences puts the realistic limit
/// closer to 300.
#[token_de(token = "DESCRIPTION")]
pub description: Option<String>,
/// Permits the tool to be made from any glass.
#[token_de(token = "GLASS_MAT")]
pub glass_mat: Option<()>,
/// Permits the tool to be made from anything with the `[ITEMS_HARD]` token, such as wood, stone
/// or metal.
#[token_de(token = "HARD_MAT")]
pub hard_mat: Option<()>,
/// Permits the tool to be made from any leather.
#[token_de(token = "LEATHER_MAT")]
pub leather_mat: Option<()>,
/// Permits the tool to be made from anything with the `[IS_METAL]` token.
#[token_de(token = "METAL_MAT")]
pub metal_mat: Option<()>,
/// Permits the tool to be made from any metal with the `[ITEMS_WEAPON]` token.
#[token_de(token = "METAL_WEAPON_MAT")]
pub metal_weapon_mat: Option<()>,
/// Permits the tool to be made from any "sheet" material, such as papyrus, paper, and
/// parchment. May be connected to the `PAPER_SLURRY`/`PAPER_PLANT` reaction classes,
/// but this is not verified.
#[token_de(token = "SHEET_MAT")]
pub sheet_mat: Option<()>,
/// Permits the tool to be made from any shell.
#[token_de(token = "SHELL_MAT")]
pub shell_mat: Option<()>,
/// Permits the tool to be made from any silk.
#[token_de(token = "SILK_MAT")]
pub silk_mat: Option<()>,
/// Permits the tool to be made from any material with the `[ITEMS_SOFT]` token, such as leather
/// or textiles.
#[token_de(token = "SOFT_MAT")]
pub soft_mat: Option<()>,
/// Permits the tool to be made from any stone. Presumably connected to the `[IS_STONE]` token.
#[token_de(token = "STONE_MAT")]
pub stone_mat: Option<()>,
/// Permits the tool to be made from any plant fiber, such as pig tails.
#[token_de(token = "THREAD_PLANT_MAT")]
pub thread_plant_mat: Option<()>,
/// Permits the tool to be made from any wood.
#[token_de(token = "WOOD_MAT")]
pub wood_mat: Option<()>,
/// According to Toady, "Won't be used in world gen libraries (to differentiate scrolls from
/// quires). Also put it on bindings, rollers, instr. pieces for completeness/future use".
/// Used on scroll rollers, book bindings, and quires.
#[token_de(token = "INCOMPLETE_ITEM")]
pub incomplete_item: Option<()>,
/// Items that appear in the wild come standard with this kind of improvement. Used on scrolls:
/// `[DEFAULT_IMPROVEMENT:SPECIFIC:ROLLERS:HARD_MAT]`
///
/// Currently bugged, the effect is also applied to everything made in-game. This causes
/// scrolls to have two sets of rollers, for example.
#[token_de(token = "DEFAULT_IMPROVEMENT")]
pub default_improvement: Option<ImprovementTypeWithMatFlagTokenArg>,
/// Prevents the tool from being improved. Used on honeycombs, scroll rollers, book bindings,
/// and quires.
#[token_de(token = "UNIMPROVABLE")]
pub unimprovable: Option<()>,
/// **This token's purpose is unknown, and it may be an alias of another token; if you know
/// what it does, please open an issue on the issue tracker.**
#[token_de(token = "NO_DEFAULT_IMPROVEMENTS")]
pub no_default_improvements: Option<()>,
/// The background of the tile will be colored, instead of the foreground.
#[token_de(token = "INVERTED_TILE")]
pub inverted_tile: Option<()>,
/// According to Toady, "only custom reactions are used to make this item". Found on scrolls and
/// quires.
#[token_de(token = "NO_DEFAULT_JOB")]
pub no_default_job: Option<()>,
/// Defines the task performed using the tool.
#[token_de(token = "TOOL_USE")]
pub tool_use: Vec<ToolUseEnum>,
/// Allows item to be stored in a furniture stockpile.
#[token_de(token = "FURNITURE")]
pub furniture: Option<()>,
// TODO: ref is shape category
#[token_de(token = "SHAPE_CATEGORY")]
pub shape_category: Option<Reference>,
/// Used on dice.
#[token_de(token = "USES_FACE_IMAGE_SET")]
pub uses_face_image_set: Option<()>,
/// Adjective preceding the material name (e.g. "large copper dagger")
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// How much the item can contain. Defaults to 0.
#[token_de(token = "CONTAINER_CAPACITY")]
pub container_capacity: Option<u32>,
/// Required for weapons.
#[token_de(token = "SHOOT_FORCE")]
pub shoot_force: Option<u32>,
/// Required for weapons.
#[token_de(token = "SHOOT_MAXVEL")]
pub shoot_maxvel: Option<u32>,
/// The skill to determine effectiveness in melee with this tool. Required for weapons.
#[token_de(token = "SKILL")]
pub skill: Option<SkillEnum>,
/// Makes this tool a ranged weapon that uses the specified ammo. The specified skill
/// determines accuracy in ranged combat.
#[token_de(token = "RANGED")]
pub ranged: Option<(SkillEnum, ReferenceTo<AmmoToken>)>,
/// Creatures under this size (in cm^3) must use the tool two-handed. Required for weapons.
#[token_de(token = "TWO_HANDED")]
pub two_handed: Option<u32>,
/// Minimum body size (in cm^3) to use the tool at all (multigrasp required until `TWO_HANDED`
/// value). Required for weapons.
#[token_de(token = "MINIMUM_SIZE")]
pub minimum_size: Option<u32>,
/// Number of bar units needed for forging, as well as the amount gained from melting. Required
/// for weapons.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
/// You can have many `ATTACK` tags and one will be randomly selected for each attack, with
/// `EDGE` attacks 100 times more common than `BLUNT` attacks. Required for weapons.
#[token_de(token = "ATTACK")]
pub attack: Vec<WeaponAttack>,
// endregion ==================================================================================
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum NameTypeEnum {
#[token_de(token = "STANDARD")]
Standard,
#[token_de(token = "ALWAYS_PLURAL")]
AlwaysPlural,
#[token_de(token = "ALWAYS_SINGULAR")]
AlwaysSingular,
}
impl Default for NameTypeEnum {
fn default() -> Self {
Self::Standard
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum PitchMethodEnum {
#[token_de(token = "MEMBRANE_POSITION")]
MembranePosition,
#[token_de(token = "SUBPART_CHOICE")]
SubpartChoice,
#[token_de(token = "KEYBOARD")]
Keyboard,
/// Requires two `INSTRUMENT_PIECE` tokens, first for "string" second for "neck"
/// -- or whatever is being pressed against what.
#[token_de(token = "STOPPING_FRET")]
StoppingFret,
/// Requires two `INSTRUMENT_PIECE` tokens.
#[token_de(token = "STOPPING_AGAINST_BODY")]
StoppingAgainstBody,
#[token_de(token = "STOPPING_HOLE")]
StoppingHole,
#[token_de(token = "STOPPING_HOLE_KEY")]
StoppingHoleKey,
#[token_de(token = "SLIDE")]
Slide,
#[token_de(token = "HARMONIC_SERIES")]
HarmonicSeries,
#[token_de(token = "VALVE_ROUTES_AIR")]
ValveRoutesAir,
#[token_de(token = "BP_IN_BELL")]
BpInBell,
/// Requires two `INSTRUMENT_PIECE` tokens, first is what is being changed e.g. "strings",
/// second is "body" which has the pedalboard -- or whatever piece is being stepped on.
#[token_de(token = "FOOT_PEDALS")]
FootPedals,
}
impl Default for PitchMethodEnum {
fn default() -> Self {
Self::MembranePosition
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum TuningMethodEnum {
#[token_de(token = "PEGS")]
Pegs,
#[token_de(token = "ADJUSTABLE_BRIDGES")]
AdjustableBridhes,
#[token_de(token = "CROOKS")]
Crooks,
#[token_de(token = "TIGHTENING")]
Tightening,
#[token_de(token = "LEVERS")]
Levers,
}
impl Default for TuningMethodEnum {
fn default() -> Self {
Self::Pegs
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum SoundProductionEnum {
#[token_de(token = "PLUCKED_BY_BP")]
PluckedByBp,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "PLUCKED")]
Plucked,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "BOWED")]
Bowed,
#[token_de(token = "STRUCK_BY_BP")]
StruckByBp,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "STRUCK")]
Struck,
#[token_de(token = "VIBRATE_BP_AGAINST_OPENING")]
VibrateBpAgainstOpening,
#[token_de(token = "BLOW_AGAINST_FIPPLE")]
BlowAgainstFipple,
#[token_de(token = "BLOW_OVER_OPENING_SIDE")]
BlowOverOpeningSide,
#[token_de(token = "BLOW_OVER_OPENING_END")]
BlowOverOpeningEnd,
#[token_de(token = "BLOW_OVER_SINGLE_REED")]
BlowOverSingleReed,
#[token_de(token = "BLOW_OVER_DOUBLE_REED")]
BlowOverDoubleReed,
#[token_de(token = "BLOW_OVER_FREE_REED")]
BlowOverFreeReed,
#[token_de(token = "STRUCK_TOGETHER")]
StruckTogether,
#[token_de(token = "SHAKEN")]
Shaken,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "SCRAPED")]
Scraped,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "FRICTION")]
Friction,
#[token_de(token = "RESONATOR")]
Resonator,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "BAG_OVER_REED")]
BagOverReed,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "AIR_OVER_REED")]
AirOverReed,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "AIR_OVER_FREE_REED")]
AirOverFreeReed,
/// Requires two `INSTRUMENT_PIECE` tokens: actor, then target.
#[token_de(token = "AIR_AGAINST_FIPPLE")]
AirAgainstFipple,
}
impl Default for SoundProductionEnum {
fn default() -> Self {
Self::PluckedByBp
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum TimbreEnum {
#[token_de(token = "CLEAR")]
Clear,
#[token_de(token = "NOISY")]
Noisy,
#[token_de(token = "FULL")]
Full,
#[token_de(token = "THIN")]
Thin,
#[token_de(token = "ROUND")]
Round,
#[token_de(token = "SHARP")]
Sharp,
#[token_de(token = "SMOOTH")]
Smooth,
#[token_de(token = "CHOPPY")]
Choppy,
#[token_de(token = "STEADY")]
Steady,
#[token_de(token = "EVOLVING")]
Evolving,
#[token_de(token = "STRONG")]
Strong,
#[token_de(token = "DELICATE")]
Delicate,
#[token_de(token = "BRIGHT")]
Bright,
#[token_de(token = "GRACEFUL")]
Graceful,
#[token_de(token = "SPARSE")]
Sparse,
#[token_de(token = "BREATHY")]
Breathy,
#[token_de(token = "STRAINED")]
Strained,
#[token_de(token = "BROAD")]
Broad,
#[token_de(token = "LIGHT")]
Light,
#[token_de(token = "MELLOW")]
Mellow,
#[token_de(token = "WOBBLING")]
Wobbling,
#[token_de(token = "FOCUSED")]
Focused,
#[token_de(token = "EVEN")]
Even,
#[token_de(token = "FLUID")]
Fluid,
#[token_de(token = "VIBRATING")]
Vibrating,
#[token_de(token = "QUAVERING")]
Quavering,
#[token_de(token = "EERIE")]
Eerie,
#[token_de(token = "FRAGILE")]
Fragile,
#[token_de(token = "BRITTLE")]
Brittle,
#[token_de(token = "PURE")]
Pure,
#[token_de(token = "PIERCING")]
Piercing,
#[token_de(token = "STRIDENT")]
Strident,
#[token_de(token = "WAVERING")]
Wavering,
#[token_de(token = "HARSH")]
Harsh,
#[token_de(token = "REEDY")]
Reedy,
#[token_de(token = "NASAL")]
Nasal,
#[token_de(token = "BUZZY")]
Buzzy,
#[token_de(token = "ROUGH")]
Rough,
#[token_de(token = "WARM")]
Warm,
#[token_de(token = "RUGGED")]
Rugged,
#[token_de(token = "HEAVY")]
Heavy,
#[token_de(token = "FLAT")]
Flat,
#[token_de(token = "DARK")]
Dark,
#[token_de(token = "CRISP")]
Crisp,
#[token_de(token = "SONOROUS")]
Sonorous,
#[token_de(token = "WATERY")]
Watery,
#[token_de(token = "GENTLE")]
Gentle,
#[token_de(token = "SLICING")]
Slicing,
#[token_de(token = "LIQUID")]
Liquid,
#[token_de(token = "RAUCOUS")]
Raucous,
#[token_de(token = "BREEZY")]
Breezy,
#[token_de(token = "RASPY")]
Raspy,
#[token_de(token = "WISPY")]
Wispy,
#[token_de(token = "SHRILL")]
Shrill,
#[token_de(token = "MUDDY")]
Muddy,
#[token_de(token = "RICH")]
Rich,
#[token_de(token = "DULL")]
Dull,
#[token_de(token = "FLOATING")]
Floating,
#[token_de(token = "RINGING")]
Ringing,
#[token_de(token = "RESONANT")]
Resonant,
#[token_de(token = "SWEET")]
Sweet,
#[token_de(token = "RIPPLING")]
Rippling,
#[token_de(token = "SPARKLING")]
Sparkling,
}
impl Default for TimbreEnum {
fn default() -> Self {
Self::Clear
}
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct PantsToken {
/// Argument 1 of `[ITEM_PANTS:...]`
#[token_de(token = "ITEM_PANTS", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
// region: Shared by garments/shields/trapcomp/weapons; are all required ======================
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Most important with bars. The number of bars
/// required to make the item is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
// endregion ==================================================================================
// region: Shared by all garments =============================================================
/// Adjective preceding the material name (e.g. "large copper dagger").
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// Metal versions of this item count as one `ARMORLEVEL` higher and thus won't be worn by
/// random peasants. This tag will not work unless `ARMORLEVEL` is explicitly declared: if you
/// leave out `ARMORLEVEL`, even metal armor will default to level 0.
#[token_de(token = "METAL_ARMOR_LEVELS")]
pub metal_armor_levels: Option<()>,
/// Metal versions of this item will have "chain" added between the material and item name.
#[token_de(token = "CHAIN_METAL_TEXT")]
pub chain_metal_text: Option<()>,
/// Clothiers can make this item from all kinds of cloth. If paired with `[LEATHER]`, the item
/// has an equal chance of being either in randomly generated outfits. Further uses of this tag
/// are unknown.
#[token_de(token = "SOFT")]
pub soft: Option<()>,
/// Default state in the absence of a `[SOFT]` token. Actual effects unknown.
#[token_de(token = "HARD")]
pub hard: Option<()>,
/// Item can be made from metal. Overrides `[SOFT]` and `[LEATHER]` in randomly generated
/// outfits, if the `ARMORLEVEL` permits. Civilizations with `[WOOD_ARMOR]` will make this
/// item out of wood instead.
#[token_de(token = "METAL")]
pub metal: Option<()>,
/// Craftsmen can make this item from bones. Randomly generated outfits don't include bone
/// armor.
#[token_de(token = "BARRED")]
pub barred: Option<()>,
/// Craftsmen can make this item from shells. Randomly generated outfits don't include shell
/// armor.
#[token_de(token = "SCALED")]
pub scaled: Option<()>,
/// Leatherworkers can make this item from leather. If paired with `[SOFT]`, this item has an
/// equal chance of being either in randomly generated outfits.
#[token_de(token = "LEATHER")]
pub leather: Option<()>,
/// Only one shaped piece of clothing can be worn on a single body slot at a time.
#[token_de(token = "SHAPED")]
pub shaped: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, if lower.
/// This makes the garment flex and give way instead of shattering under force. Strong materials
/// that resist cutting will blunt edged attacks into bone-crushing hits instead.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_ALL")]
pub structural_elasticity_chain_all: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, but only if
/// the garment is made from metal.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_METAL")]
pub structural_elasticity_chain_metal: Option<()>,
/// Reduces the armor material's `SHEAR_YIELD` to 20000, `SHEAR_FRACTURE` to 30000 and increases
/// the `*_STRAIN_AT_YIELD` properties to 50000, but only if the garment is made from cloth.
/// This makes the item very weak against edged attacks, even if the thread material is
/// normally very strong.
#[token_de(token = "STRUCTURAL_ELASTICITY_WOVEN_THREAD")]
pub structural_elasticity_woven_thread: Option<()>,
/// The item's bulkiness when worn. Aside from the layer limitations, it's a big contributor to
/// the thickness and weight (and therefore price) of the garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_SIZE")]
pub layer_size: Option<u32>,
/// The maximum amount of garments that can fit underneath this garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_PERMIT")]
pub layer_permit: Option<u32>,
/// Where the item goes in relation to other clothes. Socks cannot be worn on top of boots!
///
/// The `LAYER_PERMIT` of the highest layer is used on a given section of the body - you can fit
/// a lot of shirts and other undergarments underneath a robe, but not if you wear a leather
/// jerkin on top of it, and you can still wear a cloak over the whole ensemble. Defaults to
/// `UNDER`.
#[token_de(token = "LAYER")]
pub layer: Option<LayerEnum>,
/// How often the garment gets in the way of a contaminant or an attack. Armor with a 5%
/// coverage value, for example, will be near useless because 95% of attacks will bypass it
/// completely. Temperature effects and armor thickness are also influenced. Defaults to 100.
#[token_de(token = "COVERAGE")]
pub coverage: Option<u8>,
/// The garment's general purpose. Defaults to 1 for shields, 0 for everything else. Class 0
/// items are claimed and used by civilians as ordinary clothing and are subject to wear.
#[token_de(token = "ARMORLEVEL")] // shared by all garments, and shields
pub armorlevel: Option<u8>,
// endregion ==================================================================================
// region: Shared by ARMOR and PANTS ==========================================================
/// Changes the plural form of this item to "`phrase of` item". Primarily pertains to the stock
/// screens.
///
/// Example, "suits of" platemail, "pairs of" trousers, etc.
#[token_de(token = "PREPLURAL")]
pub preplural: Option<String>,
/// If the item has no material associated with it (e.g. stockpile menus and trade
/// negotiations), this will be displayed in its place. Used for leather armor in vanilla.
#[token_de(token = "MATERIAL_PLACEHOLDER")]
pub material_placeholder: Option<String>,
/// Length of the legs/hem, counted in `[LIMB]` body parts towards the feet. A value of 0 only
/// covers the lower body, 1 extends over the upper legs and so on. Regardless of the value,
/// body armor or pants can never extend to cover the feet.
#[token_de(token = "LBSTEP")]
pub lbstep: Option<Choose<u8, MaxEnum>>,
// endregion ==================================================================================
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct ShieldToken {
/// Argument 1 of `[ITEM_SHIELD:...]`
#[token_de(token = "ITEM_SHIELD", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// Affects the block chance of the shield. Defaults to 10.
#[token_de(token = "BLOCKCHANCE")]
pub blockchance: Option<Clamp<u8, 0, 100>>,
/// Length of gloves or footwear, counted in `[LIMB]` body parts towards the torso. A value of 1
/// lets gloves cover the lower arms, a value of 2 stretches a boot all the way over the upper
/// leg and so on.
///
/// Regardless of the value, none of these items can ever extend to cover the upper or lower
/// body. Shields also have this token, but it only seems to affect weight.
#[token_de(token = "UPSTEP")]
pub upstep: Option<Choose<u8, MaxEnum>>, // shared by glove, shield, shoes
/// The garment's general purpose. Defaults to 1 for shields, 0 for everything else. Class 0
/// items are claimed and used by civilians as ordinary clothing and are subject to wear.
#[token_de(token = "ARMORLEVEL")]
pub armorlevel: Option<u8>, // shared by all garments, and shields
// region: Shared by garments/shields/trapcomp/weapons; are all required ======================
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Most important with bars. The number of bars
/// required to make the item is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
// endregion ==================================================================================
/// Adjective preceding the material name (e.g. "large copper dagger").
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct ShoesToken {
/// Argument 1 of `[ITEM_SHOES:...]`
#[token_de(token = "ITEM_SHOES", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// Length of gloves or footwear, counted in `[LIMB]` body parts towards the torso. A value of 1
/// lets gloves cover the lower arms, a value of 2 stretches a boot all the way over the upper
/// leg and so on.
///
/// Regardless of the value, none of these items can ever extend to cover the upper or lower
/// body. Shields also have this token, but it only seems to affect weight.
#[token_de(token = "UPSTEP")]
pub upstep: Option<Choose<u8, MaxEnum>>, // shared by glove, shield, shoes
// region: Shared by garments/shields/trapcomp/weapons; are all required ======================
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Most important with bars. The number of bars
/// required to make the item is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
// endregion ==================================================================================
// region: Shared by all garments =============================================================
/// Adjective preceding the material name (e.g. "large copper dagger").
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// Metal versions of this item count as one `ARMORLEVEL` higher and thus won't be worn by
/// random peasants. This tag will not work unless `ARMORLEVEL` is explicitly declared: if you
/// leave out `ARMORLEVEL`, even metal armor will default to level 0.
#[token_de(token = "METAL_ARMOR_LEVELS")]
pub metal_armor_levels: Option<()>,
/// Metal versions of this item will have "chain" added between the material and item name.
#[token_de(token = "CHAIN_METAL_TEXT")]
pub chain_metal_text: Option<()>,
/// Clothiers can make this item from all kinds of cloth. If paired with `[LEATHER]`, the item
/// has an equal chance of being either in randomly generated outfits. Further uses of this tag
/// are unknown.
#[token_de(token = "SOFT")]
pub soft: Option<()>,
/// Default state in the absence of a `[SOFT]` token. Actual effects unknown.
#[token_de(token = "HARD")]
pub hard: Option<()>,
/// Item can be made from metal. Overrides `[SOFT]` and `[LEATHER]` in randomly generated
/// outfits, if the `ARMORLEVEL` permits. Civilizations with `[WOOD_ARMOR]` will make this
/// item out of wood instead.
#[token_de(token = "METAL")]
pub metal: Option<()>,
/// Craftsmen can make this item from bones. Randomly generated outfits don't include bone
/// armor.
#[token_de(token = "BARRED")]
pub barred: Option<()>,
/// Craftsmen can make this item from shells. Randomly generated outfits don't include shell
/// armor.
#[token_de(token = "SCALED")]
pub scaled: Option<()>,
/// Leatherworkers can make this item from leather. If paired with `[SOFT]`, this item has an
/// equal chance of being either in randomly generated outfits.
#[token_de(token = "LEATHER")]
pub leather: Option<()>,
/// Only one shaped piece of clothing can be worn on a single body slot at a time.
#[token_de(token = "SHAPED")]
pub shaped: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, if lower.
/// This makes the garment flex and give way instead of shattering under force. Strong materials
/// that resist cutting will blunt edged attacks into bone-crushing hits instead.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_ALL")]
pub structural_elasticity_chain_all: Option<()>,
/// Increases the `*_STRAIN_AT_YIELD` properties of the armor's material to 50000, but only if
/// the garment is made from metal.
#[token_de(token = "STRUCTURAL_ELASTICITY_CHAIN_METAL")]
pub structural_elasticity_chain_metal: Option<()>,
/// Reduces the armor material's `SHEAR_YIELD` to 20000, `SHEAR_FRACTURE` to 30000 and increases
/// the `*_STRAIN_AT_YIELD` properties to 50000, but only if the garment is made from cloth.
/// This makes the item very weak against edged attacks, even if the thread material is
/// normally very strong.
#[token_de(token = "STRUCTURAL_ELASTICITY_WOVEN_THREAD")]
pub structural_elasticity_woven_thread: Option<()>,
/// The item's bulkiness when worn. Aside from the layer limitations, it's a big contributor to
/// the thickness and weight (and therefore price) of the garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_SIZE")]
pub layer_size: Option<u32>,
/// The maximum amount of garments that can fit underneath this garment. See
/// [Armor](https://dwarffortresswiki.org/index.php/Armor) for more on item sizes and
/// layering. Defaults to 10.
#[token_de(token = "LAYER_PERMIT")]
pub layer_permit: Option<u32>,
/// Where the item goes in relation to other clothes. Socks cannot be worn on top of boots!
///
/// The `LAYER_PERMIT` of the highest layer is used on a given section of the body - you can fit
/// a lot of shirts and other undergarments underneath a robe, but not if you wear a leather
/// jerkin on top of it, and you can still wear a cloak over the whole ensemble. Defaults to
/// `UNDER`.
#[token_de(token = "LAYER")]
pub layer: Option<LayerEnum>,
/// How often the garment gets in the way of a contaminant or an attack. Armor with a 5%
/// coverage value, for example, will be near useless because 95% of attacks will bypass it
/// completely. Temperature effects and armor thickness are also influenced. Defaults to 100.
#[token_de(token = "COVERAGE")]
pub coverage: Option<u8>,
/// The garment's general purpose. Defaults to 1 for shields, 0 for everything else. Class 0
/// items are claimed and used by civilians as ordinary clothing and are subject to wear.
#[token_de(token = "ARMORLEVEL")] // shared by all garments, and shields
pub armorlevel: Option<u8>,
// endregion ==================================================================================
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum LayerEnum {
#[token_de(token = "UNDER")]
Under,
#[token_de(token = "OVER")]
Over,
#[token_de(token = "ARMOR")]
Armor,
#[token_de(token = "COVER")]
Cover,
}
impl Default for LayerEnum {
fn default() -> Self {
Self::Under
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum MaxEnum {
#[token_de(token = "MAX")]
Max,
}
impl Default for MaxEnum {
fn default() -> Self {
Self::Max
}
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct SiegeAmmoToken {
/// Argument 1 of `[ITEM_SIEGEAMMO:...]`
#[token_de(token = "ITEM_SIEGEAMMO", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// Specifies what type of siege engine uses this ammunition. Currently, only `BALLISTA` is
/// permitted.
#[token_de(token = "CLASS")]
pub class: Option<SiegeAmmoClassEnum>,
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum SiegeAmmoClassEnum {
#[token_de(token = "BALLISTA")]
Ballista,
}
impl Default for SiegeAmmoClassEnum {
fn default() -> Self {
Self::Ballista
}
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct ToolToken {
/// Argument 1 of `[ITEM_TOOL:...]`
#[token_de(token = "ITEM_TOOL", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// Volume of tool in mL or cubic centimeters. Required.
#[token_de(token = "SIZE")]
pub size: Option<u32>,
/// Name of the tool. Required.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// Defines the item value of the tool. Required.
#[token_de(token = "VALUE")]
pub value: Option<u32>,
/// Defines the tile used to represent the tool. Required.
#[token_de(token = "TILE")]
pub tile: Option<DFChar>,
/// Permits the tool to be made from any bone.
#[token_de(token = "BONE_MAT")]
pub bone_mat: Option<()>,
/// Permits the tool to be made from any ceramic material.
#[token_de(token = "CERAMIC_MAT")]
pub ceramic_mat: Option<()>,
/// Allows a string to describe the tool when viewed. The text box can accommodate up to 325
/// characters until it cuts off, but the spacing of actual sentences puts the realistic limit
/// closer to 300.
#[token_de(token = "DESCRIPTION")]
pub description: Option<String>,
/// Permits the tool to be made from any glass.
#[token_de(token = "GLASS_MAT")]
pub glass_mat: Option<()>,
/// Permits the tool to be made from anything with the `[ITEMS_HARD]` token, such as wood, stone
/// or metal.
#[token_de(token = "HARD_MAT")]
pub hard_mat: Option<()>,
/// Permits the tool to be made from any leather.
#[token_de(token = "LEATHER_MAT")]
pub leather_mat: Option<()>,
/// Permits the tool to be made from anything with the `[IS_METAL]` token.
#[token_de(token = "METAL_MAT")]
pub metal_mat: Option<()>,
/// Permits the tool to be made from any metal with the `[ITEMS_WEAPON]` token.
#[token_de(token = "METAL_WEAPON_MAT")]
pub metal_weapon_mat: Option<()>,
/// Permits the tool to be made from any "sheet" material, such as papyrus, paper, and
/// parchment. May be connected to the `PAPER_SLURRY`/`PAPER_PLANT` reaction classes,
/// but this is not verified.
#[token_de(token = "SHEET_MAT")]
pub sheet_mat: Option<()>,
/// Permits the tool to be made from any shell.
#[token_de(token = "SHELL_MAT")]
pub shell_mat: Option<()>,
/// Permits the tool to be made from any silk.
#[token_de(token = "SILK_MAT")]
pub silk_mat: Option<()>,
/// Permits the tool to be made from any material with the `[ITEMS_SOFT]` token, such as leather
/// or textiles.
#[token_de(token = "SOFT_MAT")]
pub soft_mat: Option<()>,
/// Permits the tool to be made from any stone. Presumably connected to the `[IS_STONE]` token.
#[token_de(token = "STONE_MAT")]
pub stone_mat: Option<()>,
/// Permits the tool to be made from any plant fiber, such as pig tails.
#[token_de(token = "THREAD_PLANT_MAT")]
pub thread_plant_mat: Option<()>,
/// Permits the tool to be made from any wood.
#[token_de(token = "WOOD_MAT")]
pub wood_mat: Option<()>,
/// According to Toady, "Won't be used in world gen libraries (to differentiate scrolls from
/// quires). Also put it on bindings, rollers, instr. pieces for completeness/future use".
/// Used on scroll rollers, book bindings, and quires.
#[token_de(token = "INCOMPLETE_ITEM")]
pub incomplete_item: Option<()>,
/// Items that appear in the wild come standard with this kind of improvement. Used on scrolls:
/// `[DEFAULT_IMPROVEMENT:SPECIFIC:ROLLERS:HARD_MAT]`
///
/// Currently bugged, the effect is also applied to everything made in-game. This causes
/// scrolls to have two sets of rollers, for example.
#[token_de(token = "DEFAULT_IMPROVEMENT")]
pub default_improvement: Option<ImprovementTypeWithMatFlagTokenArg>,
/// Prevents the tool from being improved. Used on honeycombs, scroll rollers, book bindings,
/// and quires.
#[token_de(token = "UNIMPROVABLE")]
pub unimprovable: Option<()>,
/// **This token's purpose is unknown, and it may be an alias of another token; if you know
/// what it does, please open an issue on the issue tracker.**
#[token_de(token = "NO_DEFAULT_IMPROVEMENTS")]
pub no_default_improvements: Option<()>,
/// The background of the tile will be colored, instead of the foreground.
#[token_de(token = "INVERTED_TILE")]
pub inverted_tile: Option<()>,
/// According to Toady, "only custom reactions are used to make this item". Found on scrolls and
/// quires.
#[token_de(token = "NO_DEFAULT_JOB")]
pub no_default_job: Option<()>,
/// Defines the task performed using the tool.
#[token_de(token = "TOOL_USE")]
pub tool_use: Vec<ToolUseEnum>,
/// Allows item to be stored in a furniture stockpile.
#[token_de(token = "FURNITURE")]
pub furniture: Option<()>,
// TODO: ref is shape category
#[token_de(token = "SHAPE_CATEGORY")]
pub shape_category: Option<Reference>,
/// Used on dice.
#[token_de(token = "USES_FACE_IMAGE_SET")]
pub uses_face_image_set: Option<()>,
/// Adjective preceding the material name (e.g. "large copper dagger")
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// How much the item can contain. Defaults to 0.
#[token_de(token = "CONTAINER_CAPACITY")]
pub container_capacity: Option<u32>,
/// Required for weapons.
#[token_de(token = "SHOOT_FORCE")]
pub shoot_force: Option<u32>,
/// Required for weapons.
#[token_de(token = "SHOOT_MAXVEL")]
pub shoot_maxvel: Option<u32>,
/// The skill to determine effectiveness in melee with this tool. Required for weapons.
#[token_de(token = "SKILL")]
pub skill: Option<SkillEnum>,
/// Makes this tool a ranged weapon that uses the specified ammo. The specified skill
/// determines accuracy in ranged combat.
#[token_de(token = "RANGED")]
pub ranged: Option<(SkillEnum, ReferenceTo<AmmoToken>)>,
/// Creatures under this size (in cm^3) must use the tool two-handed. Required for weapons.
#[token_de(token = "TWO_HANDED")]
pub two_handed: Option<u32>,
/// Minimum body size (in cm^3) to use the tool at all (multigrasp required until `TWO_HANDED`
/// value). Required for weapons.
#[token_de(token = "MINIMUM_SIZE")]
pub minimum_size: Option<u32>,
/// Number of bar units needed for forging, as well as the amount gained from melting. Required
/// for weapons.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>,
/// You can have many `ATTACK` tags and one will be randomly selected for each attack, with
/// `EDGE` attacks 100 times more common than `BLUNT` attacks. Required for weapons.
#[token_de(token = "ATTACK")]
pub attack: Vec<WeaponAttack>,
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum ToolUseEnum {
/// Cauldron adventure mode decoration / weapon
#[token_de(token = "LIQUID_COOKING")]
LiquidCooking,
/// Ladle, an adventure mode decoration/weapon.
#[token_de(token = "LIQUID_SCOOP")]
LiquidScoop,
/// Mortar, an adventure mode decoration/weapon.
#[token_de(token = "GRIND_POWDER_RECEPTACLE")]
GrindPowderReceptacle,
/// Pestle, an adventure mode decoration/weapon.
#[token_de(token = "GRIND_POWDER_GRINDER")]
GrindPowderGrinder,
/// Carving knife, an adventure mode decoration/weapon.
#[token_de(token = "MEAT_CARVING")]
MeatCarving,
/// Boning knife, an adventure mode decoration/weapon.
#[token_de(token = "MEAT_BONING")]
MeatBoning,
/// Slicing knife, an adventure mode decoration/weapon.
#[token_de(token = "MEAT_SLICING")]
MeatSlicing,
/// Meat cleaver, an adventure mode decoration/weapon.
#[token_de(token = "MEAT_CLEAVING")]
MeatCleaving,
/// Carving fork, an adventure mode decoration/weapon.
#[token_de(token = "HOLD_MEAT_FOR_CARVING")]
HoldMeatForCarving,
/// Bowl, an adventure mode decoration/weapon.
#[token_de(token = "MEAL_CONTAINER")]
MealContainer,
/// Nest box for your birds to lay eggs.
#[token_de(token = "NEST_BOX")]
NestBox,
/// Jug; can store honey or oil.
#[token_de(token = "LIQUID_CONTAINER")]
LiquidContainer,
/// Large pot; can store beer.
#[token_de(token = "FOOD_STORAGE")]
FoodStorage,
/// Hive; can make honey.
#[token_de(token = "HIVE")]
Hive,
/// Pouch, an adventure mode coin purse.
#[token_de(token = "SMALL_OBJECT_STORAGE")]
SmallObjectStorage,
/// Minecart; item hauling/weapon.
#[token_de(token = "TRACK_CART")]
TrackCart,
/// Wheelbarrow; allows hauling items faster.
#[token_de(token = "HEAVY_OBJECT_HAULING")]
HeavyObjectHauling,
/// Stepladder, allows gathering fruit from trees.
#[token_de(token = "STAND_AND_WORK_ABOVE")]
StandAndWorkAbove,
/// Scroll rollers.
#[token_de(token = "ROLL_UP_SHEET")]
RollUpSheet,
/// Book binding.
#[token_de(token = "PROTECT_FOLDED_SHEETS")]
ProtectFoldedSheets,
/// Scroll & quire.
#[token_de(token = "CONTAIN_WRITING")]
ContainWriting,
/// Bookcase.
#[token_de(token = "BOOKCASE")]
Bookcase,
/// Pedestal & display case for museums.
#[token_de(token = "DISPLAY_OBJECT")]
DisplayObject,
/// Altar for (eventually) offering sacrifices.
#[token_de(token = "PLACE_OFFERING")]
PlaceOffering,
/// Dice.
#[token_de(token = "DIVINATION")]
Divination,
/// Dice.
#[token_de(token = "GAMES_OF_CHANCE")]
GamesOfChance,
}
impl Default for ToolUseEnum {
fn default() -> Self {
Self::LiquidCooking
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum ImprovementTypeWithMatFlagTokenArg {
// TODO: token should be marked as deprecated/unused/ignored by the game, see #83
// #[token_de(token = "ART_IMAGE")]
// ArtImage,
// #[token_de(token = "COVERED")]
Covered(ImprovementMaterialFlagEnum),
// #[token_de(token = "RINGS_HANGING")]
RingsHanging(ImprovementMaterialFlagEnum),
// #[token_de(token = "BANDS")]
Bands(ImprovementMaterialFlagEnum),
// #[token_de(token = "SPIKES")]
Spikes(ImprovementMaterialFlagEnum),
// #[token_de(token = "SPECIFIC", alias = "ITEMSPECIFIC")]
Specific((ItemSpecificEnum, ImprovementMaterialFlagEnum)),
// TODO: token should be marked as deprecated/unused/ignored by the game, see #83
// #[token_de(token = "THREAD")]
// Thread,
// TODO: token should be marked as deprecated/unused/ignored by the game, see #83
// #[token_de(token = "CLOTH")]
// Cloth,
// TODO: token should be marked as deprecated/unused/ignored by the game, see #83
// #[token_de(token = "SEWN_IMAGE")]
// SewnImage,
// #[token_de(token = "PAGES")]
Pages(ImprovementMaterialFlagEnum),
// TODO: token should be marked as deprecated/unused/ignored by the game, see #83
// #[token_de(token = "ILLUSTRATION")]
// Illustration,
// #[token_de(token = "INSTRUMENT_PIECE")]
InstrumentPiece((Reference, ImprovementMaterialFlagEnum)), // Ref to INSTRUMENT PIECE, distinct from ITEM_INSTRUMENT
// #[token_de(token = "WRITING")]
Writing(ImprovementMaterialFlagEnum),
// TODO: token should be marked as deprecated/unused/ignored by the game, see #83
// #[token_de(token = "IMAGE_SET")]
// ImageSet,
}
impl Default for ImprovementTypeWithMatFlagTokenArg {
fn default() -> Self {
Self::Covered(ImprovementMaterialFlagEnum::default())
}
}
// Deserialize a token with following pattern: `[REF:improvement_type_token_arg:...]`
df_ls_syntax_analysis::token_deserialize_unary_token!(ImprovementTypeWithMatFlagTokenArg);
impl TryFromArgumentGroup for ImprovementTypeWithMatFlagTokenArg {
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() {
"COVERED" => {
let covered = ImprovementMaterialFlagEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::Covered(covered)
}
"RINGS_HANGING" => {
let rings_hanging = ImprovementMaterialFlagEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::RingsHanging(rings_hanging)
}
"BANDS" => {
let bands = ImprovementMaterialFlagEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::Bands(bands)
}
"SPIKES" => {
let spikes = ImprovementMaterialFlagEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::Spikes(spikes)
}
// TODO: add alias warning
"SPECIFIC" | "ITEMSPECIFIC" => {
let specific =
<(ItemSpecificEnum, ImprovementMaterialFlagEnum)>::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::Specific(specific)
}
"PAGES" => {
let pages = ImprovementMaterialFlagEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::Pages(pages)
}
"INSTRUMENT_PIECE" => {
let instrument_piece =
<(Reference, ImprovementMaterialFlagEnum)>::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::InstrumentPiece(instrument_piece)
}
"WRITING" => {
let writing = ImprovementMaterialFlagEnum::try_from_argument_group(
token,
source,
diagnostics,
add_diagnostics_on_err,
)?;
ImprovementTypeWithMatFlagTokenArg::Writing(writing)
}
_ => {
Self::diagnostics_wrong_enum_type(
&arg0?,
vec![
"COVERED",
"RINGS_HANGING",
"BANDS",
"SPIKES",
"SPECIFIC",
"ITEMSPECIFIC",
"PAGES",
"INSTRUMENT_PIECE",
"WRITING",
],
source,
diagnostics,
add_diagnostics_on_err,
);
return Err(());
}
};
Ok(bp_criteria)
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum ItemSpecificEnum {
#[token_de(token = "ROLLERS")]
Rollers,
#[token_de(token = "HANDLE")]
Handle,
}
impl Default for ItemSpecificEnum {
fn default() -> Self {
Self::Rollers
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum ImprovementMaterialFlagEnum {
/// Permits the improvement to be made from any bone.
#[token_de(token = "BONE_MAT")]
BoneMat,
/// Permits the improvement to be made from any ceramic material.
#[token_de(token = "CERAMIC_MAT")]
CeramicMat,
/// Permits the improvement to be made from any glass.
#[token_de(token = "GLASS_MAT")]
GlassMat,
/// Permits the improvement to be made from anything with the `[ITEMS_HARD]` token, such as wood, stone
/// or metal.
#[token_de(token = "HARD_MAT")]
HardMat,
/// Permits the improvement to be made from any leather.
#[token_de(token = "LEATHER_MAT")]
LeatherMat,
/// Permits the improvement to be made from anything with the `[IS_METAL]` token.
#[token_de(token = "METAL_MAT")]
MetalMat,
/// Permits the improvement to be made from any metal with the `[ITEMS_WEAPON]` token.
#[token_de(token = "METAL_WEAPON_MAT")]
MetalWeaponMat,
/// Permits the improvement to be made from any "sheet" material, such as papyrus, paper, and
/// parchment. May be connected to the `PAPER_SLURRY`/`PAPER_PLANT` reaction classes,
/// but this is not verified.
#[token_de(token = "SHEET_MAT")]
SheetMat,
/// Permits the improvement to be made from any shell.
#[token_de(token = "SHELL_MAT")]
ShellMat,
/// Permits the improvement to be made from any silk.
#[token_de(token = "SILK_MAT")]
SilkMat,
/// Permits the improvement to be made from any material with the `[ITEMS_SOFT]` token, such as leather
/// or textiles.
#[token_de(token = "SOFT_MAT")]
SoftMat,
/// Permits the improvement to be made from any stone. Presumably connected to the `[IS_STONE]` token.
#[token_de(token = "STONE_MAT")]
StoneMat,
/// Permits the improvement to be made from any plant fiber, such as pig tails.
#[token_de(token = "THREAD_PLANT_MAT")]
ThreadPlantMat,
/// Permits the improvement to be made from any wood.
#[token_de(token = "WOOD_MAT")]
WoodMat,
}
impl Default for ImprovementMaterialFlagEnum {
fn default() -> Self {
Self::BoneMat
}
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct ToyToken {
/// Argument 1 of `[ITEM_TOY:...]`
#[token_de(token = "ITEM_TOY", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// Presumably prevents the item from being made from cloth, silk, or leather, present on
/// everything but puzzleboxes and drums. Appears to work backwards for strange moods.
#[token_de(token = "HARD_MAT")]
pub hard_mat: Option<()>,
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct TrapCompToken {
/// Argument 1 of `[ITEM_TRAPCOMP:...]`
#[token_de(token = "ITEM_TRAPCOMP", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// What this item will be called in-game.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>,
/// How much material is needed to make the item. Is most important with bars.
/// The number of bars needed is the value divided by three.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>, // TODO: required
/// Appears before the name of the weapon's material. For example: "menacing steel spike".
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// How large the item is. Defaults to 100.
#[token_de(token = "SIZE")]
pub size: Option<u32>,
/// Number of times it hits. Defaults to 1
#[token_de(token = "HITS")]
pub hits: Option<u32>,
/// Weapon may be installed in a screw pump.
#[token_de(token = "IS_SCREW")]
pub is_screw: Option<()>,
/// Weapon may be installed in a spike trap.
#[token_de(token = "IS_SPIKE")]
pub is_spike: Option<()>,
/// Weapon may be made out of wood.
#[token_de(token = "WOOD")]
pub wood: Option<()>,
/// Weapon may be made out of metal.
#[token_de(token = "METAL")]
pub metal: Option<()>,
/// Sets the attack characteristics of the weapon
#[token_de(token = "ATTACK")]
pub attack: Option<ItemAttack>,
}
#[derive(
Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq, Referenceable,
)]
pub struct WeaponToken {
/// Argument 1 of `[ITEM_WEAPON:...]`
#[token_de(token = "ITEM_WEAPON", on_duplicate_to_parent, primary_token)]
#[referenceable(self_reference)]
pub reference: Option<ReferenceTo<Self>>,
/// Name of the weapon.
#[token_de(token = "NAME")]
pub name: Option<(String, String)>, // TODO: required
/// Number of bar units needed for forging, as well as the amount gained from melting.
#[token_de(token = "MATERIAL_SIZE")]
pub material_size: Option<u32>, // TODO: Required
/// Adjective of the weapon, e.g. the "large" in "large copper dagger".
#[token_de(token = "ADJECTIVE")]
pub adjective: Option<String>,
/// Volume of weapon in mL or cubic cm. Defaults to 100.
#[token_de(token = "SIZE")]
pub size: Option<u32>,
/// The amount of force used when firing projectiles - velocity is presumably determined by the
/// projectile's mass. Defaults to 0.
#[token_de(token = "SHOOT_FORCE")]
pub shoot_force: Option<u32>,
/// The maximum speed a fired projectile can have.
#[token_de(token = "SHOOT_MAXVEL")]
pub shoot_maxvel: Option<u32>,
/// The skill to determine effectiveness in melee with this weapon. Defaults to `MACE`.
///
/// Skill of `AXE` will allow it to be used to chop down trees. Skill of `MINER` will allow
/// it to be used for mining.
///
/// Outsider adventurers (or regular ones with no points in offensive skills) will receive a
/// weapon with the `SPEAR` skill, selected at random if multiple ones have been modded in.
/// All adventurers will also start with a weapon using the `DAGGER` skill, again selected at
/// random if multiple such weapons exist.
#[token_de(token = "SKILL")]
pub skill: Option<SkillEnum>,
/// Makes this a ranged weapon that uses the specified ammo. The specified skill determines
/// accuracy in ranged combat.
#[token_de(token = "RANGED")]
pub ranged: Option<(SkillEnum, Reference)>, // `TODO` reference is ammo class
/// Creatures under this size (in cm^3) must use the weapon two-handed. Defaults to 50000.
#[token_de(token = "TWO_HANDED")]
pub two_handed: Option<u32>,
/// Minimum body size (in cm^3) to use the weapon at all (multigrasp required until `TWO_HANDED`
/// value). Defaults to 40000.
#[token_de(token = "MINIMUM_SIZE")]
pub minimum_size: Option<u32>,
/// Allows the weapon to be made at a craftsdwarf's workshop from a sharp (`[MAX_EDGE:10000]` or
/// higher) stone (i.e. obsidian) plus a wood log.
#[token_de(token = "CAN_STONE")]
pub can_stone: Option<()>,
/// Restricts this weapon to being made of wood.
#[token_de(token = "TRAINING")]
pub training: Option<()>,
/// List of attacks this weapon can have.
#[token_de(token = "ATTACK")]
pub attack: Vec<WeaponAttack>,
}
// region: Attack definitions
/// Specifies the attack characteristics of this item.
/// - attack type: `BLUNT` or `EDGE`
/// - contact_area: value
/// - penetration_size: value
/// - verb2nd: string
/// - verb3rd: string
/// - noun: string or `NO_SUB`
/// - velocity_multiplier: value
#[derive(Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq)]
pub struct ItemAttack {
/// Arguments of the `ATTACK` token
#[token_de(token = "ATTACK")]
pub attack: Option<(
AttackTypeEnum,
u32,
u32,
String,
String,
Choose<NoSubEnum, String>,
u32,
)>,
/// Determines the length of time to prepare this attack and until one can perform this attack
/// again. Values appear to be calculated in adventure mode ticks.
#[token_de(token = "ATTACK_PREPARE_AND_RECOVER")]
pub attack_prepare_and_recover: Option<(u32, u32)>,
}
/// Defines an attack on this weapon.
/// You can have many `ATTACK` tags and one will be randomly selected for each attack, with `EDGE`
/// attacks used 100 times more often than `BLUNT` attacks.
///
/// Contact area is usually high for slashing and low for bludgeoning, piercing, and poking.
/// Penetration value tends to be low for slashing and high for stabbing. Penetration is ignored if
/// attack is `BLUNT`.
/// - attack type: `BLUNT` or `EDGE`
/// - contact_area: value
/// - penetration_size: value
/// - verb2nd: string
/// - verb3rd: string
/// - noun: string or `NO_SUB`
/// - velocity_multiplier: value
#[derive(Serialize, Deserialize, Clone, Debug, Default, TokenDeserialize, PartialEq, Eq)]
pub struct WeaponAttack {
/// Arguments of the `ATTACK` token
#[token_de(token = "ATTACK", on_duplicate_to_parent, primary_token)]
pub attack: Option<(
AttackTypeEnum,
u32,
u32,
String,
String,
Choose<NoSubEnum, String>,
u32,
)>,
/// Determines the length of time to prepare this attack and until one can perform this attack
/// again. Values appear to be calculated in adventure mode ticks.
#[token_de(token = "ATTACK_PREPARE_AND_RECOVER")]
pub attack_prepare_and_recover: Option<(u32, u32)>,
/// Multiple strikes with this attack cannot be performed effectively.
#[token_de(token = "ATTACK_FLAG_BAD_MULTIATTACK")]
pub attack_flag_bad_multiattack: Option<()>,
/// Multiple strikes with this attack can be performed with no penalty.
#[token_de(token = "ATTACK_FLAG_INDEPENDENT_MULTIATTACK")]
pub attack_flag_independent_multiattack: Option<()>,
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum AttackTypeEnum {
#[token_de(token = "EDGE")]
Edge,
#[token_de(token = "BLUNT")]
Blunt,
}
impl Default for AttackTypeEnum {
fn default() -> Self {
Self::Edge
}
}
#[derive(Serialize, Deserialize, Clone, Debug, TokenDeserialize, PartialEq, Eq)]
#[token_de(enum_value)]
pub enum NoSubEnum {
#[token_de(token = "NO_SUB")]
NoSub,
}
impl Default for NoSubEnum {
fn default() -> Self {
Self::NoSub
}
}
// endregion