using System.Numerics; using System.Collections.ObjectModel; using Raylib_cs; namespace OnekoOnline; abstract class Oneko : Drawable { public readonly Bitmap SpriteSheet; public Rectangle Sprite {get; protected set;} = Idle1; protected Color ColorTint = Color.White; protected byte FrameId { get => (byte)Array.IndexOf(FrameArray, Sprite); set => Sprite = FrameArray[value]; } public string Name = "Oneko"; protected static List allNekos = []; public static ReadOnlyCollection AllNekos => allNekos.AsReadOnly(); protected readonly static Image FallbackImg = Raylib.LoadImageFromMemory(".png", EmbeddedResources.GetResource("nekos.oneko.png")); public Oneko() : base() { Size = new(32,32); Position = new(320/2, 240/2); string SpriteSheetPath = OnekoOnline.Config.GetValue("SpriteSheetPath", "nekos/oneko.png"); if (File.Exists(SpriteSheetPath) && new FileInfo(SpriteSheetPath).Length < 128*256*3) { #if DEBUG //Bitmap Serialization test using Bitmap SerializeTest = Bitmap.FromPNGMemory(File.ReadAllBytes(SpriteSheetPath), 256, 128); SpriteSheet = Bitmap.Deserialize(SerializeTest.Serialize()); #else SpriteSheet = Bitmap.FromPNGMemory(File.ReadAllBytes(SpriteSheetPath), 256, 128); #endif } else { Console.WriteLine("Path to spritesheet was invalid or the file was too big, using the default."); SpriteSheet = new Bitmap(Raylib.ImageCopy(FallbackImg), 256, 128); } allNekos.Add(this); } public Oneko(Bitmap spriteSheet) : base() { Size = new(32,32); Position = new(0, 0); SpriteSheet = spriteSheet; allNekos.Add(this); } public override void Draw() { //Nametag Vector2 NametagPosition = new(Position.X-(Name.Length*3)+4, Position.Y-28); Raylib.DrawTextEx(OnekoOnline.DefaultFont, Name, NametagPosition+Directions.Down, 11, 0, Color.Black); //Shadow Raylib.DrawTextEx(OnekoOnline.DefaultFont, Name, NametagPosition, 11, 0, Color.White); //The neko Raylib.DrawTexturePro(SpriteSheet.Texture, Sprite, new Rectangle(Position.X, Position.Y, Size.X, Size.Y), Size/2, Rotation, ColorTint); } protected override void Unload() { allNekos.Remove(this); SpriteSheet.Dispose(); } protected struct OnekoAnimation(Rectangle frame1, Rectangle frame2, byte animSpeed) { public byte AnimSpeed = animSpeed; Rectangle Frame1 = frame1; Rectangle Frame2 = frame2; public readonly Rectangle GetFrame(int frame) { return (frame % 2 == 0) ? Frame1 : Frame2; } } static protected OnekoAnimation GetDirectionalRun(Vector2 direction) { direction = Vector2.Normalize(direction); Vector2 nearestDir = Directions.Up; float nearestDistance = 10f; foreach (Vector2 dir in RunDirections.Keys) { float distanceCheck = Vector2.Distance(direction, dir); if (distanceCheck < nearestDistance) { nearestDir = dir; nearestDistance = distanceCheck; } } return RunDirections[nearestDir]; } static protected readonly Rectangle Idle1 = new(32*3, 32*3, 32, 32); static protected readonly Rectangle Alert1 = new(32*7, 32*3, 32, 32); static protected readonly Rectangle Yawn1 = new(32*3, 32*2, 32, 32); static protected readonly Rectangle Clean1 = new(32*7, 0, 32, 32); static protected readonly Rectangle Scratch1 = new(32*5, 0, 32, 32); static protected readonly Rectangle Scratch2 = new(32*6, 0, 32, 32); static protected readonly Rectangle Sleep1 = new(32*2, 0, 32, 32); static protected readonly Rectangle Sleep2 = new(32*2, 32, 32, 32); static protected readonly Rectangle RunUp1 = new(32, 32*3, 32, 32); static protected readonly Rectangle RunUp2 = new(32, 32*2, 32, 32); static protected readonly Rectangle RunUpLeft1 = new(32, 32, 32, 32); static protected readonly Rectangle RunUpLeft2 = new(32, 0, 32, 32); static protected readonly Rectangle RunLeft1 = new(32*4, 32*3, 32, 32); static protected readonly Rectangle RunLeft2 = new(32*4, 32*2, 32, 32); static protected readonly Rectangle RunDownLeft1 = new(32*6, 32, 32, 32); static protected readonly Rectangle RunDownLeft2 = new(32*5, 32*3, 32, 32); static protected readonly Rectangle RunDown1 = new(32*7, 32*2, 32, 32); static protected readonly Rectangle RunDown2 = new(32*6, 32*3, 32, 32); static protected readonly Rectangle RunDownRight1 = new(32*5, 32*2, 32, 32); static protected readonly Rectangle RunDownRight2 = new(32*5, 32, 32, 32); static protected readonly Rectangle RunRight1 = new(32*3, 32, 32, 32); static protected readonly Rectangle RunRight2 = new(32*3, 0, 32, 32); static protected readonly Rectangle RunUpRight1 = new(0, 32*3, 32, 32); static protected readonly Rectangle RunUpRight2 = new(0, 32*2, 32, 32); static protected readonly Rectangle ScratchUp1 = new(0, 0, 32, 32); static protected readonly Rectangle ScratchUp2 = new(0, 32, 32, 32); static protected readonly Rectangle ScratchLeft1 = new(32*4, 0, 32, 32); static protected readonly Rectangle ScratchLeft2 = new(32*4, 32, 32, 32); static protected readonly Rectangle ScratchDown1 = new(32*7, 32, 32, 32); static protected readonly Rectangle ScratchDown2 = new(32*6, 32*2, 32, 32); static protected readonly Rectangle ScratchRight1 = new(32*2, 32*2, 32, 32); static protected readonly Rectangle ScratchRight2 = new(32*2, 32*3, 32, 32); static protected readonly OnekoAnimation Idle = new(Idle1, Idle1, 1); static protected readonly OnekoAnimation Alert = new(Alert1, Alert1, 1); static protected readonly OnekoAnimation Yawn = new(Yawn1, Yawn1, 1); static protected readonly OnekoAnimation Clean = new(Idle1, Clean1, 1); static protected readonly OnekoAnimation ScratchSelf = new(Scratch1, Scratch2, 1); static protected readonly OnekoAnimation Sleep = new(Sleep1, Sleep2, 10); static protected readonly OnekoAnimation RunUp = new(RunUp1, RunUp2, 1); static protected readonly OnekoAnimation RunUpLeft = new(RunUpLeft1, RunUpLeft2, 1); static protected readonly OnekoAnimation RunLeft = new(RunLeft1, RunLeft2, 1); static protected readonly OnekoAnimation RunDownLeft = new(RunDownLeft1, RunDownLeft2, 1); static protected readonly OnekoAnimation RunDown = new(RunDown1, RunDown2, 1); static protected readonly OnekoAnimation RunDownRight = new(RunDownRight1, RunDownRight2, 1); static protected readonly OnekoAnimation RunRight = new(RunRight1, RunRight2, 1); static protected readonly OnekoAnimation RunUpRight = new(RunUpRight1, RunUpRight2, 1); static protected readonly OnekoAnimation ScratchUp = new(ScratchUp1, ScratchUp2, 1); static protected readonly OnekoAnimation ScratchLeft = new(ScratchLeft1, ScratchLeft2, 1); static protected readonly OnekoAnimation ScratchDown = new(ScratchDown1, ScratchDown2, 1); static protected readonly OnekoAnimation ScratchRight = new(ScratchRight1, ScratchRight2, 1); static readonly Dictionary RunDirections = new() { {Directions.Up, RunUp}, {Directions.Down, RunDown}, {Directions.Left, RunLeft}, {Directions.Right, RunRight}, {Directions.UpLeft, RunUpLeft}, {Directions.UpRight, RunUpRight}, {Directions.DownRight, RunDownRight}, {Directions.DownLeft, RunDownLeft}, }; static readonly Rectangle[] FrameArray = [ Idle1, Alert1, Yawn1, Clean1, Scratch1, Scratch2, Sleep1, Sleep2, RunUp1,RunUpLeft1, RunLeft1, RunDownLeft1, RunDown1, RunDownRight1, RunRight1, RunUpRight1, RunUp2,RunUpLeft2, RunLeft2, RunDownLeft2, RunDown2, RunDownRight2, RunRight2, RunUpRight2, ScratchUp1, ScratchLeft1, ScratchDown1, ScratchRight1, ScratchUp2, ScratchLeft2, ScratchDown2, ScratchRight2 ]; static readonly OnekoAnimation[] AnimationArray = [ Idle, Alert, Yawn, Clean, ScratchSelf, Sleep, RunUp,RunUpLeft, RunLeft, RunDownLeft, RunDown, RunDownRight, RunRight, RunUpRight, ScratchUp, ScratchLeft, ScratchDown, ScratchRight ]; }