using System.Numerics; using LiteNetLib.Utils; using OnekoOnline.Net; using Raylib_cs; namespace OnekoOnline; class OnekoLocal : Oneko { public static Oneko? Instance; static int Id => OnekoOnline.Client?.Id ?? -1; OnekoAIState? CurrentAIState; Vector2 TargetPosition = Vector2.Zero; float InactivityTimer = 0f; OnekoAnimation Animation; float updateTimer = 0f; const float updateRate = 1f/5f; int Frame = 0; int FrameCounter = 0; public OnekoLocal() : base() { Instance ??= this; Client.UserConnected += OnekoNet.SpawnNetNeko; Name = Client.UserName; } public override void Update(float delta) { updateTimer += delta; if (updateTimer < updateRate) return; OnekoUpdate(updateTimer); updateTimer = 0f; } public void OnekoUpdate(float delta) { InactivityTimer += delta; Mouse? NearestMouse = Mouse.AllMice.Where(m => m.Visible).MinBy(m => Vector2.Distance(m.Position, Position)); if (NearestMouse != null) TargetPosition = NearestMouse.Position; else TargetPosition = new Vector2(Math.Clamp((Id+1)*40, 20, 300), 240/2); Vector2 TargetDirection = (TargetPosition-Position).LimitLength(10f); if (TargetDirection.Length() > 1) { Animation = GetDirectionalRun(TargetDirection); InactivityTimer = 0f; } else Animation = Idle; Position += TargetDirection; if (InactivityTimer > 3f) Animation = ScratchSelf; if (InactivityTimer > 5f) Animation = Yawn; if (InactivityTimer > 6f) Animation = Sleep; FrameCounter = (FrameCounter+1)%(Animation.AnimSpeed+1); Frame = (int)MathF.Round(FrameCounter/(float)Animation.AnimSpeed); Sprite = Animation.GetFrame(Frame); if (OnekoOnline.Client!.Connected) { NetDataWriter writer = new(); writer.Put(new PacketInfo(PacketType.OnekoState, Id)); writer.Put(Position); writer.Put(FrameId); OnekoOnline.Client?.ConnectedServer.Send(writer, LiteNetLib.DeliveryMethod.Unreliable); } } protected abstract class OnekoAIState(OnekoLocal neko) { protected OnekoLocal Neko = neko; public abstract int GetPriority(); public abstract void Update(float delta); protected bool IsCurrentState => Neko.CurrentAIState == this; } }