117 lines
3.5 KiB
Rust
117 lines
3.5 KiB
Rust
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<String>,
|
|
pub file_position: FilePosition,
|
|
}
|
|
|
|
impl Tag {
|
|
fn parse_value<T: SliceParse>(&self) -> Result<T, ParseError> {
|
|
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<Self, ParseError> {
|
|
let mut result = Self {
|
|
id: header.parse_value::<String>().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<u32>,
|
|
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<Self, ParseError> {
|
|
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)
|
|
}
|
|
}
|