Initial commit of Escoria-Reloaded. Still a lot of missing stuff.
This commit is contained in:
162
addons/escoria-core/editor/plugin_escoria.gd
Normal file
162
addons/escoria-core/editor/plugin_escoria.gd
Normal file
@@ -0,0 +1,162 @@
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
const autoloads = {
|
||||
"escoria": "res://addons/escoria-core/game/escoria.tscn",
|
||||
"esctypes": "res://addons/escoria-core/game/core-scripts/escoria_types.gd"
|
||||
}
|
||||
|
||||
func _enter_tree():
|
||||
add_autoloads()
|
||||
|
||||
add_custom_type("ESCBackground", "Sprite",
|
||||
load("res://addons/escoria-core/game/core-scripts/escbackground.gd"), null)
|
||||
add_custom_type("ESCCharacter", "KinematicBody2D",
|
||||
load("res://addons/escoria-core/game/core-scripts/esccharacter.gd"), null)
|
||||
add_custom_type("ESCHotspot", "Area2D",
|
||||
load("res://addons/escoria-core/game/core-scripts/eschotspot.gd"), null)
|
||||
add_custom_type("ESCItem", "Sprite",
|
||||
load("res://addons/escoria-core/game/core-scripts/escitem.gd"), null)
|
||||
add_custom_type("ESCItemsInventory", "GridContainer",
|
||||
load("res://addons/escoria-core/game/core-scripts/items_inventory.gd"), null)
|
||||
add_custom_type("ESCInventoryItem", "TextureButton",
|
||||
load("res://addons/escoria-core/game/core-scripts/inventory_item.gd"), null)
|
||||
add_custom_type("ESCPlayer", "KinematicBody2D",
|
||||
load("res://addons/escoria-core/game/core-scripts/escplayer.gd"), null)
|
||||
add_custom_type("ESCRoom", "Node2D",
|
||||
load("res://addons/escoria-core/game/core-scripts/escroom.gd"), null)
|
||||
add_custom_type("ESCTerrain", "Navigation2D",
|
||||
load("res://addons/escoria-core/game/core-scripts/escterrain.gd"), null)
|
||||
add_custom_type("ESCTriggerZone", "Area2D",
|
||||
load("res://addons/escoria-core/game/core-scripts/esctriggerzone.gd"), null)
|
||||
|
||||
set_escoria_main_settings()
|
||||
set_escoria_debug_settings()
|
||||
set_escoria_ui_settings()
|
||||
set_escoria_internal_settings()
|
||||
|
||||
|
||||
func set_escoria_ui_settings():
|
||||
if !ProjectSettings.has_setting("escoria/ui/tooltip_follows_mouse"):
|
||||
ProjectSettings.set_setting("escoria/ui/tooltip_follows_mouse", true)
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/ui/dialogs_folder"):
|
||||
ProjectSettings.set_setting("escoria/ui/dialogs_folder", "")
|
||||
var dialogs_folder_property_info = {
|
||||
"name": "escoria/ui/dialogs_folder",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_DIR
|
||||
}
|
||||
ProjectSettings.add_property_info(dialogs_folder_property_info)
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/ui/default_dialog_scene"):
|
||||
ProjectSettings.set_setting("escoria/ui/default_dialog_scene", "")
|
||||
var default_dialog_scene_property_info = {
|
||||
"name": "escoria/ui/default_dialog_scene",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_FILE,
|
||||
"hint_string": "*.tscn, *.scn"
|
||||
}
|
||||
ProjectSettings.add_property_info(default_dialog_scene_property_info)
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/ui/main_menu_scene"):
|
||||
ProjectSettings.set_setting("escoria/ui/main_menu_scene", "")
|
||||
var main_menu_scene_property_info = {
|
||||
"name": "escoria/ui/main_menu_scene",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_FILE,
|
||||
"hint_string": "*.tscn, *.scn"
|
||||
}
|
||||
ProjectSettings.add_property_info(main_menu_scene_property_info)
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/ui/game_scene"):
|
||||
ProjectSettings.set_setting("escoria/ui/game_scene", "")
|
||||
var game_scene_property_info = {
|
||||
"name": "escoria/ui/game_scene",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_FILE,
|
||||
"hint_string": "*.tscn, *.scn"
|
||||
}
|
||||
ProjectSettings.add_property_info(game_scene_property_info)
|
||||
|
||||
|
||||
func set_escoria_main_settings():
|
||||
if !ProjectSettings.has_setting("escoria/main/game_start_script"):
|
||||
ProjectSettings.set_setting("escoria/main/game_start_script", "")
|
||||
var game_start_script_property_info = {
|
||||
"name": "escoria/main/game_start_script",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_FILE,
|
||||
"hint_string": "*.esc"
|
||||
}
|
||||
ProjectSettings.add_property_info(game_start_script_property_info)
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/main/force_quit"):
|
||||
ProjectSettings.set_setting("escoria/main/force_quit", true)
|
||||
var force_quit_property_info = {
|
||||
"name": "escoria/main/force_quit",
|
||||
"type": TYPE_BOOL
|
||||
}
|
||||
ProjectSettings.add_property_info(force_quit_property_info)
|
||||
|
||||
ProjectSettings.set_setting("application/run/main_scene", "res://addons/escoria-core/game/main_scene.tscn")
|
||||
|
||||
|
||||
|
||||
func set_escoria_debug_settings():
|
||||
if !ProjectSettings.has_setting("escoria/debug/terminate_on_warnings"):
|
||||
ProjectSettings.set_setting("escoria/debug/terminate_on_warnings", false)
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/debug/terminate_on_errors"):
|
||||
ProjectSettings.set_setting("escoria/debug/terminate_on_errors", true)
|
||||
|
||||
# Main language the game is developed in. Useful for translation management
|
||||
if !ProjectSettings.has_setting("escoria/debug/development_lang"):
|
||||
ProjectSettings.set_setting("escoria/debug/development_lang", "en")
|
||||
|
||||
|
||||
func set_escoria_internal_settings():
|
||||
if !ProjectSettings.has_setting("escoria/internals/save_data"):
|
||||
ProjectSettings.set_setting("escoria/internals/save_data", "")
|
||||
var save_data_property_info = {
|
||||
"name": "escoria/internals/save_data",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_FILE,
|
||||
"hint_string": "*.tscn, *.scn"
|
||||
}
|
||||
ProjectSettings.add_property_info(save_data_property_info)
|
||||
|
||||
# Defines platform-specific parameters. Those are the ones that must be re-set for each platform export.
|
||||
func set_escoria_platform_settings():
|
||||
# Skip cache - certain platforms (esp. mobile) lack memory for caching scenes
|
||||
# If true, all generic scenes (UI, inventory, etc) will be loaded as any other scene.
|
||||
if !ProjectSettings.has_setting("escoria/platform/skip_cache"):
|
||||
ProjectSettings.set_setting("escoria/platform/skip_cache", false)
|
||||
|
||||
|
||||
|
||||
func add_autoloads():
|
||||
for key in autoloads.keys():
|
||||
add_autoload_singleton(key, autoloads[key])
|
||||
|
||||
func remove_autoloads():
|
||||
for key in autoloads.keys():
|
||||
if ProjectSettings.has_setting(key):
|
||||
remove_autoload_singleton(key)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
remove_custom_type("ESCBackground")
|
||||
remove_custom_type("ESCCharacter")
|
||||
remove_custom_type("ESCHotspot")
|
||||
remove_custom_type("ESCItem")
|
||||
remove_custom_type("ESCInventoryItem")
|
||||
remove_custom_type("ESCItemsInventory")
|
||||
remove_custom_type("ESCPlayer")
|
||||
remove_custom_type("ESCRoom")
|
||||
remove_custom_type("ESCTerrain")
|
||||
remove_custom_type("ESCTriggerZone")
|
||||
|
||||
remove_autoloads()
|
||||
|
||||
|
||||
BIN
addons/escoria-core/game/assets/fonts/efmi/efmi.TTF
Executable file
BIN
addons/escoria-core/game/assets/fonts/efmi/efmi.TTF
Executable file
Binary file not shown.
66299
addons/escoria-core/game/assets/fonts/efmi/efmi.inc
Executable file
66299
addons/escoria-core/game/assets/fonts/efmi/efmi.inc
Executable file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/assets/fonts/efmi/efmi.TTF" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
size = 25
|
||||
font_data = ExtResource( 1 )
|
||||
BIN
addons/escoria-core/game/assets/fonts/onesize/ONESIZE_.TTF
Executable file
BIN
addons/escoria-core/game/assets/fonts/onesize/ONESIZE_.TTF
Executable file
Binary file not shown.
BIN
addons/escoria-core/game/assets/fonts/onesize/ONESR___.TTF
Executable file
BIN
addons/escoria-core/game/assets/fonts/onesize/ONESR___.TTF
Executable file
Binary file not shown.
BIN
addons/escoria-core/game/assets/fonts/onesize/Readme1st.doc
Executable file
BIN
addons/escoria-core/game/assets/fonts/onesize/Readme1st.doc
Executable file
Binary file not shown.
BIN
addons/escoria-core/game/assets/images/no_image.png
Normal file
BIN
addons/escoria-core/game/assets/images/no_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
34
addons/escoria-core/game/assets/images/no_image.png.import
Normal file
34
addons/escoria-core/game/assets/images/no_image.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/no_image.png-7e4632ad2d21010b279ddaa4725bacb7.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/escoria-core/game/assets/images/no_image.png"
|
||||
dest_files=[ "res://.import/no_image.png-7e4632ad2d21010b279ddaa4725bacb7.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=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
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
BIN
addons/escoria-core/game/assets/images/no_image.xcf
Normal file
BIN
addons/escoria-core/game/assets/images/no_image.xcf
Normal file
Binary file not shown.
540
addons/escoria-core/game/core-scripts/esc/esc_compiler.gd
Normal file
540
addons/escoria-core/game/core-scripts/esc/esc_compiler.gd
Normal file
@@ -0,0 +1,540 @@
|
||||
extends Node
|
||||
"""
|
||||
ESC files:
|
||||
Lines beginning with ":" such as :push, :say are EVENTS.
|
||||
Lines in between are usually the ESC API functions calls. They are called COMMANDS.
|
||||
|
||||
|
||||
Steps
|
||||
compile_script(path/to/esc) : called once
|
||||
> compile(path/to/esc, errors) : called once
|
||||
> read_events() : called once
|
||||
> create an ESCState, initialized with 1st line
|
||||
> for each line in ESCState that corresponds to an event (:event), create a new level
|
||||
> add_level(state, level, errors)
|
||||
> for each state.line that belongs to same group (same indentation), create a command
|
||||
> read_cmd(state, level, errors)
|
||||
> get the token in state.line : this is the actual command (say, teleport, etc.)
|
||||
> get the parameters next to the token
|
||||
> create an ESCCommand, check it and push it into level array
|
||||
> create an ESCEvent with the level created
|
||||
> add it to the returned Dictionary of events
|
||||
In the end, the ESCState has read all lines in the file and is deleted
|
||||
Returned value is a Dictionary { event name : ESCEvent}
|
||||
And ESCEvent.level is an array of ESCCommand
|
||||
"""
|
||||
|
||||
|
||||
|
||||
var commands = {
|
||||
"accept_input": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"autosave": { "min_args": 0 },
|
||||
"anim": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL] },
|
||||
"camera_push": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"camera_set_drag_margin_enabled": { "min_args": 2, "types": [TYPE_BOOL, TYPE_BOOL] },
|
||||
"camera_set_pos": { "min_args": 3, "types": [TYPE_REAL, TYPE_INT, TYPE_INT] },
|
||||
"camera_set_target": { "min_args": 1, "types": [TYPE_REAL] },
|
||||
"camera_set_zoom": { "min_args": 1, "types": [TYPE_REAL] },
|
||||
"camera_set_zoom_height": { "min_args": 1, "types": [TYPE_INT] },
|
||||
"camera_shift": { "min_args": 2, "types": [TYPE_INT, TYPE_INT] },
|
||||
"change_scene": { "min_args": 1, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"custom": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING] },
|
||||
"cut_scene": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL] },
|
||||
"debug": { "min_args": 1 },
|
||||
"dec_global": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"dialog_config": { "min_args": 3, "types": [TYPE_STRING, TYPE_BOOL, TYPE_BOOL] },
|
||||
"enable_terrain": { "min_args": 1, "types": [TYPE_STRING]},
|
||||
"game_over": { "min_args": 1, "types": [TYPE_BOOL] },
|
||||
"inc_global": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"inventory_add": { "min_args": 1 },
|
||||
"inventory_remove": { "min_args": 1 },
|
||||
"inventory_open": { "min_args": 1, "types": [TYPE_BOOL] },
|
||||
"jump": { "min_args": 1 },
|
||||
"play_snd": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL] },
|
||||
"queue_animation": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL] },
|
||||
"queue_resource": { "min_args": 1, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"repeat": true,
|
||||
"set_state": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL] },
|
||||
"set_hud_visible": { "min_args": 1, "types": [TYPE_BOOL]},
|
||||
"say": { "min_args": 2 },
|
||||
"sched_event": { "min_args": 3, "types": [TYPE_REAL, TYPE_STRING, TYPE_STRING] },
|
||||
"set_active": { "min_args": 2, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"set_angle": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"set_global": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING] },
|
||||
"set_globals": { "min_args": 2, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"set_interactive": { "min_args": 2, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"set_speed": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"slide": { "min_args": 2 },
|
||||
"slide_block": { "min_args": 2 },
|
||||
"spawn": { "min_args": 1 },
|
||||
"stop": true,
|
||||
"teleport": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_INT] },
|
||||
"teleport_pos": { "min_args": 3 },
|
||||
"turn_to": { "min_args": 2 },
|
||||
"wait": true,
|
||||
"walk": { "min_args": 2 },
|
||||
"walk_block": { "min_args": 2 },
|
||||
|
||||
"%": { "alias": "label", "min_args": 1},
|
||||
"?": { "alias": "dialog"},
|
||||
"!": { "alias": "end_dialog", "min_args": 0 },
|
||||
">": { "alias": "branch"},
|
||||
}
|
||||
|
||||
# Commands that can be called only by the ESC debug prompt
|
||||
var debug_commands = {
|
||||
"get_active": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"get_global": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"get_interactive": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"get_state": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
}
|
||||
|
||||
# Loads a Dictionary of actions from a file, given its path.
|
||||
func load_esc_file(esc_file_path : String) -> Dictionary:
|
||||
var f = File.new()
|
||||
if !f.file_exists(esc_file_path):
|
||||
escoria.report_errors("esc_compiler.gd:load_esc_file()", ["File " + esc_file_path + " not found."])
|
||||
return {}
|
||||
return compile_script(esc_file_path)
|
||||
|
||||
# Loads the parameter script file. Can be either GDScript of ESC type.
|
||||
# Returns the Dictionary of actions loaded from the file.
|
||||
func compile_script(p_path : String) -> Dictionary:
|
||||
var ev_table
|
||||
# Script is GDScript
|
||||
if p_path.find(".gd") != -1:
|
||||
var res = ResourceLoader.load(p_path)
|
||||
if res == null:
|
||||
return {}
|
||||
ev_table = res.new().get_events()
|
||||
else: # Script is ESC
|
||||
var errors = []
|
||||
ev_table = compile(p_path, errors)
|
||||
if errors.size() > 0:
|
||||
escoria.call_deferred("report_errors", p_path, errors)
|
||||
return ev_table
|
||||
|
||||
func check_command(commands_list : Dictionary, cmd : esctypes.ESCCommand, state : esctypes.ESCState, errors : Array):
|
||||
if !(cmd.name in commands_list):
|
||||
errors.push_back("line "+str(state.line_count)+": command "+cmd.name+" not valid.")
|
||||
return false
|
||||
|
||||
var cmd_data = commands_list[cmd.name]
|
||||
if typeof(cmd_data) == TYPE_BOOL:
|
||||
return true
|
||||
|
||||
if "alias" in cmd_data:
|
||||
cmd.name = cmd_data.alias
|
||||
|
||||
if "min_args" in cmd_data:
|
||||
if cmd.params.size() < cmd_data.min_args:
|
||||
errors.push_back("line "+str(state.line_count)+": command "+cmd.name+" takes "+str(cmd_data.min_args)+" parameters ("+str(cmd.params.size())+" were given).")
|
||||
return false
|
||||
|
||||
var ret = true
|
||||
if "types" in cmd_data:
|
||||
var i = 0
|
||||
for t in cmd_data.types:
|
||||
if i >= cmd.params.size():
|
||||
break
|
||||
if t == TYPE_BOOL:
|
||||
if cmd.params[i] == "true":
|
||||
cmd.params[i] = true
|
||||
elif cmd.params[i] == "false":
|
||||
cmd.params[i] = false
|
||||
else:
|
||||
errors.push_back("line " + str(state.line_count) + ": Invalid parameter " + cmd.params[i] + " for command " + cmd.name + ". Must be 'true' or 'false'.")
|
||||
ret = false
|
||||
if t == TYPE_INT:
|
||||
if not cmd.params[i].is_valid_integer():
|
||||
errors.push_back("line " + str(state.line_count) + ": Invalid parameter " + cmd.params[i] + " for command " + cmd.name + ". Expected integer.")
|
||||
cmd.params[i] = int(cmd.params[i])
|
||||
if t == TYPE_REAL:
|
||||
if not cmd.params[i].is_valid_float():
|
||||
errors.push_back("line " + str(state.line_count) + ": Invalid parameter " + cmd.params[i] + " for command " + cmd.name + ". Expected float.")
|
||||
cmd.params[i] = float(cmd.params[i])
|
||||
i+=1
|
||||
return ret
|
||||
|
||||
# Check that the given command exists and respects the right number of parameters
|
||||
func check_normal_command(cmd : esctypes.ESCCommand, state : esctypes.ESCState, errors : Array):
|
||||
return check_command(commands, cmd, state, errors)
|
||||
|
||||
func check_debug_command(cmd : esctypes.ESCCommand, state : esctypes.ESCState, errors : Array):
|
||||
return check_command(debug_commands, cmd, state, errors)
|
||||
|
||||
# Fills the given "state" with the next line read from the file
|
||||
func read_line(state : esctypes.ESCState) -> void:
|
||||
while true:
|
||||
if _eof_reached(state.file):
|
||||
state.line = null
|
||||
return
|
||||
else:
|
||||
state.line = _get_line(state.file)
|
||||
state.line_count += 1
|
||||
if !is_comment(state.line):
|
||||
return
|
||||
|
||||
# Returns true if line is a comment (starting with #)
|
||||
func is_comment(line : String) -> bool:
|
||||
for i in range(0, line.length()):
|
||||
var c = line[i]
|
||||
if c == "#":
|
||||
return true
|
||||
if c != " " && c != "\t":
|
||||
return false
|
||||
return true
|
||||
|
||||
# Returns the position of the first non-blank character in given line string
|
||||
func get_indent(line : String):
|
||||
for i in range(0, line.length()):
|
||||
if line[i] != " " && line[i] != "\t":
|
||||
return i
|
||||
|
||||
# If the given line string is a event (begins with ":"), returns its name
|
||||
# Else, return false
|
||||
func is_event(line : String):
|
||||
var trimmed = trim(line)
|
||||
if trimmed.find(":") == 0:
|
||||
return trimmed.substr(1, trimmed.length()-1)
|
||||
return false
|
||||
|
||||
# Returns true if the given string is a flag (ie. "[.+]")
|
||||
func is_flags(tk : String) -> bool:
|
||||
var trimmed = trim(tk)
|
||||
if trimmed.find("[") == 0 && trimmed.find("]") == trimmed.length()-1:
|
||||
return true
|
||||
return false
|
||||
|
||||
# Reads each line contained in the state (ESCState) (updates state.line)
|
||||
# While the new line belongs to the same group, creates an ESCCommand from the current state
|
||||
func add_level(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
read_line(state)
|
||||
while state.line != null:
|
||||
if is_event(state.line):
|
||||
return
|
||||
var ind_level = get_indent(state.line)
|
||||
if ind_level < state.indent:
|
||||
return
|
||||
if ind_level > state.indent:
|
||||
errors.push_back("line "+str(state.line_count)+": invalid indentation for group")
|
||||
read_line(state)
|
||||
continue
|
||||
|
||||
read_cmd(state, level, errors)
|
||||
|
||||
func add_dialog(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
read_line(state)
|
||||
|
||||
while typeof(state.line) != typeof(null):
|
||||
if is_event(state.line):
|
||||
return
|
||||
|
||||
var ind_level = get_indent(state.line)
|
||||
|
||||
if ind_level < state.indent:
|
||||
return
|
||||
|
||||
if ind_level > state.indent:
|
||||
errors.push_back("line "+str(state.line_count)+": invalid indentation for dialog")
|
||||
read_line(state)
|
||||
continue
|
||||
|
||||
read_dialog_option(state, level, errors)
|
||||
|
||||
func get_token(line : String, p_from : int, line_count : int, errors : Array) -> int:
|
||||
while p_from < line.length():
|
||||
if line[p_from] == " " || line[p_from] == "\t":
|
||||
p_from += 1
|
||||
else:
|
||||
break
|
||||
if p_from >= line.length():
|
||||
return -1
|
||||
var tk_end
|
||||
if line[p_from] == "[":
|
||||
tk_end = line.find("]", p_from)
|
||||
if tk_end == -1:
|
||||
errors.push_back("line "+str(line_count)+": unterminated flags")
|
||||
tk_end += 1
|
||||
elif line[p_from] == "\"":
|
||||
tk_end = line.find("\"", p_from+1)
|
||||
if tk_end == -1:
|
||||
errors.push_back("line "+str(line_count)+": unterminated quotes, line '"+line+"'")
|
||||
else:
|
||||
tk_end = p_from
|
||||
while tk_end < line.length():
|
||||
if line[tk_end] == ":":
|
||||
var ntk = get_token(line, tk_end+1, line_count, errors)
|
||||
tk_end = ntk
|
||||
break
|
||||
if line[tk_end] == " " || line[tk_end] == "\t":
|
||||
break
|
||||
tk_end += 1
|
||||
return tk_end
|
||||
|
||||
# Remove blank characters around p_str
|
||||
func trim(p_str : String) -> String:
|
||||
while p_str.length() && (p_str[0] == " " || p_str[0] == "\t"):
|
||||
p_str = p_str.substr(1, p_str.length()-1)
|
||||
while p_str.length() && p_str[p_str.length()-1] == " " || p_str[p_str.length()-1] == "\t":
|
||||
p_str = p_str.substr(0, p_str.length()-1)
|
||||
|
||||
if p_str[0] == "\"":
|
||||
p_str = p_str.substr(1, p_str.length()-1)
|
||||
if p_str[p_str.length()-1] == "\"":
|
||||
p_str = p_str.substr(0, p_str.length()-1)
|
||||
return p_str
|
||||
|
||||
# Parses a flags string (usually defined by '[.*]') and fills the flags_list array
|
||||
# and ifs variable (Dictionary containing all ifs conditions)
|
||||
func parse_flags(p_flags : String, flags_list : Array, ifs : Dictionary):
|
||||
var from = 1
|
||||
while true:
|
||||
var next = p_flags.find(",", from)
|
||||
var flag
|
||||
if next == -1:
|
||||
flag = p_flags.substr(from, (p_flags.length()-1) - from)
|
||||
else:
|
||||
flag = p_flags.substr(from, next - from)
|
||||
flag = trim(flag)
|
||||
var list = []
|
||||
|
||||
if flag[0] == "!":
|
||||
list.push_back(true)
|
||||
flag = trim(flag.substr(1, flag.length()-1))
|
||||
if flag.find("inv-") == 0:
|
||||
ifs["if_not_inv"].push_back(trim(flag).substr(4, flag.length()-1))
|
||||
elif flag.find("a/") == 0:
|
||||
ifs["if_not_active"].push_back(trim(flag).substr(2, flag.length() - 1))
|
||||
elif flag.substr(0, 3) in ["eq ", "gt ", "lt "]:
|
||||
var elems = flag.split(" ", true, 2)
|
||||
var comparison = "ne" if elems[0] == "eq" else "le" if elems[0] == "gt" else "ge"
|
||||
ifs["if_" + comparison].push_back([elems[1], elems[2]])
|
||||
else:
|
||||
ifs["if_false"].push_back(trim(flag))
|
||||
else:
|
||||
list.push_back(false)
|
||||
if flag.find("inv-") == 0:
|
||||
ifs["if_inv"].push_back(trim(flag).substr(4, flag.length()-1))
|
||||
elif flag.find("a/") == 0:
|
||||
ifs["if_active"].push_back(trim(flag).substr(2, flag.length() - 1))
|
||||
elif flag.substr(0, 3) in ["eq ", "gt ", "lt "]:
|
||||
var elems = flag.split(" ", true, 2)
|
||||
ifs["if_" + elems[0]].push_back([elems[1], elems[2]])
|
||||
else:
|
||||
ifs["if_true"].push_back(trim(flag))
|
||||
|
||||
if flag.find(":") >= 0:
|
||||
var pos = flag.substr(0, flag.find(":"))
|
||||
var inv = flag.substr(0, pos)
|
||||
inv = trim(inv)
|
||||
list.push_back(inv)
|
||||
flag = flag.substr(pos, flag.length() - pos)
|
||||
elif flag.find("inv-") == 0:
|
||||
flag = trim(flag).substr(4, flag.length()-1)
|
||||
list.push_back("i")
|
||||
else:
|
||||
list.push_back("g")
|
||||
|
||||
list.push_back(trim(flag))
|
||||
# printt("adding flag ", list)
|
||||
flags_list.push_back(list)
|
||||
if next == -1:
|
||||
return
|
||||
from = next+1
|
||||
|
||||
func read_dialog_option(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
var tk_end = get_token(state.line, 0, state.line_count, errors)
|
||||
var tk = trim(state.line.substr(0, tk_end))
|
||||
if tk != "*" && tk != "-":
|
||||
errors.append("line "+str(state.line_count)+": Invalid dialog option")
|
||||
read_line(state)
|
||||
return
|
||||
|
||||
# Remove inline comments
|
||||
var comment_idx = state.line.find("#")
|
||||
if comment_idx > -1:
|
||||
state.line = state.line.substr(0, comment_idx)
|
||||
|
||||
tk_end += 1
|
||||
# var c_start = state.line.find("\"", 0)
|
||||
var c_end = state.line.find_last("\"")
|
||||
var q_end = state.line.find("[", c_end)
|
||||
var q_flags = null
|
||||
#printt("flags before", q_flags)
|
||||
if q_end == -1:
|
||||
q_end = state.line.length()
|
||||
else:
|
||||
var f_end = state.line.find("]", q_end)
|
||||
if f_end == -1:
|
||||
errors.append("line "+str(state.line_count)+": unterminated flags")
|
||||
else:
|
||||
f_end += 1
|
||||
q_flags = state.line.substr(q_end, f_end - q_end)
|
||||
var question = trim(state.line.substr(tk_end, q_end - tk_end))
|
||||
var cmd = { "name": "*", "params": [question, []] }
|
||||
|
||||
if q_flags:
|
||||
var ifs = {
|
||||
"if_true": [], "if_false": [], "if_inv": [], "if_not_inv": [],
|
||||
"if_active": [], "if_not_active": [],
|
||||
"if_eq": [], "if_ne": [], # string and integer comparison
|
||||
"if_gt": [], "if_ge": [], "if_lt": [], "if_le": [] # integer comparison
|
||||
}
|
||||
var flag_list = []
|
||||
parse_flags(q_flags, flag_list, ifs)
|
||||
for key in ifs:
|
||||
if ifs[key].size():
|
||||
cmd.conditions[key] = ifs[key]
|
||||
if flag_list.size():
|
||||
cmd.flags = flag_list
|
||||
|
||||
state.indent += 1
|
||||
add_level(state, cmd.params[1], errors)
|
||||
state.indent -= 1
|
||||
|
||||
level.push_back(cmd)
|
||||
|
||||
# Read an ESCState and converts it to ESCCommand
|
||||
# then puts it into level (Array of ESCCommand)
|
||||
func read_cmd(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
var params = []
|
||||
var from = 0
|
||||
var tk_end = get_token(state.line, from, state.line_count, errors)
|
||||
var ifs = {
|
||||
"if_true": [], "if_false": [], "if_inv": [], "if_not_inv": [],
|
||||
"if_active": [], "if_not_active": [],
|
||||
"if_eq": [], "if_ne": [], # string and integer comparison
|
||||
"if_gt": [], "if_ge": [], "if_lt": [], "if_le": [] # integer comparison
|
||||
}
|
||||
var flags = []
|
||||
while tk_end != -1:
|
||||
var tk = trim(state.line.substr(from, tk_end - from))
|
||||
from = tk_end + 1
|
||||
if is_flags(tk):
|
||||
parse_flags(tk, flags, ifs)
|
||||
else:
|
||||
params.push_back(tk)
|
||||
tk_end = get_token(state.line, from, state.line_count, errors)
|
||||
|
||||
if params.size() == 0:
|
||||
errors.append("line "+str(state.line_count)+": Invalid command.")
|
||||
read_line(state)
|
||||
return
|
||||
|
||||
var cmd = esctypes.ESCCommand.new(params[0])
|
||||
|
||||
if params[0] == ">":
|
||||
cmd.params = []
|
||||
state.indent += 1
|
||||
add_level(state, cmd.params, errors)
|
||||
state.indent -= 1
|
||||
elif params[0] == "?":
|
||||
params.remove(0)
|
||||
var dialog_params = []
|
||||
state.indent += 1
|
||||
add_dialog(state, dialog_params, errors)
|
||||
cmd.params = params
|
||||
cmd.params.insert(0, dialog_params)
|
||||
state.indent -= 1
|
||||
elif params[0] == "*":
|
||||
errors.push_back("line "+str(state.line_count)+": Invalid command: dialog option outside dialog")
|
||||
read_line(state)
|
||||
return
|
||||
else:
|
||||
params.remove(0)
|
||||
|
||||
# Remove inline comments
|
||||
var comment_idx = params.find("#")
|
||||
if comment_idx > -1:
|
||||
params.resize(comment_idx)
|
||||
|
||||
cmd.params = params
|
||||
read_line(state)
|
||||
|
||||
for key in ifs:
|
||||
if ifs[key].size():
|
||||
cmd.conditions[key] = ifs[key]
|
||||
|
||||
if flags.size():
|
||||
cmd.flags = flags
|
||||
|
||||
var errors_before = errors.duplicate()
|
||||
var valid = check_normal_command(cmd, state, errors)
|
||||
if valid:
|
||||
level.push_back(cmd)
|
||||
else:
|
||||
var debug_valid = check_debug_command(cmd, state, errors)
|
||||
if debug_valid:
|
||||
errors.clear()
|
||||
level.push_back(cmd)
|
||||
|
||||
# Read events from f (Dictionary or File) into ret Dictionary
|
||||
func read_events(f, ret : Dictionary, errors : Array):
|
||||
#var state = { "file": f, "line": _get_line(f), "indent": 0, "line_count": 0 }
|
||||
var state = esctypes.ESCState.new(f, _get_line(f), 0, 0)
|
||||
|
||||
while state.line != null:
|
||||
if is_comment(state.line):
|
||||
read_line(state)
|
||||
continue
|
||||
var ev = is_event(state.line)
|
||||
if typeof(ev) != typeof(null):
|
||||
var level = []
|
||||
var abort = add_level(state, level, errors)
|
||||
var ev_flags = []
|
||||
if ev is String:
|
||||
if "|" in ev:
|
||||
var ev_split = ev.split("|", true, 1)
|
||||
ev = ev_split[0]
|
||||
ev = ev.strip_edges()
|
||||
if ev_split.size() > 1:
|
||||
ev_split[1] = ev_split[1].strip_edges()
|
||||
ev_flags = ev_split[1].split(" ")
|
||||
|
||||
ret[ev] = esctypes.ESCEvent.new(ev, level, Array(ev_flags))
|
||||
if abort:
|
||||
return abort
|
||||
|
||||
# If f is a File, returns the next line as String (or null)
|
||||
# If f is a Dictionary, returns the next line from f.lines
|
||||
func _get_line(f):
|
||||
if f is Dictionary:
|
||||
if f.line >= f.lines.size():
|
||||
return null
|
||||
var line = f.lines[f.line]
|
||||
f.line += 1
|
||||
#printt("reading line ", line)
|
||||
return line
|
||||
else:
|
||||
return f.get_line()
|
||||
|
||||
func _eof_reached(f):
|
||||
if typeof(f) == typeof({}):
|
||||
return f.line >= f.lines.size()
|
||||
else:
|
||||
return f.eof_reached()
|
||||
|
||||
func compile_str(p_str : String, errors : Array):
|
||||
var f = { "line": 0, "lines": p_str.split("\n") }
|
||||
|
||||
#printt("esc compile str ", f)
|
||||
|
||||
var ret = {}
|
||||
read_events(f, ret, errors)
|
||||
|
||||
#printt("returning ", p_fname, ret)
|
||||
return ret
|
||||
|
||||
# Returns a Dictionary of events read from p_fname filename
|
||||
func compile(p_fname : String, errors : Array) -> Dictionary:
|
||||
var f = File.new()
|
||||
f.open(p_fname, File.READ)
|
||||
if !f.is_open():
|
||||
return {}
|
||||
|
||||
var ret = {}
|
||||
read_events(f, ret, errors)
|
||||
|
||||
#printt("returning ", p_fname, ret)
|
||||
return ret
|
||||
630
addons/escoria-core/game/core-scripts/esc/esc_runner.gd
Normal file
630
addons/escoria-core/game/core-scripts/esc/esc_runner.gd
Normal file
@@ -0,0 +1,630 @@
|
||||
extends Node
|
||||
|
||||
# This is the script that runs in background, checking for events in the events stack
|
||||
# and executing them.
|
||||
# Events are managed using 2 structures:
|
||||
# - event_queue: a queue for scheduled events. On each iteration, every event in the queue is updated
|
||||
# according time delta. If an event time occurs, it is run (see check_event_queue()).
|
||||
# - levels_stack: stack of events to be run immediately (from an event in ESC file usually)
|
||||
|
||||
signal global_changed(global_name)
|
||||
signal inventory_changed
|
||||
signal open_inventory
|
||||
signal saved
|
||||
signal run_event(ev_name, ev_data)
|
||||
signal event_done(ev_name)
|
||||
signal music_volume_changed
|
||||
signal action_changed
|
||||
signal paused(p_paused)
|
||||
|
||||
onready var resource_cache = load("res://addons/escoria-core/game/core-scripts/resource_queue.gd").new()
|
||||
#save_data = load(ProjectSettings.get_setting("escoria/internals/save_data")).new()
|
||||
onready var save_data = load("res://addons/escoria-core/game/core-scripts/save_data/save_data.gd").new()
|
||||
|
||||
# Cached scenes
|
||||
var scenes_cache_list : Array = []
|
||||
var scenes_cache : Dictionary = {} # this will eventually have everything in scenes_cache_list forever
|
||||
|
||||
# Event currently running
|
||||
var running_event
|
||||
# Events queue for timed events
|
||||
var event_queue : Array = []
|
||||
# Events stack
|
||||
var levels_stack : Array = []
|
||||
|
||||
var reserved_globals = [
|
||||
"ESC_LAST_SCENE"
|
||||
]
|
||||
# Dictionary of global variables
|
||||
var globals : Dictionary = {}
|
||||
|
||||
# Dictionary of active objects
|
||||
## Active == visible to the player
|
||||
## Inactive == invisible to the player
|
||||
var actives : Dictionary = {}
|
||||
# Dictionary of all objects
|
||||
## in the form : { "object global_id" : object }
|
||||
var objects : Dictionary = {}
|
||||
# Dictionary of all objects' states
|
||||
## in the form : { "object_name" : "state_name" }
|
||||
var states : Dictionary = {}
|
||||
var interactives : Dictionary = {}
|
||||
|
||||
# Array containing the event table for each registered object
|
||||
var objects_events_table : Dictionary
|
||||
|
||||
var continue_enabled : bool = true
|
||||
var loading_game : bool = false
|
||||
var game
|
||||
|
||||
# VERBS & TOOLS
|
||||
# to be used like this:
|
||||
# <current_action> <current_tool> with (target item or hotspot)
|
||||
# eg: "use" "wrench" (with) (target item or hotspot)
|
||||
|
||||
# Current verb used
|
||||
var current_action : String = "" setget set_current_action
|
||||
# Current tool (ESCItem/ESCInventoryItem) used
|
||||
var current_tool
|
||||
|
||||
## If true, we are accepting inputs
|
||||
#var accept_input : bool
|
||||
#enum ACCEPTABLE_INPUT {
|
||||
# INPUT_NONE
|
||||
#}
|
||||
|
||||
func _ready():
|
||||
save_data.start()
|
||||
|
||||
get_tree().set_auto_accept_quit(ProjectSettings.get('escoria/main/force_quit'))
|
||||
randomize()
|
||||
save_data.load_settings([self, "settings_loaded"])
|
||||
|
||||
printt("calling res cache start")
|
||||
resource_cache.start()
|
||||
|
||||
if !ProjectSettings.get_setting("escoria/platform/skip_cache"):
|
||||
scenes_cache_list.push_back(ProjectSettings.get_setting("escoria/main/curtain"))
|
||||
scenes_cache_list.push_back(ProjectSettings.get_setting("escoria/main/hud"))
|
||||
|
||||
printt("cache list ", scenes_cache_list)
|
||||
for s in scenes_cache_list:
|
||||
if s != null:
|
||||
resource_cache.queue_resource(s, false, true)
|
||||
set_process(true)
|
||||
|
||||
func _process(delta : float):
|
||||
check_event_queue(delta)
|
||||
run()
|
||||
check_autosave()
|
||||
|
||||
# Process the event queue
|
||||
func check_event_queue(delta : float):
|
||||
# Update every event's time in the queue
|
||||
for e in event_queue:
|
||||
if e.qe_time > 0:
|
||||
e.qe_time -= delta
|
||||
|
||||
# if !can_interact() or running_event:
|
||||
# return
|
||||
|
||||
var i = event_queue.size()
|
||||
while i:
|
||||
i -= 1
|
||||
var queued_next = event_queue[i]
|
||||
print(queued_next)
|
||||
# if queued_next.qe_time <= 0:
|
||||
# var obj = get_object(queued_next.qe_objname)
|
||||
# run_event(obj.event_table[queued_next.qe_event])
|
||||
# event_queue.remove(i)
|
||||
# break
|
||||
|
||||
func is_debug_command(p_event):
|
||||
if p_event["ev_name"] != "debug":
|
||||
return false
|
||||
if p_event["ev_level"].size() != 1:
|
||||
return false
|
||||
if !(p_event["ev_level"][0].name in escoria.esc_compiler.debug_commands):
|
||||
return false
|
||||
return true
|
||||
|
||||
# Called by run_game()
|
||||
func run_event(p_event):
|
||||
"""
|
||||
Run an event
|
||||
"""
|
||||
if is_debug_command(p_event):
|
||||
return run_debug_command(p_event)
|
||||
else:
|
||||
running_event = p_event
|
||||
add_level(p_event, true)
|
||||
|
||||
func run_debug_command(p_event):
|
||||
return callv(p_event["ev_level"][0].name, p_event["ev_level"][0].params)
|
||||
|
||||
func add_level(p_event, p_root : bool):
|
||||
"""
|
||||
Add an ESCEvent to events stack
|
||||
p_event: the ESCEvent
|
||||
p_root: bool
|
||||
"""
|
||||
levels_stack.push_back(instance_level(p_event, p_root))
|
||||
return esctypes.EVENT_LEVEL_STATE.CALL
|
||||
|
||||
func instance_level(p_event : esctypes.ESCEvent, p_root : bool):
|
||||
var new_level = {
|
||||
"ip": 0,
|
||||
"instructions": p_event.ev_level,
|
||||
"waiting": false,
|
||||
"break_stop": p_root,
|
||||
"labels": {},
|
||||
"flags": p_event.ev_flags
|
||||
}
|
||||
|
||||
for i in range(p_event.ev_level.size()):
|
||||
if p_event.ev_level[i].name == "label":
|
||||
var lname = p_event.ev_level[i].params[0]
|
||||
new_level.labels[lname] = i
|
||||
return new_level
|
||||
|
||||
func run():
|
||||
if levels_stack.size() == 0:
|
||||
# Constantly run in _process: we may have an empty levels_stack and no event
|
||||
if running_event:
|
||||
emit_signal("event_done", running_event.ev_name)
|
||||
running_event = null
|
||||
return
|
||||
|
||||
while levels_stack.size() > 0:
|
||||
var ret = run_top()
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.YIELD:
|
||||
return
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.BREAK:
|
||||
while levels_stack.size() > 0 && !(levels_stack[levels_stack.size()-1].break_stop):
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
|
||||
func run_top():
|
||||
var top = levels_stack[levels_stack.size()-1]
|
||||
# printt("-----> TOP:", top)
|
||||
var ret = $esc_level_runner.resume(top)
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.RETURN || ret == esctypes.EVENT_LEVEL_STATE.BREAK:
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
return ret
|
||||
|
||||
func test(cmd):
|
||||
if "if_true" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_true:
|
||||
if !get_global(flag):
|
||||
return false
|
||||
if "if_false" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_false:
|
||||
if get_global(flag):
|
||||
return false
|
||||
if "if_inv" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_inv:
|
||||
if !inventory_has(flag):
|
||||
return false
|
||||
if "if_not_inv" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_not_inv:
|
||||
if inventory_has(flag):
|
||||
return false
|
||||
if "if_active" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_active:
|
||||
if not flag in actives or not actives[flag]:
|
||||
return false
|
||||
if "if_not_active" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_not_active:
|
||||
if flag in actives and actives[flag]:
|
||||
return false
|
||||
if "if_eq" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_eq:
|
||||
if !is_global_equal_to(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_ne" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_ne:
|
||||
if is_global_equal_to(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_gt" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_gt:
|
||||
if !is_global_greater_than(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_ge" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_ge:
|
||||
if is_global_less_than(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_lt" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_lt:
|
||||
if !is_global_less_than(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_le" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_le:
|
||||
if is_global_greater_than(flag[0], flag[1]):
|
||||
return false
|
||||
return true
|
||||
|
||||
func inventory_has(p_obj):
|
||||
return get_global("i/"+p_obj)
|
||||
|
||||
func items_in_inventory():
|
||||
var items = []
|
||||
for glob in globals.keys():
|
||||
if glob.begins_with("i/") and globals[glob] == "true":
|
||||
items.push_back(glob.rsplit("i/", false)[0])
|
||||
return items
|
||||
|
||||
func get_global(name):
|
||||
# If no value or looks like boolean, return boolean for backwards compatibility
|
||||
if not name in globals or globals[name].to_lower() == "false":
|
||||
return false
|
||||
if globals[name].to_lower() == "true":
|
||||
return true
|
||||
return globals[name]
|
||||
|
||||
# Set global state 'name' to 'value' (can be true or false)
|
||||
#
|
||||
func set_global(name, val, force_change_reserved : bool = false):
|
||||
if name in reserved_globals and !force_change_reserved:
|
||||
escoria.report_warnings("esc_runner.gd:set_global()",
|
||||
["Global " + name + " is reserved. Value not modified."])
|
||||
return
|
||||
globals[name] = val
|
||||
# printt("global changed at global_vm, emitting for ", name, val)
|
||||
emit_signal("global_changed", name)
|
||||
|
||||
func dec_global(name, diff):
|
||||
var global = get_global(name)
|
||||
global = int(global) if global else 0
|
||||
set_global(name, str(global - diff))
|
||||
|
||||
func inc_global(name, diff):
|
||||
var global = get_global(name)
|
||||
global = int(global) if global else 0
|
||||
set_global(name, str(global + diff))
|
||||
|
||||
func set_globals(pat, val):
|
||||
for key in globals:
|
||||
if key.match(pat):
|
||||
globals[key] = val
|
||||
emit_signal("global_changed", key)
|
||||
|
||||
func is_global_equal_to(name, val):
|
||||
var global = get_global(name)
|
||||
if global and val and global == val:
|
||||
return true
|
||||
|
||||
func is_global_greater_than(name, val):
|
||||
var global = get_global(name)
|
||||
if global and val and int(global) > int(val):
|
||||
return true
|
||||
|
||||
func is_global_less_than(name, val):
|
||||
var global = get_global(name)
|
||||
if global and val and int(global) < int(val):
|
||||
return true
|
||||
|
||||
func check_autosave():
|
||||
pass
|
||||
|
||||
func set_current_action(action : String):
|
||||
if ! action is String:
|
||||
escoria.report_errors("esc_runner.gd",
|
||||
["Trying to set_current_action: " + str(typeof(action))])
|
||||
|
||||
if action != current_action:
|
||||
clear_current_tool()
|
||||
|
||||
current_action = action
|
||||
emit_signal("action_changed")
|
||||
|
||||
func clear_current_action():
|
||||
set_current_action("")
|
||||
|
||||
func clear_current_tool():
|
||||
current_tool = null
|
||||
|
||||
func change_scene(params, context, run_events=true):
|
||||
printt("change scene to ", params[0], " with run_events ", run_events)
|
||||
# check_cache()
|
||||
# main.clear_scene()
|
||||
# camera = null
|
||||
event_queue = []
|
||||
|
||||
# Regular events need to be reset immediately, so we don't
|
||||
# accidentally `yield()` on them, for performance reasons.
|
||||
# This does not affect `stack` so execution is fine anyway.
|
||||
if running_event and running_event.ev_name != "load":
|
||||
emit_signal("event_done", running_event.ev_name)
|
||||
running_event = null
|
||||
|
||||
var res_room = resource_cache.get_resource(params[0])
|
||||
var res_game = resource_cache.get_resource(ProjectSettings.get_setting("escoria/ui/game_scene"))
|
||||
if !res_room:
|
||||
escoria.report_errors("esc_runner.gd:change_scene()",
|
||||
["Resource not found: " + params[0]])
|
||||
if !res_game:
|
||||
escoria.report_errors("esc_runner.gd:change_scene()",
|
||||
["Resource not found: " + ProjectSettings.get_setting("escoria/ui/game_scene")])
|
||||
|
||||
resource_cache.clear()
|
||||
|
||||
# Load game scene
|
||||
var game_scene = res_game.instance()
|
||||
if !game_scene:
|
||||
escoria.report_errors("esc_runner.gd:change_scene()",
|
||||
["Failed loading scene " + ProjectSettings.get_setting("escoria/ui/game_scene")])
|
||||
|
||||
|
||||
# Load room scene
|
||||
var room_scene = res_room.instance()
|
||||
if room_scene:
|
||||
room_scene.add_child(game_scene)
|
||||
room_scene.move_child(game_scene, 0)
|
||||
escoria.main.set_scene(room_scene, run_events)
|
||||
escoria.inputs_manager.is_hotspot_focused = false
|
||||
if !scenes_cache_list.has(params[0]):
|
||||
scenes_cache_list.push_back(params[0])
|
||||
scenes_cache[room_scene.global_id] = params[0]
|
||||
else:
|
||||
escoria.report_errors("esc_runner.gd:change_scene()",
|
||||
["Failed loading scene " + params[0]])
|
||||
|
||||
if context != null:
|
||||
context.waiting = false
|
||||
|
||||
# Re-apply actives
|
||||
for active in actives:
|
||||
set_active(active, actives[active])
|
||||
|
||||
# cam_target = null
|
||||
# autosave_pending = true
|
||||
|
||||
func run_game(actions : Dictionary):
|
||||
set_process(true)
|
||||
# `load` and `ready` are exclusive because you probably don't want to
|
||||
# reset the game state when a scene becomes ready, and `ready` is
|
||||
# redundant when `load`ing state anyway.
|
||||
# `start` is used only in your `escoria/platform/game_start_script` .esc
|
||||
# file to start the game.
|
||||
if "start" in actions:
|
||||
clear()
|
||||
run_event(actions["start"])
|
||||
escoria.main_menu_instance.hide()
|
||||
elif "load" in actions:
|
||||
clear()
|
||||
run_event(actions["load"])
|
||||
elif "ready" in actions:
|
||||
run_event(actions["ready"])
|
||||
|
||||
func clear():
|
||||
get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFAULT, "game", "game_cleared")
|
||||
levels_stack = []
|
||||
globals = {}
|
||||
objects = {}
|
||||
states = {}
|
||||
actives = {}
|
||||
interactives = {}
|
||||
event_queue = []
|
||||
continue_enabled = true
|
||||
loading_game = false
|
||||
|
||||
|
||||
func register_object(name : String, val : Object, force : bool = false):
|
||||
if !name:
|
||||
escoria.report_errors("esc_runner.gd:register_object()",
|
||||
["global_id not given for " + val.get_class() + " " + val.name])
|
||||
|
||||
if name in objects and not force:
|
||||
escoria.report_errors("esc_runner.gd:register_object()",
|
||||
["Trying to register already registered object " + name + ": " \
|
||||
+ val.get_class() + " (" + val.name + ")"])
|
||||
|
||||
objects[name] = val
|
||||
|
||||
if not val.is_connected("tree_exited", self, "object_exit_scene"):
|
||||
val.connect("tree_exited", self, "object_exit_scene", [name])
|
||||
|
||||
# Most objects have states/animations, but don't count on it
|
||||
# if val.has_method("set_state"):
|
||||
if val is ESCItem or val is ESCPlayer or val is ESCCharacter or val is ESCHotspot:
|
||||
if name in states:
|
||||
set_state(name, [states[name], true])
|
||||
else:
|
||||
set_state(name, [esctypes.OBJ_DEFAULT_STATE])
|
||||
|
||||
if val is ESCItem or val is ESCHotspot:
|
||||
if val.is_interactive:
|
||||
set_interactive(name, true)
|
||||
|
||||
|
||||
# if val.has_method("set_active"):
|
||||
# if name in actives:
|
||||
# val.set_active(actives[name])
|
||||
|
||||
# if val.has_method("set_interactive"):
|
||||
# if name in interactives:
|
||||
# val.set_interactive(interactives[name])
|
||||
|
||||
if val.get("esc_script") != null and !val.get("esc_script").empty():
|
||||
objects_events_table[name] = escoria.esc_compiler.load_esc_file(val.esc_script)
|
||||
|
||||
|
||||
func get_object(name):
|
||||
if !(name in objects):
|
||||
return null
|
||||
return objects[name]
|
||||
|
||||
|
||||
# Activates the action for given params
|
||||
# p_action String Action to execute (defined in attached ESC file and in action verbs UI)
|
||||
# - eg: arrived, use, look, pickup...
|
||||
# p_params Array
|
||||
# - 0 Object Target object
|
||||
func activate(p_action : String, p_param : Array):
|
||||
printt("Action", p_action, "with params", p_param)
|
||||
# if p_param[0].global_id:
|
||||
# printt("("+p_param[0].global_id+")")
|
||||
var what = p_param[0]
|
||||
|
||||
# If we're using an action which item requires to combine
|
||||
if what is ESCItem and p_action in what.combine_if_action_used_among:
|
||||
# Check if object must be in inventory to be used
|
||||
if what is ESCItem and what.use_from_inventory_only:
|
||||
if !inventory_has(what.global_id):
|
||||
# TODO Either use fallback here, or run pickup action before use
|
||||
escoria.report_warnings("esc_runner.gd:activate()", ["Trying to "
|
||||
+ p_action + " on object " + what.global_id
|
||||
+ " but item must be in inventory."])
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
else:
|
||||
|
||||
# Player has item in inventory, we check the element to use on
|
||||
if p_param.size() > 1:
|
||||
var combine_with = p_param[1]
|
||||
|
||||
var do_combine = false
|
||||
if combine_with is ESCItem and combine_with.use_from_inventory_only:
|
||||
if inventory_has(combine_with.global_id):
|
||||
do_combine = true
|
||||
else:
|
||||
do_combine = true
|
||||
|
||||
if do_combine:
|
||||
if objects_events_table[what.global_id].has(p_action + " " + combine_with.global_id):
|
||||
run_event(objects_events_table[what.global_id][p_action + " " + combine_with.global_id])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
elif objects_events_table[combine_with.global_id].has(p_action + " " + what.global_id) \
|
||||
and !combine_with.combine_is_one_way:
|
||||
run_event(objects_events_table[combine_with.global_id][p_action + " " + what.global_id])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
else:
|
||||
var errors = ["Attempted to execute inexisting action " + \
|
||||
p_action + " between item " + combine_with.global_id + " and item " + what.global_id]
|
||||
if combine_with.combine_is_one_way:
|
||||
errors.append("Reason: " + combine_with.global_id + "'s item interaction is one-way.")
|
||||
escoria.report_warnings("esc_runner.gd:activate()", errors)
|
||||
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
else:
|
||||
# TODO Use fallback here
|
||||
pass
|
||||
|
||||
else:
|
||||
# We're missing a target here.
|
||||
# Tell the Label to add a conjunction and wait for another click
|
||||
# to add the target to p_param. Until then, return false.
|
||||
current_tool = what
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
if what.global_id in objects_events_table:
|
||||
if p_action in objects_events_table[what.global_id]:
|
||||
run_event(objects_events_table[what.global_id][p_action])
|
||||
else:
|
||||
escoria.report_warnings("esc_runner.gd:activate()",
|
||||
["Action '" + p_action + "' requested on object '" \
|
||||
+ what.global_id + "' but action doesn't exist in attached ESC file.",
|
||||
"TODO: manage fallbacks."])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
else:
|
||||
escoria.report_warnings("esc_runner.gd:activate()",
|
||||
["Action '" + p_action + "' requested on object '" + what.global_id \
|
||||
+ "' but object does not exist in objects_events_table.", \
|
||||
"Does object " + what.global_id + " have an attached ESC file?"])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
func get_state(name : String):
|
||||
return states[name]
|
||||
|
||||
|
||||
func get_active(name : String) -> bool:
|
||||
if actives.has(name):
|
||||
return actives[name]
|
||||
return false
|
||||
|
||||
"""
|
||||
Return the interactive object given its global_id.
|
||||
"""
|
||||
func get_interactive(global_id : String):
|
||||
if interactives.has(global_id):
|
||||
return interactives[global_id]
|
||||
return false
|
||||
|
||||
|
||||
"""
|
||||
Change an object state and play its animation (if it has one)
|
||||
p_params[] :
|
||||
- String state : the state name
|
||||
- bool immediate (default=false) : if true, the animation is not played and immediately goes to the last frame
|
||||
"""
|
||||
func set_state(global_id : String, p_params : Array):
|
||||
var obj = get_object(global_id)
|
||||
states[global_id] = p_params[0]
|
||||
var immediate : bool = false
|
||||
if p_params.size() > 1:
|
||||
immediate = p_params[1]
|
||||
|
||||
# A Hotspot can have a child item, if this item has an empty sprite
|
||||
# (the hotspot is there to get the user input)
|
||||
var animation_node
|
||||
if obj is ESCItem:
|
||||
#if obj.get("animation") != null:
|
||||
# animation_node = obj.get("animation")
|
||||
if obj.get_animation_player() != null:
|
||||
animation_node = obj.get_animation_player()
|
||||
elif obj is ESCHotspot and obj.get_item_child_if_any() != null:
|
||||
#if obj.get_item_child_if_any().get("animation") != null:
|
||||
# animation_node = obj.get_item_child_if_any().animation
|
||||
if obj.get_item_child_if_any().get_animation_player() != null:
|
||||
animation_node = obj.get_item_child_if_any().get_animation_player()
|
||||
|
||||
if animation_node:
|
||||
animation_node.stop()
|
||||
if animation_node.has_animation(p_params[0]):
|
||||
if !immediate:
|
||||
animation_node.play(p_params[0])
|
||||
else:
|
||||
# The animation is not played, we directly set it at its last frame
|
||||
animation_node.current_animation = p_params[0]
|
||||
var animation = animation_node.get_animation(p_params[0])
|
||||
var animation_length = animation.length
|
||||
animation_node.seek(animation_length)
|
||||
|
||||
|
||||
"""
|
||||
When object is active, it is VISIBLE.
|
||||
When object is inactive, it is HIDDEN.
|
||||
"""
|
||||
func set_active(name : String, active):
|
||||
if objects[name] is ESCInventoryItem:
|
||||
return
|
||||
actives[name] = active
|
||||
if objects.has(name) and is_instance_valid(objects[name]):
|
||||
if active:
|
||||
objects[name].show()
|
||||
else:
|
||||
objects[name].hide()
|
||||
|
||||
"""
|
||||
When object is interactive, it can be focused
|
||||
When object is not interactive, it cannot be focused and used
|
||||
"""
|
||||
func set_interactive(name : String, active):
|
||||
interactives[name] = active
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Callback called by ESCItems when it emits "tree_exit", ie. removed from scene.
|
||||
Item is kept in objects[] array if it is in inventory.
|
||||
"""
|
||||
func object_exit_scene(name : String):
|
||||
# If object is in inventory, save it before it's destroyed so we still have
|
||||
# its data in objects[]
|
||||
if inventory_has(name):
|
||||
objects[name] = objects[name].duplicate()
|
||||
else:
|
||||
printt("Object " + name + " removed from scene.")
|
||||
objects.erase(name)
|
||||
|
||||
463
addons/escoria-core/game/core-scripts/esc/esc_runner_level.gd
Normal file
463
addons/escoria-core/game/core-scripts/esc/esc_runner_level.gd
Normal file
@@ -0,0 +1,463 @@
|
||||
extends Node
|
||||
|
||||
# This script runs the ESCCommands contained in the ESCEvent.
|
||||
|
||||
var current_context
|
||||
onready var esc_runner = get_parent()
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func finished(context = null):
|
||||
if context != null:
|
||||
context.waiting = false
|
||||
else:
|
||||
current_context.waiting = false
|
||||
|
||||
|
||||
func check_obj(name, cmd):
|
||||
var obj = escoria.esc_runner.get_object(name)
|
||||
if obj == null:
|
||||
escoria.report_errors("", ["Global id "+name+" not found for " + cmd])
|
||||
return false
|
||||
return true
|
||||
|
||||
func resume(context):
|
||||
current_context = context
|
||||
if context.waiting:
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
var count = context.instructions.size()
|
||||
while context.ip < count:
|
||||
var top = esc_runner.levels_stack.size()
|
||||
var ret = run(context)
|
||||
context.ip += 1
|
||||
if top < esc_runner.levels_stack.size():
|
||||
return esctypes.EVENT_LEVEL_STATE.CALL
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.YIELD:
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.CALL:
|
||||
return esctypes.EVENT_LEVEL_STATE.CALL
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.BREAK:
|
||||
if context.break_stop:
|
||||
break
|
||||
else:
|
||||
return esctypes.EVENT_LEVEL_STATE.BREAK
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.REPEAT:
|
||||
context.ip = 0
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.JUMP:
|
||||
return esctypes.EVENT_LEVEL_STATE.JUMP
|
||||
context.ip = 0
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
func run(context):
|
||||
var cmd = context.instructions[context.ip]
|
||||
if cmd.name == "label":
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
if !esc_runner.test(cmd):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
#print("name is ", cmd.name)
|
||||
#if !(cmd.name in self):
|
||||
# esc_runner.report_errors("", ["Unexisting command "+cmd.name])
|
||||
return call(cmd.name, cmd.params)
|
||||
|
||||
|
||||
"""
|
||||
Automatically called when a dialog line is said.
|
||||
"""
|
||||
func dialog_line_finished() -> void:
|
||||
# escoria.esc_runner.get_node("esc_level_runner").finished()
|
||||
finished()
|
||||
escoria.dialog_player.is_speaking = false
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
|
||||
"""
|
||||
"""
|
||||
func accept_input():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func autosave():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func anim():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func branch(command_params : Array):
|
||||
var branch_ev = esctypes.ESCEvent.new("branch", command_params, [])
|
||||
return escoria.esc_runner.add_level(branch_ev, false)
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_push():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_set_drag_margin_enabled():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_set_pos():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_set_target():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_set_zoom():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_set_zoom_height():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func camera_shift():
|
||||
pass
|
||||
|
||||
"""
|
||||
"""
|
||||
func change_scene(params):
|
||||
# Savegames must have events disabled, so saving the game adds a false to params
|
||||
var run_events = true
|
||||
if params.size() == 2:
|
||||
run_events = bool(params[1])
|
||||
|
||||
# looking for localized string format in scene. this should be somewhere else
|
||||
var sep = params[0].find(":\"")
|
||||
if sep >= 0:
|
||||
var path = params[0].substr(sep + 2, params[0].length() - (sep + 2))
|
||||
escoria.esc_runner.call_deferred("change_scene", [path], current_context, run_events)
|
||||
else:
|
||||
escoria.esc_runner.call_deferred("change_scene", params, current_context, run_events)
|
||||
|
||||
current_context.waiting = true
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
"""
|
||||
"""
|
||||
func custom():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func cut_scene():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func debug():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func dec_global():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func inc_global():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func dialog(command_params : Array):
|
||||
current_context.waiting = true
|
||||
current_context.in_dialog = true
|
||||
escoria.current_state = escoria.GAME_STATE.DIALOG
|
||||
if !escoria.dialog_player:
|
||||
escoria.dialog_player = escoria.main.current_scene.get_node("game/ui/dialog_layer/dialog_player")
|
||||
var options = command_params.slice(1, command_params.size())
|
||||
escoria.dialog_player.start_dialog_choices(command_params[0], options)
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func dialog_config():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
Enable the ESCTerrain's NavigationPolygonInstance defined by given node name.
|
||||
Disables previously activated NavigationPolygonInstance.
|
||||
"""
|
||||
func enable_terrain(command_params : Array):
|
||||
var name : String = command_params[0]
|
||||
if escoria.room_terrain.has_node(name):
|
||||
var new_active_navigation_instance = escoria.room_terrain.get_node(name)
|
||||
escoria.room_terrain.current_active_navigation_instance.enabled = false
|
||||
escoria.room_terrain.current_active_navigation_instance = new_active_navigation_instance
|
||||
escoria.room_terrain.current_active_navigation_instance.enabled = true
|
||||
|
||||
"""
|
||||
"""
|
||||
func game_over(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func inventory_add(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func inventory_remove(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func inventory_open(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func jump(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func play_snd(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func queue_animation(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func queue_resource(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func repeat(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
Make a character say one line.
|
||||
Usage: say object_id line [dialog_ui_name]
|
||||
"""
|
||||
func say(command_params : Array) -> esctypes:
|
||||
current_context.waiting = true
|
||||
|
||||
var dict : Dictionary
|
||||
var dialog_scene_name = ProjectSettings.get_setting("escoria/ui/default_dialog_scene")
|
||||
|
||||
if dialog_scene_name.empty():
|
||||
escoria.report_errors("level_esc_runners.gd:say()", ["Project setting 'escoria/ui/default_dialog_scene' is not set. Please set a default dialog scene."])
|
||||
var file = dialog_scene_name.get_file()
|
||||
var extension = dialog_scene_name.get_extension()
|
||||
dialog_scene_name = file.rstrip("." + extension)
|
||||
|
||||
# Manage specific dialog scene
|
||||
if command_params.size() > 2:
|
||||
dialog_scene_name = command_params[2]
|
||||
|
||||
dict = {
|
||||
"line": command_params[1],
|
||||
"ui": dialog_scene_name
|
||||
#"ui": "dialog_label"
|
||||
#"ui": "dialog_box_inset"
|
||||
}
|
||||
escoria.current_state = escoria.GAME_STATE.DIALOG
|
||||
if !escoria.dialog_player:
|
||||
escoria.dialog_player = escoria.main.current_scene.get_node("game/ui/dialog_layer/dialog_player")
|
||||
escoria.dialog_player.say(command_params[0], dict)
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
Sets object as active or inactive. Active objects are displayed in scene and respond
|
||||
to inputs. Inactives are hidden.
|
||||
"""
|
||||
func set_active(command_params : Array):
|
||||
if !check_obj(command_params[0], "set_active"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
var name : String = command_params[0]
|
||||
var value = command_params[1]
|
||||
escoria.esc_runner.set_active(name, value)
|
||||
|
||||
"""
|
||||
Set the angle of an object.
|
||||
Usage: set_angle object_id angle_degrees
|
||||
"""
|
||||
func set_angle(params : Array):
|
||||
if !check_obj(params[0], "set_angle"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
var obj = escoria.esc_runner.get_object(params[0])
|
||||
obj.set_angle(int(params[1]))
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func set_state(command_params : Array):
|
||||
var global_id : String = command_params[0]
|
||||
var p_params : Array = command_params.slice(1, command_params.size())
|
||||
escoria.esc_runner.set_state(global_id, p_params)
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func set_hud_visible(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func sched_event(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func set_global(command_params : Array):
|
||||
var name : String = command_params[0]
|
||||
var value = command_params[1]
|
||||
escoria.esc_runner.set_global(name, value)
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func set_globals(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func set_interactive(command_params : Array):
|
||||
var name : String = command_params[0]
|
||||
var value = command_params[1]
|
||||
escoria.esc_runner.set_interactive(name, value)
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func set_speed(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func slide(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func slide_block(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func spawn(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func stop(command_params : Array):
|
||||
return esctypes.EVENT_LEVEL_STATE.BREAK
|
||||
|
||||
"""
|
||||
Teleports obj1 at obj2's position. If angle_degrees is set (int), sets obj1's
|
||||
angle to angle_degrees.
|
||||
Usage: teleport obj1 obj2 [angle_degrees]
|
||||
"""
|
||||
func teleport(params):
|
||||
if !check_obj(params[0], "teleport"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
if !check_obj(params[1], "teleport"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
var angle
|
||||
if params.size() > 2:
|
||||
angle = int(params[2])
|
||||
|
||||
escoria.esc_runner.get_object(params[0]).teleport(escoria.esc_runner.get_object(params[1]), angle)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func teleport_pos(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func turn_to(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
Wait for given time in seconds.
|
||||
Usage: wait time_in_seconds
|
||||
"""
|
||||
func wait(command_params : Array):
|
||||
escoria.current_state = escoria.GAME_STATE.WAIT
|
||||
var time = float(command_params[0])
|
||||
if time <= 0:
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
# get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFAULT, "game", "wait", time, p_level)
|
||||
escoria.main.wait(command_params, current_context)
|
||||
current_context.waiting = true
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
Make object1 walk towards object2. This command is not blocking (user input not disabled)
|
||||
Usage: walk object_id1 object_id2
|
||||
"""
|
||||
func walk(command_params : Array):
|
||||
escoria.do("walk", command_params)
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func walk_block(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
97
addons/escoria-core/game/core-scripts/escbackground.gd
Normal file
97
addons/escoria-core/game/core-scripts/escbackground.gd
Normal file
@@ -0,0 +1,97 @@
|
||||
tool
|
||||
extends TextureRect
|
||||
class_name ESCBackground
|
||||
|
||||
func get_class():
|
||||
return "ESCBackground"
|
||||
|
||||
signal double_left_click_on_bg(position)
|
||||
signal left_click_on_bg(position)
|
||||
signal right_click_on_bg(position)
|
||||
signal mouse_moved
|
||||
|
||||
export(String, FILE, "*.esc") var esc_script = ""
|
||||
|
||||
# Actual size of the scene
|
||||
var size : Vector2
|
||||
|
||||
"""
|
||||
ESCBackground purpose is to display a background image and receive input events
|
||||
on the background. More precisely, the TextureRect under ESCBackground does not
|
||||
receive events itself - if it did, it would also eat all events like hotspot
|
||||
focusing and such. Instead, we set the TextureRect mouse filter to
|
||||
MOUSE_FILTER_IGNORE, and we use an Area2D node to receive the input events.
|
||||
|
||||
If ESCBackground doesn't contain a texture, it is important that its rect_size
|
||||
is set over the whole scene, because its rect_size is then used to create the
|
||||
Area2D node under it. If the rect_size is wrongly set, the background may
|
||||
receive no input.
|
||||
"""
|
||||
|
||||
# PRIVATE VARS
|
||||
var area : Area2D
|
||||
var actual_click_position : Vector2
|
||||
|
||||
# Godot doesn't do doubleclicks so we must
|
||||
var last_lmb_dt = 0
|
||||
var waiting_dblclick = null # null or [pos, event]
|
||||
|
||||
func _enter_tree():
|
||||
# Use size of background texture to calculate collision shape if any
|
||||
if get_texture():
|
||||
size = get_texture().get_size()
|
||||
else:
|
||||
size = rect_size
|
||||
|
||||
area = Area2D.new()
|
||||
var shape = RectangleShape2D.new()
|
||||
|
||||
var sid = area.create_shape_owner(area)
|
||||
|
||||
# Move origin of Area2D to center of Sprite
|
||||
var transform = area.shape_owner_get_transform(sid)
|
||||
transform.origin = size / 2
|
||||
area.shape_owner_set_transform(sid, transform)
|
||||
|
||||
# Set extents of RectangleShape2D to cover entire Sprite
|
||||
shape.set_extents(size / 2)
|
||||
area.shape_owner_add_shape(sid, shape)
|
||||
|
||||
add_child(area)
|
||||
|
||||
func _ready():
|
||||
mouse_filter = MOUSE_FILTER_IGNORE
|
||||
area.connect("input_event", self, "manage_input")
|
||||
connect("gui_input", self, "manage_input_texturerect")
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
connect("left_click_on_bg", escoria.inputs_manager, "_on_left_click_on_bg")
|
||||
connect("right_click_on_bg", escoria.inputs_manager, "_on_right_click_on_bg")
|
||||
connect("double_left_click_on_bg", escoria.inputs_manager, "_on_double_left_click_on_bg")
|
||||
# connect("mouse_moved_on_bg", escoria.inputs_manager, "_on_mouse_moved_on_bg")
|
||||
|
||||
func manage_input(_viewport, event, _shape_idx):
|
||||
if event is InputEventMouseButton:
|
||||
var p = get_global_mouse_position()
|
||||
if event.doubleclick:
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("double_left_click_on_bg", p)
|
||||
else:
|
||||
if event.is_pressed():
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("left_click_on_bg", p)
|
||||
if event.button_index == BUTTON_RIGHT:
|
||||
emit_signal("right_click_on_bg", p)
|
||||
# elif event is InputEventMouseMotion:
|
||||
# emit_signal("mouse_moved_on_bg")
|
||||
|
||||
|
||||
|
||||
func manage_input_texturerect(event):
|
||||
if event is InputEventMouseButton and event.is_pressed():
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("left_click_on_bg", event.position)
|
||||
if event.button_index == BUTTON_RIGHT:
|
||||
emit_signal("right_click_on_bg", event.position)
|
||||
else:
|
||||
pass
|
||||
9
addons/escoria-core/game/core-scripts/esccharacter.gd
Normal file
9
addons/escoria-core/game/core-scripts/esccharacter.gd
Normal file
@@ -0,0 +1,9 @@
|
||||
tool
|
||||
extends Node
|
||||
class_name ESCCharacter
|
||||
|
||||
export(String) var character_id
|
||||
export(String, FILE, ".esc") var esc_script = ""
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
148
addons/escoria-core/game/core-scripts/eschotspot.gd
Normal file
148
addons/escoria-core/game/core-scripts/eschotspot.gd
Normal file
@@ -0,0 +1,148 @@
|
||||
tool
|
||||
extends Area2D
|
||||
class_name ESCHotspot
|
||||
|
||||
func get_class():
|
||||
return "ESCHotspot"
|
||||
|
||||
"""
|
||||
ESCHotspot is an Area2D (hotspot).
|
||||
A hotspot is a simple area that can be defined by the user and is thus invisible
|
||||
Usually, hotspots are used to define areas of the background that the player can
|
||||
look at.
|
||||
"""
|
||||
|
||||
signal mouse_entered_hotspot(global_id)
|
||||
signal mouse_exited_hotspot
|
||||
signal mouse_left_clicked_hotspot(global_id, click_position)
|
||||
signal mouse_double_left_clicked_hotspot(global_id, click_position)
|
||||
signal mouse_right_clicked_hotspot(global_id, click_position)
|
||||
|
||||
export(String) var global_id
|
||||
export(bool) var is_exit
|
||||
export(String, FILE, "*.esc") var esc_script
|
||||
export(bool) var is_interactive = true
|
||||
export(bool) var player_orients_on_arrival = true
|
||||
export(ESCPlayer.Directions) var interaction_direction
|
||||
export(String) var tooltip_name
|
||||
export(String) var default_action
|
||||
# If action used by player is in the list, game will wait for a second click on another item
|
||||
# to combine objects together (typical USE <X> WITH <Y>, GIVE <X> TO <Y>)
|
||||
export(PoolStringArray) var combine_if_action_used_among = []
|
||||
export(Color) var dialog_color = ColorN("white")
|
||||
|
||||
# Detected interact position set by a Position2D node OUTSIDE OF THE HOTSPOT SCENE.
|
||||
# You have to add a child to the INSTANCED HOTSPOT SCENE, IN THE ROOM SCENE.
|
||||
export(Dictionary) var interact_positions : Dictionary = { "default": null}
|
||||
|
||||
var collision
|
||||
|
||||
var terrain : ESCTerrain
|
||||
# If the terrain node type is scalenodes
|
||||
var terrain_is_scalenodes : bool
|
||||
var check_maps = true
|
||||
|
||||
var pose_scale : int
|
||||
var last_scale : Vector2
|
||||
|
||||
func _ready():
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
connect("mouse_entered_hotspot", escoria.inputs_manager, "_on_mouse_entered_hotspot")
|
||||
connect("mouse_exited_hotspot", escoria.inputs_manager, "_on_mouse_exited_hotspot")
|
||||
connect("mouse_left_clicked_hotspot", escoria.inputs_manager, "_on_mouse_left_clicked_hotspot")
|
||||
connect("mouse_right_clicked_hotspot", escoria.inputs_manager, "_on_mouse_right_clicked_hotspot")
|
||||
|
||||
connect("mouse_entered", self, "_on_mouse_entered")
|
||||
connect("mouse_exited", self, "_on_mouse_exited")
|
||||
connect("input_event", self, "manage_input")
|
||||
init_interact_position_with_node()
|
||||
terrain = escoria.room_terrain
|
||||
|
||||
|
||||
update_terrain()
|
||||
|
||||
|
||||
func init_interact_position_with_node():
|
||||
"""
|
||||
Initialize the interact_position attribute by searching for a Position2D
|
||||
node in children nodes.
|
||||
If any is found, the first one is used as interaction position with this hotspot.
|
||||
If none is found, we use the CollisionShape2D or CollisionPolygon2D child node's
|
||||
position instead.
|
||||
"""
|
||||
for c in get_children():
|
||||
if c is Position2D:
|
||||
# If the position2D node is part of the hotspot, it means it is not an interact position
|
||||
# but a dialog position for example. Interact position node must be set in the room scene.
|
||||
if c.get_owner() == self:
|
||||
continue
|
||||
interact_positions.default = c.global_position
|
||||
break
|
||||
if c is CollisionShape2D or c is CollisionPolygon2D:
|
||||
interact_positions.default = c.global_position
|
||||
|
||||
|
||||
func manage_input(viewport : Viewport, event : InputEvent, shape_idx : int):
|
||||
if event is InputEventMouseButton:
|
||||
# var p = get_global_mouse_position()
|
||||
if event.doubleclick:
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_double_left_clicked_hotspot", global_id, event)
|
||||
else:
|
||||
if event.is_pressed():
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_left_clicked_hotspot", global_id, event)
|
||||
if event.button_index == BUTTON_RIGHT:
|
||||
emit_signal("mouse_right_clicked_hotspot", global_id, event)
|
||||
|
||||
|
||||
func _on_mouse_entered():
|
||||
emit_signal("mouse_entered_hotspot", global_id)
|
||||
|
||||
|
||||
func _on_mouse_exited():
|
||||
emit_signal("mouse_exited_hotspot")
|
||||
|
||||
|
||||
func get_item_child_if_any():
|
||||
for c in get_children():
|
||||
if c is ESCItem:
|
||||
return c
|
||||
|
||||
|
||||
func update_terrain(on_event_finished_name = null):
|
||||
if !terrain:
|
||||
return
|
||||
if on_event_finished_name != null and on_event_finished_name != "setup":
|
||||
return
|
||||
|
||||
var pos = position
|
||||
z_index = pos.y if pos.y <= VisualServer.CANVAS_ITEM_Z_MAX else VisualServer.CANVAS_ITEM_Z_MAX
|
||||
|
||||
var color
|
||||
if terrain_is_scalenodes:
|
||||
last_scale = terrain.get_terrain(pos)
|
||||
self.scale = last_scale
|
||||
elif check_maps:
|
||||
color = terrain.get_terrain(pos)
|
||||
var scal = terrain.get_scale_range(color.b)
|
||||
if scal != get_scale():
|
||||
last_scale = scal
|
||||
self.scale = last_scale
|
||||
|
||||
# Do not flip the entire player character, because that would conflict
|
||||
# with shadows that expect to be siblings of $"sprite"
|
||||
if pose_scale == -1 and $"sprite".scale.x > 0:
|
||||
$"sprite".scale.x *= pose_scale
|
||||
collision.scale.x *= pose_scale
|
||||
elif pose_scale == 1 and $"sprite".scale.x < 0:
|
||||
$"sprite".scale.x *= -1
|
||||
collision.scale.x *= -1
|
||||
|
||||
# if check_maps:
|
||||
# color = terrain.get_light(pos)
|
||||
#
|
||||
# if color:
|
||||
# for s in sprites:
|
||||
# s.set_modulate(color)
|
||||
123
addons/escoria-core/game/core-scripts/escitem.gd
Normal file
123
addons/escoria-core/game/core-scripts/escitem.gd
Normal file
@@ -0,0 +1,123 @@
|
||||
tool
|
||||
extends Sprite
|
||||
class_name ESCItem
|
||||
|
||||
func get_class():
|
||||
return "ESCItem"
|
||||
|
||||
"""
|
||||
ESCItem is a Sprite that defines an item, potentially interactive
|
||||
"""
|
||||
|
||||
signal mouse_entered_item(global_id)
|
||||
signal mouse_exited_item
|
||||
signal mouse_left_clicked_item(global_id)
|
||||
signal mouse_double_left_clicked_item(global_id)
|
||||
signal mouse_right_clicked_item(global_id)
|
||||
|
||||
export(String) var global_id
|
||||
export(String, FILE, "*.esc") var esc_script
|
||||
# If true, the ESC script may have an ":exit_scene" event to manage scene changes
|
||||
export(bool) var is_exit
|
||||
export(bool) var is_interactive = true
|
||||
export(bool) var player_orients_on_arrival = true
|
||||
export(ESCPlayer.Directions) var interaction_direction
|
||||
export(String) var tooltip_name
|
||||
export(String) var default_action
|
||||
# If action used by player is in the list, game will wait for a second click on another item
|
||||
# to combine objects together (typical USE <X> WITH <Y>, GIVE <X> TO <Y>)
|
||||
export(PoolStringArray) var combine_if_action_used_among = []
|
||||
# If true, combination must be done in the way it is written in ESC script
|
||||
# ie. :use ON_ITEM
|
||||
# If false, combination will be tried in the other way.
|
||||
export(bool) var combine_is_one_way = false
|
||||
# If use_from_inventory_only is true, then the object must have been picked up before using it.
|
||||
# A false value is useful for items in the background, such as buttons.
|
||||
export(bool) var use_from_inventory_only = false
|
||||
# Scene used in inventory for the object if it is picked up
|
||||
export(PackedScene) var inventory_item_scene_file : PackedScene
|
||||
|
||||
|
||||
export(Color) var dialog_color = ColorN("white")
|
||||
|
||||
# Animation node (null if none was found)
|
||||
var animation
|
||||
onready var interact_positions : Dictionary = { "default": null}
|
||||
|
||||
|
||||
# PRIVATE VARS
|
||||
var area : Area2D
|
||||
# Size of the item
|
||||
var size : Vector2
|
||||
|
||||
func _ready():
|
||||
|
||||
for n in get_children():
|
||||
if n is AnimationPlayer:
|
||||
animation = n
|
||||
continue
|
||||
if n is Area2D:
|
||||
area = n
|
||||
continue
|
||||
|
||||
if area:
|
||||
area.connect("mouse_entered", self, "_on_mouse_entered")
|
||||
area.connect("mouse_exited", self, "_on_mouse_exited")
|
||||
area.connect("input_event", self, "manage_input")
|
||||
|
||||
init_interact_position_with_node()
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
connect("mouse_entered_item", escoria.inputs_manager, "_on_mouse_entered_item")
|
||||
connect("mouse_exited_item", escoria.inputs_manager, "_on_mouse_exited_item")
|
||||
connect("mouse_left_clicked_item", escoria.inputs_manager, "_on_mouse_left_clicked_item")
|
||||
connect("mouse_double_left_clicked_item", escoria.inputs_manager, "_on_mouse_left_double_clicked_item")
|
||||
connect("mouse_right_clicked_item", escoria.inputs_manager, "_on_mouse_right_clicked_item")
|
||||
|
||||
|
||||
func get_animation_player():
|
||||
if animation == null:
|
||||
for n in get_children():
|
||||
if n is AnimationPlayer:
|
||||
animation = n
|
||||
return animation
|
||||
|
||||
|
||||
"""
|
||||
Initialize the interact_position attribute by searching for a Position2D
|
||||
node in children nodes.
|
||||
If any is found, the first one is used as interaction position with this hotspot.
|
||||
If none is found, we use the CollisionShape2D or CollisionPolygon2D child node's
|
||||
position instead.
|
||||
"""
|
||||
func init_interact_position_with_node():
|
||||
for c in get_children():
|
||||
if c is Position2D:
|
||||
interact_positions.default = c.global_position
|
||||
break
|
||||
if c is CollisionShape2D or c is CollisionPolygon2D:
|
||||
interact_positions.default = c.global_position
|
||||
if interact_positions.default == null:
|
||||
interact_positions.default = self.global_position
|
||||
|
||||
func manage_input(viewport : Viewport, event : InputEvent, shape_idx : int):
|
||||
if event is InputEventMouseButton:
|
||||
# var p = get_global_mouse_position()
|
||||
if event.doubleclick:
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_double_left_clicked_item", global_id, event)
|
||||
else:
|
||||
if event.is_pressed():
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_left_clicked_item", global_id, event)
|
||||
if event.button_index == BUTTON_RIGHT:
|
||||
emit_signal("mouse_right_clicked_item", global_id, event)
|
||||
|
||||
|
||||
func _on_mouse_entered():
|
||||
emit_signal("mouse_entered_item", global_id)
|
||||
|
||||
func _on_mouse_exited():
|
||||
emit_signal("mouse_exited_item")
|
||||
|
||||
86
addons/escoria-core/game/core-scripts/escoria_types.gd
Normal file
86
addons/escoria-core/game/core-scripts/escoria_types.gd
Normal file
@@ -0,0 +1,86 @@
|
||||
extends Node
|
||||
|
||||
const OBJ_DEFAULT_STATE = "default"
|
||||
|
||||
## Custom nodes:
|
||||
#var ESCBackground = preload("res://addons/escoria-core/game/core-scripts/escbackground.gd")
|
||||
#var ESCCharacter = preload("res://addons/escoria-core/game/core-scripts/esccharacter.gd")
|
||||
#var ESCHotspot = preload("res://addons/escoria-core/game/core-scripts/eschotspot.gd")
|
||||
#var ESCItem = preload("res://addons/escoria-core/game/core-scripts/escitem.gd")
|
||||
#var ESCItemsInventory = preload("res://addons/escoria-core/game/core-scripts/items_inventory.gd")
|
||||
#var ESCInventoryItem = preload("res://addons/escoria-core/game/core-scripts/inventory_item.gd")
|
||||
#var ESCPlayer = preload("res://addons/escoria-core/game/core-scripts/escplayer.gd")
|
||||
#var ESCRoom = preload("res://addons/escoria-core/game/core-scripts/escroom.gd")
|
||||
#var ESCTerrain = preload("res://addons/escoria-core/game/core-scripts/escterrain.gd")
|
||||
#var ESCTriggerZone = preload("res://addons/escoria-core/game/core-scripts/esctriggerzone.gd")
|
||||
|
||||
enum EVENT_LEVEL_STATE {
|
||||
RETURN, # 0
|
||||
YIELD, # 1
|
||||
BREAK, # 2
|
||||
REPEAT, # 3
|
||||
CALL, # 4
|
||||
JUMP # 5
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
ESCState is a helper class used to read ESC files. Once the ESC file is read and
|
||||
decoded into ESCEvents and ESCCommands, the ESCState instance is removed.
|
||||
"""
|
||||
class ESCState:
|
||||
var file # File or Dictionary
|
||||
var line # String, can be null
|
||||
var indent : int
|
||||
var line_count : int
|
||||
|
||||
func _init(p_file, p_line, p_indent, p_line_count):
|
||||
file = p_file
|
||||
line = p_line
|
||||
indent = p_indent
|
||||
line_count = p_line_count
|
||||
|
||||
func _to_string():
|
||||
return """ESCState: {
|
||||
file: """ + file + """,
|
||||
line: """ + line + """,
|
||||
indent: """ + indent + """,
|
||||
line_count: """ + line_count + """
|
||||
}"""
|
||||
|
||||
|
||||
class ESCEvent:
|
||||
var ev_name : String
|
||||
var ev_level : Array
|
||||
var ev_flags : Array
|
||||
|
||||
func _init(p_name, p_level, p_flags):
|
||||
ev_name = p_name
|
||||
ev_level = p_level
|
||||
ev_flags = p_flags
|
||||
|
||||
func _to_string():
|
||||
return """ESCEvent: {
|
||||
ev_name: """ + ev_name + """,
|
||||
ev_level: """ + String(ev_level) + """,
|
||||
ev_flags: """ + String(ev_flags) + """
|
||||
}"""
|
||||
|
||||
|
||||
class ESCCommand:
|
||||
var name : String
|
||||
var params : Array
|
||||
var conditions : Dictionary
|
||||
var flags : Array
|
||||
|
||||
func _init(p_name):
|
||||
name = p_name
|
||||
params = []
|
||||
|
||||
func _to_string():
|
||||
return """ESCCommand: {
|
||||
name: """ + name + """,
|
||||
params: """ + String(params) + """,
|
||||
conditions: """ + String(conditions) + """,
|
||||
flags: """ + String(flags) + """
|
||||
}"""
|
||||
401
addons/escoria-core/game/core-scripts/escplayer.gd
Normal file
401
addons/escoria-core/game/core-scripts/escplayer.gd
Normal file
@@ -0,0 +1,401 @@
|
||||
tool
|
||||
extends KinematicBody2D
|
||||
class_name ESCPlayer
|
||||
|
||||
func get_class():
|
||||
return "ESCPlayer"
|
||||
|
||||
signal arrived
|
||||
|
||||
export var global_id : String
|
||||
|
||||
var params_queue : Array
|
||||
var terrain : ESCTerrain
|
||||
var camera : ESCCamera
|
||||
|
||||
# If the terrain node type is scalenodes
|
||||
var terrain_is_scalenodes : bool
|
||||
var check_maps = true
|
||||
|
||||
var walk_path : Array = []
|
||||
var walk_destination : Vector2
|
||||
var walk_context
|
||||
var target_object : Object = null
|
||||
var moved : bool
|
||||
var path_ofs : float
|
||||
|
||||
export(int) var speed : int = 300
|
||||
export(float) var v_speed_damp : float = 1.0
|
||||
var orig_speed : float
|
||||
|
||||
enum PLAYER_TASKS {
|
||||
NONE,
|
||||
WALK,
|
||||
SLIDE
|
||||
}
|
||||
var task # type PLAYER_TASKS
|
||||
|
||||
# State machine defining the current interact state of the player
|
||||
enum INTERACT_STATES {
|
||||
INTERACT_STARTED, #
|
||||
INTERACT_NONE, #
|
||||
INTERACT_WALKING # Player is walking
|
||||
}
|
||||
var interact_status # Current interact status, type INTERACT_STATES
|
||||
|
||||
|
||||
enum Directions {
|
||||
NORTH = 0, # 0
|
||||
NORTHEAST = 1, # 1
|
||||
EAST = 2, # 2
|
||||
SOUTHEAST = 3, # 3
|
||||
SOUTH = 4, # 4
|
||||
SOUTHWEST = 5, # 5
|
||||
WEST = 6, # 6
|
||||
NORTHWEST = 7, # 7
|
||||
TOP = 0,
|
||||
TOP_RIGHT = 1
|
||||
RIGHT = 2,
|
||||
BOTTOM_RIGHT = 3,
|
||||
BOTTOM = 4,
|
||||
BOTTOM_LEFT = 5,
|
||||
LEFT = 6,
|
||||
TOP_LEFT = 7,
|
||||
}
|
||||
|
||||
var last_deg : int
|
||||
var last_dir : int
|
||||
var last_scale : Vector2
|
||||
var pose_scale : int
|
||||
|
||||
export(Script) var animations
|
||||
|
||||
# AnimatedSprite node (if any)
|
||||
var animation_sprite
|
||||
# AnimationPlayer node (if any)
|
||||
## NOT USED YET
|
||||
#var animation
|
||||
var collision
|
||||
|
||||
# Dialogs parameters
|
||||
export(NodePath) var dialog_position_node
|
||||
export(Color) var dialog_color = ColorN("white")
|
||||
|
||||
# Camera parameters
|
||||
export(NodePath) var camera_position_node
|
||||
|
||||
|
||||
func _ready():
|
||||
# Connect the player to the event_done signal, so we can react to a finished
|
||||
# ":setup" event. In this case, we need to run update_terrain()
|
||||
escoria.esc_runner.connect("event_done", self, "update_terrain")
|
||||
|
||||
# assert(is_angle_in_interval(0, [340,40])) # true
|
||||
# assert(is_angle_in_interval(359, [340,40])) # true
|
||||
# assert(is_angle_in_interval(1, [340,40])) # true
|
||||
# assert(!is_angle_in_interval(90, [340,40])) # false
|
||||
#
|
||||
# assert(is_angle_in_interval(90, [70,40])) #true
|
||||
# assert(!is_angle_in_interval(180, [70,40])) #false
|
||||
#
|
||||
# assert(is_angle_in_interval(179, [160, 40])) #true
|
||||
# assert(is_angle_in_interval(180, [160, 40])) #true
|
||||
# assert(is_angle_in_interval(181, [160, 40])) #true
|
||||
# assert(!is_angle_in_interval(0, [160, 40])) #false
|
||||
#
|
||||
# assert(is_angle_in_interval(270, [250, 40])) # true
|
||||
# assert(!is_angle_in_interval(270, [70,40])) #false
|
||||
|
||||
for n in get_children():
|
||||
if n is AnimatedSprite:
|
||||
animation_sprite = n
|
||||
|
||||
# for sprite_child in n.get_children():
|
||||
# if sprite_child is AnimationPlayer:
|
||||
# animation = sprite_child
|
||||
# break
|
||||
|
||||
if n is CollisionShape2D or n is CollisionPolygon2D:
|
||||
collision = n
|
||||
|
||||
animation_sprite.connect("animation_finished", self, "anim_finished")
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
terrain = escoria.room_terrain
|
||||
|
||||
last_scale = scale
|
||||
set_process(true)
|
||||
|
||||
|
||||
func _process(time):
|
||||
$debug.text = str(z_index)
|
||||
|
||||
if task == PLAYER_TASKS.WALK or task == PLAYER_TASKS.SLIDE:
|
||||
var pos = get_position()
|
||||
var old_pos = pos
|
||||
var next
|
||||
if walk_path.size() > 1:
|
||||
next = walk_path[path_ofs + 1]
|
||||
else:
|
||||
next = walk_path[path_ofs]
|
||||
|
||||
var dist = speed * time * pow(last_scale.x, 2) * terrain.player_speed_multiplier
|
||||
if walk_context and "fast" in walk_context and walk_context.fast:
|
||||
dist *= terrain.player_doubleclick_speed_multiplier
|
||||
var dir = (next - pos).normalized()
|
||||
|
||||
# assume that x^2 + y^2 == 1, apply v_speed_damp the y axis
|
||||
#printt("dir before", dir)
|
||||
dir = dir * (dir.x * dir.x + dir.y * dir.y * v_speed_damp)
|
||||
#printt("dir after", dir, dist)
|
||||
|
||||
var new_pos
|
||||
if pos.distance_to(next) < dist:
|
||||
new_pos = next
|
||||
path_ofs += 1
|
||||
else:
|
||||
new_pos = pos + dir * dist
|
||||
|
||||
if path_ofs >= walk_path.size() - 1:
|
||||
walk_stop(walk_destination)
|
||||
return
|
||||
|
||||
pos = new_pos
|
||||
|
||||
var angle = (old_pos.angle_to_point(pos))
|
||||
set_position(pos)
|
||||
|
||||
if task == PLAYER_TASKS.WALK:
|
||||
last_deg = escoria.utils._get_deg_from_rad(angle)
|
||||
last_dir = _get_dir_deg(last_deg, animations)
|
||||
|
||||
var current_animation = ""
|
||||
if animation_sprite != null:
|
||||
current_animation = animation_sprite.animation
|
||||
# elif animation != null:
|
||||
# current_animation = animation.current_animation
|
||||
|
||||
if current_animation != animations.directions[last_dir][0]:
|
||||
animation_sprite.play(animations.directions[last_dir][0])
|
||||
|
||||
pose_scale = animations.directions[last_dir][1]
|
||||
|
||||
update_terrain()
|
||||
else:
|
||||
moved = false
|
||||
set_process(false)
|
||||
|
||||
|
||||
func update_terrain(on_event_finished_name = null):
|
||||
if !terrain:
|
||||
return
|
||||
if on_event_finished_name != null and on_event_finished_name != "setup":
|
||||
return
|
||||
|
||||
var pos = position
|
||||
z_index = pos.y if pos.y <= VisualServer.CANVAS_ITEM_Z_MAX else VisualServer.CANVAS_ITEM_Z_MAX
|
||||
|
||||
var color
|
||||
if terrain_is_scalenodes:
|
||||
last_scale = terrain.get_terrain(pos)
|
||||
self.scale = last_scale
|
||||
elif check_maps:
|
||||
color = terrain.get_terrain(pos)
|
||||
var scal = terrain.get_scale_range(color.b)
|
||||
if scal != get_scale():
|
||||
last_scale = scal
|
||||
self.scale = last_scale
|
||||
|
||||
# Do not flip the entire player character, because that would conflict
|
||||
# with shadows that expect to be siblings of $"sprite"
|
||||
if pose_scale == -1 and $"sprite".scale.x > 0:
|
||||
$"sprite".scale.x *= pose_scale
|
||||
collision.scale.x *= pose_scale
|
||||
elif pose_scale == 1 and $"sprite".scale.x < 0:
|
||||
$"sprite".scale.x *= -1
|
||||
collision.scale.x *= -1
|
||||
|
||||
# if check_maps:
|
||||
# color = terrain.get_light(pos)
|
||||
#
|
||||
# if color:
|
||||
# for s in sprites:
|
||||
# s.set_modulate(color)
|
||||
|
||||
# Sets player angle and plays according animation.
|
||||
func set_angle(deg):
|
||||
if deg < 0 or deg > 360:
|
||||
escoria.report_errors("player.gd:set_angle()", ["Invalid degree to turn to " + str(deg)])
|
||||
moved = true
|
||||
last_deg = deg
|
||||
last_dir = _get_dir_deg(deg, animations)
|
||||
|
||||
# The player may have a state animation from before, which would be
|
||||
# resumed, so we immediately force the correct idle animation
|
||||
if animation_sprite.animation != animations.idles[last_dir][0]:
|
||||
animation_sprite.play(animations.idles[last_dir][0])
|
||||
pose_scale = animations.idles[last_dir][1]
|
||||
update_terrain()
|
||||
|
||||
|
||||
func teleport(target, angle : Object = null) -> void:
|
||||
"""
|
||||
Teleports the player on target position.
|
||||
target can be Vector2 or Object
|
||||
"""
|
||||
if typeof(target) == TYPE_VECTOR2:
|
||||
printt("Player teleported at position", target, "with angle", angle)
|
||||
position = target
|
||||
elif typeof(target) == TYPE_OBJECT:
|
||||
if target.get("interact_positions") != null:
|
||||
position = target.interact_positions.default #.global_position
|
||||
else:
|
||||
position = target.position
|
||||
printt("Player teleported at", target.name, "position", position, "with angle", angle)
|
||||
else:
|
||||
escoria.report_errors("escplayer.gd", ["target to teleport player to is null or unusable (" + target + ")"])
|
||||
|
||||
# PUBLIC FUNCTION
|
||||
func walk_to(pos : Vector2, p_walk_context = null):
|
||||
if not terrain:
|
||||
return walk_stop(get_position())
|
||||
|
||||
if interact_status == INTERACT_STATES.INTERACT_WALKING:
|
||||
return
|
||||
if interact_status == INTERACT_STATES.INTERACT_STARTED:
|
||||
interact_status = INTERACT_STATES.INTERACT_WALKING
|
||||
walk_path = terrain.get_terrain_path(get_position(), pos)
|
||||
walk_context = p_walk_context
|
||||
if walk_path.size() == 0:
|
||||
task = PLAYER_TASKS.NONE
|
||||
walk_stop(get_position())
|
||||
set_process(false)
|
||||
return
|
||||
moved = true
|
||||
walk_destination = walk_path[walk_path.size()-1]
|
||||
if terrain.is_solid(pos):
|
||||
walk_destination = walk_path[walk_path.size()-1]
|
||||
path_ofs = 0.0
|
||||
task = PLAYER_TASKS.WALK
|
||||
set_process(true)
|
||||
|
||||
# PRIVATE FUNCTION
|
||||
func walk(target_pos, p_speed, context = null):
|
||||
if p_speed:
|
||||
orig_speed = speed
|
||||
speed = p_speed
|
||||
walk_to(target_pos, context)
|
||||
|
||||
# PRIVATE FUNCTION
|
||||
func walk_stop(pos):
|
||||
position = pos
|
||||
interact_status = INTERACT_STATES.INTERACT_NONE
|
||||
walk_path = []
|
||||
|
||||
if orig_speed:
|
||||
speed = orig_speed
|
||||
orig_speed = 0.0
|
||||
|
||||
task = PLAYER_TASKS.NONE
|
||||
moved = false
|
||||
set_process(false)
|
||||
if params_queue != null && !params_queue.empty():
|
||||
if animations.dir_angles.size() > 0:
|
||||
if params_queue[0].interact_angle == -1:
|
||||
escoria.tools.resolve_angle_to(params_queue[0])
|
||||
else:
|
||||
last_dir = _get_dir_deg(params_queue[0].interact_angle, animations)
|
||||
animation_sprite.play(animations.idles[last_dir][0])
|
||||
pose_scale = animations.idles[last_dir][1]
|
||||
update_terrain()
|
||||
else:
|
||||
animation_sprite.play(animations.idles[last_dir][0])
|
||||
pose_scale = animations.idles[last_dir][1]
|
||||
get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFAULT, "game", "interact", params_queue)
|
||||
# Clear params queue to prevent the same action from being triggered again
|
||||
params_queue = []
|
||||
else:
|
||||
|
||||
# If we're heading to an object and reached its interaction position,
|
||||
# orient towards the defined interaction direction set on the object (if any)
|
||||
if walk_context.has("target_object") and walk_context.target_object.player_orients_on_arrival \
|
||||
and escoria.esc_runner.get_interactive(walk_context.target_object.global_id):
|
||||
var orientation = walk_context["target_object"].interaction_direction
|
||||
animation_sprite.play(animations.idles[orientation][0])
|
||||
pose_scale = animations.idles[orientation][1]
|
||||
else:
|
||||
animation_sprite.play(animations.idles[last_dir][0])
|
||||
pose_scale = animations.idles[last_dir][1]
|
||||
update_terrain()
|
||||
|
||||
if walk_context != null:
|
||||
escoria.esc_level_runner.finished(walk_context)
|
||||
walk_context = null
|
||||
emit_signal("arrived")
|
||||
|
||||
|
||||
func anim_finished():
|
||||
pass
|
||||
|
||||
|
||||
func get_camera_pos():
|
||||
if camera_position_node and get_node(camera_position_node):
|
||||
return get_node(camera_position_node).global_position
|
||||
return global_position
|
||||
|
||||
|
||||
func get_animations_list() -> PoolStringArray:
|
||||
return animation_sprite.get_sprite_frames().get_animation_names()
|
||||
|
||||
|
||||
func _get_dir(angle : float, animations) -> int:
|
||||
var deg = escoria.utils._get_deg_from_rad(angle)
|
||||
return _get_dir_deg(deg, animations)
|
||||
|
||||
|
||||
func _get_dir_deg(deg : int, animations) -> int:
|
||||
# We turn the angle by -90° because angle_to_point gives the angle against X axis, not Y
|
||||
deg = wrapi(deg - 90, 0, 360)
|
||||
var dir = -1
|
||||
var i = 0
|
||||
|
||||
for arr_angle_zone in animations.dir_angles:
|
||||
if is_angle_in_interval(deg, arr_angle_zone):
|
||||
dir = i
|
||||
break
|
||||
else:
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# It's an error to have the animations misconfigured
|
||||
if dir == -1:
|
||||
escoria.report_errors("player", ["No direction found for " + str(deg)])
|
||||
|
||||
return dir
|
||||
|
||||
|
||||
# Returns true if given angle is inside the interval given by a starting_angle and the size.
|
||||
# @param angle : Angle to test
|
||||
# @param: interval : Array of size 2, containing the starting angle, and the size of interval
|
||||
# eg: [90, 40] corresponds to angle between 90° and 130°
|
||||
func is_angle_in_interval(angle: float, interval : Array) -> bool:
|
||||
angle = wrapi(angle, 0, 360)
|
||||
if angle == 0:
|
||||
angle = 360
|
||||
var start_angle = wrapi(interval[0], 0, 360)
|
||||
var angle_area = interval[1]
|
||||
var end_angle = wrapi(interval[0] + angle_area, 0, 360)
|
||||
|
||||
if (angle >= 270 and angle <= 360) or (angle >= 0 and angle <= 90):
|
||||
if wrapi(angle+180, 0, 360) > wrapi(interval[0]+ 180, 0, 360) \
|
||||
&& wrapi(angle+180, 0, 360) <= wrapi(interval[0] + angle_area + 180, 0, 360):
|
||||
return true
|
||||
else:
|
||||
if wrapi(angle, 0, 360) > start_angle && wrapi(angle, 0, 360) <= end_angle:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
27
addons/escoria-core/game/core-scripts/escroom.gd
Normal file
27
addons/escoria-core/game/core-scripts/escroom.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
extends Node2D
|
||||
class_name ESCRoom
|
||||
|
||||
func get_class():
|
||||
return "ESCRoom"
|
||||
|
||||
export(String) var global_id = ""
|
||||
export(String, FILE, "*.esc") var esc_script = ""
|
||||
export(PackedScene) var player_scene
|
||||
export(Rect2) var camera_limits = Rect2()
|
||||
var player
|
||||
onready var game = $game
|
||||
|
||||
func _ready():
|
||||
|
||||
if player_scene:
|
||||
player = player_scene.instance()
|
||||
add_child(player)
|
||||
escoria.register_object(player)
|
||||
game.get_node("camera").set_target(player)
|
||||
|
||||
if has_node("player_start"):
|
||||
escoria.register_object($player_start)
|
||||
|
||||
if global_id.empty():
|
||||
global_id = name
|
||||
|
||||
63
addons/escoria-core/game/core-scripts/escterrain.gd
Normal file
63
addons/escoria-core/game/core-scripts/escterrain.gd
Normal file
@@ -0,0 +1,63 @@
|
||||
tool
|
||||
extends "res://addons/escoria-core/game/core-scripts/escterrain_base.gd"
|
||||
class_name ESCTerrain
|
||||
|
||||
func get_class():
|
||||
return "ESCTerrain"
|
||||
|
||||
export var scale_min = 0.3
|
||||
export var scale_max = 1.0
|
||||
|
||||
var current_active_navigation_instance : NavigationPolygonInstance
|
||||
|
||||
func _ready():
|
||||
var navigation_enabled_found = false
|
||||
for n in get_children():
|
||||
if n is NavigationPolygonInstance:
|
||||
if n.enabled:
|
||||
if navigation_enabled_found:
|
||||
escoria.report_errors("escterrain.gd:_ready()", ["Multiple NavigationPolygonInstances enabled at the same time."])
|
||||
navigation_enabled_found = true
|
||||
current_active_navigation_instance = n
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
#path = ImagePathFinder.new()
|
||||
_update_texture()
|
||||
|
||||
func get_scale_range(r):
|
||||
r = scale_min + (scale_max - scale_min) * r
|
||||
return Vector2(r, r)
|
||||
|
||||
func get_terrain(pos):
|
||||
if scales == null || scales.get_data().is_empty():
|
||||
return Color(1, 1, 1, 1)
|
||||
return get_pixel(pos, scales.get_data())
|
||||
|
||||
func get_pixel(pos, p_image):
|
||||
if pos.x + 1 >= p_image.get_width() || pos.y + 1 >= p_image.get_height() || pos.x < 0 || pos.y < 0:
|
||||
return Color(1.0, 0.0, 0.0)
|
||||
|
||||
# `get_pixel()` is slow; this is accurate enough
|
||||
# without interpolating neighboring pixels and accounting for fractions
|
||||
p_image.lock()
|
||||
var pixel = p_image.get_pixel(pos.x, pos.y)
|
||||
p_image.unlock()
|
||||
return pixel
|
||||
|
||||
func _draw():
|
||||
if typeof(texture) == typeof(null):
|
||||
return
|
||||
if !Engine.is_editor_hint():
|
||||
return
|
||||
if debug_mode == 0:
|
||||
return
|
||||
var scale_vect = bitmaps_scale
|
||||
|
||||
var src = Rect2(0, 0, texture.get_width(), texture.get_height())
|
||||
var dst = Rect2(0, 0, texture.get_width() * scale_vect.x, texture.get_height() * scale_vect.y)
|
||||
|
||||
draw_texture_rect_region(texture, dst, src)
|
||||
#draw_texture(texture, Vector2(0, 0))
|
||||
|
||||
|
||||
177
addons/escoria-core/game/core-scripts/escterrain_base.gd
Normal file
177
addons/escoria-core/game/core-scripts/escterrain_base.gd
Normal file
@@ -0,0 +1,177 @@
|
||||
tool
|
||||
extends Navigation2D
|
||||
|
||||
export(Texture) var scales setget set_scales,get_scales
|
||||
export var bitmaps_scale = Vector2(1,1) setget set_bm_scale,get_bm_scale
|
||||
export(Texture) var lightmap setget set_lightmap,get_lightmap
|
||||
var lightmap_data
|
||||
|
||||
#warning-ignore:unused_class_variable
|
||||
export var player_speed_multiplier = 1.0 # Override player speed in current scene
|
||||
#warning-ignore:unused_class_variable
|
||||
export var player_doubleclick_speed_multiplier = 1.5 # Make the player move faster when doubleclicked
|
||||
export var lightmap_modulate = Color(1, 1, 1, 1)
|
||||
export(int, "None", "Scales", "Lightmap") var debug_mode = 1 setget debug_mode_updated
|
||||
|
||||
var texture
|
||||
var img_area
|
||||
var _texture_dirty = false
|
||||
|
||||
func set_bm_scale(p_scale):
|
||||
bitmaps_scale = p_scale
|
||||
_update_texture()
|
||||
|
||||
func get_bm_scale():
|
||||
return bitmaps_scale
|
||||
|
||||
func set_lightmap(p_lightmap):
|
||||
var need_init = (lightmap != p_lightmap) or (lightmap and not lightmap_data)
|
||||
|
||||
lightmap = p_lightmap
|
||||
|
||||
# It's bad enough a new copy is created when reading a pixel, we don't
|
||||
# also need to get the data for every read to make yet another copy
|
||||
if need_init:
|
||||
if lightmap_data:
|
||||
lightmap_data.unlock()
|
||||
lightmap_data = lightmap.get_data()
|
||||
lightmap_data.lock()
|
||||
|
||||
_update_texture()
|
||||
|
||||
func get_lightmap():
|
||||
return lightmap
|
||||
|
||||
func set_scales(p_scales):
|
||||
scales = p_scales
|
||||
_update_texture()
|
||||
|
||||
func get_scales():
|
||||
return scales
|
||||
|
||||
func debug_mode_updated(p_mode):
|
||||
debug_mode = p_mode
|
||||
_update_texture()
|
||||
|
||||
func _update_texture():
|
||||
if _texture_dirty:
|
||||
return
|
||||
|
||||
_texture_dirty = true
|
||||
call_deferred("_do_update_texture")
|
||||
|
||||
func _do_update_texture():
|
||||
_texture_dirty = false
|
||||
if !is_inside_tree():
|
||||
return
|
||||
if !Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if debug_mode == 0:
|
||||
update()
|
||||
return
|
||||
|
||||
texture = ImageTexture.new()
|
||||
if debug_mode == 1:
|
||||
if scales != null:
|
||||
#texture.create_from_image(scales)
|
||||
texture = scales
|
||||
else:
|
||||
if lightmap != null:
|
||||
#texture.create_from_image(lightmap)
|
||||
texture = lightmap
|
||||
|
||||
update()
|
||||
|
||||
|
||||
|
||||
func make_local(pos):
|
||||
pos = pos - get_position()
|
||||
pos = pos * 1.0 / get_scale()
|
||||
pos = get_closest_point(pos)
|
||||
return pos
|
||||
|
||||
func make_global(pos):
|
||||
pos = pos * get_scale()
|
||||
pos = pos + get_position()
|
||||
return pos
|
||||
|
||||
func get_terrain_path(p_src, p_dest):
|
||||
# printt("get path ", p_src, p_dest)
|
||||
p_src = make_local(p_src)
|
||||
p_dest = make_local(p_dest)
|
||||
|
||||
var r_path = get_simple_path(p_src, p_dest, true)
|
||||
r_path = Array(r_path)
|
||||
for i in range(0, r_path.size()):
|
||||
r_path[i] = make_global(r_path[i])
|
||||
return r_path
|
||||
|
||||
func is_solid(pos):
|
||||
pos = pos - get_position()
|
||||
pos = pos * 1.0 / get_scale()
|
||||
|
||||
var closest = get_closest_point(pos)
|
||||
return pos == closest
|
||||
|
||||
func _color_mul(a, b):
|
||||
var c = Color()
|
||||
c.r = a.r * b.r
|
||||
c.g = a.g * b.g
|
||||
c.b = a.b * b.b
|
||||
c.a = a.a * b.a
|
||||
return c
|
||||
|
||||
func get_light(pos):
|
||||
if not lightmap or lightmap.get_data().is_empty():
|
||||
return
|
||||
|
||||
return _color_mul(get_pixel(pos, lightmap_data), lightmap_modulate)
|
||||
|
||||
func get_pixel(pos, p_image):
|
||||
p_image.lock()
|
||||
|
||||
pos = make_local(pos)
|
||||
pos = pos * 1.0 / bitmaps_scale
|
||||
|
||||
if pos.x + 1 >= p_image.get_width() || pos.y + 1 >= p_image.get_height() || pos.x < 0 || pos.y < 0:
|
||||
return Color()
|
||||
|
||||
var ll = p_image.get_pixel(pos.x, pos.y)
|
||||
var ndif = Vector2()
|
||||
ndif.x = pos.x - floor(pos.x)
|
||||
ndif.y = pos.y - floor(pos.y)
|
||||
var ur
|
||||
|
||||
img_area = Rect2(0, 0, p_image.get_width(), p_image.get_height())
|
||||
|
||||
var lr = ll
|
||||
if ndif.x > 0 && img_area.has_point(Vector2(pos.x+1, pos.y)):
|
||||
lr = p_image.get_pixel(pos.x+1, pos.y)
|
||||
#if lr.a < 128:
|
||||
# lr = ll
|
||||
ur = lr
|
||||
|
||||
var ul = ll
|
||||
if ndif.y > 0 && img_area.has_point(Vector2(pos.x, pos.y+1)):
|
||||
ul = p_image.get_pixel(pos.x, pos.y+1)
|
||||
#if ul.a < 128:
|
||||
# ul = ll
|
||||
ur = ul
|
||||
|
||||
if ndif.x > 0 && ndif.y > 0 && img_area.has_point(Vector2(pos.x+1, pos.y+1)):
|
||||
var pix = p_image.get_pixel(pos.x+1, pos.y+1)
|
||||
#if pix.a > 128:
|
||||
ur = pix
|
||||
|
||||
var bottom = ll.linear_interpolate(lr, ndif.x)
|
||||
var top
|
||||
if ur != null:
|
||||
top = ul.linear_interpolate(ur, ndif.x)
|
||||
else:
|
||||
top = ul
|
||||
|
||||
var final = bottom.linear_interpolate(top, ndif.y)
|
||||
|
||||
p_image.unlock()
|
||||
return final
|
||||
@@ -0,0 +1,92 @@
|
||||
tool
|
||||
|
||||
extends "terrain_base.gd"
|
||||
|
||||
const DIST_EPSILON = 0.000001
|
||||
|
||||
var scale_nodes = []
|
||||
|
||||
onready var scale_min = $"scale_min"
|
||||
onready var scale_max = $"scale_max"
|
||||
|
||||
func debug_mode_updated(p_mode):
|
||||
debug_mode = p_mode
|
||||
|
||||
._update_texture()
|
||||
|
||||
func _do_update_texture():
|
||||
_texture_dirty = false
|
||||
if !is_inside_tree():
|
||||
return
|
||||
if !Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if debug_mode == 0:
|
||||
update()
|
||||
return
|
||||
|
||||
texture = ImageTexture.new()
|
||||
|
||||
if lightmap != null:
|
||||
#texture.create_from_image(lightmap)
|
||||
texture = lightmap
|
||||
|
||||
update()
|
||||
|
||||
static func sort_by_y(a, b):
|
||||
return a.global_position.y < b.global_position.y
|
||||
|
||||
# Return a "scale range" immediately based on the interpolated scale size
|
||||
func get_terrain(pos):
|
||||
# printt("Called", pos)
|
||||
var prev
|
||||
var next
|
||||
var prev_target
|
||||
var node_target
|
||||
for i in range(1, scale_nodes.size()):
|
||||
prev = scale_nodes[i - 1]
|
||||
next = scale_nodes[i]
|
||||
|
||||
if prev.global_position.y < pos.y and pos.y < next.global_position.y:
|
||||
# printt("1:", prev.global_position.y, " < ", pos.y, " and ", pos.y, " < ", next.global_position.y)
|
||||
prev_target = prev.target_scale.y
|
||||
node_target = next.target_scale.y
|
||||
break
|
||||
|
||||
var nodes_dist = next.global_position.y - prev.global_position.y
|
||||
if nodes_dist < DIST_EPSILON:
|
||||
nodes_dist = DIST_EPSILON
|
||||
var interp_dist = (pos.y - prev.global_position.y) / nodes_dist
|
||||
|
||||
var y_1 = Vector2(0, prev_target)
|
||||
var y_2 = Vector2(0, node_target)
|
||||
|
||||
var interp = y_1.linear_interpolate(y_2, interp_dist)
|
||||
|
||||
return Vector2(interp.y, interp.y)
|
||||
|
||||
func get_pixel(pos, p_image):
|
||||
if pos.x + 1 >= p_image.get_width() || pos.y + 1 >= p_image.get_height() || pos.x < 0 || pos.y < 0:
|
||||
return Color(1.0, 0.0, 0.0)
|
||||
|
||||
# `get_pixel()` is slow; this is accurate enough
|
||||
# without interpolating neighboring pixels and accounting for fractions
|
||||
return p_image.get_pixel(pos.x, pos.y)
|
||||
|
||||
func _draw():
|
||||
if not texture:
|
||||
return
|
||||
|
||||
if debug_mode == 0:
|
||||
return
|
||||
|
||||
draw_texture(texture, Vector2(0, 0))
|
||||
|
||||
func _ready():
|
||||
for c in get_children():
|
||||
if c is preload("scalenode.gd"):
|
||||
scale_nodes.push_back(c)
|
||||
|
||||
scale_nodes.sort_custom(self, "sort_by_y")
|
||||
scale_nodes.push_front(scale_min)
|
||||
scale_nodes.push_back(scale_max)
|
||||
31
addons/escoria-core/game/core-scripts/esctriggerzone.gd
Normal file
31
addons/escoria-core/game/core-scripts/esctriggerzone.gd
Normal file
@@ -0,0 +1,31 @@
|
||||
tool
|
||||
extends Area2D
|
||||
class_name ESCTriggerZone
|
||||
|
||||
signal left_click_on_trigger
|
||||
signal left_dblclick_on_trigger
|
||||
signal right_click_on_trigger
|
||||
signal mouse_enter_trigger
|
||||
signal mouse_exit_trigger
|
||||
|
||||
func mouse_enter():
|
||||
emit_signal("mouse_enter_trigger", self)
|
||||
|
||||
func mouse_exit():
|
||||
emit_signal("mouse_exit_trigger", self)
|
||||
|
||||
func body_entered(body):
|
||||
# if body is esc_type.PLAYER:
|
||||
# if self.visible:
|
||||
# run_event("enter")
|
||||
pass
|
||||
|
||||
func body_exited(body):
|
||||
# if body is esc_type.PLAYER:
|
||||
# if self.visible:
|
||||
# run_event("exit")
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
41
addons/escoria-core/game/core-scripts/inventory_item.gd
Normal file
41
addons/escoria-core/game/core-scripts/inventory_item.gd
Normal file
@@ -0,0 +1,41 @@
|
||||
extends TextureButton
|
||||
class_name ESCInventoryItem
|
||||
|
||||
func get_class():
|
||||
return "ESCInventoryItem"
|
||||
|
||||
export(String) var global_id
|
||||
#export(String, FILE, "*.esc") var esc_script
|
||||
|
||||
signal mouse_left_inventory_item(item_id)
|
||||
signal mouse_right_inventory_item(item_id)
|
||||
signal mouse_double_left_inventory_item(item_id)
|
||||
signal inventory_item_focused(item_id)
|
||||
signal inventory_item_unfocused()
|
||||
|
||||
|
||||
func _ready():
|
||||
connect("gui_input", self, "_on_inventory_item_gui_input")
|
||||
connect("mouse_entered", self, "_on_inventory_item_mouse_enter")
|
||||
connect("mouse_exited", self, "_on_inventory_item_mouse_exit")
|
||||
|
||||
func _on_inventory_item_gui_input(event : InputEvent):
|
||||
if event is InputEventMouseButton:
|
||||
# var p = get_global_mouse_position()
|
||||
if event.doubleclick:
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_double_left_inventory_item", global_id, event)
|
||||
else:
|
||||
if event.is_pressed():
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_left_inventory_item", global_id, event)
|
||||
if event.button_index == BUTTON_RIGHT:
|
||||
emit_signal("mouse_right_inventory_item", global_id, event)
|
||||
|
||||
func _on_inventory_item_mouse_enter():
|
||||
# Notify UI that item is focused (room.game.ui.Label UI)
|
||||
emit_signal("inventory_item_focused", global_id)
|
||||
|
||||
func _on_inventory_item_mouse_exit():
|
||||
# Notify UI that item is unfocused (room.game.ui.Label UI)
|
||||
emit_signal("inventory_item_unfocused")
|
||||
9
addons/escoria-core/game/core-scripts/items_inventory.gd
Normal file
9
addons/escoria-core/game/core-scripts/items_inventory.gd
Normal file
@@ -0,0 +1,9 @@
|
||||
extends Node
|
||||
|
||||
|
||||
func get_inventory_item(item_id : String) -> ESCInventoryItem:
|
||||
for c in get_children():
|
||||
if c.global_id == item_id:
|
||||
if c.inventory_item_scene_file:
|
||||
return c.inventory_item_scene_file.instance()
|
||||
return null
|
||||
9
addons/escoria-core/game/core-scripts/log/logging.gd
Normal file
9
addons/escoria-core/game/core-scripts/log/logging.gd
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
func warning(string : String):
|
||||
printerr("(W)\t" + string)
|
||||
|
||||
func info(string : String):
|
||||
print("(I)\t" + string)
|
||||
|
||||
func error(string : String):
|
||||
printerr("(E)\t" + string)
|
||||
69
addons/escoria-core/game/core-scripts/old/background.gd
Normal file
69
addons/escoria-core/game/core-scripts/old/background.gd
Normal file
@@ -0,0 +1,69 @@
|
||||
extends Sprite
|
||||
|
||||
signal left_click_on_bg
|
||||
signal right_click_on_bg # Connect this in your game/signal_script
|
||||
|
||||
export var action = "walk"
|
||||
var area
|
||||
|
||||
# Godot doesn't do doubleclicks so we must
|
||||
var last_lmb_dt = 0
|
||||
var waiting_dblclick = null # null or [pos, event]
|
||||
|
||||
func input(_viewport, event, _shape_idx):
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
# If we are hovering items, do not allow background to receive a click
|
||||
# and let the items sort out who's on top and gets to be `clicked`
|
||||
if vm.hover_stack:
|
||||
return
|
||||
|
||||
if event.is_action("game_general"):
|
||||
last_lmb_dt = 0
|
||||
waiting_dblclick = [get_global_mouse_position(), event]
|
||||
elif event.is_action("game_rmb"):
|
||||
emit_signal("right_click_on_bg", self, get_global_mouse_position(), event)
|
||||
|
||||
func get_action():
|
||||
return action
|
||||
|
||||
func _physics_process(dt):
|
||||
last_lmb_dt += dt
|
||||
|
||||
if waiting_dblclick and last_lmb_dt > vm.DOUBLECLICK_TIMEOUT:
|
||||
emit_signal("left_click_on_bg", self, waiting_dblclick[0], waiting_dblclick[1])
|
||||
last_lmb_dt = 0
|
||||
waiting_dblclick = null
|
||||
|
||||
func _enter_tree():
|
||||
# Use size of background texture to calculate collision shape
|
||||
var size = get_texture().get_size()
|
||||
|
||||
area = Area2D.new()
|
||||
var shape = RectangleShape2D.new()
|
||||
|
||||
var sid = area.create_shape_owner(area)
|
||||
|
||||
# Move origin of Area2D to center of Sprite
|
||||
var transform = area.shape_owner_get_transform(sid)
|
||||
transform.origin = size / 2
|
||||
area.shape_owner_set_transform(sid, transform)
|
||||
|
||||
# Set extents of RectangleShape2D to cover entire Sprite
|
||||
shape.set_extents(size / 2)
|
||||
area.shape_owner_add_shape(sid, shape)
|
||||
|
||||
add_child(area)
|
||||
|
||||
func _ready():
|
||||
var conn_err
|
||||
|
||||
conn_err = area.connect("input_event", self, "input")
|
||||
if conn_err:
|
||||
vm.report_errors("item", ["area.input_event -> input error: " + String(conn_err)])
|
||||
|
||||
conn_err = connect("left_click_on_bg", $"/root/scene/game", "ev_left_click_on_bg")
|
||||
if conn_err:
|
||||
vm.report_errors("item", ["left_click_on_bg -> ev_left_click_on_bg error: " + String(conn_err)])
|
||||
|
||||
add_to_group("background")
|
||||
|
||||
5
addons/escoria-core/game/core-scripts/old/scalenode.gd
Normal file
5
addons/escoria-core/game/core-scripts/old/scalenode.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Position2D
|
||||
|
||||
#warning-ignore:unused_class_variable
|
||||
export(Vector2) var target_scale = Vector2(1.0, 1.0)
|
||||
|
||||
191
addons/escoria-core/game/core-scripts/resource_queue.gd
Normal file
191
addons/escoria-core/game/core-scripts/resource_queue.gd
Normal file
@@ -0,0 +1,191 @@
|
||||
var thread : Thread
|
||||
var mutex : Mutex
|
||||
var sem : Semaphore
|
||||
|
||||
#warning-ignore:unused_class_variable
|
||||
var time_max = 100 # msec
|
||||
|
||||
var queue : Array = []
|
||||
var pending : Dictionary = {}
|
||||
|
||||
signal resource_loading_progress(path, progress)
|
||||
signal resource_loading_done(path)
|
||||
signal resource_queue_progress(queue_size)
|
||||
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _lock(caller):
|
||||
mutex.lock()
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _unlock(caller):
|
||||
mutex.unlock()
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _post(caller):
|
||||
sem.post()
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _wait(caller):
|
||||
sem.wait()
|
||||
|
||||
|
||||
func queue_resource(path : String, p_in_front : bool = false, p_permanent : bool = false):
|
||||
_lock("queue_resource")
|
||||
if path in pending:
|
||||
_unlock("queue_resource")
|
||||
return
|
||||
|
||||
elif ResourceLoader.has(path):
|
||||
var res = ResourceLoader.load(path)
|
||||
pending[path] = { "res": res, "permanent": p_permanent }
|
||||
_unlock("queue_resource")
|
||||
return
|
||||
else:
|
||||
var res = ResourceLoader.load_interactive(path)
|
||||
res.set_meta("path", path)
|
||||
if p_in_front:
|
||||
queue.insert(0, res)
|
||||
else:
|
||||
queue.push_back(res)
|
||||
pending[path] = { "res": res, "permanent": p_permanent }
|
||||
_post("queue_resource")
|
||||
_unlock("queue_resource")
|
||||
return
|
||||
|
||||
func cancel_resource(path):
|
||||
_lock("cancel_resource")
|
||||
if path in pending:
|
||||
if pending[path].res is ResourceInteractiveLoader:
|
||||
queue.erase(pending[path].res)
|
||||
pending.erase(path)
|
||||
_unlock("cancel_resource")
|
||||
|
||||
func clear():
|
||||
_lock("clear")
|
||||
|
||||
for p in pending.keys():
|
||||
if pending[p].permanent:
|
||||
continue
|
||||
cancel_resource(p)
|
||||
#queue = []
|
||||
#pending = {}
|
||||
|
||||
_unlock("clear")
|
||||
|
||||
|
||||
func get_progress(path):
|
||||
_lock("get_progress")
|
||||
var ret = -1
|
||||
if path in pending:
|
||||
if pending[path].res is ResourceInteractiveLoader:
|
||||
ret = float(pending[path].res.get_stage()) / float(pending[path].res.get_stage_count())
|
||||
else:
|
||||
ret = 1.0
|
||||
emit_signal("resource_loading_done", path)
|
||||
emit_signal("resource_loading_progress", path, ret)
|
||||
_unlock("get_progress")
|
||||
|
||||
return ret
|
||||
|
||||
func is_ready(path):
|
||||
var ret
|
||||
_lock("is_ready")
|
||||
if path in pending:
|
||||
ret = !(pending[path].res is ResourceInteractiveLoader)
|
||||
else:
|
||||
ret = false
|
||||
|
||||
_unlock("is_ready")
|
||||
|
||||
return ret
|
||||
|
||||
func _wait_for_resource(res, path):
|
||||
_unlock("wait_for_resource")
|
||||
while true:
|
||||
#VisualServer.call("sync") # workaround because sync is a keyword
|
||||
VisualServer.force_sync()
|
||||
OS.delay_usec(16000) # wait 1 frame
|
||||
_lock("wait_for_resource")
|
||||
if queue.size() == 0 || queue[0] != res:
|
||||
return pending[path].res
|
||||
_unlock("wait_for_resource")
|
||||
|
||||
|
||||
func get_resource(path):
|
||||
_lock("get_resource")
|
||||
if path in pending:
|
||||
if pending[path].res is ResourceInteractiveLoader:
|
||||
var res = pending[path].res
|
||||
if res != queue[0]:
|
||||
var pos = queue.find(res)
|
||||
queue.remove(pos)
|
||||
queue.insert(0, res)
|
||||
|
||||
res = _wait_for_resource(res, path)
|
||||
|
||||
if !pending[path].permanent:
|
||||
pending.erase(path)
|
||||
_unlock("return")
|
||||
return res
|
||||
|
||||
else:
|
||||
var res = pending[path].res
|
||||
if !pending[path].permanent:
|
||||
pending.erase(path)
|
||||
_unlock("return")
|
||||
return res
|
||||
else:
|
||||
_unlock("return")
|
||||
return ResourceLoader.load(path)
|
||||
|
||||
func thread_process():
|
||||
_wait("thread_process")
|
||||
|
||||
_lock("process")
|
||||
|
||||
while queue.size() > 0:
|
||||
var res = queue[0]
|
||||
|
||||
_unlock("process_poll")
|
||||
var ret = res.poll()
|
||||
_lock("process_check_queue")
|
||||
|
||||
var path = res.get_meta("path")
|
||||
if ret == ERR_FILE_EOF || ret != OK:
|
||||
printt("finished loading ", path)
|
||||
if path in pending: # else it was already retrieved
|
||||
pending[res.get_meta("path")].res = res.get_resource()
|
||||
|
||||
queue.erase(res) # something might have been put at the front of the queue while we polled, so use erase instead of remove
|
||||
emit_signal("resource_queue_progress", queue.size())
|
||||
|
||||
get_progress(path)
|
||||
|
||||
_unlock("process")
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func thread_func(u):
|
||||
while true:
|
||||
thread_process()
|
||||
|
||||
func print_progress(p_path, p_progress):
|
||||
printt(p_path, "loading", round(p_progress * 100), "%")
|
||||
|
||||
func res_loaded(p_path):
|
||||
printt("loaded resource", p_path)
|
||||
|
||||
func print_queue_progress(p_queue_size):
|
||||
printt("queue size:", p_queue_size)
|
||||
|
||||
func start():
|
||||
mutex = Mutex.new()
|
||||
sem = Semaphore.new()
|
||||
thread = Thread.new()
|
||||
thread.start(self, "thread_func", 0)
|
||||
|
||||
|
||||
## Uncomment these for debug, or wait for someone to implement log levels
|
||||
# connect("resource_loading_progress", self, "print_progress")
|
||||
# connect("resource_loading_done", self, "res_loaded")
|
||||
# connect("resource_queue_progress", self, "print_queue_progress")
|
||||
202
addons/escoria-core/game/core-scripts/save_data/save_data.gd
Normal file
202
addons/escoria-core/game/core-scripts/save_data/save_data.gd
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
const DATA_STRING = 0
|
||||
const DATA_STRING_ARRAY = 1
|
||||
const DATA_VARIANT = 2
|
||||
|
||||
var base = "user://esc_saves"
|
||||
var slots = {}
|
||||
var max_slots = 3
|
||||
var settings
|
||||
|
||||
func save_settings(p_data, p_callback):
|
||||
var f = File.new()
|
||||
f.open("user://settings.bin", File.WRITE)
|
||||
f.store_var(p_data)
|
||||
f.close()
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], OK)
|
||||
|
||||
return OK
|
||||
|
||||
func load_settings(p_callback):
|
||||
var f = File.new()
|
||||
f.open("user://settings.bin", File.READ)
|
||||
if !f.is_open():
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], null)
|
||||
return FAILED
|
||||
|
||||
settings = f.get_var()
|
||||
f.close()
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], settings)
|
||||
|
||||
return OK
|
||||
|
||||
func _get_fname(p_slot):
|
||||
|
||||
var date = OS.get_date()
|
||||
var time = OS.get_time()
|
||||
|
||||
var day = str(date.day)
|
||||
if date.day < 10:
|
||||
day = "0"+day
|
||||
|
||||
|
||||
var hour = str(time.hour)
|
||||
if time.hour < 10:
|
||||
hour = "0"+hour
|
||||
|
||||
var minute = str(time.minute)
|
||||
if time.minute < 10:
|
||||
minute = "0"+minute
|
||||
|
||||
var second = str(time.second)
|
||||
if time.second < 10:
|
||||
second = "0"+second
|
||||
|
||||
var fname = str(p_slot) + "-"
|
||||
fname = fname + day + "-" + str(date.month) + "-" + str(date.year) + " " + hour+"."+minute+"."+second+".esc"
|
||||
|
||||
return fname
|
||||
|
||||
|
||||
func save_game(p_data, p_slot, p_callback):
|
||||
|
||||
if p_slot < 0 || p_slot >= max_slots:
|
||||
return FAILED
|
||||
|
||||
var fname = _get_fname(p_slot)
|
||||
var ret = _do_save(base + "/" + fname, p_data)
|
||||
if ret != OK:
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], FAILED)
|
||||
return FAILED
|
||||
|
||||
if p_slot in slots:
|
||||
var old_fname = slots[p_slot].fname
|
||||
var d = Directory.new()
|
||||
d.open(base)
|
||||
d.remove(old_fname)
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], OK)
|
||||
return OK
|
||||
|
||||
func _do_save(fname, p_data):
|
||||
var f = File.new()
|
||||
var ret = f.open(fname, File.WRITE)
|
||||
if ret or not f.is_open():
|
||||
print("Unable to open file for save ", fname)
|
||||
return FAILED
|
||||
|
||||
if typeof(p_data) == typeof([]):
|
||||
for s in p_data:
|
||||
f.store_string(s)
|
||||
else:
|
||||
f.store_string(p_data)
|
||||
|
||||
f.close()
|
||||
printt("Saved game to " + fname)
|
||||
|
||||
return OK
|
||||
|
||||
func load_slot(p_slot, p_callback):
|
||||
if p_callback == null:
|
||||
return FAILED
|
||||
|
||||
if !(p_slot in slots):
|
||||
return FAILED
|
||||
|
||||
var data = _do_load(slots[p_slot].fname)
|
||||
if !data:
|
||||
return FAILED
|
||||
|
||||
p_callback[0].call_deferred(p_callback[1], data)
|
||||
|
||||
return OK
|
||||
|
||||
func load_autosave(p_callback):
|
||||
if p_callback == null:
|
||||
return FAILED
|
||||
|
||||
var data = _do_load("user://quick_save.esc")
|
||||
if data == null:
|
||||
return FAILED
|
||||
|
||||
p_callback[0].call_deferred(p_callback[1], data)
|
||||
|
||||
return OK
|
||||
|
||||
|
||||
func _do_load(fname):
|
||||
|
||||
var f = File.new()
|
||||
if !f.file_exists(fname):
|
||||
return null
|
||||
|
||||
f.open(fname, File.READ)
|
||||
var data = f.get_as_text()
|
||||
f.close()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
func autosave(p_data, p_callback):
|
||||
var err = _do_save("user://quick_save.esc", p_data)
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], err)
|
||||
|
||||
return err
|
||||
|
||||
func get_slots_available(p_callback):
|
||||
|
||||
if p_callback == null:
|
||||
return FAILED
|
||||
|
||||
var d = Directory.new()
|
||||
d.open("user://")
|
||||
if !d.dir_exists(base):
|
||||
d.make_dir(base)
|
||||
d.open(base)
|
||||
|
||||
|
||||
d.list_dir_begin()
|
||||
var f = d.get_next()
|
||||
while f != "":
|
||||
|
||||
if f.find(".esc") < 0 || f.find("-") < 0:
|
||||
f = d.get_next()
|
||||
continue
|
||||
|
||||
var sep = f.find("-")
|
||||
var n = int(f.substr(0, sep))
|
||||
if n >= max_slots:
|
||||
f = d.get_next()
|
||||
continue
|
||||
|
||||
var t = f.replace(".esc", "")
|
||||
t = t.substr(2, t.length()-2)
|
||||
var l = t.split(" ")
|
||||
var h = l[1]
|
||||
var date = l[0]
|
||||
|
||||
slots[n] = { "n": n, "fname": base + "/" + f, "date": date, "hour": h }
|
||||
|
||||
f = d.get_next()
|
||||
|
||||
d.list_dir_end()
|
||||
|
||||
p_callback[0].call_deferred(p_callback[1], slots)
|
||||
|
||||
return OK
|
||||
|
||||
func autosave_available():
|
||||
var f = File.new()
|
||||
return f.file_exists("user://quick_save.esc")
|
||||
|
||||
func start():
|
||||
pass
|
||||
4
addons/escoria-core/game/core-scripts/scalenode.gd
Normal file
4
addons/escoria-core/game/core-scripts/scalenode.gd
Normal file
@@ -0,0 +1,4 @@
|
||||
extends Position2D
|
||||
|
||||
#warning-ignore:unused_class_variable
|
||||
export(Vector2) var target_scale = Vector2(1.0, 1.0)
|
||||
10
addons/escoria-core/game/core-scripts/utils/utils.gd
Normal file
10
addons/escoria-core/game/core-scripts/utils/utils.gd
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
# Helpers to deal with player's and items' angles
|
||||
func _get_deg_from_rad(rad_angle : float):
|
||||
var deg = rad2deg(rad_angle)
|
||||
if deg >= 360.0:
|
||||
deg = clamp(deg, 0.0, 360.0)
|
||||
if deg == 360.0:
|
||||
deg = 0.0
|
||||
return deg
|
||||
|
||||
249
addons/escoria-core/game/escoria.gd
Normal file
249
addons/escoria-core/game/escoria.gd
Normal file
@@ -0,0 +1,249 @@
|
||||
extends Node
|
||||
|
||||
# Scripts
|
||||
onready var esc_compiler = $esc_compiler
|
||||
onready var logger = load("res://addons/escoria-core/game/core-scripts/log/logging.gd").new()
|
||||
onready var main = $main
|
||||
onready var esc_runner = $esc_runner
|
||||
onready var esc_level_runner = $esc_runner/esc_level_runner
|
||||
onready var inputs_manager = $inputs_manager
|
||||
onready var utils = load("res://addons/escoria-core/game/core-scripts/utils/utils.gd").new()
|
||||
|
||||
# INSTANCES
|
||||
var main_menu_instance
|
||||
## Dialog player instantiator. This instance is called directly for dialogs.
|
||||
var dialog_player
|
||||
## Inventory scene
|
||||
var inventory
|
||||
|
||||
# Game variables
|
||||
var room_terrain
|
||||
|
||||
enum GAME_STATE {
|
||||
DEFAULT,
|
||||
DIALOG,
|
||||
WAIT
|
||||
}
|
||||
onready var current_state = GAME_STATE.DEFAULT
|
||||
|
||||
##################################################################################
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
|
||||
# Called by Main menu "start new game"
|
||||
func new_game():
|
||||
var actions = esc_compiler.load_esc_file(ProjectSettings.get_setting("escoria/main/game_start_script"))
|
||||
$esc_runner.run_game(actions)
|
||||
|
||||
|
||||
func change_scene_path(scene_path):
|
||||
var scene = load(scene_path).instance()
|
||||
get_tree().get_root().call_deferred("add_child", scene)
|
||||
return scene
|
||||
|
||||
|
||||
func set_main_menu(scene):
|
||||
main_menu_instance = scene
|
||||
|
||||
func report_warnings(p_path : String, warnings : Array) -> void:
|
||||
var text = "Warnings in file "+p_path+"\n"
|
||||
for w in warnings:
|
||||
if w is Array:
|
||||
text += str(w)+"\n"
|
||||
else:
|
||||
text += w+"\n"
|
||||
printerr("warning is: ", text)
|
||||
|
||||
|
||||
func report_errors(p_path : String, errors : Array) -> void:
|
||||
var text = "Errors in file "+p_path+"\n"
|
||||
for e in errors:
|
||||
if e is Array:
|
||||
text += str(e)+"\n"
|
||||
else:
|
||||
text += e+"\n"
|
||||
printerr("error is: ", text)
|
||||
if ProjectSettings.get_setting("escoria/debug/terminate_on_errors"):
|
||||
print_stack()
|
||||
assert(false)
|
||||
# If your game stopped here, you may want to look at the Output tab and check for
|
||||
# the error that caused the game to stop.
|
||||
|
||||
|
||||
"""
|
||||
Add object to the environement.
|
||||
"""
|
||||
func register_object(object : Object):
|
||||
var object_id
|
||||
if object.get("global_id"):
|
||||
object_id = object.global_id
|
||||
else:
|
||||
object_id = object.name
|
||||
|
||||
if object is ESCDialogsPlayer:
|
||||
dialog_player = object
|
||||
|
||||
if object is ESCPlayer:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCHotspot or object is Position2D:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCItem:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCTerrain:
|
||||
room_terrain = object
|
||||
|
||||
if object is ESCCamera:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCInventory:
|
||||
inventory = object
|
||||
|
||||
|
||||
"""
|
||||
Generic action function that runs an action on an element of the room (eg player walk)
|
||||
action: type of the action ()
|
||||
"""
|
||||
func do(action : String, params : Array = []) -> void:
|
||||
if current_state == GAME_STATE.DEFAULT:
|
||||
match action:
|
||||
"walk":
|
||||
# Reset current action
|
||||
esc_runner.set_current_action("")
|
||||
|
||||
# Walk to position2D
|
||||
if params[1] is Vector2:
|
||||
var target_position = params[1]
|
||||
var is_fast : bool = false
|
||||
if params.size() > 2 and params[2] == true:
|
||||
is_fast = true
|
||||
var walk_context = {"fast": is_fast}
|
||||
main.current_scene.player.walk_to(target_position, walk_context)
|
||||
# Walk to object from its id
|
||||
elif params[1] is String:
|
||||
var object = escoria.esc_runner.get_object(params[1])
|
||||
if object:
|
||||
var target_position : Vector2 = object.interact_position
|
||||
|
||||
if params[0] == main.current_scene.player.global_id:
|
||||
var is_fast : bool = false
|
||||
if params.size() > 2 and params[2] == true:
|
||||
is_fast = true
|
||||
var walk_context = {"fast": is_fast, "target_object" : object}
|
||||
|
||||
main.current_scene.player.walk_to(target_position, walk_context)
|
||||
else:
|
||||
report_errors("escoria.gd: do() > walk", ["TODO: code NPC walking"])
|
||||
|
||||
"hotspot_left_click", "item_left_click":
|
||||
if params[0] is String:
|
||||
printt("escoria.do : item_left_click on item ", params[0])
|
||||
|
||||
# call : ev_left_click_on_item()
|
||||
ev_left_click_on_item($esc_runner.get_object(params[0]), params[1])
|
||||
|
||||
"hotspot_right_click", "item_right_click":
|
||||
if params[0] is String:
|
||||
printt("escoria.do : item_right_click on item ", params[0])
|
||||
|
||||
# call : ev_left_click_on_item()
|
||||
ev_left_click_on_item($esc_runner.get_object(params[0]), params[1], true)
|
||||
|
||||
_:
|
||||
# $esc_runner.activate(action, params[0])
|
||||
report_warnings("escoria.gd:do()", ["Action received:", action, "with params ", params])
|
||||
elif current_state == GAME_STATE.DIALOG:
|
||||
dialog_player.finish_fast()
|
||||
elif current_state == GAME_STATE.WAIT:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# PRIVATE
|
||||
func ev_left_click_on_item(obj, event, default_action = false):
|
||||
"""
|
||||
Event occurring when an object/item is left clicked
|
||||
obj : object that was left clicked
|
||||
event :
|
||||
"""
|
||||
if obj is String:
|
||||
obj = esc_runner.objects[obj]
|
||||
printt(obj.global_id, "left-clicked with", event)
|
||||
|
||||
var need_combine = false
|
||||
# Check if current_action and current_tool are already set
|
||||
if esc_runner.current_action:
|
||||
if esc_runner.current_tool:
|
||||
if esc_runner.current_action in esc_runner.current_tool.combine_if_action_used_among:
|
||||
need_combine = true
|
||||
else:
|
||||
esc_runner.current_tool = obj
|
||||
else:
|
||||
if default_action:
|
||||
esc_runner.current_action = obj.default_action
|
||||
elif esc_runner.current_action in obj.combine_if_action_used_among:
|
||||
esc_runner.current_tool = obj
|
||||
|
||||
|
||||
var action = "walk"
|
||||
# Don't interact after player movement towards object (because object is inactive for example)
|
||||
var dont_interact = false
|
||||
var destination_position : Vector2 = main.current_scene.player.global_position
|
||||
|
||||
# Create walk context
|
||||
var walk_context = {"fast": event.doubleclick, "target_object" : obj}
|
||||
|
||||
# If object not in inventory, player walks towards it
|
||||
if !esc_runner.inventory_has(obj.global_id):
|
||||
var clicked_object_has_interact_position = false
|
||||
|
||||
if esc_runner.get_interactive(obj.global_id):
|
||||
if obj.interact_positions.default != null:
|
||||
destination_position = obj.interact_positions.default#.global_position
|
||||
clicked_object_has_interact_position = true
|
||||
else:
|
||||
destination_position = obj.position
|
||||
else:
|
||||
destination_position = event.position
|
||||
dont_interact = true
|
||||
|
||||
main.current_scene.player.walk_to(destination_position, walk_context)
|
||||
|
||||
# Wait for the player to arrive before continuing with action.
|
||||
yield(main.current_scene.player, "arrived")
|
||||
|
||||
# If no interaction should happen after player has arrived, leave immediately.
|
||||
if dont_interact:
|
||||
return
|
||||
|
||||
var player_global_pos = main.current_scene.player.global_position
|
||||
var clicked_position = event.position
|
||||
|
||||
# If player has arrived at the position he was supposed to reach so he can interact
|
||||
if player_global_pos == destination_position:
|
||||
# Manage exits
|
||||
if obj.is_exit and $esc_runner.current_action == "" or $esc_runner.current_action == "walk":
|
||||
var params = [obj]
|
||||
$esc_runner.activate("exit_scene", params)
|
||||
|
||||
else:
|
||||
# Manage movements towards object before activating it
|
||||
if $esc_runner.current_action == "" or $esc_runner.current_action == "walk":
|
||||
if destination_position != clicked_position \
|
||||
and !esc_runner.inventory_has(obj.global_id):
|
||||
esc_runner.activate("arrived", [obj])
|
||||
# Manage action on object
|
||||
elif $esc_runner.current_action != "" and $esc_runner.current_action != "walk":
|
||||
# If apply_interact, perform combine between items
|
||||
if need_combine:
|
||||
esc_runner.activate(esc_runner.current_action, [esc_runner.current_tool, obj])
|
||||
|
||||
else:
|
||||
esc_runner.activate(esc_runner.current_action, [obj])
|
||||
|
||||
else:
|
||||
# escoria.fallback("")
|
||||
pass
|
||||
30
addons/escoria-core/game/escoria.tscn
Normal file
30
addons/escoria-core/game/escoria.tscn
Normal file
@@ -0,0 +1,30 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/esc_runner.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/game/main.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/escoria-core/game/escoria.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/esc_runner_level.gd" type="Script" id=4]
|
||||
[ext_resource path="res://addons/escoria-core/game/inputs_manager.gd" type="Script" id=5]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/esc_compiler.gd" type="Script" id=6]
|
||||
|
||||
[node name="escoria" type="Node"]
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="inputs_manager" type="Node" parent="."]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
[node name="esc_compiler" type="Node" parent="."]
|
||||
script = ExtResource( 6 )
|
||||
|
||||
[node name="esc_runner" type="Node" parent="."]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="esc_level_runner" type="Node" parent="esc_runner"]
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="main" parent="." instance=ExtResource( 2 )]
|
||||
|
||||
[node name="Viewport" type="Viewport" parent="."]
|
||||
usage = 0
|
||||
|
||||
[editable path="main"]
|
||||
101
addons/escoria-core/game/inputs_manager.gd
Normal file
101
addons/escoria-core/game/inputs_manager.gd
Normal file
@@ -0,0 +1,101 @@
|
||||
tool
|
||||
extends Node
|
||||
|
||||
var is_hotspot_focused : bool
|
||||
|
||||
func _ready():
|
||||
set_process_input(true)
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("esc_show_debug_prompt"):
|
||||
escoria.main.get_node("layers/debug_layer/esc_prompt_popup").popup()
|
||||
|
||||
###################################################################################
|
||||
|
||||
func _on_left_click_on_bg(position : Vector2):
|
||||
if !is_hotspot_focused:
|
||||
printt("Left click on background at ", str(position))
|
||||
escoria.main.current_scene.game.left_click_on_bg(position)
|
||||
|
||||
|
||||
func _on_double_left_click_on_bg(position : Vector2):
|
||||
if !is_hotspot_focused:
|
||||
printt("Double left click on background at ", str(position))
|
||||
escoria.main.current_scene.game.left_double_click_on_bg(position)
|
||||
|
||||
|
||||
func _on_right_click_on_bg(position : Vector2):
|
||||
if !is_hotspot_focused:
|
||||
printt("Right click on background at ", str(position))
|
||||
escoria.main.current_scene.game.right_click_on_bg(position)
|
||||
|
||||
##################################################################################
|
||||
|
||||
func _on_mouse_entered_hotspot(hotspot_global_id : String) -> void:
|
||||
printt("Hotspot focused : ", hotspot_global_id)
|
||||
is_hotspot_focused = true
|
||||
escoria.main.current_scene.game.element_focused(hotspot_global_id)
|
||||
|
||||
func _on_mouse_exited_hotspot() -> void:
|
||||
print("Hotspot unfocused")
|
||||
is_hotspot_focused = false
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
|
||||
func _on_mouse_left_clicked_hotspot(hotspot_global_id : String, event : InputEvent) -> void:
|
||||
printt("Hotspot left clicked", hotspot_global_id, event)
|
||||
escoria.main.current_scene.game.left_click_on_hotspot(hotspot_global_id, event)
|
||||
|
||||
func _on_mouse_right_clicked_hotspot(hotspot_global_id : String, event : InputEvent) -> void:
|
||||
printt("Hotspot right clicked", hotspot_global_id, event)
|
||||
escoria.main.current_scene.game.right_click_on_hotspot(hotspot_global_id, event)
|
||||
|
||||
func _on_mouse_left_double_clicked_hotspot(hotspot_global_id : String, event : InputEvent) -> void:
|
||||
printt("Hotspot right clicked", hotspot_global_id, event)
|
||||
escoria.main.current_scene.game.left_double_click_on_hotspot(hotspot_global_id, event)
|
||||
|
||||
##################################################################################
|
||||
|
||||
func _on_mouse_left_click_inventory_item(inventory_item_global_id, event : InputEvent) -> void:
|
||||
printt("Inventory item left clicked ", inventory_item_global_id)
|
||||
escoria.main.current_scene.game.left_click_on_inventory_item(inventory_item_global_id, event)
|
||||
|
||||
func _on_mouse_right_click_inventory_item(inventory_item_global_id, event : InputEvent) -> void:
|
||||
printt("Inventory item right clicked ", inventory_item_global_id)
|
||||
escoria.main.current_scene.game.right_click_on_inventory_item(inventory_item_global_id, event)
|
||||
|
||||
func _on_mouse_double_left_click_inventory_item(inventory_item_global_id, event : InputEvent) -> void:
|
||||
printt("Inventory item double left clicked ", inventory_item_global_id)
|
||||
escoria.main.current_scene.game.double_left_click_on_inventory_item(inventory_item_global_id, event)
|
||||
|
||||
func _on_mouse_entered_inventory_item(inventory_item_global_id) -> void:
|
||||
printt("Inventory item focused ", inventory_item_global_id)
|
||||
escoria.main.current_scene.game.inventory_item_focused(inventory_item_global_id)
|
||||
|
||||
func _on_mouse_exited_inventory_item() -> void:
|
||||
printt("Inventory item unfocused")
|
||||
escoria.main.current_scene.game.inventory_item_unfocused()
|
||||
|
||||
|
||||
##################################################################################
|
||||
|
||||
func _on_mouse_entered_item(item_global_id : String) -> void:
|
||||
printt("Item focused : ", item_global_id)
|
||||
is_hotspot_focused = true
|
||||
escoria.main.current_scene.game.element_focused(item_global_id)
|
||||
|
||||
func _on_mouse_exited_item() -> void:
|
||||
print("Item unfocused")
|
||||
is_hotspot_focused = false
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
|
||||
func _on_mouse_left_clicked_item(item_global_id : String, event : InputEvent) -> void:
|
||||
printt("Item left clicked", item_global_id, event)
|
||||
escoria.main.current_scene.game.left_click_on_item(item_global_id, event)
|
||||
|
||||
func _on_mouse_left_double_clicked_item(item_global_id : String, event : InputEvent) -> void:
|
||||
printt("Item left double clicked", item_global_id, event)
|
||||
escoria.main.current_scene.game.left_double_click_on_item(item_global_id, event)
|
||||
|
||||
func _on_mouse_right_clicked_item(item_global_id : String, event : InputEvent) -> void:
|
||||
printt("Item right clicked", item_global_id, event)
|
||||
escoria.main.current_scene.game.right_click_on_item(item_global_id, event)
|
||||
158
addons/escoria-core/game/main.gd
Normal file
158
addons/escoria-core/game/main.gd
Normal file
@@ -0,0 +1,158 @@
|
||||
extends Node
|
||||
|
||||
# This script is basically the scene-switcher.
|
||||
|
||||
# Global id of the last scene the player was before current scene
|
||||
var last_scene_global_id
|
||||
# Current scene room being displayed
|
||||
var current_scene
|
||||
|
||||
var wait_level
|
||||
|
||||
var screen_ofs = Vector2(0, 0)
|
||||
|
||||
func _ready():
|
||||
$layers/wait_timer.connect("timeout", self, "_on_wait_finished")
|
||||
|
||||
func set_scene(p_scene, run_events=true):
|
||||
"""
|
||||
Sets p_scene as current scene
|
||||
If run_events=true, plays the events defined in :setup event
|
||||
"""
|
||||
if !p_scene:
|
||||
escoria.report_errors("main", ["Trying to set empty scene"])
|
||||
|
||||
# Ensure we don't have a regular event running when changing scenes
|
||||
if escoria.esc_runner.running_event:
|
||||
assert(escoria.esc_runner.running_event.ev_name == "load")
|
||||
|
||||
if "esc_script" in p_scene and p_scene.esc_script and run_events:
|
||||
var events = escoria.esc_compiler.load_esc_file(p_scene.esc_script)
|
||||
|
||||
# :setup is pretty much required in the code, but fortunately
|
||||
# we can help out with cases where one isn't necessary otherwise
|
||||
if not "setup" in events:
|
||||
var fake_setup = escoria.esc_compiler.compile_str(":setup\n")
|
||||
events["setup"] = fake_setup["setup"]
|
||||
|
||||
escoria.esc_runner.run_event(events["setup"])
|
||||
|
||||
# If scene was never visited, run "ready" event
|
||||
if !escoria.esc_runner.scenes_cache.has(p_scene.global_id) \
|
||||
and "ready" in events:
|
||||
escoria.esc_runner.run_event(events["ready"])
|
||||
|
||||
if current_scene != null:
|
||||
clear_scene()
|
||||
|
||||
# var game_scene =
|
||||
|
||||
get_node("/root").add_child(p_scene)
|
||||
set_current_scene(p_scene, run_events)
|
||||
set_camera_limits()
|
||||
|
||||
|
||||
func set_current_scene(p_scene, run_events=true):
|
||||
current_scene = p_scene
|
||||
$"/root".move_child(current_scene, 0)
|
||||
|
||||
# Loading a save game must set the scene but not run events
|
||||
if "events_path" in current_scene and current_scene.events_path and run_events:
|
||||
if escoria.esc_runner.game:
|
||||
# Having a game with `:setup` means we must wait for it to finish
|
||||
if "setup" in escoria.esc_runner.game:
|
||||
if not escoria.esc_runner.running_event:
|
||||
escoria.report_errors("main.gd:set_current_scene()", ["escoria.esc_runner.game has setup but no running_event"])
|
||||
|
||||
if escoria.esc_runner.running_event.ev_name != "setup":
|
||||
escoria.report_errors("main.gd:set_current_scene()", ["escoria.esc_runner.game has setup but it is not running: " + escoria.esc_runner.running_event.ev_name])
|
||||
|
||||
yield(escoria.esc_runner, "event_done")
|
||||
else:
|
||||
escoria.esc_compiler.load_file(current_scene.events_path)
|
||||
# For a new game, we must run `:setup` if available
|
||||
# and wait for it to finish
|
||||
if "setup" in escoria.esc_runner.game:
|
||||
escoria.esc_runner.run_event(escoria.esc_runner.game["setup"])
|
||||
yield(escoria.esc_runner, "event_done")
|
||||
|
||||
# Because 1) changing a scene and 2) having a scene become ready
|
||||
# both call `set_current_scene`, we don't want to duplicate thing
|
||||
if not escoria.esc_runner.running_event:
|
||||
escoria.esc_runner.run_game()
|
||||
|
||||
escoria.esc_runner.register_object("_scene", p_scene, true) # Force overwrite of global
|
||||
|
||||
|
||||
func clear_scene():
|
||||
if current_scene == null:
|
||||
return
|
||||
|
||||
escoria.esc_runner.clear_current_action()
|
||||
escoria.esc_runner.clear_current_tool()
|
||||
# escoria.esc_runner.hover_clear_stack()
|
||||
# escoria.clear_inventory()
|
||||
|
||||
last_scene_global_id = current_scene.global_id
|
||||
escoria.esc_runner.set_global("ESC_LAST_SCENE", last_scene_global_id, true)
|
||||
get_node("/root").remove_child(current_scene)
|
||||
current_scene.free()
|
||||
current_scene = null
|
||||
|
||||
func wait(params : Array, level):
|
||||
wait_level = level
|
||||
$layers/wait_timer.set_wait_time(float(params[0]))
|
||||
$layers/wait_timer.set_one_shot(true)
|
||||
$layers/wait_timer.start()
|
||||
|
||||
func _on_wait_finished():
|
||||
escoria.esc_level_runner.finished(wait_level)
|
||||
|
||||
|
||||
func set_camera_limits():
|
||||
var limits = {}
|
||||
var scene_camera_limits = current_scene.camera_limits
|
||||
if scene_camera_limits.size.x == 0 and scene_camera_limits.size.y == 0:
|
||||
var area = Rect2()
|
||||
for child in current_scene.get_children():
|
||||
if child is ESCBackground:
|
||||
var pos = child.get_global_position()
|
||||
var size : Vector2
|
||||
if child.get_texture():
|
||||
size = child.get_texture().get_size()
|
||||
else:
|
||||
size = child.rect_size
|
||||
|
||||
if child.rect_scale.x != 1 or child.rect_scale.y != 1:
|
||||
size.x *= child.rect_scale.x
|
||||
size.y *= child.rect_scale.y
|
||||
|
||||
area = area.expand(pos)
|
||||
area = area.expand(pos + size)
|
||||
break
|
||||
|
||||
# if the background is smaller than the viewport, we want the camera to stick centered on the background
|
||||
if area.size.x == 0 or area.size.y == 0 or area.size < get_viewport().size:
|
||||
printt("No limit area! Using viewport")
|
||||
area.size = get_viewport().size
|
||||
|
||||
printt("setting camera limits from scene ", area)
|
||||
limits = {
|
||||
"limit_left": area.position.x,
|
||||
"limit_right": area.position.x + area.size.x,
|
||||
"limit_top": area.position.y,
|
||||
"limit_bottom": area.position.y + area.size.y,
|
||||
"set_default": true,
|
||||
}
|
||||
else:
|
||||
limits = {
|
||||
"limit_left": scene_camera_limits.position.x,
|
||||
"limit_right": scene_camera_limits.position.x + scene_camera_limits.size.x,
|
||||
"limit_top": scene_camera_limits.position.y,
|
||||
"limit_bottom": scene_camera_limits.position.y + scene_camera_limits.size.y + screen_ofs.y * 2,
|
||||
"set_default": true,
|
||||
}
|
||||
printt("setting camera limits from parameter ", scene_camera_limits)
|
||||
|
||||
escoria.esc_runner.get_object("camera").set_limits(limits)
|
||||
escoria.esc_runner.get_object("camera").set_offset(screen_ofs * 2)
|
||||
19
addons/escoria-core/game/main.tscn
Normal file
19
addons/escoria-core/game/main.tscn
Normal file
@@ -0,0 +1,19 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/main.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="main" type="Node"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="layers" type="Node" parent="."]
|
||||
|
||||
[node name="curtain" type="CanvasLayer" parent="layers"]
|
||||
|
||||
[node name="menu" type="CanvasLayer" parent="layers"]
|
||||
|
||||
[node name="wait_timer" type="Timer" parent="layers"]
|
||||
|
||||
[node name="debug_layer" type="CanvasLayer" parent="layers"]
|
||||
|
||||
[node name="esc_prompt_popup" parent="layers/debug_layer" instance=ExtResource( 2 )]
|
||||
10
addons/escoria-core/game/main_scene.gd
Normal file
10
addons/escoria-core/game/main_scene.gd
Normal file
@@ -0,0 +1,10 @@
|
||||
extends Node
|
||||
|
||||
# Main_scene is the entry point for Godot Engine.
|
||||
# This scene sets up the main menu scene to load.
|
||||
|
||||
func _ready():
|
||||
var main_menu_path = ProjectSettings.get_setting("escoria/main/main_menu_scene")
|
||||
var main_menu = escoria.change_scene_path(main_menu_path)
|
||||
escoria.set_main_menu(main_menu)
|
||||
|
||||
6
addons/escoria-core/game/main_scene.tscn
Normal file
6
addons/escoria-core/game/main_scene.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/main_scene.gd" type="Script" id=1]
|
||||
|
||||
[node name="main_scene" type="Node"]
|
||||
script = ExtResource( 1 )
|
||||
11
addons/escoria-core/game/scenes/camera_player/camera.tscn
Normal file
11
addons/escoria-core/game/scenes/camera_player/camera.tscn
Normal file
@@ -0,0 +1,11 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/scenes/camera_player/esccamera.gd" type="Script" id=1]
|
||||
|
||||
[node name="camera" type="Camera2D"]
|
||||
current = true
|
||||
drag_margin_h_enabled = true
|
||||
drag_margin_v_enabled = true
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="tween" type="Tween" parent="."]
|
||||
166
addons/escoria-core/game/scenes/camera_player/esccamera.gd
Normal file
166
addons/escoria-core/game/scenes/camera_player/esccamera.gd
Normal file
@@ -0,0 +1,166 @@
|
||||
extends Camera2D
|
||||
class_name ESCCamera
|
||||
|
||||
onready var tween = $"tween"
|
||||
|
||||
var default_limits = {} # This does not change once set
|
||||
|
||||
var speed = 0.0
|
||||
var target
|
||||
var target_pos
|
||||
|
||||
var zoom_time
|
||||
var zoom_target
|
||||
|
||||
# This is needed to adjust dialog positions and such, see dialog_instance.gd
|
||||
var zoom_transform
|
||||
|
||||
func set_limits(kwargs=null):
|
||||
if not kwargs:
|
||||
kwargs = {
|
||||
"limit_left": -10000,
|
||||
"limit_right": 10000,
|
||||
"limit_top": -10000,
|
||||
"limit_bottom": 10000,
|
||||
"set_default": false,
|
||||
}
|
||||
print_stack()
|
||||
|
||||
self.limit_left = kwargs["limit_left"]
|
||||
self.limit_right = kwargs["limit_right"]
|
||||
self.limit_top = kwargs["limit_top"]
|
||||
self.limit_bottom = kwargs["limit_bottom"]
|
||||
|
||||
if "set_default" in kwargs and kwargs["set_default"] and not default_limits:
|
||||
default_limits = kwargs
|
||||
|
||||
func resolve_target_pos():
|
||||
if typeof(target) == TYPE_VECTOR2:
|
||||
target_pos = target
|
||||
elif typeof(target) == TYPE_ARRAY:
|
||||
var count = 0
|
||||
|
||||
for obj in target:
|
||||
target_pos += obj.get_camera_pos()
|
||||
count += 1
|
||||
|
||||
# Let the error in if an empty array was passed (divzero)
|
||||
target_pos = target_pos / count
|
||||
else:
|
||||
target_pos = target.get_camera_pos()
|
||||
|
||||
return target_pos
|
||||
|
||||
func set_drag_margin_enabled(p_dm_h_enabled, p_dm_v_enabled):
|
||||
self.drag_margin_h_enabled = p_dm_h_enabled
|
||||
self.drag_margin_v_enabled = p_dm_v_enabled
|
||||
|
||||
func set_target(p_target, p_speed : float = 0.0):
|
||||
speed = p_speed
|
||||
target = p_target
|
||||
|
||||
resolve_target_pos()
|
||||
|
||||
if speed == 0.0:
|
||||
self.global_position = target_pos
|
||||
else:
|
||||
var time = self.global_position.distance_to(target_pos) / speed
|
||||
|
||||
if tween.is_active():
|
||||
var tweenstat = String(tween.tell()) + "/" + String(tween.get_runtime())
|
||||
escoria.report_warnings("camera.gd:set_target()", ["Tween still active running camera_set_target: " + tweenstat])
|
||||
tween.emit_signal("tween_completed")
|
||||
|
||||
tween.interpolate_property(self, "global_position", self.global_position, target_pos, time, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
|
||||
tween.start()
|
||||
|
||||
func set_camera_zoom(p_zoom_level, p_time):
|
||||
if p_zoom_level <= 0.0:
|
||||
escoria.report_errors("camera.gd:set_camera_zoom()", ["Tried to set negative or zero zoom level"])
|
||||
|
||||
zoom_time = p_time
|
||||
zoom_target = Vector2(1, 1) * p_zoom_level
|
||||
|
||||
if zoom_time == 0:
|
||||
self.zoom = zoom_target
|
||||
else:
|
||||
if tween.is_active():
|
||||
var tweenstat = String(tween.tell()) + "/" + String(tween.get_runtime())
|
||||
escoria.report_warnings("camera", ["Tween still active running camera_set_zoom: " + tweenstat])
|
||||
tween.emit_signal("tween_completed")
|
||||
|
||||
tween.interpolate_property(self, "zoom", self.zoom, zoom_target, zoom_time, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
|
||||
tween.start()
|
||||
|
||||
func push(p_target, p_time, p_type):
|
||||
var time = float(p_time)
|
||||
var type = "TRANS_" + p_type
|
||||
|
||||
target = p_target
|
||||
|
||||
var camera_pos
|
||||
var camera_pos_coords
|
||||
if target.has_node("camera_pos"):
|
||||
camera_pos = target.get_node("camera_pos")
|
||||
camera_pos_coords = camera_pos.global_position
|
||||
else:
|
||||
camera_pos_coords = target.global_position
|
||||
|
||||
if time == 0:
|
||||
self.global_position = camera_pos_coords
|
||||
|
||||
if camera_pos and camera_pos is Camera2D:
|
||||
self.zoom = camera_pos.zoom
|
||||
else:
|
||||
if tween.is_active():
|
||||
var tweenstat = String(tween.tell()) + "/" + String(tween.get_runtime())
|
||||
escoria.report_warnings("camera", ["Tween still active running camera_push: " + tweenstat])
|
||||
tween.emit_signal("tween_completed")
|
||||
|
||||
if camera_pos and camera_pos is Camera2D:
|
||||
tween.interpolate_property(self, "zoom", self.zoom, camera_pos.zoom, time, tween.get(type), Tween.EASE_IN_OUT)
|
||||
|
||||
tween.interpolate_property(self, "global_position", self.global_position, camera_pos_coords, time, tween.get(type), Tween.EASE_IN_OUT)
|
||||
|
||||
tween.start()
|
||||
|
||||
func shift(p_x, p_y, p_time, p_type):
|
||||
var x = int(p_x)
|
||||
var y = int(p_y)
|
||||
var time = float(p_time)
|
||||
var type = "TRANS_" + p_type
|
||||
|
||||
var new_pos = self.global_position + Vector2(x, y)
|
||||
|
||||
target = new_pos
|
||||
|
||||
if tween.is_active():
|
||||
var tweenstat = String(tween.tell()) + "/" + String(tween.get_runtime())
|
||||
escoria.report_warnings("camera", ["Tween still active running camera_shift: " + tweenstat])
|
||||
tween.emit_signal("tween_completed")
|
||||
|
||||
tween.interpolate_property(self, "global_position", self.global_position, new_pos, time, tween.get(type), Tween.EASE_IN_OUT)
|
||||
|
||||
tween.start()
|
||||
|
||||
func target_reached(_obj=null, _key=null):
|
||||
tween.stop_all()
|
||||
|
||||
func _process(_delta):
|
||||
zoom_transform = self.get_canvas_transform()
|
||||
|
||||
if target and not tween.is_active():
|
||||
if typeof(target) == TYPE_VECTOR2 or typeof(target) == TYPE_ARRAY:
|
||||
self.global_position = resolve_target_pos()
|
||||
elif "moved" in target and target.moved:
|
||||
self.global_position = resolve_target_pos()
|
||||
|
||||
func _ready():
|
||||
if not target:
|
||||
target = Vector2(0, 0)
|
||||
|
||||
tween.connect("tween_completed", self, "target_reached")
|
||||
escoria.register_object(self)
|
||||
|
||||
74
addons/escoria-core/game/scenes/dialogs/dialog_player.gd
Normal file
74
addons/escoria-core/game/scenes/dialogs/dialog_player.gd
Normal file
@@ -0,0 +1,74 @@
|
||||
tool
|
||||
extends ResourcePreloader
|
||||
class_name ESCDialogsPlayer
|
||||
|
||||
func get_class():
|
||||
return "ESCDialogsPlayer"
|
||||
|
||||
# This scene is in charge of ALL dialogs management :
|
||||
# - characters sayings
|
||||
# - player dialog options panel display/hiding and choices
|
||||
|
||||
var path_to_dialog_scenes : String
|
||||
|
||||
var is_speaking = false
|
||||
var dialog_ui = null
|
||||
var dialog_chooser_ui = null
|
||||
|
||||
func _ready():
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
preload_resources(ProjectSettings.get_setting("escoria/ui/dialogs_folder"))
|
||||
|
||||
func preload_resources(path : String):
|
||||
path_to_dialog_scenes = path
|
||||
|
||||
var dialog_folder := Directory.new()
|
||||
if !path_to_dialog_scenes.empty() and dialog_folder.open(path_to_dialog_scenes) == OK:
|
||||
dialog_folder.list_dir_begin()
|
||||
var file_name = dialog_folder.get_next()
|
||||
while file_name != "":
|
||||
if !dialog_folder.current_is_dir() and file_name.get_extension() == "tscn":
|
||||
var extension = "." + file_name.get_extension()
|
||||
var basename = file_name.replace(extension, "")
|
||||
|
||||
if !has_resource(basename):
|
||||
var file_path = dialog_folder.get_current_dir() + "/" + file_name
|
||||
var dialog_scene = load(file_path)
|
||||
|
||||
if dialog_scene != null:
|
||||
add_resource(basename, dialog_scene)
|
||||
file_name = dialog_folder.get_next()
|
||||
else:
|
||||
escoria.report_errors("dialog_player.gd:preload_resources()", ["An error occurred when trying to access the path: {_}.".format(path)])
|
||||
|
||||
|
||||
func say(character : String, params : Dictionary):
|
||||
is_speaking = true
|
||||
dialog_ui = get_resource(params.ui).instance()
|
||||
get_parent().add_child(dialog_ui)
|
||||
dialog_ui.say(character, params)
|
||||
|
||||
func finish_fast():
|
||||
dialog_ui.finish_fast()
|
||||
|
||||
# Options:
|
||||
# type: (default value "default") the type of dialog menu to use. All types are in the "dd_player" scene.
|
||||
# avatar: (default value "default") the avatar to use in the dialog ui.
|
||||
# timeout: (default value 0) timeout to select an option. After the time has passed, the "timeout_option" will be selected automatically. If the value is 0, there's no timeout.
|
||||
# timeout_option: (default value 0) option selected when timeout is reached.
|
||||
func start_dialog_choices(answers : Array, options : Array):
|
||||
if answers.empty():
|
||||
escoria.report_errors("dialog_player.gd:start_dialog_choices()", ["Received answers array was empty."])
|
||||
dialog_chooser_ui = get_resource("text_dialog_choice").instance()
|
||||
get_parent().add_child(dialog_chooser_ui)
|
||||
dialog_chooser_ui.set_answers(answers)
|
||||
|
||||
func play_dialog_option_chosen(level_to_run : Array):
|
||||
# escoria.esc_runner.finished(context)
|
||||
var ev_level = level_to_run
|
||||
var ev = esctypes.ESCEvent.new("dialog_choice_done", ev_level, [])
|
||||
escoria.esc_runner.add_level(ev, false)
|
||||
dialog_chooser_ui.hide()
|
||||
# stop()
|
||||
|
||||
10
addons/escoria-core/game/scenes/dialogs/dialog_player.tscn
Normal file
10
addons/escoria-core/game/scenes/dialogs/dialog_player.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://game/ui/commons/dialogs/dialog_label.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://game/ui/commons/dialogs/text_dialog_choice.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/escoria-core/game/scenes/dialogs/dialog_player.gd" type="Script" id=3]
|
||||
[ext_resource path="res://game/ui/commons/dialogs/dialog_box_inset.tscn" type="PackedScene" id=4]
|
||||
|
||||
[node name="dialog_player" type="ResourcePreloader"]
|
||||
resources = [ PoolStringArray( "dialog_box_inset", "dialog_label", "text_dialog_choice" ), [ ExtResource( 4 ), ExtResource( 1 ), ExtResource( 2 ) ] ]
|
||||
script = ExtResource( 3 )
|
||||
@@ -0,0 +1,40 @@
|
||||
extends WindowDialog
|
||||
|
||||
onready var past_actions = $VBoxContainer/past_actions
|
||||
onready var command = $VBoxContainer/command
|
||||
|
||||
var last_event_done := true
|
||||
|
||||
func _on_command_text_entered(p_command_str : String):
|
||||
if p_command_str.empty():
|
||||
return
|
||||
|
||||
last_event_done = false
|
||||
command.text = ""
|
||||
past_actions.text += "\n"
|
||||
past_actions.text += "# " + p_command_str
|
||||
past_actions.text += "\n"
|
||||
|
||||
var actual_command = ":debug\n" + p_command_str + "\n"
|
||||
|
||||
var errors = []
|
||||
var events = escoria.esc_compiler.compile_str(actual_command, errors)
|
||||
|
||||
if errors.empty():
|
||||
#past_actions.text += str(events)
|
||||
var ret = escoria.esc_runner.run_event(events["debug"])
|
||||
if ret != null:
|
||||
past_actions.text += str(ret)
|
||||
else:
|
||||
# Display first error only
|
||||
past_actions.text += str(errors[0].split(":")[1].strip_edges())
|
||||
|
||||
|
||||
func _on_event_done(event_name : String):
|
||||
if event_name == "debug" and !last_event_done:
|
||||
last_event_done = true
|
||||
# past_actions.text += "\nDone.\n"
|
||||
|
||||
|
||||
func _on_esc_prompt_popup_about_to_show():
|
||||
command.grab_focus()
|
||||
@@ -0,0 +1,42 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd" type="Script" id=1]
|
||||
|
||||
[node name="esc_prompt_popup" type="WindowDialog"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 64.0
|
||||
margin_top = 68.0
|
||||
margin_right = -617.0
|
||||
margin_bottom = -456.0
|
||||
window_title = "ESC debug prompt"
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="past_actions" type="TextEdit" parent="VBoxContainer"]
|
||||
margin_right = 599.0
|
||||
margin_bottom = 240.0
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
|
||||
margin_top = 244.0
|
||||
margin_right = 599.0
|
||||
margin_bottom = 248.0
|
||||
|
||||
[node name="command" type="LineEdit" parent="VBoxContainer"]
|
||||
margin_top = 252.0
|
||||
margin_right = 599.0
|
||||
margin_bottom = 276.0
|
||||
caret_blink = true
|
||||
|
||||
[connection signal="about_to_show" from="." to="." method="_on_esc_prompt_popup_about_to_show"]
|
||||
[connection signal="text_entered" from="VBoxContainer/command" to="." method="_on_command_text_entered"]
|
||||
101
addons/escoria-core/game/scenes/inventory/inventory_ui.gd
Normal file
101
addons/escoria-core/game/scenes/inventory/inventory_ui.gd
Normal file
@@ -0,0 +1,101 @@
|
||||
extends Control
|
||||
class_name ESCInventory
|
||||
|
||||
func get_class():
|
||||
return "ESCInventory"
|
||||
|
||||
# Define the actual container node to add items as children of. Should be a Container.
|
||||
export(NodePath) var items_container
|
||||
onready var all_items = $all_items
|
||||
|
||||
# Methods available for selecting an item
|
||||
enum ITEM_SELECTION_METHODS {
|
||||
VERB_ACTION, # Use a verb action, such as use or give, on inventory item
|
||||
ONE_CLICK, # One click on inventory item selects it (eventually put it on cursor)
|
||||
DRAG_N_DROP # (Useful for mobile) Drag n drop item on another or on background to use/give it
|
||||
}
|
||||
export(ITEM_SELECTION_METHODS) var selection_method
|
||||
|
||||
var items_ids_in_inventory : Dictionary = {} # { item_id : TextureButton}
|
||||
|
||||
func _ready():
|
||||
# # For debugging scene only. These 2 lines should remain commented on normal run.
|
||||
# if !Engine.is_editor_hint():
|
||||
# return
|
||||
|
||||
for item_id in escoria.esc_runner.items_in_inventory():
|
||||
call_deferred("add_new_item_by_id", item_id)
|
||||
|
||||
escoria.register_object(self)
|
||||
|
||||
if items_container == null or items_container.is_empty():
|
||||
escoria.report_errors(self.get_path(), ["Items container is empty."])
|
||||
return
|
||||
for c in get_node(items_container).get_items():
|
||||
items_ids_in_inventory[c.item_id] = c
|
||||
# c.connect("pressed", escoria.inputs_manager, "_on_inventory_item_pressed", [c.item_id])
|
||||
|
||||
escoria.esc_runner.connect("global_changed", self, "_on_escoria_global_changed")
|
||||
|
||||
|
||||
# add item to Inventory UI using its id set in its scene
|
||||
func add_new_item_by_id(item_id : String) -> void:
|
||||
if item_id.begins_with("i/"):
|
||||
item_id = item_id.rsplit("i/", false)[0]
|
||||
if !items_ids_in_inventory.has(item_id):
|
||||
var item_inventory_button = all_items.get_inventory_item(item_id).duplicate()
|
||||
items_ids_in_inventory[item_id] = item_inventory_button
|
||||
get_node(items_container).add_item(item_inventory_button)
|
||||
|
||||
# Add the item to inventory
|
||||
if !escoria.esc_runner.objects.has(item_id):
|
||||
escoria.esc_runner.register_object(item_id, item_inventory_button)
|
||||
item_inventory_button.visible = true
|
||||
|
||||
# connect this new item TextureButton's signals to our inventory UI
|
||||
item_inventory_button.connect("mouse_left_inventory_item",
|
||||
escoria.inputs_manager, "_on_mouse_left_click_inventory_item")
|
||||
item_inventory_button.connect("mouse_double_left_inventory_item",
|
||||
escoria.inputs_manager, "_on_mouse_double_left_click_inventory_item")
|
||||
item_inventory_button.connect("mouse_right_inventory_item",
|
||||
escoria.inputs_manager, "_on_mouse_right_click_inventory_item")
|
||||
|
||||
item_inventory_button.connect("inventory_item_focused",
|
||||
escoria.inputs_manager, "_on_mouse_entered_inventory_item")
|
||||
item_inventory_button.connect("inventory_item_unfocused",
|
||||
escoria.inputs_manager, "_on_mouse_exited_inventory_item")
|
||||
|
||||
# remove item fromInventory UI using its id set in its scene
|
||||
func remove_item_by_id(item_id : String) -> void:
|
||||
if items_ids_in_inventory.has(item_id):
|
||||
var item_inventory_button = items_ids_in_inventory[item_id]
|
||||
|
||||
item_inventory_button.disconnect("mouse_left_inventory_item",
|
||||
escoria.inputs_manager, "_on_mouse_left_click_inventory_item")
|
||||
item_inventory_button.disconnect("mouse_double_left_inventory_item",
|
||||
escoria.inputs_manager, "_on_mouse_double_left_click_inventory_item")
|
||||
item_inventory_button.disconnect("mouse_right_inventory_item",
|
||||
escoria.inputs_manager, "_on_mouse_right_click_inventory_item")
|
||||
item_inventory_button.disconnect("inventory_item_focused",
|
||||
escoria.inputs_manager, "_on_mouse_entered_inventory_item")
|
||||
item_inventory_button.disconnect("inventory_item_unfocused",
|
||||
escoria.inputs_manager, "_on_mouse_exited_inventory_item")
|
||||
|
||||
get_node(items_container).remove_item(item_inventory_button)
|
||||
item_inventory_button.queue_free()
|
||||
items_ids_in_inventory.erase(item_id)
|
||||
|
||||
func _on_escoria_global_changed(global : String) -> void:
|
||||
if !global.begins_with("i/"):
|
||||
return
|
||||
var item = global.rsplit("i/", false)
|
||||
if item.size() == 1:
|
||||
if escoria.esc_runner.globals[global] == "true":
|
||||
add_new_item_by_id(item[0])
|
||||
elif escoria.esc_runner.globals[global] == "false":
|
||||
remove_item_by_id(item[0])
|
||||
else:
|
||||
escoria.report_warnings("inventory_ui.gd:_on_escoria_global_changed()", \
|
||||
["Inventory global " + global + " is neither 'true' nor 'false' (was " + escoria.esc_runner.globals[global] + "). "])
|
||||
else:
|
||||
escoria.report_errors("inventory_ui.gd:_on_escoria_global_changed()", ["Global must contain 1 item name.", "(received: " + global + ")"])
|
||||
358
addons/escoria-core/logo/escoria-logo.svg
Normal file
358
addons/escoria-core/logo/escoria-logo.svg
Normal file
@@ -0,0 +1,358 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg3926"
|
||||
inkscape:version="0.92.2 (unknown)"
|
||||
sodipodi:docname="escoria_logo.svg">
|
||||
<defs
|
||||
id="defs3920">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 148.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="210 : 148.5 : 1"
|
||||
inkscape:persp3d-origin="105 : 99 : 1"
|
||||
id="perspective4883" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4283">
|
||||
<stop
|
||||
style="stop-color:#71c837;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4279" />
|
||||
<stop
|
||||
style="stop-color:#d4ff2a;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4281" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6342"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-313.79291"
|
||||
y1="4263.0801"
|
||||
x2="-313.79291"
|
||||
y2="4156.5371" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6344"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-313.79291"
|
||||
y1="4263.0801"
|
||||
x2="-313.79291"
|
||||
y2="4156.5371" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6346"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-313.79291"
|
||||
y1="4263.0801"
|
||||
x2="-313.79291"
|
||||
y2="4156.5371" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6348"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-313.79291"
|
||||
y1="4263.0801"
|
||||
x2="-313.79291"
|
||||
y2="4156.5371" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6350"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-310.535"
|
||||
y1="4116.6665"
|
||||
x2="-607.86578"
|
||||
y2="4116.6665" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6352"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-6179.8599"
|
||||
y1="6275.8198"
|
||||
x2="-6179.8599"
|
||||
y2="6166.0386" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6354"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-6179.8599"
|
||||
y1="6275.8198"
|
||||
x2="-6179.8599"
|
||||
y2="6166.0386" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6356"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-6179.8599"
|
||||
y1="6275.8198"
|
||||
x2="-6179.8599"
|
||||
y2="6166.0386" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient6358"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-6179.8599"
|
||||
y1="6275.8198"
|
||||
x2="-6179.8599"
|
||||
y2="6166.0386" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient1300"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-310.535"
|
||||
y1="4116.6665"
|
||||
x2="-607.86578"
|
||||
y2="4116.6665" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4283"
|
||||
id="linearGradient1370"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-310.535"
|
||||
y1="4116.6665"
|
||||
x2="-607.86578"
|
||||
y2="4116.6665" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.11313708"
|
||||
inkscape:cx="309.63405"
|
||||
inkscape:cy="525.46506"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
showborder="false"
|
||||
inkscape:window-width="1641"
|
||||
inkscape:window-height="995"
|
||||
inkscape:window-x="39"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:lockguides="false" />
|
||||
<metadata
|
||||
id="metadata3923">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="opacity:0.50899999;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ff0000;stroke-width:3.0587821;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4471"
|
||||
width="690.93744"
|
||||
height="290.39264"
|
||||
x="-492.16605"
|
||||
y="-105.54419" />
|
||||
<g
|
||||
id="g1885"
|
||||
transform="matrix(0.58267536,0,0,0.58267536,15.656304,-914.40014)" />
|
||||
<g
|
||||
transform="matrix(1.9244583,0,0,1.9244583,-58.446902,-1925.0775)"
|
||||
id="g2198">
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot1729"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1;font-family:Jellee;-inkscape-font-specification:Jellee;letter-spacing:0px;word-spacing:0px;fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,1519.0252,-612.12873)"><flowRegion
|
||||
style="fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="flowRegion1725"><rect
|
||||
style="fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1723"
|
||||
width="2296.6829"
|
||||
height="605.28339"
|
||||
x="-6363.9609"
|
||||
y="6123.1787" /></flowRegion><flowPara
|
||||
id="flowPara1727"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:Jellee;-inkscape-font-specification:Jellee;fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">ESC</flowPara></flowRoot> <flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot1737"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1;font-family:Jellee;-inkscape-font-specification:Jellee;letter-spacing:0px;word-spacing:0px;fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,109.17355,-80.073949)"><flowRegion
|
||||
id="flowRegion1733"
|
||||
style="fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><rect
|
||||
id="rect1731"
|
||||
width="548.71484"
|
||||
height="203.64674"
|
||||
x="-478.00418"
|
||||
y="4112.167"
|
||||
style="fill:#d4ff2a;fill-opacity:1;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></flowRegion><flowPara
|
||||
id="flowPara1735"
|
||||
style="font-size:192px;stroke:#1b2f0d;stroke-width:56.69291306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">RIA</flowPara></flowRoot> <g
|
||||
aria-label="RIA"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,109.17355,-80.073949)"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1;font-family:Jellee;-inkscape-font-specification:Jellee;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient6348);fill-opacity:1;stroke:#1b2f0d;stroke-opacity:1"
|
||||
id="flowRoot1715">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -447.47591,4263.08 q -7.68,0 -13.056,-5.376 -5.376,-5.376 -5.376,-13.056 v -111.744 q 0,-7.872 4.224,-12.096 4.224,-4.224 12.096,-4.224 h 47.04 q 24.96,0 39.168,11.712 14.4,11.52 14.4,32.64 0,14.016 -6.72,24.576 -6.72,10.56 -19.008,16.512 v 0.384 l 18.048,34.752 q 2.112,3.648 2.112,8.256 0,7.296 -5.184,12.48 -5.184,5.184 -12.672,5.184 -4.992,0 -9.408,-2.496 -4.224,-2.688 -6.336,-7.104 l -21.504,-41.472 h -19.392 v 32.64 q 0,7.68 -5.376,13.056 -5.376,5.376 -13.056,5.376 z m 37.056,-80.256 q 10.752,0 17.088,-4.224 6.528,-4.224 6.528,-15.168 0,-11.328 -6.336,-15.552 -6.336,-4.224 -17.28,-4.224 h -18.624 v 39.168 z"
|
||||
style="font-size:192px;fill:url(#linearGradient6342);fill-opacity:1;stroke:#1b2f0d;stroke-opacity:1"
|
||||
id="path2076" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -313.79291,4263.08 q -7.68,0 -13.056,-5.376 -5.376,-5.376 -5.376,-13.056 V 4133.48 q 0,-7.68 5.376,-13.056 5.376,-5.376 13.056,-5.376 7.68,0 13.056,5.376 5.376,5.376 5.376,13.056 v 111.168 q 0,7.68 -5.376,13.056 -5.376,5.376 -13.056,5.376 z"
|
||||
style="font-size:192px;fill:url(#linearGradient6344);fill-opacity:1;stroke:#1b2f0d;stroke-opacity:1"
|
||||
id="path2078" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -263.79491,4263.08 q -6.912,0 -11.904,-4.8 -4.8,-4.992 -4.8,-11.904 0,-2.496 0.96,-5.376 l 36.48,-105.6 q 3.072,-9.024 10.944,-14.592 7.872,-5.76 17.856,-5.76 9.792,0 17.664,5.76 7.872,5.568 10.944,14.592 l 36.096,104.448 q 0.96,3.264 0.96,5.76 0,7.104 -5.184,12.288 -4.992,5.184 -12.288,5.184 -5.76,0 -10.368,-3.264 -4.608,-3.456 -6.336,-8.832 l -6.336,-20.16 h -52.224 l -6.336,20.544 q -1.536,5.184 -5.952,8.448 -4.416,3.264 -10.176,3.264 z m 65.664,-60.672 -9.216,-29.376 q -2.88,-9.216 -4.8,-16.896 l -1.92,-7.488 h -2.304 l -1.92,7.488 q -1.92,7.68 -4.8,16.896 l -9.216,29.376 z"
|
||||
style="font-size:192px;fill:url(#linearGradient6346);fill-opacity:1;stroke:#1b2f0d;stroke-opacity:1"
|
||||
id="path2080" />
|
||||
</g>
|
||||
<g
|
||||
id="g1908"
|
||||
transform="matrix(0.59424771,1.0292672,-1.0292672,0.59424771,1156.6208,812.41899)">
|
||||
<path
|
||||
id="path1869"
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)"
|
||||
d="m -548.03711,3773.5391 a 344.24474,337.98426 0 0 1 17.03125,0.8359 c -0.31189,-0.024 -0.6226,-0.052 -0.93555,-0.072 -1.76454,-0.116 -3.53934,-0.1977 -5.31054,-0.2929 -1.53249,-0.082 -3.06037,-0.1812 -4.59766,-0.2481 -0.0227,0 -0.0338,-6e-4 -0.0527,0 -2.04041,-0.089 -4.08551,-0.1589 -6.13477,-0.2207 z"
|
||||
style="opacity:1;fill:#c83737;fill-opacity:1;stroke:none;stroke-width:6.79609203;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path1871"
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)"
|
||||
d="m -499.00391,4444.8438 a 344.24474,337.98426 0 0 1 -19.28906,2.2988 c 0.0599,-0.01 0.11976,-0.012 0.17969,-0.018 1.83269,-0.1776 3.66935,-0.3446 5.49414,-0.5449 1.81478,-0.2003 3.61714,-0.4336 5.42383,-0.6543 1.37782,-0.1701 2.7599,-0.3236 4.13281,-0.5039 1.35772,-0.1788 2.7072,-0.3817 4.05859,-0.5781 z"
|
||||
style="opacity:1;fill:#c83737;fill-opacity:1;stroke:none;stroke-width:6.79609203;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;fill:#c83737;fill-opacity:1;stroke:none;stroke-width:6.79609203;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m -548.03711,3773.5391 a 344.24474,337.98426 0 0 1 17.03125,0.8359 c -0.31189,-0.024 -0.6226,-0.052 -0.93555,-0.072 -1.76454,-0.116 -3.53934,-0.1977 -5.31054,-0.2929 -1.53249,-0.082 -3.06037,-0.1812 -4.59766,-0.2481 -0.0227,0 -0.0338,-6e-4 -0.0527,0 -2.04041,-0.089 -4.08551,-0.1589 -6.13477,-0.2207 z"
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)"
|
||||
id="path1875"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;fill:#c83737;fill-opacity:1;stroke:none;stroke-width:6.79609203;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m -499.00391,4444.8438 a 344.24474,337.98426 0 0 1 -19.28906,2.2988 c 0.0599,-0.01 0.11976,-0.012 0.17969,-0.018 1.83269,-0.1776 3.66935,-0.3446 5.49414,-0.5449 1.81478,-0.2003 3.61714,-0.4336 5.42383,-0.6543 1.37782,-0.1701 2.7599,-0.3236 4.13281,-0.5039 1.35772,-0.1788 2.7072,-0.3817 4.05859,-0.5781 z"
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)"
|
||||
id="path1877"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1881"
|
||||
transform="matrix(0.25475377,0,0,0.25475377,-306.71149,683.99286)"
|
||||
style="opacity:1;fill:#1b2f0d;fill-opacity:1;stroke:none;stroke-width:1.79813266;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m -342.56353,1151.6482 c -7.0772,0 -12.7748,5.6975 -12.7748,12.7748 0,7.0772 5.6976,12.7747 12.7748,12.7747 h 13.2842 c 7.0773,0 12.7748,-5.6975 12.7748,-12.7748 0,-7.0772 -5.6975,-12.7747 -12.7748,-12.7747 z m 0,-153.30048 c -7.0772,-2e-5 -12.7748,5.69758 -12.7748,12.77478 0,7.0772 5.6976,12.7748 12.7748,12.7748 h 13.2843 c 7.0772,0 12.7747,-5.6976 12.7747,-12.7748 0,-7.0772 -5.6975,-12.77478 -12.7747,-12.7748 z m 64.35054,10e-5 -8.85836,0.003 c -8.72831,0 -15.75512,5.69718 -15.75512,12.77438 0,7.0772 7.02681,12.775 15.75512,12.775 h 8.85836 14.96602 c 8.72832,0 15.75511,5.6976 15.75511,12.7749 -2e-5,7.0772 -7.02682,12.7744 -15.75511,12.7744 h -78.04123 -7.32203 c -8.72831,0 -15.75512,5.6977 -15.75512,12.7749 0,7.0772 7.02681,12.7749 15.75512,12.7749 h 7.32203 6.89364 c 8.72828,0 15.75511,5.6978 15.75511,12.775 0,7.0772 -7.02683,12.7745 -15.75511,12.7744 h -6.77686 -7.32202 c -8.72831,0 -15.75512,5.6977 -15.75512,12.7749 0,7.0773 7.02681,12.775 15.75512,12.775 h 7.32202 92.99861 c 8.72831,0 15.75511,5.6972 15.75512,12.7744 0,7.0772 -7.02681,12.7749 -15.75512,12.7749 h -8.92193 -10.81898 c -8.7282,0 -15.75511,5.6976 -15.75511,12.7749 0,7.0772 7.02691,12.7744 15.75511,12.7744 h 10.81898 40.33604 68.16829 c 0.62444,0 1.24701,-0.01 1.86862,-0.016 0.1154,0.01 0.23081,0.012 0.34623,0.017 50.302833,0 91.081283,-40.037 91.081262,-89.425 2.1e-5,-49.388 -40.778429,-89.42493 -91.081262,-89.42501 -0.22706,0.007 -0.45409,0.0151 -0.68109,0.0238 -8e-4,0 -0.002,3e-5 -0.003,0 -0.50883,-0.007 -1.0184,-0.0109 -1.52911,-0.0109 h -83.24395 z m 40.75566,89.42508 c 0.003,2.0372 0.0763,4.0737 0.22065,6.106 -0.14437,-2.0323 -0.21796,-4.0688 -0.22065,-6.106 z m 0.8108,11.036 c 0.13325,1.3242 0.29658,2.6454 0.48989,3.9625 -0.19331,-1.3171 -0.35664,-2.6383 -0.48989,-3.9625 z m 1.67741,9.2495 c 0.23768,1.1446 0.49819,2.2844 0.78135,3.419 -0.28316,-1.1346 -0.54367,-2.2744 -0.78135,-3.419 z m 2.61793,8.9153 c 0.31876,1.0001 15.72957,1.9947 16.08393,2.9832 -0.35436,-0.9885 -15.76517,-1.9831 -16.08393,-2.9832 z m 18.64036,8.6485 c 0.36472,0.8342 0.74234,1.6628 1.13275,2.4856 -0.39041,-0.8228 -0.76803,-1.6514 -1.13275,-2.4856 z m 4.50361,8.3054 c 0.36769,0.6478 0.74358,1.2911 1.12757,1.9297 -0.38399,-0.6386 -0.75988,-1.2819 -1.12757,-1.9297 z m -9.82333,7.6368 c 0.37594,0.5279 0.75768,1.0517 1.14515,1.5715 -0.38747,-0.5198 -0.76921,-1.0436 -1.14515,-1.5715 z m 6.0849,7.1339 c 0.34214,0.3892 0.6877,0.7754 1.03662,1.1586 -0.34892,-0.3832 -0.69448,-0.7694 -1.03662,-1.1586 z m 6.69313,6.3723 c 0.32401,0.3008 0.65027,0.5993 0.97875,0.8955 -0.32848,-0.2962 -0.65474,-0.5947 -0.97875,-0.8955 z m 7.34684,5.6859 c 0.28312,0.2137 0.56751,0.4257 0.85317,0.6361 -0.28566,-0.2104 -0.57005,-0.4224 -0.85317,-0.6361 z m 8.00933,4.9801 c 0.19145,0.1163 0.38334,0.2318 0.57567,0.3467 -0.19233,-0.1149 -0.38422,-0.2304 -0.57567,-0.3467 z m 8.25944,4.0261 c 0.16529,0.079 0.33083,0.1576 0.49661,0.2356 -0.16578,-0.078 -0.33132,-0.1566 -0.49661,-0.2356 z m 8.78138,3.2391 c 0.0818,0.03 0.1636,0.059 0.24546,0.088 -0.0819,-0.029 -0.16369,-0.059 -0.24546,-0.088 z m 8.79843,2.2665 c 0.0868,0.022 0.17359,0.043 0.26044,0.065 -0.0868,-0.022 -0.17366,-0.043 -0.26044,-0.065 z m 9.09866,1.4097 0.154,0.023 z" />
|
||||
<path
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)"
|
||||
id="path1883"
|
||||
d="m -548.98438,3869.0234 c -6.41901,0.032 -12.83422,0.3183 -19.23046,0.8594 -0.4722,-0.014 -0.94238,-0.035 -1.41797,-0.035 h -204.81765 c -26.74885,0 -48.28321,21.5347 -48.28321,48.2832 0,26.7484 21.53436,48.2832 48.28321,48.2832 h 15.24218 -22.51475 33.61133 c 26.74885,0 48.2832,21.5327 48.2832,48.2812 0,26.7489 -21.53435,48.2832 -48.2832,48.2832 h -5.55166 l -0.002,0.012 h -136.92063 c -26.74885,0 -48.2832,21.5348 -48.2832,48.2832 0,26.7485 21.53435,48.2832 48.2832,48.2832 h 147.23808 12.12305 3.3027 c 26.74885,0 48.28321,21.5328 48.28321,48.2813 0,26.7488 -21.53436,48.2832 -48.28321,48.2832 h -15.42575 -8.91601 c -26.74885,0 -48.28321,21.5347 -48.28321,48.2832 0,26.7485 21.53436,48.2812 48.28321,48.2812 h 182.63106 c 0.88706,0 1.76758,-0.027 2.64258,-0.074 5.9887,0.5234 11.99481,0.8238 18.00585,0.9004 133.7876,-3e-4 242.2438,-108.4565 242.24415,-242.2441 -2.9e-4,-133.7876 -108.45651,-242.2439 -242.24415,-242.2442 z m -535.34762,193.9668 c -26.7489,0 -48.2832,21.5348 -48.2832,48.2832 0,26.7485 21.5343,48.2832 48.2832,48.2832 h 45.1797 c 26.7484,0 48.28323,-21.5347 48.28316,-48.2832 7e-5,-26.7484 -21.53476,-48.2832 -48.28316,-48.2832 z"
|
||||
style="opacity:1;fill:url(#linearGradient6350);fill-opacity:1;stroke:none;stroke-width:2.8148098;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccssssccsssccsssccssccsssscccccsssscss" />
|
||||
</g>
|
||||
<g
|
||||
aria-label="ESC"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,1519.0252,-612.12873)"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1;font-family:Jellee;-inkscape-font-specification:Jellee;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient6358);fill-opacity:1;stroke:none"
|
||||
id="flowRoot1713">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -6335.5449,6272.5557 q -7.872,0 -12.096,-4.224 -4.224,-4.224 -4.224,-12.096 v -112.32 q 0,-7.872 4.224,-12.096 4.224,-4.224 12.096,-4.224 h 70.656 q 6.144,0 10.368,4.416 4.416,4.416 4.416,10.56 0,5.952 -4.416,10.368 -4.224,4.416 -10.368,4.416 h -50.496 v 28.224 h 41.664 q 5.952,0 10.176,4.224 4.224,4.224 4.224,10.176 0,5.952 -4.224,10.368 -4.224,4.224 -10.176,4.224 h -41.664 v 28.224 h 54.336 q 6.144,0 10.368,4.416 4.416,4.224 4.416,10.368 0,6.144 -4.416,10.56 -4.224,4.416 -10.368,4.416 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:Jellee;-inkscape-font-specification:Jellee;fill:url(#linearGradient6352);fill-opacity:1"
|
||||
id="path2069" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -6179.8599,6275.8197 q -15.936,0 -28.8,-4.608 -12.864,-4.608 -21.504,-12.672 -2.304,-2.304 -3.648,-5.76 -1.344,-3.648 -1.344,-7.488 0,-7.296 5.184,-12.288 5.184,-5.184 12.288,-5.184 4.608,0 8.448,2.304 3.84,2.112 6.144,5.76 3.84,5.76 9.984,8.832 6.144,2.88 14.016,2.88 11.52,0 17.28,-4.224 5.76,-4.224 5.76,-11.52 0,-5.568 -3.84,-9.216 -3.84,-3.84 -13.632,-5.952 l -23.616,-4.992 q -20.352,-4.416 -30.336,-14.784 -9.792,-10.56 -9.792,-28.224 0,-12.672 6.72,-22.848 6.912,-10.176 19.968,-15.936 13.056,-5.76 31.104,-5.76 29.376,0 45.696,15.36 4.8,4.608 4.8,12.672 0,6.912 -4.992,11.904 -4.8,4.992 -11.712,4.992 -4.416,0 -8.256,-2.112 -3.648,-2.304 -5.952,-5.76 -5.952,-9.6 -19.776,-9.6 -10.56,0 -15.552,3.84 -4.992,3.84 -4.992,9.408 0,5.76 3.84,9.6 4.032,3.84 14.4,5.952 l 23.424,4.992 q 21.504,4.608 31.296,15.36 9.792,10.752 9.792,27.648 0,13.056 -6.336,23.808 -6.144,10.56 -20.16,17.088 -14.016,6.528 -35.904,6.528 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:Jellee;-inkscape-font-specification:Jellee;fill:url(#linearGradient6354);fill-opacity:1"
|
||||
id="path2071" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m -6036.6609,6275.8197 q -34.56,0 -52.8,-19.584 -18.24,-19.776 -18.24,-54.912 0,-22.656 8.64,-39.936 8.832,-17.472 24.768,-27.072 16.128,-9.792 37.632,-9.792 17.664,0 31.104,5.76 13.44,5.568 21.888,15.936 3.456,4.032 3.456,11.328 0,7.296 -5.184,12.48 -4.992,4.992 -12.288,4.992 -4.608,0 -8.832,-2.304 -4.032,-2.304 -6.336,-6.144 -7.68,-13.056 -23.808,-13.056 -14.592,0 -23.424,11.52 -8.832,11.328 -8.832,34.56 0,23.808 9.024,35.52 9.024,11.712 23.232,11.712 16.896,0 24.96,-14.592 2.304,-4.224 6.528,-6.72 4.224,-2.688 9.216,-2.688 7.296,0 12.48,5.376 5.376,5.184 5.376,12.672 0,5.76 -3.456,10.752 -17.664,24.192 -55.104,24.192 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:192px;font-family:Jellee;-inkscape-font-specification:Jellee;fill:url(#linearGradient6356);fill-opacity:1"
|
||||
id="path2073" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g7164"
|
||||
transform="matrix(0.34566325,-0.59870631,0.59870631,0.34566325,46.553206,-1019.4322)" />
|
||||
<g
|
||||
transform="matrix(1.5594927,2.7011205,-2.7011205,1.5594927,2467.9041,-478.22072)"
|
||||
id="g1335">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1276"
|
||||
transform="matrix(0.25475377,0,0,0.25475377,-306.71149,683.99286)"
|
||||
style="opacity:1;fill:#1b2f0d;fill-opacity:1;stroke:none;stroke-width:1.79813266;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m -342.56353,1151.6482 c -7.0772,0 -12.7748,5.6975 -12.7748,12.7748 0,7.0772 5.6976,12.7747 12.7748,12.7747 h 13.2842 c 7.0773,0 12.7748,-5.6975 12.7748,-12.7748 0,-7.0772 -5.6975,-12.7747 -12.7748,-12.7747 z m 0,-153.30048 c -7.0772,-2e-5 -12.7748,5.69758 -12.7748,12.77478 0,7.0772 5.6976,12.7748 12.7748,12.7748 h 13.2843 c 7.0772,0 12.7747,-5.6976 12.7747,-12.7748 0,-7.0772 -5.6975,-12.77478 -12.7747,-12.7748 z m 64.35054,10e-5 -8.85836,0.003 c -8.72831,0 -15.75512,5.69718 -15.75512,12.77438 0,7.0772 7.02681,12.775 15.75512,12.775 h 8.85836 14.96602 c 8.72832,0 15.75511,5.6976 15.75511,12.7749 -2e-5,7.0772 -7.02682,12.7744 -15.75511,12.7744 h -78.04123 -7.32203 c -8.72831,0 -15.75512,5.6977 -15.75512,12.7749 0,7.0772 7.02681,12.7749 15.75512,12.7749 h 7.32203 6.89364 c 8.72828,0 15.75511,5.6978 15.75511,12.775 0,7.0772 -7.02683,12.7745 -15.75511,12.7744 h -6.77686 -7.32202 c -8.72831,0 -15.75512,5.6977 -15.75512,12.7749 0,7.0773 7.02681,12.775 15.75512,12.775 h 7.32202 92.99861 c 8.72831,0 15.75511,5.6972 15.75512,12.7744 0,7.0772 -7.02681,12.7749 -15.75512,12.7749 h -8.92193 -10.81898 c -8.7282,0 -15.75511,5.6976 -15.75511,12.7749 0,7.0772 7.02691,12.7744 15.75511,12.7744 h 10.81898 40.33604 68.16829 c 0.62444,0 1.24701,-0.01 1.86862,-0.016 0.1154,0.01 0.23081,0.012 0.34623,0.017 50.302833,0 91.081283,-40.037 91.081262,-89.425 2.1e-5,-49.388 -40.778429,-89.42493 -91.081262,-89.42501 -0.22706,0.007 -0.45409,0.0151 -0.68109,0.0238 -8e-4,0 -0.002,3e-5 -0.003,0 -0.50883,-0.007 -1.0184,-0.0109 -1.52911,-0.0109 h -83.24395 z m 40.75566,89.42508 c 0.003,2.0372 0.0763,4.0737 0.22065,6.106 -0.14437,-2.0323 -0.21796,-4.0688 -0.22065,-6.106 z m 0.8108,11.036 c 0.13325,1.3242 0.29658,2.6454 0.48989,3.9625 -0.19331,-1.3171 -0.35664,-2.6383 -0.48989,-3.9625 z m 1.67741,9.2495 c 0.23768,1.1446 0.49819,2.2844 0.78135,3.419 -0.28316,-1.1346 -0.54367,-2.2744 -0.78135,-3.419 z m 2.61793,8.9153 c 0.31876,1.0001 15.72957,1.9947 16.08393,2.9832 -0.35436,-0.9885 -15.76517,-1.9831 -16.08393,-2.9832 z m 18.64036,8.6485 c 0.36472,0.8342 0.74234,1.6628 1.13275,2.4856 -0.39041,-0.8228 -0.76803,-1.6514 -1.13275,-2.4856 z m 4.50361,8.3054 c 0.36769,0.6478 0.74358,1.2911 1.12757,1.9297 -0.38399,-0.6386 -0.75988,-1.2819 -1.12757,-1.9297 z m -9.82333,7.6368 c 0.37594,0.5279 0.75768,1.0517 1.14515,1.5715 -0.38747,-0.5198 -0.76921,-1.0436 -1.14515,-1.5715 z m 6.0849,7.1339 c 0.34214,0.3892 0.6877,0.7754 1.03662,1.1586 -0.34892,-0.3832 -0.69448,-0.7694 -1.03662,-1.1586 z m 6.69313,6.3723 c 0.32401,0.3008 0.65027,0.5993 0.97875,0.8955 -0.32848,-0.2962 -0.65474,-0.5947 -0.97875,-0.8955 z m 7.34684,5.6859 c 0.28312,0.2137 0.56751,0.4257 0.85317,0.6361 -0.28566,-0.2104 -0.57005,-0.4224 -0.85317,-0.6361 z m 8.00933,4.9801 c 0.19145,0.1163 0.38334,0.2318 0.57567,0.3467 -0.19233,-0.1149 -0.38422,-0.2304 -0.57567,-0.3467 z m 8.25944,4.0261 c 0.16529,0.079 0.33083,0.1576 0.49661,0.2356 -0.16578,-0.078 -0.33132,-0.1566 -0.49661,-0.2356 z m 8.78138,3.2391 c 0.0818,0.03 0.1636,0.059 0.24546,0.088 -0.0819,-0.029 -0.16369,-0.059 -0.24546,-0.088 z m 8.79843,2.2665 c 0.0868,0.022 0.17359,0.043 0.26044,0.065 -0.0868,-0.022 -0.17366,-0.043 -0.26044,-0.065 z m 9.09866,1.4097 0.154,0.023 z" />
|
||||
<path
|
||||
id="path1278"
|
||||
d="m -548.98438,3869.0234 c -6.41901,0.032 -12.83422,0.3183 -19.23046,0.8594 -0.4722,-0.014 -0.94238,-0.035 -1.41797,-0.035 h -204.81765 c -26.74885,0 -48.28321,21.5347 -48.28321,48.2832 0,26.7484 21.53436,48.2832 48.28321,48.2832 h 15.24218 -22.51475 33.61133 c 26.74885,0 48.2832,21.5327 48.2832,48.2812 0,26.7489 -21.53435,48.2832 -48.2832,48.2832 h -5.55166 l -0.002,0.012 h -136.92063 c -26.74885,0 -48.2832,21.5348 -48.2832,48.2832 0,26.7485 21.53435,48.2832 48.2832,48.2832 h 147.23808 12.12305 3.3027 c 26.74885,0 48.28321,21.5328 48.28321,48.2813 0,26.7488 -21.53436,48.2832 -48.28321,48.2832 h -15.42575 -8.91601 c -26.74885,0 -48.28321,21.5347 -48.28321,48.2832 0,26.7485 21.53436,48.2812 48.28321,48.2812 h 182.63106 c 0.88706,0 1.76758,-0.027 2.64258,-0.074 5.9887,0.5234 11.99481,0.8238 18.00585,0.9004 133.7876,-3e-4 242.2438,-108.4565 242.24415,-242.2441 -2.9e-4,-133.7876 -108.45651,-242.2439 -242.24415,-242.2442 z m -535.34762,193.9668 c -26.7489,0 -48.2832,21.5348 -48.2832,48.2832 0,26.7485 21.5343,48.2832 48.2832,48.2832 h 45.1797 c 26.7484,0 48.28323,-21.5347 48.28316,-48.2832 7e-5,-26.7484 -21.53476,-48.2832 -48.28316,-48.2832 z"
|
||||
style="opacity:1;fill:url(#linearGradient1300);fill-opacity:1;stroke:none;stroke-width:2.8148098;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccssssccsssccsssccssccsssscccccsssscss"
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)" />
|
||||
</g>
|
||||
<rect
|
||||
y="-105.54419"
|
||||
x="-838.6853"
|
||||
height="290.39264"
|
||||
width="290.39264"
|
||||
id="rect1346"
|
||||
style="opacity:0.50899999;fill:#000000;fill-opacity:0;fill-rule:nonzero;stroke:#ff0000;stroke-width:2.34518576;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<g
|
||||
id="g1376"
|
||||
transform="translate(-334.8262,324.11459)">
|
||||
<g
|
||||
transform="matrix(3.1189853,-4.1386156e-8,4.1386156e-8,3.1189853,429.86477,-3282.1415)"
|
||||
id="g1366">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1362"
|
||||
transform="matrix(0.25475377,0,0,0.25475377,-306.71149,683.99286)"
|
||||
style="opacity:1;fill:#1b2f0d;fill-opacity:1;stroke:none;stroke-width:1.79813266;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m -342.56353,1151.6482 c -7.0772,0 -12.7748,5.6975 -12.7748,12.7748 0,7.0772 5.6976,12.7747 12.7748,12.7747 h 13.2842 c 7.0773,0 12.7748,-5.6975 12.7748,-12.7748 0,-7.0772 -5.6975,-12.7747 -12.7748,-12.7747 z m 0,-153.30048 c -7.0772,-2e-5 -12.7748,5.69758 -12.7748,12.77478 0,7.0772 5.6976,12.7748 12.7748,12.7748 h 13.2843 c 7.0772,0 12.7747,-5.6976 12.7747,-12.7748 0,-7.0772 -5.6975,-12.77478 -12.7747,-12.7748 z m 64.35054,10e-5 -8.85836,0.003 c -8.72831,0 -15.75512,5.69718 -15.75512,12.77438 0,7.0772 7.02681,12.775 15.75512,12.775 h 8.85836 14.96602 c 8.72832,0 15.75511,5.6976 15.75511,12.7749 -2e-5,7.0772 -7.02682,12.7744 -15.75511,12.7744 h -78.04123 -7.32203 c -8.72831,0 -15.75512,5.6977 -15.75512,12.7749 0,7.0772 7.02681,12.7749 15.75512,12.7749 h 7.32203 6.89364 c 8.72828,0 15.75511,5.6978 15.75511,12.775 0,7.0772 -7.02683,12.7745 -15.75511,12.7744 h -6.77686 -7.32202 c -8.72831,0 -15.75512,5.6977 -15.75512,12.7749 0,7.0773 7.02681,12.775 15.75512,12.775 h 7.32202 92.99861 c 8.72831,0 15.75511,5.6972 15.75512,12.7744 0,7.0772 -7.02681,12.7749 -15.75512,12.7749 h -8.92193 -10.81898 c -8.7282,0 -15.75511,5.6976 -15.75511,12.7749 0,7.0772 7.02691,12.7744 15.75511,12.7744 h 10.81898 40.33604 68.16829 c 0.62444,0 1.24701,-0.01 1.86862,-0.016 0.1154,0.01 0.23081,0.012 0.34623,0.017 50.302833,0 91.081283,-40.037 91.081262,-89.425 2.1e-5,-49.388 -40.778429,-89.42493 -91.081262,-89.42501 -0.22706,0.007 -0.45409,0.0151 -0.68109,0.0238 -8e-4,0 -0.002,3e-5 -0.003,0 -0.50883,-0.007 -1.0184,-0.0109 -1.52911,-0.0109 h -83.24395 z m 40.75566,89.42508 c 0.003,2.0372 0.0763,4.0737 0.22065,6.106 -0.14437,-2.0323 -0.21796,-4.0688 -0.22065,-6.106 z m 0.8108,11.036 c 0.13325,1.3242 0.29658,2.6454 0.48989,3.9625 -0.19331,-1.3171 -0.35664,-2.6383 -0.48989,-3.9625 z m 1.67741,9.2495 c 0.23768,1.1446 0.49819,2.2844 0.78135,3.419 -0.28316,-1.1346 -0.54367,-2.2744 -0.78135,-3.419 z m 2.61793,8.9153 c 0.31876,1.0001 15.72957,1.9947 16.08393,2.9832 -0.35436,-0.9885 -15.76517,-1.9831 -16.08393,-2.9832 z m 18.64036,8.6485 c 0.36472,0.8342 0.74234,1.6628 1.13275,2.4856 -0.39041,-0.8228 -0.76803,-1.6514 -1.13275,-2.4856 z m 4.50361,8.3054 c 0.36769,0.6478 0.74358,1.2911 1.12757,1.9297 -0.38399,-0.6386 -0.75988,-1.2819 -1.12757,-1.9297 z m -9.82333,7.6368 c 0.37594,0.5279 0.75768,1.0517 1.14515,1.5715 -0.38747,-0.5198 -0.76921,-1.0436 -1.14515,-1.5715 z m 6.0849,7.1339 c 0.34214,0.3892 0.6877,0.7754 1.03662,1.1586 -0.34892,-0.3832 -0.69448,-0.7694 -1.03662,-1.1586 z m 6.69313,6.3723 c 0.32401,0.3008 0.65027,0.5993 0.97875,0.8955 -0.32848,-0.2962 -0.65474,-0.5947 -0.97875,-0.8955 z m 7.34684,5.6859 c 0.28312,0.2137 0.56751,0.4257 0.85317,0.6361 -0.28566,-0.2104 -0.57005,-0.4224 -0.85317,-0.6361 z m 8.00933,4.9801 c 0.19145,0.1163 0.38334,0.2318 0.57567,0.3467 -0.19233,-0.1149 -0.38422,-0.2304 -0.57567,-0.3467 z m 8.25944,4.0261 c 0.16529,0.079 0.33083,0.1576 0.49661,0.2356 -0.16578,-0.078 -0.33132,-0.1566 -0.49661,-0.2356 z m 8.78138,3.2391 c 0.0818,0.03 0.1636,0.059 0.24546,0.088 -0.0819,-0.029 -0.16369,-0.059 -0.24546,-0.088 z m 8.79843,2.2665 c 0.0868,0.022 0.17359,0.043 0.26044,0.065 -0.0868,-0.022 -0.17366,-0.043 -0.26044,-0.065 z m 9.09866,1.4097 0.154,0.023 z" />
|
||||
<path
|
||||
id="path1364"
|
||||
d="m -548.98438,3869.0234 c -6.41901,0.032 -12.83422,0.3183 -19.23046,0.8594 -0.4722,-0.014 -0.94238,-0.035 -1.41797,-0.035 h -204.81765 c -26.74885,0 -48.28321,21.5347 -48.28321,48.2832 0,26.7484 21.53436,48.2832 48.28321,48.2832 h 15.24218 -22.51475 33.61133 c 26.74885,0 48.2832,21.5327 48.2832,48.2812 0,26.7489 -21.53435,48.2832 -48.2832,48.2832 h -5.55166 l -0.002,0.012 h -136.92063 c -26.74885,0 -48.2832,21.5348 -48.2832,48.2832 0,26.7485 21.53435,48.2832 48.2832,48.2832 h 147.23808 12.12305 3.3027 c 26.74885,0 48.28321,21.5328 48.28321,48.2813 0,26.7488 -21.53436,48.2832 -48.28321,48.2832 h -15.42575 -8.91601 c -26.74885,0 -48.28321,21.5347 -48.28321,48.2832 0,26.7485 21.53436,48.2812 48.28321,48.2812 h 182.63106 c 0.88706,0 1.76758,-0.027 2.64258,-0.074 5.9887,0.5234 11.99481,0.8238 18.00585,0.9004 133.7876,-3e-4 242.2438,-108.4565 242.24415,-242.2441 -2.9e-4,-133.7876 -108.45651,-242.2439 -242.24415,-242.2442 z m -535.34762,193.9668 c -26.7489,0 -48.2832,21.5348 -48.2832,48.2832 0,26.7485 21.5343,48.2832 48.2832,48.2832 h 45.1797 c 26.7484,0 48.28323,-21.5347 48.28316,-48.2832 7e-5,-26.7484 -21.53476,-48.2832 -48.28316,-48.2832 z"
|
||||
style="opacity:1;fill:url(#linearGradient1370);fill-opacity:1;stroke:none;stroke-width:2.8148098;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccssssccsssccsssccssccsssscccccsssscss"
|
||||
transform="matrix(0.0674036,0,0,0.0674036,-306.71149,683.99286)" />
|
||||
</g>
|
||||
<rect
|
||||
y="-429.65878"
|
||||
x="-838.6853"
|
||||
height="290.39264"
|
||||
width="290.39264"
|
||||
id="rect1368"
|
||||
style="opacity:0.50899999;fill:#000000;fill-opacity:0;fill-rule:nonzero;stroke:#ff0000;stroke-width:2.34518576;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 33 KiB |
34
addons/escoria-core/logo/escoria-logo.svg.import
Normal file
34
addons/escoria-core/logo/escoria-logo.svg.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/escoria-logo.svg-57c45ba33015e24cb2a3cf19c461f16b.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/escoria-core/logo/escoria-logo.svg"
|
||||
dest_files=[ "res://.import/escoria-logo.svg-57c45ba33015e24cb2a3cf19c461f16b.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=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
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
7
addons/escoria-core/plugin.cfg
Executable file
7
addons/escoria-core/plugin.cfg
Executable file
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Escoria"
|
||||
description="A point'n'click framework within Godot Engine."
|
||||
author="StraToN"
|
||||
version="1.0.0"
|
||||
script="editor/plugin_escoria.gd"
|
||||
16
addons/escoria-core/template_scenes/character.tscn
Normal file
16
addons/escoria-core/template_scenes/character.tscn
Normal file
@@ -0,0 +1,16 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esccharacter.gd" type="Script" id=1]
|
||||
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id=1]
|
||||
|
||||
[node name="character" type="KinematicBody2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="AnimatedSprite" type="AnimatedSprite" parent="."]
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource( 1 )
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
@@ -0,0 +1,27 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://icon.png" type="Texture" id=1]
|
||||
|
||||
[node name="dialog_avatars" type="Control"]
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="character1" type="TextureRect" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
texture = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="character2" type="TextureRect" parent="."]
|
||||
modulate = Color( 1, 0, 0, 1 )
|
||||
margin_left = 46.0
|
||||
margin_top = 80.0
|
||||
margin_right = 110.0
|
||||
margin_bottom = 144.0
|
||||
texture = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
tool
|
||||
extends PanelContainer
|
||||
|
||||
signal dialog_line_finished
|
||||
|
||||
export(String) var current_character setget set_current_character
|
||||
onready var avatar_node = $MarginContainer/HSplitContainer/VBoxContainer/avatar
|
||||
onready var name_node = $MarginContainer/HSplitContainer/VBoxContainer/name
|
||||
onready var text_node = $MarginContainer/HSplitContainer/text
|
||||
onready var tween = text_node.get_node("Tween")
|
||||
|
||||
export(float, 0.0, 0.3) var text_speed_per_character = 0.1
|
||||
export(float) var fast_text_speed_per_character = 0.25
|
||||
export(float) var max_time_to_text_disappear = 2.0
|
||||
|
||||
func _ready():
|
||||
var centered_position_on_screen = Vector2(
|
||||
ProjectSettings.get_setting("display/window/size/width") / 2,
|
||||
ProjectSettings.get_setting("display/window/size/height") / 2
|
||||
) - rect_size / 2
|
||||
rect_position = centered_position_on_screen
|
||||
text_node.bbcode_enabled = true
|
||||
$MarginContainer/HSplitContainer/text/Tween.connect("tween_completed", self, "_on_dialog_line_typed")
|
||||
|
||||
func set_current_character(name: String):
|
||||
current_character = name
|
||||
if $dialog_avatars:
|
||||
if $dialog_avatars.has_node(name):
|
||||
avatar_node.texture = ($dialog_avatars.get_node(name) as TextureRect).texture
|
||||
else:
|
||||
avatar_node.texture = null
|
||||
|
||||
|
||||
"""
|
||||
Make a character say something.
|
||||
|
||||
character: global id of the character who speaks
|
||||
params: Dictionary
|
||||
line: line of dialog to say
|
||||
"""
|
||||
func say(character : String, params : Dictionary) :
|
||||
show()
|
||||
set_current_character(character)
|
||||
|
||||
if !params["line"]:
|
||||
escoria.report_errors("dialog_box_inset.gd:say()", ["No line field in params!"])
|
||||
return
|
||||
|
||||
text_node.bbcode_text = params["line"]
|
||||
|
||||
text_node.percent_visible = 0.0
|
||||
var time_show_full_text = text_speed_per_character * len(params["line"])
|
||||
|
||||
tween.interpolate_property(text_node, "percent_visible",
|
||||
0.0, 1.0, time_show_full_text,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
|
||||
func finish_fast():
|
||||
tween.stop(text_node)
|
||||
tween.interpolate_property(text_node, "percent_visible",
|
||||
text_node.percent_visible, 1.0, fast_text_speed_per_character,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
|
||||
|
||||
func _on_dialog_line_typed(object, key):
|
||||
text_node.visible_characters = -1
|
||||
$Timer.start(max_time_to_text_disappear)
|
||||
$Timer.connect("timeout", self, "_on_dialog_finished")
|
||||
|
||||
func _on_dialog_finished():
|
||||
emit_signal("dialog_line_finished")
|
||||
queue_free()
|
||||
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventMouseButton:
|
||||
if event.pressed:
|
||||
finish_fast()
|
||||
@@ -0,0 +1,67 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/dialog_scenes/dialog_box_inset.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/dialog_scenes/dialog_avatars.tscn" type="PackedScene" id=4]
|
||||
|
||||
[node name="dialog_box" type="PopupPanel"]
|
||||
visible = true
|
||||
anchor_right = 0.685
|
||||
anchor_bottom = 0.452
|
||||
margin_right = 0.199951
|
||||
margin_bottom = 0.399994
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
current_character = "guybrush"
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 4.0
|
||||
margin_top = 4.0
|
||||
margin_right = -4.0
|
||||
margin_bottom = -4.0
|
||||
custom_constants/margin_right = 20
|
||||
custom_constants/margin_top = 20
|
||||
custom_constants/margin_left = 20
|
||||
custom_constants/margin_bottom = 20
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HSplitContainer" type="HSplitContainer" parent="MarginContainer"]
|
||||
margin_left = 20.0
|
||||
margin_top = 20.0
|
||||
margin_right = 848.0
|
||||
margin_bottom = 334.0
|
||||
custom_constants/separation = 35
|
||||
dragger_visibility = 1
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer"]
|
||||
margin_right = 60.0
|
||||
margin_bottom = 314.0
|
||||
|
||||
[node name="avatar" type="TextureRect" parent="MarginContainer/HSplitContainer/VBoxContainer"]
|
||||
margin_right = 60.0
|
||||
|
||||
[node name="name" type="Label" parent="MarginContainer/HSplitContainer/VBoxContainer"]
|
||||
margin_top = 4.0
|
||||
margin_right = 60.0
|
||||
margin_bottom = 18.0
|
||||
text = "Character"
|
||||
valign = 1
|
||||
|
||||
[node name="text" type="RichTextLabel" parent="MarginContainer/HSplitContainer"]
|
||||
margin_left = 95.0
|
||||
margin_right = 828.0
|
||||
margin_bottom = 314.0
|
||||
bbcode_enabled = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Tween" type="Tween" parent="MarginContainer/HSplitContainer/text"]
|
||||
|
||||
[node name="dialog_avatars" parent="." instance=ExtResource( 4 )]
|
||||
[connection signal="gui_input" from="." to="." method="_on_PopupPanel_gui_input"]
|
||||
@@ -0,0 +1,10 @@
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
|
||||
func set_answers(answers_array : PoolStringArray):
|
||||
|
||||
func _on_answer1_gui_input(event):
|
||||
pass # Replace with function body.
|
||||
@@ -0,0 +1,57 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
export(Color, RGB) var color_normal = Color(1.0,1.0,1.0,1.0)
|
||||
export(Color, RGB) var color_hover = Color(165.0,42.0,42.0, 1.0)
|
||||
export(Font) var font
|
||||
|
||||
var commands
|
||||
|
||||
func _ready():
|
||||
for c in $ScrollContainer/VBoxContainer.get_children():
|
||||
c.queue_free()
|
||||
|
||||
|
||||
func set_answers(p_commands : Array):
|
||||
commands = p_commands
|
||||
var c = 0
|
||||
for option in commands:
|
||||
var new_answer_label = RichTextLabel.new()
|
||||
new_answer_label.text = option.params[0]
|
||||
new_answer_label.fit_content_height = true
|
||||
new_answer_label.add_font_override("normal_font", font)
|
||||
|
||||
$ScrollContainer/VBoxContainer.add_child(new_answer_label)
|
||||
new_answer_label.fit_content_height = true
|
||||
new_answer_label.connect("focus_entered", self, "_on_answer_focus_entered", [new_answer_label]) # Focus entered
|
||||
new_answer_label.connect("focus_exited", self, "_on_answer_focus_exited", [new_answer_label]) # Focus exited
|
||||
new_answer_label.connect("mouse_entered", self, "_on_answer_mouse_entered", [new_answer_label]) # Mouse entered
|
||||
new_answer_label.connect("mouse_exited", self, "_on_answer_mouse_exited", [new_answer_label]) # Mouse exited
|
||||
new_answer_label.connect("gui_input", self, "_on_answer_gui_input", [c]) # Clicks
|
||||
c += 1
|
||||
|
||||
func _on_answer_gui_input(event : InputEvent, answer_id : int):
|
||||
if event is InputEventMouseButton and event.is_pressed():
|
||||
var answer = commands[answer_id].params[1]
|
||||
printt(answer)
|
||||
escoria.dialog_player.play_dialog_option_chosen(answer)
|
||||
|
||||
func _on_answer_mouse_entered(answer_node : Node):
|
||||
var text = answer_node.text
|
||||
answer_node.clear()
|
||||
answer_node.push_color(color_hover.to_html(false))
|
||||
answer_node.append_bbcode(text)
|
||||
answer_node.pop()
|
||||
|
||||
func _on_answer_mouse_exited(answer_node : Node):
|
||||
var text = answer_node.text
|
||||
answer_node.clear()
|
||||
answer_node.push_color(color_normal.to_html(false))
|
||||
answer_node.append_bbcode(text)
|
||||
answer_node.pop()
|
||||
|
||||
func _on_answer_focus_entered(answer_node : Node):
|
||||
pass
|
||||
|
||||
func _on_answer_focus_exited(answer_node : Node):
|
||||
pass
|
||||
@@ -0,0 +1,43 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/dialog_scenes/dialog_choosers/text_dialog_choice.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/game/assets/fonts/efmi/efmi_font.tres" type="DynamicFont" id=2]
|
||||
|
||||
[node name="text_dialog_choice" type="MarginContainer"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_constants/margin_top = 20
|
||||
custom_constants/margin_left = 20
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
color_hover = Color( 0.647059, 0.164706, 0.164706, 1 )
|
||||
font = ExtResource( 2 )
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="."]
|
||||
margin_left = 20.0
|
||||
margin_top = 20.0
|
||||
margin_right = 1280.0
|
||||
margin_bottom = 800.0
|
||||
scroll_horizontal_enabled = false
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer"]
|
||||
margin_right = 1260.0
|
||||
margin_bottom = 780.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
custom_constants/separation = 20
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="example" type="RichTextLabel" parent="ScrollContainer/VBoxContainer"]
|
||||
margin_right = 1260.0
|
||||
margin_bottom = 25.0
|
||||
custom_fonts/normal_font = ExtResource( 2 )
|
||||
text = "This answer is an example for vizualisation purpose. You can safely keep it in the scene as it will be removed on game launch."
|
||||
fit_content_height = true
|
||||
@@ -0,0 +1,68 @@
|
||||
extends RichTextLabel
|
||||
|
||||
signal dialog_line_finished
|
||||
|
||||
export(String) var current_character
|
||||
onready var tween = $Tween
|
||||
onready var text_node = self
|
||||
|
||||
export(float, 0.0, 0.3) var text_speed_per_character = 0.1
|
||||
export(float) var fast_text_speed_per_character = 0.25
|
||||
export(float) var max_time_to_text_disappear = 2.0
|
||||
|
||||
func _ready():
|
||||
bbcode_enabled = true
|
||||
$Tween.connect("tween_completed", self, "_on_dialog_line_typed")
|
||||
|
||||
"""
|
||||
Make a character say something.
|
||||
|
||||
character: global id of the character who speaks
|
||||
params: Dictionary
|
||||
line: line of dialog to say
|
||||
"""
|
||||
func say(character : String, params : Dictionary) :
|
||||
show()
|
||||
|
||||
if !params["line"]:
|
||||
escoria.report_errors("dialog_box_inset.gd:say()", ["No line field in params!"])
|
||||
return
|
||||
|
||||
# Position the RichTextLabel on the character's dialog position, if any.
|
||||
var character_node = escoria.esc_runner.get_object(character)
|
||||
rect_position = character_node.get_node("dialog_position").get_global_transform_with_canvas().origin
|
||||
rect_position.x -= rect_size.x / 2
|
||||
|
||||
# Set text color to color set in the actor
|
||||
var text_color = character_node.dialog_color
|
||||
var text_color_html = text_color.to_html(false)
|
||||
|
||||
text_node.bbcode_text = "[center][color=#" + text_color_html + "]".format(text_color_html) + params["line"] + "[/color][center]"
|
||||
|
||||
text_node.percent_visible = 0.0
|
||||
var time_show_full_text = text_speed_per_character * len(params["line"])
|
||||
|
||||
tween.interpolate_property(text_node, "percent_visible",
|
||||
0.0, 1.0, time_show_full_text,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
|
||||
func finish_fast():
|
||||
tween.stop(text_node)
|
||||
tween.interpolate_property(text_node, "percent_visible",
|
||||
text_node.percent_visible, 1.0, fast_text_speed_per_character,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
|
||||
|
||||
func _on_dialog_line_typed(object, key):
|
||||
text_node.visible_characters = -1
|
||||
$Timer.start(max_time_to_text_disappear)
|
||||
$Timer.connect("timeout", self, "_on_dialog_finished")
|
||||
|
||||
func _on_dialog_finished():
|
||||
# emit_signal("dialog_line_finished")
|
||||
escoria.esc_level_runner.finished()
|
||||
escoria.dialog_player.is_speaking = false
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
queue_free()
|
||||
@@ -0,0 +1,20 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/assets/fonts/efmi/efmi_font.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/dialog_scenes/dialog_label.gd" type="Script" id=2]
|
||||
|
||||
[node name="dialog_label" type="RichTextLabel"]
|
||||
margin_left = 5.4126
|
||||
margin_top = 7.0
|
||||
margin_right = 874.413
|
||||
margin_bottom = 259.0
|
||||
custom_fonts/normal_font = ExtResource( 1 )
|
||||
bbcode_text = "Here be some text"
|
||||
text = "Here be some text"
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Tween" type="Tween" parent="."]
|
||||
[connection signal="tween_completed" from="Tween" to="." method="_on_dialog_line_finished"]
|
||||
3
addons/escoria-core/template_scenes/game.tscn
Normal file
3
addons/escoria-core/template_scenes/game.tscn
Normal file
@@ -0,0 +1,3 @@
|
||||
[gd_scene format=2]
|
||||
|
||||
[node name="game" type="CanvasLayer"]
|
||||
10
addons/escoria-core/template_scenes/inventory_item.tscn
Normal file
10
addons/escoria-core/template_scenes/inventory_item.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/inventory_item.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/game/assets/images/no_image.png" type="Texture" id=2]
|
||||
|
||||
[node name="inventory_item" type="TextureButton"]
|
||||
margin_right = 50.0
|
||||
margin_bottom = 50.0
|
||||
texture_normal = ExtResource( 2 )
|
||||
script = ExtResource( 1 )
|
||||
60
addons/escoria-core/template_scenes/inventory_ui.tscn
Normal file
60
addons/escoria-core/template_scenes/inventory_ui.tscn
Normal file
@@ -0,0 +1,60 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/scenes/inventory/inventory_ui.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/inventory_item.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="inventory_ui_template" type="Control"]
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
margin_right = 282.0
|
||||
margin_bottom = 151.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer"]
|
||||
margin_left = 7.0
|
||||
margin_top = 7.0
|
||||
margin_right = 275.0
|
||||
margin_bottom = 144.0
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="PanelContainer/ScrollContainer"]
|
||||
margin_right = 268.0
|
||||
margin_bottom = 137.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
columns = 4
|
||||
|
||||
[node name="inventory_item1" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
|
||||
[node name="inventory_item2" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
margin_left = 54.0
|
||||
margin_right = 104.0
|
||||
|
||||
[node name="inventory_item3" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
margin_left = 108.0
|
||||
margin_right = 158.0
|
||||
|
||||
[node name="inventory_item4" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
margin_left = 162.0
|
||||
margin_right = 212.0
|
||||
|
||||
[node name="inventory_item5" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
margin_top = 54.0
|
||||
margin_bottom = 104.0
|
||||
|
||||
[node name="inventory_item6" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
margin_left = 54.0
|
||||
margin_top = 54.0
|
||||
margin_right = 104.0
|
||||
margin_bottom = 104.0
|
||||
|
||||
[node name="inventory_item7" parent="PanelContainer/ScrollContainer/GridContainer" instance=ExtResource( 2 )]
|
||||
margin_left = 108.0
|
||||
margin_top = 54.0
|
||||
margin_right = 158.0
|
||||
margin_bottom = 104.0
|
||||
10
addons/escoria-core/template_scenes/items_inventory.tscn
Normal file
10
addons/escoria-core/template_scenes/items_inventory.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/items_inventory.gd" type="Script" id=1]
|
||||
|
||||
[node name="items_inventory" type="GridContainer"]
|
||||
columns = 5
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
extends RichTextLabel
|
||||
|
||||
# Infinitive verb
|
||||
var current_action : String
|
||||
# Target item/hotspot
|
||||
var current_target : String
|
||||
# Preposition: on, with...
|
||||
var current_prep : String = "with"
|
||||
# Target 2 item/hotspot
|
||||
var current_target2 : String
|
||||
|
||||
var waiting_for_target2 = false
|
||||
|
||||
func _ready():
|
||||
escoria.esc_runner.connect("action_changed", self, "on_action_selected")
|
||||
escoria.inputs_manager.connect("element_focused", self, "on_element_focused")
|
||||
|
||||
|
||||
func on_action_selected() -> void:
|
||||
current_action = escoria.esc_runner.current_action
|
||||
update_tooltip_text()
|
||||
|
||||
func on_element_focused(element_id : String) -> void:
|
||||
printt("action_target_tooltip.gd:on_element_focused()", "Element focused: ", element_id)
|
||||
|
||||
if element_id == "":
|
||||
set_target("")
|
||||
return
|
||||
|
||||
var object = escoria.esc_runner.get_object(element_id)
|
||||
|
||||
if object == null or !is_instance_valid(object):
|
||||
escoria.report_warnings("action_target_tooltip.gd:on_element_focused()",
|
||||
["Object exists but is not loaded for id " + element_id])
|
||||
set_target(element_id)
|
||||
return
|
||||
|
||||
if !escoria.esc_runner.get_interactive(element_id) and !object is ESCInventoryItem:
|
||||
set_target("")
|
||||
return
|
||||
|
||||
var wait_for_target = false
|
||||
if object is ESCItem or object is ESCInventoryItem:
|
||||
if current_action in object.combine_if_action_used_among:
|
||||
wait_for_target = true
|
||||
|
||||
set_target(object.tooltip_name, wait_for_target)
|
||||
|
||||
|
||||
func set_target(target : String, needs_second_target : bool = false) -> void:
|
||||
current_target = target
|
||||
if needs_second_target:
|
||||
waiting_for_target2 = true
|
||||
|
||||
update_tooltip_text()
|
||||
|
||||
|
||||
func set_target2(target2 : String) -> void:
|
||||
current_target2 = target2
|
||||
update_tooltip_text()
|
||||
|
||||
|
||||
func update_tooltip_text():
|
||||
bbcode_text = "[center]"
|
||||
|
||||
if !current_action.empty():
|
||||
bbcode_text += current_action
|
||||
bbcode_text += "\t"
|
||||
|
||||
bbcode_text += current_target
|
||||
|
||||
if waiting_for_target2 and current_target2.empty():
|
||||
bbcode_text += "\t"
|
||||
bbcode_text += current_prep
|
||||
|
||||
if !current_target2.empty():
|
||||
bbcode_text += "\t"
|
||||
bbcode_text += current_prep
|
||||
bbcode_text += "\t"
|
||||
bbcode_text += current_target2
|
||||
|
||||
bbcode_text += "[/center]"
|
||||
@@ -0,0 +1,26 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/assets/fonts/onesize/ONESIZE_.TTF" type="DynamicFontData" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/label/action_target_tooltip.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="DynamicFont" id=1]
|
||||
size = 30
|
||||
font_data = ExtResource( 1 )
|
||||
|
||||
[sub_resource type="DynamicFont" id=2]
|
||||
size = 30
|
||||
font_data = ExtResource( 1 )
|
||||
|
||||
[node name="tooltip" type="RichTextLabel"]
|
||||
anchor_right = 0.526
|
||||
anchor_bottom = 0.06
|
||||
margin_right = -0.280029
|
||||
margin_bottom = -10.0
|
||||
custom_fonts/mono_font = SubResource( 1 )
|
||||
custom_fonts/normal_font = SubResource( 2 )
|
||||
bbcode_enabled = true
|
||||
scroll_active = false
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
11
addons/escoria-core/template_scenes/label/target_tooltip.gd
Normal file
11
addons/escoria-core/template_scenes/label/target_tooltip.gd
Normal file
@@ -0,0 +1,11 @@
|
||||
extends RichTextLabel
|
||||
|
||||
var current_target : String
|
||||
|
||||
|
||||
func set_target(target : String) -> void:
|
||||
current_target = target
|
||||
update_tooltip_text()
|
||||
|
||||
func update_tooltip_text():
|
||||
bbcode_text = current_target
|
||||
@@ -0,0 +1,28 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/assets/fonts/onesize/ONESIZE_.TTF" type="DynamicFontData" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/label/target_tooltip.gd" type="Script" id=2]
|
||||
|
||||
[sub_resource type="DynamicFont" id=1]
|
||||
size = 30
|
||||
font_data = ExtResource( 1 )
|
||||
|
||||
[sub_resource type="DynamicFont" id=2]
|
||||
size = 30
|
||||
font_data = ExtResource( 1 )
|
||||
|
||||
[node name="tooltip" type="RichTextLabel"]
|
||||
anchor_right = 0.7
|
||||
anchor_bottom = 0.06
|
||||
margin_left = 1.49829
|
||||
margin_right = 1.21826
|
||||
margin_bottom = -10.0
|
||||
custom_fonts/mono_font = SubResource( 1 )
|
||||
custom_fonts/normal_font = SubResource( 2 )
|
||||
bbcode_enabled = true
|
||||
bbcode_text = "[center][/center]"
|
||||
scroll_active = false
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
35
addons/escoria-core/template_scenes/room.tscn
Normal file
35
addons/escoria-core/template_scenes/room.tscn
Normal file
@@ -0,0 +1,35 @@
|
||||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/escterrain.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/escbackground.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/eschotspot.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/escroom.gd" type="Script" id=4]
|
||||
|
||||
[sub_resource type="NavigationPolygon" id=1]
|
||||
|
||||
[node name="room" type="Node2D"]
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="ESCBackground" type="TextureRect" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
mouse_filter = 2
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="walkable_area" type="Navigation2D" parent="."]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="area" type="NavigationPolygonInstance" parent="walkable_area"]
|
||||
navpoly = SubResource( 1 )
|
||||
|
||||
[node name="Hotspots" type="Node2D" parent="."]
|
||||
|
||||
[node name="ESCHotspot" type="Area2D" parent="Hotspots"]
|
||||
script = ExtResource( 3 )
|
||||
dialog_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Hotspots/ESCHotspot"]
|
||||
polygon = PoolVector2Array( 105, 65, 157, 47, 186, 118, 87, 134, 77, 87 )
|
||||
46
addons/escoria-core/template_scenes/verbs_cursor_icons.tscn
Normal file
46
addons/escoria-core/template_scenes/verbs_cursor_icons.tscn
Normal file
@@ -0,0 +1,46 @@
|
||||
[gd_scene load_steps=5 format=2]
|
||||
|
||||
[ext_resource path="res://game/ui/ui_mouse_icons/cursors/cursor_hand.png" type="Texture" id=1]
|
||||
[ext_resource path="res://game/ui/ui_mouse_icons/cursors/cursor_foot.png" type="Texture" id=2]
|
||||
[ext_resource path="res://game/ui/ui_mouse_icons/cursors/cursor_examine.png" type="Texture" id=3]
|
||||
[ext_resource path="res://game/ui/ui_mouse_icons/cursors/cursor_tool.png" type="Texture" id=4]
|
||||
|
||||
|
||||
|
||||
[node name="verbs_menu" type="Control"]
|
||||
margin_left = 1.0
|
||||
margin_right = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="actions" type="GridContainer" parent="."]
|
||||
margin_right = 333.0
|
||||
margin_bottom = 175.0
|
||||
columns = 3
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="look" type="TextureRect" parent="actions"]
|
||||
margin_right = 301.0
|
||||
margin_bottom = 300.0
|
||||
texture = ExtResource( 3 )
|
||||
|
||||
[node name="walk" type="TextureRect" parent="actions"]
|
||||
margin_left = 305.0
|
||||
margin_right = 606.0
|
||||
margin_bottom = 300.0
|
||||
texture = ExtResource( 2 )
|
||||
|
||||
[node name="pickup" type="TextureRect" parent="actions"]
|
||||
margin_left = 610.0
|
||||
margin_right = 911.0
|
||||
margin_bottom = 300.0
|
||||
texture = ExtResource( 1 )
|
||||
|
||||
[node name="use" type="TextureRect" parent="actions"]
|
||||
margin_top = 304.0
|
||||
margin_right = 301.0
|
||||
margin_bottom = 604.0
|
||||
texture = ExtResource( 4 )
|
||||
14
addons/escoria-core/template_scenes/verbs_menu_scumm9.gd
Normal file
14
addons/escoria-core/template_scenes/verbs_menu_scumm9.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
for but in $actions.get_children():
|
||||
but.connect("pressed", self, "_on_action_selected", [but.name])
|
||||
but.toggle_mode = true
|
||||
|
||||
func _on_action_selected(action : String):
|
||||
escoria.set_current_action(action)
|
||||
|
||||
for but in $actions.get_children():
|
||||
but.set_pressed(but.get_name() == action)
|
||||
|
||||
121
addons/escoria-core/template_scenes/verbs_menu_scumm9.tscn
Normal file
121
addons/escoria-core/template_scenes/verbs_menu_scumm9.tscn
Normal file
@@ -0,0 +1,121 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/verbs_menu_scumm9.gd" type="Script" id=1]
|
||||
|
||||
[node name="verbs_menu" type="Control"]
|
||||
margin_left = 1.0
|
||||
margin_right = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="actions" type="GridContainer" parent="."]
|
||||
margin_right = 333.0
|
||||
margin_bottom = 175.0
|
||||
columns = 3
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="open" type="Button" parent="actions"]
|
||||
margin_right = 108.0
|
||||
margin_bottom = 55.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Open"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="pickup" type="Button" parent="actions"]
|
||||
margin_left = 112.0
|
||||
margin_right = 220.0
|
||||
margin_bottom = 55.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Pick up"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="push" type="Button" parent="actions"]
|
||||
margin_left = 224.0
|
||||
margin_right = 332.0
|
||||
margin_bottom = 55.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Push"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="close" type="Button" parent="actions"]
|
||||
margin_top = 59.0
|
||||
margin_right = 108.0
|
||||
margin_bottom = 114.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Close"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="lookat" type="Button" parent="actions"]
|
||||
margin_left = 112.0
|
||||
margin_top = 59.0
|
||||
margin_right = 220.0
|
||||
margin_bottom = 114.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Look at"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="pull" type="Button" parent="actions"]
|
||||
margin_left = 224.0
|
||||
margin_top = 59.0
|
||||
margin_right = 332.0
|
||||
margin_bottom = 114.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Pull"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="give" type="Button" parent="actions"]
|
||||
margin_top = 118.0
|
||||
margin_right = 108.0
|
||||
margin_bottom = 173.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Give"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="use" type="Button" parent="actions"]
|
||||
margin_left = 112.0
|
||||
margin_top = 118.0
|
||||
margin_right = 220.0
|
||||
margin_bottom = 173.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Use"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="talk" type="Button" parent="actions"]
|
||||
margin_left = 224.0
|
||||
margin_top = 118.0
|
||||
margin_right = 332.0
|
||||
margin_bottom = 173.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
text = "Talk"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
BIN
addons/escoria-core/testing/NotoSans-Regular.ttf
Normal file
BIN
addons/escoria-core/testing/NotoSans-Regular.ttf
Normal file
Binary file not shown.
8
addons/escoria-core/testing/README
Normal file
8
addons/escoria-core/testing/README
Normal file
@@ -0,0 +1,8 @@
|
||||
In this folder, you can find various scenes and tools to test some of the scenes of your actual game project.
|
||||
|
||||
These scenes are not intended to be shipped with your game, you may want to use them only for testing purposes, such as:
|
||||
|
||||
- RichTextLabels screen clamping (rtl_screen_clamping.tscn)
|
||||
This scene helps you test the RichTextLabels used in your game, such as labels used when pointing an item or NPC or dialogs.
|
||||
To use this testing scene, simply add your actual label scene as a child of the root node and set the path to this node in it.
|
||||
You can then run the scene, move your mouse around the edges of the screen and see if the label reacts properly.
|
||||
231
addons/escoria-core/testing/player_angles_finder.gd
Normal file
231
addons/escoria-core/testing/player_angles_finder.gd
Normal file
@@ -0,0 +1,231 @@
|
||||
extends Node2D
|
||||
|
||||
# This scenes purpose is to help determining the angles between X and Y axis
|
||||
# when clicking somewhere on the screen.
|
||||
# Let us consider that player position is always 0,0.
|
||||
# Clicking right above his head is angle 0.
|
||||
# Clicking on the right is angle 90.
|
||||
# Clicking under his feet is angle 180.
|
||||
# etc.
|
||||
|
||||
var number_of_directions : int
|
||||
var angle_horizontal_axes : float
|
||||
var angle_vertical_axes : float
|
||||
var angle_diagonal_axes : float
|
||||
const POLYGON_DISTANCE = 400
|
||||
|
||||
enum Directions {
|
||||
NORTH, # 0
|
||||
NORTHEAST, # 1
|
||||
EAST, # 2
|
||||
SOUTHEAST, # 3
|
||||
SOUTH, # 4
|
||||
SOUTHWEST, # 5
|
||||
WEST, # 6
|
||||
NORTHWEST # 7
|
||||
}
|
||||
|
||||
const starting_angles = [
|
||||
0, # 0 NORTH
|
||||
PI/4, # 1 NORTHEAST
|
||||
PI/2, # 2 EAST
|
||||
3*PI/4, # 3 SOUTHEAST
|
||||
PI, # 4 SOUTH
|
||||
5*PI/4, # 5 SOUTHWEST
|
||||
3*PI/2, # 6 WEST
|
||||
7*PI/4, # 7 NORTHWEST
|
||||
]
|
||||
|
||||
var colors = [
|
||||
ColorN("red"), # 0 NORTH
|
||||
ColorN("green"), # 1 NORTHEAST
|
||||
ColorN("blue"), # 2 EAST
|
||||
ColorN("black"), # 3 SOUTHEAST
|
||||
ColorN("yellow"), # 4 SOUTH
|
||||
ColorN("cyan"), # 5 SOUTHWEST
|
||||
ColorN("white"), # 6 WEST
|
||||
ColorN("purple") # 7 NORTHWEST
|
||||
]
|
||||
|
||||
var result_angles = []
|
||||
|
||||
#onready var result_angles_anim = {
|
||||
# "angle_offset_rad" : PI/2,
|
||||
# Directions.NORTH : {
|
||||
# "direction_base_angle_rad" : 0,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animations" : {}
|
||||
# },
|
||||
# Directions.NORTHEAST : {
|
||||
# "direction_base_angle_rad" : PI/4,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
# },
|
||||
# Directions.EAST : {
|
||||
# "direction_base_angle_rad" : PI/2,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
# },
|
||||
# Directions.SOUTHEAST : {
|
||||
# "direction_base_angle_rad" : 3*PI/4,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
# },
|
||||
# Directions.SOUTH : {
|
||||
# "direction_base_angle_rad" : PI,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
#
|
||||
# },
|
||||
# Directions.SOUTHWEST : {
|
||||
# "direction_base_angle_rad" : 5*PI/4,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
# },
|
||||
# Directions.WEST : {
|
||||
# "direction_base_angle_rad" : 3*PI/2,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
# },
|
||||
# Directions.NORTHWEST : {
|
||||
# "direction_base_angle_rad" : 7*PI/4,
|
||||
# "angle_start_deg" : 0,
|
||||
# "angle_area_deg" : 0,
|
||||
# "animation" : ""
|
||||
# }
|
||||
# }
|
||||
|
||||
|
||||
|
||||
func _ready():
|
||||
# Find player animations
|
||||
$player_animations.add_item("")
|
||||
for anim_name in $player.get_animations_list():
|
||||
$player_animations.add_item(anim_name)
|
||||
|
||||
# Set initial angles
|
||||
var initial_angle : float = 360.0 / 8.0
|
||||
$VBoxContainer/angle_x/angle_horiz.text = str(40)
|
||||
$VBoxContainer/angle_y/angle_vert.text = str(40)
|
||||
$VBoxContainer/angle_diag/angle_diag.text = str(50)
|
||||
angle_horizontal_axes = 40
|
||||
angle_vertical_axes = 40
|
||||
angle_diagonal_axes = 50
|
||||
|
||||
calculate_areas()
|
||||
|
||||
|
||||
func _on_number_of_directions_text_changed(new_text : String):
|
||||
if !new_text.is_valid_integer():
|
||||
return
|
||||
number_of_directions = int(new_text)
|
||||
calculate_areas(number_of_directions)
|
||||
|
||||
|
||||
func clear_areas_node():
|
||||
for n in $areas.get_children():
|
||||
n.queue_free()
|
||||
|
||||
|
||||
func calculate_areas(nb_directions : int = 8):
|
||||
clear_areas_node()
|
||||
var angles = []
|
||||
for i in range(nb_directions):
|
||||
var angle_area : float = 0.0
|
||||
var start_angle : float = 0.0
|
||||
# MANUAL
|
||||
match i:
|
||||
Directions.EAST,Directions.WEST:
|
||||
angle_area = deg2rad(angle_horizontal_axes)
|
||||
Directions.NORTH,Directions.SOUTH:
|
||||
angle_area = deg2rad(angle_vertical_axes)
|
||||
Directions.NORTHEAST,Directions.NORTHWEST,Directions.SOUTHEAST,Directions.SOUTHWEST:
|
||||
angle_area = deg2rad(angle_diagonal_axes)
|
||||
|
||||
# Since angles start from EAST, offset by -PI/2 (= -90°) to start on up direction
|
||||
# Then minus angle_area/2 to align on direction
|
||||
start_angle = PI/2 + angle_area / 2
|
||||
|
||||
var angle_start = starting_angles[i] - start_angle
|
||||
var angle_end = angle_start + angle_area
|
||||
angles.push_back([angle_start, angle_end])
|
||||
|
||||
result_angles.push_back([clamp360(rad2deg(angle_start) + rad2deg(PI/2)),clamp360(rad2deg(angle_area))])
|
||||
|
||||
$VBoxContainer/VBoxContainer/angles/angle_array.text = str(result_angles)
|
||||
construct_scene_nodes(angles)
|
||||
|
||||
func construct_scene_nodes(angles):
|
||||
|
||||
var areas_nodes = []
|
||||
for i in angles.size():
|
||||
var polygon_node = Polygon2D.new()
|
||||
polygon_node.color = colors[i]
|
||||
var area_node = Area2D.new()
|
||||
area_node.name = Directions.keys()[i]
|
||||
area_node.connect("input_event", self, "_on_area_click", [area_node.name])
|
||||
polygon_node.add_child(area_node)
|
||||
|
||||
var collision = CollisionShape2D.new()
|
||||
var collision_shape = ConvexPolygonShape2D.new()
|
||||
|
||||
var p_points = []
|
||||
p_points.push_back($player.position)
|
||||
p_points.push_back(polar2cartesian(POLYGON_DISTANCE, angles[i][0]) + $player.position)
|
||||
p_points.push_back(polar2cartesian(POLYGON_DISTANCE, angles[i][1]) + $player.position)
|
||||
polygon_node.polygon = p_points
|
||||
collision_shape.points = p_points
|
||||
collision.set_shape(collision_shape)
|
||||
area_node.add_child(collision)
|
||||
|
||||
$areas.add_child(polygon_node)
|
||||
|
||||
|
||||
func _on_angle_horiz_text_changed(new_text : String):
|
||||
if !new_text.is_valid_float():
|
||||
return
|
||||
angle_horizontal_axes = float(new_text)
|
||||
# result_angles_anim.Directions.EAST.angle_area_deg = clamp360(angle_horizontal_axes)
|
||||
# result_angles_anim.Directions.WEST.angle_area_deg = clamp360(angle_horizontal_axes)
|
||||
calculate_areas()
|
||||
|
||||
|
||||
func _on_angle_vert_text_changed(new_text : String):
|
||||
if !new_text.is_valid_float():
|
||||
return
|
||||
angle_vertical_axes = float(new_text)
|
||||
# result_angles_anim.Directions.NORTH.angle_area_deg = clamp360(angle_vertical_axes)
|
||||
# result_angles_anim.Directions.SOUTH.angle_area_deg = clamp360(angle_vertical_axes)
|
||||
calculate_areas()
|
||||
|
||||
|
||||
func _on_angle_diag_text_changed(new_text : String):
|
||||
if !new_text.is_valid_float():
|
||||
return
|
||||
angle_diagonal_axes = float(new_text)
|
||||
# result_angles_anim.Directions.NORTHEAST.angle_area_deg = clamp360(angle_diagonal_axes)
|
||||
# result_angles_anim.Directions.SOUTHEAST.angle_area_deg = clamp360(angle_diagonal_axes)
|
||||
# result_angles_anim.Directions.NORTHWEST.angle_area_deg = clamp360(angle_diagonal_axes)
|
||||
# result_angles_anim.Directions.SOUTHWEST.angle_area_deg = clamp360(angle_diagonal_axes)
|
||||
calculate_areas()
|
||||
|
||||
|
||||
func _on_area_click(viewport: Object, event: InputEvent, shape_idx: int, area_name : String):
|
||||
if event is InputEventMouseButton and event.is_pressed():
|
||||
pass
|
||||
|
||||
func clamp360(angle : float):
|
||||
if angle < 0.0:
|
||||
while angle < 0.0:
|
||||
angle += 360.0
|
||||
elif angle >= 360.0:
|
||||
while angle >= 360.0:
|
||||
angle -= 360.0
|
||||
return angle
|
||||
219
addons/escoria-core/testing/player_angles_finder.tscn
Normal file
219
addons/escoria-core/testing/player_angles_finder.tscn
Normal file
@@ -0,0 +1,219 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://game/characters/guybrush/guybrush.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/testing/player_angles_finder.gd" type="Script" id=2]
|
||||
|
||||
[node name="player_angles_finder" type="Node2D"]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="areas" type="Node2D" parent="."]
|
||||
|
||||
[node name="player" parent="." instance=ExtResource( 1 )]
|
||||
position = Vector2( 640, 480 )
|
||||
dialog_position_node = NodePath("../../player_angles_finder/player/dialog_position")
|
||||
|
||||
[node name="x_axis" type="Line2D" parent="."]
|
||||
points = PoolVector2Array( -10, 480, 1300, 480 )
|
||||
width = 2.0
|
||||
default_color = Color( 0.980392, 0.00392157, 0.00392157, 1 )
|
||||
|
||||
[node name="y_axis" type="Line2D" parent="."]
|
||||
points = PoolVector2Array( 640, -20, 640, 810 )
|
||||
width = 2.0
|
||||
default_color = Color( 0.156863, 0.0117647, 0.984314, 1 )
|
||||
|
||||
[node name="three" type="Node2D" parent="."]
|
||||
visible = false
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="three"]
|
||||
points = PoolVector2Array( 160, 0, 1120, 960 )
|
||||
width = 2.0
|
||||
default_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Line2D2" type="Line2D" parent="three"]
|
||||
points = PoolVector2Array( 160, 960, 1120, 0 )
|
||||
width = 2.0
|
||||
default_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="six" type="Node2D" parent="."]
|
||||
visible = false
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="six"]
|
||||
points = PoolVector2Array( 0, 210, 640, 480 )
|
||||
width = 2.0
|
||||
default_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Line2D4" type="Line2D" parent="six"]
|
||||
points = PoolVector2Array( 320, 0, 640, 480 )
|
||||
width = 2.0
|
||||
default_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Line2D2" type="Line2D" parent="six"]
|
||||
points = PoolVector2Array( 640, 480, 1280, 210 )
|
||||
width = 2.0
|
||||
default_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="Line2D3" type="Line2D" parent="six"]
|
||||
points = PoolVector2Array( 640, 480, 960, 0 )
|
||||
width = 2.0
|
||||
default_color = Color( 1, 1, 1, 1 )
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
visible = false
|
||||
margin_right = 420.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"]
|
||||
margin_top = 5.0
|
||||
margin_right = 136.0
|
||||
margin_bottom = 19.0
|
||||
text = "Number of directions"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="number_of_directions" type="LineEdit" parent="VBoxContainer/HBoxContainer"]
|
||||
margin_left = 140.0
|
||||
margin_right = 198.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_x" type="HBoxContainer" parent="VBoxContainer"]
|
||||
margin_right = 235.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/angle_x"]
|
||||
margin_top = 5.0
|
||||
margin_right = 173.0
|
||||
margin_bottom = 19.0
|
||||
text = "Angle on horizontal axis (X)"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_horiz" type="LineEdit" parent="VBoxContainer/angle_x"]
|
||||
margin_left = 177.0
|
||||
margin_right = 235.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_y" type="HBoxContainer" parent="VBoxContainer"]
|
||||
margin_top = 28.0
|
||||
margin_right = 235.0
|
||||
margin_bottom = 52.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/angle_y"]
|
||||
margin_top = 5.0
|
||||
margin_right = 155.0
|
||||
margin_bottom = 19.0
|
||||
text = "Angle on vertical axis (Y)"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_vert" type="LineEdit" parent="VBoxContainer/angle_y"]
|
||||
margin_left = 159.0
|
||||
margin_right = 217.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_diag" type="HBoxContainer" parent="VBoxContainer"]
|
||||
margin_top = 56.0
|
||||
margin_right = 235.0
|
||||
margin_bottom = 80.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/angle_diag"]
|
||||
margin_top = 5.0
|
||||
margin_right = 146.0
|
||||
margin_bottom = 19.0
|
||||
text = "Angle on diagonal axes"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_diag" type="LineEdit" parent="VBoxContainer/angle_diag"]
|
||||
margin_left = 150.0
|
||||
margin_right = 208.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
|
||||
margin_top = 84.0
|
||||
margin_right = 235.0
|
||||
margin_bottom = 88.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer"]
|
||||
margin_top = 92.0
|
||||
margin_right = 235.0
|
||||
margin_bottom = 116.0
|
||||
__meta__ = {
|
||||
"_editor_description_": ""
|
||||
}
|
||||
|
||||
[node name="angles" type="HBoxContainer" parent="VBoxContainer/VBoxContainer"]
|
||||
margin_right = 235.0
|
||||
margin_bottom = 24.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/VBoxContainer/angles"]
|
||||
margin_top = 5.0
|
||||
margin_right = 78.0
|
||||
margin_bottom = 19.0
|
||||
text = "Angles array"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="angle_array" type="LineEdit" parent="VBoxContainer/VBoxContainer/angles"]
|
||||
margin_left = 82.0
|
||||
margin_right = 235.0
|
||||
margin_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
editable = false
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="player_animations" type="OptionButton" parent="."]
|
||||
visible = false
|
||||
margin_left = 470.0
|
||||
margin_top = 10.0
|
||||
margin_right = 638.0
|
||||
margin_bottom = 33.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
[connection signal="text_changed" from="VBoxContainer/HBoxContainer/number_of_directions" to="." method="_on_number_of_directions_text_changed"]
|
||||
[connection signal="text_changed" from="VBoxContainer/angle_x/angle_horiz" to="." method="_on_angle_horiz_text_changed"]
|
||||
[connection signal="text_changed" from="VBoxContainer/angle_y/angle_vert" to="." method="_on_angle_vert_text_changed"]
|
||||
[connection signal="text_changed" from="VBoxContainer/angle_diag/angle_diag" to="." method="_on_angle_diag_text_changed"]
|
||||
[connection signal="text_changed" from="VBoxContainer/VBoxContainer/angles/angle_array" to="." method="_on_angle_diag_text_changed"]
|
||||
169
addons/escoria-core/testing/rtl_screen_offset_testing.gd
Normal file
169
addons/escoria-core/testing/rtl_screen_offset_testing.gd
Normal file
@@ -0,0 +1,169 @@
|
||||
extends Control
|
||||
|
||||
onready var screen_width = get_tree().get_root().get_viewport().size.x
|
||||
onready var screen_height = get_tree().get_root().get_viewport().size.y
|
||||
var global_distance_to_clamp = 40 setget set_global_dist_clamp,get_global_dist_clamp
|
||||
|
||||
signal mouse_moved(position)
|
||||
signal text_selected(text)
|
||||
|
||||
export(NodePath) var path_to_richtextlabel
|
||||
const ONE_LINE_HEIGHT = 16
|
||||
export(int) var max_width = 200
|
||||
|
||||
func _ready():
|
||||
assert(!path_to_richtextlabel.is_empty())
|
||||
$VBoxContainer/HBoxContainer/clamp_distance.text = str(global_distance_to_clamp)
|
||||
|
||||
# Add a white TextureRect behind the RTL to see its actual size
|
||||
var texturerect_node = TextureRect.new()
|
||||
get_node(path_to_richtextlabel).add_child(texturerect_node)
|
||||
texturerect_node.texture = load("res://addons/escoria-core/testing/white.png")
|
||||
texturerect_node.expand = true
|
||||
texturerect_node.stretch_mode = TextureRect.STRETCH_TILE
|
||||
texturerect_node.size_flags_horizontal = SIZE_EXPAND_FILL
|
||||
texturerect_node.size_flags_vertical = SIZE_EXPAND_FILL
|
||||
texturerect_node.show_behind_parent = true
|
||||
texturerect_node.anchor_right = 1.0
|
||||
texturerect_node.anchor_bottom = 1.0
|
||||
move_child(get_node(path_to_richtextlabel), 1)
|
||||
|
||||
update_line2d()
|
||||
_on_new_text_pressed()
|
||||
set_process_input(true)
|
||||
|
||||
func set_path_to_richtextlabel(path):
|
||||
path_to_richtextlabel = path
|
||||
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventMouseMotion:
|
||||
emit_signal("mouse_moved", event.position)
|
||||
|
||||
func set_global_dist_clamp(d):
|
||||
global_distance_to_clamp = d
|
||||
update_line2d()
|
||||
|
||||
func get_global_dist_clamp():
|
||||
return global_distance_to_clamp
|
||||
|
||||
func update_line2d():
|
||||
$Line2D.clear_points()
|
||||
$Line2D.add_point(Vector2(global_distance_to_clamp, global_distance_to_clamp))
|
||||
$Line2D.add_point(Vector2(global_distance_to_clamp, screen_height - global_distance_to_clamp))
|
||||
$Line2D.add_point(Vector2(screen_width - global_distance_to_clamp, screen_height - global_distance_to_clamp))
|
||||
$Line2D.add_point(Vector2(screen_width - global_distance_to_clamp, global_distance_to_clamp))
|
||||
$Line2D.add_point(Vector2(global_distance_to_clamp, global_distance_to_clamp))
|
||||
|
||||
|
||||
func _on_new_text_pressed():
|
||||
var pressed_button = $HBoxContainer2/foo.group.get_pressed_button()
|
||||
printt(pressed_button.name, pressed_button.text)
|
||||
emit_signal("text_selected", pressed_button.text)
|
||||
|
||||
|
||||
func tooltip_distance_to_edge_top(position_y):
|
||||
return position_y
|
||||
|
||||
func tooltip_distance_to_edge_bottom(position_y):
|
||||
return screen_height - position_y
|
||||
|
||||
func tooltip_distance_to_edge_left(position_x):
|
||||
return position_x
|
||||
|
||||
func tooltip_distance_to_edge_right(position_x):
|
||||
return screen_width - position_x
|
||||
|
||||
func _on_Control_mouse_moved(mouse_pos):
|
||||
# printt("mousepos", mouse_pos)
|
||||
# printt("label_container_pos", rect_position)
|
||||
|
||||
#var corrected_position = _offset(new_pos)
|
||||
var corrected_position = mouse_pos
|
||||
|
||||
# clamp TOP
|
||||
if tooltip_distance_to_edge_top(mouse_pos.y) <= global_distance_to_clamp:
|
||||
corrected_position.y = global_distance_to_clamp
|
||||
|
||||
# clamp BOTTOM
|
||||
if tooltip_distance_to_edge_bottom(mouse_pos.y + get_node(path_to_richtextlabel).rect_size.y) <= global_distance_to_clamp:
|
||||
corrected_position.y = screen_height - global_distance_to_clamp - get_node(path_to_richtextlabel).rect_size.y
|
||||
|
||||
# clamp LEFT
|
||||
if tooltip_distance_to_edge_left(mouse_pos.x - get_node(path_to_richtextlabel).rect_size.x/2) <= global_distance_to_clamp:
|
||||
corrected_position.x = global_distance_to_clamp
|
||||
|
||||
# clamp RIGHT
|
||||
if tooltip_distance_to_edge_right(mouse_pos.x + get_node(path_to_richtextlabel).rect_size.x/2) <= global_distance_to_clamp:
|
||||
corrected_position.x = screen_width - global_distance_to_clamp - get_node(path_to_richtextlabel).rect_size.x
|
||||
|
||||
get_node(path_to_richtextlabel).anchor_right = 0.2
|
||||
get_node(path_to_richtextlabel).rect_position = corrected_position
|
||||
|
||||
|
||||
func _on_Control_text_selected(text):
|
||||
get_node(path_to_richtextlabel).bbcode_text = "[color=red]" + text.replace("<br>", "\n") + "[/color]"
|
||||
update_size()
|
||||
|
||||
func _on_clamp_distance_text_changed(new_text):
|
||||
global_distance_to_clamp = int(new_text)
|
||||
update_line2d()
|
||||
|
||||
func _on_rtl_sizex_text_changed(text):
|
||||
pass
|
||||
get_node(path_to_richtextlabel).rect_size.x = float(text)
|
||||
update_size()
|
||||
|
||||
|
||||
func _offset(position):
|
||||
var center_offset_x = rect_size.x / 2
|
||||
var offset_y = 5
|
||||
|
||||
position.x -= center_offset_x
|
||||
position.y += offset_y
|
||||
return position
|
||||
|
||||
|
||||
func update_size():
|
||||
## RECT_SIZE ##
|
||||
var rtl_node = get_node(path_to_richtextlabel)
|
||||
var rtl_width = rtl_node.rect_size.x
|
||||
var rtl_height = rtl_node.rect_size.y
|
||||
var content_height = rtl_node.get_content_height()
|
||||
var nb_visible_characters = rtl_node.visible_characters
|
||||
var nb_visible_lines = rtl_node.get_visible_line_count()
|
||||
|
||||
printt("BEFORE", "text_height", content_height, "rtl_height", rtl_node.rect_size.y)
|
||||
|
||||
# if text is too long and is wrapped
|
||||
# var nblines = float(rtl_node.get_content_height()) / float(ONE_LINE_HEIGHT)
|
||||
var nblines = nb_visible_lines
|
||||
if nblines >= 1:
|
||||
# reset size
|
||||
#get_parent().rect_size.x = 10
|
||||
#get_parent().rect_size.y = ONE_LINE_HEIGHT
|
||||
|
||||
var text_height = rtl_node.get_content_height()
|
||||
var parent_width = rtl_node.rect_size.x
|
||||
|
||||
# first, try to increase width until it goes above max_width
|
||||
while parent_width < max_width && float(text_height) / float(ONE_LINE_HEIGHT) > 1.0:
|
||||
rtl_node.rect_size.x += 1
|
||||
parent_width = rtl_node.rect_size.x
|
||||
yield(get_tree(), "idle_frame")
|
||||
yield(get_tree(), "idle_frame")
|
||||
# text_height = get_parent().rect_size.y
|
||||
|
||||
rtl_node.rect_size.y = text_height
|
||||
|
||||
if rtl_node.rect_size.x >= max_width:
|
||||
rtl_node.rect_size.x = max_width
|
||||
|
||||
|
||||
|
||||
## END RECT_SIZE ##
|
||||
rtl_node.anchor_top = 0.0
|
||||
rtl_node.anchor_right = 0.0
|
||||
rtl_node.anchor_bottom = 0.0
|
||||
rtl_node.anchor_left = 0.0
|
||||
printt("AFTER", "text_height", get_node(path_to_richtextlabel).get_content_height(), "rtl_height", rtl_node.rect_size.y)
|
||||
90
addons/escoria-core/testing/rtl_screen_offset_testing.tscn
Normal file
90
addons/escoria-core/testing/rtl_screen_offset_testing.tscn
Normal file
@@ -0,0 +1,90 @@
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/testing/rtl_screen_offset_testing.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/template_scenes/label/target_tooltip.tscn" type="PackedScene" id=2]
|
||||
|
||||
[sub_resource type="ButtonGroup" id=1]
|
||||
|
||||
[node name="rtl_screen_offset" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = -1280.0
|
||||
margin_bottom = -800.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_lock_": true
|
||||
}
|
||||
path_to_richtextlabel = NodePath("tooltip")
|
||||
|
||||
[node name="Line2D" type="Line2D" parent="."]
|
||||
points = PoolVector2Array( 40, 40, 40, 976, 1808, 976, 1808, 40, 40, 40 )
|
||||
width = 2.51
|
||||
texture_mode = 116
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_left = 315.72
|
||||
margin_top = 269.104
|
||||
margin_right = 475.72
|
||||
margin_bottom = 321.104
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
margin_right = 160.0
|
||||
margin_bottom = 24.0
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"]
|
||||
margin_top = 5.0
|
||||
margin_right = 98.0
|
||||
margin_bottom = 19.0
|
||||
text = "Clamp distance"
|
||||
|
||||
[node name="clamp_distance" type="LineEdit" parent="VBoxContainer/HBoxContainer"]
|
||||
margin_left = 102.0
|
||||
margin_right = 160.0
|
||||
margin_bottom = 24.0
|
||||
text = "40"
|
||||
max_length = 4
|
||||
|
||||
[node name="HBoxContainer2" type="VBoxContainer" parent="."]
|
||||
margin_left = 310.0
|
||||
margin_top = 340.0
|
||||
margin_right = 470.0
|
||||
margin_bottom = 380.0
|
||||
|
||||
[node name="foo" type="CheckBox" parent="HBoxContainer2"]
|
||||
margin_right = 624.0
|
||||
margin_bottom = 24.0
|
||||
pressed = true
|
||||
group = SubResource( 1 )
|
||||
text = "Foo"
|
||||
|
||||
[node name="foobar" type="CheckBox" parent="HBoxContainer2"]
|
||||
margin_top = 28.0
|
||||
margin_right = 624.0
|
||||
margin_bottom = 52.0
|
||||
group = SubResource( 1 )
|
||||
text = "Foo bar"
|
||||
|
||||
[node name="whatisit" type="CheckBox" parent="HBoxContainer2"]
|
||||
margin_top = 56.0
|
||||
margin_right = 624.0
|
||||
margin_bottom = 80.0
|
||||
group = SubResource( 1 )
|
||||
text = "Une phrase extremement<br>longue pour tester<br>le comportement de ce RichTextLabel..."
|
||||
|
||||
[node name="tooltip" parent="." instance=ExtResource( 2 )]
|
||||
margin_left = 238.815
|
||||
margin_top = 131.18
|
||||
margin_right = 638.815
|
||||
margin_bottom = 231.18
|
||||
rect_min_size = Vector2( 400, 0 )
|
||||
bbcode_text = "Tooltip content"
|
||||
fit_content_height = true
|
||||
[connection signal="mouse_moved" from="." to="." method="_on_Control_mouse_moved"]
|
||||
[connection signal="text_selected" from="." to="." method="_on_Control_text_selected"]
|
||||
[connection signal="text_changed" from="VBoxContainer/HBoxContainer/clamp_distance" to="." method="_on_clamp_distance_text_changed"]
|
||||
[connection signal="pressed" from="HBoxContainer2/foo" to="." method="_on_new_text_pressed"]
|
||||
[connection signal="pressed" from="HBoxContainer2/foobar" to="." method="_on_new_text_pressed"]
|
||||
[connection signal="pressed" from="HBoxContainer2/whatisit" to="." method="_on_new_text_pressed"]
|
||||
BIN
addons/escoria-core/testing/white.png
Normal file
BIN
addons/escoria-core/testing/white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 B |
34
addons/escoria-core/testing/white.png.import
Normal file
34
addons/escoria-core/testing/white.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/white.png-e746adb12fed1043fc3bcc319345fecb.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/escoria-core/testing/white.png"
|
||||
dest_files=[ "res://.import/white.png-e746adb12fed1043fc3bcc319345fecb.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=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
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
Reference in New Issue
Block a user