using Microsoft.Xna.Framework; using OpenVIII.Encoding.Tags; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace OpenVIII.IGMData { public abstract class Base : Menu_Base { #region Fields public BitArray BLANKS; /// /// location of where pointer finger will point. /// public Point[] CURSOR; public Menu_Base[,] ITEM; public int PointerZIndex = byte.MaxValue; /// /// Size of the entire area /// public Rectangle[] SIZE; protected bool DepthFirst = false; protected bool skipdata = false; protected bool skipsnd = false; private byte _count = 0; private int _cursor_select; #endregion Fields #region Constructors public Base() => CONTAINER = new IGMDataItem.Empty(); #endregion Constructors #region Properties public static Vector2 TextScale => Menu.TextScale; public byte Cols { get; protected set; } = 1; /// /// Total number of items /// public byte Count { get => _count; protected set => _count = checked((byte)(value + ExtraCount)); } public int CURSOR_SELECT { get => GetCursor_select(); set => SetCursor_select(value); } /// /// How many Peices per Item. Example 1 box could have 9 things to draw in it. /// public byte Depth { get; protected set; } = 0; public Dictionary Descriptions { get; protected set; } public byte ExtraCount { get; protected set; } = 0; /// /// Container's Height /// public override int Height => CONTAINER != null ? Pos.Height : 0; public override Rectangle Pos { get => CONTAINER?.Pos ?? Rectangle.Empty; set => CONTAINER.Pos = value; } public byte Rows { get; protected set; } = 1; public bool SkipSIZE { get; set; } = false; public Table_Options Table_Options { get; set; } = Table_Options.Default; /// /// Container's Width /// public override int Width => CONTAINER != null ? Pos.Width : 0; /// /// Container's X Position /// public override int X => CONTAINER != null ? Pos.X : 0; /// /// Container's Y Position /// public override int Y => CONTAINER != null ? Pos.Y : 0; #endregion Properties #region Indexers public Menu_Base this[int pos, int i] { get => ITEM[pos, i]; set => ITEM[pos, i] = value; } #endregion Indexers #region Methods public static T Create(int count = 0, int depth = 0, Menu_Base container = null, int? cols = null, int? rows = null, Damageable damageable = null, sbyte? partypos = null, bool battle = false) where T : Base, new() { var r = Create(damageable, partypos); r.Battle = battle; r.Init(count, depth, container, cols, rows); return r; } /// /// Convert to rectangle based on container. /// /// Input data public static implicit operator Rectangle(Base v) => v.CONTAINER ?? Rectangle.Empty; //public object PrevSetting { get; protected set; } = null; //public object Setting { get; protected set; } = null; public virtual int CURSOR_NEXT() { if ((Cursor_Status & Cursor_Status.Enabled) != 0) { var value = GetCursor_select(); var loop = 0; while (true) { if (++value >= CURSOR.Length) { value = 0; if (loop++ > 1) break; } if ((CURSOR[value] != Point.Zero && !BLANKS[value])) break; } SetCursor_select(value); } return GetCursor_select(); } public virtual int CURSOR_PREV() { if ((Cursor_Status & Cursor_Status.Enabled) != 0) { var value = GetCursor_select(); var loop = 0; while (true) { if (--value < 0) { value = CURSOR.Length - 1; if (loop++ > 1) break; } if ((CURSOR[value] != Point.Zero && !BLANKS[value])) break; } SetCursor_select(value); } return GetCursor_select(); } /// /// Draw all items /// public override void Draw() { if (Enabled) { if (CONTAINER != null) CONTAINER.Draw(); var pointer = false; Target.Group targetgroup = null; if (!skipdata && ITEM != null) if (DepthFirst) for (var d = 0; d < Depth; d++) for (var i = 0; i < Count; i++) { if (i == PointerZIndex && !pointer) pointer = DrawPointer(); if (ITEM[i, d] != null && (ITEM[i, d].GetType()).Equals(typeof(Target.Group))) targetgroup = (Target.Group)(ITEM[i, d]); else DrawITEM(i, d); } else for (var i = 0; i < Count; i++) for (var d = 0; d < Depth; d++) { if (i == PointerZIndex && !pointer) pointer = DrawPointer(); if (ITEM[i, d]!=null && (ITEM[i, d].GetType()).Equals(typeof(Target.Group))) targetgroup = (Target.Group)(ITEM[i, d]); else DrawITEM(i, d); } if (!pointer) { pointer = DrawPointer(); } targetgroup?.Draw(); } } public void DrawPointer(Point cursor, Vector2? offset = null, bool blink = false) => Menu.DrawPointer(cursor, offset, blink); public override void HideChildren() { if (Enabled) { //base.Hide(); //maybe overkill to run hide on items. if group is hidden it won't draw. if (!skipdata) { foreach (var i in ITEM) { if (i != null) { i.HideChildren(); i.Hide(); } } } } } public void InitSize(bool force = false) { var cellcount = Rows * Cols; //SetSize(cellcount); if (((SIZE != null && SIZE.Length > 0) || force)) { if (cellcount > 1) { InitRowsSize(force); } else { SIZE[0] = new Rectangle(X, Y, Width, Height); CURSOR[0] = Point.Zero; BLANKS[0] = false; InitShift(0, 0, 0); InitCursor(0, 0, 0); } } } /// /// Check inputs /// /// True = input detected public override bool Inputs() { var ret = false; var mouse = false; if ((Cursor_Status & Cursor_Status.Enabled) != 0) { Cursor_Status &= ~Cursor_Status.Blinking; if ((Cursor_Status & Cursor_Status.Static) == 0) for (var i = 0; i < SIZE.Length; i++) { if (SIZE[i].Contains(MouseLocation) && !SIZE[i].IsEmpty && CURSOR[i] != Point.Zero && !BLANKS[i]) { CURSOR_SELECT = i; ret = true; mouse = true; } } if (!ret && (Cursor_Status & Cursor_Status.Horizontal) != 0 && (Cursor_Status & Cursor_Status.Static) == 0) { if (Input2.DelayedButton(FF8TextTagKey.Left)) { CURSOR_PREV(); ret = true; } else if (Input2.DelayedButton(FF8TextTagKey.Right)) { CURSOR_NEXT(); ret = true; } } if ((!ret && (Cursor_Status & Cursor_Status.Horizontal) == 0 || (Cursor_Status & Cursor_Status.Vertical) != 0) && (Cursor_Status & Cursor_Status.Static) == 0) { if (Input2.DelayedButton(FF8TextTagKey.Up)) { CURSOR_PREV(); ret = true; } else if (Input2.DelayedButton(FF8TextTagKey.Down)) { CURSOR_NEXT(); ret = true; } } if (mouse || !ret) { if (Input2.DelayedButton(FF8TextTagKey.Confirm)) { return Inputs_OKAY(); } else if (Input2.DelayedButton(FF8TextTagKey.Cancel)) { return Inputs_CANCEL(); } else if (Input2.DelayedButton(FF8TextTagKey.RotateRight)) { Inputs_RotateRight(); return true; } else if (Input2.DelayedButton(FF8TextTagKey.Cards)) { Inputs_Cards(); return true; } else if (Input2.DelayedButton(FF8TextTagKey.Menu)) { Inputs_Menu(); return true; } else if ((Cursor_Status & Cursor_Status.Horizontal) == 0 && (Cursor_Status & Cursor_Status.Static) == 0) { if (Input2.DelayedButton(FF8TextTagKey.Left)) { Inputs_Left(); return true; } else if (Input2.DelayedButton(FF8TextTagKey.Right)) { Inputs_Right(); return true; } } } if (ret && !mouse) { if (!skipsnd) AV.Sound.Play(0); } } skipsnd = false; return ret; } public virtual bool Inputs_CANCEL() { if (!skipsnd) AV.Sound.Play(8); return false; } public virtual void Inputs_Cards() { if (!skipsnd) AV.Sound.Play(0); } public virtual void Inputs_Left() { if (!skipsnd) AV.Sound.Play(0); } public virtual void Inputs_Menu() { if (!skipsnd) AV.Sound.Play(31); } public virtual bool Inputs_RotateRight() { if (!skipsnd) AV.Sound.Play(0); return false; } public virtual bool Inputs_OKAY() { if (!skipsnd) AV.Sound.Play(0); return false; } public virtual void Inputs_Right() { if (!skipsnd) AV.Sound.Play(0); } public override void Refresh() { var count = Memory.State?.PartyData.Count ?? 0; if (Memory.State?.PartyData != null && Damageable == null && PartyPos >= 0 && PartyPos < count) { Damageable = Memory.State[Memory.State.PartyData[PartyPos]]; } base.Refresh(); } public override void Reset() { foreach (var i in ITEM) { i?.Reset(); } base.Reset(); } /// /// Things that change on every update. /// /// True = signifigant change public override bool Update() { var ret = false; if (!skipdata && ITEM != null) foreach (var i in ITEM) { if (i != null) ret = i.Update() || ret; } return ret; } protected void AutoAdjustContainerWidth(Rectangle DataSize) { if (DataSize.Right > Pos.Right) { CONTAINER.Width += DataSize.Right - Pos.Right + Math.Abs(DataSize.Left - Pos.Left); } } protected bool CheckBounds(ref Rectangle DataSize, Rectangle input) { if (input.Right > Pos.Right && input.Right > DataSize.Right) { DataSize = input; return true; } return false; } protected bool CheckBounds(ref Rectangle DataSize, int pos) => CheckBounds(ref DataSize, ((IGMDataItem.Text)ITEM[pos, 0]).DataSize); protected virtual void DrawITEM(int i, int d) => ITEM[i, d]?.Draw(); protected virtual bool DrawPointer() { if ((Cursor_Status & (Cursor_Status.Enabled | Cursor_Status.Draw)) != 0 && (Cursor_Status & Cursor_Status.Hidden) == 0) { if ((Cursor_Status & Cursor_Status.All) != 0) { for (var i = 0; i < CURSOR.Length; i++) if (!BLANKS[i]) DrawPointer(CURSOR[i], blink: true); } else DrawPointer(CURSOR[CURSOR_SELECT], blink: ((Cursor_Status & Cursor_Status.Blinking) != 0)); return true; } return false; } protected int GetCursor_select() => _cursor_select; /// /// Most objects set all these values. also Init Refresh and Update /// /// /// /// /// /// protected void Init(int count, int depth, Menu_Base container = null, int? cols = null, int? rows = null) { if (count >= 0) Count = checked((byte)count); if (depth >= 0) Depth = checked((byte)depth); if (container != null) CONTAINER = container; if (cols.HasValue && cols.Value > 0) Cols = checked((byte)cols.Value); if (rows.HasValue && rows.Value > 0) Rows = checked((byte)rows.Value); Init(); Refresh(); Update(); } /// /// Things that are fixed values at startup. /// protected override void Init() { if (Count <= 0 || Depth <= 0) { if (CONTAINER.Pos == Rectangle.Empty) { Debug.WriteLine($"{this}:: Count {Count} or depth {Depth}, is invalid must be >= 1, or a CONTAINER {CONTAINER} and CONTAINER.Pos { Pos.ToString() } must be set instead, Skipping Init()"); return; } } else { //if (SIZE == null) // SIZE = new Rectangle[Count]; if (ITEM == null) ITEM = new Menu_Base[Count, Depth]; //if (CURSOR == null) // CURSOR = new Point[Count]; //if (BLANKS == null) // BLANKS = new bool[Count]; if (Descriptions == null) Descriptions = new Dictionary(Count); SetSize(Math.Max(Rows * Cols, Count)); } if (!SkipSIZE) InitSize(); SkipSIZE = false; } protected virtual void InitCursor(int i, int col, int row, bool zero = false) { if (zero) CURSOR[i] = Point.Zero; CURSOR[i].Y += (int)(SIZE[i].Y + 6 * TextScale.Y); CURSOR[i].X += SIZE[i].X; } protected virtual void InitShift(int i, int col, int row) { } protected bool InputITEM(Menu_Base menuitem, ref bool ret) { if (menuitem != null && menuitem.Enabled) { Cursor_Status |= (Cursor_Status.Enabled | Cursor_Status.Blinking); ret = menuitem.Inputs(); return true; } return false; } protected override void RefreshChild() { base.RefreshChild(); if (!skipdata) { if (CONTAINER != null) { if (ForceNullDamageable) CONTAINER.ForceNullDamageable = ForceNullDamageable; CONTAINER.Refresh(Damageable); } if (ITEM != null) for (var i = 0; i < Count; i++) for (var d = 0; d < Depth; d++) { if (ForceNullDamageable && ITEM[i, d] != null) ITEM[i, d].ForceNullDamageable = ForceNullDamageable; ITEM[i, d]?.Refresh(Damageable); } } } protected virtual void SetCursor_select(int value) { if (value >= 0 && CURSOR != null && value < CURSOR.Length && CURSOR[value] != Point.Zero) _cursor_select = value; } //protected Base(int Count = 0, int depth = 0, Menu_Base container = null, int? cols = null, int? rows = null, Damageable damageable = null, sbyte? PartyPos = null) //{ // Init(damageable, PartyPos); // Init(Count, depth, container, cols, rows); //} private static T Create(Damageable damageable = null, sbyte? partypos = null) where T : Base, new() { var r = new T(); r.SetDamageable(damageable, partypos); return r; } private void InitRowsSize(bool force) { for (var i = 0; i < SIZE.Length; i++) { var col = (Table_Options & Table_Options.FillRows) != 0 ? i % Cols : i / Rows; var row = (Table_Options & Table_Options.FillRows) != 0 ? i / Cols : i % Rows; if (col < Cols && row < Rows) { if (SIZE[i].IsEmpty || force) //allows for override a size value before the loop. { SIZE[i] = new Rectangle { X = X + (Width * col) / Cols, Y = Y + (Height * row) / Rows, Width = Width / Cols, Height = Height / Rows, }; } CURSOR[i] = Point.Zero; InitShift(i, col, row); InitCursor(i, col, row); } } } private void SetSize(int cellcount) { cellcount = cellcount > 1 ? cellcount : 1; if (CURSOR == null || CURSOR.Length == 0 || SIZE == null || SIZE.Length == 0 || BLANKS == null || BLANKS.Length == 0) { CURSOR = new Point[cellcount]; SIZE = new Rectangle[cellcount]; BLANKS = new BitArray(cellcount,false); } } #endregion Methods } }