Menu.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Concurrent;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. namespace OpenVIII
  8. {
  9. public abstract class Menu : Menu_Base
  10. {
  11. #region Fields
  12. public static Slide<float> BlinkSlider = new Slide<float>(_fadedout, _fadedin, _blinkinspeed, MathHelper.Lerp) { ReversedTime = _blinkoutspeed };
  13. public static EventHandler FadedInHandler;
  14. public static EventHandler FadedOutHandler;
  15. public static Slide<float> FadeSlider = new Slide<float>(_fadedout, _fadedin, _fadeinspeed, MathHelper.Lerp) { ReversedTime = _fadeoutspeed };
  16. public ConcurrentDictionary<Enum, Menu_Base> Data;
  17. protected Enum _mode;
  18. protected bool skipdata;
  19. private const float _fadedin = 1f;
  20. private const float _fadedout = 0f;
  21. /// <summary>
  22. /// Scale of Menu Items (Background and Cursor)
  23. /// </summary>
  24. private const float _menuitemscale = 2f;
  25. private static BattleMenus _battlemenus;
  26. private static Debug_Menu _debug_menu;
  27. //private static bool _blinkstate;
  28. //private static bool _fadeout = false;
  29. private static IGM _igm;
  30. private static IGM_Items _igm_items;
  31. private static IGM_Junction _igm_junction;
  32. private static IGM_LGSG _igm_lgsg;
  33. private static IGM_Lobby _igm_lobby;
  34. private static object _igm_lock = new object();
  35. private bool _backup = false;
  36. private Vector2 _size;
  37. private static MenuModule _module;
  38. #endregion Fields
  39. #region Events
  40. public event EventHandler<Enum> ModeChangeHandler;
  41. #endregion Events
  42. #region Properties
  43. public static BattleMenus BattleMenus => _battlemenus;
  44. //public Menu(Damageable damageable)
  45. //{
  46. // _damageable = damageable;
  47. // InitConstructor(); // because base() would always run first :(
  48. //}
  49. /// <summary>
  50. /// Blink works like Fade except it goes up to 1f then to 0f and back.
  51. /// </summary>
  52. public static float Blink_Amount { get; private set; } = _fadedin;
  53. /// <summary>
  54. /// Debug Menu
  55. /// </summary>
  56. public static Debug_Menu Debug_Menu => _debug_menu;
  57. /// <summary>
  58. /// Fade by default scales from 0f to 1f. Unless FadeOut then it goes from 1f to 0f.
  59. /// </summary>
  60. public static float Fade { get; private set; } = _fadedin;
  61. public static bool FadingOut => FadeSlider.Reversed;
  62. //_fadeout;
  63. /// <summary>
  64. /// In Game Menu
  65. /// </summary>
  66. public static IGM IGM => _igm;
  67. /// <summary>
  68. /// In Game Menu - Items Menu
  69. /// </summary>
  70. public static IGM_Items IGM_Items => _igm_items;
  71. /// <summary>
  72. /// In Game Menu - Junction Menu
  73. /// </summary>
  74. public static IGM_Junction IGM_Junction => _igm_junction;
  75. /// <summary>
  76. /// Lobby Menu
  77. /// </summary>
  78. public static IGM_LGSG IGM_LGSG => _igm_lgsg;
  79. /// <summary>
  80. /// Lobby Menu
  81. /// </summary>
  82. public static IGM_Lobby IGM_Lobby => _igm_lobby;
  83. public static Vector2 StaticSize { get; protected set; }
  84. /// <summary>
  85. /// Size of text the real game doesn't use a 1:1 ratio.
  86. /// </summary>
  87. public static Vector2 TextScale { get; } = new Vector2(2.545455f, 3.0375f);
  88. /// <summary>
  89. /// If true Inputs won't be called from Update(). So will need to be called sepperately.
  90. /// </summary>
  91. public bool NoInputOnUpdate { get; set; } = false;
  92. /// <summary>
  93. /// Size of the menu. If kept in a 4:3 region it won't scale down till after losing enough width.
  94. /// </summary>
  95. public Vector2 Size { get => _size; protected set => _size = value; }
  96. public bool SkipFocus { get; set; } = false;
  97. /// <summary>
  98. /// Viewport dimensions
  99. /// </summary>
  100. protected Vector2 vp => new Vector2(Memory.graphics.GraphicsDevice.Viewport.Width, Memory.graphics.GraphicsDevice.Viewport.Height);
  101. /// <summary>
  102. /// <para>Time to fade out in milliseconds</para>
  103. /// <para>Larger is slower</para>
  104. /// </summary>
  105. private static TimeSpan _blinkinspeed => TimeSpan.FromMilliseconds(500d);
  106. /// <summary>
  107. /// <para>Time to fade out in milliseconds</para>
  108. /// <para>Larger is slower</para>
  109. /// </summary>
  110. private static TimeSpan _blinkoutspeed => TimeSpan.FromMilliseconds(900d);
  111. /// <summary>
  112. /// <para>Time to fade out in milliseconds</para>
  113. /// <para>Larger is slower</para>
  114. /// </summary>
  115. private static TimeSpan _fadeinspeed => TimeSpan.FromMilliseconds(700d);
  116. /// <summary>
  117. /// <para>Time to fade out in milliseconds</para>
  118. /// <para>Larger is slower</para>
  119. /// </summary>
  120. private static TimeSpan _fadeoutspeed => TimeSpan.FromMilliseconds(1500d);
  121. /// <summary>
  122. /// if canceled don't init menu.
  123. /// </summary>
  124. private bool cancel => Memory.Token.IsCancellationRequested;
  125. public static MenuModule Module { get => _module; set => _module = value; }
  126. #endregion Properties
  127. #region Methods
  128. //public Menu() => InitConstructor();
  129. public static T Create<T>(Damageable damageable = null) where T : Menu, new()
  130. {
  131. T r = new T
  132. {
  133. Damageable = damageable,
  134. };
  135. r.InitConstructor();
  136. return r;
  137. }
  138. public static BoxReturn DrawBox(Rectangle dst, FF8String buffer = null, Icons.ID? title = null, Vector2? textScale = null, Vector2? boxScale = null, Box_Options options = Box_Options.Default)
  139. {
  140. if (textScale == null) textScale = Vector2.One;
  141. if (boxScale == null) boxScale = Vector2.One;
  142. Point cursor = Point.Zero;
  143. Rectangle font = new Rectangle();
  144. Rectangle backup = dst;
  145. if (buffer != null && buffer.Length > 0)
  146. {
  147. font = Memory.font.RenderBasicText(buffer, dst.Location.ToVector2(), TextScale * textScale.Value, Fade: Fade, skipdraw: true);
  148. if (dst.Size == Point.Zero)
  149. {
  150. dst.Size = font.Size;
  151. if (title == null)
  152. {
  153. dst.Inflate(20, 10);
  154. }
  155. else
  156. dst.Inflate(20, 30);
  157. dst.Location = backup.Location;
  158. backup = dst;
  159. }
  160. }
  161. Vector2 bgscale = new Vector2(_menuitemscale) * textScale.Value;
  162. Rectangle box = dst.Scale(boxScale.Value);
  163. Rectangle hotspot = dst;
  164. if ((options & Box_Options.SkipDraw) == 0 && dst.Size != Point.Zero)
  165. {
  166. if (dst.Width > 256 * bgscale.X)
  167. Memory.Icons.Draw(Icons.ID.Menu_BG_368, 0, box, bgscale, Fade);
  168. else
  169. Memory.Icons.Draw(Icons.ID.Menu_BG_256, 0, box, bgscale, Fade);
  170. if (title != null)
  171. {
  172. dst.Offset(15, 0);
  173. dst.Y = (int)(dst.Y * boxScale.Value.Y);
  174. Memory.Icons.Draw(title.Value, 2, dst, (bgscale + new Vector2(.5f)), Fade);
  175. }
  176. dst = backup;
  177. }
  178. if (buffer != null && buffer.Length > 0)
  179. {
  180. //font = Memory.font.RenderBasicText(buffer, dst.Location.ToVector2(), TextScale * textScale.Value, Fade: Fade, skipdraw: true);
  181. if ((options & Box_Options.Indent) != 0)
  182. dst.Offset(70 * textScale.Value.X, 0);
  183. else if ((options & Box_Options.Center) != 0)
  184. dst.Offset(dst.Width / 2 - font.Width / 2, 0);
  185. else if ((options & Box_Options.Right) != 0)
  186. dst.Offset(dst.Width - font.Width - 5 * textScale.Value.X, 0);
  187. else
  188. dst.Offset(25 * textScale.Value.X, 0);
  189. if ((options & Box_Options.Buttom) != 0)
  190. dst.Offset(0, (dst.Height - 48));
  191. else if ((options & Box_Options.Middle) != 0)
  192. dst.Offset(0, dst.Height / 2 - font.Height / 2 + 2);
  193. else
  194. dst.Offset(0, 21);
  195. dst.Y = (int)(dst.Y * boxScale.Value.Y);
  196. font = Memory.font.RenderBasicText(buffer, dst.Location.ToVector2(), TextScale * textScale.Value, Fade: Fade, skipdraw: (options & Box_Options.SkipDraw) != 0);
  197. cursor = dst.Location;
  198. cursor.Y += (int)(TextScale.Y * 6); // 12 * (3.0375/2)
  199. }
  200. return new BoxReturn(hotspot, cursor, font);
  201. }
  202. public static void DrawPointer(Point cursor, Vector2? offset = null, bool blink = false)
  203. {
  204. if (offset == null)
  205. offset = new Vector2(-1.15f, -.3f);
  206. Vector2 scale = new Vector2(_menuitemscale);
  207. Vector2 size = Memory.Icons.GetEntry(Icons.ID.Finger_Right, 0).Size * scale;
  208. Rectangle dst = new Rectangle(cursor, Point.Zero);
  209. byte pallet = 2;
  210. byte fadedpallet = 7;
  211. dst.Offset(size * offset.Value);
  212. Memory.Icons.Trim(Icons.ID.Finger_Right, pallet);
  213. if (blink)
  214. {
  215. Memory.Icons.Draw(Icons.ID.Finger_Right, fadedpallet, dst, scale, Fade);
  216. }
  217. Memory.Icons.Draw(Icons.ID.Finger_Right, pallet, dst, scale, blink ? Fade * Blink_Amount : Fade);
  218. }
  219. public static void FadeIn()
  220. {
  221. if (FadeSlider.Reversed)
  222. FadeSlider.ReverseRestart();
  223. else
  224. FadeSlider.Restart();
  225. //Fade = _fadedout;
  226. //_fadeout = false;
  227. }
  228. public static void FadeOut()
  229. {
  230. if (!FadeSlider.Reversed)
  231. FadeSlider.ReverseRestart();
  232. else
  233. FadeSlider.Restart();
  234. //Fade = _fadedin;
  235. //_fadeout = true;
  236. }
  237. public static void InitStaticMembers()
  238. {
  239. lock (_igm_lock)
  240. {
  241. if (_igm_lobby == null)
  242. _igm_lobby = IGM_Lobby.Create();
  243. if (_igm == null)
  244. _igm = IGM.Create();
  245. if (_igm_junction == null)
  246. _igm_junction = IGM_Junction.Create();
  247. if (_igm_items == null)
  248. _igm_items = IGM_Items.Create();
  249. if (_battlemenus == null)
  250. _battlemenus = BattleMenus.Create();
  251. if (_igm_lgsg == null)
  252. _igm_lgsg = IGM_LGSG.Create();
  253. if (_debug_menu == null)
  254. _debug_menu = Debug_Menu.Create();
  255. if (_module == null)
  256. _module = MenuModule.Create();
  257. FadeIn();
  258. }
  259. }
  260. public static void UpdateOnce() => UpdateFade(null);
  261. public override void Draw()
  262. {
  263. StartDraw();
  264. DrawData();
  265. EndDraw();
  266. }
  267. public virtual void DrawData()
  268. {
  269. if (!skipdata && Enabled && Data != null)
  270. foreach (Menu_Base i in Data.Where(x => x.Value != null && x.Value.Enabled).OrderBy(x => x.Key).Select(x => x.Value))
  271. i?.Draw();
  272. }
  273. public virtual void EndDraw()
  274. {
  275. if (Enabled)
  276. Memory.SpriteBatchEnd();
  277. }
  278. public virtual Enum GetMode() => _mode;
  279. public override bool Inputs() => false;
  280. public override void Refresh()
  281. {
  282. Backup();
  283. base.Refresh();
  284. }
  285. public void Refresh(bool backup) => Refresh(Damageable, backup);
  286. public override void Refresh(Damageable damageable) => Refresh(damageable, false);
  287. public virtual void Refresh(Damageable damageable, bool backup)
  288. {
  289. _backup = backup;
  290. base.Refresh(damageable);
  291. }
  292. public override void Reset()
  293. {
  294. if (!skipdata)
  295. foreach (KeyValuePair<Enum, Menu_Base> i in Data)
  296. {
  297. i.Value?.Reset();
  298. }
  299. base.Reset();
  300. }
  301. public virtual bool SetMode(Enum mode)
  302. {
  303. if (!mode.Equals(_mode))
  304. {
  305. _mode = mode;
  306. ModeChangeHandler?.Invoke(this, mode);
  307. return true;
  308. }
  309. return false;
  310. }
  311. public virtual void StartDraw()
  312. {
  313. if (Enabled)
  314. Memory.SpriteBatchStartAlpha(ss: SamplerState.PointClamp, tm: Focus);
  315. }
  316. public override bool Update()
  317. {
  318. bool ret = false;
  319. if (!SkipFocus)
  320. GenerateFocus();
  321. if(Size != Vector2.Zero)
  322. StaticSize = Size;
  323. if (Enabled)
  324. {
  325. //todo detect when there is no saves detected.
  326. //check for null
  327. if (!skipdata && Data != null)
  328. {
  329. ret = ((from i in Data
  330. where i.Value != null && i.Value.Update()
  331. select new { isTrue = true }).FirstOrDefault()?.isTrue ?? false) || ret;
  332. }
  333. //foreach (KeyValuePair<Enum, Menu_Base> i in Data.Where(x=>x.Value!=null))
  334. //{
  335. // ret = (i?.Value.Update() ?? false) || ret;
  336. //}
  337. }
  338. if (!NoInputOnUpdate)
  339. return Inputs() || ret;
  340. else return ret;
  341. }
  342. protected void GenerateFocus(Vector2? inputsize = null, Box_Options options = Box_Options.Default)
  343. {
  344. Vector2 size = inputsize ?? Size;
  345. Vector2 Zoom = Memory.Scale(size.X, size.Y, Memory.ScaleMode.FitBoth);
  346. size /= 2;
  347. Vector2 t = new Vector2(vp.X / 2, vp.Y / 2);
  348. if ((options & Box_Options.Top) != 0)
  349. {
  350. t.Y = 0;
  351. size.Y = 0;
  352. }
  353. else if ((options & Box_Options.Buttom) != 0)
  354. {
  355. t.Y = vp.Y - (size.Y * 2 * Zoom.Y);
  356. size.Y = 0;
  357. }
  358. Focus = Matrix.CreateTranslation(-size.X, -size.Y, 0) *
  359. Matrix.CreateScale(new Vector3(Zoom.X, Zoom.Y, 1)) *
  360. Matrix.CreateTranslation(t.X, t.Y, 0);
  361. }
  362. protected override void Init()
  363. {
  364. }
  365. protected override void RefreshChild()
  366. {
  367. if (!skipdata)
  368. foreach (KeyValuePair<Enum, Menu_Base> i in Data)
  369. // children might have a damageable set.
  370. // if parents may not always have one set.
  371. {
  372. if (ForceNullDamageable)
  373. i.Value.ForceNullDamageable = ForceNullDamageable;
  374. i.Value.Refresh(Damageable);
  375. }
  376. ForceNullDamageable = false;
  377. }
  378. private static void UpdateFade(object sender = null)
  379. {
  380. if (!BlinkSlider.Done)
  381. {
  382. Blink_Amount = BlinkSlider.Update();
  383. if (BlinkSlider.Done)
  384. {
  385. BlinkSlider.Reverse();
  386. BlinkSlider.Restart();
  387. }
  388. }
  389. if (!FadeSlider.Done)
  390. {
  391. Fade = FadeSlider.Update();
  392. if (FadeSlider.Reversed)
  393. {
  394. if (FadeSlider.Done)
  395. {
  396. FadedOutHandler?.Invoke(sender, null);
  397. FadeSlider.ReverseRestart();
  398. }
  399. }
  400. else
  401. {
  402. Fade = FadeSlider.Update();
  403. if (FadeSlider.Done)
  404. {
  405. FadedInHandler?.Invoke(sender, null);
  406. }
  407. }
  408. }
  409. }
  410. private void Backup()
  411. {
  412. //backup memory
  413. if (_backup)
  414. Memory.PrevState = Memory.State.Clone();
  415. _backup = false;
  416. }
  417. private void InitConstructor()
  418. {
  419. //WaitForInit();
  420. if (!cancel)
  421. {
  422. Data = new ConcurrentDictionary<Enum, Menu_Base>();
  423. Init();
  424. skipdata = true;
  425. Refresh();
  426. skipdata = false;
  427. }
  428. }
  429. #endregion Methods
  430. #region Structs
  431. public struct BoxReturn
  432. {
  433. #region Fields
  434. public Point Cursor;
  435. public Rectangle Font;
  436. public Rectangle HotSpot;
  437. #endregion Fields
  438. #region Constructors
  439. public BoxReturn(Rectangle hotSpot, Point cursor, Rectangle font)
  440. {
  441. HotSpot = hotSpot;
  442. Cursor = cursor;
  443. Font = font;
  444. }
  445. #endregion Constructors
  446. }
  447. #endregion Structs
  448. }
  449. }