2024-09-27 18:09:30 +02:00
|
|
|
class_name Game
|
2024-12-01 21:14:04 +01:00
|
|
|
extends Node3D
|
|
|
|
|
|
|
|
# Takes care of game state including
|
|
|
|
# * player state
|
|
|
|
# * current level
|
|
|
|
# * player-world state (i.e. which items were picked up in the level)
|
|
|
|
|
|
|
|
signal item_picked_up(node_path:NodePath)
|
2024-09-14 12:45:42 +02:00
|
|
|
|
|
|
|
@onready var camera = %Camera
|
2024-12-01 21:14:04 +01:00
|
|
|
@onready var player:Player = %Player
|
2024-09-14 12:45:42 +02:00
|
|
|
|
2024-09-27 18:09:30 +02:00
|
|
|
@onready var build_system:BuildSystem = %BuildSystem
|
2024-09-14 12:45:42 +02:00
|
|
|
|
2024-12-01 21:14:04 +01:00
|
|
|
var picked_up_level_items:Array[NodePath] = []
|
|
|
|
var level = null
|
|
|
|
|
2024-09-14 12:45:42 +02:00
|
|
|
var _player_camera_offset:Vector3 = Vector3.ZERO
|
|
|
|
|
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
|
|
func _ready():
|
|
|
|
_player_camera_offset = camera.global_position - player.global_position + Vector3.UP * 1
|
2024-12-01 21:14:04 +01:00
|
|
|
picked_up_level_items.clear()
|
|
|
|
|
|
|
|
level = get_node("Level")
|
|
|
|
|
2024-12-01 21:57:39 +01:00
|
|
|
InteractionSystem.player = player
|
|
|
|
|
2024-12-01 21:14:04 +01:00
|
|
|
register_item_pickups()
|
2024-09-14 12:45:42 +02:00
|
|
|
|
|
|
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
|
|
func _process(_delta):
|
2024-11-27 20:51:20 +01:00
|
|
|
if build_system.is_active:
|
2024-09-14 12:45:42 +02:00
|
|
|
player.process_mode = Node.PROCESS_MODE_DISABLED
|
|
|
|
else:
|
|
|
|
player.process_mode = Node.PROCESS_MODE_ALWAYS
|
|
|
|
|
|
|
|
camera.global_position = player.global_position + _player_camera_offset
|
|
|
|
camera.look_at(player.global_position)
|
2024-12-01 21:14:04 +01:00
|
|
|
|
|
|
|
func register_item_pickups() -> void:
|
|
|
|
# When saving a game we need to know which items were picked up.
|
|
|
|
for pickup_item in get_tree().get_nodes_in_group("pickup_item"):
|
|
|
|
pickup_item.connect("item_picked_up", on_item_pickup)
|
|
|
|
|
|
|
|
func on_item_pickup(node_path:NodePath):
|
|
|
|
picked_up_level_items.append(node_path)
|
|
|
|
item_picked_up.emit(node_path)
|
|
|
|
|
|
|
|
func load_level(level_resource_path:String) -> void:
|
|
|
|
var level_resource = load(level_resource_path) as PackedScene
|
|
|
|
|
|
|
|
var level_node = get_node("Level") as Node3D
|
|
|
|
assert(level_node != null)
|
|
|
|
|
|
|
|
level_node.queue_free()
|
|
|
|
remove_child(level_node)
|
|
|
|
|
|
|
|
level = level_resource.instantiate()
|
|
|
|
name = "Level"
|
|
|
|
add_child(level)
|
|
|
|
|
|
|
|
register_item_pickups()
|
|
|
|
|
|
|
|
func save_game(game_profile_path:String):
|
|
|
|
var save_data:SaveGameResource = SaveGameResource.new()
|
|
|
|
|
|
|
|
save_data.level = level.scene_file_path
|
|
|
|
save_data.level_pickup_items = picked_up_level_items
|
|
|
|
save_data.player_transform = player.global_transform
|
|
|
|
|
|
|
|
for node:Node in get_tree().get_nodes_in_group("quest_state"):
|
|
|
|
save_data.quest_states[node.name] = {}
|
|
|
|
|
|
|
|
for property in node.get_property_list():
|
|
|
|
if (property.usage & PROPERTY_USAGE_STORAGE != 0) and (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE) != 0:
|
|
|
|
save_data.quest_states[node.name][property.name] = node.get(property.name)
|
|
|
|
|
|
|
|
for item_stack in player.inventory.get_item_stacks():
|
|
|
|
save_data.inventory.append({"item": item_stack.item, "count": item_stack.count})
|
|
|
|
|
|
|
|
for structure:BuiltStructure in get_tree().get_nodes_in_group("built_structure"):
|
|
|
|
var built_structure_resource = BuiltStructureResource.new()
|
|
|
|
built_structure_resource.global_transform = structure.global_transform
|
|
|
|
built_structure_resource.item = structure.item
|
|
|
|
var item_array = save_data.built_structures.get_or_add(structure.item, [])
|
|
|
|
|
|
|
|
item_array.append(structure.global_transform)
|
|
|
|
|
|
|
|
print("Saving game: " + game_profile_path + "/savegame.tres")
|
|
|
|
ResourceSaver.save(save_data, game_profile_path + "/savegame.tres")
|
|
|
|
|
|
|
|
func load_game(game_profile_path:String) -> void:
|
|
|
|
print("Loading game: " + game_profile_path + "/savegame.tres")
|
|
|
|
var save_data:SaveGameResource = load(game_profile_path + "/savegame.tres") as SaveGameResource
|
|
|
|
|
|
|
|
load_level(save_data.level)
|
|
|
|
|
|
|
|
player.global_transform = save_data.player_transform
|
|
|
|
player.init_look_target_direction()
|
|
|
|
|
|
|
|
# Quest state
|
|
|
|
for quest_state:Node in get_tree().get_nodes_in_group("quest_state"):
|
|
|
|
for property in quest_state.get_property_list():
|
|
|
|
if (property.usage & PROPERTY_USAGE_STORAGE != 0) and (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE) != 0 and (save_data.quest_states.has(quest_state.name)) and (save_data.quest_states[quest_state.name].has(property.name)):
|
|
|
|
quest_state.set(property.name, save_data.quest_states[quest_state.name][property.name])
|
|
|
|
|
|
|
|
# Inventory
|
|
|
|
player.inventory.clear()
|
|
|
|
var inventory_item_stacks:Array[ItemStack] = player.inventory.get_item_stacks()
|
|
|
|
|
|
|
|
assert(inventory_item_stacks.size() >= save_data.inventory.size())
|
|
|
|
|
|
|
|
for i in range(save_data.inventory.size()):
|
|
|
|
inventory_item_stacks[i].item = save_data.inventory[i]["item"]
|
|
|
|
inventory_item_stacks[i].count = save_data.inventory[i]["count"]
|
|
|
|
|
|
|
|
# Picked up items
|
|
|
|
for item_path in save_data.level_pickup_items:
|
|
|
|
if get_tree().root.has_node(item_path):
|
|
|
|
var item_node = get_tree().root.get_node(item_path)
|
|
|
|
picked_up_level_items.append(item_path)
|
|
|
|
item_node.queue_free()
|
|
|
|
|
|
|
|
# Built structures
|
|
|
|
for item:ItemResource in save_data.built_structures.keys():
|
|
|
|
var item_transform_array = save_data.built_structures[item] as Array[Transform3D]
|
|
|
|
for structure_transform in item_transform_array:
|
|
|
|
build_system.build_structure(item, structure_transform)
|