Compare commits

..

4 Commits

Author SHA1 Message Date
42ff38f39b yow it's working or wat
Some checks failed
Create tag and build when new code gets to main / BumpTag (push) Successful in 24s
Create tag and build when new code gets to main / Export (push) Failing after 4m23s
2026-03-29 17:30:14 +02:00
dafb0c96cc fix manabar cue issue 2026-03-28 18:40:03 +01:00
ef454e9502 Trying custom execution periodic data 2026-03-28 18:20:47 +01:00
cc70fb361b WIP: integrating forge systems into the game, now trying periodic abilities 2026-03-28 11:43:34 +01:00
15 changed files with 404 additions and 190 deletions

View File

@@ -11,18 +11,33 @@ public partial class ForgeManager : Node
[
// entities
"character.player",
"character.enemy",
"weapon",
// Statuses
"status.stunned",
"status.weapon.inHand",
"status.weapon.flying",
"status.weapon.planted",
// Abilities
"abilities.weapon.land",
"abilities.weapon.flying",
"abilities.weapon.left",
// Events
"events.combat.damage",
"events.combat.hit",
"events.weapon.land",
"events.weapon.flyingTick",
"events.weapon.startedFlying",
"events.weapon.stoppedFlying",
"events.weapon.handToFlying",
"events.weapon.flyingToHand",
"events.weapon.plantedToHand",
"events.weapon.plantedToFlying",
"events.weapon.planted",
// Cooldowns
"cooldown.empoweredAction",

View File

@@ -13,28 +13,13 @@ using Movementtests.interfaces;
namespace Movementtests.forge.abilities;
[GlobalClass]
public partial class RAbilityBase(float cost, float cooldown) : Resource, IAbilityBase
public partial class RAbilityBase : Resource
{
[Export(PropertyHint.Range, "0,100,1,or_greater")]
public float Cost { get; set; } = cost;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float Cooldown { get; set; } = cooldown;
public RAbilityBase() : this(20.0f, 0.0f)
public RAbilityBase()
{
}
public virtual AbilityData Ability(TagsManager tagsManager, Node3D owner)
{
throw new NotImplementedException();
}
public virtual EffectData CostEffect(TagsManager tagsManager)
{
throw new NotImplementedException();
}
public virtual EffectData CooldownEffect(TagsManager tagsManager)
public virtual AbilityData Ability(TagContainer? tags, Node3D owner)
{
throw new NotImplementedException();
}

View File

@@ -0,0 +1,73 @@
using System;
using Gamesmiths.Forge.Abilities;
using Gamesmiths.Forge.Cues;
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;
using Godot;
using Movementtests.interfaces;
using Movementtests.systems;
namespace Movementtests.forge.abilities;
public record struct ExplodingSwordCreation(Node3D Owner);
[GlobalClass, Icon("res://assets/ui/IconGodotNode/white/icon_projectile.png")]
public partial class RExplodingSword(PackedScene? explosion) : Resource, IAbilityBase<ExplodingSwordCreation, WeaponEventPayload>
{
[Export] public PackedScene? Explosion { get; set; } = explosion;
public RExplodingSword() : this(null) {}
public AbilityData Ability(ExplodingSwordCreation creationData, TagContainer? tags)
{
return new AbilityData(
name: "Exploding Sword Throw",
abilityTags: tags,
instancingPolicy: AbilityInstancingPolicy.PerEntity,
behaviorFactory: () => new ExplodingSwordThrowBehavior<WeaponEventPayload>(creationData.Owner, Explosion));
}
public IAbilityBehavior<WeaponEventPayload> Behavior(ExplodingSwordCreation creationData)
{
return new ExplodingSwordThrowBehavior<WeaponEventPayload>(creationData.Owner, Explosion);
}
}
public class ExplodingSwordThrowBehavior<TPayload>(Node3D owner, PackedScene? explosion) : IAbilityBehavior<TPayload>
{
private Node3D _owner = owner;
private PackedScene? _explosion = explosion;
public void OnStarted(AbilityBehaviorContext context, TPayload payload)
{
if (_explosion?.Instantiate() is not Explosion explosion)
{
GD.Print("Cannot instantiate");
context.InstanceHandle.End();
return;
}
if (!_owner.IsInsideTree())
{
GD.Print("Not inside tree");
context.InstanceHandle.End();
return;
}
GD.Print("EXPLOSION");
explosion.Radius = 6f;
_owner.GetTree().GetRoot().CallDeferred(Node.MethodName.AddChild, explosion);
explosion.CallDeferred(Node3D.MethodName.SetGlobalPosition, _owner.GlobalPosition);
context.AbilityHandle.CommitAbility();
context.InstanceHandle.End();
}
public void OnEnded(AbilityBehaviorContext context)
{
}
}

View File

@@ -1,104 +0,0 @@
using Gamesmiths.Forge.Abilities;
using Gamesmiths.Forge.Cues;
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;
using Godot;
namespace Movementtests.forge.abilities;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/white/icon_projectile.png")]
public partial class RExplodingSwordThrow(PackedScene? explosion, float cost, float cooldown) : RAbilityBase(cost, cooldown)
{
[Export] public PackedScene? Explosion { get; set; } = explosion;
public RExplodingSwordThrow() : this(null, 20.0f, 0.0f)
{
}
public override AbilityData Ability(TagsManager tagsManager, Node3D owner)
{
return new AbilityData(
name: "Exploding Sword Throw",
costEffect: CostEffect(tagsManager),
cooldownEffects: [CooldownEffect(tagsManager)],
abilityTags: Tag.RequestTag(tagsManager, "abilities.weapon.land").GetSingleTagContainer(),
instancingPolicy: AbilityInstancingPolicy.PerEntity,
behaviorFactory: () => new ExplodingSwordThrowBehavior(owner, Explosion));
}
public override EffectData CostEffect(TagsManager tagsManager)
{
return new(
"Exploding Sword Throw Mana Cost",
new DurationData(DurationType.Instant),
new[]
{
new Modifier(
"PlayerAttributeSet.Mana",
ModifierOperation.FlatBonus,
new ModifierMagnitude(
MagnitudeCalculationType.ScalableFloat,
new ScalableFloat(-Cost)
)
)
},
cues: new []
{
new CueData(
CueTags: Tag.RequestTag(tagsManager, "cues.resources.mana").GetSingleTagContainer(),
MinValue: 0,
MaxValue: 100,
MagnitudeType: CueMagnitudeType.AttributeValueChange,
MagnitudeAttribute: "PlayerAttributeSet.Mana"
)
});
}
public override EffectData CooldownEffect(TagsManager tagsManager)
{
return new(
"Exploding Sword Throw Cooldown",
new DurationData(
DurationType.HasDuration,
new ModifierMagnitude(
MagnitudeCalculationType.ScalableFloat,
new ScalableFloat(Cooldown))),
effectComponents: new[]
{
new ModifierTagsEffectComponent(
tagsManager.RequestTagContainer(new[] { "cooldown.empoweredSwordThrow" })
)
});
}
}
public class ExplodingSwordThrowBehavior(Node3D owner, PackedScene? explosion) : IAbilityBehavior
{
private Node3D _owner = owner;
private PackedScene? _explosion = explosion;
public void OnStarted(AbilityBehaviorContext context)
{
if (_explosion?.Instantiate() is not Explosion explosion)
{
context.InstanceHandle.End();
return;
}
explosion.Radius = 10f;
_owner.GetTree().GetRoot().AddChild(explosion);
explosion.GlobalPosition = _owner.GlobalPosition;
context.AbilityHandle.CommitAbility();
context.InstanceHandle.End();
}
public void OnEnded(AbilityBehaviorContext context)
{
}
}

View File

@@ -0,0 +1,30 @@
using System.Collections.Generic;
using Gamesmiths.Forge.Attributes;
using Gamesmiths.Forge.Core;
using Gamesmiths.Forge.Effects;
using Gamesmiths.Forge.Effects.Calculator;
using Gamesmiths.Forge.Effects.Magnitudes;
using Gamesmiths.Forge.Effects.Modifiers;
using Gamesmiths.Forge.Events;
using Godot;
using Movementtests.systems;
namespace Movementtests.tools.calculators;
public class FlyingWeaponExecution(WeaponSystem weaponSystem) : CustomExecution
{
public override ModifierEvaluatedData[] EvaluateExecution(Effect effect, IForgeEntity target, EffectEvaluatedData? effectEvaluatedData)
{
GD.Print("Custom execution executed");
weaponSystem.Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = weaponSystem.WeaponFlyingTickEventTag.GetSingleTagContainer()!,
Source = weaponSystem,
EventMagnitude = 12f,
Payload = new WeaponEventPayload(Message: "flying")
});
return [];
}
}

