starting in town
This commit is contained in:
parent
34e7ec40ee
commit
f2fabafe57
9 changed files with 551 additions and 61 deletions
|
|
@ -66,10 +66,10 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
|
||||||
let entity_offset_y = pos.y - min_y;
|
let entity_offset_y = pos.y - min_y;
|
||||||
if entity_offset_x > 0 && entity_offset_x < map_width && entity_offset_y > 0 && entity_offset_y < map_height
|
if entity_offset_x > 0 && entity_offset_x < map_width && entity_offset_y > 0 && entity_offset_y < map_height
|
||||||
{
|
{
|
||||||
let offsets = RGB::from_u8(map.red_offset[idx], map.green_offset[idx], map.blue_offset[idx]);
|
let offsets = map.colour_offset[idx];
|
||||||
let mut draw = false;
|
let mut draw = false;
|
||||||
let mut fg = render.fg;
|
let mut fg = render.fg;
|
||||||
let mut bg = render.bg.add(RGB::from_u8(26, 45, 45)).add(offsets);
|
let mut bg = offset(render.bg, offsets);
|
||||||
// Get bloodstain colours
|
// Get bloodstain colours
|
||||||
if map.bloodstains.contains(&idx) {
|
if map.bloodstains.contains(&idx) {
|
||||||
bg = bg.add(RGB::from_f32(0.6, 0., 0.));
|
bg = bg.add(RGB::from_f32(0.6, 0., 0.));
|
||||||
|
|
@ -104,34 +104,96 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn offset(rgb: rltk::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);
|
||||||
|
}
|
||||||
|
|
||||||
fn get_tile_glyph(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
fn get_tile_glyph(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||||
let offsets = RGB::from_u8(map.red_offset[idx], map.green_offset[idx], map.blue_offset[idx]);
|
let offsets = map.colour_offset[idx];
|
||||||
let glyph;
|
let glyph: rltk::FontCharType;
|
||||||
let mut fg = offsets.mul(2.0);
|
let mut fg: RGB = RGB::new();
|
||||||
let mut bg = offsets.add(RGB::from_u8(26, 45, 45));
|
let mut bg: RGB;
|
||||||
|
|
||||||
|
let default_bg: RGB = RGB::from_u8(26, 45, 45);
|
||||||
|
|
||||||
match map.tiles[idx] {
|
match map.tiles[idx] {
|
||||||
TileType::Floor => {
|
TileType::Floor => {
|
||||||
glyph = rltk::to_cp437('.');
|
glyph = rltk::to_cp437('.');
|
||||||
fg = fg.add(RGB::from_f32(0.1, 0.8, 0.5));
|
fg = RGB::from_f32(0.1, 0.8, 0.5);
|
||||||
|
bg = default_bg;
|
||||||
|
}
|
||||||
|
TileType::WoodFloor => {
|
||||||
|
glyph = rltk::to_cp437('.');
|
||||||
|
bg = RGB::from_u8(47, 36, 28);
|
||||||
|
}
|
||||||
|
TileType::Fence => {
|
||||||
|
glyph = rltk::to_cp437('=');
|
||||||
|
fg = RGB::from_u8(66, 32, 6);
|
||||||
|
bg = RGB::from_u8(44, 34, 26);
|
||||||
}
|
}
|
||||||
TileType::Wall => {
|
TileType::Wall => {
|
||||||
let x = idx as i32 % map.width;
|
let x = idx as i32 % map.width;
|
||||||
let y = idx as i32 / map.width;
|
let y = idx as i32 / map.width;
|
||||||
glyph = wall_glyph(&*map, x, y);
|
glyph = wall_glyph(&*map, x, y);
|
||||||
fg = fg.add(RGB::from_f32(0.6, 0.5, 0.25));
|
fg = RGB::from_f32(0.6, 0.5, 0.25);
|
||||||
|
bg = default_bg;
|
||||||
}
|
}
|
||||||
TileType::DownStair => {
|
TileType::DownStair => {
|
||||||
glyph = rltk::to_cp437('>');
|
glyph = rltk::to_cp437('>');
|
||||||
fg = RGB::from_f32(0., 1., 1.);
|
fg = RGB::from_f32(0., 1., 1.);
|
||||||
|
bg = default_bg;
|
||||||
|
}
|
||||||
|
TileType::Bridge => {
|
||||||
|
glyph = rltk::to_cp437('.');
|
||||||
|
fg = default_bg;
|
||||||
|
bg = default_bg;
|
||||||
|
}
|
||||||
|
TileType::Gravel => {
|
||||||
|
glyph = rltk::to_cp437(';');
|
||||||
|
bg = RGB::from_u8(26, 26, 36);
|
||||||
|
}
|
||||||
|
TileType::Road => {
|
||||||
|
glyph = rltk::to_cp437('~');
|
||||||
|
//fg = RGB::from_u8(112, 105, 94);
|
||||||
|
bg = default_bg;
|
||||||
|
}
|
||||||
|
TileType::Grass => {
|
||||||
|
glyph = rltk::to_cp437('"');
|
||||||
|
bg = RGB::from_u8(26, 45, 26);
|
||||||
|
}
|
||||||
|
TileType::Sand => {
|
||||||
|
glyph = rltk::to_cp437('.');
|
||||||
|
bg = RGB::from_u8(54, 54, 28);
|
||||||
|
}
|
||||||
|
TileType::ShallowWater => {
|
||||||
|
glyph = rltk::to_cp437('~');
|
||||||
|
bg = RGB::from_u8(34, 42, 62);
|
||||||
|
}
|
||||||
|
TileType::DeepWater => {
|
||||||
|
glyph = rltk::to_cp437('~');
|
||||||
|
bg = RGB::from_u8(24, 30, 42);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if map.bloodstains.contains(&idx) {
|
if map.bloodstains.contains(&idx) {
|
||||||
bg = bg.add(RGB::from_f32(0.6, 0., 0.));
|
bg = bg.add(RGB::from_f32(0.6, 0., 0.));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the foreground hasn't been changed, just add
|
||||||
|
// the bg to it. Otherwise, leave it as is.
|
||||||
|
if fg == RGB::new() {
|
||||||
|
fg = fg.add(bg).add(map.additional_fg_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
fg = offset(fg, offsets);
|
||||||
|
bg = offset(bg, offsets);
|
||||||
|
|
||||||
if !map.visible_tiles[idx] {
|
if !map.visible_tiles[idx] {
|
||||||
fg = fg.mul(0.6);
|
fg = fg.mul(0.75);
|
||||||
bg = bg.mul(0.6);
|
bg = bg.mul(0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (glyph, fg, bg);
|
return (glyph, fg, bg);
|
||||||
|
|
@ -291,14 +353,14 @@ pub fn render_debug_map(map: &Map, ctx: &mut Rltk) {
|
||||||
let min_y = player_pos.y - center_y;
|
let min_y = player_pos.y - center_y;
|
||||||
let max_y = min_y + y_chars as i32;
|
let max_y = min_y + y_chars as i32;
|
||||||
|
|
||||||
let map_width = map.width - 1;
|
let map_width = map.width;
|
||||||
let map_height = map.height - 1;
|
let map_height = map.height;
|
||||||
|
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
for ty in min_y..max_y {
|
for ty in min_y..max_y {
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
for tx in min_x..max_x {
|
for tx in min_x..max_x {
|
||||||
if tx > 0 && tx < map_width && ty > 0 && ty < map_height {
|
if tx >= 0 && tx < map_width && ty >= 0 && ty < map_height {
|
||||||
let idx = map.xy_idx(tx, ty);
|
let idx = map.xy_idx(tx, ty);
|
||||||
if map.revealed_tiles[idx] {
|
if map.revealed_tiles[idx] {
|
||||||
let (glyph, fg, bg) = get_tile_glyph(idx, &*map);
|
let (glyph, fg, bg) = get_tile_glyph(idx, &*map);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ rltk::embedded_resource!(SCANLINESFS, "../resources/scanlines.fs");
|
||||||
rltk::embedded_resource!(SCANLINESVS, "../resources/scanlines.vs");
|
rltk::embedded_resource!(SCANLINESVS, "../resources/scanlines.vs");
|
||||||
|
|
||||||
//Consts
|
//Consts
|
||||||
pub const SHOW_MAPGEN: bool = false;
|
pub const SHOW_MAPGEN: bool = true;
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
pub enum RunState {
|
pub enum RunState {
|
||||||
|
|
@ -82,7 +82,7 @@ impl State {
|
||||||
self.mapgen_timer = 0.0;
|
self.mapgen_timer = 0.0;
|
||||||
self.mapgen_history.clear();
|
self.mapgen_history.clear();
|
||||||
let mut rng = self.ecs.write_resource::<rltk::RandomNumberGenerator>();
|
let mut rng = self.ecs.write_resource::<rltk::RandomNumberGenerator>();
|
||||||
let mut builder = map_builders::random_builder(new_depth, &mut rng, 64, 64);
|
let mut builder = map_builders::level_builder(new_depth, &mut rng, 80, 50);
|
||||||
builder.build_map(&mut rng);
|
builder.build_map(&mut rng);
|
||||||
std::mem::drop(rng);
|
std::mem::drop(rng);
|
||||||
self.mapgen_history = builder.build_data.history.clone();
|
self.mapgen_history = builder.build_data.history.clone();
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,8 @@ use rltk::{Algorithm2D, BaseMap, Point};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
mod tiletype;
|
||||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
pub use tiletype::{tile_cost, tile_opaque, tile_walkable, TileType};
|
||||||
pub enum TileType {
|
|
||||||
Wall,
|
|
||||||
Floor,
|
|
||||||
DownStair,
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: If the map size gets too small, entities stop being rendered starting from the right.
|
// FIXME: If the map size gets too small, entities stop being rendered starting from the right.
|
||||||
// i.e. on a map size of 40*40, only entities to the left of the player are rendered.
|
// i.e. on a map size of 40*40, only entities to the left of the player are rendered.
|
||||||
|
|
@ -24,9 +19,8 @@ pub struct Map {
|
||||||
pub lit_tiles: Vec<bool>,
|
pub lit_tiles: Vec<bool>,
|
||||||
pub telepath_tiles: Vec<bool>,
|
pub telepath_tiles: Vec<bool>,
|
||||||
// Combine these offsets into one Vec<(u8, u8, u8)>
|
// Combine these offsets into one Vec<(u8, u8, u8)>
|
||||||
pub red_offset: Vec<u8>,
|
pub colour_offset: Vec<(f32, f32, f32)>,
|
||||||
pub green_offset: Vec<u8>,
|
pub additional_fg_offset: rltk::RGB,
|
||||||
pub blue_offset: Vec<u8>,
|
|
||||||
pub blocked: Vec<bool>,
|
pub blocked: Vec<bool>,
|
||||||
pub depth: i32,
|
pub depth: i32,
|
||||||
pub bloodstains: HashSet<usize>,
|
pub bloodstains: HashSet<usize>,
|
||||||
|
|
@ -52,9 +46,8 @@ impl Map {
|
||||||
visible_tiles: vec![false; map_tile_count],
|
visible_tiles: vec![false; map_tile_count],
|
||||||
lit_tiles: vec![true; map_tile_count], // NYI: Light sources. Once those exist, we can set this to false.
|
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],
|
telepath_tiles: vec![false; map_tile_count],
|
||||||
red_offset: vec![0; map_tile_count],
|
colour_offset: vec![(1.0, 1.0, 1.0); map_tile_count],
|
||||||
green_offset: vec![0; map_tile_count],
|
additional_fg_offset: rltk::RGB::from_u8(HALF_OFFSET, HALF_OFFSET, HALF_OFFSET),
|
||||||
blue_offset: vec![0; map_tile_count],
|
|
||||||
blocked: vec![false; map_tile_count],
|
blocked: vec![false; map_tile_count],
|
||||||
depth: new_depth,
|
depth: new_depth,
|
||||||
bloodstains: HashSet::new(),
|
bloodstains: HashSet::new(),
|
||||||
|
|
@ -62,20 +55,16 @@ impl Map {
|
||||||
tile_content: vec![Vec::new(); map_tile_count],
|
tile_content: vec![Vec::new(); map_tile_count],
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_OFFSET: u8 = 32;
|
const HALF_OFFSET: u8 = 5;
|
||||||
|
const OFFSET_PERCENT: i32 = 10;
|
||||||
|
const TWICE_OFFSET: i32 = OFFSET_PERCENT * 2;
|
||||||
let mut rng = rltk::RandomNumberGenerator::new();
|
let mut rng = rltk::RandomNumberGenerator::new();
|
||||||
|
|
||||||
for idx in 0..map.red_offset.len() {
|
for idx in 0..map.colour_offset.len() {
|
||||||
let roll = rng.roll_dice(1, MAX_OFFSET as i32);
|
let red_roll: f32 = (rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32 / 100f32 + 1.0;
|
||||||
map.red_offset[idx] = roll as u8;
|
let green_roll: f32 = (rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32 / 100f32 + 1.0;
|
||||||
}
|
let blue_roll: f32 = (rng.roll_dice(1, TWICE_OFFSET - 1) + 1 - OFFSET_PERCENT) as f32 / 100f32 + 1.0;
|
||||||
for idx in 0..map.green_offset.len() {
|
map.colour_offset[idx] = (red_roll, green_roll, blue_roll);
|
||||||
let roll = rng.roll_dice(1, MAX_OFFSET as i32);
|
|
||||||
map.green_offset[idx] = roll as u8;
|
|
||||||
}
|
|
||||||
for idx in 0..map.blue_offset.len() {
|
|
||||||
let roll = rng.roll_dice(1, MAX_OFFSET as i32);
|
|
||||||
map.blue_offset[idx] = roll as u8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
|
|
@ -92,7 +81,7 @@ impl Map {
|
||||||
|
|
||||||
pub fn populate_blocked(&mut self) {
|
pub fn populate_blocked(&mut self) {
|
||||||
for (i, tile) in self.tiles.iter_mut().enumerate() {
|
for (i, tile) in self.tiles.iter_mut().enumerate() {
|
||||||
self.blocked[i] = *tile == TileType::Wall;
|
self.blocked[i] = !tile_walkable(*tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,7 +101,11 @@ impl Algorithm2D for Map {
|
||||||
impl BaseMap for Map {
|
impl BaseMap for Map {
|
||||||
fn is_opaque(&self, idx: usize) -> bool {
|
fn is_opaque(&self, idx: usize) -> bool {
|
||||||
let idx_u = idx as usize;
|
let idx_u = idx as usize;
|
||||||
return self.tiles[idx_u] == TileType::Wall || self.view_blocked.contains(&idx_u);
|
if idx_u > 0 && idx_u < self.tiles.len() {
|
||||||
|
return tile_opaque(self.tiles[idx_u]) || self.view_blocked.contains(&idx_u);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pathing_distance(&self, idx1: usize, idx2: usize) -> f32 {
|
fn get_pathing_distance(&self, idx1: usize, idx2: usize) -> f32 {
|
||||||
|
|
@ -128,33 +121,34 @@ impl BaseMap for Map {
|
||||||
let x = (idx as i32) % self.width;
|
let x = (idx as i32) % self.width;
|
||||||
let y = (idx as i32) / self.width;
|
let y = (idx as i32) / self.width;
|
||||||
let w = self.width as usize;
|
let w = self.width as usize;
|
||||||
|
let tt = self.tiles[idx as usize];
|
||||||
|
|
||||||
// Cardinal directions
|
// Cardinal directions
|
||||||
if self.is_exit_valid(x - 1, y) {
|
if self.is_exit_valid(x - 1, y) {
|
||||||
exits.push((idx - 1, 1.0));
|
exits.push((idx - 1, tile_cost(tt)));
|
||||||
}
|
}
|
||||||
if self.is_exit_valid(x + 1, y) {
|
if self.is_exit_valid(x + 1, y) {
|
||||||
exits.push((idx + 1, 1.0));
|
exits.push((idx + 1, tile_cost(tt)));
|
||||||
}
|
}
|
||||||
if self.is_exit_valid(x, y - 1) {
|
if self.is_exit_valid(x, y - 1) {
|
||||||
exits.push((idx - w, 1.0));
|
exits.push((idx - w, tile_cost(tt)));
|
||||||
}
|
}
|
||||||
if self.is_exit_valid(x, y + 1) {
|
if self.is_exit_valid(x, y + 1) {
|
||||||
exits.push((idx + w, 1.0));
|
exits.push((idx + w, tile_cost(tt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagonals
|
// Diagonals
|
||||||
if self.is_exit_valid(x - 1, y - 1) {
|
if self.is_exit_valid(x - 1, y - 1) {
|
||||||
exits.push((idx - w - 1, 1.45));
|
exits.push((idx - w - 1, tile_cost(tt) * 1.45));
|
||||||
}
|
}
|
||||||
if self.is_exit_valid(x + 1, y - 1) {
|
if self.is_exit_valid(x + 1, y - 1) {
|
||||||
exits.push((idx - w + 1, 1.45));
|
exits.push((idx - w + 1, tile_cost(tt) * 1.45));
|
||||||
}
|
}
|
||||||
if self.is_exit_valid(x - 1, y + 1) {
|
if self.is_exit_valid(x - 1, y + 1) {
|
||||||
exits.push((idx + w - 1, 1.45));
|
exits.push((idx + w - 1, tile_cost(tt) * 1.45));
|
||||||
}
|
}
|
||||||
if self.is_exit_valid(x + 1, y + 1) {
|
if self.is_exit_valid(x + 1, y + 1) {
|
||||||
exits.push((idx + w + 1, 1.45));
|
exits.push((idx + w + 1, tile_cost(tt) * 1.45));
|
||||||
}
|
}
|
||||||
|
|
||||||
exits
|
exits
|
||||||
52
src/map/tiletype.rs
Normal file
52
src/map/tiletype.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum TileType {
|
||||||
|
// Walls (opaque)
|
||||||
|
Wall,
|
||||||
|
// Impassable (transparent)
|
||||||
|
DeepWater,
|
||||||
|
Fence,
|
||||||
|
// Floors (walkable)
|
||||||
|
Floor,
|
||||||
|
WoodFloor,
|
||||||
|
Gravel,
|
||||||
|
Road,
|
||||||
|
Grass,
|
||||||
|
Sand,
|
||||||
|
ShallowWater,
|
||||||
|
Bridge,
|
||||||
|
// Stairs (changes floor)
|
||||||
|
DownStair,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_walkable(tt: TileType) -> bool {
|
||||||
|
match tt {
|
||||||
|
TileType::Floor
|
||||||
|
| TileType::WoodFloor
|
||||||
|
| TileType::Gravel
|
||||||
|
| TileType::Road
|
||||||
|
| TileType::Grass
|
||||||
|
| TileType::Sand
|
||||||
|
| TileType::ShallowWater
|
||||||
|
| TileType::Bridge
|
||||||
|
| TileType::DownStair => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_opaque(tt: TileType) -> bool {
|
||||||
|
match tt {
|
||||||
|
TileType::Wall => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_cost(tt: TileType) -> f32 {
|
||||||
|
match tt {
|
||||||
|
TileType::Road => 0.8,
|
||||||
|
TileType::Grass => 1.1,
|
||||||
|
TileType::ShallowWater => 1.2,
|
||||||
|
_ => 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ impl AreaStartingPosition {
|
||||||
|
|
||||||
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||||
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
|
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
|
||||||
if *tiletype == TileType::Floor {
|
if crate::tile_walkable(*tiletype) {
|
||||||
available_floors.push((
|
available_floors.push((
|
||||||
idx,
|
idx,
|
||||||
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ mod door_placement;
|
||||||
use door_placement::DoorPlacement;
|
use door_placement::DoorPlacement;
|
||||||
mod fill_edges;
|
mod fill_edges;
|
||||||
use fill_edges::FillEdges;
|
use fill_edges::FillEdges;
|
||||||
|
mod town;
|
||||||
|
use town::town_builder;
|
||||||
|
|
||||||
// Shared data to be passed around build chain
|
// Shared data to be passed around build chain
|
||||||
pub struct BuilderMap {
|
pub struct BuilderMap {
|
||||||
|
|
@ -314,3 +316,11 @@ pub fn random_builder(new_depth: i32, rng: &mut rltk::RandomNumberGenerator, wid
|
||||||
|
|
||||||
builder
|
builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn level_builder(new_depth: i32, rng: &mut rltk::RandomNumberGenerator, width: i32, height: i32) -> BuilderChain {
|
||||||
|
rltk::console::log(format!("DEBUGINFO: Depth: {}", new_depth));
|
||||||
|
match new_depth {
|
||||||
|
1 => town_builder(new_depth, rng, width, height),
|
||||||
|
_ => random_builder(new_depth, rng, width, height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
372
src/map_builders/town.rs
Normal file
372
src/map_builders/town.rs
Normal file
|
|
@ -0,0 +1,372 @@
|
||||||
|
use super::{BuilderChain, BuilderMap, InitialMapBuilder, Position, TileType};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
pub fn town_builder(new_depth: i32, rng: &mut rltk::RandomNumberGenerator, width: i32, height: i32) -> BuilderChain {
|
||||||
|
let mut chain = BuilderChain::new(new_depth, width, height);
|
||||||
|
chain.start_with(TownBuilder::new());
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TownBuilder {}
|
||||||
|
|
||||||
|
impl InitialMapBuilder for TownBuilder {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build_rooms(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TownBuilder {
|
||||||
|
pub fn new() -> Box<TownBuilder> {
|
||||||
|
return Box::new(TownBuilder {});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_rooms(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
// Make visible for snapshot
|
||||||
|
for t in build_data.map.visible_tiles.iter_mut() {
|
||||||
|
*t = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.grass_layer(build_data);
|
||||||
|
rltk::console::log("Placed grass.");
|
||||||
|
let piers = self.water_and_piers(rng, build_data);
|
||||||
|
rltk::console::log("Placed water and piers.");
|
||||||
|
let (mut available_building_tiles, wall_gap_y) = self.town_walls(rng, build_data);
|
||||||
|
rltk::console::log("Placed walls.");
|
||||||
|
let mut buildings = self.buildings(rng, build_data, &mut available_building_tiles);
|
||||||
|
rltk::console::log("Placed buildings.");
|
||||||
|
let doors = self.add_doors(rng, build_data, &mut buildings, wall_gap_y);
|
||||||
|
rltk::console::log("Placed doors.");
|
||||||
|
self.path_from_tiles_to_nearest_tiletype(build_data, &doors, TileType::Road, TileType::Road, true);
|
||||||
|
rltk::console::log("Placed path from doors to road.");
|
||||||
|
self.path_from_tiles_to_nearest_tiletype(build_data, &piers, TileType::Road, TileType::Road, false);
|
||||||
|
rltk::console::log("Placed path from piers to road.");
|
||||||
|
|
||||||
|
build_data.take_snapshot();
|
||||||
|
|
||||||
|
// Sort buildings by size
|
||||||
|
let mut building_size: Vec<(usize, i32)> = Vec::new();
|
||||||
|
for (i, building) in buildings.iter().enumerate() {
|
||||||
|
building_size.push((i, building.2 * building.3));
|
||||||
|
}
|
||||||
|
building_size.sort_by(|a, b| b.1.cmp(&a.1));
|
||||||
|
|
||||||
|
// Largest building as start position
|
||||||
|
let tavern = &buildings[building_size[0].0];
|
||||||
|
build_data.starting_position = Some(Position { x: tavern.0 + (tavern.2 / 2), y: tavern.1 + (tavern.3 / 2) });
|
||||||
|
|
||||||
|
// Smallest building as mine entrance
|
||||||
|
let mine = &buildings[building_size[building_size.len() - 1].0];
|
||||||
|
let exit_idx = build_data.map.xy_idx(mine.0 + (mine.2 / 2), mine.1 + (mine.3 / 2));
|
||||||
|
build_data.map.tiles[exit_idx] = TileType::DownStair;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grass_layer(&mut self, build_data: &mut BuilderMap) {
|
||||||
|
// Grass everywhere
|
||||||
|
for t in build_data.map.tiles.iter_mut() {
|
||||||
|
*t = TileType::Grass;
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn water_and_piers(&mut self, rng: &mut rltk::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;
|
||||||
|
let minimum_width = variance + 10;
|
||||||
|
let shallow_width = 6;
|
||||||
|
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);
|
||||||
|
water_width.push(n_water);
|
||||||
|
n += 0.1;
|
||||||
|
for x in 0..n_water {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::DeepWater;
|
||||||
|
}
|
||||||
|
for x in n_water..n_water + shallow_width {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::ShallowWater;
|
||||||
|
}
|
||||||
|
for x in n_water + shallow_width..n_water + sand_width {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::Sand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
|
||||||
|
// Add piers
|
||||||
|
let mut placed_piers: Vec<i32> = Vec::new();
|
||||||
|
let pier_width = 4;
|
||||||
|
let mut pier_idxs: Vec<usize> = Vec::new();
|
||||||
|
|
||||||
|
for _i in 0..rng.roll_dice(1, 3) + 2 {
|
||||||
|
let mut y;
|
||||||
|
loop {
|
||||||
|
y = rng.roll_dice(1, build_data.height - 3) - 1;
|
||||||
|
if !(placed_piers.contains(&y) || placed_piers.contains(&(y + pier_width))) {
|
||||||
|
rltk::console::log(format!("Placing pier at y {}-{}", y, y + 3));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..=pier_width {
|
||||||
|
placed_piers.push(y + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_roll = rng.roll_dice(1, 4);
|
||||||
|
let largest_water_width;
|
||||||
|
if water_width[y as usize] > water_width[y as usize + 1] {
|
||||||
|
largest_water_width = water_width[y as usize];
|
||||||
|
} else {
|
||||||
|
largest_water_width = water_width[y as usize + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make pier length
|
||||||
|
for x in 2 + start_roll..largest_water_width + sand_width {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::Fence;
|
||||||
|
let idx = build_data.map.xy_idx(x, y + 1);
|
||||||
|
build_data.map.tiles[idx] = TileType::WoodFloor;
|
||||||
|
let idx = build_data.map.xy_idx(x, y + 2);
|
||||||
|
build_data.map.tiles[idx] = TileType::WoodFloor;
|
||||||
|
let idx = build_data.map.xy_idx(x, y + 3);
|
||||||
|
build_data.map.tiles[idx] = TileType::Fence;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set end of pier to fences
|
||||||
|
for y in y + 1..y + pier_width - 1 {
|
||||||
|
let idx = build_data.map.xy_idx(2 + start_roll, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::Fence;
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
|
||||||
|
pier_idxs.push(build_data.map.xy_idx(largest_water_width + sand_width, y + 1));
|
||||||
|
pier_idxs.push(build_data.map.xy_idx(largest_water_width + sand_width, y + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pier_idxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn town_walls(
|
||||||
|
&mut self,
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
) -> (HashSet<usize>, i32) {
|
||||||
|
let mut available_building_tiles: HashSet<usize> = HashSet::new();
|
||||||
|
|
||||||
|
const BORDER: i32 = 4;
|
||||||
|
const OFFSET_FROM_LEFT: i32 = 30 + BORDER;
|
||||||
|
const PATH_OFFSET_FROM_CENTRE: i32 = 4;
|
||||||
|
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;
|
||||||
|
rltk::console::log(format!("Placing road centred at y {}", wall_gap_y));
|
||||||
|
|
||||||
|
for y in BORDER..build_data.height - BORDER {
|
||||||
|
if !(y > wall_gap_y - HALF_PATH_THICKNESS && y < wall_gap_y + HALF_PATH_THICKNESS) {
|
||||||
|
let idx = build_data.map.xy_idx(OFFSET_FROM_LEFT, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::Wall;
|
||||||
|
|
||||||
|
let idx_right = build_data.map.xy_idx(build_data.width - BORDER, y);
|
||||||
|
build_data.map.tiles[idx_right] = TileType::Wall;
|
||||||
|
|
||||||
|
for x in OFFSET_FROM_LEFT + 1..build_data.width - BORDER {
|
||||||
|
let gravel_idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[gravel_idx] = TileType::Sand;
|
||||||
|
if y > BORDER + 1
|
||||||
|
&& y < build_data.height - BORDER - 1
|
||||||
|
&& x > OFFSET_FROM_LEFT + 2
|
||||||
|
&& x < build_data.width - BORDER - 1
|
||||||
|
{
|
||||||
|
available_building_tiles.insert(gravel_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for x in OFFSET_FROM_LEFT - 1..build_data.width {
|
||||||
|
let road_idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[road_idx] = TileType::Road;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
|
||||||
|
for x in OFFSET_FROM_LEFT..build_data.width - BORDER + 1 {
|
||||||
|
let idx_top = build_data.map.xy_idx(x, BORDER - 1);
|
||||||
|
build_data.map.tiles[idx_top] = TileType::Wall;
|
||||||
|
let idx_bottom = build_data.map.xy_idx(x, build_data.height - BORDER);
|
||||||
|
build_data.map.tiles[idx_bottom] = TileType::Wall;
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
|
||||||
|
(available_building_tiles, wall_gap_y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn buildings(
|
||||||
|
&mut self,
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
available_building_tiles: &mut HashSet<usize>,
|
||||||
|
) -> Vec<(i32, i32, i32, i32)> {
|
||||||
|
let mut buildings: Vec<(i32, i32, i32, i32)> = Vec::new();
|
||||||
|
let mut n_buildings = 0;
|
||||||
|
|
||||||
|
const BORDER: i32 = 2;
|
||||||
|
const REQUIRED_BUILDINGS: i32 = 8;
|
||||||
|
const OFFSET_FROM_LEFT: i32 = 30;
|
||||||
|
const MIN_BUILDING_SIZE: i32 = 4;
|
||||||
|
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 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;
|
||||||
|
let mut possible = true;
|
||||||
|
for y in by..by + bh {
|
||||||
|
for x in bx..bx + bw {
|
||||||
|
if x < 0 || x > build_data.width - 1 || y < 0 || y > build_data.height - 1 {
|
||||||
|
possible = false;
|
||||||
|
} else {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
if !available_building_tiles.contains(&idx) {
|
||||||
|
possible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if possible {
|
||||||
|
n_buildings += 1;
|
||||||
|
buildings.push((bx, by, bw, bh));
|
||||||
|
for y in by..by + bh {
|
||||||
|
for x in bx..bx + bw {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
build_data.map.tiles[idx] = TileType::WoodFloor;
|
||||||
|
available_building_tiles.remove(&idx);
|
||||||
|
available_building_tiles.remove(&(idx + 1));
|
||||||
|
available_building_tiles.remove(&(idx + build_data.width as usize));
|
||||||
|
available_building_tiles.remove(&(idx - 1));
|
||||||
|
available_building_tiles.remove(&(idx - build_data.width as usize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
rltk::console::log(format!("Placed building {}", n_buildings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outlines
|
||||||
|
let mut mapclone = build_data.map.clone();
|
||||||
|
for y in BORDER..build_data.height - BORDER {
|
||||||
|
for x in OFFSET_FROM_LEFT + BORDER..build_data.width - BORDER {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
if build_data.map.tiles[idx] == TileType::WoodFloor {
|
||||||
|
let mut neighbours = 0;
|
||||||
|
if build_data.map.tiles[idx - 1] != TileType::WoodFloor {
|
||||||
|
neighbours += 1;
|
||||||
|
}
|
||||||
|
if build_data.map.tiles[idx + 1] != TileType::WoodFloor {
|
||||||
|
neighbours += 1;
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
neighbours += 1;
|
||||||
|
}
|
||||||
|
if neighbours > 0 {
|
||||||
|
mapclone.tiles[idx] = TileType::Wall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build_data.map = mapclone;
|
||||||
|
build_data.take_snapshot();
|
||||||
|
|
||||||
|
buildings
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_doors(
|
||||||
|
&mut self,
|
||||||
|
rng: &mut rltk::RandomNumberGenerator,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
buildings: &mut Vec<(i32, i32, i32, i32)>,
|
||||||
|
wall_gap_y: i32,
|
||||||
|
) -> Vec<usize> {
|
||||||
|
let mut doors = Vec::new();
|
||||||
|
for building in buildings.iter() {
|
||||||
|
let door_x = building.0 + 1 + rng.roll_dice(1, building.2 - 3);
|
||||||
|
let cy = building.1 + (building.3 / 2);
|
||||||
|
let idx = if cy > wall_gap_y {
|
||||||
|
// Door on north wall
|
||||||
|
build_data.map.xy_idx(door_x, building.1)
|
||||||
|
} else {
|
||||||
|
build_data.map.xy_idx(door_x, building.1 + building.3 - 1)
|
||||||
|
};
|
||||||
|
build_data.map.tiles[idx] = TileType::Floor;
|
||||||
|
build_data.spawn_list.push((idx, "door".to_string()));
|
||||||
|
doors.push(idx);
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
doors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_from_tiles_to_nearest_tiletype(
|
||||||
|
&mut self,
|
||||||
|
build_data: &mut BuilderMap,
|
||||||
|
tiles: &[usize],
|
||||||
|
tiletype: TileType,
|
||||||
|
new_road_tiletype: TileType,
|
||||||
|
include_new_tiles: bool,
|
||||||
|
) {
|
||||||
|
let mut roads = self.find_tiletype(build_data, tiletype);
|
||||||
|
|
||||||
|
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(
|
||||||
|
*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::PythagorasSquared.distance2d(
|
||||||
|
tile_pt,
|
||||||
|
rltk::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);
|
||||||
|
if path.success {
|
||||||
|
for step in path.steps.iter() {
|
||||||
|
let idx = *step as usize;
|
||||||
|
build_data.map.tiles[idx] = new_road_tiletype;
|
||||||
|
if include_new_tiles {
|
||||||
|
roads.push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_tiletype(&mut self, build_data: &mut BuilderMap, tile: TileType) -> Vec<usize> {
|
||||||
|
let mut found_tiles = Vec::new();
|
||||||
|
for y in 0..build_data.height {
|
||||||
|
for x in 0..build_data.width {
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
if build_data.map.tiles[idx] == tile {
|
||||||
|
found_tiles.push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found_tiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,9 +28,9 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let delta_x = i;
|
let delta_x = i;
|
||||||
let delta_y = j;
|
let delta_y = j;
|
||||||
|
|
||||||
if !(pos.x + delta_x < 1
|
if !(pos.x + delta_x < 0
|
||||||
|| pos.x + delta_x > map.width - 1
|
|| pos.x + delta_x > map.width - 1
|
||||||
|| pos.y + delta_y < 1
|
|| pos.y + delta_y < 0
|
||||||
|| pos.y + delta_y > map.height - 1)
|
|| pos.y + delta_y > map.height - 1)
|
||||||
{
|
{
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
@ -108,9 +108,9 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let delta_x = i;
|
let delta_x = i;
|
||||||
let delta_y = j;
|
let delta_y = j;
|
||||||
|
|
||||||
if !(pos.x + delta_x < 1
|
if !(pos.x + delta_x < 0
|
||||||
|| pos.x + delta_x > map.width - 1
|
|| pos.x + delta_x > map.width - 1
|
||||||
|| pos.y + delta_y < 1
|
|| pos.y + delta_y < 0
|
||||||
|| pos.y + delta_y > map.height - 1)
|
|| pos.y + delta_y > map.height - 1)
|
||||||
{
|
{
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
@ -177,9 +177,9 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState {
|
||||||
let delta_x = i;
|
let delta_x = i;
|
||||||
let delta_y = j;
|
let delta_y = j;
|
||||||
|
|
||||||
if !(pos.x + delta_x < 1
|
if !(pos.x + delta_x < 0
|
||||||
|| pos.x + delta_x > map.width - 1
|
|| pos.x + delta_x > map.width - 1
|
||||||
|| pos.y + delta_y < 1
|
|| pos.y + delta_y < 0
|
||||||
|| pos.y + delta_y > map.height - 1)
|
|| pos.y + delta_y > map.height - 1)
|
||||||
{
|
{
|
||||||
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
|
||||||
|
|
@ -281,9 +281,9 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> bool {
|
||||||
let names = ecs.read_storage::<Name>();
|
let names = ecs.read_storage::<Name>();
|
||||||
|
|
||||||
for (entity, _player, pos, viewshed) in (&entities, &mut players, &mut positions, &mut viewsheds).join() {
|
for (entity, _player, pos, viewshed) in (&entities, &mut players, &mut positions, &mut viewsheds).join() {
|
||||||
if pos.x + delta_x < 1
|
if pos.x + delta_x < 0
|
||||||
|| pos.x + delta_x > map.width - 1
|
|| pos.x + delta_x > map.width - 1
|
||||||
|| pos.y + delta_y < 1
|
|| pos.y + delta_y < 0
|
||||||
|| pos.y + delta_y > map.height - 1
|
|| pos.y + delta_y > map.height - 1
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||||
})
|
})
|
||||||
.with(Player {})
|
.with(Player {})
|
||||||
.with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true })
|
.with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true })
|
||||||
.with(Name { name: "wanderer".to_string(), plural: "wanderers".to_string() })
|
.with(Name { name: "you".to_string(), plural: "you".to_string() })
|
||||||
.with(CombatStats { max_hp: 12, hp: 12, defence: 0, power: 4 })
|
.with(CombatStats { max_hp: 12, hp: 12, defence: 0, power: 4 })
|
||||||
.with(HungerClock { state: HungerState::Satiated, duration: 50 })
|
.with(HungerClock { state: HungerState::Satiated, duration: 50 })
|
||||||
.with(Attributes {
|
.with(Attributes {
|
||||||
|
|
@ -36,7 +36,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consts
|
// Consts
|
||||||
const MAX_ENTITIES: i32 = 4;
|
const MAX_ENTITIES: i32 = 3;
|
||||||
|
|
||||||
/// Fills a room with stuff!
|
/// Fills a room with stuff!
|
||||||
pub fn spawn_room(
|
pub fn spawn_room(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue