Compare commits

...

22 Commits

Author SHA1 Message Date
7bf19868e7 Setup the base for abilities and events
All checks were successful
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) Successful in 5m6s
2026-03-22 16:28:57 +01:00
d1f83525b1 updating mana through cues 2026-03-18 16:59:52 +01:00
4bcbda9690 fix: inputs were eaten by a tutorial text because of node ordering
All checks were successful
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) Successful in 5m12s
Create tag and build when new code gets to main / ReleaseName (push) Successful in 3s
Create tag and build when new code gets to main / Release (push) Successful in 13m52s
2026-03-18 11:10:06 +01:00
e51ef5a517 probably fixed stuttering of the camera and weapon animations 2026-03-18 11:02:08 +01:00
50de6abb5d mana bar 2026-03-15 21:26:59 +01:00
95616f61fc Implemented mana regeneration
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 40s
Create tag and build when new code gets to main / Export (push) Successful in 5m18s
2026-03-11 16:29:09 +01:00
b15a4fef95 empowered action as a forge ability 2026-03-11 15:56:17 +01:00
14d29d68bb Setup empowered action as a Forge ability 2026-03-10 09:22:39 +01:00
9d612682ec created a normal process function
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 41s
Create tag and build when new code gets to main / Export (push) Successful in 4m39s
2026-03-08 18:12:57 +01:00
9bfe37af62 trying cache
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 30s
Create tag and build when new code gets to main / Export (push) Successful in 4m56s
2026-03-08 10:08:06 +01:00
55eba7fcc8 trying to remove xunit
Some checks failed
Create tag and build when new code gets to main / BumpTag (push) Successful in 27s
Create tag and build when new code gets to main / Export (push) Failing after 3m37s
2026-03-08 09:49:18 +01:00
7a3e61b86f added lights in dark tutorial area 2026-03-08 09:46:33 +01:00
8153ec07e7 Revert "removing tests because they might break the solution"
This reverts commit 3a21f00528.
2026-03-08 09:44:02 +01:00
ddc85655be Revert "removed internal"
This reverts commit 5408f455af.
2026-03-08 09:43:38 +01:00
c92eb19a1c Revert "removed null!"
This reverts commit 290f79afd4.
2026-03-08 09:43:12 +01:00
290f79afd4 removed null!
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 20s
Create tag and build when new code gets to main / Export (push) Successful in 4m52s
2026-02-26 19:18:27 +01:00
5408f455af removed internal
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 20s
Create tag and build when new code gets to main / Export (push) Successful in 5m2s
2026-02-26 18:56:50 +01:00
3a21f00528 removing tests because they might break the solution
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 21s
Create tag and build when new code gets to main / Export (push) Successful in 4m50s
2026-02-26 18:42:46 +01:00
22e8c27878 trying somthing
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 20s
Create tag and build when new code gets to main / Export (push) Successful in 5m3s
2026-02-26 18:36:18 +01:00
6c4454848a removed something that has nothing to do on the vcs
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 25s
Create tag and build when new code gets to main / Export (push) Successful in 4m52s
2026-02-26 18:15:50 +01:00
175e67d2d6 export fix
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 21s
Create tag and build when new code gets to main / Export (push) Successful in 4m53s
2026-02-26 17:55:02 +01:00
ab69fa9323 trying to fix export
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 23s
Create tag and build when new code gets to main / Export (push) Successful in 5m24s
2026-02-26 17:36:33 +01:00
46 changed files with 1459 additions and 531 deletions

View File

@@ -83,6 +83,8 @@ jobs:
Export:
runs-on: godot
env:
RUNNER_TOOL_CACHE: /toolcache # Runner Tool Cache
needs:
- BumpTag
@@ -105,6 +107,7 @@ jobs:
run: |
mkdir -v -p build/windows
${{ steps.setup-godot.outputs.godot_bin }} --headless --verbose --export-release "Windows Desktop" build/windows/${{ env.GAME_NAME }}.exe
ls -la build/windows
# - name: Setup Butler
# shell: bash

View File

@@ -63,6 +63,7 @@ jobs:
run: |
mkdir -v -p build/windows
${{ steps.setup-godot.outputs.godot_bin }} --headless --verbose --build-solutions --export-release "Windows Desktop" build/windows/${{ env.GAME_NAME }}.exe
ls -la build/windows
zip -r Windows.zip build/windows
- name: Upload Windows to itch.io
shell: bash
@@ -79,7 +80,7 @@ jobs:
mkdir -v -p build/windowsArm
${{ steps.setup-godot.outputs.godot_bin }} --headless --verbose --build-solutions --export-release "Windows ARM" build/windowsArm/${{ env.GAME_NAME }}.exe
zip -r WindowsArm.zip build/windowsArm
- name: Upload Windows to itch.io
- name: Upload Windows ARM to itch.io
shell: bash
env:
BUTLER_API_KEY: ${{ secrets.BUTLER_TOKEN }}
@@ -94,7 +95,7 @@ jobs:
mkdir -v -p build/linux
${{ steps.setup-godot.outputs.godot_bin }} --headless --verbose --export-release "Linux/X11" build/linux/${{ env.GAME_NAME }}.x86_64
zip -r Linux.zip build/linux
- name: Upload Windows to itch.io
- name: Upload Linux to itch.io
shell: bash
env:
BUTLER_API_KEY: ${{ secrets.BUTLER_TOKEN }}
@@ -109,7 +110,7 @@ jobs:
mkdir -v -p build/mac
${{ steps.setup-godot.outputs.godot_bin }} --headless --verbose --export-release "macOS" build/mac/${{ env.GAME_NAME }}.zip
zip -r Mac.zip build/mac
- name: Upload Windows to itch.io
- name: Upload Mac to itch.io
shell: bash
env:
BUTLER_API_KEY: ${{ secrets.BUTLER_TOKEN }}

1
.gitignore vendored
View File

@@ -20,6 +20,7 @@
*.suo
*.user
_ReSharper.*
*.DotSettings.user
bin
obj
packages

View File

