core/npc/NpcDogBrain.cs
using System.IO;

public class NpcDogBrain : Component {
	[Property, ReadOnly] public float PlayerDistance {get; set;}
	private TimeUntil SitTime {get; set;}
	private TimeUntil Following {get; set;}
	private bool Running {get; set;}
	protected override void OnFixedUpdate() {
		PlayerDistance = WorldPosition.Distance(BasePlayer.Local.IsoMovement.EntityRoot);
		var a = Components.Get<NpcAnimator>();
		var m = Components.Get<NpcMovement>();
		a.Activity = "stand";
		var sitdist = 100;
		if (!Following)
			sitdist = 60;
		if (PlayerDistance < sitdist && (BasePlayer.Local.IsoMovement.Path.Count == 0 || WorldPosition.Distance(BasePlayer.Local.IsoMovement.Goal) < 150f)) {
			Following = 0;
			if (SitTime)
				a.Activity = "sit";
			Running = false;
			m.Path.Clear();
			return;
		}
		SitTime = 2.5f;
		if (Following && PlayerDistance < 80 && (BasePlayer.Local.IsoMovement.Path.Count == 0 || !BasePlayer.Local.IsoMovement.Run)) {
			m.Path.Clear();
			Running = false;
			return;
		}
		a.Activity = "walk";
		Following = 10;
		if (PlayerDistance > 230)
			Running = true;
		else if (PlayerDistance < 150)
			Running = false;
		if (Running)
			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();
	}
}