mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 11:15:33 +00:00
222 lines
No EOL
7.1 KiB
C#
222 lines
No EOL
7.1 KiB
C#
using System;
|
|
using System.Linq;
|
|
using Cirno.Scripts.Components.FSM;
|
|
using Cirno.Scripts.Enums;
|
|
using Cirno.Scripts.Resources;
|
|
using Godot;
|
|
using Godot.Collections;
|
|
|
|
namespace Cirno.Scripts.Components.Actors;
|
|
|
|
public partial class PlayerDamageReceiver : Area2D
|
|
{
|
|
[Export]
|
|
public bool Enabled { get; set; } = false;
|
|
[Export]
|
|
public bool Invulnerable { get; private set; } = false;
|
|
[Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.Player;
|
|
|
|
[ExportCategory("Extensions")]
|
|
[Export] public StringName HealthExtendName { get; private set; } = "HEALTH_EXTEND";
|
|
[Export] public StringName ShieldExtendName { get; private set; } = "SHIELD_EXTEND";
|
|
|
|
[Export] public float BaseHealth { get; private set; } = 32f;
|
|
[Export] public float BaseShield { get; private set; } = 32f;
|
|
|
|
[Export] public float HealthExtendAmount { get; private set; } = 4f;
|
|
[Export] public float ShieldExtendAmount { get; private set; } = 4f;
|
|
|
|
[ExportCategory("Providers")]
|
|
[Export]
|
|
private ActorResourceProvider _healthProvider;
|
|
[Export]
|
|
private ActorResourceProvider _shieldProvider;
|
|
|
|
[ExportCategory("Damage Types")]
|
|
[Export] public StringName AcidGroupName { get; private set; } = "Acid";
|
|
|
|
[Export] public Array<DamageResistance> ShieldDamageResistances { get; set; } = [];
|
|
[Export] public Array<DamageResistance> HealthDamageResistances { get; set; } = [];
|
|
|
|
[Signal]
|
|
public delegate void HealthChangedEventHandler(float newValue, float maxValue);
|
|
[Signal]
|
|
public delegate void HealthDecreasedEventHandler(float value, float newValue, float maxValue);
|
|
|
|
[Signal]
|
|
public delegate void ShieldChangedEventHandler(float newValue, float maxValue);
|
|
[Signal]
|
|
public delegate void ShieldDecreasedEventHandler(float value, float newValue, float maxValue);
|
|
|
|
[Signal]
|
|
public delegate void DeathEventHandler();
|
|
|
|
public float CurrentHealth
|
|
{
|
|
get => _healthProvider.CurrentResource;
|
|
set => _healthProvider.CurrentResource = value;
|
|
}
|
|
|
|
public float CurrentShield
|
|
{
|
|
get => _shieldProvider.CurrentResource;
|
|
set => _shieldProvider.CurrentResource = value;
|
|
}
|
|
|
|
private IStateMachine<PlayerState, CharacterBody2D> _stateMachine;
|
|
|
|
public void Init(IStateMachine<PlayerState, CharacterBody2D> machine)
|
|
{
|
|
_stateMachine = machine;
|
|
|
|
Invulnerable = GlobalState.Instance.SessionSettings.GodMode;
|
|
|
|
_healthProvider.ResourceChanged += ((value, maxValue) =>
|
|
{
|
|
//if (!Enabled) return;
|
|
Hud.Instance?.UpdateHealth(value, maxValue);
|
|
EmitSignal(SignalName.HealthChanged, value, maxValue);
|
|
});
|
|
|
|
_healthProvider.ResourceDecreased += (value, newValue, maxValue) =>
|
|
{
|
|
EmitSignal(SignalName.HealthDecreased, value, newValue, maxValue);
|
|
};
|
|
|
|
_shieldProvider.ResourceDecreased += (value, newValue, maxValue) =>
|
|
{
|
|
EmitSignal(SignalName.ShieldDecreased, value, newValue, maxValue);
|
|
};
|
|
|
|
_shieldProvider.ResourceChanged += ((value, maxValue) =>
|
|
{
|
|
//if (!Enabled) return;
|
|
Hud.Instance?.UpdateShield(value, maxValue);
|
|
EmitSignal(SignalName.ShieldChanged, value, maxValue);
|
|
});
|
|
|
|
_healthProvider.ResourceDepleted += () =>
|
|
{
|
|
//if (!Enabled) return;
|
|
EmitSignal(SignalName.Death);
|
|
};
|
|
|
|
// Set max resources based on inventory
|
|
SetMaxResources();
|
|
|
|
InventoryManager.Instance.ItemAdded += (item, amount) =>
|
|
{
|
|
if (item.ItemKey != HealthExtendName && item.ItemKey != ShieldExtendName) return;
|
|
|
|
SetMaxResources();
|
|
};
|
|
}
|
|
|
|
private void SetMaxResources()
|
|
{
|
|
var healthExtends = InventoryManager.Instance.GetItemCount(HealthExtendName);
|
|
|
|
var shieldExtends = InventoryManager.Instance.GetItemCount(ShieldExtendName);
|
|
|
|
_healthProvider.MaxResource = BaseHealth + (healthExtends * HealthExtendAmount);
|
|
|
|
_shieldProvider.MaxResource = BaseShield + (shieldExtends * ShieldExtendAmount);
|
|
}
|
|
|
|
public void RefillHealth()
|
|
{
|
|
_healthProvider.FillResource();
|
|
}
|
|
|
|
public void RefillShield()
|
|
{
|
|
_shieldProvider.FillResource();
|
|
}
|
|
|
|
private void _on_damage_hitbox_area_entered(Area2D area)
|
|
{
|
|
if (!Enabled) return;
|
|
if (Invulnerable) return;
|
|
if (area.IsInGroup(AcidGroupName))
|
|
{
|
|
// Handle acid death
|
|
AcidDeath();
|
|
return;
|
|
}
|
|
if (area is not Bullet bullet || bullet.BulletOwner == BulletGroup) return;
|
|
this.Hit(bullet.Damage, bullet.DamageType);
|
|
bullet.RequestCollisionDestruction();
|
|
}
|
|
|
|
private void AcidDeath()
|
|
{
|
|
if (!Enabled) return;
|
|
GD.Print("Acid death");
|
|
_stateMachine.SetState(PlayerState.Drowning);
|
|
//_healthProvider.CurrentResource = 0;
|
|
}
|
|
|
|
private void ApplyDamageToHealth(float damage, DamageType type = DamageType.Neutral)
|
|
{
|
|
if (HealthDamageResistances.Where(x => x.DamageType == type)
|
|
.Any(x => x.Attribute is DamageAttribute.Skip)) return;
|
|
|
|
var dmg = HealthDamageResistances.Aggregate(damage, (current, resistance) => current * resistance.CalculateDamage(current, type));
|
|
|
|
CurrentHealth -= dmg;
|
|
}
|
|
public void Hit(float damage, DamageType type = DamageType.Neutral)
|
|
{
|
|
if (!Enabled) return;
|
|
|
|
// Check if the shield is empty or damage has skip attributes
|
|
if (CurrentShield <= 0 || ShieldDamageResistances.Where(x => x.DamageType == type).Any(x => x.Attribute is DamageAttribute.Skip))
|
|
{
|
|
// do not apply, go to health
|
|
ApplyDamageToHealth(damage, type);
|
|
}
|
|
else
|
|
{
|
|
var shieldDmg = ShieldDamageResistances.Aggregate(damage, (current, resistance) => current * resistance.CalculateDamage(current, type));
|
|
|
|
// apply and get remainder
|
|
var remainder = CurrentShield - shieldDmg;
|
|
CurrentShield = remainder; // Let the resource's self-balancing take care of any remainders
|
|
|
|
if (remainder < 0)
|
|
{
|
|
// Apply remainder to health
|
|
ApplyDamageToHealth(-remainder, type);
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
if (CurrentShield > 0 && type is not DamageType.Explosive or DamageType.Acid)
|
|
{
|
|
// Reduce shield
|
|
//PlayShieldAnimation(); // Let this be handled by event
|
|
CurrentShield -= damage;
|
|
if (CurrentShield < 0)
|
|
{
|
|
CurrentHealth -= Math.Abs(CurrentShield);
|
|
CurrentShield = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (type is DamageType.Fire)
|
|
{
|
|
CurrentHealth -= damage * 2;
|
|
}
|
|
else
|
|
{
|
|
CurrentHealth -= damage;
|
|
}
|
|
|
|
//Blink(); // Let this be handled by event
|
|
}
|
|
|
|
if (!(CurrentHealth <= 0)) return;
|
|
}
|
|
} |