Implement save and loading games (#8)
This commit is contained in:
@@ -32,16 +32,16 @@ var walk_context: ESCWalkContext = null
|
||||
var moved: bool
|
||||
|
||||
# Angle degrees to the last position (TODO is that correct?)
|
||||
var last_deg : int
|
||||
var last_deg: int
|
||||
|
||||
# Direction of the last position (TODO is that correct?)
|
||||
var last_dir : int
|
||||
var last_dir: int
|
||||
|
||||
# Scale of the last position (TODO is that correct?)
|
||||
var last_scale : Vector2
|
||||
var last_scale: Vector2
|
||||
|
||||
# TODO Isn't this actually the flip state of the current animation?
|
||||
var pose_scale : int
|
||||
var pose_scale: int
|
||||
|
||||
|
||||
var _orig_speed: float = 0.0
|
||||
@@ -157,16 +157,9 @@ func _process(delta: float) -> void:
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - target: Vector2, Position2d or ESCItem
|
||||
func teleport(target, angle : Object = null) -> void:
|
||||
if typeof(target) == TYPE_VECTOR2 :
|
||||
escoria.logger.info(
|
||||
"Object %s teleported at position %s with angle" %
|
||||
[parent.global_id, str(target)],
|
||||
[angle]
|
||||
)
|
||||
parent.position = target
|
||||
elif target is Position2D:
|
||||
# - target: Position2d or ESCItem to teleport to
|
||||
func teleport(target: Node, angle: Object = null) -> void:
|
||||
if target is Position2D:
|
||||
escoria.logger.info(
|
||||
"Object %s teleported at position %s with angle" %
|
||||
[parent.global_id, str(target.position)],
|
||||
@@ -185,7 +178,27 @@ func teleport(target, angle : Object = null) -> void:
|
||||
+ str(parent.position) + " with angle ", str(angle))
|
||||
else:
|
||||
escoria.logger.report_errors("escitem.gd:teleport()",
|
||||
["Target to teleport to is null or unusable (" + target + ")"])
|
||||
["Target to teleport to is null or unusable (" + str(target) + ")"])
|
||||
|
||||
|
||||
# Teleports this item to the target position.
|
||||
# TODO angle is only used for logging and has no further use, so it probably
|
||||
# can be removed
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - target: Vector2 target position to teleport to
|
||||
func teleport_to(target: Vector2, angle: Object = null) -> void:
|
||||
if typeof(target) == TYPE_VECTOR2 :
|
||||
escoria.logger.info(
|
||||
"Object %s teleported at position %s with angle" %
|
||||
[parent.global_id, str(target)],
|
||||
[angle]
|
||||
)
|
||||
parent.position = target
|
||||
else:
|
||||
escoria.logger.report_errors("escitem.gd:teleport_to()",
|
||||
["Target to teleport to is null or unusable (" + str(target) + ")"])
|
||||
|
||||
|
||||
# Walk to a given position
|
||||
@@ -194,7 +207,7 @@ func teleport(target, angle : Object = null) -> void:
|
||||
#
|
||||
# - pos: Position to walk to
|
||||
# - p_walk_context: Walk context to use
|
||||
func walk_to(pos : Vector2, p_walk_context: ESCWalkContext = null) -> void:
|
||||
func walk_to(pos: Vector2, p_walk_context: ESCWalkContext = null) -> void:
|
||||
if not parent.terrain:
|
||||
walk_stop(parent.get_position())
|
||||
return
|
||||
@@ -334,7 +347,7 @@ func update_terrain(on_event_finished_name = null) -> void:
|
||||
#
|
||||
# - angle: The rotation angle
|
||||
# - animations: The list of character animations
|
||||
func _get_dir(angle : float, animations) -> int:
|
||||
func _get_dir(angle: float, animations) -> int:
|
||||
var deg = escoria.utils.get_deg_from_rad(angle)
|
||||
return _get_dir_deg(deg, animations)
|
||||
|
||||
@@ -377,10 +390,10 @@ func _get_dir_deg(deg: int, animations: Script) -> int:
|
||||
# #### Parameters
|
||||
#
|
||||
# - angle: Angle to test
|
||||
# - interval : Array of size 2, containing the starting angle, and the size of
|
||||
# - 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:
|
||||
func is_angle_in_interval(angle: float, interval: Array) -> bool:
|
||||
angle = wrapi(angle, 0, 360)
|
||||
if angle == 0:
|
||||
angle = 360
|
||||
@@ -419,7 +432,7 @@ func is_angle_in_interval(angle: float, interval : Array) -> bool:
|
||||
# - immediate bool (currently unused, see TODO below)
|
||||
# If true, direction is switched immediately. Else, successive animations are
|
||||
# used so that the character turns to target angle.
|
||||
func set_angle(deg : int, immediate = true) -> void:
|
||||
func set_angle(deg: int, immediate = true) -> void:
|
||||
if deg < 0 or deg > 360:
|
||||
escoria.logger.report_errors(
|
||||
"movable.gd:set_angle()",
|
||||
@@ -436,3 +449,8 @@ func set_angle(deg : int, immediate = true) -> void:
|
||||
parent.animation_sprite.play(parent.animations.idles[last_dir][0])
|
||||
pose_scale = parent.animations.idles[last_dir][1]
|
||||
update_terrain()
|
||||
|
||||
# Returns the angle that corresponds to the current direction of the object.
|
||||
func _get_angle() -> int:
|
||||
return parent.animations.dir_angles[last_dir][0]
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Sets the camera limits to the one defined under `camlimits_id` in ESCRoom's
|
||||
# camera_limits array.
|
||||
# - camlimits_id : int : id of the camera limits to apply (defined in ESCRoom's
|
||||
# - camlimits_id: int: id of the camera limits to apply (defined in ESCRoom's
|
||||
# camera_limits array)
|
||||
#
|
||||
# @ESC
|
||||
|
||||
@@ -19,7 +19,7 @@ func configure() -> ESCCommandArgumentDescriptor:
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var name : String = command_params[0]
|
||||
var name: String = command_params[0]
|
||||
if escoria.room_terrain.has_node(name):
|
||||
var new_active_navigation_instance = \
|
||||
escoria.room_terrain.get_node(name)
|
||||
|
||||
@@ -30,7 +30,7 @@ func configure() -> ESCCommandArgumentDescriptor:
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
|
||||
var dict : Dictionary
|
||||
var dict: Dictionary
|
||||
var dialog_scene_name = ProjectSettings.get_setting(
|
||||
"escoria/ui/default_dialog_scene"
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT],
|
||||
[null, true]
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
@@ -40,6 +40,6 @@ func run(command_params: Array) -> int:
|
||||
# angle against X axis not Y, we need to check direction using (angle-90°).
|
||||
# Since the ESC command already gives the right angle, we add 90.
|
||||
escoria.object_manager.get_object(command_params[0]).node\
|
||||
.set_angle(int(command_params[1] + 90))
|
||||
.set_angle(wrapi(int(command_params[1]) + 90, 0, 360))
|
||||
return ESCExecution.RC_OK
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# `teleport_pos object1 x y
|
||||
#
|
||||
# Sets the position of object1 to the position (x,y).
|
||||
# FIXME re-add the angle parameter here
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name TeleportPosCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"teleport_pos: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object(command_params[0]).node as ESCPlayer)\
|
||||
.teleport_to(Vector2(int(command_params[1]), int(command_params[2])))
|
||||
return ESCExecution.RC_OK
|
||||
@@ -8,14 +8,14 @@ signal action_changed
|
||||
|
||||
|
||||
# Current verb used
|
||||
var current_action : String = "" setget set_current_action
|
||||
var current_action: String = "" setget set_current_action
|
||||
|
||||
# Current tool (ESCItem/ESCInventoryItem) used
|
||||
var current_tool: ESCObject
|
||||
|
||||
|
||||
# Set the current action
|
||||
func set_current_action(action : String):
|
||||
func set_current_action(action: String):
|
||||
if action != current_action:
|
||||
clear_current_tool()
|
||||
|
||||
|
||||
@@ -93,3 +93,15 @@ func set_global_wildcard(pattern: String, value) -> void:
|
||||
for global_key in _globals.keys:
|
||||
if global_key.match(pattern):
|
||||
self.set_global(global_key, value)
|
||||
|
||||
|
||||
# Save the state of globals in the savegame.
|
||||
#
|
||||
# #### Parameters
|
||||
# - p_savegame: ESCSaveGame resource that holds all data of the save
|
||||
func save_game(p_savegame: ESCSaveGame) -> void:
|
||||
p_savegame.globals = {}
|
||||
for g in _globals:
|
||||
if g in RESERVED_GLOBALS:
|
||||
continue
|
||||
p_savegame.globals[g] = _globals[g]
|
||||
|
||||
@@ -4,7 +4,8 @@ class_name ESCObjectManager
|
||||
|
||||
|
||||
const RESERVED_OBJECTS = [
|
||||
"bg_music"
|
||||
"bg_music",
|
||||
"bg_sound"
|
||||
]
|
||||
|
||||
|
||||
@@ -23,7 +24,7 @@ func _process(_delta):
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - object: Obejct to register
|
||||
# - object: Object to register
|
||||
# - force: Register the object, even if it has already been registered
|
||||
func register_object(object: ESCObject, force: bool = false) -> void:
|
||||
if objects.has(object.global_id) and not force:
|
||||
@@ -70,6 +71,11 @@ func has(global_id: String) -> bool:
|
||||
|
||||
|
||||
# Get the object from the object registry
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - global_id: The global id of the object to retrieve
|
||||
# **Returns** The retrieved object, or null if not found
|
||||
func get_object(global_id: String) -> ESCObject:
|
||||
if objects.has(global_id):
|
||||
return objects[global_id]
|
||||
@@ -93,3 +99,17 @@ func unregister_object(object: ESCObject) -> void:
|
||||
and not object.global_id in RESERVED_OBJECTS:
|
||||
|
||||
objects.erase(object.global_id)
|
||||
|
||||
|
||||
# Insert data to save into savegame.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - p_savegame: The savegame resource
|
||||
func save_game(p_savegame: ESCSaveGame) -> void:
|
||||
p_savegame.objects = {}
|
||||
for obj_global_id in objects:
|
||||
if !objects[obj_global_id] is ESCObject:
|
||||
continue
|
||||
p_savegame.objects[obj_global_id] = \
|
||||
objects[obj_global_id].get_save_data()
|
||||
|
||||
@@ -70,3 +70,21 @@ func set_state(p_state: String, immediate: bool = false):
|
||||
func _set_active(value: bool):
|
||||
active = value
|
||||
self.node.visible = value
|
||||
|
||||
|
||||
# Return the data of the object to be inserted in a savegame file.
|
||||
#
|
||||
# **Returns**
|
||||
# A dictionary containing the data to be saved for this object.
|
||||
func get_save_data() -> Dictionary:
|
||||
var save_data: Dictionary = {}
|
||||
save_data["active"] = self.active
|
||||
save_data["interactive"] = self.interactive
|
||||
save_data["state"] = self.state
|
||||
|
||||
if self.node.get("is_movable") and self.node.is_movable:
|
||||
save_data["global_transform"] = self.node.global_transform
|
||||
save_data["last_deg"] = wrapi(self.node._movable._get_angle() + 1, 0, 360)
|
||||
save_data["last_dir"] = self.node._movable.last_dir
|
||||
|
||||
return save_data
|
||||
|
||||
@@ -107,9 +107,9 @@ func manage_input(_viewport, event, _shape_idx) -> void:
|
||||
# Texture or set size
|
||||
# **Returns** The correct area size
|
||||
func get_full_area_rect2() -> Rect2:
|
||||
var area_rect2 : Rect2 = Rect2()
|
||||
var area_rect2: Rect2 = Rect2()
|
||||
var pos = get_global_position()
|
||||
var size : Vector2
|
||||
var size: Vector2
|
||||
if get_texture():
|
||||
size = get_texture().get_size()
|
||||
else:
|
||||
|
||||
@@ -20,7 +20,7 @@ export(float) var mouse_tooltip_margin = 50.0
|
||||
|
||||
|
||||
# A reference to the node handling tooltips
|
||||
var tooltip_node : Object
|
||||
var tooltip_node: Object
|
||||
|
||||
|
||||
# Which (if any) debug mode for the editor is used
|
||||
@@ -36,7 +36,7 @@ func _draw():
|
||||
return
|
||||
|
||||
if editor_debug_mode == EDITOR_GAME_DEBUG_DISPLAY.MOUSE_TOOLTIP_LIMITS:
|
||||
var mouse_limits : Rect2 = get_viewport_rect().grow(-mouse_tooltip_margin)
|
||||
var mouse_limits: Rect2 = get_viewport_rect().grow(-mouse_tooltip_margin)
|
||||
print(mouse_limits)
|
||||
|
||||
# Draw lines for tooltip limits
|
||||
@@ -173,7 +173,7 @@ func left_double_click_on_inventory_item(
|
||||
# #### Parameters
|
||||
#
|
||||
# - inventory_item_global_id: Global id of the inventory item that was focused
|
||||
func inventory_item_focused(inventory_item_global_id : String) -> void:
|
||||
func inventory_item_focused(inventory_item_global_id: String) -> void:
|
||||
pass
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ func close_inventory():
|
||||
# #### Parameter
|
||||
#
|
||||
# - direction: The direction in which the mouse wheel was rotated
|
||||
func mousewheel_action(direction : int):
|
||||
func mousewheel_action(direction: int):
|
||||
pass
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ func show_ui():
|
||||
# #### Parameters
|
||||
#
|
||||
# - p_position: Position of the mouse
|
||||
func update_tooltip_following_mouse_position(p_position : Vector2):
|
||||
func update_tooltip_following_mouse_position(p_position: Vector2):
|
||||
var corrected_position = p_position
|
||||
|
||||
# clamp TOP
|
||||
@@ -246,6 +246,6 @@ func update_tooltip_following_mouse_position(p_position : Vector2):
|
||||
|
||||
|
||||
# Set the Editor debug mode
|
||||
func _set_editor_debug_mode(p_editor_debug_mode : int) -> void:
|
||||
func _set_editor_debug_mode(p_editor_debug_mode: int) -> void:
|
||||
editor_debug_mode = p_editor_debug_mode
|
||||
update()
|
||||
|
||||
@@ -52,7 +52,7 @@ func _ready():
|
||||
# #### Parameters
|
||||
#
|
||||
# - event: The event received
|
||||
func _on_inventory_item_gui_input(event : InputEvent):
|
||||
func _on_inventory_item_gui_input(event: InputEvent):
|
||||
if event.is_action_pressed("switch_action_verb"):
|
||||
if event.button_index == BUTTON_WHEEL_UP:
|
||||
escoria.inputs_manager._on_mousewheel_action(-1)
|
||||
|
||||
@@ -105,7 +105,7 @@ export(bool) var use_from_inventory_only = false
|
||||
|
||||
# Scene based on ESCInventoryItem used in inventory for the object if it is
|
||||
# picked up, that displays and handles the item
|
||||
export(PackedScene) var inventory_item_scene_file : PackedScene
|
||||
export(PackedScene) var inventory_item_scene_file: PackedScene
|
||||
|
||||
# Color used for dialogs
|
||||
export(Color) var dialog_color = ColorN("white")
|
||||
@@ -115,10 +115,10 @@ export(Color) var dialog_color = ColorN("white")
|
||||
export(bool) var dont_apply_terrain_scaling = false
|
||||
|
||||
# Speed of this item ifmovable
|
||||
export(int) var speed : int = 300
|
||||
export(int) var speed: int = 300
|
||||
|
||||
# Speed damp of this item if movable
|
||||
export(float) var v_speed_damp : float = 1.0
|
||||
export(float) var v_speed_damp: float = 1.0
|
||||
|
||||
# Animations script (for walking, idling...)
|
||||
export(Script) var animations
|
||||
@@ -224,9 +224,9 @@ func get_interact_position() -> Vector2:
|
||||
# - event: Triggered event
|
||||
# - _shape_idx: not used
|
||||
func manage_input(
|
||||
_viewport : Viewport,
|
||||
event : InputEvent,
|
||||
_shape_idx : int
|
||||
_viewport: Viewport,
|
||||
event: InputEvent,
|
||||
_shape_idx: int
|
||||
) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
|
||||
@@ -276,18 +276,27 @@ func element_exited(body):
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - target: Target item to teleport to
|
||||
# - target: Target node to teleport to
|
||||
func teleport(target: Node) -> void:
|
||||
_movable.teleport(target)
|
||||
|
||||
|
||||
# Use the movable node to teleport this item to the target position
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - target: Vector2 position to teleport to
|
||||
func teleport_to(target: Vector2) -> void:
|
||||
_movable.teleport_to(target)
|
||||
|
||||
|
||||
# Use the movable node to make the item walk to the given position
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - pos: Position to walk to
|
||||
# - p_walk_context: Walk context to use
|
||||
func walk_to(pos : Vector2, p_walk_context: ESCWalkContext = null) -> void:
|
||||
func walk_to(pos: Vector2, p_walk_context: ESCWalkContext = null) -> void:
|
||||
_movable.walk_to(pos, p_walk_context)
|
||||
|
||||
|
||||
@@ -296,7 +305,7 @@ func walk_to(pos : Vector2, p_walk_context: ESCWalkContext = null) -> void:
|
||||
# #### Parameters
|
||||
#
|
||||
# - speed_value: Set the new speed
|
||||
func set_speed(speed_value : int) -> void:
|
||||
func set_speed(speed_value: int) -> void:
|
||||
speed = speed_value
|
||||
|
||||
|
||||
@@ -310,7 +319,7 @@ func has_moved() -> bool:
|
||||
# #### Parameters
|
||||
#
|
||||
# Set the angle
|
||||
func set_angle(deg : int, immediate = true):
|
||||
func set_angle(deg: int, immediate = true):
|
||||
_movable.set_angle(deg, immediate)
|
||||
|
||||
|
||||
@@ -359,3 +368,4 @@ func _get_inventory_item() -> ESCInventoryItem:
|
||||
inventory_item.global_id = self.global_id
|
||||
return inventory_item
|
||||
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
extends Object
|
||||
class_name ESCResourceCache
|
||||
|
||||
var thread : Thread
|
||||
var mutex : Mutex
|
||||
var sem : Semaphore
|
||||
var thread: Thread
|
||||
var mutex: Mutex
|
||||
var sem: Semaphore
|
||||
|
||||
var queue : Array = []
|
||||
var pending : Dictionary = {}
|
||||
var queue: Array = []
|
||||
var pending: Dictionary = {}
|
||||
|
||||
signal resource_loading_progress(path, progress)
|
||||
signal resource_loading_done(path)
|
||||
@@ -31,7 +31,7 @@ func _wait(caller):
|
||||
sem.wait()
|
||||
|
||||
|
||||
func queue_resource(path : String, p_in_front : bool = false, p_permanent : bool = false):
|
||||
func queue_resource(path: String, p_in_front: bool = false, p_permanent: bool = false):
|
||||
_lock("queue_resource")
|
||||
if path in pending:
|
||||
_unlock("queue_resource")
|
||||
|
||||
@@ -23,7 +23,7 @@ export(String, FILE, "*.esc") var esc_script = ""
|
||||
export(PackedScene) var player_scene
|
||||
|
||||
# The camera limits available in this room
|
||||
export(Array, Rect2) var camera_limits : Array = [Rect2()] setget set_camera_limits
|
||||
export(Array, Rect2) var camera_limits: Array = [Rect2()] setget set_camera_limits
|
||||
|
||||
# The editor debug display mode
|
||||
export(int) var editor_debug_mode = EditorRoomDebugDisplay.NONE setget set_editor_debug_mode
|
||||
@@ -89,7 +89,7 @@ func _draw():
|
||||
if editor_debug_mode == EditorRoomDebugDisplay.NONE:
|
||||
return
|
||||
|
||||
var camera_limits_colors : Array = [
|
||||
var camera_limits_colors: Array = [
|
||||
ColorN("red"), ColorN("blue"), ColorN("green")
|
||||
]
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ func _ready():
|
||||
navigation_enabled_found = true
|
||||
current_active_navigation_instance = n
|
||||
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.room_terrain = self
|
||||
_update_texture()
|
||||
|
||||
@@ -7,13 +7,13 @@ func get_class():
|
||||
|
||||
|
||||
# Infinitive verb
|
||||
var current_action : String
|
||||
var current_action: String
|
||||
# Target item/hotspot
|
||||
var current_target : String setget set_target
|
||||
var current_target: String setget set_target
|
||||
# Preposition: on, with...
|
||||
var current_prep : String = "with"
|
||||
var current_prep: String = "with"
|
||||
# Target 2 item/hotspot
|
||||
var current_target2 : String
|
||||
var current_target2: String
|
||||
# True if tooltip is waiting for a click on second target (use x with y)
|
||||
var waiting_for_target2 = false
|
||||
|
||||
@@ -21,7 +21,7 @@ export(Color) var color setget set_color
|
||||
export(Vector2) var offset_from_cursor = Vector2(10,0)
|
||||
|
||||
export(bool) var debug_mode = false setget set_debug_mode
|
||||
var debug_texturerect_node : TextureRect
|
||||
var debug_texturerect_node: TextureRect
|
||||
|
||||
const MAX_WIDTH = 200
|
||||
const MIN_HEIGHT = 30
|
||||
@@ -36,12 +36,12 @@ func _ready():
|
||||
escoria.action_manager.connect("action_changed", self, "on_action_selected")
|
||||
|
||||
|
||||
func set_color(p_color : Color):
|
||||
func set_color(p_color: Color):
|
||||
color = p_color
|
||||
update_tooltip_text()
|
||||
|
||||
|
||||
func set_debug_mode(p_debug_mode : bool):
|
||||
func set_debug_mode(p_debug_mode: bool):
|
||||
debug_mode = p_debug_mode
|
||||
if debug_mode:
|
||||
# Add a white TextureRect behind the RTL to see its actual size
|
||||
@@ -67,14 +67,14 @@ func on_action_selected() -> void:
|
||||
update_tooltip_text()
|
||||
|
||||
|
||||
func set_target(target : String, needs_second_target : bool = false) -> void:
|
||||
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:
|
||||
func set_target2(target2: String) -> void:
|
||||
current_target2 = target2
|
||||
update_tooltip_text()
|
||||
|
||||
@@ -142,16 +142,16 @@ func _offset(position):
|
||||
return position
|
||||
|
||||
|
||||
func tooltip_distance_to_edge_top(position : Vector2):
|
||||
func tooltip_distance_to_edge_top(position: Vector2):
|
||||
return position.y
|
||||
|
||||
func tooltip_distance_to_edge_bottom(position: Vector2):
|
||||
return escoria.game_size.y - position.y
|
||||
|
||||
func tooltip_distance_to_edge_left(position : Vector2):
|
||||
func tooltip_distance_to_edge_left(position: Vector2):
|
||||
return position.x
|
||||
|
||||
func tooltip_distance_to_edge_right(position : Vector2):
|
||||
func tooltip_distance_to_edge_right(position: Vector2):
|
||||
return escoria.game_size.x - position.x
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ class_name ESCLogger
|
||||
|
||||
# The path of the ESC file that was reported last (used for removing
|
||||
# duplicate warnings
|
||||
var warning_path : String
|
||||
var warning_path: String
|
||||
|
||||
|
||||
# Valid log levels
|
||||
@@ -27,7 +27,7 @@ var _level_map: Dictionary = {
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func debug(string : String, args = []):
|
||||
func debug(string: String, args = []):
|
||||
if _get_log_level() >= LOG_DEBUG:
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(D)\t" + string + " \t" + argsstr)
|
||||
@@ -39,7 +39,7 @@ func debug(string : String, args = []):
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func info(string : String, args = []):
|
||||
func info(string: String, args = []):
|
||||
if _get_log_level() >= LOG_INFO:
|
||||
var argsstr = []
|
||||
if !args.empty():
|
||||
@@ -58,7 +58,7 @@ func info(string : String, args = []):
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func warning(string : String, args = []):
|
||||
func warning(string: String, args = []):
|
||||
if _get_log_level() >= LOG_WARNING:
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(W)\t" + string + " \t" + argsstr)
|
||||
@@ -73,7 +73,7 @@ func warning(string : String, args = []):
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func error(string : String, args = []):
|
||||
func error(string: String, args = []):
|
||||
if _get_log_level() >= LOG_ERROR:
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(E)\t" + string + " \t" + argsstr)
|
||||
@@ -89,7 +89,7 @@ func error(string : String, args = []):
|
||||
# * p_path: Path to the file
|
||||
# * warnings: Array of warnings to put out
|
||||
# * report_once: Additional messages about the same file will be ignored
|
||||
func report_warnings(p_path : String, warnings : Array, report_once = false) -> void:
|
||||
func report_warnings(p_path: String, warnings: Array, report_once = false) -> void:
|
||||
var warning_is_reported = false
|
||||
if p_path == warning_path:
|
||||
warning_is_reported = true
|
||||
@@ -113,7 +113,7 @@ func report_warnings(p_path : String, warnings : Array, report_once = false) ->
|
||||
#
|
||||
# * p_path: Path to the file
|
||||
# * errors: Array of errors to put out
|
||||
func report_errors(p_path : String, errors : Array) -> void:
|
||||
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:
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
# Saves and loads savegame and settings files
|
||||
class_name ESCSaveManager
|
||||
|
||||
# Variable containing the saves folder obtained from Project Settings
|
||||
var save_folder: String
|
||||
|
||||
# Template for savegames filenames
|
||||
const SAVE_NAME_TEMPLATE: String = "save_%03d.tres"
|
||||
|
||||
# Variable containing the settings folder obtained from Project Settings
|
||||
var settings_folder: String
|
||||
|
||||
# Template for settings filename
|
||||
const SETTINGS_TEMPLATE: String = "settings.tres"
|
||||
|
||||
# Constructor of ESCSaveManager object.
|
||||
func _init():
|
||||
save_folder = ProjectSettings.get_setting("escoria/main/savegames_path")
|
||||
settings_folder = ProjectSettings.get_setting("escoria/main/settings_path")
|
||||
|
||||
# Return a list of savegames metadata (id, date, name and game version)
|
||||
func get_saves_list() -> Dictionary:
|
||||
var regex = RegEx.new()
|
||||
regex.compile("save_([0-9]{3})\\.tres")
|
||||
|
||||
var saves = {}
|
||||
var dirsave = Directory.new()
|
||||
if dirsave.open(save_folder) == OK:
|
||||
dirsave.list_dir_begin(true, true)
|
||||
var nextfile = dirsave.get_next()
|
||||
while nextfile != "":
|
||||
var save_path = save_folder.plus_file(nextfile)
|
||||
var file: File = File.new()
|
||||
var save_game_res: Resource = load(save_path)
|
||||
var save_game_data = {
|
||||
"date": save_game_res["date"],
|
||||
"name": save_game_res["name"],
|
||||
"game_version": save_game_res["game_version"],
|
||||
}
|
||||
|
||||
var id: int
|
||||
var matches = regex.search(nextfile)
|
||||
if matches.strings.size() > 1:
|
||||
id = int(matches.strings[1])
|
||||
|
||||
saves[id] = save_game_data
|
||||
nextfile = dirsave.get_next()
|
||||
return saves
|
||||
|
||||
|
||||
# Returns true whether the savegame identified by id does exist
|
||||
#
|
||||
# ## Parameters
|
||||
# - id: integer suffix of the savegame file
|
||||
func save_game_exists(id: int) -> bool:
|
||||
var save_file_path: String = save_folder.plus_file(SAVE_NAME_TEMPLATE % id)
|
||||
var file: File = File.new()
|
||||
return file.file_exists(save_file_path)
|
||||
|
||||
|
||||
# Save the current state of the game in a file suffixed with the id value.
|
||||
# This id can help with slots development for the game developer.
|
||||
#
|
||||
# ## Parameters
|
||||
# - id: integer suffix of the savegame file
|
||||
# - p_savename: name of the savegame
|
||||
func save_game(id: int, p_savename: String):
|
||||
var save_game := ESCSaveGame.new()
|
||||
save_game.escoria_version = escoria.ESCORIA_VERSION
|
||||
save_game.game_version = ProjectSettings.get_setting(
|
||||
"escoria/main/game_version"
|
||||
)
|
||||
save_game.name = p_savename
|
||||
|
||||
var datetime = OS.get_datetime()
|
||||
var datetime_string = "%02d/%02d/%02d %02d:%02d" % [
|
||||
datetime["day"],
|
||||
datetime["month"],
|
||||
datetime["year"],
|
||||
datetime["hour"],
|
||||
datetime["minute"],
|
||||
]
|
||||
save_game.date = datetime_string
|
||||
|
||||
escoria.globals_manager.save_game(save_game)
|
||||
escoria.object_manager.save_game(save_game)
|
||||
escoria.main.save_game(save_game)
|
||||
|
||||
var directory: Directory = Directory.new()
|
||||
if not directory.dir_exists(save_folder):
|
||||
directory.make_dir_recursive(save_folder)
|
||||
|
||||
var save_path = save_folder.plus_file(SAVE_NAME_TEMPLATE % id)
|
||||
var error: int = ResourceSaver.save(save_path, save_game)
|
||||
if error != OK:
|
||||
escoria.logger.report_errors(
|
||||
"esc_save_data_resources.gd",
|
||||
["There was an issue writing the save %s to %s" % [id, save_path]])
|
||||
|
||||
# Load a savegame file from its id.
|
||||
#
|
||||
# ## Parameters
|
||||
# - id: integer suffix of the savegame file
|
||||
func load_game(id: int):
|
||||
var save_file_path: String = save_folder.plus_file(SAVE_NAME_TEMPLATE % id)
|
||||
var file: File = File.new()
|
||||
if not file.file_exists(save_file_path):
|
||||
escoria.logger.report_errors(
|
||||
"esc_save_data_resources.gd",
|
||||
["Save file %s doesn't exist" % save_file_path])
|
||||
return
|
||||
|
||||
var save_game: Resource = ResourceLoader.load(save_file_path)
|
||||
|
||||
var load_event = ESCEvent.new(":load")
|
||||
var load_statements = []
|
||||
|
||||
## GLOBALS
|
||||
for k in save_game.globals.keys():
|
||||
load_statements.append(
|
||||
ESCCommand.new("set_global %s \"%s\"\n" \
|
||||
% [k, save_game.globals[k]])
|
||||
)
|
||||
|
||||
## ROOM
|
||||
load_statements.append(
|
||||
ESCCommand.new("change_scene %s true" \
|
||||
% save_game.main["current_scene_filename"])
|
||||
)
|
||||
|
||||
## OBJECTS
|
||||
for object_global_id in save_game.objects.keys():
|
||||
if save_game.objects[object_global_id].has("active"):
|
||||
load_statements.append(ESCCommand.new("set_active %s %s" \
|
||||
% [object_global_id,
|
||||
save_game.objects[object_global_id]["active"]])
|
||||
)
|
||||
|
||||
if save_game.objects[object_global_id].has("interactive"):
|
||||
load_statements.append(ESCCommand.new("set_interactive %s %s" \
|
||||
% [object_global_id,
|
||||
save_game.objects[object_global_id]["interactive"]])
|
||||
)
|
||||
|
||||
if save_game.objects[object_global_id].has("state"):
|
||||
load_statements.append(ESCCommand.new("set_state %s %s true" \
|
||||
% [object_global_id,
|
||||
save_game.objects[object_global_id]["state"]])
|
||||
)
|
||||
|
||||
if save_game.objects[object_global_id].has("global_transform"):
|
||||
load_statements.append(ESCCommand.new("teleport_pos %s %s %s" \
|
||||
% [object_global_id,
|
||||
save_game.objects[object_global_id] \
|
||||
["global_transform"].origin.x,
|
||||
save_game.objects[object_global_id] \
|
||||
["global_transform"].origin.y])
|
||||
)
|
||||
load_statements.append(ESCCommand.new("set_angle %s %s" \
|
||||
% [object_global_id,
|
||||
save_game.objects[object_global_id]["last_deg"]])
|
||||
)
|
||||
|
||||
load_event.statements = load_statements
|
||||
escoria.event_manager.queue_event(load_event)
|
||||
|
||||
|
||||
# Save the game settings in the settings file.
|
||||
func save_settings():
|
||||
var settings_res := ESCSaveSettings.new()
|
||||
settings_res.escoria_version = escoria.ESCORIA_VERSION
|
||||
settings_res.text_lang = escoria.settings.text_lang
|
||||
settings_res.voice_lang = escoria.settings.voice_lang
|
||||
settings_res.speech_enabled = escoria.settings.speech_enabled
|
||||
settings_res.master_volume = escoria.settings.master_volume
|
||||
settings_res.music_volume = escoria.settings.music_volume
|
||||
settings_res.sfx_volume = escoria.settings.sfx_volume
|
||||
settings_res.voice_volume = escoria.settings.voice_volume
|
||||
settings_res.fullscreen = escoria.settings.fullscreen
|
||||
settings_res.skip_dialog = escoria.settings.skip_dialog
|
||||
settings_res.rate_shown = escoria.settings.rate_shown
|
||||
|
||||
var directory: Directory = Directory.new()
|
||||
if not directory.dir_exists(settings_folder):
|
||||
directory.make_dir_recursive(settings_folder)
|
||||
|
||||
var save_path = settings_folder.plus_file(SETTINGS_TEMPLATE)
|
||||
var error: int = ResourceSaver.save(save_path, settings_res)
|
||||
if error != OK:
|
||||
escoria.logger.report_errors(
|
||||
"esc_save_data_resources.gd:save_settings()",
|
||||
["There was an issue writing settings %s" % save_path])
|
||||
|
||||
# Load the game settings from the settings file
|
||||
func load_settings():
|
||||
var save_settings_path: String = settings_folder.plus_file(SETTINGS_TEMPLATE)
|
||||
var file: File = File.new()
|
||||
if not file.file_exists(save_settings_path):
|
||||
escoria.logger.report_warnings(
|
||||
"esc_save_data_resources.gd:load_settings()",
|
||||
["Settings file %s doesn't exist" % save_settings_path,
|
||||
"Setting default settings."])
|
||||
save_settings()
|
||||
return
|
||||
|
||||
var settings_resource: Resource = load(save_settings_path)
|
||||
escoria._on_settings_loaded(settings_resource)
|
||||
@@ -0,0 +1,29 @@
|
||||
# Resource used for holding savegames data.
|
||||
extends Resource
|
||||
class_name ESCSaveGame
|
||||
|
||||
# Access key for the main data last_scene_global_id
|
||||
const MAIN_LAST_SCENE_GLOBAL_ID_KEY = "last_scene_global_id"
|
||||
# Access key for the main data current_scene_filename
|
||||
const MAIN_CURRENT_SCENE_FILENAME_KEY = "current_scene_filename"
|
||||
|
||||
# Escoria version which the savegame was created with.
|
||||
export var escoria_version: String
|
||||
|
||||
# Game version which the savegame was created with.
|
||||
export var game_version: String = ""
|
||||
|
||||
# Name of the savegame. Can be custom value, provided by the player.
|
||||
export var name: String = ""
|
||||
|
||||
# Date of creation of the savegame.
|
||||
export var date: String = ""
|
||||
|
||||
# Main data to be saved
|
||||
export var main: Dictionary = {}
|
||||
|
||||
# Escoria Global variables exported from ESCGlobalsManager
|
||||
export var globals: Dictionary = {}
|
||||
|
||||
# Escoria objects exported from ESCObjectsManager
|
||||
export var objects: Dictionary = {}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Resource holding game settings.
|
||||
extends Resource
|
||||
class_name ESCSaveSettings
|
||||
|
||||
# Version of ESCORIA Framework
|
||||
export var escoria_version: String
|
||||
|
||||
# Language of displayed text
|
||||
export var text_lang: String = ProjectSettings.get_setting("escoria/main/text_lang")
|
||||
|
||||
# Language of voice speech
|
||||
export var voice_lang: String = ProjectSettings.get_setting("escoria/main/voice_lang")
|
||||
|
||||
# Whether speech is enabled
|
||||
export var speech_enabled: bool = ProjectSettings.get_setting(
|
||||
"escoria/sound/speech_enabled")
|
||||
|
||||
# Master volume (mix of music, voice and sfx)
|
||||
export var master_volume: float = ProjectSettings.get_setting(
|
||||
"escoria/sound/master_volume")
|
||||
|
||||
# Volume of music only
|
||||
export var music_volume: float = ProjectSettings.get_setting(
|
||||
"escoria/sound/music_volume")
|
||||
|
||||
# Volume of SFX only
|
||||
export var sfx_volume: float = ProjectSettings.get_setting("escoria/sound/sfx_volume")
|
||||
|
||||
# Voice volume only
|
||||
export var voice_volume: float = ProjectSettings.get_setting(
|
||||
"escoria/sound/speech_volume")
|
||||
|
||||
# True if game has to be fullscreen
|
||||
export var fullscreen: bool = false
|
||||
|
||||
# True if skipping dialogs is allowed
|
||||
export var skip_dialog: bool = true
|
||||
|
||||
# FIXME: to be defined (achievements?)
|
||||
export var rate_shown: bool = false
|
||||
@@ -1,218 +0,0 @@
|
||||
|
||||
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.json", File.WRITE)
|
||||
f.store_string(to_json(p_data))
|
||||
f.close()
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], OK)
|
||||
|
||||
return OK
|
||||
|
||||
|
||||
func check_settings():
|
||||
var f = File.new()
|
||||
var error = f.open("user://settings.json", File.READ)
|
||||
if !f.is_open() and error != OK:
|
||||
match error:
|
||||
ERR_FILE_NOT_FOUND:
|
||||
f.close()
|
||||
save_settings(escoria.settings_default, null)
|
||||
|
||||
|
||||
func load_settings(p_callback):
|
||||
var f = File.new()
|
||||
var error = f.open("user://settings.json", File.READ)
|
||||
if !f.is_open() and error != OK:
|
||||
escoria.logger.report_warnings("save_data.gd:load_settings()",
|
||||
["Failed opening settings file user://settings.json.",
|
||||
"File.open() returned " + error])
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], null)
|
||||
return FAILED
|
||||
|
||||
settings = f.get_as_text()
|
||||
f.close()
|
||||
|
||||
if typeof(p_callback) != typeof(null):
|
||||
p_callback[0].call_deferred(p_callback[1], settings)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
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
|
||||
@@ -9,7 +9,7 @@ class_name ESCUtils
|
||||
#
|
||||
# - rad_angle: Angle in radians
|
||||
# **Returns** Degrees
|
||||
func get_deg_from_rad(rad_angle : float):
|
||||
func get_deg_from_rad(rad_angle: float):
|
||||
var deg = rad2deg(rad_angle)
|
||||
if deg >= 360.0:
|
||||
deg = clamp(deg, 0.0, 360.0)
|
||||
|
||||
Reference in New Issue
Block a user