diff --git a/src/raws.rs b/src/raws.rs index ccbd56a..dd3221f 100644 --- a/src/raws.rs +++ b/src/raws.rs @@ -1,10 +1,19 @@ mod item_structs; +mod mob_structs; mod rawmaster; use std::sync::Mutex; -use item_structs::Raws; +use item_structs::*; +use mob_structs::*; pub use rawmaster::*; +use serde::Deserialize; + +#[derive(Deserialize, Debug)] +pub struct Raws { + pub items: Vec, + pub mobs: Vec, +} rltk::embedded_resource!(RAW_FILE, "../raws/spawns.json"); diff --git a/src/raws/item_structs.rs b/src/raws/item_structs.rs index 862dd08..c5c559e 100644 --- a/src/raws/item_structs.rs +++ b/src/raws/item_structs.rs @@ -2,11 +2,6 @@ use std::collections::HashMap; use serde::Deserialize; -#[derive(Deserialize, Debug)] -pub struct Raws { - pub items: Vec, -} - #[derive(Deserialize, Debug)] pub struct Item { pub name: String, diff --git a/src/raws/mob_structs.rs b/src/raws/mob_structs.rs new file mode 100644 index 0000000..9a6bee9 --- /dev/null +++ b/src/raws/mob_structs.rs @@ -0,0 +1,20 @@ +use serde::Deserialize; + +use super::item_structs::Renderable; + +#[derive(Deserialize, Debug)] +pub struct Mob { + pub name: String, + pub renderable: Option, + pub blocks_tile: bool, + pub stats: MobStats, + pub vision_range: i32, +} + +#[derive(Deserialize, Debug)] +pub struct MobStats { + pub max_hp: i32, + pub hp: i32, + pub power: i32, + pub defense: i32, +} diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index ea60f75..b7db18c 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use specs::prelude::*; -use super::Raws; use crate::components::*; +use crate::raws::Raws; pub enum SpawnType { AtPosition { x: i32, y: i32 }, @@ -12,13 +12,18 @@ pub enum SpawnType { pub struct RawMaster { raws: Raws, item_index: HashMap, + mob_index: HashMap, } impl RawMaster { pub fn empty() -> RawMaster { RawMaster { - raws: Raws { items: Vec::new() }, + raws: Raws { + items: Vec::new(), + mobs: Vec::new(), + }, item_index: HashMap::new(), + mob_index: HashMap::new(), } } @@ -29,6 +34,33 @@ impl RawMaster { for (i, item) in self.raws.items.iter().enumerate() { self.item_index.insert(item.name.clone(), i); } + for (i, mob) in self.raws.mobs.iter().enumerate() { + self.mob_index.insert(mob.name.clone(), i); + } + } +} + +fn spawn_position(pos: SpawnType, new_entity: EntityBuilder) -> EntityBuilder { + let mut eb = new_entity; + + // Spawn in the specified location + match pos { + SpawnType::AtPosition { x, y } => { + eb = eb.with(Position { x, y }); + } + } + + eb +} + +fn get_renderable_component( + renderable: &super::item_structs::Renderable, +) -> crate::components::Renderable { + crate::components::Renderable { + glyph: rltk::to_cp437(renderable.glyph.chars().next().unwrap()), + fg: rltk::RGB::from_hex(&renderable.fg).expect("Invalid RGB"), + bg: rltk::RGB::from_hex(&renderable.bg).expect("Invalid RGB"), + render_order: renderable.order, } } @@ -44,20 +76,11 @@ pub fn spawn_named_item( let mut eb = new_entity; // Spawn in the specified location - match pos { - SpawnType::AtPosition { x, y } => { - eb = eb.with(Position { x, y }); - } - } + eb = spawn_position(pos, eb); // Renderable if let Some(renderable) = &item_template.renderable { - eb = eb.with(Renderable { - glyph: rltk::to_cp437(renderable.glyph.chars().next().unwrap()), - fg: rltk::RGB::from_hex(&renderable.fg).expect("Invalid RGB"), - bg: rltk::RGB::from_hex(&renderable.bg).expect("Invalid RGB"), - render_order: renderable.order, - }); + eb = eb.with(get_renderable_component(renderable)); } eb = eb.with(Name::from(&item_template.name)); @@ -129,3 +152,63 @@ pub fn spawn_named_item( None } + +pub fn spawn_named_mob( + raws: &RawMaster, + new_entity: EntityBuilder, + key: &str, + pos: SpawnType, +) -> Option { + if raws.mob_index.contains_key(key) { + let mob_template = &raws.raws.mobs[raws.mob_index[key]]; + + let mut eb = new_entity; + + // Spawn in the specified location + eb = spawn_position(pos, eb); + + // Renderable + if let Some(renderable) = &mob_template.renderable { + eb = eb.with(get_renderable_component(renderable)); + } + + eb = eb.with(Name::from(&mob_template.name)); + + eb = eb.with(Monster {}); + if mob_template.blocks_tile { + eb = eb.with(BlocksTile {}); + } + + eb = eb.with(CombatStats { + max_hp: mob_template.stats.max_hp, + hp: mob_template.stats.hp, + power: mob_template.stats.power, + defense: mob_template.stats.defense, + }); + + eb = eb.with(Viewshed { + visible_tiles: Vec::new(), + range: mob_template.vision_range, + dirty: true, + }); + + return Some(eb.build()); + } + + None +} + +pub fn spawn_named_entity( + raws: &RawMaster, + new_entity: EntityBuilder, + key: &str, + pos: SpawnType, +) -> Option { + if raws.item_index.contains_key(key) { + return spawn_named_item(raws, new_entity, key, pos); + } else if raws.mob_index.contains_key(key) { + return spawn_named_mob(raws, new_entity, key, pos); + } + + None +} diff --git a/src/spawner.rs b/src/spawner.rs index 71bc957..0892256 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -6,7 +6,7 @@ use specs::saveload::{MarkedBuilder, SimpleMarker}; use crate::components::*; use crate::random_table::RandomTable; -use crate::raws::{spawn_named_item, SpawnType, RAWS}; +use crate::raws::{spawn_named_entity, SpawnType, RAWS}; use crate::{Map, Rect, TileType}; /// Spawns the player and returns their entity object @@ -133,7 +133,7 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) { // Drop this map reference to make the borrow checker happy std::mem::drop(map); - let item_result = spawn_named_item( + let item_result = spawn_named_entity( &RAWS.lock().unwrap(), ecs.create_entity(), spawn.1, @@ -144,45 +144,12 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) { } match spawn.1.as_ref() { - "Goblin" => goblin(ecs, x, y), - "Orc" => orc(ecs, x, y), "Bear Trap" => bear_trap(ecs, x, y), "Door" => door(ecs, x, y), _ => {} } } -fn orc(ecs: &mut World, x: i32, y: i32) { - monster(ecs, x, y, rltk::to_cp437('o'), "Orc"); -} - -fn goblin(ecs: &mut World, x: i32, y: i32) { - monster(ecs, x, y, rltk::to_cp437('g'), "Goblin"); -} - -fn monster(ecs: &mut World, x: i32, y: i32, glyph: rltk::FontCharType, name: S) { - ecs.create_entity() - .with(Position { x, y }) - .with(Renderable { - glyph, - fg: RGB::named(rltk::RED), - bg: RGB::named(rltk::BLACK), - render_order: 1, - }) - .with(Viewshed::default()) - .with(Monster {}) - .with(Name::from(name)) - .with(BlocksTile {}) - .with(CombatStats { - max_hp: 16, - hp: 16, - defense: 1, - power: 4, - }) - .marked::>() - .build(); -} - fn bear_trap(ecs: &mut World, x: i32, y: i32) { ecs.create_entity() .with(Position { x, y })