building and theming the forest
This commit is contained in:
parent
3e9ebaa002
commit
42113ad6a4
12 changed files with 327 additions and 111 deletions
|
|
@ -96,6 +96,24 @@
|
|||
"vision_range": 4,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }]
|
||||
},
|
||||
{
|
||||
"id": "deer_little",
|
||||
"name": "fawn",
|
||||
"renderable": { "glyph": "q", "fg": "#a57037", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"bac": 8,
|
||||
"vision_range": 8,
|
||||
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
||||
},
|
||||
{
|
||||
"id": "sheep_little",
|
||||
"name": "lamb",
|
||||
"renderable": { "glyph": "q", "fg": "#e7e7e7", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"bac": 10,
|
||||
"vision_range": 4,
|
||||
"attacks": [{ "name": "kicks", "hit_bonus": 0, "damage": "1d2" }]
|
||||
},
|
||||
{
|
||||
"id": "chicken_little",
|
||||
"name": "chick",
|
||||
|
|
@ -105,6 +123,45 @@
|
|||
"vision_range": 4,
|
||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
||||
},
|
||||
{
|
||||
"id": "horse_little",
|
||||
"name": "pony",
|
||||
"renderable": { "glyph": "u", "fg": "#b36c29", "bg": "#000000", "order": 1 },
|
||||
"flags": ["BYSTANDER", "BLOCKS_TILE"],
|
||||
"level": 3,
|
||||
"bac": 6,
|
||||
"vision_range": 8,
|
||||
"attacks": [
|
||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d6" },
|
||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "horse",
|
||||
"name": "horse",
|
||||
"renderable": { "glyph": "u", "fg": "#744d29", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"level": 5,
|
||||
"bac": 5,
|
||||
"vision_range": 8,
|
||||
"attacks": [
|
||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d8" },
|
||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "horse_large",
|
||||
"name": "warhorse",
|
||||
"renderable": { "glyph": "u", "fg": "#8a3520", "bg": "#000000", "order": 1 },
|
||||
"flags": ["MONSTER", "BLOCKS_TILE"],
|
||||
"level": 7,
|
||||
"bac": 4,
|
||||
"vision_range": 8,
|
||||
"attacks": [
|
||||
{ "name": "kicks", "hit_bonus": 0, "damage": "1d10" },
|
||||
{ "name": "bites", "hit_bonus": 0, "damage": "1d4" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rat_giant",
|
||||
"name": "giant rat",
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@
|
|||
{ "id": "kobold", "weight": 1, "difficulty": 1},
|
||||
{ "id": "fox", "weight": 1, "difficulty": 1},
|
||||
{ "id": "jackal", "weight": 4, "difficulty": 1},
|
||||
{ "id": "deer_little", "weight": 1, "difficulty": 1},
|
||||
{ "id": "sheep_little", "weight": 1, "difficulty": 1},
|
||||
{ "id": "rat_giant", "weight": 2, "difficulty": 2},
|
||||
{ "id": "coyote", "weight": 4, "difficulty": 2},
|
||||
{ "id": "dog_little", "weight": 1, "difficulty": 3},
|
||||
|
|
@ -74,9 +76,12 @@
|
|||
{ "id": "orc_large", "weight": 1, "difficulty": 3},
|
||||
{ "id": "goblin_chieftain", "weight": 1, "difficulty": 3},
|
||||
{ "id": "ogre", "weight": 1, "difficulty": 4},
|
||||
{ "id": "horse_little", "weight": 2, "difficulty": 4},
|
||||
{ "id": "dog", "weight": 1, "difficulty": 5},
|
||||
{ "id": "wolf", "weight": 2, "difficulty": 6},
|
||||
{ "id": "dog_large", "weight": 1, "difficulty": 7}
|
||||
{ "id": "dog_large", "weight": 1, "difficulty": 7},
|
||||
{ "id": "horse", "weight": 2, "difficulty": 7},
|
||||
{ "id": "horse_large", "weight": 2, "difficulty": 9}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
|
|||
if t_x >= 0 && t_x < map.width && t_y >= 0 && t_y < map.height {
|
||||
let idx = map.xy_idx(t_x, t_y);
|
||||
if map.revealed_tiles[idx] {
|
||||
let (glyph, fg, bg) = crate::map::themes::get_tile_glyph(idx, &*map);
|
||||
let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id(idx, &*map);
|
||||
ctx.set(x + x_offset, y + y_offset, fg, bg, glyph);
|
||||
}
|
||||
} else if SHOW_BOUNDARIES {
|
||||
|
|
@ -63,7 +63,7 @@ pub fn render_camera(ecs: &World, ctx: &mut Rltk) {
|
|||
if pos.x < max_x && pos.y < max_y && pos.x >= min_x && pos.y >= min_y {
|
||||
let mut draw = false;
|
||||
let mut fg = render.fg;
|
||||
let (_glyph, _fg, bg) = crate::map::themes::get_tile_glyph(idx, &*map);
|
||||
let (_glyph, _fg, bg) = crate::map::themes::get_tile_renderables_for_id(idx, &*map);
|
||||
// Draw entities on visible tiles
|
||||
if map.visible_tiles[idx] {
|
||||
draw = true;
|
||||
|
|
@ -114,7 +114,7 @@ pub fn render_debug_map(map: &Map, ctx: &mut Rltk) {
|
|||
if tx >= 0 && tx < map_width && ty >= 0 && ty < map_height {
|
||||
let idx = map.xy_idx(tx, ty);
|
||||
if map.revealed_tiles[idx] {
|
||||
let (glyph, fg, bg) = crate::map::themes::get_tile_glyph(idx, &*map);
|
||||
let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id(idx, &*map);
|
||||
ctx.set(x, y, fg, bg, glyph);
|
||||
}
|
||||
} else if SHOW_BOUNDARIES {
|
||||
|
|
|
|||
|
|
@ -26,17 +26,21 @@ impl Tooltip {
|
|||
return self.lines.len() as i32 + 2i32;
|
||||
}
|
||||
fn render(&self, ctx: &mut Rltk, x: i32, y: i32) {
|
||||
let white = RGB::named(rltk::WHITE);
|
||||
let weak = RGB::named(rltk::CYAN);
|
||||
let strong = RGB::named(rltk::ORANGE);
|
||||
let attribute = RGB::named(rltk::PINK);
|
||||
|
||||
ctx.draw_box(x, y, self.width() - 1, self.height() - 1, RGB::named(WHITE), RGB::named(BLACK));
|
||||
for (i, s) in self.lines.iter().enumerate() {
|
||||
let col = if i == 0 {
|
||||
RGB::named(WHITE)
|
||||
white
|
||||
} else if s.starts_with('-') {
|
||||
weak
|
||||
} else {
|
||||
} else if s.starts_with('*') {
|
||||
strong
|
||||
} else {
|
||||
attribute
|
||||
};
|
||||
ctx.print_color(x + 1, y + i as i32 + 1, col, RGB::named(BLACK), &s);
|
||||
}
|
||||
|
|
@ -91,9 +95,12 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
if a.intelligence.bonus > 2 { s += "smart "};
|
||||
if a.wisdom.bonus < -2 { s += "unwise "};
|
||||
if a.wisdom.bonus > 2 { s += "wisened "};
|
||||
if a.charisma.bonus < -2 { s += "ugly "};
|
||||
if a.charisma.bonus > 2 { s += "attractive "};
|
||||
if a.charisma.bonus < -2 { s += "ugly"};
|
||||
if a.charisma.bonus > 2 { s += "attractive"};
|
||||
if !s.is_empty() {
|
||||
if s.ends_with(" ") {
|
||||
s.pop();
|
||||
}
|
||||
tip.add(s);
|
||||
}
|
||||
}
|
||||
|
|
@ -114,13 +121,12 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
|
||||
if tooltips.is_empty() { return ; }
|
||||
|
||||
let box_gray : RGB = RGB::from_hex("#999999").expect("Oops");
|
||||
let white = RGB::named(rltk::WHITE);
|
||||
|
||||
let arrow;
|
||||
let arrow_x;
|
||||
let arrow_y = mouse_pos.1;
|
||||
if mouse_pos.0 < 50 {
|
||||
if mouse_pos.0 < 35 {
|
||||
// Render to the left
|
||||
arrow = to_cp437('→');
|
||||
arrow_x = mouse_pos.0 - 1;
|
||||
|
|
@ -129,7 +135,7 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
arrow = to_cp437('←');
|
||||
arrow_x = mouse_pos.0 + 1;
|
||||
}
|
||||
ctx.set(arrow_x, arrow_y, white, box_gray, arrow);
|
||||
ctx.set(arrow_x, arrow_y, white, RGB::named(rltk::BLACK), arrow);
|
||||
|
||||
let mut total_height = 0;
|
||||
for t in tooltips.iter() {
|
||||
|
|
@ -142,10 +148,10 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
|||
}
|
||||
|
||||
for t in tooltips.iter() {
|
||||
let x = if mouse_pos.0 < 40 {
|
||||
let x = if mouse_pos.0 < 35 {
|
||||
mouse_pos.0 - (1 + t.width())
|
||||
} else {
|
||||
mouse_pos.0 + (1 + t.width())
|
||||
mouse_pos.0 + (1 + 1)
|
||||
};
|
||||
t.render(ctx, x, y);
|
||||
y += t.height();
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ mod rex_assets;
|
|||
extern crate lazy_static;
|
||||
|
||||
//Consts
|
||||
pub const SHOW_MAPGEN: bool = false;
|
||||
pub const SHOW_MAPGEN: bool = true;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum RunState {
|
||||
|
|
|
|||
24
src/map/colours.rs
Normal file
24
src/map/colours.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
pub const NON_VISIBLE_MULTIPLIER: f32 = 0.7;
|
||||
pub const BLOODSTAIN_COLOUR: (u8, u8, u8) = (153, 0, 0);
|
||||
|
||||
// DEFAULT THEME
|
||||
pub const DEFAULT_BG_COLOUR: (u8, u8, u8) = (29, 50, 50);
|
||||
pub const WALL_COLOUR: (u8, u8, u8) = (229, 191, 94);
|
||||
pub const FLOOR_COLOUR: (u8, u8, u8) = (25, 204, 122);
|
||||
pub const DOWN_STAIR_COLOUR: (u8, u8, u8) = (200, 200, 0);
|
||||
pub const WOOD_FLOOR_COLOUR: (u8, u8, u8) = (41, 30, 20);
|
||||
pub const FENCE_FG_COLOUR: (u8, u8, u8) = (110, 24, 0);
|
||||
pub const FENCE_COLOUR: (u8, u8, u8) = (45, 30, 10);
|
||||
pub const BRIDGE_COLOUR: (u8, u8, u8) = (42, 48, 37);
|
||||
pub const GRAVEL_COLOUR: (u8, u8, u8) = (26, 26, 53);
|
||||
pub const ROAD_COLOUR: (u8, u8, u8) = (8, 38, 40);
|
||||
pub const GRASS_COLOUR: (u8, u8, u8) = (9, 65, 6);
|
||||
pub const FOLIAGE_COLOUR: (u8, u8, u8) = (5, 60, 5);
|
||||
pub const HEAVY_FOLIAGE_COLOUR: (u8, u8, u8) = (5, 55, 5);
|
||||
pub const SAND_COLOUR: (u8, u8, u8) = (70, 70, 21);
|
||||
pub const SHALLOW_WATER_COLOUR: (u8, u8, u8) = (24, 47, 99);
|
||||
pub const DEEP_WATER_COLOUR: (u8, u8, u8) = (18, 33, 63);
|
||||
pub const BARS_COLOUR: (u8, u8, u8) = (100, 100, 100);
|
||||
|
||||
// FOREST THEME
|
||||
pub const FOREST_WALL_COLOUR: (u8, u8, u8) = (0, 153, 0);
|
||||
19
src/map/glyphs.rs
Normal file
19
src/map/glyphs.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// DEFAULT THEME
|
||||
pub const WALL_GLYPH: char = '#';
|
||||
pub const FLOOR_GLYPH: char = '.';
|
||||
pub const DOWN_STAIR_GLYPH: char = '>';
|
||||
pub const WOOD_FLOOR_GLYPH: char = '.';
|
||||
pub const FENCE_GLYPH: char = '=';
|
||||
pub const BRIDGE_GLYPH: char = '.';
|
||||
pub const GRAVEL_GLYPH: char = ';';
|
||||
pub const ROAD_GLYPH: char = '.';
|
||||
pub const GRASS_GLYPH: char = '"';
|
||||
pub const FOLIAGE_GLYPH: char = ':';
|
||||
pub const HEAVY_FOLIAGE_GLYPH: char = ';';
|
||||
pub const SAND_GLYPH: char = '.';
|
||||
pub const SHALLOW_WATER_GLYPH: char = '~';
|
||||
pub const DEEP_WATER_GLYPH: char = '≈';
|
||||
pub const BARS_GLYPH: char = '#';
|
||||
|
||||
// FOREST THEME
|
||||
pub const FOREST_WALL_GLYPH: char = '♣';
|
||||
|
|
@ -2,6 +2,8 @@ use rltk::{Algorithm2D, BaseMap, Point};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use specs::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
pub mod colours;
|
||||
mod glyphs;
|
||||
mod tiletype;
|
||||
pub use tiletype::{tile_cost, tile_opaque, tile_walkable, TileType};
|
||||
pub mod themes;
|
||||
|
|
@ -50,7 +52,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![(1.0, 1.0, 1.0); map_tile_count],
|
||||
additional_fg_offset: rltk::RGB::from_u8(HALF_OFFSET, HALF_OFFSET, HALF_OFFSET),
|
||||
additional_fg_offset: rltk::RGB::from_u8(OFFSET_PERCENT as u8, OFFSET_PERCENT as u8, OFFSET_PERCENT as u8),
|
||||
blocked: vec![false; map_tile_count],
|
||||
id: new_id,
|
||||
name: name.to_string(),
|
||||
|
|
@ -60,7 +62,6 @@ impl Map {
|
|||
tile_content: vec![Vec::new(); map_tile_count],
|
||||
};
|
||||
|
||||
const HALF_OFFSET: u8 = 5;
|
||||
const OFFSET_PERCENT: i32 = 10;
|
||||
const TWICE_OFFSET: i32 = OFFSET_PERCENT * 2;
|
||||
let mut rng = rltk::RandomNumberGenerator::new();
|
||||
|
|
|
|||
|
|
@ -1,109 +1,70 @@
|
|||
use super::{Map, TileType};
|
||||
use super::{colours::*, glyphs::*, Map, TileType};
|
||||
use rltk::RGB;
|
||||
use std::ops::{Add, Mul};
|
||||
|
||||
pub 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;
|
||||
pub fn get_tile_renderables_for_id(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||
let (glyph, mut fg, mut bg) = match map.id {
|
||||
2 => get_forest_theme_renderables(idx, map),
|
||||
_ => get_default_theme_renderables(idx, map),
|
||||
};
|
||||
|
||||
return rltk::RGB::from_f32(r, g, b);
|
||||
}
|
||||
|
||||
pub fn get_tile_glyph(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||
let offsets = map.colour_offset[idx];
|
||||
let glyph: rltk::FontCharType;
|
||||
let mut fg: RGB = RGB::new();
|
||||
let mut bg: RGB;
|
||||
|
||||
let default_bg: RGB = RGB::from_u8(29, 50, 50);
|
||||
|
||||
match map.tiles[idx] {
|
||||
TileType::Floor => {
|
||||
glyph = rltk::to_cp437('.');
|
||||
fg = RGB::from_f32(0.1, 0.8, 0.5);
|
||||
bg = default_bg;
|
||||
}
|
||||
TileType::WoodFloor => {
|
||||
glyph = rltk::to_cp437('.');
|
||||
bg = RGB::from_u8(41, 30, 20);
|
||||
}
|
||||
TileType::Fence => {
|
||||
glyph = rltk::to_cp437('=');
|
||||
fg = RGB::from_u8(110, 24, 0);
|
||||
bg = RGB::from_u8(45, 30, 10);
|
||||
}
|
||||
TileType::Wall => {
|
||||
let x = idx as i32 % map.width;
|
||||
let y = idx as i32 / map.width;
|
||||
glyph = wall_glyph(&*map, x, y);
|
||||
fg = RGB::from_f32(0.9, 0.75, 0.37);
|
||||
bg = default_bg;
|
||||
}
|
||||
TileType::DownStair => {
|
||||
glyph = rltk::to_cp437('>');
|
||||
fg = RGB::from_u8(200, 200, 0);
|
||||
bg = default_bg;
|
||||
}
|
||||
TileType::Bridge => {
|
||||
glyph = rltk::to_cp437('.');
|
||||
bg = RGB::from_u8(42, 48, 37);
|
||||
}
|
||||
TileType::Gravel => {
|
||||
glyph = rltk::to_cp437(';');
|
||||
bg = RGB::from_u8(26, 26, 53);
|
||||
}
|
||||
TileType::Road => {
|
||||
glyph = rltk::to_cp437('.');
|
||||
//fg = RGB::from_u8(112, 105, 94);
|
||||
bg = RGB::from_u8(8, 38, 40);
|
||||
}
|
||||
TileType::Grass => {
|
||||
glyph = rltk::to_cp437('"');
|
||||
bg = RGB::from_u8(9, 65, 6);
|
||||
}
|
||||
TileType::Foliage => {
|
||||
glyph = rltk::to_cp437(':');
|
||||
bg = RGB::from_u8(5, 60, 5);
|
||||
}
|
||||
TileType::HeavyFoliage => {
|
||||
glyph = rltk::to_cp437(';');
|
||||
bg = RGB::from_u8(5, 55, 5);
|
||||
}
|
||||
TileType::Sand => {
|
||||
glyph = rltk::to_cp437('.');
|
||||
bg = RGB::from_u8(70, 70, 21);
|
||||
}
|
||||
TileType::ShallowWater => {
|
||||
glyph = rltk::to_cp437('~');
|
||||
bg = RGB::from_u8(24, 47, 99);
|
||||
}
|
||||
TileType::DeepWater => {
|
||||
glyph = rltk::to_cp437('≈');
|
||||
bg = RGB::from_u8(18, 33, 63);
|
||||
}
|
||||
}
|
||||
if map.bloodstains.contains(&idx) {
|
||||
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 one of the colours was left blank, make them the same.
|
||||
if fg == RGB::new() {
|
||||
fg = fg.add(bg).add(map.additional_fg_offset).add(map.additional_fg_offset);
|
||||
fg = bg
|
||||
} else if bg == RGB::new() {
|
||||
bg = fg;
|
||||
}
|
||||
|
||||
fg = offset(fg, offsets);
|
||||
bg = offset(bg, offsets);
|
||||
|
||||
if !map.visible_tiles[idx] {
|
||||
fg = fg.mul(0.7);
|
||||
bg = bg.mul(0.7);
|
||||
}
|
||||
fg = fg.add(map.additional_fg_offset);
|
||||
(fg, bg) = apply_colour_offset(fg, bg, map, idx);
|
||||
bg = apply_bloodstain_if_necessary(bg, map, idx);
|
||||
(fg, bg) = darken_if_not_visible(fg, bg, map, idx);
|
||||
|
||||
return (glyph, fg, bg);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn get_default_theme_renderables(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||
let glyph: rltk::FontCharType;
|
||||
let mut fg: RGB = RGB::new();
|
||||
let mut bg: RGB = RGB::new();
|
||||
|
||||
match map.tiles[idx] {
|
||||
TileType::Floor => { glyph = rltk::to_cp437(FLOOR_GLYPH); fg = RGB::named(FLOOR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
||||
TileType::WoodFloor => { glyph = rltk::to_cp437(WOOD_FLOOR_GLYPH); bg = RGB::named(WOOD_FLOOR_COLOUR); }
|
||||
TileType::Fence => { glyph = rltk::to_cp437(FENCE_GLYPH); fg = RGB::named(FENCE_FG_COLOUR); bg = RGB::named(FENCE_COLOUR); }
|
||||
TileType::Wall => { let x = idx as i32 % map.width; let y = idx as i32 / map.width; glyph = wall_glyph(&*map, x, y); fg = RGB::named(WALL_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
||||
TileType::DownStair => { glyph = rltk::to_cp437(DOWN_STAIR_GLYPH); fg = RGB::named(DOWN_STAIR_COLOUR); bg = RGB::named(DEFAULT_BG_COLOUR); }
|
||||
TileType::Bridge => { glyph = rltk::to_cp437(BRIDGE_GLYPH); bg = RGB::named(BRIDGE_COLOUR); }
|
||||
TileType::Gravel => { glyph = rltk::to_cp437(GRAVEL_GLYPH); bg = RGB::named(GRAVEL_COLOUR); }
|
||||
TileType::Road => { glyph = rltk::to_cp437(ROAD_GLYPH); bg = RGB::named(ROAD_COLOUR); }
|
||||
TileType::Grass => { glyph = rltk::to_cp437(GRASS_GLYPH); bg = RGB::named(GRASS_COLOUR); }
|
||||
TileType::Foliage => { glyph = rltk::to_cp437(FOLIAGE_GLYPH); bg = RGB::named(FOLIAGE_COLOUR); }
|
||||
TileType::HeavyFoliage => { glyph = rltk::to_cp437(HEAVY_FOLIAGE_GLYPH); bg = RGB::named(HEAVY_FOLIAGE_COLOUR); }
|
||||
TileType::Sand => { glyph = rltk::to_cp437(SAND_GLYPH); bg = RGB::named(SAND_COLOUR); }
|
||||
TileType::ShallowWater => { glyph = rltk::to_cp437(SHALLOW_WATER_GLYPH); bg = RGB::named(SHALLOW_WATER_COLOUR); }
|
||||
TileType::DeepWater => { glyph = rltk::to_cp437(DEEP_WATER_GLYPH); bg = RGB::named(DEEP_WATER_COLOUR); }
|
||||
TileType::Bars => { glyph = rltk::to_cp437(BARS_GLYPH); fg = RGB::named(BARS_COLOUR); bg = RGB::named(FLOOR_COLOUR); }
|
||||
}
|
||||
return (glyph, fg, bg);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn get_forest_theme_renderables(idx:usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||
let glyph;
|
||||
let mut fg = RGB::new();
|
||||
let mut bg = RGB::new();
|
||||
|
||||
match map.tiles[idx] {
|
||||
TileType::Wall => { glyph = rltk::to_cp437(FOREST_WALL_GLYPH); fg = RGB::named(FOREST_WALL_COLOUR); bg = RGB::named(GRASS_COLOUR) }
|
||||
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); }
|
||||
_ => { (glyph, fg, _) = get_default_theme_renderables(idx, map); bg = RGB::named(GRASS_COLOUR) }
|
||||
}
|
||||
|
||||
(glyph, fg, bg)
|
||||
}
|
||||
|
||||
fn is_revealed_and_wall(map: &Map, x: i32, y: i32) -> bool {
|
||||
let idx = map.xy_idx(x, y);
|
||||
map.tiles[idx] == TileType::Wall && map.revealed_tiles[idx]
|
||||
|
|
@ -245,3 +206,33 @@ fn wall_glyph(map: &Map, x: i32, y: i32) -> rltk::FontCharType {
|
|||
_ => 35, // We missed one?
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_colour_offset(mut fg: RGB, mut bg: RGB, map: &Map, idx: usize) -> (RGB, RGB) {
|
||||
let offsets = map.colour_offset[idx];
|
||||
fg = multiply_by_float(fg.add(map.additional_fg_offset), offsets);
|
||||
bg = multiply_by_float(bg, offsets);
|
||||
return (fg, bg);
|
||||
}
|
||||
|
||||
fn darken_if_not_visible(mut fg: RGB, mut bg: RGB, map: &Map, idx: usize) -> (RGB, RGB) {
|
||||
if !map.visible_tiles[idx] {
|
||||
fg = fg.mul(NON_VISIBLE_MULTIPLIER);
|
||||
bg = bg.mul(NON_VISIBLE_MULTIPLIER);
|
||||
}
|
||||
return (fg, bg);
|
||||
}
|
||||
|
||||
fn apply_bloodstain_if_necessary(mut bg: RGB, map: &Map, idx: usize) -> RGB {
|
||||
if map.bloodstains.contains(&idx) {
|
||||
bg = bg.add(RGB::named(BLOODSTAIN_COLOUR));
|
||||
}
|
||||
return bg;
|
||||
}
|
||||
|
||||
pub fn multiply_by_float(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub enum TileType {
|
|||
// Impassable (transparent)
|
||||
DeepWater,
|
||||
Fence,
|
||||
Bars,
|
||||
// Floors (walkable)
|
||||
Floor,
|
||||
WoodFloor,
|
||||
|
|
|
|||
109
src/map_builders/forest.rs
Normal file
109
src/map_builders/forest.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use super::{
|
||||
AreaStartingPosition, BuilderChain, BuilderMap, CellularAutomataBuilder, CullUnreachable, MetaMapBuilder, TileType,
|
||||
VoronoiSpawning, XStart, YStart,
|
||||
};
|
||||
use rltk::prelude::*;
|
||||
|
||||
pub fn forest_builder(
|
||||
new_id: i32,
|
||||
_rng: &mut rltk::RandomNumberGenerator,
|
||||
width: i32,
|
||||
height: i32,
|
||||
difficulty: i32,
|
||||
) -> BuilderChain {
|
||||
let mut chain = BuilderChain::new(new_id, width, height, difficulty, "Into the Woods");
|
||||
chain.start_with(CellularAutomataBuilder::new());
|
||||
chain.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE));
|
||||
chain.with(CullUnreachable::new());
|
||||
chain.with(AreaStartingPosition::new(XStart::LEFT, YStart::CENTRE));
|
||||
// Setup an exit and spawn mobs
|
||||
chain.with(VoronoiSpawning::new());
|
||||
chain.with(RoadExit::new());
|
||||
return chain;
|
||||
}
|
||||
|
||||
pub struct RoadExit {}
|
||||
|
||||
impl MetaMapBuilder for RoadExit {
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl RoadExit {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Box<RoadExit> {
|
||||
return Box::new(RoadExit {});
|
||||
}
|
||||
|
||||
fn find_exit(&self, build_data: &mut BuilderMap, seed_x: i32, seed_y: i32) -> (i32, i32) {
|
||||
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
|
||||
if crate::map::tile_walkable(*tiletype) {
|
||||
available_floors.push((
|
||||
idx,
|
||||
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.");
|
||||
}
|
||||
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;
|
||||
let end_y = available_floors[0].0 as i32 / build_data.map.width;
|
||||
return (end_x, end_y);
|
||||
}
|
||||
|
||||
fn paint_road(&self, build_data: &mut BuilderMap, x: i32, y: i32) {
|
||||
if x < 1 || x > build_data.map.width - 2 || y < 1 || y > build_data.map.width - 2 {
|
||||
return;
|
||||
}
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
if build_data.map.tiles[idx] != TileType::DownStair {
|
||||
build_data.map.tiles[idx] = TileType::Road;
|
||||
}
|
||||
}
|
||||
|
||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
||||
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
||||
let (end_x, end_y) = self.find_exit(build_data, build_data.map.width - 2, build_data.height / 2);
|
||||
let end_idx = build_data.map.xy_idx(end_x, end_y);
|
||||
build_data.map.populate_blocked();
|
||||
|
||||
let path = a_star_search(start_idx, end_idx, &mut build_data.map);
|
||||
for idx in path.steps.iter() {
|
||||
let x = *idx as i32 % build_data.map.width;
|
||||
let y = *idx as i32 / build_data.map.width;
|
||||
self.paint_road(build_data, x, y);
|
||||
self.paint_road(build_data, x - 1, y);
|
||||
self.paint_road(build_data, x + 1, y);
|
||||
self.paint_road(build_data, x, y - 1);
|
||||
self.paint_road(build_data, x, y + 1);
|
||||
}
|
||||
build_data.take_snapshot();
|
||||
|
||||
let exit_dir = rng.roll_dice(1, 2);
|
||||
let (seed_x, seed_y, stream_start_x, stream_start_y) = if exit_dir == 1 {
|
||||
(build_data.map.width - 1, 1, 0, build_data.height - 1)
|
||||
} else {
|
||||
(build_data.map.width - 1, build_data.height - 1, 1, build_data.height - 1)
|
||||
};
|
||||
let (stairs_x, stairs_y) = self.find_exit(build_data, seed_x, seed_y);
|
||||
let stairs_idx = build_data.map.xy_idx(stairs_x, stairs_y);
|
||||
let (stream_x, stream_y) = self.find_exit(build_data, stream_start_x, stream_start_y);
|
||||
let stream_idx = build_data.map.xy_idx(stream_x, stream_y) as usize;
|
||||
let stream = a_star_search(stairs_idx, stream_idx, &mut build_data.map);
|
||||
for tile in stream.steps.iter() {
|
||||
if build_data.map.tiles[*tile as usize] == TileType::Floor {
|
||||
build_data.map.tiles[*tile as usize] = TileType::ShallowWater;
|
||||
}
|
||||
}
|
||||
build_data.map.tiles[stairs_idx] = TileType::DownStair;
|
||||
build_data.take_snapshot();
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,8 @@ mod fill_edges;
|
|||
use fill_edges::FillEdges;
|
||||
mod town;
|
||||
use town::town_builder;
|
||||
mod forest;
|
||||
use forest::forest_builder;
|
||||
|
||||
// Shared data to be passed around build chain
|
||||
pub struct BuilderMap {
|
||||
|
|
@ -342,6 +344,7 @@ pub fn level_builder(new_id: i32, rng: &mut rltk::RandomNumberGenerator, width:
|
|||
let difficulty = new_id;
|
||||
match new_id {
|
||||
1 => town_builder(new_id, rng, width, height),
|
||||
2 => forest_builder(new_id, rng, width, height, difficulty),
|
||||
_ => random_builder(new_id, rng, width, height, difficulty),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue