summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/data/rules/magic_items.yaml41
-rw-r--r--src/main.rs1
-rw-r--r--src/rules/classes.rs2
-rw-r--r--src/rules/npcs.rs46
4 files changed, 88 insertions, 2 deletions
diff --git a/src/data/rules/magic_items.yaml b/src/data/rules/magic_items.yaml
index c474cf0..3108e7c 100644
--- a/src/data/rules/magic_items.yaml
+++ b/src/data/rules/magic_items.yaml
@@ -1,3 +1,44 @@
+#####
+# Dummy data, so we can at least generate kinds prior to having all magic items
+# implemented.
+#####
+
+potion:
+ name: "Potion"
+ kind: potion
+
+scroll:
+ name: "Scroll"
+ kind: scroll
+
+ring:
+ name: "Ring"
+ kind: ring
+
+rod_staff_wand:
+ name: "Rod/Staff/Wand"
+ kind: rod_staff_wand
+
+misc:
+ name: "Misc"
+ kind: misc
+
+armor_shield:
+ name: "Armor/Shield"
+ kind: armor_shield
+
+sword:
+ name: "Sword"
+ kind: sword
+
+protection:
+ name: "Protection"
+ kind: ring # Not actually, but this is fine for now.
+
+#####
+# Remainder of file is actual data.
+#####
+
sword_plus_one:
name: "Sword +1"
kind: sword
diff --git a/src/main.rs b/src/main.rs
index 4b2d91e..bc9e200 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -40,6 +40,7 @@ fn main() {
Some(class_ref),
None,
None,
+ Vec::new(),
);
npc.roll_henchman_ability_scores();
diff --git a/src/rules/classes.rs b/src/rules/classes.rs
index d933bc1..1e4c24d 100644
--- a/src/rules/classes.rs
+++ b/src/rules/classes.rs
@@ -12,7 +12,7 @@ pub struct Class {
pub prime_requisites: Vec<AbilityScore>,
#[serde(default)]
pub npc_ability_score_modifiers: HashMap<AbilityScore, i32>,
- pub chances_for_magic: Vec<i32>,
+ pub chances_for_magic: HashMap<String, i32>,
}
lazy_static! {
diff --git a/src/rules/npcs.rs b/src/rules/npcs.rs
index ccf9936..ab111de 100644
--- a/src/rules/npcs.rs
+++ b/src/rules/npcs.rs
@@ -1,9 +1,11 @@
use crate::dice::roll_formula;
use crate::random_tables::RANDOM_TABLES;
use crate::rules::ability_scores::{AbilityScore, AbilityScoreCollection};
-use crate::rules::classes::Class;
+use crate::rules::classes::{Class, CLASSES};
+use crate::rules::magic_items::{MagicItem, MAGIC_ITEMS};
use crate::rules::races::Race;
use log::debug;
+use rand::Rng;
use std::collections::HashMap;
// use std::fmt;
@@ -13,6 +15,7 @@ pub struct Npc {
pub class: Option<&'static Class>,
pub ability_scores: Option<AbilityScoreCollection>,
pub persona: Option<String>,
+ pub magic_items: Vec<&'static MagicItem>,
}
impl Npc {
@@ -22,6 +25,7 @@ impl Npc {
class: Option<&'static Class>,
ability_scores: Option<AbilityScoreCollection>,
persona: Option<String>,
+ magic_items: Vec<&'static MagicItem>,
) -> Self {
Npc {
alignment,
@@ -29,6 +33,7 @@ impl Npc {
class,
ability_scores,
persona,
+ magic_items,
}
}
@@ -112,6 +117,44 @@ impl Npc {
self.persona = Some(components.join(", "));
}
+ // This uses the Appendix C method provided in the city/town section.
+ // I prefer it to the Monster Manual method and the NPC party method
+ // because it provides more variance.
+ // TODO: Support other levels than 1st.
+ pub fn add_random_magic_items(&mut self) {
+ let mut rng = rand::thread_rng();
+ let class_ref = self.class.unwrap();
+
+ // "Protection" isn't a real magic item kind, it's only used for this,
+ // which is why we don't just use MagicItemKind. Can improve this later.
+ let kind_strings_for_chances = [
+ "sword",
+ "potion",
+ "scroll",
+ "ring",
+ "rod_staff_wand",
+ "misc",
+ "armor_shield",
+ "protection",
+ ];
+
+ for &kind_string in kind_strings_for_chances.iter() {
+ if class_ref
+ .chances_for_magic
+ .get(kind_string)
+ .copied()
+ .unwrap_or(0)
+ <= rng.gen_range(1..=100)
+ {
+ self.magic_items.push(
+ MAGIC_ITEMS
+ .get(kind_string)
+ .expect("Failed to load magic item"),
+ );
+ }
+ }
+ }
+
// TODO: Probably break this out later like this.
// fn increase_prime_requisites(&mut self, roll_result: &mut RollResult) {
// let class_ref = self.class.unwrap();
@@ -159,6 +202,7 @@ mod tests {
class: Some(class_ref),
ability_scores: None,
persona: None,
+ magic_items: Vec::new(),
};
// Roll ability scores for the Npc.