7 Hour Roguelike, spring 2022
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
3.4 KiB

pub mod player;
use super::*;
use rogue_util::{coord::*, raster, grid::Grid};
use std::fmt::Debug;
pub trait Visible {
fn is_transparent(&self) -> bool;
}
impl Visible for Tile {
fn is_transparent(&self) -> bool { self.content == Content::Air }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LinfDir {
UL, U, UR,
L, R,
DL, D, DR,
}
impl LinfDir {
pub fn to_v2i(self) -> V2i {
use LinfDir::*;
match self {
UL => V2i(-1, -1),
U => V2i(0, -1),
UR => V2i(1, -1),
L => V2i(-1, 0),
R => V2i(1, 0),
DL => V2i(-1, 1),
D => V2i(0, 1),
DR => V2i(1, 1),
}
}
}
#[derive(Debug, Clone)]
pub enum Action {
Move(LinfDir),
Wait,
Quit,
}
impl Default for Action {
fn default() -> Action { Action::Wait }
}
#[derive(Debug, Clone)]
pub struct Observation {
pub sight: SightObs
}
impl Observation {
pub fn new(world: &World, v: V2i, sr: usize) -> Observation {
Observation {
sight: SightObs::new(world, v, sr),
}
}
}
#[derive(Debug, Clone)]
pub struct SightObs {
pub tiles: Grid<Option<V2i>>, // NB: Relative coordinate; 0,0 is this
pub entities: Vec<usize>, // NB: Entity indices
}
impl SightObs {
pub fn new(world: &World, v: V2i, sr: usize) -> SightObs {
let srsq = (sr as Vi) * (sr as Vi);
SightObs {
tiles: Grid::from_generator(|p| {
if p.l2_sq() > srsq {
return None;
}
{
let mut rg = world.region_mut();
for pt in raster::line(v, v + p) {
let tile = rg.get_or_create(pt);
if !tile.is_transparent() {
return None;
}
}
}
Some(v + p)
}, V2i(-(sr as Vi), -(sr as Vi)), V2i(2*sr as Vi, 2*sr as Vi)).unwrap(),
entities: world.entities().enumerate().filter_map(|(idx, eref)| {
let e = eref.borrow();
let pos = e.pos();
if (pos - v).l2_sq() > srsq {
return None;
}
{
let mut rg = world.region_mut();
for pt in raster::line(v, pos) {
let tile = rg.get_or_create(pt);
if !tile.is_transparent() {
return None;
}
}
}
Some(idx)
}).collect(),
}
}
}
const DEFAULT_SIGHT_RADIUS: usize = 10;
const DEFAULT_ACT_TIME: usize = 10000;
const ECLS_LIVING: usize = 1;
pub trait Entity {
fn pos(&self) -> V2i;
fn set_pos(&mut self, v: V2i);
fn next_time(&self) -> usize;
fn set_next_time(&mut self, t: usize);
fn class(&self) -> usize { 0 }
fn hp(&self) -> isize { 100 }
fn set_hp(&mut self, _hp: isize) {}
fn char(&self) -> char { 'E' }
fn sight(&self) -> usize { DEFAULT_SIGHT_RADIUS }
fn act_time(&self) -> usize { DEFAULT_ACT_TIME }
fn is_dead(&self) -> bool { self.hp() <= 0 }
fn act(&mut self, _obs: &Observation) -> Action { Action::Wait }
}
pub type EntBox = Box<dyn Entity>;
pub type EntCell = RefCell<EntBox>;
pub type EntRef = Rc<EntCell>;
pub type EntWeak = Weak<EntCell>;