core/npc/NpcWolfBrain.cs
public class NpcWolfBrain : Component {
	[Property, ReadOnly] public float PlayerDistance {get; set;}
	public TimeUntil ExitCombat {get; set;}
	private TimeUntil RandomMove {get; set;} = 5f;
	private TimeUntil NextAttack {get; set;}
	protected override void OnFixedUpdate() {
		if (!Components.Get<IsoEntity>().IsValid())
			return;
		PlayerDistance = WorldPosition.Distance(BasePlayer.Local.IsoMovement.EntityRoot);
		var a = Components.GetOrCreate<NpcAnimator>();
		var m = Components.GetOrCreate<NpcMovement>();
		if (Components.Get<IsoEntity>().Health <= 0)
			a.Activity = "die";
		if (a.ActivitySet.NonInteruptActivities.Contains(a.Activity))
			return;
		if (ExitCombat && PlayerDistance < 300)
			ExitCombat = 10;
		if (ExitCombat) {
			if (RandomMove) {
				m.Goal = Grid.Snap(WorldPosition + Vector3.Random * 100);
				m.Go();
				RandomMove = Random.Shared.Float(5,15);
			}
			return;
		}
		a.AttackAction = () => {
			if (m.EntityRoot.Distance(BasePlayer.Local.IsoMovement.EntityRoot) <= 100) {
				BasePlayer.Local.IsoEntity.Health -= Random.Shared.Int(1,3);
				var a = BasePlayer.Local.IsoEntity.Components.Get<NpcAnimator>();
				if (a.IsValid() && !a.ActivitySet.NonInteruptActivities.Contains(a.Activity))
					a.Activity = "flinch";
				NextAttack = Random.Shared.Float(0.2f,1f);
			}
		};
		a.Activity = "idle";
		if (NextAttack)
			a.Activity = "attack";
		if (PlayerDistance > 100)
			a.Activity = "run";
		m.DontUpdateActivity = true;
		if (m.Path.Count < 1) {
			var start = m.EntityRoot;
			if (m.Path.Count > 0)
				start = m.Path.Last();
			var best = -1f;
			var point = m.EntityRoot;
			for (int i = 0; i < 6; i++) {
				var canidate = Grid.Snap(start + Rotation.FromYaw(i * 60f - 30f).Forward * 30f);
				if (Grid.IsBlocked(canidate))
					continue;
				var dot = Vector3.Direction(start, canidate).Dot(Vector3.Direction(start, BasePlayer.Local.IsoMovement.EntityRoot));
				if (dot < best)
					continue;
				point = canidate;
				best = dot;
			}
			m.Path.Add(point);
		}
		base.OnFixedUpdate();
		base.OnFixedUpdate();
	}
}