feat: added colors and protagonist to preview
This commit is contained in:
parent
b62d8793b9
commit
1e1bb8936f
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
.import
|
.import
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
export
|
||||||
|
|
|
@ -41,7 +41,7 @@ There are few things that need to be ironed out to be 100% feature compatible wi
|
||||||
- [ ] Support for [format functions](https://yarnspinner.dev/docs/syntax/#format-functions).
|
- [ ] Support for [format functions](https://yarnspinner.dev/docs/syntax/#format-functions).
|
||||||
- [ ] ~Support~ Fix for conditional options.
|
- [ ] ~Support~ Fix for conditional options.
|
||||||
- [ ] In-editor dialogue editor with preview.
|
- [ ] In-editor dialogue editor with preview.
|
||||||
- [ ] Lines connecting different nodes if they refer to eachother.
|
- [x] Lines connecting different nodes if they refer to eachother.
|
||||||
- [x] Error hints when doing something wrong.
|
- [x] Error hints when doing something wrong.
|
||||||
- [x] Basic saving, opening and saving-as.
|
- [x] Basic saving, opening and saving-as.
|
||||||
- [ ] Remove all `printerr` in favor of (soft) `assert`s.
|
- [ ] Remove all `printerr` in favor of (soft) `assert`s.
|
||||||
|
|
|
@ -50,12 +50,13 @@ class Command:
|
||||||
|
|
||||||
class WolNode:
|
class WolNode:
|
||||||
var name = ''
|
var name = ''
|
||||||
|
var program
|
||||||
var instructions = []
|
var instructions = []
|
||||||
var labels = {}
|
var labels = {}
|
||||||
var tags = []
|
var tags = []
|
||||||
var source_id = ''
|
var source_id = ''
|
||||||
|
|
||||||
func _init(other = null):
|
func _init(_program, other = null):
|
||||||
if other != null and other.get_script() == self.get_script():
|
if other != null and other.get_script() == self.get_script():
|
||||||
name = other.name
|
name = other.name
|
||||||
instructions += other.instructions
|
instructions += other.instructions
|
||||||
|
@ -64,6 +65,8 @@ class WolNode:
|
||||||
tags += other.tags
|
tags += other.tags
|
||||||
source_id = other.source_id
|
source_id = other.source_id
|
||||||
|
|
||||||
|
program = _program
|
||||||
|
|
||||||
func equals(other):
|
func equals(other):
|
||||||
if other.get_script() != get_script():
|
if other.get_script() != get_script():
|
||||||
return false
|
return false
|
||||||
|
@ -80,6 +83,15 @@ class WolNode:
|
||||||
func _to_string():
|
func _to_string():
|
||||||
return "WolNode[%s:%s]" % [name, source_id]
|
return "WolNode[%s:%s]" % [name, source_id]
|
||||||
|
|
||||||
|
func get_lines():
|
||||||
|
var lines = []
|
||||||
|
|
||||||
|
for instruction in instructions:
|
||||||
|
if instruction.operation == Constants.ByteCode.RunLine:
|
||||||
|
lines.append(program.strings[instruction.operands.front().value])
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
# TODO: Make this make sense
|
# TODO: Make this make sense
|
||||||
class Operand:
|
class Operand:
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
|
|
|
@ -163,7 +163,7 @@ func compile():
|
||||||
func compile_node(program, parsed_node):
|
func compile_node(program, parsed_node):
|
||||||
self.assert(not program.nodes.has(parsed_node.name), 'Duplicate node in program: %s' % parsed_node.name)
|
self.assert(not program.nodes.has(parsed_node.name), 'Duplicate node in program: %s' % parsed_node.name)
|
||||||
|
|
||||||
var node_compiled = Program.WolNode.new()
|
var node_compiled = Program.WolNode.new(program)
|
||||||
|
|
||||||
node_compiled.name = parsed_node.name
|
node_compiled.name = parsed_node.name
|
||||||
node_compiled.tags = parsed_node.tags
|
node_compiled.tags = parsed_node.tags
|
||||||
|
|
|
@ -4,12 +4,14 @@ extends Panel
|
||||||
var current_graph_node
|
var current_graph_node
|
||||||
|
|
||||||
onready var preview = get_node('../Preview')
|
onready var preview = get_node('../Preview')
|
||||||
|
onready var wol_editor = find_parent('WolEditor')
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
hide()
|
hide()
|
||||||
connect('visibility_changed', self, '_on_visibility_changed')
|
connect('visibility_changed', self, '_on_visibility_changed')
|
||||||
$Tools/Left/Play.connect('pressed', self, '_on_play')
|
$Tools/Left/Play.connect('pressed', self, '_on_play')
|
||||||
$Tools/Right/Close.connect('pressed', self, 'close')
|
$Tools/Right/Close.connect('pressed', self, 'close')
|
||||||
|
$Tools/Right/Delete.connect('pressed', self, '_on_delete_pressed')
|
||||||
|
|
||||||
func close():
|
func close():
|
||||||
hide()
|
hide()
|
||||||
|
@ -55,6 +57,9 @@ func toggle_text_edit(text_edit):
|
||||||
func _on_play():
|
func _on_play():
|
||||||
preview.open_node(current_graph_node)
|
preview.open_node(current_graph_node)
|
||||||
|
|
||||||
|
func _on_delete_pressed():
|
||||||
|
wol_editor.confirm_delete_node(current_graph_node)
|
||||||
|
|
||||||
func _on_title_changed():
|
func _on_title_changed():
|
||||||
current_graph_node.node.title = $HBoxContainer/TextEdit.text
|
current_graph_node.node.title = $HBoxContainer/TextEdit.text
|
||||||
current_graph_node.compile()
|
current_graph_node.compile()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
tool
|
||||||
extends Panel
|
extends Panel
|
||||||
|
|
||||||
var current_graph_node
|
var current_graph_node
|
||||||
|
@ -7,14 +8,15 @@ onready var button_template = $Options/List/ButtonTemplate
|
||||||
|
|
||||||
onready var wol_editor = find_parent('WolEditor')
|
onready var wol_editor = find_parent('WolEditor')
|
||||||
|
|
||||||
# TODO: Make sure all focus is lost when clicking this pane
|
|
||||||
# TODO: Add restart button
|
|
||||||
# TODO: Add next button
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
hide()
|
hide()
|
||||||
$Wol.connect('line', self, '_on_line')
|
$Wol.connect('line', self, '_on_line')
|
||||||
$Wol.connect('options', self, '_on_options')
|
$Wol.connect('options', self, '_on_options')
|
||||||
|
|
||||||
|
connect('gui_input', self, '_on_gui_input')
|
||||||
|
|
||||||
|
$Tools/Left/Next.connect('pressed', self, 'next')
|
||||||
|
$Tools/Left/Restart.connect('pressed', self, 'restart')
|
||||||
$Tools/Right/Close.connect('pressed', self, 'close')
|
$Tools/Right/Close.connect('pressed', self, 'close')
|
||||||
|
|
||||||
func open_node(graph_node):
|
func open_node(graph_node):
|
||||||
|
@ -22,6 +24,23 @@ func open_node(graph_node):
|
||||||
|
|
||||||
$Wol.stop()
|
$Wol.stop()
|
||||||
|
|
||||||
|
yield(get_tree(), 'idle_frame')
|
||||||
|
|
||||||
|
clear_chat()
|
||||||
|
|
||||||
|
$Tools/Left/Protagonist.text = guess_protagonist()
|
||||||
|
|
||||||
|
$Wol.variable_storage = {}
|
||||||
|
$Wol.set_program(wol_editor.get_program())
|
||||||
|
|
||||||
|
yield(get_tree(), 'idle_frame')
|
||||||
|
|
||||||
|
$Wol.start(current_graph_node.node.title)
|
||||||
|
|
||||||
|
show()
|
||||||
|
grab_focus()
|
||||||
|
|
||||||
|
func clear_chat():
|
||||||
for child in $Content/List.get_children():
|
for child in $Content/List.get_children():
|
||||||
if child != line_template and not 'Padding' in child.name:
|
if child != line_template and not 'Padding' in child.name:
|
||||||
$Content/List.remove_child(child)
|
$Content/List.remove_child(child)
|
||||||
|
@ -31,11 +50,24 @@ func open_node(graph_node):
|
||||||
if child != button_template:
|
if child != button_template:
|
||||||
$Options/List.remove_child(child)
|
$Options/List.remove_child(child)
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
|
|
||||||
$Wol.variable_storage = {}
|
|
||||||
$Wol.set_program(wol_editor.get_program())
|
func guess_protagonist():
|
||||||
$Wol.start(current_graph_node.node.title)
|
var protagonist = 'You'
|
||||||
show()
|
var wol_node = wol_editor.get_program().nodes[current_graph_node.node.title]
|
||||||
|
|
||||||
|
for line in wol_node.get_lines():
|
||||||
|
if get_protagonist(line):
|
||||||
|
protagonist = get_protagonist(line)
|
||||||
|
if protagonist == 'You':
|
||||||
|
break
|
||||||
|
|
||||||
|
return protagonist
|
||||||
|
|
||||||
|
func get_protagonist(line):
|
||||||
|
if ':' in line.text and line.text.find(':') < 30:
|
||||||
|
return line.text.split(':')[0]
|
||||||
|
return
|
||||||
|
|
||||||
func close():
|
func close():
|
||||||
hide()
|
hide()
|
||||||
|
@ -45,14 +77,33 @@ func close():
|
||||||
func next():
|
func next():
|
||||||
$Wol.resume()
|
$Wol.resume()
|
||||||
|
|
||||||
|
func restart():
|
||||||
|
$Wol.stop()
|
||||||
|
|
||||||
|
yield(get_tree(), 'idle_frame')
|
||||||
|
|
||||||
|
clear_chat()
|
||||||
|
|
||||||
|
yield(get_tree(), 'idle_frame')
|
||||||
|
|
||||||
|
$Wol.start(current_graph_node.node.title)
|
||||||
|
|
||||||
func _on_line(line):
|
func _on_line(line):
|
||||||
var line_node = line_template.duplicate()
|
var line_node = line_template.duplicate()
|
||||||
$Content/List.add_child(line_node)
|
$Content/List.add_child(line_node)
|
||||||
$Content/List/PaddingBottom.raise()
|
$Content/List/PaddingBottom.raise()
|
||||||
# TODO: Add hash() based color from speaker
|
|
||||||
|
|
||||||
|
# TODO: Add hash() based color from speaker
|
||||||
line_node.get_node('RichTextLabel').bbcode_text = line.text
|
line_node.get_node('RichTextLabel').bbcode_text = line.text
|
||||||
|
|
||||||
|
var padding_node = 'PaddingRight' if get_protagonist(line) == $Tools/Left/Protagonist.text else 'PaddingLeft'
|
||||||
|
line_node.get_node(padding_node).size_flags_horizontal = SIZE_EXPAND_FILL
|
||||||
|
var panel = line_node.get_node('RichTextLabel/Panel').get('custom_styles/panel').duplicate()
|
||||||
|
panel.bg_color = Color(hash(get_protagonist(line)))
|
||||||
|
line_node.get_node('RichTextLabel/Panel').set('custom_styles/panel', panel)
|
||||||
|
|
||||||
line_node.show()
|
line_node.show()
|
||||||
|
|
||||||
yield(get_tree(), 'idle_frame')
|
yield(get_tree(), 'idle_frame')
|
||||||
$Content.scroll_vertical = $Content/List.rect_size.y
|
$Content.scroll_vertical = $Content/List.rect_size.y
|
||||||
|
|
||||||
|
@ -73,10 +124,14 @@ func _on_option_pressed(option):
|
||||||
$Options/List.remove_child(child)
|
$Options/List.remove_child(child)
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
|
|
||||||
|
func _on_gui_input(event):
|
||||||
|
if visible:
|
||||||
|
if event is InputEventMouseButton and event.doubleclick:
|
||||||
|
next()
|
||||||
|
|
||||||
|
if event is InputEventMouseButton and event.pressed:
|
||||||
|
grab_focus()
|
||||||
|
|
||||||
func _input(event):
|
func _input(event):
|
||||||
if visible \
|
if visible and has_focus() and event is InputEventKey and not event.pressed and event.scancode in [KEY_SPACE, KEY_ENTER]:
|
||||||
and ( \
|
|
||||||
(event is InputEventMouseButton and event.doubleclick) \
|
|
||||||
or (event is InputEventKey and not event.pressed and event.scancode in [KEY_SPACE, KEY_ENTER]) \
|
|
||||||
):
|
|
||||||
next()
|
next()
|
||||||
|
|
|
@ -10,6 +10,17 @@ var selected_node
|
||||||
|
|
||||||
onready var original_delete_node_dialog = $DeleteNodeDialog.dialog_text
|
onready var original_delete_node_dialog = $DeleteNodeDialog.dialog_text
|
||||||
|
|
||||||
|
# TODO: Conditionally load in theme based on Editor or standalone
|
||||||
|
# TODO: Make deleting undo-able
|
||||||
|
# TODO: Implement alternative "single" line style of connecting
|
||||||
|
# TODO: Test out web version
|
||||||
|
# TODO: Make web loading / saving work
|
||||||
|
# TODO: Make theme for standalone editor
|
||||||
|
# TODO: Make a "Godot editor" version of the editor theme
|
||||||
|
# FIXME: Make lines render appropriately after connecting
|
||||||
|
# FIXME: Make all parts of the code "tool"s and safekeep its execution while in editor
|
||||||
|
# FIXME: Fix changing of titles
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
for menu_button in [$Menu/File]:
|
for menu_button in [$Menu/File]:
|
||||||
menu_button.get_popup().connect('index_pressed', self, '_on_menu_pressed', [menu_button.get_popup()])
|
menu_button.get_popup().connect('index_pressed', self, '_on_menu_pressed', [menu_button.get_popup()])
|
||||||
|
@ -20,13 +31,10 @@ func _ready():
|
||||||
|
|
||||||
$DeleteNodeDialog.connect('confirmed', self, 'delete_node')
|
$DeleteNodeDialog.connect('confirmed', self, 'delete_node')
|
||||||
|
|
||||||
# TODO: Conditionally load in theme based on Editor or standalone
|
|
||||||
|
|
||||||
path = 'res://dialogue.wol'
|
path = 'res://dialogue.wol'
|
||||||
build_nodes()
|
build_nodes()
|
||||||
|
|
||||||
func create_node(position = Vector2.ZERO):
|
func create_node(position = Vector2.ZERO):
|
||||||
print('creating node!')
|
|
||||||
var graph_node = GraphNodeTemplate.duplicate()
|
var graph_node = GraphNodeTemplate.duplicate()
|
||||||
$GraphEdit.add_child(graph_node)
|
$GraphEdit.add_child(graph_node)
|
||||||
|
|
||||||
|
@ -43,9 +51,16 @@ func create_node(position = Vector2.ZERO):
|
||||||
graph_node.show()
|
graph_node.show()
|
||||||
|
|
||||||
func delete_node(node = selected_node):
|
func delete_node(node = selected_node):
|
||||||
|
if $HBoxContainer/Editor.visible:
|
||||||
|
$HBoxContainer/Editor.close()
|
||||||
$GraphEdit.remove_child(node)
|
$GraphEdit.remove_child(node)
|
||||||
node.queue_free()
|
node.queue_free()
|
||||||
|
|
||||||
|
func confirm_delete_node(node = selected_node):
|
||||||
|
selected_node = node
|
||||||
|
$DeleteNodeDialog.dialog_text = original_delete_node_dialog % selected_node.name
|
||||||
|
$DeleteNodeDialog.popup()
|
||||||
|
|
||||||
func build_nodes():
|
func build_nodes():
|
||||||
for node in Compiler.new(path).get_nodes():
|
for node in Compiler.new(path).get_nodes():
|
||||||
var graph_node = GraphNodeTemplate.duplicate()
|
var graph_node = GraphNodeTemplate.duplicate()
|
||||||
|
@ -178,6 +193,5 @@ func _input(event):
|
||||||
and not event.pressed and event.scancode == KEY_DELETE \
|
and not event.pressed and event.scancode == KEY_DELETE \
|
||||||
and selected_node \
|
and selected_node \
|
||||||
and not $HBoxContainer/Editor.visible:
|
and not $HBoxContainer/Editor.visible:
|
||||||
$DeleteNodeDialog.dialog_text = original_delete_node_dialog % selected_node.name
|
confirm_delete_node()
|
||||||
$DeleteNodeDialog.popup()
|
|
||||||
|
|
||||||
|
|
BIN
addons/Wol/editor/WolEditor.tscn
(Stored with Git LFS)
BIN
addons/Wol/editor/WolEditor.tscn
(Stored with Git LFS)
Binary file not shown.
Reference in a new issue