diff options
| author | Matheus <matheus.guedes.mg.m@gmail.com> | 2025-10-26 20:02:15 -0300 |
|---|---|---|
| committer | Matheus <matheus.guedes.mg.m@gmail.com> | 2025-10-26 20:02:15 -0300 |
| commit | f4ed469fc9eaeebf39093fbf6601581cc10c6e2f (patch) | |
| tree | d8f29ae3288e950b5fb1f5251845d57949ca2ac0 /scripts | |
| parent | 639cd8cef403e9e66bf31e7888e786effac2b292 (diff) | |
feat:save AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
O vazio dentro de mim é como uma xícara de café esquecida
no canto da mesa.
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/Entities/Actions/EscapeAction.cs | 1 | ||||
| -rw-r--r-- | scripts/Entities/Actors/Actor.cs | 49 | ||||
| -rw-r--r-- | scripts/Entities/Actors/Enemy.cs | 32 | ||||
| -rw-r--r-- | scripts/Entities/Actors/Inventory.cs | 34 | ||||
| -rw-r--r-- | scripts/Entities/Actors/Player.cs | 32 | ||||
| -rw-r--r-- | scripts/Entities/Entity.cs | 25 | ||||
| -rw-r--r-- | scripts/Entities/Items/Item.cs | 24 | ||||
| -rw-r--r-- | scripts/Entities/Items/ItemEntity.cs | 40 | ||||
| -rw-r--r-- | scripts/GUI/MainMenu.cs | 2 | ||||
| -rw-r--r-- | scripts/Game.cs | 41 | ||||
| -rw-r--r-- | scripts/GameManager.cs | 21 | ||||
| -rw-r--r-- | scripts/Magic/SpellBook.cs | 30 | ||||
| -rw-r--r-- | scripts/Map/DungeonGenerator.cs | 2 | ||||
| -rw-r--r-- | scripts/Map/Map.cs | 18 | ||||
| -rw-r--r-- | scripts/Map/MapData.cs | 120 | ||||
| -rw-r--r-- | scripts/Map/Tile.cs | 49 | ||||
| -rw-r--r-- | scripts/Utils/ISaveable.cs | 9 | ||||
| -rw-r--r-- | scripts/Utils/ISaveable.cs.uid | 1 |
18 files changed, 510 insertions, 20 deletions
diff --git a/scripts/Entities/Actions/EscapeAction.cs b/scripts/Entities/Actions/EscapeAction.cs index cc5d289..f0b1ed5 100644 --- a/scripts/Entities/Actions/EscapeAction.cs +++ b/scripts/Entities/Actions/EscapeAction.cs @@ -7,6 +7,7 @@ public partial class EscapeAction(Actor actor) : Action(actor) { public override bool Perform() { + Actor.MapData.SaveGame(); SignalBus.Instance.EmitSignal(SignalBus.SignalName.EscapeRequested); return false; } diff --git a/scripts/Entities/Actors/Actor.cs b/scripts/Entities/Actors/Actor.cs index ec00e30..71a32a5 100644 --- a/scripts/Entities/Actors/Actor.cs +++ b/scripts/Entities/Actors/Actor.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Magic; using TheLegendOfGustav.Map; using TheLegendOfGustav.Utils; @@ -9,7 +10,7 @@ namespace TheLegendOfGustav.Entities.Actors; /// A classe de ator define um personagem no jogo. /// </summary> [GlobalClass] -public partial class Actor : Entity +public partial class Actor : Entity, ISaveable { #region Fields private int mp; @@ -29,6 +30,9 @@ public partial class Actor : Entity { SetDefinition(definition); } + public Actor(Vector2I initialPosition, MapData map) : base(initialPosition, map) + { + } #endregion #region Signals @@ -278,5 +282,48 @@ public partial class Actor : Entity MapData.UnregisterBlockingEntity(this); EmitSignal(SignalName.Died); } + + public new Dictionary<string, Variant> GetSaveData() + { + Dictionary<string, Variant> baseData = base.GetSaveData(); + baseData.Add("energy", Energy); + baseData.Add("max_hp", MaxHp); + baseData.Add("hp", Hp); + baseData.Add("max_mp", MaxMp); + baseData.Add("mp", MaxMp); + baseData.Add("atk", Atk); + baseData.Add("def", Def); + baseData.Add("men", Men); + baseData.Add("mp_regen_rate", MpRegenRate); + baseData.Add("mp_regen_per_turn", MpRegenPerTurn); + baseData.Add("spell_book", SpellBook.GetSaveData()); + + return baseData; + } + + public new bool LoadSaveData(Dictionary<string, Variant> saveData) + { + if (!base.LoadSaveData(saveData)) + { + return false; + } + + if (!SpellBook.LoadSaveData((Dictionary<string, Variant>)saveData["spell_book"])) + { + return false; + } + + Energy = (int)saveData["energy"]; + MaxHp = (int)saveData["max_hp"]; + Hp = (int)saveData["hp"]; + MaxMp = (int)saveData["max_mp"]; + Mp = (int)saveData["max_mp"]; + Atk = (int)saveData["atk"]; + Def = (int)saveData["def"]; + Men = (int)saveData["men"]; + MpRegenRate = (int)saveData["mp_regen_rate"]; + MpRegenPerTurn = (int)saveData["mp_regen_per_turn"]; + return true; + } #endregion }
\ No newline at end of file diff --git a/scripts/Entities/Actors/Enemy.cs b/scripts/Entities/Actors/Enemy.cs index d398176..4994534 100644 --- a/scripts/Entities/Actors/Enemy.cs +++ b/scripts/Entities/Actors/Enemy.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Entities.Actors.AI; using TheLegendOfGustav.Map; @@ -8,7 +9,7 @@ namespace TheLegendOfGustav.Entities.Actors; /// Um inimigo é uma espécie de ator que é /// hostil ao jogador. Inimigos são controlados por IA. /// </summary> -public partial class Enemy : Actor +public partial class Enemy : Actor, ISaveable { private EnemyDefinition definition; @@ -17,6 +18,9 @@ public partial class Enemy : Actor this.definition = definition; SetDefinition(definition); } + public Enemy(Vector2I initialPosition, MapData map) : base(initialPosition, map) + { + } /// <summary> /// A alma do ator. Gera ações que são executadas todo turno. @@ -30,9 +34,12 @@ public partial class Enemy : Actor /// <param name="definition">Definição do inimigo.</param> public void SetDefinition(EnemyDefinition definition) { + this.definition = definition; // Definimos as características do ator. base.SetDefinition(this.definition); + Soul?.QueueFree(); + // Definimos qual IA utilizar. switch (definition.AI) { @@ -51,4 +58,27 @@ public partial class Enemy : Actor Soul = null; base.Die(); } + + public new Dictionary<string, Variant> GetSaveData() + { + Dictionary<string, Variant> baseData = base.GetSaveData(); + baseData.Add("definition", definition.ResourcePath); + + return baseData; + } + + public new bool LoadSaveData(Dictionary<string, Variant> saveData) + { + string definitionPath = (string)saveData["definition"]; + EnemyDefinition definition = GD.Load<EnemyDefinition>(definitionPath); + + SetDefinition(definition); + + if (!base.LoadSaveData(saveData)) + { + return false; + } + + return true; + } } diff --git a/scripts/Entities/Actors/Inventory.cs b/scripts/Entities/Actors/Inventory.cs index 5ae61b4..ebc60e4 100644 --- a/scripts/Entities/Actors/Inventory.cs +++ b/scripts/Entities/Actors/Inventory.cs @@ -1,11 +1,12 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Entities.Items; using TheLegendOfGustav.Map; using TheLegendOfGustav.Utils; namespace TheLegendOfGustav.Entities.Actors; -public partial class Inventory(int capacity) : Node +public partial class Inventory(int capacity) : Node, ISaveable { private Player player; public int Capacity { get; private set; } = capacity; @@ -42,4 +43,35 @@ public partial class Inventory(int capacity) : Node { Items.Remove(item); } + + public Dictionary<string, Variant> GetSaveData() + { + Godot.Collections.Array<Dictionary<string, Variant>> itemsData = []; + foreach (Item item in Items) { + itemsData.Add(item.GetSaveData()); + } + + return new() + { + {"items", itemsData} + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + Array<Dictionary<string, Variant>> itemRess = (Array<Dictionary<string, Variant>>)saveData["items"]; + + foreach(Dictionary<string, Variant> item in itemRess) + { + Item it = new(); + if(!it.LoadSaveData(item)) + { + return false; + } + + Items.Add(it); + } + + return true; + } }
\ No newline at end of file diff --git a/scripts/Entities/Actors/Player.cs b/scripts/Entities/Actors/Player.cs index d6fedb9..7304e0a 100644 --- a/scripts/Entities/Actors/Player.cs +++ b/scripts/Entities/Actors/Player.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Map; namespace TheLegendOfGustav.Entities.Actors; @@ -7,7 +8,7 @@ namespace TheLegendOfGustav.Entities.Actors; /// Classe do jogador. Por enquanto não é diferente do Ator, mas isso pode mudar. /// </summary> [GlobalClass] -public partial class Player : Actor +public partial class Player : Actor, ISaveable { private PlayerDefinition definition; @@ -19,8 +20,37 @@ public partial class Player : Actor public Inventory Inventory { get; private set; } + public new Dictionary<string, Variant> GetSaveData() + { + Dictionary<string, Variant> baseData = base.GetSaveData(); + baseData.Add("inventory", Inventory.GetSaveData()); + baseData.Add("definition", definition.ResourcePath); + + return baseData; + } + + public new bool LoadSaveData(Dictionary<string, Variant> saveData) + { + PlayerDefinition definition = GD.Load<PlayerDefinition>((string)saveData["definition"]); + + SetDefinition(definition); + + if (!base.LoadSaveData(saveData)) + { + return false; + } + + if(!Inventory.LoadSaveData((Dictionary<string, Variant>)saveData["inventory"])) + { + return false; + } + + return true; + } + public void SetDefinition(PlayerDefinition definition) { + Inventory?.QueueFree(); Inventory = new(definition.InventoryCapacity); AddChild(Inventory); diff --git a/scripts/Entities/Entity.cs b/scripts/Entities/Entity.cs index b7dbcc2..76002b1 100644 --- a/scripts/Entities/Entity.cs +++ b/scripts/Entities/Entity.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Map; using TheLegendOfGustav.Utils; @@ -18,7 +19,7 @@ public enum EntityType /// <summary> /// Classe para elementos móveis que o jogador pode interagir. /// </summary> -public abstract partial class Entity : Sprite2D +public abstract partial class Entity : Sprite2D, ISaveable { private Vector2I gridPosition = Vector2I.Zero; @@ -138,4 +139,26 @@ public abstract partial class Entity : Sprite2D Type = definition.Type; Texture = definition.texture; } + + public Dictionary<string, Variant> GetSaveData() + { + return new() + { + {"position_x", GridPosition.X}, + {"position_y", GridPosition.Y}, + {"blocks_movement", BlocksMovement}, + {"name", DisplayName}, + {"layer", (int)Type}, + + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + GridPosition = new((int)saveData["position_x"], (int)saveData["position_y"]); + BlocksMovement = (bool)saveData["blocks_movement"]; + DisplayName = (string)saveData["name"]; + Type = (EntityType)(int)saveData["layer"]; + return true; + } }
\ No newline at end of file diff --git a/scripts/Entities/Items/Item.cs b/scripts/Entities/Items/Item.cs index 0eeffd8..17c318c 100644 --- a/scripts/Entities/Items/Item.cs +++ b/scripts/Entities/Items/Item.cs @@ -1,11 +1,12 @@ using System.Reflection.Metadata; using Godot; +using Godot.Collections; using TheLegendOfGustav.Entities.Actions; using TheLegendOfGustav.Entities.Actors; namespace TheLegendOfGustav.Entities.Items; -public partial class Item : RefCounted +public partial class Item : RefCounted, ISaveable { public Item(ItemResource definition) @@ -14,6 +15,10 @@ public partial class Item : RefCounted Uses = Definition.MaxUses; } + public Item() + { + } + public ItemResource Definition { get; private set; } public int Uses { get; set; } @@ -58,4 +63,21 @@ public partial class Item : RefCounted Inventory inventory = consumer.Inventory; inventory.RemoveItem(this); } + + public Dictionary<string, Variant> GetSaveData() + { + return new() + { + {"definition", Definition.ResourcePath}, + {"uses", Uses} + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + Definition = GD.Load<ItemResource>((string)saveData["definition"]); + Uses = (int)saveData["uses"]; + + return true; + } }
\ No newline at end of file diff --git a/scripts/Entities/Items/ItemEntity.cs b/scripts/Entities/Items/ItemEntity.cs index e646e40..66944ce 100644 --- a/scripts/Entities/Items/ItemEntity.cs +++ b/scripts/Entities/Items/ItemEntity.cs @@ -1,10 +1,11 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Map; namespace TheLegendOfGustav.Entities.Items; -public partial class ItemEntity : Entity +public partial class ItemEntity : Entity, ISaveable { public Item Item { get; private set; } @@ -14,7 +15,7 @@ public partial class ItemEntity : Entity // Eu quero muito reescrever o jogo do zero, mas não tenho tempo :( EntityDefinition sad = new() { - blocksMovement = true, + blocksMovement = false, name = item.Definition.DisplayName, texture = item.Definition.Icon, Type = EntityType.ITEM, @@ -22,4 +23,39 @@ public partial class ItemEntity : Entity SetDefinition(sad); } + public ItemEntity(Vector2I initialPosition, MapData map) : base(initialPosition, map) + { + } + + public new Dictionary<string, Variant> GetSaveData() + { + Dictionary<string, Variant> baseData = base.GetSaveData(); + baseData.Add("item", Item.GetSaveData()); + + return baseData; + } + + public new bool LoadSaveData(Dictionary<string, Variant> saveData) + { + Item = new(); + + if (!Item.LoadSaveData((Dictionary<string, Variant>)saveData["item"])) + { + return false; + } + // Eu quero muito reescrever o jogo do zero, mas não tenho tempo :( + EntityDefinition sad = new() + { + blocksMovement = false, + name = Item.Definition.DisplayName, + texture = Item.Definition.Icon, + Type = EntityType.ITEM, + }; + + SetDefinition(sad); + + base.LoadSaveData(saveData); + + return true; + } }
\ No newline at end of file diff --git a/scripts/GUI/MainMenu.cs b/scripts/GUI/MainMenu.cs index 74592c2..fc46cd2 100644 --- a/scripts/GUI/MainMenu.cs +++ b/scripts/GUI/MainMenu.cs @@ -24,7 +24,7 @@ public partial class MainMenu : Control quitButton.Pressed += OnQuitButtonPressed; newGameButton.GrabFocus(); - bool hasSaveFile = FileAccess.FileExists("user://save.dat"); + bool hasSaveFile = FileAccess.FileExists("user://save_game.json"); loadGameButton.Disabled = !hasSaveFile; } diff --git a/scripts/Game.cs b/scripts/Game.cs index f03aa20..47102c1 100644 --- a/scripts/Game.cs +++ b/scripts/Game.cs @@ -14,6 +14,7 @@ namespace TheLegendOfGustav; /// </summary> public partial class Game : Node { + private bool initialized = false; /// <summary> /// Definição de um jogador. /// </summary> @@ -41,10 +42,12 @@ public partial class Game : Node public override void _Ready() { base._Ready(); - escapeLambda = () => EmitSignal(SignalName.MainMenuRequested); SignalBus.Instance.EscapeRequested += escapeLambda; + } + public void NewGame() + { map = GetNode<Map.Map>("Map"); inputHandler = GetNode<InputHandler>("InputHandler"); @@ -67,6 +70,38 @@ public partial class Game : Node turnManager = new(map); MessageLogData.Instance.AddMessage("Boa sorte!"); + initialized = true; + } + public bool LoadGame() + { + map = GetNode<Map.Map>("Map"); + + inputHandler = GetNode<InputHandler>("InputHandler"); + hud = GetNode<Hud>("HUD"); + + // O jogador é criado pelo jogo. + Player player = new Player(Vector2I.Zero, null, playerDefinition); + Camera2D camera = GetNode<Camera2D>("Camera2D"); + RemoveChild(camera); + + player.AddChild(camera); + + if (!map.LoadGame(player)) + { + return false; + } + + player.HealthChanged += (int hp, int maxHp) => hud.OnHealthChanged(hp, maxHp); + player.ManaChanged += hud.OnManaChanged; + player.Died += () => inputHandler.SetInputHandler(InputHandlers.GameOver); + + map.UpdateFOV(player.GridPosition); + + turnManager = new(map); + + MessageLogData.Instance.AddMessage("Boa sorte!"); + initialized = true; + return true; } public override void _Notification(int what) @@ -90,6 +125,8 @@ public partial class Game : Node { base._PhysicsProcess(delta); + if(initialized) + { Player player = map.MapData.Player; // Pegamos uma ação do usuário @@ -102,6 +139,8 @@ public partial class Game : Node // Computamos um turno. turnManager.Tick(); + + } } } diff --git a/scripts/GameManager.cs b/scripts/GameManager.cs index 8bc8b6b..a17ae79 100644 --- a/scripts/GameManager.cs +++ b/scripts/GameManager.cs @@ -50,10 +50,29 @@ public partial class GameManager : Node MessageLogData.Instance.ClearMessages(); Game game = (Game)SwitchToScene(gameScene); game.MainMenuRequested += LoadMainMenu; + if (!game.LoadGame()) + { + SwitchToScene(mainMenuScene); + } + } + + private void NewGame() + { + MessageLogData.Instance.ClearMessages(); + Game game = (Game)SwitchToScene(gameScene); + game.NewGame(); + game.MainMenuRequested += LoadMainMenu; } private void OnGameRequest(bool load) { - LoadGame(); + if (!load) + { + NewGame(); + } + else + { + LoadGame(); + } } } diff --git a/scripts/Magic/SpellBook.cs b/scripts/Magic/SpellBook.cs index 8ccba71..914add6 100644 --- a/scripts/Magic/SpellBook.cs +++ b/scripts/Magic/SpellBook.cs @@ -1,8 +1,9 @@ using Godot; +using Godot.Collections; namespace TheLegendOfGustav.Magic; -public partial class SpellBook : Node +public partial class SpellBook : Node, ISaveable { public Godot.Collections.Array<SpellResource> KnownSpells { get; private set; } = []; @@ -17,4 +18,31 @@ public partial class SpellBook : Node public void ForgetSpell(SpellResource spell) { KnownSpells.Remove(spell); } + + public Dictionary<string, Variant> GetSaveData() + { + Array<string> spellPaths = []; + foreach(SpellResource spell in KnownSpells) + { + spellPaths.Add(spell.ResourcePath); + } + + return new() + { + {"spells", spellPaths} + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + Array<string> paths = (Array<string>)saveData["spells"]; + + foreach(string path in paths) + { + SpellResource spell = GD.Load<SpellResource>(path); + KnownSpells.Add(spell); + } + + return true; + } }
\ No newline at end of file diff --git a/scripts/Map/DungeonGenerator.cs b/scripts/Map/DungeonGenerator.cs index 7e447b0..2d5ef8d 100644 --- a/scripts/Map/DungeonGenerator.cs +++ b/scripts/Map/DungeonGenerator.cs @@ -144,7 +144,7 @@ public partial class DungeonGenerator : Node Tile tile = data.GetTile(pos); if (tile == null) return; - tile.SetDefinition(MapData.floorDefinition); + tile.Key = TileType.FLOOR; } /// <summary> diff --git a/scripts/Map/Map.cs b/scripts/Map/Map.cs index 8521797..04ccabd 100644 --- a/scripts/Map/Map.cs +++ b/scripts/Map/Map.cs @@ -1,3 +1,4 @@ +using System.Net.Http.Headers; using Godot; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Actors; @@ -95,4 +96,21 @@ public partial class Map : Node2D { entitiesNode.AddChild(entity); } + + public bool LoadGame(Player player) + { + + MapData = new(0, 0, player); + + if (!MapData.LoadGame()) + { + return false; + } + + PlaceTiles(); + PlaceEntities(); + + MapData.EntityPlaced += OnEntityPlaced; + return true; + } } diff --git a/scripts/Map/MapData.cs b/scripts/Map/MapData.cs index 49e4ca0..5f96743 100644 --- a/scripts/Map/MapData.cs +++ b/scripts/Map/MapData.cs @@ -1,4 +1,5 @@ using Godot; +using Godot.Collections; using TheLegendOfGustav.Entities; using TheLegendOfGustav.Entities.Actors; using TheLegendOfGustav.Entities.Items; @@ -10,11 +11,9 @@ namespace TheLegendOfGustav.Map; /// O mapa é o cenário onde as ações do jogo ocorrem. /// Mais especificamente, o mapa é um único andar da masmorra. /// </summary> -public partial class MapData : RefCounted +public partial class MapData : RefCounted, ISaveable { #region Fields - public static readonly TileDefinition wallDefinition = GD.Load<TileDefinition>("res://assets/definitions/tiles/wall.tres"); - public static readonly TileDefinition floorDefinition = GD.Load<TileDefinition>("res://assets/definitions/tiles/floor.tres"); /// <summary> /// Peso do ator no pathfinder. /// A IA irá evitar de passar por espaços com peso alto. @@ -275,11 +274,16 @@ public partial class MapData : RefCounted /// </summary> private void SetupTiles() { + if (Tiles.Count > 1) + { + Tiles.Clear(); + } + for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { - Tiles.Add(new Tile(new Vector2I(j, i), wallDefinition)); + Tiles.Add(new Tile(new Vector2I(j, i), TileType.WALL)); } } } @@ -314,5 +318,113 @@ public partial class MapData : RefCounted return true; } + + public Dictionary<string, Variant> GetSaveData() + { + Array<Dictionary<string, Variant>> serializedTiles = []; + Array<Dictionary<string, Variant>> serializedItemEntities = []; + Array<Dictionary<string, Variant>> serializedEnemies = []; + foreach (Tile tile in Tiles) + { + serializedTiles.Add(tile.GetSaveData()); + } + + foreach (Entity ent in Entities) + { + if (ent is Enemy enemy) + { + serializedEnemies.Add(enemy.GetSaveData()); + } + else if (ent is ItemEntity it) + { + serializedItemEntities.Add(it.GetSaveData()); + } + } + + return new() + { + {"tiles", serializedTiles}, + {"enemies", serializedEnemies}, + {"items", serializedItemEntities}, + {"player", Player.GetSaveData()}, + {"width", Width}, + {"height", Height}, + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + Width = (int)saveData["width"]; + Height = (int)saveData["height"]; + + SetupTiles(); + + Array<Dictionary<string, Variant>> serializedTiles = (Array<Dictionary<string, Variant>>)saveData["tiles"]; + Array<Dictionary<string, Variant>> serializedItemEntities = (Array<Dictionary<string, Variant>>)saveData["items"]; + Array<Dictionary<string, Variant>> serializedEnemies = (Array<Dictionary<string, Variant>>)saveData["enemies"]; + + for (int i = 0; i < serializedTiles.Count; i++) + { + if (!Tiles[i].LoadSaveData(serializedTiles[i])) + { + return false; + } + } + SetupPathfinding(); + if (!Player.LoadSaveData((Dictionary<string, Variant>)saveData["player"])) + { + return false; + } + + Player.MapData = this; + + foreach(Dictionary<string, Variant> enemy in serializedEnemies) + { + Enemy en = new(Vector2I.Zero, this); + if (!en.LoadSaveData(enemy)) + { + return false; + } + + InsertEntity(en); + } + + foreach(Dictionary<string, Variant> item in serializedItemEntities) + { + ItemEntity en = new(Vector2I.Zero, this); + + if (!en.LoadSaveData(item)) + { + return false; + } + + InsertEntity(en); + } + + return true; + } + + public void SaveGame() + { + using var saveFile = FileAccess.Open("user://save_game.json", FileAccess.ModeFlags.Write); + var saveData = GetSaveData(); + string saveString = Json.Stringify(saveData); + + saveFile.StoreLine(saveString); + } + + public bool LoadGame() + { + using var saveFile = FileAccess.Open("user://save_game.json", FileAccess.ModeFlags.Read); + string saveString = saveFile.GetLine(); + var saveData = (Dictionary<string, Variant>)Json.ParseString(saveString); + + if (!LoadSaveData(saveData)) + { + return false; + } + + return true; + } #endregion } diff --git a/scripts/Map/Tile.cs b/scripts/Map/Tile.cs index 488d124..6790f3e 100644 --- a/scripts/Map/Tile.cs +++ b/scripts/Map/Tile.cs @@ -1,16 +1,41 @@ +using System.Threading; using Godot; +using Godot.Collections; using TheLegendOfGustav.Utils; namespace TheLegendOfGustav.Map; +public enum TileType +{ + WALL, + FLOOR +} + /// <summary> /// O mundo do jogo é composto por Tiles. /// Um tile é um quadrado de 16x16 que representa uma /// unidade discreta do cenário. Tiles podem agir como /// parede, chão, ou outras funções. /// </summary> -public partial class Tile : Sprite2D +public partial class Tile : Sprite2D, ISaveable { + private static readonly Godot.Collections.Dictionary<TileType, TileDefinition> Types = new() + { + {TileType.WALL, GD.Load<TileDefinition>("res://assets/definitions/tiles/wall.tres")}, + {TileType.FLOOR, GD.Load<TileDefinition>("res://assets/definitions/tiles/floor.tres")} + }; + + TileType key; + public TileType Key + { + get => key; + set + { + key = value; + SetDefinition(Types[value]); + } + } + private bool isExplored = false; private bool isInView = false; @@ -19,7 +44,7 @@ public partial class Tile : Sprite2D /// </summary> private TileDefinition definition; - public Tile(Vector2I pos, TileDefinition definition) + public Tile(Vector2I pos, TileType type) { // Tile herda da classe Sprite2D. // Por padrão, a posição do Sprite2D é no centro de sua textura. @@ -29,7 +54,7 @@ public partial class Tile : Sprite2D // Tiles começam invisíveis porque não foram vistos pelo jogador. Visible = false; Position = Grid.GridToWorld(pos); - SetDefinition(definition); + Key = type; } /// <summary> @@ -89,4 +114,22 @@ public partial class Tile : Sprite2D IsWalkable = definition.IsWalkable; IsTransparent = definition.IsTransparent; } + + public Dictionary<string, Variant> GetSaveData() + { + return new() + { + {"key", (int)Key}, + {"is_explored", IsExplored} + }; + } + + public bool LoadSaveData(Dictionary<string, Variant> saveData) + { + // É o seguinte, não tenho tempo, não vou verificar se a entrada está correta. + Key = (TileType)(int)saveData["key"]; + + IsExplored = (bool)saveData["is_explored"]; + return true; + } } diff --git a/scripts/Utils/ISaveable.cs b/scripts/Utils/ISaveable.cs new file mode 100644 index 0000000..12f5784 --- /dev/null +++ b/scripts/Utils/ISaveable.cs @@ -0,0 +1,9 @@ + +using Godot; + +public interface ISaveable +{ + public Godot.Collections.Dictionary<string, Variant> GetSaveData(); + + public bool LoadSaveData(Godot.Collections.Dictionary<string, Variant> saveData); +}
\ No newline at end of file diff --git a/scripts/Utils/ISaveable.cs.uid b/scripts/Utils/ISaveable.cs.uid new file mode 100644 index 0000000..6274214 --- /dev/null +++ b/scripts/Utils/ISaveable.cs.uid @@ -0,0 +1 @@ +uid://dx53repg15jv |
