From d7a49ba974f1d0017fb2bbe93ceb480ff7c045ec Mon Sep 17 00:00:00 2001 From: Zenny Date: Wed, 4 Sep 2024 01:24:37 -0700 Subject: [PATCH] Damage calculation including elemental buff/resistance --- src/enemy/Enemy.cs | 30 +++-- src/enemy/EnemyDatabase.tscn | 2 +- src/enemy/EnemyStatInfo.cs | 26 ++++ src/enemy/EnemyStats.cs | 14 --- src/enemy/enemy_types/FloatingEnemy.tres | 8 -- .../DISSAPPEARING ENEMY.gltf | 0 .../DISSAPPEARING ENEMY.gltf.import | 6 +- .../floating_enemy/FloatingEnemy.tres | 12 ++ .../{ => floating_enemy}/FloatingEnemy.tscn | 8 +- src/enemy/state/EnemyLogic.Input.cs | 4 +- src/enemy/state/EnemyLogic.Output.cs | 2 +- .../state/states/EnemyLogic.State.Alive.cs | 16 +-- src/game/Game.tscn | 112 ++++++++++++++++-- src/map/dungeon/rooms/Room1.tscn | 6 +- src/player/Player.cs | 22 +++- src/player/Player.tscn | 4 +- src/player/PlayerData.cs | 9 ++ src/player/PlayerStatInfo.cs | 38 ++++++ src/player/PlayerStats.tres | 16 +++ src/player/state/PlayerLogic.Input.cs | 2 + .../state/states/PlayerLogic.State.Alive.cs | 9 +- src/system/stats/DamageCalculator.cs | 18 +++ src/system/stats/ICharacterStats.cs | 17 +++ 23 files changed, 311 insertions(+), 70 deletions(-) create mode 100644 src/enemy/EnemyStatInfo.cs delete mode 100644 src/enemy/EnemyStats.cs delete mode 100644 src/enemy/enemy_types/FloatingEnemy.tres rename src/enemy/enemy_types/{ => floating_enemy}/DISSAPPEARING ENEMY.gltf (100%) rename src/enemy/enemy_types/{ => floating_enemy}/DISSAPPEARING ENEMY.gltf.import (71%) create mode 100644 src/enemy/enemy_types/floating_enemy/FloatingEnemy.tres rename src/enemy/enemy_types/{ => floating_enemy}/FloatingEnemy.tscn (99%) create mode 100644 src/player/PlayerStatInfo.cs create mode 100644 src/player/PlayerStats.tres create mode 100644 src/system/stats/DamageCalculator.cs create mode 100644 src/system/stats/ICharacterStats.cs diff --git a/src/enemy/Enemy.cs b/src/enemy/Enemy.cs index 872f246f..66ac7299 100644 --- a/src/enemy/Enemy.cs +++ b/src/enemy/Enemy.cs @@ -1,7 +1,9 @@ using Chickensoft.AutoInject; +using Chickensoft.Collections; using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using Godot; +using System; using System.Linq; namespace GameJamDungeon; @@ -10,9 +12,9 @@ public interface IEnemy : ICharacterBody3D { public IEnemyLogic EnemyLogic { get; } - public int CurrentHP { get; set; } + public AutoProp CurrentHP { get; set; } - public Resource EnemyStats { get; set; } + public EnemyStatInfo EnemyStatInfo { get; set; } public NavigationAgent3D NavAgent { get; set; } } @@ -31,28 +33,28 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide [Dependency] IGameRepo GameRepo => this.DependOn(); [Export] - public Resource EnemyStats { get; set; } = new(); + public EnemyStatInfo EnemyStatInfo { get; set; } = new(); public static PackedScene CollisionDetectorScene => GD.Load("res://src/enemy/CollisionDetector.tscn"); public static Area3D CollisionDetector { get; set; } = default!; - public int CurrentHP { get; set; } + public AutoProp CurrentHP { get; set; } [Node] public NavigationAgent3D NavAgent { get; set; } = default!; public void Setup() { EnemyLogic = new EnemyLogic(); - EnemyLogic.Set(EnemyStats); + EnemyLogic.Set(EnemyStatInfo); EnemyLogic.Set(this as IEnemy); EnemyLogic.Set(GameRepo); } public void Initialize() { - var enemyResource = EnemyStats as EnemyStats; - CurrentHP = enemyResource.MaximumHP; + CurrentHP = new AutoProp(EnemyStatInfo.MaximumHP); + CurrentHP.Sync += OnHPChanged; } public void OnResolved() @@ -71,7 +73,6 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide }) .Handle((in EnemyLogic.Output.Die output) => { - CollisionDetector.Dispose(); QueueFree(); }) .Handle((in EnemyLogic.Output.HitByPlayer output) => @@ -112,14 +113,21 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide { if (body is IHitbox hitBox) { - if (CurrentHP > 0) + if (CurrentHP.Value > 0) { - GD.Print("Enemy Hit"); - EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(hitBox.Damage)); + var damage = DamageCalculator.CalculatePlayerDamage(hitBox.Damage, hitBox.GetParent().PlayerStatInfo, EnemyStatInfo); + GD.Print($"Enemy Hit for {damage} damage."); + EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(damage)); } } } + private void OnHPChanged(double newHP) + { + if (newHP <= 0) + EnemyLogic.Input(new EnemyLogic.Input.Killed()); + } + public void OnReady() { SetPhysicsProcess(true); diff --git a/src/enemy/EnemyDatabase.tscn b/src/enemy/EnemyDatabase.tscn index 0bde905b..153f22e1 100644 --- a/src/enemy/EnemyDatabase.tscn +++ b/src/enemy/EnemyDatabase.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://dbvr8ewajja6a"] [ext_resource type="Script" path="res://src/enemy/EnemyDatabase.cs" id="1_ywy58"] -[ext_resource type="PackedScene" uid="uid://dcgj5i52i76gj" path="res://src/enemy/enemy_types/FloatingEnemy.tscn" id="2_8cbrh"] +[ext_resource type="PackedScene" uid="uid://dcgj5i52i76gj" path="res://src/enemy/enemy_types/floating_enemy/FloatingEnemy.tscn" id="2_8cbrh"] [node name="EnemyDatabase" type="Node"] script = ExtResource("1_ywy58") diff --git a/src/enemy/EnemyStatInfo.cs b/src/enemy/EnemyStatInfo.cs new file mode 100644 index 00000000..68b05794 --- /dev/null +++ b/src/enemy/EnemyStatInfo.cs @@ -0,0 +1,26 @@ +using Godot; + +namespace GameJamDungeon +{ + [GlobalClass] + public partial class EnemyStatInfo : Resource, ICharacterStats + { + [Export] + public double MaximumHP { get; set; } + + [Export] + public int BaseAttack { get; set; } + + [Export] + public int BaseDefense { get; set; } + + [Export] + public double ElementAResistance { get; set; } + + [Export] + public double ElementBResistance { get; set; } + + [Export] + public double ElementCResistance { get; set; } + } +} diff --git a/src/enemy/EnemyStats.cs b/src/enemy/EnemyStats.cs deleted file mode 100644 index 43be298b..00000000 --- a/src/enemy/EnemyStats.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Godot; - -namespace GameJamDungeon -{ - [GlobalClass] - public partial class EnemyStats : Resource - { - [Export(PropertyHint.Range, "0, 100, 1")] - public int MaximumHP = 1; - - [Export] - public string Name = string.Empty; - } -} diff --git a/src/enemy/enemy_types/FloatingEnemy.tres b/src/enemy/enemy_types/FloatingEnemy.tres deleted file mode 100644 index 3fd65718..00000000 --- a/src/enemy/enemy_types/FloatingEnemy.tres +++ /dev/null @@ -1,8 +0,0 @@ -[gd_resource type="Resource" script_class="EnemyStats" load_steps=2 format=3 uid="uid://bcsyqy7rmbpbl"] - -[ext_resource type="Script" path="res://src/enemy/EnemyStats.cs" id="1_0ks7j"] - -[resource] -script = ExtResource("1_0ks7j") -MaximumHP = 12 -Name = "Floating Guy" diff --git a/src/enemy/enemy_types/DISSAPPEARING ENEMY.gltf b/src/enemy/enemy_types/floating_enemy/DISSAPPEARING ENEMY.gltf similarity index 100% rename from src/enemy/enemy_types/DISSAPPEARING ENEMY.gltf rename to src/enemy/enemy_types/floating_enemy/DISSAPPEARING ENEMY.gltf diff --git a/src/enemy/enemy_types/DISSAPPEARING ENEMY.gltf.import b/src/enemy/enemy_types/floating_enemy/DISSAPPEARING ENEMY.gltf.import similarity index 71% rename from src/enemy/enemy_types/DISSAPPEARING ENEMY.gltf.import rename to src/enemy/enemy_types/floating_enemy/DISSAPPEARING ENEMY.gltf.import index 91f4edd1..574e29bc 100644 --- a/src/enemy/enemy_types/DISSAPPEARING ENEMY.gltf.import +++ b/src/enemy/enemy_types/floating_enemy/DISSAPPEARING ENEMY.gltf.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://cli0nlukrd4dc" -path="res://.godot/imported/DISSAPPEARING ENEMY.gltf-86890683bfa8a9cc2bc15c917a019516.scn" +path="res://.godot/imported/DISSAPPEARING ENEMY.gltf-623f05c3c418a59abcec04651db9cb14.scn" [deps] -source_file="res://src/enemy/enemy_types/DISSAPPEARING ENEMY.gltf" -dest_files=["res://.godot/imported/DISSAPPEARING ENEMY.gltf-86890683bfa8a9cc2bc15c917a019516.scn"] +source_file="res://src/enemy/enemy_types/floating_enemy/DISSAPPEARING ENEMY.gltf" +dest_files=["res://.godot/imported/DISSAPPEARING ENEMY.gltf-623f05c3c418a59abcec04651db9cb14.scn"] [params] diff --git a/src/enemy/enemy_types/floating_enemy/FloatingEnemy.tres b/src/enemy/enemy_types/floating_enemy/FloatingEnemy.tres new file mode 100644 index 00000000..5a4bc9fe --- /dev/null +++ b/src/enemy/enemy_types/floating_enemy/FloatingEnemy.tres @@ -0,0 +1,12 @@ +[gd_resource type="Resource" script_class="EnemyStatInfo" load_steps=2 format=3 uid="uid://c8h26ip4ly18r"] + +[ext_resource type="Script" path="res://src/enemy/EnemyStatInfo.cs" id="1_oabqi"] + +[resource] +script = ExtResource("1_oabqi") +MaximumHP = 50.0 +BaseAttack = 2 +BaseDefense = 1 +ElementAResistance = 15.0 +ElementBResistance = -20.0 +ElementCResistance = 0.0 diff --git a/src/enemy/enemy_types/FloatingEnemy.tscn b/src/enemy/enemy_types/floating_enemy/FloatingEnemy.tscn similarity index 99% rename from src/enemy/enemy_types/FloatingEnemy.tscn rename to src/enemy/enemy_types/floating_enemy/FloatingEnemy.tscn index 6fd6e45c..952ad663 100644 --- a/src/enemy/enemy_types/FloatingEnemy.tscn +++ b/src/enemy/enemy_types/floating_enemy/FloatingEnemy.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=9 format=4 uid="uid://dcgj5i52i76gj"] -[ext_resource type="Script" path="res://src/enemy/Enemy.cs" id="1_4d86o"] -[ext_resource type="Resource" uid="uid://bcsyqy7rmbpbl" path="res://src/enemy/enemy_types/FloatingEnemy.tres" id="2_q8v6p"] +[ext_resource type="Script" path="res://src/enemy/Enemy.cs" id="1_jw471"] +[ext_resource type="Resource" uid="uid://c8h26ip4ly18r" path="res://src/enemy/enemy_types/floating_enemy/FloatingEnemy.tres" id="2_ewaf6"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_5tio6"] resource_name = "Material.001" @@ -109,8 +109,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) collision_layer = 10 collision_mask = 9 motion_mode = 1 -script = ExtResource("1_4d86o") -EnemyStats = ExtResource("2_q8v6p") +script = ExtResource("1_jw471") +EnemyStatInfo = ExtResource("2_ewaf6") [node name="DISSAPPEARING ENEMY" type="Node3D" parent="."] diff --git a/src/enemy/state/EnemyLogic.Input.cs b/src/enemy/state/EnemyLogic.Input.cs index 2b473f13..d5feb16f 100644 --- a/src/enemy/state/EnemyLogic.Input.cs +++ b/src/enemy/state/EnemyLogic.Input.cs @@ -10,7 +10,9 @@ public readonly record struct PhysicsTick(double Delta); - public readonly record struct HitByPlayer(int Damage); + public readonly record struct HitByPlayer(double Damage); + + public readonly record struct Killed(); } } } diff --git a/src/enemy/state/EnemyLogic.Output.cs b/src/enemy/state/EnemyLogic.Output.cs index ba117a90..e52b7b5a 100644 --- a/src/enemy/state/EnemyLogic.Output.cs +++ b/src/enemy/state/EnemyLogic.Output.cs @@ -10,7 +10,7 @@ namespace GameJamDungeon public readonly record struct MovementComputed(Vector3 Velocity); - public readonly record struct HitByPlayer(int CurrentHP); + public readonly record struct HitByPlayer(double CurrentHP); public readonly record struct Die(); } diff --git a/src/enemy/state/states/EnemyLogic.State.Alive.cs b/src/enemy/state/states/EnemyLogic.State.Alive.cs index 44c94ff3..17995370 100644 --- a/src/enemy/state/states/EnemyLogic.State.Alive.cs +++ b/src/enemy/state/states/EnemyLogic.State.Alive.cs @@ -8,23 +8,25 @@ namespace GameJamDungeon public partial record State { [Meta, Id("enemy_logic_state_alive")] - public abstract partial record Alive : State, IGet + public abstract partial record Alive : State, IGet, IGet { public Transition On(in Input.HitByPlayer input) { var enemy = Get(); - var gameRepo = Get(); - enemy.CurrentHP -= input.Damage; - GD.Print("Current HP: " + enemy.CurrentHP); - GD.Print($"Hit by {gameRepo.EquippedWeapon.Name}"); + enemy.CurrentHP.OnNext(enemy.CurrentHP.Value - input.Damage); + GD.Print("Current HP: " + enemy.CurrentHP.Value); Output(new Output.HitByPlayer()); - if (enemy.CurrentHP <= 0) - Output(new Output.Die()); Input(new Input.Alerted()); return ToSelf(); } + + public Transition On(in Input.Killed input) + { + Output(new Output.Die()); + return To(); + } } } } diff --git a/src/game/Game.tscn b/src/game/Game.tscn index 308a012f..225c74e5 100644 --- a/src/game/Game.tscn +++ b/src/game/Game.tscn @@ -1,12 +1,14 @@ -[gd_scene load_steps=12 format=3 uid="uid://33ek675mfb5n"] +[gd_scene load_steps=14 format=3 uid="uid://33ek675mfb5n"] [ext_resource type="Script" path="res://src/game/Game.cs" id="1_ytcii"] -[ext_resource type="PackedScene" uid="uid://wg25dg65ksgg" path="res://src/map/dungeon/DungeonGenerator.tscn" id="2_cgboj"] [ext_resource type="PackedScene" uid="uid://cfecvvav8kkp6" path="res://src/player/Player.tscn" id="3_kk6ly"] -[ext_resource type="PackedScene" uid="uid://dhpwwqow1ahrc" path="res://src/map/dungeon/rooms/Room1.tscn" id="4_56rmd"] -[ext_resource type="PackedScene" uid="uid://bbwgmqy3evhh2" path="res://src/map/dungeon/rooms/Room2.tscn" id="4_clpvl"] [ext_resource type="PackedScene" uid="uid://dlj8qdg1c5048" path="res://src/inventory_menu/InventoryMenu.tscn" id="4_wk8gw"] +[ext_resource type="Script" path="res://addons/SimpleDungeons/DungeonGenerator3D.gd" id="5_fqkhg"] +[ext_resource type="PackedScene" uid="uid://dhpwwqow1ahrc" path="res://src/map/dungeon/rooms/Room1.tscn" id="6_04w8n"] [ext_resource type="PackedScene" uid="uid://bwbofurcvf3yh" path="res://src/minimap/Minimap.tscn" id="6_owlf4"] +[ext_resource type="PackedScene" uid="uid://bn4gslp2gk8ds" path="res://src/map/dungeon/corridor/Corridor.tscn" id="6_swtay"] +[ext_resource type="PackedScene" uid="uid://bbwgmqy3evhh2" path="res://src/map/dungeon/rooms/Room2.tscn" id="7_1ynbc"] +[ext_resource type="Script" path="res://addons/SimpleDungeons/DungeonRoom3D.gd" id="9_p0lbc"] [sub_resource type="Environment" id="Environment_fke5g"] @@ -57,8 +59,100 @@ omni_attenuation = -0.183 unique_name_in_owner = true navigation_mesh = SubResource("NavigationMesh_xligp") -[node name="DungeonGenerator3D" parent="NavigationRegion" instance=ExtResource("2_cgboj")] -room_scenes = Array[PackedScene]([ExtResource("4_56rmd"), ExtResource("4_clpvl")]) -corridor_cost_multiplier = 1.0 -room_cost_multiplier = 8.0 -room_cost_at_end_for_required_doors = 1.0 +[node name="DungeonGenerator3D" type="Node3D" parent="."] +script = ExtResource("5_fqkhg") +room_scenes = Array[PackedScene]([ExtResource("6_04w8n"), ExtResource("7_1ynbc")]) +corridor_room_scene = ExtResource("6_swtay") +dungeon_size = Vector3i(10, 1, 10) + +[node name="RoomsContainer" type="Node3D" parent="DungeonGenerator3D"] + +[node name="DungeonRoom3D_0" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("7_1ynbc")] +transform = Transform3D(1.19249e-08, 0, -1, 0, 1, 0, 1, 0, 1.19249e-08, -15, 0, 15) +script = ExtResource("9_p0lbc") +size_in_voxels = Vector3i(5, 1, 1) + +[node name="DungeonRoom3D_1" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_04w8n")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0, -35) +script = ExtResource("9_p0lbc") + +[node name="DungeonRoom3D_2" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_04w8n")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 25, 0, -45) +script = ExtResource("9_p0lbc") + +[node name="DungeonRoom3D_3" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("7_1ynbc")] +transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 15, 0, -25) +script = ExtResource("9_p0lbc") +size_in_voxels = Vector3i(5, 1, 1) + +[node name="Corridor_4" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0, -15) +script = ExtResource("9_p0lbc") + +[node name="Corridor_5" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0, -25) +script = ExtResource("9_p0lbc") + +[node name="Corridor_6" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0, -45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_7" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 0, -45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_8" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, -45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_9" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 0, -45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_10" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0, 45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_11" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, 45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_12" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, 35) +script = ExtResource("9_p0lbc") + +[node name="Corridor_13" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, 25) +script = ExtResource("9_p0lbc") + +[node name="Corridor_14" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, 15) +script = ExtResource("9_p0lbc") + +[node name="Corridor_15" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, 5) +script = ExtResource("9_p0lbc") + +[node name="Corridor_16" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, -5) +script = ExtResource("9_p0lbc") + +[node name="Corridor_17" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0, -15) +script = ExtResource("9_p0lbc") + +[node name="Corridor_18" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 35, 0, -45) +script = ExtResource("9_p0lbc") + +[node name="Corridor_19" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 35, 0, -35) +script = ExtResource("9_p0lbc") + +[node name="Corridor_20" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 45, 0, -35) +script = ExtResource("9_p0lbc") + +[node name="Corridor_21" type="Node3D" parent="DungeonGenerator3D/RoomsContainer" instance=ExtResource("6_swtay")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 45, 0, -25) +script = ExtResource("9_p0lbc") diff --git a/src/map/dungeon/rooms/Room1.tscn b/src/map/dungeon/rooms/Room1.tscn index 056e21ed..d27b9a0a 100644 --- a/src/map/dungeon/rooms/Room1.tscn +++ b/src/map/dungeon/rooms/Room1.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=19 format=3 uid="uid://dhpwwqow1ahrc"] +[gd_scene load_steps=17 format=3 uid="uid://dhpwwqow1ahrc"] [ext_resource type="Script" path="res://addons/SimpleDungeons/DungeonRoom3D.gd" id="1_0tfda"] [ext_resource type="Script" path="res://src/map/dungeon/rooms/DungeonRoom.cs" id="1_ti7ur"] @@ -6,10 +6,8 @@ [ext_resource type="PackedScene" uid="uid://twrj4wixcbu7" path="res://src/items/ItemDatabase.tscn" id="4_2mnb7"] [ext_resource type="PackedScene" uid="uid://b6atdgf2e6e2t" path="res://src/items/weapons/models/CommonSword.tscn" id="4_chdi8"] [ext_resource type="PackedScene" uid="uid://dbvr8ewajja6a" path="res://src/enemy/EnemyDatabase.tscn" id="5_owpbq"] -[ext_resource type="PackedScene" uid="uid://dcgj5i52i76gj" path="res://src/enemy/enemy_types/FloatingEnemy.tscn" id="5_urvkv"] [ext_resource type="PackedScene" uid="uid://cbb1fxllrnlyr" path="res://src/items/weapons/models/UncommonSword.tscn" id="5_viqv4"] [ext_resource type="PackedScene" uid="uid://c10nhqq8su6pp" path="res://src/items/weapons/models/RareSword.tscn" id="6_c8gn4"] -[ext_resource type="PackedScene" uid="uid://u1vmmakcoplh" path="res://src/enemy/enemy_types/Capricorn/Capricorn.tscn" id="6_hp0mx"] [ext_resource type="PackedScene" uid="uid://dorr7v1tkeiy0" path="res://src/items/armor/Armor.tscn" id="7_bm50w"] [sub_resource type="PlaneMesh" id="PlaneMesh_luhnj"] @@ -71,8 +69,6 @@ DropRate = PackedFloat32Array(0.25, 0.25, 0.25, 0.25) [node name="EnemyDatabase" parent="." instance=ExtResource("5_owpbq")] unique_name_in_owner = true -EnemyList = Array[PackedScene]([ExtResource("5_urvkv"), ExtResource("6_hp0mx")]) -SpawnRate = PackedFloat32Array(0.1, 0.9) [node name="CSGBox3D" type="CSGBox3D" parent="."] use_collision = true diff --git a/src/player/Player.cs b/src/player/Player.cs index 0fa83e8d..8dc5a2ab 100644 --- a/src/player/Player.cs +++ b/src/player/Player.cs @@ -11,6 +11,8 @@ namespace GameJamDungeon { public interface IPlayer : ICharacterBody3D { + PlayerStatInfo PlayerStatInfo { get; } + PlayerLogic PlayerLogic { get; } PlayerData PlayerData { get; } @@ -46,6 +48,9 @@ namespace GameJamDungeon [Export(PropertyHint.Range, "0, 100, 0.1")] public float Acceleration { get; set; } = 4f; + [Export] + public PlayerStatInfo PlayerStatInfo { get; set; } + public PlayerLogic.Settings Settings { get; set; } = default!; public PlayerLogic PlayerLogic { get; set; } = default!; @@ -62,6 +67,10 @@ namespace GameJamDungeon private IAutoProp EquippedWeapon { get; set; } = default!; + private AutoProp _currentHP { get; set; } = default!; + + private IAutoProp _currentVT { get; set; } = default!; + public void Initialize() { AnimationPlayer.AnimationFinished += OnAnimationFinished; @@ -69,9 +78,7 @@ namespace GameJamDungeon public void Setup() { - Settings = new PlayerLogic.Settings( - RotationSpeed, - MoveSpeed); + Settings = new PlayerLogic.Settings(RotationSpeed, MoveSpeed); PlayerLogic = new PlayerLogic(); PlayerLogic.Set(this as IPlayer); @@ -82,6 +89,8 @@ namespace GameJamDungeon GameRepo.SetPlayerGlobalPosition(GlobalPosition); EquippedWeapon = new AutoProp(WeaponInfo.Default); + _currentHP = new AutoProp(PlayerStatInfo.MaximumHP); + _currentVT = new AutoProp(PlayerStatInfo.MaximumVT); GameRepo.PlayerGlobalPosition.Sync += OnPlayerPositionUpdated; } @@ -108,6 +117,7 @@ namespace GameJamDungeon PlayerLogic.Start(); EquippedWeapon.Sync += OnEquippedWeaponChanged; + _currentHP.Sync += OnHPChanged; SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2; } @@ -166,6 +176,12 @@ namespace GameJamDungeon private void OnEquippedWeaponChanged(WeaponInfo info) => Hitbox.Damage = info.Damage; + private void OnHPChanged(double newHP) + { + if (newHP <= 0.0) + PlayerLogic.Input(new PlayerLogic.Input.Killed()); + } + private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition; } } diff --git a/src/player/Player.tscn b/src/player/Player.tscn index 9c74632a..ffbd029f 100644 --- a/src/player/Player.tscn +++ b/src/player/Player.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=16 format=3 uid="uid://cfecvvav8kkp6"] +[gd_scene load_steps=17 format=3 uid="uid://cfecvvav8kkp6"] [ext_resource type="Script" path="res://src/player/Player.cs" id="1_xcol5"] [ext_resource type="Texture2D" uid="uid://bokx3h8kfdo5i" path="res://src/player/slash_0000_Classic_30.png" id="2_la11l"] [ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="2_lb3qc"] +[ext_resource type="Resource" uid="uid://cofd1ylluj24" path="res://src/player/PlayerStats.tres" id="2_nuh2a"] [ext_resource type="Texture2D" uid="uid://byosr5gk51237" path="res://src/player/slash_0001_Classic_29.png" id="3_ux3f1"] [ext_resource type="Texture2D" uid="uid://nh071o6ii03j" path="res://src/player/slash_0002_Classic_28.png" id="4_gqnq0"] [ext_resource type="Texture2D" uid="uid://bodfblud4kea3" path="res://src/player/slash_0003_Classic_27.png" id="5_eebal"] @@ -117,6 +118,7 @@ axis_lock_angular_z = true motion_mode = 1 script = ExtResource("1_xcol5") RotationSpeed = 0.025 +PlayerStatInfo = ExtResource("2_nuh2a") [node name="CollisionShape3D" type="CollisionShape3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.937567, 0) diff --git a/src/player/PlayerData.cs b/src/player/PlayerData.cs index 5bcb1a9e..6761e8a4 100644 --- a/src/player/PlayerData.cs +++ b/src/player/PlayerData.cs @@ -18,5 +18,14 @@ namespace GameJamDungeon [Save("PlayerInventory")] public required IEnumerable Inventory { get; set; } + + [Save("PlayerStats")] + public required PlayerStatInfo PlayerStats { get; set; } + + [Save("CurrentHP")] + public required int CurrentHP { get; set; } + + [Save("CurrentVT")] + public required int CurrentVT { get; set; } } } diff --git a/src/player/PlayerStatInfo.cs b/src/player/PlayerStatInfo.cs new file mode 100644 index 00000000..03a7b6f5 --- /dev/null +++ b/src/player/PlayerStatInfo.cs @@ -0,0 +1,38 @@ +using Godot; + +namespace GameJamDungeon +{ + [GlobalClass] + public partial class PlayerStatInfo : Resource, ICharacterStats + { + [Export] + public double MaximumHP { get; set; } + + [Export] + public int MaximumVT { get; set; } + + [Export] + public int BaseAttack { get; set; } + + [Export] + public int BaseDefense { get; set; } + + [Export] + public double ElementAResistance { get; set; } + + [Export] + public double ElementBResistance { get; set; } + + [Export] + public double ElementCResistance { get; set; } + + [Export] + public double BaseElementADamageBonus { get; set; } + + [Export] + public double BaseElementBDamageBonus { get; set; } + + [Export] + public double BaseElementCDamageBonus { get; set; } + } +} diff --git a/src/player/PlayerStats.tres b/src/player/PlayerStats.tres new file mode 100644 index 00000000..87498a3b --- /dev/null +++ b/src/player/PlayerStats.tres @@ -0,0 +1,16 @@ +[gd_resource type="Resource" script_class="PlayerStatInfo" load_steps=2 format=3 uid="uid://cofd1ylluj24"] + +[ext_resource type="Script" path="res://src/player/PlayerStatInfo.cs" id="1_a84hi"] + +[resource] +script = ExtResource("1_a84hi") +MaximumHP = 120.0 +MaximumVT = 90 +BaseAttack = 10 +BaseDefense = 0 +ElementAResistance = 0.0 +ElementBResistance = 0.0 +ElementCResistance = 15.0 +BaseElementADamageBonus = 30.0 +BaseElementBDamageBonus = 15.0 +BaseElementCDamageBonus = 20.0 diff --git a/src/player/state/PlayerLogic.Input.cs b/src/player/state/PlayerLogic.Input.cs index f003f6a9..8a1b2f5f 100644 --- a/src/player/state/PlayerLogic.Input.cs +++ b/src/player/state/PlayerLogic.Input.cs @@ -15,6 +15,8 @@ namespace GameJamDungeon public readonly record struct Attack; public readonly record struct AttackAnimationFinished; + + public readonly record struct Killed; } } } diff --git a/src/player/state/states/PlayerLogic.State.Alive.cs b/src/player/state/states/PlayerLogic.State.Alive.cs index 7cf0a732..4a721c1d 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.cs @@ -8,7 +8,7 @@ namespace GameJamDungeon public partial record State { [Meta, Id("player_logic_alive")] - public abstract partial record Alive : State, IGet, IGet + public abstract partial record Alive : State, IGet, IGet, IGet { public virtual Transition On(in Input.PhysicsTick input) { @@ -36,9 +36,14 @@ namespace GameJamDungeon { var gameRepo = Get(); gameRepo.SetPlayerGlobalPosition(input.GlobalPosition); - GD.Print($"Current position: {input.GlobalPosition}"); return ToSelf(); } + + public Transition On(in Input.Killed input) + { + GD.Print("Player died"); + return To(); + } } } } diff --git a/src/system/stats/DamageCalculator.cs b/src/system/stats/DamageCalculator.cs new file mode 100644 index 00000000..eb8fee88 --- /dev/null +++ b/src/system/stats/DamageCalculator.cs @@ -0,0 +1,18 @@ +using Godot; + +namespace GameJamDungeon +{ + public static class DamageCalculator + { + public static double CalculatePlayerDamage(int attackDamage, PlayerStatInfo playerStatInfo, EnemyStatInfo enemyStatInfo) + { + var baseDamage = attackDamage + playerStatInfo.BaseAttack; + var elementADamage = (playerStatInfo.BaseElementADamageBonus > 0 ? playerStatInfo.BaseElementADamageBonus - enemyStatInfo.ElementAResistance : 0) / 100; + var elementBDamage = (playerStatInfo.BaseElementBDamageBonus > 0 ? playerStatInfo.BaseElementBDamageBonus - enemyStatInfo.ElementBResistance : 0) / 100; + var elementCDamage = (playerStatInfo.BaseElementCDamageBonus > 0 ? playerStatInfo.BaseElementCDamageBonus - enemyStatInfo.ElementCResistance : 0) / 100; + var elementalBonusDamage = baseDamage + (baseDamage * elementADamage) + (baseDamage * elementBDamage) + (baseDamage * elementCDamage); + var calculatedDamage = elementalBonusDamage - enemyStatInfo.BaseDefense; + return calculatedDamage; + } + } +} diff --git a/src/system/stats/ICharacterStats.cs b/src/system/stats/ICharacterStats.cs new file mode 100644 index 00000000..14e6359f --- /dev/null +++ b/src/system/stats/ICharacterStats.cs @@ -0,0 +1,17 @@ +namespace GameJamDungeon +{ + public interface ICharacterStats + { + public double MaximumHP { get; } + + public int BaseAttack { get; } + + public int BaseDefense { get; } + + public double ElementAResistance { get; } + + public double ElementBResistance { get; } + + public double ElementCResistance { get; } + } +}