Add chapter: 18
This commit is contained in:
parent
0e2c91dd12
commit
cb17a9c356
File diff suppressed because one or more lines are too long
@ -173,3 +173,8 @@ pub struct DefenseBonus {
|
|||||||
pub struct WantsToRemoveItem {
|
pub struct WantsToRemoveItem {
|
||||||
pub item: Entity,
|
pub item: Entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ParticleLifetime {
|
||||||
|
pub lifetime_ms: f32,
|
||||||
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use rltk::console;
|
use rltk::console;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
use crate::{Map, Name, Position, RunState};
|
|
||||||
use crate::components::{CombatStats, Player, SufferDamage};
|
use crate::components::{CombatStats, Player, SufferDamage};
|
||||||
use crate::gamelog::GameLog;
|
use crate::gamelog::GameLog;
|
||||||
|
use crate::{Map, Name, Position, RunState};
|
||||||
|
|
||||||
pub struct DamageSystem {}
|
pub struct DamageSystem {}
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ impl<'a> System<'a> for DamageSystem {
|
|||||||
WriteStorage<'a, SufferDamage>,
|
WriteStorage<'a, SufferDamage>,
|
||||||
ReadStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
WriteExpect<'a, Map>,
|
||||||
Entities<'a>
|
Entities<'a>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
43
src/gui.rs
43
src/gui.rs
@ -1,14 +1,14 @@
|
|||||||
use rltk::{Rltk};
|
use rltk::Rltk;
|
||||||
use rltk::{Point, VirtualKeyCode};
|
|
||||||
use rltk::RGB;
|
use rltk::RGB;
|
||||||
|
use rltk::{Point, VirtualKeyCode};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
use crate::{CombatStats, InBackpack, RunState, State, Viewshed};
|
|
||||||
use crate::{Equipped, Map};
|
|
||||||
use crate::gamelog::GameLog;
|
use crate::gamelog::GameLog;
|
||||||
use crate::Name;
|
use crate::Name;
|
||||||
use crate::Player;
|
use crate::Player;
|
||||||
use crate::Position;
|
use crate::Position;
|
||||||
|
use crate::{CombatStats, InBackpack, RunState, State, Viewshed};
|
||||||
|
use crate::{Equipped, Map};
|
||||||
|
|
||||||
pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
||||||
ctx.draw_box(
|
ctx.draw_box(
|
||||||
@ -603,17 +603,40 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub enum GameOverResult { NoSelection, QuitToMenu }
|
pub enum GameOverResult {
|
||||||
|
NoSelection,
|
||||||
|
QuitToMenu,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn game_over(ctx: &mut Rltk) -> GameOverResult {
|
pub fn game_over(ctx: &mut Rltk) -> GameOverResult {
|
||||||
ctx.print_color_centered(15, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "Your journey has ended!");
|
ctx.print_color_centered(
|
||||||
ctx.print_color_centered(17, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "One day, we'll tell you all about how you did.");
|
15,
|
||||||
ctx.print_color_centered(18, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "That day, sadly, is not in this chapter..");
|
RGB::named(rltk::YELLOW),
|
||||||
|
RGB::named(rltk::BLACK),
|
||||||
|
"Your journey has ended!",
|
||||||
|
);
|
||||||
|
ctx.print_color_centered(
|
||||||
|
17,
|
||||||
|
RGB::named(rltk::WHITE),
|
||||||
|
RGB::named(rltk::BLACK),
|
||||||
|
"One day, we'll tell you all about how you did.",
|
||||||
|
);
|
||||||
|
ctx.print_color_centered(
|
||||||
|
18,
|
||||||
|
RGB::named(rltk::WHITE),
|
||||||
|
RGB::named(rltk::BLACK),
|
||||||
|
"That day, sadly, is not in this chapter..",
|
||||||
|
);
|
||||||
|
|
||||||
ctx.print_color_centered(20, RGB::named(rltk::MAGENTA), RGB::named(rltk::BLACK), "Press any key to return to the menu.");
|
ctx.print_color_centered(
|
||||||
|
20,
|
||||||
|
RGB::named(rltk::MAGENTA),
|
||||||
|
RGB::named(rltk::BLACK),
|
||||||
|
"Press any key to return to the menu.",
|
||||||
|
);
|
||||||
|
|
||||||
match ctx.key {
|
match ctx.key {
|
||||||
None => GameOverResult::NoSelection,
|
None => GameOverResult::NoSelection,
|
||||||
Some(_) => GameOverResult::QuitToMenu
|
Some(_) => GameOverResult::QuitToMenu,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
use crate::gamelog::GameLog;
|
use crate::gamelog::GameLog;
|
||||||
|
use crate::particle_system::ParticleBuilder;
|
||||||
use crate::{
|
use crate::{
|
||||||
AreaOfEffect, CombatStats, Confusion, Consumable, Equippable, Equipped, InBackpack,
|
AreaOfEffect, CombatStats, Confusion, Consumable, Equippable, Equipped, InBackpack,
|
||||||
InflictsDamage, Map, Name, Position, ProvidesHealing, Ranged, SufferDamage, WantsToDropItem,
|
InflictsDamage, Map, Name, Position, ProvidesHealing, Ranged, SufferDamage, WantsToDropItem,
|
||||||
@ -69,6 +70,8 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
ReadStorage<'a, Equippable>,
|
ReadStorage<'a, Equippable>,
|
||||||
WriteStorage<'a, Equipped>,
|
WriteStorage<'a, Equipped>,
|
||||||
WriteStorage<'a, InBackpack>,
|
WriteStorage<'a, InBackpack>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
ReadStorage<'a, Position>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -90,6 +93,8 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
equippable,
|
equippable,
|
||||||
mut equipped,
|
mut equipped,
|
||||||
mut backpack,
|
mut backpack,
|
||||||
|
mut particle_builder,
|
||||||
|
positions,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, use_item) in (&entities, &wants_use).join() {
|
for (entity, use_item) in (&entities, &wants_use).join() {
|
||||||
@ -118,8 +123,17 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
for mob in map.tile_content[idx].iter() {
|
for mob in map.tile_content[idx].iter() {
|
||||||
targets.push(*mob);
|
targets.push(*mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
particle_builder.request(
|
||||||
|
tile_idx.x,
|
||||||
|
tile_idx.y,
|
||||||
|
rltk::RGB::named(rltk::ORANGE),
|
||||||
|
rltk::RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('░'),
|
||||||
|
200.,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,6 +186,17 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
"You use {} on {}, inflicting {} hp.",
|
"You use {} on {}, inflicting {} hp.",
|
||||||
item_name.name, mob_name.name, item_damages.damage
|
item_name.name, mob_name.name, item_damages.damage
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if let Some(pos) = positions.get(*mob) {
|
||||||
|
particle_builder.request(
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
rltk::RGB::named(rltk::RED),
|
||||||
|
rltk::RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('‼'),
|
||||||
|
200.,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
used_item = true;
|
used_item = true;
|
||||||
@ -192,6 +217,16 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
used_item = true;
|
used_item = true;
|
||||||
|
if let Some(pos) = positions.get(*target) {
|
||||||
|
particle_builder.request(
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
rltk::RGB::named(rltk::GREEN),
|
||||||
|
rltk::RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('♥'),
|
||||||
|
200.,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +244,17 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
"You use {} on {}, confusing them.",
|
"You use {} on {}, confusing them.",
|
||||||
item_name.name, mob_name.name
|
item_name.name, mob_name.name
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if let Some(pos) = positions.get(*mob) {
|
||||||
|
particle_builder.request(
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
rltk::RGB::named(rltk::MAGENTA),
|
||||||
|
rltk::RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('?'),
|
||||||
|
200.,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/main.rs
16
src/main.rs
@ -14,7 +14,10 @@ use player::*;
|
|||||||
use visibility_system::*;
|
use visibility_system::*;
|
||||||
|
|
||||||
use crate::gamelog::GameLog;
|
use crate::gamelog::GameLog;
|
||||||
use crate::inventory_system::{ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem};
|
use crate::inventory_system::{
|
||||||
|
ItemCollectionSystem, ItemDropSystem, ItemRemoveSystem, ItemUseSystem,
|
||||||
|
};
|
||||||
|
use crate::particle_system::ParticleSpawnSystem;
|
||||||
|
|
||||||
mod components;
|
mod components;
|
||||||
mod damage_system;
|
mod damage_system;
|
||||||
@ -25,6 +28,7 @@ mod map;
|
|||||||
mod map_indexing_system;
|
mod map_indexing_system;
|
||||||
mod melee_combat_system;
|
mod melee_combat_system;
|
||||||
mod monster_ai_system;
|
mod monster_ai_system;
|
||||||
|
mod particle_system;
|
||||||
mod player;
|
mod player;
|
||||||
mod random_table;
|
mod random_table;
|
||||||
mod rect;
|
mod rect;
|
||||||
@ -221,6 +225,9 @@ impl State {
|
|||||||
let mut remove_items = ItemRemoveSystem {};
|
let mut remove_items = ItemRemoveSystem {};
|
||||||
remove_items.run_now(&self.ecs);
|
remove_items.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut particle_spawn = ParticleSpawnSystem {};
|
||||||
|
particle_spawn.run_now(&self.ecs);
|
||||||
|
|
||||||
self.ecs.maintain();
|
self.ecs.maintain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,6 +241,7 @@ impl GameState for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.cls();
|
ctx.cls();
|
||||||
|
particle_system::cull_dead_particles(&mut self.ecs, ctx);
|
||||||
|
|
||||||
match new_run_state {
|
match new_run_state {
|
||||||
RunState::MainMenu { .. } => {}
|
RunState::MainMenu { .. } => {}
|
||||||
@ -392,7 +400,9 @@ impl GameState for State {
|
|||||||
gui::GameOverResult::NoSelection => {}
|
gui::GameOverResult::NoSelection => {}
|
||||||
gui::GameOverResult::QuitToMenu => {
|
gui::GameOverResult::QuitToMenu => {
|
||||||
self.game_over_cleanup();
|
self.game_over_cleanup();
|
||||||
new_run_state = RunState::MainMenu { menu_selection: gui::MainMenuSelection::NewGame };
|
new_run_state = RunState::MainMenu {
|
||||||
|
menu_selection: gui::MainMenuSelection::NewGame,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,6 +427,7 @@ fn main() -> rltk::BError {
|
|||||||
let mut gs = State { ecs: World::new() };
|
let mut gs = State { ecs: World::new() };
|
||||||
|
|
||||||
gs.ecs.insert(rltk::RandomNumberGenerator::new());
|
gs.ecs.insert(rltk::RandomNumberGenerator::new());
|
||||||
|
gs.ecs.insert(particle_system::ParticleBuilder::new());
|
||||||
|
|
||||||
gs.ecs.register::<Position>();
|
gs.ecs.register::<Position>();
|
||||||
gs.ecs.register::<Renderable>();
|
gs.ecs.register::<Renderable>();
|
||||||
@ -446,6 +457,7 @@ fn main() -> rltk::BError {
|
|||||||
gs.ecs.register::<MeleePowerBonus>();
|
gs.ecs.register::<MeleePowerBonus>();
|
||||||
gs.ecs.register::<DefenseBonus>();
|
gs.ecs.register::<DefenseBonus>();
|
||||||
gs.ecs.register::<WantsToRemoveItem>();
|
gs.ecs.register::<WantsToRemoveItem>();
|
||||||
|
gs.ecs.register::<ParticleLifetime>();
|
||||||
|
|
||||||
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
|
||||||
|
|
||||||
|
56
src/map.rs
56
src/map.rs
@ -1,7 +1,7 @@
|
|||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use rltk::{Algorithm2D, BaseMap, FontCharType, Point, RandomNumberGenerator, RGB, Rltk};
|
use rltk::{Algorithm2D, BaseMap, FontCharType, Point, RandomNumberGenerator, Rltk, RGB};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
||||||
@ -246,32 +246,42 @@ pub fn draw_map(ecs: &World, ctx: &mut Rltk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wall_glyph(map: &Map, x: i32, y: i32) -> FontCharType {
|
fn wall_glyph(map: &Map, x: i32, y: i32) -> FontCharType {
|
||||||
if x < 1 || x > map.width - 2 || y < 1 || y > map.height - 2 as i32 { return 35; }
|
if x < 1 || x > map.width - 2 || y < 1 || y > map.height - 2 as i32 {
|
||||||
|
return 35;
|
||||||
|
}
|
||||||
let mut mask: u8 = 0;
|
let mut mask: u8 = 0;
|
||||||
|
|
||||||
if is_revealed_and_wall(map, x, y - 1) { mask += 1; }
|
if is_revealed_and_wall(map, x, y - 1) {
|
||||||
if is_revealed_and_wall(map, x, y + 1) { mask += 2; }
|
mask += 1;
|
||||||
if is_revealed_and_wall(map, x - 1, y) { mask += 4; }
|
}
|
||||||
if is_revealed_and_wall(map, x + 1, y) { mask += 8; }
|
if is_revealed_and_wall(map, x, y + 1) {
|
||||||
|
mask += 2;
|
||||||
|
}
|
||||||
|
if is_revealed_and_wall(map, x - 1, y) {
|
||||||
|
mask += 4;
|
||||||
|
}
|
||||||
|
if is_revealed_and_wall(map, x + 1, y) {
|
||||||
|
mask += 8;
|
||||||
|
}
|
||||||
|
|
||||||
match mask {
|
match mask {
|
||||||
0 => { 9 } // Pillar because we can't see neighbors
|
0 => 9, // Pillar because we can't see neighbors
|
||||||
1 => { 186 } // Wall only to the north
|
1 => 186, // Wall only to the north
|
||||||
2 => { 186 } // Wall only to the south
|
2 => 186, // Wall only to the south
|
||||||
3 => { 186 } // Wall to the north and south
|
3 => 186, // Wall to the north and south
|
||||||
4 => { 205 } // Wall only to the west
|
4 => 205, // Wall only to the west
|
||||||
5 => { 188 } // Wall to the north and west
|
5 => 188, // Wall to the north and west
|
||||||
6 => { 187 } // Wall to the south and west
|
6 => 187, // Wall to the south and west
|
||||||
7 => { 185 } // Wall to the north, south and west
|
7 => 185, // Wall to the north, south and west
|
||||||
8 => { 205 } // Wall only to the east
|
8 => 205, // Wall only to the east
|
||||||
9 => { 200 } // Wall to the north and east
|
9 => 200, // Wall to the north and east
|
||||||
10 => { 201 } // Wall to the south and east
|
10 => 201, // Wall to the south and east
|
||||||
11 => { 204 } // Wall to the north, south and east
|
11 => 204, // Wall to the north, south and east
|
||||||
12 => { 205 } // Wall to the east and west
|
12 => 205, // Wall to the east and west
|
||||||
13 => { 202 } // Wall to the east, west, and south
|
13 => 202, // Wall to the east, west, and south
|
||||||
14 => { 203 } // Wall to the east, west, and north
|
14 => 203, // Wall to the east, west, and north
|
||||||
15 => { 206 } // ╬ Wall on all sides
|
15 => 206, // ╬ Wall on all sides
|
||||||
_ => { 35 } // We missed one?
|
_ => 35, // We missed one?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,13 @@ use specs::prelude::*;
|
|||||||
|
|
||||||
use crate::components::{CombatStats, Name, SufferDamage, WantsToMelee};
|
use crate::components::{CombatStats, Name, SufferDamage, WantsToMelee};
|
||||||
use crate::gamelog::GameLog;
|
use crate::gamelog::GameLog;
|
||||||
use crate::{DefenseBonus, Equipped, MeleePowerBonus};
|
use crate::particle_system::ParticleBuilder;
|
||||||
|
use crate::{DefenseBonus, Equipped, MeleePowerBonus, Position};
|
||||||
|
|
||||||
pub struct MeleeCombatSystem {}
|
pub struct MeleeCombatSystem {}
|
||||||
|
|
||||||
impl<'a> System<'a> for MeleeCombatSystem {
|
impl<'a> System<'a> for MeleeCombatSystem {
|
||||||
|
#[allow(clippy::complexity)]
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
WriteExpect<'a, GameLog>,
|
WriteExpect<'a, GameLog>,
|
||||||
@ -17,6 +19,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
ReadStorage<'a, MeleePowerBonus>,
|
ReadStorage<'a, MeleePowerBonus>,
|
||||||
ReadStorage<'a, DefenseBonus>,
|
ReadStorage<'a, DefenseBonus>,
|
||||||
ReadStorage<'a, Equipped>,
|
ReadStorage<'a, Equipped>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
ReadStorage<'a, Position>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -30,6 +34,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
melee_bonus,
|
melee_bonus,
|
||||||
defense_bonus,
|
defense_bonus,
|
||||||
equipped,
|
equipped,
|
||||||
|
mut particle_builder,
|
||||||
|
positions,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, wants_melee, name, stats) in
|
for (entity, wants_melee, name, stats) in
|
||||||
@ -58,6 +64,17 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(pos) = positions.get(wants_melee.target) {
|
||||||
|
particle_builder.request(
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
rltk::RGB::named(rltk::ORANGE),
|
||||||
|
rltk::RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('‼'),
|
||||||
|
200.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let damage = i32::max(
|
let damage = i32::max(
|
||||||
0,
|
0,
|
||||||
(stats.power + offensive_bonus) - (target_stats.defense + defensive_bonus),
|
(stats.power + offensive_bonus) - (target_stats.defense + defensive_bonus),
|
||||||
|
@ -3,9 +3,10 @@ use specs::prelude::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{Monster, Position, Viewshed, WantsToMelee},
|
components::{Monster, Position, Viewshed, WantsToMelee},
|
||||||
map::Map,
|
Confusion,
|
||||||
Confusion, RunState,
|
map::Map, RunState,
|
||||||
};
|
};
|
||||||
|
use crate::particle_system::ParticleBuilder;
|
||||||
|
|
||||||
pub struct MonsterAI {}
|
pub struct MonsterAI {}
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
WriteStorage<'a, WantsToMelee>,
|
WriteStorage<'a, WantsToMelee>,
|
||||||
WriteStorage<'a, Confusion>,
|
WriteStorage<'a, Confusion>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -36,6 +38,7 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
mut position,
|
mut position,
|
||||||
mut wants_to_melee,
|
mut wants_to_melee,
|
||||||
mut confused,
|
mut confused,
|
||||||
|
mut particle_builder
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
if *runstate != RunState::MonsterTurn {
|
if *runstate != RunState::MonsterTurn {
|
||||||
@ -43,7 +46,7 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (entity, mut viewshed, _monster, mut pos) in
|
for (entity, mut viewshed, _monster, mut pos) in
|
||||||
(&entities, &mut viewshed, &monster, &mut position).join()
|
(&entities, &mut viewshed, &monster, &mut position).join()
|
||||||
{
|
{
|
||||||
let mut can_act = true;
|
let mut can_act = true;
|
||||||
|
|
||||||
@ -53,6 +56,8 @@ impl<'a> System<'a> for MonsterAI {
|
|||||||
confused.remove(entity);
|
confused.remove(entity);
|
||||||
}
|
}
|
||||||
can_act = false;
|
can_act = false;
|
||||||
|
|
||||||
|
particle_builder.request(pos.x, pos.y, rltk::RGB::named(rltk::MAGENTA), rltk::RGB::named(rltk::BLACK), rltk::to_cp437('?'), 200.);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !can_act {
|
if !can_act {
|
||||||
|
119
src/particle_system.rs
Normal file
119
src/particle_system.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
use rltk::{Rltk, RGB};
|
||||||
|
use specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::{ParticleLifetime, Position, Renderable};
|
||||||
|
|
||||||
|
pub fn cull_dead_particles(ecs: &mut World, ctx: &Rltk) {
|
||||||
|
let mut dead_particles: Vec<Entity> = Vec::new();
|
||||||
|
{
|
||||||
|
let mut particles = ecs.write_storage::<ParticleLifetime>();
|
||||||
|
let mut entities = ecs.entities();
|
||||||
|
for (entity, mut particle) in (&entities, &mut particles).join() {
|
||||||
|
particle.lifetime_ms -= ctx.frame_time_ms;
|
||||||
|
if particle.lifetime_ms < 0. {
|
||||||
|
dead_particles.push(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dead_particle in dead_particles.iter() {
|
||||||
|
ecs.delete_entity(*dead_particle)
|
||||||
|
.expect("Particle will not die");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParticleRequest {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
fg: RGB,
|
||||||
|
bg: RGB,
|
||||||
|
glyph: rltk::FontCharType,
|
||||||
|
lifetime: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParticleBuilder {
|
||||||
|
requests: Vec<ParticleRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParticleBuilder {
|
||||||
|
pub fn new() -> ParticleBuilder {
|
||||||
|
ParticleBuilder {
|
||||||
|
requests: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request(
|
||||||
|
&mut self,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
fg: RGB,
|
||||||
|
bg: RGB,
|
||||||
|
glyph: rltk::FontCharType,
|
||||||
|
lifetime: f32,
|
||||||
|
) {
|
||||||
|
self.requests.push(ParticleRequest {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
fg,
|
||||||
|
bg,
|
||||||
|
glyph,
|
||||||
|
lifetime,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParticleSpawnSystem {}
|
||||||
|
|
||||||
|
impl<'a> System<'a> for ParticleSpawnSystem {
|
||||||
|
type SystemData = (
|
||||||
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, Position>,
|
||||||
|
WriteStorage<'a, Renderable>,
|
||||||
|
WriteStorage<'a, ParticleLifetime>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
let (
|
||||||
|
entities,
|
||||||
|
mut positions,
|
||||||
|
mut renderables,
|
||||||
|
mut particle_lifetimes,
|
||||||
|
mut particle_builder,
|
||||||
|
) = data;
|
||||||
|
|
||||||
|
for new_particle in particle_builder.requests.iter() {
|
||||||
|
let p = entities.create();
|
||||||
|
positions
|
||||||
|
.insert(
|
||||||
|
p,
|
||||||
|
Position {
|
||||||
|
x: new_particle.x,
|
||||||
|
y: new_particle.y,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Unable to insert position");
|
||||||
|
renderables
|
||||||
|
.insert(
|
||||||
|
p,
|
||||||
|
Renderable {
|
||||||
|
fg: new_particle.fg,
|
||||||
|
bg: new_particle.bg,
|
||||||
|
glyph: new_particle.glyph,
|
||||||
|
render_order: 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Unable to insert renderable");
|
||||||
|
particle_lifetimes
|
||||||
|
.insert(
|
||||||
|
p,
|
||||||
|
ParticleLifetime {
|
||||||
|
lifetime_ms: new_particle.lifetime,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Unable to insert particle lifetime");
|
||||||
|
}
|
||||||
|
|
||||||
|
particle_builder.requests.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -76,7 +76,8 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
Equipped,
|
Equipped,
|
||||||
MeleePowerBonus,
|
MeleePowerBonus,
|
||||||
DefenseBonus,
|
DefenseBonus,
|
||||||
WantsToRemoveItem
|
WantsToRemoveItem,
|
||||||
|
ParticleLifetime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +156,8 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
Equipped,
|
Equipped,
|
||||||
MeleePowerBonus,
|
MeleePowerBonus,
|
||||||
DefenseBonus,
|
DefenseBonus,
|
||||||
WantsToRemoveItem
|
WantsToRemoveItem,
|
||||||
|
ParticleLifetime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use crate::rect::Rect;
|
|||||||
use crate::{
|
use crate::{
|
||||||
AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, DefenseBonus, EquipmentSlot,
|
AreaOfEffect, BlocksTile, CombatStats, Confusion, Consumable, DefenseBonus, EquipmentSlot,
|
||||||
Equippable, InflictsDamage, Item, MeleePowerBonus, Monster, Name, Player, Position,
|
Equippable, InflictsDamage, Item, MeleePowerBonus, Monster, Name, Player, Position,
|
||||||
ProvidesHealing, Ranged, Renderable, SerializeMe, Viewshed, MAP_WIDTH, MAX_MONSTER,
|
ProvidesHealing, Ranged, Renderable, SerializeMe, Viewshed, MAP_WIDTH, MAX_MONSTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||||
@ -249,7 +249,6 @@ fn dagger(ecs: &mut World, x: i32, y: i32) {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn longsword(ecs: &mut World, x: i32, y: i32) {
|
fn longsword(ecs: &mut World, x: i32, y: i32) {
|
||||||
ecs.create_entity()
|
ecs.create_entity()
|
||||||
.with(Position { x, y })
|
.with(Position { x, y })
|
||||||
@ -292,7 +291,6 @@ fn shield(ecs: &mut World, x: i32, y: i32) {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn tower_shield(ecs: &mut World, x: i32, y: i32) {
|
fn tower_shield(ecs: &mut World, x: i32, y: i32) {
|
||||||
ecs.create_entity()
|
ecs.create_entity()
|
||||||
.with(Position { x, y })
|
.with(Position { x, y })
|
||||||
|
Loading…
Reference in New Issue
Block a user