various fixes: moved turnloss handling into energy system, anims
This commit is contained in:
parent
7b5cd0ec70
commit
1b12d70b23
11 changed files with 235 additions and 53 deletions
|
|
@ -1,5 +1,16 @@
|
||||||
use crate::data::entity::*;
|
use crate::data::entity::*;
|
||||||
use crate::{ Burden, BurdenLevel, Clock, Energy, Name, Position, RunState, Map, TakingTurn };
|
use crate::{
|
||||||
|
Burden,
|
||||||
|
BurdenLevel,
|
||||||
|
Clock,
|
||||||
|
Energy,
|
||||||
|
Name,
|
||||||
|
Position,
|
||||||
|
RunState,
|
||||||
|
Map,
|
||||||
|
TakingTurn,
|
||||||
|
Confusion,
|
||||||
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use crate::config::CONFIG;
|
use crate::config::CONFIG;
|
||||||
|
|
@ -24,6 +35,7 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
ReadExpect<'a, Entity>,
|
ReadExpect<'a, Entity>,
|
||||||
ReadStorage<'a, Name>,
|
ReadStorage<'a, Name>,
|
||||||
ReadExpect<'a, Point>,
|
ReadExpect<'a, Point>,
|
||||||
|
ReadStorage<'a, Confusion>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
|
@ -40,6 +52,7 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
player,
|
player,
|
||||||
names,
|
names,
|
||||||
player_pos,
|
player_pos,
|
||||||
|
confusion,
|
||||||
) = data;
|
) = data;
|
||||||
// If not ticking, do nothing.
|
// If not ticking, do nothing.
|
||||||
if *runstate != RunState::Ticking {
|
if *runstate != RunState::Ticking {
|
||||||
|
|
@ -51,17 +64,29 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
for (entity, _clock, energy) in (&entities, &clock, &mut energies).join() {
|
for (entity, _clock, energy) in (&entities, &clock, &mut energies).join() {
|
||||||
energy.current += NORMAL_SPEED;
|
energy.current += NORMAL_SPEED;
|
||||||
if energy.current >= TURN_COST {
|
if energy.current >= TURN_COST {
|
||||||
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn for turn counter.");
|
turns
|
||||||
|
.insert(entity, TakingTurn {})
|
||||||
|
.expect("Unable to insert turn for turn counter.");
|
||||||
energy.current -= TURN_COST;
|
energy.current -= TURN_COST;
|
||||||
crate::gamelog::record_event(EVENT::TURN(1));
|
crate::gamelog::record_event(EVENT::TURN(1));
|
||||||
// Handle spawning mobs each turn
|
// Handle spawning mobs each turn
|
||||||
if CONFIG.logging.log_ticks {
|
if CONFIG.logging.log_ticks {
|
||||||
console::log(format!("===== TURN {} =====", crate::gamelog::get_event_count(EVENT::COUNT_TURN)));
|
console::log(
|
||||||
|
format!(
|
||||||
|
"===== TURN {} =====",
|
||||||
|
crate::gamelog::get_event_count(EVENT::COUNT_TURN)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// EVERYTHING ELSE
|
// EVERYTHING ELSE
|
||||||
for (entity, energy, pos) in (&entities, &mut energies, &positions).join() {
|
for (entity, energy, pos, _c) in (
|
||||||
|
&entities,
|
||||||
|
&mut energies,
|
||||||
|
&positions,
|
||||||
|
!&confusion,
|
||||||
|
).join() {
|
||||||
let burden_modifier = if let Some(burden) = burdens.get(entity) {
|
let burden_modifier = if let Some(burden) = burdens.get(entity) {
|
||||||
match burden.level {
|
match burden.level {
|
||||||
BurdenLevel::Burdened => SPEED_MOD_BURDENED,
|
BurdenLevel::Burdened => SPEED_MOD_BURDENED,
|
||||||
|
|
@ -73,7 +98,9 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
};
|
};
|
||||||
let overmap_mod = if map.overmap { SPEED_MOD_OVERMAP_TRAVEL } else { 1.0 };
|
let overmap_mod = if map.overmap { SPEED_MOD_OVERMAP_TRAVEL } else { 1.0 };
|
||||||
// Every entity has a POTENTIAL equal to their speed.
|
// Every entity has a POTENTIAL equal to their speed.
|
||||||
let mut energy_potential: i32 = ((energy.speed as f32) * burden_modifier * overmap_mod) as i32;
|
let mut energy_potential: i32 = ((energy.speed as f32) *
|
||||||
|
burden_modifier *
|
||||||
|
overmap_mod) as i32;
|
||||||
// Increment current energy by NORMAL_SPEED for every
|
// Increment current energy by NORMAL_SPEED for every
|
||||||
// whole number of NORMAL_SPEEDS in their POTENTIAL.
|
// whole number of NORMAL_SPEEDS in their POTENTIAL.
|
||||||
while energy_potential >= NORMAL_SPEED {
|
while energy_potential >= NORMAL_SPEED {
|
||||||
|
|
@ -99,7 +126,10 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
if entity == *player {
|
if entity == *player {
|
||||||
*runstate = RunState::AwaitingInput;
|
*runstate = RunState::AwaitingInput;
|
||||||
} else {
|
} else {
|
||||||
let distance = rltk::DistanceAlg::Pythagoras.distance2d(*player_pos, Point::new(pos.x, pos.y));
|
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
|
||||||
|
*player_pos,
|
||||||
|
Point::new(pos.x, pos.y)
|
||||||
|
);
|
||||||
if distance > 20.0 {
|
if distance > 20.0 {
|
||||||
my_turn = false;
|
my_turn = false;
|
||||||
}
|
}
|
||||||
|
|
@ -107,9 +137,17 @@ impl<'a> System<'a> for EnergySystem {
|
||||||
if my_turn {
|
if my_turn {
|
||||||
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn.");
|
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn.");
|
||||||
if CONFIG.logging.log_ticks {
|
if CONFIG.logging.log_ticks {
|
||||||
let name = if let Some(name) = names.get(entity) { &name.name } else { "Unknown entity" };
|
let name = if let Some(name) = names.get(entity) {
|
||||||
|
&name.name
|
||||||
|
} else {
|
||||||
|
"Unknown entity"
|
||||||
|
};
|
||||||
console::log(
|
console::log(
|
||||||
format!("ENERGY SYSTEM: {} granted a turn. [leftover energy: {}].", name, energy.current)
|
format!(
|
||||||
|
"ENERGY SYSTEM: {} granted a turn. [leftover energy: {}].",
|
||||||
|
name,
|
||||||
|
energy.current
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ use crate::{
|
||||||
Name,
|
Name,
|
||||||
Renderable,
|
Renderable,
|
||||||
TakingTurn,
|
TakingTurn,
|
||||||
|
Item,
|
||||||
|
Prop,
|
||||||
};
|
};
|
||||||
use rltk::prelude::*;
|
use rltk::prelude::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
|
|
@ -24,10 +26,22 @@ impl<'a> System<'a> for TurnStatusSystem {
|
||||||
ReadStorage<'a, Name>,
|
ReadStorage<'a, Name>,
|
||||||
ReadExpect<'a, Entity>,
|
ReadExpect<'a, Entity>,
|
||||||
ReadStorage<'a, Renderable>,
|
ReadStorage<'a, Renderable>,
|
||||||
|
ReadStorage<'a, Item>,
|
||||||
|
ReadStorage<'a, Prop>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (mut turns, clock, mut confusion, entities, names, player_entity, renderables) = data;
|
let (
|
||||||
|
mut turns,
|
||||||
|
clock,
|
||||||
|
mut confusion,
|
||||||
|
entities,
|
||||||
|
names,
|
||||||
|
player_entity,
|
||||||
|
renderables,
|
||||||
|
items,
|
||||||
|
props,
|
||||||
|
) = data;
|
||||||
let mut clock_tick = false;
|
let mut clock_tick = false;
|
||||||
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
|
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
|
||||||
clock_tick = true;
|
clock_tick = true;
|
||||||
|
|
@ -39,7 +53,13 @@ impl<'a> System<'a> for TurnStatusSystem {
|
||||||
let mut log = false;
|
let mut log = false;
|
||||||
let mut not_my_turn: Vec<Entity> = Vec::new();
|
let mut not_my_turn: Vec<Entity> = Vec::new();
|
||||||
let mut not_confused: Vec<Entity> = Vec::new();
|
let mut not_confused: Vec<Entity> = Vec::new();
|
||||||
for (entity, _turn, confused, name) in (&entities, &mut turns, &mut confusion, &names).join() {
|
for (entity, confused, name, _i, _p) in (
|
||||||
|
&entities,
|
||||||
|
&mut confusion,
|
||||||
|
&names,
|
||||||
|
!&items,
|
||||||
|
!&props,
|
||||||
|
).join() {
|
||||||
confused.turns -= 1;
|
confused.turns -= 1;
|
||||||
if confused.turns < 1 {
|
if confused.turns < 1 {
|
||||||
not_confused.push(entity);
|
not_confused.push(entity);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,11 @@ pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) {
|
||||||
target_pool.hit_points.current -= amount;
|
target_pool.hit_points.current -= amount;
|
||||||
let bleeders = ecs.read_storage::<Bleeds>();
|
let bleeders = ecs.read_storage::<Bleeds>();
|
||||||
if let Some(bleeds) = bleeders.get(target) {
|
if let Some(bleeds) = bleeders.get(target) {
|
||||||
add_effect(None, EffectType::Bloodstain { colour: bleeds.colour }, Targets::Entity { target });
|
add_effect(
|
||||||
|
None,
|
||||||
|
EffectType::Bloodstain { colour: bleeds.colour },
|
||||||
|
Targets::Entity { target }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
add_effect(
|
add_effect(
|
||||||
None,
|
None,
|
||||||
|
|
@ -60,7 +64,10 @@ pub fn heal_damage(ecs: &mut World, heal: &EffectSpawner, target: Entity) {
|
||||||
if let Some(pool) = pools.get_mut(target) {
|
if let Some(pool) = pools.get_mut(target) {
|
||||||
if let EffectType::Healing { amount, increment_max } = &heal.effect_type {
|
if let EffectType::Healing { amount, increment_max } = &heal.effect_type {
|
||||||
let before = pool.hit_points.current;
|
let before = pool.hit_points.current;
|
||||||
pool.hit_points.current = i32::min(pool.hit_points.max, pool.hit_points.current + amount);
|
pool.hit_points.current = i32::min(
|
||||||
|
pool.hit_points.max,
|
||||||
|
pool.hit_points.current + amount
|
||||||
|
);
|
||||||
if pool.hit_points.current - before < *amount && *increment_max {
|
if pool.hit_points.current - before < *amount && *increment_max {
|
||||||
// If the heal was not fully effective, and healing source was noncursed, increase max HP by 1.
|
// If the heal was not fully effective, and healing source was noncursed, increase max HP by 1.
|
||||||
pool.hit_points.max += 1;
|
pool.hit_points.max += 1;
|
||||||
|
|
@ -83,6 +90,12 @@ pub fn heal_damage(ecs: &mut World, heal: &EffectSpawner, target: Entity) {
|
||||||
|
|
||||||
pub fn add_confusion(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
pub fn add_confusion(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
if let EffectType::Confusion { turns } = &effect.effect_type {
|
if let EffectType::Confusion { turns } = &effect.effect_type {
|
||||||
|
let name = if let Some(name) = ecs.read_storage::<Name>().get(target) {
|
||||||
|
name.name.clone()
|
||||||
|
} else {
|
||||||
|
"Something".to_string()
|
||||||
|
};
|
||||||
|
console::log(format!("adding confusion to: {}", name));
|
||||||
ecs.write_storage::<Confusion>()
|
ecs.write_storage::<Confusion>()
|
||||||
.insert(target, Confusion { turns: *turns })
|
.insert(target, Confusion { turns: *turns })
|
||||||
.expect("Unable to insert Confusion");
|
.expect("Unable to insert Confusion");
|
||||||
|
|
@ -168,7 +181,9 @@ fn get_death_message(ecs: &World, source: Entity) -> String {
|
||||||
if source == *player {
|
if source == *player {
|
||||||
result.push_str(format!("{}", PLAYER_DIED_SUICIDE).as_str());
|
result.push_str(format!("{}", PLAYER_DIED_SUICIDE).as_str());
|
||||||
} else if let Some(name) = ecs.read_storage::<Name>().get(source) {
|
} else if let Some(name) = ecs.read_storage::<Name>().get(source) {
|
||||||
result.push_str(format!("{} {}", PLAYER_DIED_NAMED_ATTACKER, with_article(name.name.clone())).as_str());
|
result.push_str(
|
||||||
|
format!("{} {}", PLAYER_DIED_NAMED_ATTACKER, with_article(name.name.clone())).as_str()
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
result.push_str(format!("{}", PLAYER_DIED_UNKNOWN).as_str());
|
result.push_str(format!("{}", PLAYER_DIED_UNKNOWN).as_str());
|
||||||
}
|
}
|
||||||
|
|
@ -238,7 +253,12 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
// If it was the PLAYER that levelled up:
|
// If it was the PLAYER that levelled up:
|
||||||
if ecs.read_storage::<Player>().get(source).is_some() {
|
if ecs.read_storage::<Player>().get(source).is_some() {
|
||||||
gamelog::record_event(EVENT::LEVEL(1));
|
gamelog::record_event(EVENT::LEVEL(1));
|
||||||
gamelog::Logger::new().append(LEVELUP_PLAYER).append_n(source_pools.level).append("!").log();
|
gamelog::Logger
|
||||||
|
::new()
|
||||||
|
.append(LEVELUP_PLAYER)
|
||||||
|
.append_n(source_pools.level)
|
||||||
|
.append("!")
|
||||||
|
.log();
|
||||||
let player_pos = ecs.fetch::<Point>();
|
let player_pos = ecs.fetch::<Point>();
|
||||||
let map = ecs.fetch_mut::<Map>();
|
let map = ecs.fetch_mut::<Map>();
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
|
|
@ -264,7 +284,12 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
lifespan: LONG_PARTICLE_LIFETIME,
|
lifespan: LONG_PARTICLE_LIFETIME,
|
||||||
delay: (i as f32) * 100.0,
|
delay: (i as f32) * 100.0,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(player_pos.x + (i - 2), player_pos.y - i) }
|
Targets::Tile {
|
||||||
|
target: map.xy_idx(
|
||||||
|
player_pos.x + (i - 2),
|
||||||
|
player_pos.y - i
|
||||||
|
),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
add_effect(
|
add_effect(
|
||||||
None,
|
None,
|
||||||
|
|
@ -275,7 +300,12 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
lifespan: LONG_PARTICLE_LIFETIME,
|
lifespan: LONG_PARTICLE_LIFETIME,
|
||||||
delay: (i as f32) * 100.0,
|
delay: (i as f32) * 100.0,
|
||||||
},
|
},
|
||||||
Targets::Tile { target: map.xy_idx(player_pos.x - (i - 2), player_pos.y - i) }
|
Targets::Tile {
|
||||||
|
target: map.xy_idx(
|
||||||
|
player_pos.x - (i - 2),
|
||||||
|
player_pos.y - i
|
||||||
|
),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -307,7 +337,9 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
|
||||||
gamelog::record_event(EVENT::PLAYER_DIED("You starved to death!".to_string()));
|
gamelog::record_event(EVENT::PLAYER_DIED("You starved to death!".to_string()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gamelog::record_event(EVENT::PLAYER_DIED("You died from unknown causes!".to_string()));
|
gamelog::record_event(
|
||||||
|
EVENT::PLAYER_DIED("You died from unknown causes!".to_string())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,9 +121,11 @@ fn target_applicator(ecs: &mut World, effect: &EffectSpawner) {
|
||||||
// Otherwise, just match the effect and enact it directly.
|
// Otherwise, just match the effect and enact it directly.
|
||||||
match &effect.target {
|
match &effect.target {
|
||||||
Targets::Tile { target } => affect_tile(ecs, effect, *target),
|
Targets::Tile { target } => affect_tile(ecs, effect, *target),
|
||||||
Targets::TileList { targets } => targets.iter().for_each(|target| affect_tile(ecs, effect, *target)),
|
Targets::TileList { targets } =>
|
||||||
|
targets.iter().for_each(|target| affect_tile(ecs, effect, *target)),
|
||||||
Targets::Entity { target } => affect_entity(ecs, effect, *target),
|
Targets::Entity { target } => affect_entity(ecs, effect, *target),
|
||||||
Targets::EntityList { targets } => targets.iter().for_each(|target| affect_entity(ecs, effect, *target)),
|
Targets::EntityList { targets } =>
|
||||||
|
targets.iter().for_each(|target| affect_entity(ecs, effect, *target)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
use super::{ gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State };
|
use super::{
|
||||||
|
gamesystem::attr_bonus,
|
||||||
|
gamesystem::get_attribute_rolls,
|
||||||
|
Attributes,
|
||||||
|
Pools,
|
||||||
|
Renderable,
|
||||||
|
RunState,
|
||||||
|
State,
|
||||||
|
};
|
||||||
use crate::data::entity;
|
use crate::data::entity;
|
||||||
use crate::data::char_create::*;
|
use crate::data::char_create::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -248,7 +256,9 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
||||||
let player_skills = if let Some(skills) = skills.get_mut(*player) {
|
let player_skills = if let Some(skills) = skills.get_mut(*player) {
|
||||||
skills
|
skills
|
||||||
} else {
|
} else {
|
||||||
skills.insert(*player, Skills { skills: HashMap::new() }).expect("Unable to insert skills component");
|
skills
|
||||||
|
.insert(*player, Skills { skills: HashMap::new() })
|
||||||
|
.expect("Unable to insert skills component");
|
||||||
skills.get_mut(*player).unwrap()
|
skills.get_mut(*player).unwrap()
|
||||||
};
|
};
|
||||||
let mut ancestries = ecs.write_storage::<HasAncestry>();
|
let mut ancestries = ecs.write_storage::<HasAncestry>();
|
||||||
|
|
@ -277,11 +287,18 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
||||||
.expect("Unable to insert renderable component");
|
.expect("Unable to insert renderable component");
|
||||||
let mut telepaths = ecs.write_storage::<Telepath>();
|
let mut telepaths = ecs.write_storage::<Telepath>();
|
||||||
telepaths
|
telepaths
|
||||||
.insert(*player, Telepath { telepath_tiles: Vec::new(), range: ELF_TELEPATH_RANGE, dirty: true })
|
.insert(*player, Telepath {
|
||||||
|
telepath_tiles: Vec::new(),
|
||||||
|
range: ELF_TELEPATH_RANGE,
|
||||||
|
dirty: true,
|
||||||
|
})
|
||||||
.expect("Unable to insert telepath component");
|
.expect("Unable to insert telepath component");
|
||||||
let mut speeds = ecs.write_storage::<Energy>();
|
let mut speeds = ecs.write_storage::<Energy>();
|
||||||
speeds
|
speeds
|
||||||
.insert(*player, Energy { current: 0, speed: entity::NORMAL_SPEED + ELF_SPEED_BONUS })
|
.insert(*player, Energy {
|
||||||
|
current: 0,
|
||||||
|
speed: entity::NORMAL_SPEED + ELF_SPEED_BONUS,
|
||||||
|
})
|
||||||
.expect("Unable to insert energy component");
|
.expect("Unable to insert energy component");
|
||||||
}
|
}
|
||||||
Ancestry::Catfolk => {
|
Ancestry::Catfolk => {
|
||||||
|
|
@ -295,7 +312,10 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
|
||||||
.expect("Unable to insert renderable component");
|
.expect("Unable to insert renderable component");
|
||||||
let mut speeds = ecs.write_storage::<Energy>();
|
let mut speeds = ecs.write_storage::<Energy>();
|
||||||
speeds
|
speeds
|
||||||
.insert(*player, Energy { current: 0, speed: entity::NORMAL_SPEED + CATFOLK_SPEED_BONUS })
|
.insert(*player, Energy {
|
||||||
|
current: 0,
|
||||||
|
speed: entity::NORMAL_SPEED + CATFOLK_SPEED_BONUS,
|
||||||
|
})
|
||||||
.expect("Unable to insert energy component");
|
.expect("Unable to insert energy component");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -334,8 +354,14 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
|
||||||
let mut pools = ecs.write_storage::<Pools>();
|
let mut pools = ecs.write_storage::<Pools>();
|
||||||
pools
|
pools
|
||||||
.insert(player, Pools {
|
.insert(player, Pools {
|
||||||
hit_points: Pool { current: 8 + attr_bonus(con), max: entity::STANDARD_HIT_DIE + attr_bonus(con) },
|
hit_points: Pool {
|
||||||
mana: Pool { current: 1 + attr_bonus(int), max: entity::MINIMUM_MANA_PLAYER + attr_bonus(int) },
|
current: 8 + attr_bonus(con),
|
||||||
|
max: entity::STANDARD_HIT_DIE + attr_bonus(con),
|
||||||
|
},
|
||||||
|
mana: Pool {
|
||||||
|
current: 1 + attr_bonus(int),
|
||||||
|
max: entity::MINIMUM_MANA_PLAYER + attr_bonus(int),
|
||||||
|
},
|
||||||
xp: 0,
|
xp: 0,
|
||||||
level: 1,
|
level: 1,
|
||||||
bac: entity::STANDARD_BAC,
|
bac: entity::STANDARD_BAC,
|
||||||
|
|
@ -371,7 +397,10 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_starting_inventory(class: Class, rng: &mut RandomNumberGenerator) -> (Vec<String>, Vec<String>) {
|
fn get_starting_inventory(
|
||||||
|
class: Class,
|
||||||
|
rng: &mut RandomNumberGenerator
|
||||||
|
) -> (Vec<String>, Vec<String>) {
|
||||||
let mut equipped: Vec<String> = Vec::new();
|
let mut equipped: Vec<String> = Vec::new();
|
||||||
let mut carried: Vec<String> = Vec::new();
|
let mut carried: Vec<String> = Vec::new();
|
||||||
let starting_food: &str;
|
let starting_food: &str;
|
||||||
|
|
@ -387,13 +416,32 @@ fn get_starting_inventory(class: Class, rng: &mut RandomNumberGenerator) -> (Vec
|
||||||
Class::Rogue => {
|
Class::Rogue => {
|
||||||
starting_food = ROGUE_STARTING_FOOD;
|
starting_food = ROGUE_STARTING_FOOD;
|
||||||
equipped = vec![ROGUE_STARTING_WEAPON.to_string(), ROGUE_STARTING_ARMOUR.to_string()];
|
equipped = vec![ROGUE_STARTING_WEAPON.to_string(), ROGUE_STARTING_ARMOUR.to_string()];
|
||||||
carried = vec!["equip_dagger".to_string(), "equip_dagger".to_string()];
|
carried = vec![
|
||||||
|
"equip_dagger".to_string(),
|
||||||
|
"equip_dagger".to_string(),
|
||||||
|
"scroll_confusion".to_string(),
|
||||||
|
"scroll_confusion".to_string(),
|
||||||
|
"scroll_confusion".to_string(),
|
||||||
|
"scroll_confusion".to_string()
|
||||||
|
];
|
||||||
}
|
}
|
||||||
Class::Wizard => {
|
Class::Wizard => {
|
||||||
starting_food = WIZARD_STARTING_FOOD;
|
starting_food = WIZARD_STARTING_FOOD;
|
||||||
equipped = vec![WIZARD_STARTING_WEAPON.to_string(), WIZARD_STARTING_ARMOUR.to_string()];
|
equipped = vec![WIZARD_STARTING_WEAPON.to_string(), WIZARD_STARTING_ARMOUR.to_string()];
|
||||||
pick_random_table_item(rng, &mut carried, "scrolls", WIZARD_SCROLL_AMOUNT, Some(WIZARD_MAX_SCROLL_LVL));
|
pick_random_table_item(
|
||||||
pick_random_table_item(rng, &mut carried, "potions", WIZARD_POTION_AMOUNT, Some(WIZARD_MAX_SCROLL_LVL));
|
rng,
|
||||||
|
&mut carried,
|
||||||
|
"scrolls",
|
||||||
|
WIZARD_SCROLL_AMOUNT,
|
||||||
|
Some(WIZARD_MAX_SCROLL_LVL)
|
||||||
|
);
|
||||||
|
pick_random_table_item(
|
||||||
|
rng,
|
||||||
|
&mut carried,
|
||||||
|
"potions",
|
||||||
|
WIZARD_POTION_AMOUNT,
|
||||||
|
Some(WIZARD_MAX_SCROLL_LVL)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Class::Villager => {
|
Class::Villager => {
|
||||||
starting_food = VILLAGER_STARTING_FOOD;
|
starting_food = VILLAGER_STARTING_FOOD;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
|
use crate::tile_walkable;
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct CullUnreachable {}
|
pub struct CullUnreachable {}
|
||||||
|
|
@ -28,7 +29,7 @@ impl CullUnreachable {
|
||||||
1000.0
|
1000.0
|
||||||
);
|
);
|
||||||
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||||
if *tile == TileType::Floor {
|
if tile_walkable(*tile) {
|
||||||
let distance_to_start = dijkstra_map.map[i];
|
let distance_to_start = dijkstra_map.map[i];
|
||||||
// We can't get to this tile - so we'll make it a wall
|
// We can't get to this tile - so we'll make it a wall
|
||||||
if distance_to_start == std::f32::MAX {
|
if distance_to_start == std::f32::MAX {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
use super::{ BuilderMap, MetaMapBuilder, TileType };
|
||||||
|
use crate::tile_walkable;
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct DistantExit {}
|
pub struct DistantExit {}
|
||||||
|
|
@ -29,7 +30,7 @@ impl DistantExit {
|
||||||
);
|
);
|
||||||
let mut exit_tile = (0, 0.0f32);
|
let mut exit_tile = (0, 0.0f32);
|
||||||
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||||
if *tile == TileType::Floor {
|
if tile_walkable(*tile) {
|
||||||
let distance_to_start = dijkstra_map.map[i];
|
let distance_to_start = dijkstra_map.map[i];
|
||||||
if distance_to_start != std::f32::MAX {
|
if distance_to_start != std::f32::MAX {
|
||||||
// If it is further away than our current exit candidate, move the exit
|
// If it is further away than our current exit candidate, move the exit
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,9 @@ pub fn forest_builder(
|
||||||
chain.with(CullUnreachable::new());
|
chain.with(CullUnreachable::new());
|
||||||
chain.with(AreaStartingPosition::new(XStart::LEFT, YStart::CENTRE));
|
chain.with(AreaStartingPosition::new(XStart::LEFT, YStart::CENTRE));
|
||||||
// Setup an exit and spawn mobs
|
// Setup an exit and spawn mobs
|
||||||
chain.with(VoronoiSpawning::new());
|
|
||||||
chain.with(RoadExit::new());
|
chain.with(RoadExit::new());
|
||||||
chain.with(Foliage::percent(TileType::Grass, 30));
|
chain.with(Foliage::percent(TileType::Grass, 30));
|
||||||
|
chain.with(VoronoiSpawning::new());
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +66,10 @@ impl RoadExit {
|
||||||
available_floors.push((
|
available_floors.push((
|
||||||
idx,
|
idx,
|
||||||
DistanceAlg::PythagorasSquared.distance2d(
|
DistanceAlg::PythagorasSquared.distance2d(
|
||||||
Point::new((idx as i32) % build_data.map.width, (idx as i32) / build_data.map.width),
|
Point::new(
|
||||||
|
(idx as i32) % build_data.map.width,
|
||||||
|
(idx as i32) / build_data.map.width
|
||||||
|
),
|
||||||
Point::new(seed_x, seed_y)
|
Point::new(seed_x, seed_y)
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
@ -94,7 +97,11 @@ impl RoadExit {
|
||||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
||||||
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
||||||
let (end_x, end_y) = self.find_exit(build_data, build_data.map.width - 2, build_data.height / 2);
|
let (end_x, end_y) = self.find_exit(
|
||||||
|
build_data,
|
||||||
|
build_data.map.width - 2,
|
||||||
|
build_data.height / 2
|
||||||
|
);
|
||||||
let end_idx = build_data.map.xy_idx(end_x, end_y);
|
let end_idx = build_data.map.xy_idx(end_x, end_y);
|
||||||
build_data.map.populate_blocked();
|
build_data.map.populate_blocked();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{ spawner, BuilderMap, MetaMapBuilder, TileType };
|
use super::{ spawner, BuilderMap, MetaMapBuilder, TileType };
|
||||||
|
use crate::tile_walkable;
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -27,7 +28,7 @@ impl VoronoiSpawning {
|
||||||
for y in 1..build_data.map.height - 1 {
|
for y in 1..build_data.map.height - 1 {
|
||||||
for x in 1..build_data.map.width - 1 {
|
for x in 1..build_data.map.width - 1 {
|
||||||
let idx = build_data.map.xy_idx(x, y);
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
if build_data.map.tiles[idx] == TileType::Floor {
|
if tile_walkable(build_data.map.tiles[idx]) {
|
||||||
let cell_value_f = noise.get_noise(x as f32, y as f32) * 10240.0;
|
let cell_value_f = noise.get_noise(x as f32, y as f32) * 10240.0;
|
||||||
let cell_value = cell_value_f as i32;
|
let cell_value = cell_value_f as i32;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use super::{
|
||||||
Skill,
|
Skill,
|
||||||
Skills,
|
Skills,
|
||||||
TileType,
|
TileType,
|
||||||
|
tile_walkable,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
BlocksTile,
|
BlocksTile,
|
||||||
Bleeds,
|
Bleeds,
|
||||||
|
|
@ -42,7 +43,10 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||||
skills.skills.insert(Skill::Magic, 0);
|
skills.skills.insert(Skill::Magic, 0);
|
||||||
let (int, con) = (10, 10);
|
let (int, con) = (10, 10);
|
||||||
// We only create the player once, so create the Clock here for counting turns too.
|
// We only create the player once, so create the Clock here for counting turns too.
|
||||||
ecs.create_entity().with(Clock {}).with(Energy { current: 0, speed: entity::NORMAL_SPEED }).build();
|
ecs.create_entity()
|
||||||
|
.with(Clock {})
|
||||||
|
.with(Energy { current: 0, speed: entity::NORMAL_SPEED })
|
||||||
|
.build();
|
||||||
let player = ecs
|
let player = ecs
|
||||||
.create_entity()
|
.create_entity()
|
||||||
.with(Position { x: player_x, y: player_y })
|
.with(Position { x: player_x, y: player_y })
|
||||||
|
|
@ -57,7 +61,11 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||||
.with(Player {})
|
.with(Player {})
|
||||||
.with(Mind {})
|
.with(Mind {})
|
||||||
.with(Faction { name: "player".to_string() })
|
.with(Faction { name: "player".to_string() })
|
||||||
.with(Viewshed { visible_tiles: Vec::new(), range: entity::DEFAULT_VIEWSHED_STANDARD, dirty: true })
|
.with(Viewshed {
|
||||||
|
visible_tiles: Vec::new(),
|
||||||
|
range: entity::DEFAULT_VIEWSHED_STANDARD,
|
||||||
|
dirty: true,
|
||||||
|
})
|
||||||
.with(Name { name: "you".to_string(), plural: "you".to_string() })
|
.with(Name { name: "you".to_string(), plural: "you".to_string() })
|
||||||
.with(HungerClock { state: HungerState::Satiated, duration: 1200 })
|
.with(HungerClock { state: HungerState::Satiated, duration: 1200 })
|
||||||
.with(Attributes {
|
.with(Attributes {
|
||||||
|
|
@ -102,7 +110,7 @@ pub fn spawn_room(
|
||||||
for y in room.y1 + 1..room.y2 {
|
for y in room.y1 + 1..room.y2 {
|
||||||
for x in room.x1 + 1..room.x2 {
|
for x in room.x1 + 1..room.x2 {
|
||||||
let idx = map.xy_idx(x, y);
|
let idx = map.xy_idx(x, y);
|
||||||
if map.tiles[idx] == TileType::Floor {
|
if tile_walkable(map.tiles[idx]) {
|
||||||
possible_targets.push(idx);
|
possible_targets.push(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -209,14 +217,22 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
|
||||||
|
|
||||||
// 3 scrolls : 3 potions : 1 equipment : 1 wand?
|
// 3 scrolls : 3 potions : 1 equipment : 1 wand?
|
||||||
fn item_category_table() -> RandomTable {
|
fn item_category_table() -> RandomTable {
|
||||||
return RandomTable::new().add("equipment", 20).add("food", 20).add("potion", 16).add("scroll", 16).add("wand", 4);
|
return RandomTable::new()
|
||||||
|
.add("equipment", 20)
|
||||||
|
.add("food", 20)
|
||||||
|
.add("potion", 16)
|
||||||
|
.add("scroll", 16)
|
||||||
|
.add("wand", 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_table() -> RandomTable {
|
fn debug_table() -> RandomTable {
|
||||||
return RandomTable::new().add("debug", 1);
|
return RandomTable::new().add("debug", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_random_item_category(rng: &mut RandomNumberGenerator, difficulty: Option<i32>) -> RandomTable {
|
fn get_random_item_category(
|
||||||
|
rng: &mut RandomNumberGenerator,
|
||||||
|
difficulty: Option<i32>
|
||||||
|
) -> RandomTable {
|
||||||
let item_category = item_category_table().roll(rng);
|
let item_category = item_category_table().roll(rng);
|
||||||
match item_category.as_ref() {
|
match item_category.as_ref() {
|
||||||
"equipment" => {
|
"equipment" => {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ impl State {
|
||||||
let mut encumbrance_system = ai::EncumbranceSystem {}; // Must run first, as it affects energy regen.
|
let mut encumbrance_system = ai::EncumbranceSystem {}; // Must run first, as it affects energy regen.
|
||||||
let mut energy = ai::EnergySystem {}; // Figures out who deserves a turn.
|
let mut energy = ai::EnergySystem {}; // Figures out who deserves a turn.
|
||||||
let mut regen_system = ai::RegenSystem {}; // Restores HP on appropriate clock ticks.
|
let mut regen_system = ai::RegenSystem {}; // Restores HP on appropriate clock ticks.
|
||||||
let mut turn_status_system = ai::TurnStatusSystem {}; // Ticks stasuses. Should anyone now lose their turn? i.e. confusion
|
let mut turn_status_system = ai::TurnStatusSystem {}; // Ticks statuses. Should anyone now lose their turn? i.e. confusion
|
||||||
let mut quip_system = ai::QuipSystem {}; // Quipping is "free". It doesn't use up a turn.
|
let mut quip_system = ai::QuipSystem {}; // Quipping is "free". It doesn't use up a turn.
|
||||||
let mut adjacent_ai = ai::AdjacentAI {}; // AdjacentAI -> DefaultAI are all exclusive. If one acts, the entity's turn is over.
|
let mut adjacent_ai = ai::AdjacentAI {}; // AdjacentAI -> DefaultAI are all exclusive. If one acts, the entity's turn is over.
|
||||||
let mut visible_ai = ai::VisibleAI {};
|
let mut visible_ai = ai::VisibleAI {};
|
||||||
|
|
@ -300,10 +300,8 @@ impl GameState for State {
|
||||||
if let Some(ranged_item) = ranged_item {
|
if let Some(ranged_item) = ranged_item {
|
||||||
let is_aoe = self.ecs.read_storage::<AOE>();
|
let is_aoe = self.ecs.read_storage::<AOE>();
|
||||||
let aoe_item = is_aoe.get(item_entity);
|
let aoe_item = is_aoe.get(item_entity);
|
||||||
let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = camera::get_screen_bounds(
|
let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) =
|
||||||
&self.ecs,
|
camera::get_screen_bounds(&self.ecs, ctx);
|
||||||
ctx
|
|
||||||
);
|
|
||||||
let ppos = self.ecs.fetch::<Point>();
|
let ppos = self.ecs.fetch::<Point>();
|
||||||
if let Some(aoe_item) = aoe_item {
|
if let Some(aoe_item) = aoe_item {
|
||||||
new_runstate = RunState::ShowTargeting {
|
new_runstate = RunState::ShowTargeting {
|
||||||
|
|
@ -325,7 +323,10 @@ impl GameState for State {
|
||||||
} else {
|
} else {
|
||||||
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
||||||
intent
|
intent
|
||||||
.insert(*self.ecs.fetch::<Entity>(), WantsToUseItem { item: item_entity, target: None })
|
.insert(*self.ecs.fetch::<Entity>(), WantsToUseItem {
|
||||||
|
item: item_entity,
|
||||||
|
target: None,
|
||||||
|
})
|
||||||
.expect("Unable to insert intent.");
|
.expect("Unable to insert intent.");
|
||||||
new_runstate = RunState::Ticking;
|
new_runstate = RunState::Ticking;
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +344,9 @@ impl GameState for State {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
let mut intent = self.ecs.write_storage::<WantsToDropItem>();
|
let mut intent = self.ecs.write_storage::<WantsToDropItem>();
|
||||||
intent
|
intent
|
||||||
.insert(*self.ecs.fetch::<Entity>(), WantsToDropItem { item: item_entity })
|
.insert(*self.ecs.fetch::<Entity>(), WantsToDropItem {
|
||||||
|
item: item_entity,
|
||||||
|
})
|
||||||
.expect("Unable to insert intent");
|
.expect("Unable to insert intent");
|
||||||
new_runstate = RunState::Ticking;
|
new_runstate = RunState::Ticking;
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +363,9 @@ impl GameState for State {
|
||||||
let item_entity = result.1.unwrap();
|
let item_entity = result.1.unwrap();
|
||||||
let mut intent = self.ecs.write_storage::<WantsToRemoveItem>();
|
let mut intent = self.ecs.write_storage::<WantsToRemoveItem>();
|
||||||
intent
|
intent
|
||||||
.insert(*self.ecs.fetch::<Entity>(), WantsToRemoveItem { item: item_entity })
|
.insert(*self.ecs.fetch::<Entity>(), WantsToRemoveItem {
|
||||||
|
item: item_entity,
|
||||||
|
})
|
||||||
.expect("Unable to insert intent");
|
.expect("Unable to insert intent");
|
||||||
new_runstate = RunState::Ticking;
|
new_runstate = RunState::Ticking;
|
||||||
}
|
}
|
||||||
|
|
@ -378,7 +383,10 @@ impl GameState for State {
|
||||||
gui::TargetResult::Selected => {
|
gui::TargetResult::Selected => {
|
||||||
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
let mut intent = self.ecs.write_storage::<WantsToUseItem>();
|
||||||
intent
|
intent
|
||||||
.insert(*self.ecs.fetch::<Entity>(), WantsToUseItem { item, target: result.1 })
|
.insert(*self.ecs.fetch::<Entity>(), WantsToUseItem {
|
||||||
|
item,
|
||||||
|
target: result.1,
|
||||||
|
})
|
||||||
.expect("Unable to insert intent.");
|
.expect("Unable to insert intent.");
|
||||||
new_runstate = RunState::Ticking;
|
new_runstate = RunState::Ticking;
|
||||||
}
|
}
|
||||||
|
|
@ -414,7 +422,11 @@ impl GameState for State {
|
||||||
let mut dm = self.ecs.fetch_mut::<MasterDungeonMap>();
|
let mut dm = self.ecs.fetch_mut::<MasterDungeonMap>();
|
||||||
dm.identified_items.insert(name.name.clone());
|
dm.identified_items.insert(name.name.clone());
|
||||||
}
|
}
|
||||||
if let Some(beatitude) = self.ecs.write_storage::<Beatitude>().get_mut(item_entity) {
|
if
|
||||||
|
let Some(beatitude) = self.ecs
|
||||||
|
.write_storage::<Beatitude>()
|
||||||
|
.get_mut(item_entity)
|
||||||
|
{
|
||||||
beatitude.known = true;
|
beatitude.known = true;
|
||||||
}
|
}
|
||||||
new_runstate = RunState::Ticking;
|
new_runstate = RunState::Ticking;
|
||||||
|
|
@ -457,7 +469,9 @@ impl GameState for State {
|
||||||
}
|
}
|
||||||
gui::CharCreateResult::Selected { ancestry, class } => {
|
gui::CharCreateResult::Selected { ancestry, class } => {
|
||||||
if ancestry == gui::Ancestry::NULL {
|
if ancestry == gui::Ancestry::NULL {
|
||||||
new_runstate = RunState::MainMenu { menu_selection: gui::MainMenuSelection::NewGame };
|
new_runstate = RunState::MainMenu {
|
||||||
|
menu_selection: gui::MainMenuSelection::NewGame,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
gui::setup_player_ancestry(&mut self.ecs, ancestry);
|
gui::setup_player_ancestry(&mut self.ecs, ancestry);
|
||||||
gui::setup_player_class(&mut self.ecs, class, ancestry);
|
gui::setup_player_class(&mut self.ecs, class, ancestry);
|
||||||
|
|
@ -468,7 +482,9 @@ impl GameState for State {
|
||||||
}
|
}
|
||||||
RunState::SaveGame => {
|
RunState::SaveGame => {
|
||||||
saveload_system::save_game(&mut self.ecs);
|
saveload_system::save_game(&mut self.ecs);
|
||||||
new_runstate = RunState::MainMenu { menu_selection: gui::MainMenuSelection::LoadGame };
|
new_runstate = RunState::MainMenu {
|
||||||
|
menu_selection: gui::MainMenuSelection::LoadGame,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
RunState::GameOver => {
|
RunState::GameOver => {
|
||||||
let result = gui::game_over(ctx);
|
let result = gui::game_over(ctx);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue