use parser::{SliceParseError, TagParseError}; use serde::{Deserialize, Serialize}; use self::parser::{FilePosition, ParseError, SliceParse}; pub mod parser; #[derive(Debug)] pub enum TopLevelTag { Site, Creature, } #[derive(Default, Debug, Clone)] pub struct Tag { pub name: String, pub values: Vec, pub file_position: FilePosition, } impl Tag { fn parse_value(&self) -> Result { T::parse(&self.values).map_err(|err| { ParseError::TagParseError(match err { SliceParseError::ParseError => TagParseError::ParseError(self.clone()), SliceParseError::MissingValue => TagParseError::MissingValue(self.clone()), }) }) } } #[derive(Clone, Default, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] pub struct SiteDef { pub id: String, pub min_size: i32, pub max_size: i32, pub is_underground: bool, pub is_natural: bool, } impl SiteDef { pub fn parse(header: Tag, tags: &[Tag]) -> Result { let mut result = Self { id: header.parse_value::().unwrap(), ..Default::default() }; for tag in tags { match tag.name.as_str() { "SIZE" => (result.min_size, result.max_size) = tag.parse_value().unwrap(), "NATURAL" => result.is_natural = true, _ => { eprintln!("Unknown tag '{}' in SITE defs", tag.name); } } } Ok(result) } } #[derive(Clone, Default, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] pub struct CreatureDef { pub id: String, pub name_singular: String, pub name_plural: String, pub health: i32, pub armor_class: i8, pub to_hit_modifier: i8, pub min_damage: i32, pub max_damage: i32, pub multiattack: Option, pub is_humanoid: bool, pub is_animal: bool, pub is_intelligent: bool, pub patrols: bool, pub prefers_dark: bool, pub invulnerable: bool, } impl CreatureDef { pub fn parse(header: Tag, tags: &[Tag]) -> Result { let mut result = Self { id: header.parse_value().unwrap(), ..Default::default() }; for tag in tags { match tag.name.as_str() { "NAME" => (result.name_singular, result.name_plural) = tag.parse_value()?, "HEALTH" => result.health = tag.parse_value()?, "AC" => result.armor_class = tag.parse_value()?, "ATTACK" => { (result.to_hit_modifier, result.min_damage, result.max_damage) = tag.parse_value()? } "MULTIATTACK" => result.multiattack = Some(tag.parse_value()?), "HUMANOID" => result.is_humanoid = true, "ANIMAL" => result.is_animal = true, "INTELLIGENT" => result.is_intelligent = true, "PATROL" => result.patrols = true, "PREFER_DARK" => result.prefers_dark = true, "INVULNERABLE" => result.invulnerable = true, _ => { eprintln!("Unknown tag '{}' in CREATURE defs", tag.name); } } } Ok(result) } pub fn attack_count(&self) -> u32 { self.multiattack.unwrap_or(1) } pub fn damage_roll(&self) -> i32 { fastrand::i32(self.min_damage..=self.max_damage) } }