From cf43f77ce7ea656edd3d7b9909ec5a493ced4878 Mon Sep 17 00:00:00 2001 From: Lex Date: Tue, 21 Jul 2026 23:37:46 -0300 Subject: [PATCH 1/2] Refactored inputs for GrantAbilityNodes --- .../Nodes/GrantAbilityNodesTests.cs | 19 ++++++++---- .../Action/GrantAbilityPermanentlyNode.cs | 18 +++++------ .../Nodes/State/GrantAbilityNode.cs | 30 +++++++------------ .../action/grant-ability-permanently-node.md | 4 +-- .../nodes/state/grant-ability-node.md | 10 +++---- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/Forge.Tests/Statescript/Nodes/GrantAbilityNodesTests.cs b/Forge.Tests/Statescript/Nodes/GrantAbilityNodesTests.cs index bb77781..3325921 100644 --- a/Forge.Tests/Statescript/Nodes/GrantAbilityNodesTests.cs +++ b/Forge.Tests/Statescript/Nodes/GrantAbilityNodesTests.cs @@ -33,7 +33,7 @@ public void Grant_ability_node_grants_while_active_and_revokes_on_deactivation() var grantNode = new GrantAbilityNode(); grantNode.BindInput(GrantAbilityNode.AbilityDataInput, "abilityData"); - grantNode.BindInput(GrantAbilityNode.TargetInput, "target"); + grantNode.BindInput(GrantAbilityNode.EntityInput, "target"); grantNode.BindOutput(GrantAbilityNode.AbilityOutput, "grantedAbility"); graph.AddNode(grantNode); @@ -60,7 +60,7 @@ public void Grant_ability_node_grants_while_active_and_revokes_on_deactivation() [Fact] [Trait("Graph", "GrantAbility")] - public void Grant_ability_node_can_activate_the_granted_ability() + public void Grant_ability_node_output_feeds_try_activate_ability_node() { var owner = new TestEntity(_tagsManager, _cuesManager); @@ -78,15 +78,24 @@ public void Grant_ability_node_can_activate_the_granted_ability() var graph = new Graph(); graph.VariableDefinitions.DefineObjectVariable("abilityData", abilityData); graph.VariableDefinitions.DefineObjectVariable("target", owner); + graph.VariableDefinitions.DefineObjectVariable("grantedAbility"); - var grantNode = new GrantAbilityNode(tryActivateOnGrant: true); + var grantNode = new GrantAbilityNode(); grantNode.BindInput(GrantAbilityNode.AbilityDataInput, "abilityData"); - grantNode.BindInput(GrantAbilityNode.TargetInput, "target"); + grantNode.BindInput(GrantAbilityNode.EntityInput, "target"); + grantNode.BindOutput(GrantAbilityNode.AbilityOutput, "grantedAbility"); + + var activateNode = new TryActivateAbilityNode(); + activateNode.BindInput(TryActivateAbilityNode.AbilityInput, "grantedAbility"); graph.AddNode(grantNode); + graph.AddNode(activateNode); graph.AddConnection(new Connection( graph.EntryNode.OutputPorts[EntryNode.OutputPort], grantNode.InputPorts[StateNode.InputPort])); + graph.AddConnection(new Connection( + grantNode.OutputPorts[StateNode.OnActivatePort], + activateNode.InputPorts[ConditionNode.InputPort])); var processor = new GraphProcessor(graph); processor.StartGraph(); @@ -107,7 +116,7 @@ public void Grant_ability_permanently_node_grants_beyond_the_graph_lifetime() var grantNode = new GrantAbilityPermanentlyNode(); grantNode.BindInput(GrantAbilityPermanentlyNode.AbilityDataInput, "abilityData"); - grantNode.BindInput(GrantAbilityPermanentlyNode.TargetInput, "target"); + grantNode.BindInput(GrantAbilityPermanentlyNode.EntityInput, "target"); graph.AddNode(grantNode); graph.AddConnection(new Connection( diff --git a/Forge/Statescript/Nodes/Action/GrantAbilityPermanentlyNode.cs b/Forge/Statescript/Nodes/Action/GrantAbilityPermanentlyNode.cs index e8bcd07..858aeae 100644 --- a/Forge/Statescript/Nodes/Action/GrantAbilityPermanentlyNode.cs +++ b/Forge/Statescript/Nodes/Action/GrantAbilityPermanentlyNode.cs @@ -12,9 +12,9 @@ namespace Gamesmiths.Forge.Statescript.Nodes.Action; /// Permanent grants cannot be revoked or inhibited, use them for unlock-style progression. For grants tied to /// a graph state's lifetime, use the GrantAbility state node instead; for data-driven grants, use effects with a /// grant-ability component. -/// The ability-data input must resolve to an . The target input defaults to the -/// ability context's owner when unbound. The level input defaults to the ability context's level, or 1 -/// without a context. +/// The ability-data input must resolve to an . The entity input selects who receives +/// the grant, defaulting to the ability context's owner when unbound. The level input defaults to the ability +/// context's level, or 1 without a context. /// The granted is written to the node's output variable. /// /// When the ability is already granted, which level relationships override the @@ -29,7 +29,7 @@ public class GrantAbilityPermanentlyNode(LevelComparison levelOverridePolicy = L /// /// Input property index for the entity to grant the ability on. /// - public const byte TargetInput = 1; + public const byte EntityInput = 1; /// /// Input property index for the ability level. @@ -55,7 +55,7 @@ public class GrantAbilityPermanentlyNode(LevelComparison levelOverridePolicy = L protected override void DefineParameters(List inputProperties, List outputVariables) { inputProperties.Add(new InputProperty("Ability Data", typeof(AbilityData))); - inputProperties.Add(new InputProperty("Target", typeof(IForgeEntity))); + inputProperties.Add(new InputProperty("Entity", typeof(IForgeEntity))); inputProperties.Add(new InputProperty("Level", typeof(int))); inputProperties.Add(new InputProperty("Source", typeof(IForgeEntity))); outputVariables.Add(new OutputVariable("Ability", typeof(AbilityHandle))); @@ -72,11 +72,11 @@ protected override void Execute(GraphContext graphContext) return; } - IForgeEntity? target = AbilityNodeUtilities.ResolveEntityOrOwner( + IForgeEntity? entity = AbilityNodeUtilities.ResolveEntityOrOwner( graphContext, - InputProperties[TargetInput].BoundName); + InputProperties[EntityInput].BoundName); - if (target is null) + if (entity is null) { return; } @@ -86,7 +86,7 @@ protected override void Execute(GraphContext graphContext) graphContext, InputProperties[SourceInput].BoundName); - AbilityHandle handle = target.Abilities.GrantAbilityPermanently( + AbilityHandle handle = entity.Abilities.GrantAbilityPermanently( abilityData, level, _levelOverridePolicy, diff --git a/Forge/Statescript/Nodes/State/GrantAbilityNode.cs b/Forge/Statescript/Nodes/State/GrantAbilityNode.cs index 228d9d1..85b81d9 100644 --- a/Forge/Statescript/Nodes/State/GrantAbilityNode.cs +++ b/Forge/Statescript/Nodes/State/GrantAbilityNode.cs @@ -10,11 +10,11 @@ namespace Gamesmiths.Forge.Statescript.Nodes.State; /// on deactivation. /// /// -/// The ability-data input must resolve to an . The target input selects the entity to -/// grant on, defaulting to the ability context's owner when unbound. The level input defaults to the ability +/// The ability-data input must resolve to an . The entity input selects who receives +/// the grant, defaulting to the ability context's owner when unbound. The level input defaults to the ability /// context's level, or 1 without a context. The optional source input records the granting entity. /// The granted is written to the node's output variable, so the graph can activate -/// or inspect the granted ability. +/// or inspect the granted ability, for example through a TryActivateAbility node. /// Grants are reference counted per source: if other grant sources (such as effects) also granted the same /// ability, removing this node's grant only removes its own share. /// @@ -22,11 +22,9 @@ namespace Gamesmiths.Forge.Statescript.Nodes.State; /// . /// When the ability is already granted, which level relationships override the /// existing level. -/// Whether to try activating the ability right after granting it. public class GrantAbilityNode( AbilityDeactivationPolicy removalPolicy = AbilityDeactivationPolicy.CancelImmediately, - LevelComparison levelOverridePolicy = LevelComparison.None, - bool tryActivateOnGrant = false) : StateNode + LevelComparison levelOverridePolicy = LevelComparison.None) : StateNode { /// /// Input property index for the ability data to grant. @@ -36,7 +34,7 @@ public class GrantAbilityNode( /// /// Input property index for the entity to grant the ability on. /// - public const byte TargetInput = 1; + public const byte EntityInput = 1; /// /// Input property index for the ability level. @@ -55,7 +53,6 @@ public class GrantAbilityNode( private readonly AbilityDeactivationPolicy _removalPolicy = removalPolicy; private readonly LevelComparison _levelOverridePolicy = levelOverridePolicy; - private readonly bool _tryActivateOnGrant = tryActivateOnGrant; /// public override string Description => "Grants an ability while active, removing the grant on deactivation."; @@ -64,7 +61,7 @@ public class GrantAbilityNode( protected override void DefineParameters(List inputProperties, List outputVariables) { inputProperties.Add(new InputProperty("Ability Data", typeof(AbilityData))); - inputProperties.Add(new InputProperty("Target", typeof(IForgeEntity))); + inputProperties.Add(new InputProperty("Entity", typeof(IForgeEntity))); inputProperties.Add(new InputProperty("Level", typeof(int))); inputProperties.Add(new InputProperty("Source", typeof(IForgeEntity))); outputVariables.Add(new OutputVariable("Ability", typeof(AbilityHandle))); @@ -86,11 +83,11 @@ protected override void OnActivate(GraphContext graphContext) return; } - IForgeEntity? target = AbilityNodeUtilities.ResolveEntityOrOwner( + IForgeEntity? entity = AbilityNodeUtilities.ResolveEntityOrOwner( graphContext, - InputProperties[TargetInput].BoundName); + InputProperties[EntityInput].BoundName); - if (target is null) + if (entity is null) { return; } @@ -102,7 +99,7 @@ protected override void OnActivate(GraphContext graphContext) var grantSource = new StatescriptGrantSource(_removalPolicy, AbilityDeactivationPolicy.Ignore); - AbilityHandle handle = target.Abilities.GrantAbility( + AbilityHandle handle = entity.Abilities.GrantAbility( abilityData, level, _levelOverridePolicy, @@ -110,15 +107,10 @@ protected override void OnActivate(GraphContext graphContext) source); nodeContext.GrantedHandle = handle; - nodeContext.GrantedOn = target; + nodeContext.GrantedOn = entity; nodeContext.GrantSource = grantSource; AbilityNodeUtilities.WriteHandleOutput(graphContext, OutputVariables[AbilityOutput], handle); - - if (_tryActivateOnGrant) - { - handle.Activate(out _); - } } /// diff --git a/docs/statescript/nodes/action/grant-ability-permanently-node.md b/docs/statescript/nodes/action/grant-ability-permanently-node.md index 1097914..dc2b675 100644 --- a/docs/statescript/nodes/action/grant-ability-permanently-node.md +++ b/docs/statescript/nodes/action/grant-ability-permanently-node.md @@ -38,7 +38,7 @@ new GrantAbilityPermanentlyNode(levelOverridePolicy = LevelComparison.None) | Index | Label | Type | Description | |-------|-------|------|-------------| | 0 | Ability Data | `AbilityData` | The ability to grant. | -| 1 | Target | `IForgeEntity` | Optional. The entity to grant on. Defaults to the ability context's owner. | +| 1 | Entity | `IForgeEntity` | Optional. The entity to grant on. Defaults to the ability context's owner. | | 2 | Level | `int` | Optional. The grant level. Defaults to the ability context's level, or `1`. | | 3 | Source | `IForgeEntity` | Optional. The granting source entity. | @@ -50,7 +50,7 @@ new GrantAbilityPermanentlyNode(levelOverridePolicy = LevelComparison.None) ## Behavior -1. Resolves the ability data, target (default owner), level (default context level), and optional source. +1. Resolves the ability data, entity (default owner), level (default context level), and optional source. 2. Calls `EntityAbilities.GrantAbilityPermanently(...)`. 3. Writes the resulting `AbilityHandle` to the **Ability** output when bound. diff --git a/docs/statescript/nodes/state/grant-ability-node.md b/docs/statescript/nodes/state/grant-ability-node.md index f64e07b..e1f5e70 100644 --- a/docs/statescript/nodes/state/grant-ability-node.md +++ b/docs/statescript/nodes/state/grant-ability-node.md @@ -17,15 +17,13 @@ Standard state ports (the grant/revoke happens on activate/deactivate). ```csharp new GrantAbilityNode( removalPolicy = AbilityDeactivationPolicy.CancelImmediately, - levelOverridePolicy = LevelComparison.None, - tryActivateOnGrant = false) + levelOverridePolicy = LevelComparison.None) ``` | Parameter | Type | Description | |-----------|------|-------------| | removalPolicy | `AbilityDeactivationPolicy` | How the ability is removed when the node deactivates. | | levelOverridePolicy | `LevelComparison` | When the ability is already granted, which level relationships override the existing level. | -| tryActivateOnGrant | `bool` | Whether to try activating the ability right after granting it. | ## Parameters @@ -34,7 +32,7 @@ new GrantAbilityNode( | Index | Label | Type | Description | |-------|-------|------|-------------| | 0 | Ability Data | `AbilityData` | The ability to grant. | -| 1 | Target | `IForgeEntity` | Optional. The entity to grant on. Defaults to the ability context's owner. | +| 1 | Entity | `IForgeEntity` | Optional. The entity to grant on. Defaults to the ability context's owner. | | 2 | Level | `int` | Optional. The grant level. Defaults to the context level, or `1`. | | 3 | Source | `IForgeEntity` | Optional. The granting source entity. | @@ -46,9 +44,11 @@ new GrantAbilityNode( ## Behavior -1. On activation, grants the ability through the internal grant-source machinery (the same path effects use), optionally activating it, and writes the handle to the **Ability** output. +1. On activation, grants the ability through the internal grant-source machinery (the same path effects use) and writes the handle to the **Ability** output. 2. On deactivation, removes this node's grant according to `removalPolicy`. +To activate the granted ability, feed the **Ability** output into a [TryActivateAbilityNode](../condition/try-activate-ability-node.md). + ## Usage ```csharp From 8eaf9edf89e756c8a55d0e19dec6df5deee0dc73 Mon Sep 17 00:00:00 2001 From: Lex Date: Tue, 21 Jul 2026 23:52:37 -0300 Subject: [PATCH 2/2] Linked doc --- Forge/Statescript/Nodes/State/GrantAbilityNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Forge/Statescript/Nodes/State/GrantAbilityNode.cs b/Forge/Statescript/Nodes/State/GrantAbilityNode.cs index 85b81d9..8951b1f 100644 --- a/Forge/Statescript/Nodes/State/GrantAbilityNode.cs +++ b/Forge/Statescript/Nodes/State/GrantAbilityNode.cs @@ -14,7 +14,7 @@ namespace Gamesmiths.Forge.Statescript.Nodes.State; /// the grant, defaulting to the ability context's owner when unbound. The level input defaults to the ability /// context's level, or 1 without a context. The optional source input records the granting entity. /// The granted is written to the node's output variable, so the graph can activate -/// or inspect the granted ability, for example through a TryActivateAbility node. +/// or inspect the granted ability, for example through a . /// Grants are reference counted per source: if other grant sources (such as effects) also granted the same /// ability, removing this node's grant only removes its own share. ///