Co-authored-by: Dennis Ploeger <develop@dieploegers.de> Co-authored-by: dploeger <dploeger@users.noreply.github.com>
391 lines
10 KiB
GDScript
391 lines
10 KiB
GDScript
# The escoria main script
|
||
extends Node
|
||
|
||
# Escoria version number
|
||
const ESCORIA_VERSION = "0.1.0"
|
||
|
||
# Current game state
|
||
# * DEFAULT: Common game function
|
||
# * DIALOG: Game is playing a dialog
|
||
# * WAIT: Game is waiting
|
||
enum GAME_STATE {
|
||
DEFAULT,
|
||
DIALOG,
|
||
WAIT
|
||
}
|
||
|
||
|
||
# Logger used
|
||
var logger: ESCLogger
|
||
|
||
# Several utilities
|
||
var utils: ESCUtils
|
||
|
||
# The inventory manager instance
|
||
var inventory_manager: ESCInventoryManager
|
||
|
||
# The action manager instance
|
||
var action_manager: ESCActionManager
|
||
|
||
# ESC compiler instance
|
||
var esc_compiler: ESCCompiler
|
||
|
||
# ESC Event manager instance
|
||
var event_manager: ESCEventManager
|
||
|
||
# ESC globals registry instance
|
||
var globals_manager: ESCGlobalsManager
|
||
|
||
# ESC object manager instance
|
||
var object_manager: ESCObjectManager
|
||
|
||
# ESC command registry instance
|
||
var command_registry: ESCCommandRegistry
|
||
|
||
# Resource cache handler
|
||
var resource_cache: ESCResourceCache
|
||
|
||
# Instance of the main menu
|
||
var main_menu_instance
|
||
|
||
# Terrain of the current room
|
||
var room_terrain
|
||
|
||
# Dialog player instantiator. This instance is called directly for dialogs.
|
||
var dialog_player: ESCDialogsPlayer
|
||
|
||
# Inventory scene
|
||
var inventory
|
||
|
||
# These are settings that the player can affect and save/load later
|
||
var settings: ESCSaveSettings
|
||
|
||
|
||
# The current state of the game
|
||
onready var current_state = GAME_STATE.DEFAULT
|
||
|
||
# The game resolution
|
||
onready var game_size = get_viewport().size
|
||
|
||
# The main scene
|
||
onready var main = $main
|
||
|
||
# The escoria inputs manager
|
||
var inputs_manager: ESCInputsManager
|
||
|
||
# Savegames and settings manager
|
||
var save_manager: ESCSaveManager
|
||
|
||
|
||
# Initialize various objects
|
||
func _init():
|
||
self.logger = ESCLogger.new()
|
||
self.utils = ESCUtils.new()
|
||
self.inventory_manager = ESCInventoryManager.new()
|
||
self.action_manager = ESCActionManager.new()
|
||
self.event_manager = ESCEventManager.new()
|
||
self.globals_manager = ESCGlobalsManager.new()
|
||
self.add_child(self.event_manager)
|
||
self.object_manager = ESCObjectManager.new()
|
||
self.command_registry = ESCCommandRegistry.new()
|
||
self.esc_compiler = ESCCompiler.new()
|
||
self.resource_cache = ESCResourceCache.new()
|
||
self.resource_cache.start()
|
||
self.save_manager = ESCSaveManager.new()
|
||
self.inputs_manager = ESCInputsManager.new()
|
||
|
||
|
||
# Load settings
|
||
func _ready():
|
||
settings = ESCSaveSettings.new()
|
||
settings = save_manager.load_settings()
|
||
escoria._on_settings_loaded(escoria.settings)
|
||
|
||
|
||
# Called by Main menu "start new game"
|
||
func new_game():
|
||
var script = self.esc_compiler.load_esc_file(
|
||
ProjectSettings.get_setting("escoria/main/game_start_script")
|
||
)
|
||
event_manager.queue_event(script.events["start"])
|
||
var rc = yield(event_manager, "event_finished")
|
||
while rc[1] != "start":
|
||
rc = yield(event_manager, "event_finished")
|
||
|
||
if rc[0] != ESCExecution.RC_OK:
|
||
self.logger.report_errors(
|
||
"Start event of the start script returned unsuccessful: %d" % rc[0],
|
||
[]
|
||
)
|
||
return
|
||
|
||
|
||
# Run a generic action
|
||
#
|
||
# #### Parameters
|
||
#
|
||
# - action: type of the action to run
|
||
# - params: Parameters for the action
|
||
func do(action: String, params: Array = []) -> void:
|
||
if current_state == GAME_STATE.DEFAULT:
|
||
match action:
|
||
"walk":
|
||
self.action_manager.clear_current_action()
|
||
|
||
# Check moving object.
|
||
if not self.object_manager.has(params[0]):
|
||
self.logger.report_errors(
|
||
"escoria.gd:do()",
|
||
[
|
||
"Walk action requested on inexisting " + \
|
||
"object: %s " % params[0]
|
||
]
|
||
)
|
||
return
|
||
|
||
var moving_obj = self.object_manager.get_object(params[0])\
|
||
.node
|
||
|
||
# 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 = ESCWalkContext.new(
|
||
null,
|
||
target_position,
|
||
is_fast
|
||
)
|
||
moving_obj.walk_to(target_position, walk_context)
|
||
|
||
# Walk to object from its id
|
||
elif params[1] is String:
|
||
if not self.object_manager.has(params[1]):
|
||
self.logger.report_errors(
|
||
"escoria.gd:do()",
|
||
[
|
||
"Walk action requested TOWARDS " +\
|
||
"inexisting object: %s" % params[1]
|
||
]
|
||
)
|
||
return
|
||
|
||
var object = self.object_manager.get_object(params[1])
|
||
if object:
|
||
var target_position: Vector2
|
||
if object.node is ESCLocation:
|
||
target_position = object.node.global_position
|
||
else:
|
||
target_position = object.node.interact_position
|
||
|
||
var is_fast: bool = false
|
||
if params.size() > 2 and params[2] == true:
|
||
is_fast = true
|
||
var walk_context = ESCWalkContext.new(
|
||
object,
|
||
Vector2(),
|
||
is_fast
|
||
)
|
||
|
||
moving_obj.walk_to(target_position, walk_context)
|
||
|
||
"item_left_click":
|
||
if params[0] is String:
|
||
self.logger.info(
|
||
"escoria.do(): item_left_click on item ",
|
||
[params[0]]
|
||
)
|
||
var item = self.object_manager.get_object(params[0])
|
||
_ev_left_click_on_item(item, params[1])
|
||
|
||
"item_right_click":
|
||
if params[0] is String:
|
||
self.logger.info(
|
||
"escoria.do(): item_right_click on item ",
|
||
[params[0]]
|
||
)
|
||
var item = self.object_manager.get_object(params[0])
|
||
_ev_left_click_on_item(item, params[1], true)
|
||
|
||
"trigger_in":
|
||
var trigger_id = params[0]
|
||
var object_id = params[1]
|
||
var trigger_in_verb = params[2]
|
||
self.logger.info("escoria.do(): trigger_in %s by %s" % [
|
||
trigger_id,
|
||
object_id
|
||
])
|
||
self.event_manager.queue_event(
|
||
object_manager.get_object(trigger_id).events[
|
||
trigger_in_verb
|
||
]
|
||
)
|
||
|
||
"trigger_out":
|
||
var trigger_id = params[0]
|
||
var object_id = params[1]
|
||
var trigger_out_verb = params[2]
|
||
self.logger.info("escoria.do(): trigger_out %s by %s" % [
|
||
trigger_id,
|
||
object_id
|
||
])
|
||
self.event_manager.queue_event(
|
||
object_manager.get_object(trigger_id).events[
|
||
trigger_out_verb
|
||
]
|
||
)
|
||
|
||
_:
|
||
self.logger.report_warnings("escoria.gd:do()",
|
||
["Action received:", action, "with params ", params])
|
||
elif current_state == GAME_STATE.WAIT:
|
||
pass
|
||
|
||
|
||
# Event handler when an object/item was clicked
|
||
#
|
||
# #### Parameters
|
||
#
|
||
# - ob: Object that was left clicked
|
||
# - event: Input event that was received
|
||
# - default_action: Run the inventory default action
|
||
func _ev_left_click_on_item(obj, event, default_action = false):
|
||
if obj is String:
|
||
obj = object_manager.get_object(obj)
|
||
self.logger.info(obj.global_id + " left-clicked with event ", [event])
|
||
|
||
var need_combine = false
|
||
# Check if current_action and current_tool are already set
|
||
if self.action_manager.current_action:
|
||
if self.action_manager.current_tool:
|
||
if self.action_manager.current_action in self.action_manager\
|
||
.current_tool.node.combine_if_action_used_among:
|
||
need_combine = true
|
||
else:
|
||
self.action_manager.current_tool = obj
|
||
else:
|
||
if default_action:
|
||
if self.inventory_manager.inventory_has(obj.global_id):
|
||
self.action_manager.current_action = \
|
||
obj.node.default_action_inventory
|
||
else:
|
||
self.action_manager.current_action = \
|
||
obj.node.default_action
|
||
elif self.action_manager.current_action in \
|
||
obj.node.combine_if_action_used_among:
|
||
self.action_manager.current_tool = obj
|
||
|
||
|
||
# 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 = ESCWalkContext.new(
|
||
obj,
|
||
Vector2(),
|
||
event.doubleclick
|
||
)
|
||
|
||
# If object not in inventory, player walks towards it
|
||
if not inventory_manager.inventory_has(obj.global_id):
|
||
var clicked_object_has_interact_position = false
|
||
|
||
if object_manager.get_object(obj.global_id).interactive:
|
||
if obj.node.get_interact_position() != null:
|
||
destination_position = obj.node.get_interact_position()
|
||
clicked_object_has_interact_position = true
|
||
else:
|
||
destination_position = obj.node.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.
|
||
var context: ESCWalkContext = yield(
|
||
main.current_scene.player,
|
||
"arrived"
|
||
)
|
||
|
||
self.logger.info("Context arrived: %s" % var2str(context))
|
||
|
||
if context.target_object and \
|
||
context.target_object.global_id != walk_context.\
|
||
target_object.global_id:
|
||
dont_interact = true
|
||
elif context.target_position != walk_context.target_position:
|
||
dont_interact = true
|
||
|
||
# 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.node.is_exit and self.action_manager.current_action == "" \
|
||
or self.action_manager.current_action == "walk":
|
||
self.action_manager.activate("exit_scene", obj)
|
||
else:
|
||
# Manage movements towards object before activating it
|
||
if self.action_manager.current_action == "" \
|
||
or self.action_manager.current_action == "walk":
|
||
if destination_position != clicked_position \
|
||
and not inventory_manager.inventory_has(obj.global_id):
|
||
self.action_manager.activate("arrived", obj)
|
||
# Manage action on object
|
||
elif self.action_manager.current_action != "" and \
|
||
self.action_manager.current_action != "walk":
|
||
# If apply_interact, perform combine between items
|
||
if need_combine:
|
||
self.action_manager.activate(
|
||
self.action_manager.current_action,
|
||
self.action_manager.current_tool,
|
||
obj
|
||
)
|
||
|
||
else:
|
||
self.action_manager.activate(
|
||
self.action_manager.current_action,
|
||
obj
|
||
)
|
||
|
||
|
||
# Apply the loaded settings
|
||
#
|
||
# #### Parameters
|
||
#
|
||
# * p_settings: Loaded settings
|
||
func _on_settings_loaded(p_settings: ESCSaveSettings) -> void:
|
||
escoria.logger.info("******* settings loaded")
|
||
if p_settings != null:
|
||
settings = p_settings
|
||
else:
|
||
settings = ESCSaveSettings.new()
|
||
|
||
AudioServer.set_bus_volume_db(
|
||
AudioServer.get_bus_index("Master"),
|
||
linear2db(settings.master_volume)
|
||
)
|
||
AudioServer.set_bus_volume_db(
|
||
AudioServer.get_bus_index("SFX"),
|
||
linear2db(settings.sfx_volume)
|
||
)
|
||
AudioServer.set_bus_volume_db(
|
||
AudioServer.get_bus_index("Music"),
|
||
linear2db(settings.music_volume)
|
||
)
|
||
TranslationServer.set_locale(settings.text_lang)
|
||
|