2026-07-07 23:55:27 -05:00
|
|
|
use std::cell::RefCell;
|
|
|
|
|
use std::rc::Rc;
|
2026-06-25 00:04:42 -05:00
|
|
|
use crate::keys::Keyring;
|
|
|
|
|
|
2026-06-25 19:16:46 -05:00
|
|
|
/// The game-global player state: stats that follow the player across boards.
|
|
|
|
|
///
|
|
|
|
|
/// Owned by [`GameState::player`](crate::game::GameState) (a single value, not
|
|
|
|
|
/// per-board), so health, gems, and keys persist through board transitions.
|
|
|
|
|
/// Distinct from [`PlayerPos`](crate::utils::PlayerPos), which is the player's
|
|
|
|
|
/// position *on a particular board*. A `Copy` snapshot is handed to each script
|
|
|
|
|
/// hook and exposed to Rhai (read-only) as the `Player` constant.
|
2026-06-25 00:04:42 -05:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct Player {
|
|
|
|
|
/// The player's current health. Game-global (not per-board), so it persists
|
|
|
|
|
/// across board transitions. Scripts change it via `alter_health(dh)`, which
|
|
|
|
|
/// clamps to `[0, max_health]`. Front-ends display it via the status sidebar.
|
|
|
|
|
pub health: i64,
|
|
|
|
|
|
|
|
|
|
/// The maximum health the player can have. Scripts clamp `alter_health` to
|
|
|
|
|
/// this ceiling; the status sidebar uses it to size the heart row.
|
|
|
|
|
pub max_health: i64,
|
|
|
|
|
|
|
|
|
|
/// The player's key inventory. Game-global; persists across board transitions.
|
|
|
|
|
pub keys: Keyring,
|
|
|
|
|
|
|
|
|
|
/// The number of gems the player has collected. Game-global like
|
2026-06-25 19:16:46 -05:00
|
|
|
/// [`health`](Player::health); starts at `0`.
|
2026-06-25 00:04:42 -05:00
|
|
|
pub gems: i64,
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-07 23:55:27 -05:00
|
|
|
pub type PlayerRef = Rc<RefCell<Player>>;
|
|
|
|
|
|
2026-06-25 00:04:42 -05:00
|
|
|
impl Player {
|
2026-07-07 23:55:27 -05:00
|
|
|
/// Create a new PlayerRef from a default player
|
|
|
|
|
pub fn new_ref() -> PlayerRef {
|
|
|
|
|
Rc::new(RefCell::from(Player::default()))
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-25 00:04:42 -05:00
|
|
|
/// Attempt to modify the gem total by the given amount, but maintain a minimum of zero.
|
|
|
|
|
/// If the modification would take up below zero, leave it alone and return false.
|
|
|
|
|
pub fn alter_gems(&mut self, delta: i64) -> bool {
|
|
|
|
|
if delta + self.gems < 0 {
|
|
|
|
|
false
|
|
|
|
|
} else {
|
|
|
|
|
self.gems += delta;
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Modify the player's health by the given delta, clamped to within the range `[0, max_health]`
|
|
|
|
|
pub fn alter_health(&mut self, delta: i64) {
|
|
|
|
|
self.health = (self.health + delta).clamp(0, self.max_health);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Player {
|
|
|
|
|
fn default() -> Player {
|
|
|
|
|
Self {
|
|
|
|
|
health: 5,
|
|
|
|
|
max_health: 5,
|
|
|
|
|
gems: 0,
|
|
|
|
|
keys: Keyring::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|