Add Fireball scroll

This commit is contained in:
Timothy Warren 2021-11-05 13:12:22 -04:00
parent d2ebe5dc1d
commit 36af877217
4 changed files with 83 additions and 18 deletions

View File

@ -128,3 +128,8 @@ pub struct Ranged {
pub struct InflictsDamage { pub struct InflictsDamage {
pub damage: i32, pub damage: i32,
} }
#[derive(Component, Debug)]
pub struct AreaOfEffect {
pub radius: i32,
}

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
game_log::GameLog, CombatStats, Consumable, InBackpack, InflictsDamage, Map, Name, Position, game_log::GameLog, AreaOfEffect, CombatStats, Consumable, InBackpack, InflictsDamage, Map,
ProvidesHealing, SufferDamage, WantsToDropItem, WantsToPickupItem, WantsToUseItem, Name, Position, ProvidesHealing, SufferDamage, WantsToDropItem, WantsToPickupItem,
WantsToUseItem,
}; };
use specs::prelude::*; use specs::prelude::*;
@ -60,6 +61,7 @@ impl<'a> System<'a> for ItemUseSystem {
ReadStorage<'a, InflictsDamage>, ReadStorage<'a, InflictsDamage>,
WriteStorage<'a, CombatStats>, WriteStorage<'a, CombatStats>,
WriteStorage<'a, SufferDamage>, WriteStorage<'a, SufferDamage>,
ReadStorage<'a, AreaOfEffect>,
); );
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
@ -75,27 +77,67 @@ impl<'a> System<'a> for ItemUseSystem {
inflict_damage, inflict_damage,
mut combat_stats, mut combat_stats,
mut suffer_damage, mut suffer_damage,
aoe,
) = data; ) = data;
for (entity, useitem, stats) in (&entities, &wants_use, &mut combat_stats).join() { for (entity, useitem) in (&entities, &wants_use).join() {
let mut used_item = true; let mut used_item = true;
// Targeting
let mut targets: Vec<Entity> = Vec::new();
match useitem.target {
None => {
targets.push(*player_entity);
}
Some(target) => {
match aoe.get(useitem.item) {
None => {
// Single target in tile
let idx = map.xy_idx(target.x, target.y);
for mob in map.tile_content[idx].iter() {
targets.push(*mob);
}
}
Some(area_effect) => {
// AoE
let mut blast_tiles =
rltk::field_of_view(target, area_effect.radius, &*map);
blast_tiles.retain(|p| {
p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1
});
for tile_idx in blast_tiles.iter() {
let idx = map.xy_idx(tile_idx.x, tile_idx.y);
for mob in map.tile_content[idx].iter() {
targets.push(*mob);
}
}
}
}
}
}
// If the item heals, apply the healing // If the item heals, apply the healing
match healing.get(useitem.item) { match healing.get(useitem.item) {
None => {} None => {}
Some(healer) => { Some(healer) => {
used_item = false; used_item = false;
stats.hp = i32::min(stats.max_hp, stats.hp + healer.heal_amount); for target in targets.iter() {
if entity == *player_entity { let stats = combat_stats.get_mut(*target);
gamelog.entries.push(format!( if let Some(stats) = stats {
"You drink the {}, healing {} hp.", stats.hp = i32::min(stats.max_hp, stats.hp + healer.heal_amount);
names.get(useitem.item).unwrap().name, if entity == *player_entity {
healer.heal_amount gamelog.entries.push(format!(
)); "You drink the {}, healing {} hp.",
} names.get(useitem.item).unwrap().name,
healer.heal_amount
));
}
used_item = true; used_item = true;
}
}
} }
} }
@ -103,11 +145,9 @@ impl<'a> System<'a> for ItemUseSystem {
match inflict_damage.get(useitem.item) { match inflict_damage.get(useitem.item) {
None => {} None => {}
Some(damage) => { Some(damage) => {
let target_point = useitem.target.unwrap();
let idx = map.xy_idx(target_point.x, target_point.y);
used_item = false; used_item = false;
for mob in map.tile_content[idx].iter() { for mob in targets.iter() {
SufferDamage::new_damage(&mut suffer_damage, *mob, damage.damage); SufferDamage::new_damage(&mut suffer_damage, *mob, damage.damage);
if entity == *player_entity { if entity == *player_entity {
let mob_name = names.get(*mob).unwrap(); let mob_name = names.get(*mob).unwrap();

View File

@ -253,6 +253,7 @@ fn main() -> rltk::BError {
Consumable, Consumable,
Ranged, Ranged,
InflictsDamage, InflictsDamage,
AreaOfEffect,
); );
let map = Map::new_map_rooms_and_corridors(); let map = Map::new_map_rooms_and_corridors();

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
BlocksTile, CombatStats, Consumable, InflictsDamage, Item, Monster, Name, Player, Position, AreaOfEffect, BlocksTile, CombatStats, Consumable, InflictsDamage, Item, Monster, Name, Player,
ProvidesHealing, Ranged, Rect, Renderable, Viewshed, MAP_WIDTH, Position, ProvidesHealing, Ranged, Rect, Renderable, Viewshed, MAP_WIDTH,
}; };
use rltk::{RandomNumberGenerator, RGB}; use rltk::{RandomNumberGenerator, RGB};
use specs::prelude::*; use specs::prelude::*;
@ -172,11 +172,30 @@ fn random_item(ecs: &mut World, x: i32, y: i32) {
let roll: i32; let roll: i32;
{ {
let mut rng = ecs.write_resource::<RandomNumberGenerator>(); let mut rng = ecs.write_resource::<RandomNumberGenerator>();
roll = rng.roll_dice(1, 2); roll = rng.roll_dice(1, 3);
} }
match roll { match roll {
1 => health_potion(ecs, x, y), 1 => health_potion(ecs, x, y),
2 => fireball_scroll(ecs, x, y),
_ => magic_missile_scroll(ecs, x, y), _ => magic_missile_scroll(ecs, x, y),
} }
} }
fn fireball_scroll(ecs: &mut World, x: i32, y: i32) {
ecs.create_entity()
.with(Position { x, y })
.with(Renderable {
glyph: rltk::to_cp437(')'),
fg: RGB::named(rltk::ORANGE),
bg: RGB::named(rltk::BLACK),
render_order: 2,
})
.with(Name::new("Fireball Scroll"))
.with(Item {})
.with(Consumable {})
.with(Ranged { range: 6 })
.with(InflictsDamage { damage: 20 })
.with(AreaOfEffect { radius: 3 })
.build();
}