diff --git a/Movement tests.csproj b/Movement tests.csproj index 48481545..4cbe4366 100644 --- a/Movement tests.csproj +++ b/Movement tests.csproj @@ -126,6 +126,7 @@ + diff --git a/tools/ForgeManager.cs b/forge/ForgeManager.cs similarity index 84% rename from tools/ForgeManager.cs rename to forge/ForgeManager.cs index a77fcdb1..89e10069 100644 --- a/tools/ForgeManager.cs +++ b/forge/ForgeManager.cs @@ -13,15 +13,10 @@ public partial class ForgeManager : Node "class.warrior", "status.stunned", "status.burning", - "status.enraged", "status.immune.fire", "cues.damage.fire", "events.combat.damage", "events.combat.hit", - "cooldown.fireball" + "cooldown.empoweredAction", ]); - - public ForgeManager() - { - } } \ No newline at end of file diff --git a/tools/ForgeManager.cs.uid b/forge/ForgeManager.cs.uid similarity index 100% rename from tools/ForgeManager.cs.uid rename to forge/ForgeManager.cs.uid diff --git a/forge/abilities/EmpoweredActionBehavior.cs b/forge/abilities/EmpoweredActionBehavior.cs new file mode 100644 index 00000000..3034e084 --- /dev/null +++ b/forge/abilities/EmpoweredActionBehavior.cs @@ -0,0 +1,56 @@ +using Gamesmiths.Forge.Abilities; +using Gamesmiths.Forge.Effects; +using Gamesmiths.Forge.Effects.Components; +using Gamesmiths.Forge.Effects.Duration; +using Gamesmiths.Forge.Effects.Magnitudes; +using Gamesmiths.Forge.Effects.Modifiers; +using Gamesmiths.Forge.Tags; + +namespace Movementtests.forge.abilities; + +public class EmpoweredAction(TagsManager tagsManager) +{ + public EffectData EmpoweredActionCostEffect = new( + "Empowered Action Mana Cost", + new DurationData(DurationType.Instant), + new[] { + new Modifier( + "PlayerAttributeSet.Mana", + ModifierOperation.FlatBonus, + new ModifierMagnitude( + MagnitudeCalculationType.ScalableFloat, + new ScalableFloat(-20) + ) + ) + }); + + public EffectData EmpoweredActionCooldown = new( + "Empowered Action Cooldown", + new DurationData( + DurationType.HasDuration, + new ModifierMagnitude( + MagnitudeCalculationType.ScalableFloat, + new ScalableFloat(1.0f))), + effectComponents: new[] { + new ModifierTagsEffectComponent( + tagsManager.RequestTagContainer(new[] { "cooldown.empoweredAction" }) + ) + }); + +} + + +public class EmpoweredActionBehavior : IAbilityBehavior +{ + public void OnStarted(AbilityBehaviorContext context) + { + // Apply costs and cooldowns + context.AbilityHandle.CommitAbility(); + context.InstanceHandle.End(); + } + + public void OnEnded(AbilityBehaviorContext context) + { + // Do any necessary cleanups + } +} \ No newline at end of file diff --git a/forge/abilities/EmpoweredActionBehavior.cs.uid b/forge/abilities/EmpoweredActionBehavior.cs.uid new file mode 100644 index 00000000..b8e46822 --- /dev/null +++ b/forge/abilities/EmpoweredActionBehavior.cs.uid @@ -0,0 +1 @@ +uid://d0l07gcx1ef18 diff --git a/scenes/enemies/Enemy.cs b/scenes/enemies/Enemy.cs index 9b86f798..9c8e9f5c 100644 --- a/scenes/enemies/Enemy.cs +++ b/scenes/enemies/Enemy.cs @@ -1,7 +1,14 @@ using System; +using Gamesmiths.Forge.Core; +using Gamesmiths.Forge.Effects; +using Gamesmiths.Forge.Events; +using Gamesmiths.Forge.Tags; using Godot; using Movementtests.interfaces; +using Movementtests.scenes.enemies; +using Movementtests.scenes.player_controller.scripts; using Movementtests.systems; +using Movementtests.tools; [GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_beetle.png")] public partial class Enemy : CharacterBody3D, @@ -13,7 +20,8 @@ public partial class Enemy : CharacterBody3D, ISpawnable, IKnockbackable, ITargetable, - IStunnable + IStunnable, + IForgeEntity { // Signals and events public event Action DamageTaken = null!; @@ -55,6 +63,12 @@ public partial class Enemy : CharacterBody3D, set => CHealth.CurrentHealth = value; } + public EntityAttributes Attributes { get; set; } = null!; + public EntityTags Tags { get; set; } = null!; + public EffectsManager EffectsManager { get; set; } = null!; + public EntityAbilities Abilities { get; set; } = null!; + public EventManager Events { get; set; } = null!; + // Private stuff private Area3D _damageBox = null!; internal Node3D _target = null!; @@ -71,6 +85,21 @@ public partial class Enemy : CharacterBody3D, _damageBox = GetNode("DamageBox"); _target = GetNode("CTarget"); + // Forge stuff + var forgeManager = GetTree().Root.GetNode("ForgeManager")!; + var baseTags = new TagContainer( + forgeManager.TagsManager, + [ + Tag.RequestTag(forgeManager.TagsManager, "character.player"), + Tag.RequestTag(forgeManager.TagsManager, "class.warrior") + ]); + + Attributes = new EntityAttributes(new EnemyAttributeSet()); + Tags = new EntityTags(baseTags); + EffectsManager = new EffectsManager(this, forgeManager.CuesManager); + Abilities = new(this); + Events = new(); + CDamageable = (GetNode("CDamageable") as IDamageable)!; CMovement = (GetNode("CMovement") as IMoveable)!; CHealth = (GetNode("CHealth") as IHealthable)!; diff --git a/scenes/enemies/EnemyAttributeSet.cs b/scenes/enemies/EnemyAttributeSet.cs new file mode 100644 index 00000000..194a3f02 --- /dev/null +++ b/scenes/enemies/EnemyAttributeSet.cs @@ -0,0 +1,16 @@ +using Gamesmiths.Forge.Attributes; +namespace Movementtests.scenes.enemies; + +public class EnemyAttributeSet : AttributeSet +{ + public EntityAttribute Health { get; } + public EntityAttribute Strength { get; } + public EntityAttribute Speed { get; } + + public EnemyAttributeSet() + { + Health = InitializeAttribute(nameof(Health), 100, 0, 150); + Strength = InitializeAttribute(nameof(Strength), 10, 0, 99); + Speed = InitializeAttribute(nameof(Speed), 5, 0, 10); + } +} \ No newline at end of file diff --git a/scenes/enemies/EnemyAttributeSet.cs.uid b/scenes/enemies/EnemyAttributeSet.cs.uid new file mode 100644 index 00000000..37745accf --- /dev/null +++ b/scenes/enemies/EnemyAttributeSet.cs.uid @@ -0,0 +1 @@ +uid://nqxdkkg3l7go diff --git a/scenes/player_controller/scripts/PlayerAttributeSet.cs b/scenes/player_controller/scripts/PlayerAttributeSet.cs index 66502bdc..13b0548d 100644 --- a/scenes/player_controller/scripts/PlayerAttributeSet.cs +++ b/scenes/player_controller/scripts/PlayerAttributeSet.cs @@ -11,7 +11,6 @@ public class PlayerAttributeSet : AttributeSet public PlayerAttributeSet() { - // Initialize the attributes with the current, min and max values. Health = InitializeAttribute(nameof(Health), 100, 0, 150); Mana = InitializeAttribute(nameof(Mana), 100, 0, 100); Strength = InitializeAttribute(nameof(Strength), 10, 0, 99); diff --git a/scenes/player_controller/scripts/PlayerController.cs b/scenes/player_controller/scripts/PlayerController.cs index 9e79b2f3..09faea61 100644 --- a/scenes/player_controller/scripts/PlayerController.cs +++ b/scenes/player_controller/scripts/PlayerController.cs @@ -1,17 +1,25 @@ using System; using System.Collections.Generic; +using Gamesmiths.Forge.Abilities; using Gamesmiths.Forge.Core; using Gamesmiths.Forge.Effects; +using Gamesmiths.Forge.Effects.Components; +using Gamesmiths.Forge.Effects.Duration; +using Gamesmiths.Forge.Effects.Magnitudes; using Gamesmiths.Forge.Events; using Gamesmiths.Forge.Tags; + using Godot; using GodotStateCharts; + 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 RustyOptions; [GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_character.png")] @@ -398,6 +406,8 @@ public partial class PlayerController : CharacterBody3D, private ShapeCast3D _closeEnemyDetector = null!; private RayCast3D _aimAssisRayCast = null!; private Camera3D _camera = null!; + + private AbilityHandle? _empoweredActionHandle; public override void _Ready() { @@ -428,12 +438,26 @@ public partial class PlayerController : CharacterBody3D, EffectsManager = new EffectsManager(this, forgeManager.CuesManager); Abilities = new(this); Events = new(); + + var empoweredAction = new EmpoweredAction(forgeManager.TagsManager); + var empoweredActionData = new AbilityData( + name: "Empowered Action", + costEffect: empoweredAction.EmpoweredActionCostEffect, + cooldownEffects: [empoweredAction.EmpoweredActionCooldown], + instancingPolicy: AbilityInstancingPolicy.PerEntity, + behaviorFactory: () => new EmpoweredActionBehavior()); + + // Grant permanently + _empoweredActionHandle = Abilities.GrantAbilityPermanently( + empoweredActionData, + abilityLevel: 1, + levelOverridePolicy: LevelComparison.None, + sourceEntity: this); var health = Attributes["PlayerAttributeSet.Health"].CurrentValue; // 100 var mana = Attributes["PlayerAttributeSet.Mana"].CurrentValue; // 100 var strength = Attributes["PlayerAttributeSet.Strength"].CurrentValue; // 10 var speed = Attributes["PlayerAttributeSet.Speed"].CurrentValue; // 5 - GD.Print(health, mana, strength, speed); // DashIndicator = GetNode("%DashIndicator"); PowerCooldownIndicator = GetNode("%DashCooldownIndicator"); @@ -1913,10 +1937,47 @@ public partial class PlayerController : CharacterBody3D, public bool CanPerformEmpoweredAction() { + if(_empoweredActionHandle == null) return false; + var cooldowns = _empoweredActionHandle.GetCooldownData(); + foreach (var cd in cooldowns) + { + //GD.Print($"Cooldown remaining: {cd.RemainingTime}"); + } + var costs = _empoweredActionHandle.GetCostData(); + foreach (var cost in costs) + { + // Assuming you want to check Mana costs + if (cost.Attribute == "PlayerAttributeSet.Mana") + { + //GD.Print($"Mana Cost: {cost.Cost}"); + } + } + + var canActivate = _empoweredActionHandle.CanActivate(out var failures); + if (!canActivate) + { + GD.PrintErr($"Cannot activate empowered action: {failures}"); + if (failures.HasFlag(AbilityActivationFailures.Cooldown)) GD.PrintErr("In Cooldown"); + if (failures.HasFlag(AbilityActivationFailures.InsufficientResources)) GD.PrintErr("Not Enough Mana"); + } + return canActivate; return EmpoweredActionsLeft > 0 && TutorialDone; } public void PerformEmpoweredAction() { + if(_empoweredActionHandle == null) return; + var canActivate = _empoweredActionHandle.Activate(out var failures); + if (!canActivate) + { + GD.PrintErr($"Cannot activate empowered action: {failures}"); + if (failures.HasFlag(AbilityActivationFailures.Cooldown)) GD.PrintErr("In Cooldown"); + if (failures.HasFlag(AbilityActivationFailures.InsufficientResources)) GD.PrintErr("Not Enough Mana"); + } + else + { + GD.Print($"Remaining mana: {Attributes["PlayerAttributeSet.Mana"].CurrentValue}"); + } + _isWallJumpAvailable = true; _canDashAirborne = true; EmpoweredActionsLeft--;