View File

@@ -0,0 +1 @@
uid://br7ut4lbau66w

View File

@@ -5,9 +5,8 @@ using Godot;
namespace Movementtests.interfaces;
public interface IAbilityBase
public interface IAbilityBase<TCreation, TPayload>
{
AbilityData Ability(TagsManager tagsManager, Node3D owner);
EffectData CostEffect(TagsManager tagsManager);
EffectData CooldownEffect(TagsManager tagsManager);
AbilityData Ability(TCreation creationData, TagContainer? tags);
IAbilityBehavior<TPayload> Behavior(TCreation creationData);
}

View File

@@ -90,8 +90,7 @@ public partial class Enemy : CharacterBody3D,
var baseTags = new TagContainer(
forgeManager.TagsManager,
[
Tag.RequestTag(forgeManager.TagsManager, "character.player"),
Tag.RequestTag(forgeManager.TagsManager, "class.warrior")
Tag.RequestTag(forgeManager.TagsManager, "character.enemy")
]);
Attributes = new EntityAttributes(new EnemyAttributeSet());

View File

@@ -7,7 +7,7 @@
[ext_resource type="Resource" uid="uid://bl5crtu1gkrtr" path="res://inputs/base_mode/base_mode.tres" id="3_cresl"]
[ext_resource type="Resource" uid="uid://dtmhtlix2amme" path="res://scenes/player_controller/resources/player_mana_regen.tres" id="3_n24vh"]
[ext_resource type="PackedScene" uid="uid://c4ikbhojckpnc" path="res://scenes/components/health/CHealth.tscn" id="3_q7bng"]
[ext_resource type="Script" uid="uid://rux15j7q78e8" path="res://forge/abilities/RExplodingSwordThrow.cs" id="4_11013"]
[ext_resource type="Resource" uid="uid://cdxbwirfiaipi" path="res://scenes/player_controller/resources/forge/exploding_sword_throw.tres" id="4_11013"]
[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"]
@@ -56,12 +56,6 @@
[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"]
[sub_resource type="Resource" id="Resource_5b7hb"]
script = ExtResource("4_11013")
Explosion = ExtResource("5_ue7xq")
Cost = 10.0
metadata/_custom_type_script = "uid://rux15j7q78e8"
[sub_resource type="Resource" id="Resource_cb2lu"]
script = ExtResource("2_x835q")
DamageDealt = 10.0
@@ -126,7 +120,7 @@ collision_mask = 272
script = ExtResource("1_poq2x")
EmpoweredAction = ExtResource("7_qheee")
ManaRegen = ExtResource("3_n24vh")
AbilityLoadout = [SubResource("Resource_5b7hb")]
AbilityLoadout = [ExtResource("4_11013")]
AimAssistStrength = 0.3
AimAssistReductionWhenCloseToTarget = 0.1
AimAssistReductionStartDistance = 8.0

View File

@@ -90,16 +90,9 @@ public partial class PlayerUi : Control, ICueHandler
public void OnExecute(IForgeEntity? target, CueParameters? parameters)
{
// One-shot effect (like impact)
// Called when an instant effect with this cue is applied
// Also called when a periodic effect with this cue executes its period
if (target == null || !parameters.HasValue) return;
if (target == null || !parameters.HasValue || !IsInstanceValid(_manabar)) return;
// Extract parameters
float magnitude = parameters.Value.Magnitude;
// Play effects scaled by magnitude
// PlayFireImpactSound(normalizedMagnitude);
// SpawnFireImpactParticles(target, magnitude);
_manabar.CurrentHealth += magnitude;
}

View File

@@ -1,18 +1,41 @@
using System;
using System.Collections.Generic;
using Gamesmiths.Forge.Abilities;
using Gamesmiths.Forge.Core;
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.Periodic;
using Gamesmiths.Forge.Events;
using Gamesmiths.Forge.Tags;
using Godot;
using GodotStateCharts;
using Movementtests.addons.godot_state_charts.csharp;
using Movementtests.forge.abilities;
using Movementtests.interfaces;
using Movementtests.scenes.player_controller.components.weapon;
using Movementtests.systems.damage;
using Movementtests.tools;
using Movementtests.tools.calculators;
namespace Movementtests.systems;
public record struct WeaponLandPayload(int Damage, bool IsCritical);
public record struct WeaponEventPayload(String Message);
public class ClosureBehavior<TPayload>(
Action<AbilityBehaviorContext, TPayload> callback) : IAbilityBehavior<TPayload>
{
public void OnStarted(AbilityBehaviorContext context, TPayload data)
{
callback(context, data);
context.InstanceHandle.End();
}
public void OnEnded(AbilityBehaviorContext context){}
}
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_sword.png")]
public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
@@ -36,11 +59,18 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
public EntityAbilities Abilities { get; set; } = null!;
public EventManager Events { get; set; } = null!;
private StateChart _weaponState = null!;
private StateChart _weaponState = null!;
public StateChartState InHandState = null!;
public StateChartState FlyingState = null!;
public StateChartState PlantedState = null!;
private Transition _handToFlying = null!;
private Transition _flyingToHand = null!;
private Transition _plantedToHand = null!;
private Transition _plantedToFlying = null!;
private Transition _toPlanted = null!;
private ShapeCast3D _dashCast3D = null!;
public Timer WeaponFlyingTick = null!;
private Transform3D _startTransform;
private Vector3 _startMeshRotation;
@@ -54,7 +84,23 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
public StandardMaterial3D WeaponLocationIndicatorMaterial { get; set; } = null!;
public MeshInstance3D WeaponMesh { get; set; } = null!;
public Tag WeaponLandTag;
public Tag WeaponFlyingTickEventTag;
public Tag WeaponStartedFlyingEventTag;
public Tag WeaponStoppedFlyingEventTag;
public Tag WeaponHandToFlyingEventTag;
public Tag WeaponFlyingToHandEventTag;
public Tag WeaponPlantedToHandEventTag;
public Tag WeaponPlantedToFlyingEventTag;
public Tag WeaponPlantedEventTag;
public Tag WeaponInHandStatusTag;
public Tag WeaponFlyingStatusTag;
public Tag WeaponPlantedStatusTag;
public Tag WeaponFlyingAbilityTag;
private RAbilityBase? _flyingAbility;
public List<RAbilityBase> AbilityLoadout { get; } = [];
public void Init()
{
@@ -62,10 +108,17 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand"));
FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying"));
PlantedState = StateChartState.Of(GetNode("StateChart/Root/Planted"));
_handToFlying = Transition.Of(GetNode("StateChart/Root/InHand/ToFlying"));
_flyingToHand = Transition.Of(GetNode("StateChart/Root/Flying/ToHand"));
_plantedToHand = Transition.Of(GetNode("StateChart/Root/Planted/ToHand"));
_plantedToFlying = Transition.Of(GetNode("StateChart/Root/Planted/ToFlying"));
_toPlanted = Transition.Of(GetNode("StateChart/Root/ToPlanted"));
WeaponLocationIndicator = GetNode<MeshInstance3D>("WeaponLocationIndicator");
WeaponLocationIndicator.Visible = false;
WeaponLocationIndicatorMaterial = (WeaponLocationIndicator.GetActiveMaterial(0) as StandardMaterial3D)!;
WeaponFlyingTick = GetNode<Timer>("WeaponFlyingTick");
WeaponMesh = GetNode<MeshInstance3D>("Weapon");
_startMeshRotation = WeaponMesh.Rotation;
@@ -74,12 +127,29 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
Freeze = true;
Visible = false;
// Forge
var tagsManager = ForgeManager.GetTagsManager(this);
var cuesManager = ForgeManager.GetCuesManager(this);
WeaponFlyingTickEventTag = Tag.RequestTag(tagsManager, "events.weapon.flyingTick");
WeaponStartedFlyingEventTag = Tag.RequestTag(tagsManager, "events.weapon.startedFlying");
WeaponStoppedFlyingEventTag = Tag.RequestTag(tagsManager, "events.weapon.stoppedFlying");
WeaponHandToFlyingEventTag = Tag.RequestTag(tagsManager, "events.weapon.handToFlying");
WeaponFlyingToHandEventTag = Tag.RequestTag(tagsManager, "events.weapon.flyingToHand");
WeaponPlantedToHandEventTag = Tag.RequestTag(tagsManager, "events.weapon.plantedToHand");
WeaponPlantedToFlyingEventTag = Tag.RequestTag(tagsManager, "events.weapon.plantedToFlying");
WeaponPlantedEventTag = Tag.RequestTag(tagsManager, "events.weapon.planted");
WeaponInHandStatusTag = Tag.RequestTag(tagsManager, "status.weapon.inHand");
WeaponFlyingStatusTag = Tag.RequestTag(tagsManager, "status.weapon.flying");
WeaponPlantedStatusTag = Tag.RequestTag(tagsManager, "status.weapon.planted");
WeaponFlyingAbilityTag = Tag.RequestTag(tagsManager,"abilities.weapon.flying");
var baseTags = new TagContainer(
tagsManager,
[
Tag.RequestTag(tagsManager, "weapon")
Tag.RequestTag(tagsManager, "weapon"),
]);
Attributes = new EntityAttributes(new WeaponAttributeSet());
@@ -88,12 +158,149 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
Abilities = new(this);
Events = new();
WeaponLandTag = Tag.RequestTag(tagsManager, "events.weapon.land");
CreateFlyingAbility();
BodyEntered += OnThrownWeaponReachesGround;
InHandState.StateExited += WeaponLeft;
InHandState.StateEntered += WeaponBack;
_handToFlying.Taken += () =>
{
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponHandToFlyingEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "handToFlying")
});
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponStartedFlyingEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "startedFlying")
});
};
_flyingToHand.Taken += () =>
{
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponFlyingToHandEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "flyingToHand")
});
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponStoppedFlyingEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "stoppedFlying")
});
};
_plantedToHand.Taken += () =>
{
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponPlantedToHandEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "plantedToHand")
});
};
_plantedToFlying.Taken += () =>
{
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponPlantedToFlyingEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "plantedToFlying")
});
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponStartedFlyingEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "startedFlying")
});
};
_toPlanted.Taken += () =>
{
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponPlantedEventTag.GetSingleTagContainer()!,
Source = this,
Target = _plantedEntity,
Payload = new WeaponEventPayload(Message: "planted")
});
Events.Raise(new EventData<WeaponEventPayload>
{
EventTags = WeaponStoppedFlyingEventTag.GetSingleTagContainer()!,
Source = this,
Payload = new WeaponEventPayload(Message: "stoppedFlying")
});
};
Events.Subscribe<WeaponEventPayload>(WeaponStoppedFlyingEventTag, data =>
{
GD.Print("This is removing the periodic effect to the flying weapon");
GD.Print(data.Payload.Message);
if (_flyingWeaponEffectHandle is { IsValid: true }) EffectsManager.RemoveEffect(_flyingWeaponEffectHandle);
});
}
private ActiveEffectHandle? _flyingWeaponEffectHandle;
public void CreateFlyingAbility()
{
var flyingWeaponEffectData = new EffectData(
"Flying Weapon Effect Data",
new DurationData(DurationType.Infinite),
customExecutions:
[
new FlyingWeaponExecution(this)
],
periodicData: new PeriodicData(new ScalableFloat(0.2f), false, PeriodInhibitionRemovedPolicy.ResetPeriod)
);
var weaponHandToFlyingAbilityData = new AbilityData(
name: "WeaponHandToFlyingSword",
abilityTags: WeaponFlyingAbilityTag.GetSingleTagContainer(),
instancingPolicy: AbilityInstancingPolicy.PerEntity,
abilityTriggerData: AbilityTriggerData.ForEvent<WeaponEventPayload>(WeaponStartedFlyingEventTag),
behaviorFactory: () => new ClosureBehavior<WeaponEventPayload>((ctx, payload) =>
{
GD.Print("This is applying the periodic effect to the flying weapon");
GD.Print(payload.Message);
_flyingWeaponEffectHandle = EffectsManager.ApplyEffect(new Effect(flyingWeaponEffectData, new EffectOwnership(this, this)));
}));
Abilities.GrantAbilityPermanently(weaponHandToFlyingAbilityData, 1, LevelComparison.None, this);
}
public void GrantNewAbilityForWeaponFly(RExplodingSword ability)
{
var weaponFlyingAbilityData = new AbilityData(
name: "WeaponFlyingSwordAbility",
abilityTags: WeaponFlyingAbilityTag.GetSingleTagContainer(),
instancingPolicy: AbilityInstancingPolicy.PerEntity,
abilityTriggerData: AbilityTriggerData.ForEvent<WeaponEventPayload>(WeaponFlyingTickEventTag),
behaviorFactory: () => ability.Behavior(new ExplodingSwordCreation(this)));
var weaponFlyGrantAbilityConfig = new GrantAbilityConfig(
weaponFlyingAbilityData,
ScalableLevel: new ScalableInt(1),
RemovalPolicy: AbilityDeactivationPolicy.CancelImmediately,
InhibitionPolicy: AbilityDeactivationPolicy.CancelImmediately,
TryActivateOnGrant: false,
TryActivateOnEnable: false,
LevelOverridePolicy: LevelComparison.Higher);
var weaponFlyGrantComponent = new GrantAbilityEffectComponent([weaponFlyGrantAbilityConfig]);
var weaponFlyGrantEffect = new EffectData(
"Grant Weapon Fly Ability",
new DurationData(DurationType.Infinite),
effectComponents: [weaponFlyGrantComponent]);
EffectsManager.ApplyEffect(new Effect(weaponFlyGrantEffect, new EffectOwnership(this, this)));
GD.Print("New weapon flight ability granted");
}
public void WeaponLeft()
@@ -121,15 +328,12 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal, Node collidedObject)
{
_weaponState.SendEvent("throw");
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 1f, 1f);
_throwDirection = (end - GlobalPosition).Normalized();
PlantLocation = collisionLocation;
PlantNormal = collisionNormal;
LookAt(end);
var tween = GetTree().CreateTween();
tween.TweenProperty(this, "global_position", end, StraightThrowDuration);
if (hasHit)
@@ -141,25 +345,14 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
tween.Finished += ThrowWeaponOnCurve;
}
public void RaiseWeaponLandEvent(IForgeEntity? victim = null)
{
Events.Raise(new EventData<WeaponLandPayload>
{
EventTags = WeaponLandTag.GetSingleTagContainer(),
Source = this,
Target = victim,
EventMagnitude = 25f,
Payload = new WeaponLandPayload(Damage: 25, IsCritical: true)
});
}
private IForgeEntity? _plantedEntity;
public void PlantInEnemy(Node3D enemy)
{
GetTree().GetRoot().CallDeferred(Node.MethodName.RemoveChild, this);
enemy.CallDeferred(Node.MethodName.AddChild, this);
if (enemy is IForgeEntity victim) RaiseWeaponLandEvent(victim);
else RaiseWeaponLandEvent();
if (enemy is IForgeEntity victim) _plantedEntity = victim;
else _plantedEntity = null;
if (enemy is IDamageable damageable)
{
@@ -170,6 +363,7 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
public void RethrowWeapon()
{
_weaponState.SendEvent("throw");
_throwDirection = Vector3.Up;
ThrowWeaponOnCurve();
}
@@ -182,17 +376,14 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
public void PlantWeaponInWall()
{
_weaponState.SendEvent("plant");
Freeze = true;
WeaponMesh.Rotation = _startMeshRotation;
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 0.2f, 0.2f);
if (PlantObject is Node3D node)
{
PlantInEnemy(node);
}
else RaiseWeaponLandEvent();
_weaponState.SendEvent("plant");
CallDeferred(Node3D.MethodName.SetGlobalPosition, PlantLocation);
CallDeferred(Node3D.MethodName.LookAt, GlobalTransform.Origin + PlantNormal, Vector3.Up, true);

View File

@@ -50,6 +50,9 @@ max_contacts_reported = 1
script = ExtResource("1_csqwk")
RDamage = SubResource("Resource_jpdh0")
[node name="WeaponFlyingTick" type="Timer" parent="." unique_id=656309486]
wait_time = 0.2
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=884463982]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0)
shape = SubResource("CylinderShape3D_avini")

