1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
use serde::Deserialize;
use serde_yaml;
use std::collections::HashMap;
use std::error::Error;
use std::string::String;
use crate::dice;
#[derive(Debug, Deserialize)]
struct RandomTable {
formula: String,
rows: Vec<TableRow>,
}
#[derive(Debug, Deserialize)]
struct TableRow {
roll: String,
elements: Vec<TableRowElement>,
}
#[derive(Debug, Deserialize)]
enum TableRowElement {
Text(String),
Table(String),
}
pub struct RandomTables {
tables: HashMap<String, RandomTable>,
}
impl RandomTables {
pub fn new() -> Result<Self, Box<dyn Error>> {
let tables_yaml = include_str!("data/random_tables/ua_magic_items.yaml");
let tables: HashMap<String, RandomTable> = serde_yaml::from_str(tables_yaml)?;
Ok(RandomTables { tables })
}
pub fn roll_table(&self, table_name: &str) -> String {
let random_table = self.tables.get(table_name);
if let Some(table) = random_table {
// TODO: Probably return an error instead of using #unwrap.
let roll_result = dice::roll_formula(&table.formula).unwrap();
for table_row in &table.rows {
if let Some((start, end)) = RandomTables::parse_roll(&table_row.roll) {
if start <= roll_result.total() && roll_result.total() <= end {
let mut output_text = String::new();
for element in &table_row.elements {
match element {
TableRowElement::Text(text) => output_text.push_str(text),
TableRowElement::Table(inner_table) => {
let inner_output = self.roll_table(inner_table);
output_text.push_str(&inner_output);
}
}
output_text.push_str(" ");
}
return output_text.trim().to_string();
}
} else {
panic!("Invalid roll format in yaml")
}
}
}
String::new()
}
fn parse_roll(roll: &str) -> Option<(u32, u32)> {
let parts: Vec<&str> = roll.split('-').collect();
match parts.len() {
1 => {
if let Ok(num) = parts[0].parse::<u32>() {
Some((num, num))
} else {
None
}
}
2 => {
if let (Ok(start), Ok(end)) = (parts[0].parse::<u32>(), parts[1].parse::<u32>()) {
Some((start, end))
} else {
None
}
}
_ => None
}
}
}
|