using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using OpenVIII.IGMDataItem;
using OpenVIII.IGMDataItem.Gradient;
using System;
using System.Collections.Generic;
using System.Linq;
using Texture = OpenVIII.IGMDataItem.Texture;
namespace OpenVIII.IGMData
{
public class NamesHPATB : Base
{
#region Fields
private const float ATBAlpha = .8f;
private const int ATBWidth = 150;
private static Texture2D _dot;
private Damageable.BattleMode _battleMode = Damageable.BattleMode.EndTurn;
private bool _eventAdded;
#endregion Fields
#region Destructors
~NamesHPATB()
{
if (_eventAdded)
Damageable.BattleModeChangeEventHandler -= ModeChangeEvent;
}
#endregion Destructors
#region Enums
private enum DepthID : byte
{
///
/// Name
///
Name,
///
/// HP
///
HP,
///
/// Box with GF HP
///
GFHPBox,
///
/// Box with GF name
///
GFNameBox,
///
/// ATB charging orange red or dark blue (haste/slowed)
///
ATBCharging,
///
/// ATB charged blink yellow
///
ATBCharged,
///
/// blue white gradient that decreases as the gf is charging.
///
GFCharging,
///
/// border around ATB bar
///
ATBBorder,
///
/// Max?
///
Max
}
#endregion Enums
#region Methods
public static NamesHPATB Create(Rectangle pos, Damageable damageable) => Create(1, (int)DepthID.Max, new Empty { Pos = pos }, 1, 1, damageable);
public override void ModeChangeEvent(object sender, Enum e)
{
if (!e.Equals(_battleMode))
{
base.ModeChangeEvent(sender, e);
_battleMode = (Damageable.BattleMode)e;
if (!e.Equals(Damageable.BattleMode.EndTurn)) //because endturn triggers BattleMenu refresh.
Refresh();
}
}
public override void Refresh(Damageable damageable)
{
if (_eventAdded && damageable != Damageable)
{
_eventAdded = false;
if (Damageable != null)
Damageable.BattleModeChangeEventHandler -= ModeChangeEvent;
}
base.Refresh(damageable);
}
public override void Refresh()
{
if (Damageable == null) return;
if (Memory.State?.Characters != null && Damageable.GetCharacterData(out _))
{
var party = GetParty();
if (GetCharPos(party) == 0xFF) return;
}
var pos = PartyPos;
var rectangle = SIZE[0];
rectangle.Offset(0f, SIZE[0].Height * pos);
var atbBarPos = new Rectangle(rectangle.X + 230, rectangle.Y + 12, ATBWidth, 15);
((ATB)ITEM[0, (int)DepthID.ATBCharging]).Pos = atbBarPos;
((Texture)ITEM[0, (byte)DepthID.ATBCharged]).Pos = atbBarPos;
((Icon)ITEM[0, (byte)DepthID.ATBBorder]).Pos = atbBarPos;
((GF)ITEM[0, (byte)DepthID.GFCharging]).Pos = atbBarPos;
((Text)ITEM[0, (byte)DepthID.Name]).Data = Damageable.Name;
((Text)ITEM[0, (byte)DepthID.Name]).Pos = new Rectangle(rectangle.X - 60, rectangle.Y, 0, 0);
((Integer)ITEM[0, (byte)DepthID.HP]).Pos = new Rectangle(rectangle.X + 128, rectangle.Y, 0, 0);
((Text)ITEM[0, (byte)DepthID.Name]).Draw(true);
((Integer)ITEM[0, (byte)DepthID.HP]).Draw(true);
((Box)ITEM[0, (byte)DepthID.GFHPBox]).Pos = Rectangle.Union(
((Text)ITEM[0, (byte)DepthID.Name]).DataSize,
((Integer)ITEM[0, (byte)DepthID.HP]).DataSize);
((Box)ITEM[0, (byte)DepthID.GFHPBox]).Y -= 4;
((Box)ITEM[0, (byte)DepthID.GFNameBox]).Y = ((Box)ITEM[0, (byte)DepthID.GFHPBox]).Y;
((Box)ITEM[0, (byte)DepthID.GFNameBox]).Height = ((Box)ITEM[0, (byte)DepthID.GFHPBox]).Height = rectangle.Height;
((Box)ITEM[0, (byte)DepthID.GFNameBox]).X =
((Box)ITEM[0, (byte)DepthID.GFHPBox]).X -
(((Box)ITEM[0, (byte)DepthID.GFHPBox]).Width * 3) / 8;
((Box)ITEM[0, (byte)DepthID.GFNameBox]).Width = (((Box)ITEM[0, (byte)DepthID.GFHPBox]).Width * 7) / 8;
if (Damageable.SummonedGF != null)
{
((Box)ITEM[0, (byte)DepthID.GFNameBox]).Data = Damageable.SummonedGF.Name;
((Box)ITEM[0, (byte)DepthID.GFHPBox]).Data = $"{Damageable.SummonedGF.CurrentHP()}";
}
if (_eventAdded == false)
{
_eventAdded = true;
Damageable.BattleModeChangeEventHandler += ModeChangeEvent;
}
var blink = false;
var charging = false;
_battleMode = (Damageable.BattleMode)Damageable.GetBattleMode();
ITEM[0, (byte)DepthID.HP].Show();
ITEM[0, (byte)DepthID.Name].Show();
ITEM[0, (byte)DepthID.GFNameBox].Hide();
ITEM[0, (byte)DepthID.GFHPBox].Hide();
ITEM[0, (int)DepthID.ATBCharged].Hide();
ITEM[0, (int)DepthID.GFCharging].Hide();
ITEM[0, (int)DepthID.ATBCharging].Hide();
switch (_battleMode)
{
case Damageable.BattleMode.YourTurn:
((Texture)ITEM[0, (int)DepthID.ATBCharged]).Color = Color.LightYellow * ATBAlpha;
blink = true;
break;
case Damageable.BattleMode.ATB_Charged:
((Texture)ITEM[0, (int)DepthID.ATBCharged]).Color = Color.Yellow * ATBAlpha;
break;
case Damageable.BattleMode.ATB_Charging:
charging = true;
((ATB)ITEM[0, (int)DepthID.ATBCharging]).Refresh(Damageable);
ITEM[0, (int)DepthID.ATBCharging].Show();
break;
case Damageable.BattleMode.GF_Charging:
charging = true;
ITEM[0, (byte)DepthID.HP].Hide();
ITEM[0, (byte)DepthID.Name].Hide();
ITEM[0, (byte)DepthID.GFNameBox].Show();
ITEM[0, (byte)DepthID.GFHPBox].Show();
ITEM[0, (int)DepthID.GFCharging].Show();
ITEM[0, (int)DepthID.GFCharging].Refresh(Damageable.SummonedGF);
break;
case Damageable.BattleMode.EndTurn:
break;
default:
throw new ArgumentOutOfRangeException();
}
if (!charging)
{
ITEM[0, (int)DepthID.ATBCharged].Show();
}
((Texture)ITEM[0, (int)DepthID.ATBCharged]).Blink = blink;
((Text)ITEM[0, (byte)DepthID.Name]).Blink = blink;
((Integer)ITEM[0, (byte)DepthID.HP]).Blink = blink;
base.Refresh();
}
public void ThreadUnsafeOperations()
{
if (_dot == null)
{
if (Memory.IsMainThread)
{
var texture2D = new Texture2D(Memory.Graphics.GraphicsDevice, 4, 4);
var tmp = new Color[texture2D.Height * texture2D.Width];
for (var i = 0; i < tmp.Length; i++)
tmp[i] = Color.White;
texture2D.SetData(tmp);
_dot = texture2D;
ATB.ThreadUnsafeOperations(ATBWidth);
}
else throw new Exception("Must be in main thread!");
}
if (_dot != null)
((Texture)(ITEM[0, (byte)DepthID.ATBCharged])).
Data = _dot;
}
public override bool Update()
{
if (ITEM[0, 2] is ATB)
{
// unsure if need
}
if (Damageable == null) return base.Update();
int hp = Damageable.CurrentHP();
int criticalHP = Damageable.CriticalHP();
var colorID = Font.ColorID.White;
if (hp < criticalHP)
{
colorID = Font.ColorID.Yellow;
}
if (hp <= 0)
{
colorID = Font.ColorID.Red;
}
((Text)ITEM[0, (byte)DepthID.Name]).FontColor = colorID;
((Integer)ITEM[0, (byte)DepthID.HP]).Data = hp;
((Integer)ITEM[0, (byte)DepthID.HP]).FontColor = colorID;
return base.Update();
}
protected override void Init()
{
base.Init();
Memory.MainThreadOnlyActions.Enqueue(ThreadUnsafeOperations);
// TODO: make a font render that can draw right to left from a point. For Right aligning the names.
var atbBarPos = new Rectangle(SIZE[0].X + 230, SIZE[0].Y + 12, ATBWidth, 15);
ITEM[0, (byte)DepthID.Name] = new Text();
ITEM[0, (byte)DepthID.HP] = new Integer { Spaces = 4, NumType = Icons.NumType.Num8X16A };
ITEM[0, (byte)DepthID.GFHPBox] = new Box { Options = Box_Options.Right | Box_Options.Middle };
ITEM[0, (byte)DepthID.GFHPBox].Hide();
ITEM[0, (byte)DepthID.GFNameBox] = new Box { Options = Box_Options.Center | Box_Options.Middle };
ITEM[0, (byte)DepthID.GFNameBox].Hide();
ITEM[0, (byte)DepthID.ATBBorder] = new Icon { Data = Icons.ID.Size_08x64_Bar, Palette = 0 };
ITEM[0, (byte)DepthID.ATBCharged] = new Texture { Color = Color.LightYellow * ATBAlpha, Faded_Color = new Color(125, 125, 0, 255) * ATBAlpha };
ITEM[0, (byte)DepthID.ATBCharged].Hide();
ITEM[0, (int)DepthID.ATBCharging] = ATB.Create(atbBarPos);
ITEM[0, (int)DepthID.GFCharging] = GF.Create(atbBarPos);
((ATB)ITEM[0, (byte)DepthID.ATBCharging]).Color = Color.Orange * ATBAlpha;
((ATB)ITEM[0, (byte)DepthID.ATBCharging]).Faded_Color = Color.Orange * ATBAlpha;
((ATB)ITEM[0, (byte)DepthID.ATBCharging]).Refresh(Damageable);
}
private static List> GetParty()
{
if (Memory.State != null && Memory.State.Characters)
return Memory.State.Party.Select((element, index) => new { element, index }).ToDictionary(m => m.index, m => m.element).Where(m => !m.Value.Equals(Characters.Blank)).ToList();
return null;
}
private byte GetCharPos(List> party)
{
int i;
if (party != null && (i = party.FindIndex(x => Damageable.GetCharacterData(out var c) && x.Value == c.ID)) > -1)
return checked((byte)i);
return 0xFF;
}
#endregion Methods
}
}