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,
|
"vision_range": 4,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d3" }]
|
"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",
|
"id": "chicken_little",
|
||||||
"name": "chick",
|
"name": "chick",
|
||||||
|
|
@ -105,6 +123,45 @@
|
||||||
"vision_range": 4,
|
"vision_range": 4,
|
||||||
"attacks": [{ "name": "bites", "hit_bonus": 0, "damage": "1d2" }]
|
"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",
|
"id": "rat_giant",
|
||||||
"name": "giant rat",
|
"name": "giant rat",
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@
|
||||||
{ "id": "kobold", "weight": 1, "difficulty": 1},
|
{ "id": "kobold", "weight": 1, "difficulty": 1},
|
||||||
{ "id": "fox", "weight": 1, "difficulty": 1},
|
{ "id": "fox", "weight": 1, "difficulty": 1},
|
||||||
{ "id": "jackal", "weight": 4, "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": "rat_giant", "weight": 2, "difficulty": 2},
|
||||||
{ "id": "coyote", "weight": 4, "difficulty": 2},
|
{ "id": "coyote", "weight": 4, "difficulty": 2},
|
||||||
{ "id": "dog_little", "weight": 1, "difficulty": 3},
|
{ "id": "dog_little", "weight": 1, "difficulty": 3},
|
||||||
|
|
@ -74,9 +76,12 @@
|
||||||
{ "id": "orc_large", "weight": 1, "difficulty": 3},
|
{ "id": "orc_large", "weight": 1, "difficulty": 3},
|
||||||
{ "id": "goblin_chieftain", "weight": 1, "difficulty": 3},
|
{ "id": "goblin_chieftain", "weight": 1, "difficulty": 3},
|
||||||
{ "id": "ogre", "weight": 1, "difficulty": 4},
|
{ "id": "ogre", "weight": 1, "difficulty": 4},
|
||||||
|
{ "id": "horse_little", "weight": 2, "difficulty": 4},
|
||||||
{ "id": "dog", "weight": 1, "difficulty": 5},
|
{ "id": "dog", "weight": 1, "difficulty": 5},
|
||||||
{ "id": "wolf", "weight": 2, "difficulty": 6},
|
{ "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 {
|
if t_x >= 0 && t_x < map.width && t_y >= 0 && t_y < map.height {
|
||||||
let idx = map.xy_idx(t_x, t_y);
|
let idx = map.xy_idx(t_x, t_y);
|
||||||
if map.revealed_tiles[idx] {
|
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);
|
ctx.set(x + x_offset, y + y_offset, fg, bg, glyph);
|
||||||
}
|
}
|
||||||
} else if SHOW_BOUNDARIES {
|
} 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 {
|
if pos.x < max_x && pos.y < max_y && pos.x >= min_x && pos.y >= min_y {
|
||||||
let mut draw = false;
|
let mut draw = false;
|
||||||
let mut fg = render.fg;
|
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
|
// Draw entities on visible tiles
|
||||||
if map.visible_tiles[idx] {
|
if map.visible_tiles[idx] {
|
||||||
draw = true;
|
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 {
|
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) = 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);
|
ctx.set(x, y, fg, bg, glyph);
|
||||||
}
|
}
|
||||||
} else if SHOW_BOUNDARIES {
|
} else if SHOW_BOUNDARIES {
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,21 @@ impl Tooltip {
|
||||||
return self.lines.len() as i32 + 2i32;
|
return self.lines.len() as i32 + 2i32;
|
||||||
}
|
}
|
||||||
fn render(&self, ctx: &mut Rltk, x: i32, y: i32) {
|
fn render(&self, ctx: &mut Rltk, x: i32, y: i32) {
|
||||||
|
let white = RGB::named(rltk::WHITE);
|
||||||
let weak = RGB::named(rltk::CYAN);
|
let weak = RGB::named(rltk::CYAN);
|
||||||
let strong = RGB::named(rltk::ORANGE);
|
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));
|
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() {
|
for (i, s) in self.lines.iter().enumerate() {
|
||||||
let col = if i == 0 {
|
let col = if i == 0 {
|
||||||
RGB::named(WHITE)
|
white
|
||||||
} else if s.starts_with('-') {
|
} else if s.starts_with('-') {
|
||||||
weak
|
weak
|
||||||
} else {
|
} else if s.starts_with('*') {
|
||||||
strong
|
strong
|
||||||
|
} else {
|
||||||
|
attribute
|
||||||
};
|
};
|
||||||
ctx.print_color(x + 1, y + i as i32 + 1, col, RGB::named(BLACK), &s);
|
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.intelligence.bonus > 2 { s += "smart "};
|
||||||
if a.wisdom.bonus < -2 { s += "unwise "};
|
if a.wisdom.bonus < -2 { s += "unwise "};
|
||||||
if a.wisdom.bonus > 2 { s += "wisened "};
|
if a.wisdom.bonus > 2 { s += "wisened "};
|
||||||
if a.charisma.bonus < -2 { s += "ugly "};
|
if a.charisma.bonus < -2 { s += "ugly"};
|
||||||
if a.charisma.bonus > 2 { s += "attractive "};
|
if a.charisma.bonus > 2 { s += "attractive"};
|
||||||
if !s.is_empty() {
|
if !s.is_empty() {
|
||||||
|
if s.ends_with(" ") {
|
||||||
|
s.pop();
|
||||||
|
}
|
||||||
tip.add(s);
|
tip.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,13 +121,12 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
||||||
|
|
||||||
if tooltips.is_empty() { return ; }
|
if tooltips.is_empty() { return ; }
|
||||||
|
|
||||||
let box_gray : RGB = RGB::from_hex("#999999").expect("Oops");
|
|
||||||
let white = RGB::named(rltk::WHITE);
|
let white = RGB::named(rltk::WHITE);
|
||||||
|
|
||||||
let arrow;
|
let arrow;
|
||||||
let arrow_x;
|
let arrow_x;
|
||||||
let arrow_y = mouse_pos.1;
|
let arrow_y = mouse_pos.1;
|
||||||
if mouse_pos.0 < 50 {
|
if mouse_pos.0 < 35 {
|
||||||
// Render to the left
|
// Render to the left
|
||||||
arrow = to_cp437('→');
|
arrow = to_cp437('→');
|
||||||
arrow_x = mouse_pos.0 - 1;
|
arrow_x = mouse_pos.0 - 1;
|
||||||
|
|
@ -129,7 +135,7 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
||||||
arrow = to_cp437('←');
|
arrow = to_cp437('←');
|
||||||
arrow_x = mouse_pos.0 + 1;
|
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;
|
let mut total_height = 0;
|
||||||
for t in tooltips.iter() {
|
for t in tooltips.iter() {
|
||||||
|
|
@ -142,10 +148,10 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut Rltk) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for t in tooltips.iter() {
|
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())
|
mouse_pos.0 - (1 + t.width())
|
||||||
} else {
|
} else {
|
||||||
mouse_pos.0 + (1 + t.width())
|
mouse_pos.0 + (1 + 1)
|
||||||
};
|
};
|
||||||
t.render(ctx, x, y);
|
t.render(ctx, x, y);
|
||||||
y += t.height();
|
y += t.height();
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ mod rex_assets;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
//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 {
|
||||||
|
|
|
||||||
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 serde::{Deserialize, Serialize};
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
pub mod colours;
|
||||||
|
mod glyphs;
|
||||||
mod tiletype;
|
mod tiletype;
|
||||||
pub use tiletype::{tile_cost, tile_opaque, tile_walkable, TileType};
|
pub use tiletype::{tile_cost, tile_opaque, tile_walkable, TileType};
|
||||||
pub mod themes;
|
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.
|
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],
|
||||||
colour_offset: vec![(1.0, 1.0, 1.0); 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],
|
blocked: vec![false; map_tile_count],
|
||||||
id: new_id,
|
id: new_id,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
@ -60,7 +62,6 @@ impl Map {
|
||||||
tile_content: vec![Vec::new(); map_tile_count],
|
tile_content: vec![Vec::new(); map_tile_count],
|
||||||
};
|
};
|
||||||
|
|
||||||
const HALF_OFFSET: u8 = 5;
|
|
||||||
const OFFSET_PERCENT: i32 = 10;
|
const OFFSET_PERCENT: i32 = 10;
|
||||||
const TWICE_OFFSET: i32 = OFFSET_PERCENT * 2;
|
const TWICE_OFFSET: i32 = OFFSET_PERCENT * 2;
|
||||||
let mut rng = rltk::RandomNumberGenerator::new();
|
let mut rng = rltk::RandomNumberGenerator::new();
|
||||||
|
|
|
||||||
|
|
@ -1,109 +1,70 @@
|
||||||
use super::{Map, TileType};
|
use super::{colours::*, glyphs::*, Map, TileType};
|
||||||
use rltk::RGB;
|
use rltk::RGB;
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{Add, Mul};
|
||||||
|
|
||||||
pub fn offset(rgb: rltk::RGB, offsets: (f32, f32, f32)) -> RGB {
|
pub fn get_tile_renderables_for_id(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) {
|
||||||
let r = rgb.r * offsets.0;
|
let (glyph, mut fg, mut bg) = match map.id {
|
||||||
let g = rgb.g * offsets.1;
|
2 => get_forest_theme_renderables(idx, map),
|
||||||
let b = rgb.b * offsets.2;
|
_ => get_default_theme_renderables(idx, map),
|
||||||
|
};
|
||||||
|
|
||||||
return rltk::RGB::from_f32(r, g, b);
|
// If one of the colours was left blank, make them the same.
|
||||||
}
|
|
||||||
|
|
||||||
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 fg == RGB::new() {
|
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);
|
fg = fg.add(map.additional_fg_offset);
|
||||||
bg = offset(bg, offsets);
|
(fg, bg) = apply_colour_offset(fg, bg, map, idx);
|
||||||
|
bg = apply_bloodstain_if_necessary(bg, map, idx);
|
||||||
if !map.visible_tiles[idx] {
|
(fg, bg) = darken_if_not_visible(fg, bg, map, idx);
|
||||||
fg = fg.mul(0.7);
|
|
||||||
bg = bg.mul(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (glyph, fg, bg);
|
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 {
|
fn is_revealed_and_wall(map: &Map, x: i32, y: i32) -> bool {
|
||||||
let idx = map.xy_idx(x, y);
|
let idx = map.xy_idx(x, y);
|
||||||
map.tiles[idx] == TileType::Wall && map.revealed_tiles[idx]
|
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?
|
_ => 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)
|
// Impassable (transparent)
|
||||||
DeepWater,
|
DeepWater,
|
||||||
Fence,
|
Fence,
|
||||||
|
Bars,
|
||||||
// Floors (walkable)
|
// Floors (walkable)
|
||||||
Floor,
|
Floor,
|
||||||
WoodFloor,
|
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;
|
use fill_edges::FillEdges;
|
||||||
mod town;
|
mod town;
|
||||||
use town::town_builder;
|
use town::town_builder;
|
||||||
|
mod forest;
|
||||||
|
use forest::forest_builder;
|
||||||
|
|
||||||
// Shared data to be passed around build chain
|
// Shared data to be passed around build chain
|
||||||
pub struct BuilderMap {
|
pub struct BuilderMap {
|
||||||
|
|
@ -342,6 +344,7 @@ pub fn level_builder(new_id: i32, rng: &mut rltk::RandomNumberGenerator, width:
|
||||||
let difficulty = new_id;
|
let difficulty = new_id;
|
||||||
match new_id {
|
match new_id {
|
||||||
1 => town_builder(new_id, rng, width, height),
|
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),
|
_ => random_builder(new_id, rng, width, height, difficulty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue