Cleanup code now handled by effects module

This commit is contained in:
Timothy Warren 2022-01-20 16:24:12 -05:00
parent 64cc39eba1
commit 64aeb189c9
6 changed files with 90 additions and 192 deletions

View File

@ -88,29 +88,6 @@ pub struct Item {
pub base_value: f32, pub base_value: f32,
} }
#[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct SufferDamage {
pub amount: Vec<(i32, bool)>,
}
impl SufferDamage {
pub fn new_damage(
store: &mut WriteStorage<SufferDamage>,
victim: Entity,
amount: i32,
from_player: bool,
) {
if let Some(suffering) = store.get_mut(victim) {
suffering.amount.push((amount, from_player));
} else {
let dmg = SufferDamage {
amount: vec![(amount, from_player)],
};
store.insert(victim, dmg).expect("Unable to insert damage");
}
}
}
#[derive(Component, Debug, ConvertSaveload, Clone)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct Ranged { pub struct Ranged {
pub range: i32, pub range: i32,

View File

@ -1,109 +1,10 @@
use ::rltk::{Point, RandomNumberGenerator}; use ::rltk::RandomNumberGenerator;
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{ use crate::components::{Equipped, InBackpack, LootTable, Name, Player, Pools, Position};
Attributes, Equipped, InBackpack, LootTable, Name, Player, Pools, Position, SufferDamage,
};
use crate::game_log::GameLog; use crate::game_log::GameLog;
use crate::gamesystem::{mana_at_level, player_hp_at_level};
use crate::particle_system::ParticleBuilder;
use crate::raws::{self, SpawnType, RAWS}; use crate::raws::{self, SpawnType, RAWS};
use crate::{colors, Map, RunState}; use crate::RunState;
pub struct DamageSystem {}
impl<'a> System<'a> for DamageSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteStorage<'a, Pools>,
WriteStorage<'a, SufferDamage>,
ReadStorage<'a, Position>,
WriteExpect<'a, Map>,
Entities<'a>,
ReadExpect<'a, Entity>,
ReadStorage<'a, Attributes>,
WriteExpect<'a, GameLog>,
WriteExpect<'a, ParticleBuilder>,
ReadExpect<'a, Point>,
);
fn run(&mut self, data: Self::SystemData) {
let (
mut stats,
mut damage,
positions,
mut map,
entities,
player,
attributes,
mut log,
mut particles,
player_pos,
) = data;
let mut xp_gain = 0;
let mut gold_gain = 0.0_f32;
for (entity, mut stats, damage) in (&entities, &mut stats, &damage).join() {
gold_gain += stats.gold;
for dmg in damage.amount.iter() {
if !stats.god_mode {
stats.hit_points.current -= dmg.0;
}
if let Some(pos) = positions.get(entity) {
let idx = map.xy_idx(pos.x, pos.y);
map.bloodstains.insert(idx);
}
if stats.hit_points.current < 1 && dmg.1 {
xp_gain += stats.level * 100;
}
}
}
if xp_gain != 0 || gold_gain != 0.0 {
let mut player_stats = stats.get_mut(*player).unwrap();
let player_attributes = attributes.get(*player).unwrap();
player_stats.xp += xp_gain;
player_stats.gold += gold_gain;
if player_stats.xp >= player_stats.level * 1000 {
// We've gone up a level!
player_stats.level += 1;
log.append(format!(
"Congratulations, you are now level {}",
player_stats.level
));
player_stats.hit_points.max = player_hp_at_level(
player_attributes.fitness.base + player_attributes.fitness.modifiers,
player_stats.level,
);
player_stats.hit_points.current = player_stats.hit_points.max;
player_stats.mana.max = mana_at_level(
player_attributes.intelligence.base + player_attributes.intelligence.modifiers,
player_stats.level,
);
player_stats.mana.current = player_stats.mana.max;
for i in 0..10 {
if player_pos.y - i > 1 {
particles.request(
player_pos.x,
player_pos.y - i,
colors::GOLD,
colors::BLACK,
rltk::to_cp437('░'),
400.0,
);
}
}
}
}
damage.clear();
}
}
pub fn delete_the_dead(ecs: &mut World) { pub fn delete_the_dead(ecs: &mut World) {
let mut dead: Vec<Entity> = Vec::new(); let mut dead: Vec<Entity> = Vec::new();

View File

@ -9,10 +9,10 @@ use crate::{GameLog, Map, RunState};
pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) { pub fn item_trigger(creator: Option<Entity>, item: Entity, targets: &Targets, ecs: &mut World) {
// Use the item via the generic system // Use the item via the generic system
event_trigger(creator, item, targets, ecs); let did_something = event_trigger(creator, item, targets, ecs);
// If it was a consumable, then it gets deleted // If it was a consumable, then it gets deleted
if ecs.read_storage::<Consumable>().get(item).is_some() { if did_something && ecs.read_storage::<Consumable>().get(item).is_some() {
ecs.entities() ecs.entities()
.delete(item) .delete(item)
.expect("Failed to delete consumable item"); .expect("Failed to delete consumable item");
@ -24,13 +24,14 @@ pub fn trigger(creator: Option<Entity>, trigger: Entity, targets: &Targets, ecs:
ecs.write_storage::<Hidden>().remove(trigger); ecs.write_storage::<Hidden>().remove(trigger);
// Use the item via the generic system // Use the item via the generic system
event_trigger(creator, trigger, targets, ecs); let did_something = event_trigger(creator, trigger, targets, ecs);
// If it was a single activation, then it gets deleted // If it was a single activation, then it gets deleted
if ecs if did_something
.read_storage::<SingleActivation>() && ecs
.get(trigger) .read_storage::<SingleActivation>()
.is_some() .get(trigger)
.is_some()
{ {
ecs.entities() ecs.entities()
.delete(trigger) .delete(trigger)
@ -38,7 +39,13 @@ pub fn trigger(creator: Option<Entity>, trigger: Entity, targets: &Targets, ecs:
} }
} }
fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs: &mut World) { fn event_trigger(
creator: Option<Entity>,
entity: Entity,
targets: &Targets,
ecs: &mut World,
) -> bool {
let mut did_something = false;
let mut gamelog = ecs.fetch_mut::<GameLog>(); let mut gamelog = ecs.fetch_mut::<GameLog>();
// Providing food // Providing food
@ -46,6 +53,8 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
add_effect(creator, EffectType::WellFed, targets.clone()); add_effect(creator, EffectType::WellFed, targets.clone());
let names = ecs.read_storage::<Name>(); let names = ecs.read_storage::<Name>();
gamelog.append(format!("You eat the {}.", names.get(entity).unwrap().name)); gamelog.append(format!("You eat the {}.", names.get(entity).unwrap().name));
did_something = true;
} }
// Magic mapper // Magic mapper
@ -53,6 +62,8 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
let mut runstate = ecs.fetch_mut::<RunState>(); let mut runstate = ecs.fetch_mut::<RunState>();
gamelog.append("The map is revealed to you!"); gamelog.append("The map is revealed to you!");
*runstate = RunState::MagicMapReveal { row: 0 }; *runstate = RunState::MagicMapReveal { row: 0 };
did_something = true;
} }
// Town Portal // Town Portal
@ -64,6 +75,8 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
gamelog.append("You are teleported back to town!"); gamelog.append("You are teleported back to town!");
let mut runstate = ecs.fetch_mut::<RunState>(); let mut runstate = ecs.fetch_mut::<RunState>();
*runstate = RunState::TownPortal; *runstate = RunState::TownPortal;
did_something = true;
} }
} }
@ -76,6 +89,8 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
}, },
targets.clone(), targets.clone(),
); );
did_something = true;
} }
// Damage // Damage
@ -87,6 +102,8 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
}, },
targets.clone(), targets.clone(),
); );
did_something = true;
} }
// Confusion // Confusion
@ -98,6 +115,8 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
}, },
targets.clone(), targets.clone(),
); );
did_something = true;
} }
// Teleport // Teleport
@ -112,5 +131,9 @@ fn event_trigger(creator: Option<Entity>, entity: Entity, targets: &Targets, ecs
}, },
targets.clone(), targets.clone(),
); );
did_something = true;
} }
did_something
} }

View File

@ -1,6 +1,7 @@
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::{HungerClock, HungerState, MyTurn, SufferDamage}; use crate::components::{HungerClock, HungerState, MyTurn};
use crate::effects::{add_effect, EffectType, Targets};
use crate::game_log::GameLog; use crate::game_log::GameLog;
pub struct HungerSystem {} pub struct HungerSystem {}
@ -11,13 +12,12 @@ impl<'a> System<'a> for HungerSystem {
Entities<'a>, Entities<'a>,
WriteStorage<'a, HungerClock>, WriteStorage<'a, HungerClock>,
ReadExpect<'a, Entity>, // The player ReadExpect<'a, Entity>, // The player
WriteStorage<'a, SufferDamage>,
WriteExpect<'a, GameLog>, WriteExpect<'a, GameLog>,
ReadStorage<'a, MyTurn>, ReadStorage<'a, MyTurn>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let (entities, mut hunger_clock, player_entity, mut inflict_damage, mut log, turns) = data; let (entities, mut hunger_clock, player_entity, mut log, turns) = data;
for (entity, mut clock, _myturn) in (&entities, &mut hunger_clock, &turns).join() { for (entity, mut clock, _myturn) in (&entities, &mut hunger_clock, &turns).join() {
clock.duration -= 1; clock.duration -= 1;
@ -54,7 +54,11 @@ impl<'a> System<'a> for HungerSystem {
log.append("Your hunger pangs are getting painful!"); log.append("Your hunger pangs are getting painful!");
} }
SufferDamage::new_damage(&mut inflict_damage, entity, 1, false); add_effect(
None,
EffectType::Damage { amount: 1 },
Targets::Single { target: entity },
);
} }
} }
} }

View File

@ -268,6 +268,51 @@ pub fn string_to_slot(slot: &str) -> EquipmentSlot {
} }
} }
macro_rules! apply_effects {
($effects:expr, $eb:expr) => {
for effect in $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 {}),
"town_portal" => $eb = $eb.with(TownPortal {}),
"food" => $eb = $eb.with(ProvidesFood {}),
"single_activation" => $eb = $eb.with(SingleActivation {}),
_ => {
::rltk::console::log(format!(
"Warning: consumable effect {} not implemented.",
effect_name
));
}
}
}
};
}
pub fn spawn_named_item( pub fn spawn_named_item(
raws: &RawMaster, raws: &RawMaster,
ecs: &mut World, ecs: &mut World,
@ -303,45 +348,7 @@ pub fn spawn_named_item(
if let Some(consumable) = &item_template.consumable { if let Some(consumable) = &item_template.consumable {
eb = eb.with(Consumable {}); eb = eb.with(Consumable {});
for effect in consumable.effects.iter() { apply_effects!(consumable.effects, eb);
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 {}),
"town_portal" => eb = eb.with(TownPortal {}),
"food" => eb = eb.with(ProvidesFood {}),
_ => {
rltk::console::log(format!(
"Warning: consumable effect {} not implemented.",
effect_name
));
}
}
}
} }
if let Some(weapon) = &item_template.weapon { if let Some(weapon) = &item_template.weapon {
@ -636,17 +643,7 @@ pub fn spawn_named_prop(
} }
if let Some(entry_trigger) = &prop_template.entry_trigger { if let Some(entry_trigger) = &prop_template.entry_trigger {
eb = eb.with(EntryTrigger {}); eb = eb.with(EntryTrigger {});
for effect in entry_trigger.effects.iter() { apply_effects!(entry_trigger.effects, eb);
match effect.0.as_str() {
"damage" => {
eb = eb.with(InflictsDamage {
damage: effect.1.parse::<i32>().unwrap(),
});
}
"single_activation" => eb = eb.with(SingleActivation {}),
_ => {}
}
}
} }
if let Some(light) = &prop_template.light { if let Some(light) = &prop_template.light {
eb = eb eb = eb

View File

@ -2,7 +2,6 @@ use ::rltk::{GameState, Point, Rltk};
use ::specs::prelude::*; use ::specs::prelude::*;
use crate::components::*; use crate::components::*;
use crate::damage_system::{self, DamageSystem};
use crate::game_log::GameLog; use crate::game_log::GameLog;
use crate::gui::{self, show_cheat_mode, CheatMenuResult, MainMenuSelection}; use crate::gui::{self, show_cheat_mode, CheatMenuResult, MainMenuSelection};
use crate::hunger_system::HungerSystem; use crate::hunger_system::HungerSystem;
@ -20,7 +19,7 @@ use crate::player::*;
use crate::raws::*; use crate::raws::*;
use crate::trigger_system::TriggerSystem; use crate::trigger_system::TriggerSystem;
use crate::visibility_system::VisibilitySystem; use crate::visibility_system::VisibilitySystem;
use crate::{ai, camera, effects, saveload_system, spawner}; use crate::{ai, camera, damage_system, effects, saveload_system, spawner};
pub const SHOW_MAPGEN_VISUALIZER: bool = false; pub const SHOW_MAPGEN_VISUALIZER: bool = false;
@ -119,9 +118,6 @@ impl State {
let mut melee = MeleeCombatSystem {}; let mut melee = MeleeCombatSystem {};
melee.run_now(&self.ecs); melee.run_now(&self.ecs);
let mut damage = DamageSystem {};
damage.run_now(&self.ecs);
let mut pickup = ItemCollectionSystem {}; let mut pickup = ItemCollectionSystem {};
pickup.run_now(&self.ecs); pickup.run_now(&self.ecs);