Added basic Gatherer node
parent
8c451c28e7
commit
a7776b3c86
|
|
@ -7,6 +7,10 @@ extends Node
|
|||
func predicate() -> bool:
|
||||
return true
|
||||
|
||||
func get_action_name() -> String:
|
||||
push_error("get_action_name is unimplemented!")
|
||||
return "UNIMPLEMENTED"
|
||||
|
||||
# Called when the action starts
|
||||
func action_ready():
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ func handle_decide_action():
|
|||
#print("deciding action...")
|
||||
pass
|
||||
|
||||
func handle_perform_action():
|
||||
func handle_perform_action(_action: String):
|
||||
#print("performing action: ", actor.get_current_action())
|
||||
pass
|
||||
|
||||
func handle_turn_end():
|
||||
func handle_turn_end(_action: String):
|
||||
#print("turn end!")
|
||||
pass
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ func try_perform(action_node: Action) -> bool:
|
|||
|
||||
func inner_perform(action_node: Action):
|
||||
current_action = action_node
|
||||
actor.perform_action(action_node.name)
|
||||
actor.perform_action(action_node.get_action_name())
|
||||
current_action.done.connect(_on_action_done, CONNECT_ONE_SHOT)
|
||||
current_action.abort.connect(_on_action_abort, CONNECT_ONE_SHOT)
|
||||
current_action.action_ready()
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ func _init(new_mover: GridPosition, new_dir: Vector2i) -> void:
|
|||
mover = new_mover
|
||||
dir = new_dir
|
||||
|
||||
func get_action_name() -> String:
|
||||
return "move"
|
||||
|
||||
func predicate():
|
||||
return mover.can_move(dir)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,5 +2,8 @@
|
|||
class_name SkipAction
|
||||
extends Action
|
||||
|
||||
func get_action_name() -> String:
|
||||
return "skip"
|
||||
|
||||
func action_ready():
|
||||
done.emit()
|
||||
|
|
|
|||
|
|
@ -22,4 +22,4 @@ frame = 1
|
|||
position = Vector2(16, 16)
|
||||
zoom = Vector2(2, 2)
|
||||
|
||||
[node name="Gatherer" type="Node" parent="GridPosition"]
|
||||
[node name="Gatherer" type="Gatherer" parent="GridPosition"]
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use godot::prelude::*;
|
|||
|
||||
pub struct VelhoExtension;
|
||||
|
||||
mod common;
|
||||
mod level;
|
||||
mod turn_manager;
|
||||
mod overworld;
|
||||
mod turn;
|
||||
mod utils;
|
||||
|
||||
#[gdextension]
|
||||
unsafe impl ExtensionLibrary for VelhoExtension {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use godot::{classes::*, prelude::*};
|
||||
use godot::{classes::*, obj::WithBaseField, prelude::*};
|
||||
|
||||
use crate::{turn::TurnActor, utils};
|
||||
|
||||
#[derive(Debug, GodotClass)]
|
||||
#[class(init, base=Node)]
|
||||
|
|
@ -20,6 +22,8 @@ impl INode for Level {
|
|||
if self.foreground.is_none() {
|
||||
self.foreground = self.base().try_get_node_as::<TileMapLayer>("./Foreground");
|
||||
}
|
||||
assert_ne!(self.background, None);
|
||||
assert_ne!(self.foreground, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +54,11 @@ impl Level {
|
|||
.is_some_and(|layer| get_custom_data_bool(layer, coords, Self::HAS_COLLISION))
|
||||
}
|
||||
|
||||
#[func]
|
||||
pub fn get_bg(&self) -> Gd<TileMapLayer> {
|
||||
self.background.clone().unwrap()
|
||||
}
|
||||
|
||||
#[func]
|
||||
pub fn get_fg(&self) -> Gd<TileMapLayer> {
|
||||
self.foreground.clone().unwrap()
|
||||
|
|
@ -101,8 +110,6 @@ impl INode2D for GridPosition {
|
|||
self.is_moving = false;
|
||||
self.signals().finished_moving().emit(target_coords);
|
||||
} else {
|
||||
// self.base_mut()
|
||||
// .set_global_position(start.move_toward(end, movement_speed * delta));
|
||||
self.base_mut()
|
||||
.set_global_position(start.lerp(end, movement_speed * delta as f32));
|
||||
}
|
||||
|
|
@ -114,10 +121,22 @@ impl INode2D for GridPosition {
|
|||
impl GridPosition {
|
||||
const TILE_SNAP_DIST_SQR: f32 = 1.0;
|
||||
|
||||
fn level(&self) -> Option<Gd<Level>> {
|
||||
pub fn level(&self) -> Option<Gd<Level>> {
|
||||
Level::find_from_node(self.to_gd().upcast::<Node>())
|
||||
}
|
||||
|
||||
// #[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_target_pos(&self) -> Vector2 {
|
||||
self.target_coords.cast_float() * self.grid_size
|
||||
|
|
@ -172,3 +191,68 @@ impl GridPosition {
|
|||
#[signal]
|
||||
fn finished_moving(coords: Vector2i);
|
||||
}
|
||||
|
||||
#[derive(GodotConvert, Var, Export, Clone, Copy, Default, Debug, PartialEq, Eq)]
|
||||
#[godot(via = GString)]
|
||||
pub enum ItemKind {
|
||||
#[default]
|
||||
Blueberry,
|
||||
}
|
||||
|
||||
#[derive(Debug, GodotClass)]
|
||||
#[class(init, base=Node)]
|
||||
pub struct Gatherer {
|
||||
#[export]
|
||||
#[init(val = 0)]
|
||||
radius: i32,
|
||||
|
||||
level: Option<Gd<Level>>,
|
||||
grid_position: Option<Gd<GridPosition>>,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl INode for Gatherer {
|
||||
fn ready(&mut self) {
|
||||
self.level = utils::find_in_parents(self.to_gd());
|
||||
self.grid_position = utils::find_in_parents(self.to_gd());
|
||||
let actor = TurnActor::find_from_node(self.to_gd().upcast::<Node>())
|
||||
.expect("Getting Actor in some parent");
|
||||
actor
|
||||
.signals()
|
||||
.turn_ended()
|
||||
.connect_other(self, |this, action| this.on_turn_end(action));
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl Gatherer {
|
||||
fn on_turn_end(&self, action: GString) -> Option<()> {
|
||||
let coords = self.grid_position.clone()?.bind().get_coords();
|
||||
if let Some((item, count)) = self.try_gather_tile(coords) {
|
||||
godot_print!("Gathered {count} x {:?}", item);
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn try_gather_tile(&self, coords: Vector2i) -> Option<(ItemKind, i32)> {
|
||||
let mut fg = self.level.clone()?.bind().get_fg();
|
||||
// TODO: This is a horrible way to handle this
|
||||
if get_custom_data_bool(&fg, coords, "is_berry") {
|
||||
let source_id = fg.get_cell_source_id(coords);
|
||||
let alternative_tile = fg.get_cell_alternative_tile(coords);
|
||||
let new_atlas_coords = fg.get_cell_atlas_coords(coords) + Vector2i::RIGHT;
|
||||
fg.set_cell_ex(coords)
|
||||
.source_id(source_id)
|
||||
.alternative_tile(alternative_tile)
|
||||
.atlas_coords(new_atlas_coords)
|
||||
.done();
|
||||
return Some((ItemKind::Blueberry, 1));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[signal]
|
||||
fn gathered(item: ItemKind, count: i32);
|
||||
}
|
||||
|
|
@ -1,4 +1,59 @@
|
|||
use godot::{classes::*, prelude::*};
|
||||
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)]
|
||||
|
|
@ -44,6 +99,18 @@ impl TurnActor {
|
|||
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() {
|
||||
|
|
@ -104,8 +171,8 @@ impl TurnActor {
|
|||
);
|
||||
}
|
||||
self.state = TurnActorState::PerformingAction;
|
||||
self.current_action = Some(action_name);
|
||||
self.signals().performing_action().emit();
|
||||
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.
|
||||
|
|
@ -118,8 +185,9 @@ impl TurnActor {
|
|||
);
|
||||
}
|
||||
self.state = TurnActorState::WaitingForTurn;
|
||||
let action = self.current_action.clone().unwrap_or_default();
|
||||
self.current_action = None;
|
||||
self.signals().turn_ended().emit();
|
||||
self.signals().turn_ended().emit(&action);
|
||||
}
|
||||
|
||||
#[signal]
|
||||
|
|
@ -129,8 +197,8 @@ impl TurnActor {
|
|||
pub fn deciding_action();
|
||||
|
||||
#[signal]
|
||||
pub fn performing_action();
|
||||
pub fn performing_action(action_name: GString);
|
||||
|
||||
#[signal]
|
||||
pub fn turn_ended();
|
||||
pub fn turn_ended(action_name: GString);
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
use godot::{
|
||||
classes::{object::ConnectFlags, *},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::common::TurnActor;
|
||||
|
||||
#[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| 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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
use godot::prelude::*;
|
||||
|
||||
pub fn find_in_parents<T, U>(from: Gd<U>) -> Option<Gd<T>>
|
||||
where
|
||||
T: Inherits<Node>,
|
||||
U: Inherits<Node>,
|
||||
{
|
||||
let mut current = from.clone().upcast::<Node>();
|
||||
while let Some(parent) = current.get_parent() {
|
||||
match parent.try_cast::<T>() {
|
||||
Ok(level) => return Some(level),
|
||||
Err(other) => current = other,
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
Loading…
Reference in New Issue