gdritter repos delve / 22e49e3
Use parsed card repr to simplify rendering logic Getty Ritter 6 years ago
2 changed file(s) with 83 addition(s) and 73 deletion(s). Collapse all Expand all
88 pangocairo = "0.5.0"
99 png = "0.11.0"
1010 failure = "0.1.1"
11 heck = "0.3.0"
1211 rsvg = "0.4.0"
1312
1413 [dependencies.cairo-rs]
11 extern crate cairo;
22 #[macro_use] extern crate failure;
3 extern crate heck;
43 extern crate pango;
54 extern crate pangocairo;
65 extern crate rrecutils;
76 extern crate rsvg;
87
98 use std::{fs,io};
10 use heck::TitleCase;
119 use pango::LayoutExt;
1210 use rsvg::HandleExt;
1311
4240 },
4341 }
4442
45 #[derive(Debug)]
43 #[derive(Debug, Clone, Copy)]
4644 enum Kind { Ability, Equipment, Item, Plant, Treasure }
4745
48 #[derive(Debug)]
46 #[derive(Debug, Clone, Copy)]
4947 enum WeaponType { Melee, Ranged, Arcane }
5048
5149 impl<'a> Card<'a> {
5351 -> Result<Card<'a>, failure::Error>
5452 {
5553 let name = rec.get("Name")?;
56
57 let card_type = match rec.get_type()? {
54 let typ = rec.get_type()?;
55
56 let card_type = match typ {
5857 "Weapon" => CardType::Weapon {
5958 weapon_type: match rec.get("Type")? {
6059 "melee" => WeaponType::Melee,
8887 };
8988
9089
91 let icon = format!("icon");
90 let lower_type = typ.to_lowercase();
91 let icon = format!(
92 "../icons/{}-icon.svg",
93 rec.get("Icon").unwrap_or(
94 match typ {
95 "Weapon" => rec.get("Type")?,
96 _ => &lower_type,
97 }
98 ),
99 );
92100
93101 Ok(Card { name, icon, card_type })
94102 }
95 }
96
97 fn draw_card(rec: &rrecutils::Record) -> Result<(), failure::Error> {
98 let typ = match rec.rec_type {
99 Some(ref t) => t,
100 None => return Ok(()),
101 };
102 let _ = Card::from_record(rec)?;
103 let name = rec.get("Name")?;
103
104 fn type_name(&self) -> &'static str {
105 match self.card_type {
106 CardType::Weapon { .. } => "weapon",
107 CardType::Monster { .. } => "monster",
108 CardType::Generic { kind, .. } => match kind {
109 Kind::Ability => "ability",
110 Kind::Item => "item",
111 Kind::Equipment => "equipment",
112 Kind::Plant => "plant",
113 Kind::Treasure => "treasure",
114 },
115 }
116 }
117
118 fn card_name(&self) -> String {
119 self.name.chars().filter_map(|c| {
120 if c == ' '{
121 Some('_')
122 } else if c.is_alphabetic() {
123 Some(c.to_ascii_lowercase())
124 } else {
125 None
126 }
127 }).collect()
128 }
129 }
130
131
132
133 fn draw_card(card: &Card) -> Result<(), failure::Error> {
134 use CardType::*;
104135
105136 let surf = cairo::ImageSurface::create(
106137 cairo::Format::Rgb24,
129160 layout.set_font_description(&font);
130161
131162 ctx.move_to(100.0, 8.0);
132 let title = match typ.as_ref() {
133 "Weapon" => format!(
134 "{} (Weapon, {})",
135 name,
136 rec.get("Type")?
137 .to_title_case(),
138 ),
139 "Ability" | "Equipment" | "Item" | "Plant" | "Treasure" =>
140 format!("{} ({})", name, typ),
141 "Monster" => {
163 let title = match card.card_type {
164 Weapon { ref weapon_type, .. } =>
165 format!("{} (Weapon, {:?})", card.name, weapon_type),
166 Monster { ref hp, ref melee, ref ranged, ref arcane, ref defense, .. } => {
142167 let mut buf = String::new();
143 let hp = rec.get("HP")?;
144 buf.push_str(&format!("{} (Beast <span font='8' font_weight='heavy'>HP</span>{}", name, hp));
145 if let Ok(m) = rec.get("Melee") {
168 buf.push_str(&format!(
169 "{} (Beast <span font='8' font_weight='heavy'>HP</span>{}",
170 card.name,
171 hp,
172 ));
173 if let &Some(ref m) = melee {
146174 buf.push_str(&format!(" <span font='8' font_weight='heavy'>M</span>{}", m));
147175 }
148 if let Ok(m) = rec.get("Ranged") {
176 if let &Some(ref m) = ranged {
149177 buf.push_str(&format!(" <span font='8' font_weight='heavy'>R</span>{}", m));
150178 }
151 if let Ok(m) = rec.get("Arcane") {
179 if let &Some(ref m) = arcane {
152180 buf.push_str(&format!(" <span font='8' font_weight='heavy'>A</span>{}", m));
153181 }
154 if let Ok(m) = rec.get("Defense") {
182 if let &Some(ref m) = defense {
155183 buf.push_str(&format!(" <span font='8' font_weight='heavy'>D</span>{}", m));
156184 }
157185 buf.push_str(")");
158
159186 buf
160187 }
161 _ => bail!("Unknown type: {}", typ),
188 Generic { ref kind, .. } => format!("{} ({:?})", card.name, kind),
162189 };
163190
164191 let (attrs, text, _) = pango::parse_markup(&title, '\0')?;
176203
177204 let (attrs, text, _) = {
178205 let mut buf = String::new();
179 match typ.as_ref() {
180 "Weapon" => {
206 match card.card_type {
207 Weapon { ability, effect, .. } => {
181208 buf.push_str("<span font_weight=\"bold\">");
182 buf.push_str(rec.get("Ability")?);
209 buf.push_str(ability);
183210 buf.push_str(":</span> ");
184 buf.push_str(rec.get("Effect")?);
185 }
186 "Ability" | "Equipment" | "Item" | "Plant" | "Treasure" =>
187 buf.push_str(rec.get("Effect")?),
188 "Monster" => {
211 buf.push_str(effect);
212 },
213 Monster { action, effect, .. } => {
189214 buf.push_str("<span font_weight=\"bold\">");
190 buf.push_str(rec.get("Action")?);
215 buf.push_str(action);
191216 buf.push_str(":</span> ");
192 buf.push_str(rec.get("Effect")?);
193 }
194 _ => bail!("Unknown type: {}", typ),
217 buf.push_str(effect);
218 },
219 Generic { effect, .. } => {
220 buf.push_str(effect);
221 },
195222 }
196223 pango::parse_markup(&buf, '\0')?
197224 };
200227 layout.set_text(&text);
201228 pangocairo::functions::show_layout(&ctx, &layout);
202229
203 let special_icon = rec.get("Icon").map(|i| format!("../icons/{}-icon.svg", i));
204 let icon_path = special_icon.unwrap_or(format!(
205 "../icons/{}-icon.svg",
206 match typ.as_ref() {
207 "Weapon" => rec.get("Type")?.to_owned(),
208 _ => typ.to_lowercase(),
209 },
210 ));
211 let icon = rsvg::Handle::new_from_file(&icon_path)
212 .map_err(|_| format_err!("Error loading image: {}", icon_path))?;
230 let icon = rsvg::Handle::new_from_file(&card.icon)
231 .map_err(|_| format_err!("Error loading image: {}", card.icon))?;
213232 ctx.translate(10.0, 10.0);
214233 ctx.scale(0.9, 0.9);
215234 icon.render_cairo(&ctx);
216235
217236
218 {
219 let name = name.chars().filter_map(|c| {
220 if c == ' ' {
221 Some('_')
222 } else if c.is_alphabetic() {
223 Some(c.to_ascii_lowercase())
224 } else {
225 None
226 }
227 }).collect::<String>();
228 let path = format!("cards/{}_{}.png", typ.to_lowercase(), name);
229 let mut f = fs::File::create(&path)?;
230 println!("Writing to {}", path);
231 surf.write_to_png(&mut f)?;
232 }
237 let path = format!("cards/{}_{}.png", card.type_name(), card.card_name());
238 let mut f = fs::File::create(&path)?;
239 println!("Writing to {}", path);
240 surf.write_to_png(&mut f)?;
233241
234242 Ok(())
235243 }
239247 let recfile = rrecutils::Recfile::parse(&mut f)?;
240248
241249 for w in recfile.iter() {
242 draw_card(w)?;
250 if w.rec_type.is_some() {
251 let card = Card::from_record(w)?;
252 draw_card(&card)?;
253 }
243254 }
244255
245256 Ok(())