SupaLidlGame/State/Thinker/DashDefensive.cs

127 lines
4.3 KiB
C#

using Godot;
using SupaLidlGame.State.Character;
using SupaLidlGame.Extensions;
namespace SupaLidlGame.State.Thinker;
public partial class DashDefensive : AttackState
{
protected bool _dashedAway = false;
protected State.Character.CharacterDashState _dashState;
protected float _originalDashModifier;
public override void _Ready()
{
_dashState = NPC.StateMachine.FindChildOfType<CharacterDashState>();
_originalDashModifier = _dashState.VelocityModifier;
base._Ready();
}
public override ThinkerState Think()
{
Characters.Character bestTarget = NPC.FindBestTarget();
if (bestTarget is not null)
{
Vector2 pos = bestTarget.GlobalPosition;
NPC.Target = pos - NPC.GlobalPosition;
Vector2 dir = NPC.GlobalPosition.DirectionTo(pos);
float dist = NPC.GlobalPosition.DistanceTo(pos);
UpdateWeights(pos);
if (dist > MaxDistanceToTarget)
{
if (PursueState is not null)
{
return PursueState;
}
if (PassiveState is not null)
{
return PassiveState;
}
}
if (PursueOnNoLOS && !NPC.HasLineOfSight(bestTarget))
{
return PursueState;
}
if (NPC.CanAttack && NPC.StunTime <= 0)
{
bool isTargetStunned = bestTarget.StunTime > 0;
bool shouldDashAway = false;
bool shouldDashTowards = false;
var currentItem = NPC.Inventory.SelectedItem;
if (currentItem is not Items.Weapons.Sword sword)
{
return null;
}
var swordState = sword.StateMachine.CurrentState;
float dot = NPC.Direction.Normalized()
.Dot(bestTarget.Direction.Normalized());
// doc will still dash if you are farther than normal but
// moving towards him
float distThreshold = UseItemDistance - (dot * 20);
// dash towards if lance in anticipate state
// or just directly dash towards you if you are too far
shouldDashTowards = (isTargetStunned || _dashedAway) &&
(swordState is State.Weapon.SwordAnticipateState ||
dist > MaxDistanceToTarget);
shouldDashAway = dist < distThreshold && !isTargetStunned &&
swordState is State.Weapon.SwordIdleState;
//if (!isTargetStunned && dist < 2500 && !_dashedAway)
if (shouldDashAway && !shouldDashTowards)
{
// dash away if too close
_dashState.VelocityModifier = _originalDashModifier;
DashTo(-dir);
NPC.UseCurrentItem();
_dashedAway = true;
}
else if (shouldDashTowards && !shouldDashAway)
{
// our required velocity is dependent on final distance to target
float maxVelocity = dist / 0.1f;
var dashSpeed = Mathf.Max(maxVelocity,
_originalDashModifier * NPC.Speed);
float ratio = dashSpeed / NPC.Speed;
_dashState.VelocityModifier = ratio;
// dash to player's predicted position
var newPos = Utils.Physics.PredictNewPosition(
NPC.GlobalPosition,
dashSpeed,
pos,
bestTarget.Velocity,
out float _);
DashTo(NPC.GlobalPosition.DirectionTo(newPos));
_dashedAway = false;
}
else if (isTargetStunned)
{
NPC.UseCurrentItem();
}
}
return null;
}
return PursueState ?? PassiveState;
}
private void DashTo(Vector2 direction)
{
var stateMachine = NPC.StateMachine;
stateMachine.ChangeState<CharacterDashState>(out var state);
state.DashDirection = direction;
}
}