205 lines
6.1 KiB
Rust
205 lines
6.1 KiB
Rust
use godot::{
|
|
classes::{object::ConnectFlags, *},
|
|
prelude::*,
|
|
};
|
|
|
|
#[derive(Debug, GodotClass)]
|
|
#[class(init, base=Node)]
|
|
pub struct TurnManager {
|
|
round_queue: Array<Gd<TurnActor>>,
|
|
current_actor: Option<Gd<TurnActor>>,
|
|
|
|
base: Base<Node>,
|
|
}
|
|
|
|
#[godot_api]
|
|
impl INode for TurnManager {
|
|
fn process(&mut self, _delta: f64) {
|
|
if self.current_actor.is_none() && self.round_queue.is_empty() {
|
|
self.start_round();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[godot_api]
|
|
impl TurnManager {
|
|
fn start_round(&mut self) {
|
|
self.round_queue = self.find_sibling_actors();
|
|
godot_print!("New round: {:?}", self.round_queue);
|
|
self.start_next_turn();
|
|
}
|
|
|
|
fn start_next_turn(&mut self) {
|
|
self.current_actor = self.round_queue.pop();
|
|
if let Some(mut actor) = self.current_actor.clone() {
|
|
actor
|
|
.signals()
|
|
.turn_ended()
|
|
.builder()
|
|
.flags(ConnectFlags::ONE_SHOT)
|
|
.connect_other_mut(self, |this, _action| this.start_next_turn());
|
|
actor.bind_mut().start_turn();
|
|
}
|
|
}
|
|
|
|
fn find_sibling_actors(&self) -> Array<Gd<TurnActor>> {
|
|
let mut actors: Array<Gd<TurnActor>> = Array::new();
|
|
self.base()
|
|
.get_parent()
|
|
.unwrap()
|
|
.get_children()
|
|
.iter_shared()
|
|
.filter_map(|node| node.try_cast::<TurnActor>().ok())
|
|
.for_each(|actor| actors.push(&actor));
|
|
actors
|
|
}
|
|
}
|
|
|
|
#[derive(GodotConvert, Var, Export, Clone, Copy, Default, Debug, PartialEq, Eq)]
|
|
#[godot(via = GString)]
|
|
pub enum TurnActorState {
|
|
/// The default value in Godot.
|
|
/// Turn manager should call `start_turn` to advance.
|
|
#[default]
|
|
WaitingForTurn,
|
|
/// Currently just automatically and immediately advances to `DecidingAction` state.
|
|
/// This is reserved for animations and such in the future.
|
|
TurnStarted,
|
|
/// An action decision script should call `take_control` to advance from this state.
|
|
DecidingAction,
|
|
/// An action script should call `end_turn` to advance from this state.
|
|
PerformingAction,
|
|
}
|
|
|
|
/// Turn breakdown:
|
|
///
|
|
/// Actor can be in 4 different states:
|
|
/// 1. Waiting for the turn to start. `TurnActor`s start in this state. (`turn_ended` emitted)
|
|
/// 2. Turn has started, waiting for enabled controls (`turn_started` emitted)
|
|
/// 3. Deciding what to do (`deciding_action` emitted)
|
|
/// 4. Performing the action (`performing_action` emitted)
|
|
/// ```
|
|
#[derive(Debug, GodotClass)]
|
|
#[class(init, base=Node2D)]
|
|
pub struct TurnActor {
|
|
state: TurnActorState,
|
|
current_action: Option<GString>,
|
|
base: Base<Node2D>,
|
|
}
|
|
|
|
#[godot_api]
|
|
impl INode2D for TurnActor {
|
|
fn ready(&mut self) {}
|
|
}
|
|
|
|
#[godot_api]
|
|
impl TurnActor {
|
|
#[func]
|
|
pub fn get_state(&self) -> TurnActorState {
|
|
self.state
|
|
}
|
|
|
|
#[func]
|
|
pub fn find_from_node(node: Gd<Node>) -> Option<Gd<Self>> {
|
|
let mut current = node.clone();
|
|
while let Some(parent) = current.get_parent() {
|
|
match parent.try_cast::<Self>() {
|
|
Ok(level) => return Some(level),
|
|
Err(other) => current = other,
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[func]
|
|
pub fn get_current_action(&self) -> Variant {
|
|
match self.current_action.clone() {
|
|
Some(action) => action.to_variant(),
|
|
None => Variant::nil(),
|
|
}
|
|
}
|
|
|
|
#[func]
|
|
pub fn is_deciding(&self) -> bool {
|
|
self.state == TurnActorState::DecidingAction
|
|
}
|
|
|
|
#[func]
|
|
pub fn is_my_turn(&self) -> bool {
|
|
match self.state {
|
|
TurnActorState::TurnStarted
|
|
| TurnActorState::DecidingAction
|
|
| TurnActorState::PerformingAction => true,
|
|
TurnActorState::WaitingForTurn => false,
|
|
}
|
|
}
|
|
|
|
/// Should be called by a turn manager
|
|
#[func]
|
|
pub fn start_turn(&mut self) {
|
|
if self.state != TurnActorState::WaitingForTurn {
|
|
godot_error!(
|
|
"TurnActor: incorrect state transfer. Called 'start_turn' while the actor is in state {:?} (expected WaitingForTurn)",
|
|
self.state,
|
|
);
|
|
}
|
|
self.state = TurnActorState::TurnStarted;
|
|
self.signals().turn_started().emit();
|
|
self.start_deciding();
|
|
}
|
|
|
|
/// Currently called automatically after the turn is started
|
|
#[func]
|
|
pub fn start_deciding(&mut self) {
|
|
if self.state != TurnActorState::TurnStarted {
|
|
godot_error!(
|
|
"TurnActor: incorrect state transfer. Called 'start_deciding' while the actor is in state {:?} (expected TurnStarted)",
|
|
self.state,
|
|
);
|
|
}
|
|
self.state = TurnActorState::DecidingAction;
|
|
self.signals().deciding_action().emit();
|
|
}
|
|
|
|
/// Should be called by an action script.
|
|
#[func]
|
|
pub fn perform_action(&mut self, action_name: GString) {
|
|
if self.state != TurnActorState::DecidingAction {
|
|
godot_error!(
|
|
"TurnActor: incorrect state transfer. Called 'take_control(\"{action_name}\")' while the actor is in state {:?} (expected DecidingAction)",
|
|
self.state,
|
|
);
|
|
}
|
|
self.state = TurnActorState::PerformingAction;
|
|
self.current_action = Some(action_name.clone());
|
|
self.signals().performing_action().emit(&action_name);
|
|
}
|
|
|
|
/// Should be called by an action script after it's done.
|
|
#[func]
|
|
pub fn end_turn(&mut self) {
|
|
if self.state != TurnActorState::PerformingAction {
|
|
godot_error!(
|
|
"TurnActor: incorrect state transfer. Called 'end_turn' while the actor is in state {:?} (expected PerformingAction)",
|
|
self.state,
|
|
);
|
|
}
|
|
self.state = TurnActorState::WaitingForTurn;
|
|
let action = self.current_action.clone().unwrap_or_default();
|
|
self.current_action = None;
|
|
self.signals().turn_ended().emit(&action);
|
|
}
|
|
|
|
#[signal]
|
|
pub fn turn_started();
|
|
|
|
#[signal]
|
|
pub fn deciding_action();
|
|
|
|
#[signal]
|
|
pub fn performing_action(action_name: GString);
|
|
|
|
#[signal]
|
|
pub fn turn_ended(action_name: GString);
|
|
}
|