initial commit.
This commit is contained in:
commit
2ae288a3d6
|
@ -0,0 +1,17 @@
|
|||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.bmp filter=lfs diff=lfs merge=lfs -text
|
||||
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
||||
*.ase filter=lfs diff=lfs merge=lfs -text
|
||||
*.atex filter=lfs diff=lfs merge=lfs -text
|
||||
*.tex filter=lfs diff=lfs merge=lfs -text
|
||||
*.vs filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdn filter=lfs diff=lfs merge=lfs -text
|
||||
*.aseprite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tga filter=lfs diff=lfs merge=lfs -text
|
||||
*.tga filter=lfs diff=lfs merge=lfs -text
|
||||
*.scn filter=lfs diff=lfs merge=lfs -text
|
||||
*.res filter=lfs diff=lfs merge=lfs -text
|
|
@ -0,0 +1,3 @@
|
|||
.import
|
||||
.cache
|
||||
*.*.s??
|
|
@ -0,0 +1,55 @@
|
|||
extends Node
|
||||
|
||||
# globals, for the game
|
||||
var reading_speed = 1.0
|
||||
|
||||
var game_started = false setget _on_game_started_set
|
||||
|
||||
var current_registry
|
||||
|
||||
# music related
|
||||
onready var music_player = get_node("music_player")
|
||||
onready var sfx_player = get_node("sfx_player")
|
||||
|
||||
signal on_music_volume_changed(new_value)
|
||||
signal on_sfx_volume_changed(new_value)
|
||||
signal on_reading_speed_changed(new_value)
|
||||
|
||||
signal on_settings_enter()
|
||||
signal on_settings_exit()
|
||||
|
||||
const Themes = {}
|
||||
|
||||
# voices for characters
|
||||
const brain_voice = null
|
||||
const arborator_voice = null
|
||||
|
||||
const Characters = {
|
||||
BRAIN = {
|
||||
name = "~brain~",
|
||||
voice = brain_voice,
|
||||
talking_speed = 1.0,
|
||||
},
|
||||
ARBORATOR = {
|
||||
name = "arborator",
|
||||
voice = arborator_voice,
|
||||
talking_speed = 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
func _register_functions():
|
||||
pass
|
||||
|
||||
func _on_game_started_set(v):
|
||||
if v and not game_started:
|
||||
_on_game_start()
|
||||
game_started = v
|
||||
|
||||
func _on_game_start():
|
||||
|
||||
# all game state here
|
||||
current_registry = {}
|
||||
|
||||
|
||||
func _ready():
|
||||
pass
|
|
@ -0,0 +1,23 @@
|
|||
[gd_resource type="AudioBusLayout" format=2]
|
||||
|
||||
[resource]
|
||||
|
||||
bus/0/name = "Master"
|
||||
bus/0/solo = false
|
||||
bus/0/mute = false
|
||||
bus/0/bypass_fx = false
|
||||
bus/0/volume_db = 0.0
|
||||
bus/0/send = ""
|
||||
bus/1/name = "Music"
|
||||
bus/1/solo = false
|
||||
bus/1/mute = false
|
||||
bus/1/bypass_fx = false
|
||||
bus/1/volume_db = 0.0
|
||||
bus/1/send = "Master"
|
||||
bus/2/name = "Sfx"
|
||||
bus/2/solo = false
|
||||
bus/2/mute = false
|
||||
bus/2/bypass_fx = false
|
||||
bus/2/volume_db = 0.0
|
||||
bus/2/send = "Master"
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
[gd_resource type="Environment" load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
radiance_size = 4
|
||||
sky_top_color = Color( 0.0470588, 0.454902, 0.976471, 1 )
|
||||
sky_horizon_color = Color( 0.556863, 0.823529, 0.909804, 1 )
|
||||
sky_curve = 0.25
|
||||
sky_energy = 1.0
|
||||
ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 )
|
||||
ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 )
|
||||
ground_curve = 0.01
|
||||
ground_energy = 1.0
|
||||
sun_color = Color( 1, 1, 1, 1 )
|
||||
sun_latitude = 35.0
|
||||
sun_longitude = 0.0
|
||||
sun_angle_min = 1.0
|
||||
sun_angle_max = 100.0
|
||||
sun_curve = 0.05
|
||||
sun_energy = 16.0
|
||||
texture_size = 2
|
||||
|
||||
[resource]
|
||||
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
||||
background_sky_custom_fov = 0.0
|
||||
background_color = Color( 0, 0, 0, 1 )
|
||||
background_energy = 1.0
|
||||
background_canvas_max_layer = 0
|
||||
ambient_light_color = Color( 0, 0, 0, 1 )
|
||||
ambient_light_energy = 1.0
|
||||
ambient_light_sky_contribution = 1.0
|
||||
fog_enabled = false
|
||||
fog_color = Color( 0.5, 0.6, 0.7, 1 )
|
||||
fog_sun_color = Color( 1, 0.9, 0.7, 1 )
|
||||
fog_sun_amount = 0.0
|
||||
fog_depth_enabled = true
|
||||
fog_depth_begin = 10.0
|
||||
fog_depth_curve = 1.0
|
||||
fog_transmit_enabled = false
|
||||
fog_transmit_curve = 1.0
|
||||
fog_height_enabled = false
|
||||
fog_height_min = 0.0
|
||||
fog_height_max = 100.0
|
||||
fog_height_curve = 1.0
|
||||
tonemap_mode = 0
|
||||
tonemap_exposure = 1.0
|
||||
tonemap_white = 1.0
|
||||
auto_exposure_enabled = false
|
||||
auto_exposure_scale = 0.4
|
||||
auto_exposure_min_luma = 0.05
|
||||
auto_exposure_max_luma = 8.0
|
||||
auto_exposure_speed = 0.5
|
||||
ss_reflections_enabled = false
|
||||
ss_reflections_max_steps = 64
|
||||
ss_reflections_fade_in = 0.15
|
||||
ss_reflections_fade_out = 2.0
|
||||
ss_reflections_depth_tolerance = 0.2
|
||||
ss_reflections_roughness = true
|
||||
ssao_enabled = false
|
||||
ssao_radius = 1.0
|
||||
ssao_intensity = 1.0
|
||||
ssao_radius2 = 0.0
|
||||
ssao_intensity2 = 1.0
|
||||
ssao_bias = 0.01
|
||||
ssao_light_affect = 0.0
|
||||
ssao_color = Color( 0, 0, 0, 1 )
|
||||
ssao_quality = 0
|
||||
ssao_blur = 3
|
||||
ssao_edge_sharpness = 4.0
|
||||
dof_blur_far_enabled = false
|
||||
dof_blur_far_distance = 10.0
|
||||
dof_blur_far_transition = 5.0
|
||||
dof_blur_far_amount = 0.1
|
||||
dof_blur_far_quality = 1
|
||||
dof_blur_near_enabled = false
|
||||
dof_blur_near_distance = 2.0
|
||||
dof_blur_near_transition = 1.0
|
||||
dof_blur_near_amount = 0.1
|
||||
dof_blur_near_quality = 1
|
||||
glow_enabled = false
|
||||
glow_levels/1 = false
|
||||
glow_levels/2 = false
|
||||
glow_levels/3 = true
|
||||
glow_levels/4 = false
|
||||
glow_levels/5 = true
|
||||
glow_levels/6 = false
|
||||
glow_levels/7 = false
|
||||
glow_intensity = 0.8
|
||||
glow_strength = 1.0
|
||||
glow_bloom = 0.0
|
||||
glow_blend_mode = 2
|
||||
glow_hdr_threshold = 1.0
|
||||
glow_hdr_scale = 2.0
|
||||
glow_bicubic_upscale = false
|
||||
adjustment_enabled = false
|
||||
adjustment_brightness = 1.0
|
||||
adjustment_contrast = 1.0
|
||||
adjustment_saturation = 1.0
|
||||
|
|
@ -0,0 +1,450 @@
|
|||
extends Control
|
||||
|
||||
# load from dialog vm
|
||||
const Dialog = preload("res://dialog_vm.gd")
|
||||
const DialogController = preload("res://dialog_controller.gd")
|
||||
|
||||
# classes from there
|
||||
const DialogSegment = Dialog.DialogSegment
|
||||
const DialogWithSubjectSegment = Dialog.DialogWithSubjectSegment
|
||||
const DialogWithSubjectExpressionSegment = Dialog.DialogWithSubjectExpressionSegment
|
||||
const QuestionSegment = Dialog.QuestionSegment
|
||||
const ChoiceSegment = Dialog.ChoiceSegment
|
||||
const ChoiceWithJump = Dialog.ChoiceWithJump
|
||||
const Choice = Dialog.Choice
|
||||
|
||||
const WaitSegment = Dialog.YieldCallSegment
|
||||
|
||||
# resources specific to this dialogy thingy
|
||||
const DialogChoices = preload("res://ui/dialog_choices.tscn")
|
||||
const DialogChoice = preload("res://ui/dialog_choice.tscn")
|
||||
|
||||
var IS_DEBUG = false
|
||||
|
||||
var current_dialog
|
||||
var current_dialog_controller
|
||||
|
||||
# ui elements
|
||||
onready var advance_button = get_node("top_panel/auto_btn")
|
||||
onready var fastforward_button = get_node("top_panel/ffwd_btn")
|
||||
|
||||
onready var title_label = get_node("body_container/bottom_panel/subject_margin/subject_panel/subject_label")
|
||||
onready var body_container = get_node("body_container")
|
||||
onready var body_label = get_node("body_container/bottom_panel/body_margin/body_label")
|
||||
|
||||
# clickable regions, for accessibility
|
||||
onready var top_panel = get_node("top_panel")
|
||||
|
||||
onready var audio_player = get_node("audio_player")
|
||||
|
||||
# params to set from outside
|
||||
var dialog_path
|
||||
|
||||
# activeness
|
||||
var active
|
||||
|
||||
# tween to fade in/out
|
||||
var tween
|
||||
|
||||
# timer
|
||||
var timer
|
||||
|
||||
# anim player, if any
|
||||
var anim_player
|
||||
|
||||
# linkin in ur get_node relative to where you want
|
||||
var get_node_fnc
|
||||
|
||||
# various main dialog related constants
|
||||
|
||||
# signals
|
||||
signal entered_dialog
|
||||
signal exited_frame
|
||||
|
||||
# character related signals
|
||||
signal on_speaker_expression_changed(spkr, expr)
|
||||
|
||||
signal on_dialog_init(d)
|
||||
signal on_dialog_completed(d)
|
||||
|
||||
# setters
|
||||
func set_auto_advance(v):
|
||||
current_dialog_controller.set_advance_state(v)
|
||||
advance_button.pressed = v
|
||||
|
||||
# signals from dialog controller
|
||||
func _on_printing_changed(v):
|
||||
pass
|
||||
# next_arrow.visible = v
|
||||
|
||||
func _on_reading_speed_changed(new_value):
|
||||
current_dialog_controller.set_reading_speed(new_value)
|
||||
|
||||
func set_advance_state():
|
||||
current_dialog_controller.set_advance_state(advance_button.is_pressed())
|
||||
|
||||
func set_fastforward_state():
|
||||
var ffwd_pressed = fastforward_button.is_pressed()
|
||||
current_dialog_controller.set_fastforward_state(fastforward_button.is_pressed())
|
||||
advance_button.set_disabled(ffwd_pressed)
|
||||
|
||||
# init functions, must be called before use
|
||||
func set_dialog_path(path):
|
||||
dialog_path = path
|
||||
|
||||
func set_dialog_vm(vm):
|
||||
current_dialog = vm
|
||||
|
||||
func set_dialog_controller(c):
|
||||
current_dialog_controller = c
|
||||
|
||||
func set_dialog_anim_player(p):
|
||||
anim_player = p
|
||||
|
||||
func set_get_character_function(fnc):
|
||||
get_node_fnc = fnc
|
||||
|
||||
func _ready():
|
||||
|
||||
advance_button.connect("pressed", self, "set_advance_state")
|
||||
fastforward_button.connect("pressed", self, "set_fastforward_state")
|
||||
|
||||
# clicking to advance
|
||||
body_container.connect("gui_input", self, "_on_body_click")
|
||||
top_panel.connect("gui_input", self, "_on_body_click")
|
||||
|
||||
Game.connect("on_reading_speed_changed", self, "_on_reading_speed_changed")
|
||||
Game.connect("on_settings_enter", self, "_on_settings_enter")
|
||||
Game.connect("on_settings_exit", self, "_on_settings_exit")
|
||||
|
||||
tween = Tween.new()
|
||||
add_child(tween)
|
||||
|
||||
timer = Timer.new()
|
||||
add_child(timer)
|
||||
|
||||
|
||||
func _on_body_click(ev):
|
||||
current_dialog_controller._on_body_click(is_active(), ev)
|
||||
|
||||
func _register_func(r, reg_name, func_name):
|
||||
if r.has(reg_name):
|
||||
r[reg_name].set_instance(self)
|
||||
else:
|
||||
r[reg_name] = funcref(self, func_name)
|
||||
|
||||
func _register_functions():
|
||||
var r = current_dialog.get_local_registry()
|
||||
|
||||
# normal functions
|
||||
_register_func(r, "SET_EXPR", "_set_expr_fnc")
|
||||
_register_func(r, "FLIP", "_flip_char")
|
||||
_register_func(r, "HIDE", "_hide_char")
|
||||
_register_func(r, "SHOW", "_show_char")
|
||||
|
||||
# yieldy function
|
||||
_register_func(r, "WAIT", "_wait_dialog_fnc")
|
||||
|
||||
# anim shite, also yieldy
|
||||
_register_func(r, "PLAY_ANIM", "_play_anim_fnc")
|
||||
|
||||
# PLAY AND WAIT; HOW ABOUT DEM APPLES
|
||||
_register_func(r, "PLAY_ANIM_WITH_WAIT", "_play_wait_with_anim_fnc")
|
||||
|
||||
func _play_wait_with_anim_fnc(args):
|
||||
if args.size() == 2:
|
||||
var anim_name = args[0]
|
||||
var wait_time = float(args[1])
|
||||
|
||||
if anim_player:
|
||||
anim_player.play(anim_name)
|
||||
|
||||
timer.one_shot = true
|
||||
timer.wait_time = wait_time
|
||||
timer.start()
|
||||
return [timer, "timeout"]
|
||||
|
||||
func _play_anim_fnc(args):
|
||||
if args.size() == 1:
|
||||
var anim_name = args[0]
|
||||
if anim_player:
|
||||
anim_player.play(anim_name)
|
||||
return [anim_player, "animation_finished"]
|
||||
|
||||
func _wait_dialog_fnc(args):
|
||||
if args.size() == 1:
|
||||
var time = float(args[0])
|
||||
print("Dialog: waiting for: %f seconds" % time)
|
||||
timer.wait_time = time
|
||||
timer.one_shot = true
|
||||
timer.start()
|
||||
return [timer, "timeout"]
|
||||
|
||||
func _set_expr_fnc(args):
|
||||
if args.size() == 2:
|
||||
var speaker = args[0]
|
||||
var expr = args[1]
|
||||
_set_speaker_expression(speaker, expr)
|
||||
|
||||
func _show_char(args):
|
||||
var char_name = args[0]
|
||||
var character = get_node_fnc.call(char_name)
|
||||
_do_show_char(character)
|
||||
|
||||
func _do_show_char(c):
|
||||
tween.interpolate_property(
|
||||
c, "modulate:a", c.modulate.a, 1.0,
|
||||
1.0, Tween.TRANS_QUAD,
|
||||
Tween.EASE_IN_OUT
|
||||
)
|
||||
tween.start()
|
||||
|
||||
func _hide_char(args):
|
||||
var char_name = args[0]
|
||||
var character = get_node_fnc.call(char_name)
|
||||
_do_hide_char(character)
|
||||
|
||||
func _do_hide_char(c):
|
||||
tween.interpolate_property(
|
||||
c, "modulate:a", c.modulate.a, 0.0,
|
||||
1.0, Tween.TRANS_QUAD,
|
||||
Tween.EASE_IN_OUT
|
||||
)
|
||||
tween.start()
|
||||
|
||||
func _flip_char(args):
|
||||
var char_name = args[0]
|
||||
var character = get_node_fnc.call(char_name)
|
||||
_do_flip_char(character)
|
||||
|
||||
func _do_flip_char(c):
|
||||
c.flip_h = !c.flip_h
|
||||
|
||||
func _on_settings_enter(s):
|
||||
if is_active():
|
||||
visible = false
|
||||
|
||||
func _on_settings_exit(s):
|
||||
if is_active():
|
||||
visible = true
|
||||
|
||||
func reload_dialog():
|
||||
initialize_dialog()
|
||||
|
||||
func get_local_registry():
|
||||
return current_dialog.get_local_registry()
|
||||
|
||||
func initialize_dialog():
|
||||
|
||||
assert(dialog_path != null)
|
||||
|
||||
var dialog_file = File.new()
|
||||
dialog_file.open(dialog_path, File.READ)
|
||||
var text = dialog_file.get_as_text()
|
||||
dialog_file.close()
|
||||
|
||||
var dialog = Dialog.dialog_from_text(text)
|
||||
current_dialog = dialog
|
||||
|
||||
# also setup kv store for dialog variables
|
||||
current_dialog.set_registry(Game.current_registry)
|
||||
|
||||
# set up controller too yes
|
||||
current_dialog_controller = DialogController.new(dialog, audio_player)
|
||||
|
||||
# register functions
|
||||
_register_functions()
|
||||
|
||||
# signals
|
||||
current_dialog_controller.connect("on_update_dialog", self, "_on_update_dialog")
|
||||
current_dialog_controller.connect("on_dialog_completed", self, "_on_dialog_completed")
|
||||
current_dialog_controller.connect("on_printing_changed", self, "_on_printing_changed")
|
||||
|
||||
emit_signal("on_dialog_init", self)
|
||||
|
||||
func _on_dialog_completed(d):
|
||||
emit_signal("on_dialog_completed", self)
|
||||
exit_frame()
|
||||
|
||||
func _on_update_dialog(s):
|
||||
_update_dialog(s)
|
||||
|
||||
func _fade_in():
|
||||
var FADE_TIME = 1.0
|
||||
tween.interpolate_property(
|
||||
self,
|
||||
"modulate:a", 0.0, 1.0, FADE_TIME,
|
||||
Tween.TRANS_QUAD, Tween.EASE_IN
|
||||
)
|
||||
tween.start()
|
||||
|
||||
func _fade_out():
|
||||
var FADE_TIME = 1.0
|
||||
tween.interpolate_property(
|
||||
self,
|
||||
"modulate:a", 1.0, 0.0, FADE_TIME,
|
||||
Tween.TRANS_QUAD, Tween.EASE_OUT
|
||||
)
|
||||
tween.start()
|
||||
|
||||
yield(tween, "tween_completed")
|
||||
visible = false
|
||||
|
||||
func enter_frame():
|
||||
|
||||
_fade_in()
|
||||
|
||||
var r = Game.current_registry
|
||||
r["IS_IN_DIALOG"] = true
|
||||
|
||||
# reload if is debug
|
||||
if IS_DEBUG: reload_dialog()
|
||||
|
||||
active = true
|
||||
visible = true
|
||||
current_dialog.reset()
|
||||
# next_arrow.visible = false
|
||||
emit_signal("entered_dialog")
|
||||
|
||||
# dialogs
|
||||
var first_segment = current_dialog.advance()
|
||||
_update_dialog(first_segment)
|
||||
|
||||
|
||||
func is_active():
|
||||
return active
|
||||
|
||||
func exit_frame():
|
||||
|
||||
_fade_out()
|
||||
|
||||
# HACK: cludge to reset state
|
||||
advance_button.set_pressed(false)
|
||||
fastforward_button.set_pressed(false)
|
||||
advance_button.emit_signal("pressed")
|
||||
fastforward_button.emit_signal("pressed")
|
||||
|
||||
current_dialog_controller.reset()
|
||||
active = false
|
||||
|
||||
var r = Game.current_registry
|
||||
r["IS_IN_DIALOG"] = false
|
||||
emit_signal("exited_frame")
|
||||
|
||||
|
||||
func _set_speaker_subject(subject):
|
||||
if Game.Characters.has(subject):
|
||||
var data = Game.Characters[subject]
|
||||
var subject_name = data.name
|
||||
var subject_colour = data.name_colour
|
||||
var subject_voice = data.voice
|
||||
current_dialog_controller.chars_per_second = Game.DEFAULT_CHARS_PER_SECOND * data.talking_speed
|
||||
_set_speaker_name(subject_name, subject_colour)
|
||||
if subject_voice != null:
|
||||
_set_speaker_voice(subject_voice)
|
||||
else:
|
||||
var subject_name = subject
|
||||
current_dialog_controller.chars_per_second = Game.DEFAULT_CHARS_PER_SECOND
|
||||
_set_speaker_name(subject_name, Color(1, 1, 1))
|
||||
|
||||
func _get_speaker_name():
|
||||
return title_label.text
|
||||
|
||||
func _set_speaker_name(speaker_name, colour = Color(1, 1, 1)):
|
||||
title_label.set_text(speaker_name)
|
||||
title_label.modulate = colour
|
||||
|
||||
func _set_speaker_voice(voice_sample):
|
||||
audio_player.stream = voice_sample
|
||||
|
||||
func _set_speaker_expression(speaker, expression):
|
||||
emit_signal("on_speaker_expression_changed", speaker, expression)
|
||||
|
||||
# temporary maybe
|
||||
|
||||
func _setup_question(new_question):
|
||||
body_container.add_child(new_question)
|
||||
current_dialog_controller.waiting_for_answer = true
|
||||
|
||||
func _question_answered_yes(qs):
|
||||
body_container.remove_child(qs)
|
||||
current_dialog_controller.waiting_for_answer = false
|
||||
current_dialog_controller._advance_dialog()
|
||||
|
||||
func _question_answered_no(qs):
|
||||
body_container.remove_child(qs)
|
||||
current_dialog_controller.waiting_for_answer = false
|
||||
exit_frame()
|
||||
|
||||
func _choice_made(choice_modal, choice):
|
||||
if IS_DEBUG: print("chose: ", choice.get_choice())
|
||||
# Game.add_history_entry("you", choice.get_choice())
|
||||
remove_child(choice_modal)
|
||||
if choice is ChoiceWithJump:
|
||||
# HACK: fix this later or make this unnecessary
|
||||
var current_segment = current_dialog.jump(choice.target)
|
||||
call_deferred("_update_dialog", current_segment)
|
||||
else:
|
||||
_update_dialog(choice)
|
||||
current_dialog_controller.waiting_for_answer = false
|
||||
|
||||
# loop de loop
|
||||
func _update_dialog(segment):
|
||||
|
||||
if segment is ChoiceSegment:
|
||||
|
||||
var choices = segment.get_choices()
|
||||
|
||||
# create new dialog choices and shit
|
||||
var new_choices = DialogChoices.instance()
|
||||
var vbox = new_choices.get_node("vbox")
|
||||
|
||||
for choice in choices:
|
||||
var new_choice = DialogChoice.instance()
|
||||
new_choice.text = choice.get_choice()
|
||||
new_choice.connect("pressed", self, "_choice_made", [new_choices, choice])
|
||||
vbox.add_child(new_choice)
|
||||
|
||||
add_child(new_choices)
|
||||
|
||||
elif segment is Choice:
|
||||
var new_content = segment.get_response()
|
||||
if typeof(new_content) == TYPE_OBJECT and (new_content is DialogWithSubjectSegment or new_content is DialogWithSubjectExpressionSegment):
|
||||
_update_dialog(new_content)
|
||||
else:
|
||||
body_label.text = new_content
|
||||
# Game.add_history_entry(_get_speaker_name(), new_content)
|
||||
|
||||
elif segment is DialogSegment or segment is DialogWithSubjectSegment or segment is DialogWithSubjectExpressionSegment:
|
||||
var new_content = segment.get_content()
|
||||
body_label.visible_characters = 0
|
||||
body_label.text = new_content
|
||||
|
||||
if segment is DialogWithSubjectSegment:
|
||||
_set_speaker_subject(segment.subject)
|
||||
# Game.add_history_entry(_get_speaker_name(), new_content)
|
||||
elif segment is DialogWithSubjectExpressionSegment:
|
||||
_set_speaker_subject(segment.subject)
|
||||
_set_speaker_expression(segment.subject, segment.expression)
|
||||
# Game.add_history_entry("%s (%s)" % [_get_speaker_name(), segment.expression], new_content)
|
||||
else:
|
||||
pass
|
||||
# Game.add_history_entry(_get_speaker_name(), new_content)
|
||||
|
||||
elif segment is WaitSegment:
|
||||
var new_content = segment.get_content()
|
||||
body_label.visible_characters = 0
|
||||
body_label.text = new_content
|
||||
|
||||
# whatever subject you want during functions to wait on, animations and such
|
||||
_set_speaker_subject("")
|
||||
|
||||
else:
|
||||
print("encountered unknown segment: " + segment.get_content())
|
||||
|
||||
current_dialog_controller.update_logic_dialog(segment)
|
||||
|
||||
func _process(delta):
|
||||
if is_active():
|
||||
current_dialog_controller.tick(delta, body_label)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<BRAIN> ... You wake up to the sound of sirens blaring.
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
extends Reference
|
||||
|
||||
const Dialog = preload("res://dialog_vm.gd")
|
||||
|
||||
# classes from vm
|
||||
const DialogSegment = Dialog.DialogSegment
|
||||
const DialogWithSubjectSegment = Dialog.DialogWithSubjectSegment
|
||||
const DialogWithSubjectExpressionSegment = Dialog.DialogWithSubjectExpressionSegment
|
||||
const QuestionSegment = Dialog.QuestionSegment
|
||||
const ChoiceSegment = Dialog.ChoiceSegment
|
||||
const ChoiceWithJump = Dialog.ChoiceWithJump
|
||||
const Choice = Dialog.Choice
|
||||
|
||||
const WaitSegment = Dialog.YieldCallSegment
|
||||
|
||||
# current dialog vm
|
||||
var current_dialog
|
||||
var audio_player
|
||||
|
||||
# dialog controller related state, internal
|
||||
|
||||
# speed at which dialog prints characters
|
||||
var chars_per_second = 16 # initialized from which character is speaking
|
||||
var reading_speed_mul = 1
|
||||
var special_speed_mul = 1
|
||||
|
||||
# intermediate state for dialog
|
||||
var waiting_for_answer = false
|
||||
var print_done = false setget _on_print_set
|
||||
var print_target = 0
|
||||
var print_delta = 0
|
||||
|
||||
# ui button controlled state
|
||||
var is_auto_advancing = false
|
||||
var auto_advance_delay = 1
|
||||
var auto_advance_timer = 0
|
||||
|
||||
var is_new_word = false
|
||||
var is_fastforwarding = false
|
||||
var ff_speed_mul = 1
|
||||
|
||||
# character printing sound related state
|
||||
var sound_playing = false
|
||||
var sound_play_time = 2.08 # TODO: maybe adjust this too depending on voice sample/chars per second
|
||||
var sound_played_time = 0
|
||||
|
||||
# signals
|
||||
signal on_printing_done()
|
||||
signal on_printing_changed(status)
|
||||
signal on_update_dialog(segment)
|
||||
signal on_dialog_completed(d)
|
||||
|
||||
func _init(d, a):
|
||||
current_dialog = d
|
||||
audio_player = a
|
||||
|
||||
func reset():
|
||||
self.print_done = true
|
||||
print_target = 0
|
||||
print_delta = 0
|
||||
|
||||
# sfx related
|
||||
|
||||
func sound_play():
|
||||
sound_playing = true
|
||||
audio_player.play()
|
||||
|
||||
func sound_stop():
|
||||
audio_player.stop()
|
||||
sound_playing = false
|
||||
|
||||
func sound_done_playing(delta):
|
||||
sound_played_time += delta * reading_speed_mul * special_speed_mul
|
||||
if sound_played_time >= sound_play_time / chars_per_second:
|
||||
sound_played_time = 0
|
||||
sound_playing = false
|
||||
return not sound_playing
|
||||
|
||||
# temporary hopefully
|
||||
func _advance_dialog():
|
||||
var current_segment = current_dialog.advance()
|
||||
if not current_segment == null:
|
||||
emit_signal("on_update_dialog", current_segment)
|
||||
else:
|
||||
emit_signal("on_dialog_completed", self)
|
||||
|
||||
func _on_body_click(is_visible, event):
|
||||
if is_visible and not waiting_for_answer:
|
||||
if event.is_action_pressed("dialog_click"):
|
||||
if print_done == false: # if still printing, jump forwards now
|
||||
print_delta = print_target - 1
|
||||
self.print_done = true
|
||||
else:
|
||||
_advance_dialog()
|
||||
|
||||
# interior callbacks
|
||||
func _on_print_set(v):
|
||||
print_done = v
|
||||
if print_done:
|
||||
emit_signal("on_printing_done")
|
||||
emit_signal("on_printing_changed", v)
|
||||
|
||||
func set_reading_speed(spd):
|
||||
reading_speed_mul = spd
|
||||
|
||||
func set_advance_state(s):
|
||||
is_auto_advancing = s
|
||||
|
||||
func set_fastforward_state(s):
|
||||
is_fastforwarding = s
|
||||
if is_fastforwarding:
|
||||
is_auto_advancing = true
|
||||
ff_speed_mul = 10
|
||||
auto_advance_delay = 0.1
|
||||
else:
|
||||
ff_speed_mul = 1
|
||||
auto_advance_delay = 1
|
||||
|
||||
func update_logic_dialog(segment):
|
||||
|
||||
if segment is QuestionSegment:
|
||||
var new_content = segment.get_content()
|
||||
print_target = new_content.length()
|
||||
self.print_done = false
|
||||
print_delta = 0
|
||||
|
||||
elif segment is ChoiceSegment:
|
||||
waiting_for_answer = true
|
||||
|
||||
elif segment is Choice:
|
||||
var new_content = segment.get_response()
|
||||
if typeof(new_content) == TYPE_OBJECT and (new_content is DialogWithSubjectSegment or new_content is DialogWithSubjectExpressionSegment):
|
||||
_update_logic_dialog(new_content)
|
||||
else:
|
||||
print_target = new_content.length()
|
||||
self.print_done = false
|
||||
print_delta = 0
|
||||
|
||||
elif segment is DialogSegment or segment is DialogWithSubjectSegment or segment is DialogWithSubjectExpressionSegment:
|
||||
var new_content = segment.get_content()
|
||||
print_target = new_content.length()
|
||||
self.print_done = false
|
||||
print_delta = 0
|
||||
|
||||
elif segment is WaitSegment:
|
||||
var new_content = segment.get_content()
|
||||
print_target = new_content.length()
|
||||
self.print_done = false
|
||||
print_delta = 0
|
||||
|
||||
else:
|
||||
print("encountered unknown segment: " + segment.get_content())
|
||||
|
||||
func tick(delta, body_label):
|
||||
|
||||
if not current_dialog.is_eof():
|
||||
var cur_segment = current_dialog.segments[current_dialog.segment_index]
|
||||
if cur_segment is WaitSegment and cur_segment.finished: _advance_dialog()
|
||||
|
||||
if print_target != 0:
|
||||
if print_delta >= print_target:
|
||||
self.print_done = true
|
||||
auto_advance_timer = auto_advance_delay
|
||||
print_target = 0
|
||||
print_delta = 0
|
||||
else:
|
||||
if sound_done_playing(delta) and not is_fastforwarding: sound_play()
|
||||
body_label.visible_characters = print_delta
|
||||
print_delta += delta * (chars_per_second * reading_speed_mul) * ff_speed_mul
|
||||
elif print_target == 0:
|
||||
auto_advance_timer -= delta
|
||||
if auto_advance_timer <= 0 and is_auto_advancing and not waiting_for_answer:
|
||||
call_deferred("_advance_dialog")
|
|
@ -0,0 +1,29 @@
|
|||
extends CanvasLayer
|
||||
|
||||
export (String, FILE, "*.txt") var dialog_path;
|
||||
|
||||
onready var dialog_box = get_node("dialog_box")
|
||||
|
||||
func _ready():
|
||||
|
||||
# start signal
|
||||
get_parent().connect("on_scene_ready", self, "_on_scene_ready")
|
||||
|
||||
dialog_box.connect("on_dialog_init", self, "_on_dialog_init")
|
||||
dialog_box.connect("on_dialog_completed", self, "_on_dialog_completed")
|
||||
|
||||
# set up params
|
||||
dialog_box.set_dialog_path(dialog_path)
|
||||
|
||||
# init after yes
|
||||
dialog_box.initialize_dialog()
|
||||
|
||||
|
||||
func _on_scene_ready():
|
||||
dialog_box.enter_frame()
|
||||
|
||||
func _on_dialog_init(d):
|
||||
pass
|
||||
|
||||
func _on_dialog_completed(d):
|
||||
dialog_box.exit_frame()
|
|
@ -0,0 +1,570 @@
|
|||
extends Reference
|
||||
|
||||
static func dialog_from_text(text):
|
||||
|
||||
var label_regex = RegEx.new()
|
||||
label_regex.compile("[A-Z0-9_]+:")
|
||||
|
||||
# validation
|
||||
var has_question = false
|
||||
var lines = text.split("\n")
|
||||
|
||||
var new_dialog = Dialog.new()
|
||||
|
||||
# intermediate state
|
||||
var current_choice_segment
|
||||
var choices = 0
|
||||
|
||||
if current_choice_segment == null:
|
||||
current_choice_segment = ChoiceSegment.new()
|
||||
|
||||
var line_number = 0
|
||||
for line in lines:
|
||||
|
||||
line_number += 1
|
||||
|
||||
# comment lines
|
||||
if line.begins_with("#"):
|
||||
pass
|
||||
|
||||
# is flag unset
|
||||
elif line.begins_with("!@"):
|
||||
var l = line.right(3).strip_edges()
|
||||
var flag = l.left(l.length() - 1)
|
||||
# if OS.is_debug_build(): print("flag to false: ", flag)
|
||||
new_dialog.add_segment(FlagSetSegment.new(flag, false))
|
||||
|
||||
# is goto, or conditional goto
|
||||
elif line.begins_with("!"):
|
||||
|
||||
var label_end = line.find(",")
|
||||
|
||||
# unconditional goto
|
||||
if label_end == -1:
|
||||
var label = line.substr(2, line.length() - 3).strip_edges()
|
||||
|
||||
# if OS.is_debug_build(): print("goto: ", label)
|
||||
new_dialog.add_segment(GotoSegment.new(label))
|
||||
else: # conditional goto
|
||||
var label = line.substr(2, label_end - 2).strip_edges()
|
||||
var target_end = line.find("]")
|
||||
var target = line.substr(label_end + 1, (target_end - 1) - label_end).strip_edges()
|
||||
|
||||
# if OS.is_debug_build(): print("goto: ", target, " - ", label)
|
||||
new_dialog.add_segment(ConditionalGotoSegment.new(target, label, true))
|
||||
|
||||
# is either random goto or question
|
||||
elif line.begins_with("?"):
|
||||
|
||||
var str_line = line.strip_edges().right(1)
|
||||
|
||||
# question, initiates dialog, treat first encountered question as question
|
||||
if str_line.begins_with("<"):
|
||||
|
||||
var q_line = str_line.strip_edges()
|
||||
|
||||
has_question = true
|
||||
var subject_right_bracket_index = q_line.find(">")
|
||||
var subject = q_line.substr(1, subject_right_bracket_index - 1).strip_edges()
|
||||
var question_text = q_line.right(subject_right_bracket_index + 1).strip_edges()
|
||||
|
||||
var question_segment = QuestionSegment.new(question_text, subject)
|
||||
new_dialog.add_segment(question_segment)
|
||||
|
||||
else: # random goto: picks one of the choices to goto, used like ?[P1, P2, P3]
|
||||
|
||||
var left_bracket = str_line.find("[")
|
||||
var right_bracket = str_line.find("]")
|
||||
|
||||
if left_bracket == -1:
|
||||
printerr("couldn't find left [ on line: %d" % line_number)
|
||||
assert(false)
|
||||
|
||||
if right_bracket == -1:
|
||||
printerr("couldn't find right ] on line: %d" % line_number)
|
||||
assert(false)
|
||||
|
||||
# if there's actually even a single thing inside
|
||||
if right_bracket - left_bracket > 1:
|
||||
|
||||
var arg_string = str_line.substr(left_bracket + 1, (right_bracket - left_bracket) - 1)
|
||||
var args = arg_string.split(",", false)
|
||||
|
||||
var stripped_args = []
|
||||
for arg in args:
|
||||
stripped_args.push_back(arg.strip_edges())
|
||||
|
||||
# if OS.is_debug_build(): print("random goto, arg_string: %s" % arg_string)
|
||||
|
||||
new_dialog.add_segment(RandomGotoSegment.new(stripped_args))
|
||||
|
||||
# is flag set, either a normal set to true with @[SOME_FLAG] or a set to string with @[FLAG, STR]
|
||||
elif line.begins_with("@"):
|
||||
var l = line.right(2)
|
||||
var comma_index = l.find(",")
|
||||
if comma_index == -1:
|
||||
var flag = l.left(l.length() - 1)
|
||||
# if OS.is_debug_build(): print("flag to true: ", flag)
|
||||
new_dialog.add_segment(FlagSetSegment.new(flag, true))
|
||||
else:
|
||||
var flag = l.left(comma_index).strip_edges()
|
||||
var arg_end = l.find("]")
|
||||
var arg_int = l.right(comma_index + 1)
|
||||
var arg = arg_int.left(arg_int.length() - 1).strip_edges()
|
||||
# if OS.is_debug_build(): print("flag: ", flag, " with arg: ", arg)
|
||||
new_dialog.add_segment(FlagSetSegment.new(flag, arg))
|
||||
|
||||
# is label, can goto
|
||||
elif line.ends_with(":") and label_regex.search(line):
|
||||
var label = line.left(line.length() - 1).strip_edges()
|
||||
|
||||
# if OS.is_debug_build(): print("label: ", label)
|
||||
new_dialog.add_segment(LabelSegment.new(label))
|
||||
|
||||
# is choice in conversation by player
|
||||
elif line.begins_with("["):
|
||||
|
||||
var right_end_index = line.find("]")
|
||||
var choice = line.substr(1, right_end_index - 1).strip_edges()
|
||||
var response = line.right(right_end_index + 1).strip_edges()
|
||||
|
||||
# is it a jump choice?
|
||||
var left_brace_index = response.find("[")
|
||||
var right_brace_index = response.find("]")
|
||||
if left_brace_index != -1 and right_brace_index != -1:
|
||||
var jump_target = response.substr(left_brace_index + 1, right_brace_index - 1)
|
||||
# if OS.is_debug_build(): print("choice: ", choice, " target: ", jump_target)
|
||||
current_choice_segment.add_choice_with_jump(choice, jump_target)
|
||||
else:
|
||||
|
||||
var subject_right_comma_index = response.find(",")
|
||||
var subject_right_bracket_index = response.find(">")
|
||||
|
||||
# is response with <SUBJECT, EXPR>
|
||||
if response.begins_with("<") and subject_right_bracket_index > 0 and subject_right_comma_index < subject_right_bracket_index:
|
||||
var subject = response.substr(1, subject_right_comma_index - 1).strip_edges()
|
||||
var expression = response.substr(subject_right_comma_index + 1, (subject_right_bracket_index - 1) - subject_right_comma_index).strip_edges()
|
||||
var line_text = response.right(subject_right_bracket_index + 1).strip_edges()
|
||||
# if OS.is_debug_build(): print("choice: ", choice, " response: ", line_text, " with: <", subject, ", ", expression, ">")
|
||||
current_choice_segment.add_choice(choice, DialogWithSubjectExpressionSegment.new(line_text, subject, expression))
|
||||
elif response.begins_with("<"): # is response with <SUBJECT>
|
||||
var subject = response.substr(1, subject_right_bracket_index - 1).strip_edges()
|
||||
var line_text = response.right(subject_right_bracket_index + 1).strip_edges()
|
||||
# if OS.is_debug_build(): print("choice: ", choice, " response: ", line_text, " with: <", subject, ">")
|
||||
current_choice_segment.add_choice(choice, DialogWithSubjectSegment.new(line_text, subject))
|
||||
else:
|
||||
# if OS.is_debug_build(): print("choice: ", choice, " response: ", response)
|
||||
current_choice_segment.add_choice(choice, response)
|
||||
|
||||
choices += 1
|
||||
|
||||
# we're full
|
||||
if choices == 3:
|
||||
# if OS.is_debug_build(): print("choice segment created.")
|
||||
new_dialog.add_segment(current_choice_segment)
|
||||
|
||||
# setup new one for next round
|
||||
current_choice_segment = ChoiceSegment.new()
|
||||
choices = 0
|
||||
|
||||
elif line.begins_with("<"):
|
||||
|
||||
# test for right comma and >
|
||||
var subject_right_comma_index = line.find(",")
|
||||
var subject_right_bracket_index = line.find(">")
|
||||
|
||||
# is <SUBJECT, EXPRESSION> dialog
|
||||
if subject_right_comma_index > 0 and subject_right_comma_index < subject_right_bracket_index:
|
||||
var subject = line.substr(1, subject_right_comma_index - 1).strip_edges()
|
||||
var expression = line.substr(subject_right_comma_index + 1, (subject_right_bracket_index - 1) - subject_right_comma_index).strip_edges()
|
||||
var line_text = line.right(subject_right_bracket_index + 1).strip_edges()
|
||||
var dialog_subject_segment = DialogWithSubjectExpressionSegment.new(line_text, subject, expression)
|
||||
new_dialog.add_segment(dialog_subject_segment)
|
||||
|
||||
else: # is <SUBJECT> dialog
|
||||
var subject = line.substr(1, subject_right_bracket_index - 1).strip_edges()
|
||||
var line_text = line.right(subject_right_bracket_index + 1).strip_edges()
|
||||
var dialog_subject_segment = DialogWithSubjectSegment.new(line_text, subject)
|
||||
new_dialog.add_segment(dialog_subject_segment)
|
||||
|
||||
# simple function calls, can look like: > FUNC, but also like > FUNC [A, B, C, D]
|
||||
# yieldable function calls can look like: >> FUNC, but also like >> FUNC [A, B, C, D]
|
||||
elif line.begins_with(">"):
|
||||
|
||||
var str_line = line.right(1).strip_edges()
|
||||
var is_yielding_function = false
|
||||
|
||||
if str_line.begins_with(">"):
|
||||
str_line = str_line.right(1).strip_edges()
|
||||
is_yielding_function = true
|
||||
|
||||
var left_bracket = str_line.find("[")
|
||||
var right_bracket = str_line.find("]")
|
||||
|
||||
# has left bracket, should have right bracket, has params
|
||||
if (left_bracket != -1 and right_bracket != -1) or \
|
||||
(left_bracket != -1 and right_bracket == -1) or \
|
||||
(left_bracket == -1 and right_bracket != -1):
|
||||
|
||||
var command_end = str_line.find("[")
|
||||
var command = str_line.left(command_end).strip_edges()
|
||||
# if OS.is_debug_build(): print("parsing command with args: ", command)
|
||||
|
||||
if left_bracket == -1:
|
||||
printerr("couldn't find left [ on line: %d" % line_number)
|
||||
assert(false)
|
||||
|
||||
if right_bracket == -1:
|
||||
printerr("couldn't find right ] on line: %d" % line_number)
|
||||
assert(false)
|
||||
|
||||
var args_str = str_line.substr(left_bracket + 1, (right_bracket - left_bracket) - 1).strip_edges()
|
||||
var args = args_str.split(",", false)
|
||||
|
||||
var stripped_args = []
|
||||
for a in args:
|
||||
stripped_args.push_back(a.strip_edges())
|
||||
|
||||
if is_yielding_function:
|
||||
var call_segment = YieldCallSegment.new(command, stripped_args)
|
||||
new_dialog.add_segment(call_segment)
|
||||
else:
|
||||
var call_segment = CallSegment.new(command, stripped_args)
|
||||
new_dialog.add_segment(call_segment)
|
||||
|
||||
else: # no params, argless call
|
||||
|
||||
var command = str_line.strip_edges()
|
||||
# if OS.is_debug_build(): print("parsing command: ", command)
|
||||
|
||||
if is_yielding_function:
|
||||
var call_segment = YieldCallSegment.new(command)
|
||||
new_dialog.add_segment(call_segment)
|
||||
else:
|
||||
var call_segment = CallSegment.new(command)
|
||||
new_dialog.add_segment(call_segment)
|
||||
|
||||
|
||||
else: # is normal text
|
||||
var line_text = line.strip_edges()
|
||||
|
||||
# if line is not empty, process
|
||||
if not line_text.empty():
|
||||
var dialog_segment = DialogSegment.new(line_text)
|
||||
new_dialog.add_segment(dialog_segment)
|
||||
|
||||
return new_dialog
|
||||
|
||||
static func parse_dialog_line(text):
|
||||
pass
|
||||
|
||||
# types of segments of text, held in Dialogs array
|
||||
|
||||
class QuestionSegment:
|
||||
|
||||
var subject
|
||||
var question
|
||||
|
||||
func _init(q, s):
|
||||
question = q
|
||||
subject = s
|
||||
|
||||
func get_content():
|
||||
return question
|
||||
|
||||
class DialogSegment:
|
||||
|
||||
var text
|
||||
|
||||
func _init(t):
|
||||
text = t
|
||||
|
||||
func get_content():
|
||||
return text
|
||||
|
||||
class DialogWithSubjectSegment:
|
||||
|
||||
var text
|
||||
var subject
|
||||
|
||||
func _init(t, s):
|
||||
text = t
|
||||
subject = s
|
||||
|
||||
func get_content():
|
||||
return text
|
||||
|
||||
class DialogWithSubjectExpressionSegment:
|
||||
|
||||
var text
|
||||
var subject
|
||||
var expression
|
||||
|
||||
func _init(t, s, e):
|
||||
text = t
|
||||
subject = s
|
||||
expression = e
|
||||
|
||||
func get_content():
|
||||
return text
|
||||
|
||||
class Choice:
|
||||
|
||||
var choice
|
||||
var response
|
||||
|
||||
func _init(c, r):
|
||||
choice = c
|
||||
response = r
|
||||
|
||||
func get_choice():
|
||||
return choice
|
||||
|
||||
func get_response():
|
||||
return response
|
||||
|
||||
class ChoiceWithJump:
|
||||
|
||||
var choice
|
||||
var target
|
||||
|
||||
func _init(c, t):
|
||||
choice = c
|
||||
target = t
|
||||
|
||||
func get_choice():
|
||||
return choice
|
||||
|
||||
func get_target():
|
||||
return target
|
||||
|
||||
class ChoiceSegment:
|
||||
|
||||
var choices
|
||||
|
||||
func _init():
|
||||
choices = []
|
||||
|
||||
func add_choice(choice, response):
|
||||
var new_choice = Choice.new(choice, response)
|
||||
choices.push_back(new_choice)
|
||||
|
||||
func add_choice_with_jump(choice, target):
|
||||
var new_choice = ChoiceWithJump.new(choice, target)
|
||||
choices.push_back(new_choice)
|
||||
|
||||
func get_choices():
|
||||
return choices
|
||||
|
||||
class LabelSegment:
|
||||
|
||||
var label
|
||||
|
||||
func _init(l):
|
||||
label = l
|
||||
|
||||
class GotoSegment:
|
||||
|
||||
var target
|
||||
|
||||
func _init(t):
|
||||
target = t
|
||||
|
||||
class RandomGotoSegment:
|
||||
|
||||
var targets
|
||||
|
||||
func _init(t):
|
||||
targets = t
|
||||
|
||||
class ConditionalGotoSegment extends GotoSegment:
|
||||
|
||||
var variable
|
||||
var expected_value
|
||||
|
||||
func _init(t, v, e).(t):
|
||||
variable = v
|
||||
expected_value = e
|
||||
|
||||
func test(registry):
|
||||
if variable in registry:
|
||||
var v = registry[variable]
|
||||
return v
|
||||
else:
|
||||
return false
|
||||
|
||||
class CallSegment:
|
||||
|
||||
var fname
|
||||
var args
|
||||
|
||||
func _init(f, a = null):
|
||||
fname = f
|
||||
args = a
|
||||
|
||||
func call(l, r):
|
||||
if l.has(fname):
|
||||
if args != null: return l[fname].call_func(args)
|
||||
else: return l[fname].call_func([])
|
||||
elif r.has(fname):
|
||||
if args != null: return r[fname].call_func(args)
|
||||
else: return r[fname].call_func([])
|
||||
|
||||
class YieldCallSegment extends CallSegment:
|
||||
|
||||
var started
|
||||
var finished
|
||||
|
||||
func _init(f, a = null).(f, a):
|
||||
started = false
|
||||
|
||||
func call(l, r):
|
||||
started = true
|
||||
finished = false
|
||||
return .call(l, r)
|
||||
|
||||
func get_content():
|
||||
return "..."
|
||||
|
||||
class FlagSetSegment:
|
||||
|
||||
var flag
|
||||
var value
|
||||
|
||||
func _init(f, v):
|
||||
flag = f
|
||||
value = v
|
||||
|
||||
func set(registry):
|
||||
registry[flag] = value
|
||||
|
||||
class Dialog:
|
||||
|
||||
var segment_index = -1
|
||||
var segments
|
||||
|
||||
# goto label dictionary
|
||||
var labels
|
||||
|
||||
# local registry
|
||||
var locals
|
||||
|
||||
# dependency, registry of stuff
|
||||
var registry
|
||||
|
||||
# yield state
|
||||
var is_yielding
|
||||
|
||||
func _init():
|
||||
is_yielding = false
|
||||
segments = []
|
||||
labels = {}
|
||||
locals = {}
|
||||
|
||||
func get_local_registry():
|
||||
return locals
|
||||
|
||||
func set_registry(r):
|
||||
registry = r
|
||||
|
||||
func add_segment(s):
|
||||
|
||||
if s is GotoSegment:
|
||||
if not s.target in labels:
|
||||
labels[s.target] = -1
|
||||
elif s is RandomGotoSegment:
|
||||
for t in s.targets:
|
||||
if not t in labels:
|
||||
labels[t] = -1
|
||||
elif s is LabelSegment:
|
||||
var sz = segments.size()
|
||||
if not labels.has(s.label) or labels[s.label] == -1:
|
||||
# if OS.is_debug_build(): print("added label: ", s.label, " to: ", sz)
|
||||
labels[s.label] = sz
|
||||
else:
|
||||
printerr("ERROR: label with name: %s already registered at %d!" % [s.label, labels[s.label]])
|
||||
assert(labels[s.label] != -1)
|
||||
|
||||
segments.push_back(s)
|
||||
|
||||
func push_instruction():
|
||||
if is_eof(): return null
|
||||
var new_segment = segments[segment_index]
|
||||
while (new_segment is GotoSegment \
|
||||
or new_segment is RandomGotoSegment \
|
||||
or new_segment is LabelSegment \
|
||||
or new_segment is CallSegment \
|
||||
or new_segment is FlagSetSegment) and not is_yielding and not is_eof():
|
||||
new_segment = segments[segment_index]
|
||||
if new_segment is ConditionalGotoSegment:
|
||||
if new_segment.test(registry): # if true, jump to offset
|
||||
var offset = labels[new_segment.target]
|
||||
if offset == -1:
|
||||
printerr("could not find label: %s" % new_segment.target)
|
||||
assert(offset != -1)
|
||||
# if OS.is_debug_build(): print("conditionally jumped to offset: ", offset)
|
||||
segment_index = offset
|
||||
else: # else skip
|
||||
segment_index += 1
|
||||
elif new_segment is RandomGotoSegment:
|
||||
var rand_idx = floor(rand_range(0, new_segment.targets.size()))
|
||||
var rand_target = new_segment.targets[rand_idx]
|
||||
var offset = labels[rand_target]
|
||||
if offset == -1:
|
||||
printerr("could not find label: %s" % rand_target)
|
||||
assert(offset != -1)
|
||||
# if OS.is_debug_build(): print("random jumped to: ", offset, " with: ", rand_target)
|
||||
segment_index = offset
|
||||
elif new_segment is GotoSegment:
|
||||
var offset = labels[new_segment.target]
|
||||
if offset == -1:
|
||||
printerr("could not find label: %s" % new_segment.target)
|
||||
assert(offset != -1)
|
||||
# if OS.is_debug_build(): print("jumped to: ", offset, " with: ", new_segment.target, " at: ", segment_index)
|
||||
segment_index = offset
|
||||
elif new_segment is YieldCallSegment:
|
||||
if not new_segment.started:
|
||||
var state = new_segment.call(locals, registry)
|
||||
if state != null:
|
||||
var obj = state[0]
|
||||
var sgn = state[1]
|
||||
is_yielding = true
|
||||
_do_yield_wait(obj, sgn, new_segment)
|
||||
else:
|
||||
segment_index += 1
|
||||
elif new_segment is CallSegment:
|
||||
new_segment.call(locals, registry)
|
||||
segment_index += 1
|
||||
elif new_segment is FlagSetSegment:
|
||||
new_segment.set(registry)
|
||||
segment_index += 1
|
||||
elif new_segment is LabelSegment:
|
||||
segment_index += 1
|
||||
if not is_eof():
|
||||
return segments[segment_index]
|
||||
else:
|
||||
return null
|
||||
|
||||
func advance():
|
||||
if not is_yielding:
|
||||
segment_index += 1
|
||||
return push_instruction()
|
||||
else:
|
||||
return push_instruction()
|
||||
|
||||
# external jump, is fudge
|
||||
func jump(target):
|
||||
segment_index = labels[target]
|
||||
return push_instruction()
|
||||
|
||||
func is_eof():
|
||||
return segment_index >= segments.size()
|
||||
|
||||
func reset():
|
||||
segment_index = -1
|
||||
|
||||
func _do_yield_wait(obj, sgn, segment):
|
||||
yield(obj, sgn)
|
||||
segment.finished = true
|
||||
is_yielding = false
|
||||
printt("Dialog VM: %s %s %s" % [obj, sgn, "completed"])
|
|
@ -0,0 +1,59 @@
|
|||
extends Node
|
||||
|
||||
# globals, for the game
|
||||
var reading_speed = 1.0
|
||||
|
||||
var game_started = false setget _on_game_started_set
|
||||
|
||||
var current_registry
|
||||
|
||||
# music related
|
||||
onready var music_player = get_node("music_player")
|
||||
onready var sfx_player = get_node("sfx_player")
|
||||
|
||||
signal on_music_volume_changed(new_value)
|
||||
signal on_sfx_volume_changed(new_value)
|
||||
signal on_reading_speed_changed(new_value)
|
||||
|
||||
signal on_settings_enter()
|
||||
signal on_settings_exit()
|
||||
|
||||
const Themes = {}
|
||||
|
||||
# voices for characters
|
||||
const brain_voice = null
|
||||
const arborator_voice = null
|
||||
|
||||
const DEFAULT_CHARS_PER_SECOND = 32
|
||||
|
||||
const Characters = {
|
||||
BRAIN = {
|
||||
name = "~brain~",
|
||||
name_colour = Color(1, 1, 1, 1),
|
||||
voice = brain_voice,
|
||||
talking_speed = 1.0,
|
||||
},
|
||||
ARBORATOR = {
|
||||
name = "arborator",
|
||||
name_colour = Color(1, 1, 1, 1),
|
||||
voice = arborator_voice,
|
||||
talking_speed = 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
func _register_functions():
|
||||
pass
|
||||
|
||||
func _on_game_started_set(v):
|
||||
if v and not game_started:
|
||||
_on_game_start()
|
||||
game_started = v
|
||||
|
||||
func _on_game_start():
|
||||
|
||||
# all game state here
|
||||
current_registry = {}
|
||||
|
||||
|
||||
func _ready():
|
||||
pass
|
|
@ -0,0 +1,27 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://game.gd" type="Script" id=1]
|
||||
|
||||
[node name="Game" type="Node"]
|
||||
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="music_player" type="AudioStreamPlayer" parent="." index="0"]
|
||||
|
||||
stream = null
|
||||
volume_db = 0.0
|
||||
pitch_scale = 1.0
|
||||
autoplay = false
|
||||
mix_target = 0
|
||||
bus = "Music"
|
||||
|
||||
[node name="sfx_player" type="AudioStreamPlayer" parent="." index="1"]
|
||||
|
||||
stream = null
|
||||
volume_db = 0.0
|
||||
pitch_scale = 1.0
|
||||
autoplay = false
|
||||
mix_target = 0
|
||||
bus = "Sfx"
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
|
@ -0,0 +1,26 @@
|
|||
extends Control
|
||||
|
||||
onready var start_btn = get_node("split/buttons/start_btn")
|
||||
onready var load_btn = get_node("split/buttons/load_btn")
|
||||
onready var options_btn = get_node("split/buttons/options_btn")
|
||||
onready var quit_btn = get_node("split/buttons/quit_btn")
|
||||
|
||||
func _ready():
|
||||
|
||||
start_btn.connect("pressed", self, "_on_start_pressed")
|
||||
load_btn.connect("pressed", self, "_on_load_pressed")
|
||||
options_btn.connect("pressed", self, "_on_options_pressed")
|
||||
quit_btn.connect("pressed", self, "_on_quit_pressed")
|
||||
|
||||
|
||||
func _on_start_pressed():
|
||||
pass
|
||||
|
||||
func _on_load_pressed():
|
||||
pass
|
||||
|
||||
func _on_options_pressed():
|
||||
pass
|
||||
|
||||
func _on_quit_pressed():
|
||||
get_tree().quit()
|
|
@ -0,0 +1,182 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://menus/main_menu.gd" type="Script" id=1]
|
||||
|
||||
[node name="main_menu" type="Control"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="split" type="VSplitContainer" parent="." index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
split_offset = 0
|
||||
collapsed = false
|
||||
dragger_visibility = 0
|
||||
|
||||
[node name="title" type="Label" parent="split" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 140.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 154.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 6
|
||||
text = "godot-vn"
|
||||
align = 1
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "Size Flags" ]
|
||||
|
||||
[node name="buttons" type="VBoxContainer" parent="split" index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 306.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 600.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 3
|
||||
alignment = 0
|
||||
_sections_unfolded = [ "Size Flags" ]
|
||||
|
||||
[node name="start_btn" type="Button" parent="split/buttons" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "start game"
|
||||
flat = true
|
||||
align = 1
|
||||
|
||||
[node name="load_btn" type="Button" parent="split/buttons" index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 24.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 44.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "load game"
|
||||
flat = true
|
||||
align = 1
|
||||
|
||||
[node name="options_btn" type="Button" parent="split/buttons" index="2"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 48.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 68.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "options"
|
||||
flat = true
|
||||
align = 1
|
||||
|
||||
[node name="quit_btn" type="Button" parent="split/buttons" index="3"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 72.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 92.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 0, 0, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "quit"
|
||||
flat = true
|
||||
align = 1
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=3
|
||||
|
||||
[application]
|
||||
|
||||
config/name="godot-vn"
|
||||
run/main_scene="res://scene.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
SceneSwitcher="*res://scene_switcher.gd"
|
||||
Game="*res://game.tscn"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/resizable=false
|
||||
|
||||
[input]
|
||||
|
||||
dialog_click=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
|
||||
]
|
||||
|
||||
[rendering]
|
||||
|
||||
environment/default_environment="res://default_env.tres"
|
|
@ -0,0 +1,7 @@
|
|||
extends Node2D
|
||||
|
||||
signal on_scene_ready
|
||||
|
||||
func _ready():
|
||||
Game.game_started = true
|
||||
emit_signal("on_scene_ready")
|
|
@ -0,0 +1,307 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://scene.gd" type="Script" id=1]
|
||||
[ext_resource path="res://dialog_layer.gd" type="Script" id=2]
|
||||
[ext_resource path="res://dialog.gd" type="Script" id=3]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id=1]
|
||||
|
||||
content_margin_left = -1.0
|
||||
content_margin_right = -1.0
|
||||
content_margin_top = -1.0
|
||||
content_margin_bottom = -1.0
|
||||
|
||||
[node name="scene" type="Node2D" index="0"]
|
||||
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="background" type="Sprite" parent="." index="0"]
|
||||
|
||||
[node name="dialog_layer" type="CanvasLayer" parent="." index="1"]
|
||||
|
||||
layer = 1
|
||||
offset = Vector2( 0, 0 )
|
||||
rotation = 0.0
|
||||
scale = Vector2( 1, 1 )
|
||||
transform = Transform2D( 1, 0, 0, 1, 0, 0 )
|
||||
script = ExtResource( 2 )
|
||||
dialog_path = "res://dialog/introduction.txt"
|
||||
|
||||
[node name="dialog_box" type="Control" parent="dialog_layer" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="audio_player" type="AudioStreamPlayer" parent="dialog_layer/dialog_box" index="0"]
|
||||
|
||||
stream = null
|
||||
volume_db = 0.0
|
||||
pitch_scale = 1.0
|
||||
autoplay = false
|
||||
mix_target = 0
|
||||
bus = "Master"
|
||||
|
||||
[node name="top_panel" type="HBoxContainer" parent="dialog_layer/dialog_box" index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 16.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 1
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 2
|
||||
_sections_unfolded = [ "Margin", "Size Flags", "Theme", "custom_constants" ]
|
||||
|
||||
[node name="auto_btn" type="Button" parent="dialog_layer/dialog_box/top_panel" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 847.0
|
||||
margin_right = 887.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color_disabled = Color( 0.378906, 0.378906, 0.378906, 1 )
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 1, 0.647059, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 1, 0.647059, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "auto"
|
||||
flat = true
|
||||
align = 1
|
||||
_sections_unfolded = [ "custom_constants" ]
|
||||
|
||||
[node name="ffwd_btn" type="Button" parent="dialog_layer/dialog_box/top_panel" index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 891.0
|
||||
margin_right = 926.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color_disabled = Color( 0.378906, 0.378906, 0.378906, 1 )
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 1, 0.647059, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 1, 0.647059, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = "fast"
|
||||
flat = true
|
||||
align = 1
|
||||
|
||||
[node name="menu_btn" type="Button" parent="dialog_layer/dialog_box/top_panel" index="2"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 930.0
|
||||
margin_right = 1002.0
|
||||
margin_bottom = 20.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color_disabled = Color( 0.378906, 0.378906, 0.378906, 1 )
|
||||
custom_colors/font_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/font_color_hover = Color( 1, 0.647059, 0, 1 )
|
||||
custom_colors/font_color_pressed = Color( 1, 0.647059, 0, 1 )
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
text = " | menu"
|
||||
flat = true
|
||||
align = 1
|
||||
|
||||
[node name="spacing" type="Control" parent="dialog_layer/dialog_box/top_panel" index="3"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 1006.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 20.0
|
||||
rect_min_size = Vector2( 18, 0 )
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
_sections_unfolded = [ "Rect" ]
|
||||
|
||||
[node name="body_container" type="PanelContainer" parent="dialog_layer/dialog_box" index="2"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = -100.0
|
||||
grow_vertical = 0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_styles/panel = SubResource( 1 )
|
||||
_sections_unfolded = [ "Grow Direction", "Mouse", "Size Flags", "custom_styles" ]
|
||||
|
||||
[node name="bottom_panel" type="VBoxContainer" parent="dialog_layer/dialog_box/body_container" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 100.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
_sections_unfolded = [ "Grow Direction", "Mouse" ]
|
||||
|
||||
[node name="subject_margin" type="MarginContainer" parent="dialog_layer/dialog_box/body_container/bottom_panel" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 14.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_constants/margin_right = 0
|
||||
custom_constants/margin_top = 0
|
||||
custom_constants/margin_left = 4
|
||||
custom_constants/margin_bottom = 0
|
||||
_sections_unfolded = [ "Mouse", "custom_constants" ]
|
||||
|
||||
[node name="subject_panel" type="HBoxContainer" parent="dialog_layer/dialog_box/body_container/bottom_panel/subject_margin" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 4.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 14.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
alignment = 0
|
||||
_sections_unfolded = [ "Mouse" ]
|
||||
|
||||
[node name="subject_label" type="Label" parent="dialog_layer/dialog_box/body_container/bottom_panel/subject_margin/subject_panel" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 14.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 4
|
||||
text = "Arborator"
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "Margin" ]
|
||||
|
||||
[node name="body_margin" type="MarginContainer" parent="dialog_layer/dialog_box/body_container/bottom_panel" index="1"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_top = 18.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 48.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
custom_constants/margin_top = 8
|
||||
custom_constants/margin_left = 8
|
||||
custom_constants/margin_bottom = 8
|
||||
_sections_unfolded = [ "Margin", "Mouse", "custom_constants" ]
|
||||
|
||||
[node name="body_label" type="Label" parent="dialog_layer/dialog_box/body_container/bottom_panel/body_margin" index="0"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 8.0
|
||||
margin_top = 8.0
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 22.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 2
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
text = "Sup new kid, you skippin?"
|
||||
percent_visible = 1.0
|
||||
lines_skipped = 0
|
||||
max_lines_visible = -1
|
||||
_sections_unfolded = [ "Margin", "Mouse", "Rect", "Size Flags" ]
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
extends Node
|
||||
|
||||
var current_scene
|
||||
|
||||
func _ready():
|
||||
var root = get_tree().get_root()
|
||||
current_scene = root.get_child(root.get_child_count() - 1)
|
||||
|
||||
func goto_scene(path, from_end = false):
|
||||
call_deferred("_deferred_goto_scene", path, from_end)
|
||||
|
||||
func _deferred_goto_scene(path, from_end):
|
||||
|
||||
# Store old name so we can pass it to next one
|
||||
var current_scene_name = current_scene.get_filename()
|
||||
|
||||
var old_scene = current_scene
|
||||
current_scene.get_parent().remove_child(current_scene)
|
||||
current_scene.queue_free()
|
||||
|
||||
# Load new scene
|
||||
var s = ResourceLoader.load(path)
|
||||
|
||||
# Instance the new scene
|
||||
current_scene = s.instance()
|
||||
|
||||
if "from_scene_name" in current_scene:
|
||||
if current_scene_name != current_scene.get_filename():
|
||||
current_scene.from_scene_name = current_scene_name
|
||||
else:
|
||||
if "from_scene_name" in old_scene:
|
||||
current_scene.from_scene_name = old_scene.from_scene_name
|
||||
|
||||
# Add it to the active scene, as child of root
|
||||
get_tree().get_root().add_child(current_scene)
|
||||
|
||||
# optional, to make it compatible with the SceneTree.change_scene() API
|
||||
get_tree().set_current_scene(current_scene)
|
|
@ -0,0 +1,25 @@
|
|||
[gd_scene format=2]
|
||||
|
||||
[node name="dialog_choice" type="Button"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
focus_mode = 2
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
toggle_mode = false
|
||||
enabled_focus_mode = 2
|
||||
shortcut = null
|
||||
group = null
|
||||
flat = false
|
||||
align = 1
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
[gd_scene format=2]
|
||||
|
||||
[node name="dialog_choices" type="Control"]
|
||||
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
rect_pivot_offset = Vector2( 0, 0 )
|
||||
rect_clip_content = false
|
||||
mouse_filter = 0
|
||||
mouse_default_cursor_shape = 0
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 1
|
||||
|
||||
|
Loading…
Reference in New Issue