diff --git a/GlobalSuppressions.cs.uid b/GlobalSuppressions.cs.uid new file mode 100644 index 00000000..5c451bd6 --- /dev/null +++ b/GlobalSuppressions.cs.uid @@ -0,0 +1 @@ +uid://dd3so0j48jtyc diff --git a/project.godot b/project.godot index fd4110b3..0ee38be2 100644 --- a/project.godot +++ b/project.godot @@ -14,6 +14,7 @@ config/name="GameJamDungeon" run/main_scene="uid://d1gjaijijd5ot" run/print_header=false config/features=PackedStringArray("4.4", "C#", "GL Compatibility") +run/max_fps=60 boot_splash/show_image=false [autoload] @@ -192,6 +193,16 @@ Previous={ "events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":true,"script":null) ] } +Save={ +"deadzone": 0.2, +"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":true,"script":null) +] +} +Load={ +"deadzone": 0.2, +"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":true,"script":null) +] +} [internationalization] diff --git a/src/audio/state/states/InGameAudioLogic.State.Enabled.cs b/src/audio/state/states/InGameAudioLogic.State.Enabled.cs index 06756adf..65d80ed6 100644 --- a/src/audio/state/states/InGameAudioLogic.State.Enabled.cs +++ b/src/audio/state/states/InGameAudioLogic.State.Enabled.cs @@ -50,7 +50,7 @@ public partial class InGameAudioLogic private void OnInventorySorted() => Output(new Output.PlayInventorySortedSound()); - private void OnEquippedItem(IEquipableItem equipableItem) => Output(new Output.PlayEquipSound()); + private void OnEquippedItem(EquipableItem equipableItem) => Output(new Output.PlayEquipSound()); private void OnOverworldEntered() => Output(new Output.PlayOverworldMusic()); diff --git a/src/enemy/Enemy.cs b/src/enemy/Enemy.cs index 8c677466..669c2327 100644 --- a/src/enemy/Enemy.cs +++ b/src/enemy/Enemy.cs @@ -135,7 +135,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide _enemyModelView.PlayHitAnimation(); _enemyLogic.Input(new EnemyLogic.Input.Alerted()); - if (_player.EquippedWeapon.Value.WeaponTags.Contains(WeaponTag.SelfDamage)) + if (_player.EquippedWeapon.Value.WeaponTag == WeaponTag.SelfDamage) _player.Stats.SetCurrentHP(_player.Stats.CurrentHP.Value - 5); } } diff --git a/src/enemy/WeaponTag.cs b/src/enemy/WeaponTag.cs index bc1766a8..3b2c7f0a 100644 --- a/src/enemy/WeaponTag.cs +++ b/src/enemy/WeaponTag.cs @@ -1,13 +1,23 @@ -namespace GameJamDungeon; +using System.Text.Json.Serialization; + +namespace GameJamDungeon; public enum WeaponTag { + None, SelfDamage, IgnoreAffinity, Knockback, } +[JsonSerializable(typeof(WeaponTag))] +public partial class WeaponTagEnumContext : JsonSerializerContext; + public enum ItemTag { + None, BreaksOnChange } + +[JsonSerializable(typeof(ItemTag))] +public partial class ItemTagEnumContext : JsonSerializerContext; diff --git a/src/game/ElementType.cs b/src/game/ElementType.cs index 546d1d42..91fa5ecf 100644 --- a/src/game/ElementType.cs +++ b/src/game/ElementType.cs @@ -1,4 +1,6 @@ -namespace GameJamDungeon; +using System.Text.Json.Serialization; + +namespace GameJamDungeon; public enum ElementType { @@ -9,3 +11,6 @@ public enum ElementType Igneous, Ferrum } + +[JsonSerializable(typeof(ElementType))] +public partial class ElementTypeEnumContext : JsonSerializerContext; diff --git a/src/game/Game.cs b/src/game/Game.cs index 9fcf5437..75a71158 100644 --- a/src/game/Game.cs +++ b/src/game/Game.cs @@ -7,11 +7,12 @@ using Chickensoft.Introspection; using Chickensoft.SaveFileBuilder; using Chickensoft.Serialization; using Chickensoft.Serialization.Godot; +using GameJamDungeon.src.items; using Godot; -using Org.BouncyCastle.Asn1.Pkcs; using System; using System.IO.Abstractions; using System.Text.Json; +using System.Text.Json.Serialization.Metadata; using static GameJamDungeon.GameLogic.State; [Meta(typeof(IAutoNode))] @@ -78,6 +79,8 @@ public partial class Game : Node3D, IGame public RescuedItemDatabase RescuedItems { get; set; } = default!; + private EffectService _effectService; + public void Setup() { FileSystem = new FileSystem(); @@ -96,6 +99,7 @@ public partial class Game : Node3D, IGame var resolver = new SerializableTypeResolver(); GodotSerialization.Setup(); + Serializer.AddConverter(new Texture2DConverter()); var upgradeDependencies = new Blackboard(); @@ -104,7 +108,7 @@ public partial class Game : Node3D, IGame Converters = { new SerializableTypeConverter(upgradeDependencies) }, - TypeInfoResolver = resolver, + TypeInfoResolver = JsonTypeInfoResolver.Combine(resolver, WeaponTagEnumContext.Default, ItemTagEnumContext.Default, ElementTypeEnumContext.Default, AccessoryTagEnumContext.Default, ThrowableItemTagEnumContext.Default, UsableItemTagEnumContext.Default, BoxItemTagEnumContext.Default), WriteIndented = true }; @@ -113,23 +117,27 @@ public partial class Game : Node3D, IGame { var gameData = new GameData() { - PlayerData = new PlayerStats + PlayerData = new PlayerData() { - CurrentHP = Player.Stats.CurrentHP.Value, - MaximumHP = Player.Stats.MaximumHP.Value, - CurrentVT = Player.Stats.CurrentVT.Value, - MaximumVT = Player.Stats.MaximumVT.Value, - CurrentAttack = Player.Stats.CurrentAttack.Value, - BonusAttack = Player.Stats.BonusAttack.Value, - MaxAttack = Player.Stats.MaxAttack.Value, - CurrentDefense = Player.Stats.CurrentDefense.Value, - BonusDefense = Player.Stats.BonusDefense.Value, - MaxDefense = Player.Stats.MaxDefense.Value, - CurrentExp = Player.Stats.CurrentExp.Value, - CurrentLevel = Player.Stats.CurrentLevel.Value, - ExpToNextLevel = Player.Stats.ExpToNextLevel.Value, - Luck = Player.Stats.Luck.Value - }, + PlayerStats = new PlayerStats() + { + CurrentHP = Player.Stats.CurrentHP.Value, + MaximumHP = Player.Stats.MaximumHP.Value, + CurrentVT = Player.Stats.CurrentVT.Value, + MaximumVT = Player.Stats.MaximumVT.Value, + CurrentAttack = Player.Stats.CurrentAttack.Value, + BonusAttack = Player.Stats.BonusAttack.Value, + MaxAttack = Player.Stats.MaxAttack.Value, + CurrentDefense = Player.Stats.CurrentDefense.Value, + BonusDefense = Player.Stats.BonusDefense.Value, + MaxDefense = Player.Stats.MaxDefense.Value, + CurrentExp = Player.Stats.CurrentExp.Value, + CurrentLevel = Player.Stats.CurrentLevel.Value, + ExpToNextLevel = Player.Stats.ExpToNextLevel.Value, + Luck = Player.Stats.Luck.Value + }, + Inventory = Player.Inventory + } }; return gameData; @@ -222,12 +230,22 @@ public partial class Game : Node3D, IGame GameEventDepot.RestorativePickedUp += GameEventDepot_RestorativePickedUp; DoubleEXPTimer.Timeout += DoubleEXPTimer_Timeout; + + _effectService = new EffectService(this, Player); + } + + public void Save() + { + SaveFile.Save(); + } + + public void Load() + { + SaveFile.Load(); } public void ToggleInventory() { - SaveFile.Load(); - if (GameLogic.Value is InventoryOpened) GameLogic.Input(new GameLogic.Input.CloseInventory()); else @@ -250,7 +268,81 @@ public partial class Game : Node3D, IGame InGameUI.PlayerInfoUI.DisplayMessage($"{pickedUpItemName} picked up."); } - public void DropItem(IInventoryItem item) + public void UseItem(InventoryItem item) + { + if (item is ConsumableItem consumableItem) + { + if (Player.Stats.CurrentHP == Player.Stats.MaximumHP && consumableItem.RaiseHPAmount > 0) + Player.RaiseHP(consumableItem.RaiseHPAmount); + if (Player.Stats.CurrentVT == Player.Stats.MaximumVT && consumableItem.RaiseVTAmount > 0) + Player.RaiseVT(consumableItem.RaiseVTAmount); + + if (consumableItem.HealHPAmount > 0 && Player.Stats.CurrentHP != Player.Stats.MaximumHP) + Player.HealHP(consumableItem.HealHPAmount); + if (consumableItem.HealVTAmount > 0 && Player.Stats.CurrentVT != Player.Stats.MaximumVT) + Player.HealVT(consumableItem.HealVTAmount); + } + if (item is EffectItem effectItem) + { + switch (effectItem.UsableItemTag) + { + case UsableItemTag.DoubleEXP: + DoubleEXP(TimeSpan.FromSeconds(30)); + break; + case UsableItemTag.TeleportAllEnemiesToRoom: + _effectService.TeleportEnemiesToCurrentRoom(); + break; + case UsableItemTag.KillHalfEnemiesInRoom: + _effectService.KillHalfEnemiesInRoom(); + break; + case UsableItemTag.TurnAllEnemiesIntoHealingItem: + _effectService.TurnAllEnemiesInRoomIntoHealingItem(); + break; + case UsableItemTag.HealsAllInRoomToMaxHP: + _effectService.HealAllEnemiesAndPlayerInRoomToFull(); + break; + case UsableItemTag.AbsorbHPFromAllEnemiesInRoom: + _effectService.AbsorbHPFromAllEnemiesInRoom(); + break; + case UsableItemTag.DealElementalDamageToAllEnemiesInRoom: + _effectService.DealElementalDamageToAllEnemiesInRoom(ElementType.Hydric); + break; + case UsableItemTag.SwapHPAndVT: + _effectService.SwapHPandVT(); + break; + case UsableItemTag.RaiseCurrentWeaponAttack: + _effectService.RaiseCurrentWeaponAttack(); + break; + case UsableItemTag.RaiseCurrentDefenseArmor: + _effectService.RaiseCurrentArmorDefense(); + break; + case UsableItemTag.RaiseLevel: + _effectService.RaiseLevel(); + break; + case UsableItemTag.RandomEffect: + _effectService.RandomEffect(effectItem); + break; + } + } + if (item is ThrowableItem throwableItem) + { + if (throwableItem.HealHPAmount > 0) + Player.HealHP(throwableItem.HealHPAmount); + if (throwableItem.HealVTAmount > 0) + Player.HealVT(throwableItem.HealVTAmount); + + if (throwableItem.ThrowableItemTag == ThrowableItemTag.TeleportToRandomLocation) + _effectService.TeleportToRandomRoom(Player); + + if (throwableItem.ThrowableItemTag == ThrowableItemTag.CanChangeAffinity) + _effectService.ChangeAffinity(throwableItem); + + if (throwableItem.ThrowableItemTag == ThrowableItemTag.WarpToExitIfFound) + _effectService.WarpToExit(Player); + } + } + + public void DropItem(InventoryItem item) { var droppedScene = GD.Load("res://src/items/dropped/DroppedItem.tscn"); var dropped = droppedScene.Instantiate(); @@ -259,14 +351,14 @@ public partial class Game : Node3D, IGame dropped.Drop(); } - public void ThrowItem(IInventoryItem item) + public void ThrowItem(InventoryItem item) { var thrownScene = GD.Load("res://src/items/thrown/ThrownItem.tscn"); var thrown = thrownScene.Instantiate(); thrown.ItemThatIsThrown = item; AddChild(thrown); thrown.Position += new Vector3(0, 1.5f, 0); - thrown.Throw(); + thrown.Throw(_effectService); } public void AnnounceMessageOnInventoryScreen(string message) @@ -323,11 +415,11 @@ public partial class Game : Node3D, IGame private void FloorClearMenu_TransitionCompleted() { GameRepo.Resume(); - if (Player.EquippedWeapon.Value.ItemTags.Contains(ItemTag.BreaksOnChange)) + if (Player.EquippedWeapon.Value.ItemTag == ItemTag.BreaksOnChange) Player.Unequip(Player.EquippedWeapon.Value); - if (Player.EquippedArmor.Value.ItemTags.Contains(ItemTag.BreaksOnChange)) + if (Player.EquippedArmor.Value.ItemTag == ItemTag.BreaksOnChange) Player.Unequip(Player.EquippedArmor.Value); - if (Player.EquippedAccessory.Value.ItemTags.Contains(ItemTag.BreaksOnChange)) + if (Player.EquippedAccessory.Value.ItemTag == ItemTag.BreaksOnChange) Player.Unequip(Player.EquippedAccessory.Value); } diff --git a/src/game/Game.tscn b/src/game/Game.tscn index bf60aefe..37d7132c 100644 --- a/src/game/Game.tscn +++ b/src/game/Game.tscn @@ -4,7 +4,7 @@ [ext_resource type="Shader" uid="uid://dmjxo4k2rx1an" path="res://src/app/App.gdshader" id="2_6ifxs"] [ext_resource type="PackedScene" uid="uid://by67pn7fdsg1m" path="res://src/map/Map.tscn" id="3_d8awv"] [ext_resource type="PackedScene" uid="uid://cfecvvav8kkp6" path="res://src/player/Player.tscn" id="3_kk6ly"] -[ext_resource type="Resource" uid="uid://bpdbuf0k0exb5" path="res://src/items/weapons/resources/Sword Sword Odette.tres" id="4_6pp6l"] +[ext_resource type="Resource" uid="uid://bpdbuf0k0exb5" path="res://src/items/weapons/resources/Swan Sword Odette.tres" id="4_6pp6l"] [ext_resource type="PackedScene" uid="uid://b1muxus5qdbeu" path="res://src/ui/in_game_ui/InGameUI.tscn" id="5_lxtnp"] [ext_resource type="PackedScene" uid="uid://b16ejcwanod72" path="res://src/audio/InGameAudio.tscn" id="6_qc71l"] [ext_resource type="Script" uid="uid://daphxl6vvsbjm" path="res://src/game/DialogueController.cs" id="10_58pbt"] diff --git a/src/game/GameData.cs b/src/game/GameData.cs index 08f5fa57..07a95cfc 100644 --- a/src/game/GameData.cs +++ b/src/game/GameData.cs @@ -7,5 +7,5 @@ namespace GameJamDungeon; public partial record GameData { [Save("player_data")] - public required PlayerStats PlayerData { get; init; } + public required PlayerData PlayerData { get; init; } } diff --git a/src/game/IGame.cs b/src/game/IGame.cs index 9639fed9..d9239c32 100644 --- a/src/game/IGame.cs +++ b/src/game/IGame.cs @@ -15,9 +15,11 @@ public interface IGame : IProvide, IProvide, IProvid public IDungeonFloor CurrentFloor { get; } - public void DropItem(IInventoryItem item); + public void UseItem(InventoryItem item); - public void ThrowItem(IInventoryItem item); + public void DropItem(InventoryItem item); + + public void ThrowItem(InventoryItem item); public void DoubleEXP(TimeSpan lengthOfEffect); @@ -34,4 +36,8 @@ public interface IGame : IProvide, IProvide, IProvid public void NextFloorLoaded(); public void EnemyDefeated(Vector3 defeatedLocation, EnemyStatResource enemyStatResource); + + public void Save(); + + public void Load(); } diff --git a/src/inventory_menu/InventoryMenu.cs b/src/inventory_menu/InventoryMenu.cs index 94dc6b82..6e9ffe10 100644 --- a/src/inventory_menu/InventoryMenu.cs +++ b/src/inventory_menu/InventoryMenu.cs @@ -266,7 +266,7 @@ public partial class InventoryMenu : Control, IInventoryMenu var currentItem = ItemSlots.ElementAt(_currentIndex).Item; - if (currentItem is IEquipableItem equipable) + if (currentItem is EquipableItem equipable) { ; UseButton.Text = equipable.IsEquipped ? "Unequip" : "Equip"; @@ -339,14 +339,14 @@ public partial class InventoryMenu : Control, IInventoryMenu itemSlot.Item = item; ItemsPage.AddChildEx(itemSlot); - if (itemSlot.Item is IEquipableItem equipable && equipable.IsEquipped) + if (itemSlot.Item is EquipableItem equipable && equipable.IsEquipped) itemSlot.SetEquippedItemStyle(); } if (ItemSlots.Any()) { ItemSlots.ElementAt(_currentIndex).SetSelectedItemStyle(); - if (ItemSlots.ElementAt(_currentIndex).Item is IEquipableItem equipable && equipable.IsEquipped) + if (ItemSlots.ElementAt(_currentIndex).Item is EquipableItem equipable && equipable.IsEquipped) ItemSlots.ElementAt(_currentIndex).SetEquippedSelectedItemStyle(); } } @@ -355,7 +355,7 @@ public partial class InventoryMenu : Control, IInventoryMenu { await ToSignal(GetTree().CreateTimer(0.1f), "timeout"); itemSlot.SetItemStyle(); - if (itemSlot.Item is IEquipableItem equipable && equipable.IsEquipped) + if (itemSlot.Item is EquipableItem equipable && equipable.IsEquipped) itemSlot.SetEquippedItemStyle(); } @@ -370,7 +370,7 @@ public partial class InventoryMenu : Control, IInventoryMenu private async Task EquipOrUnequipItem() { var itemSlot = ItemSlots[_currentIndex]; - if (itemSlot.Item is IEquipableItem equipableItem) + if (itemSlot.Item is EquipableItem equipableItem) { if (equipableItem.IsEquipped) { @@ -392,21 +392,21 @@ public partial class InventoryMenu : Control, IInventoryMenu private async void UseButtonPressed() { var currentItem = ItemSlots[_currentIndex].Item; - if (currentItem is IEquipableItem) + if (currentItem is EquipableItem) await EquipOrUnequipItem(); - else if (currentItem is IUsableItem usableItem) + else { - usableItem.Use(); - DestroyItem(usableItem); + Game.UseItem(currentItem); + DestroyItem(currentItem); EmitSignal(SignalName.ClosedMenu); } RefreshUIAfterUserSelection(); } - private async void DestroyItem(IUsableItem usableItem) + private async void DestroyItem(InventoryItem item) { - Player.Inventory.Remove(usableItem); + Player.Inventory.Remove(item); if (_currentIndex >= ItemSlots.Length - 1) _currentIndex--; if (_currentIndex <= 0) diff --git a/src/inventory_menu/ItemSlot.cs b/src/inventory_menu/ItemSlot.cs index 9d59b434..b7e19efe 100644 --- a/src/inventory_menu/ItemSlot.cs +++ b/src/inventory_menu/ItemSlot.cs @@ -7,7 +7,7 @@ namespace GameJamDungeon; public interface IItemSlot : IHBoxContainer { - public IInventoryItem Item { get; set; } + public InventoryItem Item { get; set; } public void SetItemStyle(); @@ -41,7 +41,7 @@ public partial class ItemSlot : HBoxContainer, IItemSlot { ItemName.Text = Item.ItemName; //EquipBonus.Text = "..."; - ItemTexture.Texture = Item.GetTexture(); + ItemTexture.Texture = Item.ItemStats.Texture; Player.EquippedWeapon.Sync += EquippedWeapon_Sync; Player.EquippedArmor.Sync += EquippedArmor_Sync; Player.EquippedAccessory.Sync += EquippedAccessory_Sync; @@ -90,7 +90,7 @@ public partial class ItemSlot : HBoxContainer, IItemSlot } public void SetSelectedItemStyle() { - if (Item is IEquipableItem equipableItem && equipableItem.IsEquipped) + if (Item is EquipableItem equipableItem && equipableItem.IsEquipped) { ItemName.LabelSettings = SelectedEquippedItemFont; //EquipBonus.LabelSettings = EquippedItemFont; @@ -113,5 +113,5 @@ public partial class ItemSlot : HBoxContainer, IItemSlot //EquipBonus.LabelSettings = EquippedItemFont; } - public IInventoryItem Item { get; set; } = default!; + public InventoryItem Item { get; set; } = default!; } diff --git a/src/item_rescue/RescuedItemDatabase.cs b/src/item_rescue/RescuedItemDatabase.cs index 082ef850..a8c93ede 100644 --- a/src/item_rescue/RescuedItemDatabase.cs +++ b/src/item_rescue/RescuedItemDatabase.cs @@ -4,10 +4,10 @@ namespace GameJamDungeon; public class RescuedItemDatabase { - public List Items; + public List Items; public RescuedItemDatabase() { - Items = new List(); + Items = new List(); } } diff --git a/src/items/EffectService.cs b/src/items/EffectService.cs new file mode 100644 index 00000000..67edfb97 --- /dev/null +++ b/src/items/EffectService.cs @@ -0,0 +1,219 @@ +using Godot; +using System.Linq; +using System; + +namespace GameJamDungeon.src.items +{ + public class EffectService + { + private readonly IGame _game; + private readonly IPlayer _player; + + public EffectService(IGame game, IPlayer player) + { + _game = game; + _player = player; + } + + public void TeleportEnemiesToCurrentRoom() + { + var currentFloor = _game.CurrentFloor; + var rooms = currentFloor.Rooms; + var currentRoom = _player.GetCurrentRoom(); + + if (currentRoom is not MonsterRoom) + return; + + var validRooms = rooms.OfType().ToList(); + if (currentRoom is MonsterRoom monsterRoom) + validRooms.Remove(monsterRoom); + + var currentMonsterRoom = (MonsterRoom)currentRoom; + + var enemyList = validRooms.SelectMany(x => x.GetEnemiesInCurrentRoom()); + + foreach (var enemy in enemyList) + { + var spawnPoints = currentMonsterRoom.EnemySpawnPoints.GetChildren().OfType().ToList(); + var spawnPointsGodotCollection = new Godot.Collections.Array(spawnPoints); + var randomSpawnPoint = spawnPointsGodotCollection.PickRandom(); + enemy.SetEnemyGlobalPosition(randomSpawnPoint.GlobalPosition); + } + } + + public void KillHalfEnemiesInRoom() + { + var currentRoom = _player.GetCurrentRoom(); + if (currentRoom is not MonsterRoom) + return; + + var currentMonsterRoom = (MonsterRoom)currentRoom; + var enemyList = currentMonsterRoom.GetEnemiesInCurrentRoom().ToList(); + var enemiesToKill = enemyList.Count / 2; + for (var i = 0; i < enemiesToKill; i++) + enemyList[i].Die(); + } + + public void TurnAllEnemiesInRoomIntoHealingItem() + { + var currentRoom = _player.GetCurrentRoom(); + var currentEnemies = currentRoom.EnemiesInRoom; + foreach (var enemy in currentEnemies) + { + enemy.Die(); + DropHealingItem(enemy.GetEnemyGlobalPosition()); + } + } + + public void DropHealingItem(Vector3 vector) + { + var consumableFolder = "res://src/items/consumable"; + var restorativeScene = GD.Load($"{consumableFolder}/ConsumableItem.tscn"); + var consumable = restorativeScene.Instantiate(); + var resourceFiles = DirAccess.GetFilesAt($"{consumableFolder}/resources"); + var rng = new RandomNumberGenerator(); + rng.Randomize(); + var randomResource = resourceFiles[rng.RandiRange(0, resourceFiles.Length - 1)]; + var randomFile = ResourceLoader.Load($"{consumableFolder}/resources/{randomResource}"); + consumable.ItemStats = randomFile; + _game.AddChild(consumable); + consumable.GlobalPosition = vector; + } + + public void HealAllEnemiesAndPlayerInRoomToFull() + { + var currentRoom = _player.GetCurrentRoom(); + var currentEnemies = currentRoom.EnemiesInRoom; + foreach (var enemy in currentEnemies) + enemy.SetCurrentHP(enemy.GetMaximumHP()); + _player.Stats.SetCurrentHP(_player.Stats.MaximumHP.Value); + } + + public void AbsorbHPFromAllEnemiesInRoom() + { + var currentRoom = _player.GetCurrentRoom(); + var currentEnemies = currentRoom.EnemiesInRoom; + var hpToAbsorb = 0.0; + foreach (var enemy in currentEnemies) + hpToAbsorb += enemy.CurrentHP * 0.05; + _player.Stats.SetCurrentHP(_player.Stats.CurrentHP.Value + (int)hpToAbsorb); + GD.Print("HP to absorb: " + hpToAbsorb); + } + + public void DealElementalDamageToAllEnemiesInRoom(ElementType elementType) + { + var currentRoom = _player.GetCurrentRoom(); + var currentEnemies = currentRoom.EnemiesInRoom; + foreach (var enemy in currentEnemies) + enemy.TakeDamage(20, elementType); + } + + public void SwapHPandVT() + { + var oldHp = _player.Stats.CurrentHP.Value; + var oldVt = _player.Stats.CurrentVT.Value; + + _player.Stats.SetCurrentHP(oldVt); + _player.Stats.SetCurrentVT(oldHp); + } + + public void RandomEffect(EffectItem item) + { + var itemEffects = Enum.GetValues().ToList(); + itemEffects.Remove(UsableItemTag.RandomEffect); + itemEffects.Remove(UsableItemTag.None); + var randomEffect = new Godot.Collections.Array(itemEffects).PickRandom(); + item.SetEffectTag(randomEffect); + _game.UseItem(item); + } + + public void RaiseCurrentWeaponAttack() + { + if (_player.EquippedWeapon.Value.ItemName == string.Empty) + return; + + var currentWeapon = _player.EquippedWeapon.Value; + currentWeapon.IncreaseWeaponAttack(1); + } + + public void RaiseCurrentArmorDefense() + { + if (_player.EquippedArmor.Value.ItemName == string.Empty) + return; + + var currentArmor = _player.EquippedArmor.Value; + currentArmor.IncreaseArmorDefense(1); + } + + public void RaiseLevel() + { + _player.LevelUp(); + } + + public void TeleportToRandomRoom(IEnemy enemy) + { + var currentFloor = _game.CurrentFloor; + var rooms = currentFloor.Rooms; + var currentRoom = enemy.GetCurrentRoom(); + var validRooms = rooms.OfType().ToList(); + if (currentRoom is MonsterRoom currentMonsterRoom) + validRooms.Remove(currentMonsterRoom); + + if (validRooms.Count == 0) + return; + + var roomsGodotCollection = new Godot.Collections.Array(validRooms); + var randomRoom = roomsGodotCollection.PickRandom(); + var spawnPoints = randomRoom.EnemySpawnPoints.GetChildren().OfType().ToList(); + var spawnPointsGodotCollection = new Godot.Collections.Array(spawnPoints); + var randomSpawnPoint = spawnPointsGodotCollection.PickRandom(); + + enemy.SetEnemyGlobalPosition(randomSpawnPoint.GlobalPosition); + } + + public void TeleportToRandomRoom(IPlayer player) + { + var currentFloor = _game.CurrentFloor; + var rooms = currentFloor.Rooms; + + var currentRoom = rooms.SingleOrDefault(x => x.IsPlayerInRoom); + + var validRooms = rooms.OfType().ToList(); + if (currentRoom is MonsterRoom currentMonsterRoom) + validRooms.Remove(currentMonsterRoom); + + if (validRooms.Count == 0) + return; + + var roomsGodotCollection = new Godot.Collections.Array(validRooms); + var randomRoom = roomsGodotCollection.PickRandom(); + var spawnPoint = randomRoom.PlayerSpawn; + _game.ToggleInventory(); + player.TeleportPlayer(spawnPoint.GlobalPosition); + } + + public void ChangeAffinity(ThrowableItem throwableItem) + { + var maximumElements = Enum.GetNames(typeof(ElementType)).Length; + throwableItem.SetElementType(throwableItem.ElementType + 1 % maximumElements); + + // TODO: Make this an inventory animation to cycle through elements. + throwableItem.SetDescription( + $"Inflicts {throwableItem.ElementType} damage when thrown." + + $"{System.Environment.NewLine}Use item to change Affinity."); + } + + public void WarpToExit(IPlayer player) + { + var exitRoom = _game.CurrentFloor.Rooms.OfType().Single(); + if (exitRoom.PlayerDiscoveredRoom) + player.TeleportPlayer(exitRoom.PlayerSpawn.GlobalPosition); + } + + public void WarpToExit(IEnemy enemy) + { + var exitRoom = _game.CurrentFloor.Rooms.OfType().Single(); + enemy.SetEnemyGlobalPosition(exitRoom.PlayerSpawn.GlobalPosition); + } + } +} diff --git a/src/items/EffectService.cs.uid b/src/items/EffectService.cs.uid new file mode 100644 index 00000000..83f4c1de --- /dev/null +++ b/src/items/EffectService.cs.uid @@ -0,0 +1 @@ +uid://cnvyubmj6u7qw diff --git a/src/items/EquipableItem.cs b/src/items/EquipableItem.cs new file mode 100644 index 00000000..5508a663 --- /dev/null +++ b/src/items/EquipableItem.cs @@ -0,0 +1,13 @@ +using Chickensoft.Introspection; +using Chickensoft.Serialization; + +namespace GameJamDungeon; + +[Meta] +public abstract partial class EquipableItem : InventoryItem +{ + public abstract ItemTag ItemTag { get; } + + [Save("equipable_item_is_equipped")] + public bool IsEquipped { get; set; } +} diff --git a/src/items/EquipableItem.cs.uid b/src/items/EquipableItem.cs.uid new file mode 100644 index 00000000..1fea577f --- /dev/null +++ b/src/items/EquipableItem.cs.uid @@ -0,0 +1 @@ +uid://cw8s4mjrde4no diff --git a/src/items/IEquipableItem.cs b/src/items/IEquipableItem.cs deleted file mode 100644 index 53391c36..00000000 --- a/src/items/IEquipableItem.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Immutable; - -namespace GameJamDungeon; - -public interface IEquipableItem : IInventoryItem -{ - public ImmutableList ItemTags { get; } - - public bool IsEquipped { get; } -} diff --git a/src/items/Inventory.cs b/src/items/Inventory.cs index 53c0df3f..4e5c1c7a 100644 --- a/src/items/Inventory.cs +++ b/src/items/Inventory.cs @@ -1,5 +1,7 @@ using Chickensoft.AutoInject; using Chickensoft.GodotNodeInterfaces; +using Chickensoft.Introspection; +using Chickensoft.Serialization; using Godot; using System.Collections.Generic; using System.Linq; @@ -8,11 +10,11 @@ namespace GameJamDungeon; public interface IInventory : INode { - public List Items { get; } + public List Items { get; } - public bool TryAdd(IInventoryItem inventoryItem); + public bool TryAdd(InventoryItem inventoryItem); - public void Remove(IInventoryItem inventoryItem); + public void Remove(InventoryItem inventoryItem); public void Sort(); @@ -21,6 +23,7 @@ public interface IInventory : INode event Inventory.PickedUpItemEventHandler PickedUpItem; } +[Meta, Id("inventory")] public partial class Inventory : Node, IInventory { public override void _Notification(int what) => this.Notify(what); @@ -38,9 +41,10 @@ public partial class Inventory : Node, IInventory Items = []; } - public List Items { get; private set; } + [Save("inventory_items")] + public List Items { get; private set; } - public bool TryAdd(IInventoryItem inventoryItem) + public bool TryAdd(InventoryItem inventoryItem) { if (Items.Count >= _maxInventorySize) { @@ -53,7 +57,7 @@ public partial class Inventory : Node, IInventory return true; } - public void Remove(IInventoryItem inventoryItem) => Items.Remove(inventoryItem); + public void Remove(InventoryItem inventoryItem) => Items.Remove(inventoryItem); public void Sort() @@ -61,7 +65,7 @@ public partial class Inventory : Node, IInventory var equippedWeapon = Items.OfType().Where(x => x.IsEquipped); var equippedArmor = Items.OfType().Where(x => x.IsEquipped); var equippedAccessory = Items.OfType().Where(x => x.IsEquipped); - var equippedItems = new List(); + var equippedItems = new List(); equippedItems.AddRange(equippedWeapon); equippedItems.AddRange(equippedArmor); equippedItems.AddRange(equippedAccessory); diff --git a/src/items/InventoryItem.cs b/src/items/InventoryItem.cs index f6d74338..3e83206b 100644 --- a/src/items/InventoryItem.cs +++ b/src/items/InventoryItem.cs @@ -1,4 +1,6 @@ using Chickensoft.GodotNodeInterfaces; +using Chickensoft.Introspection; +using Chickensoft.Serialization; using Godot; using System; @@ -17,13 +19,22 @@ public interface IInventoryItem : INode3D double ThrowDamage { get; } float ThrowSpeed { get; } - - Texture2D GetTexture(); - - public void SetItemStats(InventoryItemStats inventoryItemStats); } -public interface IUsableItem : IInventoryItem +[Meta] +public abstract partial class InventoryItem : Node3D, IInventoryItem { - public void Use(); + [Save("inventory_item_id")] + public Guid ID => Guid.NewGuid(); + public abstract string ItemName { get; } + public abstract string Description { get; } + [Save("inventory_item_spawn_rate")] + public abstract float SpawnRate { get; } + [Save("inventory_item_throw_damage")] + public abstract double ThrowDamage { get; } + [Save("inventory_item_throw_speed")] + public abstract float ThrowSpeed { get; } + + [Save("inventory_item_stats")] + public abstract InventoryItemStats ItemStats { get; set; } } diff --git a/src/items/InventoryItemStats.cs b/src/items/InventoryItemStats.cs index 6517ab15..f65c0f89 100644 --- a/src/items/InventoryItemStats.cs +++ b/src/items/InventoryItemStats.cs @@ -1,16 +1,22 @@ +using Chickensoft.Introspection; +using Chickensoft.Serialization; using Godot; namespace GameJamDungeon; + +[Meta, Id("inventory_item_stats")] public partial class InventoryItemStats : Resource { [Export] - public string Name = string.Empty; + [Save("inventory_item_name")] + public string Name { get; set; } = string.Empty; [Export(PropertyHint.MultilineText)] - public string Description = string.Empty; + [Save("inventory_item_description")] + public string Description { get; set; } = string.Empty; - [Export] - public Texture2D Texture { get; set; } + [Save("inventory_item_texture")] + [Export] public Texture2D Texture { get; set; } = default!; [Export(PropertyHint.Range, "0, 1, 0.01")] public float SpawnRate { get; set; } = 0.5f; @@ -28,5 +34,5 @@ public partial class InventoryItemStats : Resource public int ThrowDamage { get; set; } = 5; [Export] - public Godot.Collections.Array ItemTags { get; set; } = new Godot.Collections.Array(); + public ItemTag ItemTag { get; set; } = ItemTag.None; } \ No newline at end of file diff --git a/src/items/InventoryItemTextureExtensions.cs b/src/items/InventoryItemTextureExtensions.cs new file mode 100644 index 00000000..08e21d77 --- /dev/null +++ b/src/items/InventoryItemTextureExtensions.cs @@ -0,0 +1,67 @@ +using Godot; +using System.Text.Json.Serialization; + +using System.Text.Json; +using System; + +/// Basis JSON converter. +public class Texture2DConverter : JsonConverter +{ + /// + public override bool CanConvert(Type typeToConvert) => + typeToConvert == typeof(Texture2D); + + /// + public override Texture2D Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) + { + var texture2D = new Texture2D(); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + return texture2D; + } + + if (reader.TokenType != JsonTokenType.PropertyName) + { + continue; + } + + var propertyName = reader.GetString(); + reader.Read(); + + switch (propertyName) + { + case "resource_path": + var resourcePath = JsonSerializer.Deserialize(ref reader, options); + texture2D = GD.Load(resourcePath); + break; + default: + break; + } + } + + throw new JsonException("Unexpected end when reading Texture2D."); + + } + + /// + public override void Write( + Utf8JsonWriter writer, + Texture2D value, + JsonSerializerOptions options + ) + { + var resolver = options.TypeInfoResolver; + var resourcePathType = resolver!.GetTypeInfo(typeof(string), options)!; + + writer.WriteStartObject(); + writer.WritePropertyName("resource_path"); + JsonSerializer.Serialize(writer, value.ResourcePath, resourcePathType); + writer.WriteEndObject(); + } +} \ No newline at end of file diff --git a/src/items/InventoryItemTextureExtensions.cs.uid b/src/items/InventoryItemTextureExtensions.cs.uid new file mode 100644 index 00000000..fb59dcb1 --- /dev/null +++ b/src/items/InventoryItemTextureExtensions.cs.uid @@ -0,0 +1 @@ +uid://bdc3xwj2b1oog diff --git a/src/items/ItemDatabase.cs b/src/items/ItemDatabase.cs index c1cab973..3f51c4c2 100644 --- a/src/items/ItemDatabase.cs +++ b/src/items/ItemDatabase.cs @@ -33,7 +33,7 @@ public partial class ItemDatabase : Node { var armorInfo = GD.Load($"res://src/items/armor/resources/{armor}"); var armorScene = ArmorScene.Instantiate(); - armorScene.SetItemStats(armorInfo); + armorScene.ItemStats = armorInfo; database.Add(armorScene); } @@ -41,7 +41,7 @@ public partial class ItemDatabase : Node { var weaponInfo = GD.Load($"res://src/items/weapons/resources/{weapon}"); var weaponScene = WeaponScene.Instantiate(); - weaponScene.SetItemStats(weaponInfo); + weaponScene.ItemStats = weaponInfo; database.Add(weaponScene); } @@ -49,7 +49,7 @@ public partial class ItemDatabase : Node { var accessoryInfo = GD.Load($"res://src/items/accessory/resources/{accessory}"); var accessoryScene = AccessoryScene.Instantiate(); - accessoryScene.SetItemStats(accessoryInfo); + accessoryScene.ItemStats = accessoryInfo; database.Add(accessoryScene); } @@ -57,7 +57,7 @@ public partial class ItemDatabase : Node { var throwableItemInfo = GD.Load($"res://src/items/throwable/resources/{throwable}"); var throwableItemScene = ThrowableItemScene.Instantiate(); - throwableItemScene.SetItemStats(throwableItemInfo); + throwableItemScene.ItemStats = throwableItemInfo; database.Add(throwableItemScene); } @@ -65,10 +65,10 @@ public partial class ItemDatabase : Node { var consumableItemInfo = GD.Load($"res://src/items/consumable/resources/{consumable}"); var consumableItemScene = ConsumableItemScene.Instantiate(); - consumableItemScene.SetItemStats(consumableItemInfo); + consumableItemScene.ItemStats = consumableItemInfo; database.Add(consumableItemScene); } - return database.ToArray(); + return [.. database]; } } diff --git a/src/items/accessory/Accessory.cs b/src/items/accessory/Accessory.cs index 3a6b0b11..a90a9213 100644 --- a/src/items/accessory/Accessory.cs +++ b/src/items/accessory/Accessory.cs @@ -1,39 +1,24 @@ using Chickensoft.AutoInject; using Chickensoft.Introspection; +using Chickensoft.Serialization; using Godot; -using System; -using System.Collections.Immutable; namespace GameJamDungeon; -[Meta(typeof(IAutoNode))] -public partial class Accessory : Node3D, IEquipableItem +[Meta, Id("accessory")] +public partial class Accessory : EquipableItem { - public override void _Notification(int what) => this.Notify(what); - - [Dependency] public IGameEventDepot GameEventDepot => this.DependOn(); - - [Dependency] public IPlayer Player => this.DependOn(); - [Export] private AccessoryStats _accessoryStats { get; set; } = new AccessoryStats(); - [Node] private Sprite3D Sprite { get; set; } = new Sprite3D(); + public override string ItemName => _accessoryStats.Name; - [Node] public Area3D Pickup { get; set; } = default!; + public override string Description => _accessoryStats.Description; - public Guid ID => Guid.NewGuid(); + public override float SpawnRate => _accessoryStats.SpawnRate; - public string ItemName => _accessoryStats.Name; + public override double ThrowDamage => _accessoryStats.ThrowDamage; - public string Description => _accessoryStats.Description; - - public float SpawnRate => _accessoryStats.SpawnRate; - - public Texture2D GetTexture() => _accessoryStats.Texture; - - public double ThrowDamage => _accessoryStats.ThrowDamage; - - public float ThrowSpeed => _accessoryStats.ThrowSpeed; + public override float ThrowSpeed => _accessoryStats.ThrowSpeed; public int MaxHPUp => _accessoryStats.MaxHPUp; @@ -45,32 +30,9 @@ public partial class Accessory : Node3D, IEquipableItem public int DEFUp => _accessoryStats.DEFUp; - public ImmutableList AccessoryTags => [.. _accessoryStats.AccessoryTags]; + public AccessoryTag AccessoryTag => _accessoryStats.AccessoryTag; - public ImmutableList ItemTags => [.. _accessoryStats.ItemTags]; + public override ItemTag ItemTag => _accessoryStats.ItemTag; - public bool IsEquipped { get; set; } - - public void OnReady() - { - Pickup.BodyEntered += OnEntered; - Sprite.Texture = _accessoryStats.Texture; - } - - public void SetItemStats(InventoryItemStats inventoryItemStats) - { - _accessoryStats = (AccessoryStats)inventoryItemStats; - } - - public void Throw() - { - Player.Inventory.Remove(this); - } - - public void OnEntered(Node3D body) - { - var isAdded = Player.Inventory.TryAdd(this); - if (isAdded) - QueueFree(); - } + public override InventoryItemStats ItemStats { get => _accessoryStats; set => _accessoryStats = (AccessoryStats)value; } } diff --git a/src/items/accessory/Accessory.tscn b/src/items/accessory/Accessory.tscn index 26747584..d06503e4 100644 --- a/src/items/accessory/Accessory.tscn +++ b/src/items/accessory/Accessory.tscn @@ -6,13 +6,12 @@ radius = 0.470016 [node name="Accessory" type="Node3D"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.75, 0) script = ExtResource("1_ikyk2") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true -collision_layer = 0 -collision_mask = 4 +collision_layer = 4 +collision_mask = 0 [node name="Sprite" type="Sprite3D" parent="Pickup"] unique_name_in_owner = true diff --git a/src/items/accessory/AccessoryStats.cs b/src/items/accessory/AccessoryStats.cs index 7f91bfad..7b08a68f 100644 --- a/src/items/accessory/AccessoryStats.cs +++ b/src/items/accessory/AccessoryStats.cs @@ -1,31 +1,44 @@ -using Godot; +using Chickensoft.Introspection; +using Chickensoft.Serialization; +using Godot; +using System.Text.Json.Serialization; namespace GameJamDungeon; [GlobalClass] +[Meta, Id("accessory_stat_type")] public partial class AccessoryStats : InventoryItemStats { [Export] + [Save("accessory_atk_up")] public int ATKUp { get; set; } = 0; [Export] + [Save("accessory_def_up")] public int DEFUp { get; set; } = 0; [Export] + [Save("accessory_luck_up")] public double LuckUp { get; set; } = 0; [Export] + [Save("accessory_max_hp_up")] public int MaxHPUp { get; set; } = 0; [Export] + [Save("accessory_max_vt_up")] public int MaxVTUp { get; set; } = 0; [Export] - public Godot.Collections.Array AccessoryTags { get; set; } = new Godot.Collections.Array(); + [Save("accessory_tag")] + public AccessoryTag AccessoryTag { get; set; } = AccessoryTag.None; } - public enum AccessoryTag { + None, HalfVTConsumption, StatusEffectImmunity } + +[JsonSerializable(typeof(AccessoryTag))] +public partial class AccessoryTagEnumContext : JsonSerializerContext; diff --git a/src/items/accessory/resources/MaskShunned.tres b/src/items/accessory/resources/MaskShunned.tres index 84e5008a..a0833655 100644 --- a/src/items/accessory/resources/MaskShunned.tres +++ b/src/items/accessory/resources/MaskShunned.tres @@ -1,17 +1,22 @@ [gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://c3v6r8s8yruag"] -[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_co7sc"] +[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_co7sc"] [ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_uwbei"] [resource] script = ExtResource("1_co7sc") ATKUp = 0 DEFUp = 0 -LUCKUp = 0.0 +LuckUp = 0.0 MaxHPUp = 0 MaxVTUp = 0 -AccessoryTags = [1] +AccessoryTag = 2 Name = "Mask of the Shunned Goddess" Description = "Status Effect Immunity" Texture = ExtResource("1_uwbei") SpawnRate = 0.1 +ThrowSpeed = 12.0 +HealHPAmount = 0 +HealVTAmount = 0 +ThrowDamage = 5 +ItemTags = Array[int]([]) diff --git a/src/items/accessory/resources/MaskSloth.tres b/src/items/accessory/resources/MaskSloth.tres index 54a25142..f2666bce 100644 --- a/src/items/accessory/resources/MaskSloth.tres +++ b/src/items/accessory/resources/MaskSloth.tres @@ -1,17 +1,22 @@ [gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://ct8iply3dwssv"] [ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_t16cd"] -[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_vdb56"] +[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_vdb56"] [resource] script = ExtResource("1_vdb56") ATKUp = 0 DEFUp = 0 -LUCKUp = 0.0 +LuckUp = 0.0 MaxHPUp = 0 MaxVTUp = 0 -AccessoryTags = [0] +AccessoryTag = 1 Name = "Mask of the Goddess of Sloth" Description = "Halves VT Depletion Rate" Texture = ExtResource("1_t16cd") SpawnRate = 0.1 +ThrowSpeed = 12.0 +HealHPAmount = 0 +HealVTAmount = 0 +ThrowDamage = 5 +ItemTags = Array[int]([]) diff --git a/src/items/armor/Armor.cs b/src/items/armor/Armor.cs index afb99ad8..e65cc519 100644 --- a/src/items/armor/Armor.cs +++ b/src/items/armor/Armor.cs @@ -1,72 +1,28 @@ -using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; -using System; -using System.Collections.Immutable; namespace GameJamDungeon; -[Meta(typeof(IAutoNode))] -public partial class Armor : Node3D, IEquipableItem +[Meta, Id("armor")] +public partial class Armor : EquipableItem { - public override void _Notification(int what) => this.Notify(what); + public override InventoryItemStats ItemStats { get => _armorStats; set => _armorStats = (ArmorStats)value; } - [Dependency] public IPlayer Player => this.DependOn(); + private ArmorStats _armorStats { get; set; } = new ArmorStats(); - [Export] private ArmorStats _armorStats { get; set; } = new ArmorStats(); + public override string ItemName => _armorStats.Name; - [Node] private Sprite3D Sprite { get; set; } = new Sprite3D(); + public override string Description => _armorStats.Description; - [Node] private Area3D Pickup { get; set; } = default!; + public override float SpawnRate => _armorStats.SpawnRate; - public Guid ID => Guid.NewGuid(); + public override double ThrowDamage => _armorStats.ThrowDamage; - public string ItemName => _armorStats.Name; - - public string Description => _armorStats.Description; - - public float SpawnRate => _armorStats.SpawnRate; - - public Texture2D GetTexture() => _armorStats.Texture; - - public double ThrowDamage => _armorStats.ThrowDamage; - - public float ThrowSpeed => _armorStats.ThrowSpeed; + public override float ThrowSpeed => _armorStats.ThrowSpeed; public int Defense => _armorStats.Defense; public void IncreaseArmorDefense(int bonus) => _armorStats.Defense += bonus; - - public ImmutableList ItemTags => [.. _armorStats.ItemTags]; - - public bool IsEquipped { get; set; } - - public void OnReady() - { - Pickup.BodyEntered += OnEntered; - Sprite.Texture = _armorStats.Texture; - } - - public void SetItemStats(InventoryItemStats inventoryItemStats) - { - _armorStats = (ArmorStats)inventoryItemStats; - } - - public void Throw() - { - Player.Inventory.Remove(this); - } - - public void Drop() - { - Player.Inventory.Remove(this); - } - - public void OnEntered(Node3D body) - { - var isAdded = Player.Inventory.TryAdd(this); - if (isAdded) - QueueFree(); - } + public override ItemTag ItemTag => _armorStats.ItemTag; } diff --git a/src/items/armor/Armor.tscn b/src/items/armor/Armor.tscn index a7013d41..59e86305 100644 --- a/src/items/armor/Armor.tscn +++ b/src/items/armor/Armor.tscn @@ -6,13 +6,12 @@ size = Vector3(0.778381, 0.929947, 0.731567) [node name="Armor" type="Node3D"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.75, 0) script = ExtResource("1_cmjpq") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true -collision_layer = 0 -collision_mask = 4 +collision_layer = 4 +collision_mask = 0 [node name="Sprite" type="Sprite3D" parent="Pickup"] unique_name_in_owner = true diff --git a/src/items/armor/ArmorStats.cs b/src/items/armor/ArmorStats.cs index d3751158..00fc95ae 100644 --- a/src/items/armor/ArmorStats.cs +++ b/src/items/armor/ArmorStats.cs @@ -1,25 +1,34 @@ -using Godot; +using Chickensoft.Introspection; +using Chickensoft.Serialization; +using Godot; namespace GameJamDungeon; [GlobalClass] +[Meta, Id("armor_stats")] public partial class ArmorStats : InventoryItemStats { [Export] + [Save("armor_defense")] public int Defense { get; set; } = 0; [Export] + [Save("armor_telluric_resistance")] public double TelluricResistance { get; set; } = 0; [Export] + [Save("armor_aeolic_resistance")] public double AeolicResistance { get; set; } = 0; [Export] + [Save("armor_hydric_resistance")] public double HydricResistance { get; set; } = 0; [Export] + [Save("armor_igneous_resistance")] public double IgneousResistance { get; set; } = 0; [Export] + [Save("armor_ferrum_resistance")] public double FerrumResistance { get; set; } = 0; } diff --git a/src/items/armor/resources/AtonersAdornments.tres b/src/items/armor/resources/AtonersAdornments.tres index b7cbaaca..6a7f0674 100644 --- a/src/items/armor/resources/AtonersAdornments.tres +++ b/src/items/armor/resources/AtonersAdornments.tres @@ -1,6 +1,6 @@ [gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://ce2vfa2t3io67"] -[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_6r2bl"] +[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_6r2bl"] [ext_resource type="Texture2D" uid="uid://ckcn67d64mgke" path="res://src/items/armor/textures/atoners adornment.PNG" id="1_588l8"] [resource] @@ -15,3 +15,8 @@ Name = "Atoner's Adornments" Description = "+1 DEF" Texture = ExtResource("1_588l8") SpawnRate = 0.25 +ThrowSpeed = 12.0 +HealHPAmount = 0 +HealVTAmount = 0 +ThrowDamage = 5 +ItemTag = 0 diff --git a/src/items/consumable/ConsumableItem.cs b/src/items/consumable/ConsumableItem.cs index c9b87f14..83244e30 100644 --- a/src/items/consumable/ConsumableItem.cs +++ b/src/items/consumable/ConsumableItem.cs @@ -1,68 +1,31 @@ -using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; -using System; namespace GameJamDungeon; -[Meta(typeof(IAutoNode))] -public partial class ConsumableItem : Node3D, IUsableItem +[Meta, Id("consumable_item")] +public partial class ConsumableItem : InventoryItem { - public override void _Notification(int what) => this.Notify(what); - - [Dependency] public IGame Game => this.DependOn(); - - [Dependency] public IPlayer Player => this.DependOn(); - [Export] - private ConsumableItemStats _consumableItemStats { get; set; } + private ConsumableItemStats _consumableItemStats { get; set; } = new ConsumableItemStats(); - [Node] private Sprite3D Sprite { get; set; } = new Sprite3D(); + public override string ItemName => _consumableItemStats.Name; - [Node] private Area3D Pickup { get; set; } = default!; + public override string Description => _consumableItemStats.Description; - public Guid ID => Guid.NewGuid(); + public override float SpawnRate => _consumableItemStats.SpawnRate; - public string ItemName => _consumableItemStats.Name; + public override double ThrowDamage => _consumableItemStats.ThrowDamage; - public string Description => _consumableItemStats.Description; + public override float ThrowSpeed => _consumableItemStats.ThrowSpeed; - public float SpawnRate => _consumableItemStats.SpawnRate; + public int HealHPAmount => _consumableItemStats.HealHPAmount; - public Texture2D GetTexture() => _consumableItemStats.Texture; + public int HealVTAmount => _consumableItemStats.HealVTAmount; - public double ThrowDamage => _consumableItemStats.ThrowDamage; + public int RaiseHPAmount => _consumableItemStats.RaiseHPAmount; - public float ThrowSpeed => _consumableItemStats.ThrowSpeed; + public int RaiseVTAmount => _consumableItemStats.RaiseVTAmount; - public void Use() - { - if (Player.Stats.CurrentHP == Player.Stats.MaximumHP && _consumableItemStats.RaiseHPAmount > 0) - Player.RaiseHP(_consumableItemStats.RaiseHPAmount); - if (Player.Stats.CurrentVT == Player.Stats.MaximumVT && _consumableItemStats.RaiseVTAmount > 0) - Player.RaiseVT(_consumableItemStats.RaiseVTAmount); - - if (_consumableItemStats.HealHPAmount > 0 && Player.Stats.CurrentHP != Player.Stats.MaximumHP) - Player.HealHP(_consumableItemStats.HealHPAmount); - if (_consumableItemStats.HealVTAmount > 0 && Player.Stats.CurrentVT != Player.Stats.MaximumVT) - Player.HealVT(_consumableItemStats.HealVTAmount); - } - - public void SetItemStats(InventoryItemStats inventoryItemStats) - { - _consumableItemStats = (ConsumableItemStats)inventoryItemStats; - } - - public void OnReady() - { - Pickup.BodyEntered += OnEntered; - Sprite.Texture = _consumableItemStats.Texture; - } - - public void OnEntered(Node3D body) - { - var isAdded = Player.Inventory.TryAdd(this); - if (isAdded) - QueueFree(); - } + public override InventoryItemStats ItemStats { get => _consumableItemStats; set => _consumableItemStats = (ConsumableItemStats)value; } } diff --git a/src/items/consumable/ConsumableItem.tscn b/src/items/consumable/ConsumableItem.tscn index 3073d825..6304e4b6 100644 --- a/src/items/consumable/ConsumableItem.tscn +++ b/src/items/consumable/ConsumableItem.tscn @@ -10,8 +10,8 @@ script = ExtResource("1_26bad") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true -collision_layer = 0 -collision_mask = 4 +collision_layer = 4 +collision_mask = 0 [node name="Sprite" type="Sprite3D" parent="Pickup"] unique_name_in_owner = true diff --git a/src/items/consumable/ConsumableItemStats.cs b/src/items/consumable/ConsumableItemStats.cs index dd89243a..3a9240a2 100644 --- a/src/items/consumable/ConsumableItemStats.cs +++ b/src/items/consumable/ConsumableItemStats.cs @@ -1,13 +1,18 @@ -using Godot; +using Chickensoft.Introspection; +using Chickensoft.Serialization; +using Godot; namespace GameJamDungeon; [GlobalClass] +[Meta, Id("consumable_item_stats")] public partial class ConsumableItemStats : InventoryItemStats { [Export] + [Save("consumable_item_raise_hp")] public int RaiseHPAmount { get; set; } = 0; [Export] + [Save("consumable_item_raise_vt")] public int RaiseVTAmount { get; set; } = 0; } diff --git a/src/items/dropped/DroppedItem.cs b/src/items/dropped/DroppedItem.cs index 1c83219c..718dabc7 100644 --- a/src/items/dropped/DroppedItem.cs +++ b/src/items/dropped/DroppedItem.cs @@ -21,13 +21,13 @@ public partial class DroppedItem : RigidBody3D, IDroppedItem [Node] private Sprite2D Sprite { get; set; } = default!; - public IInventoryItem Item { get; set; } + public InventoryItem Item { get; set; } public void OnResolved() { ContactMonitor = true; BodyEntered += DroppedItem_BodyEntered; - Sprite.Texture = Item.GetTexture(); + Sprite.Texture = Item.ItemStats.Texture; } public async void Drop() diff --git a/src/items/effect/EffectItem.cs b/src/items/effect/EffectItem.cs index 44064e61..c13bfae5 100644 --- a/src/items/effect/EffectItem.cs +++ b/src/items/effect/EffectItem.cs @@ -1,221 +1,27 @@ -using Chickensoft.AutoInject; -using Chickensoft.Introspection; +using Chickensoft.Introspection; using Godot; -using System; -using System.Linq; namespace GameJamDungeon; -[Meta(typeof(IAutoNode))] -public partial class EffectItem : Node3D, IUsableItem +[Meta, Id("effect_item")] +public partial class EffectItem : InventoryItem { - public override void _Notification(int what) => this.Notify(what); - - [Dependency] public IGame Game => this.DependOn(); - - [Dependency] public IPlayer Player => this.DependOn(); - [Export] - private EffectItemStats _effectItemStats { get; set; } + private EffectItemStats _effectItemStats { get; set; } = new EffectItemStats(); - [Node] private Sprite3D Sprite { get; set; } = new Sprite3D(); + public override string ItemName => _effectItemStats.Name; - [Node] private Area3D Pickup { get; set; } = default!; + public override string Description => _effectItemStats.Description; - public Guid ID => Guid.NewGuid(); + public override float SpawnRate => _effectItemStats.SpawnRate; - public string ItemName => _effectItemStats.Name; + public override double ThrowDamage => _effectItemStats.ThrowDamage; - public string Description => _effectItemStats.Description; + public override float ThrowSpeed => _effectItemStats.ThrowSpeed; - public float SpawnRate => _effectItemStats.SpawnRate; + public UsableItemTag UsableItemTag => _effectItemStats.UsableItemTag; - public Texture2D GetTexture() => _effectItemStats.Texture; + public void SetEffectTag(UsableItemTag effect) => _effectItemStats.UsableItemTag = effect; - public double ThrowDamage => _effectItemStats.ThrowDamage; - - public float ThrowSpeed => _effectItemStats.ThrowSpeed; - - public void Use() - { - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.DoubleEXP)) - Game.DoubleEXP(TimeSpan.FromSeconds(30)); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.TeleportAllEnemiesToRoom)) - TeleportEnemiesToCurrentRoom(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.KillHalfEnemiesInRoom)) - KillHalfEnemiesInRoom(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.TurnAllEnemiesIntoHealingItem)) - TurnAllEnemiesInRoomIntoHealingItem(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.HealsAllInRoomToMaxHP)) - HealAllEnemiesAndPlayerInRoomToFull(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.AbsorbHPFromAllEnemiesInRoom)) - AbsorbHPFromAllEnemiesInRoom(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.DealElementalDamageToAllEnemiesInRoom)) - DealElementalDamageToAllEnemiesInRoom(ElementType.Hydric); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.SwapHPAndVT)) - SwapHPandVT(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.RaiseCurrentWeaponAttack)) - RaiseCurrentWeaponAttack(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.RaiseCurrentDefenseArmor)) - RaiseCurrentArmorDefense(); - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.RaiseLevel)) - RaiseLevel(); - - if (_effectItemStats.UsableItemTags.Contains(UsableItemTag.RandomEffect)) - RandomEffect(); - - } - - public void SetItemStats(InventoryItemStats inventoryItemStats) - { - _effectItemStats = (EffectItemStats)inventoryItemStats; - } - - public void OnReady() - { - Pickup.BodyEntered += OnEntered; - Sprite.Texture = _effectItemStats.Texture; - } - - public void OnEntered(Node3D body) - { - var isAdded = Player.Inventory.TryAdd(this); - if (isAdded) - QueueFree(); - } - - private void TeleportEnemiesToCurrentRoom() - { - var currentFloor = Game.CurrentFloor; - var rooms = currentFloor.Rooms; - var currentRoom = Player.GetCurrentRoom(); - - if (currentRoom is not MonsterRoom) - return; - - var validRooms = rooms.OfType().ToList(); - if (currentRoom is MonsterRoom monsterRoom) - validRooms.Remove(monsterRoom); - - var currentMonsterRoom = (MonsterRoom)currentRoom; - - var enemyList = validRooms.SelectMany(x => x.GetEnemiesInCurrentRoom()); - - foreach (var enemy in enemyList) - { - var spawnPoints = currentMonsterRoom.EnemySpawnPoints.GetChildren().OfType().ToList(); - var spawnPointsGodotCollection = new Godot.Collections.Array(spawnPoints); - var randomSpawnPoint = spawnPointsGodotCollection.PickRandom(); - enemy.SetEnemyGlobalPosition(randomSpawnPoint.GlobalPosition); - } - } - - private void KillHalfEnemiesInRoom() - { - var currentRoom = Player.GetCurrentRoom(); - if (currentRoom is not MonsterRoom) - return; - - var currentMonsterRoom = (MonsterRoom)currentRoom; - var enemyList = currentMonsterRoom.GetEnemiesInCurrentRoom().ToList(); - var enemiesToKill = enemyList.Count / 2; - for (var i = 0; i < enemiesToKill; i++) - enemyList[i].Die(); - } - - private void TurnAllEnemiesInRoomIntoHealingItem() - { - var currentRoom = Player.GetCurrentRoom(); - var currentEnemies = currentRoom.EnemiesInRoom; - foreach (var enemy in currentEnemies) - { - enemy.Die(); - DropHealingItem(enemy.GetEnemyGlobalPosition()); - } - } - - private void DropHealingItem(Vector3 vector) - { - var consumableFolder = "res://src/items/consumable"; - var restorativeScene = GD.Load($"{consumableFolder}/ConsumableItem.tscn"); - var consumable = restorativeScene.Instantiate(); - var resourceFiles = DirAccess.GetFilesAt($"{consumableFolder}/resources"); - var rng = new RandomNumberGenerator(); - rng.Randomize(); - var randomResource = resourceFiles[rng.RandiRange(0, resourceFiles.Length - 1)]; - var randomFile = ResourceLoader.Load($"{consumableFolder}/resources/{randomResource}"); - consumable.SetItemStats(randomFile); - Game.AddChild(consumable); - consumable.GlobalPosition = vector; - } - - private void HealAllEnemiesAndPlayerInRoomToFull() - { - var currentRoom = Player.GetCurrentRoom(); - var currentEnemies = currentRoom.EnemiesInRoom; - foreach (var enemy in currentEnemies) - enemy.SetCurrentHP(enemy.GetMaximumHP()); - Player.Stats.SetCurrentHP(Player.Stats.MaximumHP.Value); - } - - private void AbsorbHPFromAllEnemiesInRoom() - { - var currentRoom = Player.GetCurrentRoom(); - var currentEnemies = currentRoom.EnemiesInRoom; - var hpToAbsorb = 0.0; - foreach (var enemy in currentEnemies) - hpToAbsorb += enemy.CurrentHP * 0.05; - Player.Stats.SetCurrentHP(Player.Stats.CurrentHP.Value + (int)hpToAbsorb); - GD.Print("HP to absorb: " + hpToAbsorb); - } - - private void DealElementalDamageToAllEnemiesInRoom(ElementType elementType) - { - var currentRoom = Player.GetCurrentRoom(); - var currentEnemies = currentRoom.EnemiesInRoom; - foreach (var enemy in currentEnemies) - enemy.TakeDamage(20, elementType); - } - - private void SwapHPandVT() - { - var oldHp = Player.Stats.CurrentHP.Value; - var oldVt = Player.Stats.CurrentVT.Value; - - Player.Stats.SetCurrentHP(oldVt); - Player.Stats.SetCurrentVT(oldHp); - } - - private void RandomEffect() - { - var itemEffects = Enum.GetValues().ToList(); - itemEffects.Remove(UsableItemTag.RandomEffect); - var randomEffect = new Godot.Collections.Array(itemEffects).PickRandom(); - _effectItemStats.UsableItemTags.Clear(); - _effectItemStats.UsableItemTags.Add(randomEffect); - Use(); - } - - private void RaiseCurrentWeaponAttack() - { - if (Player.EquippedWeapon.Value.ItemName == string.Empty) - return; - - var currentWeapon = Player.EquippedWeapon.Value; - currentWeapon.IncreaseWeaponAttack(1); - } - - private void RaiseCurrentArmorDefense() - { - if (Player.EquippedArmor.Value.ItemName == string.Empty) - return; - - var currentArmor = Player.EquippedArmor.Value; - currentArmor.IncreaseArmorDefense(1); - } - - private void RaiseLevel() - { - Player.LevelUp(); - } + public override InventoryItemStats ItemStats { get => _effectItemStats; set => _effectItemStats = (EffectItemStats)value; } } diff --git a/src/items/effect/EffectItem.tscn b/src/items/effect/EffectItem.tscn index 3bbb2f2c..f9c78814 100644 --- a/src/items/effect/EffectItem.tscn +++ b/src/items/effect/EffectItem.tscn @@ -10,8 +10,8 @@ script = ExtResource("1_yw2rj") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true -collision_layer = 0 -collision_mask = 4 +collision_layer = 4 +collision_mask = 0 [node name="CollisionShape3D" type="CollisionShape3D" parent="Pickup"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0600509, 0.26725, 0.180481) diff --git a/src/items/effect/EffectItemStats.cs b/src/items/effect/EffectItemStats.cs index 477467e4..96d0a72d 100644 --- a/src/items/effect/EffectItemStats.cs +++ b/src/items/effect/EffectItemStats.cs @@ -1,13 +1,18 @@ -using Godot; +using Chickensoft.Introspection; +using Chickensoft.Serialization; +using Godot; namespace GameJamDungeon; [GlobalClass] +[Meta, Id("effect_item_stats")] public partial class EffectItemStats : InventoryItemStats { [Export] - public Godot.Collections.Array UsableItemTags { get; set; } = new Godot.Collections.Array(); + [Save("effect_item_tag")] + public UsableItemTag UsableItemTag { get; set; } = UsableItemTag.None; [Export] + [Save("effect_item_element")] public ElementType ElementalDamageType { get; set; } } diff --git a/src/items/restorative/Restorative.tscn b/src/items/restorative/Restorative.tscn index 21557d93..21f72a30 100644 --- a/src/items/restorative/Restorative.tscn +++ b/src/items/restorative/Restorative.tscn @@ -23,7 +23,7 @@ texture = ExtResource("1_1rwq6") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true collision_layer = 4 -collision_mask = 4 +collision_mask = 0 [node name="CollisionShape3D" type="CollisionShape3D" parent="Pickup"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.348749, 0) diff --git a/src/items/throwable/ThrowableItem.cs b/src/items/throwable/ThrowableItem.cs index 0f1094a2..3eff027b 100644 --- a/src/items/throwable/ThrowableItem.cs +++ b/src/items/throwable/ThrowableItem.cs @@ -1,146 +1,37 @@ -using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; -using System; -using System.Collections.Immutable; -using System.Linq; namespace GameJamDungeon; -[Meta(typeof(IAutoNode))] -public partial class ThrowableItem : Node3D, IUsableItem +[Meta, Id("throwable_item")] +public partial class ThrowableItem : InventoryItem { - public override void _Notification(int what) => this.Notify(what); - - [Dependency] public IGame Game => this.DependOn(); - - [Dependency] public IPlayer Player => this.DependOn(); - - public Guid ID => Guid.NewGuid(); - - public string ItemName => _throwableItemStats.Name; - - public string Description => _throwableItemStats.Description; - - public float SpawnRate => _throwableItemStats.SpawnRate; - - public Texture2D GetTexture() => _throwableItemStats.Texture; - - public double ThrowDamage => _throwableItemStats.ThrowDamage; - - public float ThrowSpeed => _throwableItemStats.ThrowSpeed; - - public ElementType ElementType => _throwableItemStats.ElementType; - - public ImmutableList ThrowableItemTags => [.. _throwableItemStats.ThrowableItemTags]; - - public int Count { get; } - - public void SetItemStats(InventoryItemStats inventoryItemStats) - { - _throwableItemStats = (ThrowableItemStats)inventoryItemStats; - } - - public void OnEntered(Node3D body) - { - var isAdded = Player.Inventory.TryAdd(this); - if (isAdded) - QueueFree(); - } - [Export] private ThrowableItemStats _throwableItemStats { get; set; } - [Node] private Sprite3D Sprite { get; set; } = new Sprite3D(); + public override string ItemName => _throwableItemStats.Name; - [Node] private Area3D Pickup { get; set; } = default!; + public override string Description => _throwableItemStats.Description; - public void OnResolved() - { - Pickup.BodyEntered += OnEntered; - Sprite.Texture = _throwableItemStats.Texture; - } + public override float SpawnRate => _throwableItemStats.SpawnRate; - public void Use() - { - if (_throwableItemStats.HealHPAmount > 0) - Player.HealHP(_throwableItemStats.HealHPAmount); - if (_throwableItemStats.HealVTAmount > 0) - Player.HealVT(_throwableItemStats.HealVTAmount); + public override double ThrowDamage => _throwableItemStats.ThrowDamage; - if (_throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.TeleportToRandomLocation)) - TeleportToRandomRoom(Player); + public override float ThrowSpeed => _throwableItemStats.ThrowSpeed; - if (_throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.CanChangeAffinity)) - ChangeAffinity(); + public ElementType ElementType => _throwableItemStats.ElementType; - if (_throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.WarpToExitIfFound)) - WarpToExit(Player); - } + public ThrowableItemTag ThrowableItemTag => _throwableItemStats.ThrowableItemTag; - public void TeleportToRandomRoom(IEnemy enemy) - { - var currentFloor = Game.CurrentFloor; - var rooms = currentFloor.Rooms; - var currentRoom = enemy.GetCurrentRoom(); - var validRooms = rooms.OfType().ToList(); - if (currentRoom is MonsterRoom currentMonsterRoom) - validRooms.Remove(currentMonsterRoom); + public int HealHPAmount => _throwableItemStats.HealHPAmount; - if (validRooms.Count == 0) - return; + public int HealVTAmount => _throwableItemStats.HealVTAmount; - var roomsGodotCollection = new Godot.Collections.Array(validRooms); - var randomRoom = roomsGodotCollection.PickRandom(); - var spawnPoints = randomRoom.EnemySpawnPoints.GetChildren().OfType().ToList(); - var spawnPointsGodotCollection = new Godot.Collections.Array(spawnPoints); - var randomSpawnPoint = spawnPointsGodotCollection.PickRandom(); + public void SetElementType(ElementType elementType) => _throwableItemStats.ElementType = elementType; - enemy.SetEnemyGlobalPosition(randomSpawnPoint.GlobalPosition); - } + public void SetDescription(string description) => _throwableItemStats.Description = description; - private void TeleportToRandomRoom(IPlayer player) - { - var currentFloor = Game.CurrentFloor; - var rooms = currentFloor.Rooms; + public int Count { get; } - var currentRoom = rooms.SingleOrDefault(x => x.IsPlayerInRoom); - - var validRooms = rooms.OfType().ToList(); - if (currentRoom is MonsterRoom currentMonsterRoom) - validRooms.Remove(currentMonsterRoom); - - if (validRooms.Count == 0) - return; - - var roomsGodotCollection = new Godot.Collections.Array(validRooms); - var randomRoom = roomsGodotCollection.PickRandom(); - var spawnPoint = randomRoom.PlayerSpawn; - Game.ToggleInventory(); - player.TeleportPlayer(spawnPoint.GlobalPosition); - } - - private void ChangeAffinity() - { - var maximumElements = Enum.GetNames(typeof(ElementType)).Length; - _throwableItemStats.ElementType = _throwableItemStats.ElementType + 1 % maximumElements; - - // TODO: Make this an inventory animation to cycle through elements. - _throwableItemStats.Description = - $"Inflicts {_throwableItemStats.ElementType} damage when thrown." + - $"{System.Environment.NewLine}Use item to change Affinity."; - } - - private void WarpToExit(IPlayer player) - { - var exitRoom = Game.CurrentFloor.Rooms.OfType().Single(); - if (exitRoom.PlayerDiscoveredRoom) - player.TeleportPlayer(exitRoom.PlayerSpawn.GlobalPosition); - } - - public void WarpToExit(IEnemy enemy) - { - var exitRoom = Game.CurrentFloor.Rooms.OfType().Single(); - enemy.SetEnemyGlobalPosition(exitRoom.PlayerSpawn.GlobalPosition); - } + public override InventoryItemStats ItemStats { get => _throwableItemStats; set => _throwableItemStats = (ThrowableItemStats)value; } } diff --git a/src/items/throwable/ThrowableItem.tscn b/src/items/throwable/ThrowableItem.tscn index 079e97c0..ec1550c5 100644 --- a/src/items/throwable/ThrowableItem.tscn +++ b/src/items/throwable/ThrowableItem.tscn @@ -10,8 +10,8 @@ script = ExtResource("1_nac2l") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true -collision_layer = 0 -collision_mask = 4 +collision_layer = 4 +collision_mask = 0 [node name="CollisionShape3D" type="CollisionShape3D" parent="Pickup"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0600509, 0.26725, 0.180481) diff --git a/src/items/throwable/ThrowableItemStats.cs b/src/items/throwable/ThrowableItemStats.cs index 5d1230d3..5ddbd82d 100644 --- a/src/items/throwable/ThrowableItemStats.cs +++ b/src/items/throwable/ThrowableItemStats.cs @@ -1,16 +1,22 @@ -using Godot; +using Chickensoft.Introspection; +using Chickensoft.Serialization; +using Godot; namespace GameJamDungeon; [GlobalClass] +[Meta, Id("throwable_item_stats")] public partial class ThrowableItemStats : InventoryItemStats { [Export] - public Godot.Collections.Array ThrowableItemTags { get; set; } = new Godot.Collections.Array(); + [Save("throwable_item_tag")] + public ThrowableItemTag ThrowableItemTag { get; set; } = ThrowableItemTag.None; [Export] + [Save("throwable_item_element")] public ElementType ElementType { get; set; } = ElementType.None; [Export] - public Godot.Collections.Array UsableItemTags { get; set; } = new Godot.Collections.Array(); + [Save("throwable_item_usable_tag")] + public UsableItemTag UsableItemTag { get; set; } = UsableItemTag.None; } diff --git a/src/items/throwable/ThrowableItemTag.cs b/src/items/throwable/ThrowableItemTag.cs index 9f5798b2..6905933a 100644 --- a/src/items/throwable/ThrowableItemTag.cs +++ b/src/items/throwable/ThrowableItemTag.cs @@ -1,15 +1,22 @@ -namespace GameJamDungeon; +using System.Text.Json.Serialization; + +namespace GameJamDungeon; public enum ThrowableItemTag { + None, LowerTargetTo1HP, CanChangeAffinity, TeleportToRandomLocation, WarpToExitIfFound } +[JsonSerializable(typeof(ThrowableItemTag))] +public partial class ThrowableItemTagEnumContext : JsonSerializerContext; + public enum UsableItemTag { + None, DoubleEXP, IdentifyAllItemsCostHP, BriefImmunity, @@ -26,14 +33,13 @@ public enum UsableItemTag RandomEffect, } -public enum EnhancingItemTag -{ - Add1ATK, - Add1DEF, - RaiseLevelBy1, -} +[JsonSerializable(typeof(UsableItemTag))] +public partial class UsableItemTagEnumContext : JsonSerializerContext; public enum BoxItemTag { RandomNewItem, -} \ No newline at end of file +} + +[JsonSerializable(typeof(BoxItemTag))] +public partial class BoxItemTagEnumContext : JsonSerializerContext; diff --git a/src/items/thrown/ThrownItem.cs b/src/items/thrown/ThrownItem.cs index efafee3a..00cb988c 100644 --- a/src/items/thrown/ThrownItem.cs +++ b/src/items/thrown/ThrownItem.cs @@ -1,7 +1,7 @@ using Chickensoft.AutoInject; using Chickensoft.Introspection; +using GameJamDungeon.src.items; using Godot; -using System.Linq; namespace GameJamDungeon; @@ -14,15 +14,16 @@ public partial class ThrownItem : RigidBody3D [Dependency] public IGame Game => this.DependOn(); - public IInventoryItem ItemThatIsThrown; + public InventoryItem ItemThatIsThrown; + + private EffectService _effectService; [Node] public Sprite2D Sprite { get; set; } = default!; public void OnResolved() { - BodyEntered += ThrownItem_BodyEntered; GlobalPosition = Player.CurrentPosition; - Sprite.Texture = ItemThatIsThrown.GetTexture(); + Sprite.Texture = ItemThatIsThrown.ItemStats.Texture; AddCollisionExceptionWith((Node)Player); } @@ -33,8 +34,9 @@ public partial class ThrownItem : RigidBody3D QueueFree(); } - public void Throw() + public void Throw(EffectService effectService) { + _effectService = effectService; ApplyCentralImpulse(-Player.CurrentBasis.Z.Normalized() * ItemThatIsThrown.ThrowSpeed); } @@ -79,16 +81,16 @@ public partial class ThrownItem : RigidBody3D { if (ItemThatIsThrown is ThrowableItem throwableItem) { - switch (throwableItem.ThrowableItemTags.Single()) + switch (throwableItem.ThrowableItemTag) { case ThrowableItemTag.LowerTargetTo1HP: enemy.TakeDamage(enemy.CurrentHP - 1, ignoreDefense: true, ignoreElementalResistance: true); break; case ThrowableItemTag.TeleportToRandomLocation: - throwableItem.TeleportToRandomRoom(enemy); + _effectService.TeleportToRandomRoom(enemy); break; case ThrowableItemTag.WarpToExitIfFound: - throwableItem.WarpToExit(enemy); + _effectService.WarpToExit(enemy); break; default: enemy.TakeDamage(throwableItem.ThrowDamage, throwableItem.ElementType); diff --git a/src/items/weapons/Weapon.cs b/src/items/weapons/Weapon.cs index 28fe77d2..dff78d4c 100644 --- a/src/items/weapons/Weapon.cs +++ b/src/items/weapons/Weapon.cs @@ -1,51 +1,38 @@ using Chickensoft.AutoInject; using Chickensoft.Introspection; +using Chickensoft.Serialization; using Godot; -using System; -using System.Collections.Immutable; namespace GameJamDungeon; -[Meta(typeof(IAutoNode))] -public partial class Weapon : Node3D, IInventoryItem, IEquipableItem +[Meta, Id("weapon")] +public partial class Weapon : EquipableItem { - public override void _Notification(int what) => this.Notify(what); - - [Dependency] public IPlayer Player => this.DependOn(); - [Signal] public delegate void EquippedItemEventHandler(Weapon equippedWeapon); [Export] private WeaponStats _weaponStats { get; set; } = new WeaponStats(); - [Node] public Sprite3D Sprite { get; set; } = new Sprite3D(); + public override string ItemName => _weaponStats.Name; - [Node] public Area3D Pickup { get; set; } = default!; + public override string Description => _weaponStats.Description; - public Texture2D GetTexture() => _weaponStats.Texture; - - public Guid ID => Guid.NewGuid(); - - public string ItemName => _weaponStats.Name; - - public string Description => _weaponStats.Description; - - public float SpawnRate => _weaponStats.SpawnRate; + public override float SpawnRate => _weaponStats.SpawnRate; public int Damage => _weaponStats.Damage; - public double ThrowDamage => _weaponStats.ThrowDamage; + public override double ThrowDamage => _weaponStats.ThrowDamage; - public float ThrowSpeed => _weaponStats.ThrowSpeed; + public override float ThrowSpeed => _weaponStats.ThrowSpeed; public double Luck => _weaponStats.Luck; public double AttackSpeed => _weaponStats.AttackSpeed; - public ImmutableList WeaponTags => [.. _weaponStats.WeaponTags]; + public WeaponTag WeaponTag => _weaponStats.WeaponTag; - public ImmutableList ItemTags => [.. _weaponStats.ItemTags]; + public override ItemTag ItemTag => _weaponStats.ItemTag; public ElementType WeaponElement => _weaponStats.WeaponElement; @@ -53,38 +40,5 @@ public partial class Weapon : Node3D, IInventoryItem, IEquipableItem public void IncreaseWeaponAttack(int bonus) => _weaponStats.Damage += bonus; - public bool IsEquipped { get; set; } - - public void OnReady() - { - Pickup.BodyEntered += OnEntered; - Sprite.Texture = _weaponStats.Texture; - } - - public void SetItemStats(InventoryItemStats inventoryItemStats) - { - _weaponStats = (WeaponStats)inventoryItemStats; - if (inventoryItemStats.Texture != null) - { - var texture = ResourceLoader.Load(inventoryItemStats.Texture.ResourcePath) as Texture2D; - Sprite.Texture = texture; - } - } - - public void Throw() - { - Player.Inventory.Remove(this); - } - - public void Drop() - { - Player.Inventory.Remove(this); - } - - public void OnEntered(Node3D body) - { - var isAdded = Player.Inventory.TryAdd(this); - if (isAdded) - QueueFree(); - } + public override InventoryItemStats ItemStats { get => _weaponStats; set => _weaponStats = (WeaponStats)value; } } diff --git a/src/items/weapons/Weapon.tscn b/src/items/weapons/Weapon.tscn index 79012984..603a7154 100644 --- a/src/items/weapons/Weapon.tscn +++ b/src/items/weapons/Weapon.tscn @@ -12,7 +12,7 @@ script = ExtResource("1_7pkyf") [node name="Pickup" type="Area3D" parent="."] unique_name_in_owner = true collision_layer = 4 -collision_mask = 4 +collision_mask = 0 [node name="Sprite" type="Sprite3D" parent="Pickup"] unique_name_in_owner = true diff --git a/src/items/weapons/WeaponStats.cs b/src/items/weapons/WeaponStats.cs index 52fd346e..baad85a0 100644 --- a/src/items/weapons/WeaponStats.cs +++ b/src/items/weapons/WeaponStats.cs @@ -1,25 +1,34 @@ +using Chickensoft.Introspection; +using Chickensoft.Serialization; using Godot; namespace GameJamDungeon; [GlobalClass] +[Meta, Id("weapon_stat_type")] public partial class WeaponStats : InventoryItemStats { [Export] + [Save("weapon_damage")] public int Damage { get; set; } = 0; [Export] + [Save("weapon_luck")] public double Luck { get; set; } = 0.05; [Export] + [Save("weapon_atk_speed")] public double AttackSpeed { get; set; } = 1; [Export] + [Save("weapon_element")] public ElementType WeaponElement { get; set; } = ElementType.None; [Export] + [Save("weapon_elemental_damage_bonus")] public double ElementalDamageBonus { get; set; } = 1.0; [Export] - public Godot.Collections.Array WeaponTags { get; set; } = new Godot.Collections.Array(); + [Save("weapon_tag")] + public WeaponTag WeaponTag { get; set; } = WeaponTag.None; } diff --git a/src/items/weapons/resources/Sword Sword Odette.tres b/src/items/weapons/resources/Swan Sword Odette.tres similarity index 100% rename from src/items/weapons/resources/Sword Sword Odette.tres rename to src/items/weapons/resources/Swan Sword Odette.tres diff --git a/src/map/dungeon/floors/Floor00.tscn b/src/map/dungeon/floors/Floor00.tscn index d31eb1e1..30558c38 100644 --- a/src/map/dungeon/floors/Floor00.tscn +++ b/src/map/dungeon/floors/Floor00.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=62 format=4 uid="uid://dl6h1djc27ddl"] +[gd_scene load_steps=60 format=4 uid="uid://dl6h1djc27ddl"] [ext_resource type="Script" uid="uid://c1nhqlem1ew3m" path="res://src/map/dungeon/code/Floor0.cs" id="1_db2o3"] [ext_resource type="Texture2D" uid="uid://b27ksiyfefb33" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_outside_desert.png" id="2_xh2ej"] @@ -15,8 +15,6 @@ [ext_resource type="Texture2D" uid="uid://dyufabjcwlago" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_HAND_CYCLE_MOTIF.png" id="13_1i307"] [ext_resource type="Texture2D" uid="uid://4k6vtn4oip5f" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_TILE4.png" id="14_qqc7i"] [ext_resource type="Texture2D" uid="uid://cururtxtgylxf" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_COLUMN.jpg" id="15_ojbcg"] -[ext_resource type="PackedScene" uid="uid://d0pl1n1jf77jm" path="res://src/items/effect/EffectItem.tscn" id="16_aqomv"] -[ext_resource type="Resource" uid="uid://c6ecr2cquav3" path="res://src/items/effect/resources/EntropicSeal.tres" id="17_db2o3"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3ubi4"] shading_mode = 0 @@ -887,7 +885,3 @@ collision_mask = 8 [node name="CollisionShape3D" type="CollisionShape3D" parent="Room/Room"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 149.05, -4.02862, -1.76389) shape = SubResource("BoxShape3D_ntxe5") - -[node name="EffectItem" parent="." instance=ExtResource("16_aqomv")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.25212, -2.42406, 0) -_effectItemStats = ExtResource("17_db2o3") diff --git a/src/player/IPlayer.cs b/src/player/IPlayer.cs index 381a35d1..0f920d8e 100644 --- a/src/player/IPlayer.cs +++ b/src/player/IPlayer.cs @@ -5,7 +5,7 @@ using Godot; namespace GameJamDungeon; -public interface IPlayer : IKillable, IProvide> +public interface IPlayer : IKillable, IProvide> { public void Attack(); @@ -47,7 +47,7 @@ public interface IPlayer : IKillable, IProvide> public void ModifyBonusLuck(double amount); - public IInventory Inventory { get; } + public Inventory Inventory { get; } public PlayerStatController Stats { get; } @@ -61,7 +61,7 @@ public interface IPlayer : IKillable, IProvide> public IAutoProp EquippedAccessory { get; } - public void Equip(IEquipableItem equipable); + public void Equip(EquipableItem equipable); - public void Unequip(IEquipableItem equipable); + public void Unequip(EquipableItem equipable); } diff --git a/src/player/Player.cs b/src/player/Player.cs index 06d8fb07..b45fff4c 100644 --- a/src/player/Player.cs +++ b/src/player/Player.cs @@ -20,7 +20,7 @@ public partial class Player : CharacterBody3D, IPlayer #endregion #region Save - public ISaveChunk PlayerChunk { get; set; } = default!; + public ISaveChunk PlayerChunk { get; set; } = default!; #endregion public double CurrentHP => Stats.CurrentHP.Value; @@ -30,7 +30,7 @@ public partial class Player : CharacterBody3D, IPlayer public Basis CurrentBasis => Transform.Basis; public PlayerStatController Stats { get; set; } = default!; - public IInventory Inventory { get; private set; } = default!; + public Inventory Inventory { get; private set; } = default!; public IAutoProp EquippedWeapon => _equippedWeapon; private AutoProp _equippedWeapon { get; set; } = new AutoProp(new Weapon()); @@ -53,7 +53,7 @@ public partial class Player : CharacterBody3D, IPlayer [Dependency] public ISaveChunk GameChunk => this.DependOn>(); - ISaveChunk IProvide>.Value() => PlayerChunk; + ISaveChunk IProvide>.Value() => PlayerChunk; #endregion #region Event Signals @@ -82,6 +82,8 @@ public partial class Player : CharacterBody3D, IPlayer [Node] private IHitbox Hitbox { get; set; } = default!; + [Node] private Area3D CollisionDetector { get; set; } = default!; + [Node] private Timer HealthTimer { get; set; } = default!; #endregion @@ -144,9 +146,9 @@ public partial class Player : CharacterBody3D, IPlayer PlayerLogic.Set(Stats); var defaultWeapon = new Weapon(); - defaultWeapon.SetItemStats(_defaultWeapon); + defaultWeapon.ItemStats = _defaultWeapon; var defaultArmor = new Armor(); - defaultArmor.SetItemStats(_defaultArmor); + defaultArmor.ItemStats = _defaultArmor; Inventory.TryAdd(defaultWeapon); Inventory.TryAdd(defaultArmor); @@ -164,27 +166,32 @@ public partial class Player : CharacterBody3D, IPlayer public void OnResolved() { - PlayerChunk = new SaveChunk( - onSave: (chunk) => new PlayerStats + PlayerChunk = new SaveChunk( + onSave: (chunk) => new PlayerData() { - CurrentHP = Stats.CurrentHP.Value, - MaximumHP = Stats.MaximumHP.Value, - CurrentVT = Stats.CurrentVT.Value, - MaximumVT = Stats.MaximumVT.Value, - CurrentAttack = Stats.CurrentAttack.Value, - BonusAttack = Stats.BonusAttack.Value, - MaxAttack = Stats.MaxAttack.Value, - CurrentDefense = Stats.CurrentDefense.Value, - BonusDefense = Stats.BonusDefense.Value, - MaxDefense = Stats.MaxDefense.Value, - CurrentExp = Stats.CurrentExp.Value, - CurrentLevel = Stats.CurrentLevel.Value, - ExpToNextLevel = Stats.ExpToNextLevel.Value, - Luck = Stats.Luck.Value + PlayerStats = new PlayerStats() + { + CurrentHP = Stats.CurrentHP.Value, + MaximumHP = Stats.MaximumHP.Value, + CurrentVT = Stats.CurrentVT.Value, + MaximumVT = Stats.MaximumVT.Value, + CurrentAttack = Stats.CurrentAttack.Value, + BonusAttack = Stats.BonusAttack.Value, + MaxAttack = Stats.MaxAttack.Value, + CurrentDefense = Stats.CurrentDefense.Value, + BonusDefense = Stats.BonusDefense.Value, + MaxDefense = Stats.MaxDefense.Value, + CurrentExp = Stats.CurrentExp.Value, + CurrentLevel = Stats.CurrentLevel.Value, + ExpToNextLevel = Stats.ExpToNextLevel.Value, + Luck = Stats.Luck.Value + }, + Inventory = Inventory }, onLoad: (chunk, data) => { - Stats.Init(data); + Stats.Init(data.PlayerStats); + Inventory = data.Inventory; } ); @@ -208,6 +215,17 @@ public partial class Player : CharacterBody3D, IPlayer this.Provide(); HealthTimer.Timeout += OnHealthTimerTimeout; Hitbox.AreaEntered += Hitbox_AreaEntered; + CollisionDetector.BodyEntered += CollisionDetector_BodyEntered; + } + + private void CollisionDetector_BodyEntered(Node3D body) + { + if (body is InventoryItem inventoryItem) + { + var isAdded = Inventory.TryAdd(inventoryItem); + if (isAdded) + QueueFree(); + } } public void OnReady() @@ -368,6 +386,12 @@ public partial class Player : CharacterBody3D, IPlayer if (@event.IsActionPressed(GameInputs.Attack)) Attack(); + + if (@event.IsActionPressed(GameInputs.Save)) + Game.Save(); + + if (@event.IsActionPressed(GameInputs.Load)) + Game.Load(); } public void OnPhysicsProcess(double delta) @@ -376,7 +400,7 @@ public partial class Player : CharacterBody3D, IPlayer PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform)); } - public void Equip(IEquipableItem equipable) + public void Equip(EquipableItem equipable) { if (equipable is Weapon weapon) { @@ -400,7 +424,7 @@ public partial class Player : CharacterBody3D, IPlayer throw new NotImplementedException("Item type is not supported."); } - public void Unequip(IEquipableItem equipable) + public void Unequip(EquipableItem equipable) { if (equipable is Weapon weapon) { @@ -427,7 +451,7 @@ public partial class Player : CharacterBody3D, IPlayer else throw new NotImplementedException("Item type is not supported."); - if (equipable.ItemTags.Contains(ItemTag.BreaksOnChange)) + if (equipable.ItemTag == ItemTag.BreaksOnChange) Inventory.Remove(equipable); } @@ -492,7 +516,7 @@ public partial class Player : CharacterBody3D, IPlayer if (Stats.CurrentVT.Value > 0) { - if (EquippedAccessory.Value.AccessoryTags.Contains(AccessoryTag.HalfVTConsumption)) + if (EquippedAccessory.Value.AccessoryTag == AccessoryTag.HalfVTConsumption) { reduceOnTick = !reduceOnTick; } @@ -550,7 +574,7 @@ public partial class Player : CharacterBody3D, IPlayer private void HitEnemy(IEnemy enemy) { var attackValue = Stats.CurrentAttack.Value + Stats.BonusAttack.Value; - var ignoreElementalResistance = EquippedWeapon.Value.WeaponTags.Contains(WeaponTag.IgnoreAffinity); + var ignoreElementalResistance = EquippedWeapon.Value.WeaponTag == WeaponTag.IgnoreAffinity; var isCriticalHit = BattleExtensions.IsCriticalHit(Stats.Luck.Value); var element = EquippedWeapon.Value.WeaponElement; @@ -561,7 +585,7 @@ public partial class Player : CharacterBody3D, IPlayer false, ignoreElementalResistance); - if (EquippedWeapon.Value.WeaponTags.Contains(WeaponTag.Knockback)) + if (EquippedWeapon.Value.WeaponTag == WeaponTag.Knockback) enemy.Knockback(0.3f, -CurrentBasis.Z.Normalized()); } } diff --git a/src/player/Player.tscn b/src/player/Player.tscn index 06c597ef..38d37cc3 100644 --- a/src/player/Player.tscn +++ b/src/player/Player.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" uid="uid://yxmiqy7i0t7r" path="res://src/player/Player.cs" id="1_xcol5"] [ext_resource type="Script" uid="uid://6edayafleq8y" path="res://src/hitbox/Hitbox.cs" id="2_lb3qc"] [ext_resource type="Script" uid="uid://s6ku2kyc4rbk" path="res://src/player/PlayerStatResource.cs" id="2_xq68d"] -[ext_resource type="Resource" uid="uid://b7xr0l4a8g1gk" path="res://src/items/weapons/resources/SealingRod.tres" id="3_ebyyx"] +[ext_resource type="Resource" uid="uid://bpdbuf0k0exb5" path="res://src/items/weapons/resources/Swan Sword Odette.tres" id="3_es4xk"] [ext_resource type="Resource" uid="uid://ce2vfa2t3io67" path="res://src/items/armor/resources/AtonersAdornments.tres" id="4_bj1ma"] [ext_resource type="Texture2D" uid="uid://c6r3dhnkuw22w" path="res://src/vfx/hit_effects/FIRE_STRIKE_1.0.png" id="5_wr6lo"] [ext_resource type="Texture2D" uid="uid://m6xsyhnt67sh" path="res://src/player/dont_look_in_here/tendomaya_body0_tex00.png" id="6_es4xk"] @@ -32,13 +32,13 @@ BonusDefense = 0 MaxDefense = 12 Luck = 0.05 -[sub_resource type="BoxShape3D" id="BoxShape3D_wedu3"] - [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_dw45s"] radius = 1.0 +[sub_resource type="BoxShape3D" id="BoxShape3D_wedu3"] + [sub_resource type="BoxShape3D" id="BoxShape3D_hs4wf"] -size = Vector3(1.94531, 2.43945, 2.35425) +size = Vector3(1.94531, 3.38623, 2.35425) [sub_resource type="Animation" id="Animation_hcjph"] length = 0.001 @@ -470,9 +470,13 @@ collision_layer = 806 collision_mask = 775 script = ExtResource("1_xcol5") PlayerStatResource = SubResource("Resource_btp2w") -_defaultWeapon = ExtResource("3_ebyyx") +_defaultWeapon = ExtResource("3_es4xk") _defaultArmor = ExtResource("4_bj1ma") +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.06447, 0) +shape = SubResource("CapsuleShape3D_dw45s") + [node name="Hitbox" type="Area3D" parent="."] unique_name_in_owner = true transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.12691, -1) @@ -484,18 +488,14 @@ script = ExtResource("2_lb3qc") shape = SubResource("BoxShape3D_wedu3") disabled = true -[node name="CollisionShape3D" type="CollisionShape3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.06447, 0) -shape = SubResource("CapsuleShape3D_dw45s") - -[node name="CollisionDetector" type="Area3D" parent="CollisionShape3D"] +[node name="CollisionDetector" type="Area3D" parent="."] unique_name_in_owner = true -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.937567, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.126903, 0) collision_layer = 452 collision_mask = 452 -[node name="CollisionShape3D" type="CollisionShape3D" parent="CollisionShape3D/CollisionDetector"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0479561, 0.982638, -0.675098) +[node name="CollisionShape3D" type="CollisionShape3D" parent="CollisionDetector"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0479561, 0.509249, -0.675098) shape = SubResource("BoxShape3D_hs4wf") [node name="Camera3D" type="Camera3D" parent="."] diff --git a/src/player/PlayerData.cs b/src/player/PlayerData.cs new file mode 100644 index 00000000..eb84fea8 --- /dev/null +++ b/src/player/PlayerData.cs @@ -0,0 +1,14 @@ +using Chickensoft.Introspection; +using Chickensoft.Serialization; + +namespace GameJamDungeon; + +[Meta, Id("player_data")] +public partial record PlayerData +{ + [Save("player_stats")] + public required PlayerStats PlayerStats { get; init; } + + [Save("player_inventory")] + public required Inventory Inventory { get; init; } +}