2022-11-10 20:29:53 -08:00
|
|
|
using Godot;
|
2023-06-13 02:55:30 -07:00
|
|
|
using GodotUtilities;
|
2022-11-25 09:11:46 -08:00
|
|
|
using SupaLidlGame.Extensions;
|
2022-11-19 21:21:12 -08:00
|
|
|
using SupaLidlGame.Items;
|
|
|
|
using SupaLidlGame.Utils;
|
2023-05-25 15:28:33 -07:00
|
|
|
using SupaLidlGame.State.Character;
|
2022-11-10 20:29:53 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
namespace SupaLidlGame.Characters;
|
|
|
|
|
|
|
|
public partial class Character : CharacterBody2D, IFaction
|
2022-11-10 20:29:53 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
|
|
|
public float Speed { get; protected set; } = 32.0f;
|
2022-11-12 16:45:04 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
2023-08-05 23:50:08 -07:00
|
|
|
public float Friction { get; protected set; } = 4.0f;
|
2022-11-25 09:11:46 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
|
|
|
public float Mass
|
|
|
|
{
|
|
|
|
get => _mass;
|
|
|
|
set
|
2022-11-13 19:52:09 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
if (value > 0)
|
|
|
|
_mass = value;
|
2022-11-13 19:52:09 -08:00
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2022-11-13 19:52:09 -08:00
|
|
|
|
2024-03-25 21:14:06 -07:00
|
|
|
[Export]
|
2024-03-29 16:17:19 -07:00
|
|
|
public CharacterStats Stats { get; protected set; }
|
2024-03-25 21:14:06 -07:00
|
|
|
|
2023-06-06 18:39:23 -07:00
|
|
|
[Signal]
|
2023-08-13 16:49:18 -07:00
|
|
|
public delegate void HealthChangedEventHandler(Events.HealthChangedArgs args);
|
2023-06-06 18:39:23 -07:00
|
|
|
|
|
|
|
[Signal]
|
2023-08-07 02:38:51 -07:00
|
|
|
public delegate void HurtEventHandler(Events.HurtArgs args);
|
|
|
|
|
|
|
|
[Signal]
|
|
|
|
public delegate void DeathEventHandler(Events.HurtArgs args);
|
2023-06-06 18:39:23 -07:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
protected float _mass = 1.0f;
|
2022-11-13 19:52:09 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public Vector2 NetImpulse { get; set; } = Vector2.Zero;
|
2022-11-25 09:11:46 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public Vector2 Direction { get; set; } = Vector2.Zero;
|
2022-11-13 15:42:04 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public Vector2 Target { get; set; } = Vector2.Zero;
|
2023-07-22 20:23:48 -07:00
|
|
|
|
|
|
|
[Export]
|
|
|
|
public Texture2D HandTexture { get; set; }
|
2022-11-13 15:42:04 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
2023-07-22 20:23:48 -07:00
|
|
|
public virtual float Health
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
|
|
|
get => _health;
|
|
|
|
set
|
2022-11-19 21:21:12 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
if (!IsAlive && value < 0)
|
2022-11-19 21:21:12 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-13 16:49:18 -07:00
|
|
|
var args = new Events.HealthChangedArgs
|
|
|
|
{
|
|
|
|
OldHealth = _health,
|
|
|
|
NewHealth = value,
|
|
|
|
};
|
|
|
|
EmitSignal(SignalName.HealthChanged, args);
|
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
_health = value;
|
|
|
|
if (_health <= 0)
|
|
|
|
{
|
|
|
|
Die();
|
2022-11-19 21:21:12 -08:00
|
|
|
}
|
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public bool IsAlive => Health > 0;
|
2022-11-25 09:11:46 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
protected float _health = 100f;
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public double StunTime { get; set; }
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
2023-07-21 02:54:13 -07:00
|
|
|
public Sprite2D Sprite { get; set; }
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
|
|
|
public Inventory Inventory { get; set; }
|
2022-11-13 19:52:09 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
|
|
|
public CharacterStateMachine StateMachine { get; set; }
|
2022-11-10 20:29:53 -08:00
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
[Export]
|
|
|
|
public BoundingBoxes.Hurtbox Hurtbox { get; set; }
|
|
|
|
|
2024-06-04 22:12:01 -07:00
|
|
|
[Export(PropertyHint.Flags)]
|
|
|
|
public FactionName Faction { get; set; }
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-07-21 02:54:13 -07:00
|
|
|
public AnimationPlayer MovementAnimation { get; set; }
|
|
|
|
|
|
|
|
public AnimationPlayer HurtAnimation { get; set; }
|
|
|
|
|
2023-07-23 23:39:20 -07:00
|
|
|
public AnimationPlayer StunAnimation { get; set; }
|
|
|
|
|
2023-08-05 23:50:08 -07:00
|
|
|
public AnimationPlayer AttackAnimation { get; set; }
|
|
|
|
|
2023-08-15 23:05:39 -07:00
|
|
|
private UI.DamageText _curDamageText;
|
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
public override void _Ready()
|
|
|
|
{
|
2023-07-21 02:54:13 -07:00
|
|
|
MovementAnimation = GetNode<AnimationPlayer>("Animations/Movement");
|
|
|
|
HurtAnimation = GetNode<AnimationPlayer>("Animations/Hurt");
|
2023-07-23 23:39:20 -07:00
|
|
|
StunAnimation = GetNode<AnimationPlayer>("Animations/Stun");
|
2023-08-05 23:50:08 -07:00
|
|
|
AttackAnimation = GetNode<AnimationPlayer>("Animations/Attack");
|
|
|
|
|
2024-03-25 21:14:06 -07:00
|
|
|
if (Stats is not null)
|
|
|
|
{
|
2024-03-29 16:17:19 -07:00
|
|
|
Stats.Stagger += (double time, float staggerDamage) =>
|
2024-03-25 21:14:06 -07:00
|
|
|
{
|
|
|
|
Stun(time);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
Hurtbox.ReceivedDamage += OnReceivedDamage;
|
|
|
|
}
|
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public override void _Process(double delta)
|
|
|
|
{
|
2023-12-29 20:15:23 -08:00
|
|
|
if (StunTime > 0)
|
|
|
|
{
|
|
|
|
StunTime -= delta;
|
|
|
|
}
|
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
if (StateMachine != null)
|
2022-11-10 20:29:53 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
StateMachine.Process(delta);
|
2022-11-13 15:42:04 -08:00
|
|
|
}
|
|
|
|
|
2023-07-23 23:39:20 -07:00
|
|
|
if (StunTime > 0 && !StunAnimation.IsPlaying())
|
|
|
|
{
|
2023-10-02 00:10:24 -07:00
|
|
|
StunAnimation.TryPlayAny("stun", "npc_stun/stun");
|
2023-07-23 23:39:20 -07:00
|
|
|
}
|
|
|
|
else if (StunTime < 0 && StunAnimation.IsPlaying())
|
|
|
|
{
|
|
|
|
StunAnimation.Stop();
|
|
|
|
}
|
|
|
|
|
2023-09-06 23:18:53 -07:00
|
|
|
if (Target.X < 0)
|
|
|
|
{
|
|
|
|
Sprite.FlipH = true;
|
|
|
|
}
|
|
|
|
else if (Target.X > 0)
|
|
|
|
{
|
|
|
|
Sprite.FlipH = false;
|
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
DrawTarget();
|
|
|
|
}
|
2022-11-10 20:29:53 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public override void _PhysicsProcess(double delta)
|
|
|
|
{
|
|
|
|
if (StateMachine != null)
|
2022-11-19 21:21:12 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
StateMachine.PhysicsProcess(delta);
|
2022-11-19 21:21:12 -08:00
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Modify the <c>Character</c>'s velocity
|
|
|
|
/// </summary>
|
|
|
|
public virtual void ModifyVelocity()
|
|
|
|
{
|
|
|
|
if (StunTime > 0)
|
2022-11-19 21:21:12 -08:00
|
|
|
{
|
2024-03-26 12:46:37 -07:00
|
|
|
//Velocity *= 0.25f;
|
|
|
|
Velocity = Vector2.Zero;
|
2022-11-19 21:21:12 -08:00
|
|
|
}
|
2023-07-23 23:39:20 -07:00
|
|
|
|
|
|
|
var state = StateMachine.CurrentState;
|
|
|
|
if (state is State.Character.CharacterDashState dashState)
|
|
|
|
{
|
|
|
|
Velocity *= dashState.VelocityModifier;
|
|
|
|
}
|
|
|
|
// TODO: make PlayerRollState a CharacterRollState instead
|
|
|
|
else if (state is State.Character.PlayerRollState rollState)
|
|
|
|
{
|
2023-12-16 16:38:52 -08:00
|
|
|
Velocity *= rollState.VelocityModifier;
|
2023-07-23 23:39:20 -07:00
|
|
|
//Velocity *= rollState.VelocityModifier;
|
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Handles the <c>Character</c>'s death.
|
|
|
|
/// </summary>
|
2023-06-03 18:21:46 -07:00
|
|
|
public virtual void Die()
|
|
|
|
{
|
2023-10-02 00:10:24 -07:00
|
|
|
if (HurtAnimation.TryPlayAny(out var name, "death", "npc_hurt/death"))
|
2023-07-31 01:12:47 -07:00
|
|
|
{
|
2023-10-02 00:10:24 -07:00
|
|
|
HurtAnimation.Play(name);
|
2023-07-31 01:12:47 -07:00
|
|
|
HurtAnimation.AnimationFinished += (StringName name) =>
|
|
|
|
QueueFree();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QueueFree();
|
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ApplyImpulse(Vector2 impulse, bool resetVelocity = false)
|
|
|
|
{
|
|
|
|
// delta p = F delta t
|
|
|
|
if (resetVelocity)
|
|
|
|
Velocity = Vector2.Zero;
|
|
|
|
NetImpulse += impulse / Mass;
|
|
|
|
}
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Stuns the <c>Chararacter</c> for an amount of time. If
|
|
|
|
/// <paramref name="time"/> is less than the <c>Character</c>'s current
|
|
|
|
/// stun time left, it will have no effect.
|
|
|
|
/// </summary>
|
2024-03-25 21:14:06 -07:00
|
|
|
public virtual void Stun(double time)
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
2023-07-23 23:39:20 -07:00
|
|
|
StunTime = Mathf.Max(time, StunTime);
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Draws the character so that its sprite and inventory items face the
|
|
|
|
/// character's direction.
|
|
|
|
/// </summary>
|
2023-06-10 22:15:28 -07:00
|
|
|
protected virtual void DrawTarget()
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
|
|
|
Vector2 target = Target;
|
|
|
|
float angle = Mathf.Atan2(target.Y, Mathf.Abs(target.X));
|
|
|
|
Vector2 scale = Inventory.Scale;
|
|
|
|
if (target.X < 0)
|
2022-11-13 19:52:09 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
scale.Y = -1;
|
|
|
|
angle = Mathf.Pi - angle;
|
2022-11-25 09:11:46 -08:00
|
|
|
}
|
2023-09-06 23:18:53 -07:00
|
|
|
else if (target.X > 0)
|
2022-11-25 09:11:46 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
scale.Y = 1;
|
2022-11-13 19:52:09 -08:00
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
Inventory.Scale = scale;
|
|
|
|
Inventory.Rotation = angle;
|
|
|
|
}
|
2022-11-13 19:52:09 -08:00
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Use the current item the character is using. Prefer to call this over
|
|
|
|
/// <c>Item.Use</c> as it will check if the character is stunned or alive.
|
|
|
|
/// </summary>
|
2023-06-03 18:21:46 -07:00
|
|
|
public void UseCurrentItem()
|
|
|
|
{
|
2023-07-31 01:12:47 -07:00
|
|
|
if (StunTime > 0 || !IsAlive)
|
2022-11-19 21:21:12 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
return;
|
2022-11-19 21:21:12 -08:00
|
|
|
}
|
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
if (Inventory.SelectedItem is Weapon weapon)
|
2022-11-25 09:11:46 -08:00
|
|
|
{
|
2023-08-08 00:54:00 -07:00
|
|
|
weapon.Use();
|
2022-11-25 09:11:46 -08:00
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2022-11-25 09:11:46 -08:00
|
|
|
|
2023-07-23 23:39:20 -07:00
|
|
|
public void DeuseCurrentItem()
|
|
|
|
{
|
|
|
|
if (Inventory.SelectedItem is Weapon weapon)
|
|
|
|
{
|
|
|
|
weapon.Deuse();
|
|
|
|
// TODO: DeusedItem signal, implement when needed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-10 12:30:26 -07:00
|
|
|
public virtual void UseCurrentItemAlt()
|
2023-08-08 00:54:00 -07:00
|
|
|
{
|
|
|
|
if (StunTime > 0 || !IsAlive)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Inventory.SelectedItem is Weapon weapon)
|
|
|
|
{
|
|
|
|
weapon.UseAlt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void DeuseCurrentItemAlt()
|
|
|
|
{
|
|
|
|
if (Inventory.SelectedItem is Weapon weapon)
|
|
|
|
{
|
|
|
|
weapon.DeuseAlt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public void LookTowardsDirection()
|
|
|
|
{
|
|
|
|
if (!Direction.IsZeroApprox())
|
2023-05-28 17:54:48 -07:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
Target = Direction;
|
2023-05-28 17:54:48 -07:00
|
|
|
}
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2023-05-28 17:54:48 -07:00
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Override this method to modify the damage the character takes.
|
|
|
|
/// </summary>
|
2023-07-22 20:23:48 -07:00
|
|
|
protected virtual float ReceiveDamage(
|
|
|
|
float damage,
|
|
|
|
Character inflictor,
|
|
|
|
float knockback,
|
|
|
|
Vector2 knockbackDir = default) => damage;
|
|
|
|
|
2023-08-15 23:05:39 -07:00
|
|
|
protected void CreateDamageText(float damage)
|
|
|
|
{
|
|
|
|
// create damage text
|
|
|
|
var textScene = GD.Load<PackedScene>("res://UI/DamageText.tscn");
|
|
|
|
if (_curDamageText is null || !IsInstanceValid(_curDamageText))
|
|
|
|
{
|
|
|
|
_curDamageText = textScene.Instantiate<UI.DamageText>();
|
|
|
|
this.GetWorld().CurrentMap.AddChild(_curDamageText);
|
|
|
|
}
|
|
|
|
_curDamageText.Damage += damage;
|
|
|
|
_curDamageText.Timer.Start();
|
|
|
|
_curDamageText.GlobalPosition = GlobalPosition;
|
|
|
|
_curDamageText.ShowText();
|
|
|
|
}
|
2023-07-22 20:23:48 -07:00
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Handles the character taking damage.
|
|
|
|
/// </summary>
|
2023-08-07 02:38:51 -07:00
|
|
|
protected virtual void OnReceivedDamage(
|
2023-06-03 18:21:46 -07:00
|
|
|
float damage,
|
|
|
|
Character inflictor,
|
|
|
|
float knockback,
|
2023-09-03 17:42:32 -07:00
|
|
|
Weapon weapon = null,
|
2023-07-21 02:54:13 -07:00
|
|
|
Vector2 knockbackDir = default)
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
2023-06-13 02:55:30 -07:00
|
|
|
if (Health <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-25 21:14:06 -07:00
|
|
|
// update stats
|
2023-06-10 22:15:28 -07:00
|
|
|
float oldHealth = Health;
|
2023-08-15 23:05:39 -07:00
|
|
|
damage = ReceiveDamage(damage, inflictor, knockback, knockbackDir);
|
|
|
|
Health -= damage;
|
2023-06-03 18:21:46 -07:00
|
|
|
|
2024-03-25 21:14:06 -07:00
|
|
|
if (Stats is not null)
|
|
|
|
{
|
|
|
|
Stats.AddStaggerDamage(damage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// effects
|
2023-07-31 01:12:47 -07:00
|
|
|
var hurtParticles = GetNode<GpuParticles2D>("Effects/HurtParticles");
|
|
|
|
if (hurtParticles is not null)
|
|
|
|
{
|
|
|
|
hurtParticles.SetDirection(knockbackDir);
|
|
|
|
}
|
|
|
|
|
2023-08-15 23:05:39 -07:00
|
|
|
CreateDamageText(damage);
|
2023-06-03 18:21:46 -07:00
|
|
|
|
|
|
|
// apply knockback
|
|
|
|
ApplyImpulse(knockbackDir.Normalized() * knockback);
|
2023-05-28 10:57:23 -07:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
// play damage animation
|
2023-07-24 00:30:33 -07:00
|
|
|
if (HurtAnimation is not null && Health > 0)
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
2023-07-24 00:30:33 -07:00
|
|
|
HurtAnimation.Stop();
|
2023-10-02 00:10:24 -07:00
|
|
|
HurtAnimation.TryPlayAny("hurt", "npc_hurt/hurt");
|
|
|
|
HurtAnimation.TryQueue("hurt_flash");
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2022-11-26 14:53:24 -08:00
|
|
|
|
2023-07-31 01:12:47 -07:00
|
|
|
if (this.GetNode("Effects/HurtSound") is AudioStreamPlayer2D sound)
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
|
|
|
// very small pitch deviation
|
2023-06-13 02:55:30 -07:00
|
|
|
sound.At(GlobalPosition).WithPitchDeviation(0.125f).PlayOneShot();
|
2022-11-13 19:52:09 -08:00
|
|
|
}
|
2023-06-10 22:15:28 -07:00
|
|
|
|
2023-08-07 02:38:51 -07:00
|
|
|
Events.HurtArgs args = new Events.HurtArgs
|
2023-06-10 22:15:28 -07:00
|
|
|
{
|
|
|
|
Attacker = inflictor,
|
|
|
|
OldHealth = oldHealth,
|
|
|
|
NewHealth = Health,
|
2023-09-03 17:42:32 -07:00
|
|
|
Weapon = weapon,
|
2023-06-10 22:15:28 -07:00
|
|
|
Damage = damage,
|
|
|
|
};
|
2023-06-13 02:55:30 -07:00
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
EmitSignal(SignalName.Hurt, args);
|
|
|
|
|
2023-09-03 17:42:32 -07:00
|
|
|
if (inflictor is Player)
|
|
|
|
{
|
|
|
|
EmitPlayerHitSignal(args);
|
|
|
|
}
|
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
if (Health <= 0)
|
|
|
|
{
|
|
|
|
EmitSignal(SignalName.Death, args);
|
2023-08-15 11:27:03 -07:00
|
|
|
GetNode<GpuParticles2D>("DeathParticles")?
|
2023-06-13 02:55:30 -07:00
|
|
|
.CloneOnWorld<GpuParticles2D>()
|
|
|
|
.EmitOneShot();
|
2023-06-10 22:15:28 -07:00
|
|
|
}
|
2022-11-10 20:29:53 -08:00
|
|
|
}
|
2023-07-24 00:56:01 -07:00
|
|
|
|
2023-09-03 17:42:32 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Converts a HurtArgs to HitArgs if the attacker was a player and emits
|
|
|
|
/// the <c>EventBus.PlayerHit</c> signal.
|
|
|
|
/// </summary>
|
|
|
|
private void EmitPlayerHitSignal(Events.HurtArgs args)
|
|
|
|
{
|
|
|
|
var newArgs = new Events.HitArgs
|
|
|
|
{
|
|
|
|
OldHealth = args.OldHealth,
|
|
|
|
NewHealth = args.NewHealth,
|
|
|
|
Damage = args.Damage,
|
|
|
|
Weapon = args.Weapon,
|
|
|
|
Victim = this,
|
|
|
|
};
|
|
|
|
|
|
|
|
var bus = Events.EventBus.Instance;
|
|
|
|
bus.EmitSignal(Events.EventBus.SignalName.PlayerHit, newArgs);
|
|
|
|
}
|
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Plays a footstep sound. This should be called through an
|
|
|
|
/// <c>AnimationPlayer</c> to sync sounds with animations.
|
|
|
|
/// </summary>
|
2023-07-24 00:56:01 -07:00
|
|
|
public virtual void Footstep()
|
|
|
|
{
|
2023-07-31 01:12:47 -07:00
|
|
|
if (GetNode("Effects/Footstep") is AudioStreamPlayer2D player)
|
|
|
|
{
|
|
|
|
player.Play();
|
|
|
|
}
|
2023-07-24 00:56:01 -07:00
|
|
|
}
|
2023-08-05 23:50:08 -07:00
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Returns whether the <c>Character</c> has line of sight with
|
|
|
|
/// <paramref name="character"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="character">The character to check for LOS</param>
|
|
|
|
/// <param name="excludeClip">
|
|
|
|
/// Determines whether the raycast should pass through world clips (physics
|
|
|
|
/// layer 5)
|
|
|
|
/// </param>
|
2023-08-05 23:50:08 -07:00
|
|
|
public bool HasLineOfSight(Character character, bool excludeClip = false)
|
|
|
|
{
|
|
|
|
var exclude = new Godot.Collections.Array<Godot.Rid>();
|
|
|
|
exclude.Add(GetRid());
|
|
|
|
var rayParams = new PhysicsRayQueryParameters2D
|
|
|
|
{
|
|
|
|
Exclude = exclude,
|
|
|
|
From = GlobalPosition,
|
|
|
|
To = character.GlobalPosition,
|
|
|
|
//CollisionMask = 1 + (uint)(excludeClip ? 0 : 16),
|
|
|
|
CollisionMask = 1,
|
|
|
|
};
|
|
|
|
var spaceState = GetWorld2D().DirectSpaceState;
|
|
|
|
var result = spaceState.IntersectRay(rayParams);
|
|
|
|
return result.Count == 0;
|
|
|
|
}
|
2022-11-10 20:29:53 -08:00
|
|
|
}
|