Setup parts of spell system
This commit is contained in:
parent
0353c658aa
commit
969ecf7fef
@ -401,3 +401,25 @@ pub struct Duration {
|
||||
pub struct StatusEffect {
|
||||
pub target: Entity,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct KnownSpell {
|
||||
pub display_name: String,
|
||||
pub mana_cost: i32,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct KnownSpells {
|
||||
pub spells: Vec<KnownSpell>,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct SpellTemplate {
|
||||
pub mana_cost: i32,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, ConvertSaveload, Clone)]
|
||||
pub struct WantsToCastSpell {
|
||||
pub spell: Entity,
|
||||
pub target: Option<Point>,
|
||||
}
|
||||
|
21
src/gui.rs
21
src/gui.rs
@ -12,7 +12,8 @@ use tooltip::draw_tooltips;
|
||||
|
||||
use crate::components::{
|
||||
Attribute, Attributes, Consumable, CursedItem, Duration, Equipped, HungerClock, HungerState,
|
||||
InBackpack, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, StatusEffect, Viewshed,
|
||||
InBackpack, KnownSpells, MagicItem, MagicItemClass, Name, ObfuscatedName, Pools, StatusEffect,
|
||||
Viewshed,
|
||||
};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::{camera, colors, Map, MasterDungeonMap, State};
|
||||
@ -243,6 +244,24 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||
}
|
||||
}
|
||||
|
||||
// Spells
|
||||
y += 1;
|
||||
let known_spells_storage = ecs.read_storage::<KnownSpells>();
|
||||
let known_spells = &known_spells_storage.get(*player_entity).unwrap().spells;
|
||||
let mut index = 1;
|
||||
for spell in known_spells.iter() {
|
||||
ctx.print_color(50, y, colors::CYAN, colors::BLACK, &format!("^{}", index));
|
||||
ctx.print_color(
|
||||
53,
|
||||
y,
|
||||
colors::CYAN,
|
||||
colors::BLACK,
|
||||
&format!("{} ({})", spell.display_name, spell.mana_cost),
|
||||
);
|
||||
index += 1;
|
||||
y += 1;
|
||||
}
|
||||
|
||||
// Status
|
||||
y = 44;
|
||||
let hunger = ecs.read_storage::<HungerClock>();
|
||||
|
@ -108,6 +108,7 @@ fn init_state() -> State {
|
||||
InflictsDamage,
|
||||
Initiative,
|
||||
Item,
|
||||
KnownSpells,
|
||||
LightSource,
|
||||
LootTable,
|
||||
MagicItem,
|
||||
@ -136,12 +137,14 @@ fn init_state() -> State {
|
||||
Skills,
|
||||
SpawnParticleBurst,
|
||||
SpawnParticleLine,
|
||||
SpellTemplate,
|
||||
StatusEffect,
|
||||
TeleportTo,
|
||||
TownPortal,
|
||||
Vendor,
|
||||
Viewshed,
|
||||
WantsToApproach,
|
||||
WantsToCastSpell,
|
||||
WantsToDropItem,
|
||||
WantsToFlee,
|
||||
WantsToMelee,
|
||||
|
@ -9,7 +9,7 @@ use crate::components::{
|
||||
};
|
||||
use crate::game_log::GameLog;
|
||||
use crate::raws::{self, Reaction, RAWS};
|
||||
use crate::{spatial, Map, RunState, State, TileType, VendorMode};
|
||||
use crate::{spatial, Map, RunState, State, TileType, VendorMode, WantsToCastSpell};
|
||||
|
||||
pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState {
|
||||
let mut positions = ecs.write_storage::<Position>();
|
||||
@ -298,10 +298,53 @@ fn use_consumable_hotkey(gs: &mut State, key: i32) -> RunState {
|
||||
RunState::Ticking
|
||||
}
|
||||
|
||||
pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||
// Hotkeys
|
||||
if ctx.shift && ctx.key.is_some() {
|
||||
let key: Option<i32> = match ctx.key.unwrap() {
|
||||
fn use_spell_hotkey(gs: &mut State, key: i32) -> RunState {
|
||||
use crate::components::{KnownSpells, Ranged};
|
||||
use crate::raws::find_spell_entity;
|
||||
|
||||
let player_entity = gs.ecs.fetch::<Entity>();
|
||||
let known_spells_storage = gs.ecs.read_storage::<KnownSpells>();
|
||||
let known_spells = &known_spells_storage.get(*player_entity).unwrap().spells;
|
||||
|
||||
if (key as usize) < known_spells.len() {
|
||||
let pools = gs.ecs.read_storage::<Pools>();
|
||||
let player_pools = pools.get(*player_entity).unwrap();
|
||||
if player_pools.mana.current >= known_spells[key as usize].mana_cost {
|
||||
if let Some(spell_entity) =
|
||||
find_spell_entity(&gs.ecs, &known_spells[key as usize].display_name)
|
||||
{
|
||||
if let Some(ranged) = gs.ecs.read_storage::<Ranged>().get(spell_entity) {
|
||||
return RunState::ShowTargeting {
|
||||
range: ranged.range,
|
||||
item: spell_entity,
|
||||
};
|
||||
}
|
||||
|
||||
let mut intent = gs.ecs.write_storage::<WantsToCastSpell>();
|
||||
intent
|
||||
.insert(
|
||||
*player_entity,
|
||||
WantsToCastSpell {
|
||||
spell: spell_entity,
|
||||
target: None,
|
||||
},
|
||||
)
|
||||
.expect("Unable to insert intent to cast spell");
|
||||
|
||||
return RunState::Ticking;
|
||||
}
|
||||
} else {
|
||||
let mut gamelog = gs.ecs.fetch_mut::<GameLog>();
|
||||
gamelog.append("You don't have enough mana to cast that!");
|
||||
}
|
||||
}
|
||||
|
||||
RunState::Ticking
|
||||
}
|
||||
|
||||
fn get_number_key(ctx: &mut Rltk) -> Option<i32> {
|
||||
match ctx.key {
|
||||
Some(key) => match key {
|
||||
VirtualKeyCode::Key1 => Some(1),
|
||||
VirtualKeyCode::Key2 => Some(2),
|
||||
VirtualKeyCode::Key3 => Some(3),
|
||||
@ -312,11 +355,25 @@ pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||
VirtualKeyCode::Key8 => Some(8),
|
||||
VirtualKeyCode::Key9 => Some(9),
|
||||
_ => None,
|
||||
};
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn player_input(gs: &mut State, ctx: &mut Rltk) -> RunState {
|
||||
// Hotkeys
|
||||
if ctx.shift && ctx.key.is_some() {
|
||||
let key: Option<i32> = get_number_key(ctx);
|
||||
if let Some(key) = key {
|
||||
return use_consumable_hotkey(gs, key - 1);
|
||||
}
|
||||
}
|
||||
if ctx.control && ctx.key.is_some() {
|
||||
let key: Option<i32> = get_number_key(ctx);
|
||||
if let Some(key) = key {
|
||||
return use_spell_hotkey(gs, key - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Mac OS is special when it comes to the numpad. Instead of reporting
|
||||
// the keys as Numpad-specific numbers, it reports the number row scan
|
||||
|
@ -5,6 +5,7 @@ mod mob_structs;
|
||||
mod prop_structs;
|
||||
mod rawmaster;
|
||||
mod spawn_table_structs;
|
||||
mod spell_structs;
|
||||
|
||||
use std::sync::Mutex;
|
||||
|
||||
@ -17,8 +18,9 @@ use mob_structs::*;
|
||||
use prop_structs::*;
|
||||
pub use rawmaster::*;
|
||||
use spawn_table_structs::*;
|
||||
pub use spell_structs::Spell;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[derive(Deserialize, Default, Debug)]
|
||||
pub struct Raws {
|
||||
pub items: Vec<Item>,
|
||||
pub mobs: Vec<Mob>,
|
||||
@ -26,6 +28,7 @@ pub struct Raws {
|
||||
pub spawn_table: Vec<SpawnTableEntry>,
|
||||
pub loot_tables: Vec<LootTable>,
|
||||
pub faction_table: Vec<FactionInfo>,
|
||||
pub spells: Vec<Spell>,
|
||||
}
|
||||
|
||||
embedded_resource!(RAW_FILE, "../raws/spawns.json");
|
||||
|
@ -8,7 +8,7 @@ pub struct FactionInfo {
|
||||
pub responses: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub enum Reaction {
|
||||
Ignore,
|
||||
Attack,
|
||||
|
@ -40,6 +40,7 @@ pub enum SpawnType {
|
||||
Carried { by: Entity },
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RawMaster {
|
||||
raws: Raws,
|
||||
item_index: HashMap<String, usize>,
|
||||
@ -47,25 +48,12 @@ pub struct RawMaster {
|
||||
prop_index: HashMap<String, usize>,
|
||||
loot_index: HashMap<String, usize>,
|
||||
faction_index: HashMap<String, HashMap<String, Reaction>>,
|
||||
spell_index: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl RawMaster {
|
||||
pub fn empty() -> RawMaster {
|
||||
RawMaster {
|
||||
raws: Raws {
|
||||
items: Vec::new(),
|
||||
mobs: Vec::new(),
|
||||
props: Vec::new(),
|
||||
spawn_table: Vec::new(),
|
||||
loot_tables: Vec::new(),
|
||||
faction_table: Vec::new(),
|
||||
},
|
||||
item_index: HashMap::new(),
|
||||
mob_index: HashMap::new(),
|
||||
prop_index: HashMap::new(),
|
||||
loot_index: HashMap::new(),
|
||||
faction_index: HashMap::new(),
|
||||
}
|
||||
RawMaster::default()
|
||||
}
|
||||
|
||||
pub fn load(&mut self, raws: Raws) {
|
||||
@ -130,6 +118,10 @@ impl RawMaster {
|
||||
}
|
||||
self.faction_index.insert(faction.name.clone(), reactions);
|
||||
}
|
||||
|
||||
for (i, spell) in self.raws.spells.iter().enumerate() {
|
||||
self.spell_index.insert(spell.name.clone(), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -722,6 +714,26 @@ pub fn spawn_named_entity(
|
||||
None
|
||||
}
|
||||
|
||||
pub fn spawn_named_spell(raws: &RawMaster, ecs: &mut World, key: &str) -> Option<Entity> {
|
||||
if raws.spell_index.contains_key(key) {
|
||||
let spell_template = &raws.raws.spells[raws.spell_index[key]];
|
||||
|
||||
let mut eb = ecs
|
||||
.create_entity()
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.with(SpellTemplate {
|
||||
mana_cost: spell_template.mana_cost,
|
||||
})
|
||||
.with(Name::from(*spell_template.name));
|
||||
|
||||
apply_effects!(spell_template.effects, eb);
|
||||
|
||||
return Some(eb.build());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_spawn_table_for_depth(raws: &RawMaster, depth: i32) -> RandomTable {
|
||||
use super::SpawnTableEntry;
|
||||
|
||||
@ -761,3 +773,24 @@ pub fn get_item_drop(
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn spawn_all_spells(ecs: &mut World) {
|
||||
let raws = &RAWS.lock().unwrap();
|
||||
for spell in raws.raws.spells.iter() {
|
||||
spawn_named_spell(raws, ecs, &spell.name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_spell_entity(ecs: &World, name: &str) -> Option<Entity> {
|
||||
let names = ecs.read_storage::<Name>();
|
||||
let spell_templates = ecs.read_storage::<SpellTemplate>();
|
||||
let entities = ecs.entities();
|
||||
|
||||
for (entity, sname, _template) in (&entities, &names, &spell_templates).join() {
|
||||
if name == sname.name {
|
||||
return Some(entity);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
9
src/raws/spell_structs.rs
Normal file
9
src/raws/spell_structs.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ::serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Spell {
|
||||
pub name: String,
|
||||
pub effects: HashMap<String, String>,
|
||||
}
|
@ -87,6 +87,7 @@ pub fn save_game(ecs: &mut World) {
|
||||
InflictsDamage,
|
||||
Initiative,
|
||||
Item,
|
||||
KnownSpells,
|
||||
LightSource,
|
||||
LootTable,
|
||||
MagicItem,
|
||||
@ -114,12 +115,14 @@ pub fn save_game(ecs: &mut World) {
|
||||
Skills,
|
||||
SpawnParticleBurst,
|
||||
SpawnParticleLine,
|
||||
SpellTemplate,
|
||||
StatusEffect,
|
||||
TeleportTo,
|
||||
TownPortal,
|
||||
Vendor,
|
||||
Viewshed,
|
||||
WantsToApproach,
|
||||
WantsToCastSpell,
|
||||
WantsToDropItem,
|
||||
WantsToFlee,
|
||||
WantsToMelee,
|
||||
@ -210,6 +213,7 @@ pub fn load_game(ecs: &mut World) {
|
||||
InflictsDamage,
|
||||
Initiative,
|
||||
Item,
|
||||
KnownSpells,
|
||||
LightSource,
|
||||
LootTable,
|
||||
MagicItem,
|
||||
@ -237,12 +241,14 @@ pub fn load_game(ecs: &mut World) {
|
||||
Skills,
|
||||
SpawnParticleBurst,
|
||||
SpawnParticleLine,
|
||||
SpellTemplate,
|
||||
StatusEffect,
|
||||
TeleportTo,
|
||||
TownPortal,
|
||||
Vendor,
|
||||
Viewshed,
|
||||
WantsToApproach,
|
||||
WantsToCastSpell,
|
||||
WantsToDropItem,
|
||||
WantsToFlee,
|
||||
WantsToMelee,
|
||||
|
@ -7,11 +7,14 @@ use ::specs::saveload::{MarkedBuilder, SimpleMarker};
|
||||
use crate::components::*;
|
||||
use crate::gamesystem::{mana_at_level, player_hp_at_level};
|
||||
use crate::random_table::RandomTable;
|
||||
use crate::raws::{get_spawn_table_for_depth, spawn_named_entity, SpawnType, RAWS};
|
||||
use crate::raws::{
|
||||
get_spawn_table_for_depth, spawn_all_spells, spawn_named_entity, SpawnType, RAWS,
|
||||
};
|
||||
use crate::{colors, Map, MasterDungeonMap, Rect, TileType};
|
||||
|
||||
/// Spawns the player and returns their entity object
|
||||
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||
spawn_all_spells(ecs);
|
||||
let player = ecs
|
||||
.create_entity()
|
||||
.with(Position {
|
||||
@ -55,6 +58,12 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||
.with(Initiative { current: 0 })
|
||||
.with(Faction::from("Player"))
|
||||
.with(EquipmentChanged {})
|
||||
.with(KnownSpells {
|
||||
spells: vec![KnownSpell {
|
||||
display_name: "Zap".to_string(),
|
||||
mana_cost: 1,
|
||||
}],
|
||||
})
|
||||
.marked::<SimpleMarker<SerializeMe>>()
|
||||
.build();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user