@@ -125,27 +125,14 @@
</ItemGroup>
<ItemGroup>
<Folder Include="addons\" />
<Folder Include="tests\components\" />
<Folder Include="tests\enemies\" />
<Folder Include="tests\" />
<Folder Include="tools\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="RustyOptions" Version="0.10.1" />
</ItemGroup>
<Import Project="addons/forge/Forge.props" />
<!-- XUnit -->
<ItemGroup>
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.2" />
</ItemGroup>
<!-- gdUnit4 package dependencies -->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
@@ -156,5 +143,4 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/SuppressNullableWarningFix/Enabled/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,15 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=22FEBE6E_002D769C_002D4716_002DA687_002DA0AC8F3EF84A_002Fd_003Ascenes_002Fd_003Aplayer_005Fcontroller_002Fd_003Ascripts_002Ff_003APlayerController_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_00601_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7c0f83388bfc4d2c9d09befcec9dd79bc90908_003Fb8_003F4d300c4d_003FAction_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_00602_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7c0f83388bfc4d2c9d09befcec9dd79bc90908_003F87_003Fded27e2d_003FAction_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnemy_005FScriptMethods_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F8e71dc81611862c01a2cb998a1f327de14747655_003FEnemy_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F716d154fef5cbe863cd637bd32beda6e3cec5f12e8fed2dc5b2d8149a0d558ab_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fdf73a4db74df89d59655c5fb6326406f47fbfa9af1fa81518fe0a07c49d34133_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASceneTree_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F8d6960554e939a669841b1ece03d27df4ab42f92bb80be3767eaec8cdaccf84b_003FSceneTree_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=dd9a7ac6_002Dbb9b_002D4001_002Db145_002D15e6509b7e78/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Solution /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestRunner/RunConfigurationFilename/@EntryValue">D:\Godot\Projects\movement-tests\.runsettings</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=floorplane/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false
dotnet/embed_build_outputs=true
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
@@ -125,7 +125,7 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi
Remove-Item -Recurse -Force '{temp_dir}'"
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false
dotnet/embed_build_outputs=true
texture_format/bptc=true
texture_format/s3tc=true
texture_format/etc=false
@@ -472,4 +472,4 @@ Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorActi
Remove-Item -Recurse -Force '{temp_dir}'"
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false
dotnet/embed_build_outputs=true

51
forge/ForgeManager.cs Normal file
View File

@@ -0,0 +1,51 @@
using Gamesmiths.Forge.Cues;
using Gamesmiths.Forge.Tags;
using Godot;
namespace Movementtests.tools;
public partial class ForgeManager : Node
{
public CuesManager CuesManager { get; private set; } = new CuesManager();
public TagsManager TagsManager { get; private set; } = new TagsManager(
[
// entities
"character.player",
"weapon",
// Statuses
"status.stunned",
// Abilities
"abilities.weapon.land",
// Events
"events.combat.damage",
"events.combat.hit",
"events.weapon.land",
// Cooldowns
"cooldown.empoweredAction",
"cooldown.empoweredSwordThrow",
// Cues
"cues.resources.mana",
]);
public static ForgeManager GetForgeManager(Node node)
{
return node.GetTree().Root.GetNode<ForgeManager>("ForgeManager");
}
public static TagsManager GetTagsManager(Node node)
{
return GetForgeManager(node).TagsManager;
}
public static CuesManager GetCuesManager(Node node)
{
return GetForgeManager(node).CuesManager;
}
}

View File

@@ -0,0 +1,41 @@
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;
namespace Movementtests.forge.abilities;
[GlobalClass]
public partial class RAbilityBase(float cost, float cooldown) : Resource, IAbilityBase
{
[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 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)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1 @@
uid://4eosgwb3h528

View File

@@ -0,0 +1,99 @@
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_animation.png")]
public partial class REmpoweredAction(float cost, float cooldown, float manaRegenPause) : 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;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float ManaRegenPause { get; set; } = manaRegenPause;
public REmpoweredAction() : this(20.0f, 1.0f, 3.0f)
{
}
public AbilityData Ability(TagsManager tagsManager)
{
return new AbilityData(
name: "Empowered Action",
costEffect: CostEffect(tagsManager),
cooldownEffects: [CooldownEffect(tagsManager)],
instancingPolicy: AbilityInstancingPolicy.PerEntity,
behaviorFactory: () => new EmpoweredActionBehavior());
}
public EffectData CostEffect(TagsManager tagsManager)
{
return new(
"Empowered Action 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 EffectData CooldownEffect(TagsManager tagsManager)
{
return new(
"Empowered Action Cooldown",
new DurationData(
DurationType.HasDuration,
new ModifierMagnitude(
MagnitudeCalculationType.ScalableFloat,
new ScalableFloat(Cooldown))),
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
}
}

View File

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

View File

@@ -0,0 +1,104 @@
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 @@
uid://rux15j7q78e8

View File

@@ -0,0 +1,58 @@
using Gamesmiths.Forge.Cues;
using Gamesmiths.Forge.Effects;
using Gamesmiths.Forge.Effects.Duration;
using Gamesmiths.Forge.Effects.Magnitudes;
using Gamesmiths.Forge.Effects.Modifiers;
using Gamesmiths.Forge.Effects.Periodic;
using Gamesmiths.Forge.Tags;
using Godot;
namespace Movementtests.tools.effects;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/white/icon_liquid.png")]
public partial class RManaRegen(float manaRegenRate, float frequency) : Resource
{
[Export(PropertyHint.Range, "0,100,0.1,or_greater")]
public float ManaRegenRate { get; set; } = manaRegenRate;
[Export(PropertyHint.Range, "0.01,1,0.01,or_greater")]
public float Frequency { get; set; } = frequency;
public RManaRegen() : this(1.0f, 0.1f)
{
}
public EffectData ManaRegen(TagsManager tagsManager)
{
return new EffectData(
"Mana Regen",
durationData: new DurationData(
DurationType.Infinite
),
modifiers: [
new Modifier(
"PlayerAttributeSet.Mana",
ModifierOperation.FlatBonus,
new ModifierMagnitude(
MagnitudeCalculationType.ScalableFloat,
new ScalableFloat(ManaRegenRate * Frequency))
)
],
cues: new []
{
new CueData(
CueTags: Tag.RequestTag(tagsManager, "cues.resources.mana").GetSingleTagContainer(),
MinValue: 0,
MaxValue: 100,
MagnitudeType: CueMagnitudeType.AttributeValueChange,
MagnitudeAttribute: "PlayerAttributeSet.Mana"
)
},
periodicData: new PeriodicData(
Period: new ScalableFloat(Frequency),
ExecuteOnApplication: true,
PeriodInhibitionRemovedPolicy: PeriodInhibitionRemovedPolicy.ResetPeriod
)
);
}
}

View File

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

View File

@@ -1,5 +0,0 @@
{
"test": {
"runner": "Microsoft.Testing.Platform"
}
}

View File

@@ -0,0 +1,13 @@
using Gamesmiths.Forge.Abilities;
using Gamesmiths.Forge.Effects;
using Gamesmiths.Forge.Tags;
using Godot;
namespace Movementtests.interfaces;
public interface IAbilityBase
{
AbilityData Ability(TagsManager tagsManager, Node3D owner);
EffectData CostEffect(TagsManager tagsManager);
EffectData CooldownEffect(TagsManager tagsManager);
}

View File

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

View File

@@ -451,6 +451,7 @@ MovementInputs = SubResource("Resource_pxspk")
HealthInputs = ExtResource("27_lgco8")
DamageInputs = ExtResource("28_51ivn")
Target = NodePath("../Player")
IsActiveOnStart = false
[node name="Spawner2" parent="." unique_id=717610670 node_paths=PackedStringArray("Target") instance=ExtResource("24_qwuk2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 31, 7.5, -88)
@@ -459,6 +460,7 @@ MovementInputs = ExtResource("30_3w3wd")
HealthInputs = ExtResource("31_5hbxb")
DamageInputs = ExtResource("32_hmdts")
Target = NodePath("../Player")
IsActiveOnStart = false
[connection signal="timeout" from="TutorialController/WaitToShowBlockingTuto" to="TutorialController" method="_show_weapon_tutorial"]
[connection signal="body_exited" from="TutoTriggers/TriggerTutoMove" to="TutorialController" method="hide_tutorials"]

View File

@@ -770,3 +770,10 @@ transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, -0.5, 0, 0)
[node name="PlayerFellRespawn" parent="." index="10" unique_id=479136076]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 1.5, 0)
[node name="OmniLight3D" type="OmniLight3D" parent="." index="13" unique_id=702421172]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.5, 25, 4)
[node name="OmniLight3D2" type="OmniLight3D" parent="." index="14" unique_id=2016820716]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.5, 25, -9.5)
omni_range = 12.0

View File

@@ -15,8 +15,8 @@
[ext_resource type="PackedScene" uid="uid://qup00a7x2sji" path="res://scenes/fixed_dash_target/fixed_dashthrough_target.tscn" id="13_iq67o"]
[ext_resource type="PackedScene" uid="uid://b8aet6m4m2i83" path="res://scenes/tuto_trigger/TutoTrigger.tscn" id="14_lthgu"]
[sub_resource type="BoxShape3D" id="BoxShape3D_jk7w8"]
size = Vector3(6.75, 8.25, 7.25)
[sub_resource type="BoxShape3D" id="BoxShape3D_lthgu"]
size = Vector3(7.5, 3.75, 10.25)
[node name="Main" unique_id=955321579 instance=ExtResource("1_k7f42")]
@@ -105,13 +105,12 @@ transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 27, 13.5, -9)
[node name="FixedDashthroughTarget3" parent="Targets" index="9" unique_id=1106453232 instance=ExtResource("13_iq67o")]
transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 43, 6, -8.5)
[node name="Player" parent="." index="14" unique_id=1309399929]
transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 3, 0, 0)
[node name="TutoTrigger10" parent="." index="18" unique_id=840713937 instance=ExtResource("14_lthgu")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.75, 0, 3)
[node name="TutoTrigger5" parent="." index="14" unique_id=840713937 instance=ExtResource("14_lthgu")]
tuto_text = "Try to survive!"
[node name="CollisionShape3D" type="CollisionShape3D" parent="TutoTrigger10" index="1" unique_id=2145030859]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.875, 1.125, -4.625)
shape = SubResource("BoxShape3D_jk7w8")
[node name="CollisionShape3D" type="CollisionShape3D" parent="TutoTrigger5" index="1" unique_id=1820790391]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0.625, -1.875)
shape = SubResource("BoxShape3D_lthgu")
[node name="Player" parent="." index="15" unique_id=1309399929]
transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 3, 0, 0)

