BattleMenus.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Input;
  3. using OpenVIII.Encoding.Tags;
  4. using System;
  5. using System.Collections.Concurrent;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. namespace OpenVIII
  9. {
  10. /// <summary>
  11. /// Menu holds a menu for each character.
  12. /// </summary>
  13. public partial class BattleMenus : Menu
  14. {
  15. #region Fields
  16. private Dictionary<Mode, Action> DrawActions;
  17. private Dictionary<Mode, Func<bool>> InputFunctions;
  18. private MODULE lastgamestate;
  19. private MenuModule.Mode lastmenu;
  20. private ushort lastmusic;
  21. private bool lastmusicplaying;
  22. private Dictionary<Mode, Action> ReturnAction;
  23. private Dictionary<Mode, Func<bool>> UpdateFunctions;
  24. #endregion Fields
  25. #region Enums
  26. public enum Mode : byte
  27. {
  28. /// <summary>
  29. /// Spawning character's and enemies and flying the camera around
  30. /// </summary>
  31. Starting,
  32. /// <summary>
  33. /// running atb and using battle menus.
  34. /// </summary>
  35. Battle,
  36. /// <summary>
  37. /// Fade out and goto victory menu.
  38. /// </summary>
  39. Victory,
  40. /// <summary>
  41. /// Fade out and goto game over screen.
  42. /// </summary>
  43. GameOver,
  44. }
  45. public enum SectionName
  46. {
  47. /// <summary>
  48. /// Party Member Menu
  49. /// </summary>
  50. Party1,
  51. /// <summary>
  52. /// Party Member Menu
  53. /// </summary>
  54. Party2,
  55. /// <summary>
  56. /// Party Member Menu
  57. /// </summary>
  58. Party3,
  59. /// <summary>
  60. /// Debug Enemy Menu
  61. /// </summary>
  62. Enemy1,
  63. /// <summary>
  64. /// Debug Enemy Menu
  65. /// </summary>
  66. Enemy2,
  67. /// <summary>
  68. /// Debug Enemy Menu
  69. /// </summary>
  70. Enemy3,
  71. /// <summary>
  72. /// Debug Enemy Menu
  73. /// </summary>
  74. Enemy4,
  75. /// <summary>
  76. /// Debug Enemy Menu
  77. /// </summary>
  78. Enemy5,
  79. /// <summary>
  80. /// Debug Enemy Menu
  81. /// </summary>
  82. Enemy6,
  83. /// <summary>
  84. /// Debug Enemy Menu
  85. /// </summary>
  86. Enemy7,
  87. /// <summary>
  88. /// Debug Enemy Menu
  89. /// </summary>
  90. Enemy8,
  91. /// <summary>
  92. /// Victory Menu
  93. /// </summary>
  94. Victory,
  95. }
  96. #endregion Enums
  97. #region Properties
  98. protected byte Player { get; set; } = 0;
  99. /// <summary>
  100. /// Get Damageable from active battle menu;
  101. /// </summary>
  102. /// <returns></returns>
  103. public Damageable GetDamageable() => GetCurrentBattleMenu()?.Damageable;
  104. public new sbyte? PartyPos
  105. {
  106. get
  107. {
  108. BattleMenu bm = GetCurrentBattleMenu();
  109. if (bm?.Damageable?.GetBattleMode().Equals(Damageable.BattleMode.YourTurn) ?? false)
  110. {
  111. return bm.PartyPos;
  112. }
  113. return null;
  114. }
  115. }
  116. public VictoryMenu Victory_Menu { get => (VictoryMenu)(Data[SectionName.Victory]); protected set => Data[SectionName.Victory] = value; }
  117. #endregion Properties
  118. #region Methods
  119. public static BattleMenus Create() => Create<BattleMenus>();
  120. /// <summary>
  121. /// Save pre battle state.
  122. /// </summary>
  123. public void CameFrom()
  124. {
  125. lastmenu = Menu.Module.State;
  126. lastgamestate = Memory.Module;
  127. lastmusic = Memory.MusicIndex;
  128. lastmusicplaying = init_debugger_Audio.MusicPlaying;
  129. }
  130. public override void Draw()
  131. {
  132. if (GetMode() != null && DrawActions != null)
  133. {
  134. if (DrawActions.ContainsKey((Mode)GetMode()))
  135. DrawActions[(Mode)GetMode()]();
  136. }
  137. }
  138. public IEnumerable<BattleMenu> GetBattleMenus() => Data?.Where(m => m.Value.GetType().Equals(typeof(BattleMenu)) && m.Value.Damageable != null).Select(x => (BattleMenu)x.Value);
  139. public BattleMenu GetCurrentBattleMenu() => (BattleMenu)Data?[PossibleValidPlayer()];
  140. public override bool Inputs()
  141. {
  142. bool ret = false;
  143. InputMouse.Mode = MouseLockMode.Screen;
  144. Memory.IsMouseVisible = true;
  145. if (InputFunctions?.ContainsKey((Mode)GetMode()) ?? false)
  146. ret = InputFunctions[(Mode)GetMode()]() && ret;
  147. // press 6 to force victory
  148. if (Input2.DelayedButton(Keys.D6))
  149. {
  150. TriggerVictory();
  151. }
  152. // press 7 to force game over
  153. else if (Input2.DelayedButton(Keys.D7))
  154. {
  155. SetMode(Mode.GameOver);
  156. }
  157. // press 9 to go back to last state.
  158. else if (Input2.DelayedButton(Keys.D9))
  159. ReturnTo();
  160. return ret;
  161. }
  162. public override void Refresh()
  163. {
  164. SetParty();
  165. SetEnemyParty();
  166. SetMode(Mode.Battle);
  167. // exp, items and ap you are going to get after the battle is over.
  168. base.Refresh();
  169. }
  170. private void InitDictionarys()
  171. {
  172. if (UpdateFunctions == null)
  173. UpdateFunctions = new Dictionary<Mode, Func<bool>>()
  174. {
  175. {Mode.Starting, UpdateStartingFunction},
  176. {Mode.Battle, UpdateBattleFunction},
  177. {Mode.Victory, UpdateVictoryFunction},
  178. {Mode.GameOver, UpdateGameOverFunction},
  179. };
  180. if (DrawActions == null)
  181. DrawActions = new Dictionary<Mode, Action>()
  182. {
  183. {Mode.Starting, DrawStartingAction},
  184. {Mode.Battle, DrawBattleAction},
  185. {Mode.Victory, DrawVictoryAction},
  186. {Mode.GameOver, DrawGameOverAction},
  187. };
  188. if (InputFunctions == null)
  189. InputFunctions = new Dictionary<Mode, Func<bool>>()
  190. {
  191. //{Mode.Starting, InputStartingFunction},
  192. {Mode.Battle, InputBattleFunction},
  193. {Mode.Victory, InputVictoryFunction},
  194. //{Mode.GameOver, InputGameOverFunction},
  195. };
  196. if (ReturnAction == null)
  197. ReturnAction = new Dictionary<Mode, Action>()
  198. {
  199. {Mode.Starting, ReturnStartingFunction},
  200. {Mode.Battle, ReturnBattleFunction},
  201. {Mode.Victory, ReturnVictoryFunction},
  202. {Mode.GameOver, ReturnGameOverFunction},
  203. };
  204. }
  205. private void SetEnemyParty()
  206. {
  207. if (Enemy.Party != null && Enemy.Party.Count > 0)
  208. {
  209. byte i = 0;
  210. foreach (Enemy e in Enemy.Party)
  211. {
  212. Data[SectionName.Enemy1 + i].SetDamageable(e);
  213. Data[SectionName.Enemy1 + i].Show();
  214. i++;
  215. }
  216. for (; i < 8; i++)
  217. {
  218. Data[SectionName.Enemy1 + i].SetDamageable(null, forcenull: true);
  219. Data[SectionName.Enemy1 + i].Hide();
  220. }
  221. }
  222. }
  223. private void SetParty()
  224. {
  225. if (Memory.State?.Characters != null && Memory.State.Characters.Count > 0 && Memory.State.Party != null)
  226. {
  227. byte i = 0;
  228. IEnumerable<KeyValuePair<int, Characters>> party = Memory.State.Party.Select((element, index) => new { element, index }).ToDictionary(m => m.index, m => m.element).Where(m => !m.Value.Equals(Characters.Blank));
  229. int count = party.Count();
  230. foreach (KeyValuePair<int, Characters> m in party)
  231. {
  232. Data[SectionName.Party1 + i].SetDamageable(Memory.State[Memory.State.PartyData[m.Key]]);
  233. Data[SectionName.Party1 + i].Show();
  234. i++;
  235. }
  236. for (; i <= (int)SectionName.Party3; i++)
  237. {
  238. Data[SectionName.Party1 + i].SetDamageable(null, forcenull: true);
  239. Data[SectionName.Party1 + i].Hide();
  240. }
  241. }
  242. }
  243. /// <summary>
  244. /// Go back to pre battle state.
  245. /// </summary>
  246. public void ReturnTo()
  247. {
  248. Menu.Module.State = lastmenu;
  249. Memory.Module = lastgamestate;
  250. Menu.IGM.Refresh(); // else the menu stats won't update.
  251. Module_battle_debug.ResetState();
  252. if (lastmusicplaying)
  253. init_debugger_Audio.PlayMusic(lastmusic);
  254. else
  255. init_debugger_Audio.StopMusic();
  256. }
  257. public override bool SetMode(Enum mode)
  258. {
  259. if (!(base.GetMode()?.Equals(mode) ?? false))
  260. return base.SetMode(mode);
  261. return false;
  262. }
  263. public override bool Update()
  264. {
  265. bool ret = false;
  266. if (GetMode() != null)
  267. {
  268. if (UpdateFunctions != null && UpdateFunctions.TryGetValue((Mode)GetMode(), out Func<bool> u))
  269. {
  270. ret = u();
  271. }
  272. SkipFocus = true;
  273. skipdata = true;
  274. ret = base.Update() || ret;
  275. skipdata = false;
  276. }
  277. return ret;
  278. }
  279. protected override void Init()
  280. {
  281. NoInputOnUpdate = true;
  282. Size = new Vector2 { X = 881, Y = 636 };
  283. base.Init();
  284. Data.TryAdd(SectionName.Party1, BattleMenu.Create(null));
  285. Data.TryAdd(SectionName.Party2, BattleMenu.Create(null));
  286. Data.TryAdd(SectionName.Party3, BattleMenu.Create(null));
  287. Data.TryAdd(SectionName.Enemy1, BattleMenu.Create(null));
  288. Data.TryAdd(SectionName.Enemy2, BattleMenu.Create(null));
  289. Data.TryAdd(SectionName.Enemy3, BattleMenu.Create(null));
  290. Data.TryAdd(SectionName.Enemy4, BattleMenu.Create(null));
  291. Data.TryAdd(SectionName.Enemy5, BattleMenu.Create(null));
  292. Data.TryAdd(SectionName.Enemy6, BattleMenu.Create(null));
  293. Data.TryAdd(SectionName.Enemy7, BattleMenu.Create(null));
  294. Data.TryAdd(SectionName.Enemy8, BattleMenu.Create(null));
  295. Data.TryAdd(SectionName.Victory, VictoryMenu.Create());
  296. Data.ForEach(x => x.Value.Hide());
  297. InitDictionarys();
  298. }
  299. private bool BoolBattleMenu() => Data?.Any(m => m.Value.GetType().Equals(typeof(BattleMenu)) && m.Value.Enabled) ?? false;
  300. private bool BoolRenzokeken() => GetBattleMenus()?.Any(m => m.Enabled && (m.Renzokeken?.Enabled ?? false)) ?? false;
  301. private bool BoolShot() => GetBattleMenus()?.Any(m => m.Enabled && (m.Shot?.Enabled ?? false)) ?? false;
  302. public override void StartDraw()
  303. {
  304. //if (BoolShot())
  305. // GetOneShot().Shot.DrawCrosshair();
  306. base.StartDraw();
  307. }
  308. private void DrawBattleAction()
  309. {
  310. StartDraw();
  311. //Had to split up the HP and Commands drawing. So that Commands would draw over HP.
  312. if (BoolRenzokeken())
  313. GetOneRenzokeken().DrawData(BattleMenu.SectionName.Renzokeken);
  314. else if (BoolShot())
  315. GetOneShot().DrawData(BattleMenu.SectionName.Shot);
  316. else if (BoolBattleMenu())
  317. {
  318. GetBattleMenus().ForEach(m => m.DrawData(BattleMenu.SectionName.HP));
  319. GetBattleMenus().ForEach(m => m.DrawData(BattleMenu.SectionName.Commands));
  320. }
  321. //DrawData();
  322. EndDraw();
  323. }
  324. private void DrawGameOverAction()
  325. {
  326. }
  327. private void DrawStartingAction()
  328. {
  329. }
  330. private void DrawVictoryAction() => Victory_Menu.Draw();
  331. private BattleMenu GetOneRenzokeken() => GetBattleMenus()?.First(m => m.Enabled && m.Renzokeken.Enabled);
  332. private BattleMenu GetOneShot() => GetBattleMenus()?.First(m => m.Enabled && m.Shot.Enabled);
  333. private bool InputBattleFunction()
  334. {
  335. bool ret = false;
  336. if (BoolRenzokeken())
  337. {
  338. return GetOneRenzokeken().Inputs();
  339. }
  340. foreach (BattleMenu m in GetBattleMenus().Where(m => m.Damageable.GetBattleMode().Equals(Damageable.BattleMode.YourTurn)))
  341. {
  342. ret = m.Inputs() || ret;
  343. if (ret) return ret;
  344. }
  345. if (Input2.DelayedButton(FF8TextTagKey.Cancel))
  346. {
  347. if (GetCurrentBattleMenu().Damageable?.Switch() ?? true)
  348. {
  349. int cnt = 0;
  350. do
  351. {
  352. if (++Player > (int)SectionName.Enemy8) Player = 0;
  353. if (++cnt > (int)SectionName.Enemy8 * 2) return false;
  354. }
  355. while (Data.Count <= Player ||
  356. Data[PossibleValidPlayer()]?.Damageable == null ||
  357. Data[PossibleValidPlayer()].GetType() != typeof(BattleMenu) ||
  358. !GetCurrentBattleMenu().Damageable.StartTurn());
  359. NewTurnSND();
  360. }
  361. }
  362. return ret;
  363. }
  364. private bool InputGameOverFunction() => false;
  365. private bool InputStartingFunction() => false;
  366. private bool InputVictoryFunction() => Victory_Menu?.Inputs() ?? false;
  367. private void NewTurnSND()
  368. {
  369. if (((BattleMenu)Data[PossibleValidPlayer()]).CrisisLevel > -1)
  370. init_debugger_Audio.PlaySound(94);
  371. else
  372. init_debugger_Audio.PlaySound(14);
  373. }
  374. private SectionName PossibleValidPlayer() => SectionName.Party1 + MathHelper.Clamp(Player, 0, (int)SectionName.Enemy8);
  375. private void ReturnBattleFunction()
  376. {
  377. }
  378. private void ReturnGameOverFunction()
  379. {
  380. }
  381. private void ReturnStartingFunction()
  382. {
  383. }
  384. private void ReturnVictoryFunction()
  385. {
  386. }
  387. private void TriggerVictory(ConcurrentDictionary<Characters, int> expextra = null)
  388. {
  389. int exp = 0;
  390. uint ap = 0;
  391. ConcurrentDictionary<byte, byte> items = new ConcurrentDictionary<byte, byte>();
  392. ConcurrentDictionary<Cards.ID, byte> cards = new ConcurrentDictionary<Cards.ID, byte>();
  393. foreach (Enemy e in Enemy.Party)
  394. {
  395. exp += e.EXP;
  396. ap += e.AP;
  397. Saves.Item drop = e.Drop(Memory.State.PartyHasAbility(Kernel_bin.Abilities.RareItem));
  398. Cards.ID carddrop = e.CardDrop();
  399. if (drop.QTY > 0 && drop.ID > 0)
  400. if (!items.TryAdd(drop.ID, drop.QTY))
  401. items[drop.ID] += drop.QTY;
  402. if (carddrop != Cards.ID.Fail && carddrop != Cards.ID.Immune)
  403. if (!cards.TryAdd(carddrop, 1))
  404. cards[carddrop]++;
  405. }
  406. SetMode(Mode.Victory);
  407. Victory_Menu?.Refresh(exp, ap, expextra, items, cards);
  408. Victory_Menu?.Show();
  409. }
  410. private bool UpdateBattleFunction()
  411. {
  412. bool ret = false;
  413. List<BattleMenu> bml = GetBattleMenus().ToList();
  414. if (bml.Count == 0) return false;// issue here.
  415. foreach (BattleMenu m in bml)
  416. {
  417. ret = m.Update() || ret;
  418. }
  419. if (!(GetCurrentBattleMenu()?.Damageable?.GetBattleMode().Equals(Damageable.BattleMode.YourTurn) ?? false))
  420. {
  421. int cnt = bml.Count;
  422. if (Player + 1 == cnt)
  423. Player = 0;
  424. for (byte i = Player; cnt > 0; cnt--)
  425. {
  426. if (i < bml.Count && bml[i].Damageable.StartTurn())
  427. {
  428. Player = i;
  429. NewTurnSND();
  430. break;
  431. }
  432. i++;
  433. if (i >= bml.Count)
  434. i = 0;
  435. }
  436. }
  437. return ret;
  438. }
  439. private bool UpdateGameOverFunction()
  440. {
  441. Memory.Module = MODULE.FIELD_DEBUG;
  442. Memory.FieldHolder.FieldID = 75; //gover
  443. init_debugger_Audio.PlayMusic(0);
  444. Menu.Module.State = MenuModule.Mode.MainLobby;
  445. return true;
  446. }
  447. private bool UpdateStartingFunction() => throw new NotImplementedException();
  448. private bool UpdateVictoryFunction()
  449. {
  450. init_debugger_Audio.PlayMusic(1);
  451. return Victory_Menu.Update();
  452. }
  453. #endregion Methods
  454. }
  455. }