Magic.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. using Microsoft.Xna.Framework;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. namespace OpenVIII.IGMData.Pool
  6. {
  7. public partial class Magic : IGMData.Pool.Base<Saves.CharacterData, byte>
  8. {
  9. #region Fields
  10. private const Font.ColorID @default = Font.ColorID.White;
  11. private const Font.ColorID junctioned = Font.ColorID.Grey;
  12. private const Font.ColorID nostat = Font.ColorID.Dark_Grey;
  13. private bool eventAdded = false;
  14. private bool skipRefresh = false;
  15. #endregion Fields
  16. #region Destructors
  17. ~Magic()
  18. {
  19. if (eventAdded)
  20. {
  21. if (!Battle)
  22. {
  23. Menu.IGM_Junction.ModeChangeHandler -= ModeChangeEvent;
  24. StatEventListener -= StatChangeEvent;
  25. }
  26. else if (Damageable != null)
  27. Damageable.BattleModeChangeEventHandler -= ModeChangeEvent;
  28. }
  29. }
  30. #endregion Destructors
  31. #region Events
  32. public static event EventHandler<IGM_Junction.Mode> SlotConfirmListener;
  33. public static event EventHandler<Damageable> SlotRefreshListener;
  34. public static event EventHandler<IGM_Junction.Mode> SlotUndoListener;
  35. public static event EventHandler<Kernel_bin.Stat> StatEventListener;
  36. #endregion Events
  37. #region Properties
  38. public Damageable LastCharacter { get; private set; }
  39. public IGM_Junction.Mode LastMode { get; private set; }
  40. public int LastPage { get; private set; }
  41. public Kernel_bin.Stat LastStat { get; private set; }
  42. public IEnumerable<Kernel_bin.Magic_Data> Sort { get; private set; }
  43. public IGM_Junction.Mode SortMode { get; private set; }
  44. public Kernel_bin.Stat Stat { get; private set; }
  45. public IGMData.Target.Group Target_Group => (IGMData.Target.Group)(((IGMData.Base)ITEM[Targets_Window, 0]));
  46. private int Targets_Window => Rows;
  47. #endregion Properties
  48. #region Methods
  49. public static void ChangeStat(Kernel_bin.Stat stat) => StatEventListener?.Invoke(null, stat);
  50. public static Magic Create(Rectangle pos, Damageable damageable, bool battle = false)
  51. {
  52. return Create<Magic>(5, 3, new IGMDataItem.Box { Pos = pos, Title = Icons.ID.MAGIC }, 4, 13, damageable,battle:battle);
  53. }
  54. public static Magic Create() => Create<Magic>(6, 3, new IGMDataItem.Box { Pos = new Rectangle(135, 150, 300, 192), Title = Icons.ID.MAGIC }, 4, 13);
  55. public void FillMagic()
  56. {
  57. int pos = 0;
  58. int skip = Page * Rows;
  59. if (Battle || Sort == null)
  60. if (Damageable.GetEnemy(out Enemy e))
  61. {
  62. bool add(Kernel_bin.Magic_Data magic)
  63. {
  64. if (pos >= Rows)
  65. return false;
  66. if (skip-- <= 0)
  67. {
  68. addMagic(ref pos, magic);
  69. }
  70. return true;
  71. }
  72. HashSet<Kernel_bin.Magic_Data> Unique_Magic = new HashSet<Kernel_bin.Magic_Data>();
  73. foreach (var m in e.Abilities.Where(x => x.MAGIC != null))
  74. Unique_Magic.Add(m.MAGIC);
  75. foreach (var m in e.DrawList.Where(x => x.DATA != null))
  76. Unique_Magic.Add(m.DATA);
  77. foreach(var m in Unique_Magic)
  78. {
  79. if (!add(m))
  80. break;
  81. }
  82. ITEM[Rows, 2].Hide();
  83. DefaultPages = Unique_Magic.Count / Rows;
  84. UpdateTitle();
  85. }
  86. else
  87. for (int i = 0; pos < Rows && Source?.Magics != null && i < Source.Magics.Count; i++)
  88. {
  89. // magic id and count
  90. KeyValuePair<byte, byte> dat = Source.Magics[i];
  91. // if invalid
  92. if (dat.Key == 0 || Kernel_bin.MagicData.Count <= dat.Key || dat.Value == 0 || skip-- > 0) continue;
  93. addMagic(ref pos, Kernel_bin.MagicData[dat.Key], @default);
  94. }
  95. else
  96. foreach (Kernel_bin.Magic_Data i in Sort)
  97. {
  98. if (pos >= Rows) break;
  99. if (skip-- > 0) continue;
  100. if (Source.Magics.ContainsKey(i.ID) && i.ID > 0 && skip-- <= 0)
  101. {
  102. switch (SortMode)
  103. {
  104. case IGM_Junction.Mode.Mag_Pool_Stat:
  105. if (i.J_Val[Stat] == 0)
  106. addMagic(ref pos, i, nostat);
  107. else
  108. addMagic(ref pos, i, @default);
  109. break;
  110. case IGM_Junction.Mode.Mag_Pool_EL_D:
  111. if (i.J_Val[Stat] * i.EL_Def.Count() == 0)
  112. addMagic(ref pos, i, nostat);
  113. else
  114. addMagic(ref pos, i, @default);
  115. break;
  116. case IGM_Junction.Mode.Mag_Pool_EL_A:
  117. if (i.J_Val[Stat] * i.EL_Atk.Count() == 0)
  118. addMagic(ref pos, i, nostat);
  119. else
  120. addMagic(ref pos, i, @default);
  121. break;
  122. case IGM_Junction.Mode.Mag_Pool_ST_D:
  123. if (i.J_Val[Stat] * i.ST_Def.Count() == 0)
  124. addMagic(ref pos, i, nostat);
  125. else
  126. addMagic(ref pos, i, @default);
  127. break;
  128. case IGM_Junction.Mode.Mag_Pool_ST_A:
  129. if (i.J_Val[Stat] * i.ST_Atk.Count() == 0)
  130. addMagic(ref pos, i, nostat);
  131. else
  132. addMagic(ref pos, i, @default);
  133. break;
  134. default:
  135. addMagic(ref pos, i, @default);
  136. break;
  137. }
  138. }
  139. }
  140. for (; pos < Rows; pos++)
  141. {
  142. ITEM[pos, 0].Hide();
  143. ITEM[pos, 1].Hide();
  144. ITEM[pos, 2].Hide();
  145. BLANKS[pos] = true;
  146. Contents[pos] = 0;
  147. }
  148. }
  149. public void Generate_Preview(bool skipundo = false)
  150. {
  151. if (Stat != Kernel_bin.Stat.None && CURSOR_SELECT < Contents.Length)
  152. {
  153. Cursor_Status |= Cursor_Status.Enabled;
  154. if (Source.Stat_J[Stat] != Contents[CURSOR_SELECT])
  155. {
  156. if (!skipundo)
  157. {
  158. Undo();
  159. skipundo = false;
  160. }
  161. Source.JunctionSpell(Stat, Contents[CURSOR_SELECT]);
  162. SlotRefreshListener?.Invoke(this, Damageable);
  163. }
  164. }
  165. }
  166. public void Get_Slots_Values()
  167. {
  168. if (Damageable.GetCharacterData(out Saves.CharacterData c))
  169. Source = c;
  170. }
  171. public void Get_Sort()
  172. {
  173. if (!Battle)
  174. switch (SortMode)
  175. {
  176. case IGM_Junction.Mode.Mag_Pool_Stat:
  177. if (Stat != Kernel_bin.Stat.None)
  178. Sort = Source.SortedMagic(Stat);
  179. break;
  180. case IGM_Junction.Mode.Mag_Pool_EL_D:
  181. Sort = Source.SortedMagic(Kernel_bin.Stat.EL_Def_1);
  182. break;
  183. case IGM_Junction.Mode.Mag_Pool_EL_A:
  184. Sort = Source.SortedMagic(Kernel_bin.Stat.EL_Atk);
  185. break;
  186. case IGM_Junction.Mode.Mag_Pool_ST_D:
  187. Sort = Source.SortedMagic(Kernel_bin.Stat.ST_Def_1);
  188. break;
  189. case IGM_Junction.Mode.Mag_Pool_ST_A:
  190. Sort = Source.SortedMagic(Kernel_bin.Stat.ST_Atk);
  191. break;
  192. default:
  193. Sort = Kernel_bin.MagicData.AsEnumerable();
  194. break;
  195. }
  196. }
  197. public override bool Inputs()
  198. {
  199. bool ret = false;
  200. if (InputITEM(Target_Group, ref ret))
  201. { }
  202. else
  203. {
  204. Cursor_Status |= Cursor_Status.Enabled;
  205. return base.Inputs();
  206. }
  207. return ret;
  208. }
  209. public override bool Inputs_CANCEL()
  210. {
  211. if (Memory.State.Characters != null)
  212. {
  213. base.Inputs_CANCEL();
  214. if (Battle)
  215. {
  216. Hide();
  217. return true;
  218. }
  219. else
  220. {
  221. SlotUndoListener?.Invoke(this, (IGM_Junction.Mode)Menu.IGM_Junction.GetMode());
  222. SlotConfirmListener?.Invoke(this, (IGM_Junction.Mode)Menu.IGM_Junction.GetMode());
  223. SlotRefreshListener?.Invoke(this, Damageable);
  224. switch (SortMode)
  225. {
  226. case IGM_Junction.Mode.Mag_Pool_Stat:
  227. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_Stat);
  228. break;
  229. case IGM_Junction.Mode.Mag_Pool_EL_A:
  230. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_EL_A);
  231. break;
  232. case IGM_Junction.Mode.Mag_Pool_EL_D:
  233. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_EL_D);
  234. break;
  235. case IGM_Junction.Mode.Mag_Pool_ST_A:
  236. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_ST_A);
  237. break;
  238. case IGM_Junction.Mode.Mag_Pool_ST_D:
  239. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_ST_D);
  240. break;
  241. }
  242. Cursor_Status &= ~Cursor_Status.Enabled;
  243. if (Damageable.GetCharacterData(out Saves.CharacterData c))
  244. Source = c;
  245. return true;
  246. }
  247. }
  248. return false;
  249. }
  250. public override bool Inputs_OKAY()
  251. {
  252. if (Battle)
  253. {
  254. Target_Group.SelectTargetWindows(Kernel_bin.MagicData[Contents[CURSOR_SELECT]]);
  255. Target_Group.ShowTargetWindows();
  256. }
  257. else
  258. if (Memory.State.Characters != null)
  259. {
  260. if (!BLANKS[CURSOR_SELECT])
  261. {
  262. skipsnd = true;
  263. init_debugger_Audio.PlaySound(31);
  264. base.Inputs_OKAY();
  265. SlotConfirmListener?.Invoke(this, (IGM_Junction.Mode)Menu.IGM_Junction.GetMode());
  266. if (Menu.IGM_Junction.GetMode().Equals(IGM_Junction.Mode.Mag_Pool_Stat))
  267. {
  268. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_Stat);
  269. }
  270. else if (Menu.IGM_Junction.GetMode().Equals(IGM_Junction.Mode.Mag_Pool_EL_A) || Menu.IGM_Junction.GetMode().Equals(IGM_Junction.Mode.Mag_Pool_EL_D))
  271. {
  272. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_EL_A);
  273. }
  274. else if (Menu.IGM_Junction.GetMode().Equals(IGM_Junction.Mode.Mag_Pool_ST_A) || Menu.IGM_Junction.GetMode().Equals(IGM_Junction.Mode.Mag_Pool_ST_D))
  275. {
  276. Menu.IGM_Junction.SetMode(IGM_Junction.Mode.Mag_ST_A);
  277. }
  278. Cursor_Status &= ~Cursor_Status.Enabled;
  279. Menu.IGM_Junction.Refresh();
  280. return true;
  281. }
  282. }
  283. return false;
  284. }
  285. public override void ModeChangeEvent(object sender, Enum e)
  286. {
  287. if (e.GetType() == typeof(IGM_Junction.Mode))
  288. UpdateOnEvent(sender, (IGM_Junction.Mode)e);
  289. else if (e.GetType() == typeof(Damageable.BattleMode))
  290. UpdateOnEvent(sender, null);
  291. }
  292. //public IGMData Values { get; private set; } = null;
  293. public override void Refresh()
  294. {
  295. if (!skipRefresh)
  296. {
  297. if (!eventAdded && Menu.IGM_Junction != null)
  298. {
  299. if (!Battle)
  300. {
  301. Menu.IGM_Junction.ModeChangeHandler += ModeChangeEvent;
  302. StatEventListener += StatChangeEvent; eventAdded = true;
  303. }
  304. else if (Damageable != null)
  305. {
  306. Damageable.BattleModeChangeEventHandler += ModeChangeEvent; eventAdded = true;
  307. }
  308. }
  309. base.Refresh();
  310. UpdateTitle();
  311. }
  312. else skipRefresh = false;
  313. }
  314. public override void Refresh(Damageable damageable)
  315. {
  316. if (Battle && eventAdded && damageable != Damageable)
  317. {
  318. eventAdded = false;
  319. if (Damageable != null)
  320. Damageable.BattleModeChangeEventHandler -= ModeChangeEvent;
  321. }
  322. base.Refresh(damageable);
  323. }
  324. public override void Reset()
  325. {
  326. HideChildren();
  327. Hide();
  328. base.Reset();
  329. }
  330. public override void UpdateTitle()
  331. {
  332. base.UpdateTitle();
  333. if (Pages == 1)
  334. {
  335. ((IGMDataItem.Box)CONTAINER).Title = Icons.ID.MAGIC;
  336. //ITEM[Count - 1, 0] = ITEM[Count - 2, 0] = null;
  337. }
  338. else
  339. if (Page < Pages)
  340. ((IGMDataItem.Box)CONTAINER).Title = (Icons.ID)((int)Icons.ID.MAGIC_PG1 + Page);
  341. }
  342. protected override void DrawITEM(int i, int d)
  343. {
  344. if (Targets_Window >= i || !Target_Group.Enabled)
  345. base.DrawITEM(i, d);
  346. }
  347. protected override void Init()
  348. {
  349. base.Init();
  350. SIZE[Rows] = SIZE[0];
  351. SIZE[Rows].Y = Y;
  352. ITEM[Rows, 2] = new IGMDataItem.Icon { Data = Icons.ID.NUM_, Pos = new Rectangle(SIZE[Rows].X + SIZE[Rows].Width - 45, SIZE[Rows].Y, 0, 0), Scale = new Vector2(2.5f) };
  353. for (int pos = 0; pos < Rows; pos++)
  354. {
  355. ITEM[pos, 0] = new IGMDataItem.Text { Pos = SIZE[pos] };
  356. ITEM[pos, 0].Hide();
  357. ITEM[pos, 1] = new IGMDataItem.Icon { Data = Icons.ID.JunctionSYM, Pos = new Rectangle(SIZE[pos].X + SIZE[pos].Width - 75, SIZE[pos].Y, 0, 0) };
  358. ITEM[pos, 1].Hide();
  359. ITEM[pos, 2] = new IGMDataItem.Integer { Pos = new Rectangle(SIZE[pos].X + SIZE[pos].Width - 50, SIZE[pos].Y, 0, 0), Spaces = 3 };
  360. ITEM[pos, 2].Hide();
  361. }
  362. ITEM[Targets_Window, 0] = IGMData.Target.Group.Create(Damageable);
  363. BLANKS[Rows] = true;
  364. Cursor_Status &= ~Cursor_Status.Horizontal;
  365. Cursor_Status |= Cursor_Status.Vertical;
  366. Cursor_Status &= ~Cursor_Status.Blinking;
  367. PointerZIndex = Rows - 1;
  368. }
  369. protected override void InitShift(int i, int col, int row)
  370. {
  371. base.InitShift(i, col, row);
  372. SIZE[i].Inflate(-22, -8);
  373. SIZE[i].Offset(0, 12 + (-8 * row));
  374. SIZE[i].Height = (int)(12 * TextScale.Y);
  375. }
  376. protected override void PAGE_NEXT()
  377. {
  378. base.PAGE_NEXT();
  379. UpdateOnEvent(this);
  380. while (Contents[0] == 0 && Page > 0)
  381. {
  382. skipsnd = true;
  383. base.PAGE_NEXT();
  384. UpdateOnEvent(this);
  385. }
  386. }
  387. protected override void PAGE_PREV()
  388. {
  389. base.PAGE_PREV();
  390. UpdateOnEvent(this);
  391. while (Contents[0] == 0 && Page > 0)
  392. {
  393. skipsnd = true;
  394. base.PAGE_PREV();
  395. UpdateOnEvent(this);
  396. }
  397. }
  398. protected override void SetCursor_select(int value)
  399. {
  400. if (value != GetCursor_select())
  401. {
  402. base.SetCursor_select(value);
  403. UpdateOnEvent(this);
  404. }
  405. }
  406. private void addMagic(ref int pos, Kernel_bin.Magic_Data spell, Font.ColorID color = @default)
  407. {
  408. if (!Damageable.GetEnemy(out Enemy e))
  409. {
  410. e = null;
  411. }
  412. bool j = false;
  413. if (color == @default && e == null && Source != null && Source.Stat_J.ContainsValue(spell.ID))
  414. {
  415. //spell is junctioned
  416. if (!Battle)
  417. color = junctioned;
  418. j = true;
  419. }
  420. ((IGMDataItem.Text)ITEM[pos, 0]).Data = spell.Name;
  421. ((IGMDataItem.Text)ITEM[pos, 0]).FontColor = color;
  422. ITEM[pos, 0].Show();
  423. if (j)
  424. ITEM[pos, 1].Show();
  425. else
  426. ITEM[pos, 1].Hide();
  427. int count = Source?.Magics[spell.ID] ?? 0;
  428. ((IGMDataItem.Integer)ITEM[pos, 2]).Data = count;
  429. if (count <= 0)
  430. ITEM[pos, 2].Hide();
  431. else
  432. ITEM[pos, 2].Show();
  433. //makes it so you cannot junction a magic to a stat that does nothing.
  434. BLANKS[pos] = color == nostat ? true : false;
  435. Contents[pos] = spell.ID;
  436. pos++;
  437. }
  438. private void Get_Sort_Stat()
  439. {
  440. if (Battle)
  441. {
  442. //SortMode = IGM_Junction.Mode.Mag_Pool_Stat;
  443. }
  444. else
  445. {
  446. SortMode = (IGM_Junction.Mode)Menu.IGM_Junction.GetMode();
  447. switch (SortMode)
  448. {
  449. default:
  450. case IGM_Junction.Mode.Mag_Stat:
  451. case IGM_Junction.Mode.Mag_Pool_Stat:
  452. SortMode = IGM_Junction.Mode.Mag_Pool_Stat;
  453. break;
  454. case IGM_Junction.Mode.Mag_ST_D:
  455. case IGM_Junction.Mode.Mag_Pool_ST_D:
  456. SortMode = IGM_Junction.Mode.Mag_Pool_ST_D;
  457. break;
  458. case IGM_Junction.Mode.Mag_ST_A:
  459. case IGM_Junction.Mode.Mag_Pool_ST_A:
  460. SortMode = IGM_Junction.Mode.Mag_Pool_ST_A;
  461. Stat = Kernel_bin.Stat.ST_Atk;
  462. break;
  463. case IGM_Junction.Mode.Mag_EL_D:
  464. case IGM_Junction.Mode.Mag_Pool_EL_D:
  465. SortMode = IGM_Junction.Mode.Mag_Pool_EL_D;
  466. break;
  467. case IGM_Junction.Mode.Mag_EL_A:
  468. case IGM_Junction.Mode.Mag_Pool_EL_A:
  469. SortMode = IGM_Junction.Mode.Mag_Pool_EL_A;
  470. Stat = Kernel_bin.Stat.EL_Atk;
  471. break;
  472. }
  473. }
  474. }
  475. private void StatChangeEvent(object sender, Kernel_bin.Stat e) => UpdateOnEvent(sender, null, e);
  476. private bool Undo()
  477. {
  478. SlotUndoListener?.Invoke(this, (IGM_Junction.Mode)(Menu.IGM_Junction.GetMode()));
  479. if (Memory.State.Characters != null && Damageable.GetCharacterData(out Saves.CharacterData c))
  480. Source = c;
  481. return true;
  482. }
  483. private void UpdateOnEvent(object sender, IGM_Junction.Mode? mode = null, Kernel_bin.Stat? stat = null)
  484. {
  485. mode = mode ?? (IGM_Junction.Mode)Menu.IGM_Junction.GetMode();
  486. if ((
  487. mode == IGM_Junction.Mode.Mag_Pool_ST_A ||
  488. mode == IGM_Junction.Mode.Mag_Pool_ST_D ||
  489. mode == IGM_Junction.Mode.Mag_Pool_EL_A ||
  490. mode == IGM_Junction.Mode.Mag_Pool_EL_D ||
  491. mode == IGM_Junction.Mode.Mag_Pool_Stat) || Battle && Enabled)
  492. {
  493. Cursor_Status |= Cursor_Status.Enabled;
  494. }
  495. else
  496. {
  497. Cursor_Status &= ~Cursor_Status.Enabled;
  498. }
  499. if (Memory.State.Characters != null && Damageable != null)
  500. {
  501. Get_Sort_Stat();
  502. Stat = stat ?? Stat;
  503. Get_Slots_Values();
  504. if (SortMode != LastMode || this.Stat != LastStat || Damageable != LastCharacter)
  505. Get_Sort();
  506. bool skipundo = false;
  507. if (Battle || !(SortMode == LastMode && Damageable == LastCharacter && this.Stat == LastStat && Page == LastPage))
  508. {
  509. // goal of these checks were to avoid updating the whole list if we don't need to.
  510. LastCharacter = Damageable;
  511. LastStat = this.Stat;
  512. LastPage = Page;
  513. LastMode = SortMode;
  514. skipundo = Undo();
  515. FillMagic();
  516. UpdateTitle();
  517. }
  518. if (!Battle && (
  519. mode == IGM_Junction.Mode.Mag_Pool_ST_A ||
  520. mode == IGM_Junction.Mode.Mag_Pool_ST_D ||
  521. mode == IGM_Junction.Mode.Mag_Pool_EL_A ||
  522. mode == IGM_Junction.Mode.Mag_Pool_EL_D ||
  523. mode == IGM_Junction.Mode.Mag_Pool_Stat))
  524. {
  525. Generate_Preview(skipundo);
  526. }
  527. }
  528. }
  529. #endregion Methods
  530. }
  531. }