NamesHPATB.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. namespace OpenVIII.IGMData
  7. {
  8. public class NamesHPATB : IGMData.Base
  9. {
  10. #region Fields
  11. private const float ATBalpha = .8f;
  12. private const int ATBWidth = 150;
  13. private static Texture2D dot;
  14. private static object locker = new object();
  15. private Damageable.BattleMode BattleMode = Damageable.BattleMode.EndTurn;
  16. private bool EventAdded = false;
  17. #endregion Fields
  18. #region Destructors
  19. ~NamesHPATB()
  20. {
  21. if (EventAdded)
  22. Damageable.BattleModeChangeEventHandler -= ModeChangeEvent;
  23. }
  24. #endregion Destructors
  25. #region Enums
  26. private enum DepthID : byte
  27. {
  28. /// <summary>
  29. /// Name
  30. /// </summary>
  31. Name,
  32. /// <summary>
  33. /// HP
  34. /// </summary>
  35. HP,
  36. /// <summary>
  37. /// Box with GF HP
  38. /// </summary>
  39. GFHPBox,
  40. /// <summary>
  41. /// Box with GF name
  42. /// </summary>
  43. GFNameBox,
  44. /// <summary>
  45. /// ATB charging orange red or dark blue (haste/slowed)
  46. /// </summary>
  47. ATBCharging,
  48. /// <summary>
  49. /// ATB charged blink yellow
  50. /// </summary>
  51. ATBCharged,
  52. /// <summary>
  53. /// blue white gradient that decreases as the gf is charging.
  54. /// </summary>
  55. GFCharging,
  56. /// <summary>
  57. /// border around ATB bar
  58. /// </summary>
  59. ATBBorder,
  60. /// <summary>
  61. /// Max?
  62. /// </summary>
  63. Max
  64. }
  65. #endregion Enums
  66. #region Methods
  67. public static NamesHPATB Create(Rectangle pos, Damageable damageable) => Create<NamesHPATB>(1, (int)DepthID.Max, new IGMDataItem.Empty { Pos = pos }, 1, 3, damageable);
  68. public static Texture2D ThreadUnsafeOperations()
  69. {
  70. lock (locker)
  71. {
  72. if (dot == null)
  73. {
  74. //if (Memory.IsMainThread)
  75. //{
  76. Texture2D localdot = new Texture2D(Memory.graphics.GraphicsDevice, 4, 4);
  77. Color[] tmp = new Color[localdot.Height * localdot.Width];
  78. for (int i = 0; i < tmp.Length; i++)
  79. tmp[i] = Color.White;
  80. localdot.SetData(tmp);
  81. dot = localdot;
  82. IGMDataItem.Gradient.ATB.ThreadUnsafeOperations(ATBWidth);
  83. //}
  84. //else throw new Exception("Must be in main thread!");
  85. }
  86. return dot;
  87. }
  88. }
  89. public override void ModeChangeEvent(object sender, Enum e)
  90. {
  91. if (!e.Equals(BattleMode))
  92. {
  93. base.ModeChangeEvent(sender, e);
  94. BattleMode = (Damageable.BattleMode)e;
  95. if (!e.Equals(Damageable.BattleMode.EndTurn)) //because endturn triggers BattleMenu refresh.
  96. Refresh();
  97. }
  98. }
  99. public override void Refresh(Damageable damageable)
  100. {
  101. if (EventAdded && damageable != Damageable)
  102. {
  103. EventAdded = false;
  104. if (Damageable != null)
  105. Damageable.BattleModeChangeEventHandler -= ModeChangeEvent;
  106. }
  107. base.Refresh(damageable);
  108. }
  109. public override void Refresh()
  110. {
  111. if (Damageable != null)
  112. {
  113. if (Memory.State?.Characters != null && Damageable.GetCharacterData(out Saves.CharacterData c))
  114. {
  115. List<KeyValuePair<int, Characters>> party = GetParty();
  116. if (GetCharPos(party) == 0xFF) return;
  117. }
  118. else
  119. {
  120. }
  121. sbyte pos = PartyPos;
  122. Rectangle rectangle = SIZE[0];
  123. Vector2 vector = SIZE[1].Location.ToVector2() - SIZE[0].Location.ToVector2();
  124. rectangle.Offset(vector * pos);
  125. Rectangle atbbarpos = new Rectangle(rectangle.X + 230, rectangle.Y + 12, ATBWidth, 15);
  126. ((IGMDataItem.Gradient.ATB)ITEM[0, (int)DepthID.ATBCharging]).Pos = atbbarpos;
  127. ((IGMDataItem.Texture)ITEM[0, (byte)DepthID.ATBCharged]).Pos = atbbarpos;
  128. ((IGMDataItem.Icon)ITEM[0, (byte)DepthID.ATBBorder]).Pos = atbbarpos;
  129. ((IGMDataItem.Gradient.GF)ITEM[0, (byte)DepthID.GFCharging]).Pos = atbbarpos;
  130. ((IGMDataItem.Text)ITEM[0, (byte)DepthID.Name]).Data = Damageable.Name;
  131. ((IGMDataItem.Text)ITEM[0, (byte)DepthID.Name]).Pos = new Rectangle(rectangle.X - 60, rectangle.Y, 0, 0);
  132. ((IGMDataItem.Integer)ITEM[0, (byte)DepthID.HP]).Pos = new Rectangle(rectangle.X + 128, rectangle.Y, 0, 0);
  133. ((IGMDataItem.Text)ITEM[0, (byte)DepthID.Name]).Draw(true);
  134. ((IGMDataItem.Integer)ITEM[0, (byte)DepthID.HP]).Draw(true);
  135. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Pos = Rectangle.Union(
  136. ((IGMDataItem.Text)ITEM[0, (byte)DepthID.Name]).DataSize,
  137. ((IGMDataItem.Integer)ITEM[0, (byte)DepthID.HP]).DataSize);
  138. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Y -= 4;
  139. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFNameBox]).Y = ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Y;
  140. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFNameBox]).Height = ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Height = rectangle.Height;
  141. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFNameBox]).X =
  142. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).X -
  143. (((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Width * 3) / 8;
  144. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFNameBox]).Width = (((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Width * 7) / 8;
  145. if (Damageable.SummonedGF != null)
  146. {
  147. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFNameBox]).Data = Damageable.SummonedGF.Name;
  148. ((IGMDataItem.Box)ITEM[0, (byte)DepthID.GFHPBox]).Data = $"{Damageable.SummonedGF.CurrentHP()}";
  149. }
  150. if (EventAdded == false)
  151. {
  152. EventAdded = true;
  153. Damageable.BattleModeChangeEventHandler += ModeChangeEvent;
  154. }
  155. bool blink = false;
  156. bool charging = false;
  157. BattleMode = (Damageable.BattleMode)Damageable.GetBattleMode();
  158. ITEM[0, (byte)DepthID.HP].Show();
  159. ITEM[0, (byte)DepthID.Name].Show();
  160. ITEM[0, (byte)DepthID.GFNameBox].Hide();
  161. ITEM[0, (byte)DepthID.GFHPBox].Hide();
  162. ITEM[0, (int)DepthID.ATBCharged].Hide();
  163. ITEM[0, (int)DepthID.GFCharging].Hide();
  164. ITEM[0, (int)DepthID.ATBCharging].Hide();
  165. if (BattleMode.Equals(Damageable.BattleMode.YourTurn))
  166. {
  167. ((IGMDataItem.Texture)ITEM[0, (int)DepthID.ATBCharged]).Color = Color.LightYellow * ATBalpha;
  168. blink = true;
  169. }
  170. else if (BattleMode.Equals(Damageable.BattleMode.ATB_Charged))
  171. {
  172. ((IGMDataItem.Texture)ITEM[0, (int)DepthID.ATBCharged]).Color = Color.Yellow * ATBalpha;
  173. }
  174. else if (BattleMode.Equals(Damageable.BattleMode.ATB_Charging))
  175. {
  176. charging = true;
  177. ((IGMDataItem.Gradient.ATB)ITEM[0, (int)DepthID.ATBCharging]).Refresh(Damageable);
  178. ITEM[0, (int)DepthID.ATBCharging].Show();
  179. }
  180. else if (BattleMode.Equals(Damageable.BattleMode.GF_Charging))
  181. {
  182. charging = true;
  183. ITEM[0, (byte)DepthID.HP].Hide();
  184. ITEM[0, (byte)DepthID.Name].Hide();
  185. ITEM[0, (byte)DepthID.GFNameBox].Show();
  186. ITEM[0, (byte)DepthID.GFHPBox].Show();
  187. ITEM[0, (int)DepthID.GFCharging].Show();
  188. ITEM[0, (int)DepthID.GFCharging].Refresh(Damageable.SummonedGF);
  189. }
  190. if (!charging)
  191. {
  192. ITEM[0, (int)DepthID.ATBCharged].Show();
  193. }
  194. ((IGMDataItem.Texture)ITEM[0, (int)DepthID.ATBCharged]).Blink = blink;
  195. ((IGMDataItem.Text)ITEM[0, (byte)DepthID.Name]).Blink = blink;
  196. ((IGMDataItem.Integer)ITEM[0, (byte)DepthID.HP]).Blink = blink;
  197. base.Refresh();
  198. }
  199. }
  200. public override bool Update()
  201. {
  202. if (ITEM[0, 2].GetType() == typeof(IGMDataItem.Gradient.ATB))
  203. {
  204. IGMDataItem.Gradient.ATB hg = (IGMDataItem.Gradient.ATB)ITEM[0, 2];
  205. }
  206. if (Damageable != null)
  207. {
  208. int HP = Damageable.CurrentHP();
  209. int CriticalHP = Damageable.CriticalHP();
  210. Font.ColorID colorid = Font.ColorID.White;
  211. if (HP < CriticalHP)
  212. {
  213. colorid = Font.ColorID.Yellow;
  214. }
  215. if (HP <= 0)
  216. {
  217. colorid = Font.ColorID.Red;
  218. }
  219. ((IGMDataItem.Text)ITEM[0, (byte)DepthID.Name]).FontColor = colorid;
  220. ((IGMDataItem.Integer)ITEM[0, (byte)DepthID.HP]).Data = HP;
  221. ((IGMDataItem.Integer)ITEM[0, (byte)DepthID.HP]).FontColor = colorid;
  222. }
  223. return base.Update();
  224. }
  225. protected override void Init()
  226. {
  227. base.Init();
  228. ThreadUnsafeOperations();
  229. // TODO: make a font render that can draw right to left from a point. For Right aligning the names.
  230. Rectangle atbbarpos = new Rectangle(SIZE[0].X + 230, SIZE[0].Y + 12, ATBWidth, 15);
  231. ITEM[0, (byte)DepthID.Name] = new IGMDataItem.Text { };
  232. ITEM[0, (byte)DepthID.HP] = new IGMDataItem.Integer { Spaces = 4, NumType = Icons.NumType.Num_8x16_1 };
  233. ITEM[0, (byte)DepthID.GFHPBox] = new IGMDataItem.Box { Options = Box_Options.Right | Box_Options.Middle };
  234. ITEM[0, (byte)DepthID.GFHPBox].Hide();
  235. ITEM[0, (byte)DepthID.GFNameBox] = new IGMDataItem.Box { Options = Box_Options.Center | Box_Options.Middle };
  236. ITEM[0, (byte)DepthID.GFNameBox].Hide();
  237. ITEM[0, (byte)DepthID.ATBBorder] = new IGMDataItem.Icon { Data = Icons.ID.Size_08x64_Bar, Palette = 0 };
  238. ITEM[0, (byte)DepthID.ATBCharged] = new IGMDataItem.Texture { Data = dot, Color = Color.LightYellow * ATBalpha, Faded_Color = new Color(125, 125, 0, 255) * ATBalpha };
  239. ITEM[0, (byte)DepthID.ATBCharged].Hide();
  240. ITEM[0, (int)DepthID.ATBCharging] = IGMDataItem.Gradient.ATB.Create(atbbarpos);
  241. ITEM[0, (int)DepthID.GFCharging] = IGMDataItem.Gradient.GF.Create(atbbarpos);
  242. ((IGMDataItem.Gradient.ATB)ITEM[0, (byte)DepthID.ATBCharging]).Color = Color.Orange * ATBalpha;
  243. ((IGMDataItem.Gradient.ATB)ITEM[0, (byte)DepthID.ATBCharging]).Faded_Color = Color.Orange * ATBalpha;
  244. ((IGMDataItem.Gradient.ATB)ITEM[0, (byte)DepthID.ATBCharging]).Refresh(Damageable);
  245. }
  246. private static List<KeyValuePair<int, Characters>> GetParty()
  247. {
  248. if (Memory.State != null && Memory.State.Characters != null)
  249. 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();
  250. return null;
  251. }
  252. private byte GetCharPos() => GetCharPos(GetParty());
  253. private byte GetCharPos(List<KeyValuePair<int, Characters>> party)
  254. {
  255. int i = -1;
  256. if (party != null && (i = party.FindIndex(x => Damageable.GetCharacterData(out Saves.CharacterData c) && x.Value == c.ID)) > -1)
  257. return checked((byte)i);
  258. return 0xFF;
  259. }
  260. #endregion Methods
  261. }
  262. }