View File

@@ -3,14 +3,10 @@ using System;
using Movementtests.interfaces;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/white/icon_heart.png")]
public partial class RHealth : Resource
public partial class RHealth(float startingHealth) : Resource
{
[Export]
public float StartingHealth { get; set;}
public float StartingHealth { get; set;} = startingHealth;
public RHealth() : this(100.0f) {}
public RHealth(float startingHealth)
{
StartingHealth = startingHealth;
}
}

View File

@@ -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<IDamageable, DamageRecord> 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<Area3D>("DamageBox");
_target = GetNode<Node3D>("CTarget");
// Forge stuff
var forgeManager = GetTree().Root.GetNode<ForgeManager>("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<Node>("CDamageable") as IDamageable)!;
CMovement = (GetNode<Node>("CMovement") as IMoveable)!;
CHealth = (GetNode<Node>("CHealth") as IHealthable)!;

View File

@@ -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);
}
}

View File

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

View File

@@ -5,7 +5,9 @@
[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://scenes/components/damage/RDamage.cs" id="2_x835q"]
[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="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="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"]
@@ -17,6 +19,7 @@
[ext_resource type="Resource" uid="uid://t612lts1wi1s" path="res://inputs/base_mode/move_right.tres" id="6_q7bng"]
[ext_resource type="Script" uid="uid://cwbvxlfvmocc1" path="res://scenes/player_controller/scripts/StairsSystem.cs" id="7_bmt5a"]
[ext_resource type="Resource" uid="uid://brswsknpgwal2" path="res://inputs/base_mode/move_front.tres" id="7_m8gvy"]
[ext_resource type="Resource" uid="uid://7dpkk5rk3di5" path="res://scenes/player_controller/resources/forge/empowered_action.tres" id="7_qheee"]
[ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://scenes/components/knockback/CKnockback.tscn" id="7_x835q"]
[ext_resource type="Resource" uid="uid://s1l0n1iitc6m" path="res://inputs/base_mode/move_back.tres" id="8_jb43f"]
[ext_resource type="Resource" uid="uid://j1o5ud0plk4" path="res://inputs/base_mode/aim_release.tres" id="8_lhb11"]
@@ -53,6 +56,12 @@
[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
@@ -109,9 +118,15 @@ radius = 1.5
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_2q0ik"]
blend_mode = 1
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_n24vh"]
bg_color = Color(0.15869555, 0.64034444, 0.906125, 1)
[node name="Player" type="CharacterBody3D" unique_id=709076448]
collision_mask = 272
script = ExtResource("1_poq2x")
EmpoweredAction = ExtResource("7_qheee")
ManaRegen = ExtResource("3_n24vh")
AbilityLoadout = [SubResource("Resource_5b7hb")]
AimAssistStrength = 0.3
AimAssistReductionWhenCloseToTarget = 0.1
AimAssistReductionStartDistance = 8.0
@@ -223,12 +238,10 @@ debug_color = Color(0, 0.6, 0.701961, 0.341176)
[node name="HeadSystem" parent="." unique_id=1203743757 instance=ExtResource("11_rxwoh")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
LookSensitivity = 0.16
CameraInclineAcceleration = 20.0
GroundedCameraIncline = 3.0
SlidingJitterAmplitude = 0.2
WeaponSway = 8.0
WeaponLookRotation = 10.0
WeaponAdjustmentSpeed = 1.0
[node name="MantleSystem" parent="HeadSystem" unique_id=98905505 instance=ExtResource("8_qu4wy")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.6, 0)
@@ -551,6 +564,22 @@ offset_bottom = -71.99939
grow_horizontal = 2
grow_vertical = 0
[node name="Manabar" parent="UI" unique_id=1713862004 instance=ExtResource("47_76kmc")]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -859.0
offset_top = -84.0
offset_right = -347.0
offset_bottom = -72.0
grow_horizontal = 2
grow_vertical = 0
BarStyle = SubResource("StyleBoxFlat_n24vh")
[node name="StateChart" type="Node" parent="." unique_id=1675830632]
script = ExtResource("25_wv70j")
metadata/_custom_type_script = "uid://couw105c3bde4"

View File

@@ -1,13 +1,18 @@
using Godot;
using System;
using Gamesmiths.Forge.Core;
using Gamesmiths.Forge.Cues;
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
public partial class PlayerUi : Control, ICueHandler
{
internal TextureRect[] _dashIcons = new TextureRect[3];
private TextureRect _enemyTarget;
private Healthbar _healthbar;
internal TextureRect[] DashIcons = new TextureRect[3];
private TextureRect _enemyTarget = null!;
private Healthbar _healthbar = null!;
private Healthbar _manabar = null!;
public enum TargetState
{
@@ -25,17 +30,24 @@ public partial class PlayerUi : Control
public override void _Ready()
{
_dashIcons[0] = GetNode<TextureRect>("%Dash1");
_dashIcons[1] = GetNode<TextureRect>("%Dash2");
_dashIcons[2] = GetNode<TextureRect>("%Dash3");
DashIcons[0] = GetNode<TextureRect>("%Dash1");
DashIcons[1] = GetNode<TextureRect>("%Dash2");
DashIcons[2] = GetNode<TextureRect>("%Dash3");
_enemyTarget = GetNode<TextureRect>("%EnemyTarget");
_healthbar = GetNode<Healthbar>("%Healthbar");
_manabar = GetNode<Healthbar>("%Manabar");
var forgeManager = GetTree().Root.GetNode<ForgeManager>("ForgeManager")!;
var tagsManager = forgeManager.TagsManager;
var cuesManager = forgeManager.CuesManager;
cuesManager.RegisterCue(Tag.RequestTag(tagsManager, "cues.resources.mana"), this);
}
public void Initialize(float initialHealth)
public void Initialize(float initialHealth, float initialMana)
{
_healthbar.Initialize(initialHealth);
_manabar.Initialize(initialMana);
}
public void SetEnemyTargetProperties(TargetProperties targetProperties)
@@ -59,7 +71,7 @@ public partial class PlayerUi : Control
public void SetNumberOfDashesLeft(int numberOfDashes)
{
int index = 1;
foreach (var dashIcon in _dashIcons)
foreach (var dashIcon in DashIcons)
{
dashIcon.SetVisible(index <= numberOfDashes);
index++;
@@ -70,4 +82,36 @@ public partial class PlayerUi : Control
{
_healthbar.CurrentHealth = healthChanged.CurrentHealth;
}
public void OnManaChanged(float newValue)
{
_manabar.CurrentHealth = newValue;
}
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;
// Extract parameters
float magnitude = parameters.Value.Magnitude;
// Play effects scaled by magnitude
// PlayFireImpactSound(normalizedMagnitude);
// SpawnFireImpactParticles(target, 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)
{
}
}

View File

@@ -39,12 +39,12 @@ public partial class HeadSystem : Node3D
float BobbingMultiplier,
float FovMultiplier);
internal Camera3D _camera;
internal Marker3D _cameraAnchor;
internal AnimationPlayer _animationPlayer;
internal AnimationTree _animationTree;
internal Camera3D Camera = null!;
internal Node3D CameraAnchor = null!;
internal AnimationPlayer AnimationPlayer = null!;
internal AnimationTree AnimationTree = null!;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float LookSensitivity { get; set; } = 1f;
[ExportGroup("Camera incline")]
@@ -84,78 +84,75 @@ public partial class HeadSystem : Node3D
public float FovMaxedOutSpeed { get; set; } = 20f;
[ExportGroup("First Person rig")]
internal Node3D _fpRig;
internal Node3D _rightHandedWeapon;
internal Node3D _leftHandedWeapon;
internal Node3D _fpDisplacedRig;
internal Vector3 _fpDisplacedRigInitialRotation;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float WeaponSway { get; set; } = 5f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float WeaponLookRotation { get; set; } = 1f;
internal Node3D FpRig = null!;
internal Node3D RightHandedWeapon = null!;
internal Vector3 RightHandedWeaponInitialRotation = Vector3.Zero;
internal Node3D LeftHandedWeapon = null!;
internal Vector3 LeftHandedWeaponInitialRotation = Vector3.Zero;
[Export(PropertyHint.Range, "0,20,1,or_greater")]
public float WeaponSway { get; set; } = 15f;
[Export(PropertyHint.Range, "0,200,1,or_greater")]
public float WeaponMoveRotation { get; set; } = 80f;
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
public float WeaponAdjustmentSpeed { get; set; } = 10f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float DisplacedWeaponSway { get; set; } = 5f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float DisplacedWeaponLookRotation { get; set; } = 1f;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
[Export(PropertyHint.Range, "0,20,1,or_greater")]
public float WeaponAdjustmentSpeed { get; set; } = 1f;
[Export(PropertyHint.Range, "0,2,0.01,or_greater")]
public float DisplacedWeaponSway { get; set; } = 0.8f;
[Export(PropertyHint.Range, "0,0.5,0.01,or_greater")]
public float DisplacedWeaponMoveRotation { get; set; } = 0.1f;
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
public float DisplacedWeaponAdjustmentSpeed { get; set; } = 10f;
[Export(PropertyHint.Range, "0,20,1,or_greater")]
public float DisplacedWeaponAdjustmentSpeed { get; set; } = 12f;
public void Init()
{
_isPlayingForcingAnim = false;
IsPlayingForcingAnim = false;
Input.SetMouseMode(Input.MouseModeEnum.Captured);
_camera = GetNode<Camera3D>("CameraSmooth/Camera3D");
_cameraAnchor = GetNode<Marker3D>("CameraAnchor");
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
_animationTree = GetNode<AnimationTree>("AnimationTree");
_fpRig = GetNode<Node3D>("FPRig");
_rightHandedWeapon = GetNode<Node3D>("FPRig/Sword");
_leftHandedWeapon = GetNode<Node3D>("FPRig/Parry");
_fpDisplacedRig = GetNode<Node3D>("FPRig/Sword");
_fpDisplacedRigInitialRotation = _fpDisplacedRig.Rotation;
Camera = GetNode<Camera3D>("CameraSmooth/Camera3D");
CameraAnchor = GetNode<Node3D>("CameraSmooth/CameraAnchor");
//_cameraAnchor = GetNode<Camera3D>("CameraSmooth/Camera3D");
AnimationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
AnimationTree = GetNode<AnimationTree>("AnimationTree");
FpRig = GetNode<Node3D>("FPRig");
RightHandedWeapon = GetNode<Node3D>("FPRig/Sword/SwordMesh");
RightHandedWeaponInitialRotation = RightHandedWeapon.Rotation;
LeftHandedWeapon = GetNode<Node3D>("FPRig/Parry/ParryMesh");
LeftHandedWeaponInitialRotation = LeftHandedWeapon.Rotation;
_slidingNoise.NoiseType = FastNoiseLite.NoiseTypeEnum.Perlin;
_slidingNoise.SetFrequency(SlidingJitterFrequency);
}
public void SetWeaponsVisible(bool swordVisible, bool parryVisible)
{
_rightHandedWeapon.Visible = swordVisible;
_leftHandedWeapon.Visible = parryVisible;
RightHandedWeapon.Visible = swordVisible;
LeftHandedWeapon.Visible = parryVisible;
}
public void OnMantle()
{
_animationTree.Set("parameters/OnMantle/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
AnimationTree.Set("parameters/OnMantle/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnJumpStarted()
{
_animationTree.Set("parameters/OnJumpStart/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
AnimationTree.Set("parameters/OnJumpStart/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnJumpEnded()
{
_animationTree.Set("parameters/OnJumpEnd/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
AnimationTree.Set("parameters/OnJumpEnd/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnHit()
{
_animationTree.Set("parameters/OnHit/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
AnimationTree.Set("parameters/OnHit/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnParry()
{
_animationTree.Set("parameters/OnParry/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
AnimationTree.Set("parameters/OnParry/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnStartDeathAnimation()
{
_isPlayingForcingAnim = true;
_animationTree.Set("parameters/OnDie/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
IsPlayingForcingAnim = true;
AnimationTree.Set("parameters/OnDie/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnDeathAnimationFinished()
@@ -190,8 +187,8 @@ public partial class HeadSystem : Node3D
EmitSignalHitboxDeactivated();
}
internal bool _footstepEmitted;
internal bool _isPlayingForcingAnim;
internal bool FootstepEmitted;
internal bool IsPlayingForcingAnim;
public void ResetHeadBobbing()
{
@@ -200,10 +197,10 @@ public partial class HeadSystem : Node3D
public void LookAround(CameraParameters inputs)
{
if (_isPlayingForcingAnim)
if (IsPlayingForcingAnim)
{
_camera.Position = Vector3.Zero;
_camera.Rotation = Vector3.Zero;
Camera.Position = Vector3.Zero;
Camera.Rotation = Vector3.Zero;
return;
}
@@ -223,7 +220,7 @@ public partial class HeadSystem : Node3D
RotateY(angleForHorizontalRotation);
// Vertical movement of head
Vector3 currentCameraRotation = _cameraAnchor.Rotation;
Vector3 currentCameraRotation = CameraAnchor.Rotation;
currentCameraRotation.X += Convert.ToSingle(lookDir.Y * LookSensitivity * sensitivitMultiplier);
currentCameraRotation.X = Mathf.Clamp(currentCameraRotation.X, Mathf.DegToRad(-90f), Mathf.DegToRad(90f));
@@ -242,18 +239,18 @@ public partial class HeadSystem : Node3D
cameraIncline = Mathf.DegToRad(GroundedCameraIncline * cameraInclineFactor * -1.0f);
}
currentCameraRotation.Z = (float) Mathf.Lerp(currentCameraRotation.Z, cameraIncline, delta * CameraInclineAcceleration);
_cameraAnchor.Rotation = currentCameraRotation;
CameraAnchor.Rotation = currentCameraRotation;
if (withCameraJitter)
{
_cameraAnchor.Position = Vector3.Down*SlidingCameraHeightOffset;
CameraAnchor.Position = Vector3.Down*SlidingCameraHeightOffset;
float noise1D = _slidingNoise.GetNoise1D(Time.GetTicksMsec());
float noiseAmplitude = SlidingJitterAmplitude*Mathf.Clamp(playerVelocity.Length(), 0f, 1f);
_cameraAnchor.Position += Vector3.Up*noise1D*noiseAmplitude;
CameraAnchor.Position += Vector3.Up*noise1D*noiseAmplitude;
}
else
{
_cameraAnchor.Position = Vector3.Zero;
CameraAnchor.Position = Vector3.Zero;
}
Vector3 newPositionForCamera = Vector3.Zero;
@@ -268,76 +265,79 @@ public partial class HeadSystem : Node3D
newPositionForCamera.Y = Mathf.Sin(_bobbingAccumulator * BobbingFrequency) * BobbingAmplitude * bobbingMultiplier;
newPositionForCamera.X = Mathf.Cos(_bobbingAccumulator * BobbingFrequency / 2.0f) * BobbingAmplitude * bobbingMultiplier;
if (newPositionForCamera.Y < -0.07 && !_footstepEmitted) Footstep();
if (newPositionForCamera.Y > 0) _footstepEmitted = false;
if (newPositionForCamera.Y < -0.07 * bobbingMultiplier && !FootstepEmitted) Footstep();
if (newPositionForCamera.Y > 0) FootstepEmitted = false;
// Offset bobbing for weapon rig
newPositionForRig.Y = Mathf.Cos(_bobbingAccumulator * BobbingFrequency) * BobbingAmplitude * bobbingMultiplier * 0.2f;
newPositionForRig.X = Mathf.Sin(_bobbingAccumulator * BobbingFrequency / 2.0f) * BobbingAmplitude * bobbingMultiplier * 0.2f;
}
_cameraAnchor.Position += newPositionForCamera;
_camera.GlobalTransform = _cameraAnchor.GetGlobalTransformInterpolated();
CameraAnchor.Position += newPositionForCamera;
Camera.GlobalTransform = CameraAnchor.GetGlobalTransformInterpolated();
// First person rig adjustments
_fpRig.GlobalTransform = _cameraAnchor.GetGlobalTransformInterpolated();
FpRig.GlobalTransform = Camera.GlobalTransform;
// Apply bobbing
_fpRig.Position += newPositionForRig;
FpRig.Position += newPositionForRig;
// Rotate the whole rig based on movement input
var newRigRotation = _fpRig.Rotation;
var camTilt = Mathf.Lerp(_fpRig.Rotation.Z, cameraIncline*WeaponMoveRotation, delta*WeaponAdjustmentSpeed);
var newRigRotation = FpRig.Rotation;
var camTilt = Mathf.Lerp(FpRig.Rotation.Z, CameraAnchor.Rotation.Z*WeaponMoveRotation, delta * WeaponAdjustmentSpeed);
newRigRotation.Z = (float) camTilt;
// Rotate the whole rig based on camera rotation input
newRigRotation.X = Mathf.Lerp(newRigRotation.X, -lookDir.Y*WeaponSway, (float) delta*WeaponAdjustmentSpeed);
newRigRotation.Y = Mathf.Lerp(newRigRotation.Y, -lookDir.X*WeaponSway, (float) delta*WeaponAdjustmentSpeed);
newRigRotation.X = Mathf.Lerp(newRigRotation.X, -lookDir.Y*WeaponSway, (float) delta * WeaponAdjustmentSpeed);
newRigRotation.Y = Mathf.Lerp(newRigRotation.Y, -lookDir.X*WeaponSway, (float) delta * WeaponAdjustmentSpeed);
// Apply
_fpRig.Rotation = newRigRotation;
FpRig.Rotation = newRigRotation;
// Compute displaced rig adjustments, starting with movement input
var newDisplacedRigRotation = _fpDisplacedRig.Rotation;
var howMuchForward = ComputeHowMuchInputForward(playerInput);
var howMuchSideways = ComputeHowMuchInputSideways(playerInput);
var displacedCamTiltForward = Mathf.Lerp(newDisplacedRigRotation.Z,
_fpDisplacedRigInitialRotation.Z + howMuchForward*DisplacedWeaponMoveRotation,
delta*DisplacedWeaponAdjustmentSpeed);
var displacedCamTiltSide = Mathf.Lerp(newDisplacedRigRotation.X,
_fpDisplacedRigInitialRotation.X - howMuchSideways*DisplacedWeaponMoveRotation,
delta*DisplacedWeaponAdjustmentSpeed);
newDisplacedRigRotation.X = (float) displacedCamTiltSide;
newDisplacedRigRotation.Z = (float) displacedCamTiltForward;
var displacedSwayY = Mathf.Lerp(newDisplacedRigRotation.Y,
_fpDisplacedRigInitialRotation.Y - lookDir.X*DisplacedWeaponSway,
delta*DisplacedWeaponAdjustmentSpeed);
newDisplacedRigRotation.Y = (float) displacedSwayY;
// Apply
_fpDisplacedRig.Rotation = newDisplacedRigRotation;
// Compute sword meshes procedural adjustments
RightHandedWeapon.Rotation = ComputeRotationForFpMesh(RightHandedWeapon, RightHandedWeaponInitialRotation, playerInput, lookDir, (float) delta);
LeftHandedWeapon.Rotation = ComputeRotationForFpMesh(LeftHandedWeapon, LeftHandedWeaponInitialRotation, playerInput, lookDir, (float) delta);
// Camera adjustments
float velocityClamped = Mathf.Clamp(playerVelocity.Length(), 0.5f, FovMaxedOutSpeed);
float targetFov = BaseFov + FovChangeFactor * velocityClamped * fovMultiplier;
_camera.Fov = Mathf.Lerp(_camera.Fov, targetFov, (float) delta * FovChangeSpeed);
Camera.Fov = Mathf.Lerp(Camera.Fov, targetFov, (float) delta * FovChangeSpeed);
}
public Vector3 ComputeRotationForFpMesh(Node3D mesh, Vector3 initialRotation, Vector3 playerInput, Vector2 lookDir, float delta)
{
var newMeshRotation = mesh.Rotation;
var howMuchForward = ComputeHowMuchInputForward(playerInput);
var howMuchSideways = ComputeHowMuchInputSideways(playerInput);
var displacedCamTiltForward = Mathf.Lerp(newMeshRotation.Z,
initialRotation.Z + howMuchForward*DisplacedWeaponMoveRotation,
delta * DisplacedWeaponAdjustmentSpeed);
var displacedCamTiltSide = Mathf.Lerp(newMeshRotation.X,
initialRotation.X - howMuchSideways*DisplacedWeaponMoveRotation,
delta * DisplacedWeaponAdjustmentSpeed);
newMeshRotation.X = displacedCamTiltSide;
newMeshRotation.Z = displacedCamTiltForward;
var displacedSwayY = Mathf.Lerp(newMeshRotation.Y,
initialRotation.Y - lookDir.X*DisplacedWeaponSway,
delta * DisplacedWeaponAdjustmentSpeed);
newMeshRotation.Y = displacedSwayY;
return newMeshRotation;
}
public void Footstep()
{
_footstepEmitted = true;
FootstepEmitted = true;
EmitSignalStepFoot();
}
public void HideWeapon()
{
_rightHandedWeapon.Visible = false;
RightHandedWeapon.Visible = false;
}
public void ShowWeapon()
{
_rightHandedWeapon.Visible = true;
RightHandedWeapon.Visible = true;
}
public float ComputeCameraInclineFactor(Vector3 direction)
@@ -368,15 +368,15 @@ public partial class HeadSystem : Node3D
public Vector3 GetGlobalForwardVector()
{
return _camera.GlobalBasis.Z;
return Camera.GlobalBasis.Z;
}
public Vector3 GetGlobalLookRotation()
{
return new Vector3(
_camera.Rotation.X,
Camera.Rotation.X,
Rotation.Y,
_camera.Rotation.Z);
Camera.Rotation.Z);
}
public void SetHeight(float height)

View File

@@ -654,9 +654,6 @@ _data = {
[node name="HeadSystem" type="Node3D" unique_id=2067407038]
script = ExtResource("1_8abgy")
WeaponMoveRotation = 20.0
DisplacedWeaponSway = 1.0
DisplacedWeaponAdjustmentSpeed = 8.0
[node name="FPRig" type="Node3D" parent="." unique_id=922968399]
transform = Transform3D(0.9999998, 0, 0, 0, 1.0000002, 0, 0, 0, 1.0000002, 0, 0, 0)
@@ -678,6 +675,9 @@ mesh = ExtResource("3_1ay6d")
[node name="CameraSmooth" type="Node3D" parent="." unique_id=2072010960]
transform = Transform3D(0.9999998, -0.00011616429, 0, 0.00011616431, 0.99999964, 0, 0, 0, 0.99999976, 0, 0, 0)
[node name="CameraAnchor" type="Marker3D" parent="CameraSmooth" unique_id=1554357312]
transform = Transform3D(1.0000002, 0.00011616435, 0, -0.000116164374, 1.0000004, 0, 0, 0, 1.0000002, 0, 0, 0)
[node name="Camera3D" type="Camera3D" parent="CameraSmooth" unique_id=544372058]
transform = Transform3D(1, 0, 0, 0, 1.0000002, 0, 0, 0, 1.0000001, 0, 0, 0)
current = true
@@ -702,8 +702,6 @@ fade_out = 0.5547845
shakerPreset = SubResource("Resource_se3kf")
metadata/_custom_type_script = "uid://dnlxsrumw6ygp"
[node name="CameraAnchor" type="Marker3D" parent="." unique_id=1554357312]
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1831491746]
root_node = NodePath("../CameraSmooth/Camera3D")
libraries/ = SubResource("AnimationLibrary_0hyrq")

View File

@@ -0,0 +1,13 @@
using Gamesmiths.Forge.Attributes;
namespace Movementtests.scenes.player_controller.components.weapon;
public class WeaponAttributeSet : AttributeSet
{
public EntityAttribute Level { get; }
public WeaponAttributeSet()
{
Level = InitializeAttribute(nameof(Level), 1, 1, 10);
}
}

View File

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

View File

@@ -1,13 +1,21 @@
using System;
using Gamesmiths.Forge.Core;
using Gamesmiths.Forge.Effects;
using Gamesmiths.Forge.Events;
using Gamesmiths.Forge.Tags;
using Godot;
using GodotStateCharts;
using Movementtests.interfaces;
using Movementtests.scenes.player_controller.components.weapon;
using Movementtests.systems.damage;
using Movementtests.tools;
namespace Movementtests.systems;
public record struct WeaponLandPayload(int Damage, bool IsCritical);
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_sword.png")]
public partial class WeaponSystem : RigidBody3D, IDamageDealer
public partial class WeaponSystem : RigidBody3D, IDamageDealer, IForgeEntity
{
[Signal]
public delegate void WeaponThrownEventHandler();
@@ -22,6 +30,12 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer
[Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
public float StraightThrowDuration { get; set; } = 0.1f;
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 StateChart _weaponState = null!;
public StateChartState InHandState = null!;
public StateChartState FlyingState = null!;
@@ -40,6 +54,8 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer
public StandardMaterial3D WeaponLocationIndicatorMaterial { get; set; } = null!;
public MeshInstance3D WeaponMesh { get; set; } = null!;
public Tag WeaponLandTag;
public void Init()
{
_weaponState = StateChart.Of(GetNode("StateChart"));
@@ -57,6 +73,22 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer
_startTransform = Transform;
Freeze = true;
Visible = false;
var tagsManager = ForgeManager.GetTagsManager(this);
var cuesManager = ForgeManager.GetCuesManager(this);
var baseTags = new TagContainer(
tagsManager,
[
Tag.RequestTag(tagsManager, "weapon")
]);
Attributes = new EntityAttributes(new WeaponAttributeSet());
Tags = new EntityTags(baseTags);
EffectsManager = new EffectsManager(this, cuesManager);
Abilities = new(this);
Events = new();
WeaponLandTag = Tag.RequestTag(tagsManager, "events.weapon.land");
BodyEntered += OnThrownWeaponReachesGround;
@@ -109,11 +141,26 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer
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)
});
}
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 IDamageable damageable)
{
damageable.TakeDamage(new DamageRecord(GlobalPosition, RDamage));
@@ -145,6 +192,8 @@ public partial class WeaponSystem : RigidBody3D, IDamageDealer
{
PlantInEnemy(node);
}
else RaiseWeaponLandEvent();
CallDeferred(Node3D.MethodName.SetGlobalPosition, PlantLocation);
CallDeferred(Node3D.MethodName.LookAt, GlobalTransform.Origin + PlantNormal, Vector3.Up, true);
}

View File

@@ -0,0 +1,10 @@
[gd_resource type="Resource" script_class="REmpoweredAction" format=3 uid="uid://7dpkk5rk3di5"]
[ext_resource type="Script" uid="uid://d0l07gcx1ef18" path="res://forge/abilities/REmpoweredAction.cs" id="1_1rxoq"]
[resource]
script = ExtResource("1_1rxoq")
Cost = 30.0
Cooldown = 0.5
ManaRegenPause = 2.0
metadata/_custom_type_script = "uid://d0l07gcx1ef18"

View File

@@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="RExplodingSwordThrow" format=3 uid="uid://cdxbwirfiaipi"]
[ext_resource type="Script" uid="uid://rux15j7q78e8" path="res://forge/abilities/RExplodingSwordThrow.cs" id="1_5iq8v"]
[resource]
script = ExtResource("1_5iq8v")
Cost = 20.0
metadata/_custom_type_script = "uid://rux15j7q78e8"

View File

@@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="RManaRegen" format=3 uid="uid://dtmhtlix2amme"]
[ext_resource type="Script" uid="uid://di04jvuqp0h7m" path="res://forge/effects/RManaRegen.cs" id="1_ecb1p"]
[resource]
script = ExtResource("1_ecb1p")
ManaRegenRate = 20.0
Frequency = 0.05
metadata/_custom_type_script = "uid://di04jvuqp0h7m"

View File

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

View File

@@ -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 Movementtests.tools.effects;
using RustyOptions;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_character.png")]
@@ -92,6 +100,16 @@ public partial class PlayerController : CharacterBody3D,
[Export] public bool HasSword { get; set; } = true;
[Export] public bool HasParry { get; set; } = true;
// Forge stuff
[ExportCategory("Forge")]
[ExportGroup("General")]
[Export] public REmpoweredAction EmpoweredAction = null!;
[Export] public RManaRegen ManaRegen = null!;
[ExportGroup("Abilities")]
[ExportSubgroup("WeaponThrow")]
[Export] public RAbilityBase[] AbilityLoadout = [];
// Combat stuff
[ExportCategory("Combat")]
[ExportGroup("General")]
@@ -398,6 +416,9 @@ public partial class PlayerController : CharacterBody3D,
private ShapeCast3D _closeEnemyDetector = null!;
private RayCast3D _aimAssisRayCast = null!;
private Camera3D _camera = null!;
private AbilityHandle? _empoweredActionHandle;
private ActiveEffectHandle? _manaRegenEffectHandle;
public override void _Ready()
{
@@ -415,25 +436,35 @@ public partial class PlayerController : CharacterBody3D,
_aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f);
// Forge stuff
var forgeManager = GetTree().Root.GetNode<ForgeManager>("ForgeManager")!;
var tagsManager = ForgeManager.GetTagsManager(this);
var cuesManager = ForgeManager.GetCuesManager(this);
var baseTags = new TagContainer(
forgeManager.TagsManager,
tagsManager,
[
Tag.RequestTag(forgeManager.TagsManager, "character.player"),
Tag.RequestTag(forgeManager.TagsManager, "class.warrior")
Tag.RequestTag(tagsManager, "character.player")
]);
Attributes = new EntityAttributes(new PlayerAttributeSet());
Tags = new EntityTags(baseTags);
EffectsManager = new EffectsManager(this, forgeManager.CuesManager);
EffectsManager = new EffectsManager(this, cuesManager);
Abilities = new(this);
Events = new();
var empoweredActionData = EmpoweredAction.Ability(tagsManager);
// Grant permanently
_empoweredActionHandle = Abilities.GrantAbilityPermanently(
empoweredActionData,
abilityLevel: 1,
levelOverridePolicy: LevelComparison.None,
sourceEntity: this);
var manaRegenEffect = new Effect(ManaRegen.ManaRegen(tagsManager), new EffectOwnership(this, this));
_manaRegenEffectHandle = EffectsManager.ApplyEffect(manaRegenEffect);
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<TextureRect>("%DashIndicator");
PowerCooldownIndicator = GetNode<ColorRect>("%DashCooldownIndicator");
@@ -499,7 +530,7 @@ public partial class PlayerController : CharacterBody3D,
}
if (RKnockback != null) CKnockback!.RKnockback = RKnockback;
PlayerUi.Initialize(CHealth.CurrentHealth);
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;
@@ -673,9 +704,47 @@ public partial class PlayerController : CharacterBody3D,
_attackDash.StateEntered += OnDashAttackStarted;
_parryStandard.StateEntered += OnStandardParryStarted;
_parryDash.StateEntered += OnDashParryStarted;
foreach (var weaponLandAbility in AbilityLoadout)
{
var grantAbilityConfig = new GrantAbilityConfig(
weaponLandAbility.Ability(tagsManager, WeaponSystem),
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(
"Grant Weapon Land Ability",
new DurationData(DurationType.Infinite),
effectComponents: [grantComponent]);
EffectsManager.ApplyEffect(new Effect(grantEffect, new EffectOwnership(this, this)));
}
// Testing out kill
// GetTree().CreateTimer(2).Timeout += () => Kill(this);
// Forge events
EventSubscriptionToken token = WeaponSystem.Events.Subscribe<WeaponLandPayload>(WeaponSystem.WeaponLandTag, OnWeaponLanded);
}
public void OnWeaponLanded(EventData<WeaponLandPayload> data)
{
var source = data.Source;
var target = data.Target;
var magnitude = data.EventMagnitude;
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)
{
}
}
///////////////////////////
@@ -735,7 +804,7 @@ public partial class PlayerController : CharacterBody3D,
{
RHealth.StartingHealth = newHealthValue;
CHealth!.CurrentHealth = newHealthValue;
PlayerUi.Initialize(CHealth.CurrentHealth);
PlayerUi.Initialize(CHealth.CurrentHealth, Attributes["PlayerAttributeSet.Mana"].BaseValue);
}
public void SetPlayerDamageOverride(float newDamageValue)
{
@@ -1913,10 +1982,53 @@ 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}");
}
// Inhibit Mana Regeneration for a while after using an empowered action
// TODO: Use Forge events instead of relying on direct referencing
_manaRegenEffectHandle!.SetInhibit(true);
GetTree().CreateTimer(EmpoweredAction.ManaRegenPause).Timeout += () => {_manaRegenEffectHandle!.SetInhibit(false);};
_isWallJumpAvailable = true;
_canDashAirborne = true;
EmpoweredActionsLeft--;
@@ -2223,14 +2335,10 @@ public partial class PlayerController : CharacterBody3D,
_spaceState = GetWorld3D().DirectSpaceState;
if (_currentInputBufferFrames > 0) _currentInputBufferFrames -= 1;
// Limit maximum speed
if (Velocity.Length() > AbsoluteMaxSpeed)
Velocity = Velocity.Normalized() * AbsoluteMaxSpeed;
// Manage head and camera movement
LookAround(delta);
// Manage general movement
Velocity += ComputeKnockback();
MoveSlideAndHandleStairs((float) delta);
@@ -2238,21 +2346,22 @@ public partial class PlayerController : CharacterBody3D,
// Manage gameplay systems
MantleSystem.ProcessMantle(_grounded.Active);
HandleEnemyTargeting();
// Manage dash target and tutorial specific stuff
// if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone)
// {
// DashIndicatorMesh.Visible = false;
// }
// if (!WeaponSystem.InHandState.Active && TutorialDone)
// {
// DashIndicatorMesh.Visible = true;
//
// DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2;
// DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition);
// }
}
// private float _oldMana = 100;
public override void _Process(double delta)
{
// Manage head and camera movement
LookAround(delta);
EffectsManager.UpdateEffects(delta);
// TODO: change for actual Cue
// var currentMana = Attributes["PlayerAttributeSet.Mana"].CurrentValue;
// if (Mathf.Abs(currentMana - _oldMana) > Mathf.Epsilon)
// PlayerUi.OnManaChanged(currentMana);
// _oldMana = currentMana;
}
///////////////////////////
// Hit Management ///////
///////////////////////////

View File

@@ -4,8 +4,10 @@ using System;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/control/icon_heart.png")]
public partial class Healthbar : ProgressBar
{
private Timer _damageCatchUpTimer;
private ProgressBar _damagedHealth;
private Timer _damageCatchUpTimer = null!;
private ProgressBar _damagedHealth = null!;
[Export] public StyleBox? BarStyle;
private float _currentHealth;
public float CurrentHealth
@@ -21,6 +23,9 @@ public partial class Healthbar : ProgressBar
_damageCatchUpTimer.Timeout += OnDamageCatchUp;
Visible = false;
if (BarStyle != null)
AddThemeStyleboxOverride("fill", BarStyle);
}
public void Initialize(float initialHealth)

View File

@@ -5,7 +5,7 @@
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0sgot"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0k5hr"]
bg_color = Color(0.698864, 0.047356047, 0, 1)
bg_color = Color(0.69803923, 0.047058824, 0, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0sgot"]
bg_color = Color(0.14767182, 0.14767182, 0.14767176, 1)

View File

@@ -14,17 +14,20 @@ public class HeadSystemUnitTest
public void SetupTest()
{
_head = new HeadSystem();
_head._camera = new Camera3D();
_head.AddChild(_head._camera);
_head.Camera = new Camera3D();
_head.AddChild(_head.Camera);
_head._cameraAnchor = new Marker3D();
_head.AddChild(_head._cameraAnchor);
// _head._cameraAnchor = new Marker3D();
_head.AddChild(_head.CameraAnchor);
_head._fpRig = new Node3D();
_head.AddChild(_head._fpRig);
_head._fpDisplacedRig = new Node3D();
_head.AddChild(_head._fpDisplacedRig);
_head.FpRig = new Node3D();
_head.AddChild(_head.FpRig);
_head.CameraAnchor = new Node3D();
_head.AddChild(_head.CameraAnchor);
_head.RightHandedWeapon = new Node3D();
_head.AddChild(_head.RightHandedWeapon);
_head.LeftHandedWeapon = new Node3D();
_head.AddChild(_head.LeftHandedWeapon);
}
[AfterTest]

View File

@@ -99,7 +99,7 @@ public class PlayerControllerUnitTest
{
var mockUi = new PlayerUi();
var dashIcons = new TextureRect[3] { new TextureRect(), new TextureRect(), new TextureRect() };
mockUi._dashIcons = dashIcons;
mockUi.DashIcons = dashIcons;
_player.PlayerUi = mockUi;

View File

@@ -1,27 +0,0 @@
using Gamesmiths.Forge.Cues;
using Gamesmiths.Forge.Tags;
using Godot;
namespace Movementtests.tools;
public partial class ForgeManager : Node
{
public CuesManager CuesManager { get; private set; } = new CuesManager();
public TagsManager TagsManager { get; private set; } = new TagsManager(
[
"character.player",
"class.warrior",
"status.stunned",
"status.burning",
"status.enraged",
"status.immune.fire",
"cues.damage.fire",
"events.combat.damage",
"events.combat.hit",
"cooldown.fireball"
]);
public ForgeManager()
{
}
}

View File

@@ -1,3 +0,0 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json"
}