pushers
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use crate::action::Action;
|
||||
use crate::archetype::Archetype;
|
||||
use crate::board::Board;
|
||||
use crate::log::LogLine;
|
||||
use crate::script::ScriptHost;
|
||||
@@ -10,6 +11,9 @@ use crate::utils::{Direction, ObjectId, Player, ScriptArg, Solid};
|
||||
/// How long a `say()` speech bubble stays on screen, in seconds.
|
||||
pub const SAY_DURATION: f64 = 3.0;
|
||||
|
||||
/// How often pusher archetypes fire, in seconds.
|
||||
const PUSHER_INTERVAL: f64 = 0.5;
|
||||
|
||||
// Re-export ScrollLine so kiln-tui can pattern-match scroll content without
|
||||
// accessing the private `action` module directly.
|
||||
pub use crate::action::ScrollLine;
|
||||
@@ -61,6 +65,9 @@ pub struct GameState {
|
||||
/// by [`enter_board`](GameState::enter_board). Front-ends tick this down and
|
||||
/// may block input or show a visual effect while it is `Some(t)` where `t > 0`.
|
||||
pub board_transition: Option<f64>,
|
||||
/// Countdown to the next global pusher heartbeat. When it reaches zero all
|
||||
/// [`Archetype::Pusher`] cells fire and the timer resets to [`PUSHER_INTERVAL`].
|
||||
pusher_timer: f64,
|
||||
}
|
||||
|
||||
impl GameState {
|
||||
@@ -84,6 +91,7 @@ impl GameState {
|
||||
speech_bubbles: Vec::new(),
|
||||
active_scroll: None,
|
||||
board_transition: None,
|
||||
pusher_timer: PUSHER_INTERVAL,
|
||||
};
|
||||
state.drain_errors();
|
||||
state
|
||||
@@ -161,9 +169,39 @@ impl GameState {
|
||||
// Expire speech bubbles before resolving new actions so a fresh say()
|
||||
// this frame isn't immediately culled.
|
||||
self.speech_bubbles.retain_mut(|b| { b.remaining -= secs; b.remaining > 0.0 });
|
||||
self.tick_pushers(secs);
|
||||
self.resolve();
|
||||
}
|
||||
|
||||
/// Fires the global pusher heartbeat: every [`PUSHER_INTERVAL`] seconds each
|
||||
/// [`Archetype::Pusher`] cell shoves the occupant directly in front of it.
|
||||
///
|
||||
/// Two-phase to avoid holding the board borrow while calling `push()` (which
|
||||
/// needs `&mut Board`): phase A collects target coordinates, phase B applies them.
|
||||
fn tick_pushers(&mut self, secs: f64) {
|
||||
self.pusher_timer -= secs;
|
||||
if self.pusher_timer > 0.0 {
|
||||
return;
|
||||
}
|
||||
self.pusher_timer += PUSHER_INTERVAL;
|
||||
let pushers: Vec<(usize, usize)> = {
|
||||
let board = self.board();
|
||||
let mut v = Vec::new();
|
||||
for y in 0..board.height {
|
||||
for x in 0..board.width {
|
||||
if matches!(board.get(x, y).1, Archetype::Pusher(_)) {
|
||||
v.push((x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
};
|
||||
let mut board = self.board_mut();
|
||||
for (x, y) in pushers {
|
||||
board.advance_pusher(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/// Drains errors collected by the script host into the game log.
|
||||
fn drain_errors(&mut self) {
|
||||
// TODO: errors are only logged for now. This is the place to halt execution /
|
||||
|
||||
Reference in New Issue
Block a user