Fog of war lifts three tiles beyond sight
This commit is contained in:
1 parent
f164293d21
commit
3492eacd59
2 files changed
+65
-13
No files matched your search
+64
-12
@@ -7,7 +7,8 @@ use crate::map::*;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
const SIGHT: i32 = 6; // tiles a creature sees along open ground
|
||||
const START_LIGHT: i32 = 5; // tiles of known ground around a master's core
|
||||
const START_LIGHT: i32 = 4; // known core room: four tiles from the core centre
|
||||
const SHADOW_LIFT: i32 = 3; // terrain is remembered this many tiles beyond anything currently in sight
|
||||
const FOG_EVERY: f32 = 0.4;
|
||||
|
||||
// explored tiles in savegames: one bit per tile, base64
|
||||
@@ -45,13 +46,32 @@ impl Map {
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub(crate) fn own_core_corner(&self) -> (i32, i32) {
|
||||
if self.me_side == 0 {
|
||||
return self.map.core;
|
||||
}
|
||||
let owner = Owner::of_side(self.me_side);
|
||||
let mut core: Option<(i32, i32)> = None;
|
||||
for i in 0..self.map.t.len() {
|
||||
let t = self.map.t[i];
|
||||
if t.kind == Kind::Core && t.owner == owner {
|
||||
let (x, y) = xy(i);
|
||||
core = Some(match core {
|
||||
Some((cx, cy)) => (cx.min(x), cy.min(y)),
|
||||
None => (x, y),
|
||||
});
|
||||
}
|
||||
}
|
||||
core.unwrap_or(self.map.core)
|
||||
}
|
||||
|
||||
pub fn init_fog(&mut self) {
|
||||
let n = self.map.t.len();
|
||||
self.map.explored = vec![false; n];
|
||||
self.map.visible = vec![false; n];
|
||||
self.fog_t = 0.0;
|
||||
// the nearest portal is known from the start (the dungeon feels where creatures come from)
|
||||
let (cx, cy) = self.map.core;
|
||||
let (cx, cy) = self.own_core_corner();
|
||||
if let Some(&(px, py)) = self.map.portals.iter().min_by_key(|&&(px, py)| (px - cx).pow(2) + (py - cy).pow(2)) {
|
||||
for y in py - 3..=py + 5 {
|
||||
for x in px - 3..=px + 5 {
|
||||
@@ -79,21 +99,26 @@ impl Game {
|
||||
}
|
||||
let mut vis = vec![false; n];
|
||||
let (w, h) = (mw() as i32, mh() as i32);
|
||||
// own ground and everything around it
|
||||
let (cx, cy) = self.own_core_corner();
|
||||
let core_start = (cx - 3, cy - 3, cx + 5, cy + 5);
|
||||
let in_core_start = |x: i32, y: i32| x >= core_start.0 && x <= core_start.2 && y >= core_start.1 && y <= core_start.3;
|
||||
// own ground and the ground around it, except straight outside the core's starting room
|
||||
for i in 0..n {
|
||||
if self.map.t[i].owner == self.me {
|
||||
let (x, y) = xy(i);
|
||||
vis[i] = true;
|
||||
let in_start = in_core_start(x, y);
|
||||
for dy in -1..=1 {
|
||||
for dx in -1..=1 {
|
||||
if inb(x + dx, y + dy) {
|
||||
vis[idx(x + dx, y + dy)] = true;
|
||||
let (nx, ny) = (x + dx, y + dy);
|
||||
if inb(nx, ny) && !(in_start && !in_core_start(nx, ny)) {
|
||||
vis[idx(nx, ny)] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// the master is never blind at home: the shadow starts away from the core
|
||||
let (cx, cy) = self.map.core;
|
||||
// the master is never blind at home: the shadow begins five tiles from the core centre
|
||||
for dy in -START_LIGHT..=START_LIGHT {
|
||||
for dx in -START_LIGHT..=START_LIGHT {
|
||||
let (x, y) = (cx + 1 + dx, cy + 1 + dy);
|
||||
@@ -109,6 +134,8 @@ impl Game {
|
||||
let mut q = VecDeque::new();
|
||||
for (sid, &(start, r)) in eyes.iter().enumerate() {
|
||||
let sid = sid as u32 + 1;
|
||||
let (sx, sy) = xy(start);
|
||||
let starts_in_core_start = in_core_start(sx, sy);
|
||||
q.clear();
|
||||
q.push_back((start, 0));
|
||||
stamp[start] = sid;
|
||||
@@ -120,7 +147,7 @@ impl Game {
|
||||
let (x, y) = xy(i);
|
||||
for &(dx, dy) in &DIR8 {
|
||||
let (nx, ny) = (x + dx, y + dy);
|
||||
if nx >= 0 && ny >= 0 && nx < w && ny < h {
|
||||
if nx >= 0 && ny >= 0 && nx < w && ny < h && !(starts_in_core_start && !in_core_start(nx, ny)) {
|
||||
let j = idx(nx, ny);
|
||||
if stamp[j] != sid {
|
||||
stamp[j] = sid;
|
||||
@@ -130,6 +157,19 @@ impl Game {
|
||||
}
|
||||
}
|
||||
}
|
||||
let lifted = vis.clone();
|
||||
for i in 0..n {
|
||||
if lifted[i] {
|
||||
let (x, y) = xy(i);
|
||||
for dy in -SHADOW_LIFT..=SHADOW_LIFT {
|
||||
for dx in -SHADOW_LIFT..=SHADOW_LIFT {
|
||||
if inb(x + dx, y + dy) {
|
||||
self.map.explored[idx(x + dx, y + dy)] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i in 0..n {
|
||||
if vis[i] {
|
||||
self.map.explored[i] = true;
|
||||
@@ -156,15 +196,27 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn fog_lifts_around_the_dungeon_and_is_saved() {
|
||||
let mut g = Game::new(6, 64, 64);
|
||||
let map = Map::generate_with(6, 64, 64, &GenOpts { portals: Some(0), treasures: Some(0), gate: false, core_y: None });
|
||||
let mut g = Game::from_map(map, 6);
|
||||
g.init_fog();
|
||||
let (cx, cy) = g.map.core;
|
||||
assert!(g.map.shown(idx(cx + 1, cy + 1)));
|
||||
assert!(g.map.shown(idx(cx + 5, cy + 1)), "the core's starting room is known");
|
||||
assert!(g.map.shown(idx(cx + 6, cy + 1)), "the wall just beyond the start is lifted");
|
||||
assert!(g.map.shown(idx(cx + 8, cy + 1)), "three tiles beyond the wall are lifted");
|
||||
assert!(!g.map.shown(idx(cx + 9, cy + 1)), "the shadow starts beyond the lifted wall");
|
||||
assert!(g.map.shown(idx(cx - 6, cy + 1)), "three tiles beyond the wall are lifted");
|
||||
assert!(!g.map.shown(idx(cx - 7, cy + 1)), "the shadow starts beyond the lifted wall");
|
||||
assert!(!g.map.shown(idx(60, 60)), "far away is unexplored");
|
||||
let explored = g.map.explored.iter().filter(|&&b| b).count();
|
||||
// a creature walking out explores more
|
||||
g.spawn(EK::Kobold, false, cx as f32 + 1.5, cy as f32 - 2.5, 1);
|
||||
// claimed ground outside the lifted start area lifts the shadow there
|
||||
let out = idx(cx + 12, cy + 1);
|
||||
g.map.t[out].kind = Kind::Floor;
|
||||
g.map.t[out].owner = Owner::Player;
|
||||
g.spawn(EK::Kobold, false, cx as f32 + 12.5, cy as f32 + 1.5, 1);
|
||||
g.update_fog(1.0);
|
||||
assert!(g.map.explored.iter().filter(|&&b| b).count() >= explored);
|
||||
assert!(g.map.shown(out), "own ground beyond the lifted start is known");
|
||||
assert!(g.map.explored.iter().filter(|&&b| b).count() > explored);
|
||||
// savegame round trip
|
||||
let json = crate::save::to_json(&g, &crate::render3d::Cam::new(0.0, 0.0), &crate::settings::Settings::default());
|
||||
let l = crate::save::from_bytes(json.as_bytes()).unwrap();
|
||||
|
||||
Reference in new issue
Block a user