mirror of
https://github.com/yeslayla/simple-dialogue.git
synced 2025-07-04 20:55:02 +02:00
Initial commit
This commit is contained in:
7
addons/simple_dialogue/plugin.cfg
Normal file
7
addons/simple_dialogue/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Simple Dialogue"
|
||||
description=""
|
||||
author="joseph@cloudsumu.com"
|
||||
version="1.0"
|
||||
script="plugin.gd"
|
10
addons/simple_dialogue/plugin.gd
Normal file
10
addons/simple_dialogue/plugin.gd
Normal file
@ -0,0 +1,10 @@
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
pass
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
pass
|
38
addons/simple_dialogue/samples/minimal/minimal.gd
Normal file
38
addons/simple_dialogue/samples/minimal/minimal.gd
Normal file
@ -0,0 +1,38 @@
|
||||
extends Node
|
||||
|
||||
var timeline = STimeline.new("res://addons/simple_dialogue/samples/sample.yaml")
|
||||
var event : SEvent
|
||||
export var autoDecide : int = 1
|
||||
|
||||
func _process(_delta):
|
||||
if(Input.is_action_just_pressed("ui_accept")):
|
||||
|
||||
# Check for a choice before reading the timeline
|
||||
# using `STimeline.is_choice()`
|
||||
if timeline.is_choice():
|
||||
|
||||
# You can utilize `STimeline.get_choices()` to return
|
||||
# an array with all choices as strings in order
|
||||
|
||||
# This sample uses the `autoDecide` variable for every
|
||||
# choice
|
||||
print("You: ", timeline.get_choices()[autoDecide])
|
||||
|
||||
# Use `STimeline.make_choice(int)` to make a choice
|
||||
# and load that choice's events
|
||||
timeline.make_choice(autoDecide)
|
||||
return
|
||||
|
||||
# Use `STimeline.read()` to get the next SEvent
|
||||
# in a dialogue timeline
|
||||
event = timeline.read()
|
||||
|
||||
# The primary properties of a SEvent is
|
||||
# `name`, `message`, and `portrait`
|
||||
if event:
|
||||
print(event.name,": ", event.message)
|
||||
|
||||
# When STimeline.read() returns null, the timeline has
|
||||
# completed and you can exit the dialogue
|
||||
if event == null:
|
||||
get_tree().quit()
|
6
addons/simple_dialogue/samples/minimal/minimal.tscn
Normal file
6
addons/simple_dialogue/samples/minimal/minimal.tscn
Normal file
@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/simple_dialouge/samples/minimal/minimal.gd" type="Script" id=1]
|
||||
|
||||
[node name="Simple Dialogue Minimal Example" type="Node"]
|
||||
script = ExtResource( 1 )
|
53
addons/simple_dialogue/samples/sample.yaml
Normal file
53
addons/simple_dialogue/samples/sample.yaml
Normal file
@ -0,0 +1,53 @@
|
||||
apiVersion: 1.0 # `apiVersion` is used just in case of future updates to the schema
|
||||
kind: timeline # `kind` should be set to timeline for all timeline files
|
||||
events: # `events` are a list of event objects
|
||||
|
||||
# Sample Event Object
|
||||
- # Two string properties are provided for each locale
|
||||
# `name` should be the name of the speaker
|
||||
# `message` should be the words said by the speaker
|
||||
name:
|
||||
en_US: Person
|
||||
message:
|
||||
en_US: Hello, I say witty dialogue!
|
||||
|
||||
# Sample choice
|
||||
- name:
|
||||
en_US: Question Asker
|
||||
message:
|
||||
en_US: Pick a number between 1-3
|
||||
|
||||
# A `choices` block of `choice` objects can be added
|
||||
# to work as a choice
|
||||
choices:
|
||||
- # A choice object contains two properties
|
||||
# `choice` is a string that works as the display text for the choice
|
||||
# `events` is a list of all events triggered by this choice
|
||||
choice:
|
||||
en_US: 1
|
||||
events:
|
||||
- name:
|
||||
en_US: Question Asker
|
||||
message:
|
||||
en_US: You picked '1'
|
||||
- choice:
|
||||
en_US: 2
|
||||
events:
|
||||
- name:
|
||||
en_US: Question Asker
|
||||
message:
|
||||
en_US: You picked '2'
|
||||
- choice:
|
||||
en_US: 3
|
||||
events:
|
||||
- name:
|
||||
en_US: Question Asker
|
||||
message:
|
||||
en_US: You picked '3'
|
||||
|
||||
# After choice events finish, the timeline returns
|
||||
# the timeline
|
||||
- name:
|
||||
en_US: Person
|
||||
message:
|
||||
en_US: Wow! That is a very cool choice!
|
31
addons/simple_dialogue/scripts/schoice.gd
Normal file
31
addons/simple_dialogue/scripts/schoice.gd
Normal file
@ -0,0 +1,31 @@
|
||||
class_name SChoice
|
||||
|
||||
export(Dictionary) var raw_data = {}
|
||||
export(Array) var event_data = []
|
||||
|
||||
var SEVENT = load("res://addons/simple_dialogue/scripts/sevent.gd")
|
||||
|
||||
var events : Array setget ,_get_events
|
||||
var choice : String setget ,_get_choice
|
||||
|
||||
func _init(data : Dictionary):
|
||||
raw_data = data
|
||||
|
||||
func _get_events() -> Array:
|
||||
var event_array = []
|
||||
if "events" in raw_data:
|
||||
for event in raw_data["events"]:
|
||||
var dialogue = SEVENT.new(event)
|
||||
event_array.append(dialogue)
|
||||
return event_array
|
||||
|
||||
func _get_choice() -> String:
|
||||
var locale = TranslationServer.get_locale()
|
||||
if locale in raw_data["choice"]:
|
||||
return raw_data["choice"][locale]
|
||||
elif SEVENT.DEFAULT_LOCALE in raw_data["choice"]:
|
||||
return raw_data["choice"][SEVENT.DEFAULT_LOCALE]
|
||||
|
||||
push_error("Choice property does not exist with translation %s and %s"
|
||||
% [locale, SEVENT.DEFAULT_LOCALE])
|
||||
return "INVALID"
|
41
addons/simple_dialogue/scripts/sevent.gd
Normal file
41
addons/simple_dialogue/scripts/sevent.gd
Normal file
@ -0,0 +1,41 @@
|
||||
class_name SEvent
|
||||
|
||||
const DEFAULT_LOCALE = "en_US"
|
||||
|
||||
var raw_data = {}
|
||||
var name : String setget ,_get_name
|
||||
var message : String setget ,_get_message
|
||||
var portrait : Texture setget ,_get_portrait
|
||||
var choices : Array setget ,_get_choices
|
||||
|
||||
func _init(data : Dictionary):
|
||||
raw_data = data
|
||||
|
||||
func get_locale(property, locale = TranslationServer.get_locale()) -> String:
|
||||
if locale in raw_data[property]:
|
||||
return raw_data[property][locale]
|
||||
elif DEFAULT_LOCALE in raw_data[property]:
|
||||
return raw_data[property][DEFAULT_LOCALE]
|
||||
|
||||
push_error("%s property does not exist with translations %s and %s"
|
||||
% [property, locale, DEFAULT_LOCALE])
|
||||
return "INVALID"
|
||||
|
||||
func _get_choices() -> Array:
|
||||
var data = []
|
||||
if "choices" in raw_data:
|
||||
for choice in raw_data["choices"]:
|
||||
var choice_obj = SChoice.new(choice)
|
||||
data.append(choice_obj)
|
||||
return data
|
||||
|
||||
func _get_name() -> String:
|
||||
return get_locale("name")
|
||||
|
||||
func _get_message() -> String:
|
||||
return get_locale("message")
|
||||
|
||||
func _get_portrait() -> Texture:
|
||||
if raw_data.get("portrait","") != "":
|
||||
return load(raw_data["portrait"]) as Texture
|
||||
return null
|
83
addons/simple_dialogue/scripts/stimeline.gd
Normal file
83
addons/simple_dialogue/scripts/stimeline.gd
Normal file
@ -0,0 +1,83 @@
|
||||
class_name STimeline
|
||||
|
||||
export(String) var file_path = ""
|
||||
export(Array) var events = []
|
||||
|
||||
var _event_stream = []
|
||||
var _pos_lifo = []
|
||||
var _event_lifo = []
|
||||
var _pos : int = 0
|
||||
var _yaml = preload("res://addons/godot-yaml/gdyaml.gdns").new()
|
||||
|
||||
func _init(path : String):
|
||||
var file : File = File.new()
|
||||
if !file.file_exists(path):
|
||||
push_error("Could not load timeline at path: %s" % path)
|
||||
return
|
||||
file_path = path
|
||||
file.open(path, File.READ)
|
||||
|
||||
var raw_data = _yaml.parse(file.get_as_text())
|
||||
file.close()
|
||||
|
||||
if not "apiVersion" in raw_data or raw_data["apiVersion"] != 1.0:
|
||||
push_error("'%s' is using an outdated timeline!" % file_path)
|
||||
return
|
||||
if not "kind" in raw_data or raw_data["kind"] != "timeline":
|
||||
push_error("'%s' is not a timeline!" % file_path)
|
||||
return
|
||||
if "events" in raw_data:
|
||||
for event in raw_data["events"]:
|
||||
var dialogue = SEvent.new(event)
|
||||
events.push_back(dialogue)
|
||||
else:
|
||||
push_warning("'%s' timeline does not have any events!" % file_path)
|
||||
|
||||
_event_stream = events
|
||||
_pos = 0
|
||||
|
||||
func get_cursor() -> int:
|
||||
return _pos
|
||||
|
||||
func seek(new_pos : int) -> void:
|
||||
_pos = new_pos
|
||||
|
||||
func get_event(offset : int = 0) -> SEvent:
|
||||
if _pos + offset < len(_event_stream):
|
||||
return _event_stream[_pos + offset]
|
||||
return null
|
||||
|
||||
func read() -> SEvent:
|
||||
var event = get_event()
|
||||
if event == null and len(_event_lifo) > 0:
|
||||
_event_stream = _event_lifo.pop_back()
|
||||
_pos = _pos_lifo.pop_back()
|
||||
event = get_event()
|
||||
_pos += 1
|
||||
return event
|
||||
|
||||
func get_choices() -> Array:
|
||||
var choices = []
|
||||
var event = get_event(-1)
|
||||
if event:
|
||||
for choice in event.choices : choices.append(choice.choice)
|
||||
return choices
|
||||
|
||||
func is_choice() -> bool:
|
||||
return len(get_choices()) > 0
|
||||
|
||||
func make_choice(choice : int) -> void:
|
||||
var event = get_event(-1)
|
||||
if not event:
|
||||
push_error("Attempted to find choice at invalid event! Pos '%s' Event Stream: %s"
|
||||
% [_pos, _event_stream])
|
||||
return
|
||||
if choice > len(event.choices):
|
||||
push_error("Attempted to make an out of bounds choice! Timeline '%s': choice '%s' while expected size is '%s'"
|
||||
% [self.file_path, choice, len(event.choices)])
|
||||
return
|
||||
var choice_obj : SChoice = event.choices[choice]
|
||||
_event_lifo.push_back(_event_stream)
|
||||
_event_stream = choice_obj.events
|
||||
_pos_lifo.push_back(_pos)
|
||||
_pos = 0
|
Reference in New Issue
Block a user