neurodoom 0.6.7

Deterministic no_std Doom engine with semantic and depth perception buffers for AI
Documentation
//! Shared helpers for `demo.rs` and `ai_multiplayer.rs`.
//!
//! Included via `#[path = "common.rs"] mod common;` from each example.
//! Not a public API — kept out of the library crate because it depends
//! on `std` and `minifb`.

#![allow(dead_code)] // not every example uses every helper

use std::path::PathBuf;

use neurodoom::math::Fixed;

/// Default WAD path used when `DOOM_WAD` is unset.
pub const DEFAULT_WAD_PATH: &str = "doom1.wad";

/// Load the WAD the examples use. Honors `DOOM_WAD` env var; falls back
/// to `doom1.wad`. Returns both the bytes and the path that
/// was actually read (for diagnostics).
pub fn load_wad() -> std::io::Result<(Vec<u8>, PathBuf)> {
    let path: PathBuf = std::env::var_os("DOOM_WAD")
        .map(PathBuf::from)
        .unwrap_or_else(|| PathBuf::from(DEFAULT_WAD_PATH));
    let bytes = std::fs::read(&path)?;
    Ok((bytes, path))
}

/// First positional CLI arg, or `default` if none given. Examples use
/// this to pick the map name (e.g. "E1M1").
pub fn arg_or(default: &str) -> String {
    std::env::args().nth(1).unwrap_or_else(|| default.to_string())
}

/// Convert a fixed-point depth sample to a grayscale 0xRRGGBB value.
/// Near = bright, far = dim. Black for invalid (≤ 0) depths.
#[inline]
pub fn depth_to_rgb(d: Fixed) -> u32 {
    if d <= 0 {
        return 0;
    }
    // ~32 map units maps to ~255 (white), ~2048 units to ~4 (dark grey).
    let v = ((500_000_000i64 / d as i64) as u32).min(255);
    (v << 16) | (v << 8) | v
}

/// Deterministic, tiny LCG for demo-only randomness (spawn jitter,
/// wander turns). Matches Musl's `drand48`-style constants.
pub struct Lcg {
    state: u64,
}

impl Lcg {
    pub fn new(seed: u64) -> Self {
        Self { state: seed.max(1) }
    }
    pub fn next(&mut self) -> u32 {
        self.state = self
            .state
            .wrapping_mul(6364136223846793005)
            .wrapping_add(1442695040888963407);
        (self.state >> 33) as u32
    }
    pub fn next_in(&mut self, n: usize) -> usize {
        (self.next() as usize) % n.max(1)
    }
}

/// Seed an LCG from the system clock (ns since epoch). Returns a
/// fallback constant if the clock is unavailable.
pub fn seed_from_clock() -> u64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_nanos() as u64)
        .unwrap_or(0xC0FFEE)
}