forge friendlier health and damage management

Removed knockback though
This commit is contained in:
2026-04-28 11:22:24 +02:00
parent dcfd937e53
commit ec44306d48
24 changed files with 776 additions and 490 deletions

View File

@@ -5,13 +5,10 @@ using Chickensoft.Introspection;
using Gamesmiths.Forge.Abilities;
using Gamesmiths.Forge.Attributes;
using Gamesmiths.Forge.Core;
using Gamesmiths.Forge.Cues;
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.Core;
using Gamesmiths.Forge.Godot.Nodes;
@@ -27,11 +24,7 @@ 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.managers;
using Movementtests.tools.calculators;
using RustyOptions;
using Node = Godot.Node;
@@ -39,12 +32,7 @@ public record struct EmpoweredActionPayload;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_character.png"), Meta(typeof(IAutoNode))]
public partial class PlayerController : CharacterBody3D,
IDamageable,
IDamageDealer,
IHealthable,
IKnockbackable,
IForgeEntity
public partial class PlayerController : CharacterBody3D, IForgeEntity, ICueHandler
{
public override void _Notification(int what) => this.Notify(what);
@@ -53,7 +41,7 @@ public partial class PlayerController : CharacterBody3D,
public InventoryManager InventoryManager => this.DependOn<InventoryManager>();
#endregion
#region Enums
#region Utils
public enum BufferedActions
{
@@ -66,6 +54,14 @@ public partial class PlayerController : CharacterBody3D,
#endregion
#region Forge
private AbilityHandle? _empoweredActionHandle;
public required EntityAttribute HealthAttribute { get; set; }
public required EntityAttribute ManaAttribute { get; set; }
#endregion
#region Signals
[Signal]
@@ -79,27 +75,25 @@ public partial class PlayerController : CharacterBody3D,
#region Publics
public HeadSystem HeadSystem = null!;
public StairsSystem StairsSystem = null!;
public MantleSystem MantleSystem = null!;
public DashSystem DashSystem = null!;
public CollisionShape3D StandingCollider = null!;
public CollisionShape3D SlideCollider = null!;
public WeaponSystem WeaponSystem = null!;
public WallHugSystem WallHugSystem = null!;
public PlayerUi PlayerUi = null!;
public Node3D DashIndicatorNode = null!;
public MeshInstance3D DashIndicatorMesh = null!;
public CylinderMesh DashIndicatorMeshCylinder = null!;
public RayCast3D WallRunSnapper = null!;
public ShapeCast3D GroundDetector = null!;
public ShapeCast3D CeilingDetector = null!;
public RayCast3D DirectGroundDetector = null!;
public Area3D WeaponHitbox = null!;
public AudioStreamPlayer3D SfxPlayer = null!;
public ShapeCast3D DashDamageDetector = null!;
public Area3D SlidingEnemyDetector = null!;
[Node("HeadSystem")] public required HeadSystem HeadSystem { get; set; }
[Node("StairsSystem")] public required StairsSystem StairsSystem { get; set; }
[Node("HeadSystem/MantleSystem")] public required MantleSystem MantleSystem { get; set; }
[Node("DashSystem")] public required DashSystem DashSystem { get; set; }
[Node("StandingCollider")] public required CollisionShape3D StandingCollider { get; set; }
[Node("SlideCollider")] public required CollisionShape3D SlideCollider { get; set; }
[Node("WeaponSystem")] public required WeaponSystem WeaponSystem { get; set; }
[Node("WallHugSystem")] public required WallHugSystem WallHugSystem { get; set; }
[Node("UI")] public required PlayerUi PlayerUi { get; set; }
[Node("GroundDetector")] public required ShapeCast3D GroundDetector { get; set; }
[Node("CeilingDetector")] public required ShapeCast3D CeilingDetector { get; set; }
[Node("DirectGroundDetector")] public required RayCast3D DirectGroundDetector { get; set; }
[Node("%WeaponHitbox")] public required Area3D WeaponHitbox { get; set; }
[Node("SFXPlayer")] public required AudioStreamPlayer3D SfxPlayer { get; set; }
[Node("DashDamage")] public required ShapeCast3D DashDamageDetector { get; set; }
[Node("SlidingEnemyDetector")] public required Area3D SlidingEnemyDetector { get; set; }
[Node("%CloseEnemyDetector")] public required ShapeCast3D CloseEnemyDetector { get; set; }
[Node("AimAssistRayCast")] public required RayCast3D AimAssistRayCast { get; set; }
[Node("HeadSystem/CameraSmooth/Camera3D")] public required Camera3D Camera { get; set; }
public EntityAttributes Attributes { get; set; } = null!;
public EntityTags Tags { get; set; } = null!;
@@ -117,17 +111,14 @@ public partial class PlayerController : CharacterBody3D,
// Forge stuff
[ExportCategory("Forge")]
[ExportGroup("General")]
[Export]
public ForgeTagContainer BaseTags { get; set; }
[Export] public ForgeTag EmpoweredActionUsed;
[Export] public required ForgeTagContainer BaseTags { get; set; }
[Export] public required ForgeTag EmpoweredActionUsed { get; set; }
[Export] public required ForgeTag InvincibleTag { get; set; }
[ExportGroup("Abilities")]
[ExportSubgroup("Common and defaults")]
[Export] public ForgeAbilityData EmpoweredActionAbility = null!;
[Export] public ForgeAbilityData[] DefaultPermanentAbilities = [];
[ExportSubgroup("WeaponThrow")] [Export]
public ForgeAbilityBehavior WeaponExplosionBehavior;
[Export] public ForgeAbilityData? EmpoweredActionAbility;
[Export] public ForgeAbilityData[] DefaultGrantedAbilities = [];
[ExportGroup("Effects")]
[ExportSubgroup("Common and defaults")]
@@ -147,7 +138,6 @@ public partial class PlayerController : CharacterBody3D,
[ExportGroup("Damage")] [Export] public RDamage RDamage { get; set; } = null!;
[Export] public RKnockback? RKnockback { get; set; } = null!;
[Export] public RHealth? RHealth { get; set; } = null!;
[ExportGroup("Targeting")]
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
@@ -409,29 +399,48 @@ public partial class PlayerController : CharacterBody3D,
private Transition _onGroundSlideJump = null!;
private Transition _onAirGlideDoubleJump = null!;
// Damage
public CDamageable? CDamageable { get; set; }
public CHealth? CHealth { get; set; }
public CKnockback? CKnockback { get; set; }
public float CurrentHealth { get; set; }
#endregion
private bool _isInvincible;
public bool IsInvincibleOverride { get; set; }
#region DamageManagement
// Invincibility
private ActiveEffectHandle? _invincibleEffect;
public bool IsInvincible
{
get => _isInvincible || IsInvincibleOverride;
set => _isInvincible = value;
get => Tags.CombinedTags.HasTag(InvincibleTag.GetTag());
set => SetInvincible(value);
}
public void SetInvincible(bool invincible)
{
if (invincible && !IsInvincible)
{
var invincibility = new EffectData(
"Invincibility",
new DurationData(DurationType.Infinite),
effectComponents:
[
new ModifierTagsEffectComponent(
InvincibleTag.GetTag().GetSingleTagContainer()!
)
]);
GD.Print("Applying invincibility");
_invincibleEffect = EffectsManager.ApplyEffect(new Effect(invincibility,
new EffectOwnership(this, this)));
return;
}
if (_invincibleEffect == null) return;
EffectsManager.RemoveEffect(_invincibleEffect);
GD.Print("Removing effect");
_invincibleEffect = null;
}
// Damage dealing
private readonly List<IDamageable> _hitEnemies = new List<IDamageable>();
private ShapeCast3D _closeEnemyDetector = null!;
private RayCast3D _aimAssisRayCast = null!;
private Camera3D _camera = null!;
private AbilityHandle? _empoweredActionHandle;
#endregion
#endregion
public void OnReady()
{
@@ -439,16 +448,15 @@ public partial class PlayerController : CharacterBody3D,
// General use stuff
PlayerUi = GetNode<PlayerUi>("UI");
_closeEnemyDetector = GetNode<ShapeCast3D>("%CloseEnemyDetector");
_closeEnemyDetector.TargetPosition = _closeEnemyDetector.TargetPosition.Normalized() * TargetingDistance;
_aimAssisRayCast = GetNode<RayCast3D>("AimAssistRayCast");
_aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f);
CloseEnemyDetector = GetNode<ShapeCast3D>("%CloseEnemyDetector");
CloseEnemyDetector.TargetPosition = CloseEnemyDetector.TargetPosition.Normalized() * TargetingDistance;
AimAssistRayCast = GetNode<RayCast3D>("AimAssistRayCast");
AimAssistRayCast.TargetPosition = AimAssistRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f);
#region Forge
var tagsManager = ForgeManagers.Instance.TagsManager;
var cuesManager = ForgeManagers.Instance.CuesManager;
List<AttributeSet> attributeSetList = [];
foreach (Node node in GetChildren())
{
@@ -468,15 +476,24 @@ public partial class PlayerController : CharacterBody3D,
Abilities = new(this);
Events = new();
_empoweredActionHandle = Abilities.GrantAbilityPermanently(
EmpoweredActionAbility.GetAbilityData(),
abilityLevel: 1,
levelOverridePolicy: LevelComparison.None,
sourceEntity: this);
foreach (var ability in DefaultPermanentAbilities)
HealthAttribute = Attributes["PlayerAttributeSet.Health"];
ManaAttribute = Attributes["PlayerAttributeSet.Mana"];
cuesManager.RegisterCue(Tag.RequestTag(tagsManager, "cues.resources.health"), this);
if (EmpoweredActionAbility != null)
{
_empoweredActionHandle = Abilities.GrantAbilityPermanently(
EmpoweredActionAbility.GetAbilityData(),
abilityLevel: 1,
levelOverridePolicy: LevelComparison.None,
sourceEntity: this);
}
foreach (var defaultGrantedAbility in DefaultGrantedAbilities)
{
Abilities.GrantAbilityPermanently(
ability.GetAbilityData(),
defaultGrantedAbility.GetAbilityData(),
abilityLevel: 1,
levelOverridePolicy: LevelComparison.None,
sourceEntity: this);
@@ -496,37 +513,23 @@ public partial class PlayerController : CharacterBody3D,
EffectsManager.ApplyEffect(new Effect(effect.GetEffectData(), new EffectOwnership(this, this)));
});
}
Events.Subscribe(Tag.RequestTag(ForgeManagers.Instance.TagsManager, "events.combat.damage"), OnDamageReceived);
Events.Subscribe(Tag.RequestTag(ForgeManagers.Instance.TagsManager, "events.combat.death"), OnDeath);
PlayerUi.Initialize(HealthAttribute, ManaAttribute);
#endregion
// DashIndicator = GetNode<TextureRect>("%DashIndicator");
TargetSpeed = WalkSpeed;
DashIndicatorNode = GetNode<Node3D>("DashIndicator");
DashIndicatorMesh = GetNode<MeshInstance3D>("DashIndicator/DashIndicatorMesh");
DashIndicatorMeshCylinder = (DashIndicatorMesh.Mesh as CylinderMesh)!;
DashIndicatorMesh.Visible = false;
SfxPlayer = GetNode<AudioStreamPlayer3D>("SFXPlayer");
_audioStream = (SfxPlayer.GetStreamPlayback() as AudioStreamPlaybackInteractive)!;
// Camera stuff
HeadSystem = GetNode<HeadSystem>("HeadSystem");
_camera = GetNode<Camera3D>("HeadSystem/CameraSmooth/Camera3D");
Node3D cameraSmooth = GetNode<Node3D>("HeadSystem/CameraSmooth");
// Movement stuff
WeaponSystem = GetNode<WeaponSystem>("WeaponSystem");
MantleSystem = GetNode<MantleSystem>("HeadSystem/MantleSystem");
StandingCollider = GetNode<CollisionShape3D>("StandingCollider");
SlideCollider = GetNode<CollisionShape3D>("SlideCollider");
DashSystem = GetNode<DashSystem>("DashSystem");
StairsSystem = GetNode<StairsSystem>("StairsSystem");
WallHugSystem = GetNode<WallHugSystem>("WallHugSystem");
WallRunSnapper = GetNode<RayCast3D>("%WallRunSnapper");
GroundDetector = GetNode<ShapeCast3D>("GroundDetector");
CeilingDetector = GetNode<ShapeCast3D>("CeilingDetector");
DirectGroundDetector = GetNode<RayCast3D>("DirectGroundDetector");
DashDamageDetector = GetNode<ShapeCast3D>("DashDamage");
SlidingEnemyDetector = GetNode<Area3D>("SlidingEnemyDetector");
RayCast3D stairsBelowRayCast3D = GetNode<RayCast3D>("StairsBelowRayCast3D");
RayCast3D stairsAheadRayCast3D = GetNode<RayCast3D>("StairsAheadRayCast3D");
_headCollisionDetectors = new RayCast3D[NumOfHeadCollisionDetectors];
@@ -545,26 +548,18 @@ public partial class PlayerController : CharacterBody3D,
WeaponHitbox.Monitoring = false;
WeaponHitbox.BodyEntered += RegisterHitEnnemy;
CHealth = GetNode<Node>("CHealth") as CHealth;
CKnockback = GetNode<Node>("CKnockback") as CKnockback;
CDamageable = GetNode<Node>("CDamageable") as CDamageable;
if (CHealth == null) throw new Exception("CHealth not found!");
if (CKnockback == null) throw new Exception("CKnockback not found!");
if (CDamageable == null) throw new Exception("CDamageable not found!");
// if (RHealth != null)
// {
// CHealth.RHealth = RHealth;
// CHealth.CurrentHealth = RHealth.StartingHealth;
// }
// if (RKnockback != null) CKnockback!.RKnockback = RKnockback;
//
// CDamageable.DamageTaken += (damageable, record) => ReduceHealth(damageable, record);
// CDamageable.DamageTaken += (_, record) => RegisterKnockback(new KnockbackRecord(record));
// CHealth.HealthChanged += PlayerUi.OnHealthChanged;
// CHealth.HealthDepleted += (_) => Kill();
if (RHealth != null)
{
CHealth.RHealth = RHealth;
CHealth.CurrentHealth = RHealth.StartingHealth;
}
if (RKnockback != null) CKnockback!.RKnockback = RKnockback;
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;
CHealth.HealthDepleted += (_) => Kill();
#region StateManagement
_playerState = StateChart.Of(GetNode("StateChart"));
@@ -633,7 +628,7 @@ public partial class PlayerController : CharacterBody3D,
Gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity");
MantleSystem.Init();
StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth);
DashSystem.Init(HeadSystem, _camera);
DashSystem.Init(HeadSystem, Camera);
WeaponSystem.Init();
WallHugSystem.Init();
@@ -728,6 +723,8 @@ public partial class PlayerController : CharacterBody3D,
var weaponLeftToken = WeaponSystem.Events.Subscribe(WeaponSystem.WeaponStartedFlyingEventTag, OnWeaponLeft);
var weaponLandedToken = WeaponSystem.Events.Subscribe(WeaponSystem.WeaponStoppedFlyingEventTag, OnWeaponLanded);
}
#region LifecycleManagement
public void OnResolved()
{
@@ -737,8 +734,7 @@ public partial class PlayerController : CharacterBody3D,
{
foreach (var ability in abilities)
{
if (ability is not ForgeAbilityBehavior abilityBehavior) continue;
WeaponSystem.GrantNewAbilityForEvent(weaponEvent, abilityBehavior);
WeaponSystem.GrantNewAbilityForEvent(weaponEvent, ability);
}
}
@@ -753,6 +749,10 @@ public partial class PlayerController : CharacterBody3D,
InventoryManager.WeaponEventAbilityRemoved -= OnWeaponEventAbilityRemoved;
}
#endregion
#region WeaponEvents
public void OnWeaponLeft(EventData data)
{
var target = data.Target;
@@ -789,10 +789,11 @@ public partial class PlayerController : CharacterBody3D,
{
WeaponSystem.RemoveAbilityForEvent(data.ForEvent, data.Ability);
}
#endregion
///////////////////////////
// Settings & tutorial //
///////////////////////////
#region Settings
public void LoadSettings()
{
var config = new ConfigFile();
@@ -812,25 +813,26 @@ public partial class PlayerController : CharacterBody3D,
_fovChangeMultiplier = (float) config.GetValue("InputSettings", "FovChangeWithSpeed", 1.0f);
_aimAssistMultiplier = (float) config.GetValue("InputSettings", "AimAssist", 1.0f);
}
#endregion
///////////////////////////
// Toolbox Utils //
///////////////////////////
#region Toolbox
public void SetPlayerHealthOverride(float newHealthValue)
{
RHealth.StartingHealth = newHealthValue;
CHealth!.CurrentHealth = newHealthValue;
PlayerUi.Initialize(CHealth.CurrentHealth, Attributes["PlayerAttributeSet.Mana"].BaseValue);
// RHealth.StartingHealth = newHealthValue;
// CHealth!.CurrentHealth = newHealthValue;
// PlayerUi.Initialize(CHealth.CurrentHealth, Attributes["PlayerAttributeSet.Mana"].BaseValue);
}
public void SetPlayerDamageOverride(float newDamageValue)
{
RDamage.DamageDealt = newDamageValue;
}
#endregion
///////////////////////////
// Grounded management //
///////////////////////////
#region GroundManagement
public void OnGrounded()
{
_isWallJumpAvailable = true;
@@ -882,10 +884,7 @@ public partial class PlayerController : CharacterBody3D,
_audioStream.SwitchToClipByName("land");
}
public bool IsGroundLike()
{
return GroundDetector.GetCollisionResult().Count > 0;
}
public bool IsGroundLike() => GroundDetector.GetCollisionResult().Count > 0;
public void HandleGrounded(float delta)
{
@@ -972,11 +971,10 @@ public partial class PlayerController : CharacterBody3D,
{
return IsOnFloor() || StairsSystem.WasSnappedToStairsLastFrame();
}
///////////////////////////
// Airborne management //
///////////////////////////
#endregion
#region AirborneManagement
public void OnAirborne()
{
if (_aiming.Active)
@@ -1026,6 +1024,8 @@ public partial class PlayerController : CharacterBody3D,
var verticalVelocity = ComputeVerticalSpeedGravity((float) delta);
Velocity = new Vector3(horizontalVelocity.X, verticalVelocity, horizontalVelocity.Z);
}
#endregion
///////////////////////////
// Movement input //
@@ -1091,17 +1091,17 @@ public partial class PlayerController : CharacterBody3D,
// Camera stuff
private Vector2 ComputeAimAssist()
{
_aimAssisRayCast.SetRotation(HeadSystem.GetGlobalLookRotation());
if (!_aimAssisRayCast.IsColliding()) return Vector2.Zero;
AimAssistRayCast.SetRotation(HeadSystem.GetGlobalLookRotation());
if (!AimAssistRayCast.IsColliding()) return Vector2.Zero;
// Hard dependency on the aim assist to be an Area3D and having a parent
var collidedObject = _aimAssisRayCast.GetCollider() as Area3D;
var collidedObject = AimAssistRayCast.GetCollider() as Area3D;
if (collidedObject is null) return Vector2.Zero;
if (collidedObject.GetParent() is not ITargetable targetable) return Vector2.Zero;
var targetPosition = targetable.GetTargetGlobalPosition();
var targetPositionOnCamera = _camera.UnprojectPosition(targetPosition);
var centerOfScreen = _camera.GetViewport().GetVisibleRect().Size / 2f;
var targetPositionOnCamera = Camera.UnprojectPosition(targetPosition);
var centerOfScreen = Camera.GetViewport().GetVisibleRect().Size / 2f;
var aimAssistDirection = centerOfScreen - targetPositionOnCamera;
var aimAssist = aimAssistDirection * AimAssistStrength / 1000f;
@@ -2061,7 +2061,7 @@ public partial class PlayerController : CharacterBody3D,
if (!isOnFloorCustom())
ReduceTimeScaleWhileAiming();
_aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() *
AimAssistRayCast.TargetPosition = AimAssistRayCast.TargetPosition.Normalized() *
(DashSystem.DashCast3D.TargetPosition.Length() + DashSystem.DashCastRadius);
}
public void HandleAiming(float delta)
@@ -2076,7 +2076,7 @@ public partial class PlayerController : CharacterBody3D,
{
DashSystem.StopPreparingDash();
_aimAssisRayCast.TargetPosition = _aimAssisRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f);
AimAssistRayCast.TargetPosition = AimAssistRayCast.TargetPosition.Normalized() * (TargetingDistance*1.5f);
// DashIndicatorMesh.Visible = false;
}
@@ -2337,6 +2337,11 @@ public partial class PlayerController : CharacterBody3D,
// private float _oldMana = 100;
public override void _Process(double delta)
{
if (Engine.GetProcessFrames() % 60 == 0)
{
GD.Print(_invincibleEffect);
GD.Print(Tags.CombinedTags.Count);
}
EffectsManager.UpdateEffects(delta);
}
@@ -2351,7 +2356,7 @@ public partial class PlayerController : CharacterBody3D,
public void HandleEnemyTargeting()
{
_isEnemyInDashAttackRange = false;
_closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation());
CloseEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation());
var enemyTargetState = PlayerUi.TargetState.NoTarget;
var positionOnScreen = Vector2.Zero;
@@ -2359,20 +2364,20 @@ public partial class PlayerController : CharacterBody3D,
{
enemyTargetState = PlayerUi.TargetState.TargetWouldKill;
_targetLocation = dashTarget.GetTargetGlobalPosition();
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
positionOnScreen = Camera.UnprojectPosition(_targetLocation);
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
return;
}
if (!_closeEnemyDetector.IsColliding())
if (!CloseEnemyDetector.IsColliding())
{
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
return;
}
_targetHitLocation = _closeEnemyDetector.GetCollisionPoint(0);
_targetObject = _closeEnemyDetector.GetCollider(0);
_targetHitLocation = CloseEnemyDetector.GetCollisionPoint(0);
_targetObject = CloseEnemyDetector.GetCollider(0);
if (_targetObject is not ITargetable target)
{
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
@@ -2381,7 +2386,7 @@ public partial class PlayerController : CharacterBody3D,
_targetLocation = target.GetTargetGlobalPosition();
// var targetDistance = _targetLocation.DistanceTo(GlobalPosition);
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
positionOnScreen = Camera.UnprojectPosition(_targetLocation);
var wouldKill = false;
if (_targetObject is IHealthable h and IDamageable d)
@@ -2399,20 +2404,21 @@ public partial class PlayerController : CharacterBody3D,
if (IsInvincible)
return damageRecord with { Damage = new RDamage(0, damageRecord.Damage.DamageType) };
var finalDamage = CDamageable!.TakeDamage(damageRecord);
DamageTaken?.Invoke(this, finalDamage);
// var finalDamage = CDamageable!.TakeDamage(damageRecord);
// DamageTaken?.Invoke(this, finalDamage);
HeadSystem.OnGetHit();
_audioStream.SwitchToClipByName("damage_taken");
TriggerHitstop();
OnHitInvincibility();
return finalDamage;
return damageRecord;
}
public DamageRecord ComputeDamage(DamageRecord damageRecord)
{
return CDamageable!.ComputeDamage(damageRecord);
// return CDamageable!.ComputeDamage(damageRecord);
return damageRecord;
}
public void OnHitInvincibility()
@@ -2590,19 +2596,25 @@ public partial class PlayerController : CharacterBody3D,
}
public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
{
var record = CHealth!.ReduceHealth(source, damageRecord);
HealthChanged?.Invoke(this, record);
return record;
// var record = CHealth!.ReduceHealth(source, damageRecord);
// HealthChanged?.Invoke(this, record);
return new HealthChangedRecord(100, 0, 100);
}
public void RegisterKnockback(KnockbackRecord knockbackRecord)
{
CKnockback!.RegisterKnockback(knockbackRecord);
// CKnockback!.RegisterKnockback(knockbackRecord);
}
public Vector3 ComputeKnockback()
{
var kb = CKnockback!.ComputeKnockback();
return kb;
// var kb = CKnockback!.ComputeKnockback();
// return kb;
return Vector3.Zero;
}
public void OnDeath(EventData data)
{
Kill();
}
public void Kill()
@@ -2625,4 +2637,43 @@ public partial class PlayerController : CharacterBody3D,
{
_audioStream.SwitchToClipByName("footsteps");
}
// Forge Damage handling
public void OnDamageReceived(EventData data)
{
var newHealth = HealthAttribute.CurrentValue + data.EventMagnitude;
if (newHealth > HealthAttribute.Min) return;
var tagsManager = ForgeManagers.Instance.TagsManager;
Events.Raise(new EventData
{
EventTags = Tag.RequestTag(tagsManager, "events.combat.death").GetSingleTagContainer()!,
Source = data.Source,
Target = data.Target
});
}
public void OnExecute(IForgeEntity? target, CueParameters? parameters)
{
if (target == null || !parameters.HasValue) return;
float magnitude = parameters.Value.Magnitude;
if (magnitude >= 0) return;
HeadSystem.OnGetHit();
_audioStream.SwitchToClipByName("damage_taken");
TriggerHitstop();
}
public void OnApply(IForgeEntity? target, CueParameters? parameters)
{
}
public void OnRemove(IForgeEntity? target, bool interrupted)
{
}
public void OnUpdate(IForgeEntity? target, CueParameters? parameters)
{
}
}