View File

@@ -1,8 +1,10 @@
[gd_resource type="Resource" script_class="RExplodingSwordThrow" format=3 uid="uid://cdxbwirfiaipi"]
[gd_resource type="Resource" script_class="RExplodingSword" format=3 uid="uid://cdxbwirfiaipi"]
[ext_resource type="Script" uid="uid://rux15j7q78e8" path="res://forge/abilities/RExplodingSwordThrow.cs" id="1_5iq8v"]
[ext_resource type="PackedScene" uid="uid://duju3atqgltkg" path="res://scenes/explosion/explosion.tscn" id="1_aru71"]
[ext_resource type="Script" path="res://forge/abilities/RExplodingSword.cs" id="2_syk3q"]
[resource]
script = ExtResource("1_5iq8v")
Cost = 20.0
script = ExtResource("2_syk3q")
Explosion = ExtResource("1_aru71")
Cost = 10.0
metadata/_custom_type_script = "uid://rux15j7q78e8"

View File

@@ -3,10 +3,14 @@ using System.Collections.Generic;
using Gamesmiths.Forge.Abilities;
using Gamesmiths.Forge.Core;
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.Resources.Abilities;
using Gamesmiths.Forge.Tags;
using Godot;
@@ -19,6 +23,7 @@ using Movementtests.player_controller.Scripts;
using Movementtests.scenes.player_controller.scripts;
using Movementtests.tools;
using Movementtests.forge.abilities;
using Movementtests.tools.calculators;
using Movementtests.tools.effects;
using RustyOptions;
@@ -108,7 +113,7 @@ public partial class PlayerController : CharacterBody3D,
[ExportGroup("Abilities")]
[ExportSubgroup("WeaponThrow")]
[Export] public RAbilityBase[] AbilityLoadout = [];
[Export] public RExplodingSword[] AbilityLoadout = [];
// Combat stuff
[ExportCategory("Combat")]
@@ -707,28 +712,58 @@ public partial class PlayerController : CharacterBody3D,
foreach (var weaponLandAbility in AbilityLoadout)
{
var grantAbilityConfig = new GrantAbilityConfig(
weaponLandAbility.Ability(tagsManager, WeaponSystem),
var weaponLeftTag = Tag.RequestTag(tagsManager,"abilities.weapon.left").GetSingleTagContainer();
var leftGrantAbilityConfig = new GrantAbilityConfig(
weaponLandAbility.Ability(new ExplodingSwordCreation(WeaponSystem), weaponLeftTag),
ScalableLevel: new ScalableInt(1),
RemovalPolicy: AbilityDeactivationPolicy.CancelImmediately,
InhibitionPolicy: AbilityDeactivationPolicy.CancelImmediately,
TryActivateOnGrant: false,
TryActivateOnEnable: false,
LevelOverridePolicy: LevelComparison.Higher);
var grantComponent = new GrantAbilityEffectComponent([grantAbilityConfig]);
var grantEffect = new EffectData(
var leftGrantComponent = new GrantAbilityEffectComponent([leftGrantAbilityConfig]);
var leftGrantEffect = new EffectData(
"Grant Weapon Left Ability",
new DurationData(DurationType.Infinite),
effectComponents: [leftGrantComponent]);
EffectsManager.ApplyEffect(new Effect(leftGrantEffect, new EffectOwnership(this, this)));
var weaponLandedTag = Tag.RequestTag(tagsManager, "abilities.weapon.land").GetSingleTagContainer();
var landGrantAbilityConfig = new GrantAbilityConfig(
weaponLandAbility.Ability(new ExplodingSwordCreation(WeaponSystem), weaponLandedTag),
ScalableLevel: new ScalableInt(1),
RemovalPolicy: AbilityDeactivationPolicy.CancelImmediately,
InhibitionPolicy: AbilityDeactivationPolicy.CancelImmediately,
TryActivateOnGrant: false,
TryActivateOnEnable: false,
LevelOverridePolicy: LevelComparison.Higher);
var landGrantComponent = new GrantAbilityEffectComponent([landGrantAbilityConfig]);
var landGrantEffect = new EffectData(
"Grant Weapon Land Ability",
new DurationData(DurationType.Infinite),
effectComponents: [grantComponent]);
EffectsManager.ApplyEffect(new Effect(grantEffect, new EffectOwnership(this, this)));
effectComponents: [landGrantComponent]);
EffectsManager.ApplyEffect(new Effect(landGrantEffect, new EffectOwnership(this, this)));
GetTree().CreateTimer(5).Timeout += () => WeaponSystem.GrantNewAbilityForWeaponFly(weaponLandAbility);
}
// Forge events
EventSubscriptionToken token = WeaponSystem.Events.Subscribe<WeaponLandPayload>(WeaponSystem.WeaponLandTag, OnWeaponLanded);
var weaponLeftToken = WeaponSystem.Events.Subscribe<WeaponEventPayload>(WeaponSystem.WeaponStartedFlyingEventTag, OnWeaponLeft);
var weaponLandedToken = WeaponSystem.Events.Subscribe<WeaponEventPayload>(WeaponSystem.WeaponStoppedFlyingEventTag, OnWeaponLanded);
}
public void OnWeaponLanded(EventData<WeaponLandPayload> data)
public void OnWeaponLeft(EventData<WeaponEventPayload> data)
{
var target = data.Target;
var tagsManager = ForgeManager.GetTagsManager(this);
var weaponLeftTag = Tag.RequestTag(tagsManager, "abilities.weapon.left").GetSingleTagContainer();
if (weaponLeftTag == null) return;
Abilities.TryActivateAbilitiesByTag(weaponLeftTag, target, out var landedFailures);
}
public void OnWeaponLanded(EventData<WeaponEventPayload> data)
{
var source = data.Source;
var target = data.Target;
@@ -736,15 +771,13 @@ public partial class PlayerController : CharacterBody3D,
var weaponLandPayload = data.Payload;
var tagsManager = ForgeManager.GetTagsManager(this);
var weaponLandTag = Tag.RequestTag(tagsManager, "abilities.weapon.land").GetSingleTagContainer();
if (weaponLandTag == null) return;
var anyActivated = Abilities.TryActivateAbilitiesByTag(
weaponLandTag,
target,
out var failures);
if (anyActivated)
{
}
}
///////////////////////////