data/
monster.rs

1//! Data structures and logic about the DMW2 monsters and families
2
3use std::cell::RefCell;
4use std::rc::Rc;
5
6use quick_xml::events::BytesStart;
7use serde::Serialize;
8
9use error::Error;
10use crate::xml::{self, getTagAttr};
11
12/// A location in a map
13#[derive(Clone, Serialize)]
14pub struct MapLocation
15{
16    /// Name of the map. Example: Oasis Key World.
17    pub map: String,
18    /// More detailed location within the map.
19    pub desc: Option<String>,
20}
21
22impl MapLocation
23{
24    /// Parse the location tag. A location tag looks like this:
25    ///
26    /// ```xml
27    /// <location>
28    ///   <map>Oasis Key World</map>
29    ///   <description>Near Door Shrine</description>
30    /// </location>
31    /// ```
32    fn fromXML(x: &[u8]) -> Result<Self, Error>
33    {
34        let mut map = String::new();
35        let mut desc = String::new();
36        let mut p = xml::Parser::new();
37        p.addTextHandler("map", |_, text| {
38            map = text.to_owned();
39            Ok(())
40        });
41        p.addTextHandler("description", |_, text| {
42            desc = text.to_owned();
43            Ok(())
44        });
45        p.parse(x)?;
46        drop(p);
47        Ok(Self {
48            map,
49            desc: if desc.is_empty() { None } else { Some(desc) }
50        })
51    }
52}
53
54/// Monster growth data
55#[derive(Default, Clone, Serialize)]
56pub struct Growth
57{
58    pub agility: u8,
59    pub intelligence: u8,
60    pub max_level: u8,
61    pub attack: u8,
62    pub defense: u8,
63    pub mp: u8,
64    pub exp: u8,
65    pub hp: u8,
66}
67
68impl Growth
69{
70    fn fromXMLTag(tag: &BytesStart) -> Result<Self, Error>
71    {
72        let agility: u8 =  xml::getTagAttr(tag, "agl")?.ok_or_else(
73            || xmlerr!("Agility value not found"))?;
74        let intelligence: u8 =  xml::getTagAttr(tag, "int")?.ok_or_else(
75            || xmlerr!("Inteligence value not found"))?;
76        let max_level: u8 =  xml::getTagAttr(tag, "maxlvl")?.ok_or_else(
77            || xmlerr!("Max level value not found"))?;
78        let attack: u8 =  xml::getTagAttr(tag, "atk")?.ok_or_else(
79            || xmlerr!("Attack value not found"))?;
80        let defense: u8 =  xml::getTagAttr(tag, "def")?.ok_or_else(
81            || xmlerr!("Defense value not found"))?;
82        let mp: u8 =  xml::getTagAttr(tag, "mp")?.ok_or_else(
83            || xmlerr!("MP value not found"))?;
84        let exp: u8 =  xml::getTagAttr(tag, "exp")?.ok_or_else(
85            || xmlerr!("EXP value not found"))?;
86        let hp: u8 =  xml::getTagAttr(tag, "hp")?.ok_or_else(
87            || xmlerr!("HP value not found"))?;
88        Ok(Self {
89            agility, intelligence, max_level, attack, defense, mp, exp, hp,
90        })
91    }
92}
93
94
95/// The info of a monster
96#[derive(Clone, Serialize)]
97pub struct Monster
98{
99    /// Name of the monster
100    pub name: String,
101    /// Whether the monster can be find in the story maps
102    pub in_story: bool,
103    /// Spawn location of the monster. Only monsters with `in_story ==
104    /// true` has this.
105    pub locations: Vec<MapLocation>,
106    /// Natural skills of the monster
107    pub skills: Vec<String>,
108    /// Monster growth data
109    pub growth: Growth,
110    /// Family the monster belongs to
111    pub family: String,
112}
113
114impl Monster
115{
116    fn fromXML(x: &[u8], family: String) -> Result<Self, Error>
117    {
118        let mut name = String::new();
119        let mut in_story = false;
120        let mut locations = Vec::new();
121        let mut skills = Vec::new();
122        let mut growth = Growth::default();
123
124        let mut p = xml::Parser::new();
125        p.addBeginHandler("monster", |_, tag| {
126            name = xml::getTagAttr(tag, "name")?.ok_or_else(
127                || xmlerr!("Monster name value not found"))?;
128            in_story = xml::getTagAttr(tag, "in_story")?.ok_or_else(
129                || xmlerr!("In_story value not found"))?;
130            Ok(())
131        });
132        p.addTagHandler("location", |_, tag| {
133            locations.push(MapLocation::fromXML(tag)?);
134            Ok(())
135        });
136        p.addTextHandler("skill", |_, text| {
137            skills.push(text.to_owned());
138            Ok(())
139        });
140        p.addBeginHandler("growth", |_, tag| {
141            growth = Growth::fromXMLTag(tag)?;
142            Ok(())
143        });
144        p.parse(x)?;
145        drop(p);
146
147        Ok(Self { name, in_story, locations, skills, growth, family})
148    }
149}
150
151/// A family of monsters
152#[derive(Default, Clone, Serialize)]
153pub struct Family
154{
155    /// Name of the family in *lower case*.
156    pub name: String,
157    /// List of name of monsters in this family.
158    pub members: Vec<String>,
159}
160
161/// Data about a set of monsters and families.
162#[derive(Default, Clone, Serialize)]
163pub struct Info
164{
165    /// A list of monsters
166    pub monsters: Vec<Monster>,
167    /// A list of families
168    pub families: Vec<Family>,
169}
170
171impl Info
172{
173    pub fn fromXML(x: &[u8]) -> Result<Self, Error>
174    {
175        let family = Rc::new(RefCell::new(Family::default()));
176        let mut monsters = Vec::new();
177        let mut families = Vec::new();
178
179        let mut p = xml::Parser::new();
180        p.addBeginHandler("family", |_, tag| {
181            family.borrow_mut().name = getTagAttr(tag, "name")?
182                .ok_or_else(|| xmlerr!("Family name not found"))?;
183            Ok(())
184        });
185        p.addEndHandler("family", |_, _| {
186            families.push(family.take());
187            *family.borrow_mut() = Family::default();
188            Ok(())
189        });
190        p.addTagHandler("monster", |_, tag| {
191            let monster = Monster::fromXML(tag, family.borrow().name.clone())?;
192            family.borrow_mut().members.push(monster.name.clone());
193            monsters.push(monster);
194            Ok(())
195        });
196
197        p.parse(x)?;
198        drop(p);
199        Ok(Self { monsters, families })
200    }
201}