From 2c7671b34846e73d738fdd44316be407b041b81f Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Wed, 23 Aug 2023 00:00:44 +0100 Subject: [PATCH] optional darken by distance and viewshed multiplier --- src/camera.rs | 14 ++++++-------- src/gui/identify_menu.rs | 1 - src/map/colours.rs | 8 ++++++-- src/map/mod.rs | 1 + src/map/themes.rs | 21 ++++++++++++++++++--- src/raws/rawmaster.rs | 7 ++++++- src/spawner.rs | 4 +++- 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index ab9a670..3e779ab 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -33,7 +33,8 @@ 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_renderables_for_id(idx, &*map); + let (glyph, fg, bg) = + crate::map::themes::get_tile_renderables_for_id(idx, &*map, Some(*ecs.fetch::())); ctx.set(x + x_offset, y + y_offset, fg, bg, glyph); } } else if SHOW_BOUNDARIES { @@ -63,18 +64,15 @@ 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 mut bg = if render.bg == (RGB { r: 0.0, g: 0.0, b: 0.0 }) { - crate::map::themes::get_tile_renderables_for_id(idx, &*map).2 - } else { - render.bg - }; + let mut bg = crate::map::themes::get_tile_renderables_for_id(idx, &*map, Some(*ecs.fetch::())).2; // Draw entities on visible tiles if map.visible_tiles[idx] { draw = true; } else { - fg = fg.mul(0.75); + fg = fg.mul(crate::map::NON_VISIBLE_MULTIPLIER); // We don't darken BG, because get_tile_renderables_for_id handles this. } + // Draw entities with minds within telepath range if !draw { if map.telepath_tiles[idx] { @@ -124,7 +122,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_renderables_for_id(idx, &*map); + let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id(idx, &*map, None); ctx.set(x, y, fg, bg, glyph); } } else if SHOW_BOUNDARIES { diff --git a/src/gui/identify_menu.rs b/src/gui/identify_menu.rs index deadb81..729144b 100644 --- a/src/gui/identify_menu.rs +++ b/src/gui/identify_menu.rs @@ -4,7 +4,6 @@ use super::{ }; use crate::{ gamelog, Beatitude, Entity, Equipped, InBackpack, Item, MasterDungeonMap, Name, ObfuscatedName, Renderable, State, - BUC, }; use rltk::prelude::*; use specs::prelude::*; diff --git a/src/map/colours.rs b/src/map/colours.rs index 3bd60a9..444ca29 100644 --- a/src/map/colours.rs +++ b/src/map/colours.rs @@ -1,4 +1,8 @@ -pub const NON_VISIBLE_MULTIPLIER: f32 = 0.7; +pub const NON_VISIBLE_MULTIPLIER: f32 = 0.3; +pub const MAX_DARKENING: f32 = 0.3; +pub const START_DARKEN_AT_N_TILES: f32 = 9.0; +pub const MAX_DARKEN_AT_N_TILES: f32 = 12.0; + pub const BLOODSTAIN_COLOUR: (u8, u8, u8) = (153, 0, 0); // DEFAULT THEME @@ -14,7 +18,7 @@ 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 HEAVY_FOLIAGE_COLOUR: (u8, u8, u8) = (5, 60, 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); diff --git a/src/map/mod.rs b/src/map/mod.rs index 56db550..e639ca4 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -10,6 +10,7 @@ pub use interval_spawning_system::try_spawn_interval; pub mod dungeon; pub use dungeon::{level_transition, MasterDungeonMap}; pub mod themes; +pub use colours::NON_VISIBLE_MULTIPLIER; // 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. diff --git a/src/map/themes.rs b/src/map/themes.rs index e801ef1..60ec90c 100644 --- a/src/map/themes.rs +++ b/src/map/themes.rs @@ -1,8 +1,10 @@ -use super::{colours::*, glyphs::*, Map, TileType}; -use rltk::RGB; +use super::{colours::*, glyphs::*, Map, Point, TileType}; +use rltk::prelude::*; use std::ops::{Add, Mul}; -pub fn get_tile_renderables_for_id(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RGB) { +const DARKEN_TILES_BY_DISTANCE: bool = true; + +pub fn get_tile_renderables_for_id(idx: usize, map: &Map, other_pos: Option) -> (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), @@ -19,6 +21,11 @@ pub fn get_tile_renderables_for_id(idx: usize, map: &Map) -> (rltk::FontCharType (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); + if other_pos.is_some() && DARKEN_TILES_BY_DISTANCE { + let distance = + darken_by_distance(Point::new(idx as i32 % map.width, idx as i32 / map.width), other_pos.unwrap()); + (fg, bg) = (fg.mul(distance), bg.mul(distance)); + } return (glyph, fg, bg); } @@ -241,3 +248,11 @@ pub fn multiply_by_float(rgb: rltk::RGB, offsets: (f32, f32, f32)) -> RGB { return rltk::RGB::from_f32(r, g, b); } + +fn darken_by_distance(pos: Point, other_pos: Point) -> f32 { + let distance = DistanceAlg::Pythagoras.distance2d(pos, other_pos) as f32; // Get distance in tiles. + let interp_factor = (distance - START_DARKEN_AT_N_TILES) + / (MAX_DARKEN_AT_N_TILES * crate::spawner::VIEWSHED_MOD - START_DARKEN_AT_N_TILES); + let interp_factor = interp_factor.max(0.0).min(1.0); // Clamp [0-1] + return 1.0 - interp_factor * (1.0 - MAX_DARKENING); +} diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index 8e9a74f..f63467a 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -3,6 +3,7 @@ use crate::components::*; use crate::gamesystem::*; use crate::gui::Ancestry; use crate::random_table::RandomTable; +use crate::spawner; use crate::LOG_SPAWNING; use regex::Regex; use rltk::prelude::*; @@ -380,7 +381,11 @@ pub fn spawn_named_mob( eb = ecs.create_entity().marked::>(); eb = spawn_position(pos, eb, key, raws); eb = eb.with(Name { name: mob_template.name.clone(), plural: mob_template.name.clone() }); - eb = eb.with(Viewshed { visible_tiles: Vec::new(), range: mob_template.vision_range, dirty: true }); + eb = eb.with(Viewshed { + visible_tiles: Vec::new(), + range: (mob_template.vision_range as f32 * spawner::VIEWSHED_MOD) as i32, + dirty: true, + }); if let Some(telepath) = &mob_template.telepathy_range { eb = eb.with(Telepath { telepath_tiles: Vec::new(), range: *telepath, dirty: true }); } diff --git a/src/spawner.rs b/src/spawner.rs index a5a8097..cfe44fd 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -9,6 +9,8 @@ use specs::prelude::*; use specs::saveload::{MarkedBuilder, SimpleMarker}; use std::collections::HashMap; +pub const VIEWSHED_MOD: f32 = 1.25; + /// Spawns the player and returns his/her entity object. pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { let mut skills = Skills { skills: HashMap::new() }; @@ -30,7 +32,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { .with(Player {}) .with(Mind {}) .with(Faction { name: "player".to_string() }) - .with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true }) + .with(Viewshed { visible_tiles: Vec::new(), range: (12 as f32 * VIEWSHED_MOD) as i32, dirty: true }) .with(Name { name: "you".to_string(), plural: "you".to_string() }) .with(HungerClock { state: HungerState::Satiated, duration: 1200 }) .with(Attributes {