Merge branch 'master' into switching_to_draw_batches

This commit is contained in:
Llywelwyn 2023-09-23 10:12:26 +01:00
commit 441b22439f
119 changed files with 1851 additions and 3612 deletions

View file

@ -1,5 +1,5 @@
use crate::{ EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed, WantsToApproach };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub struct ApproachAI {}
@ -7,7 +7,6 @@ pub struct ApproachAI {}
impl<'a> System<'a> for ApproachAI {
#[allow(clippy::type_complexity)]
type SystemData = (
WriteExpect<'a, RandomNumberGenerator>,
WriteStorage<'a, TakingTurn>,
WriteStorage<'a, WantsToApproach>,
WriteStorage<'a, Position>,
@ -20,7 +19,6 @@ impl<'a> System<'a> for ApproachAI {
fn run(&mut self, data: Self::SystemData) {
let (
mut rng,
mut turns,
mut wants_to_approach,
mut positions,
@ -50,7 +48,7 @@ impl<'a> System<'a> for ApproachAI {
let mut curr_abs_diff = 100;
let idx = map.xy_idx(pos.x, pos.y);
for tar_idx in target_idxs {
let potential_path = rltk::a_star_search(idx, tar_idx, &mut *map);
let potential_path = a_star_search(idx, tar_idx, &mut *map);
if potential_path.success && potential_path.steps.len() > 1 {
if
path.is_none() ||

View file

@ -1,5 +1,5 @@
use crate::{ Chasing, EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::collections::HashMap;
use super::approach_ai_system::get_adjacent_unblocked;
@ -26,8 +26,16 @@ impl<'a> System<'a> for ChaseAI {
);
fn run(&mut self, data: Self::SystemData) {
let (mut turns, mut chasing, mut positions, mut map, mut viewsheds, mut telepaths, mut entity_moved, entities) =
data;
let (
mut turns,
mut chasing,
mut positions,
mut map,
mut viewsheds,
mut telepaths,
mut entity_moved,
entities,
) = data;
let mut targets: HashMap<Entity, (i32, i32)> = HashMap::new();
let mut end_chase: Vec<Entity> = Vec::new();
// For every chasing entity with a turn, look for a valid target position,
@ -67,9 +75,12 @@ impl<'a> System<'a> for ChaseAI {
let mut path: Option<NavigationPath> = None;
let idx = map.xy_idx(pos.x, pos.y);
for tar_idx in target_idxs {
let potential_path = rltk::a_star_search(idx, tar_idx, &mut *map);
let potential_path = a_star_search(idx, tar_idx, &mut *map);
if potential_path.success && potential_path.steps.len() > 1 {
if path.is_none() || potential_path.steps.len() < path.as_ref().unwrap().steps.len() {
if
path.is_none() ||
potential_path.steps.len() < path.as_ref().unwrap().steps.len()
{
path = Some(potential_path);
}
}

View file

@ -1,5 +1,16 @@
use crate::{ tile_walkable, EntityMoved, Map, MoveMode, Movement, Position, TakingTurn, Telepath, Viewshed };
use crate::{
tile_walkable,
EntityMoved,
Map,
MoveMode,
Movement,
Position,
TakingTurn,
Telepath,
Viewshed,
};
use specs::prelude::*;
use bracket_lib::prelude::*;
// Rolling a 1d8+x to decide where to move, where x are the number
// of dice rolls in which they will remian stationary. i.e. If this
@ -16,7 +27,7 @@ impl<'a> System<'a> for DefaultAI {
WriteStorage<'a, Viewshed>,
WriteStorage<'a, Telepath>,
WriteStorage<'a, EntityMoved>,
WriteExpect<'a, rltk::RandomNumberGenerator>,
WriteExpect<'a, RandomNumberGenerator>,
Entities<'a>,
);
@ -85,7 +96,9 @@ impl<'a> System<'a> for DefaultAI {
let idx = map.xy_idx(pos.x, pos.y);
pos.x = x;
pos.y = y;
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
entity_moved
.insert(entity, EntityMoved {})
.expect("Unable to insert EntityMoved");
crate::spatial::move_entity(entity, idx, dest_idx);
viewshed.dirty = true;
if let Some(is_telepath) = telepaths.get_mut(entity) {
@ -102,7 +115,9 @@ impl<'a> System<'a> for DefaultAI {
if !crate::spatial::is_blocked(path[1] as usize) {
pos.x = (path[1] as i32) % map.width;
pos.y = (path[1] as i32) / map.width;
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
entity_moved
.insert(entity, EntityMoved {})
.expect("Unable to insert EntityMoved");
let new_idx = map.xy_idx(pos.x, pos.y);
crate::spatial::move_entity(entity, idx, new_idx);
viewshed.dirty = true;
@ -112,7 +127,7 @@ impl<'a> System<'a> for DefaultAI {
path.remove(0);
} else {
// If the path is blocked, recalculate a new path to the same waypoint.
let path = rltk::a_star_search(
let path = a_star_search(
map.xy_idx(pos.x, pos.y) as i32,
map.xy_idx(
(path[path.len() - 1] as i32) % map.width,
@ -121,7 +136,9 @@ impl<'a> System<'a> for DefaultAI {
&mut *map
);
if path.success && path.steps.len() > 1 {
move_mode.mode = Movement::RandomWaypoint { path: Some(path.steps) };
move_mode.mode = Movement::RandomWaypoint {
path: Some(path.steps),
};
}
}
} else {
@ -132,7 +149,7 @@ impl<'a> System<'a> for DefaultAI {
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(
let path = a_star_search(
map.xy_idx(pos.x, pos.y) as i32,
map.xy_idx(target_x, target_y) as i32,
&mut *map

View file

@ -10,8 +10,9 @@ use crate::{
Map,
TakingTurn,
Confusion,
Intrinsics,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use crate::config::CONFIG;
use crate::data::events::*;
@ -36,6 +37,7 @@ impl<'a> System<'a> for EnergySystem {
ReadStorage<'a, Name>,
ReadExpect<'a, Point>,
ReadStorage<'a, Confusion>,
ReadStorage<'a, Intrinsics>,
);
fn run(&mut self, data: Self::SystemData) {
@ -53,6 +55,7 @@ impl<'a> System<'a> for EnergySystem {
names,
player_pos,
confusion,
intrinsics,
) = data;
// If not ticking, do nothing.
if *runstate != RunState::Ticking {
@ -68,7 +71,7 @@ impl<'a> System<'a> for EnergySystem {
.insert(entity, TakingTurn {})
.expect("Unable to insert turn for turn counter.");
energy.current -= TURN_COST;
crate::gamelog::record_event(EVENT::TURN(1));
crate::gamelog::record_event(EVENT::Turn(1));
// Handle spawning mobs each turn
if CONFIG.logging.log_ticks {
console::log(
@ -87,20 +90,14 @@ impl<'a> System<'a> for EnergySystem {
&positions,
!&confusion,
).join() {
let burden_modifier = if let Some(burden) = burdens.get(entity) {
match burden.level {
BurdenLevel::Burdened => SPEED_MOD_BURDENED,
BurdenLevel::Strained => SPEED_MOD_STRAINED,
BurdenLevel::Overloaded => SPEED_MOD_OVERLOADED,
}
} else {
1.0
};
let overmap_mod = if map.overmap { SPEED_MOD_OVERMAP_TRAVEL } else { 1.0 };
let burden_modifier = get_burden_modifier(&burdens, entity);
let overmap_mod = get_overmap_modifier(&map);
let intrinsic_speed = get_intrinsic_speed(&intrinsics, entity);
// Every entity has a POTENTIAL equal to their speed.
let mut energy_potential: i32 = ((energy.speed as f32) *
burden_modifier *
overmap_mod) as i32;
overmap_mod *
intrinsic_speed) as i32;
// Increment current energy by NORMAL_SPEED for every
// whole number of NORMAL_SPEEDS in their POTENTIAL.
while energy_potential >= NORMAL_SPEED {
@ -121,37 +118,61 @@ impl<'a> System<'a> for EnergySystem {
// has enough energy, they take a turn and decrement their energy
// by TURN_COST. If the current entity is the player, await input.
if energy.current >= TURN_COST {
let mut my_turn = true;
energy.current -= TURN_COST;
if entity == *player {
*runstate = RunState::AwaitingInput;
} else {
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
*player_pos,
Point::new(pos.x, pos.y)
);
if distance > 20.0 {
my_turn = false;
}
} else if cull_turn_by_distance(&player_pos, pos) {
continue;
}
if my_turn {
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn.");
if CONFIG.logging.log_ticks {
let name = if let Some(name) = names.get(entity) {
&name.name
} else {
"Unknown entity"
};
console::log(
format!(
"ENERGY SYSTEM: {} granted a turn. [leftover energy: {}].",
name,
energy.current
)
);
}
turns.insert(entity, TakingTurn {}).expect("Unable to insert turn.");
if CONFIG.logging.log_ticks {
let name = if let Some(name) = names.get(entity) {
&name.name
} else {
"Unknown entity"
};
console::log(
format!(
"ENERGY SYSTEM: {} granted a turn. [leftover energy: {}].",
name,
energy.current
)
);
}
}
}
}
}
fn get_burden_modifier(burdens: &ReadStorage<Burden>, entity: Entity) -> f32 {
return if let Some(burden) = burdens.get(entity) {
match burden.level {
BurdenLevel::Burdened => SPEED_MOD_BURDENED,
BurdenLevel::Strained => SPEED_MOD_STRAINED,
BurdenLevel::Overloaded => SPEED_MOD_OVERLOADED,
}
} else {
1.0
};
}
fn get_overmap_modifier(map: &ReadExpect<Map>) -> f32 {
return if map.overmap { SPEED_MOD_OVERMAP_TRAVEL } else { 1.0 };
}
fn cull_turn_by_distance(player_pos: &Point, pos: &Position) -> bool {
let distance = DistanceAlg::Pythagoras.distance2d(*player_pos, Point::new(pos.x, pos.y));
if distance > 20.0 {
return true;
}
return false;
}
fn get_intrinsic_speed(intrinsics: &ReadStorage<Intrinsics>, entity: Entity) -> f32 {
if let Some(intrinsics) = intrinsics.get(entity) {
if intrinsics.list.contains(&crate::Intrinsic::Speed) {
return 4.0 / 3.0;
}
}
return 1.0;
}

View file

@ -1,5 +1,5 @@
use crate::{ EntityMoved, Map, Position, TakingTurn, Telepath, Viewshed, WantsToFlee };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub struct FleeAI {}
@ -39,7 +39,13 @@ impl<'a> System<'a> for FleeAI {
turn_done.push(entity);
let my_idx = map.xy_idx(pos.x, pos.y);
map.populate_blocked();
let flee_map = DijkstraMap::new(map.width as usize, map.height as usize, &fleeing.indices, &*map, 100.0);
let flee_map = DijkstraMap::new(
map.width as usize,
map.height as usize,
&fleeing.indices,
&*map,
100.0
);
let flee_target = DijkstraMap::find_highest_exit(&flee_map, my_idx, &*map);
if let Some(flee_target) = flee_target {
if !crate::spatial::is_blocked(flee_target as usize) {
@ -50,7 +56,9 @@ impl<'a> System<'a> for FleeAI {
}
pos.x = (flee_target as i32) % map.width;
pos.y = (flee_target as i32) / map.width;
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert EntityMoved");
entity_moved
.insert(entity, EntityMoved {})
.expect("Unable to insert EntityMoved");
}
}
}

View file

@ -1,5 +1,5 @@
use crate::{ gamelog, gui::renderable_colour, Name, Quips, Renderable, TakingTurn, Viewshed };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub struct QuipSystem {}
@ -19,8 +19,18 @@ impl<'a> System<'a> for QuipSystem {
fn run(&mut self, data: Self::SystemData) {
let (entities, mut quips, names, renderables, turns, player_pos, viewsheds, mut rng) = data;
for (entity, quip, name, viewshed, _turn) in (&entities, &mut quips, &names, &viewsheds, &turns).join() {
if !quip.available.is_empty() && viewshed.visible_tiles.contains(&player_pos) && rng.roll_dice(1, 6) == 1 {
for (entity, quip, name, viewshed, _turn) in (
&entities,
&mut quips,
&names,
&viewsheds,
&turns,
).join() {
if
!quip.available.is_empty() &&
viewshed.visible_tiles.contains(&player_pos) &&
rng.roll_dice(1, 6) == 1
{
let quip_index = if quip.available.len() == 1 {
0
} else {

View file

@ -9,6 +9,7 @@ use crate::{
Position,
RandomNumberGenerator,
TakingTurn,
Intrinsics,
};
use specs::prelude::*;
use crate::data::events::*;
@ -36,10 +37,24 @@ impl<'a> System<'a> for RegenSystem {
ReadStorage<'a, HasClass>,
ReadStorage<'a, Attributes>,
WriteExpect<'a, RandomNumberGenerator>,
ReadStorage<'a, Intrinsics>,
ReadExpect<'a, Entity>,
);
fn run(&mut self, data: Self::SystemData) {
let (clock, entities, positions, mut pools, turns, player, classes, attributes, mut rng) = data;
let (
clock,
entities,
positions,
mut pools,
turns,
player,
classes,
attributes,
mut rng,
intrinsics,
player_entity,
) = data;
let mut clock_turn = false;
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
clock_turn = true;
@ -56,19 +71,29 @@ impl<'a> System<'a> for RegenSystem {
}
// Player HP regen
let level = gamelog::get_event_count(EVENT::COUNT_LEVEL);
if current_turn % get_player_hp_regen_turn(level) == 0 {
if
current_turn % get_player_hp_regen_turn(level) == 0 ||
intrinsics.get(*player_entity).unwrap().list.contains(&crate::Intrinsic::Regeneration)
{
for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, &player).join() {
try_hp_regen_tick(pool, get_player_hp_regen_per_tick(level));
}
}
// Both MP regen
for (e, _p, pool) in (&entities, &positions, &mut pools).join() {
let is_wizard = if let Some(class) = classes.get(e) { class.name == Class::Wizard } else { false };
let is_wizard = if let Some(class) = classes.get(e) {
class.name == Class::Wizard
} else {
false
};
let numerator = if is_wizard { WIZARD_MP_REGEN_MOD } else { NONWIZARD_MP_REGEN_MOD };
let multiplier: f32 = (numerator as f32) / (MP_REGEN_DIVISOR as f32);
let mp_regen_tick = (((MP_REGEN_BASE - pool.level) as f32) * multiplier) as i32;
if current_turn % mp_regen_tick == 0 {
try_mana_regen_tick(pool, rng.roll_dice(1, get_mana_regen_per_tick(e, &attributes)));
try_mana_regen_tick(
pool,
rng.roll_dice(1, get_mana_regen_per_tick(e, &attributes))
);
}
}
}

View file

@ -10,7 +10,7 @@ use crate::{
Item,
Prop,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use crate::data::events::*;
@ -99,7 +99,7 @@ impl<'a> System<'a> for TurnStatusSystem {
.colour(WHITE)
.append("are confused!");
log = true;
gamelog::record_event(EVENT::PLAYER_CONFUSED(1));
gamelog::record_event(EVENT::PlayerConfused(1));
} else {
logger = logger
.append("The")

View file

@ -12,7 +12,7 @@ use crate::{
WantsToApproach,
WantsToFlee,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::collections::HashSet;
@ -81,10 +81,16 @@ impl<'a> System<'a> for VisibleAI {
}
reactions.sort_by(|(a, _, _), (b, _, _)| {
let (a_x, a_y) = (a % (map.width as usize), a / (map.width as usize));
let dist_a = DistanceAlg::PythagorasSquared.distance2d(Point::new(a_x, a_y), Point::new(pos.x, pos.y));
let dist_a = DistanceAlg::PythagorasSquared.distance2d(
Point::new(a_x, a_y),
Point::new(pos.x, pos.y)
);
let dist_a_estimate = dist_a as i32;
let (b_x, b_y) = (b % (map.width as usize), b / (map.width as usize));
let dist_b = DistanceAlg::PythagorasSquared.distance2d(Point::new(b_x, b_y), Point::new(pos.x, pos.y));
let dist_b = DistanceAlg::PythagorasSquared.distance2d(
Point::new(b_x, b_y),
Point::new(pos.x, pos.y)
);
let dist_b_estimate = dist_b as i32;
return dist_b_estimate.cmp(&dist_a_estimate);
});
@ -96,7 +102,9 @@ impl<'a> System<'a> for VisibleAI {
wants_to_approach
.insert(entity, WantsToApproach { idx: reaction.0 as i32 })
.expect("Error inserting WantsToApproach");
chasing.insert(entity, Chasing { target: reaction.2 }).expect("Unable to insert Chasing");
chasing
.insert(entity, Chasing { target: reaction.2 })
.expect("Unable to insert Chasing");
continue;
}
}
@ -108,7 +116,9 @@ impl<'a> System<'a> for VisibleAI {
}
}
if !flee.is_empty() {
wants_to_flee.insert(entity, WantsToFlee { indices: flee }).expect("Unable to insert");
wants_to_flee
.insert(entity, WantsToFlee { indices: flee })
.expect("Unable to insert");
}
}
}

View file

@ -1,12 +1,12 @@
use super::{ Hidden, Map, Mind, Position, Prop, Renderable, Pools };
use rltk::prelude::*;
use super::{ Hidden, Map, Mind, Position, Prop, Renderable };
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::ops::Mul;
use super::data::visuals::{ VIEWPORT_W, VIEWPORT_H };
const SHOW_BOUNDARIES: bool = false;
pub fn get_screen_bounds(ecs: &World, _ctx: &mut Rltk) -> (i32, i32, i32, i32, i32, i32) {
pub fn get_screen_bounds(ecs: &World, _ctx: &mut BTerm) -> (i32, i32, i32, i32, i32, i32) {
let player_pos = ecs.fetch::<Point>();
let map = ecs.fetch::<Map>();
let (x_chars, y_chars, mut x_offset, mut y_offset) = (VIEWPORT_W, VIEWPORT_H, 1, 10);
@ -32,7 +32,7 @@ pub fn get_screen_bounds(ecs: &World, _ctx: &mut Rltk) -> (i32, i32, i32, i32, i
(min_x, max_x, min_y, max_y, x_offset, y_offset)
}
pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
pub fn render_camera(ecs: &World, ctx: &mut BTerm) {
let map = ecs.fetch::<Map>();
let (min_x, max_x, min_y, max_y, x_offset, y_offset) = get_screen_bounds(ecs, ctx);
@ -151,7 +151,7 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
}
}
pub fn render_debug_map(map: &Map, ctx: &mut Rltk) {
pub fn render_debug_map(map: &Map, ctx: &mut BTerm) {
let player_pos = Point::new(map.width / 2, map.height / 2);
let (x_chars, y_chars) = ctx.get_char_size();
@ -182,7 +182,7 @@ pub fn render_debug_map(map: &Map, ctx: &mut Rltk) {
ctx.set(x, y, fg, bg, glyph);
}
} else if SHOW_BOUNDARIES {
ctx.set(x, y, RGB::named(rltk::GRAY), RGB::named(rltk::BLACK), rltk::to_cp437('·'));
ctx.set(x, y, RGB::named(GRAY), RGB::named(BLACK), to_cp437('·'));
}
x += 1;
}

View file

@ -1,12 +1,12 @@
use crate::gui::Ancestry;
use crate::gui::Class;
use rltk::RGB;
use bracket_lib::prelude::*;
use serde::{ Deserialize, Serialize };
use specs::error::NoError;
use specs::prelude::*;
use specs::saveload::{ ConvertSaveload, Marker };
use specs_derive::*;
use std::collections::HashMap;
use std::collections::{ HashMap, HashSet };
// Serialization helper code. We need to implement ConvertSaveload for each type that contains an
// Entity.
@ -40,7 +40,7 @@ pub struct OtherLevelPosition {
#[derive(Component, ConvertSaveload, Clone)]
pub struct Renderable {
pub glyph: rltk::FontCharType,
pub glyph: FontCharType,
pub fg: RGB,
pub bg: RGB,
pub render_order: i32,
@ -104,14 +104,14 @@ pub struct Mind {}
#[derive(Component, ConvertSaveload, Clone)]
pub struct Viewshed {
pub visible_tiles: Vec<rltk::Point>,
pub visible_tiles: Vec<Point>,
pub range: i32,
pub dirty: bool,
}
#[derive(Component, ConvertSaveload, Clone)]
pub struct Telepath {
pub telepath_tiles: Vec<rltk::Point>,
pub telepath_tiles: Vec<Point>,
pub range: i32,
pub dirty: bool,
}
@ -316,6 +316,7 @@ pub enum WeaponAttribute {
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct MeleeWeapon {
pub damage_type: DamageType,
pub attribute: WeaponAttribute,
pub damage_n_dice: i32,
pub damage_die_type: i32,
@ -326,6 +327,7 @@ pub struct MeleeWeapon {
#[derive(Serialize, Deserialize, Clone)]
pub struct NaturalAttack {
pub name: String,
pub damage_type: DamageType,
pub damage_n_dice: i32,
pub damage_die_type: i32,
pub damage_bonus: i32,
@ -365,8 +367,74 @@ pub struct ProvidesHealing {
pub modifier: i32,
}
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
pub enum DamageType {
Physical,
Magic, // e.g. magic missiles, silvered weapons
Fire, // e.g. fireball
Cold, // e.g. cone of cold
Poison, // e.g. poison gas
Forced, // Bypasses any immunities. e.g. Hunger ticks.
}
impl DamageType {
pub fn is_magic(&self) -> bool {
match self {
DamageType::Magic | DamageType::Fire | DamageType::Cold => true,
_ => false,
}
}
}
#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
pub enum DamageModifier {
None,
Weakness,
Resistance,
Immune,
}
impl DamageModifier {
const NONE_MOD: f32 = 1.0;
const WEAK_MOD: f32 = 2.0;
const RESIST_MOD: f32 = 0.5;
const IMMUNE_MOD: f32 = 0.0;
pub fn multiplier(&self) -> f32 {
match self {
DamageModifier::None => Self::NONE_MOD,
DamageModifier::Weakness => Self::WEAK_MOD,
DamageModifier::Resistance => Self::RESIST_MOD,
DamageModifier::Immune => Self::IMMUNE_MOD,
}
}
}
#[derive(Component, Serialize, Deserialize, Debug, Clone)]
pub struct HasDamageModifiers {
pub modifiers: HashMap<DamageType, DamageModifier>,
}
impl HasDamageModifiers {
pub fn modifier(&self, damage_type: &DamageType) -> &DamageModifier {
self.modifiers.get(damage_type).unwrap_or(&DamageModifier::None)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Intrinsic {
Regeneration, // Regenerate 1 HP on every tick
Speed, // 4/3x speed multiplier
}
#[derive(Component, Serialize, Deserialize, Debug, Clone)]
pub struct Intrinsics {
pub list: HashSet<Intrinsic>,
}
#[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct InflictsDamage {
pub damage_type: DamageType,
pub n_dice: i32,
pub sides: i32,
pub modifier: i32,
@ -417,7 +485,7 @@ pub struct WantsToRemoveItem {
#[derive(Component, Debug, ConvertSaveload)]
pub struct WantsToUseItem {
pub item: Entity,
pub target: Option<rltk::Point>,
pub target: Option<Point>,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
@ -446,8 +514,8 @@ pub struct Charges {
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct SpawnParticleLine {
pub glyph: rltk::FontCharType,
pub tail_glyph: rltk::FontCharType,
pub glyph: FontCharType,
pub tail_glyph: FontCharType,
pub colour: RGB,
pub lifetime_ms: f32,
pub trail_colour: RGB,
@ -456,16 +524,16 @@ pub struct SpawnParticleLine {
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct SpawnParticleSimple {
pub glyph: rltk::FontCharType,
pub glyph: FontCharType,
pub colour: RGB,
pub lifetime_ms: f32,
}
#[derive(Component, Serialize, Deserialize, Clone)]
pub struct SpawnParticleBurst {
pub glyph: rltk::FontCharType,
pub head_glyph: rltk::FontCharType,
pub tail_glyph: rltk::FontCharType,
pub glyph: FontCharType,
pub head_glyph: FontCharType,
pub tail_glyph: FontCharType,
pub colour: RGB,
pub lerp: RGB,
pub lifetime_ms: f32,

View file

@ -1,4 +1,4 @@
use rltk::prelude::*;
use bracket_lib::prelude::*;
use toml::Value;
use serde::{ Serialize, Deserialize };

View file

@ -12,7 +12,7 @@ use super::{
Renderable,
RunState,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use crate::data::events;
@ -40,7 +40,7 @@ pub fn delete_the_dead(ecs: &mut World) {
.append("The")
.colour(renderable_colour(&renderables, entity))
.append(&victim_name.name)
.colour(rltk::WHITE)
.colour(WHITE)
.append("is destroyed!")
.log();
} else {
@ -49,7 +49,7 @@ pub fn delete_the_dead(ecs: &mut World) {
.append("The")
.colour(renderable_colour(&renderables, entity))
.append(&victim_name.name)
.colour(rltk::WHITE)
.colour(WHITE)
.append("dies!")
.log();
}
@ -81,12 +81,15 @@ pub fn delete_the_dead(ecs: &mut World) {
}
// For everything that died, increment the event log, and delete.
for victim in dead {
gamelog::record_event(events::EVENT::TURN(1));
gamelog::record_event(events::EVENT::Turn(1));
ecs.delete_entity(victim).expect("Unable to delete.");
}
}
fn handle_dead_entity_items(ecs: &mut World, dead: &Vec<Entity>) -> (Vec<Entity>, Vec<(String, Position)>) {
fn handle_dead_entity_items(
ecs: &mut World,
dead: &Vec<Entity>
) -> (Vec<Entity>, Vec<(String, Position)>) {
let mut to_drop: Vec<(Entity, Position)> = Vec::new();
let mut to_spawn: Vec<(String, Position)> = Vec::new();
let entities = ecs.entities();

View file

@ -2,17 +2,17 @@ use serde::{ Deserialize, Serialize };
#[derive(Serialize, Deserialize, Clone)]
pub enum EVENT {
TURN(i32),
LEVEL(i32),
CHANGED_FLOOR(String),
PLAYER_CONFUSED(i32),
KICKED_SOMETHING(i32),
BROKE_DOOR(i32),
LOOKED_FOR_HELP(i32),
KILLED(String),
PLAYER_DIED(String),
DISCOVERED(String),
IDENTIFIED(String),
Turn(i32),
Level(i32),
ChangedFloor(String),
PlayerConfused(i32),
KickedSomething(i32),
BrokeDoor(i32),
LookedForHelp(i32),
Killed(String),
PlayerDied(String),
Discovered(String),
Identified(String),
}
impl EVENT {
@ -20,8 +20,8 @@ impl EVENT {
pub const COUNT_KILLED: &str = "killed";
pub const COUNT_LEVEL: &str = "level";
pub const COUNT_CHANGED_FLOOR: &str = "changed_floor";
pub const COUNT_BROKE_DOOR: &str = "broke_door";
pub const COUNT_PLAYER_CONFUSED: &str = "player_confused";
pub const COUNT_BROKE_DOOR: &str = "BrokeDoor";
pub const COUNT_PLAYER_CONFUSED: &str = "PlayerConfused";
pub const COUNT_KICK: &str = "kick";
pub const COUNT_LOOKED_FOR_HELP: &str = "looked_for_help";
pub const COUNT_LOOKED_FOR_HELP: &str = "LookedForHelp";
}

View file

@ -1,6 +1,6 @@
use super::names::*;
use super::visuals::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
pub const ID_OVERMAP: i32 = 1;

View file

@ -32,7 +32,7 @@ pub const YOU_REMOVE_ITEM_CURSED: &str = "You can't remove the";
/// Prefixes death message.
pub const PLAYER_DIED: &str = "You died!";
/// Death message specifiers. Appended after PLAYER_DIED.
/// Death message specifiers. Appended after PlayerDied.
pub const PLAYER_DIED_SUICIDE: &str = "You killed yourself";
pub const PLAYER_DIED_NAMED_ATTACKER: &str = "You were killed by";
pub const PLAYER_DIED_UNKNOWN: &str = "You were killed"; // Ultimately, this should never be used. Slowly include specific messages for any death.

View file

@ -1,3 +1,5 @@
use bracket_lib::prelude::*;
// POST-PROCESSING
pub const WITH_DARKEN_BY_DISTANCE: bool = true; // If further away tiles should get darkened, instead of a harsh transition to non-visible.
pub const VIEWPORT_W: i32 = 69;
@ -17,8 +19,8 @@ pub const SHORT_PARTICLE_LIFETIME: f32 = 100.0; // in ms
pub const DEFAULT_PARTICLE_LIFETIME: f32 = 200.0;
pub const LONG_PARTICLE_LIFETIME: f32 = 300.0;
pub const TARGETING_CURSOR_COL: (u8, u8, u8) = rltk::GOLDENROD;
pub const TARGETING_LINE_COL: (u8, u8, u8) = rltk::LIGHTGOLDENROD;
pub const TARGETING_CURSOR_COL: (u8, u8, u8) = GOLDENROD;
pub const TARGETING_LINE_COL: (u8, u8, u8) = LIGHTGOLDENROD;
pub const TARGETING_AOE_COL: (u8, u8, u8) = (20, 20, 20);
pub const TARGETING_VALID_COL: (u8, u8, u8) = (10, 10, 10);

View file

@ -14,21 +14,29 @@ use crate::{
HungerClock,
HungerState,
Bleeds,
HasDamageModifiers,
};
use crate::gui::with_article;
use crate::data::visuals::{ DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME };
use crate::data::messages::LEVELUP_PLAYER;
use crate::data::events::*;
use crate::data::messages::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub fn inflict_damage(ecs: &mut World, damage: &EffectSpawner, target: Entity) {
let mut pools = ecs.write_storage::<Pools>();
if let Some(target_pool) = pools.get_mut(target) {
if !target_pool.god {
if let EffectType::Damage { amount } = damage.effect_type {
target_pool.hit_points.current -= amount;
if let EffectType::Damage { amount, damage_type } = damage.effect_type {
let mult = if
let Some(modifiers) = ecs.read_storage::<HasDamageModifiers>().get(target)
{
modifiers.modifier(&damage_type).multiplier()
} else {
1.0
};
target_pool.hit_points.current -= ((amount as f32) * mult) as i32;
let bleeders = ecs.read_storage::<Bleeds>();
if let Some(bleeds) = bleeders.get(target) {
add_effect(
@ -221,12 +229,12 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
if let Some(source) = effect.source {
// If the target was the player, game over, and record source of death.
if target == *player {
gamelog::record_event(EVENT::PLAYER_DIED(get_death_message(ecs, source)));
gamelog::record_event(EVENT::PlayerDied(get_death_message(ecs, source)));
return;
} else {
// If the player was the source, record the kill.
if let Some(tar_name) = names.get(target) {
gamelog::record_event(EVENT::KILLED(tar_name.name.clone()));
gamelog::record_event(EVENT::Killed(tar_name.name.clone()));
}
}
// Calc XP value of target.
@ -246,7 +254,7 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
source_pools.level += 1;
// If it was the PLAYER that levelled up:
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)
@ -328,11 +336,11 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) {
if target == *player {
if let Some(hc) = ecs.read_storage::<HungerClock>().get(target) {
if hc.state == HungerState::Starving {
gamelog::record_event(EVENT::PLAYER_DIED("You starved to death!".to_string()));
gamelog::record_event(EVENT::PlayerDied("You starved to death!".to_string()));
}
} else {
gamelog::record_event(
EVENT::PLAYER_DIED("You died from unknown causes!".to_string())
EVENT::PlayerDied("You died from unknown causes!".to_string())
);
}
}

View file

@ -1,9 +1,10 @@
use super::BUC;
use crate::spatial;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::collections::VecDeque;
use std::sync::Mutex;
use crate::components::DamageType;
mod damage;
mod hunger;
@ -24,6 +25,7 @@ lazy_static! {
pub enum EffectType {
Damage {
amount: i32,
damage_type: DamageType,
},
Healing {
amount: i32,

View file

@ -1,6 +1,6 @@
use super::{ add_effect, targeting, EffectSpawner, EffectType, Targets };
use crate::{ Map, ParticleBuilder, SpawnParticleBurst, SpawnParticleLine, SpawnParticleSimple };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub fn particle_to_tile(ecs: &mut World, target: i32, effect: &EffectSpawner) {
@ -8,9 +8,24 @@ pub fn particle_to_tile(ecs: &mut World, target: i32, effect: &EffectSpawner) {
let map = ecs.fetch::<Map>();
let mut particle_builder = ecs.fetch_mut::<ParticleBuilder>();
if delay <= 0.0 {
particle_builder.request(target % map.width, target / map.width, fg, bg, glyph, lifespan);
particle_builder.request(
target % map.width,
target / map.width,
fg,
bg,
glyph,
lifespan
);
} else {
particle_builder.delay(target % map.width, target / map.width, fg, bg, glyph, lifespan, delay);
particle_builder.delay(
target % map.width,
target / map.width,
fg,
bg,
glyph,
lifespan,
delay
);
}
}
}
@ -113,9 +128,14 @@ pub fn handle_line_particles(ecs: &World, entity: Entity, target: &Targets) {
if let Some(part) = ecs.read_storage::<SpawnParticleLine>().get(entity) {
if let Some(start_pos) = targeting::find_item_position(ecs, entity) {
match target {
Targets::Tile { target } => spawn_line_particles(ecs, start_pos, *target as i32, part),
Targets::Tile { target } =>
spawn_line_particles(ecs, start_pos, *target as i32, part),
Targets::TileList { targets } => {
targets.iter().for_each(|target| spawn_line_particles(ecs, start_pos, *target as i32, part))
targets
.iter()
.for_each(|target|
spawn_line_particles(ecs, start_pos, *target as i32, part)
)
}
Targets::Entity { target } => {
if let Some(end_pos) = targeting::entity_position(ecs, *target) {

View file

@ -1,5 +1,5 @@
use crate::{ Equipped, InBackpack, Map, Position };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub fn entity_position(ecs: &World, target: Entity) -> Option<usize> {
@ -10,8 +10,8 @@ pub fn entity_position(ecs: &World, target: Entity) -> Option<usize> {
return None;
}
pub fn aoe_tiles(map: &Map, target: rltk::Point, radius: i32) -> Vec<usize> {
let mut blast_tiles = rltk::field_of_view(target, radius, &*map);
pub fn aoe_tiles(map: &Map, target: Point, radius: i32) -> Vec<usize> {
let mut blast_tiles = field_of_view(target, radius, &*map);
blast_tiles.retain(|p| p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1);
let mut result = Vec::new();
for t in blast_tiles.iter() {

View file

@ -30,13 +30,12 @@ use crate::{
SingleActivation,
BUC,
GrantsSpell,
KnownSpell,
KnownSpells,
Position,
Viewshed,
};
use crate::data::messages::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub fn item_trigger(source: Option<Entity>, item: Entity, target: &Targets, ecs: &mut World) {
// Check if the item has charges, etc.
@ -47,8 +46,10 @@ pub fn item_trigger(source: Option<Entity>, item: Entity, target: &Targets, ecs:
gamelog::Logger::new().append(NOCHARGES_DIDNOTHING).log();
return;
}
gamelog::Logger::new().colour(rltk::YELLOW).append(NOCHARGES_WREST);
ecs.write_storage::<Consumable>().insert(item, Consumable {}).expect("Could not insert consumable");
gamelog::Logger::new().colour(YELLOW).append(NOCHARGES_WREST);
ecs.write_storage::<Consumable>()
.insert(item, Consumable {})
.expect("Could not insert consumable");
}
has_charges.uses -= 1;
}
@ -83,7 +84,12 @@ struct EventInfo {
// It does almost no sanity-checking to make sure the logs only appear if the effect is taking
// place on the player -- once monsters can use an item, their item usage will make logs for
// the player saying they were the one who used the item. This will need refactoring then.
fn event_trigger(source: Option<Entity>, entity: Entity, target: &Targets, ecs: &mut World) -> bool {
fn event_trigger(
source: Option<Entity>,
entity: Entity,
target: &Targets,
ecs: &mut World
) -> bool {
let buc = if let Some(beatitude) = ecs.read_storage::<Beatitude>().get(entity) {
beatitude.buc.clone()
} else {
@ -147,7 +153,11 @@ fn handle_restore_nutrition(
return (logger, false);
}
fn handle_magic_mapper(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
fn handle_magic_mapper(
ecs: &mut World,
event: &mut EventInfo,
mut logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if ecs.read_storage::<MagicMapper>().get(event.entity).is_some() {
let mut runstate = ecs.fetch_mut::<RunState>();
let cursed = if event.buc == BUC::Cursed { true } else { false };
@ -159,9 +169,17 @@ fn handle_magic_mapper(ecs: &mut World, event: &mut EventInfo, mut logger: gamel
return (logger, false);
}
fn handle_grant_spell(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
if let Some(granted_spell) = ecs.read_storage::<GrantsSpell>().get(event.entity) {
if let Some(known_spells) = ecs.write_storage::<KnownSpells>().get_mut(event.source.unwrap()) {
fn handle_grant_spell(
ecs: &mut World,
event: &mut EventInfo,
logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if let Some(_granted_spell) = ecs.read_storage::<GrantsSpell>().get(event.entity) {
if
let Some(_known_spells) = ecs
.write_storage::<KnownSpells>()
.get_mut(event.source.unwrap())
{
// TODO: Check if the player knows *this* spell, and add it if not.
} else {
// TODO: Grant the KnownSpells component, and then add the spell.
@ -170,7 +188,11 @@ fn handle_grant_spell(ecs: &mut World, event: &mut EventInfo, mut logger: gamelo
return (logger, false);
}
fn handle_healing(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
fn handle_healing(
ecs: &mut World,
event: &mut EventInfo,
mut logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if let Some(healing_item) = ecs.read_storage::<ProvidesHealing>().get(event.entity) {
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
let buc_mod = match event.buc {
@ -178,14 +200,19 @@ fn handle_healing(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::L
BUC::Cursed => -1,
_ => 0,
};
let roll = rng.roll_dice(healing_item.n_dice + buc_mod, healing_item.sides) + healing_item.modifier;
let roll =
rng.roll_dice(healing_item.n_dice + buc_mod, healing_item.sides) +
healing_item.modifier;
add_effect(
event.source,
EffectType::Healing { amount: roll, increment_max: get_noncursed(&event.buc) },
event.target.clone()
);
for target in get_entity_targets(&event.target) {
if ecs.read_storage::<Prop>().get(target).is_some() || ecs.read_storage::<Item>().get(target).is_some() {
if
ecs.read_storage::<Prop>().get(target).is_some() ||
ecs.read_storage::<Item>().get(target).is_some()
{
continue;
}
let renderables = ecs.read_storage::<Renderable>();
@ -211,11 +238,19 @@ fn handle_healing(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::L
return (logger, false);
}
fn handle_damage(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
fn handle_damage(
ecs: &mut World,
event: &mut EventInfo,
mut logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if let Some(damage_item) = ecs.read_storage::<InflictsDamage>().get(event.entity) {
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
let roll = rng.roll_dice(damage_item.n_dice, damage_item.sides) + damage_item.modifier;
add_effect(event.source, EffectType::Damage { amount: roll }, event.target.clone());
add_effect(
event.source,
EffectType::Damage { amount: roll, damage_type: damage_item.damage_type },
event.target.clone()
);
for target in get_entity_targets(&event.target) {
if ecs.read_storage::<Prop>().get(target).is_some() {
continue;
@ -232,7 +267,9 @@ fn handle_damage(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Lo
.colour(WHITE)
.append(DAMAGE_PLAYER_HIT);
event.log = true;
} else if player_viewshed.visible_tiles.contains(&Point::new(target_pos.x, target_pos.y)) {
} else if
player_viewshed.visible_tiles.contains(&Point::new(target_pos.x, target_pos.y))
{
if ecs.read_storage::<Item>().get(target).is_some() {
if ecs.read_storage::<Destructible>().get(target).is_some() {
logger = logger
@ -259,9 +296,17 @@ fn handle_damage(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Lo
}
#[allow(unused_mut)]
fn handle_confusion(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
fn handle_confusion(
ecs: &mut World,
event: &mut EventInfo,
mut logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if let Some(confusion) = ecs.read_storage::<Confusion>().get(event.entity) {
add_effect(event.source, EffectType::Confusion { turns: confusion.turns }, event.target.clone());
add_effect(
event.source,
EffectType::Confusion { turns: confusion.turns },
event.target.clone()
);
return (logger, true);
}
return (logger, false);
@ -272,7 +317,11 @@ fn select_single(ecs: &World, runstate: RunState) {
*new_runstate = runstate;
}
fn handle_identify(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
fn handle_identify(
ecs: &mut World,
event: &mut EventInfo,
mut logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if let Some(_i) = ecs.read_storage::<ProvidesIdentify>().get(event.entity) {
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
let mut dm = ecs.fetch_mut::<MasterDungeonMap>();
@ -303,7 +352,10 @@ fn handle_identify(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::
.get(event.source.unwrap())
.map(|b| b.known)
.unwrap_or(true);
return in_this_backpack && (has_obfuscated_name || !already_identified || !known_beatitude);
let result =
in_this_backpack &&
(has_obfuscated_name || !already_identified || !known_beatitude);
return result;
}) {
to_identify.push((e, name.name.clone()));
}
@ -313,14 +365,20 @@ fn handle_identify(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::
beatitude.known = true;
}
}
logger = logger.append(IDENTIFY_ALL).buc(event.buc.clone(), None, Some(IDENTIFY_ALL_BLESSED));
logger = logger
.append(IDENTIFY_ALL)
.buc(event.buc.clone(), None, Some(IDENTIFY_ALL_BLESSED));
event.log = true;
return (logger, true);
}
return (logger, false);
}
fn handle_remove_curse(ecs: &mut World, event: &mut EventInfo, mut logger: gamelog::Logger) -> (gamelog::Logger, bool) {
fn handle_remove_curse(
ecs: &mut World,
event: &mut EventInfo,
mut logger: gamelog::Logger
) -> (gamelog::Logger, bool) {
if let Some(_r) = ecs.read_storage::<ProvidesRemoveCurse>().get(event.entity) {
let mut to_decurse: Vec<Entity> = Vec::new();
match event.buc {
@ -338,7 +396,9 @@ fn handle_remove_curse(ecs: &mut World, event: &mut EventInfo, mut logger: gamel
&ecs.read_storage::<Beatitude>(),
)
.join()
.filter(|(_e, _i, bp, b)| bp.owner == event.source.unwrap() && b.buc == BUC::Cursed) {
.filter(
|(_e, _i, bp, b)| bp.owner == event.source.unwrap() && b.buc == BUC::Cursed
) {
to_decurse.push(entity);
}
}
@ -367,7 +427,9 @@ fn handle_remove_curse(ecs: &mut World, event: &mut EventInfo, mut logger: gamel
}
let mut beatitudes = ecs.write_storage::<Beatitude>();
for e in to_decurse {
beatitudes.insert(e, Beatitude { buc: BUC::Uncursed, known: true }).expect("Unable to insert beatitude");
beatitudes
.insert(e, Beatitude { buc: BUC::Uncursed, known: true })
.expect("Unable to insert beatitude");
}
logger = logger.append(REMOVECURSE).buc(event.buc.clone(), None, Some(REMOVECURSE_BLESSED));
event.log = true;

View file

@ -1,6 +1,6 @@
use super::{ append_entry, LogFragment };
use crate::BUC;
use rltk::prelude::*;
use bracket_lib::prelude::*;
pub struct Logger {
current_colour: RGB,
@ -10,7 +10,7 @@ pub struct Logger {
impl Logger {
/// Creates a blank builder for making message log entries.
pub fn new() -> Self {
Logger { current_colour: RGB::named(rltk::WHITE), fragments: Vec::new() }
Logger { current_colour: RGB::named(WHITE), fragments: Vec::new() }
}
/// Sets the colour of the current message logger.
@ -42,11 +42,23 @@ impl Logger {
pub fn buc<T: ToString>(mut self, buc: BUC, cursed: Option<T>, blessed: Option<T>) -> Self {
if buc == BUC::Cursed && cursed.is_some() {
self.fragments.push(LogFragment { colour: RGB::named(SALMON), text: cursed.unwrap().to_string() });
self.fragments.push(LogFragment { colour: self.current_colour, text: ". ".to_string() });
self.fragments.push(LogFragment {
colour: RGB::named(SALMON),
text: cursed.unwrap().to_string(),
});
self.fragments.push(LogFragment {
colour: self.current_colour,
text: ". ".to_string(),
});
} else if buc == BUC::Blessed && blessed.is_some() {
self.fragments.push(LogFragment { colour: RGB::named(CYAN), text: blessed.unwrap().to_string() });
self.fragments.push(LogFragment { colour: self.current_colour, text: ". ".to_string() });
self.fragments.push(LogFragment {
colour: RGB::named(CYAN),
text: blessed.unwrap().to_string(),
});
self.fragments.push(LogFragment {
colour: self.current_colour,
text: ". ".to_string(),
});
}
return self;
}

View file

@ -5,7 +5,7 @@ use crate::data::names::*;
lazy_static! {
/// A count of each event that has happened over the run. i.e. "turns", "descended", "ascended"
static ref EVENT_COUNTER: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
pub static ref EVENT_COUNTER: Mutex<HashMap<String, i32>> = Mutex::new(HashMap::new());
// A record of events that happened on a given turn. i.e. "Advanced to level 2".
pub static ref EVENTS: Mutex<HashMap<u32, Vec<String>>> = Mutex::new(HashMap::new());
// A record of floors visited, and monsters killed. Used to determine if an event is significant.
@ -41,8 +41,9 @@ pub fn restore_events(events: HashMap<u32, Vec<String>>) {
}
/// Wipes all events - for starting a new game.
pub fn clear_events() {
EVENT_COUNTER.lock().unwrap().clear();
EVENTS.lock().unwrap().clear();
let (mut events, mut event_counts) = (EVENTS.lock().unwrap(), EVENT_COUNTER.lock().unwrap());
events.clear();
event_counts.clear();
}
#[allow(unused_mut)]
@ -73,12 +74,12 @@ pub fn record_event(event: EVENT) {
let mut new_event: String = "unknown event".to_string();
let mut significant_event = true;
match event {
EVENT::TURN(n) => {
EVENT::Turn(n) => {
modify_event_count(EVENT::COUNT_TURN, n);
significant_event = false;
}
// If de-levelling is ever implemented, this needs refactoring (along with a lot of stuff).
EVENT::LEVEL(n) => {
EVENT::Level(n) => {
modify_event_count(EVENT::COUNT_LEVEL, n);
let new_lvl = get_event_count(EVENT::COUNT_LEVEL);
if new_lvl == 1 {
@ -87,7 +88,7 @@ pub fn record_event(event: EVENT) {
new_event = format!("Advanced to level {}", new_lvl);
}
}
EVENT::CHANGED_FLOOR(n) => {
EVENT::ChangedFloor(n) => {
modify_event_count(EVENT::COUNT_CHANGED_FLOOR, 1);
if VISITED.lock().unwrap().contains(&n) {
significant_event = false;
@ -96,23 +97,23 @@ pub fn record_event(event: EVENT) {
new_event = format!("Visited {} for the first time", n);
}
}
EVENT::KICKED_SOMETHING(n) => {
EVENT::KickedSomething(n) => {
modify_event_count(EVENT::COUNT_KICK, n);
significant_event = false;
}
EVENT::BROKE_DOOR(n) => {
EVENT::BrokeDoor(n) => {
modify_event_count(EVENT::COUNT_BROKE_DOOR, n);
significant_event = false;
}
EVENT::PLAYER_CONFUSED(n) => {
EVENT::PlayerConfused(n) => {
modify_event_count(EVENT::COUNT_PLAYER_CONFUSED, n);
significant_event = false;
}
EVENT::LOOKED_FOR_HELP(n) => {
EVENT::LookedForHelp(n) => {
modify_event_count(EVENT::COUNT_LOOKED_FOR_HELP, n);
significant_event = false;
}
EVENT::KILLED(name) => {
EVENT::Killed(name) => {
modify_event_count(EVENT::COUNT_KILLED, 1);
if KILLED.lock().unwrap().contains(&name) {
significant_event = false;
@ -121,13 +122,13 @@ pub fn record_event(event: EVENT) {
new_event = format!("Killed your first {}", name);
}
}
EVENT::DISCOVERED(name) => {
EVENT::Discovered(name) => {
new_event = format!("Discovered {}", name);
}
EVENT::IDENTIFIED(name) => {
EVENT::Identified(name) => {
new_event = format!("Identified {}", name);
}
EVENT::PLAYER_DIED(str) => {
EVENT::PlayerDied(str) => {
// Generating the String is handled in the death effect, to avoid passing the ecs here.
new_event = format!("{}", str);
}

View file

@ -1,5 +1,5 @@
use super::{ events, LogFragment, Logger };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use std::sync::Mutex;
lazy_static! {
@ -19,7 +19,13 @@ pub fn clear_log() {
LOG.lock().unwrap().clear();
}
pub fn print_log(console: &mut Box<dyn Console>, pos: Point, _descending: bool, len: usize, maximum_len: i32) {
pub fn print_log(
console: &mut Box<dyn Console>,
pos: Point,
_descending: bool,
len: usize,
maximum_len: i32
) {
let mut y = pos.y;
let mut x = pos.x;
// Reverse the log, take the number we want to show, and iterate through them
@ -61,7 +67,13 @@ pub fn print_log(console: &mut Box<dyn Console>, pos: Point, _descending: bool,
}
// Stay within bounds
if y > pos.y - (len as i32) {
console.print_color(x, y, frag.colour.into(), RGB::named(rltk::BLACK).into(), part);
console.print_color(
x,
y,
frag.colour.into(),
RGB::named(BLACK).into(),
part
);
}
x += part.len() as i32;
}
@ -80,7 +92,7 @@ pub fn setup_log() {
Logger::new()
.append("Welcome!")
.colour(rltk::CYAN)
.colour(CYAN)
.append_n("Press [?] at any time to view controls")
.period()
.log();

View file

@ -7,7 +7,7 @@ mod events;
pub use events::*;
use serde::{ Deserialize, Serialize };
use rltk::prelude::*;
use bracket_lib::prelude::*;
#[derive(Serialize, Deserialize, Clone)]
pub struct LogFragment {
pub colour: RGB,

View file

@ -2,7 +2,7 @@ use super::{ Skill, Skills };
use crate::gui::{ Ancestry, Class };
use crate::data::entity;
use crate::data::char_create::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use std::cmp::max;
/// Returns the attribute bonus for a given attribute score, where every 2 points above
@ -12,13 +12,13 @@ pub fn attr_bonus(value: i32) -> i32 {
}
/// Returns the number of HP gained per level for a given constitution score.
pub fn hp_per_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32) -> i32 {
pub fn hp_per_level(rng: &mut RandomNumberGenerator, constitution: i32) -> i32 {
return max(rng.roll_dice(1, entity::STANDARD_HIT_DIE) + attr_bonus(constitution), 1);
}
#[allow(dead_code)]
/// Returns a total HP roll for a player, based on a given constitution score and level.
pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
pub fn player_hp_at_level(rng: &mut RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
let mut total = entity::STANDARD_HIT_DIE + attr_bonus(constitution);
for _i in 0..level {
total += hp_per_level(rng, constitution);
@ -27,7 +27,7 @@ pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i
}
/// Returns a total HP roll for an NPC, based on a given constitution score and level.
pub fn npc_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
pub fn npc_hp_at_level(rng: &mut RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
if level == 0 {
return rng.roll_dice(1, entity::STANDARD_HIT_DIE_0);
}
@ -39,12 +39,12 @@ pub fn npc_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32,
}
/// Returns the number of mana gained per level for a given intelligence score.
pub fn mana_per_level(rng: &mut rltk::RandomNumberGenerator, intelligence: i32) -> i32 {
pub fn mana_per_level(rng: &mut RandomNumberGenerator, intelligence: i32) -> i32 {
return max(rng.roll_dice(1, entity::STANDARD_MANA_DIE) + attr_bonus(intelligence), 1);
}
/// Returns the number of mana gained per level for a given intelligence score.
pub fn mana_at_level(rng: &mut rltk::RandomNumberGenerator, intelligence: i32, level: i32) -> i32 {
pub fn mana_at_level(rng: &mut RandomNumberGenerator, intelligence: i32, level: i32) -> i32 {
let mut total = entity::MINIMUM_MANA;
for _i in 0..level {
total += mana_per_level(rng, intelligence);
@ -63,7 +63,7 @@ pub fn skill_bonus(skill: Skill, skills: &Skills) -> i32 {
/// Roll 4d6 and drop the lowest, for rolling d20-style stats
#[allow(unused)]
pub fn roll_4d6(rng: &mut rltk::RandomNumberGenerator) -> i32 {
pub fn roll_4d6(rng: &mut RandomNumberGenerator) -> i32 {
let mut rolls: Vec<i32> = Vec::new();
for _i in 0..4 {
rolls.push(rng.roll_dice(1, 6));

View file

@ -24,7 +24,7 @@ use crate::{
Telepath,
BUC,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use serde::{ Deserialize, Serialize };
use specs::prelude::*;
use std::collections::HashMap;
@ -119,7 +119,7 @@ pub fn character_creation(gs: &mut State, ctx: &mut Rltk) -> CharCreateResult {
let mut y = 11;
let column_width = 20;
ctx.print_color(x, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), CHAR_CREATE_HEADER);
ctx.print_color(x, y, RGB::named(WHITE), RGB::named(BLACK), CHAR_CREATE_HEADER);
y += 2;
if let RunState::CharacterCreation { ancestry, class } = *runstate {
@ -271,9 +271,9 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
Ancestry::Dwarf => {
renderables
.insert(*player, Renderable {
glyph: rltk::to_cp437(DWARF_GLYPH),
glyph: to_cp437(DWARF_GLYPH),
fg: RGB::named(DWARF_COLOUR),
bg: RGB::named(rltk::BLACK),
bg: RGB::named(BLACK),
render_order: 0,
})
.expect("Unable to insert renderable component");
@ -282,9 +282,9 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
Ancestry::Elf => {
renderables
.insert(*player, Renderable {
glyph: rltk::to_cp437(ELF_GLYPH),
glyph: to_cp437(ELF_GLYPH),
fg: RGB::named(ELF_COLOUR),
bg: RGB::named(rltk::BLACK),
bg: RGB::named(BLACK),
render_order: 0,
})
.expect("Unable to insert renderable component");
@ -307,9 +307,9 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
Ancestry::Catfolk => {
renderables
.insert(*player, Renderable {
glyph: rltk::to_cp437(CATFOLK_GLYPH),
glyph: to_cp437(CATFOLK_GLYPH),
fg: RGB::named(CATFOLK_COLOUR),
bg: RGB::named(rltk::BLACK),
bg: RGB::named(BLACK),
render_order: 0,
})
.expect("Unable to insert renderable component");
@ -453,11 +453,11 @@ fn pick_random_table_item(
rng: &mut RandomNumberGenerator,
push_to: &mut Vec<String>,
table: &'static str,
dice: &'static str,
dice_str: &'static str,
difficulty: Option<i32>
) {
let (n, d, m) = raws::parse_dice_string(dice);
for _i in 0..rng.roll_dice(n, d) + m {
let dice = parse_dice_string(dice_str).expect("Error parsing dice");
for _i in 0..rng.roll_dice(dice.n_dice, dice.die_type) + dice.bonus {
push_to.push(raws::table_by_name(&raws::RAWS.lock().unwrap(), table, difficulty).roll(rng));
}
}

View file

@ -1,5 +1,5 @@
use super::State;
use rltk::prelude::*;
use bracket_lib::prelude::*;
#[derive(PartialEq, Copy, Clone)]
pub enum CheatMenuResult {
@ -12,13 +12,13 @@ pub enum CheatMenuResult {
GodMode,
}
pub fn show_cheat_menu(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult {
pub fn show_cheat_menu(_gs: &mut State, ctx: &mut BTerm) -> CheatMenuResult {
let (x_offset, y_offset) = (1, 10);
ctx.print_color(
1 + x_offset,
1 + y_offset,
RGB::named(rltk::RED),
RGB::named(rltk::BLACK),
RGB::named(RED),
RGB::named(BLACK),
"DEBUG MENU! [aA-zZ][Esc.]"
);
let x = 1 + x_offset;
@ -26,26 +26,26 @@ pub fn show_cheat_menu(_gs: &mut State, ctx: &mut Rltk) -> CheatMenuResult {
let count = 5;
let width = 19;
ctx.draw_box(x, y, width, (count + 1) as i32, RGB::named(rltk::RED), RGB::named(rltk::BLACK));
ctx.draw_box(x, y, width, (count + 1) as i32, RGB::named(RED), RGB::named(BLACK));
y += 1;
// Asc
ctx.set(x_offset + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), rltk::to_cp437('a'));
ctx.set(x_offset + 2, y, RGB::named(YELLOW), RGB::named(BLACK), to_cp437('a'));
ctx.print(x_offset + 4, y, "ASCEND A FLOOR");
y += 1;
// Desc
ctx.set(x_offset + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), rltk::to_cp437('d'));
ctx.set(x_offset + 2, y, RGB::named(YELLOW), RGB::named(BLACK), to_cp437('d'));
ctx.print(x_offset + 4, y, "DESCEND A FLOOR");
y += 1;
// Heal
ctx.set(x_offset + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), rltk::to_cp437('h'));
ctx.set(x_offset + 2, y, RGB::named(YELLOW), RGB::named(BLACK), to_cp437('h'));
ctx.print(x_offset + 4, y, "HEAL TO FULL");
y += 1;
// Reveal map
ctx.set(x_offset + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), rltk::to_cp437('m'));
ctx.set(x_offset + 2, y, RGB::named(YELLOW), RGB::named(BLACK), to_cp437('m'));
ctx.print(x_offset + 4, y, "MAGIC MAP REVEAL");
y += 1;
// Godmode
ctx.set(x_offset + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), rltk::to_cp437('g'));
ctx.set(x_offset + 2, y, RGB::named(YELLOW), RGB::named(BLACK), to_cp437('g'));
ctx.print(x_offset + 4, y, "GOD MODE");
// Match keys
match ctx.key {

View file

@ -1,5 +1,5 @@
use super::{ State, RunState, tooltip::draw_tooltips, camera::get_screen_bounds };
use rltk::prelude::*;
use bracket_lib::prelude::*;
#[derive(PartialEq, Copy, Clone)]
pub enum FarlookResult {
@ -10,7 +10,7 @@ pub enum FarlookResult {
Cancel,
}
pub fn show_farlook(gs: &mut State, ctx: &mut Rltk) -> FarlookResult {
pub fn show_farlook(gs: &mut State, ctx: &mut BTerm) -> FarlookResult {
let runstate = gs.ecs.fetch::<RunState>();
let (_min_x, _max_x, _min_y, _max_y, x_offset, y_offset) = get_screen_bounds(&gs.ecs, ctx);
@ -27,7 +27,7 @@ pub fn show_farlook(gs: &mut State, ctx: &mut Rltk) -> FarlookResult {
let x = x.clamp(x_offset, x_offset - 1 + (screen_x as i32));
let y = y.clamp(y_offset, y_offset - 1 + (screen_y as i32));
ctx.set(x, y, RGB::named(WHITE), RGB::named(BLACK), rltk::to_cp437('X'));
ctx.set(x, y, RGB::named(WHITE), RGB::named(BLACK), to_cp437('X'));
draw_tooltips(&gs.ecs, ctx, Some((x, y)));
return match ctx.key {

View file

@ -21,12 +21,12 @@ use crate::{
Renderable,
states::state::*,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::collections::BTreeMap;
/// Handles the Identify menu.
pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
let player_entity = gs.ecs.fetch::<Entity>();
let equipped = gs.ecs.read_storage::<Equipped>();
let backpack = gs.ecs.read_storage::<InBackpack>();
@ -58,7 +58,8 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
}
// If not obfuscated, or already identified, return false.
if
(!obfuscated.get(*item_entity).is_some() || dm.identified_items.contains(&n.name)) &&
(!obfuscated.get(*item_entity).is_some() ||
dm.identified_items.contains(&n.name)) &&
beatitudes
.get(*item_entity)
.map(|beatitude| beatitude.known)
@ -93,7 +94,9 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
let mut player_inventory: super::PlayerInventory = BTreeMap::new();
for (entity, _i, renderable, name) in build_identify_iterator() {
let (singular, plural) = obfuscate_name_ecs(&gs.ecs, entity);
let beatitude_status = if let Some(beatitude) = gs.ecs.read_storage::<Beatitude>().get(entity) {
let beatitude_status = if
let Some(beatitude) = gs.ecs.read_storage::<Beatitude>().get(entity)
{
match beatitude.buc {
BUC::Blessed => 1,
BUC::Uncursed => 2,
@ -125,8 +128,8 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
ctx.print_color(
1 + x_offset,
1 + y_offset,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
"Identify which item? [aA-zZ][Esc.]"
);
ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK));
@ -138,7 +141,7 @@ pub fn identify(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entit
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => {
let selection = rltk::letter_to_option(key);
let selection = letter_to_option(key);
if selection > -1 && selection < (count as i32) {
let item = player_inventory
.iter()

View file

@ -1,4 +1,4 @@
use rltk::prelude::*;
use bracket_lib::prelude::*;
pub fn letter_to_option(key: VirtualKeyCode, shift: bool) -> i32 {
if shift {

View file

@ -62,9 +62,9 @@ pub use farlook::*;
/// Gives a popup box with a message and a title, and waits for a keypress.
#[allow(unused)]
pub fn yes_no(ctx: &mut Rltk, question: String) -> Option<bool> {
ctx.print_color_centered(15, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), question);
ctx.print_color_centered(17, RGB::named(rltk::CYAN), RGB::named(rltk::BLACK), "(y)es or (n)o");
pub fn yes_no(ctx: &mut BTerm, question: String) -> Option<bool> {
ctx.print_color_centered(15, RGB::named(YELLOW), RGB::named(BLACK), question);
ctx.print_color_centered(17, RGB::named(CYAN), RGB::named(BLACK), "(y)es or (n)o");
match ctx.key {
None => None,
Some(key) =>
@ -77,7 +77,7 @@ pub fn yes_no(ctx: &mut Rltk, question: String) -> Option<bool> {
}
pub fn draw_lerping_bar(
ctx: &mut Rltk,
ctx: &mut BTerm,
sx: i32,
sy: i32,
width: i32,
@ -181,8 +181,8 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
ctx.print_color(
26 * TEXT_FONT_MOD,
54,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
format!("XP{}/{}", stats.level, stats.xp)
);
// Draw attributes
@ -327,7 +327,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
}
// Draw equipment
let renderables = ecs.read_storage::<Renderable>();
let mut equipment: Vec<(String, RGB, RGB, rltk::FontCharType)> = Vec::new();
let mut equipment: Vec<(String, RGB, RGB, FontCharType)> = Vec::new();
let entities = ecs.entities();
for (entity, _equipped, renderable) in (&entities, &equipped, &renderables)
.join()
@ -472,7 +472,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
let (render_fg, glyph) = if let Some(renderable) = renderables.get(entity) {
(renderable.fg, renderable.glyph)
} else {
(RGB::named(rltk::WHITE), rltk::to_cp437('-'))
(RGB::named(WHITE), to_cp437('-'))
};
seen_entities.push((
obfuscate_name_ecs(ecs, entity).0,
@ -587,7 +587,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
pub fn get_input_direction(
ecs: &mut World,
ctx: &mut Rltk,
ctx: &mut BTerm,
function: fn(i: i32, j: i32, ecs: &mut World) -> RunState
) -> RunState {
let (_, _, _, _, x_offset, y_offset) = camera::get_screen_bounds(ecs, ctx);
@ -595,8 +595,8 @@ pub fn get_input_direction(
ctx.print_color(
1 + x_offset,
1 + y_offset,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
"In what direction? [0-9]/[YUHJKLBN]"
);
match ctx.key {
@ -681,14 +681,14 @@ pub fn print_options(
x += 2;
let fg = RGB::from_u8(item.renderables.0, item.renderables.1, item.renderables.2);
ctx.set(x, y, fg, RGB::named(rltk::BLACK), item.glyph);
ctx.set(x, y, fg, RGB::named(BLACK), item.glyph);
x += 2;
let fg = RGB::from_u8(item.rgb.0, item.rgb.1, item.rgb.2);
if item_count > &1 {
// If more than one, print the number and pluralise
// i.e. (a) 3 daggers
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), item_count);
ctx.print_color(x, y, fg, RGB::named(BLACK), item_count);
x += 2;
ctx.print_color(
x,
@ -701,7 +701,7 @@ pub fn print_options(
width = if width > this_width { width } else { this_width };
} else {
if item.display_name.singular.to_lowercase().ends_with("s") {
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "some");
ctx.print_color(x, y, fg, RGB::named(BLACK), "some");
x += 5;
} else if
['a', 'e', 'i', 'o', 'u']
@ -710,12 +710,12 @@ pub fn print_options(
{
// If one and starts with a vowel, print 'an'
// i.e. (a) an apple
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "an");
ctx.print_color(x, y, fg, RGB::named(BLACK), "an");
x += 3;
} else {
// If one and not a vowel, print 'a'
// i.e. (a) a dagger
ctx.print_color(x, y, fg, RGB::named(rltk::BLACK), "a");
ctx.print_color(x, y, fg, RGB::named(BLACK), "a");
x += 2;
}
ctx.print_color(
@ -951,7 +951,7 @@ pub fn item_colour(item: Entity, beatitudes: &ReadStorage<Beatitude>) -> (u8, u8
return WHITE;
}
pub fn show_help(ctx: &mut Rltk) -> YesNoResult {
pub fn show_help(ctx: &mut BTerm) -> YesNoResult {
let mut x = 3;
let mut y = 12;
let height = 22;
@ -967,7 +967,7 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult {
);
x += 2;
y += 2;
ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "MOVE COMMANDS");
ctx.print_color(x, y, RGB::named(GREEN), RGB::named(BLACK), "MOVE COMMANDS");
y += 2;
ctx.print(x, y, "y k u 7 8 9 > down");
ctx.print(x, y + 1, " \\|/ \\|/");
@ -975,7 +975,7 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult {
ctx.print(x, y + 3, " /|\\ /|\\");
ctx.print(x, y + 4, "b j n 1 2 3 . wait");
y += 7;
ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "OBJECT INTERACTION");
ctx.print_color(x, y, RGB::named(GREEN), RGB::named(BLACK), "OBJECT INTERACTION");
y += 2;
ctx.print(x, y, "g get d drop");
y += 1;
@ -985,7 +985,7 @@ pub fn show_help(ctx: &mut Rltk) -> YesNoResult {
y += 1;
ctx.print(x, y, "f force x farlook");
y += 2;
ctx.print_color(x, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "MOUSE CONTROL");
ctx.print_color(x, y, RGB::named(GREEN), RGB::named(BLACK), "MOUSE CONTROL");
y += 2;
ctx.print(x, y, "hover for tooltips");
@ -1139,7 +1139,7 @@ pub fn show_inventory(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
}
}
pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
let player_inventory = get_player_inventory(&gs.ecs);
let count = player_inventory.len();
@ -1179,7 +1179,7 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => {
let selection = rltk::letter_to_option(key);
let selection = letter_to_option(key);
if selection > -1 && selection < (count as i32) {
if on_overmap {
gamelog::Logger
@ -1204,7 +1204,7 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option
}
}
pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
pub fn remove_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
let player_entity = gs.ecs.fetch::<Entity>();
let backpack = gs.ecs.read_storage::<Equipped>();
let entities = gs.ecs.entities();
@ -1216,8 +1216,8 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
ctx.print_color(
1 + x_offset,
1 + y_offset,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
"Unequip what? [aA-zZ][Esc.]"
);
@ -1235,7 +1235,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
let x = 1 + x_offset;
let mut y = 3 + y_offset;
ctx.draw_box(x, y, width, (count + 1) as i32, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK));
ctx.draw_box(x, y, width, (count + 1) as i32, RGB::named(WHITE), RGB::named(BLACK));
y += 1;
let mut j = 0;
@ -1244,7 +1244,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
let (mut fg, glyph) = if let Some(renderable) = renderables.get(*e) {
(renderable.fg, renderable.glyph)
} else {
(RGB::named(rltk::WHITE), rltk::to_cp437('-'))
(RGB::named(WHITE), to_cp437('-'))
};
ctx.set(
x + 1,
@ -1255,7 +1255,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
);
ctx.set(x + 3, y, fg, RGB::named(rltk::BLACK), glyph);
fg = RGB::named(item_colour_ecs(&gs.ecs, *e));
ctx.print_color(x + 5, y, fg, RGB::named(rltk::BLACK), name);
ctx.print_color(x + 5, y, fg, RGB::named(BLACK), name);
y += 1;
j += 1;
}
@ -1266,7 +1266,7 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Opti
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => {
let selection = rltk::letter_to_option(key);
let selection = letter_to_option(key);
if selection > -1 && selection < (count as i32) {
return (ItemMenuResult::Selected, Some(equippable[selection as usize].0));
}
@ -1288,7 +1288,7 @@ pub enum TargetResult {
pub fn ranged_target(
gs: &mut State,
ctx: &mut Rltk,
ctx: &mut BTerm,
x: i32,
y: i32,
range: i32,
@ -1302,8 +1302,8 @@ pub fn ranged_target(
ctx.print_color(
1 + x_offset,
1 + y_offset,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
"Targeting which tile? [mouse input]"
);
@ -1313,7 +1313,7 @@ pub fn ranged_target(
if let Some(visible) = visible {
// We have a viewshed
for idx in visible.visible_tiles.iter() {
let distance = rltk::DistanceAlg::Pythagoras.distance2d(*player_pos, *idx);
let distance = DistanceAlg::Pythagoras.distance2d(*player_pos, *idx);
if distance <= (range as f32) {
let screen_x = idx.x - min_x;
let screen_y = idx.y - min_y;
@ -1354,7 +1354,7 @@ pub fn ranged_target(
}
let mut result = (TargetResult::NoResponse { x, y }, None);
if valid_target {
let path = rltk::line2d(
let path = line2d(
LineAlg::Bresenham,
Point::new(player_pos.x, player_pos.y),
Point::new(mouse_pos_adjusted.0, mouse_pos_adjusted.1)
@ -1374,7 +1374,7 @@ pub fn ranged_target(
if aoe > 0 {
// We adjust for camera position when getting FOV, but then we need to adjust back
// when iterating through the tiles themselves, by taking away min_x/min_y.
let mut blast_tiles = rltk::field_of_view(
let mut blast_tiles = field_of_view(
Point::new(mouse_pos_adjusted.0, mouse_pos_adjusted.1),
aoe,
&*map
@ -1411,7 +1411,7 @@ pub fn ranged_target(
}
};
} else {
ctx.set_bg(mouse_pos.0, mouse_pos.1, RGB::named(rltk::RED));
ctx.set_bg(mouse_pos.0, mouse_pos.1, RGB::named(RED));
}
result = match ctx.key {
@ -1450,7 +1450,7 @@ pub enum MainMenuResult {
},
}
pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
pub fn main_menu(gs: &mut State, ctx: &mut BTerm) -> MainMenuResult {
let save_exists = super::saveload_system::does_save_exist();
let runstate = gs.ecs.fetch::<RunState>();
let assets = gs.ecs.fetch::<RexAssets>();
@ -1464,8 +1464,8 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
height -= 1;
}
ctx.draw_box_double(x, y - 4, 13, height, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK));
ctx.print_color(x + 3, y - 2, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "RUST-RL!");
ctx.draw_box_double(x, y - 4, 13, height, RGB::named(WHITE), RGB::named(BLACK));
ctx.print_color(x + 3, y - 2, RGB::named(YELLOW), RGB::named(BLACK), "RUST-RL!");
if let RunState::MainMenu { menu_selection: selection } = *runstate {
if save_exists {
@ -1491,19 +1491,19 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
y += 1;
}
if selection == MainMenuSelection::NewGame {
ctx.print_color(x + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "[");
ctx.print_color(x + 3, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "new game");
ctx.print_color(x + 11, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "]");
ctx.print_color(x + 2, y, RGB::named(YELLOW), RGB::named(BLACK), "[");
ctx.print_color(x + 3, y, RGB::named(GREEN), RGB::named(BLACK), "new game");
ctx.print_color(x + 11, y, RGB::named(YELLOW), RGB::named(BLACK), "]");
} else {
ctx.print_color(x + 3, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "new game");
ctx.print_color(x + 3, y, RGB::named(WHITE), RGB::named(BLACK), "new game");
}
y += 1;
if selection == MainMenuSelection::Quit {
ctx.print_color(x + 2, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "[");
ctx.print_color(x + 3, y, RGB::named(rltk::GREEN), RGB::named(rltk::BLACK), "goodbye!");
ctx.print_color(x + 11, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "]");
ctx.print_color(x + 2, y, RGB::named(YELLOW), RGB::named(BLACK), "[");
ctx.print_color(x + 3, y, RGB::named(GREEN), RGB::named(BLACK), "goodbye!");
ctx.print_color(x + 11, y, RGB::named(YELLOW), RGB::named(BLACK), "]");
} else {
ctx.print_color(x + 5, y, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "quit");
ctx.print_color(x + 5, y, RGB::named(WHITE), RGB::named(BLACK), "quit");
}
match ctx.key {
@ -1578,18 +1578,18 @@ pub enum YesNoResult {
No,
}
pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
pub fn game_over(ctx: &mut BTerm) -> YesNoResult {
let mut x = 3;
let mut y = 12;
let width = 45;
let height = 20;
ctx.draw_box(x, y, width, height, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK));
ctx.print_color(x + 3, y, RGB::named(rltk::YELLOW), RGB::named(rltk::BLACK), "You died!");
ctx.draw_box(x, y, width, height, RGB::named(WHITE), RGB::named(BLACK));
ctx.print_color(x + 3, y, RGB::named(YELLOW), RGB::named(BLACK), "You died!");
ctx.print_color(
x + 3,
y + height,
RGB::named(rltk::YELLOW),
RGB::named(rltk::BLACK),
RGB::named(YELLOW),
RGB::named(BLACK),
" Write a morgue file? [y/n] "
);
x += 2;
@ -1597,8 +1597,8 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
ctx.print_color(
x,
y,
RGB::named(rltk::GREEN),
RGB::named(rltk::BLACK),
RGB::named(GREEN),
RGB::named(BLACK),
format!("You survived for {} turns.", crate::gamelog::get_event_count(EVENT::COUNT_TURN))
);
y += 2;
@ -1627,8 +1627,8 @@ pub fn game_over(ctx: &mut Rltk) -> YesNoResult {
ctx.print_color(
x + 1,
y,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
format!(
"- kicked {} time(s), breaking {} object(s)",
crate::gamelog::get_event_count(EVENT::COUNT_KICK),

View file

@ -7,13 +7,24 @@ use super::{
ItemMenuResult,
UniqueInventoryItem,
};
use crate::{ gamelog, Beatitude, Entity, Equipped, InBackpack, Item, Name, Renderable, states::state::*, BUC };
use rltk::prelude::*;
use crate::{
gamelog,
Beatitude,
Entity,
Equipped,
InBackpack,
Item,
Name,
Renderable,
states::state::*,
BUC,
};
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::collections::BTreeMap;
/// Handles the Remove Curse menu.
pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<Entity>) {
pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Entity>) {
let player_entity = gs.ecs.fetch::<Entity>();
let equipped = gs.ecs.read_storage::<Equipped>();
let backpack = gs.ecs.read_storage::<InBackpack>();
@ -24,33 +35,35 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
let renderables = gs.ecs.read_storage::<Renderable>();
let build_cursed_iterator = || {
(&entities, &items, &beatitudes, &renderables, &names).join().filter(|(item_entity, _i, b, _r, _n)| {
// Set all items to FALSE initially.
let mut keep = false;
// If found in the player's backpack, set to TRUE
if let Some(bp) = backpack.get(*item_entity) {
if bp.owner == *player_entity {
keep = true;
(&entities, &items, &beatitudes, &renderables, &names)
.join()
.filter(|(item_entity, _i, b, _r, _n)| {
// Set all items to FALSE initially.
let mut keep = false;
// If found in the player's backpack, set to TRUE
if let Some(bp) = backpack.get(*item_entity) {
if bp.owner == *player_entity {
keep = true;
}
}
}
// If found in the player's equipslot, set to TRUE
if let Some(equip) = equipped.get(*item_entity) {
if equip.owner == *player_entity {
keep = true;
// If found in the player's equipslot, set to TRUE
if let Some(equip) = equipped.get(*item_entity) {
if equip.owner == *player_entity {
keep = true;
}
}
}
// If it's not OUR item, RETURN FALSE.
if !keep {
return false;
}
// If it's identified as noncursed, RETURN FALSE.
if b.known && b.buc != BUC::Cursed {
return false;
}
// Otherwise, return: returns any items that are unidentified,
// or identified as being cursed.
return true;
})
// If it's not OUR item, RETURN FALSE.
if !keep {
return false;
}
// If it's identified as noncursed, RETURN FALSE.
if b.known && b.buc != BUC::Cursed {
return false;
}
// Otherwise, return: returns any items that are unidentified,
// or identified as being cursed.
return true;
})
};
// Build list of items to display
@ -76,7 +89,9 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
let mut player_inventory: super::PlayerInventory = BTreeMap::new();
for (entity, _i, _b, renderable, name) in build_cursed_iterator() {
let (singular, plural) = obfuscate_name_ecs(&gs.ecs, entity);
let beatitude_status = if let Some(beatitude) = gs.ecs.read_storage::<Beatitude>().get(entity) {
let beatitude_status = if
let Some(beatitude) = gs.ecs.read_storage::<Beatitude>().get(entity)
{
match beatitude.buc {
BUC::Blessed => 1,
BUC::Uncursed => 2,
@ -108,8 +123,8 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
ctx.print_color(
1 + x_offset,
1 + y_offset,
RGB::named(rltk::WHITE),
RGB::named(rltk::BLACK),
RGB::named(WHITE),
RGB::named(BLACK),
"Decurse which item? [aA-zZ][Esc.]"
);
ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK));
@ -121,7 +136,7 @@ pub fn remove_curse(gs: &mut State, ctx: &mut Rltk) -> (ItemMenuResult, Option<E
match key {
VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None),
_ => {
let selection = rltk::letter_to_option(key);
let selection = letter_to_option(key);
if selection > -1 && selection < (count as i32) {
let item = player_inventory
.iter()

View file

@ -7,13 +7,12 @@ use super::{
Pools,
Position,
Renderable,
Rltk,
World,
RGB,
};
use crate::TileType;
use crate::data::ids::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
struct Tooltip {
@ -63,7 +62,7 @@ impl Tooltip {
}
#[rustfmt::skip]
pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk, xy: Option<(i32, i32)>) {
pub fn draw_tooltips(ecs: &World, ctx: &mut BTerm, xy: Option<(i32, i32)>) {
let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(ecs, ctx);
let map = ecs.fetch::<Map>();
let names = ecs.read_storage::<Name>();
@ -164,7 +163,7 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk, xy: Option<(i32, i32)>) {
if tooltips.is_empty() { return ; }
let white = RGB::named(rltk::WHITE);
let white = RGB::named(WHITE);
let arrow;
let arrow_x;

View file

@ -1,5 +1,14 @@
use super::{ effects::{ add_effect, EffectType, Targets }, gamelog, Clock, HungerClock, HungerState, TakingTurn };
use rltk::prelude::*;
use super::{
effects::{ add_effect, EffectType, Targets },
gamelog,
Clock,
HungerClock,
HungerState,
TakingTurn,
DamageType,
Intrinsics,
};
use bracket_lib::prelude::*;
use specs::prelude::*;
use crate::config::CONFIG;
@ -45,10 +54,11 @@ impl<'a> System<'a> for HungerSystem {
ReadExpect<'a, Entity>,
ReadStorage<'a, Clock>,
ReadStorage<'a, TakingTurn>,
ReadStorage<'a, Intrinsics>,
);
fn run(&mut self, data: Self::SystemData) {
let (entities, mut hunger_clock, player_entity, turn_clock, turns) = data;
let (entities, mut hunger_clock, player_entity, turn_clock, turns, intrinsics) = data;
// If the turn clock isn't taking a turn this tick, don't bother ticking hunger.
let mut ticked = false;
@ -64,16 +74,32 @@ impl<'a> System<'a> for HungerSystem {
if hunger_clock.duration >= MAX_SATIATION {
hunger_clock.duration = MAX_SATIATION;
} else {
hunger_clock.duration -= BASE_CLOCK_DECREMENT_PER_TURN;
let mut modifier = 0;
let intrinsic_regen = if let Some(i) = intrinsics.get(entity) {
i.list.contains(&crate::Intrinsic::Regeneration)
} else {
false
};
if intrinsic_regen {
modifier += 1;
}
hunger_clock.duration -= BASE_CLOCK_DECREMENT_PER_TURN + modifier;
}
let initial_state = hunger_clock.state;
hunger_clock.state = get_hunger_state(hunger_clock.duration);
if hunger_clock.state == HungerState::Starving {
add_effect(None, EffectType::Damage { amount: 1 }, Targets::Entity { target: entity });
add_effect(
None,
EffectType::Damage { amount: 1, damage_type: DamageType::Forced },
Targets::Entity { target: entity }
);
}
if CONFIG.logging.log_ticks && entity == *player_entity {
rltk::console::log(
format!("HUNGER SYSTEM: Ticked for player entity. [clock: {}]", hunger_clock.duration)
console::log(
format!(
"HUNGER SYSTEM: Ticked for player entity. [clock: {}]",
hunger_clock.duration
)
);
}
if hunger_clock.state == initial_state {

View file

@ -12,10 +12,10 @@ use crate::{
ObfuscatedName,
Position,
WantsToPickupItem,
Renderable,
};
use specs::prelude::*;
use crate::data::messages;
use bracket_lib::prelude::*;
pub struct ItemCollectionSystem {}
@ -52,7 +52,9 @@ impl<'a> System<'a> for ItemCollectionSystem {
for pickup in wants_pickup.join() {
positions.remove(pickup.item);
backpack.insert(pickup.item, InBackpack { owner: pickup.collected_by }).expect("Unable to pickup item.");
backpack
.insert(pickup.item, InBackpack { owner: pickup.collected_by })
.expect("Unable to pickup item.");
equipment_changed
.insert(pickup.collected_by, EquipmentChanged {})
.expect("Unable to insert EquipmentChanged.");
@ -76,7 +78,7 @@ impl<'a> System<'a> for ItemCollectionSystem {
).0
)
)
.colour(rltk::WHITE)
.colour(WHITE)
.period()
.log();
}

View file

@ -15,6 +15,7 @@ use crate::{
};
use specs::prelude::*;
use crate::data::messages;
use bracket_lib::prelude::*;
pub struct ItemDropSystem {}
@ -52,7 +53,9 @@ impl<'a> System<'a> for ItemDropSystem {
) = data;
for (entity, to_drop) in (&entities, &wants_drop).join() {
equipment_changed.insert(entity, EquipmentChanged {}).expect("Unable to insert EquipmentChanged.");
equipment_changed
.insert(entity, EquipmentChanged {})
.expect("Unable to insert EquipmentChanged.");
let mut dropper_pos: Position = Position { x: 0, y: 0 };
{
let dropped_pos = positions.get(entity).unwrap();
@ -83,7 +86,7 @@ impl<'a> System<'a> for ItemDropSystem {
).0
)
)
.colour(rltk::WHITE)
.colour(WHITE)
.period()
.log();
}

View file

@ -17,6 +17,7 @@ use crate::{
};
use specs::prelude::*;
use crate::data::messages;
use bracket_lib::prelude::*;
pub struct ItemEquipSystem {}
@ -66,7 +67,11 @@ impl<'a> System<'a> for ItemEquipSystem {
// Remove any items target has in item's slot
let mut can_equip = true;
let mut to_unequip: Vec<Entity> = Vec::new();
for (item_entity, already_equipped, _name) in (&entities, &equipped, &names).join() {
for (item_entity, already_equipped, _name) in (
&entities,
&equipped,
&names,
).join() {
if already_equipped.owner == target && already_equipped.slot == target_slot {
if let Some(beatitude) = beatitudes.get(item_entity) {
if beatitude.buc == BUC::Cursed {
@ -85,7 +90,7 @@ impl<'a> System<'a> for ItemEquipSystem {
None
).0
)
.colour(rltk::WHITE)
.colour(WHITE)
.append("!");
identified_beatitude
.insert(item_entity, IdentifiedBeatitude {})
@ -101,15 +106,25 @@ impl<'a> System<'a> for ItemEquipSystem {
}
for item in to_unequip.iter() {
equipped.remove(*item);
backpack.insert(*item, InBackpack { owner: target }).expect("Unable to insert backpack");
backpack
.insert(*item, InBackpack { owner: target })
.expect("Unable to insert backpack");
if target == *player_entity {
logger = logger
.append(messages::YOU_REMOVE_ITEM)
.colour(item_colour(*item, &beatitudes))
.append_n(
obfuscate_name(*item, &names, &magic_items, &obfuscated_names, &beatitudes, &dm, None).0
obfuscate_name(
*item,
&names,
&magic_items,
&obfuscated_names,
&beatitudes,
&dm,
None
).0
)
.colour(rltk::WHITE)
.colour(WHITE)
.period();
}
}
@ -134,7 +149,7 @@ impl<'a> System<'a> for ItemEquipSystem {
None
).0
)
.colour(rltk::WHITE)
.colour(WHITE)
.period();
logger.log();
identified_items

View file

@ -1,4 +1,13 @@
use crate::{ Beatitude, IdentifiedBeatitude, IdentifiedItem, Item, MasterDungeonMap, Name, ObfuscatedName, Player };
use crate::{
Beatitude,
IdentifiedBeatitude,
IdentifiedItem,
Item,
MasterDungeonMap,
Name,
ObfuscatedName,
Player,
};
use specs::prelude::*;
use crate::data::events::*;
use crate::gamelog;
@ -35,7 +44,7 @@ impl<'a> System<'a> for ItemIdentificationSystem {
let tag = crate::raws::get_id_from_name(id.name.clone());
if !dm.identified_items.contains(&id.name) && crate::raws::is_tag_magic(&tag) {
if gamelog::get_event_count(EVENT::COUNT_TURN) != 1 {
gamelog::record_event(EVENT::IDENTIFIED(id.name.clone()));
gamelog::record_event(EVENT::Identified(id.name.clone()));
}
dm.identified_items.insert(id.name.clone());
for (entity, _item, name) in (&entities, &items, &names).join() {

View file

@ -11,7 +11,7 @@ use crate::{
WantsToRemoveItem,
BUC,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
use crate::data::messages;
@ -99,7 +99,9 @@ impl<'a> System<'a> for ItemRemoveSystem {
.log();
}
}
backpack.insert(to_remove.item, InBackpack { owner: entity }).expect("Unable to insert backpack");
backpack
.insert(to_remove.item, InBackpack { owner: entity })
.expect("Unable to insert backpack");
}
wants_remove.clear();

View file

@ -1,7 +1,7 @@
// src/lib.rs
// 31-Aug-2023
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
extern crate serde;

View file

@ -1,12 +1,12 @@
use rust_rl::*;
use specs::prelude::*;
use specs::saveload::{ SimpleMarker, SimpleMarkerAllocator };
use rltk::prelude::*;
use bracket_lib::prelude::*;
const DISPLAYWIDTH: i32 = 100;
const DISPLAYHEIGHT: i32 = 56;
fn main() -> rltk::BError {
fn main() -> BError {
// Embedded resources for use in wasm build
const CURSES_16_16_BYTES: &[u8] = include_bytes!("../resources/curses16x16.png");
const CURSES_8_16_BYTES: &[u8] = include_bytes!("../resources/curses8x16.png");
@ -122,6 +122,8 @@ fn main() -> rltk::BError {
gs.ecs.register::<SpawnParticleSimple>();
gs.ecs.register::<SpawnParticleBurst>();
gs.ecs.register::<SpawnParticleLine>();
gs.ecs.register::<HasDamageModifiers>();
gs.ecs.register::<Intrinsics>();
gs.ecs.register::<SimpleMarker<SerializeMe>>();
gs.ecs.register::<SerializationHelper>();
gs.ecs.register::<DMSerializationHelper>();
@ -130,11 +132,11 @@ fn main() -> rltk::BError {
raws::load_raws();
// Insert calls
gs.ecs.insert(rltk::RandomNumberGenerator::new());
gs.ecs.insert(RandomNumberGenerator::new());
gs.ecs.insert(map::MasterDungeonMap::new()); // Master map list
gs.ecs.insert(Map::new(true, 1, 64, 64, 0, "New Map", "N", 0)); // Map
gs.ecs.insert(Point::new(0, 0)); // Player pos
gs.ecs.insert(gui::Ancestry::Dwarf); // ancestry
gs.ecs.insert(gui::Ancestry::Human); // ancestry
let player_entity = spawner::player(&mut gs.ecs, 0, 0);
gs.ecs.insert(player_entity); // Player entity
gs.ecs.insert(RunState::MapGeneration {}); // RunState
@ -142,8 +144,8 @@ fn main() -> rltk::BError {
gs.ecs.insert(rex_assets::RexAssets::new());
gamelog::setup_log();
gamelog::record_event(data::events::EVENT::LEVEL(1));
gamelog::record_event(data::events::EVENT::Level(1));
gs.generate_world_map(1, TileType::Floor);
rltk::main_loop(context, gs)
main_loop(context, gs)
}

View file

@ -1,6 +1,6 @@
use super::{ Map, TileType };
use crate::{ gamelog, map_builders, OtherLevelPosition, Position, Telepath, Viewshed };
use rltk::prelude::*;
use bracket_lib::prelude::*;
use serde::{ Deserialize, Serialize };
use specs::prelude::*;
use std::collections::{ HashMap, HashSet };
@ -61,7 +61,11 @@ impl MasterDungeonMap {
fn make_scroll_name(rng: &mut RandomNumberGenerator) -> String {
let len = 4 + rng.roll_dice(1, 6);
let space_at_i = if len > 6 && rng.roll_dice(1, 2) == 1 { rng.roll_dice(1, len - 6) + 3 } else { -1 };
let space_at_i = if len > 6 && rng.roll_dice(1, 2) == 1 {
rng.roll_dice(1, len - 6) + 3
} else {
-1
};
let offset = rng.roll_dice(1, 2) - 1;
let mut name = "".to_string();
for i in 0..len {
@ -142,7 +146,9 @@ const POTION_ADJECTIVES: &[&str] = &[
fn make_potion_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet<String>) -> String {
loop {
let mut name: String =
POTION_ADJECTIVES[(rng.roll_dice(1, POTION_ADJECTIVES.len() as i32) as usize) - 1].to_string();
POTION_ADJECTIVES[
(rng.roll_dice(1, POTION_ADJECTIVES.len() as i32) as usize) - 1
].to_string();
name += " ";
name += POTION_COLOURS[(rng.roll_dice(1, POTION_COLOURS.len() as i32) as usize) - 1];
name += " potion";
@ -178,7 +184,8 @@ const WAND_TYPES: &[&str] = &[
fn make_wand_name(rng: &mut RandomNumberGenerator, used_names: &mut HashSet<String>) -> String {
loop {
let mut name: String = WAND_TYPES[(rng.roll_dice(1, WAND_TYPES.len() as i32) as usize) - 1].to_string();
let mut name: String =
WAND_TYPES[(rng.roll_dice(1, WAND_TYPES.len() as i32) as usize) - 1].to_string();
name += " wand";
if !used_names.contains(&name) {
@ -227,8 +234,9 @@ fn transition_to_existing_map(ecs: &mut World, new_id: i32, dest_tile: TileType)
}
possible_destinations.push(((map.width * map.height) as usize) / 2); // Centre of map
}
let mut rng = ecs.write_resource::<rltk::RandomNumberGenerator>();
let idx = possible_destinations[(rng.roll_dice(1, possible_destinations.len() as i32) as usize) - 1];
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
let idx =
possible_destinations[(rng.roll_dice(1, possible_destinations.len() as i32) as usize) - 1];
let mut player_position = ecs.write_resource::<Point>();
*player_position = Point::new((idx as i32) % w, (idx as i32) / w);
let mut position_components = ecs.write_storage::<Position>();
@ -253,7 +261,7 @@ fn transition_to_existing_map(ecs: &mut World, new_id: i32, dest_tile: TileType)
}
fn transition_to_new_map(ecs: &mut World, new_id: i32, _dest_tile: TileType) -> Vec<Map> {
let mut rng = ecs.write_resource::<rltk::RandomNumberGenerator>();
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
// Might need this to fallback to 1, but if player
// level isn't found at all, there's a bigger concern
// concern than just this function not working.
@ -346,7 +354,9 @@ pub fn thaw_entities(ecs: &mut World) {
let mut pos_to_delete: Vec<Entity> = Vec::new();
for (entity, pos) in (&entities, &other_positions).join() {
if entity != *player_entity && pos.id == map_id {
positions.insert(entity, Position { x: pos.x, y: pos.y }).expect("Failed to insert OtherLevelPosition");
positions
.insert(entity, Position { x: pos.x, y: pos.y })
.expect("Failed to insert OtherLevelPosition");
pos_to_delete.push(entity);
}
}

View file

@ -1,5 +1,15 @@
use crate::{ config::CONFIG, gamelog, raws, spawner, Clock, Map, RandomNumberGenerator, TakingTurn };
use crate::{
config::CONFIG,
gamelog,
raws,
spawner,
Clock,
Map,
RandomNumberGenerator,
TakingTurn,
};
use specs::prelude::*;
use bracket_lib::prelude::*;
use crate::data::events::*;
const TRY_SPAWN_CHANCE: i32 = 70;
@ -15,7 +25,7 @@ pub fn maybe_map_message(ecs: &mut World) {
{
let clock = ecs.read_storage::<Clock>();
let turns = ecs.read_storage::<TakingTurn>();
let mut rng = ecs.write_resource::<rltk::RandomNumberGenerator>();
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
for (_c, _t) in (&clock, &turns).join() {
if rng.roll_dice(1, FEATURE_MESSAGE_CHANCE) == 1 {
maybe_message = true;
@ -42,7 +52,7 @@ pub fn try_spawn_interval(ecs: &mut World) {
}
let clock = ecs.read_storage::<Clock>();
let turns = ecs.read_storage::<TakingTurn>();
let mut rng = ecs.write_resource::<rltk::RandomNumberGenerator>();
let mut rng = ecs.write_resource::<RandomNumberGenerator>();
for (_c, _t) in (&clock, &turns).join() {
if rng.roll_dice(1, TRY_SPAWN_CHANCE) == 1 {
try_spawn = true;
@ -51,7 +61,7 @@ pub fn try_spawn_interval(ecs: &mut World) {
}
if try_spawn {
if CONFIG.logging.log_spawning {
rltk::console::log("SPAWNINFO: Trying spawn.");
console::log("SPAWNINFO: Trying spawn.");
}
spawn_random_mob_in_free_nonvisible_tile(ecs);
}
@ -61,11 +71,11 @@ fn spawn_random_mob_in_free_nonvisible_tile(ecs: &mut World) {
let map = ecs.fetch::<Map>();
let mut available_tiles = populate_unblocked_nonvisible(&map);
let player_level = gamelog::get_event_count(EVENT::COUNT_LEVEL);
rltk::console::log(player_level);
console::log(player_level);
let difficulty = (map.difficulty + player_level) / 2;
if available_tiles.len() == 0 {
if CONFIG.logging.log_spawning {
rltk::console::log("SPAWNINFO: No free tiles; not spawning anything..");
console::log("SPAWNINFO: No free tiles; not spawning anything..");
}
return;
}
@ -84,7 +94,7 @@ fn spawn_random_mob_in_free_nonvisible_tile(ecs: &mut World) {
// For every idx in the spawn list, spawn mob.
for idx in spawn_locations {
if CONFIG.logging.log_spawning {
rltk::console::log(format!("SPAWNINFO: Spawning {} at {}, {}.", key, idx.0, idx.1));
console::log(format!("SPAWNINFO: Spawning {} at {}, {}.", key, idx.0, idx.1));
}
raws::spawn_named_entity(
&raws::RAWS.lock().unwrap(),
@ -109,8 +119,12 @@ fn populate_unblocked_nonvisible(map: &Map) -> Vec<usize> {
}
/// Picks a random index from a vector of indexes, and removes it from the vector.
fn get_random_idx_from_tiles(rng: &mut rltk::RandomNumberGenerator, area: &mut Vec<usize>) -> usize {
let idx = if area.len() == 1 { 0usize } else { (rng.roll_dice(1, area.len() as i32) - 1) as usize };
fn get_random_idx_from_tiles(rng: &mut RandomNumberGenerator, area: &mut Vec<usize>) -> usize {
let idx = if area.len() == 1 {
0usize
} else {
(rng.roll_dice(1, area.len() as i32) - 1) as usize
};
area.remove(idx);
return area[idx];
}

View file

@ -1,4 +1,4 @@
use rltk::prelude::*;
use bracket_lib::prelude::*;
use serde::{ Deserialize, Serialize };
use std::collections::{ HashSet, HashMap };
mod tiletype;
@ -75,7 +75,7 @@ impl Map {
lit_tiles: vec![true; map_tile_count], // NYI: Light sources. Once those exist, we can set this to false.
telepath_tiles: vec![false; map_tile_count],
colour_offset: vec![((0.0, 0.0, 0.0), (0.0, 0.0, 0.0)); map_tile_count],
additional_fg_offset: rltk::RGB::from_u8(
additional_fg_offset: RGB::from_u8(
BRIGHTEN_FG_COLOUR_BY as u8,
BRIGHTEN_FG_COLOUR_BY as u8,
BRIGHTEN_FG_COLOUR_BY as u8
@ -90,7 +90,7 @@ impl Map {
view_blocked: HashSet::new(),
};
let mut rng = rltk::RandomNumberGenerator::new();
let mut rng = RandomNumberGenerator::new();
for idx in 0..map.colour_offset.len() {
map.colour_offset[idx].0 = (
@ -146,12 +146,12 @@ impl BaseMap for Map {
let w = self.width as usize;
let p1 = Point::new(idx1 % w, idx1 / w);
let p2 = Point::new(idx2 % w, idx2 / w);
rltk::DistanceAlg::Pythagoras.distance2d(p1, p2)
DistanceAlg::Pythagoras.distance2d(p1, p2)
}
/// Evaluate every possible exit from a given tile in a cardinal direction, and return it as a vector.
fn get_available_exits(&self, idx: usize) -> rltk::SmallVec<[(usize, f32); 10]> {
let mut exits = rltk::SmallVec::new();
fn get_available_exits(&self, idx: usize) -> SmallVec<[(usize, f32); 10]> {
let mut exits = SmallVec::new();
let x = (idx as i32) % self.width;
let y = (idx as i32) / self.width;
let w = self.width as usize;

View file

@ -2,7 +2,7 @@ use super::{ Map, Point, TileType };
use crate::data::visuals::*;
use crate::config::CONFIG;
use crate::data::ids::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use std::ops::{ Add, Mul };
/// Gets the renderables for a tile, with darkening/offset/post-processing/etc. Passing a val for "debug" will ignore viewshed.
@ -11,7 +11,7 @@ pub fn get_tile_renderables_for_id(
map: &Map,
other_pos: Option<Point>,
debug: Option<bool>
) -> (rltk::FontCharType, RGB, RGB) {
) -> (FontCharType, RGB, RGB) {
let coloured_bg = CONFIG.visuals.use_coloured_tile_bg;
let (glyph, mut fg, mut bg, fg_offset, bg_offset) = match map.id {
@ -78,8 +78,8 @@ pub fn get_tile_renderables_for_id(
}
#[rustfmt::skip]
pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option<bool>) -> (rltk::FontCharType, RGB, RGB, (i32, i32, i32), (i32, i32, i32)) {
let glyph: rltk::FontCharType;
pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option<bool>) -> (FontCharType, RGB, RGB, (i32, i32, i32), (i32, i32, i32)) {
let glyph: FontCharType;
#[allow(unused_assignments)]
let mut fg: RGB = RGB::new();
#[allow(unused_assignments)]
@ -88,25 +88,25 @@ pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option<bool>)
let mut bg_offsets: (i32, i32, i32) = (-1, -1, -1);
match map.tiles[idx] {
TileType::Floor => { glyph = rltk::to_cp437(FLOOR_GLYPH); fg = RGB::named(FLOOR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = FLOOR_OFFSETS; }
TileType::WoodFloor => { glyph = rltk::to_cp437(WOOD_FLOOR_GLYPH); bg = RGB::named(WOOD_FLOOR_COLOUR); offsets = WOOD_FLOOR_OFFSETS; }
TileType::Fence => { glyph = rltk::to_cp437(FENCE_GLYPH); fg = RGB::named(FENCE_FG_COLOUR); bg = RGB::named(FENCE_COLOUR); offsets = FENCE_OFFSETS; }
TileType::Floor => { glyph = to_cp437(FLOOR_GLYPH); fg = RGB::named(FLOOR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = FLOOR_OFFSETS; }
TileType::WoodFloor => { glyph = to_cp437(WOOD_FLOOR_GLYPH); bg = RGB::named(WOOD_FLOOR_COLOUR); offsets = WOOD_FLOOR_OFFSETS; }
TileType::Fence => { glyph = to_cp437(FENCE_GLYPH); fg = RGB::named(FENCE_FG_COLOUR); bg = RGB::named(FENCE_COLOUR); offsets = FENCE_OFFSETS; }
TileType::Wall => { let x = idx as i32 % map.width; let y = idx as i32 / map.width; glyph = wall_glyph(&*map, x, y, debug); fg = RGB::named(WALL_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = WALL_OFFSETS; bg_offsets = DEFAULT_BG_OFFSETS }
TileType::DownStair => { glyph = rltk::to_cp437(DOWN_STAIR_GLYPH); fg = RGB::named(STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = STAIR_OFFSETS;}
TileType::UpStair => { glyph = rltk::to_cp437(UP_STAIR_GLYPH); fg = RGB::named(STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = STAIR_OFFSETS; }
TileType::Bridge => { glyph = rltk::to_cp437(BRIDGE_GLYPH); bg = RGB::named(BRIDGE_COLOUR); offsets = BRIDGE_OFFSETS; }
TileType::Gravel => { glyph = rltk::to_cp437(GRAVEL_GLYPH); bg = RGB::named(GRAVEL_COLOUR); offsets = GRAVEL_OFFSETS;}
TileType::Road => { glyph = rltk::to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); offsets = ROAD_OFFSETS;}
TileType::Grass => { glyph = rltk::to_cp437(GRASS_GLYPH); bg = RGB::named(GRASS_COLOUR); offsets = GRASS_OFFSETS; }
TileType::Foliage => { glyph = rltk::to_cp437(FOLIAGE_GLYPH); bg = RGB::named(FOLIAGE_COLOUR); offsets = FOLIAGE_OFFSETS; }
TileType::HeavyFoliage => { glyph = rltk::to_cp437(HEAVY_FOLIAGE_GLYPH); bg = RGB::named(HEAVY_FOLIAGE_COLOUR); offsets = HEAVY_FOLIAGE_OFFSETS; }
TileType::Sand => { glyph = rltk::to_cp437(SAND_GLYPH); bg = RGB::named(SAND_COLOUR); offsets = SAND_OFFSETS; }
TileType::ShallowWater => { glyph = rltk::to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); offsets = SHALLOW_WATER_OFFSETS; }
TileType::DeepWater => { glyph = rltk::to_cp437(DEEP_WATER_GLYPH); bg = RGB::named(DEEP_WATER_COLOUR); offsets = DEEP_WATER_OFFSETS; }
TileType::Bars => { glyph = rltk::to_cp437(BARS_GLYPH); fg = RGB::named(BARS_COLOUR); bg = RGB::named(FLOOR_COLOUR); }
TileType::ImpassableMountain => { glyph = rltk::to_cp437(IMPASSABLE_MOUNTAIN_GLYPH); bg = RGB::named(IMPASSABLE_MOUNTAIN_COLOUR); offsets = IMPASSABLE_MOUNTAIN_OFFSETS }
TileType::ToOvermap(_) => { glyph = rltk::to_cp437(TO_OVERMAP_GLYPH); fg = RGB::named(TO_OVERMAP_COLOUR); bg = RGB::named(GRASS_COLOUR); }
TileType::ToLocal(_) => { glyph = rltk::to_cp437(TO_TOWN_GLYPH); fg = RGB::named(TO_TOWN_COLOUR); bg = RGB::named(GRASS_COLOUR); }
TileType::DownStair => { glyph = to_cp437(DOWN_STAIR_GLYPH); fg = RGB::named(STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = STAIR_OFFSETS;}
TileType::UpStair => { glyph = to_cp437(UP_STAIR_GLYPH); fg = RGB::named(STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); offsets = STAIR_OFFSETS; }
TileType::Bridge => { glyph = to_cp437(BRIDGE_GLYPH); bg = RGB::named(BRIDGE_COLOUR); offsets = BRIDGE_OFFSETS; }
TileType::Gravel => { glyph = to_cp437(GRAVEL_GLYPH); bg = RGB::named(GRAVEL_COLOUR); offsets = GRAVEL_OFFSETS;}
TileType::Road => { glyph = to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); offsets = ROAD_OFFSETS;}
TileType::Grass => { glyph = to_cp437(GRASS_GLYPH); bg = RGB::named(GRASS_COLOUR); offsets = GRASS_OFFSETS; }
TileType::Foliage => { glyph = to_cp437(FOLIAGE_GLYPH); bg = RGB::named(FOLIAGE_COLOUR); offsets = FOLIAGE_OFFSETS; }
TileType::HeavyFoliage => { glyph = to_cp437(HEAVY_FOLIAGE_GLYPH); bg = RGB::named(HEAVY_FOLIAGE_COLOUR); offsets = HEAVY_FOLIAGE_OFFSETS; }
TileType::Sand => { glyph = to_cp437(SAND_GLYPH); bg = RGB::named(SAND_COLOUR); offsets = SAND_OFFSETS; }
TileType::ShallowWater => { glyph = to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); offsets = SHALLOW_WATER_OFFSETS; }
TileType::DeepWater => { glyph = to_cp437(DEEP_WATER_GLYPH); bg = RGB::named(DEEP_WATER_COLOUR); offsets = DEEP_WATER_OFFSETS; }
TileType::Bars => { glyph = to_cp437(BARS_GLYPH); fg = RGB::named(BARS_COLOUR); bg = RGB::named(FLOOR_COLOUR); }
TileType::ImpassableMountain => { glyph = to_cp437(IMPASSABLE_MOUNTAIN_GLYPH); bg = RGB::named(IMPASSABLE_MOUNTAIN_COLOUR); offsets = IMPASSABLE_MOUNTAIN_OFFSETS }
TileType::ToOvermap(_) => { glyph = to_cp437(TO_OVERMAP_GLYPH); fg = RGB::named(TO_OVERMAP_COLOUR); bg = RGB::named(GRASS_COLOUR); }
TileType::ToLocal(_) => { glyph = to_cp437(TO_TOWN_GLYPH); fg = RGB::named(TO_TOWN_COLOUR); bg = RGB::named(GRASS_COLOUR); }
}
if bg_offsets == (-1, -1, -1) {
bg_offsets = offsets;
@ -115,7 +115,7 @@ pub fn get_default_theme_renderables(idx: usize, map: &Map, debug: Option<bool>)
}
#[rustfmt::skip]
fn get_forest_theme_renderables(idx:usize, map: &Map, debug: Option<bool>) -> (rltk::FontCharType, RGB, RGB, (i32, i32, i32), (i32, i32, i32)) {
fn get_forest_theme_renderables(idx:usize, map: &Map, debug: Option<bool>) -> (FontCharType, RGB, RGB, (i32, i32, i32), (i32, i32, i32)) {
let glyph;
#[allow(unused_assignments)]
let mut fg = RGB::new();
@ -125,9 +125,9 @@ fn get_forest_theme_renderables(idx:usize, map: &Map, debug: Option<bool>) -> (r
let mut bg_offsets: (i32, i32, i32) = (-1, -1, -1);
match map.tiles[idx] {
TileType::Wall => { glyph = rltk::to_cp437(FOREST_WALL_GLYPH); fg = RGB::named(FOREST_WALL_COLOUR); bg = RGB::named(GRASS_COLOUR); offsets = GRASS_OFFSETS; }
TileType::Road => { glyph = rltk::to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); }
TileType::ShallowWater => { glyph = rltk::to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); offsets = SHALLOW_WATER_OFFSETS; }
TileType::Wall => { glyph = to_cp437(FOREST_WALL_GLYPH); fg = RGB::named(FOREST_WALL_COLOUR); bg = RGB::named(GRASS_COLOUR); offsets = GRASS_OFFSETS; }
TileType::Road => { glyph = to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); }
TileType::ShallowWater => { glyph = to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); offsets = SHALLOW_WATER_OFFSETS; }
_ => { (glyph, fg, _, offsets, _) = get_default_theme_renderables(idx, map, debug); bg = RGB::named(GRASS_COLOUR); bg_offsets = GRASS_OFFSETS; }
}
if bg_offsets == (-1, -1, -1) {
@ -142,7 +142,7 @@ fn is_revealed_and_wall(map: &Map, x: i32, y: i32, debug: Option<bool>) -> bool
(if debug.is_none() { map.revealed_tiles[idx] } else { true })
}
fn wall_glyph(map: &Map, x: i32, y: i32, debug: Option<bool>) -> rltk::FontCharType {
fn wall_glyph(map: &Map, x: i32, y: i32, debug: Option<bool>) -> FontCharType {
if
x < 1 ||
x > map.width - 2 ||
@ -315,15 +315,15 @@ pub fn add_i32_offsets(rgb: RGB, offsets: (f32, f32, f32)) -> RGB {
let g = rgb.g + (offsets.1 as f32) / 255.0;
let b = rgb.b + (offsets.2 as f32) / 255.0;
return rltk::RGB::from_f32(r, g, b);
return RGB::from_f32(r, g, b);
}
pub fn multiply_by_float(rgb: rltk::RGB, offsets: (f32, f32, f32)) -> RGB {
pub fn multiply_by_float(rgb: RGB, offsets: (f32, f32, f32)) -> RGB {
let r = rgb.r * offsets.0;
let g = rgb.g * offsets.1;
let b = rgb.b * offsets.2;
return rltk::RGB::from_f32(r, g, b);
return RGB::from_f32(r, g, b);
}
fn darken_by_distance(pos: Point, other_pos: Point) -> f32 {

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, MetaMapBuilder, Position };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
#[allow(dead_code)]
pub enum XStart {
@ -21,7 +21,7 @@ pub struct AreaStartingPosition {
}
impl MetaMapBuilder for AreaStartingPosition {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -64,15 +64,18 @@ impl AreaStartingPosition {
if crate::tile_walkable(*tiletype) {
available_floors.push((
idx,
rltk::DistanceAlg::PythagorasSquared.distance2d(
rltk::Point::new((idx as i32) % build_data.map.width, (idx as i32) / build_data.map.width),
rltk::Point::new(seed_x, seed_y)
DistanceAlg::PythagorasSquared.distance2d(
Point::new(
(idx as i32) % build_data.map.width,
(idx as i32) / build_data.map.width
),
Point::new(seed_x, seed_y)
),
));
}
}
if available_floors.is_empty() {
panic!("No valid floors to start on");
unreachable!("No valid floors to start on.");
}
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, InitialMapBuilder, Rect, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct BspDungeonBuilder {
rects: Vec<Rect>,
@ -7,7 +7,7 @@ pub struct BspDungeonBuilder {
impl InitialMapBuilder for BspDungeonBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}

View file

@ -1,5 +1,5 @@
use super::{ draw_corridor, BuilderMap, InitialMapBuilder, Rect, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
const MIN_ROOM_SIZE: i32 = 8;
@ -9,7 +9,7 @@ pub struct BspInteriorBuilder {
impl InitialMapBuilder for BspInteriorBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, InitialMapBuilder, MetaMapBuilder, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct CellularAutomataBuilder {
floor_tile: TileType,
@ -7,14 +7,14 @@ pub struct CellularAutomataBuilder {
impl InitialMapBuilder for CellularAutomataBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl MetaMapBuilder for CellularAutomataBuilder {
#[allow(dead_code)]
fn build_map(&mut self, _rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.apply_iteration(build_data);
}
}
@ -69,16 +69,28 @@ impl CellularAutomataBuilder {
if build_data.map.tiles[idx + (build_data.map.width as usize)] == TileType::Wall {
neighbors += 1;
}
if build_data.map.tiles[idx - ((build_data.map.width as usize) - 1)] == TileType::Wall {
if
build_data.map.tiles[idx - ((build_data.map.width as usize) - 1)] ==
TileType::Wall
{
neighbors += 1;
}
if build_data.map.tiles[idx - ((build_data.map.width as usize) + 1)] == TileType::Wall {
if
build_data.map.tiles[idx - ((build_data.map.width as usize) + 1)] ==
TileType::Wall
{
neighbors += 1;
}
if build_data.map.tiles[idx + ((build_data.map.width as usize) - 1)] == TileType::Wall {
if
build_data.map.tiles[idx + ((build_data.map.width as usize) - 1)] ==
TileType::Wall
{
neighbors += 1;
}
if build_data.map.tiles[idx + ((build_data.map.width as usize) + 1)] == TileType::Wall {
if
build_data.map.tiles[idx + ((build_data.map.width as usize) + 1)] ==
TileType::Wall
{
neighbors += 1;
}

View file

@ -1,11 +1,11 @@
use super::{ BuilderMap, MetaMapBuilder, TileType };
use crate::tile_walkable;
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct CullUnreachable {}
impl MetaMapBuilder for CullUnreachable {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -21,7 +21,7 @@ impl CullUnreachable {
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
build_data.map.populate_blocked();
let map_starts: Vec<usize> = vec![start_idx];
let dijkstra_map = rltk::DijkstraMap::new(
let dijkstra_map = DijkstraMap::new(
build_data.map.width as usize,
build_data.map.height as usize,
&map_starts,

View file

@ -1,11 +1,11 @@
use super::{ BuilderMap, MetaMapBuilder, TileType };
use crate::tile_walkable;
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct DistantExit {}
impl MetaMapBuilder for DistantExit {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -21,7 +21,7 @@ impl DistantExit {
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
build_data.map.populate_blocked();
let map_starts: Vec<usize> = vec![start_idx];
let dijkstra_map = rltk::DijkstraMap::new(
let dijkstra_map = DijkstraMap::new(
build_data.map.width as usize,
build_data.map.height as usize,
&map_starts,

View file

@ -1,5 +1,5 @@
use super::{ paint, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, Symmetry, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
#[derive(PartialEq, Copy, Clone)]
#[allow(dead_code)]
@ -18,14 +18,14 @@ pub struct DLABuilder {
impl InitialMapBuilder for DLABuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl MetaMapBuilder for DLABuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -94,7 +94,10 @@ impl DLABuilder {
#[allow(clippy::map_entry)]
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
// Carve a starting seed
let starting_position = Position { x: build_data.map.width / 2, y: build_data.map.height / 2 };
let starting_position = Position {
x: build_data.map.width / 2,
y: build_data.map.height / 2,
};
let start_idx = build_data.map.xy_idx(starting_position.x, starting_position.y);
build_data.take_snapshot();
build_data.map.tiles[start_idx] = TileType::Floor;
@ -189,10 +192,10 @@ impl DLABuilder {
let mut prev_y = digger_y;
let mut digger_idx = build_data.map.xy_idx(digger_x, digger_y);
let mut path = rltk::line2d(
rltk::LineAlg::Bresenham,
rltk::Point::new(digger_x, digger_y),
rltk::Point::new(starting_position.x, starting_position.y)
let mut path = line2d(
LineAlg::Bresenham,
Point::new(digger_x, digger_y),
Point::new(starting_position.x, starting_position.y)
);
while build_data.map.tiles[digger_idx] == TileType::Wall && !path.is_empty() {

View file

@ -1,11 +1,11 @@
use super::{ BuilderMap, MetaMapBuilder, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct DoorPlacement {}
impl MetaMapBuilder for DoorPlacement {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.doors(rng, build_data);
}
}
@ -30,7 +30,11 @@ impl DoorPlacement {
// There are no corridors - scan for possible places
let tiles = build_data.map.tiles.clone();
for (i, tile) in tiles.iter().enumerate() {
if *tile == TileType::Floor && self.door_possible(build_data, i) && rng.roll_dice(1, 6) == 1 {
if
*tile == TileType::Floor &&
self.door_possible(build_data, i) &&
rng.roll_dice(1, 6) == 1
{
build_data.spawn_list.push((i, "door".to_string()));
}
}

View file

@ -1,5 +1,5 @@
use super::{ paint, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, Symmetry, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
#[derive(PartialEq, Copy, Clone)]
#[allow(dead_code)]
@ -22,14 +22,14 @@ pub struct DrunkardsWalkBuilder {
impl InitialMapBuilder for DrunkardsWalkBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl MetaMapBuilder for DrunkardsWalkBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -107,7 +107,10 @@ impl DrunkardsWalkBuilder {
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
// Set a central starting point
let starting_position = Position { x: build_data.map.width / 2, y: build_data.map.height / 2 };
let starting_position = Position {
x: build_data.map.width / 2,
y: build_data.map.height / 2,
};
let start_idx = build_data.map.xy_idx(starting_position.x, starting_position.y);
build_data.map.tiles[start_idx] = TileType::Floor;
@ -144,7 +147,13 @@ impl DrunkardsWalkBuilder {
if build_data.map.tiles[drunk_idx] == TileType::Wall {
did_something = true;
}
paint(&mut build_data.map, self.settings.symmetry, self.settings.brush_size, drunk_x, drunk_y);
paint(
&mut build_data.map,
self.settings.symmetry,
self.settings.brush_size,
drunk_x,
drunk_y
);
build_data.map.tiles[drunk_idx] = TileType::DownStair;
let stagger_direction = rng.roll_dice(1, 4);

View file

@ -1,6 +1,6 @@
use super::{ BuilderMap, MetaMapBuilder, TileType };
use crate::tile_walkable;
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct FillEdges {
fill_with: TileType,
@ -9,7 +9,7 @@ pub struct FillEdges {
impl MetaMapBuilder for FillEdges {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.fill_edges(rng, build_data);
}
}

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, MetaMapBuilder, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct Foliage {
start_tile: TileType,
@ -8,7 +8,7 @@ pub struct Foliage {
impl MetaMapBuilder for Foliage {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.apply(rng, build_data);
}
}

View file

@ -11,12 +11,12 @@ use super::{
YStart,
Foliage,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use crate::data::names::*;
pub fn forest_builder(
new_id: i32,
_rng: &mut rltk::RandomNumberGenerator,
_rng: &mut RandomNumberGenerator,
width: i32,
height: i32,
difficulty: i32,
@ -76,7 +76,7 @@ impl RoadExit {
}
}
if available_floors.is_empty() {
panic!("No valid floors to start on.");
unreachable!("No valid floors to start on.");
}
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
let end_x = (available_floors[0].0 as i32) % build_data.map.width;

View file

@ -1,11 +1,11 @@
use super::{ BuilderMap, InitialMapBuilder, Map, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct MazeBuilder {}
impl InitialMapBuilder for MazeBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -75,7 +75,14 @@ struct Grid<'a> {
impl<'a> Grid<'a> {
fn new(width: i32, height: i32, rng: &mut RandomNumberGenerator) -> Grid {
let mut grid = Grid { width, height, cells: Vec::new(), backtrace: Vec::new(), current: 0, rng };
let mut grid = Grid {
width,
height,
cells: Vec::new(),
backtrace: Vec::new(),
current: 0,
rng,
};
for row in 0..height {
for column in 0..width {
@ -122,7 +129,9 @@ impl<'a> Grid<'a> {
if neighbors.len() == 1 {
return Some(neighbors[0]);
} else {
return Some(neighbors[(self.rng.roll_dice(1, neighbors.len() as i32) - 1) as usize]);
return Some(
neighbors[(self.rng.roll_dice(1, neighbors.len() as i32) - 1) as usize]
);
}
}
None
@ -141,7 +150,9 @@ impl<'a> Grid<'a> {
// __lower_part__ __higher_part_
// / \ / \
// --------cell1------ | cell2-----------
let (lower_part, higher_part) = self.cells.split_at_mut(std::cmp::max(self.current, next));
let (lower_part, higher_part) = self.cells.split_at_mut(
std::cmp::max(self.current, next)
);
let cell1 = &mut lower_part[std::cmp::min(self.current, next)];
let cell2 = &mut higher_part[0];
cell1.remove_walls(cell2);

View file

@ -1,4 +1,6 @@
use super::{ spawner, Map, Position, Rect, TileType };
use bracket_lib::prelude::*;
mod bsp_dungeon;
use bsp_dungeon::BspDungeonBuilder;
mod bsp_interior;
@ -68,7 +70,7 @@ use forest::forest_builder;
mod foliage;
use foliage::Foliage;
mod room_themer;
use room_themer::{ Theme, ThemeRooms };
use room_themer::ThemeRooms;
// Shared data to be passed around build chain
pub struct BuilderMap {
@ -135,7 +137,7 @@ impl BuilderChain {
None => {
self.starter = Some(starter);
}
Some(_) => panic!("You can only have one starting builder."),
Some(_) => unreachable!("You can only have one starting builder."),
};
}
@ -143,9 +145,9 @@ impl BuilderChain {
self.builders.push(metabuilder);
}
pub fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator) {
pub fn build_map(&mut self, rng: &mut RandomNumberGenerator) {
match &mut self.starter {
None => panic!("Cannot run a map builder chain without a starting build system"),
None => unreachable!("Cannot run a map builder chain without a starting build system"),
Some(starter) => {
// Build the starting map
starter.build_map(rng, &mut self.build_data);
@ -165,20 +167,20 @@ impl BuilderChain {
spawner::spawn_entity(ecs, &(&entity.0, &entity.1));
}
if CONFIG.logging.log_spawning {
rltk::console::log(format!("DEBUGINFO: SPAWNED ENTITIES = {:?}", spawned_entities));
console::log(format!("DEBUGINFO: SPAWNED ENTITIES = {:?}", spawned_entities));
}
}
}
pub trait InitialMapBuilder {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap);
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap);
}
pub trait MetaMapBuilder {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap);
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap);
}
fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YStart) {
fn random_start_position(rng: &mut RandomNumberGenerator) -> (XStart, YStart) {
let x;
let xroll = rng.roll_dice(1, 3);
match xroll {
@ -210,11 +212,7 @@ fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YSta
(x, y)
}
fn random_room_builder(
rng: &mut rltk::RandomNumberGenerator,
builder: &mut BuilderChain,
end: bool
) {
fn random_room_builder(rng: &mut RandomNumberGenerator, builder: &mut BuilderChain, end: bool) {
let build_roll = rng.roll_dice(1, 3);
// Start with a room builder.
match build_roll {
@ -296,7 +294,7 @@ fn random_room_builder(
}
fn random_shape_builder(
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
builder: &mut BuilderChain,
end: bool
) -> bool {
@ -368,7 +366,7 @@ pub enum BuildType {
pub fn random_builder(
new_id: i32,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
width: i32,
height: i32,
difficulty: i32,
@ -377,7 +375,7 @@ pub fn random_builder(
end: bool,
build_type: BuildType
) -> BuilderChain {
rltk::console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty));
console::log(format!("DEBUGINFO: Building random (ID:{}, DIFF:{})", new_id, difficulty));
let mut builder = BuilderChain::new(
false,
new_id,
@ -441,7 +439,7 @@ pub fn random_builder(
pub fn level_builder(
new_id: i32,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
width: i32,
height: i32,
initial_player_level: i32

View file

@ -1,5 +1,5 @@
use super::{ spawner, BuilderMap, InitialMapBuilder, MetaMapBuilder, Position, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub mod prefab_levels;
pub mod prefab_sections;
pub mod prefab_vaults;
@ -25,14 +25,14 @@ pub struct PrefabBuilder {
}
impl MetaMapBuilder for PrefabBuilder {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl InitialMapBuilder for PrefabBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -65,7 +65,8 @@ impl PrefabBuilder {
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
match self.mode {
PrefabMode::Overmap => self.load_ascii_map(&prefab_levels::OVERMAP, rng, build_data, true),
PrefabMode::Overmap =>
self.load_ascii_map(&prefab_levels::OVERMAP, rng, build_data, true),
PrefabMode::Constant { level } => self.load_ascii_map(&level, rng, build_data, false),
PrefabMode::Sectional { section } => self.apply_sectional(&section, rng, build_data),
PrefabMode::RoomVaults => self.apply_room_vaults(rng, build_data),
@ -73,7 +74,13 @@ impl PrefabBuilder {
build_data.take_snapshot();
}
fn char_to_map(&mut self, ch: char, idx: usize, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
fn char_to_map(
&mut self,
ch: char,
idx: usize,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap
) {
let difficulty = (build_data.map.difficulty + build_data.initial_player_level) / 2;
match ch {
' ' => {
@ -123,7 +130,10 @@ impl PrefabBuilder {
}
'!' => {
build_data.map.tiles[idx] = TileType::Floor;
build_data.spawn_list.push((idx, spawner::potion_table(Some(difficulty)).roll(rng)));
build_data.spawn_list.push((
idx,
spawner::potion_table(Some(difficulty)).roll(rng),
));
}
'/' => {
build_data.map.tiles[idx] = TileType::Floor;
@ -131,14 +141,20 @@ impl PrefabBuilder {
}
'?' => {
build_data.map.tiles[idx] = TileType::Floor;
build_data.spawn_list.push((idx, spawner::scroll_table(Some(difficulty)).roll(rng)));
build_data.spawn_list.push((
idx,
spawner::scroll_table(Some(difficulty)).roll(rng),
));
}
')' => {
build_data.map.tiles[idx] = TileType::Floor;
build_data.spawn_list.push((idx, spawner::equipment_table(Some(difficulty)).roll(rng)));
build_data.spawn_list.push((
idx,
spawner::equipment_table(Some(difficulty)).roll(rng),
));
}
_ => {
rltk::console::log(format!("Unknown glyph '{}' when loading prefab", ch as u8 as char));
console::log(format!("Unknown glyph '{}' when loading prefab", ch as u8 as char));
}
}
}
@ -185,14 +201,19 @@ impl PrefabBuilder {
build_data.map.tiles[idx] = TileType::ToLocal(ID_INFINITE);
}
_ => {
rltk::console::log(format!("Unknown glyph '{}' when loading overmap", ch as u8 as char));
console::log(format!("Unknown glyph '{}' when loading overmap", ch as u8 as char));
}
}
}
#[allow(dead_code)]
fn load_rex_map(&mut self, path: &str, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
let xp_file = rltk::rex::XpFile::from_resource(path).unwrap();
fn load_rex_map(
&mut self,
path: &str,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap
) {
let xp_file = rex::XpFile::from_resource(path).unwrap();
for layer in &xp_file.layers {
for y in 0..layer.height {

View file

@ -1,10 +1,10 @@
use super::{ spawner, BuilderMap, MetaMapBuilder };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct RoomBasedSpawner {}
impl MetaMapBuilder for RoomBasedSpawner {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -27,7 +27,7 @@ impl RoomBasedSpawner {
);
}
} else {
panic!("RoomBasedSpawner only works after rooms have been created");
unreachable!("RoomBasedSpawner tried to run without any rooms.");
}
}
}

View file

@ -1,10 +1,10 @@
use super::{ BuilderMap, MetaMapBuilder, TileType };
use rltk::prelude::*;
use bracket_lib::prelude::*;
pub struct RoomBasedStairs {}
impl MetaMapBuilder for RoomBasedStairs {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -22,7 +22,7 @@ impl RoomBasedStairs {
build_data.map.tiles[stairs_idx] = TileType::DownStair;
build_data.take_snapshot();
} else {
panic!("RoomBasedStairs only works after rooms have been created");
unreachable!("RoomBasedStairs tried to run without any rooms.");
}
}
}

View file

@ -1,10 +1,10 @@
use super::{ BuilderMap, MetaMapBuilder, Position };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct RoomBasedStartingPosition {}
impl MetaMapBuilder for RoomBasedStartingPosition {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -20,7 +20,7 @@ impl RoomBasedStartingPosition {
let start_pos = rooms[0].center();
build_data.starting_position = Some(Position { x: start_pos.x, y: start_pos.y });
} else {
panic!("RoomBasedStartingPosition only works after rooms have been created");
unreachable!("RoomBasedStartingPosition tried to run without any rooms.");
}
}
}

View file

@ -1,10 +1,10 @@
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct RoomCornerRounder {}
impl MetaMapBuilder for RoomCornerRounder {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -42,7 +42,7 @@ impl RoomCornerRounder {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("RoomCornerRounding requires a builder with rooms.");
unreachable!("RoomCornerRounding tried to run without any rooms.");
}
for room in rooms.iter() {

View file

@ -1,10 +1,10 @@
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct RoomDrawer {}
impl MetaMapBuilder for RoomDrawer {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -29,14 +29,11 @@ impl RoomDrawer {
fn circle(&mut self, build_data: &mut BuilderMap, room: &Rect) {
let radius = (i32::min(room.x2 - room.x1, room.y2 - room.y1) as f32) / 2.0;
let center = room.center();
let center_pt = rltk::Point::new(center.x, center.y);
let center_pt = Point::new(center.x, center.y);
for y in room.y1..=room.y2 {
for x in room.x1..=room.x2 {
let idx = build_data.map.xy_idx(x, y);
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
center_pt,
rltk::Point::new(x, y)
);
let distance = DistanceAlg::Pythagoras.distance2d(center_pt, Point::new(x, y));
if
idx > 0 &&
idx < ((build_data.map.width * build_data.map.height - 1) as usize) &&
@ -53,7 +50,7 @@ impl RoomDrawer {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("RoomDrawer require a builder with rooms");
unreachable!("RoomDrawer tried to run without any rooms.");
}
for room in rooms.iter() {

View file

@ -1,10 +1,10 @@
use super::{ paint, BuilderMap, MetaMapBuilder, Rect, Symmetry, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct RoomExploder {}
impl MetaMapBuilder for RoomExploder {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -20,7 +20,7 @@ impl RoomExploder {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("RoomExploder requires a builder with rooms.");
unreachable!("RoomExploder tried to run without any rooms.");
}
for room in rooms.iter() {
let start = room.center();

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, MetaMapBuilder, Rect };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
#[allow(dead_code)]
pub enum RoomSort {
@ -16,7 +16,7 @@ pub struct RoomSorter {
impl MetaMapBuilder for RoomSorter {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.sorter(rng, build_data);
}
}
@ -50,21 +50,18 @@ impl RoomSorter {
.unwrap()
.sort_by(|a, b| b.y2.cmp(&a.y2)),
RoomSort::CENTRAL => {
let map_centre = rltk::Point::new(
build_data.map.width / 2,
build_data.map.height / 2
);
let map_centre = Point::new(build_data.map.width / 2, build_data.map.height / 2);
build_data.rooms
.as_mut()
.unwrap()
.sort_by(|a: &Rect, b: &Rect| {
let a_centre_pt = rltk::Point::new(a.center().x, a.center().y);
let b_centre_pt = rltk::Point::new(b.center().x, b.center().y);
let distance_a = rltk::DistanceAlg::Pythagoras.distance2d(
let a_centre_pt = Point::new(a.center().x, a.center().y);
let b_centre_pt = Point::new(b.center().x, b.center().y);
let distance_a = DistanceAlg::Pythagoras.distance2d(
a_centre_pt,
map_centre
);
let distance_b = rltk::DistanceAlg::Pythagoras.distance2d(
let distance_b = DistanceAlg::Pythagoras.distance2d(
b_centre_pt,
map_centre
);

View file

@ -7,7 +7,7 @@ use crate::data::messages::{
FEATURE_BARRACKS_ORC,
};
use crate::raws;
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
use std::collections::HashSet;
pub enum Theme {
@ -22,7 +22,7 @@ pub struct ThemeRooms {
}
impl MetaMapBuilder for ThemeRooms {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -141,7 +141,7 @@ impl ThemeRooms {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("RoomCornerRounding requires a builder with rooms.");
unreachable!("RoomCornerRounding tried to run without any rooms.");
}
let count = roll_until_fail(rng, self.percent);
@ -173,7 +173,7 @@ fn roll_until_fail(rng: &mut RandomNumberGenerator, target: i32) -> i32 {
loop {
if rng.roll_dice(1, 100) <= target - accumulator {
accumulator += 1;
rltk::console::log(accumulator);
console::log(accumulator);
} else {
break;
}

View file

@ -1,12 +1,12 @@
use super::{ BuilderMap, MetaMapBuilder, Rect, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
use std::collections::HashSet;
pub struct BresenhamCorridors {}
impl MetaMapBuilder for BresenhamCorridors {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.corridors(rng, build_data);
}
}
@ -22,7 +22,7 @@ impl BresenhamCorridors {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("BresenhamCorridors require a builder with room structures");
unreachable!("BresenhamCorridors tried to run without any rooms.");
}
let mut connected: HashSet<usize> = HashSet::new();
@ -30,12 +30,12 @@ impl BresenhamCorridors {
for (i, room) in rooms.iter().enumerate() {
let mut room_distance: Vec<(usize, f32)> = Vec::new();
let room_centre = room.center();
let room_centre_pt = rltk::Point::new(room_centre.x, room_centre.y);
let room_centre_pt = Point::new(room_centre.x, room_centre.y);
for (j, other_room) in rooms.iter().enumerate() {
if i != j && !connected.contains(&j) {
let other_centre = other_room.center();
let other_centre_pt = rltk::Point::new(other_centre.x, other_centre.y);
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
let other_centre_pt = Point::new(other_centre.x, other_centre.y);
let distance = DistanceAlg::Pythagoras.distance2d(
room_centre_pt,
other_centre_pt
);
@ -46,10 +46,10 @@ impl BresenhamCorridors {
if !room_distance.is_empty() {
room_distance.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
let dest_centre = rooms[room_distance[0].0].center();
let line = rltk::line2d(
rltk::LineAlg::Bresenham,
let line = line2d(
LineAlg::Bresenham,
room_centre_pt,
rltk::Point::new(dest_centre.x, dest_centre.y)
Point::new(dest_centre.x, dest_centre.y)
);
let mut corridor = Vec::new();
for cell in line.iter() {

View file

@ -1,11 +1,11 @@
use super::{ draw_corridor, BuilderMap, MetaMapBuilder, Rect };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct BspCorridors {}
impl MetaMapBuilder for BspCorridors {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.corridors(rng, build_data);
}
}
@ -21,7 +21,7 @@ impl BspCorridors {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("BSP Corridors require a builder with room structures");
unreachable!("BSP Corridors tried to run without any rooms.");
}
let mut corridors: Vec<Vec<usize>> = Vec::new();
@ -30,8 +30,10 @@ impl BspCorridors {
let next_room = rooms[i + 1];
let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2)) - 1);
let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2)) - 1);
let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2)) - 1);
let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1);
let end_x =
next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2)) - 1);
let end_y =
next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1);
let corridor = draw_corridor(&mut build_data.map, start_x, start_y, end_x, end_y);
corridors.push(corridor);
build_data.take_snapshot();

View file

@ -1,11 +1,11 @@
use super::{ apply_horizontal_tunnel, apply_vertical_tunnel, BuilderMap, MetaMapBuilder, Rect };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct DoglegCorridors {}
impl MetaMapBuilder for DoglegCorridors {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.corridors(rng, build_data);
}
}
@ -21,7 +21,7 @@ impl DoglegCorridors {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("DoglegCorridors require a builder with rooms.");
unreachable!("DoglegCorridors tried to run without any rooms.");
}
let mut corridors: Vec<Vec<usize>> = Vec::new();

View file

@ -1,12 +1,12 @@
use super::{ draw_corridor, BuilderMap, MetaMapBuilder, Rect };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
use std::collections::HashSet;
pub struct NearestCorridors {}
impl MetaMapBuilder for NearestCorridors {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.corridors(rng, build_data);
}
}
@ -22,7 +22,7 @@ impl NearestCorridors {
if let Some(rooms_builder) = &build_data.rooms {
rooms = rooms_builder.clone();
} else {
panic!("NearestCorridors requires a builder with rooms");
unreachable!("NearestCorridors tried to run without any rooms.");
}
let mut connected: HashSet<usize> = HashSet::new();
@ -30,12 +30,12 @@ impl NearestCorridors {
for (i, room) in rooms.iter().enumerate() {
let mut room_distance: Vec<(usize, f32)> = Vec::new();
let room_centre = room.center();
let room_centre_pt = rltk::Point::new(room_centre.x, room_centre.y);
let room_centre_pt = Point::new(room_centre.x, room_centre.y);
for (j, other_room) in rooms.iter().enumerate() {
if i != j && !connected.contains(&j) {
let other_centre = other_room.center();
let other_centre_pt = rltk::Point::new(other_centre.x, other_centre.y);
let distance = rltk::DistanceAlg::Pythagoras.distance2d(
let other_centre_pt = Point::new(other_centre.x, other_centre.y);
let distance = DistanceAlg::Pythagoras.distance2d(
room_centre_pt,
other_centre_pt
);

View file

@ -1,10 +1,10 @@
use super::{ spawner, BuilderMap, MetaMapBuilder };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct CorridorSpawner {}
impl MetaMapBuilder for CorridorSpawner {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -27,7 +27,7 @@ impl CorridorSpawner {
);
}
} else {
panic!("CorridorSpawner only works after corridors have been created");
unreachable!("CorridorSpawner tried to run without any corridors.");
}
}
}

View file

@ -2,7 +2,7 @@ use super::{
generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant, spawner, Map, MapBuilder,
Position, TileType, SHOW_MAPGEN,
};
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::collections::HashMap;

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, InitialMapBuilder, Rect };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
pub struct SimpleMapBuilder {
room_params: (i32, i32, i32),
@ -7,7 +7,7 @@ pub struct SimpleMapBuilder {
impl InitialMapBuilder for SimpleMapBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build_rooms(rng, build_data);
}
}

View file

@ -1,16 +1,17 @@
use super::{ BuilderChain, BuilderMap, InitialMapBuilder, Position, TileType, FillEdges };
use std::collections::HashSet;
use crate::data::names::*;
use bracket_lib::prelude::*;
pub fn town_builder(
new_id: i32,
_rng: &mut rltk::RandomNumberGenerator,
_rng: &mut RandomNumberGenerator,
width: i32,
height: i32,
difficulty: i32,
initial_player_level: i32
) -> BuilderChain {
rltk::console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty));
console::log(format!("DEBUGINFO: Building town (ID:{}, DIFF:{})", new_id, difficulty));
let mut chain = BuilderChain::new(
false,
new_id,
@ -32,7 +33,7 @@ pub struct TownBuilder {}
impl InitialMapBuilder for TownBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build_map(rng, build_data);
}
}
@ -52,7 +53,7 @@ impl TownBuilder {
return Box::new(TownBuilder {});
}
pub fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
pub fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
// Make visible for snapshot
for t in build_data.map.visible_tiles.iter_mut() {
*t = true;
@ -64,8 +65,20 @@ impl TownBuilder {
let (mut available_building_tiles, wall_gap_y) = self.town_walls(rng, build_data);
let mut buildings = self.buildings(rng, build_data, &mut available_building_tiles);
let doors = self.add_doors(rng, build_data, &mut buildings, wall_gap_y);
self.path_from_tiles_to_nearest_tiletype(build_data, &doors, TileType::Road, TileType::Road, true);
self.path_from_tiles_to_nearest_tiletype(build_data, &piers, TileType::Road, TileType::Road, false);
self.path_from_tiles_to_nearest_tiletype(
build_data,
&doors,
TileType::Road,
TileType::Road,
true
);
self.path_from_tiles_to_nearest_tiletype(
build_data,
&piers,
TileType::Road,
TileType::Road,
false
);
// Spawn entities
let building_size = self.sort_buildings(&buildings);
@ -81,7 +94,10 @@ impl TownBuilder {
build_data.take_snapshot();
}
fn sort_buildings(&mut self, buildings: &[(i32, i32, i32, i32)]) -> Vec<(usize, i32, BuildingTag)> {
fn sort_buildings(
&mut self,
buildings: &[(i32, i32, i32, i32)]
) -> Vec<(usize, i32, BuildingTag)> {
// Sort buildings by size, defaulting them to Unassigned buildings
let mut building_size: Vec<(usize, i32, BuildingTag)> = Vec::new();
for (i, building) in buildings.iter().enumerate() {
@ -105,7 +121,7 @@ impl TownBuilder {
fn building_factory(
&mut self,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap,
buildings: &[(i32, i32, i32, i32)],
building_index: &[(usize, i32, BuildingTag)]
@ -124,7 +140,7 @@ impl TownBuilder {
}
}
fn spawn_dockers(&mut self, build_data: &mut BuilderMap, rng: &mut rltk::RandomNumberGenerator) {
fn spawn_dockers(&mut self, build_data: &mut BuilderMap, rng: &mut RandomNumberGenerator) {
for (idx, tt) in build_data.map.tiles.iter().enumerate() {
if *tt == TileType::Bridge && rng.roll_dice(1, 20) == 1 {
let roll = rng.roll_dice(1, 2);
@ -139,7 +155,7 @@ impl TownBuilder {
fn spawn_townsfolk(
&mut self,
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
available_building_tiles: &mut HashSet<usize>
) {
for idx in available_building_tiles.iter() {
@ -176,7 +192,7 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
to_place: &mut Vec<&str>,
avoid_tile: usize
) {
@ -201,9 +217,12 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator
rng: &mut RandomNumberGenerator
) {
let player_idx = build_data.map.xy_idx(building.0 + building.2 / 2, building.1 + building.3 / 2);
let player_idx = build_data.map.xy_idx(
building.0 + building.2 / 2,
building.1 + building.3 / 2
);
// Place other items
let mut to_place: Vec<&str> = vec![
@ -224,7 +243,7 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator
rng: &mut RandomNumberGenerator
) {
let mut to_place: Vec<&str> = vec![
"npc_priest",
@ -244,10 +263,13 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator
rng: &mut RandomNumberGenerator
) {
// Place exit
let exit_idx = build_data.map.xy_idx(building.0 + building.2 / 2, building.1 + building.3 / 2);
let exit_idx = build_data.map.xy_idx(
building.0 + building.2 / 2,
building.1 + building.3 / 2
);
build_data.map.tiles[exit_idx] = TileType::DownStair;
let mut to_place: Vec<&str> = vec!["npc_miner", "npc_miner", "npc_guard", "prop_chair"];
self.random_building_spawn(building, build_data, rng, &mut to_place, exit_idx)
@ -257,9 +279,15 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator
rng: &mut RandomNumberGenerator
) {
let mut to_place: Vec<&str> = vec!["prop_bed", "prop_table", "dog_little", "prop_chair", "prop_chair"];
let mut to_place: Vec<&str> = vec![
"prop_bed",
"prop_table",
"dog_little",
"prop_chair",
"prop_chair"
];
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
}
@ -267,9 +295,14 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator
rng: &mut RandomNumberGenerator
) {
let mut to_place: Vec<&str> = vec!["npc_townsperson", "prop_bed", "prop_table", "prop_chair"];
let mut to_place: Vec<&str> = vec![
"npc_townsperson",
"prop_bed",
"prop_table",
"prop_chair"
];
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
}
@ -277,7 +310,7 @@ impl TownBuilder {
&mut self,
building: &(i32, i32, i32, i32),
build_data: &mut BuilderMap,
rng: &mut rltk::RandomNumberGenerator
rng: &mut RandomNumberGenerator
) {
let mut to_place: Vec<&str> = vec!["rat", "rat", "rat", "prop_table", "prop_chair"];
self.random_building_spawn(building, build_data, rng, &mut to_place, 0);
@ -291,7 +324,11 @@ impl TownBuilder {
build_data.take_snapshot();
}
fn water_and_piers(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) -> Vec<usize> {
fn water_and_piers(
&mut self,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap
) -> Vec<usize> {
let mut n = (rng.roll_dice(1, 65535) as f32) / 65535f32;
let mut water_width: Vec<i32> = Vec::new();
let variance = 5;
@ -300,7 +337,8 @@ impl TownBuilder {
let sand_width = shallow_width + 4;
for y in 0..build_data.height {
let n_water = ((f32::sin(n) * (variance as f32)) as i32) + minimum_width + rng.roll_dice(1, 2);
let n_water =
((f32::sin(n) * (variance as f32)) as i32) + minimum_width + rng.roll_dice(1, 2);
water_width.push(n_water);
n += 0.1;
for x in 0..n_water {
@ -374,7 +412,7 @@ impl TownBuilder {
fn town_walls(
&mut self,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap
) -> (HashSet<usize>, i32) {
let mut available_building_tiles: HashSet<usize> = HashSet::new();
@ -385,7 +423,10 @@ impl TownBuilder {
const HALF_PATH_THICKNESS: i32 = 3;
let wall_gap_y =
build_data.height / 2 + rng.roll_dice(1, PATH_OFFSET_FROM_CENTRE * 2) - 1 - PATH_OFFSET_FROM_CENTRE;
build_data.height / 2 +
rng.roll_dice(1, PATH_OFFSET_FROM_CENTRE * 2) -
1 -
PATH_OFFSET_FROM_CENTRE;
for y in BORDER..build_data.height - BORDER {
if !(y > wall_gap_y - HALF_PATH_THICKNESS && y < wall_gap_y + HALF_PATH_THICKNESS) {
@ -438,7 +479,7 @@ impl TownBuilder {
fn buildings(
&mut self,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap,
available_building_tiles: &mut HashSet<usize>
) -> Vec<(i32, i32, i32, i32)> {
@ -452,7 +493,9 @@ impl TownBuilder {
const MAX_BUILDING_SIZE: i32 = 10;
while n_buildings < REQUIRED_BUILDINGS {
let bx = rng.roll_dice(1, build_data.map.width - OFFSET_FROM_LEFT - BORDER) + OFFSET_FROM_LEFT;
let bx =
rng.roll_dice(1, build_data.map.width - OFFSET_FROM_LEFT - BORDER) +
OFFSET_FROM_LEFT;
let by = rng.roll_dice(1, build_data.map.height) - BORDER;
let bw = rng.roll_dice(1, MAX_BUILDING_SIZE - MIN_BUILDING_SIZE) + MIN_BUILDING_SIZE;
let bh = rng.roll_dice(1, MAX_BUILDING_SIZE - MIN_BUILDING_SIZE) + MIN_BUILDING_SIZE;
@ -500,10 +543,16 @@ impl TownBuilder {
if build_data.map.tiles[idx + 1] != TileType::WoodFloor {
neighbours += 1;
}
if build_data.map.tiles[idx - (build_data.width as usize)] != TileType::WoodFloor {
if
build_data.map.tiles[idx - (build_data.width as usize)] !=
TileType::WoodFloor
{
neighbours += 1;
}
if build_data.map.tiles[idx + (build_data.width as usize)] != TileType::WoodFloor {
if
build_data.map.tiles[idx + (build_data.width as usize)] !=
TileType::WoodFloor
{
neighbours += 1;
}
if neighbours > 0 {
@ -520,7 +569,7 @@ impl TownBuilder {
fn add_doors(
&mut self,
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
build_data: &mut BuilderMap,
buildings: &mut Vec<(i32, i32, i32, i32)>,
wall_gap_y: i32
@ -556,23 +605,26 @@ impl TownBuilder {
build_data.map.populate_blocked();
for tile_idx in tiles.iter() {
let mut nearest_tiletype: Vec<(usize, f32)> = Vec::new();
let tile_pt = rltk::Point::new(
let tile_pt = Point::new(
(*tile_idx as i32) % (build_data.map.width as i32),
(*tile_idx as i32) / (build_data.map.width as i32)
);
for r in roads.iter() {
nearest_tiletype.push((
*r,
rltk::DistanceAlg::Manhattan.distance2d(
DistanceAlg::Manhattan.distance2d(
tile_pt,
rltk::Point::new((*r as i32) % build_data.map.width, (*r as i32) / build_data.map.width)
Point::new(
(*r as i32) % build_data.map.width,
(*r as i32) / build_data.map.width
)
),
));
}
nearest_tiletype.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
let destination = nearest_tiletype[0].0;
let path = rltk::a_star_search(*tile_idx, destination, &mut build_data.map);
let path = a_star_search(*tile_idx, destination, &mut build_data.map);
if path.success {
for step in path.steps.iter() {
let idx = *step as usize;

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, InitialMapBuilder, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
#[derive(PartialEq, Copy, Clone)]
#[allow(dead_code)]
@ -16,7 +16,7 @@ pub struct VoronoiBuilder {
impl InitialMapBuilder for VoronoiBuilder {
#[allow(dead_code)]
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -40,20 +40,21 @@ impl VoronoiBuilder {
#[allow(clippy::map_entry)]
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
// Make a Voronoi diagram. We'll do this the hard way to learn about the technique!
let mut voronoi_seeds: Vec<(usize, rltk::Point)> = Vec::new();
let mut voronoi_seeds: Vec<(usize, Point)> = Vec::new();
while voronoi_seeds.len() < self.n_seeds {
let vx = rng.roll_dice(1, build_data.map.width - 1);
let vy = rng.roll_dice(1, build_data.map.height - 1);
let vidx = build_data.map.xy_idx(vx, vy);
let candidate = (vidx, rltk::Point::new(vx, vy));
let candidate = (vidx, Point::new(vx, vy));
if !voronoi_seeds.contains(&candidate) {
voronoi_seeds.push(candidate);
}
}
let mut voronoi_distance = vec![(0, 0.0f32); self.n_seeds];
let mut voronoi_membership: Vec<i32> = vec![0; build_data.map.width as usize * build_data.map.height as usize];
let mut voronoi_membership: Vec<i32> =
vec![0; build_data.map.width as usize * build_data.map.height as usize];
for (i, vid) in voronoi_membership.iter_mut().enumerate() {
let x = (i as i32) % build_data.map.width;
let y = (i as i32) / build_data.map.width;
@ -62,13 +63,16 @@ impl VoronoiBuilder {
let distance;
match self.distance_algorithm {
DistanceAlgorithm::Pythagoras => {
distance = rltk::DistanceAlg::PythagorasSquared.distance2d(rltk::Point::new(x, y), pos.1);
distance = DistanceAlg::PythagorasSquared.distance2d(
Point::new(x, y),
pos.1
);
}
DistanceAlgorithm::Manhattan => {
distance = rltk::DistanceAlg::Manhattan.distance2d(rltk::Point::new(x, y), pos.1);
distance = DistanceAlg::Manhattan.distance2d(Point::new(x, y), pos.1);
}
DistanceAlgorithm::Chebyshev => {
distance = rltk::DistanceAlg::Chebyshev.distance2d(rltk::Point::new(x, y), pos.1);
distance = DistanceAlg::Chebyshev.distance2d(Point::new(x, y), pos.1);
}
}
voronoi_distance[seed] = (seed, distance);

View file

@ -1,12 +1,12 @@
use super::{ spawner, BuilderMap, MetaMapBuilder, TileType };
use super::{ spawner, BuilderMap, MetaMapBuilder };
use crate::tile_walkable;
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
use std::collections::HashMap;
pub struct VoronoiSpawning {}
impl MetaMapBuilder for VoronoiSpawning {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -20,10 +20,10 @@ impl VoronoiSpawning {
#[allow(clippy::map_entry)]
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
let mut noise_areas: HashMap<i32, Vec<usize>> = HashMap::new();
let mut noise = rltk::FastNoise::seeded(rng.roll_dice(1, 65536) as u64);
noise.set_noise_type(rltk::NoiseType::Cellular);
let mut noise = FastNoise::seeded(rng.roll_dice(1, 65536) as u64);
noise.set_noise_type(NoiseType::Cellular);
noise.set_frequency(0.08);
noise.set_cellular_distance_function(rltk::CellularDistanceFunction::Manhattan);
noise.set_cellular_distance_function(CellularDistanceFunction::Manhattan);
for y in 1..build_data.map.height - 1 {
for x in 1..build_data.map.width - 1 {

View file

@ -1,7 +1,13 @@
use super::{Map, MapChunk, TileType};
use super::{ Map, MapChunk, TileType };
use std::collections::HashSet;
use bracket_lib::prelude::*;
pub fn build_patterns(map: &Map, chunk_size: i32, include_flipping: bool, dedupe: bool) -> Vec<Vec<TileType>> {
pub fn build_patterns(
map: &Map,
chunk_size: i32,
include_flipping: bool,
dedupe: bool
) -> Vec<Vec<TileType>> {
let chunks_x = map.width / chunk_size;
let chunks_y = map.height / chunk_size;
let mut patterns = Vec::new();
@ -49,16 +55,22 @@ pub fn build_patterns(map: &Map, chunk_size: i32, include_flipping: bool, dedupe
// Dedupe
if dedupe {
rltk::console::log(format!("Pre de-duplication, there are {} patterns.", patterns.len()));
console::log(format!("Pre de-duplication, there are {} patterns.", patterns.len()));
let set: HashSet<Vec<TileType>> = patterns.drain(..).collect(); // Dedupes
patterns.extend(set.into_iter());
rltk::console::log(format!("There are {} patterns.", patterns.len()));
console::log(format!("There are {} patterns.", patterns.len()));
}
return patterns;
}
pub fn render_pattern_to_map(map: &mut Map, chunk: &MapChunk, chunk_size: i32, start_x: i32, start_y: i32) {
pub fn render_pattern_to_map(
map: &mut Map,
chunk: &MapChunk,
chunk_size: i32,
start_x: i32,
start_y: i32
) {
let mut i = 0usize;
for tile_y in 0..chunk_size {
for tile_x in 0..chunk_size {
@ -70,25 +82,25 @@ pub fn render_pattern_to_map(map: &mut Map, chunk: &MapChunk, chunk_size: i32, s
}
for (x, northbound) in chunk.exits[0].iter().enumerate() {
if *northbound {
let map_idx = map.xy_idx(start_x + x as i32, start_y);
let map_idx = map.xy_idx(start_x + (x as i32), start_y);
map.tiles[map_idx] = TileType::DownStair;
}
}
for (x, southbound) in chunk.exits[1].iter().enumerate() {
if *southbound {
let map_idx = map.xy_idx(start_x + x as i32, start_y + chunk_size - 1);
let map_idx = map.xy_idx(start_x + (x as i32), start_y + chunk_size - 1);
map.tiles[map_idx] = TileType::DownStair;
}
}
for (x, westbound) in chunk.exits[2].iter().enumerate() {
if *westbound {
let map_idx = map.xy_idx(start_x, start_y + x as i32);
let map_idx = map.xy_idx(start_x, start_y + (x as i32));
map.tiles[map_idx] = TileType::DownStair;
}
}
for (x, eastbound) in chunk.exits[3].iter().enumerate() {
if *eastbound {
let map_idx = map.xy_idx(start_x + chunk_size - 1, start_y + x as i32);
let map_idx = map.xy_idx(start_x + chunk_size - 1, start_y + (x as i32));
map.tiles[map_idx] = TileType::DownStair;
}
}

View file

@ -1,5 +1,5 @@
use super::{ BuilderMap, Map, MetaMapBuilder, TileType };
use rltk::RandomNumberGenerator;
use bracket_lib::prelude::*;
mod common;
use common::*;
mod constraints;
@ -11,7 +11,7 @@ use solver::*;
pub struct WaveFunctionCollapseBuilder {}
impl MetaMapBuilder for WaveFunctionCollapseBuilder {
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
@ -54,7 +54,12 @@ impl WaveFunctionCollapseBuilder {
build_data.spawn_list.clear();
}
fn render_tile_gallery(&mut self, constraints: &[MapChunk], chunk_size: i32, build_data: &mut BuilderMap) {
fn render_tile_gallery(
&mut self,
constraints: &[MapChunk],
chunk_size: i32,
build_data: &mut BuilderMap
) {
build_data.map = Map::new(
false,
0,

View file

@ -1,5 +1,6 @@
use super::{Map, MapChunk};
use super::{ Map, MapChunk };
use std::collections::HashSet;
use bracket_lib::prelude::*;
pub struct Solver {
constraints: Vec<MapChunk>,
@ -16,7 +17,7 @@ impl Solver {
let chunks_x = (map.width / chunk_size) as usize;
let chunks_y = (map.height / chunk_size) as usize;
let mut remaining: Vec<(usize, i32)> = Vec::new();
for i in 0..(chunks_x * chunks_y) {
for i in 0..chunks_x * chunks_y {
remaining.push((i, 0));
}
@ -32,7 +33,7 @@ impl Solver {
}
fn chunk_idx(&self, x: usize, y: usize) -> usize {
return ((y * self.chunks_x) + x) as usize;
return (y * self.chunks_x + x) as usize;
}
fn count_neighbours(&self, chunk_x: usize, chunk_y: usize) -> i32 {
@ -99,8 +100,11 @@ impl Solver {
self.remaining = remain_copy;
// Pick a random chunk we haven't dealt with yet and get its index, remove from remaining list
let remaining_index =
if !neighbours_exist { (rng.roll_dice(1, self.remaining.len() as i32) - 1) as usize } else { 0usize };
let remaining_index = if !neighbours_exist {
(rng.roll_dice(1, self.remaining.len() as i32) - 1) as usize
} else {
0usize
};
let chunk_index = self.remaining[remaining_index].0;
self.remaining.remove(remaining_index);
@ -158,10 +162,10 @@ impl Solver {
// There is nothing nearby, so we can have anything!
let new_chunk_idx = (rng.roll_dice(1, self.constraints.len() as i32) - 1) as usize;
self.chunks[chunk_index] = Some(new_chunk_idx);
let left_x = chunk_x as i32 * self.chunk_size as i32;
let right_x = (chunk_x as i32 + 1) * self.chunk_size as i32;
let top_y = chunk_y as i32 * self.chunk_size as i32;
let bottom_y = (chunk_y as i32 + 1) * self.chunk_size as i32;
let left_x = (chunk_x as i32) * (self.chunk_size as i32);
let right_x = ((chunk_x as i32) + 1) * (self.chunk_size as i32);
let top_y = (chunk_y as i32) * (self.chunk_size as i32);
let bottom_y = ((chunk_y as i32) + 1) * (self.chunk_size as i32);
let mut i: usize = 0;
for y in top_y..bottom_y {
@ -195,18 +199,21 @@ impl Solver {
}
if possible_options.is_empty() {
rltk::console::log("Oh no! It's not possible!");
console::log("Oh no! It's not possible!");
self.possible = false;
return true;
} else {
let new_chunk_idx =
if possible_options.len() == 1 { 0 } else { rng.roll_dice(1, possible_options.len() as i32) - 1 };
let new_chunk_idx = if possible_options.len() == 1 {
0
} else {
rng.roll_dice(1, possible_options.len() as i32) - 1
};
self.chunks[chunk_index] = Some(new_chunk_idx as usize);
let left_x = chunk_x as i32 * self.chunk_size as i32;
let right_x = (chunk_x as i32 + 1) * self.chunk_size as i32;
let top_y = chunk_y as i32 * self.chunk_size as i32;
let bottom_y = (chunk_y as i32 + 1) * self.chunk_size as i32;
let left_x = (chunk_x as i32) * (self.chunk_size as i32);
let right_x = ((chunk_x as i32) + 1) * (self.chunk_size as i32);
let top_y = (chunk_y as i32) * (self.chunk_size as i32);
let bottom_y = ((chunk_y as i32) + 1) * (self.chunk_size as i32);
let mut i: usize = 0;
for y in top_y..bottom_y {

View file

@ -25,7 +25,7 @@ use super::{
WeaponAttribute,
config::CONFIG,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub struct MeleeCombatSystem {}
@ -50,7 +50,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
ReadStorage<'a, HungerClock>,
ReadStorage<'a, MultiAttack>,
ReadStorage<'a, Blind>,
WriteExpect<'a, rltk::RandomNumberGenerator>,
WriteExpect<'a, RandomNumberGenerator>,
);
fn run(&mut self, data: Self::SystemData) {
@ -123,6 +123,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
} else {
attacks.push((
MeleeWeapon {
damage_type: crate::DamageType::Physical,
attribute: WeaponAttribute::Strength,
damage_n_dice: 1,
damage_die_type: 4,
@ -194,7 +195,8 @@ impl<'a> System<'a> for MeleeCombatSystem {
armour_ac_bonus += ac.amount;
}
}
let actual_armour_class = bac - attribute_ac_bonus - skill_ac_bonus - armour_ac_bonus;
let actual_armour_class =
bac - attribute_ac_bonus - skill_ac_bonus - armour_ac_bonus;
let mut armour_class_roll = actual_armour_class;
if actual_armour_class < 0 {
@ -205,13 +207,17 @@ impl<'a> System<'a> for MeleeCombatSystem {
}
// Monster attacks receive a +10 to-hit bonus against the player.
let monster_v_player_bonus = if wants_melee.target == *player_entity { 10 } else { 0 };
let monster_v_player_bonus = if wants_melee.target == *player_entity {
10
} else {
0
};
let target_number = monster_v_player_bonus + armour_class_roll + attacker_bonuses;
let target_name = names.get(wants_melee.target).unwrap();
if CONFIG.logging.log_combat {
rltk::console::log(
console::log(
format!(
"ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} ({} + {}AC + {}to-hit)",
&name.name,
@ -228,8 +234,14 @@ impl<'a> System<'a> for MeleeCombatSystem {
if d20 < target_number {
// Target hit!
let base_damage = rng.roll_dice(weapon_info.damage_n_dice, weapon_info.damage_die_type);
let skill_damage_bonus = gamesystem::skill_bonus(Skill::Melee, &*attacker_skills);
let base_damage = rng.roll_dice(
weapon_info.damage_n_dice,
weapon_info.damage_die_type
);
let skill_damage_bonus = gamesystem::skill_bonus(
Skill::Melee,
&*attacker_skills
);
let mut attribute_damage_bonus = weapon_info.damage_bonus;
match weapon_info.attribute {
WeaponAttribute::Dexterity => {
@ -239,17 +251,23 @@ impl<'a> System<'a> for MeleeCombatSystem {
attribute_damage_bonus += attacker_attributes.strength.bonus;
}
WeaponAttribute::Finesse => {
if attacker_attributes.dexterity.bonus > attacker_attributes.strength.bonus {
if
attacker_attributes.dexterity.bonus >
attacker_attributes.strength.bonus
{
attribute_damage_bonus += attacker_attributes.dexterity.bonus;
} else {
attribute_damage_bonus += attacker_attributes.strength.bonus;
}
}
}
let mut damage = i32::max(0, base_damage + skill_damage_bonus + attribute_damage_bonus);
let mut damage = i32::max(
0,
base_damage + skill_damage_bonus + attribute_damage_bonus
);
if CONFIG.logging.log_combat {
rltk::console::log(
console::log(
format!(
"ATTACKLOG: {} HIT for {} ({}[{}d{}]+{}[skill]+{}[attr])",
&name.name,
@ -267,7 +285,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
let ac_damage_reduction = rng.roll_dice(1, -actual_armour_class);
damage = i32::min(1, damage - ac_damage_reduction);
if CONFIG.logging.log_combat {
rltk::console::log(
console::log(
format!(
"ATTACKLOG: {} reduced their damage taken by {} (1dAC), and took {} hp damage.",
&target_name.name,
@ -284,7 +302,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
}
add_effect(
Some(entity),
EffectType::Damage { amount: damage },
EffectType::Damage { amount: damage, damage_type: weapon_info.damage_type },
Targets::Entity { target: wants_melee.target }
);
if entity == *player_entity {
@ -321,7 +339,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
}
} else {
if CONFIG.logging.log_combat {
rltk::console::log(format!("ATTACKLOG: {} *MISSED*", &name.name));
console::log(format!("ATTACKLOG: {} *MISSED*", &name.name));
}
let pos = positions.get(wants_melee.target);
@ -365,7 +383,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
}
fn get_natural_attacks(
rng: &mut rltk::RandomNumberGenerator,
rng: &mut RandomNumberGenerator,
nat: NaturalAttacks,
multi_attack: bool,
attacks: &mut Vec<(MeleeWeapon, String)>
@ -375,6 +393,7 @@ fn get_natural_attacks(
for a in nat.attacks.iter() {
attacks.push((
MeleeWeapon {
damage_type: a.damage_type,
attribute: WeaponAttribute::Strength,
hit_bonus: a.hit_bonus,
damage_n_dice: a.damage_n_dice,
@ -392,6 +411,7 @@ fn get_natural_attacks(
};
attacks.push((
MeleeWeapon {
damage_type: nat.attacks[attack_index].damage_type,
attribute: WeaponAttribute::Strength,
hit_bonus: nat.attacks[attack_index].hit_bonus,
damage_n_dice: nat.attacks[attack_index].damage_n_dice,

View file

@ -6,8 +6,8 @@ use crate::gamelog;
use crate::components::*;
use crate::gui::{ Class, Ancestry, unobf_name_ecs };
use specs::prelude::*;
use rltk::prelude::*;
use rltk::to_char;
use bracket_lib::prelude::*;
use to_char;
use std::collections::HashMap;
use crate::data::events::*;
@ -49,7 +49,14 @@ fn create_file_name(ecs: &World, morgue_dir: &str) -> String {
Ancestry::Catfolk => "catfolk",
Ancestry::NULL => "NULL",
};
return format!("{}/lv{}-{}-{}-{}.txt", morgue_dir, &pool.level, &ancestry, &class, get_timestamp());
return format!(
"{}/lv{}-{}-{}-{}.txt",
morgue_dir,
&pool.level,
&ancestry,
&class,
get_timestamp()
);
}
fn create_morgue_string(ecs: &World) -> String {
@ -165,7 +172,12 @@ fn draw_map(ecs: &World) -> String {
}
});
} else {
glyph_u16 = crate::map::themes::get_tile_renderables_for_id(idx, &*map, None, Some(true)).0;
glyph_u16 = crate::map::themes::get_tile_renderables_for_id(
idx,
&*map,
None,
Some(true)
).0;
}
let char = to_char((glyph_u16 & 0xff) as u8);
result.push_str(&char.to_string());
@ -201,7 +213,11 @@ fn draw_equipment(ecs: &World) -> String {
EquipmentSlot::Back => "back -",
EquipmentSlot::Neck => "neck -",
};
let name = if item.1 != 1 { unobf_name_ecs(ecs, item.0).1 } else { unobf_name_ecs(ecs, item.0).0 };
let name = if item.1 != 1 {
unobf_name_ecs(ecs, item.0).1
} else {
unobf_name_ecs(ecs, item.0).0
};
result.push_str(&format!("{:>8} {}\n", slot, name));
}
result.push_str("\n");
@ -211,7 +227,11 @@ fn draw_equipment(ecs: &World) -> String {
fn draw_backpack(ecs: &World) -> String {
// Get all of the player's backpack.
let mut pack: HashMap<(String, String), (i32, Entity)> = HashMap::new();
for (entity, _bp, _n) in (&ecs.entities(), &ecs.read_storage::<InBackpack>(), &ecs.read_storage::<Name>())
for (entity, _bp, _n) in (
&ecs.entities(),
&ecs.read_storage::<InBackpack>(),
&ecs.read_storage::<Name>(),
)
.join()
.filter(|item| item.1.owner == *ecs.fetch::<Entity>()) {
pack.entry(unobf_name_ecs(ecs, entity))

View file

@ -1,5 +1,5 @@
use super::{ ParticleLifetime, Position, Renderable, Rltk };
use rltk::RGB;
use super::{ ParticleLifetime, Position, Renderable, BTerm };
use bracket_lib::prelude::*;
use specs::prelude::*;
use crate::data::visuals::{ DEFAULT_PARTICLE_LIFETIME, SHORT_PARTICLE_LIFETIME };
@ -8,12 +8,12 @@ use crate::data::visuals::{ DEFAULT_PARTICLE_LIFETIME, SHORT_PARTICLE_LIFETIME }
// running through a list and removing the frame_time_ms from the
// delay. When delay is <= 0, make a particle_builder.request for
// the particle.
pub fn particle_ticker(ecs: &mut World, ctx: &Rltk) {
pub fn particle_ticker(ecs: &mut World, ctx: &BTerm) {
cull_dead_particles(ecs, ctx);
create_delayed_particles(ecs, ctx);
}
fn cull_dead_particles(ecs: &mut World, ctx: &Rltk) {
fn cull_dead_particles(ecs: &mut World, ctx: &BTerm) {
let mut dead_particles: Vec<Entity> = Vec::new();
{
// Age out particles
@ -39,7 +39,7 @@ pub fn check_queue(ecs: &World) -> bool {
return false;
}
fn create_delayed_particles(ecs: &mut World, ctx: &Rltk) {
fn create_delayed_particles(ecs: &mut World, ctx: &BTerm) {
let mut particle_builder = ecs.write_resource::<ParticleBuilder>();
let mut handled_particles: Vec<ParticleRequest> = Vec::new();
for delayed_particle in particle_builder.delayed_requests.iter_mut() {
@ -76,11 +76,20 @@ fn create_delayed_particles(ecs: &mut World, ctx: &Rltk) {
.unwrap();
particle_builder.delayed_requests.remove(index);
let p = entities.create();
positions.insert(p, Position { x: handled.x, y: handled.y }).expect("Could not insert position");
positions
.insert(p, Position { x: handled.x, y: handled.y })
.expect("Could not insert position");
renderables
.insert(p, Renderable { fg: handled.fg, bg: handled.bg, glyph: handled.glyph, render_order: 0 })
.insert(p, Renderable {
fg: handled.fg,
bg: handled.bg,
glyph: handled.glyph,
render_order: 0,
})
.expect("Could not insert renderables");
particles.insert(p, ParticleLifetime { lifetime_ms: handled.lifetime }).expect("Could not insert lifetime");
particles
.insert(p, ParticleLifetime { lifetime_ms: handled.lifetime })
.expect("Could not insert lifetime");
}
}
@ -90,7 +99,7 @@ pub struct ParticleRequest {
y: i32,
fg: RGB,
bg: RGB,
glyph: rltk::FontCharType,
glyph: FontCharType,
lifetime: f32,
}
@ -112,11 +121,28 @@ impl ParticleBuilder {
}
/// Makes a single particle request.
pub fn request(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32) {
pub fn request(
&mut self,
x: i32,
y: i32,
fg: RGB,
bg: RGB,
glyph: FontCharType,
lifetime: f32
) {
self.requests.push(ParticleRequest { x, y, fg, bg, glyph, lifetime });
}
pub fn delay(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32, delay: f32) {
pub fn delay(
&mut self,
x: i32,
y: i32,
fg: RGB,
bg: RGB,
glyph: FontCharType,
lifetime: f32,
delay: f32
) {
self.delayed_requests.push(DelayedParticleRequest {
delay: delay,
particle: ParticleRequest { x, y, fg, bg, glyph, lifetime },
@ -127,9 +153,9 @@ impl ParticleBuilder {
self.request(
x,
y,
rltk::RGB::named(rltk::ORANGE),
rltk::RGB::named(rltk::BLACK),
rltk::to_cp437('‼'),
RGB::named(ORANGE),
RGB::named(BLACK),
to_cp437('‼'),
DEFAULT_PARTICLE_LIFETIME
);
}
@ -138,9 +164,9 @@ impl ParticleBuilder {
self.request(
x,
y,
rltk::RGB::named(rltk::CYAN),
rltk::RGB::named(rltk::BLACK),
rltk::to_cp437('‼'),
RGB::named(CYAN),
RGB::named(BLACK),
to_cp437('‼'),
DEFAULT_PARTICLE_LIFETIME
);
}
@ -149,9 +175,9 @@ impl ParticleBuilder {
self.request(
x,
y,
rltk::RGB::named(rltk::CHOCOLATE),
rltk::RGB::named(rltk::BLACK),
rltk::to_cp437('‼'),
RGB::named(CHOCOLATE),
RGB::named(BLACK),
to_cp437('‼'),
SHORT_PARTICLE_LIFETIME
);
}
@ -164,57 +190,97 @@ impl ParticleBuilder {
y: i32,
fg: RGB,
bg: RGB,
glyph: rltk::FontCharType,
glyph: FontCharType,
lifetime: f32,
secondary_fg: RGB
) {
let eighth_l = lifetime / 8.0;
let quarter_l = eighth_l * 2.0;
self.request(x, y, fg, bg, glyph, lifetime);
self.delay(x + 1, y + 1, secondary_fg.lerp(bg, 0.8), bg, rltk::to_cp437('/'), quarter_l, eighth_l);
self.delay(x + 1, y - 1, secondary_fg.lerp(bg, 0.6), bg, rltk::to_cp437('\\'), quarter_l, quarter_l);
self.delay(x - 1, y - 1, secondary_fg.lerp(bg, 0.2), bg, rltk::to_cp437('/'), quarter_l, eighth_l * 3.0);
self.delay(x - 1, y + 1, secondary_fg.lerp(bg, 0.4), bg, rltk::to_cp437('\\'), quarter_l, lifetime);
self.delay(
x + 1,
y + 1,
secondary_fg.lerp(bg, 0.8),
bg,
to_cp437('/'),
quarter_l,
eighth_l
);
self.delay(
x + 1,
y - 1,
secondary_fg.lerp(bg, 0.6),
bg,
to_cp437('\\'),
quarter_l,
quarter_l
);
self.delay(
x - 1,
y - 1,
secondary_fg.lerp(bg, 0.2),
bg,
to_cp437('/'),
quarter_l,
eighth_l * 3.0
);
self.delay(
x - 1,
y + 1,
secondary_fg.lerp(bg, 0.4),
bg,
to_cp437('\\'),
quarter_l,
lifetime
);
}
// Makes a rainbow particle request in the shape of an 'x'. Sort of.
#[allow(dead_code)]
pub fn request_rainbow_star(&mut self, x: i32, y: i32, glyph: rltk::FontCharType, lifetime: f32) {
let bg = RGB::named(rltk::BLACK);
pub fn request_rainbow_star(&mut self, x: i32, y: i32, glyph: FontCharType, lifetime: f32) {
let bg = RGB::named(BLACK);
let eighth_l = lifetime / 8.0;
let quarter_l = eighth_l * 2.0;
let half_l = quarter_l * 2.0;
self.request(x, y, RGB::named(rltk::CYAN), bg, glyph, lifetime);
self.delay(x + 1, y + 1, RGB::named(rltk::RED), bg, rltk::to_cp437('\\'), half_l, eighth_l);
self.delay(x + 1, y - 1, RGB::named(rltk::ORANGE), bg, rltk::to_cp437('/'), half_l, quarter_l);
self.delay(x - 1, y - 1, RGB::named(rltk::GREEN), bg, rltk::to_cp437('\\'), half_l, eighth_l * 3.0);
self.delay(x - 1, y + 1, RGB::named(rltk::YELLOW), bg, rltk::to_cp437('/'), half_l, half_l);
self.request(x, y, RGB::named(CYAN), bg, glyph, lifetime);
self.delay(x + 1, y + 1, RGB::named(RED), bg, to_cp437('\\'), half_l, eighth_l);
self.delay(x + 1, y - 1, RGB::named(ORANGE), bg, to_cp437('/'), half_l, quarter_l);
self.delay(x - 1, y - 1, RGB::named(GREEN), bg, to_cp437('\\'), half_l, eighth_l * 3.0);
self.delay(x - 1, y + 1, RGB::named(YELLOW), bg, to_cp437('/'), half_l, half_l);
}
// Makes a rainbow particle request. Sort of.
#[allow(dead_code)]
pub fn request_rainbow(&mut self, x: i32, y: i32, glyph: rltk::FontCharType, lifetime: f32) {
let bg = RGB::named(rltk::BLACK);
pub fn request_rainbow(&mut self, x: i32, y: i32, glyph: FontCharType, lifetime: f32) {
let bg = RGB::named(BLACK);
let eighth_l = lifetime / 8.0;
self.request(x, y, RGB::named(rltk::RED), bg, glyph, eighth_l);
self.delay(x, y, RGB::named(rltk::ORANGE), bg, glyph, eighth_l, eighth_l);
self.delay(x, y, RGB::named(rltk::YELLOW), bg, glyph, eighth_l, eighth_l * 2.0);
self.delay(x, y, RGB::named(rltk::GREEN), bg, glyph, eighth_l, eighth_l * 3.0);
self.delay(x, y, RGB::named(rltk::BLUE), bg, glyph, eighth_l, eighth_l * 4.0);
self.delay(x, y, RGB::named(rltk::INDIGO), bg, glyph, eighth_l, eighth_l * 5.0);
self.delay(x, y, RGB::named(rltk::VIOLET), bg, glyph, eighth_l, eighth_l * 6.0);
self.request(x, y, RGB::named(RED), bg, glyph, eighth_l);
self.delay(x, y, RGB::named(ORANGE), bg, glyph, eighth_l, eighth_l);
self.delay(x, y, RGB::named(YELLOW), bg, glyph, eighth_l, eighth_l * 2.0);
self.delay(x, y, RGB::named(GREEN), bg, glyph, eighth_l, eighth_l * 3.0);
self.delay(x, y, RGB::named(BLUE), bg, glyph, eighth_l, eighth_l * 4.0);
self.delay(x, y, RGB::named(INDIGO), bg, glyph, eighth_l, eighth_l * 5.0);
self.delay(x, y, RGB::named(VIOLET), bg, glyph, eighth_l, eighth_l * 6.0);
}
/// Makes a particle request in the shape of a +.
#[allow(dead_code)]
pub fn request_plus(&mut self, x: i32, y: i32, fg: RGB, bg: RGB, glyph: rltk::FontCharType, lifetime: f32) {
pub fn request_plus(
&mut self,
x: i32,
y: i32,
fg: RGB,
bg: RGB,
glyph: FontCharType,
lifetime: f32
) {
self.request(x, y, fg, bg, glyph, lifetime * 2.0);
self.request(x + 1, y, fg, bg, rltk::to_cp437('─'), lifetime);
self.request(x - 1, y, fg, bg, rltk::to_cp437('─'), lifetime);
self.request(x, y + 1, fg, bg, rltk::to_cp437('│'), lifetime);
self.request(x, y - 1, fg, bg, rltk::to_cp437('│'), lifetime);
self.request(x + 1, y, fg, bg, to_cp437('─'), lifetime);
self.request(x - 1, y, fg, bg, to_cp437('─'), lifetime);
self.request(x, y + 1, fg, bg, to_cp437('│'), lifetime);
self.request(x, y - 1, fg, bg, to_cp437('│'), lifetime);
}
}
@ -235,7 +301,9 @@ impl<'a> System<'a> for ParticleSpawnSystem {
for new_particle in particle_builder.requests.iter() {
let p = entities.create();
positions.insert(p, Position { x: new_particle.x, y: new_particle.y }).expect("Could not insert position");
positions
.insert(p, Position { x: new_particle.x, y: new_particle.y })
.expect("Could not insert position");
renderables
.insert(p, Renderable {
fg: new_particle.fg,

View file

@ -19,7 +19,6 @@ use super::{
Item,
Map,
Name,
ParticleBuilder,
Player,
Pools,
Position,
@ -33,9 +32,9 @@ use super::{
WantsToPickupItem,
get_dest,
Destination,
DamageType,
};
use rltk::prelude::*;
use rltk::{ Point, RandomNumberGenerator, Rltk, VirtualKeyCode };
use bracket_lib::prelude::*;
use specs::prelude::*;
use std::cmp::{ max, min };
use crate::data::events::*;
@ -133,7 +132,7 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
std::mem::drop(renderables);
let mut renderables = ecs.write_storage::<Renderable>();
let render_data = renderables.get_mut(potential_target).unwrap();
render_data.glyph = rltk::to_cp437('+'); // Nethack open door, maybe just use '/' instead.
render_data.glyph = to_cp437('+'); // Nethack open door, maybe just use '/' instead.
door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
}
result = RunState::Ticking;
@ -230,7 +229,7 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState {
std::mem::drop(renderables);
let mut renderables = ecs.write_storage::<Renderable>();
let render_data = renderables.get_mut(potential_target).unwrap();
render_data.glyph = rltk::to_cp437('▓'); // Nethack open door, maybe just use '/' instead.
render_data.glyph = to_cp437('▓'); // Nethack open door, maybe just use '/' instead.
door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y));
}
result = RunState::Ticking;
@ -292,7 +291,7 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
if rng.roll_dice(1, 20) == 20 {
add_effect(
None,
EffectType::Damage { amount: 1 },
EffectType::Damage { amount: 1, damage_type: DamageType::Physical },
Targets::Entity { target: entity }
);
gamelog::Logger
@ -352,7 +351,7 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
destroyed_pos = Some(
Point::new(pos.x + delta_x, pos.y + delta_y)
);
gamelog::record_event(EVENT::BROKE_DOOR(1));
gamelog::record_event(EVENT::BrokeDoor(1));
return false;
// 66% chance of just kicking it.
} else {
@ -416,7 +415,7 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
ecs.delete_entity(destroyed_thing).expect("Unable to delete.");
}
gamelog::record_event(EVENT::KICKED_SOMETHING(1));
gamelog::record_event(EVENT::KickedSomething(1));
return RunState::Ticking;
}
@ -505,7 +504,7 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState
::new()
.append("The")
.colour(colour)
.append_n(&name.name)
.append(&name.name)
.colour(WHITE)
.append("is in your way.")
.log();
@ -643,7 +642,7 @@ fn get_item(ecs: &mut World) -> RunState {
}
}
pub fn player_input(gs: &mut State, ctx: &mut Rltk, on_overmap: bool) -> RunState {
pub fn player_input(gs: &mut State, ctx: &mut BTerm, on_overmap: bool) -> RunState {
match ctx.key {
None => {
return RunState::AwaitingInput;
@ -878,7 +877,7 @@ pub fn auto_explore(ecs: &mut World) {
}
}
let path = rltk::a_star_search(map.xy_idx(player_pos.x, player_pos.y), unexplored_tile.0, &*map);
let path = a_star_search(map.xy_idx(player_pos.x, player_pos.y), unexplored_tile.0, &*map);
if path.success && path.steps.len() > 1 {
let mut idx = map.xy_idx(player_pos.x, player_pos.y);
map.blocked[idx] = false;

View file

@ -1,4 +1,4 @@
use rltk::RandomNumberGenerator;
use bracket_lib::random::RandomNumberGenerator;
// FIXME: note to self,
// passing around strings here is super inefficient, so this is

View file

@ -14,7 +14,7 @@ pub struct Mob {
pub attacks: Option<Vec<NaturalAttack>>,
pub attributes: Option<MobAttributes>,
pub skills: Option<HashMap<String, i32>>,
pub vision_range: i32,
pub vision_range: Option<i32>,
pub telepathy_range: Option<i32>,
pub equipped: Option<Vec<String>>,
pub loot: Option<LootTableInfo>,

View file

@ -15,6 +15,7 @@ mod reaction_structs;
pub use reaction_structs::Reaction;
use reaction_structs::{ AncestryData, FactionData };
use std::sync::Mutex;
use bracket_lib::prelude::*;
lazy_static! {
pub static ref RAWS: Mutex<RawMaster> = Mutex::new(RawMaster::empty());
@ -31,22 +32,22 @@ pub struct Raws {
pub ancestries: Vec<AncestryData>,
}
rltk::embedded_resource!(RAW_ITEMS, "../../raws/items.json");
rltk::embedded_resource!(RAW_MOBS, "../../raws/mobs.json");
rltk::embedded_resource!(RAW_PROPS, "../../raws/props.json");
rltk::embedded_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
rltk::embedded_resource!(RAW_LOOT_TABLES, "../../raws/loot_tables.json");
rltk::embedded_resource!(RAW_FACTIONS, "../../raws/factions.json");
rltk::embedded_resource!(RAW_ANCESTRIES, "../../raws/ancestries.json");
embedded_resource!(RAW_ITEMS, "../../raws/items.json");
embedded_resource!(RAW_MOBS, "../../raws/mobs.json");
embedded_resource!(RAW_PROPS, "../../raws/props.json");
embedded_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
embedded_resource!(RAW_LOOT_TABLES, "../../raws/loot_tables.json");
embedded_resource!(RAW_FACTIONS, "../../raws/factions.json");
embedded_resource!(RAW_ANCESTRIES, "../../raws/ancestries.json");
pub fn load_raws() {
rltk::link_resource!(RAW_ITEMS, "../../raws/items.json");
rltk::link_resource!(RAW_MOBS, "../../raws/mobs.json");
rltk::link_resource!(RAW_PROPS, "../../raws/props.json");
rltk::link_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
rltk::link_resource!(RAW_LOOT_TABLES, "../../raws/loot_tables.json");
rltk::link_resource!(RAW_FACTIONS, "../../raws/factions.json");
rltk::link_resource!(RAW_ANCESTRIES, "../../raws/ancestries.json");
link_resource!(RAW_ITEMS, "../../raws/items.json");
link_resource!(RAW_MOBS, "../../raws/mobs.json");
link_resource!(RAW_PROPS, "../../raws/props.json");
link_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
link_resource!(RAW_LOOT_TABLES, "../../raws/loot_tables.json");
link_resource!(RAW_FACTIONS, "../../raws/factions.json");
link_resource!(RAW_ANCESTRIES, "../../raws/ancestries.json");
let decoded_raws = get_decoded_raws();
RAWS.lock().unwrap().load(decoded_raws);
@ -56,10 +57,18 @@ pub fn get_decoded_raws() -> Raws {
let items: Vec<Item> = ParseJson::parse_raws_into_vector("../../raws/items.json".to_string());
let mobs: Vec<Mob> = ParseJson::parse_raws_into_vector("../../raws/mobs.json".to_string());
let props: Vec<Prop> = ParseJson::parse_raws_into_vector("../../raws/props.json".to_string());
let spawn_tables: Vec<SpawnTable> = ParseJson::parse_raws_into_vector("../../raws/spawn_tables.json".to_string());
let loot_tables: Vec<LootTable> = ParseJson::parse_raws_into_vector("../../raws/loot_tables.json".to_string());
let factions: Vec<FactionData> = ParseJson::parse_raws_into_vector("../../raws/factions.json".to_string());
let ancestries: Vec<AncestryData> = ParseJson::parse_raws_into_vector("../../raws/ancestries.json".to_string());
let spawn_tables: Vec<SpawnTable> = ParseJson::parse_raws_into_vector(
"../../raws/spawn_tables.json".to_string()
);
let loot_tables: Vec<LootTable> = ParseJson::parse_raws_into_vector(
"../../raws/loot_tables.json".to_string()
);
let factions: Vec<FactionData> = ParseJson::parse_raws_into_vector(
"../../raws/factions.json".to_string()
);
let ancestries: Vec<AncestryData> = ParseJson::parse_raws_into_vector(
"../../raws/ancestries.json".to_string()
);
return Raws { items, mobs, props, spawn_tables, loot_tables, factions, ancestries };
}
@ -71,7 +80,7 @@ macro_rules! impl_ParseJson {
(for $($t:ty),+) => {
$(impl ParseJson for $t {
fn parse_raws_into_vector(path: String) -> $t {
let raw_data = rltk::embedding::EMBED.lock().get_resource(path).unwrap();
let raw_data = EMBED.lock().get_resource(path).unwrap();
let raw_string = std::str::from_utf8(&raw_data).expect("Failed to convert UTF-8 to &str.");
return serde_json::from_str(&raw_string).expect("Failed to convert &str to json");
}

View file

@ -5,8 +5,8 @@ use crate::gui::Ancestry;
use crate::random_table::RandomTable;
use crate::config::CONFIG;
use crate::data::visuals::BLOODSTAIN_COLOUR;
use regex::Regex;
use rltk::prelude::*;
use crate::data::entity::DEFAULT_VIEWSHED_STANDARD;
use bracket_lib::prelude::*;
use specs::prelude::*;
use specs::saveload::{ MarkedBuilder, SimpleMarker };
use std::collections::{ HashMap, HashSet };
@ -19,13 +19,13 @@ macro_rules! apply_effects {
let effect_name = effect.0.as_str();
match effect_name {
"heal" => {
let (n_dice, sides, modifier) = parse_dice_string(effect.1.as_str());
$eb = $eb.with(ProvidesHealing { n_dice, sides, modifier })
let dice = parse_dice_string(effect.1.as_str()).expect("Failed to parse dice string");
$eb = $eb.with(ProvidesHealing { n_dice: dice.n_dice, sides: dice.die_type, modifier: dice.bonus })
}
"ranged" => $eb = $eb.with(Ranged { range: effect.1.parse::<i32>().unwrap() }),
"damage" => {
let (n_dice, sides, modifier) = parse_dice_string(effect.1.as_str());
$eb = $eb.with(InflictsDamage { n_dice, sides, modifier })
let (damage_type, dice) = parse_damage_string(effect.1.as_str());
$eb = $eb.with(InflictsDamage { damage_type, n_dice: dice.n_dice, sides: dice.die_type, modifier: dice.bonus })
}
"aoe" => $eb = $eb.with(AOE { radius: effect.1.parse::<i32>().unwrap() }),
"confusion" => $eb = $eb.with(Confusion { turns: effect.1.parse::<i32>().unwrap() }),
@ -44,6 +44,7 @@ macro_rules! apply_effects {
/// flags are components that have no parameters to modify.
macro_rules! apply_flags {
($flags:expr, $eb:expr) => {
let mut damage_modifiers: HashMap<DamageType, DamageModifier> = HashMap::new();
for flag in $flags.iter() {
match flag.as_str() {
// --- PROP FLAGS BEGIN HERE ---
@ -88,6 +89,22 @@ macro_rules! apply_flags {
"NEUTRAL" => $eb = $eb.with(Faction { name: "neutral".to_string() }),
"HERBIVORE" => $eb = $eb.with(Faction { name: "herbivore".to_string() }),
"CARNIVORE" => $eb = $eb.with(Faction { name: "carnivore".to_string() }),
// --- DAMAGE MODIFIERS ---
"PHYS_IMMUNITY" => { damage_modifiers.insert(DamageType::Physical, DamageModifier::Immune); }
"PHYS_WEAK" => { damage_modifiers.insert(DamageType::Physical, DamageModifier::Weakness); }
"PHYS_RES" => { damage_modifiers.insert(DamageType::Physical, DamageModifier::Resistance); }
"MAGIC_IMMUNITY" => { damage_modifiers.insert(DamageType::Magic, DamageModifier::Immune); }
"MAGIC_WEAK" => { damage_modifiers.insert(DamageType::Magic, DamageModifier::Weakness); }
"MAGIC_RES" => { damage_modifiers.insert(DamageType::Magic, DamageModifier::Resistance); }
"FIRE_IMMUNITY" => { damage_modifiers.insert(DamageType::Fire, DamageModifier::Immune); }
"FIRE_WEAK" => { damage_modifiers.insert(DamageType::Fire, DamageModifier::Weakness); }
"FIRE_RES" => { damage_modifiers.insert(DamageType::Fire, DamageModifier::Resistance); }
"COLD_IMMUNITY" => { damage_modifiers.insert(DamageType::Cold, DamageModifier::Immune); }
"COLD_WEAK" => { damage_modifiers.insert(DamageType::Cold, DamageModifier::Weakness); }
"COLD_RES" => { damage_modifiers.insert(DamageType::Cold, DamageModifier::Resistance); }
"POISON_IMMUNITY" => { damage_modifiers.insert(DamageType::Poison, DamageModifier::Immune); }
"POISON_WEAK" => { damage_modifiers.insert(DamageType::Poison, DamageModifier::Weakness); }
"POISON_RES" => { damage_modifiers.insert(DamageType::Poison, DamageModifier::Resistance); }
// --- MOVEMENT MODES --- ( defaults to WANDER )
"STATIC" => $eb = $eb.with(MoveMode { mode: Movement::Static }),
"RANDOM_PATH" => $eb = $eb.with(MoveMode { mode: Movement::RandomWaypoint { path: None } }),
@ -98,9 +115,12 @@ macro_rules! apply_flags {
"LARGE_GROUP" => {} // and don't need to apply a component.
"MULTIATTACK" => $eb = $eb.with(MultiAttack {}),
"BLIND" => $eb = $eb.with(Blind {}),
_ => rltk::console::log(format!("Unrecognised flag: {}", flag.as_str())),
_ => console::log(format!("Unrecognised flag: {}", flag.as_str())),
}
}
if damage_modifiers.len() > 0 {
$eb = $eb.with(HasDamageModifiers { modifiers: damage_modifiers });
}
};
}
@ -203,13 +223,13 @@ impl RawMaster {
/// Checks a string against a HashSet, logging if a duplicate is found.
fn check_for_duplicate_entries(used_names: &HashSet<String>, id: &String) {
if used_names.contains(id) {
rltk::console::log(format!("DEBUGINFO: Duplicate ID found in raws [{}]", id));
console::log(format!("DEBUGINFO: Duplicate ID found in raws [{}]", id));
}
}
/// Checks a string against a HashSet, logging if the string isn't found.
fn check_for_unspecified_entity(used_names: &HashSet<String>, id: &String) {
if !used_names.contains(id) {
rltk::console::log(format!("DEBUGINFO: Table references unspecified entity [{}]", id));
console::log(format!("DEBUGINFO: Table references unspecified entity [{}]", id));
}
}
@ -266,8 +286,14 @@ pub fn spawn_named_item(
// -- DROP EVERYTHING THAT INVOLVES THE ECS BEFORE THIS POINT ---
let mut eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
eb = eb.with(Name { name: item_template.name.name.clone(), plural: item_template.name.plural.clone() });
eb = eb.with(Item { weight: item_template.weight.unwrap_or(0.0), value: item_template.value.unwrap_or(0.0) });
eb = eb.with(Name {
name: item_template.name.name.clone(),
plural: item_template.name.plural.clone(),
});
eb = eb.with(Item {
weight: item_template.weight.unwrap_or(0.0),
value: item_template.value.unwrap_or(0.0),
});
eb = spawn_position(pos, eb, key, raws);
if let Some(renderable) = &item_template.renderable {
@ -333,17 +359,18 @@ pub fn spawn_named_item(
}
if let Some(weapon) = &item_template.equip {
let (n_dice, die_type, bonus) = parse_dice_string(weapon.damage.as_str());
let (damage_type, dice) = parse_damage_string(weapon.damage.as_str());
let weapon_attribute = match weapon.flag.as_str() {
"DEXTERITY" => WeaponAttribute::Dexterity,
"FINESSE" => WeaponAttribute::Finesse,
_ => WeaponAttribute::Strength,
};
let wpn = MeleeWeapon {
damage_type,
attribute: weapon_attribute,
damage_n_dice: n_dice,
damage_die_type: die_type,
damage_bonus: bonus,
damage_n_dice: dice.n_dice,
damage_die_type: dice.die_type,
damage_bonus: dice.bonus,
hit_bonus: weapon.to_hit.unwrap_or(0),
};
eb = eb.with(wpn);
@ -379,7 +406,15 @@ pub fn spawn_named_mob(
eb = ecs.create_entity().marked::<SimpleMarker<SerializeMe>>();
eb = spawn_position(pos, eb, key, raws);
eb = eb.with(Name { name: mob_template.name.clone(), plural: mob_template.name.clone() });
eb = eb.with(Viewshed { visible_tiles: Vec::new(), range: mob_template.vision_range as i32, dirty: true });
eb = eb.with(Viewshed {
visible_tiles: Vec::new(),
range: if let Some(range) = mob_template.vision_range {
range
} else {
DEFAULT_VIEWSHED_STANDARD
},
dirty: true,
});
if let Some(telepath) = &mob_template.telepathy_range {
eb = eb.with(Telepath { telepath_tiles: Vec::new(), range: *telepath, dirty: true });
}
@ -447,7 +482,11 @@ pub fn spawn_named_mob(
let speed = if mob_template.speed.is_some() { mob_template.speed.unwrap() } else { 12 };
eb = eb.with(Energy { current: 0, speed: speed });
let base_mob_level = if mob_template.level.is_some() { mob_template.level.unwrap() } else { 0 };
let base_mob_level = if mob_template.level.is_some() {
mob_template.level.unwrap()
} else {
0
};
let mut mob_level = base_mob_level;
// If the level difficulty is smaller than the mob's base level, subtract 1;
// else, if the level difficulty is larger, add one-fifth of the difference
@ -464,7 +503,7 @@ pub fn spawn_named_mob(
mob_level = i32::min(mob_level, (1.5 * (base_mob_level as f32)).trunc() as i32);
// Should really use existing RNG here
let mut rng = rltk::RandomNumberGenerator::new();
let mut rng = RandomNumberGenerator::new();
let mob_hp = npc_hp_at_level(&mut rng, mob_con, mob_level);
let mob_mana = mana_at_level(&mut rng, mob_int, mob_level);
let mob_bac = if mob_template.bac.is_some() { mob_template.bac.unwrap() } else { 10 };
@ -497,7 +536,7 @@ pub fn spawn_named_mob(
skills.skills.insert(Skill::Magic, *sk.1);
}
_ => {
rltk::console::log(format!("Unknown skill referenced: [{}]", sk.0));
console::log(format!("Unknown skill referenced: [{}]", sk.0));
}
}
}
@ -507,13 +546,14 @@ pub fn spawn_named_mob(
if let Some(natural_attacks) = &mob_template.attacks {
let mut natural = NaturalAttacks { attacks: Vec::new() };
for na in natural_attacks.iter() {
let (n, d, b) = parse_dice_string(&na.damage);
let (damage_type, dice) = parse_damage_string(&na.damage);
let attack = NaturalAttack {
name: na.name.clone(),
damage_type,
hit_bonus: na.hit_bonus,
damage_n_dice: n,
damage_die_type: d,
damage_bonus: b,
damage_n_dice: dice.n_dice,
damage_die_type: dice.die_type,
damage_bonus: dice.bonus,
};
natural.attacks.push(attack);
}
@ -548,7 +588,7 @@ pub fn spawn_named_mob(
}
if CONFIG.logging.log_spawning {
rltk::console::log(
console::log(
format!(
"SPAWNLOG: {} ({}HP, {}MANA, {}BAC) spawned at level {} ({}[base], {}[map difficulty], {}[player level]), worth {} XP",
&mob_template.name,
@ -569,7 +609,14 @@ pub fn spawn_named_mob(
// Build entity, then check for anything they're wearing
if let Some(wielding) = &mob_template.equipped {
for tag in wielding.iter() {
spawn_named_entity(raws, ecs, tag, None, SpawnType::Equipped { by: new_mob }, map_difficulty);
spawn_named_entity(
raws,
ecs,
tag,
None,
SpawnType::Equipped { by: new_mob },
map_difficulty
);
}
}
@ -578,7 +625,12 @@ pub fn spawn_named_mob(
None
}
pub fn spawn_named_prop(raws: &RawMaster, ecs: &mut World, key: &str, pos: SpawnType) -> Option<Entity> {
pub fn spawn_named_prop(
raws: &RawMaster,
ecs: &mut World,
key: &str,
pos: SpawnType
) -> Option<Entity> {
if raws.prop_index.contains_key(key) {
// ENTITY BUILDER PREP
let prop_template = &raws.raws.props[raws.prop_index[key]];
@ -610,7 +662,12 @@ pub fn spawn_named_prop(raws: &RawMaster, ecs: &mut World, key: &str, pos: Spawn
None
}
fn spawn_position<'a>(pos: SpawnType, new_entity: EntityBuilder<'a>, tag: &str, raws: &RawMaster) -> EntityBuilder<'a> {
fn spawn_position<'a>(
pos: SpawnType,
new_entity: EntityBuilder<'a>,
tag: &str,
raws: &RawMaster
) -> EntityBuilder<'a> {
let mut eb = new_entity;
match pos {
@ -629,11 +686,13 @@ fn spawn_position<'a>(pos: SpawnType, new_entity: EntityBuilder<'a>, tag: &str,
eb
}
fn get_renderable_component(renderable: &super::item_structs::Renderable) -> crate::components::Renderable {
fn get_renderable_component(
renderable: &super::item_structs::Renderable
) -> crate::components::Renderable {
crate::components::Renderable {
glyph: rltk::to_cp437(renderable.glyph.chars().next().unwrap()),
fg: rltk::RGB::from_hex(&renderable.fg).expect("Invalid RGB"),
bg: rltk::RGB::from_hex(&renderable.bg).expect("Invalid RGB"),
glyph: to_cp437(renderable.glyph.chars().next().unwrap()),
fg: RGB::from_hex(&renderable.fg).expect("Invalid RGB"),
bg: RGB::from_hex(&renderable.bg).expect("Invalid RGB"),
render_order: renderable.order,
}
}
@ -668,19 +727,16 @@ pub fn table_by_name(raws: &RawMaster, key: &str, optional_difficulty: Option<i3
return rt;
}
}
rltk::console::log(
format!(
"DEBUGINFO: Something went wrong when trying to spawn {} @ map difficulty {} [upper bound: {}, lower bound: {}]. Returned debug entry.",
key,
difficulty,
upper_bound,
lower_bound
)
unreachable!(
"Something went wrong when trying to spawn {} @ map difficulty {} [upper bound: {}, lower bound: {}].",
key,
difficulty,
upper_bound,
lower_bound
);
return RandomTable::new().add("debug", 1);
}
pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) {
/*pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) {
lazy_static! {
static ref DICE_RE: Regex = Regex::new(r"(\d+)d(\d+)([\+\-]\d+)?").unwrap();
}
@ -699,11 +755,11 @@ pub fn parse_dice_string(dice: &str) -> (i32, i32, i32) {
}
}
(n_dice, die_type, die_bonus)
}
}*/
fn find_slot_for_equippable_item(tag: &str, raws: &RawMaster) -> EquipmentSlot {
if !raws.item_index.contains_key(tag) {
panic!("Trying to equip an unknown item: {}", tag);
unreachable!("Tried to equip an unknown item: {}", tag);
}
let item_index = raws.item_index[tag];
let item = &raws.raws.items[item_index];
@ -738,10 +794,14 @@ fn find_slot_for_equippable_item(tag: &str, raws: &RawMaster) -> EquipmentSlot {
}
}
}
panic!("Trying to equip {}, but it has no slot tag.", tag);
unreachable!("Tried to equip {}, but it has no slot tag.", tag);
}
pub fn roll_on_loot_table(raws: &RawMaster, rng: &mut RandomNumberGenerator, key: &str) -> Option<String> {
pub fn roll_on_loot_table(
raws: &RawMaster,
rng: &mut RandomNumberGenerator,
key: &str
) -> Option<String> {
if raws.loot_index.contains_key(key) {
console::log(format!("DEBUGINFO: Rolling on loot table: {}", key));
let mut rt = RandomTable::new();
@ -792,7 +852,11 @@ pub fn get_mob_spawn_type(raws: &RawMaster, key: &str) -> SpawnsAs {
return SpawnsAs::Single;
}
pub fn get_mob_spawn_amount(rng: &mut RandomNumberGenerator, spawn_type: &SpawnsAs, player_level: i32) -> i32 {
pub fn get_mob_spawn_amount(
rng: &mut RandomNumberGenerator,
spawn_type: &SpawnsAs,
player_level: i32
) -> i32 {
let n = match spawn_type {
// Single mobs always spawn alone.
SpawnsAs::Single => 1,
@ -893,7 +957,11 @@ pub fn faction_reaction(this_faction: &str, other_faction: &str, raws: &RawMaste
return Reaction::Ignore;
}
pub fn ancestry_reaction(this_ancestry: Ancestry, other_ancestry: Ancestry, raws: &RawMaster) -> Option<Reaction> {
pub fn ancestry_reaction(
this_ancestry: Ancestry,
other_ancestry: Ancestry,
raws: &RawMaster
) -> Option<Reaction> {
if this_ancestry == other_ancestry {
return Some(Reaction::Ignore);
} else {
@ -989,3 +1057,21 @@ fn parse_particle_burst(n: &str) -> SpawnParticleBurst {
trail_lifetime_ms: tokens[7].parse::<f32>().unwrap(),
}
}
fn parse_damage_string(n: &str) -> (DamageType, DiceType) {
let tokens: Vec<_> = n.split(';').collect();
let damage_type = if tokens.len() > 1 {
match tokens[1] {
"physical" => DamageType::Physical,
"magic" => DamageType::Magic,
"fire" => DamageType::Fire,
"cold" => DamageType::Cold,
"poison" => DamageType::Poison,
_ => unreachable!("Unrecognised damage type in raws: {}", tokens[1]),
}
} else {
DamageType::Physical
};
let dice = parse_dice_string(tokens[0]).expect("Failed to parse dice string");
return (damage_type, dice);
}

View file

@ -1,8 +1,8 @@
use rltk::rex::XpFile;
use bracket_lib::prelude::*;
rltk::embedded_resource!(TITLEIMAGE_105_56_BYTES, "../resources/title_image.xp");
rltk::embedded_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp");
rltk::embedded_resource!(WFC_POPULATED, "../resources/wfc-populated.xp");
embedded_resource!(TITLEIMAGE_105_56_BYTES, "../resources/title_image.xp");
embedded_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp");
embedded_resource!(WFC_POPULATED, "../resources/wfc-populated.xp");
pub struct RexAssets {
pub menu: XpFile,
@ -11,9 +11,9 @@ pub struct RexAssets {
impl RexAssets {
#[allow(clippy::new_without_default)]
pub fn new() -> RexAssets {
rltk::link_resource!(TITLEIMAGE_105_56_BYTES, "../resources/title_image.xp");
rltk::link_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp");
rltk::link_resource!(WFC_POPULATED, "../resources/wfc-populated.xp");
link_resource!(TITLEIMAGE_105_56_BYTES, "../resources/title_image.xp");
link_resource!(WFC_DEMO_IMAGE1, "../resources/wfc-demo1.xp");
link_resource!(WFC_POPULATED, "../resources/wfc-populated.xp");
RexAssets { menu: XpFile::from_resource("../resources/title_image.xp").unwrap() }
}

View file

@ -1,4 +1,5 @@
use super::components::*;
use bracket_lib::prelude::*;
use specs::error::NoError;
use specs::prelude::*;
use specs::saveload::{
@ -87,12 +88,14 @@ pub fn save_game(ecs: &mut World) {
GrantsXP,
HasAncestry,
HasClass,
HasDamageModifiers,
Hidden,
HungerClock,
IdentifiedBeatitude,
IdentifiedItem,
InBackpack,
InflictsDamage,
Intrinsics,
Item,
KnownSpells,
LootTable,
@ -217,12 +220,14 @@ pub fn load_game(ecs: &mut World) {
GrantsXP,
HasAncestry,
HasClass,
HasDamageModifiers,
Hidden,
HungerClock,
IdentifiedBeatitude,
IdentifiedItem,
InBackpack,
InflictsDamage,
Intrinsics,
Item,
KnownSpells,
LootTable,
@ -293,8 +298,8 @@ pub fn load_game(ecs: &mut World) {
crate::gamelog::restore_events(h.events.clone());
}
for (e, _p, pos) in (&entities, &player, &position).join() {
let mut ppos = ecs.write_resource::<rltk::Point>();
*ppos = rltk::Point::new(pos.x, pos.y);
let mut ppos = ecs.write_resource::<Point>();
*ppos = Point::new(pos.x, pos.y);
let mut player_resource = ecs.write_resource::<Entity>();
*player_resource = e;
}

View file

@ -21,19 +21,20 @@ use super::{
SerializeMe,
Skill,
Skills,
TileType,
tile_walkable,
Viewshed,
BlocksTile,
Bleeds,
HasDamageModifiers,
Intrinsics,
};
use crate::data::entity;
use crate::data::visuals::BLOODSTAIN_COLOUR;
use crate::gamesystem::*;
use rltk::{ RandomNumberGenerator, RGB };
use bracket_lib::prelude::*;
use specs::prelude::*;
use specs::saveload::{ MarkedBuilder, SimpleMarker };
use std::collections::HashMap;
use std::collections::{ HashMap, HashSet };
/// Spawns the player and returns his/her entity object.
pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
@ -52,9 +53,9 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
.with(Position { x: player_x, y: player_y })
.with(BlocksTile {})
.with(Renderable {
glyph: rltk::to_cp437('@'),
fg: RGB::named(rltk::YELLOW),
bg: RGB::named(rltk::BLACK),
glyph: to_cp437('@'),
fg: RGB::named(YELLOW),
bg: RGB::named(BLACK),
render_order: 0,
})
.with(Bleeds { colour: RGB::named(BLOODSTAIN_COLOUR) })
@ -87,7 +88,9 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
weight: 0.0,
god: false,
})
.with(EquipmentChanged {})
.with(HasDamageModifiers { modifiers: HashMap::new() })
.with(Intrinsics { list: HashSet::new() })
.with(EquipmentChanged {}) // To force re-calc of equipment bonuses.
.with(skills)
.with(Energy { current: 0, speed: entity::NORMAL_SPEED })
.marked::<SimpleMarker<SerializeMe>>()
@ -132,7 +135,7 @@ pub fn spawn_region(
let difficulty = (map.difficulty + player_level) / 2;
// If no area, log and return.
if areas.len() == 0 {
rltk::console::log("DEBUGINFO: No areas capable of spawning mobs!");
console::log("DEBUGINFO: No areas capable of spawning mobs!");
return;
}
// Get num of each entity type.
@ -212,7 +215,7 @@ pub fn spawn_entity(ecs: &mut World, spawn: &(&usize, &String)) {
return;
}
rltk::console::log(format!("WARNING: We don't know how to spawn [{}]!", spawn.1));
console::log(format!("WARNING: We don't know how to spawn [{}]!", spawn.1));
}
// 3 scrolls : 3 potions : 1 equipment : 1 wand?

View file

@ -1,5 +1,5 @@
use specs::prelude::*;
use rltk::prelude::*;
use bracket_lib::prelude::*;
use super::runstate::RunState;
use crate::map::*;
use crate::hunger_system;
@ -125,10 +125,10 @@ impl State {
.append("You head to")
.colour(rgb_to_u8(get_local_col(id)))
.append_n(&mapname)
.colour(rltk::WHITE)
.colour(WHITE)
.period()
.log();
gamelog::record_event(EVENT::CHANGED_FLOOR(mapname));
gamelog::record_event(EVENT::ChangedFloor(mapname));
}
fn game_over_cleanup(&mut self) {
@ -152,12 +152,12 @@ impl State {
self.generate_world_map(1, TileType::Floor);
gamelog::setup_log();
gamelog::record_event(EVENT::LEVEL(1));
gamelog::record_event(EVENT::Level(1));
}
}
impl GameState for State {
fn tick(&mut self, ctx: &mut Rltk) {
fn tick(&mut self, ctx: &mut BTerm) {
let mut new_runstate;
{
let runstate = self.ecs.fetch::<RunState>();
@ -518,7 +518,7 @@ impl GameState for State {
let result = gui::show_help(ctx);
match result {
gui::YesNoResult::Yes => {
gamelog::record_event(EVENT::LOOKED_FOR_HELP(1));
gamelog::record_event(EVENT::LookedForHelp(1));
new_runstate = RunState::AwaitingInput;
}
_ => {}
@ -591,6 +591,6 @@ impl GameState for State {
damage_system::delete_the_dead(&mut self.ecs);
let _ = rltk::render_draw_buffer(ctx);
let _ = render_draw_buffer(ctx);
}
}

View file

@ -11,7 +11,7 @@ use super::{
Renderable,
AOE,
};
use rltk::prelude::*;
use bracket_lib::prelude::*;
use specs::prelude::*;
pub struct TriggerSystem {}
@ -30,7 +30,8 @@ impl<'a> System<'a> for TriggerSystem {
);
fn run(&mut self, data: Self::SystemData) {
let (map, mut entity_moved, position, entry_trigger, names, entities, aoes, renderables) = data;
let (map, mut entity_moved, position, entry_trigger, names, entities, aoes, renderables) =
data;
for (entity, mut _entity_moved, pos) in (&entities, &mut entity_moved, &position).join() {
let idx = map.xy_idx(pos.x, pos.y);
crate::spatial::for_each_tile_content(idx, |entity_id| {
@ -51,15 +52,21 @@ impl<'a> System<'a> for TriggerSystem {
.log();
}
}
add_effect(Some(entity_id), EffectType::TriggerFire { trigger: entity_id }, if
let Some(aoe) = aoes.get(entity_id)
{
Targets::TileList {
targets: aoe_tiles(&*map, Point::new(pos.x, pos.y), aoe.radius),
add_effect(
Some(entity_id),
EffectType::TriggerFire { trigger: entity_id },
if let Some(aoe) = aoes.get(entity_id) {
Targets::TileList {
targets: aoe_tiles(
&*map,
Point::new(pos.x, pos.y),
aoe.radius
),
}
} else {
Targets::Tile { target: idx }
}
} else {
Targets::Tile { target: idx }
});
);
}
}
}

View file

@ -13,7 +13,8 @@ use super::{
gui::renderable_colour,
tile_blocks_telepathy,
};
use rltk::{ FieldOfViewAlg::SymmetricShadowcasting, Point };
use bracket_lib::prelude::*;
use bracket_lib::pathfinding::FieldOfViewAlg::SymmetricShadowcasting;
use specs::prelude::*;
pub struct VisibilitySystem {}
@ -23,7 +24,7 @@ const BLIND_TELEPATHY_RANGE_MULTIPLIER: i32 = 3;
impl<'a> System<'a> for VisibilitySystem {
type SystemData = (
WriteExpect<'a, Map>,
WriteExpect<'a, rltk::RandomNumberGenerator>,
WriteExpect<'a, RandomNumberGenerator>,
Entities<'a>,
WriteStorage<'a, Viewshed>,
WriteStorage<'a, Telepath>,
@ -74,8 +75,7 @@ impl<'a> System<'a> for VisibilitySystem {
p.y >= 0 &&
p.y < map.height &&
(map.lit_tiles[map.xy_idx(p.x, p.y)] == true ||
rltk::DistanceAlg::Pythagoras.distance2d(Point::new(p.x, p.y), origin) <
1.5)
DistanceAlg::Pythagoras.distance2d(Point::new(p.x, p.y), origin) < 1.5)
});
// If this is the player, reveal what they can see
@ -101,7 +101,7 @@ impl<'a> System<'a> for VisibilitySystem {
.append("You spot a")
.colour(renderable_colour(&renderables, e))
.append_n(&name.name)
.colour(rltk::WHITE)
.colour(WHITE)
.period()
.log();
}
@ -121,7 +121,7 @@ impl<'a> System<'a> for VisibilitySystem {
if let Some(_is_blind) = blind_entities.get(ent) {
range *= BLIND_TELEPATHY_RANGE_MULTIPLIER;
}
telepath.telepath_tiles = fast_fov(pos.x, pos.y, range, &map);
telepath.telepath_tiles = fast_fov(pos.x, pos.y, range);
telepath.telepath_tiles.retain(
|p| p.x >= 0 && p.x < map.width && p.y >= 0 && p.y < map.height
);