use std::collections::VecDeque;
#[derive(Debug, Clone)]
pub struct CutsceneManager {
pub active: bool,
pub current_script: Option<String>,
pub blocking: bool,
pub queue: VecDeque<String>,
pub started: bool,
}
impl CutsceneManager {
pub fn new() -> Self {
Self {
active: false,
current_script: None,
blocking: true,
queue: VecDeque::new(),
started: false,
}
}
pub fn start_cutscene(&mut self, script_name: &str, blocking: bool) {
if self.active {
self.queue.push_back(script_name.to_string());
return;
}
self.active = true;
self.current_script = Some(script_name.to_string());
self.blocking = blocking;
self.started = false;
}
pub fn is_active(&self) -> bool {
self.active
}
pub fn is_blocking(&self) -> bool {
self.active && self.blocking
}
pub fn current_script_name(&self) -> Option<&str> {
self.current_script.as_deref()
}
pub fn end_cutscene(&mut self) -> Option<String> {
self.active = false;
self.current_script = None;
self.started = false;
if let Some(next) = self.queue.pop_front() {
self.active = true;
self.current_script = Some(next.clone());
self.started = false;
return Some(next);
}
None
}
pub fn queue_script(&mut self, script_name: &str) {
self.queue.push_back(script_name.to_string());
}
pub fn queue_len(&self) -> usize {
self.queue.len()
}
pub fn has_queued(&self) -> bool {
!self.queue.is_empty()
}
pub fn clear_queue(&mut self) {
self.queue.clear();
}
pub fn force_stop(&mut self) {
self.active = false;
self.current_script = None;
self.queue.clear();
self.started = false;
}
pub fn mark_started(&mut self) {
self.started = true;
}
pub fn needs_start(&self) -> bool {
self.active && !self.started
}
}
impl Default for CutsceneManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_cutscene_manager() {
let cm = CutsceneManager::new();
assert!(!cm.is_active());
assert!(cm.current_script.is_none());
assert!(cm.queue.is_empty());
}
#[test]
fn test_start_and_end_cutscene() {
let mut cm = CutsceneManager::new();
cm.start_cutscene("prof_lab_intro", true);
assert!(cm.is_active());
assert!(cm.is_blocking());
assert_eq!(cm.current_script_name(), Some("prof_lab_intro"));
cm.end_cutscene();
assert!(!cm.is_active());
assert!(cm.current_script.is_none());
}
#[test]
fn test_non_blocking_cutscene() {
let mut cm = CutsceneManager::new();
cm.start_cutscene("ambient_chatter", false);
assert!(cm.is_active());
assert!(!cm.is_blocking());
}
#[test]
fn test_queue_when_active() {
let mut cm = CutsceneManager::new();
cm.start_cutscene("first", true);
cm.start_cutscene("second", true);
cm.start_cutscene("third", true);
assert_eq!(cm.current_script_name(), Some("first"));
assert_eq!(cm.queue_len(), 2);
let next = cm.end_cutscene();
assert_eq!(next, Some("second".to_string()));
assert_eq!(cm.current_script_name(), Some("second"));
assert_eq!(cm.queue_len(), 1);
let next = cm.end_cutscene();
assert_eq!(next, Some("third".to_string()));
assert_eq!(cm.current_script_name(), Some("third"));
assert_eq!(cm.queue_len(), 0);
let next = cm.end_cutscene();
assert_eq!(next, None);
assert!(!cm.is_active());
}
#[test]
fn test_queue_script() {
let mut cm = CutsceneManager::new();
cm.queue_script("intro");
cm.queue_script("prof_arrives");
assert_eq!(cm.queue_len(), 2);
assert!(!cm.is_active());
cm.start_cutscene("manual_start", true);
assert_eq!(cm.current_script_name(), Some("manual_start"));
let next = cm.end_cutscene();
assert_eq!(next, Some("intro".to_string()));
let next = cm.end_cutscene();
assert_eq!(next, Some("prof_arrives".to_string()));
}
#[test]
fn test_force_stop() {
let mut cm = CutsceneManager::new();
cm.start_cutscene("running", true);
cm.queue_script("next1");
cm.queue_script("next2");
cm.force_stop();
assert!(!cm.is_active());
assert!(cm.current_script.is_none());
assert!(cm.queue.is_empty());
}
#[test]
fn test_clear_queue() {
let mut cm = CutsceneManager::new();
cm.queue_script("a");
cm.queue_script("b");
cm.clear_queue();
assert_eq!(cm.queue_len(), 0);
assert!(cm.queue.is_empty());
}
#[test]
fn test_default() {
let cm: CutsceneManager = Default::default();
assert!(!cm.is_active());
assert!(cm.queue.is_empty());
}
}