Spawn items from JSON data

This commit is contained in:
Timothy Warren 2021-12-23 11:38:37 -05:00
parent 70494d8122
commit 98407d2c77
6 changed files with 228 additions and 30 deletions

View File

@ -7,6 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lazy_static = "1.4.0"
rltk = { version = "0.8.0", features=["serde"] }
specs = { version = "0.16.1", features=["serde"] }
specs-derive = "0.4.1"

View File

@ -1,30 +1,93 @@
{
"items": [{
"name": "Health Potion",
"renderable": {
"glpyh": "!",
"fg": "#FF00FF",
"bg": "#000000",
"order": 2
"items": [
{
"name": "Health Potion",
"renderable": {
"glyph": "!",
"fg": "#FF00FF",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"provides_healing": "8"
}
}
},
"consumable": {
"effects": {
"provides_healing": "8"
{
"name": "Magic Missile Scroll",
"renderable": {
"glyph": ")",
"fg": "#00FFFF",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"ranged": "6",
"damage": "20"
}
}
},
{
"name": "Fireball Scroll",
"renderable": {
"glyph": ")",
"fg": "#FFA500",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"ranged": "6",
"damage": "20",
"area_of_effect": "3"
}
}
},
{
"name": "Confusion Scroll",
"renderable": {
"glyph": ")",
"fg": "#FFAAAA",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"ranged": "6",
"damage": "20",
"confusion": "4"
}
}
},
{
"name": "Magic Mapping Scroll",
"renderable": {
"glyph": ")",
"fg": "#AAAAFF",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"magic_mapping": ""
}
}
},
{
"name": "Rations",
"renderable": {
"glyph": "%",
"fg": "#00FF00",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"food": ""
}
}
}
}, {
"name": "Magic Missile Scroll",
"renderable": {
"glyph": ")",
"fg": "#00FFFF",
"bg": "#000000",
"order": 2
},
"consumable": {
"effects": {
"ranged": "6",
"damage": "20"
}
}
}]
]
}

View File

@ -1,7 +1,3 @@
use rltk::{GameState, Point, RandomNumberGenerator, Rltk};
use specs::prelude::*;
use specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
pub mod camera;
mod components;
mod damage_system;
@ -25,6 +21,9 @@ mod spawner;
mod trigger_system;
mod visibility_system;
#[macro_use]
extern crate lazy_static;
use components::*;
use damage_system::DamageSystem;
pub use game_log::GameLog;
@ -35,6 +34,9 @@ use melee_combat_system::MeleeCombatSystem;
use monster_ai_system::MonsterAI;
use player::*;
pub use rect::Rect;
use rltk::{GameState, Point, RandomNumberGenerator, Rltk};
use specs::prelude::*;
use specs::saveload::{SimpleMarker, SimpleMarkerAllocator};
use visibility_system::VisibilitySystem;
/// Cut down on the amount of syntax to register components

View File

@ -1,10 +1,20 @@
mod item_structs;
mod rawmaster;
use std::sync::Mutex;
use item_structs::Raws;
pub use rawmaster::*;
rltk::embedded_resource!(RAW_FILE, "../raws/spawns.json");
lazy_static! {
pub static ref RAWS: Mutex<RawMaster> = Mutex::new(RawMaster::empty());
}
pub fn load_raws() {
rltk::link_resource!(RAW_FILE, "../raws/spawns.json");
let raw_data = rltk::embedding::EMBED
.lock()
.get_resource("../raws/spawns.json".to_string())
@ -14,5 +24,5 @@ pub fn load_raws() {
std::str::from_utf8(&raw_data).expect("Unable to convert to a valid UTF-8 string.");
let decoder: Raws = serde_json::from_str(&raw_string).expect("Unable to parse JSON");
rltk::console::log(format!("{:?}", decoder));
RAWS.lock().unwrap().load(decoder);
}

111
src/raws/rawmaster.rs Normal file
View File

@ -0,0 +1,111 @@
use std::collections::HashMap;
use specs::prelude::*;
use super::Raws;
use crate::components::*;
pub enum SpawnType {
AtPosition { x: i32, y: i32 },
}
pub struct RawMaster {
raws: Raws,
item_index: HashMap<String, usize>,
}
impl RawMaster {
pub fn empty() -> RawMaster {
RawMaster {
raws: Raws { items: Vec::new() },
item_index: HashMap::new(),
}
}
pub fn load(&mut self, raws: Raws) {
self.raws = raws;
self.item_index = HashMap::new();
for (i, item) in self.raws.items.iter().enumerate() {
self.item_index.insert(item.name.clone(), i);
}
}
}
pub fn spawn_named_item(
raws: &RawMaster,
new_entity: EntityBuilder,
key: &str,
pos: SpawnType,
) -> Option<Entity> {
if raws.item_index.contains_key(key) {
let item_template = &raws.raws.items[raws.item_index[key]];
let mut eb = new_entity;
// Spawn in the specified location
match pos {
SpawnType::AtPosition { x, y } => {
eb = eb.with(Position { x, y });
}
}
// 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(Name::from(&item_template.name)).with(Item {});
if let Some(consumable) = &item_template.consumable {
eb = eb.with(Consumable {});
for effect in consumable.effects.iter() {
let effect_name = effect.0.as_str();
match effect_name {
"provides_healing" => {
eb = eb.with(ProvidesHealing {
heal_amount: effect.1.parse::<i32>().unwrap(),
})
}
"ranged" => {
eb = eb.with(Ranged {
range: effect.1.parse::<i32>().unwrap(),
})
}
"damage" => {
eb = eb.with(InflictsDamage {
damage: effect.1.parse::<i32>().unwrap(),
})
}
"area_of_effect" => {
eb = eb.with(AreaOfEffect {
radius: effect.1.parse::<i32>().unwrap(),
})
}
"confusion" => {
eb = eb.with(Confusion {
turns: effect.1.parse::<i32>().unwrap(),
})
}
"magic_mapping" => eb = eb.with(MagicMapper {}),
"food" => [eb = eb.with(ProvidesFood {})],
_ => {
rltk::console::log(format!(
"Warning: consumable effect {} not implemented.",
effect_name
));
}
}
}
}
return Some(eb.build());
}
None
}

View File

@ -6,6 +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::{Map, Rect, TileType};
/// Spawns the player and returns their entity object
@ -132,6 +133,16 @@ 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(
&RAWS.lock().unwrap(),
ecs.create_entity(),
&spawn.1,
SpawnType::AtPosition { x, y },
);
if item_result.is_some() {
return;
}
match spawn.1.as_ref() {
"Goblin" => goblin(ecs, x, y),
"Orc" => orc(ecs, x, y),