diff --git a/forge/abilities/ForgeSimpleHitBehavior.cs b/forge/abilities/ForgeSimpleHitBehavior.cs new file mode 100644 index 00000000..66b6d947 --- /dev/null +++ b/forge/abilities/ForgeSimpleHitBehavior.cs @@ -0,0 +1,31 @@ +using Gamesmiths.Forge.Abilities; +using Gamesmiths.Forge.Effects; +using Gamesmiths.Forge.Godot.Resources; +using Gamesmiths.Forge.Godot.Resources.Abilities; +using Godot; + +namespace Movementtests.forge.abilities; + +public class SimpleHitBehavior(ForgeEffectData? damage) : IAbilityBehavior +{ + public void OnStarted(AbilityBehaviorContext context) + { + if (context.Target == null || damage == null) return; + + var effect = new Effect(damage.GetEffectData(), new EffectOwnership(context.Owner, context.Target)); + context.Target.EffectsManager.ApplyEffect(effect); + + context.AbilityHandle.CommitAbility(); + context.InstanceHandle.End(); + } + + public void OnEnded(AbilityBehaviorContext context) {} +} + +[Tool] +[GlobalClass] +public partial class ForgeSimpleHitBehavior : ForgeAbilityBehavior +{ + [Export] public ForgeEffectData? DamageEffect { get; set; } + public override IAbilityBehavior GetBehavior() => new SimpleHitBehavior(DamageEffect); +} \ No newline at end of file diff --git a/forge/abilities/ForgeSimpleHitBehavior.cs.uid b/forge/abilities/ForgeSimpleHitBehavior.cs.uid new file mode 100644 index 00000000..17c78799 --- /dev/null +++ b/forge/abilities/ForgeSimpleHitBehavior.cs.uid @@ -0,0 +1 @@ +uid://n6efm5o4uxvr diff --git a/forge/attribute_sets/PlayerAttributeSet.cs b/forge/attribute_sets/PlayerAttributeSet.cs index 13b0548d..4a404506 100644 --- a/forge/attribute_sets/PlayerAttributeSet.cs +++ b/forge/attribute_sets/PlayerAttributeSet.cs @@ -11,7 +11,7 @@ public class PlayerAttributeSet : AttributeSet public PlayerAttributeSet() { - Health = InitializeAttribute(nameof(Health), 100, 0, 150); + Health = InitializeAttribute(nameof(Health), 100, 0, 100); Mana = InitializeAttribute(nameof(Mana), 100, 0, 100); Strength = InitializeAttribute(nameof(Strength), 10, 0, 99); Speed = InitializeAttribute(nameof(Speed), 5, 0, 10); diff --git a/forge/calculators/ForgeRaiseEventTagExecution.cs b/forge/calculators/ForgeRaiseEventTagExecution.cs index a1674ed3..008cc624 100644 --- a/forge/calculators/ForgeRaiseEventTagExecution.cs +++ b/forge/calculators/ForgeRaiseEventTagExecution.cs @@ -16,19 +16,33 @@ using Movementtests.systems; namespace Movementtests.tools.calculators; -public class RaiseEventTagExecution(TagContainer eventTags) : CustomExecution +public class RaiseEventTagExecution(TagContainer? ownerEventTags, TagContainer? targetEventTags) : CustomExecution { public override ModifierEvaluatedData[] EvaluateExecution(Effect effect, IForgeEntity target, EffectEvaluatedData? effectEvaluatedData) { var owner = effect.Ownership.Owner; - if (owner == null) return []; - - owner.Events.Raise(new EventData + var magnitude = effectEvaluatedData is { ModifiersEvaluatedData.Length: > 0 } + ? effectEvaluatedData.ModifiersEvaluatedData[0].Magnitude + : 0f; + if (owner != null && ownerEventTags != null) { - EventTags = eventTags, - Source = owner, - EventMagnitude = 12f - }); + owner.Events.Raise(new EventData + { + EventTags = ownerEventTags, + Source = owner, + EventMagnitude = magnitude + }); + } + + if (targetEventTags != null) + { + target.Events.Raise(new EventData + { + EventTags = targetEventTags, + Source = owner, + EventMagnitude = magnitude + }); + } return []; } @@ -39,10 +53,11 @@ public class RaiseEventTagExecution(TagContainer eventTags) : CustomExecution [GlobalClass] public partial class ForgeRaiseEventTagExecution : ForgeCustomExecution { - [Export] ForgeTagContainer EventTags { get; set; } + [Export] ForgeTagContainer? EventTags { get; set; } + [Export] ForgeTagContainer? TargetEventTags { get; set; } public override CustomExecution GetExecutionClass() { - return new RaiseEventTagExecution(EventTags.GetTagContainer()); + return new RaiseEventTagExecution(EventTags?.GetTagContainer(), TargetEventTags?.GetTagContainer()); } } \ No newline at end of file diff --git a/forge/forge_data.tres b/forge/forge_data.tres index 9b9ba880..7542c355 100644 --- a/forge/forge_data.tres +++ b/forge/forge_data.tres @@ -4,4 +4,4 @@ [resource] script = ExtResource("1_l686n") -RegisteredTags = Array[String](["character.player", "character.enemy", "weapon", "status.stunned", "status.burning", "status.frozen", "abilities.weapon.land", "abilities.weapon.flying", "abilities.weapon.left", "events.combat.damage", "events.combat.hit", "events.weapon.flyingTick", "events.weapon.startedFlying", "events.weapon.stoppedFlying", "events.weapon.handToFlying", "events.weapon.flyingToHand", "events.weapon.plantedToHand", "events.weapon.plantedToFlying", "events.weapon.planted", "cooldown.empoweredAction", "cooldown.empoweredSwordThrow", "cues.resources.mana", "events.player.empowered_action_used", "cues.resources.mana.inhibited"]) +RegisteredTags = Array[String](["character.player", "character.enemy", "weapon", "status.stunned", "status.burning", "status.frozen", "abilities.weapon.land", "abilities.weapon.flying", "abilities.weapon.left", "events.combat.damage", "events.combat.hit", "events.weapon.flyingTick", "events.weapon.startedFlying", "events.weapon.stoppedFlying", "events.weapon.handToFlying", "events.weapon.flyingToHand", "events.weapon.plantedToHand", "events.weapon.plantedToFlying", "events.weapon.planted", "cooldown.empoweredAction", "cooldown.empoweredSwordThrow", "cues.resources.mana", "events.player.empowered_action_used", "cues.resources.mana.inhibited", "cues.resources.health", "cooldown.enemy.hit", "status.invincible", "events.combat.death"]) diff --git a/forge/resources/ability_datas/on_hit_invinciblity.tres b/forge/resources/ability_datas/on_hit_invinciblity.tres new file mode 100644 index 00000000..edda6dd2 --- /dev/null +++ b/forge/resources/ability_datas/on_hit_invinciblity.tres @@ -0,0 +1,100 @@ +[gd_resource type="Resource" script_class="ForgeAbilityData" format=3 uid="uid://b0ikxp5j8fn3n"] + +[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_xjqwu"] +[ext_resource type="Script" uid="uid://dngf30hxy5go4" path="res://addons/forge/resources/components/ModifierTags.cs" id="2_a16tf"] +[ext_resource type="Script" uid="uid://cn3b4ya15fg7e" path="res://addons/forge/resources/magnitudes/ForgeScalableFloat.cs" id="3_1wliv"] +[ext_resource type="Script" uid="uid://2gm1hdhi8u08" path="res://addons/forge/resources/magnitudes/ForgeModifierMagnitude.cs" id="4_7dtdc"] +[ext_resource type="Script" uid="uid://1hgogislo1l6" path="res://addons/forge/resources/magnitudes/ForgeScalableInt.cs" id="5_ewbg3"] +[ext_resource type="Script" uid="uid://b83hf13nj37k3" path="res://addons/forge/resources/ForgeEffectData.cs" id="6_0akms"] +[ext_resource type="Script" uid="uid://cl5hudinl1rex" path="res://forge/abilities/ForgeEffectApplicationBehavior.cs" id="7_mhqpo"] +[ext_resource type="Script" uid="uid://dpakv7agvir6y" path="res://addons/forge/resources/ForgeTag.cs" id="8_4vjp3"] +[ext_resource type="Script" uid="uid://dhxfbxh54pyxp" path="res://addons/forge/resources/abilities/ForgeAbilityData.cs" id="9_go27d"] + +[sub_resource type="Resource" id="Resource_87uc3"] +script = ExtResource("1_xjqwu") +ContainerTags = Array[String](["status.invincible"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" + +[sub_resource type="Resource" id="Resource_5ht6k"] +script = ExtResource("2_a16tf") +TagsToAdd = SubResource("Resource_87uc3") +metadata/_custom_type_script = "uid://dngf30hxy5go4" + +[sub_resource type="Resource" id="Resource_bn2qi"] +script = ExtResource("3_1wliv") +BaseValue = 1.0 + +[sub_resource type="Resource" id="Resource_pl2a2"] +script = ExtResource("3_1wliv") + +[sub_resource type="Resource" id="Resource_g02pf"] +script = ExtResource("3_1wliv") + +[sub_resource type="Resource" id="Resource_7ak88"] +script = ExtResource("3_1wliv") +BaseValue = 1.0 + +[sub_resource type="Resource" id="Resource_f12ll"] +script = ExtResource("3_1wliv") + +[sub_resource type="Resource" id="Resource_xodo6"] +script = ExtResource("3_1wliv") + +[sub_resource type="Resource" id="Resource_mcqfd"] +script = ExtResource("3_1wliv") +BaseValue = 2.0 +metadata/_custom_type_script = "uid://cn3b4ya15fg7e" + +[sub_resource type="Resource" id="Resource_w3q2i"] +script = ExtResource("4_7dtdc") +ScalableFloat = SubResource("Resource_mcqfd") +Coefficient = SubResource("Resource_7ak88") +PreMultiplyAdditiveValue = SubResource("Resource_xodo6") +PostMultiplyAdditiveValue = SubResource("Resource_f12ll") +CalculatorCoefficient = SubResource("Resource_bn2qi") +CalculatorPreMultiplyAdditiveValue = SubResource("Resource_g02pf") +CalculatorPostMultiplyAdditiveValue = SubResource("Resource_pl2a2") +metadata/_custom_type_script = "uid://2gm1hdhi8u08" + +[sub_resource type="Resource" id="Resource_vgvi5"] +script = ExtResource("5_ewbg3") +BaseValue = 1 + +[sub_resource type="Resource" id="Resource_0ujop"] +script = ExtResource("5_ewbg3") +BaseValue = 1 + +[sub_resource type="Resource" id="Resource_s8mqp"] +script = ExtResource("6_0akms") +Name = "Add Invincible tag effect" +Modifiers = Array[Object]([]) +Components = Array[Object]([SubResource("Resource_5ht6k")]) +Executions = [] +DurationType = 2 +Duration = SubResource("Resource_w3q2i") +StackLimit = SubResource("Resource_0ujop") +InitialStack = SubResource("Resource_vgvi5") +Cues = [] +metadata/_custom_type_script = "uid://b83hf13nj37k3" + +[sub_resource type="Resource" id="Resource_tcrdt"] +script = ExtResource("7_mhqpo") +EffectData = SubResource("Resource_s8mqp") +Name = "OnHitInvincibility" +Description = "Adds the invincible tag for a given period" +metadata/_custom_type_script = "uid://cl5hudinl1rex" + +[sub_resource type="Resource" id="Resource_xs7wf"] +script = ExtResource("8_4vjp3") +Tag = "events.combat.damage" +metadata/_custom_type_script = "uid://dpakv7agvir6y" + +[resource] +script = ExtResource("9_go27d") +Name = "OnHitInvincibility" +InstancingPolicy = 1 +CooldownEffects = [] +AbilityBehavior = SubResource("Resource_tcrdt") +TriggerSource = 1 +TriggerTag = SubResource("Resource_xs7wf") +metadata/_custom_type_script = "uid://dhxfbxh54pyxp" diff --git a/forge/resources/cues/player_health_changed_cue.tres b/forge/resources/cues/player_health_changed_cue.tres new file mode 100644 index 00000000..c907c4ea --- /dev/null +++ b/forge/resources/cues/player_health_changed_cue.tres @@ -0,0 +1,17 @@ +[gd_resource type="Resource" script_class="ForgeCue" format=3 uid="uid://bsqvfefpb7jix"] + +[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_tvgrb"] +[ext_resource type="Script" uid="uid://cmrsxccn0ei4j" path="res://addons/forge/resources/ForgeCue.cs" id="2_dyb6j"] + +[sub_resource type="Resource" id="Resource_f35o6"] +script = ExtResource("1_tvgrb") +ContainerTags = Array[String](["cues.resources.health"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" + +[resource] +script = ExtResource("2_dyb6j") +CueKeys = SubResource("Resource_f35o6") +MaxValue = 100 +MagnitudeType = 2 +MagnitudeAttribute = "PlayerAttributeSet.Health" +metadata/_custom_type_script = "uid://cmrsxccn0ei4j" diff --git a/forge/resources/cues/player_mana_changed_cue.tres b/forge/resources/cues/player_mana_changed_cue.tres index 5b70830a..2d28e5de 100644 --- a/forge/resources/cues/player_mana_changed_cue.tres +++ b/forge/resources/cues/player_mana_changed_cue.tres @@ -1,15 +1,15 @@ [gd_resource type="Resource" script_class="ForgeCue" format=3 uid="uid://dn7b8frkoxpxr"] -[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_lbula"] -[ext_resource type="Script" uid="uid://cmrsxccn0ei4j" path="res://addons/forge/resources/ForgeCue.cs" id="2_jijlk"] +[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_0pc1u"] +[ext_resource type="Script" uid="uid://cmrsxccn0ei4j" path="res://addons/forge/resources/ForgeCue.cs" id="2_g0vcr"] [sub_resource type="Resource" id="Resource_4mhqs"] -script = ExtResource("1_lbula") +script = ExtResource("1_0pc1u") ContainerTags = Array[String](["cues.resources.mana"]) metadata/_custom_type_script = "uid://cw525n4mjqgw0" [resource] -script = ExtResource("2_jijlk") +script = ExtResource("2_g0vcr") CueKeys = SubResource("Resource_4mhqs") MaxValue = 100 MagnitudeType = 2 diff --git a/forge/resources/effect_datas/mana_regeneration.tres b/forge/resources/effect_datas/mana_regeneration.tres index 2f617aeb..e03895ba 100644 --- a/forge/resources/effect_datas/mana_regeneration.tres +++ b/forge/resources/effect_datas/mana_regeneration.tres @@ -1,54 +1,54 @@ [gd_resource type="Resource" script_class="ForgeEffectData" format=3 uid="uid://dh437cuxgjv6b"] -[ext_resource type="Script" uid="uid://1hgogislo1l6" path="res://addons/forge/resources/magnitudes/ForgeScalableInt.cs" id="1_mlifq"] -[ext_resource type="Resource" uid="uid://dn7b8frkoxpxr" path="res://forge/resources/cues/player_mana_changed_cue.tres" id="1_nsr3v"] -[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_q8tml"] -[ext_resource type="Script" uid="uid://b83hf13nj37k3" path="res://addons/forge/resources/ForgeEffectData.cs" id="2_5tp50"] -[ext_resource type="Script" uid="uid://cn3b4ya15fg7e" path="res://addons/forge/resources/magnitudes/ForgeScalableFloat.cs" id="2_pm3n3"] -[ext_resource type="Script" uid="uid://b0eq12mjqfage" path="res://addons/forge/resources/components/TargetTagRequirements.cs" id="2_xbgy2"] -[ext_resource type="Script" uid="uid://bdfcavbjyhxxa" path="res://addons/forge/resources/ForgeModifier.cs" id="3_nsr3v"] +[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_b244r"] +[ext_resource type="Script" uid="uid://b0eq12mjqfage" path="res://addons/forge/resources/components/TargetTagRequirements.cs" id="2_h46co"] +[ext_resource type="Resource" uid="uid://dn7b8frkoxpxr" path="res://forge/resources/cues/player_mana_changed_cue.tres" id="3_kw6jm"] +[ext_resource type="Script" uid="uid://1hgogislo1l6" path="res://addons/forge/resources/magnitudes/ForgeScalableInt.cs" id="4_fgmkc"] +[ext_resource type="Script" uid="uid://cn3b4ya15fg7e" path="res://addons/forge/resources/magnitudes/ForgeScalableFloat.cs" id="5_m4art"] +[ext_resource type="Script" uid="uid://bdfcavbjyhxxa" path="res://addons/forge/resources/ForgeModifier.cs" id="6_73cww"] +[ext_resource type="Script" uid="uid://b83hf13nj37k3" path="res://addons/forge/resources/ForgeEffectData.cs" id="7_xa46f"] [sub_resource type="Resource" id="Resource_5yygy"] -script = ExtResource("1_q8tml") +script = ExtResource("1_b244r") ContainerTags = Array[String](["character.player.mana.regen.inhibited", "cues.resources.mana.inhibited"]) metadata/_custom_type_script = "uid://cw525n4mjqgw0" [sub_resource type="Resource" id="Resource_ncjx6"] -script = ExtResource("2_xbgy2") +script = ExtResource("2_h46co") OngoingIgnoredTags = SubResource("Resource_5yygy") metadata/_custom_type_script = "uid://b0eq12mjqfage" [sub_resource type="Resource" id="Resource_pm3n3"] -script = ExtResource("1_mlifq") +script = ExtResource("4_fgmkc") BaseValue = 1 [sub_resource type="Resource" id="Resource_q8tml"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") BaseValue = 1.0 [sub_resource type="Resource" id="Resource_xbgy2"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") [sub_resource type="Resource" id="Resource_rhldn"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") [sub_resource type="Resource" id="Resource_p6h8c"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") BaseValue = 1.0 [sub_resource type="Resource" id="Resource_yqxv4"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") [sub_resource type="Resource" id="Resource_b6opn"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") [sub_resource type="Resource" id="Resource_5frso"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") BaseValue = 2.0 metadata/_custom_type_script = "uid://cn3b4ya15fg7e" [sub_resource type="Resource" id="Resource_okenf"] -script = ExtResource("3_nsr3v") +script = ExtResource("6_73cww") Attribute = "PlayerAttributeSet.Mana" ScalableFloat = SubResource("Resource_5frso") Coefficient = SubResource("Resource_p6h8c") @@ -60,16 +60,16 @@ CalculatorPostMultiplyAdditiveValue = SubResource("Resource_xbgy2") metadata/_custom_type_script = "uid://bdfcavbjyhxxa" [sub_resource type="Resource" id="Resource_w35mq"] -script = ExtResource("2_pm3n3") +script = ExtResource("5_m4art") BaseValue = 0.1 metadata/_custom_type_script = "uid://cn3b4ya15fg7e" [sub_resource type="Resource" id="Resource_nsr3v"] -script = ExtResource("1_mlifq") +script = ExtResource("4_fgmkc") BaseValue = 1 [resource] -script = ExtResource("2_5tp50") +script = ExtResource("7_xa46f") Name = "Mana Regeneration" Modifiers = Array[Object]([SubResource("Resource_okenf")]) Components = [SubResource("Resource_ncjx6")] @@ -79,5 +79,5 @@ HasPeriodicApplication = true Period = SubResource("Resource_w35mq") StackLimit = SubResource("Resource_nsr3v") InitialStack = SubResource("Resource_pm3n3") -Cues = Array[Object]([ExtResource("1_nsr3v")]) +Cues = Array[Object]([ExtResource("3_kw6jm")]) metadata/_custom_type_script = "uid://b83hf13nj37k3" diff --git a/forge/resources/tag_containers/status_invincible.tres b/forge/resources/tag_containers/status_invincible.tres new file mode 100644 index 00000000..2bace4d3 --- /dev/null +++ b/forge/resources/tag_containers/status_invincible.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="ForgeTagContainer" format=3 uid="uid://cw2ytd34jsxj"] + +[ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="1_vmvhu"] + +[resource] +script = ExtResource("1_vmvhu") +ContainerTags = Array[String](["status.invincible"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" diff --git a/menus/scenes/components/AbilitySelection.cs b/menus/scenes/components/AbilitySelection.cs index aae1e7ab..56c9854f 100644 --- a/menus/scenes/components/AbilitySelection.cs +++ b/menus/scenes/components/AbilitySelection.cs @@ -6,7 +6,7 @@ using Gamesmiths.Forge.Godot.Resources.Abilities; using Godot; using Movementtests.systems; -[Tool, GlobalClass, Meta(typeof(IAutoConnect))] +[Tool, GlobalClass, Meta(typeof(IAutoConnect), typeof(IAutoOn))] public partial class AbilitySelection : Control { public override void _Notification(int what) => this.Notify(what); diff --git a/menus/scenes/overlaid_menus/toolbox.gd b/menus/scenes/overlaid_menus/toolbox.gd index 95ca4a89..5d74feba 100644 --- a/menus/scenes/overlaid_menus/toolbox.gd +++ b/menus/scenes/overlaid_menus/toolbox.gd @@ -11,9 +11,7 @@ extends OverlaidMenu @onready var player_damage_spin_box: SpinBox = %PlayerDamageSpinBox func _ready() -> void: - player_invicible_toggle.button_pressed = player.IsInvincibleOverride - player_health_spin_box.value = player.RHealth.StartingHealth - player_damage_spin_box.value = player.RDamage.DamageDealt + player_invicible_toggle.button_pressed = player.IsInvincible func _on_kill_player_button_pressed() -> void: @@ -21,7 +19,7 @@ func _on_kill_player_button_pressed() -> void: close() func _on_player_invicible_toggled(toggled_on: bool) -> void: - player.IsInvincibleOverride = toggled_on + player.IsInvincible = toggled_on func _on_restart_current_level_pressed() -> void: @@ -38,8 +36,8 @@ func _on_level_selected() -> void: close() func _on_player_health_changed(value: float) -> void: - player.SetPlayerHealthOverride(value) + pass func _on_player_damage_changed(value: float) -> void: - player.SetPlayerDamageOverride(value) + pass diff --git a/scenes/components/health/CHealthbar.cs b/scenes/components/health/CHealthbar.cs index 03ce4bb1..a865bec6 100644 --- a/scenes/components/health/CHealthbar.cs +++ b/scenes/components/health/CHealthbar.cs @@ -1,14 +1,12 @@ using Godot; using System; +using Chickensoft.AutoInject; +using Chickensoft.Introspection; -[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_heart.png")] +[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_heart.png"), Meta(typeof(IAutoConnect))] public partial class CHealthbar : Sprite3D { - private Healthbar _healthbar; - public Healthbar Healthbar => _healthbar; - - public override void _Ready() - { - _healthbar = GetNode("%Healthbar"); - } + public override void _Notification(int what) => this.Notify(what); + + [Node("%Healthbar")] public required ResourceBar ResourceBar { get; set;} } diff --git a/scenes/enemies/Enemy.cs b/scenes/enemies/Enemy.cs index b98d9e42..70256e03 100644 --- a/scenes/enemies/Enemy.cs +++ b/scenes/enemies/Enemy.cs @@ -1,9 +1,13 @@ using System; +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Gamesmiths.Forge.Abilities; using Gamesmiths.Forge.Core; using Gamesmiths.Forge.Effects; using Gamesmiths.Forge.Events; using Gamesmiths.Forge.Godot.Core; using Gamesmiths.Forge.Godot.Nodes; +using Gamesmiths.Forge.Godot.Resources.Abilities; using Gamesmiths.Forge.Statescript; using Gamesmiths.Forge.Tags; using Godot; @@ -14,10 +18,9 @@ using Movementtests.systems; using Movementtests.tools; using Node = Godot.Node; -[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_beetle.png")] +[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_beetle.png"), Meta(typeof(IAutoOn), typeof(IAutoConnect))] public partial class Enemy : CharacterBody3D, IDamageable, - IDamageDealer, IHealthable, IKillable, IMoveable, @@ -27,14 +30,16 @@ public partial class Enemy : CharacterBody3D, IStunnable, IForgeEntity { - // Signals and events - public event Action DamageTaken = null!; + public override void _Notification(int what) => this.Notify(what); + + // Signals and events + public event Action DamageTaken = null!; public event Action HealthChanged = null!; public event Action HealthDepleted = null!; // Public export components [Export] - public Node3D Target { get; set; } = null!; + public Node3D? Target { get; set; } [Export] public float EnemyHeight { get; set; } = 1f; @@ -48,16 +53,16 @@ public partial class Enemy : CharacterBody3D, [ExportGroup("Damage")] [Export] - public RDamage RDamage { get; set; } = null!; + public RDamage? RDamage { get; set; } public IDamageable CDamageable { get; set; } = null!; [Export] - public RKnockback RKnockback { get; set; } = null!; + public RKnockback? RKnockback { get; set; } public IKnockbackable CKnockback { get; set; } = null!; [ExportGroup("Movement")] [Export] - public RMovement RMovement { get; set; } = null!; + public RMovement? RMovement { get; set; } public IMoveable CMovement { get; set; } = null!; // Public stuff @@ -93,13 +98,15 @@ public partial class Enemy : CharacterBody3D, get => _forgeEntity.Events; set => _forgeEntity.Events = value; } + + [Export] public ForgeAbilityData? HitAbility; public Variables SharedVariables { get; } // Private stuff private Area3D _damageBox = null!; internal Node3D _target = null!; - private Healthbar _healthbar = null!; + private ResourceBar _resourceBar = null!; private ForgeEntity _forgeEntity; public override void _Ready() @@ -107,6 +114,8 @@ public partial class Enemy : CharacterBody3D, Initialize(); SetupSignals(); } + + private AbilityHandle? _hitAbilityHandle; public void Initialize() { @@ -119,14 +128,18 @@ public partial class Enemy : CharacterBody3D, CHealth = (GetNode("CHealth") as IHealthable)!; CKnockback = (GetNode("CKnockback") as IKnockbackable)!; - _healthbar = GetNode("CHealthBar").Healthbar; + _resourceBar = GetNode("CHealthBar").ResourceBar; CMovement.RMovement = RMovement; CHealth.RHealth = RHealth; CHealth.CurrentHealth = RHealth.StartingHealth; CKnockback.RKnockback = RKnockback; - - _healthbar.Initialize(CHealth.CurrentHealth); + + if (HitAbility != null) + _hitAbilityHandle = Abilities.GrantAbilityPermanently(HitAbility.GetAbilityData(), 1, LevelComparison.None, this); + + Events.Subscribe(Tag.RequestTag(ForgeManagers.Instance.TagsManager, "events.combat.hit"), + data => {}); } public void SetupSignals() @@ -135,7 +148,7 @@ public partial class Enemy : CharacterBody3D, CDamageable.DamageTaken += (source, record) => ReduceHealth(source, record); CDamageable.DamageTaken += (_, record) => RegisterKnockback(new KnockbackRecord(record)); CHealth.HealthDepleted += Kill; - HealthChanged += (_, record) => _healthbar.SetHealth(record.CurrentHealth); + HealthChanged += (_, record) => _resourceBar.SetValue(record.CurrentHealth); } public override void _PhysicsProcess(double delta) @@ -160,13 +173,19 @@ public partial class Enemy : CharacterBody3D, public void ProcessGameplay(double delta) { - if (IsStunned) return; + if (IsStunned || _hitAbilityHandle == null) return; var bodies = _damageBox.GetOverlappingBodies(); foreach (var body in bodies) { - if(body is IDamageable spawnable) - spawnable.TakeDamage(new DamageRecord(GlobalPosition, RDamage)); + if (body is not IForgeEntity forgeEntity) continue; + var canActivate = _hitAbilityHandle.CanActivate(out var _); + if (!canActivate) return; + + _hitAbilityHandle.Activate(out var _, forgeEntity); + + // if(body is IDamageable spawnable) + // spawnable.TakeDamage(new DamageRecord(GlobalPosition, RDamage)); } } diff --git a/scenes/enemies/grounded_enemy/grounded_enemy.tscn b/scenes/enemies/grounded_enemy/grounded_enemy.tscn index c8a8c7dc..7ced8f34 100644 --- a/scenes/enemies/grounded_enemy/grounded_enemy.tscn +++ b/scenes/enemies/grounded_enemy/grounded_enemy.tscn @@ -6,16 +6,192 @@ [ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://scenes/components/damage/RDamageModifier.cs" id="2_r3cnf"] [ext_resource type="Resource" uid="uid://bohbojc68j7y1" path="res://scenes/enemies/grounded_enemy/grounded_enemy_health.tres" id="2_w4lm8"] [ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="4_na24f"] +[ext_resource type="Script" uid="uid://dhxfbxh54pyxp" path="res://addons/forge/resources/abilities/ForgeAbilityData.cs" id="6_4jf2q"] +[ext_resource type="Resource" uid="uid://cw2ytd34jsxj" path="res://forge/resources/tag_containers/status_invincible.tres" id="6_5lf6m"] +[ext_resource type="Script" uid="uid://cn3b4ya15fg7e" path="res://addons/forge/resources/magnitudes/ForgeScalableFloat.cs" id="6_jryek"] +[ext_resource type="Script" uid="uid://n6efm5o4uxvr" path="res://forge/abilities/ForgeSimpleHitBehavior.cs" id="6_msmv1"] +[ext_resource type="Resource" uid="uid://bsqvfefpb7jix" path="res://forge/resources/cues/player_health_changed_cue.tres" id="6_oo2a1"] [ext_resource type="Script" uid="uid://8uj04dfe8oql" path="res://addons/forge/nodes/ForgeEntity.cs" id="6_x50ya"] [ext_resource type="Script" uid="uid://cxihb42t2mfqi" path="res://addons/forge/nodes/ForgeAttributeSet.cs" id="6_yk4hc"] [ext_resource type="Script" uid="uid://b0u23nkpaimyc" path="res://scenes/components/damage/CDamageable.cs" id="7_1tw73"] +[ext_resource type="Script" uid="uid://b0eq12mjqfage" path="res://addons/forge/resources/components/TargetTagRequirements.cs" id="7_5eesh"] [ext_resource type="PackedScene" uid="uid://bwx2um43k0ou4" path="res://scenes/components/health/CHealthbar.tscn" id="7_18xwy"] [ext_resource type="Script" uid="uid://cw525n4mjqgw0" path="res://addons/forge/resources/ForgeTagContainer.cs" id="7_f22p3"] +[ext_resource type="Script" uid="uid://2gm1hdhi8u08" path="res://addons/forge/resources/magnitudes/ForgeModifierMagnitude.cs" id="7_msmv1"] [ext_resource type="PackedScene" uid="uid://dbr7ioio158ew" path="res://scenes/components/movement/CGroundedMovement.tscn" id="7_qyswd"] [ext_resource type="Script" uid="uid://ccovd5i0wr3kk" path="res://addons/forge/editor/attributes/AttributeValues.cs" id="7_x50ya"] +[ext_resource type="Script" uid="uid://bdfcavbjyhxxa" path="res://addons/forge/resources/ForgeModifier.cs" id="8_3gkmr"] [ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://scenes/components/movement/RMovement.cs" id="8_6d4gl"] +[ext_resource type="Script" uid="uid://1hgogislo1l6" path="res://addons/forge/resources/magnitudes/ForgeScalableInt.cs" id="8_m0osh"] +[ext_resource type="Script" uid="uid://br7ut4lbau66w" path="res://forge/calculators/ForgeRaiseEventTagExecution.cs" id="8_q86ag"] +[ext_resource type="Script" uid="uid://b83hf13nj37k3" path="res://addons/forge/resources/ForgeEffectData.cs" id="9_3gkmr"] [ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://scenes/components/knockback/CKnockback.tscn" id="10_jqqi6"] [ext_resource type="Resource" uid="uid://cektf6waf4s04" path="res://scenes/enemies/grounded_enemy/grounded_enemy_knockback.tres" id="11_8k3xb"] +[ext_resource type="Script" uid="uid://dngf30hxy5go4" path="res://addons/forge/resources/components/ModifierTags.cs" id="12_3gkmr"] + +[sub_resource type="Resource" id="Resource_nt1hl"] +script = ExtResource("7_5eesh") +ApplicationIgnoredTags = ExtResource("6_5lf6m") +metadata/_custom_type_script = "uid://b0eq12mjqfage" + +[sub_resource type="Resource" id="Resource_f35o6"] +script = ExtResource("7_f22p3") +ContainerTags = Array[String](["events.combat.hit"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" + +[sub_resource type="Resource" id="Resource_46obe"] +script = ExtResource("7_f22p3") +ContainerTags = Array[String](["events.combat.damage"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" + +[sub_resource type="Resource" id="Resource_33a4r"] +script = ExtResource("8_q86ag") +EventTags = SubResource("Resource_f35o6") +TargetEventTags = SubResource("Resource_46obe") +metadata/_custom_type_script = "uid://br7ut4lbau66w" + +[sub_resource type="Resource" id="Resource_rjo6h"] +script = ExtResource("8_m0osh") +BaseValue = 1 + +[sub_resource type="Resource" id="Resource_8qlid"] +script = ExtResource("6_jryek") +BaseValue = 1.0 + +[sub_resource type="Resource" id="Resource_lbthk"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_hguc3"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_ugrvo"] +script = ExtResource("6_jryek") +BaseValue = 1.0 + +[sub_resource type="Resource" id="Resource_6406e"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_x0rol"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_1s1j3"] +script = ExtResource("6_jryek") +BaseValue = -10.0 +metadata/_custom_type_script = "uid://cn3b4ya15fg7e" + +[sub_resource type="Resource" id="Resource_khx4r"] +script = ExtResource("8_3gkmr") +Attribute = "PlayerAttributeSet.Health" +ScalableFloat = SubResource("Resource_1s1j3") +Coefficient = SubResource("Resource_ugrvo") +PreMultiplyAdditiveValue = SubResource("Resource_x0rol") +PostMultiplyAdditiveValue = SubResource("Resource_6406e") +CalculatorCoefficient = SubResource("Resource_8qlid") +CalculatorPreMultiplyAdditiveValue = SubResource("Resource_hguc3") +CalculatorPostMultiplyAdditiveValue = SubResource("Resource_lbthk") +metadata/_custom_type_script = "uid://bdfcavbjyhxxa" + +[sub_resource type="Resource" id="Resource_xmw7i"] +script = ExtResource("8_m0osh") +BaseValue = 1 + +[sub_resource type="Resource" id="Resource_lj45k"] +script = ExtResource("9_3gkmr") +Name = "SimpleHitEffect" +Modifiers = Array[Object]([SubResource("Resource_khx4r")]) +Components = [SubResource("Resource_nt1hl")] +Executions = [SubResource("Resource_33a4r")] +StackLimit = SubResource("Resource_xmw7i") +InitialStack = SubResource("Resource_rjo6h") +Cues = [ExtResource("6_oo2a1")] +metadata/_custom_type_script = "uid://b83hf13nj37k3" + +[sub_resource type="Resource" id="Resource_m0osh"] +script = ExtResource("6_msmv1") +DamageEffect = SubResource("Resource_lj45k") +Name = "Simple hit" +Description = "This is a simple hit from an enemy" +metadata/_custom_type_script = "uid://n6efm5o4uxvr" + +[sub_resource type="Resource" id="Resource_msmv1"] +script = ExtResource("7_f22p3") +ContainerTags = Array[String](["status.stunned"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" + +[sub_resource type="Resource" id="Resource_xdbds"] +script = ExtResource("7_f22p3") +ContainerTags = Array[String](["cooldown.enemy.hit"]) +metadata/_custom_type_script = "uid://cw525n4mjqgw0" + +[sub_resource type="Resource" id="Resource_gna8g"] +script = ExtResource("12_3gkmr") +TagsToAdd = SubResource("Resource_xdbds") +metadata/_custom_type_script = "uid://dngf30hxy5go4" + +[sub_resource type="Resource" id="Resource_oo2a1"] +script = ExtResource("6_jryek") +BaseValue = 1.0 + +[sub_resource type="Resource" id="Resource_q86ag"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_5eesh"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_5lf6m"] +script = ExtResource("6_jryek") +BaseValue = 1.0 + +[sub_resource type="Resource" id="Resource_bv3hg"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_tb7hu"] +script = ExtResource("6_jryek") + +[sub_resource type="Resource" id="Resource_bw6ul"] +script = ExtResource("6_jryek") +BaseValue = 1.0 +metadata/_custom_type_script = "uid://cn3b4ya15fg7e" + +[sub_resource type="Resource" id="Resource_g5uhf"] +script = ExtResource("7_msmv1") +ScalableFloat = SubResource("Resource_bw6ul") +Coefficient = SubResource("Resource_5lf6m") +PreMultiplyAdditiveValue = SubResource("Resource_tb7hu") +PostMultiplyAdditiveValue = SubResource("Resource_bv3hg") +CalculatorCoefficient = SubResource("Resource_oo2a1") +CalculatorPreMultiplyAdditiveValue = SubResource("Resource_5eesh") +CalculatorPostMultiplyAdditiveValue = SubResource("Resource_q86ag") +metadata/_custom_type_script = "uid://2gm1hdhi8u08" + +[sub_resource type="Resource" id="Resource_vl5ta"] +script = ExtResource("8_m0osh") +BaseValue = 1 + +[sub_resource type="Resource" id="Resource_82a7m"] +script = ExtResource("8_m0osh") +BaseValue = 1 + +[sub_resource type="Resource" id="Resource_0gdnn"] +script = ExtResource("9_3gkmr") +Name = "HitCooldown" +Modifiers = [] +Components = [SubResource("Resource_gna8g")] +Executions = [] +DurationType = 2 +Duration = SubResource("Resource_g5uhf") +StackLimit = SubResource("Resource_82a7m") +InitialStack = SubResource("Resource_vl5ta") +Cues = [] +metadata/_custom_type_script = "uid://b83hf13nj37k3" + +[sub_resource type="Resource" id="Resource_ub34u"] +script = ExtResource("6_4jf2q") +Name = "Hit" +CooldownEffects = [SubResource("Resource_0gdnn")] +AbilityBehavior = SubResource("Resource_m0osh") +ActivationBlockedTags = SubResource("Resource_msmv1") +metadata/_custom_type_script = "uid://dhxfbxh54pyxp" [sub_resource type="Resource" id="Resource_4jf2q"] script = ExtResource("7_f22p3") @@ -39,7 +215,7 @@ Default = 1 Min = 1 Max = 100 -[sub_resource type="ViewportTexture" id="ViewportTexture_ub34u"] +[sub_resource type="ViewportTexture" id="ViewportTexture_5lf6m"] viewport_path = NodePath("SubViewport") [sub_resource type="Resource" id="Resource_qj0ob"] @@ -87,6 +263,7 @@ DeathEffects = Array[Object]([]) RDamage = ExtResource("2_bn56u") RKnockback = ExtResource("11_8k3xb") RMovement = ExtResource("4_na24f") +HitAbility = SubResource("Resource_ub34u") [node name="ForgeEntity" type="Node" parent="." unique_id=432521027] script = ExtResource("6_x50ya") @@ -110,7 +287,7 @@ metadata/_custom_type_script = "uid://bjwrpv3jpsc1e" [node name="CHealthBar" parent="." unique_id=1278247727 instance=ExtResource("7_18xwy")] transform = Transform3D(0.4, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.2, 0) -texture = SubResource("ViewportTexture_ub34u") +texture = SubResource("ViewportTexture_5lf6m") [node name="CDamageable" type="Node" parent="." unique_id=1601518000] script = ExtResource("7_1tw73") diff --git a/scenes/player_controller/PlayerController.tscn b/scenes/player_controller/PlayerController.tscn index 8fee73b6..bd588866 100644 --- a/scenes/player_controller/PlayerController.tscn +++ b/scenes/player_controller/PlayerController.tscn @@ -7,14 +7,13 @@ [ext_resource type="Script" uid="uid://b44cse62qru7j" path="res://scenes/components/knockback/RKnockback.cs" id="3_cb2lu"] [ext_resource type="Resource" uid="uid://bl5crtu1gkrtr" path="res://inputs/base_mode/base_mode.tres" id="3_cresl"] [ext_resource type="PackedScene" uid="uid://c4ikbhojckpnc" path="res://scenes/components/health/CHealth.tscn" id="3_q7bng"] -[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://scenes/components/health/RHealth.cs" id="4_abfq8"] [ext_resource type="Resource" uid="uid://bjyd801wvverk" path="res://scenes/player_controller/resources/player_health.tres" id="4_m8gvy"] [ext_resource type="Resource" uid="uid://cpdaw41ah5gic" path="res://inputs/base_mode/rotate_y.tres" id="4_rxwoh"] [ext_resource type="Resource" uid="uid://dh437cuxgjv6b" path="res://forge/resources/effect_datas/mana_regeneration.tres" id="5_2rkt1"] [ext_resource type="Resource" uid="uid://ccrb5xsnphc8" path="res://inputs/base_mode/rotate_floorplane.tres" id="5_4u7i3"] [ext_resource type="PackedScene" uid="uid://hpsg4fqwrx1u" path="res://scenes/components/damage/CDamageable.tscn" id="5_jb43f"] [ext_resource type="Resource" uid="uid://f3vs6l4m623s" path="res://inputs/base_mode/move_left.tres" id="5_q14ux"] -[ext_resource type="Resource" uid="uid://ifeavnlps7hy" path="res://forge/resources/behaviors/exploding_sword.tres" id="5_u8yay"] +[ext_resource type="Resource" uid="uid://b0ikxp5j8fn3n" path="res://forge/resources/ability_datas/on_hit_invinciblity.tres" id="5_u8yay"] [ext_resource type="PackedScene" uid="uid://duju3atqgltkg" path="res://scenes/explosion/explosion.tscn" id="5_ue7xq"] [ext_resource type="Resource" uid="uid://dyru7mxo121w6" path="res://scenes/player_controller/resources/player_normal_damage_mod.tres" id="6_cmijs"] [ext_resource type="Resource" uid="uid://t612lts1wi1s" path="res://inputs/base_mode/move_right.tres" id="6_q7bng"] @@ -58,7 +57,7 @@ [ext_resource type="Texture2D" uid="uid://chvt6g0xn5c2m" path="res://scenes/player_controller/components/dash/light-ring.jpg" id="32_lgpc8"] [ext_resource type="Script" uid="uid://b4dwolbvt8our" path="res://addons/godot_state_charts/history_state.gd" id="41_ruloh"] [ext_resource type="Texture2D" uid="uid://c40orhfdgsim" path="res://assets/ui/IconGodotNode/white/icon_circle.png" id="45_u8rdp"] -[ext_resource type="PackedScene" uid="uid://cyw8p0p6a78tl" path="res://scenes/ui/healthbar/healthbar.tscn" id="47_76kmc"] +[ext_resource type="PackedScene" uid="uid://cyw8p0p6a78tl" path="res://scenes/ui/resourcebar/healthbar.tscn" id="47_76kmc"] [sub_resource type="Resource" id="Resource_mpigw"] script = ExtResource("2_u8yay") @@ -70,6 +69,11 @@ script = ExtResource("11_u8yay") Tag = "events.player.empowered_action_used" metadata/_custom_type_script = "uid://dpakv7agvir6y" +[sub_resource type="Resource" id="Resource_2rkt1"] +script = ExtResource("11_u8yay") +Tag = "status.invincible" +metadata/_custom_type_script = "uid://dpakv7agvir6y" + [sub_resource type="Resource" id="Resource_cb2lu"] script = ExtResource("2_x835q") DamageDealt = 10.0 @@ -80,11 +84,6 @@ script = ExtResource("3_cb2lu") Modifier = 5.0 metadata/_custom_type_script = "uid://b44cse62qru7j" -[sub_resource type="Resource" id="Resource_ue7xq"] -script = ExtResource("4_abfq8") -StartingHealth = 10.0 -metadata/_custom_type_script = "uid://baiapod3csndf" - [sub_resource type="Resource" id="Resource_u8yay"] script = ExtResource("11_2rkt1") Default = 100 @@ -156,8 +155,9 @@ collision_mask = 272 script = ExtResource("1_poq2x") BaseTags = SubResource("Resource_mpigw") EmpoweredActionUsed = SubResource("Resource_5gbhg") +InvincibleTag = SubResource("Resource_2rkt1") EmpoweredActionAbility = ExtResource("10_2rkt1") -WeaponExplosionBehavior = ExtResource("5_u8yay") +DefaultGrantedAbilities = [ExtResource("5_u8yay")] DefaultPermanentEffects = [ExtResource("5_2rkt1")] EmpoweredActionEffects = [ExtResource("6_u8yay")] AimAssistStrength = 0.3 @@ -165,7 +165,6 @@ AimAssistReductionWhenCloseToTarget = 0.1 AimAssistReductionStartDistance = 8.0 RDamage = SubResource("Resource_cb2lu") RKnockback = SubResource("Resource_abfq8") -RHealth = SubResource("Resource_ue7xq") TargetingDistance = 5.0 Explosion = ExtResource("5_ue7xq") WalkSpeed = 7.5 diff --git a/scenes/player_controller/PlayerUi.cs b/scenes/player_controller/PlayerUi.cs index edcd5028..a9b3fc02 100644 --- a/scenes/player_controller/PlayerUi.cs +++ b/scenes/player_controller/PlayerUi.cs @@ -1,5 +1,8 @@ using Godot; using System; +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Gamesmiths.Forge.Attributes; using Gamesmiths.Forge.Core; using Gamesmiths.Forge.Cues; using Gamesmiths.Forge.Godot.Core; @@ -7,12 +10,12 @@ using Gamesmiths.Forge.Tags; using Movementtests.interfaces; using Movementtests.tools; -[GlobalClass, Icon("res://assets/ui/IconGodotNode/control/icon_text_panel.png")] -public partial class PlayerUi : Control, ICueHandler +[GlobalClass, Icon("res://assets/ui/IconGodotNode/control/icon_text_panel.png"), Meta(typeof(IAutoOn), typeof(IAutoConnect))] +public partial class PlayerUi : Control { - private TextureRect _enemyTarget = null!; - private Healthbar _healthbar = null!; - private Healthbar _manabar = null!; + public override void _Notification(int what) => this.Notify(what); + + #region Utils public enum TargetState { @@ -20,29 +23,33 @@ public partial class PlayerUi : Control, ICueHandler TargetWouldNotKill, TargetWouldKill } - public record TargetProperties(TargetState State, Vector2 Position); + + #endregion + + #region Nodes + + [Node] public required TextureRect EnemyTarget { get; set; } + [Node] public required ResourceBar Healthbar { get; set; } + [Node] public required ResourceBar Manabar { get; set; } + + #endregion + + #region Exports [Export] public Color WouldKillColor { get; set; } = new Color("009c8f"); [Export] public Color WouldNotKillColor { get; set; } = new Color("fc001c"); - - public override void _Ready() - { - _enemyTarget = GetNode("%EnemyTarget"); - _healthbar = GetNode("%Healthbar"); - _manabar = GetNode("%Manabar"); - - var tagsManager = ForgeManagers.Instance.TagsManager; - var cuesManager = ForgeManagers.Instance.CuesManager; - cuesManager.RegisterCue(Tag.RequestTag(tagsManager, "cues.resources.mana"), this); - } - public void Initialize(float initialHealth, float initialMana) + #endregion + + + public void Initialize(EntityAttribute health, EntityAttribute mana) { - _healthbar.Initialize(initialHealth); - _manabar.Initialize(initialMana); + var tagsManager = ForgeManagers.Instance.TagsManager; + Healthbar.Initialize(health, Tag.RequestTag(tagsManager, "cues.resources.health")); + Manabar.Initialize(mana, Tag.RequestTag(tagsManager, "cues.resources.mana")); } public void SetEnemyTargetProperties(TargetProperties targetProperties) @@ -57,38 +64,8 @@ public partial class PlayerUi : Control, ICueHandler TargetState.TargetWouldKill => WouldKillColor, _ => WouldNotKillColor }; - _enemyTarget.SetVisible(visible); - _enemyTarget.SetPosition(position - _enemyTarget.Size / 2); - _enemyTarget.SetModulate(modulation); - } - - public void OnHealthChanged(IHealthable healthable, HealthChangedRecord healthChanged) - { - _healthbar.CurrentHealth = healthChanged.CurrentHealth; - } - - public void OnManaChanged(float newValue) - { - _manabar.CurrentHealth = newValue; - } - - public void OnExecute(IForgeEntity? target, CueParameters? parameters) - { - if (target == null || !parameters.HasValue || !IsInstanceValid(_manabar)) return; - - float magnitude = parameters.Value.Magnitude; - _manabar.CurrentHealth += magnitude; - } - - public void OnApply(IForgeEntity? target, CueParameters? parameters) - { - } - - public void OnRemove(IForgeEntity? target, bool interrupted) - { - } - - public void OnUpdate(IForgeEntity? target, CueParameters? parameters) - { + EnemyTarget.SetVisible(visible); + EnemyTarget.SetPosition(position - EnemyTarget.Size / 2); + EnemyTarget.SetModulate(modulation); } } diff --git a/scenes/player_controller/scripts/PlayerController.cs b/scenes/player_controller/scripts/PlayerController.cs index 96f80217..1770b32a 100644 --- a/scenes/player_controller/scripts/PlayerController.cs +++ b/scenes/player_controller/scripts/PlayerController.cs @@ -5,13 +5,10 @@ using Chickensoft.Introspection; using Gamesmiths.Forge.Abilities; using Gamesmiths.Forge.Attributes; using Gamesmiths.Forge.Core; +using Gamesmiths.Forge.Cues; using Gamesmiths.Forge.Effects; -using Gamesmiths.Forge.Effects.Calculator; using Gamesmiths.Forge.Effects.Components; using Gamesmiths.Forge.Effects.Duration; -using Gamesmiths.Forge.Effects.Magnitudes; -using Gamesmiths.Forge.Effects.Modifiers; -using Gamesmiths.Forge.Effects.Periodic; using Gamesmiths.Forge.Events; using Gamesmiths.Forge.Godot.Core; using Gamesmiths.Forge.Godot.Nodes; @@ -27,11 +24,7 @@ using Movementtests.addons.godot_state_charts.csharp; using Movementtests.interfaces; using Movementtests.systems; using Movementtests.player_controller.Scripts; -using Movementtests.scenes.player_controller.scripts; -using Movementtests.tools; -using Movementtests.forge.abilities; using Movementtests.managers; -using Movementtests.tools.calculators; using RustyOptions; using Node = Godot.Node; @@ -39,12 +32,7 @@ public record struct EmpoweredActionPayload; [GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_character.png"), Meta(typeof(IAutoNode))] -public partial class PlayerController : CharacterBody3D, - IDamageable, - IDamageDealer, - IHealthable, - IKnockbackable, - IForgeEntity +public partial class PlayerController : CharacterBody3D, IForgeEntity, ICueHandler { public override void _Notification(int what) => this.Notify(what); @@ -53,7 +41,7 @@ public partial class PlayerController : CharacterBody3D, public InventoryManager InventoryManager => this.DependOn(); #endregion - #region Enums + #region Utils public enum BufferedActions { @@ -66,6 +54,14 @@ public partial class PlayerController : CharacterBody3D, #endregion + #region Forge + + private AbilityHandle? _empoweredActionHandle; + public required EntityAttribute HealthAttribute { get; set; } + public required EntityAttribute ManaAttribute { get; set; } + + #endregion + #region Signals [Signal] @@ -79,27 +75,25 @@ public partial class PlayerController : CharacterBody3D, #region Publics - public HeadSystem HeadSystem = null!; - public StairsSystem StairsSystem = null!; - public MantleSystem MantleSystem = null!; - public DashSystem DashSystem = null!; - public CollisionShape3D StandingCollider = null!; - public CollisionShape3D SlideCollider = null!; - public WeaponSystem WeaponSystem = null!; - public WallHugSystem WallHugSystem = null!; - public PlayerUi PlayerUi = null!; - public Node3D DashIndicatorNode = null!; - public MeshInstance3D DashIndicatorMesh = null!; - public CylinderMesh DashIndicatorMeshCylinder = null!; - public RayCast3D WallRunSnapper = null!; - public ShapeCast3D GroundDetector = null!; - public ShapeCast3D CeilingDetector = null!; - public RayCast3D DirectGroundDetector = null!; - public Area3D WeaponHitbox = null!; - public AudioStreamPlayer3D SfxPlayer = null!; - - public ShapeCast3D DashDamageDetector = null!; - public Area3D SlidingEnemyDetector = null!; + [Node("HeadSystem")] public required HeadSystem HeadSystem { get; set; } + [Node("StairsSystem")] public required StairsSystem StairsSystem { get; set; } + [Node("HeadSystem/MantleSystem")] public required MantleSystem MantleSystem { get; set; } + [Node("DashSystem")] public required DashSystem DashSystem { get; set; } + [Node("StandingCollider")] public required CollisionShape3D StandingCollider { get; set; } + [Node("SlideCollider")] public required CollisionShape3D SlideCollider { get; set; } + [Node("WeaponSystem")] public required WeaponSystem WeaponSystem { get; set; } + [Node("WallHugSystem")] public required WallHugSystem WallHugSystem { get; set; } + [Node("UI")] public required PlayerUi PlayerUi { get; set; } + [Node("GroundDetector")] public required ShapeCast3D GroundDetector { get; set; } + [Node("CeilingDetector")] public required ShapeCast3D CeilingDetector { get; set; } + [Node("DirectGroundDetector")] public required RayCast3D DirectGroundDetector { get; set; } + [Node("%WeaponHitbox")] public required Area3D WeaponHitbox { get; set; } + [Node("SFXPlayer")] public required AudioStreamPlayer3D SfxPlayer { get; set; } + [Node("DashDamage")] public required ShapeCast3D DashDamageDetector { get; set; } + [Node("SlidingEnemyDetector")] public required Area3D SlidingEnemyDetector { get; set; } + [Node("%CloseEnemyDetector")] public required ShapeCast3D CloseEnemyDetector { get; set; } + [Node("AimAssistRayCast")] public required RayCast3D AimAssistRayCast { get; set; } + [Node("HeadSystem/CameraSmooth/Camera3D")] public required Camera3D Camera { get; set; } public EntityAttributes Attributes { get; set; } = null!; public EntityTags Tags { get; set; } = null!; @@ -117,17 +111,14 @@ public partial class PlayerController : CharacterBody3D, // Forge stuff [ExportCategory("Forge")] [ExportGroup("General")] - [Export] - public ForgeTagContainer BaseTags { get; set; } - [Export] public ForgeTag EmpoweredActionUsed; + [Export] public required ForgeTagContainer BaseTags { get; set; } + [Export] public required ForgeTag EmpoweredActionUsed { get; set; } + [Export] public required ForgeTag InvincibleTag { get; set; } [ExportGroup("Abilities")] [ExportSubgroup("Common and defaults")] - [Export] public ForgeAbilityData EmpoweredActionAbility = null!; - [Export] public ForgeAbilityData[] DefaultPermanentAbilities = []; - - [ExportSubgroup("WeaponThrow")] [Export] - public ForgeAbilityBehavior WeaponExplosionBehavior; + [Export] public ForgeAbilityData? EmpoweredActionAbility; + [Export] public ForgeAbilityData[] DefaultGrantedAbilities = []; [ExportGroup("Effects")] [ExportSubgroup("Common and defaults")] @@ -147,7 +138,6 @@ public partial class PlayerController : CharacterBody3D, [ExportGroup("Damage")] [Export] public RDamage RDamage { get; set; } = null!; [Export] public RKnockback? RKnockback { get; set; } = null!; - [Export] public RHealth? RHealth { get; set; } = null!; [ExportGroup("Targeting")] [Export(PropertyHint.Range, "0,20,0.1,or_greater")] @@ -409,29 +399,48 @@ public partial class PlayerController : CharacterBody3D, private Transition _onGroundSlideJump = null!; private Transition _onAirGlideDoubleJump = null!; - // Damage - public CDamageable? CDamageable { get; set; } - public CHealth? CHealth { get; set; } - public CKnockback? CKnockback { get; set; } - public float CurrentHealth { get; set; } + #endregion - private bool _isInvincible; - public bool IsInvincibleOverride { get; set; } + #region DamageManagement + + // Invincibility + private ActiveEffectHandle? _invincibleEffect; public bool IsInvincible { - get => _isInvincible || IsInvincibleOverride; - set => _isInvincible = value; + get => Tags.CombinedTags.HasTag(InvincibleTag.GetTag()); + set => SetInvincible(value); } - + public void SetInvincible(bool invincible) + { + if (invincible && !IsInvincible) + { + var invincibility = new EffectData( + "Invincibility", + new DurationData(DurationType.Infinite), + effectComponents: + [ + new ModifierTagsEffectComponent( + InvincibleTag.GetTag().GetSingleTagContainer()! + ) + ]); + GD.Print("Applying invincibility"); + _invincibleEffect = EffectsManager.ApplyEffect(new Effect(invincibility, + new EffectOwnership(this, this))); + + return; + } + + if (_invincibleEffect == null) return; + EffectsManager.RemoveEffect(_invincibleEffect); + GD.Print("Removing effect"); + _invincibleEffect = null; + } + + // Damage dealing private readonly List _hitEnemies = new List(); - private ShapeCast3D _closeEnemyDetector = null!; - private RayCast3D _aimAssisRayCast = null!; - private Camera3D _camera = null!; - - private AbilityHandle? _empoweredActionHandle; + #endregion - #endregion public void OnReady() { @@ -439,16 +448,15 @@ public partial class PlayerController : CharacterBody3D, // General use stuff PlayerUi = GetNode("UI"); - _closeEnemyDetector = GetNode("%CloseEnemyDetector"); - _closeEnemyDetector.TargetPosition = _closeEnemyDetector.TargetPosition.Normalized() * TargetingDistance; - _aimAssisRayCast = GetNode("AimAssistRayCast"); - _aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f); + CloseEnemyDetector = GetNode("%CloseEnemyDetector"); + CloseEnemyDetector.TargetPosition = CloseEnemyDetector.TargetPosition.Normalized() * TargetingDistance; + AimAssistRayCast = GetNode("AimAssistRayCast"); + AimAssistRayCast.TargetPosition = AimAssistRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f); #region Forge - + var tagsManager = ForgeManagers.Instance.TagsManager; var cuesManager = ForgeManagers.Instance.CuesManager; - List attributeSetList = []; foreach (Node node in GetChildren()) { @@ -468,15 +476,24 @@ public partial class PlayerController : CharacterBody3D, Abilities = new(this); Events = new(); - _empoweredActionHandle = Abilities.GrantAbilityPermanently( - EmpoweredActionAbility.GetAbilityData(), - abilityLevel: 1, - levelOverridePolicy: LevelComparison.None, - sourceEntity: this); - foreach (var ability in DefaultPermanentAbilities) + HealthAttribute = Attributes["PlayerAttributeSet.Health"]; + ManaAttribute = Attributes["PlayerAttributeSet.Mana"]; + + cuesManager.RegisterCue(Tag.RequestTag(tagsManager, "cues.resources.health"), this); + + if (EmpoweredActionAbility != null) + { + _empoweredActionHandle = Abilities.GrantAbilityPermanently( + EmpoweredActionAbility.GetAbilityData(), + abilityLevel: 1, + levelOverridePolicy: LevelComparison.None, + sourceEntity: this); + } + + foreach (var defaultGrantedAbility in DefaultGrantedAbilities) { Abilities.GrantAbilityPermanently( - ability.GetAbilityData(), + defaultGrantedAbility.GetAbilityData(), abilityLevel: 1, levelOverridePolicy: LevelComparison.None, sourceEntity: this); @@ -496,37 +513,23 @@ public partial class PlayerController : CharacterBody3D, EffectsManager.ApplyEffect(new Effect(effect.GetEffectData(), new EffectOwnership(this, this))); }); } + + Events.Subscribe(Tag.RequestTag(ForgeManagers.Instance.TagsManager, "events.combat.damage"), OnDamageReceived); + Events.Subscribe(Tag.RequestTag(ForgeManagers.Instance.TagsManager, "events.combat.death"), OnDeath); + + PlayerUi.Initialize(HealthAttribute, ManaAttribute); #endregion // DashIndicator = GetNode("%DashIndicator"); TargetSpeed = WalkSpeed; - DashIndicatorNode = GetNode("DashIndicator"); - DashIndicatorMesh = GetNode("DashIndicator/DashIndicatorMesh"); - DashIndicatorMeshCylinder = (DashIndicatorMesh.Mesh as CylinderMesh)!; - DashIndicatorMesh.Visible = false; SfxPlayer = GetNode("SFXPlayer"); _audioStream = (SfxPlayer.GetStreamPlayback() as AudioStreamPlaybackInteractive)!; // Camera stuff - HeadSystem = GetNode("HeadSystem"); - _camera = GetNode("HeadSystem/CameraSmooth/Camera3D"); Node3D cameraSmooth = GetNode("HeadSystem/CameraSmooth"); // Movement stuff - WeaponSystem = GetNode("WeaponSystem"); - MantleSystem = GetNode("HeadSystem/MantleSystem"); - StandingCollider = GetNode("StandingCollider"); - SlideCollider = GetNode("SlideCollider"); - DashSystem = GetNode("DashSystem"); - StairsSystem = GetNode("StairsSystem"); - WallHugSystem = GetNode("WallHugSystem"); - WallRunSnapper = GetNode("%WallRunSnapper"); - GroundDetector = GetNode("GroundDetector"); - CeilingDetector = GetNode("CeilingDetector"); - DirectGroundDetector = GetNode("DirectGroundDetector"); - DashDamageDetector = GetNode("DashDamage"); - SlidingEnemyDetector = GetNode("SlidingEnemyDetector"); RayCast3D stairsBelowRayCast3D = GetNode("StairsBelowRayCast3D"); RayCast3D stairsAheadRayCast3D = GetNode("StairsAheadRayCast3D"); _headCollisionDetectors = new RayCast3D[NumOfHeadCollisionDetectors]; @@ -545,26 +548,18 @@ public partial class PlayerController : CharacterBody3D, WeaponHitbox.Monitoring = false; WeaponHitbox.BodyEntered += RegisterHitEnnemy; - CHealth = GetNode("CHealth") as CHealth; - CKnockback = GetNode("CKnockback") as CKnockback; - CDamageable = GetNode("CDamageable") as CDamageable; - if (CHealth == null) throw new Exception("CHealth not found!"); - if (CKnockback == null) throw new Exception("CKnockback not found!"); - if (CDamageable == null) throw new Exception("CDamageable not found!"); + // if (RHealth != null) + // { + // CHealth.RHealth = RHealth; + // CHealth.CurrentHealth = RHealth.StartingHealth; + // } + // if (RKnockback != null) CKnockback!.RKnockback = RKnockback; + // + // CDamageable.DamageTaken += (damageable, record) => ReduceHealth(damageable, record); + // CDamageable.DamageTaken += (_, record) => RegisterKnockback(new KnockbackRecord(record)); + // CHealth.HealthChanged += PlayerUi.OnHealthChanged; + // CHealth.HealthDepleted += (_) => Kill(); - if (RHealth != null) - { - CHealth.RHealth = RHealth; - CHealth.CurrentHealth = RHealth.StartingHealth; - } - if (RKnockback != null) CKnockback!.RKnockback = RKnockback; - - PlayerUi.Initialize(CHealth.CurrentHealth, Attributes["PlayerAttributeSet.Mana"].BaseValue); - CDamageable.DamageTaken += (damageable, record) => ReduceHealth(damageable, record); - CDamageable.DamageTaken += (_, record) => RegisterKnockback(new KnockbackRecord(record)); - CHealth.HealthChanged += PlayerUi.OnHealthChanged; - CHealth.HealthDepleted += (_) => Kill(); - #region StateManagement _playerState = StateChart.Of(GetNode("StateChart")); @@ -633,7 +628,7 @@ public partial class PlayerController : CharacterBody3D, Gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity"); MantleSystem.Init(); StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth); - DashSystem.Init(HeadSystem, _camera); + DashSystem.Init(HeadSystem, Camera); WeaponSystem.Init(); WallHugSystem.Init(); @@ -728,6 +723,8 @@ public partial class PlayerController : CharacterBody3D, var weaponLeftToken = WeaponSystem.Events.Subscribe(WeaponSystem.WeaponStartedFlyingEventTag, OnWeaponLeft); var weaponLandedToken = WeaponSystem.Events.Subscribe(WeaponSystem.WeaponStoppedFlyingEventTag, OnWeaponLanded); } + + #region LifecycleManagement public void OnResolved() { @@ -737,8 +734,7 @@ public partial class PlayerController : CharacterBody3D, { foreach (var ability in abilities) { - if (ability is not ForgeAbilityBehavior abilityBehavior) continue; - WeaponSystem.GrantNewAbilityForEvent(weaponEvent, abilityBehavior); + WeaponSystem.GrantNewAbilityForEvent(weaponEvent, ability); } } @@ -753,6 +749,10 @@ public partial class PlayerController : CharacterBody3D, InventoryManager.WeaponEventAbilityRemoved -= OnWeaponEventAbilityRemoved; } + #endregion + + #region WeaponEvents + public void OnWeaponLeft(EventData data) { var target = data.Target; @@ -789,10 +789,11 @@ public partial class PlayerController : CharacterBody3D, { WeaponSystem.RemoveAbilityForEvent(data.ForEvent, data.Ability); } + + #endregion - /////////////////////////// - // Settings & tutorial // - /////////////////////////// + #region Settings + public void LoadSettings() { var config = new ConfigFile(); @@ -812,25 +813,26 @@ public partial class PlayerController : CharacterBody3D, _fovChangeMultiplier = (float) config.GetValue("InputSettings", "FovChangeWithSpeed", 1.0f); _aimAssistMultiplier = (float) config.GetValue("InputSettings", "AimAssist", 1.0f); } + + #endregion - /////////////////////////// - // Toolbox Utils // - /////////////////////////// + #region Toolbox + public void SetPlayerHealthOverride(float newHealthValue) { - RHealth.StartingHealth = newHealthValue; - CHealth!.CurrentHealth = newHealthValue; - PlayerUi.Initialize(CHealth.CurrentHealth, Attributes["PlayerAttributeSet.Mana"].BaseValue); + // RHealth.StartingHealth = newHealthValue; + // CHealth!.CurrentHealth = newHealthValue; + // PlayerUi.Initialize(CHealth.CurrentHealth, Attributes["PlayerAttributeSet.Mana"].BaseValue); } public void SetPlayerDamageOverride(float newDamageValue) { RDamage.DamageDealt = newDamageValue; } + + #endregion - /////////////////////////// - // Grounded management // - /////////////////////////// - + #region GroundManagement + public void OnGrounded() { _isWallJumpAvailable = true; @@ -882,10 +884,7 @@ public partial class PlayerController : CharacterBody3D, _audioStream.SwitchToClipByName("land"); } - public bool IsGroundLike() - { - return GroundDetector.GetCollisionResult().Count > 0; - } + public bool IsGroundLike() => GroundDetector.GetCollisionResult().Count > 0; public void HandleGrounded(float delta) { @@ -972,11 +971,10 @@ public partial class PlayerController : CharacterBody3D, { return IsOnFloor() || StairsSystem.WasSnappedToStairsLastFrame(); } - - /////////////////////////// - // Airborne management // - /////////////////////////// + #endregion + + #region AirborneManagement public void OnAirborne() { if (_aiming.Active) @@ -1026,6 +1024,8 @@ public partial class PlayerController : CharacterBody3D, var verticalVelocity = ComputeVerticalSpeedGravity((float) delta); Velocity = new Vector3(horizontalVelocity.X, verticalVelocity, horizontalVelocity.Z); } + + #endregion /////////////////////////// // Movement input // @@ -1091,17 +1091,17 @@ public partial class PlayerController : CharacterBody3D, // Camera stuff private Vector2 ComputeAimAssist() { - _aimAssisRayCast.SetRotation(HeadSystem.GetGlobalLookRotation()); - if (!_aimAssisRayCast.IsColliding()) return Vector2.Zero; + AimAssistRayCast.SetRotation(HeadSystem.GetGlobalLookRotation()); + if (!AimAssistRayCast.IsColliding()) return Vector2.Zero; // Hard dependency on the aim assist to be an Area3D and having a parent - var collidedObject = _aimAssisRayCast.GetCollider() as Area3D; + var collidedObject = AimAssistRayCast.GetCollider() as Area3D; if (collidedObject is null) return Vector2.Zero; if (collidedObject.GetParent() is not ITargetable targetable) return Vector2.Zero; var targetPosition = targetable.GetTargetGlobalPosition(); - var targetPositionOnCamera = _camera.UnprojectPosition(targetPosition); - var centerOfScreen = _camera.GetViewport().GetVisibleRect().Size / 2f; + var targetPositionOnCamera = Camera.UnprojectPosition(targetPosition); + var centerOfScreen = Camera.GetViewport().GetVisibleRect().Size / 2f; var aimAssistDirection = centerOfScreen - targetPositionOnCamera; var aimAssist = aimAssistDirection * AimAssistStrength / 1000f; @@ -2061,7 +2061,7 @@ public partial class PlayerController : CharacterBody3D, if (!isOnFloorCustom()) ReduceTimeScaleWhileAiming(); - _aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() * + AimAssistRayCast.TargetPosition = AimAssistRayCast.TargetPosition.Normalized() * (DashSystem.DashCast3D.TargetPosition.Length() + DashSystem.DashCastRadius); } public void HandleAiming(float delta) @@ -2076,7 +2076,7 @@ public partial class PlayerController : CharacterBody3D, { DashSystem.StopPreparingDash(); - _aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f); + AimAssistRayCast.TargetPosition = AimAssistRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f); // DashIndicatorMesh.Visible = false; } @@ -2337,6 +2337,11 @@ public partial class PlayerController : CharacterBody3D, // private float _oldMana = 100; public override void _Process(double delta) { + if (Engine.GetProcessFrames() % 60 == 0) + { + GD.Print(_invincibleEffect); + GD.Print(Tags.CombinedTags.Count); + } EffectsManager.UpdateEffects(delta); } @@ -2351,7 +2356,7 @@ public partial class PlayerController : CharacterBody3D, public void HandleEnemyTargeting() { _isEnemyInDashAttackRange = false; - _closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation()); + CloseEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation()); var enemyTargetState = PlayerUi.TargetState.NoTarget; var positionOnScreen = Vector2.Zero; @@ -2359,20 +2364,20 @@ public partial class PlayerController : CharacterBody3D, { enemyTargetState = PlayerUi.TargetState.TargetWouldKill; _targetLocation = dashTarget.GetTargetGlobalPosition(); - positionOnScreen = _camera.UnprojectPosition(_targetLocation); + positionOnScreen = Camera.UnprojectPosition(_targetLocation); PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen)); return; } - if (!_closeEnemyDetector.IsColliding()) + if (!CloseEnemyDetector.IsColliding()) { PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen)); return; } - _targetHitLocation = _closeEnemyDetector.GetCollisionPoint(0); - _targetObject = _closeEnemyDetector.GetCollider(0); + _targetHitLocation = CloseEnemyDetector.GetCollisionPoint(0); + _targetObject = CloseEnemyDetector.GetCollider(0); if (_targetObject is not ITargetable target) { PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen)); @@ -2381,7 +2386,7 @@ public partial class PlayerController : CharacterBody3D, _targetLocation = target.GetTargetGlobalPosition(); // var targetDistance = _targetLocation.DistanceTo(GlobalPosition); - positionOnScreen = _camera.UnprojectPosition(_targetLocation); + positionOnScreen = Camera.UnprojectPosition(_targetLocation); var wouldKill = false; if (_targetObject is IHealthable h and IDamageable d) @@ -2399,20 +2404,21 @@ public partial class PlayerController : CharacterBody3D, if (IsInvincible) return damageRecord with { Damage = new RDamage(0, damageRecord.Damage.DamageType) }; - var finalDamage = CDamageable!.TakeDamage(damageRecord); - DamageTaken?.Invoke(this, finalDamage); + // var finalDamage = CDamageable!.TakeDamage(damageRecord); + // DamageTaken?.Invoke(this, finalDamage); HeadSystem.OnGetHit(); _audioStream.SwitchToClipByName("damage_taken"); TriggerHitstop(); OnHitInvincibility(); - return finalDamage; + return damageRecord; } public DamageRecord ComputeDamage(DamageRecord damageRecord) { - return CDamageable!.ComputeDamage(damageRecord); + // return CDamageable!.ComputeDamage(damageRecord); + return damageRecord; } public void OnHitInvincibility() @@ -2590,19 +2596,25 @@ public partial class PlayerController : CharacterBody3D, } public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord) { - var record = CHealth!.ReduceHealth(source, damageRecord); - HealthChanged?.Invoke(this, record); - return record; + // var record = CHealth!.ReduceHealth(source, damageRecord); + // HealthChanged?.Invoke(this, record); + return new HealthChangedRecord(100, 0, 100); } public void RegisterKnockback(KnockbackRecord knockbackRecord) { - CKnockback!.RegisterKnockback(knockbackRecord); + // CKnockback!.RegisterKnockback(knockbackRecord); } public Vector3 ComputeKnockback() { - var kb = CKnockback!.ComputeKnockback(); - return kb; + // var kb = CKnockback!.ComputeKnockback(); + // return kb; + return Vector3.Zero; + } + + public void OnDeath(EventData data) + { + Kill(); } public void Kill() @@ -2625,4 +2637,43 @@ public partial class PlayerController : CharacterBody3D, { _audioStream.SwitchToClipByName("footsteps"); } + + // Forge Damage handling + public void OnDamageReceived(EventData data) + { + var newHealth = HealthAttribute.CurrentValue + data.EventMagnitude; + if (newHealth > HealthAttribute.Min) return; + + var tagsManager = ForgeManagers.Instance.TagsManager; + Events.Raise(new EventData + { + EventTags = Tag.RequestTag(tagsManager, "events.combat.death").GetSingleTagContainer()!, + Source = data.Source, + Target = data.Target + }); + } + + public void OnExecute(IForgeEntity? target, CueParameters? parameters) + { + if (target == null || !parameters.HasValue) return; + + float magnitude = parameters.Value.Magnitude; + if (magnitude >= 0) return; + + HeadSystem.OnGetHit(); + _audioStream.SwitchToClipByName("damage_taken"); + TriggerHitstop(); + } + + public void OnApply(IForgeEntity? target, CueParameters? parameters) + { + } + + public void OnRemove(IForgeEntity? target, bool interrupted) + { + } + + public void OnUpdate(IForgeEntity? target, CueParameters? parameters) + { + } } diff --git a/scenes/ui/healthbar/Healthbar.cs b/scenes/ui/healthbar/Healthbar.cs deleted file mode 100644 index 07083ff9..00000000 --- a/scenes/ui/healthbar/Healthbar.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Godot; -using System; - -[GlobalClass, Icon("res://assets/ui/IconGodotNode/control/icon_heart.png")] -public partial class Healthbar : ProgressBar -{ - private Timer _damageCatchUpTimer = null!; - private ProgressBar _damagedHealth = null!; - - [Export] public StyleBox? BarStyle; - - private float _currentHealth; - public float CurrentHealth - { - get => _currentHealth; - set => SetHealth(value); - } - - public override void _Ready() - { - _damageCatchUpTimer = GetNode("DamageCatchUp"); - _damagedHealth = GetNode("Damagebar"); - - _damageCatchUpTimer.Timeout += OnDamageCatchUp; - Visible = false; - - if (BarStyle != null) - AddThemeStyleboxOverride("fill", BarStyle); - } - - public void Initialize(float initialHealth) - { - _currentHealth = initialHealth; - MaxValue = initialHealth; - Value = initialHealth; - _damagedHealth.MaxValue = initialHealth; - _damagedHealth.Value = initialHealth; - } - - public void SetHealth(float newHealth) - { - var previousHealth = _currentHealth; - _currentHealth = Mathf.Min(newHealth, (float) MaxValue); - _currentHealth = newHealth; - Value = _currentHealth; - - Visible = _currentHealth < MaxValue; - - if (_currentHealth < previousHealth) - { - _damageCatchUpTimer.Start(); - } - else - { - _damagedHealth.Value = _currentHealth; - } - } - - public void OnDamageCatchUp() - { - _damagedHealth.Value = _currentHealth; - } -} diff --git a/scenes/ui/resourcebar/ResourceBar.cs b/scenes/ui/resourcebar/ResourceBar.cs new file mode 100644 index 00000000..ca5cb72c --- /dev/null +++ b/scenes/ui/resourcebar/ResourceBar.cs @@ -0,0 +1,92 @@ +using Godot; +using System; +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Gamesmiths.Forge.Attributes; +using Gamesmiths.Forge.Core; +using Gamesmiths.Forge.Cues; +using Gamesmiths.Forge.Godot.Core; +using Gamesmiths.Forge.Tags; + +[GlobalClass, Icon("res://assets/ui/IconGodotNode/control/icon_heart.png"), Meta(typeof(IAutoOn), typeof(IAutoConnect))] +public partial class ResourceBar : ProgressBar, ICueHandler +{ + public override void _Notification(int what) => this.Notify(what); + + [Node("DamageCatchUp")] public required Timer DamageCatchUp { get; set; } + [Node("Damagebar")] public required ProgressBar DamageBar { get; set; } + + [Export] public StyleBox? BarStyle; + + private float _currentValue; + public float CurrentValue + { + get => _currentValue; + set => SetValue(value); + } + + public void OnReady() + { + DamageCatchUp.Timeout += OnDamageCatchUp; + Visible = false; + + if (BarStyle != null) + AddThemeStyleboxOverride("fill", BarStyle); + } + + public void Initialize(EntityAttribute attribute, Tag cueTag) + { + _currentValue = attribute.BaseValue; + MaxValue = attribute.Max; + Value = attribute.BaseValue; + DamageBar.MaxValue = attribute.Max; + DamageBar.Value = attribute.BaseValue; + + var cuesManager = ForgeManagers.Instance.CuesManager; + cuesManager.RegisterCue(cueTag, this); + } + + public void SetValue(float newValue) + { + var previousValue = _currentValue; + _currentValue = Mathf.Min(newValue, (float) MaxValue); + _currentValue = newValue; + Value = _currentValue; + + Visible = _currentValue < MaxValue; + + if (_currentValue < previousValue) + { + DamageCatchUp.Start(); + } + else + { + DamageBar.Value = _currentValue; + } + } + + public void OnDamageCatchUp() + { + DamageBar.Value = _currentValue; + } + + public void OnExecute(IForgeEntity? target, CueParameters? parameters) + { + if (target == null || !parameters.HasValue) return; + + float magnitude = parameters.Value.Magnitude; + CurrentValue += magnitude; + } + + public void OnApply(IForgeEntity? target, CueParameters? parameters) + { + } + + public void OnRemove(IForgeEntity? target, bool interrupted) + { + } + + public void OnUpdate(IForgeEntity? target, CueParameters? parameters) + { + } +} diff --git a/scenes/ui/healthbar/Healthbar.cs.uid b/scenes/ui/resourcebar/ResourceBar.cs.uid similarity index 100% rename from scenes/ui/healthbar/Healthbar.cs.uid rename to scenes/ui/resourcebar/ResourceBar.cs.uid diff --git a/scenes/ui/healthbar/healthbar.tscn b/scenes/ui/resourcebar/healthbar.tscn similarity index 100% rename from scenes/ui/healthbar/healthbar.tscn rename to scenes/ui/resourcebar/healthbar.tscn diff --git a/tests/player/PlayerControllerUnitTest.cs b/tests/player/PlayerControllerUnitTest.cs deleted file mode 100644 index 45a40ba6..00000000 --- a/tests/player/PlayerControllerUnitTest.cs +++ /dev/null @@ -1,133 +0,0 @@ -using Godot; -using GdUnit4; -using static GdUnit4.Assertions; -using Movementtests.interfaces; -using Movementtests.systems.damage; - -namespace Movementtests.tests; - -[TestSuite, RequireGodotRuntime] -public class PlayerControllerUnitTest -{ - private PlayerController _player; - - [BeforeTest] - public void SetupTest() - { - _player = new PlayerController(); - _player.TargetSpeed = 7.0f; - _player.Gravity = 9.8f; - - var rHealth = new RHealth(100.0f); - _player.RHealth = rHealth; - _player.CHealth = new CHealth { RHealth = rHealth, CurrentHealth = 100.0f }; - } - - [AfterTest] - public void CleanupTest() - { - _player?.Free(); - } - - [TestCase] - public void TestCalculateGravityForce() - { - _player.Weight = 3.0f; - // gravity is 9.8f - AssertFloat(_player.CalculateGravityForce()).IsEqualApprox(29.4f, 0.001f); - } - - [TestCase] - public void TestIsPlayerInputtingForward() - { - // Test Keyboard Input - _player.InputDeviceChanged(false); - _player.OnInputMoveKeyboard(Vector3.Forward); - AssertBool(_player.IsPlayerInputtingForward()).IsTrue(); - - _player.OnInputMoveKeyboard(Vector3.Back); - AssertBool(_player.IsPlayerInputtingForward()).IsFalse(); - - // Test Gamepad Input - _player.InputDeviceChanged(true); - _player.OnInputMove(new Vector3(0, 0, -1)); - AssertBool(_player.IsPlayerInputtingForward()).IsTrue(); - } - - [TestCase] - public void TestSetVerticalVelocity() - { - _player.Velocity = new Vector3(1, 0, 2); - _player.SetVerticalVelocity(5.0f); - AssertVector(_player.Velocity).IsEqual(new Vector3(1, 5, 2)); - } - - [TestCase] - public void TestComputeHVelocityGround() - { - _player.Velocity = Vector3.Zero; - _player.AccelerationFloor = 10.0f; - - float delta = 0.1f; - Vector3 newVelocity = _player.ComputeHVelocity(delta, _player.AccelerationFloor, _player.DecelerationFloor, Vector3.Forward); - AssertVector(newVelocity).IsEqual(new Vector3(0, 0, -7.0f)); - } - - [TestCase] - public void TestComputeHVelocityAir() - { - _player.Velocity = new Vector3(5, 0, 0); - _player.AccelerationAir = 2.0f; - _player.DecelerationAir = 2.0f; - - float delta = 0.5f; - Vector3 newVelocity = _player.ComputeHVelocity(delta, _player.AccelerationAir, _player.DecelerationAir, Vector3.Zero); - - AssertVector(newVelocity).IsEqual(Vector3.Zero); - } - - [TestCase] - public void TestReduceHealth() - { - var damageRecord = new DamageRecord(Vector3.Zero, new RDamage(25.0f, EDamageTypes.Normal)); - _player.ReduceHealth(_player, damageRecord); - AssertFloat(_player.CHealth.CurrentHealth).IsEqual(75.0f); - } - - [TestCase] - public void TestDashCooldownTimeout() - { - _player.CanDash = false; - _player.DashCooldownTimeout(); - AssertBool(_player.CanDash).IsTrue(); - } - - [TestCase] - public void TestGetInputLocalHDirection() - { - _player.InputDeviceChanged(false); - _player.OnInputMoveKeyboard(new Vector3(1, 0, 1)); - - Vector3 expected = new Vector3(1, 0, 1).Normalized(); - AssertVector(_player.GetInputLocalHDirection()).IsEqualApprox(expected, new Vector3(0.001f, 0.001f, 0.001f)); - } - - [TestCase] - public void TestComputeKnockback() - { - var cKnockback = new CKnockback(); - cKnockback.RKnockback = new RKnockback(10.0f); - _player.CKnockback = cKnockback; - - var damageRecord = new DamageRecord(new Vector3(10, 0, 0), new RDamage(0, EDamageTypes.Normal)); - var knockbackRecord = new KnockbackRecord(damageRecord, 1.0f); - - _player.GlobalPosition = Vector3.Zero; - cKnockback.GlobalPosition = Vector3.Zero; - - _player.RegisterKnockback(knockbackRecord); - - Vector3 knockback = cKnockback.ComputeKnockback(); - AssertVector(knockback).IsEqual(new Vector3(-10, 0, 0)); - } -} diff --git a/tests/player/PlayerControllerUnitTest.cs.uid b/tests/player/PlayerControllerUnitTest.cs.uid deleted file mode 100644 index 16a906a1..00000000 --- a/tests/player/PlayerControllerUnitTest.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://kmphtu0ovixi