Refactor movement system, partially implement town portals
This commit is contained in:
parent
9132b6ae2f
commit
878ee5b480
@ -1,8 +1,8 @@
|
|||||||
use ::rltk::a_star_search;
|
use ::rltk::a_star_search;
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MyTurn, Position, Viewshed, WantsToApproach};
|
use crate::components::{ApplyMove, MyTurn, Position, WantsToApproach};
|
||||||
use crate::{spatial, Map};
|
use crate::Map;
|
||||||
|
|
||||||
pub struct ApproachAI {}
|
pub struct ApproachAI {}
|
||||||
|
|
||||||
@ -11,33 +11,18 @@ impl<'a> System<'a> for ApproachAI {
|
|||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
WriteStorage<'a, WantsToApproach>,
|
WriteStorage<'a, WantsToApproach>,
|
||||||
WriteStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
ReadExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
|
||||||
WriteStorage<'a, EntityMoved>,
|
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, ApplyMove>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (
|
let (mut turns, mut want_approach, positions, map, entities, mut apply_move) = data;
|
||||||
mut turns,
|
|
||||||
mut want_approach,
|
|
||||||
mut positions,
|
|
||||||
map,
|
|
||||||
mut viewsheds,
|
|
||||||
mut entity_moved,
|
|
||||||
entities,
|
|
||||||
) = data;
|
|
||||||
|
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, mut pos, approach, mut viewshed, _myturn) in (
|
for (entity, pos, approach, _myturn) in
|
||||||
&entities,
|
(&entities, &positions, &want_approach, &turns).join()
|
||||||
&mut positions,
|
|
||||||
&want_approach,
|
|
||||||
&mut viewsheds,
|
|
||||||
&turns,
|
|
||||||
)
|
|
||||||
.join()
|
|
||||||
{
|
{
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
|
|
||||||
@ -48,16 +33,14 @@ impl<'a> System<'a> for ApproachAI {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if path.success && path.steps.len() > 1 {
|
if path.success && path.steps.len() > 1 {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
apply_move
|
||||||
pos.x = path.steps[1] as i32 % map.width;
|
.insert(
|
||||||
pos.y = path.steps[1] as i32 / map.width;
|
entity,
|
||||||
entity_moved
|
ApplyMove {
|
||||||
.insert(entity, EntityMoved {})
|
dest_idx: path.steps[1],
|
||||||
.expect("Unable to insert moved marker");
|
},
|
||||||
|
)
|
||||||
let new_idx = map.xy_idx(pos.x, pos.y);
|
.expect("Unable to insert intent to move.");
|
||||||
spatial::move_entity(entity, idx, new_idx);
|
|
||||||
viewshed.dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Chasing, EntityMoved, MyTurn, Position, Viewshed};
|
use crate::components::{ApplyMove, Chasing, MyTurn, Position};
|
||||||
use crate::{spatial, Map};
|
use crate::Map;
|
||||||
|
|
||||||
pub struct ChaseAI {}
|
pub struct ChaseAI {}
|
||||||
|
|
||||||
@ -12,16 +12,14 @@ impl<'a> System<'a> for ChaseAI {
|
|||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
WriteStorage<'a, Chasing>,
|
WriteStorage<'a, Chasing>,
|
||||||
WriteStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
ReadExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
|
||||||
WriteStorage<'a, EntityMoved>,
|
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, ApplyMove>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (mut turns, mut chasing, mut positions, map, mut viewsheds, mut entity_moved, entities) =
|
let (mut turns, mut chasing, positions, map, entities, mut apply_move) = data;
|
||||||
data;
|
|
||||||
|
|
||||||
let mut targets: HashMap<Entity, (i32, i32)> = HashMap::new();
|
let mut targets: HashMap<Entity, (i32, i32)> = HashMap::new();
|
||||||
let mut end_chase: Vec<Entity> = Vec::new();
|
let mut end_chase: Vec<Entity> = Vec::new();
|
||||||
@ -39,9 +37,7 @@ impl<'a> System<'a> for ChaseAI {
|
|||||||
end_chase.clear();
|
end_chase.clear();
|
||||||
|
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, mut pos, _chase, mut viewshed, _myturn) in
|
for (entity, pos, _chase, _myturn) in (&entities, &positions, &chasing, &turns).join() {
|
||||||
(&entities, &mut positions, &chasing, &mut viewsheds, &turns).join()
|
|
||||||
{
|
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
let target_pos = targets[&entity];
|
let target_pos = targets[&entity];
|
||||||
let path = ::rltk::a_star_search(
|
let path = ::rltk::a_star_search(
|
||||||
@ -51,16 +47,14 @@ impl<'a> System<'a> for ChaseAI {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if path.success && path.steps.len() > 1 && path.steps.len() < 15 {
|
if path.success && path.steps.len() > 1 && path.steps.len() < 15 {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
apply_move
|
||||||
pos.x = path.steps[1] as i32 % map.width;
|
.insert(
|
||||||
pos.y = path.steps[1] as i32 / map.width;
|
entity,
|
||||||
entity_moved
|
ApplyMove {
|
||||||
.insert(entity, EntityMoved {})
|
dest_idx: path.steps[1],
|
||||||
.expect("Unable to insert movement marker");
|
},
|
||||||
|
)
|
||||||
let new_idx = map.xy_idx(pos.x, pos.y);
|
.expect("Unable to insert intent to move.");
|
||||||
viewshed.dirty = true;
|
|
||||||
spatial::move_entity(entity, idx, new_idx);
|
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
} else {
|
} else {
|
||||||
end_chase.push(entity);
|
end_chase.push(entity);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use ::rltk::RandomNumberGenerator;
|
use ::rltk::RandomNumberGenerator;
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MoveMode, Movement, MyTurn, Position, Viewshed};
|
use crate::components::{ApplyMove, MoveMode, Movement, MyTurn, Position};
|
||||||
use crate::{spatial, tile_walkable, Map};
|
use crate::{spatial, tile_walkable, Map};
|
||||||
|
|
||||||
pub struct DefaultMoveAI {}
|
pub struct DefaultMoveAI {}
|
||||||
@ -11,35 +11,19 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
WriteStorage<'a, MoveMode>,
|
WriteStorage<'a, MoveMode>,
|
||||||
WriteStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
ReadExpect<'a, Map>,
|
ReadExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
|
||||||
WriteStorage<'a, EntityMoved>,
|
|
||||||
WriteExpect<'a, RandomNumberGenerator>,
|
WriteExpect<'a, RandomNumberGenerator>,
|
||||||
|
WriteStorage<'a, ApplyMove>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (
|
let (mut turns, mut move_mode, positions, map, mut rng, mut apply_move, entities) = data;
|
||||||
mut turns,
|
|
||||||
mut move_mode,
|
|
||||||
mut positions,
|
|
||||||
map,
|
|
||||||
mut viewsheds,
|
|
||||||
mut entity_moved,
|
|
||||||
mut rng,
|
|
||||||
entities,
|
|
||||||
) = data;
|
|
||||||
|
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, mut pos, mut mode, mut viewshed, _myturn) in (
|
for (entity, pos, mut mode, _myturn) in
|
||||||
&entities,
|
(&entities, &positions, &mut move_mode, &turns).join()
|
||||||
&mut positions,
|
|
||||||
&mut move_mode,
|
|
||||||
&mut viewsheds,
|
|
||||||
&turns,
|
|
||||||
)
|
|
||||||
.join()
|
|
||||||
{
|
{
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
|
|
||||||
@ -60,33 +44,23 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
if x > 0 && x < map.width - 1 && y > 0 && y < map.height - 1 {
|
if x > 0 && x < map.width - 1 && y > 0 && y < map.height - 1 {
|
||||||
let dest_idx = map.xy_idx(x, y);
|
let dest_idx = map.xy_idx(x, y);
|
||||||
if !spatial::is_blocked(dest_idx) {
|
if !spatial::is_blocked(dest_idx) {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
apply_move
|
||||||
pos.x = x;
|
.insert(entity, ApplyMove { dest_idx })
|
||||||
pos.y = y;
|
.expect("Unable to insert intent to move.");
|
||||||
entity_moved
|
turn_done.push(entity);
|
||||||
.insert(entity, EntityMoved {})
|
|
||||||
.expect("Unable to insert movement marker");
|
|
||||||
crate::spatial::move_entity(entity, idx, dest_idx);
|
|
||||||
viewshed.dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Movement::RandomWaypoint { path } => {
|
Movement::RandomWaypoint { path } => {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
// We have a target - go there
|
// We have a target - go there
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
|
||||||
if path.len() > 1 {
|
if path.len() > 1 {
|
||||||
if !spatial::is_blocked(path[1]) {
|
if !spatial::is_blocked(path[1]) {
|
||||||
pos.x = (path[1] as i32 % map.width) as i32;
|
apply_move
|
||||||
pos.y = (path[1] as i32 / map.width) as i32;
|
.insert(entity, ApplyMove { dest_idx: path[1] })
|
||||||
entity_moved
|
.expect("Unable to insert intent to move.");
|
||||||
.insert(entity, EntityMoved {})
|
|
||||||
.expect("Unable to insert movement marker");
|
|
||||||
|
|
||||||
let new_idx = map.xy_idx(pos.x, pos.y);
|
|
||||||
spatial::move_entity(entity, idx, new_idx);
|
|
||||||
viewshed.dirty = true;
|
|
||||||
path.remove(0); // Remove the first step in the path
|
path.remove(0); // Remove the first step in the path
|
||||||
|
turn_done.push(entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we wait a turn to see if the path clears up
|
// Otherwise we wait a turn to see if the path clears up
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use ::rltk::DijkstraMap;
|
use ::rltk::DijkstraMap;
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MyTurn, Position, Viewshed, WantsToFlee};
|
use crate::components::{ApplyMove, MyTurn, Position, WantsToFlee};
|
||||||
use crate::{spatial, Map};
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
pub struct FleeAI {}
|
pub struct FleeAI {}
|
||||||
@ -13,32 +13,15 @@ impl<'a> System<'a> for FleeAI {
|
|||||||
WriteStorage<'a, WantsToFlee>,
|
WriteStorage<'a, WantsToFlee>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
WriteExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
|
||||||
WriteStorage<'a, EntityMoved>,
|
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, ApplyMove>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (
|
let (mut turns, mut want_flee, positions, mut map, entities, mut apply_move) = data;
|
||||||
mut turns,
|
|
||||||
mut want_flee,
|
|
||||||
mut positions,
|
|
||||||
mut map,
|
|
||||||
mut viewsheds,
|
|
||||||
mut entity_moved,
|
|
||||||
entities,
|
|
||||||
) = data;
|
|
||||||
|
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, mut pos, flee, mut viewshed, _myturn) in (
|
for (entity, pos, flee, _myturn) in (&entities, &positions, &want_flee, &turns).join() {
|
||||||
&entities,
|
|
||||||
&mut positions,
|
|
||||||
&want_flee,
|
|
||||||
&mut viewsheds,
|
|
||||||
&turns,
|
|
||||||
)
|
|
||||||
.join()
|
|
||||||
{
|
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
|
|
||||||
let my_idx = map.xy_idx(pos.x, pos.y);
|
let my_idx = map.xy_idx(pos.x, pos.y);
|
||||||
@ -47,13 +30,15 @@ impl<'a> System<'a> for FleeAI {
|
|||||||
let flee_map = DijkstraMap::new(map.width, map.height, &flee.indices, &*map, 100.0);
|
let flee_map = DijkstraMap::new(map.width, map.height, &flee.indices, &*map, 100.0);
|
||||||
if let Some(flee_target) = DijkstraMap::find_highest_exit(&flee_map, my_idx, &*map) {
|
if let Some(flee_target) = DijkstraMap::find_highest_exit(&flee_map, my_idx, &*map) {
|
||||||
if !spatial::is_blocked(flee_target) {
|
if !spatial::is_blocked(flee_target) {
|
||||||
spatial::move_entity(entity, my_idx, flee_target);
|
apply_move
|
||||||
viewshed.dirty = true;
|
.insert(
|
||||||
pos.x = flee_target as i32 % map.width;
|
entity,
|
||||||
pos.y = flee_target as i32 / map.width;
|
ApplyMove {
|
||||||
entity_moved
|
dest_idx: flee_target,
|
||||||
.insert(entity, EntityMoved {})
|
},
|
||||||
.expect("Unable to insert intent to flee");
|
)
|
||||||
|
.expect("Unable to insert intention to flee");
|
||||||
|
turn_done.push(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,6 +354,26 @@ pub struct Vendor {
|
|||||||
pub categories: Vec<String>,
|
pub categories: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct TeleportTo {
|
||||||
|
pub x: i32,
|
||||||
|
pub y: i32,
|
||||||
|
pub depth: i32,
|
||||||
|
pub player_only: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ApplyMove {
|
||||||
|
pub dest_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ApplyTeleport {
|
||||||
|
pub dest_x: i32,
|
||||||
|
pub dest_y: i32,
|
||||||
|
pub dest_depth: i32,
|
||||||
|
}
|
||||||
|
|
||||||
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
|
// Serialization helper code. We need to implement ConvertSaveLoad for each type that contains an
|
||||||
// Entity.
|
// Entity.
|
||||||
|
|
||||||
|
@ -39,3 +39,6 @@ pub struct MyTurn {}
|
|||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct EquipmentChanged {}
|
pub struct EquipmentChanged {}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct TownPortal {}
|
||||||
|
@ -84,6 +84,7 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
ReadStorage<'a, MagicMapper>,
|
ReadStorage<'a, MagicMapper>,
|
||||||
WriteExpect<'a, RunState>,
|
WriteExpect<'a, RunState>,
|
||||||
WriteStorage<'a, EquipmentChanged>,
|
WriteStorage<'a, EquipmentChanged>,
|
||||||
|
ReadStorage<'a, TownPortal>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
@ -112,6 +113,7 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
magic_mapper,
|
magic_mapper,
|
||||||
mut runstate,
|
mut runstate,
|
||||||
mut dirty,
|
mut dirty,
|
||||||
|
town_portal,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, useitem) in (&entities, &wants_use).join() {
|
for (entity, useitem) in (&entities, &wants_use).join() {
|
||||||
@ -236,6 +238,18 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it's a town portal...
|
||||||
|
if town_portal.get(useitem.item).is_some() {
|
||||||
|
if map.depth == 1 {
|
||||||
|
gamelog.append("You are already in town, so the scroll does nothing");
|
||||||
|
} else {
|
||||||
|
used_item = true;
|
||||||
|
gamelog.append("You are teleported back to town!");
|
||||||
|
|
||||||
|
*runstate = RunState::TownPortal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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 => {}
|
||||||
|
23
src/main.rs
23
src/main.rs
@ -13,6 +13,7 @@ mod map;
|
|||||||
pub mod map_builders;
|
pub mod map_builders;
|
||||||
mod map_indexing_system;
|
mod map_indexing_system;
|
||||||
mod melee_combat_system;
|
mod melee_combat_system;
|
||||||
|
mod movement_system;
|
||||||
mod particle_system;
|
mod particle_system;
|
||||||
mod player;
|
mod player;
|
||||||
pub mod random_table;
|
pub mod random_table;
|
||||||
@ -41,6 +42,7 @@ use lighting_system::LightingSystem;
|
|||||||
pub use map::*;
|
pub use map::*;
|
||||||
use map_indexing_system::MapIndexingSystem;
|
use map_indexing_system::MapIndexingSystem;
|
||||||
use melee_combat_system::MeleeCombatSystem;
|
use melee_combat_system::MeleeCombatSystem;
|
||||||
|
use movement_system::MovementSystem;
|
||||||
use particle_system::ParticleSpawnSystem;
|
use particle_system::ParticleSpawnSystem;
|
||||||
use player::*;
|
use player::*;
|
||||||
use raws::*;
|
use raws::*;
|
||||||
@ -84,6 +86,7 @@ pub enum RunState {
|
|||||||
SaveGame,
|
SaveGame,
|
||||||
NextLevel,
|
NextLevel,
|
||||||
PreviousLevel,
|
PreviousLevel,
|
||||||
|
TownPortal,
|
||||||
ShowRemoveItem,
|
ShowRemoveItem,
|
||||||
GameOver,
|
GameOver,
|
||||||
MagicMapReveal {
|
MagicMapReveal {
|
||||||
@ -155,6 +158,9 @@ impl State {
|
|||||||
let mut defaultmove = ai::DefaultMoveAI {};
|
let mut defaultmove = ai::DefaultMoveAI {};
|
||||||
defaultmove.run_now(&self.ecs);
|
defaultmove.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut moving = MovementSystem {};
|
||||||
|
moving.run_now(&self.ecs);
|
||||||
|
|
||||||
let mut triggers = TriggerSystem {};
|
let mut triggers = TriggerSystem {};
|
||||||
triggers.run_now(&self.ecs);
|
triggers.run_now(&self.ecs);
|
||||||
|
|
||||||
@ -244,6 +250,7 @@ impl GameState for State {
|
|||||||
newrunstate = match *self.ecs.fetch::<RunState>() {
|
newrunstate = match *self.ecs.fetch::<RunState>() {
|
||||||
RunState::AwaitingInput => RunState::AwaitingInput,
|
RunState::AwaitingInput => RunState::AwaitingInput,
|
||||||
RunState::MagicMapReveal { .. } => RunState::MagicMapReveal { row: 0 },
|
RunState::MagicMapReveal { .. } => RunState::MagicMapReveal { row: 0 },
|
||||||
|
RunState::TownPortal => RunState::TownPortal,
|
||||||
_ => RunState::Ticking,
|
_ => RunState::Ticking,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -483,6 +490,18 @@ impl GameState for State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RunState::TownPortal => {
|
||||||
|
// Spawn the portal
|
||||||
|
spawner::spawn_town_portal(&mut self.ecs);
|
||||||
|
|
||||||
|
// Transition
|
||||||
|
let map_depth = self.ecs.fetch::<Map>().depth;
|
||||||
|
let destination_offset = 0 - (map_depth - 1);
|
||||||
|
self.goto_level(destination_offset);
|
||||||
|
self.mapgen_next_state = Some(RunState::PreRun);
|
||||||
|
|
||||||
|
newrunstate = RunState::MapGeneration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -556,6 +575,8 @@ fn main() -> ::rltk::BError {
|
|||||||
|
|
||||||
register!(
|
register!(
|
||||||
gs <-
|
gs <-
|
||||||
|
ApplyMove,
|
||||||
|
ApplyTeleport,
|
||||||
AreaOfEffect,
|
AreaOfEffect,
|
||||||
Attributes,
|
Attributes,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
@ -600,6 +621,8 @@ fn main() -> ::rltk::BError {
|
|||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
SufferDamage,
|
SufferDamage,
|
||||||
|
TeleportTo,
|
||||||
|
TownPortal,
|
||||||
Vendor,
|
Vendor,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use ::rltk::RandomNumberGenerator;
|
use ::rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
use super::prefab_builder::prefab_sections;
|
||||||
use super::{
|
use super::{
|
||||||
prefab_builder::prefab_sections, AreaEndingPosition, AreaStartingPosition, BspDungeonBuilder,
|
AreaEndingPosition, AreaStartingPosition, BspDungeonBuilder, BuilderChain, BuilderMap,
|
||||||
BuilderChain, BuilderMap, CellularAutomataBuilder, CullUnreachable, DLABuilder, DistantExit,
|
CellularAutomataBuilder, CullUnreachable, DLABuilder, DistantExit, DrunkardsWalkBuilder,
|
||||||
DrunkardsWalkBuilder, MetaMapBuilder, NearestCorridors, PrefabBuilder, RoomBasedSpawner,
|
MetaMapBuilder, NearestCorridors, PrefabBuilder, RoomBasedSpawner, RoomDrawer, RoomExploder,
|
||||||
RoomDrawer, RoomExploder, RoomSort, RoomSorter, VoronoiSpawning, XEnd, XStart, YEnd, YStart,
|
RoomSort, RoomSorter, VoronoiSpawning, XEnd, XStart, YEnd, YStart,
|
||||||
};
|
};
|
||||||
use crate::map::TileType;
|
use crate::map::TileType;
|
||||||
|
|
||||||
|
89
src/movement_system.rs
Normal file
89
src/movement_system.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::{
|
||||||
|
ApplyMove, ApplyTeleport, BlocksTile, EntityMoved, OtherLevelPosition, Position, Viewshed,
|
||||||
|
};
|
||||||
|
use crate::{spatial, Map};
|
||||||
|
|
||||||
|
pub struct MovementSystem {}
|
||||||
|
|
||||||
|
impl<'a> System<'a> for MovementSystem {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type SystemData = (
|
||||||
|
WriteExpect<'a, Map>,
|
||||||
|
WriteStorage<'a, Position>,
|
||||||
|
ReadStorage<'a, BlocksTile>,
|
||||||
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, ApplyMove>,
|
||||||
|
WriteStorage<'a, ApplyTeleport>,
|
||||||
|
WriteStorage<'a, OtherLevelPosition>,
|
||||||
|
WriteStorage<'a, EntityMoved>,
|
||||||
|
WriteStorage<'a, Viewshed>,
|
||||||
|
ReadExpect<'a, Entity>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
let (
|
||||||
|
mut map,
|
||||||
|
mut position,
|
||||||
|
blockers,
|
||||||
|
entities,
|
||||||
|
mut apply_move,
|
||||||
|
mut apply_teleport,
|
||||||
|
mut other_level,
|
||||||
|
mut moved,
|
||||||
|
mut viewsheds,
|
||||||
|
player_entity,
|
||||||
|
) = data;
|
||||||
|
|
||||||
|
// Apply teleports
|
||||||
|
for (entity, teleport) in (&entities, &apply_teleport).join() {
|
||||||
|
if teleport.dest_depth == map.depth {
|
||||||
|
apply_move
|
||||||
|
.insert(
|
||||||
|
entity,
|
||||||
|
ApplyMove {
|
||||||
|
dest_idx: map.xy_idx(teleport.dest_x, teleport.dest_y),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Unable to insert intent to teleport");
|
||||||
|
} else if entity == *player_entity {
|
||||||
|
// it's the player - we have a mess
|
||||||
|
::rltk::console::log(format!("Not implemented yet."))
|
||||||
|
} else if let Some(pos) = position.get(entity) {
|
||||||
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
let dest_idx = map.xy_idx(teleport.dest_x, teleport.dest_y);
|
||||||
|
spatial::move_entity(entity, idx, dest_idx);
|
||||||
|
other_level
|
||||||
|
.insert(
|
||||||
|
entity,
|
||||||
|
OtherLevelPosition {
|
||||||
|
x: teleport.dest_x,
|
||||||
|
y: teleport.dest_y,
|
||||||
|
depth: teleport.dest_depth,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Unable to insert intent to teleport.");
|
||||||
|
|
||||||
|
position.remove(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply_teleport.clear();
|
||||||
|
|
||||||
|
// Apply broad movement
|
||||||
|
for (entity, movement, mut pos) in (&entities, &apply_move, &mut position).join() {
|
||||||
|
let start_idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
let dest_idx = movement.dest_idx as usize;
|
||||||
|
spatial::move_entity(entity, start_idx, dest_idx);
|
||||||
|
pos.x = movement.dest_idx as i32 % map.width;
|
||||||
|
pos.y = movement.dest_idx as i32 / map.width;
|
||||||
|
if let Some(vs) = viewsheds.get_mut(entity) {
|
||||||
|
vs.dirty = true;
|
||||||
|
}
|
||||||
|
moved
|
||||||
|
.insert(entity, EntityMoved {})
|
||||||
|
.expect("Unable to insert moved marker");
|
||||||
|
}
|
||||||
|
apply_move.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -285,6 +285,7 @@ pub fn spawn_named_item(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
"magic_mapping" => eb = eb.with(MagicMapper {}),
|
"magic_mapping" => eb = eb.with(MagicMapper {}),
|
||||||
|
"town_portal" => eb = eb.with(TownPortal {}),
|
||||||
"food" => eb = eb.with(ProvidesFood {}),
|
"food" => eb = eb.with(ProvidesFood {}),
|
||||||
_ => {
|
_ => {
|
||||||
rltk::console::log(format!(
|
rltk::console::log(format!(
|
||||||
|
@ -61,6 +61,8 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
ecs,
|
ecs,
|
||||||
serializer,
|
serializer,
|
||||||
data,
|
data,
|
||||||
|
ApplyMove,
|
||||||
|
ApplyTeleport,
|
||||||
AreaOfEffect,
|
AreaOfEffect,
|
||||||
Attributes,
|
Attributes,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
@ -104,6 +106,8 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
SufferDamage,
|
SufferDamage,
|
||||||
|
TeleportTo,
|
||||||
|
TownPortal,
|
||||||
Vendor,
|
Vendor,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
@ -170,6 +174,8 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
ecs,
|
ecs,
|
||||||
de,
|
de,
|
||||||
d,
|
d,
|
||||||
|
ApplyMove,
|
||||||
|
ApplyTeleport,
|
||||||
AreaOfEffect,
|
AreaOfEffect,
|
||||||
Attributes,
|
Attributes,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
@ -213,6 +219,8 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
SufferDamage,
|
SufferDamage,
|
||||||
|
TeleportTo,
|
||||||
|
TownPortal,
|
||||||
Vendor,
|
Vendor,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ::rltk::RandomNumberGenerator;
|
use ::rltk::{Point, RandomNumberGenerator};
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
use ::specs::saveload::{MarkedBuilder, SimpleMarker};
|
use ::specs::saveload::{MarkedBuilder, SimpleMarker};
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ use crate::components::*;
|
|||||||
use crate::gamesystem::{mana_at_level, player_hp_at_level};
|
use crate::gamesystem::{mana_at_level, player_hp_at_level};
|
||||||
use crate::random_table::RandomTable;
|
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_named_entity, SpawnType, RAWS};
|
||||||
use crate::{colors, Map, Rect, TileType};
|
use crate::{colors, Map, MasterDungeonMap, Rect, TileType};
|
||||||
|
|
||||||
/// Spawns the player and returns their entity object
|
/// Spawns the player and returns their entity object
|
||||||
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 {
|
||||||
@ -95,6 +95,12 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
|||||||
"Old Boots",
|
"Old Boots",
|
||||||
SpawnType::Equipped { by: player },
|
SpawnType::Equipped { by: player },
|
||||||
);
|
);
|
||||||
|
spawn_named_entity(
|
||||||
|
&RAWS.lock().unwrap(),
|
||||||
|
ecs,
|
||||||
|
"Town Portal Scroll",
|
||||||
|
SpawnType::Carried { by: player },
|
||||||
|
);
|
||||||
|
|
||||||
player
|
player
|
||||||
}
|
}
|
||||||
@ -195,3 +201,52 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
|||||||
spawn.1
|
spawn.1
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn spawn_town_portal(ecs: &mut World) {
|
||||||
|
// Get current position & depth
|
||||||
|
let map = ecs.fetch::<Map>();
|
||||||
|
let player_depth = map.depth;
|
||||||
|
let player_pos = ecs.fetch::<Point>();
|
||||||
|
let player_x = player_pos.x;
|
||||||
|
let player_y = player_pos.y;
|
||||||
|
std::mem::drop(player_pos);
|
||||||
|
std::mem::drop(map);
|
||||||
|
|
||||||
|
// Find part of the town for the portal
|
||||||
|
let dm = ecs.fetch::<MasterDungeonMap>();
|
||||||
|
let town_map = dm.get_map(1).unwrap();
|
||||||
|
let mut stairs_idx = 0;
|
||||||
|
for (idx, tt) in town_map.tiles.iter().enumerate() {
|
||||||
|
if *tt == TileType::DownStairs {
|
||||||
|
stairs_idx = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let portal_x = (stairs_idx as i32 % town_map.width) - 2;
|
||||||
|
let portal_y = stairs_idx as i32 / town_map.width;
|
||||||
|
|
||||||
|
std::mem::drop(dm);
|
||||||
|
|
||||||
|
// Spawn the portal itself
|
||||||
|
ecs.create_entity()
|
||||||
|
.with(OtherLevelPosition {
|
||||||
|
x: portal_x,
|
||||||
|
y: portal_y,
|
||||||
|
depth: 1,
|
||||||
|
})
|
||||||
|
.with(Renderable {
|
||||||
|
glyph: ::rltk::to_cp437('♥'),
|
||||||
|
fg: colors::CYAN,
|
||||||
|
bg: colors::BLACK,
|
||||||
|
render_order: 0,
|
||||||
|
})
|
||||||
|
.with(EntryTrigger {})
|
||||||
|
.with(TeleportTo {
|
||||||
|
x: player_x,
|
||||||
|
y: player_y,
|
||||||
|
depth: player_depth,
|
||||||
|
player_only: true,
|
||||||
|
})
|
||||||
|
.with(Name::from("Town Portal"))
|
||||||
|
.with(SingleActivation {})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user