Skip to content

Commit

Permalink
Merge pull request #45 from Lamby777/dialogue-logic
Browse files Browse the repository at this point in the history
Implement Basic Dialogue... (finally omfg)
  • Loading branch information
Lamby777 authored Nov 30, 2023
2 parents b51a936 + 7ab7f8d commit 50f3ac4
Show file tree
Hide file tree
Showing 24 changed files with 209 additions and 99 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ control of your own hardware overly complicated... and is also open-source! <3

- [Soundtrack](https://www.youtube.com/playlist?list=PLxLRTqK8yZMO14zFG12650hGkPOZYV_2p)
- [Promo page](https://sparklet.org/pets)
- [Dialogue Toolkit](https://github.com/Lamby777/dialogical)
- [Discord server](https://discord.gg/xEWa6Kwcad)

---
Expand All @@ -34,6 +35,26 @@ the world, right?

---

## Setting Up

First, make sure you're using the `nightly` channel for Rust. It **WILL NOT
COMPILE ON STABLE** due to use of experimental Rust features!

Then, go download the correct version of Godot Engine... with whatever method is
best for your environment. Add it to your `PATH` as well if you want the "quick
launch" scripts mentioned below to work.

Then, install `dg`, a crate written for managing and compiling dialogue /
interaction files for this game.

```
cargo install dialogical
```

... and you should be ready to go!

---

## (Recommended...?) Workflow

You're probably gonna want to spend most of your time in the `pets-lib` folder.
Expand Down
2 changes: 1 addition & 1 deletion _piskels/Char/BobbyTables.piskel

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion _piskels/Char/Lyembo.piskel

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions pets-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ edition = "2021"
crate-type = ["cdylib"]

[dependencies]
anyhow = "1.0.75"
concat-idents = "1.1.5"
const_format = { version = "0.2.31", features = ["fmt"] }
field_count = "0.1.1"
dialogical = "*"
godot = { git = "https://github.com/godot-rust/gdext", branch = "master" }
indoc = "2.0.4"
num-derive = "0.4.0"
num-traits = "0.2.16"
strum = "0.25.0"
strum_macros = "0.25.2"
serde = {version = "1.0.188", features= ["derive"] }
serde_json = "1.0.107"
thiserror = "1.0.50"
19 changes: 19 additions & 0 deletions pets-lib/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
println!("cargo:rerun-if-changed=./dg/src");
println!("cargo:rerun-if-changed=build.rs");

let dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let dir = PathBuf::from(&dir);

let dg_dir = dir.join("dg");

Command::new("dg")
.args(&["src/main.dg", "-o", "packed.dgc"])
.current_dir(&dg_dir)
.status()
.unwrap();
}
2 changes: 2 additions & 0 deletions pets-lib/dg/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# ignore compiled dialogue
*.dgc
8 changes: 8 additions & 0 deletions pets-lib/dg/src/main.dg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
% Main
###

Import ./rodrick.dg

###
---

45 changes: 45 additions & 0 deletions pets-lib/dg/src/rodrick.dg
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
% Rodrick Sign #1
NAME Rodrick Sign Co.
VOX Default

So... you're reading a sign, eh?\n
Well...

---

Are you smart?

> Nope
@ Rodrick Sign #1 >> Nope

> Definitely not
@ Rodrick Sign #1 >> DefNot

---
% Rodrick Sign #1 >> Nope
NAME Rodrick Sign Co.
VOX Default

Yeah, I didn't think so.

@ Rodrick Sign #1 >> Exit

---
% Rodrick Sign #1 >> DefNot
NAME Rodrick Sign Co.
VOX Default

Yeah, I definitely didn't think so.

@ Rodrick Sign #1 >> Exit

---
% Rodrick Sign #1 >> Exit
NAME Rodrick Sign Co.
VOX Default

Come back when you're smart.

$ Exit
---

4 changes: 2 additions & 2 deletions pets-lib/src/battle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//!
use godot::engine::global::Key;
use godot::engine::{Node2D, Node2DVirtual};
use godot::engine::{INode2D, Node2D};
use godot::prelude::*;

mod player;
Expand All @@ -19,7 +19,7 @@ struct BattleEngine {
}

#[godot_api]
impl Node2DVirtual for BattleEngine {
impl INode2D for BattleEngine {
fn init(node: Base<Node2D>) -> Self {
Self { node }
}
Expand Down
4 changes: 2 additions & 2 deletions pets-lib/src/battle/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! Player icon that moves around n shit during battles
//!
use godot::engine::{Node2D, Node2DVirtual};
use godot::engine::{INode2D, Node2D};
use godot::prelude::*;

use super::stat_translation::to_battle;
Expand Down Expand Up @@ -66,7 +66,7 @@ impl BattleIcon {
}

#[godot_api]
impl Node2DVirtual for BattleIcon {
impl INode2D for BattleIcon {
fn init(node: Base<Node2D>) -> Self {
Self {
node,
Expand Down
4 changes: 2 additions & 2 deletions pets-lib/src/dialogue/autoload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl DBoxInterface {
}

#[func]
pub fn show_dialog(&self, spk: GodotString, msg: GodotString) {
pub fn show_dialog(&self, spk: GString, msg: GString) {
let mut dbox_gd = self.dbox_scene.instantiate_as::<DialogBox>();

dbox_gd.set_name("Dialog".into());
Expand All @@ -60,7 +60,7 @@ impl DBoxInterface {
}

#[godot_api]
impl Node2DVirtual for DBoxInterface {
impl INode2D for DBoxInterface {
fn init(node: Base<Node2D>) -> Self {
Self {
node,
Expand Down
28 changes: 14 additions & 14 deletions pets-lib/src/dialogue/dbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,44 @@
//!
use godot::engine::tween::TransitionType;
use godot::engine::{PanelContainer, PanelContainerVirtual, RichTextLabel};
use godot::engine::{IPanelContainer, PanelContainer, RichTextLabel};
use godot::prelude::*;

const DBOX_TWEEN_TIME: f64 = 1.0;
const DBOX_TWEEN_TIME: f64 = 0.5;
const DBOX_TWEEN_TRANS: TransitionType = TransitionType::TRANS_QUAD;

#[derive(GodotClass)]
#[class(base=PanelContainer)]
pub struct DialogBox {
#[base]
node: Base<PanelContainer>,
speaker: GodotString,
content: GodotString,
spk_txt: GString,
msg_txt: GString,
}

#[godot_api]
impl DialogBox {
/// Get the speaker name label
fn spk_txt(&self) -> Gd<RichTextLabel> {
self.node.get_node_as::<RichTextLabel>("VSplit/SpeakerName")
self.node.get_node_as("VSplit/SpeakerName")
}

/// Get the message text label
fn msg_txt(&self) -> Gd<RichTextLabel> {
self.node.get_node_as::<RichTextLabel>("VSplit/Content")
self.node.get_node_as("VSplit/Content")
}

#[func]
pub fn set_txts(&mut self, speaker: GodotString, content: GodotString) {
self.speaker = speaker;
self.content = content;
pub fn set_txts(&mut self, speaker: GString, content: GString) {
self.spk_txt = speaker;
self.msg_txt = content;
}

#[func]
pub fn do_draw(&mut self) {
// I THINK this clone is fine, probably RC'd
self.spk_txt().set_text(self.speaker.clone());
self.msg_txt().set_text(self.content.clone());
self.spk_txt().set_text(self.spk_txt.clone());
self.msg_txt().set_text(self.msg_txt.clone());
}

#[func]
Expand Down Expand Up @@ -80,12 +80,12 @@ impl DialogBox {
}

#[godot_api]
impl PanelContainerVirtual for DialogBox {
impl IPanelContainer for DialogBox {
fn init(node: Base<PanelContainer>) -> Self {
Self {
node,
speaker: "Cherry".into(),
content: "[wave amp=50 freq=6]Hello, World![/wave]".into(),
spk_txt: "Cherry".into(),
msg_txt: "[wave amp=50 freq=6]Hello, World![/wave]".into(),
}
}

Expand Down
48 changes: 22 additions & 26 deletions pets-lib/src/dialogue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,31 @@
pub mod autoload;
pub mod dbox;

/// Possible outcomes of picking a dialogue option.
///
/// "Yeah, this new name's WAY less confusing... right?"
/// - Devon, 2037
pub enum DialogueAction {
/// Leads to another node
/// (simple `A -> (B|C)` dialogue)
NextNode(DialogueNode),
use dialogical::InteractionMap;
use indoc::indoc;

/// Leads to running a function pointer
/// (fancy stuff like shops)
Action(fn()),
use std::sync::OnceLock;

/// End the tree with this option and (usually)
/// return control to the user ("goodbye")
End,
}
static INTERACTIONS: OnceLock<InteractionMap> = OnceLock::new();

pub struct DialogueChoice {
label: String,
available: bool,
leads_to: DialogueAction,
macro_rules! packed_dialogue {
() => {
dialogical::deserialize(include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/dg/packed.dgc"
)))
};
}

pub struct DialogueNode {
// TODO replace with &'a str
speaker: String,
vox: String,

text: String,
options: Vec<DialogueChoice>,
/// Load every interaction in the game from `packed.dgc`
pub fn ix_list() -> &'static InteractionMap {
INTERACTIONS.get_or_init(|| {
packed_dialogue!().expect(indoc! {"
Failed to load dialogues. If you are a player,
please report this to the developers. If you're
a contributor, make sure the build script has
ran properly or manually compile the interaction
list yourself.
"})
})
}
4 changes: 2 additions & 2 deletions pets-lib/src/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::prelude::*;
// Or maybe just in a vector... and there can be a function
// that looks up the item by searching the vector for an Item
// with the correct `name` property?
#[derive(Debug, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Item {
categories: Vec<ItemCategory>,

Expand All @@ -21,7 +21,7 @@ pub struct Item {
}

// are you serious m8
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)]
pub enum ItemCategory {
Weapon,
Armor,
Expand Down
24 changes: 9 additions & 15 deletions pets-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// TODO remove this soon
#![allow(dead_code)]
#![allow(unused_imports)]
#![feature(variant_count)]

use godot::engine::Engine;
Expand All @@ -27,25 +28,18 @@ mod stats;
mod world;

mod prelude {
pub use crate::macros::*;

// maybe make a data structures module if i end up making more?
pub use crate::limiq::*;

// item stuff, probably useful everywhere
pub use crate::items::*;
pub use crate::limiq::*;
pub use crate::macros::*;
pub use crate::stats::*;

pub use crate::dialogue::ix_list;
pub use crate::world::interaction::manager::InteractionManager;

// stats stuff
pub use crate::stats::pchars::PChar;
pub use crate::stats::savefiles::SaveFile;
pub use crate::stats::statcalc::{CharStatCalcs, StatCalcFn, StatCalcList};
pub use crate::stats::stats_interface::StatsInterface;
pub use crate::stats::*;

// is this bad practice? no clue and idc honestly
// it's convenient with no real caveat, therefore...
pub use anyhow::{bail, Result};
pub use serde::{Deserialize, Serialize};
pub use std::cell::RefCell;
pub use std::collections::{HashMap, HashSet};
pub use std::fmt::{Debug, Display};
Expand All @@ -61,10 +55,10 @@ unsafe impl ExtensionLibrary for PetsLib {
if level == InitLevel::Scene {
let mut engine = Engine::singleton();

let gd: Gd<StatsInterface> = Gd::new_default();
let gd = StatsInterface::alloc_gd();
engine.register_singleton("Stats".into(), gd.upcast());

let gd: Gd<DBoxInterface> = Gd::new_default();
let gd = DBoxInterface::alloc_gd();
engine.register_singleton("DBox".into(), gd.upcast());
}
}
Expand Down
Loading

0 comments on commit 50f3ac4

Please sign in to comment.