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--;