Complete section 5.14, having refactored basically every system
This commit is contained in:
parent
148e448d78
commit
eb29e28ec6
@ -1,5 +1,6 @@
|
|||||||
mod adjacent_ai_system;
|
mod adjacent_ai_system;
|
||||||
mod approach_ai_system;
|
mod approach_ai_system;
|
||||||
|
mod chase_ai_system;
|
||||||
mod default_move_system;
|
mod default_move_system;
|
||||||
mod flee_ai_system;
|
mod flee_ai_system;
|
||||||
mod initiative_system;
|
mod initiative_system;
|
||||||
@ -9,6 +10,7 @@ mod visible_ai_system;
|
|||||||
|
|
||||||
pub use adjacent_ai_system::AdjacentAI;
|
pub use adjacent_ai_system::AdjacentAI;
|
||||||
pub use approach_ai_system::ApproachAI;
|
pub use approach_ai_system::ApproachAI;
|
||||||
|
pub use chase_ai_system::ChaseAI;
|
||||||
pub use default_move_system::DefaultMoveAI;
|
pub use default_move_system::DefaultMoveAI;
|
||||||
pub use flee_ai_system::FleeAI;
|
pub use flee_ai_system::FleeAI;
|
||||||
pub use initiative_system::InitiativeSystem;
|
pub use initiative_system::InitiativeSystem;
|
||||||
|
85
src/ai/chase_ai_system.rs
Normal file
85
src/ai/chase_ai_system.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::{Chasing, EntityMoved, MyTurn, Position, Viewshed};
|
||||||
|
use crate::Map;
|
||||||
|
|
||||||
|
pub struct ChaseAI {}
|
||||||
|
|
||||||
|
impl<'a> System<'a> for ChaseAI {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
type SystemData = (
|
||||||
|
WriteStorage<'a, MyTurn>,
|
||||||
|
WriteStorage<'a, Chasing>,
|
||||||
|
WriteStorage<'a, Position>,
|
||||||
|
WriteExpect<'a, Map>,
|
||||||
|
WriteStorage<'a, Viewshed>,
|
||||||
|
WriteStorage<'a, EntityMoved>,
|
||||||
|
Entities<'a>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
let (
|
||||||
|
mut turns,
|
||||||
|
mut chasing,
|
||||||
|
mut positions,
|
||||||
|
mut map,
|
||||||
|
mut viewsheds,
|
||||||
|
mut entity_moved,
|
||||||
|
entities,
|
||||||
|
) = data;
|
||||||
|
|
||||||
|
let mut targets: HashMap<Entity, (i32, i32)> = HashMap::new();
|
||||||
|
let mut end_chase: Vec<Entity> = Vec::new();
|
||||||
|
for (entity, _turn, chasing) in (&entities, &turns, &chasing).join() {
|
||||||
|
if let Some(target_pos) = positions.get(chasing.target) {
|
||||||
|
targets.insert(entity, (target_pos.x, target_pos.y));
|
||||||
|
} else {
|
||||||
|
end_chase.push(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for done in end_chase.iter() {
|
||||||
|
chasing.remove(*done);
|
||||||
|
}
|
||||||
|
end_chase.clear();
|
||||||
|
|
||||||
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
|
for (entity, mut pos, _chase, mut viewshed, _myturn) in
|
||||||
|
(&entities, &mut positions, &chasing, &mut viewsheds, &turns).join()
|
||||||
|
{
|
||||||
|
turn_done.push(entity);
|
||||||
|
let target_pos = targets[&entity];
|
||||||
|
let path = ::rltk::a_star_search(
|
||||||
|
map.xy_idx(pos.x, pos.y) as i32,
|
||||||
|
map.xy_idx(target_pos.0, target_pos.1) as i32,
|
||||||
|
&*map,
|
||||||
|
);
|
||||||
|
|
||||||
|
if path.success && path.steps.len() > 1 && path.steps.len() < 15 {
|
||||||
|
let mut idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
map.blocked[idx] = false;
|
||||||
|
pos.x = path.steps[1] as i32 % map.width;
|
||||||
|
pos.y = path.steps[1] as i32 / map.width;
|
||||||
|
entity_moved
|
||||||
|
.insert(entity, EntityMoved {})
|
||||||
|
.expect("Unable to insert movement marker");
|
||||||
|
|
||||||
|
idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
map.blocked[idx] = true;
|
||||||
|
viewshed.dirty = true;
|
||||||
|
turn_done.push(entity);
|
||||||
|
} else {
|
||||||
|
end_chase.push(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for done in end_chase.iter() {
|
||||||
|
chasing.remove(*done);
|
||||||
|
}
|
||||||
|
for done in turn_done.iter() {
|
||||||
|
turns.remove(*done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ use ::rltk::RandomNumberGenerator;
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{EntityMoved, MoveMode, Movement, MyTurn, Position, Viewshed};
|
use crate::components::{EntityMoved, MoveMode, Movement, MyTurn, Position, Viewshed};
|
||||||
use crate::Map;
|
use crate::{tile_walkable, Map};
|
||||||
|
|
||||||
pub struct DefaultMoveAI {}
|
pub struct DefaultMoveAI {}
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteStorage<'a, MyTurn>,
|
WriteStorage<'a, MyTurn>,
|
||||||
ReadStorage<'a, MoveMode>,
|
WriteStorage<'a, MoveMode>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
WriteExpect<'a, Map>,
|
||||||
WriteStorage<'a, Viewshed>,
|
WriteStorage<'a, Viewshed>,
|
||||||
@ -22,7 +22,7 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (
|
let (
|
||||||
mut turns,
|
mut turns,
|
||||||
move_mode,
|
mut move_mode,
|
||||||
mut positions,
|
mut positions,
|
||||||
mut map,
|
mut map,
|
||||||
mut viewsheds,
|
mut viewsheds,
|
||||||
@ -32,10 +32,10 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
let mut turn_done: Vec<Entity> = Vec::new();
|
let mut turn_done: Vec<Entity> = Vec::new();
|
||||||
for (entity, mut pos, mode, mut viewshed, _myturn) in (
|
for (entity, mut pos, mut mode, mut viewshed, _myturn) in (
|
||||||
&entities,
|
&entities,
|
||||||
&mut positions,
|
&mut positions,
|
||||||
&move_mode,
|
&mut move_mode,
|
||||||
&mut viewsheds,
|
&mut viewsheds,
|
||||||
&turns,
|
&turns,
|
||||||
)
|
)
|
||||||
@ -43,7 +43,7 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
{
|
{
|
||||||
turn_done.push(entity);
|
turn_done.push(entity);
|
||||||
|
|
||||||
match mode.mode {
|
match &mut mode.mode {
|
||||||
Movement::Static => {}
|
Movement::Static => {}
|
||||||
Movement::Random => {
|
Movement::Random => {
|
||||||
let mut x = pos.x;
|
let mut x = pos.x;
|
||||||
@ -72,6 +72,46 @@ impl<'a> System<'a> for DefaultMoveAI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Movement::RandomWaypoint { path } => {
|
||||||
|
if let Some(path) = path {
|
||||||
|
// We have a target - go there
|
||||||
|
let mut idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
if path.len() > 1 {
|
||||||
|
if !map.blocked[path[1]] {
|
||||||
|
map.blocked[idx] = false;
|
||||||
|
pos.x = (path[1] as i32 % map.width) as i32;
|
||||||
|
pos.y = (path[1] as i32 / map.width) as i32;
|
||||||
|
entity_moved
|
||||||
|
.insert(entity, EntityMoved {})
|
||||||
|
.expect("Unable to insert movement marker");
|
||||||
|
|
||||||
|
idx = map.xy_idx(pos.x, pos.y);
|
||||||
|
map.blocked[idx] = true;
|
||||||
|
viewshed.dirty = true;
|
||||||
|
path.remove(0); // Remove the first step in the path
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise we wait a turn to see if the path clears up
|
||||||
|
mode.mode = Movement::RandomWaypoint { path: None };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let target_x = rng.roll_dice(1, map.width - 2);
|
||||||
|
let target_y = rng.roll_dice(1, map.height - 2);
|
||||||
|
let idx = map.xy_idx(target_x, target_y);
|
||||||
|
if tile_walkable(map.tiles[idx]) {
|
||||||
|
let path = ::rltk::a_star_search(
|
||||||
|
map.xy_idx(pos.x, pos.y) as i32,
|
||||||
|
map.xy_idx(target_x, target_y) as i32,
|
||||||
|
&*map,
|
||||||
|
);
|
||||||
|
if path.success && path.steps.len() > 1 {
|
||||||
|
mode.mode = Movement::RandomWaypoint {
|
||||||
|
path: Some(path.steps),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use ::rltk::RandomNumberGenerator;
|
use ::rltk::{DistanceAlg, Point, RandomNumberGenerator};
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Attributes, Initiative, MyTurn, Position};
|
use crate::components::{Attributes, Initiative, MyTurn, Position};
|
||||||
@ -17,6 +17,7 @@ impl<'a> System<'a> for InitiativeSystem {
|
|||||||
ReadStorage<'a, Attributes>,
|
ReadStorage<'a, Attributes>,
|
||||||
WriteExpect<'a, RunState>,
|
WriteExpect<'a, RunState>,
|
||||||
ReadExpect<'a, Entity>,
|
ReadExpect<'a, Entity>,
|
||||||
|
ReadExpect<'a, Point>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -29,23 +30,21 @@ impl<'a> System<'a> for InitiativeSystem {
|
|||||||
attributes,
|
attributes,
|
||||||
mut runstate,
|
mut runstate,
|
||||||
player,
|
player,
|
||||||
|
player_pos,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
if *runstate != RunState::Ticking {
|
if *runstate != RunState::Ticking {
|
||||||
return;
|
return;
|
||||||
} // We'll be adding Ticking in a moment
|
}
|
||||||
|
|
||||||
// Clear any remaining MyTurn we left by mistake
|
// Clear any remaining MyTurn we left by mistake
|
||||||
turns.clear();
|
turns.clear();
|
||||||
|
|
||||||
// Roll initiative
|
// Roll initiative
|
||||||
for (entity, initiative, _pos) in (&entities, &mut initiatives, &positions).join() {
|
for (entity, initiative, pos) in (&entities, &mut initiatives, &positions).join() {
|
||||||
initiative.current -= 1;
|
initiative.current -= 1;
|
||||||
if initiative.current < 1 {
|
if initiative.current < 1 {
|
||||||
// It's my turn
|
let mut myturn = true;
|
||||||
turns
|
|
||||||
.insert(entity, MyTurn {})
|
|
||||||
.expect("Unable to insert turn");
|
|
||||||
|
|
||||||
// Re-roll
|
// Re-roll
|
||||||
initiative.current = 6 + rng.roll_dice(1, 6);
|
initiative.current = 6 + rng.roll_dice(1, 6);
|
||||||
@ -60,6 +59,19 @@ impl<'a> System<'a> for InitiativeSystem {
|
|||||||
// if its the player, we want to go to an AwaitingInput state
|
// if its the player, we want to go to an AwaitingInput state
|
||||||
if entity == *player {
|
if entity == *player {
|
||||||
*runstate = RunState::AwaitingInput;
|
*runstate = RunState::AwaitingInput;
|
||||||
|
} else {
|
||||||
|
let distance =
|
||||||
|
DistanceAlg::Pythagoras.distance2d(*player_pos, Point::from(*pos));
|
||||||
|
if distance > 20.0 {
|
||||||
|
myturn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's my turn
|
||||||
|
if myturn {
|
||||||
|
turns
|
||||||
|
.insert(entity, MyTurn {})
|
||||||
|
.expect("Unable to insert turn");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Faction, MyTurn, Position, Viewshed, WantsToApproach, WantsToFlee};
|
use crate::components::{
|
||||||
|
Chasing, Faction, MyTurn, Position, Viewshed, WantsToApproach, WantsToFlee,
|
||||||
|
};
|
||||||
use crate::raws::Reaction;
|
use crate::raws::Reaction;
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
@ -18,6 +20,7 @@ impl<'a> System<'a> for VisibleAI {
|
|||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
ReadExpect<'a, Entity>,
|
ReadExpect<'a, Entity>,
|
||||||
ReadStorage<'a, Viewshed>,
|
ReadStorage<'a, Viewshed>,
|
||||||
|
WriteStorage<'a, Chasing>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -30,15 +33,16 @@ impl<'a> System<'a> for VisibleAI {
|
|||||||
mut want_flee,
|
mut want_flee,
|
||||||
entities,
|
entities,
|
||||||
player,
|
player,
|
||||||
viewshed,
|
viewsheds,
|
||||||
|
mut chasing,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, _turn, my_faction, pos, viewshed) in
|
for (entity, _turn, my_faction, pos, viewshed) in
|
||||||
(&entities, &turns, &factions, &positions, &viewshed).join()
|
(&entities, &turns, &factions, &positions, &viewsheds).join()
|
||||||
{
|
{
|
||||||
if entity != *player {
|
if entity != *player {
|
||||||
let my_idx = map.xy_idx(pos.x, pos.y);
|
let my_idx = map.xy_idx(pos.x, pos.y);
|
||||||
let mut reactions: Vec<(usize, Reaction)> = Vec::new();
|
let mut reactions: Vec<(usize, Reaction, Entity)> = Vec::new();
|
||||||
let mut flee: Vec<usize> = Vec::new();
|
let mut flee: Vec<usize> = Vec::new();
|
||||||
for visible_tile in viewshed.visible_tiles.iter() {
|
for visible_tile in viewshed.visible_tiles.iter() {
|
||||||
let idx = map.xy_idx(visible_tile.x, visible_tile.y);
|
let idx = map.xy_idx(visible_tile.x, visible_tile.y);
|
||||||
@ -59,6 +63,9 @@ impl<'a> System<'a> for VisibleAI {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.expect("Unable to insert intent to approach");
|
.expect("Unable to insert intent to approach");
|
||||||
|
chasing
|
||||||
|
.insert(entity, Chasing { target: reaction.2 })
|
||||||
|
.expect("Unable to insert intent to chase");
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
Reaction::Flee => {
|
Reaction::Flee => {
|
||||||
@ -83,7 +90,7 @@ fn evaluate(
|
|||||||
map: &Map,
|
map: &Map,
|
||||||
factions: &ReadStorage<Faction>,
|
factions: &ReadStorage<Faction>,
|
||||||
my_faction: &str,
|
my_faction: &str,
|
||||||
reactions: &mut Vec<(usize, Reaction)>,
|
reactions: &mut Vec<(usize, Reaction, Entity)>,
|
||||||
) {
|
) {
|
||||||
for other_entity in map.tile_content[idx].iter() {
|
for other_entity in map.tile_content[idx].iter() {
|
||||||
if let Some(faction) = factions.get(*other_entity) {
|
if let Some(faction) = factions.get(*other_entity) {
|
||||||
@ -94,6 +101,7 @@ fn evaluate(
|
|||||||
&faction.name,
|
&faction.name,
|
||||||
&crate::raws::RAWS.lock().unwrap(),
|
&crate::raws::RAWS.lock().unwrap(),
|
||||||
),
|
),
|
||||||
|
*other_entity,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,6 +324,11 @@ pub struct MoveMode {
|
|||||||
pub mode: Movement,
|
pub mode: Movement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug, ConvertSaveload, Clone)]
|
||||||
|
pub struct Chasing {
|
||||||
|
pub target: Entity,
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
||||||
@ -337,5 +342,5 @@ pub struct SerializationHelper {
|
|||||||
|
|
||||||
#[derive(Component, Serialize, Deserialize, Clone)]
|
#[derive(Component, Serialize, Deserialize, Clone)]
|
||||||
pub struct DMSerializationHelper {
|
pub struct DMSerializationHelper {
|
||||||
pub map: super::map::MasterDungeonMap,
|
pub map: crate::map::MasterDungeonMap,
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ pub enum HungerState {
|
|||||||
pub enum Movement {
|
pub enum Movement {
|
||||||
Static,
|
Static,
|
||||||
Random,
|
Random,
|
||||||
|
RandomWaypoint { path: Option<Vec<usize>> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
|
||||||
|
@ -5,9 +5,6 @@ use ::specs_derive::*;
|
|||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Player {}
|
pub struct Player {}
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct Monster {}
|
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Item {}
|
pub struct Item {}
|
||||||
|
|
||||||
@ -38,17 +35,5 @@ pub struct SingleActivation {}
|
|||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct BlocksVisibility {}
|
pub struct BlocksVisibility {}
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct Bystander {}
|
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct Vendor {}
|
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct Carnivore {}
|
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct Herbivore {}
|
|
||||||
|
|
||||||
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct MyTurn {}
|
pub struct MyTurn {}
|
||||||
|
11
src/main.rs
11
src/main.rs
@ -133,6 +133,9 @@ impl State {
|
|||||||
let mut flee = ai::FleeAI {};
|
let mut flee = ai::FleeAI {};
|
||||||
flee.run_now(&self.ecs);
|
flee.run_now(&self.ecs);
|
||||||
|
|
||||||
|
let mut chase = ai::ChaseAI {};
|
||||||
|
chase.run_now(&self.ecs);
|
||||||
|
|
||||||
let mut defaultmove = ai::DefaultMoveAI {};
|
let mut defaultmove = ai::DefaultMoveAI {};
|
||||||
defaultmove.run_now(&self.ecs);
|
defaultmove.run_now(&self.ecs);
|
||||||
|
|
||||||
@ -218,6 +221,7 @@ impl GameState for State {
|
|||||||
newrunstate = player_input(self, ctx);
|
newrunstate = player_input(self, ctx);
|
||||||
}
|
}
|
||||||
RunState::Ticking => {
|
RunState::Ticking => {
|
||||||
|
while newrunstate == RunState::Ticking {
|
||||||
self.run_systems();
|
self.run_systems();
|
||||||
self.ecs.maintain();
|
self.ecs.maintain();
|
||||||
|
|
||||||
@ -227,6 +231,7 @@ impl GameState for State {
|
|||||||
_ => RunState::Ticking,
|
_ => RunState::Ticking,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
RunState::ShowInventory => {
|
RunState::ShowInventory => {
|
||||||
let result = gui::show_inventory(self, ctx);
|
let result = gui::show_inventory(self, ctx);
|
||||||
match result.0 {
|
match result.0 {
|
||||||
@ -460,8 +465,7 @@ fn main() -> ::rltk::BError {
|
|||||||
Attributes,
|
Attributes,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
BlocksVisibility,
|
BlocksVisibility,
|
||||||
Bystander,
|
Chasing,
|
||||||
Carnivore,
|
|
||||||
Confusion,
|
Confusion,
|
||||||
Consumable,
|
Consumable,
|
||||||
Door,
|
Door,
|
||||||
@ -471,7 +475,6 @@ fn main() -> ::rltk::BError {
|
|||||||
Equippable,
|
Equippable,
|
||||||
Equipped,
|
Equipped,
|
||||||
Faction,
|
Faction,
|
||||||
Herbivore,
|
|
||||||
Hidden,
|
Hidden,
|
||||||
HungerClock,
|
HungerClock,
|
||||||
InBackpack,
|
InBackpack,
|
||||||
@ -482,7 +485,6 @@ fn main() -> ::rltk::BError {
|
|||||||
LootTable,
|
LootTable,
|
||||||
MagicMapper,
|
MagicMapper,
|
||||||
MeleeWeapon,
|
MeleeWeapon,
|
||||||
Monster,
|
|
||||||
MoveMode,
|
MoveMode,
|
||||||
MyTurn,
|
MyTurn,
|
||||||
Name,
|
Name,
|
||||||
@ -502,7 +504,6 @@ fn main() -> ::rltk::BError {
|
|||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
SufferDamage,
|
SufferDamage,
|
||||||
Vendor,
|
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
WantsToDropItem,
|
WantsToDropItem,
|
||||||
|
@ -4,18 +4,19 @@ use ::rltk::{Point, Rltk, VirtualKeyCode};
|
|||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
BlocksTile, BlocksVisibility, Door, EntityMoved, HungerClock, HungerState, Item, Monster,
|
Attributes, BlocksTile, BlocksVisibility, Door, EntityMoved, Faction, HungerClock, HungerState,
|
||||||
Player, Pools, Position, Renderable, Vendor, Viewshed, WantsToMelee, WantsToPickupItem,
|
Item, Player, Pools, Position, Renderable, Viewshed, WantsToMelee, WantsToPickupItem,
|
||||||
};
|
};
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
use crate::{Bystander, Map, RunState, State, TileType};
|
use crate::raws::Reaction;
|
||||||
|
use crate::{Map, RunState, State, TileType};
|
||||||
|
|
||||||
pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState {
|
pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState {
|
||||||
let mut positions = ecs.write_storage::<Position>();
|
let mut positions = ecs.write_storage::<Position>();
|
||||||
let players = ecs.read_storage::<Player>();
|
let players = ecs.read_storage::<Player>();
|
||||||
let mut viewsheds = ecs.write_storage::<Viewshed>();
|
let mut viewsheds = ecs.write_storage::<Viewshed>();
|
||||||
let entities = ecs.entities();
|
let entities = ecs.entities();
|
||||||
let combat_stats = ecs.read_storage::<Pools>();
|
let combat_stats = ecs.read_storage::<Attributes>();
|
||||||
let map = ecs.fetch::<Map>();
|
let map = ecs.fetch::<Map>();
|
||||||
let mut wants_to_melee = ecs.write_storage::<WantsToMelee>();
|
let mut wants_to_melee = ecs.write_storage::<WantsToMelee>();
|
||||||
let mut entity_moved = ecs.write_storage::<EntityMoved>();
|
let mut entity_moved = ecs.write_storage::<EntityMoved>();
|
||||||
@ -23,8 +24,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
let mut blocks_visibility = ecs.write_storage::<BlocksVisibility>();
|
let mut blocks_visibility = ecs.write_storage::<BlocksVisibility>();
|
||||||
let mut blocks_movement = ecs.write_storage::<BlocksTile>();
|
let mut blocks_movement = ecs.write_storage::<BlocksTile>();
|
||||||
let mut renderables = ecs.write_storage::<Renderable>();
|
let mut renderables = ecs.write_storage::<Renderable>();
|
||||||
let bystanders = ecs.read_storage::<Bystander>();
|
let factions = ecs.read_storage::<Faction>();
|
||||||
let vendors = ecs.read_storage::<Vendor>();
|
|
||||||
let mut result = RunState::AwaitingInput;
|
let mut result = RunState::AwaitingInput;
|
||||||
|
|
||||||
let mut swap_entities: Vec<(Entity, i32, i32)> = Vec::new();
|
let mut swap_entities: Vec<(Entity, i32, i32)> = Vec::new();
|
||||||
@ -42,9 +42,20 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
||||||
for potential_target in map.tile_content[destination_idx].iter() {
|
for potential_target in map.tile_content[destination_idx].iter() {
|
||||||
let bystander = bystanders.get(*potential_target);
|
let mut hostile = true;
|
||||||
let vendor = vendors.get(*potential_target);
|
if combat_stats.get(*potential_target).is_some() {
|
||||||
if bystander.is_some() || vendor.is_some() {
|
if let Some(faction) = factions.get(*potential_target) {
|
||||||
|
let reaction = crate::raws::faction_reaction(
|
||||||
|
&faction.name,
|
||||||
|
"Player",
|
||||||
|
&crate::raws::RAWS.lock().unwrap(),
|
||||||
|
);
|
||||||
|
if reaction != Reaction::Attack {
|
||||||
|
hostile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hostile {
|
||||||
// Note that we want to move the bystander
|
// Note that we want to move the bystander
|
||||||
swap_entities.push((*potential_target, pos.x, pos.y));
|
swap_entities.push((*potential_target, pos.x, pos.y));
|
||||||
|
|
||||||
@ -53,14 +64,15 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
pos.y = min(map.height - 1, max(0, pos.y + delta_y));
|
pos.y = min(map.height - 1, max(0, pos.y + delta_y));
|
||||||
entity_moved
|
entity_moved
|
||||||
.insert(entity, EntityMoved {})
|
.insert(entity, EntityMoved {})
|
||||||
.expect("Unable to insert moved entity marker");
|
.expect("Unable to insert marker");
|
||||||
|
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
let mut ppos = ecs.write_resource::<Point>();
|
let mut ppos = ecs.write_resource::<Point>();
|
||||||
ppos.x = pos.x;
|
ppos.x = pos.x;
|
||||||
ppos.y = pos.y;
|
ppos.y = pos.y;
|
||||||
result = RunState::Ticking;
|
} else {
|
||||||
} else if combat_stats.get(*potential_target).is_some() {
|
let target = combat_stats.get(*potential_target);
|
||||||
|
if let Some(_target) = target {
|
||||||
wants_to_melee
|
wants_to_melee
|
||||||
.insert(
|
.insert(
|
||||||
entity,
|
entity,
|
||||||
@ -72,15 +84,16 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
|
|
||||||
return RunState::Ticking;
|
return RunState::Ticking;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let Some(door) = doors.get_mut(*potential_target) {
|
let door = doors.get_mut(*potential_target);
|
||||||
|
if let Some(door) = door {
|
||||||
door.open = true;
|
door.open = true;
|
||||||
blocks_visibility.remove(*potential_target);
|
blocks_visibility.remove(*potential_target);
|
||||||
blocks_movement.remove(*potential_target);
|
blocks_movement.remove(*potential_target);
|
||||||
|
|
||||||
let glyph = renderables.get_mut(*potential_target).unwrap();
|
let glyph = renderables.get_mut(*potential_target).unwrap();
|
||||||
glyph.glyph = rltk::to_cp437('/');
|
glyph.glyph = rltk::to_cp437('/');
|
||||||
viewshed.dirty = true;
|
viewshed.dirty = true;
|
||||||
|
result = RunState::Ticking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,18 +108,18 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
|
|||||||
let mut ppos = ecs.write_resource::<Point>();
|
let mut ppos = ecs.write_resource::<Point>();
|
||||||
ppos.x = pos.x;
|
ppos.x = pos.x;
|
||||||
ppos.y = pos.y;
|
ppos.y = pos.y;
|
||||||
|
result = RunState::Ticking;
|
||||||
// Change levels by running onto a set of stairs
|
match map.tiles[destination_idx] {
|
||||||
result = match map.tiles[destination_idx] {
|
TileType::DownStairs => result = RunState::NextLevel,
|
||||||
TileType::DownStairs => RunState::NextLevel,
|
TileType::UpStairs => result = RunState::PreviousLevel,
|
||||||
TileType::UpStairs => RunState::PreviousLevel,
|
_ => {}
|
||||||
_ => RunState::Ticking,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for m in swap_entities.iter() {
|
for m in swap_entities.iter() {
|
||||||
if let Some(their_pos) = positions.get_mut(m.0) {
|
let their_pos = positions.get_mut(m.0);
|
||||||
|
if let Some(their_pos) = their_pos {
|
||||||
their_pos.x = m.1;
|
their_pos.x = m.1;
|
||||||
their_pos.y = m.2;
|
their_pos.y = m.2;
|
||||||
}
|
}
|
||||||
@ -184,7 +197,7 @@ fn get_item(ecs: &mut World) {
|
|||||||
fn skip_turn(ecs: &mut World) -> RunState {
|
fn skip_turn(ecs: &mut World) -> RunState {
|
||||||
let player_entity = ecs.fetch::<Entity>();
|
let player_entity = ecs.fetch::<Entity>();
|
||||||
let viewshed_components = ecs.read_storage::<Viewshed>();
|
let viewshed_components = ecs.read_storage::<Viewshed>();
|
||||||
let monsters = ecs.read_storage::<Monster>();
|
let factions = ecs.read_storage::<Faction>();
|
||||||
|
|
||||||
let worldmap_resource = ecs.fetch::<Map>();
|
let worldmap_resource = ecs.fetch::<Map>();
|
||||||
|
|
||||||
@ -193,14 +206,21 @@ fn skip_turn(ecs: &mut World) -> RunState {
|
|||||||
for tile in viewshed.visible_tiles.iter() {
|
for tile in viewshed.visible_tiles.iter() {
|
||||||
let idx = worldmap_resource.xy_idx(tile.x, tile.y);
|
let idx = worldmap_resource.xy_idx(tile.x, tile.y);
|
||||||
for entity_id in worldmap_resource.tile_content[idx].iter() {
|
for entity_id in worldmap_resource.tile_content[idx].iter() {
|
||||||
match monsters.get(*entity_id) {
|
match factions.get(*entity_id) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(_) => {
|
Some(faction) => {
|
||||||
|
let reaction = crate::raws::faction_reaction(
|
||||||
|
&faction.name,
|
||||||
|
"Player",
|
||||||
|
&crate::raws::RAWS.lock().unwrap(),
|
||||||
|
);
|
||||||
|
if reaction == Reaction::Attack {
|
||||||
can_heal = false;
|
can_heal = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Don't allow healing when hungry or starving
|
// Don't allow healing when hungry or starving
|
||||||
let hunger_clocks = ecs.read_storage::<HungerClock>();
|
let hunger_clocks = ecs.read_storage::<HungerClock>();
|
||||||
|
@ -342,6 +342,9 @@ pub fn spawn_named_mob(
|
|||||||
"random" => eb.with(MoveMode {
|
"random" => eb.with(MoveMode {
|
||||||
mode: Movement::Random,
|
mode: Movement::Random,
|
||||||
}),
|
}),
|
||||||
|
"random_waypoint" => eb.with(MoveMode {
|
||||||
|
mode: Movement::RandomWaypoint { path: None },
|
||||||
|
}),
|
||||||
_ => eb.with(MoveMode {
|
_ => eb.with(MoveMode {
|
||||||
mode: Movement::Static,
|
mode: Movement::Static,
|
||||||
}),
|
}),
|
||||||
|
@ -64,8 +64,7 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
Attributes,
|
Attributes,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
BlocksVisibility,
|
BlocksVisibility,
|
||||||
Bystander,
|
Chasing,
|
||||||
Carnivore,
|
|
||||||
Confusion,
|
Confusion,
|
||||||
Consumable,
|
Consumable,
|
||||||
Door,
|
Door,
|
||||||
@ -75,7 +74,6 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
Equippable,
|
Equippable,
|
||||||
Equipped,
|
Equipped,
|
||||||
Faction,
|
Faction,
|
||||||
Herbivore,
|
|
||||||
Hidden,
|
Hidden,
|
||||||
HungerClock,
|
HungerClock,
|
||||||
InBackpack,
|
InBackpack,
|
||||||
@ -86,7 +84,6 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
LootTable,
|
LootTable,
|
||||||
MagicMapper,
|
MagicMapper,
|
||||||
MeleeWeapon,
|
MeleeWeapon,
|
||||||
Monster,
|
|
||||||
MoveMode,
|
MoveMode,
|
||||||
MyTurn,
|
MyTurn,
|
||||||
Name,
|
Name,
|
||||||
@ -105,7 +102,6 @@ pub fn save_game(ecs: &mut World) {
|
|||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
SufferDamage,
|
SufferDamage,
|
||||||
Vendor,
|
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
WantsToDropItem,
|
WantsToDropItem,
|
||||||
@ -175,8 +171,7 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
Attributes,
|
Attributes,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
BlocksVisibility,
|
BlocksVisibility,
|
||||||
Bystander,
|
Chasing,
|
||||||
Carnivore,
|
|
||||||
Confusion,
|
Confusion,
|
||||||
Consumable,
|
Consumable,
|
||||||
Door,
|
Door,
|
||||||
@ -186,7 +181,6 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
Equippable,
|
Equippable,
|
||||||
Equipped,
|
Equipped,
|
||||||
Faction,
|
Faction,
|
||||||
Herbivore,
|
|
||||||
Hidden,
|
Hidden,
|
||||||
HungerClock,
|
HungerClock,
|
||||||
InBackpack,
|
InBackpack,
|
||||||
@ -197,7 +191,6 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
LootTable,
|
LootTable,
|
||||||
MagicMapper,
|
MagicMapper,
|
||||||
MeleeWeapon,
|
MeleeWeapon,
|
||||||
Monster,
|
|
||||||
MoveMode,
|
MoveMode,
|
||||||
MyTurn,
|
MyTurn,
|
||||||
Name,
|
Name,
|
||||||
@ -216,7 +209,6 @@ pub fn load_game(ecs: &mut World) {
|
|||||||
SingleActivation,
|
SingleActivation,
|
||||||
Skills,
|
Skills,
|
||||||
SufferDamage,
|
SufferDamage,
|
||||||
Vendor,
|
|
||||||
Viewshed,
|
Viewshed,
|
||||||
WantsToApproach,
|
WantsToApproach,
|
||||||
WantsToDropItem,
|
WantsToDropItem,
|
||||||
|
Loading…
Reference in New Issue
Block a user