SupaLidlGame/Characters/NPC.cs

172 lines
4.4 KiB
C#
Raw Normal View History

2023-07-31 01:12:47 -07:00
#define DEBUG_NPC
2023-07-21 02:54:13 -07:00
2022-11-10 20:29:53 -08:00
using Godot;
2022-11-27 19:37:16 -08:00
using SupaLidlGame.Extensions;
2022-11-19 21:21:12 -08:00
using SupaLidlGame.Items;
using SupaLidlGame.Utils;
2022-11-10 20:29:53 -08:00
using System;
2023-06-03 18:21:46 -07:00
namespace SupaLidlGame.Characters;
public partial class NPC : Character
2022-11-10 20:29:53 -08:00
{
2023-06-03 18:21:46 -07:00
/// <summary>
/// Time in seconds it takes for the NPC to think FeelsDankCube
/// </summary>
public const float ThinkTime = 0.125f;
public float[] Weights => _weights;
protected float _preferredWeightDistance = 64.0f;
protected float _maxWeightDistance = 8.0f;
protected float _preferredWeightDistanceSq = 4096.0f;
protected float _maxWeightDistanceSq = 64.0f;
[Export]
public float PreferredWeightDistance
{
get => _preferredWeightDistance;
protected set
{
_preferredWeightDistance = value;
_preferredWeightDistanceSq = value * value;
2023-04-01 16:25:00 -07:00
}
2023-06-03 18:21:46 -07:00
}
2023-04-01 16:25:00 -07:00
2023-06-03 18:21:46 -07:00
[Export]
public float MaxWeightDistance
{
get => _maxWeightDistance;
protected set
{
_maxWeightDistance = value;
_maxWeightDistanceSq = value * value;
2023-04-01 16:25:00 -07:00
}
2023-06-03 18:21:46 -07:00
}
2022-11-27 19:37:16 -08:00
2023-07-31 01:12:47 -07:00
[Export]
public Items.Item DefaultSelectedItem { get; set; }
2023-08-05 23:50:08 -07:00
[Export]
public bool ShouldMoveWhenUsingItem { get; set; } = true;
[Export]
public State.Thinker.ThinkerStateMachine ThinkerStateMachine { get; set; }
2023-07-21 02:54:13 -07:00
public bool ShouldMove { get; set; } = true;
2023-07-23 11:05:01 -07:00
public bool CanAttack { get; set; } = true;
2023-08-05 23:50:08 -07:00
public Vector2 LastSeenPosition { get; set; }
2023-06-03 18:21:46 -07:00
protected float[] _weights = new float[16];
protected int _bestWeightIdx;
protected double _thinkTimeElapsed = 0;
protected Vector2 _blockingDir;
protected static readonly Vector2[] _weightDirs = new Vector2[16];
2022-11-10 20:29:53 -08:00
2023-06-03 18:21:46 -07:00
static NPC()
{
for (int i = 0; i < 16; i++)
2022-11-10 20:29:53 -08:00
{
2023-06-03 18:21:46 -07:00
float y = Mathf.Sin(Mathf.Pi * i * 2 / 16);
float x = Mathf.Cos(Mathf.Pi * i * 2 / 16);
_weightDirs[i] = new Vector2(x, y);
2022-11-10 20:29:53 -08:00
}
2023-06-03 18:21:46 -07:00
}
2022-11-10 20:29:53 -08:00
2023-06-03 18:21:46 -07:00
public override void _Ready()
{
base._Ready();
Array.Fill(_weights, 0);
2023-07-31 01:12:47 -07:00
if (DefaultSelectedItem is not null)
{
Inventory.SelectedItem = DefaultSelectedItem;
}
2023-08-05 23:50:08 -07:00
Inventory.UsedItem += (Items.Item item) =>
{
if (item is Items.Weapon)
{
if (AttackAnimation is not null)
{
2023-08-14 14:07:57 -07:00
AttackAnimation.TryPlay("attack");
2023-08-05 23:50:08 -07:00
}
}
};
2023-06-03 18:21:46 -07:00
}
2022-11-27 19:37:16 -08:00
2023-08-31 19:03:16 -07:00
/// <summary>
/// Finds the NPC's best character to target.
/// </summary>
2023-07-31 01:12:47 -07:00
public virtual Character FindBestTarget()
2023-06-03 18:21:46 -07:00
{
2023-08-05 23:50:08 -07:00
float bestScore = float.MaxValue;
2023-06-03 18:21:46 -07:00
Character bestChar = null;
2024-06-06 07:59:29 -07:00
foreach (var character in World.Instance.CurrentMap.GetCharacters())
2022-11-10 20:29:53 -08:00
{
2024-06-06 07:59:29 -07:00
bool isFriendly = ((IFaction)character).AlignsWith(this);
if (isFriendly || !character.IsAlive)
2022-11-10 20:29:53 -08:00
{
2024-06-06 07:59:29 -07:00
continue;
}
2023-06-13 02:55:30 -07:00
2024-06-06 07:59:29 -07:00
float score = 0;
score += GlobalPosition.DistanceSquaredTo(character.GlobalPosition);
2023-08-05 23:50:08 -07:00
2024-06-06 07:59:29 -07:00
if (score < bestScore)
{
bestScore = score;
bestChar = character;
2022-11-10 20:29:53 -08:00
}
}
2024-06-06 07:59:29 -07:00
2023-06-03 18:21:46 -07:00
return bestChar;
}
2022-11-10 20:29:53 -08:00
/// <summary>
/// Finds the best character whose faction aligns with this character's.
/// </summary>
public virtual Character FindBestNeutral()
{
float bestScore = float.MaxValue;
Character bestChar = null;
// NOTE: this relies on all Characters being under the Entities node
foreach (Node node in GetParent().GetChildren())
{
if (node is Character character)
{
bool isFriendly = ((IFaction)this).AlignsWith(character);
if (isFriendly || character.Health <= 0)
{
continue;
}
float score = 0;
2024-06-06 07:59:29 -07:00
score -= Position.DistanceSquaredTo(character.Position);
if (score < bestScore)
{
bestScore = score;
bestChar = character;
}
}
}
return bestChar;
}
2023-08-05 23:50:08 -07:00
public override void _Process(double delta)
{
ThinkerStateMachine.Process(delta);
base._Process(delta);
}
public override void _PhysicsProcess(double delta)
{
ThinkerStateMachine.PhysicsProcess(delta);
base._PhysicsProcess(delta);
}
2022-11-10 20:29:53 -08:00
}