//! Entities: the things that *populate* a map, distinct from its terrain.
//!
//! Where [`Tile`](crate::map::Tile) says *what the ground is* and
//! [`Region`](crate::region::Region) says *what areas exist*, an [`Entity`] is a
//! discrete thing sitting **on** a walkable cell — a stairway, a chest, a
//! monster. Entities never change the terrain (they are an overlay layer on the
//! [`Map`](crate::map::Map)), so a renderer draws them on top of the tiles and a
//! game treats them as occupants of a cell.
//!
//! Like [`Tile`](crate::map::Tile) and [`RegionKind`](crate::region::RegionKind),
//! the kind enum starts minimal and grows additively; passes and renderers match
//! only on the kinds they care about. All types derive serde so entities travel
//! inside a `Map` through JSON.

use serde::{Deserialize, Serialize};

use crate::geometry::Point;

/// The [`Blackboard`](crate::blackboard::Blackboard) key under which the entity
/// placer stashes its `Vec<Entity>` for [`Pipeline`](crate::pass::Pipeline) to
/// harvest into the finished [`Map`](crate::map::Map). Shared so the producer
/// (the placer pass) and the consumer (the engine) never drift on the name.
pub const BLACKBOARD_KEY: &str = "entities";

/// What an [`Entity`] is. Additive: new kinds (traps, NPCs, altars, …) slot in
/// without disturbing existing matches.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EntityKind {
    /// Where the dungeon is entered from (the player's start / stairs up).
    Entrance,
    /// The dungeon's goal — the room farthest from the entrance (stairs down).
    Exit,
    /// A pickup: treasure, loot, an item.
    Treasure,
    /// A creature occupying the cell.
    Monster,
}

/// A single entity: its [`EntityKind`] and the cell it occupies.
///
/// `at` is always a walkable [`Floor`](crate::map::Tile::Floor) cell in a
/// well-formed map; the placer only ever drops entities onto open floor and never
/// stacks two on one cell.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Entity {
    /// What this entity is.
    pub kind: EntityKind,
    /// The cell it occupies.
    pub at: Point,
}

impl Entity {
    /// Creates an entity of `kind` at cell `at`.
    pub const fn new(kind: EntityKind, at: Point) -> Self {
        Entity { kind, at }
    }
}
