SupaLidlGame/Items/Weapons/Sword.cs

287 lines
6.8 KiB
C#
Raw Permalink Normal View History

2022-11-18 13:53:51 -08:00
using Godot;
2023-06-13 02:55:30 -07:00
using GodotUtilities;
2022-11-18 13:53:51 -08:00
using SupaLidlGame.BoundingBoxes;
2022-11-13 19:52:09 -08:00
using SupaLidlGame.Characters;
2022-11-25 09:11:46 -08:00
using SupaLidlGame.Extensions;
2023-05-26 17:42:50 -07:00
using SupaLidlGame.State.Weapon;
2022-11-13 19:52:09 -08:00
2023-06-03 18:21:46 -07:00
namespace SupaLidlGame.Items.Weapons;
2023-08-31 19:03:16 -07:00
/// <summary>
/// A basic melee weapon.
/// </summary>
2023-06-03 18:21:46 -07:00
public partial class Sword : Weapon, IParryable
2022-11-13 19:52:09 -08:00
{
2023-06-03 18:21:46 -07:00
public bool IsAttacking { get; protected set; }
2023-03-19 14:13:39 -07:00
2023-08-08 00:54:00 -07:00
public override bool IsUsing => IsUsingPrimary || IsUsingAlt;
public override bool IsUsingPrimary => StateMachine.CurrentState is
SwordAttackState;
public override bool IsUsingAlt => StateMachine.CurrentState is
SwordBlockState;
2023-05-23 00:23:53 -07:00
2023-06-03 18:21:46 -07:00
[Export]
public Hitbox Hitbox { get; set; }
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
[Export]
public AnimationPlayer AnimationPlayer { get; set; }
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
/// <summary>
/// The time frame in seconds for which the weapon will deal damage.
/// </summary>
/// <remarks>
/// The value of <c>AttackTime</c> should be less than the
/// value of <c>UseTime</c>
/// </remarks>
[Export]
public double AttackTime { get; set; } = 0;
2023-03-19 14:13:39 -07:00
2023-08-08 00:54:00 -07:00
[Export]
public double AttackAltTime { get; set; } = 0;
2023-06-03 18:21:46 -07:00
[Export]
public double AttackAnimationDuration { get; set; }
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
[Export]
2023-07-23 23:39:20 -07:00
public GpuParticles2D ParryParticles { get; set; }
2023-05-15 00:20:17 -07:00
2023-06-03 18:21:46 -07:00
[Export]
public double NPCAnticipateTime { get; set; }
2023-05-15 00:20:17 -07:00
2023-06-03 18:21:46 -07:00
[Export]
public WeaponStateMachine StateMachine { get; set; }
2023-05-15 00:20:17 -07:00
2023-06-03 18:21:46 -07:00
[Export]
public Node2D Anchor { get; set; }
2023-05-26 22:28:08 -07:00
public bool HasParried { get; protected set; }
2023-06-03 18:21:46 -07:00
public override bool IsParryable { get; protected set; }
2023-05-15 00:20:17 -07:00
2023-06-03 18:21:46 -07:00
public ulong ParryTimeOrigin { get; protected set; }
2023-05-15 00:20:17 -07:00
[Export]
public float BlockForce { get; set; } = 1;
2023-06-03 18:21:46 -07:00
private Tween _currentTween;
2023-05-15 00:20:17 -07:00
2023-06-03 18:21:46 -07:00
private AnimationNodeStateMachinePlayback _playback;
2023-05-15 00:20:17 -07:00
2023-06-03 18:21:46 -07:00
public override void Equip(Character character)
{
base.Equip(character);
Hitbox.Faction = character.Faction; // character is null before base
}
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
public override void Unequip(Character character)
{
base.Unequip(character);
}
2023-08-08 00:54:00 -07:00
public void EnableParry()
2023-06-03 18:21:46 -07:00
{
2023-08-08 00:54:00 -07:00
EnableParry(Time.GetTicksMsec());
2023-06-03 18:21:46 -07:00
}
2023-03-19 14:13:39 -07:00
2023-08-31 19:03:16 -07:00
/// <summary>
/// Makes this melee weapon be able to parry and be parried.
/// </summary>
2023-08-08 00:54:00 -07:00
public void EnableParry(ulong parryTimeOrigin)
2023-06-03 18:21:46 -07:00
{
HasParried = false;
2023-06-03 18:21:46 -07:00
IsParried = false;
IsParryable = true;
2023-08-08 00:54:00 -07:00
ParryTimeOrigin = parryTimeOrigin;
2023-06-03 18:21:46 -07:00
}
2023-03-19 14:13:39 -07:00
2023-08-31 19:03:16 -07:00
/// <summary>
/// Makes this melee weapon be able to parry and be parried.
/// </summary>
2023-06-03 18:21:46 -07:00
public void DisableParry()
{
HasParried = false;
IsParried = false;
2023-06-03 18:21:46 -07:00
IsParryable = false;
}
2023-05-23 00:23:53 -07:00
2023-08-08 00:54:00 -07:00
public override void Use()
{
StateMachine.Use();
base.Use();
}
2023-06-03 18:21:46 -07:00
public override void Deuse()
{
2023-07-23 23:39:20 -07:00
StateMachine.Deuse();
2023-06-03 18:21:46 -07:00
base.Deuse();
}
2023-05-23 00:23:53 -07:00
2023-08-08 00:54:00 -07:00
public override void UseAlt()
{
StateMachine.UseAlt();
base.UseAlt();
}
public override void DeuseAlt()
{
StateMachine.DeuseAlt();
base.DeuseAlt();
}
2023-08-31 19:03:16 -07:00
/// <summary>
/// Enables the weapon's hitbox. Prefer to call this from a state machine
/// rather than managing state through the weapon script.
/// </summary>
2023-06-03 18:21:46 -07:00
public void Attack()
{
//RemainingAttackTime = AttackTime;
IsAttacking = true;
Hitbox.IsDisabled = false;
}
2023-03-19 14:13:39 -07:00
2023-08-31 19:03:16 -07:00
/// <summary>
/// Disables the weapon's hitbox and processes all hurtboxes it hit.
/// </summary>
2023-06-03 18:21:46 -07:00
public void Deattack()
{
IsAttacking = false;
Hitbox.IsDisabled = true;
ProcessHits();
DisableParry();
2023-06-03 18:21:46 -07:00
Hitbox.ResetIgnoreList();
AnimationPlayer.SpeedScale = 1;
}
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
public override void _Ready()
{
Hitbox.Damage = Damage;
2023-07-23 11:03:55 -07:00
Hitbox.Hit += OnHitboxHit;
2023-08-10 23:08:41 -07:00
StateMachine.StateChanged += OnStateChanged;
}
public void OnStateChanged(Node state)
{
if (StateMachine.UsedItemStates is null)
{
return;
}
foreach (var nodePath in StateMachine.UsedItemStates)
{
if (StateMachine.GetNode(nodePath) == state)
{
Character.Inventory.EmitSignal(
Inventory.SignalName.UsedItem, this);
//EmitSignal(SignalName.UsedItem, this);
}
}
2023-06-03 18:21:46 -07:00
}
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
public override void _Process(double delta)
{
StateMachine.Process(delta);
base._Process(delta);
}
2023-03-19 14:13:39 -07:00
2023-08-31 19:03:16 -07:00
/// <summary>
/// Processes all hits and applies damages to hurtboxes.
/// </summary>
2023-06-03 18:21:46 -07:00
public void ProcessHits()
{
if (IsParried || HasParried)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
return;
2023-03-19 14:13:39 -07:00
}
2023-06-03 18:21:46 -07:00
foreach (BoundingBox box in Hitbox.Hits)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
if (box is Hurtbox hurtbox)
2023-03-19 14:13:39 -07:00
{
2023-09-03 17:42:32 -07:00
hurtbox.InflictDamage(
Damage,
Character,
Knockback,
this);
2023-03-19 14:13:39 -07:00
}
}
if (Hitbox.Hits.Count > 0)
{
Character.ApplyImpulse(-Character.Target.Normalized() * Knockback);
}
2023-06-03 18:21:46 -07:00
}
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
public void AttemptParry(Weapon otherWeapon)
{
if (otherWeapon.IsParryable &&
2023-07-23 23:39:20 -07:00
otherWeapon is IParryable otherParryable)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
if (ParryTimeOrigin < otherParryable.ParryTimeOrigin)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
// our character was parried
2023-07-23 23:39:20 -07:00
ParryParticles.CloneOnWorld<GpuParticles2D>().EmitOneShot();
Stun(otherParryable.BlockForce);
2023-08-08 00:54:00 -07:00
if (otherParryable is Sword sword)
{
if (sword.StateMachine.CurrentState is SwordBlockState b)
{
b.HasBlocked = true;
}
}
2023-03-19 14:13:39 -07:00
}
else
{
HasParried = true;
}
2023-03-19 14:13:39 -07:00
}
2023-06-03 18:21:46 -07:00
}
2023-08-31 19:03:16 -07:00
/// <summary>
/// Stuns the wepaon holder. This is unique to swords and melee weapons
/// if they can parry.
/// </summary>
public void Stun(float blockForce)
2023-06-03 18:21:46 -07:00
{
IsParried = true;
Character.Stats.AddStaggerDamage(Damage * blockForce);
// optionally play parry sound
GetNode<AudioStreamPlayer2D>("ParrySound")?
2023-07-23 23:39:20 -07:00
.OnWorld()
.WithPitchDeviation(0.125f)
.PlayOneShot();
2023-06-03 18:21:46 -07:00
}
2023-03-19 14:13:39 -07:00
2023-07-23 11:03:55 -07:00
public override void OnHitboxHit(BoundingBox box)
2023-06-03 18:21:46 -07:00
{
if (IsParried)
2023-05-23 00:23:53 -07:00
{
2023-06-03 18:21:46 -07:00
return;
2023-05-23 00:23:53 -07:00
}
2023-06-03 18:21:46 -07:00
if (box is Hitbox hb)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
Weapon w = hb.GetAncestor<Weapon>();
if (w is not null)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
AttemptParry(w);
2023-03-19 14:13:39 -07:00
}
2023-06-03 18:21:46 -07:00
}
2023-03-19 14:13:39 -07:00
2023-06-03 18:21:46 -07:00
if (box is Hurtbox hurt)
{
if (hurt.GetParent() is Character c)
2023-03-19 14:13:39 -07:00
{
2023-06-03 18:21:46 -07:00
var item = c.Inventory.SelectedItem;
if (item is Weapon w)
2023-03-19 14:13:39 -07:00
{
AttemptParry(w);
}
}
}
2023-06-03 18:21:46 -07:00
}
2022-11-13 19:52:09 -08:00
}