SupaLidlGame/State/Thinker/DashDefensive.cs

165 lines
5.4 KiB
C#
Raw Permalink Normal View History

2023-08-06 01:07:30 -07:00
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;
private Callable _dodgeCallable;
[Export]
public Area2D ProjectileDetection { get; set; }
2023-08-06 01:07:30 -07:00
public override void _Ready()
{
_dashState = NPC.StateMachine.FindChildOfType<CharacterDashState>();
_originalDashModifier = _dashState.VelocityModifier;
_dodgeCallable = new Callable(this, MethodName.DodgeProjectile);
2023-08-06 01:07:30 -07:00
base._Ready();
}
public override IState<ThinkerState> Enter(IState<ThinkerState> prev)
{
ProjectileDetection?.Connect(Area2D.SignalName.AreaEntered,
_dodgeCallable);
return base.Enter(prev);
}
public override void Exit(IState<ThinkerState> prev)
{
ProjectileDetection?.Disconnect(Area2D.SignalName.AreaEntered,
_dodgeCallable);
base.Exit(prev);
}
private void DodgeProjectile(Area2D area)
{
if (area is BoundingBoxes.Hitbox hitbox)
{
if (hitbox.GetOwner() is Entities.Projectile projectile)
{
GD.Print("changing direction");
var direction = projectile.Direction;
var dirToChar = projectile.GlobalPosition
.DirectionTo(NPC.GlobalPosition);
var lateralDirection = Mathf.Sign(direction.Cross(dirToChar));
DashTo(direction.Rotated(lateralDirection * Mathf.Pi / 2));
}
}
}
2023-08-06 01:07:30 -07:00
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);
2023-08-16 21:02:37 -07:00
float dist = NPC.GlobalPosition.DistanceTo(pos);
2023-08-06 01:07:30 -07:00
UpdateWeights(pos);
2023-08-16 21:02:37 -07:00
if (dist > MaxDistanceToTarget)
{
if (PursueState is not null)
{
return PursueState;
}
if (PassiveState is not null)
{
return PassiveState;
}
}
if (PursueOnNoLOS && !NPC.HasLineOfSight(bestTarget))
{
return PursueState;
}
2023-08-06 01:07:30 -07:00
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
2024-01-06 14:13:48 -08:00
float distThreshold = UseItemDistance - (dot * 20);
2023-08-06 01:07:30 -07:00
// dash towards if lance in anticipate state
2023-08-16 21:02:37 -07:00
// or just directly dash towards you if you are too far
2023-08-06 01:07:30 -07:00
shouldDashTowards = (isTargetStunned || _dashedAway) &&
2024-01-06 14:13:48 -08:00
(swordState is State.Weapon.SwordAnticipateState ||
dist > MaxDistanceToTarget);
2023-08-06 01:07:30 -07:00
2023-08-16 21:02:37 -07:00
shouldDashAway = dist < distThreshold && !isTargetStunned &&
2024-01-06 14:13:48 -08:00
swordState is State.Weapon.SwordIdleState;
2023-08-06 01:07:30 -07:00
//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)
{
2024-01-06 14:13:48 -08:00
// 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;
2023-08-06 01:07:30 -07:00
// 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;
}
2023-08-16 21:02:37 -07:00
else if (isTargetStunned)
{
NPC.UseCurrentItem();
}
2023-08-06 01:07:30 -07:00
}
2024-01-06 14:13:48 -08:00
return null;
2023-08-06 01:07:30 -07:00
}
2023-08-16 21:02:37 -07:00
return PursueState ?? PassiveState;
2023-08-06 01:07:30 -07:00
}
private void DashTo(Vector2 direction)
{
var stateMachine = NPC.StateMachine;
stateMachine.ChangeState<CharacterDashState>(out var state);
state.DashDirection = direction;
}
}