2022-11-10 20:29:53 -08:00
|
|
|
using Godot;
|
2023-06-10 22:15:28 -07:00
|
|
|
using GodotUtilities;
|
2022-11-25 11:59:55 -08:00
|
|
|
using SupaLidlGame.Utils;
|
2023-06-10 22:15:28 -07:00
|
|
|
using SupaLidlGame.BoundingBoxes;
|
2023-07-24 00:56:01 -07:00
|
|
|
using SupaLidlGame.Extensions;
|
2022-11-10 20:29:53 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
namespace SupaLidlGame.Characters;
|
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
[Scene]
|
|
|
|
public sealed partial class Player : Character
|
2022-11-10 20:29:53 -08:00
|
|
|
{
|
2023-06-03 18:21:46 -07:00
|
|
|
private string _spriteAnim;
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-09-06 23:18:53 -07:00
|
|
|
private Vector2 _desiredTarget;
|
|
|
|
|
2023-09-17 00:23:18 -07:00
|
|
|
private Node2D _effects;
|
|
|
|
|
2023-09-17 22:35:27 -07:00
|
|
|
private Node2D _characterEffects;
|
|
|
|
|
2023-09-17 00:23:18 -07:00
|
|
|
[Node]
|
|
|
|
private TargetTracer _targetTracer;
|
|
|
|
|
2023-09-06 23:18:53 -07:00
|
|
|
public Vector2 DesiredTarget
|
|
|
|
{
|
|
|
|
get => _desiredTarget;
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (value.IsZeroApprox())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_desiredTarget = value;
|
|
|
|
}
|
|
|
|
}
|
2023-09-06 22:53:39 -07:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
[Export]
|
|
|
|
public PlayerCamera Camera { get; set; }
|
2022-11-25 11:59:55 -08:00
|
|
|
|
2023-06-10 22:15:28 -07:00
|
|
|
[Export]
|
|
|
|
public Marker2D DirectionMarker { get; private set; }
|
|
|
|
|
2023-07-21 02:54:13 -07:00
|
|
|
[Export]
|
|
|
|
public AnimationTree AnimationTree { get; private set; }
|
2023-06-10 22:15:28 -07:00
|
|
|
|
2024-03-25 21:14:06 -07:00
|
|
|
public new PlayerStats Stats { get; private set; }
|
2023-09-09 22:33:57 -07:00
|
|
|
|
2023-07-21 02:54:13 -07:00
|
|
|
public InteractionRay InteractionRay { get; private set; }
|
2022-11-19 21:21:12 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public override void _Ready()
|
|
|
|
{
|
2023-06-10 22:15:28 -07:00
|
|
|
InteractionRay = GetNode<InteractionRay>("Direction2D/InteractionRay");
|
2023-09-17 00:23:18 -07:00
|
|
|
_effects = GetNode<Node2D>("%Effects");
|
2023-09-17 22:35:27 -07:00
|
|
|
_characterEffects = GetNode<Node2D>("%CharacterEffects");
|
2023-09-07 11:53:51 -07:00
|
|
|
_targetTracer = GetNode<TargetTracer>("%TargetTracer");
|
|
|
|
|
2024-03-29 16:17:19 -07:00
|
|
|
base.Stats = GetNode<PlayerStats>("Stats");
|
|
|
|
Stats = (PlayerStats)base.Stats;
|
|
|
|
|
2023-07-21 02:54:13 -07:00
|
|
|
base._Ready();
|
2024-03-25 21:14:06 -07:00
|
|
|
|
2023-07-21 02:54:13 -07:00
|
|
|
Inventory.UsedItem += (Items.Item item) =>
|
|
|
|
{
|
|
|
|
if (item is Items.Weapons.Sword)
|
|
|
|
{
|
|
|
|
AttackAnimation.Play("sword");
|
|
|
|
}
|
|
|
|
};
|
2023-08-13 16:49:18 -07:00
|
|
|
|
|
|
|
HealthChanged += (args) =>
|
|
|
|
{
|
|
|
|
var signal = Events.EventBus.SignalName.PlayerHealthChanged;
|
|
|
|
this.GetEventBus().EmitSignal(signal, args);
|
|
|
|
};
|
2023-12-31 05:59:33 -08:00
|
|
|
|
2024-01-01 22:55:53 -08:00
|
|
|
Inventory.SelectedIndex = 0;
|
2023-06-13 02:55:30 -07:00
|
|
|
}
|
|
|
|
|
2023-08-16 21:02:37 -07:00
|
|
|
public override void _Process(double delta)
|
|
|
|
{
|
|
|
|
base._Process(delta);
|
2023-09-07 11:53:51 -07:00
|
|
|
|
2023-09-10 09:37:12 -07:00
|
|
|
float angle = DesiredTarget.Angle();
|
2023-09-10 17:29:57 -07:00
|
|
|
|
|
|
|
if (Inventory.IsUsingItem)
|
|
|
|
{
|
|
|
|
_targetTracer.Intensity = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// must turn > pi / 4 radians per second to increase intensity
|
|
|
|
float deltaTheta = Mathf.Abs(_targetTracer.Rotation - angle);
|
|
|
|
_targetTracer.Intensity = Mathf.Min(_targetTracer.Intensity +
|
|
|
|
deltaTheta, 1);
|
|
|
|
_targetTracer.Intensity = Mathf.Max(_targetTracer.Intensity -
|
|
|
|
Mathf.Pi / 4 * (float)delta, 0);
|
|
|
|
}
|
|
|
|
|
2023-09-10 09:37:12 -07:00
|
|
|
_targetTracer.Rotation = angle;
|
2023-08-16 21:02:37 -07:00
|
|
|
}
|
|
|
|
|
2023-06-13 02:55:30 -07:00
|
|
|
public override void _Input(InputEvent @event)
|
|
|
|
{
|
|
|
|
if (StateMachine != null)
|
|
|
|
{
|
|
|
|
StateMachine.Input(@event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-06 14:11:45 -08:00
|
|
|
public override void _UnhandledInput(InputEvent @event)
|
|
|
|
{
|
|
|
|
if (StateMachine != null)
|
|
|
|
{
|
|
|
|
StateMachine.UnhandledInput(@event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 19:03:16 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Respawns the player with full health and plays spawn animation
|
|
|
|
/// </summary>
|
2023-06-13 02:55:30 -07:00
|
|
|
public void Spawn()
|
|
|
|
{
|
|
|
|
Health = 100;
|
2024-03-26 12:46:37 -07:00
|
|
|
Velocity = Vector2.Zero; // player retains knockback after respawning
|
2023-08-07 02:38:51 -07:00
|
|
|
HurtAnimation.Play("spawn");
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
2022-11-25 09:11:46 -08:00
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public override void ModifyVelocity()
|
|
|
|
{
|
|
|
|
base.ModifyVelocity();
|
|
|
|
}
|
|
|
|
|
2024-03-25 21:14:06 -07:00
|
|
|
public override void Stun(double time)
|
2023-06-03 18:21:46 -07:00
|
|
|
{
|
|
|
|
base.Stun(time);
|
|
|
|
Camera.Shake(2, 0.8f);
|
2024-03-25 23:46:24 -07:00
|
|
|
Events.EventBus.Instance.EmitSignal(
|
|
|
|
Events.EventBus.SignalName.PlayerStun);
|
2023-06-03 18:21:46 -07:00
|
|
|
}
|
|
|
|
|
2023-08-07 02:38:51 -07:00
|
|
|
protected override void OnReceivedDamage(
|
2023-07-19 00:17:25 -07:00
|
|
|
float damage,
|
|
|
|
Character inflictor,
|
|
|
|
float knockback,
|
2023-09-03 17:42:32 -07:00
|
|
|
Items.Weapon weapon = null,
|
2023-07-21 02:54:13 -07:00
|
|
|
Vector2 knockbackDir = default)
|
2023-07-19 00:17:25 -07:00
|
|
|
{
|
2023-09-17 00:23:18 -07:00
|
|
|
if (StateMachine.CurrentState is State.Character.PlayerRollState)
|
|
|
|
{
|
|
|
|
// dodge dots:
|
|
|
|
// melee:
|
|
|
|
float dot = Direction.Dot(knockbackDir);
|
|
|
|
GD.Print(dot);
|
|
|
|
if (weapon is Items.Weapons.Sword)
|
|
|
|
{
|
|
|
|
// if melee weapon then check if dot is away
|
|
|
|
GD.Print("sword");
|
|
|
|
if (dot > Utils.Physics.COS_30_DEG)
|
|
|
|
{
|
|
|
|
// ignore hit
|
|
|
|
GD.Print("ignore hit");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-19 00:17:25 -07:00
|
|
|
if (damage >= 10 && IsAlive)
|
|
|
|
{
|
|
|
|
Camera.Shake(2, 0.5f);
|
|
|
|
}
|
2023-07-21 02:54:13 -07:00
|
|
|
|
|
|
|
GetNode<GpuParticles2D>("Effects/HurtParticles")
|
|
|
|
.SetDirection(knockbackDir);
|
|
|
|
|
2024-03-01 21:58:44 -08:00
|
|
|
Events.EventBus.Instance.EmitSignal(
|
|
|
|
Events.EventBus.SignalName.PlayerHurt,
|
|
|
|
new Events.HurtArgs { Attacker = inflictor, Weapon = weapon }
|
|
|
|
);
|
|
|
|
|
2023-09-03 17:42:32 -07:00
|
|
|
base.OnReceivedDamage(damage,
|
|
|
|
inflictor,
|
|
|
|
knockback,
|
|
|
|
weapon,
|
|
|
|
knockbackDir);
|
2023-07-19 00:17:25 -07:00
|
|
|
}
|
|
|
|
|
2023-06-03 18:21:46 -07:00
|
|
|
public override void Die()
|
|
|
|
{
|
2023-09-01 01:53:04 -07:00
|
|
|
HurtAnimation.Play("death");
|
2022-11-13 15:42:04 -08:00
|
|
|
}
|
2023-06-10 22:15:28 -07:00
|
|
|
|
|
|
|
protected override void DrawTarget()
|
|
|
|
{
|
|
|
|
base.DrawTarget();
|
2023-09-06 22:53:39 -07:00
|
|
|
DirectionMarker.GlobalRotation = DesiredTarget.Angle();
|
2023-09-17 22:35:27 -07:00
|
|
|
if (Target.X < 0)
|
|
|
|
{
|
|
|
|
_characterEffects.Scale = new Vector2(-1, 1);
|
|
|
|
}
|
|
|
|
else if (Target.X > 0)
|
|
|
|
{
|
|
|
|
_characterEffects.Scale = new Vector2(1, 1);
|
|
|
|
}
|
2023-06-10 22:15:28 -07:00
|
|
|
}
|
2023-07-24 00:56:01 -07:00
|
|
|
|
|
|
|
public override void Footstep()
|
|
|
|
{
|
|
|
|
GetNode<AudioStreamPlayer2D>("Effects/Footstep")
|
|
|
|
.OnWorld()
|
|
|
|
.WithPitchDeviation(0.125f)
|
|
|
|
.Play();
|
|
|
|
}
|
2023-09-06 23:07:51 -07:00
|
|
|
|
2023-09-10 12:30:26 -07:00
|
|
|
public override void UseCurrentItemAlt()
|
|
|
|
{
|
|
|
|
// must have at least 1 level to use
|
|
|
|
if (Stats.Level.Value >= 1)
|
|
|
|
{
|
|
|
|
if (Inventory.SelectedItem is Items.Weapon weapon)
|
|
|
|
{
|
|
|
|
if (!weapon.IsUsingAlt)
|
|
|
|
{
|
|
|
|
Stats.Level.Value--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
base.UseCurrentItemAlt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-06 23:07:51 -07:00
|
|
|
public Vector2 GetDesiredInputFromInput()
|
|
|
|
{
|
|
|
|
Vector2 mousePos = GetGlobalMousePosition();
|
|
|
|
Vector2 dirToMouse = GlobalPosition.DirectionTo(mousePos);
|
|
|
|
Vector2 joystick = Godot.Input.GetVector("look_left", "look_right",
|
|
|
|
"look_up", "look_down");
|
|
|
|
|
|
|
|
var inputMethod = Utils.World.Instance.GlobalState
|
|
|
|
.Settings.InputMethod;
|
|
|
|
switch (inputMethod)
|
|
|
|
{
|
|
|
|
case State.Global.InputMethod.Joystick:
|
|
|
|
if (joystick.IsZeroApprox())
|
|
|
|
{
|
|
|
|
return Direction;
|
|
|
|
}
|
|
|
|
return joystick;
|
|
|
|
default:
|
|
|
|
return dirToMouse;
|
|
|
|
}
|
|
|
|
}
|
2022-11-10 20:29:53 -08:00
|
|
|
}
|