gdritter repos delve / master
Split out card stuff to separate module, more docs Getty Ritter 6 years ago
3 changed file(s) with 137 addition(s) and 121 deletion(s). Collapse all Expand all
1 use failure;
2 use rrecutils;
3
4 /// A `Card` always has a name, an icon, and some miscellaneous other information
5 #[derive(Debug)]
6 pub struct Card<'a> {
7 pub name: &'a str,
8 pub icon: String,
9 pub card_type: CardType<'a>,
10 }
11
12 /// Different card types have different miscellaneous other pieces of
13 /// information, but most of them are kept in a catch-all "Generic"
14 /// case
15 #[derive(Debug)]
16 pub enum CardType<'a> {
17 Monster {
18 hp: &'a str,
19 melee: Option<&'a str>,
20 ranged: Option<&'a str>,
21 arcane: Option<&'a str>,
22 defense: Option<&'a str>,
23 action: &'a str,
24 effect: &'a str,
25 },
26 Weapon {
27 weapon_type: WeaponType,
28 ability: &'a str,
29 effect: &'a str,
30 },
31 Generic {
32 kind: Kind,
33 effect: &'a str,
34 },
35 }
36
37 #[derive(Debug, Clone, Copy)]
38 pub enum Kind { Ability, Equipment, Item, Plant, Treasure }
39
40 #[derive(Debug, Clone, Copy)]
41 pub enum WeaponType { Melee, Ranged, Arcane }
42
43 impl<'a> Card<'a> {
44 /// Here we parse out our in-program `Card` type from the recutils
45 /// storage format of the card
46 pub fn from_record(rec: &'a rrecutils::Record)
47 -> Result<Card<'a>, failure::Error>
48 {
49 let name = rec.get("Name")?;
50 // If this doesn't have a Type set by the Recutils parser,
51 // then that's a problem!
52 let typ = rec.get_type()?;
53
54 let card_type = match typ {
55 "Weapon" => CardType::Weapon {
56 weapon_type: match rec.get("Type")? {
57 "melee" => WeaponType::Melee,
58 "ranged" => WeaponType::Ranged,
59 // XXX FIXME IN THE FILE (but for ease of writing
60 // this assumes that we might keep using the old
61 // "magic" terminology instead of "arcane")
62 "magic" | "arcane" => WeaponType::Arcane,
63 t => bail!("Unknown weapon type: {}", t),
64 },
65 ability: rec.get("Ability")?,
66 effect: rec.get("Effect")?,
67 },
68
69 "Monster" => CardType::Monster {
70 hp: rec.get("HP")?,
71 melee: rec.get("Melee").ok(),
72 ranged: rec.get("Ranged").ok(),
73 arcane: rec.get("Arcane").ok(),
74 defense: rec.get("Defense").ok(),
75 action: rec.get("Action")?,
76 effect: rec.get("Effect")?,
77 },
78
79 t => CardType::Generic {
80 kind: match t {
81 "Ability" => Kind::Ability,
82 "Item" => Kind::Item,
83 "Equipment" => Kind::Equipment,
84 "Plant" => Kind::Plant,
85 "Treasure" => Kind::Treasure,
86 _ => bail!("Unknown card type: {}", t),
87 },
88 effect: rec.get("Effect")?,
89 }
90 };
91
92
93 let lower_type = typ.to_lowercase();
94 let icon = format!(
95 "../icons/{}-icon.svg",
96 rec.get("Icon").unwrap_or(
97 match typ {
98 "Weapon" => rec.get("Type")?,
99 _ => &lower_type,
100 }
101 ),
102 );
103
104 Ok(Card { name, icon, card_type })
105 }
106
107 pub fn type_name(&self) -> &'static str {
108 match self.card_type {
109 CardType::Weapon { .. } => "weapon",
110 CardType::Monster { .. } => "monster",
111 CardType::Generic { kind, .. } => match kind {
112 Kind::Ability => "ability",
113 Kind::Item => "item",
114 Kind::Equipment => "equipment",
115 Kind::Plant => "plant",
116 Kind::Treasure => "treasure",
117 },
118 }
119 }
120
121 pub fn card_name(&self) -> String {
122 self.name.chars().filter_map(|c| {
123 if c == ' '{
124 Some('_')
125 } else if c.is_alphabetic() {
126 Some(c.to_ascii_lowercase())
127 } else {
128 None
129 }
130 }).collect()
131 }
132 }
66 extern crate rsvg;
77
88 mod markup;
9 mod data;
910
1011 use markup::Weight;
1112
1415
1516 const SCALE: i32 = 3;
1617
17 #[derive(Debug)]
18 struct Card<'a> {
19 name: &'a str,
20 icon: String,
21 card_type: CardType<'a>,
22 }
23
24 #[derive(Debug)]
25 enum CardType<'a> {
26 Monster {
27 hp: &'a str,
28 melee: Option<&'a str>,
29 ranged: Option<&'a str>,
30 arcane: Option<&'a str>,
31 defense: Option<&'a str>,
32 action: &'a str,
33 effect: &'a str,
34 },
35 Weapon {
36 weapon_type: WeaponType,
37 ability: &'a str,
38 effect: &'a str,
39 },
40 Generic {
41 kind: Kind,
42 effect: &'a str,
43 },
44 }
45
46 #[derive(Debug, Clone, Copy)]
47 enum Kind { Ability, Equipment, Item, Plant, Treasure }
48
49 #[derive(Debug, Clone, Copy)]
50 enum WeaponType { Melee, Ranged, Arcane }
51
52 impl<'a> Card<'a> {
53 fn from_record(rec: &'a rrecutils::Record)
54 -> Result<Card<'a>, failure::Error>
55 {
56 let name = rec.get("Name")?;
57 let typ = rec.get_type()?;
58
59 let card_type = match typ {
60 "Weapon" => CardType::Weapon {
61 weapon_type: match rec.get("Type")? {
62 "melee" => WeaponType::Melee,
63 "ranged" => WeaponType::Ranged,
64 "magic" | "arcane" => WeaponType::Arcane,
65 t => bail!("Unknown weapon type: {}", t),
66 },
67 ability: rec.get("Ability")?,
68 effect: rec.get("Effect")?,
69 },
70 "Monster" => CardType::Monster {
71 hp: rec.get("HP")?,
72 melee: rec.get("Melee").ok(),
73 ranged: rec.get("Ranged").ok(),
74 arcane: rec.get("Arcane").ok(),
75 defense: rec.get("Defense").ok(),
76 action: rec.get("Action")?,
77 effect: rec.get("Effect")?,
78 },
79 t => CardType::Generic {
80 kind: match t {
81 "Ability" => Kind::Ability,
82 "Item" => Kind::Item,
83 "Equipment" => Kind::Equipment,
84 "Plant" => Kind::Plant,
85 "Treasure" => Kind::Treasure,
86 _ => bail!("Unknown card type: {}", t),
87 },
88 effect: rec.get("Effect")?,
89 }
90 };
91
92
93 let lower_type = typ.to_lowercase();
94 let icon = format!(
95 "../icons/{}-icon.svg",
96 rec.get("Icon").unwrap_or(
97 match typ {
98 "Weapon" => rec.get("Type")?,
99 _ => &lower_type,
100 }
101 ),
102 );
103
104 Ok(Card { name, icon, card_type })
105 }
106
107 fn type_name(&self) -> &'static str {
108 match self.card_type {
109 CardType::Weapon { .. } => "weapon",
110 CardType::Monster { .. } => "monster",
111 CardType::Generic { kind, .. } => match kind {
112 Kind::Ability => "ability",
113 Kind::Item => "item",
114 Kind::Equipment => "equipment",
115 Kind::Plant => "plant",
116 Kind::Treasure => "treasure",
117 },
118 }
119 }
120
121 fn card_name(&self) -> String {
122 self.name.chars().filter_map(|c| {
123 if c == ' '{
124 Some('_')
125 } else if c.is_alphabetic() {
126 Some(c.to_ascii_lowercase())
127 } else {
128 None
129 }
130 }).collect()
131 }
132 }
133
134 fn draw_card(card: &Card) -> Result<(), failure::Error> {
135 use CardType::*;
18 fn draw_card(card: &data::Card) -> Result<(), failure::Error> {
19 use data::CardType::*;
13620
13721 let surf = cairo::ImageSurface::create(
13822 cairo::Format::Rgb24,
246130
247131 for w in recfile.iter() {
248132 if w.rec_type.is_some() {
249 let card = Card::from_record(w)?;
133 let card = data::Card::from_record(w)?;
250134 draw_card(&card)?;
251135 }
252136 }
124124 }
125125
126126 /// Add a string with the extra markup supplied
127 pub fn push(self, s: &str) {
127 pub fn push(&mut self, s: &str) {
128128 self.view.push("<span ");
129129 for f in self.frags.iter() {
130130 match f {