From e9ad6bda72686d812fc58eb6668beebc8921124a Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 16:15:26 -0500 Subject: [PATCH 01/30] move ix start stuff into `DBoxInterface` --- pets-lib/dg/src/main.dg | 3 +-- pets-lib/src/dialogue/autoload.rs | 32 ++++++++++++++++++++++++++ pets-lib/src/dialogue/mod.rs | 2 +- pets-lib/src/lib.rs | 4 +++- pets-lib/src/world/interaction/zone.rs | 22 +++--------------- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/pets-lib/dg/src/main.dg b/pets-lib/dg/src/main.dg index 45c27ac2..7bfe67a2 100644 --- a/pets-lib/dg/src/main.dg +++ b/pets-lib/dg/src/main.dg @@ -1,7 +1,6 @@ -% Main ### -Import ./rodrick.dg +Import rodrick.dg ### --- diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index be073ab0..bf4e99b2 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -39,6 +39,38 @@ impl DBoxInterface { .cast() } + #[func] + pub fn start_ix(&self, ix_id: String) { + use dialogical::Metaline::*; + use dialogical::Speaker::*; + + let ix = ix_map().get(&ix_id).unwrap_or_else(|| { + panic!( + "Could not find interaction \"{}\" in the interaction map", + ix_id + ) + }); + + let page = ix.pages.get(0).unwrap(); + let spk = page.metadata.speaker.clone(); + + let spk = match spk { + PageOnly(v) | Permanent(v) => v, + NoChange => todo!(), + }; + + let spk = match spk { + Named(v) => v, + Narrator => "".to_string(), + Unknown => "???".to_string(), + }; + + // TODO multi-page stuff, don't just pop up twice + let msg = page.content.clone(); + self.show_dialog(spk.into(), msg.into()); + // show_dialog!(spk, "{}", page.content.clone()); + } + #[func] pub fn show_dialog(&self, spk: GString, msg: GString) { let mut dbox_gd = self.dbox_scene.instantiate_as::(); diff --git a/pets-lib/src/dialogue/mod.rs b/pets-lib/src/dialogue/mod.rs index 772535ec..477f2c87 100644 --- a/pets-lib/src/dialogue/mod.rs +++ b/pets-lib/src/dialogue/mod.rs @@ -22,7 +22,7 @@ macro_rules! packed_dialogue { } /// Load every interaction in the game from `packed.dgc` -pub fn ix_list() -> &'static InteractionMap { +pub fn ix_map() -> &'static InteractionMap { INTERACTIONS.get_or_init(|| { packed_dialogue!().expect(indoc! {" Failed to load dialogues. If you are a player, diff --git a/pets-lib/src/lib.rs b/pets-lib/src/lib.rs index 1d60718d..79b49044 100644 --- a/pets-lib/src/lib.rs +++ b/pets-lib/src/lib.rs @@ -33,7 +33,9 @@ mod prelude { pub use crate::macros::*; pub use crate::stats::*; - pub use crate::dialogue::ix_list; + pub use crate::dialogue::autoload::DBoxInterface; + pub use crate::dialogue::ix_map; + pub use crate::world::interaction::manager::InteractionManager; // is this bad practice? no clue and idc honestly diff --git a/pets-lib/src/world/interaction/zone.rs b/pets-lib/src/world/interaction/zone.rs index 30c32f66..ec49cf78 100644 --- a/pets-lib/src/world/interaction/zone.rs +++ b/pets-lib/src/world/interaction/zone.rs @@ -23,26 +23,10 @@ pub struct InteractionZone { impl InteractionZone { #[func] pub fn interact(&self) { - use dialogical::Metaline::*; - use dialogical::Speaker::*; + let di = DBoxInterface::singleton(); + di.bind().start_ix("Rodrick Sign #1".to_string()); - let ix_list = ix_list(); - let ix = ix_list.get("Rodrick Sign #1").unwrap(); - let page = ix.pages.get(0).unwrap(); - let spk = page.metadata.speaker.clone(); - - let spk = match spk { - PageOnly(v) | Permanent(v) => v, - NoChange => unreachable!(), - }; - - let spk = match spk { - Named(v) => v, - Narrator => "".to_string(), - Unknown => "".to_string(), - }; - - show_dialog!(spk, "{}", page.content.clone()); + // show_dialog!() } #[func] From e850f9d3542bbb796fa3621220c906096c1a9edd Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 16:52:06 -0500 Subject: [PATCH 02/30] reorganized some stuff --- pets-lib/src/consts.rs | 0 pets-lib/src/dialogue/autoload.rs | 21 +++++++++------------ pets-lib/src/lib.rs | 2 ++ pets-lib/src/macros.rs | 16 ++++++++++++++++ 4 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 pets-lib/src/consts.rs diff --git a/pets-lib/src/consts.rs b/pets-lib/src/consts.rs new file mode 100644 index 00000000..e69de29b diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index bf4e99b2..a2d5fd95 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -2,6 +2,7 @@ //! Singleton for accessing player stats in GDScript. //! +use dialogical::{Interaction, Speaker}; use godot::engine::Engine; use godot::prelude::*; @@ -15,18 +16,11 @@ pub struct DBoxInterface { #[base] node: Base, dbox_scene: Gd, -} - -/// Show a dialog box with the given speaker and message -/// usage: `show_dialog!("Cherry", "Hello, {}!", name, ...)` -#[macro_export] -macro_rules! show_dialog { - ($speaker:expr, $($t:tt)*) => {{ - let msg = format!($($t)*); - let dbox = crate::dialogue::autoload::DBoxInterface::singleton(); - dbox.bind().show_dialog($speaker.into(), msg.into()); - }}; + // state for the current interaction + current_ix: Option, + current_page_number: usize, + current_speaker: Speaker, } #[godot_api] @@ -68,7 +62,6 @@ impl DBoxInterface { // TODO multi-page stuff, don't just pop up twice let msg = page.content.clone(); self.show_dialog(spk.into(), msg.into()); - // show_dialog!(spk, "{}", page.content.clone()); } #[func] @@ -97,6 +90,10 @@ impl INode2D for DBoxInterface { Self { node, dbox_scene: load::("res://scenes/dialog.tscn"), + + current_ix: None, + current_page_number: 0, + current_speaker: Speaker::Narrator, } } } diff --git a/pets-lib/src/lib.rs b/pets-lib/src/lib.rs index 79b49044..e52d070f 100644 --- a/pets-lib/src/lib.rs +++ b/pets-lib/src/lib.rs @@ -18,6 +18,8 @@ use godot::prelude::*; use dialogue::autoload::DBoxInterface; use stats::stats_interface::StatsInterface; +pub(crate) mod consts; + mod battle; mod dialogue; mod items; diff --git a/pets-lib/src/macros.rs b/pets-lib/src/macros.rs index 2023d254..e943cdbd 100644 --- a/pets-lib/src/macros.rs +++ b/pets-lib/src/macros.rs @@ -8,6 +8,22 @@ pub use crate::godot_tree; pub use crate::node_at; pub use crate::show_dialog; +/// Show a dialog box with the given speaker and message +/// usage: `show_dialog!("Cherry", "Hello, {}!", name, ...)` +/// +/// Don't use this in actual game code. It's kinda messy, +/// and more just meant for quick testing. Should probably +/// delete it later, but I'm keeping it for now. +#[macro_export] +macro_rules! show_dialog { + ($speaker:expr, $($t:tt)*) => {{ + let msg = format!($($t)*); + + let dbox = crate::dialogue::autoload::DBoxInterface::singleton(); + dbox.bind().show_dialog($speaker.into(), msg.into()); + }}; +} + #[macro_export] macro_rules! uninit { ($target:ty) => { From 3cfa270fe3773c29380f5bcb89a4ad9711af2768 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 16:56:11 -0500 Subject: [PATCH 03/30] move consts to `consts.rs` --- pets-lib/src/consts.rs | 29 +++++++++++++++++++++++++++++ pets-lib/src/dialogue/dbox.rs | 3 +-- pets-lib/src/lib.rs | 3 +-- pets-lib/src/main_menu.rs | 5 +---- pets-lib/src/world/playercb.rs | 9 +-------- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/pets-lib/src/consts.rs b/pets-lib/src/consts.rs index e69de29b..be10f51a 100644 --- a/pets-lib/src/consts.rs +++ b/pets-lib/src/consts.rs @@ -0,0 +1,29 @@ +//! +//! All the "important" constants for configuring +//! how the game works. Tinker all you want. Go nuts. :) +//! + +pub mod playercb { + // Movement physics stuff + pub const ACCELERATION: f64 = 3000.0; + pub const FRICTION: f64 = 2500.0; + pub const MAX_SPEED: f64 = 320.0; + + // Distance between party members + pub const PERSONAL_SPACE: u16 = 15; +} + +pub mod dbox { + use godot::engine::tween::TransitionType; + + pub const DBOX_TWEEN_TIME: f64 = 0.5; + pub const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; +} + +pub mod main_menu { + use godot::engine::tween::TransitionType; + + pub const MENU_TWEEN_TIME: f64 = 0.1; + pub const MENU_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; + pub const MENU_WAVE_BBCODE: &str = "[wave amp=100 freq=-6]"; +} diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 9287b9e4..f70518a3 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -6,8 +6,7 @@ use godot::engine::tween::TransitionType; use godot::engine::{IPanelContainer, PanelContainer, RichTextLabel}; use godot::prelude::*; -const DBOX_TWEEN_TIME: f64 = 0.5; -const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; +use crate::consts::dbox::*; #[derive(GodotClass)] #[class(base=PanelContainer)] diff --git a/pets-lib/src/lib.rs b/pets-lib/src/lib.rs index e52d070f..c2171c29 100644 --- a/pets-lib/src/lib.rs +++ b/pets-lib/src/lib.rs @@ -18,9 +18,8 @@ use godot::prelude::*; use dialogue::autoload::DBoxInterface; use stats::stats_interface::StatsInterface; -pub(crate) mod consts; - mod battle; +mod consts; mod dialogue; mod items; mod limiq; diff --git a/pets-lib/src/main_menu.rs b/pets-lib/src/main_menu.rs index a4fd39d7..a2de75bc 100644 --- a/pets-lib/src/main_menu.rs +++ b/pets-lib/src/main_menu.rs @@ -10,15 +10,12 @@ use godot::engine::tween::TransitionType; use godot::engine::{Control, INode2D, Node2D, RichTextLabel, Theme}; use godot::prelude::*; +use crate::consts::main_menu::*; use crate::prelude::*; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -const MENU_TWEEN_TIME: f64 = 0.1; -const MENU_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; -const MENU_WAVE_BBCODE: &str = "[wave amp=100 freq=-6]"; - #[derive(Debug, FromPrimitive)] enum MainMenuChoice { Play = 0, diff --git a/pets-lib/src/world/playercb.rs b/pets-lib/src/world/playercb.rs index f0421587..e15d0a3a 100644 --- a/pets-lib/src/world/playercb.rs +++ b/pets-lib/src/world/playercb.rs @@ -1,18 +1,11 @@ use godot::engine::{CharacterBody2D, ICharacterBody2D}; use godot::prelude::*; +use crate::consts::playercb::*; use crate::{load_pchar_scene_under, prelude::*}; use super::pchar_node::PCharNode; -// Movement physics stuff -const ACCELERATION: f64 = 3000.0; -const FRICTION: f64 = 2500.0; -const MAX_SPEED: f64 = 320.0; - -// Distance between party members -const PERSONAL_SPACE: u16 = 15; - /// This scene contains the "player" aka the invisible /// entity that is moved around with WASD. It also contains /// party members as scenes, and this script does stuff like From 102273b85647ab470bdc6ead231b077f21cf120d Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 17:01:56 -0500 Subject: [PATCH 04/30] made narrator/unknown display text constants --- pets-lib/src/consts.rs | 5 ++++- pets-lib/src/dialogue/autoload.rs | 5 +++-- pets-lib/src/dialogue/dbox.rs | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pets-lib/src/consts.rs b/pets-lib/src/consts.rs index be10f51a..7136d738 100644 --- a/pets-lib/src/consts.rs +++ b/pets-lib/src/consts.rs @@ -13,9 +13,12 @@ pub mod playercb { pub const PERSONAL_SPACE: u16 = 15; } -pub mod dbox { +pub mod dialogue { use godot::engine::tween::TransitionType; + pub const NARRATOR_DISPLAYNAME: &str = ""; + pub const UNKNOWN_DISPLAYNAME: &str = "???"; + pub const DBOX_TWEEN_TIME: f64 = 0.5; pub const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; } diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index a2d5fd95..544a9611 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -7,6 +7,7 @@ use godot::engine::Engine; use godot::prelude::*; use super::dbox::DialogBox; +use crate::consts::dialogue::*; use crate::prelude::*; /// Autoload class for easy management of dialog boxes @@ -55,8 +56,8 @@ impl DBoxInterface { let spk = match spk { Named(v) => v, - Narrator => "".to_string(), - Unknown => "???".to_string(), + Narrator => NARRATOR_DISPLAYNAME.to_string(), + Unknown => UNKNOWN_DISPLAYNAME.to_string(), }; // TODO multi-page stuff, don't just pop up twice diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index f70518a3..eb7b29ca 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -6,7 +6,7 @@ use godot::engine::tween::TransitionType; use godot::engine::{IPanelContainer, PanelContainer, RichTextLabel}; use godot::prelude::*; -use crate::consts::dbox::*; +use crate::consts::dialogue::*; #[derive(GodotClass)] #[class(base=PanelContainer)] From d2568b97ac2752e80242397932aaeb38259bda86 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 17:18:47 -0500 Subject: [PATCH 05/30] pageonly speaker probably works (untested) --- pets-lib/src/dialogue/autoload.rs | 20 +++++++++++++------- pets-lib/src/world/interaction/zone.rs | 6 ++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 544a9611..e007185e 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -35,7 +35,7 @@ impl DBoxInterface { } #[func] - pub fn start_ix(&self, ix_id: String) { + pub fn start_ix(&mut self, ix_id: String) { use dialogical::Metaline::*; use dialogical::Speaker::*; @@ -48,19 +48,25 @@ impl DBoxInterface { let page = ix.pages.get(0).unwrap(); let spk = page.metadata.speaker.clone(); + // let vox = page.metadata.vox.clone(); + // TODO so many clones lol + // prob move this to another get/set 2-in-1 function too let spk = match spk { - PageOnly(v) | Permanent(v) => v, - NoChange => todo!(), + PageOnly(v) => v, + Permanent(v) => { + self.current_speaker = v.clone(); + v + } + NoChange => self.current_speaker.clone(), }; let spk = match spk { - Named(v) => v, - Narrator => NARRATOR_DISPLAYNAME.to_string(), - Unknown => UNKNOWN_DISPLAYNAME.to_string(), + Named(ref v) => v, + Narrator => NARRATOR_DISPLAYNAME, + Unknown => UNKNOWN_DISPLAYNAME, }; - // TODO multi-page stuff, don't just pop up twice let msg = page.content.clone(); self.show_dialog(spk.into(), msg.into()); } diff --git a/pets-lib/src/world/interaction/zone.rs b/pets-lib/src/world/interaction/zone.rs index ec49cf78..3f56698f 100644 --- a/pets-lib/src/world/interaction/zone.rs +++ b/pets-lib/src/world/interaction/zone.rs @@ -23,10 +23,8 @@ pub struct InteractionZone { impl InteractionZone { #[func] pub fn interact(&self) { - let di = DBoxInterface::singleton(); - di.bind().start_ix("Rodrick Sign #1".to_string()); - - // show_dialog!() + let mut di = DBoxInterface::singleton(); + di.bind_mut().start_ix("Rodrick Sign #1".to_string()); } #[func] From 330adfb040797617f50b9a4c66d5e58939f61a0a Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 17:29:49 -0500 Subject: [PATCH 06/30] moved code into `update_spk` and `update_vox` methods --- pets-lib/src/consts.rs | 1 + pets-lib/src/dialogue/autoload.rs | 59 +++++++++++++++++++------------ 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/pets-lib/src/consts.rs b/pets-lib/src/consts.rs index 7136d738..f47882a8 100644 --- a/pets-lib/src/consts.rs +++ b/pets-lib/src/consts.rs @@ -18,6 +18,7 @@ pub mod dialogue { pub const NARRATOR_DISPLAYNAME: &str = ""; pub const UNKNOWN_DISPLAYNAME: &str = "???"; + pub const DEFAULT_VOX: &str = "_"; pub const DBOX_TWEEN_TIME: f64 = 0.5; pub const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index e007185e..5104333c 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -2,7 +2,9 @@ //! Singleton for accessing player stats in GDScript. //! -use dialogical::{Interaction, Speaker}; +use dialogical::Metaline::*; +use dialogical::Speaker::{self, *}; +use dialogical::{Interaction, Page}; use godot::engine::Engine; use godot::prelude::*; @@ -19,9 +21,11 @@ pub struct DBoxInterface { dbox_scene: Gd, // state for the current interaction + // TODO combine speaker and vox into a `PageMeta` current_ix: Option, current_page_number: usize, current_speaker: Speaker, + current_vox: String, } #[godot_api] @@ -34,25 +38,9 @@ impl DBoxInterface { .cast() } - #[func] - pub fn start_ix(&mut self, ix_id: String) { - use dialogical::Metaline::*; - use dialogical::Speaker::*; - - let ix = ix_map().get(&ix_id).unwrap_or_else(|| { - panic!( - "Could not find interaction \"{}\" in the interaction map", - ix_id - ) - }); - - let page = ix.pages.get(0).unwrap(); - let spk = page.metadata.speaker.clone(); - // let vox = page.metadata.vox.clone(); - - // TODO so many clones lol - // prob move this to another get/set 2-in-1 function too - let spk = match spk { + /// Takes a NAME metaline and updates the speaker accordingly + pub fn update_spk(&mut self, page: &Page) -> String { + let spk = match page.metadata.speaker.clone() { PageOnly(v) => v, Permanent(v) => { self.current_speaker = v.clone(); @@ -61,11 +49,37 @@ impl DBoxInterface { NoChange => self.current_speaker.clone(), }; - let spk = match spk { + match spk { Named(ref v) => v, Narrator => NARRATOR_DISPLAYNAME, Unknown => UNKNOWN_DISPLAYNAME, - }; + } + .to_owned() + } + + /// Takes a VOX metaline and updates the vox accordingly + pub fn update_vox(&mut self, page: &Page) -> String { + match page.metadata.vox.clone() { + PageOnly(v) => v, + Permanent(v) => { + self.current_vox = v.clone(); + v + } + NoChange => self.current_vox.clone(), + } + } + + #[func] + pub fn start_ix(&mut self, ix_id: String) { + let ix = ix_map().get(&ix_id).unwrap_or_else(|| { + panic!( + "Could not find interaction \"{}\" in the interaction map", + ix_id + ) + }); + + let page = ix.pages.get(0).unwrap(); + let spk = self.update_spk(page); let msg = page.content.clone(); self.show_dialog(spk.into(), msg.into()); @@ -101,6 +115,7 @@ impl INode2D for DBoxInterface { current_ix: None, current_page_number: 0, current_speaker: Speaker::Narrator, + current_vox: DEFAULT_VOX.to_owned(), } } } From 37ba2ba90c6392d2edf8ce9787068cb7f8471b12 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 17:35:06 -0500 Subject: [PATCH 07/30] pass vox into `show_dialog`, changed some `GString`s to `String`s --- pets-lib/src/dialogue/autoload.rs | 9 ++++++--- pets-lib/src/dialogue/dbox.rs | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 5104333c..2225eb0e 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -21,7 +21,7 @@ pub struct DBoxInterface { dbox_scene: Gd, // state for the current interaction - // TODO combine speaker and vox into a `PageMeta` + // TODO maybe combine these into a struct? current_ix: Option, current_page_number: usize, current_speaker: Speaker, @@ -80,15 +80,18 @@ impl DBoxInterface { let page = ix.pages.get(0).unwrap(); let spk = self.update_spk(page); + let vox = self.update_vox(page); let msg = page.content.clone(); - self.show_dialog(spk.into(), msg.into()); + self.show_dialog(spk, vox, msg); } #[func] - pub fn show_dialog(&self, spk: GString, msg: GString) { + pub fn show_dialog(&self, spk: String, _vox: String, msg: String) { let mut dbox_gd = self.dbox_scene.instantiate_as::(); + // TODO check if a box already exists + play vox sounds + dbox_gd.set_name("Dialog".into()); current_scene!() .get_node("UILayer".into()) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index eb7b29ca..b950483b 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -30,9 +30,9 @@ impl DialogBox { } #[func] - pub fn set_txts(&mut self, speaker: GString, content: GString) { - self.spk_txt = speaker; - self.msg_txt = content; + pub fn set_txts(&mut self, speaker: String, content: String) { + self.spk_txt = speaker.into(); + self.msg_txt = content.into(); } #[func] From 296222789ca336baa6d83a079ef0b3e4d7e7e793 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 17:37:45 -0500 Subject: [PATCH 08/30] clean up pointless TODO comments --- pets-lib/src/dialogue/autoload.rs | 1 - pets-lib/src/lib.rs | 1 - pets-lib/src/main_menu.rs | 8 ++++---- pets-lib/src/world/interaction/manager.rs | 1 - 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 2225eb0e..437ada5d 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -21,7 +21,6 @@ pub struct DBoxInterface { dbox_scene: Gd, // state for the current interaction - // TODO maybe combine these into a struct? current_ix: Option, current_page_number: usize, current_speaker: Speaker, diff --git a/pets-lib/src/lib.rs b/pets-lib/src/lib.rs index c2171c29..463f3ae7 100644 --- a/pets-lib/src/lib.rs +++ b/pets-lib/src/lib.rs @@ -7,7 +7,6 @@ //! - Cherry 9/2/2023 | <3 //! -// TODO remove this soon #![allow(dead_code)] #![allow(unused_imports)] #![feature(variant_count)] diff --git a/pets-lib/src/main_menu.rs b/pets-lib/src/main_menu.rs index a2de75bc..b92e7037 100644 --- a/pets-lib/src/main_menu.rs +++ b/pets-lib/src/main_menu.rs @@ -122,13 +122,13 @@ impl TitleScreen { } Options => { - // TODO scroll right into the options menu - // leaving this empty so it won't panic + // should scroll right into options menu + todo!() } Credits => { - // TODO tween the credits box - // leaving this empty so it won't panic + // should pull up credits box + todo!() } Quit => { diff --git a/pets-lib/src/world/interaction/manager.rs b/pets-lib/src/world/interaction/manager.rs index 05e00786..3f476e67 100644 --- a/pets-lib/src/world/interaction/manager.rs +++ b/pets-lib/src/world/interaction/manager.rs @@ -60,7 +60,6 @@ impl InteractionManager { let pcb = pcb.cast::(); let pcb_pos = { pcb.get_position() }; - // TODO optimize sorting self.zones.sort_by(|a, b| { let a = a.get_global_position(); let b = b.get_global_position(); From 9bcdfd82a5d949e0f26b5f96e49b6e29ddc19f73 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 18:10:32 -0500 Subject: [PATCH 09/30] decoupled interactions from dboxinterface (now stored in the individual dialog boxes) --- pets-lib/src/dialogue/autoload.rs | 69 +++++++------------------------ pets-lib/src/dialogue/dbox.rs | 63 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 53 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 437ada5d..5129057f 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -19,12 +19,6 @@ pub struct DBoxInterface { #[base] node: Base, dbox_scene: Gd, - - // state for the current interaction - current_ix: Option, - current_page_number: usize, - current_speaker: Speaker, - current_vox: String, } #[godot_api] @@ -37,37 +31,6 @@ impl DBoxInterface { .cast() } - /// Takes a NAME metaline and updates the speaker accordingly - pub fn update_spk(&mut self, page: &Page) -> String { - let spk = match page.metadata.speaker.clone() { - PageOnly(v) => v, - Permanent(v) => { - self.current_speaker = v.clone(); - v - } - NoChange => self.current_speaker.clone(), - }; - - match spk { - Named(ref v) => v, - Narrator => NARRATOR_DISPLAYNAME, - Unknown => UNKNOWN_DISPLAYNAME, - } - .to_owned() - } - - /// Takes a VOX metaline and updates the vox accordingly - pub fn update_vox(&mut self, page: &Page) -> String { - match page.metadata.vox.clone() { - PageOnly(v) => v, - Permanent(v) => { - self.current_vox = v.clone(); - v - } - NoChange => self.current_vox.clone(), - } - } - #[func] pub fn start_ix(&mut self, ix_id: String) { let ix = ix_map().get(&ix_id).unwrap_or_else(|| { @@ -78,28 +41,33 @@ impl DBoxInterface { }); let page = ix.pages.get(0).unwrap(); - let spk = self.update_spk(page); - let vox = self.update_vox(page); + // let spk = self.update_spk(page); + // let vox = self.update_vox(page); let msg = page.content.clone(); - self.show_dialog(spk, vox, msg); + self.show_dialog("Test".into(), "Test".into(), msg); } #[func] pub fn show_dialog(&self, spk: String, _vox: String, msg: String) { - let mut dbox_gd = self.dbox_scene.instantiate_as::(); - - // TODO check if a box already exists + play vox sounds + let mut dbox = self.dbox_scene.instantiate_as::(); + dbox.set_name("Dialog Box".into()); - dbox_gd.set_name("Dialog".into()); - current_scene!() + let mut ui_layer = current_scene!() .get_node("UILayer".into()) - .expect("scene should have a UILayer") - .add_child(dbox_gd.clone().upcast()); + .expect("scene should have a UILayer"); + + // check if a box already exists + if ui_layer.has_node("Dialog Box".into()) { + let node = ui_layer.get_node("Dialog Box".into()).unwrap(); + ui_layer.remove_child(node); + } + + ui_layer.add_child(dbox.clone().upcast()); // simple stuff like this is why I love this language { - let mut dbox = dbox_gd.bind_mut(); + let mut dbox = dbox.bind_mut(); dbox.set_txts(spk, msg); dbox.do_draw(); dbox.pop_up() @@ -113,11 +81,6 @@ impl INode2D for DBoxInterface { Self { node, dbox_scene: load::("res://scenes/dialog.tscn"), - - current_ix: None, - current_page_number: 0, - current_speaker: Speaker::Narrator, - current_vox: DEFAULT_VOX.to_owned(), } } } diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index b950483b..65dd90c9 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -2,6 +2,10 @@ //! Dialog box class for menus and dialogue text //! +use dialogical::Speaker::{self, *}; +use dialogical::{Interaction, Page}; +use dialogical::{Metaline::*, PageMeta}; + use godot::engine::tween::TransitionType; use godot::engine::{IPanelContainer, PanelContainer, RichTextLabel}; use godot::prelude::*; @@ -13,12 +17,33 @@ use crate::consts::dialogue::*; pub struct DialogBox { #[base] node: Base, + + // state for the current interaction + current_ix: Option, + current_page_number: usize, + current_speaker: Speaker, + current_vox: String, + spk_txt: GString, msg_txt: GString, } #[godot_api] impl DialogBox { + /// init for the purposes of reading out an interaction + pub fn new_for_ix(ix: Interaction) -> Gd { + Gd::from_init_fn(|node| Self { + node, + spk_txt: "Cherry".into(), + msg_txt: "[wave amp=50 freq=6]Hello, World![/wave]".into(), + + current_ix: Some(ix), + current_page_number: 0, + current_speaker: Speaker::Narrator, + current_vox: DEFAULT_VOX.to_owned(), + }) + } + /// Get the speaker name label fn spk_txt(&self) -> Gd { self.node.get_node_as("VSplit/SpeakerName") @@ -29,12 +54,45 @@ impl DialogBox { self.node.get_node_as("VSplit/Content") } + /// Sets the speaker and message text from strings #[func] pub fn set_txts(&mut self, speaker: String, content: String) { self.spk_txt = speaker.into(); self.msg_txt = content.into(); } + /// Takes a NAME metaline and updates the speaker accordingly + pub fn update_spk(&mut self, meta: &PageMeta) -> String { + let spk = match meta.speaker { + PageOnly(ref v) => v, + Permanent(ref v) => { + self.current_speaker = v.clone(); + v + } + NoChange => &self.current_speaker, + }; + + match spk { + Named(ref v) => v, + Narrator => NARRATOR_DISPLAYNAME, + Unknown => UNKNOWN_DISPLAYNAME, + } + .to_owned() + } + + /// Takes a VOX metaline and updates the vox accordingly + pub fn update_vox(&mut self, meta: &PageMeta) -> String { + match meta.vox { + PageOnly(ref v) => v, + Permanent(ref v) => { + self.current_vox = v.clone(); + v + } + NoChange => &self.current_vox, + } + .to_owned() + } + #[func] pub fn do_draw(&mut self) { // I THINK this clone is fine, probably RC'd @@ -85,6 +143,11 @@ impl IPanelContainer for DialogBox { node, spk_txt: "Cherry".into(), msg_txt: "[wave amp=50 freq=6]Hello, World![/wave]".into(), + + current_ix: None, + current_page_number: 0, + current_speaker: Speaker::Narrator, + current_vox: DEFAULT_VOX.to_owned(), } } From e2b96bead975ededbdde509bca41f0255a5e935f Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 18:18:31 -0500 Subject: [PATCH 10/30] refactor dbox interface, move out "dbox factory" code to separate function --- pets-lib/src/consts.rs | 1 + pets-lib/src/dialogue/autoload.rs | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/pets-lib/src/consts.rs b/pets-lib/src/consts.rs index f47882a8..6450c531 100644 --- a/pets-lib/src/consts.rs +++ b/pets-lib/src/consts.rs @@ -20,6 +20,7 @@ pub mod dialogue { pub const UNKNOWN_DISPLAYNAME: &str = "???"; pub const DEFAULT_VOX: &str = "_"; + pub const DBOX_NODE_NAME: &str = "Dialog Box"; pub const DBOX_TWEEN_TIME: f64 = 0.5; pub const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; } diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 5129057f..a394ac39 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -50,28 +50,35 @@ impl DBoxInterface { #[func] pub fn show_dialog(&self, spk: String, _vox: String, msg: String) { + // simple stuff like this is why I love this language + let mut dbox = self.instantiate_dbox(); + + { + let mut dbox = dbox.bind_mut(); + dbox.set_txts(spk, msg); + dbox.do_draw(); + dbox.pop_up() + } + } + + #[func] + pub fn instantiate_dbox(&self) -> Gd { let mut dbox = self.dbox_scene.instantiate_as::(); - dbox.set_name("Dialog Box".into()); + dbox.set_name(DBOX_NODE_NAME.into()); let mut ui_layer = current_scene!() .get_node("UILayer".into()) .expect("scene should have a UILayer"); // check if a box already exists - if ui_layer.has_node("Dialog Box".into()) { - let node = ui_layer.get_node("Dialog Box".into()).unwrap(); + if ui_layer.has_node(DBOX_NODE_NAME.into()) { + let node = ui_layer.get_node(DBOX_NODE_NAME.into()).unwrap(); ui_layer.remove_child(node); } ui_layer.add_child(dbox.clone().upcast()); - // simple stuff like this is why I love this language - { - let mut dbox = dbox.bind_mut(); - dbox.set_txts(spk, msg); - dbox.do_draw(); - dbox.pop_up() - } + dbox } } From f9063ff036dfda8c5b6ae4acf76d5f66eec81360 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 18:28:38 -0500 Subject: [PATCH 11/30] use `instantiate_dbox` in singleton's `start_ix` --- pets-lib/src/dialogue/autoload.rs | 10 +++------- pets-lib/src/dialogue/dbox.rs | 18 ++++-------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index a394ac39..fb2d32c2 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -40,19 +40,15 @@ impl DBoxInterface { ) }); - let page = ix.pages.get(0).unwrap(); - // let spk = self.update_spk(page); - // let vox = self.update_vox(page); - - let msg = page.content.clone(); - self.show_dialog("Test".into(), "Test".into(), msg); + let mut dbox = self.instantiate_dbox(); + dbox.bind_mut().set_ix(ix.clone()); } #[func] pub fn show_dialog(&self, spk: String, _vox: String, msg: String) { - // simple stuff like this is why I love this language let mut dbox = self.instantiate_dbox(); + // simple stuff like this is why I love this language { let mut dbox = dbox.bind_mut(); dbox.set_txts(spk, msg); diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 65dd90c9..bc52d518 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -30,20 +30,6 @@ pub struct DialogBox { #[godot_api] impl DialogBox { - /// init for the purposes of reading out an interaction - pub fn new_for_ix(ix: Interaction) -> Gd { - Gd::from_init_fn(|node| Self { - node, - spk_txt: "Cherry".into(), - msg_txt: "[wave amp=50 freq=6]Hello, World![/wave]".into(), - - current_ix: Some(ix), - current_page_number: 0, - current_speaker: Speaker::Narrator, - current_vox: DEFAULT_VOX.to_owned(), - }) - } - /// Get the speaker name label fn spk_txt(&self) -> Gd { self.node.get_node_as("VSplit/SpeakerName") @@ -61,6 +47,10 @@ impl DialogBox { self.msg_txt = content.into(); } + pub fn set_ix(&mut self, ix: Interaction) { + self.current_ix = Some(ix); + } + /// Takes a NAME metaline and updates the speaker accordingly pub fn update_spk(&mut self, meta: &PageMeta) -> String { let spk = match meta.speaker { From 03ef7f4639da3fa62cf952a520ef1887bd54bb50 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 18:30:39 -0500 Subject: [PATCH 12/30] forgot to actually set the text :P --- pets-lib/src/dialogue/autoload.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index fb2d32c2..3b4cbe17 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -41,7 +41,13 @@ impl DBoxInterface { }); let mut dbox = self.instantiate_dbox(); - dbox.bind_mut().set_ix(ix.clone()); + + { + let mut dbox = dbox.bind_mut(); + dbox.set_ix(ix.clone()); + dbox.do_draw(); + dbox.pop_up() + } } #[func] From 52f05f559cd6295f6825f464a6b7fb34364d4967 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 18:40:01 -0500 Subject: [PATCH 13/30] add `goto_page` fn --- pets-lib/src/dialogue/dbox.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index bc52d518..92125529 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -49,6 +49,19 @@ impl DialogBox { pub fn set_ix(&mut self, ix: Interaction) { self.current_ix = Some(ix); + self.goto_page(0); + } + + pub fn goto_page(&mut self, pageno: usize) { + let ix = self.current_ix.as_ref().unwrap().clone(); + let page = ix.pages.get(pageno).unwrap(); + let meta = &page.metadata; + + let spk = self.update_spk(meta); + let vox = self.update_vox(meta); + let msg = page.content.clone(); + + self.spk_txt = spk.into(); } /// Takes a NAME metaline and updates the speaker accordingly From 3438b423590b7da11817a041b4a38e98f6b42d11 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 19:22:42 -0500 Subject: [PATCH 14/30] add and use `permanent_` fields on dbox (for pageonly stuff) --- pets-lib/src/dialogue/dbox.rs | 58 +++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 92125529..925d7a85 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -12,6 +12,19 @@ use godot::prelude::*; use crate::consts::dialogue::*; +/// Turn a Speaker into a displayable name +/// +/// Either the name of the speaker or a special name +/// if it's a narrator or unknown speaker +pub fn spk_display(spk: Speaker) -> String { + match spk { + Named(ref v) => v, + Narrator => NARRATOR_DISPLAYNAME, + Unknown => UNKNOWN_DISPLAYNAME, + } + .to_owned() +} + #[derive(GodotClass)] #[class(base=PanelContainer)] pub struct DialogBox { @@ -23,7 +36,14 @@ pub struct DialogBox { current_page_number: usize, current_speaker: Speaker, current_vox: String, - + permanent_speaker: Speaker, + permanent_vox: String, + + // independent from any interaction-related stuff, + // these are the actual strings that are displayed + // + // you can set these directly if you're doing something + // that's not part of an interaction spk_txt: GString, msg_txt: GString, } @@ -55,45 +75,35 @@ impl DialogBox { pub fn goto_page(&mut self, pageno: usize) { let ix = self.current_ix.as_ref().unwrap().clone(); let page = ix.pages.get(pageno).unwrap(); - let meta = &page.metadata; - let spk = self.update_spk(meta); - let vox = self.update_vox(meta); + self.update_meta(&page.metadata); let msg = page.content.clone(); - self.spk_txt = spk.into(); + // TODO + // self.set_txts(spk, msg); } /// Takes a NAME metaline and updates the speaker accordingly - pub fn update_spk(&mut self, meta: &PageMeta) -> String { - let spk = match meta.speaker { + pub fn update_meta(&mut self, meta: &PageMeta) { + self.current_speaker = match meta.speaker { PageOnly(ref v) => v, Permanent(ref v) => { - self.current_speaker = v.clone(); + self.permanent_speaker = v.clone(); v } - NoChange => &self.current_speaker, - }; - - match spk { - Named(ref v) => v, - Narrator => NARRATOR_DISPLAYNAME, - Unknown => UNKNOWN_DISPLAYNAME, + NoChange => &self.permanent_speaker, } - .to_owned() - } + .clone(); - /// Takes a VOX metaline and updates the vox accordingly - pub fn update_vox(&mut self, meta: &PageMeta) -> String { - match meta.vox { + self.current_vox = match meta.vox { PageOnly(ref v) => v, Permanent(ref v) => { - self.current_vox = v.clone(); + self.permanent_vox = v.clone(); v } - NoChange => &self.current_vox, + NoChange => &self.permanent_vox, } - .to_owned() + .to_owned(); } #[func] @@ -151,6 +161,8 @@ impl IPanelContainer for DialogBox { current_page_number: 0, current_speaker: Speaker::Narrator, current_vox: DEFAULT_VOX.to_owned(), + permanent_speaker: Speaker::Narrator, + permanent_vox: DEFAULT_VOX.to_owned(), } } From a8b2ea92430918f3e576e899c9fd74bea13313e8 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 20:30:47 -0500 Subject: [PATCH 15/30] refactor/optimize dialogue manager --- pets-lib/src/dialogue/dbox.rs | 11 ++++++---- pets-lib/src/world/interaction/manager.rs | 25 +++++++++++++++-------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 925d7a85..3572420e 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -16,7 +16,7 @@ use crate::consts::dialogue::*; /// /// Either the name of the speaker or a special name /// if it's a narrator or unknown speaker -pub fn spk_display(spk: Speaker) -> String { +pub fn spk_display(spk: &Speaker) -> String { match spk { Named(ref v) => v, Narrator => NARRATOR_DISPLAYNAME, @@ -61,6 +61,9 @@ impl DialogBox { } /// Sets the speaker and message text from strings + /// + /// DON'T USE THIS FOR INTERACTIONS!! + /// That's what `goto_page` is for. #[func] pub fn set_txts(&mut self, speaker: String, content: String) { self.spk_txt = speaker.into(); @@ -72,15 +75,15 @@ impl DialogBox { self.goto_page(0); } + /// basically set_txts but for an interaction page pub fn goto_page(&mut self, pageno: usize) { let ix = self.current_ix.as_ref().unwrap().clone(); let page = ix.pages.get(pageno).unwrap(); self.update_meta(&page.metadata); let msg = page.content.clone(); - - // TODO - // self.set_txts(spk, msg); + let spk = spk_display(&self.current_speaker); + self.set_txts(spk, msg); } /// Takes a NAME metaline and updates the speaker accordingly diff --git a/pets-lib/src/world/interaction/manager.rs b/pets-lib/src/world/interaction/manager.rs index 3f476e67..772bfd60 100644 --- a/pets-lib/src/world/interaction/manager.rs +++ b/pets-lib/src/world/interaction/manager.rs @@ -3,7 +3,7 @@ //! Shows the input prompt and handles the action if pressed. //! -use godot::engine::{INode2D, Node2D, RichTextLabel}; +use godot::engine::{INode2D, InputEvent, Node2D, RichTextLabel}; use godot::prelude::*; use crate::prelude::*; @@ -54,7 +54,8 @@ impl InteractionManager { current_scene!().get_node_as("%InteractionManager") } - pub fn sort_zones(&mut self) { + /// Sorts the zones by distance from the player + pub fn sort_zones_by_distance(&mut self) { let mut tree = self.node.get_tree().unwrap(); let pcb = tree.get_first_node_in_group("playercb".into()).unwrap(); let pcb = pcb.cast::(); @@ -68,6 +69,14 @@ impl InteractionManager { a.partial_cmp(&b).unwrap() }); } + + /// Get the closest zone to the player + /// Assumes the zones are already sorted + /// + /// Panics if there are no zones + pub fn closest_zone(&mut self) -> Gd { + self.zones[0].clone() + } } #[godot_api] @@ -91,15 +100,15 @@ impl INode2D for InteractionManager { return; } - self.sort_zones(); - let mut zone = self.zones[0].clone(); + self.sort_zones_by_distance(); + let zone = self.closest_zone(); self.prompt_txt() .set_position(zone.get_position() + Vector2::new(0.0, -50.0)); + } - let input = Input::singleton(); - if input.is_action_just_pressed("ui_accept".into()) { - let zone = zone.bind_mut(); - zone.interact(); + fn input(&mut self, event: Gd) { + if event.is_action_pressed("ui_accept".into()) { + self.closest_zone().bind().interact(); } } } From fd673a42eaebd9b032e882ec1896584c245ac83f Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 20:36:27 -0500 Subject: [PATCH 16/30] remove `pop_up` and `pop_down` in favor of directly using `tween_into_view` --- pets-lib/src/dialogue/autoload.rs | 4 ++-- pets-lib/src/dialogue/dbox.rs | 12 +----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 3b4cbe17..34c46294 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -46,7 +46,7 @@ impl DBoxInterface { let mut dbox = dbox.bind_mut(); dbox.set_ix(ix.clone()); dbox.do_draw(); - dbox.pop_up() + dbox.tween_into_view(true) } } @@ -59,7 +59,7 @@ impl DBoxInterface { let mut dbox = dbox.bind_mut(); dbox.set_txts(spk, msg); dbox.do_draw(); - dbox.pop_up() + dbox.tween_into_view(true) } } diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 3572420e..b951c8b2 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -116,17 +116,7 @@ impl DialogBox { self.msg_txt().set_text(self.msg_txt.clone()); } - #[func] - pub fn pop_up(&mut self) { - self.tween_into_view(true); - } - - #[func] - pub fn pop_down(&mut self) { - self.tween_into_view(false); - } - - fn tween_into_view(&mut self, up: bool) { + pub fn tween_into_view(&mut self, up: bool) { let node = &mut self.node; let viewport_y = node.get_viewport_rect().size.y; let visible_y = viewport_y - node.get_size().y; From 24a9c0aeeecdd1d1040dc4d4e8e7bf53fac4a2de Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 20:38:49 -0500 Subject: [PATCH 17/30] rm `show_dialog` stuff, no longer needed (might revert later) --- pets-lib/src/dialogue/autoload.rs | 13 ------------- pets-lib/src/macros.rs | 17 ----------------- 2 files changed, 30 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 34c46294..c4edc77b 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -50,19 +50,6 @@ impl DBoxInterface { } } - #[func] - pub fn show_dialog(&self, spk: String, _vox: String, msg: String) { - let mut dbox = self.instantiate_dbox(); - - // simple stuff like this is why I love this language - { - let mut dbox = dbox.bind_mut(); - dbox.set_txts(spk, msg); - dbox.do_draw(); - dbox.tween_into_view(true) - } - } - #[func] pub fn instantiate_dbox(&self) -> Gd { let mut dbox = self.dbox_scene.instantiate_as::(); diff --git a/pets-lib/src/macros.rs b/pets-lib/src/macros.rs index e943cdbd..ddd324ff 100644 --- a/pets-lib/src/macros.rs +++ b/pets-lib/src/macros.rs @@ -6,23 +6,6 @@ pub use crate::current_scene; pub use crate::godot_root; pub use crate::godot_tree; pub use crate::node_at; -pub use crate::show_dialog; - -/// Show a dialog box with the given speaker and message -/// usage: `show_dialog!("Cherry", "Hello, {}!", name, ...)` -/// -/// Don't use this in actual game code. It's kinda messy, -/// and more just meant for quick testing. Should probably -/// delete it later, but I'm keeping it for now. -#[macro_export] -macro_rules! show_dialog { - ($speaker:expr, $($t:tt)*) => {{ - let msg = format!($($t)*); - - let dbox = crate::dialogue::autoload::DBoxInterface::singleton(); - dbox.bind().show_dialog($speaker.into(), msg.into()); - }}; -} #[macro_export] macro_rules! uninit { From b31a00bfcf626e17f53482027ad9162757fedb04 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 20:44:47 -0500 Subject: [PATCH 18/30] const-ify `UILayer` node name + add `scene_has_active_dbox` method --- pets-lib/src/consts.rs | 1 + pets-lib/src/dialogue/autoload.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pets-lib/src/consts.rs b/pets-lib/src/consts.rs index 6450c531..727a3b5e 100644 --- a/pets-lib/src/consts.rs +++ b/pets-lib/src/consts.rs @@ -20,6 +20,7 @@ pub mod dialogue { pub const UNKNOWN_DISPLAYNAME: &str = "???"; pub const DEFAULT_VOX: &str = "_"; + pub const UI_LAYER_NAME: &str = "UILayer"; pub const DBOX_NODE_NAME: &str = "Dialog Box"; pub const DBOX_TWEEN_TIME: f64 = 0.5; pub const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD; diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index c4edc77b..2b33e17b 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -50,13 +50,19 @@ impl DBoxInterface { } } + #[func] + pub fn scene_has_active_dbox(&self) -> bool { + let ui_layer = current_scene!().get_node(UI_LAYER_NAME.into()).unwrap(); + ui_layer.has_node(DBOX_NODE_NAME.into()) + } + #[func] pub fn instantiate_dbox(&self) -> Gd { let mut dbox = self.dbox_scene.instantiate_as::(); dbox.set_name(DBOX_NODE_NAME.into()); let mut ui_layer = current_scene!() - .get_node("UILayer".into()) + .get_node(UI_LAYER_NAME.into()) .expect("scene should have a UILayer"); // check if a box already exists From dee7d335b1c0f67518f4706cc09d0ac2cb8f33a1 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 20:51:28 -0500 Subject: [PATCH 19/30] return early and don't allow iz interact if a dialog is currently active --- pets-lib/src/world/interaction/manager.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pets-lib/src/world/interaction/manager.rs b/pets-lib/src/world/interaction/manager.rs index 772bfd60..a594fdad 100644 --- a/pets-lib/src/world/interaction/manager.rs +++ b/pets-lib/src/world/interaction/manager.rs @@ -108,6 +108,11 @@ impl INode2D for InteractionManager { fn input(&mut self, event: Gd) { if event.is_action_pressed("ui_accept".into()) { + let di = DBoxInterface::singleton(); + if di.bind().scene_has_active_dbox() { + return; + } + self.closest_zone().bind().interact(); } } From 5afe84a129547e397e510cf7152648adaf4f4a1f Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 21:07:49 -0500 Subject: [PATCH 20/30] refactor `update_meta` to avoid code duplication --- pets-lib/src/dialogue/dbox.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index b951c8b2..1cd1576b 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -4,7 +4,7 @@ use dialogical::Speaker::{self, *}; use dialogical::{Interaction, Page}; -use dialogical::{Metaline::*, PageMeta}; +use dialogical::{Metaline, Metaline::*, PageMeta}; use godot::engine::tween::TransitionType; use godot::engine::{IPanelContainer, PanelContainer, RichTextLabel}; @@ -86,27 +86,27 @@ impl DialogBox { self.set_txts(spk, msg); } - /// Takes a NAME metaline and updates the speaker accordingly + /// Updates the speaker and vox based on the given page metadata pub fn update_meta(&mut self, meta: &PageMeta) { - self.current_speaker = match meta.speaker { - PageOnly(ref v) => v, - Permanent(ref v) => { - self.permanent_speaker = v.clone(); - v - } - NoChange => &self.permanent_speaker, - } - .clone(); + // TODO maybe combine current/permanent into one tuple? + self.current_speaker = Self::match_meta(&mut self.permanent_speaker, &meta.speaker); + self.current_vox = Self::match_meta(&mut self.permanent_vox, &meta.vox); + } - self.current_vox = match meta.vox { + /// helper method for `update_meta` + /// + /// matches over a `Metaline` to update a field depending on + /// whether it's pageonly, permanent, or nochange + fn match_meta<'a, T: Clone>(field: &'a mut T, meta_field: &'a Metaline) -> T { + match meta_field { PageOnly(ref v) => v, Permanent(ref v) => { - self.permanent_vox = v.clone(); + *field = v.clone(); v } - NoChange => &self.permanent_vox, + NoChange => field, } - .to_owned(); + .clone() } #[func] From 0424d62a23263f39ee2c4d8ac4ee187368a9fc4b Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 21:26:32 -0500 Subject: [PATCH 21/30] combine `current_` and `permanent_` speaker/vox fields into `MetaPair` struct --- pets-lib/src/dialogue/dbox.rs | 47 ++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 1cd1576b..d0a78908 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -25,6 +25,24 @@ pub fn spk_display(spk: &Speaker) -> String { .to_owned() } +#[derive(Clone)] +pub struct MetaPair { + pub temporary: T, + pub permanent: T, +} + +impl MetaPair { + pub fn clone(v: T) -> Self + where + T: Clone, + { + Self { + temporary: v.clone(), + permanent: v.clone(), + } + } +} + #[derive(GodotClass)] #[class(base=PanelContainer)] pub struct DialogBox { @@ -34,10 +52,8 @@ pub struct DialogBox { // state for the current interaction current_ix: Option, current_page_number: usize, - current_speaker: Speaker, - current_vox: String, - permanent_speaker: Speaker, - permanent_vox: String, + speaker: MetaPair, + vox: MetaPair, // independent from any interaction-related stuff, // these are the actual strings that are displayed @@ -82,31 +98,30 @@ impl DialogBox { self.update_meta(&page.metadata); let msg = page.content.clone(); - let spk = spk_display(&self.current_speaker); + let spk = spk_display(&self.speaker.temporary); self.set_txts(spk, msg); } /// Updates the speaker and vox based on the given page metadata pub fn update_meta(&mut self, meta: &PageMeta) { - // TODO maybe combine current/permanent into one tuple? - self.current_speaker = Self::match_meta(&mut self.permanent_speaker, &meta.speaker); - self.current_vox = Self::match_meta(&mut self.permanent_vox, &meta.vox); + Self::match_meta(&mut self.speaker, &meta.speaker); + Self::match_meta(&mut self.vox, &meta.vox); } /// helper method for `update_meta` /// /// matches over a `Metaline` to update a field depending on /// whether it's pageonly, permanent, or nochange - fn match_meta<'a, T: Clone>(field: &'a mut T, meta_field: &'a Metaline) -> T { - match meta_field { + fn match_meta<'a, T: Clone>(field: &'a mut MetaPair, meta_field: &'a Metaline) { + field.temporary = match meta_field { PageOnly(ref v) => v, Permanent(ref v) => { - *field = v.clone(); + field.permanent = v.clone(); v } - NoChange => field, + NoChange => &field.permanent, } - .clone() + .clone(); } #[func] @@ -152,10 +167,8 @@ impl IPanelContainer for DialogBox { current_ix: None, current_page_number: 0, - current_speaker: Speaker::Narrator, - current_vox: DEFAULT_VOX.to_owned(), - permanent_speaker: Speaker::Narrator, - permanent_vox: DEFAULT_VOX.to_owned(), + speaker: MetaPair::clone(Speaker::Narrator), + vox: MetaPair::clone(DEFAULT_VOX.to_owned()), } } From e5fcf693bf9285c1d0af7c87a50acf9d1440a0ad Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 22:26:35 -0500 Subject: [PATCH 22/30] C to go to next page in dialogs --- pets-lib/src/dialogue/autoload.rs | 1 - pets-lib/src/dialogue/dbox.rs | 29 ++++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 2b33e17b..5e987140 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -41,7 +41,6 @@ impl DBoxInterface { }); let mut dbox = self.instantiate_dbox(); - { let mut dbox = dbox.bind_mut(); dbox.set_ix(ix.clone()); diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index d0a78908..ec4c5c04 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -7,10 +7,11 @@ use dialogical::{Interaction, Page}; use dialogical::{Metaline, Metaline::*, PageMeta}; use godot::engine::tween::TransitionType; -use godot::engine::{IPanelContainer, PanelContainer, RichTextLabel}; +use godot::engine::{IPanelContainer, InputEvent, PanelContainer, RichTextLabel}; use godot::prelude::*; use crate::consts::dialogue::*; +use crate::prelude::DBoxInterface; /// Turn a Speaker into a displayable name /// @@ -154,6 +155,9 @@ impl DialogBox { .from(Variant::from(tw_start)) .unwrap() .set_trans(DBOX_TWEEN_TRANS); + + // TODO use `Callable::from_fn` in godot 4.2 + // y_tween.connect("finished".into(), || {}); } } @@ -175,4 +179,27 @@ impl IPanelContainer for DialogBox { fn ready(&mut self) { self.do_draw(); } + + fn input(&mut self, event: Gd) { + if event.is_action_pressed("ui_accept".into()) { + let di = DBoxInterface::singleton(); + if !di.bind().scene_has_active_dbox() { + return; + } + + // go to next page + let ix = self.current_ix.as_ref().unwrap(); + self.current_page_number += 1; + + if self.current_page_number >= ix.pages.len() { + self.tween_into_view(false); + self.current_ix = None; + return; + } + + godot_print!("going to page {}", self.current_page_number); + self.goto_page(self.current_page_number); + self.do_draw(); + } + } } From 58a6042c2ac0de92ad47ccf6ecd67139b2ecc6a5 Mon Sep 17 00:00:00 2001 From: Cherry Date: Thu, 30 Nov 2023 23:18:30 -0500 Subject: [PATCH 23/30] refactor `process` and check if closest zone is null --- pets-lib/src/dialogue/dbox.rs | 6 +++-- pets-lib/src/world/interaction/manager.rs | 27 ++++++++++++----------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index ec4c5c04..aac4c553 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -156,8 +156,10 @@ impl DialogBox { .unwrap() .set_trans(DBOX_TWEEN_TRANS); - // TODO use `Callable::from_fn` in godot 4.2 - // y_tween.connect("finished".into(), || {}); + if !up { + let free = self.node.callable("queue_free"); + y_tween.connect("finished".into(), free); + } } } diff --git a/pets-lib/src/world/interaction/manager.rs b/pets-lib/src/world/interaction/manager.rs index a594fdad..e2ba3d2b 100644 --- a/pets-lib/src/world/interaction/manager.rs +++ b/pets-lib/src/world/interaction/manager.rs @@ -37,7 +37,7 @@ impl InteractionManager { self.prompt_txt.as_mut().unwrap() } - pub fn prompt_shown(&mut self, hidden: bool) { + pub fn prompt_hidden(&mut self, hidden: bool) { let prompt = self.prompt_txt(); if hidden { prompt.hide(); @@ -74,8 +74,8 @@ impl InteractionManager { /// Assumes the zones are already sorted /// /// Panics if there are no zones - pub fn closest_zone(&mut self) -> Gd { - self.zones[0].clone() + pub fn closest_zone(&mut self) -> Option> { + self.zones.get(0).cloned() } } @@ -94,16 +94,15 @@ impl INode2D for InteractionManager { } fn process(&mut self, _delta: f64) { - let no_zones_found = self.zones.len() == 0; - self.prompt_shown(no_zones_found); - if no_zones_found { - return; - } - self.sort_zones_by_distance(); - let zone = self.closest_zone(); - self.prompt_txt() - .set_position(zone.get_position() + Vector2::new(0.0, -50.0)); + + if let Some(zone) = self.closest_zone() { + self.prompt_hidden(false); + self.prompt_txt() + .set_position(zone.get_position() + Vector2::new(0.0, -50.0)); + } else { + self.prompt_hidden(true); + } } fn input(&mut self, event: Gd) { @@ -113,7 +112,9 @@ impl INode2D for InteractionManager { return; } - self.closest_zone().bind().interact(); + if let Some(zone) = self.closest_zone() { + zone.bind().interact(); + } } } } From 8a710f18f06ea45738e12158b12965b17a1de535 Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 00:43:50 -0500 Subject: [PATCH 24/30] use `node.callable` instead of `Callable::from_object_method` --- pets-lib/src/world/interaction/zone.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pets-lib/src/world/interaction/zone.rs b/pets-lib/src/world/interaction/zone.rs index 3f56698f..86b0a60d 100644 --- a/pets-lib/src/world/interaction/zone.rs +++ b/pets-lib/src/world/interaction/zone.rs @@ -52,8 +52,8 @@ impl IArea2D for InteractionZone { fn ready(&mut self) { let node = &mut self.node; - let enter_fn = Callable::from_object_method(node, "on_entered"); - let exit_fn = Callable::from_object_method(node, "on_exited"); + let enter_fn = node.callable("on_entered"); + let exit_fn = node.callable("on_exited"); node.connect("body_entered".into(), enter_fn); node.connect("body_exited".into(), exit_fn); } From 10aab8cc9d1103eac9d89254b3a0381dea171ea0 Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 00:57:00 -0500 Subject: [PATCH 25/30] fix panic, `tween_into_view` returns a tweener --- pets-lib/src/dialogue/autoload.rs | 2 +- pets-lib/src/dialogue/dbox.rs | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index 5e987140..e33e4305 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -45,7 +45,7 @@ impl DBoxInterface { let mut dbox = dbox.bind_mut(); dbox.set_ix(ix.clone()); dbox.do_draw(); - dbox.tween_into_view(true) + dbox.tween_into_view(true); } } diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index aac4c553..be6d3e9c 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -7,7 +7,7 @@ use dialogical::{Interaction, Page}; use dialogical::{Metaline, Metaline::*, PageMeta}; use godot::engine::tween::TransitionType; -use godot::engine::{IPanelContainer, InputEvent, PanelContainer, RichTextLabel}; +use godot::engine::{IPanelContainer, InputEvent, PanelContainer, RichTextLabel, Tween}; use godot::prelude::*; use crate::consts::dialogue::*; @@ -132,7 +132,7 @@ impl DialogBox { self.msg_txt().set_text(self.msg_txt.clone()); } - pub fn tween_into_view(&mut self, up: bool) { + pub fn tween_into_view(&mut self, up: bool) -> Gd { let node = &mut self.node; let viewport_y = node.get_viewport_rect().size.y; let visible_y = viewport_y - node.get_size().y; @@ -154,12 +154,10 @@ impl DialogBox { .unwrap() .from(Variant::from(tw_start)) .unwrap() - .set_trans(DBOX_TWEEN_TRANS); + .set_trans(DBOX_TWEEN_TRANS) + .unwrap(); - if !up { - let free = self.node.callable("queue_free"); - y_tween.connect("finished".into(), free); - } + y_tween } } @@ -194,8 +192,9 @@ impl IPanelContainer for DialogBox { self.current_page_number += 1; if self.current_page_number >= ix.pages.len() { - self.tween_into_view(false); - self.current_ix = None; + let free = self.node.callable("queue_free"); + self.tween_into_view(false).connect("finished".into(), free); + return; } From 0ebcbd36334602a28823392488c8285fe3ad3db8 Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 01:03:12 -0500 Subject: [PATCH 26/30] cancel tween fn called before init --- pets-lib/src/dialogue/autoload.rs | 9 +++++++-- pets-lib/src/dialogue/dbox.rs | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index e33e4305..fc7e8b96 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -66,8 +66,13 @@ impl DBoxInterface { // check if a box already exists if ui_layer.has_node(DBOX_NODE_NAME.into()) { - let node = ui_layer.get_node(DBOX_NODE_NAME.into()).unwrap(); - ui_layer.remove_child(node); + let mut node = ui_layer + .get_node(DBOX_NODE_NAME.into()) + .unwrap() + .cast::(); + + node.bind_mut().cancel_tween(); + ui_layer.remove_child(node.upcast()); } ui_layer.add_child(dbox.clone().upcast()); diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index be6d3e9c..59a271bc 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -55,6 +55,7 @@ pub struct DialogBox { current_page_number: usize, speaker: MetaPair, vox: MetaPair, + tween: Option>, // independent from any interaction-related stuff, // these are the actual strings that are displayed @@ -132,6 +133,12 @@ impl DialogBox { self.msg_txt().set_text(self.msg_txt.clone()); } + pub fn cancel_tween(&mut self) { + if let Some(tween) = &mut self.tween { + tween.stop() + } + } + pub fn tween_into_view(&mut self, up: bool) -> Gd { let node = &mut self.node; let viewport_y = node.get_viewport_rect().size.y; @@ -157,6 +164,7 @@ impl DialogBox { .set_trans(DBOX_TWEEN_TRANS) .unwrap(); + self.tween = Some(y_tween.clone()); y_tween } } @@ -169,6 +177,7 @@ impl IPanelContainer for DialogBox { spk_txt: "Cherry".into(), msg_txt: "[wave amp=50 freq=6]Hello, World![/wave]".into(), + tween: None, current_ix: None, current_page_number: 0, speaker: MetaPair::clone(Speaker::Narrator), From da58ded2020e733076ff8e1a5a9040200982bc9d Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 01:26:29 -0500 Subject: [PATCH 27/30] fix panic (again, yippee) --- pets-lib/src/dialogue/autoload.rs | 28 +++++++++++++++++----------- pets-lib/src/dialogue/dbox.rs | 13 +++++++++---- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index fc7e8b96..be94b2fe 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -52,32 +52,38 @@ impl DBoxInterface { #[func] pub fn scene_has_active_dbox(&self) -> bool { let ui_layer = current_scene!().get_node(UI_LAYER_NAME.into()).unwrap(); - ui_layer.has_node(DBOX_NODE_NAME.into()) + if let Some(dbox) = ui_layer.get_node(DBOX_NODE_NAME.into()) { + let dbox = dbox.cast::(); + let dbox = dbox.bind(); + dbox.is_active() + } else { + false + } } #[func] pub fn instantiate_dbox(&self) -> Gd { - let mut dbox = self.dbox_scene.instantiate_as::(); - dbox.set_name(DBOX_NODE_NAME.into()); - let mut ui_layer = current_scene!() .get_node(UI_LAYER_NAME.into()) .expect("scene should have a UILayer"); // check if a box already exists if ui_layer.has_node(DBOX_NODE_NAME.into()) { - let mut node = ui_layer + println!("Reusing existing dialog box"); + let mut dbox = ui_layer .get_node(DBOX_NODE_NAME.into()) .unwrap() .cast::(); - node.bind_mut().cancel_tween(); - ui_layer.remove_child(node.upcast()); + dbox.bind_mut().cancel_tween(); + dbox + } else { + println!("Creating new dialog box"); + let mut dbox = self.dbox_scene.instantiate_as::(); + dbox.set_name(DBOX_NODE_NAME.into()); + ui_layer.add_child(dbox.clone().upcast()); + dbox } - - ui_layer.add_child(dbox.clone().upcast()); - - dbox } } diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 59a271bc..c9149f6d 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -56,6 +56,7 @@ pub struct DialogBox { speaker: MetaPair, vox: MetaPair, tween: Option>, + active: bool, // independent from any interaction-related stuff, // these are the actual strings that are displayed @@ -73,6 +74,10 @@ impl DialogBox { self.node.get_node_as("VSplit/SpeakerName") } + pub fn is_active(&self) -> bool { + self.active + } + /// Get the message text label fn msg_txt(&self) -> Gd { self.node.get_node_as("VSplit/Content") @@ -164,6 +169,7 @@ impl DialogBox { .set_trans(DBOX_TWEEN_TRANS) .unwrap(); + self.active = up; self.tween = Some(y_tween.clone()); y_tween } @@ -177,6 +183,7 @@ impl IPanelContainer for DialogBox { spk_txt: "Cherry".into(), msg_txt: "[wave amp=50 freq=6]Hello, World![/wave]".into(), + active: false, tween: None, current_ix: None, current_page_number: 0, @@ -191,8 +198,7 @@ impl IPanelContainer for DialogBox { fn input(&mut self, event: Gd) { if event.is_action_pressed("ui_accept".into()) { - let di = DBoxInterface::singleton(); - if !di.bind().scene_has_active_dbox() { + if !self.active { return; } @@ -201,8 +207,7 @@ impl IPanelContainer for DialogBox { self.current_page_number += 1; if self.current_page_number >= ix.pages.len() { - let free = self.node.callable("queue_free"); - self.tween_into_view(false).connect("finished".into(), free); + self.tween_into_view(false); return; } From 05a5e0c8e0e758c427aa4ecde99d9ff098f4e567 Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 01:36:32 -0500 Subject: [PATCH 28/30] rm `tw_start` for dialog, just tween from current pos --- pets-lib/src/dialogue/autoload.rs | 2 -- pets-lib/src/dialogue/dbox.rs | 13 +++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index be94b2fe..d9bae5e9 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -69,7 +69,6 @@ impl DBoxInterface { // check if a box already exists if ui_layer.has_node(DBOX_NODE_NAME.into()) { - println!("Reusing existing dialog box"); let mut dbox = ui_layer .get_node(DBOX_NODE_NAME.into()) .unwrap() @@ -78,7 +77,6 @@ impl DBoxInterface { dbox.bind_mut().cancel_tween(); dbox } else { - println!("Creating new dialog box"); let mut dbox = self.dbox_scene.instantiate_as::(); dbox.set_name(DBOX_NODE_NAME.into()); ui_layer.add_child(dbox.clone().upcast()); diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index c9149f6d..c56a31d8 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -147,12 +147,12 @@ impl DialogBox { pub fn tween_into_view(&mut self, up: bool) -> Gd { let node = &mut self.node; let viewport_y = node.get_viewport_rect().size.y; - let visible_y = viewport_y - node.get_size().y; - let (tw_start, tw_end) = if up { - (viewport_y, visible_y) + let tw_end = if up { + // visible y + viewport_y - node.get_size().y } else { - (visible_y, viewport_y) + viewport_y }; let mut y_tween = node.create_tween().unwrap(); @@ -164,11 +164,13 @@ impl DialogBox { DBOX_TWEEN_TIME, ) .unwrap() - .from(Variant::from(tw_start)) + .from(Variant::from(self.node.get_position().y)) .unwrap() .set_trans(DBOX_TWEEN_TRANS) .unwrap(); + godot_print!("tweening: {}", up); + self.active = up; self.tween = Some(y_tween.clone()); y_tween @@ -208,7 +210,6 @@ impl IPanelContainer for DialogBox { if self.current_page_number >= ix.pages.len() { self.tween_into_view(false); - return; } From b7438a2935b70a4a0b7a48b09cab10974d357319 Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 01:48:18 -0500 Subject: [PATCH 29/30] it works, and... that's about it. --- pets-lib/src/dialogue/autoload.rs | 4 +++- pets-lib/src/dialogue/dbox.rs | 22 +++++++++++++++++----- pets-lib/src/world/interaction/manager.rs | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index d9bae5e9..cda095d5 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -41,11 +41,13 @@ impl DBoxInterface { }); let mut dbox = self.instantiate_dbox(); + let set_active = dbox.callable("set_active"); { let mut dbox = dbox.bind_mut(); dbox.set_ix(ix.clone()); dbox.do_draw(); - dbox.tween_into_view(true); + dbox.tween_into_view(true) + .connect("finished".into(), set_active); } } diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index c56a31d8..95b51902 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -83,6 +83,19 @@ impl DialogBox { self.node.get_node_as("VSplit/Content") } + // TODO remove this when upgrading to godot 4.2 + #[func] + pub fn set_active(&mut self) { + println!("set active"); + self.active = true; + } + + #[func] + pub fn set_inactive(&mut self) { + println!("set inactive"); + self.active = false; + } + /// Sets the speaker and message text from strings /// /// DON'T USE THIS FOR INTERACTIONS!! @@ -169,9 +182,6 @@ impl DialogBox { .set_trans(DBOX_TWEEN_TRANS) .unwrap(); - godot_print!("tweening: {}", up); - - self.active = up; self.tween = Some(y_tween.clone()); y_tween } @@ -209,11 +219,13 @@ impl IPanelContainer for DialogBox { self.current_page_number += 1; if self.current_page_number >= ix.pages.len() { - self.tween_into_view(false); + self.tween_into_view(false) + .connect("finished".into(), self.node.callable("set_inactive")); + self.current_page_number = 0; + return; } - godot_print!("going to page {}", self.current_page_number); self.goto_page(self.current_page_number); self.do_draw(); } diff --git a/pets-lib/src/world/interaction/manager.rs b/pets-lib/src/world/interaction/manager.rs index e2ba3d2b..76e30518 100644 --- a/pets-lib/src/world/interaction/manager.rs +++ b/pets-lib/src/world/interaction/manager.rs @@ -105,7 +105,7 @@ impl INode2D for InteractionManager { } } - fn input(&mut self, event: Gd) { + fn unhandled_input(&mut self, event: Gd) { if event.is_action_pressed("ui_accept".into()) { let di = DBoxInterface::singleton(); if di.bind().scene_has_active_dbox() { From d362900e485551691c518b20107b998c37b07d92 Mon Sep 17 00:00:00 2001 From: Cherry Date: Fri, 1 Dec 2023 01:56:36 -0500 Subject: [PATCH 30/30] mark input as handled via viewport method --- pets-lib/src/dialogue/autoload.rs | 4 +--- pets-lib/src/dialogue/dbox.rs | 28 ++++++++-------------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/pets-lib/src/dialogue/autoload.rs b/pets-lib/src/dialogue/autoload.rs index cda095d5..d9bae5e9 100644 --- a/pets-lib/src/dialogue/autoload.rs +++ b/pets-lib/src/dialogue/autoload.rs @@ -41,13 +41,11 @@ impl DBoxInterface { }); let mut dbox = self.instantiate_dbox(); - let set_active = dbox.callable("set_active"); { let mut dbox = dbox.bind_mut(); dbox.set_ix(ix.clone()); dbox.do_draw(); - dbox.tween_into_view(true) - .connect("finished".into(), set_active); + dbox.tween_into_view(true); } } diff --git a/pets-lib/src/dialogue/dbox.rs b/pets-lib/src/dialogue/dbox.rs index 95b51902..dca50bcd 100644 --- a/pets-lib/src/dialogue/dbox.rs +++ b/pets-lib/src/dialogue/dbox.rs @@ -7,7 +7,7 @@ use dialogical::{Interaction, Page}; use dialogical::{Metaline, Metaline::*, PageMeta}; use godot::engine::tween::TransitionType; -use godot::engine::{IPanelContainer, InputEvent, PanelContainer, RichTextLabel, Tween}; +use godot::engine::{IPanelContainer, InputEvent, PanelContainer, RichTextLabel, Tween, Viewport}; use godot::prelude::*; use crate::consts::dialogue::*; @@ -83,19 +83,6 @@ impl DialogBox { self.node.get_node_as("VSplit/Content") } - // TODO remove this when upgrading to godot 4.2 - #[func] - pub fn set_active(&mut self) { - println!("set active"); - self.active = true; - } - - #[func] - pub fn set_inactive(&mut self) { - println!("set inactive"); - self.active = false; - } - /// Sets the speaker and message text from strings /// /// DON'T USE THIS FOR INTERACTIONS!! @@ -182,6 +169,7 @@ impl DialogBox { .set_trans(DBOX_TWEEN_TRANS) .unwrap(); + self.active = up; self.tween = Some(y_tween.clone()); y_tween } @@ -219,15 +207,15 @@ impl IPanelContainer for DialogBox { self.current_page_number += 1; if self.current_page_number >= ix.pages.len() { - self.tween_into_view(false) - .connect("finished".into(), self.node.callable("set_inactive")); + self.tween_into_view(false); self.current_page_number = 0; - - return; + } else { + self.goto_page(self.current_page_number); + self.do_draw(); } - self.goto_page(self.current_page_number); - self.do_draw(); + // mark the input as handled + self.node.get_viewport().unwrap().set_input_as_handled(); } } }