Memory.cs 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Content;
  3. using Microsoft.Xna.Framework.Graphics;
  4. using OpenVIII;
  5. using OpenVIII.Core;
  6. using OpenVIII.Kernel;
  7. using System;
  8. using System.Collections.Concurrent;
  9. using System.Collections.Generic;
  10. using System.ComponentModel;
  11. using System.Diagnostics.CodeAnalysis;
  12. using System.IO;
  13. using System.Linq;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. namespace OpenVIII
  17. {
  18. /// <summary>
  19. /// Battle Speed Settings
  20. /// </summary>
  21. /// <see cref="https://gamefaqs.gamespot.com/ps/197343-final-fantasy-viii/faqs/58936"/>
  22. [SuppressMessage("ReSharper", "UnusedMember.Global")]
  23. public enum BattleSpeed : byte
  24. {
  25. Fastest = 1,
  26. Fast,
  27. Normal,
  28. Slow,
  29. Slowest,
  30. }
  31. public enum Module : sbyte
  32. {
  33. Battle = 3,
  34. BattleSwirl = 4,
  35. Field = 5,
  36. FieldDebug = -5,
  37. BattleDebug = -3,
  38. MovieTest = -9,
  39. OvertureDebug = -12,
  40. MainMenuDebug = -13,
  41. WorldDebug = -17,
  42. FaceTest = -20,
  43. IconTest = -21,
  44. CardTest = -22,
  45. FieldModelTest = -51,
  46. }
  47. public enum ScaleMode
  48. {
  49. /// <summary>
  50. /// scale object to have the same height as viewport
  51. /// </summary>
  52. FitVertical,
  53. /// <summary>
  54. /// scale object to have the same width as viewport
  55. /// </summary>
  56. FitHorizontal,
  57. /// <summary>
  58. /// Same as FitVertical unless width is too large, then it becomes FitHorizontal
  59. /// </summary>
  60. FitBoth,
  61. /// <summary>
  62. /// fill the entire viewport
  63. /// </summary>
  64. Stretch
  65. }
  66. /// <summary>
  67. /// Speed Mod
  68. /// </summary>
  69. /// <see cref="https://gamefaqs.gamespot.com/ps/197343-final-fantasy-viii/faqs/58936"/>
  70. [SuppressMessage("ReSharper", "UnusedMember.Global")]
  71. public enum SpeedMod : byte
  72. {
  73. Stop = 0,
  74. Slow = 1,
  75. Normal = 2,
  76. Haste = 3,
  77. AlwaysFull = 0xFF //not sure what i should set this too.
  78. }
  79. [SuppressMessage("ReSharper", "UnusedMember.Global")]
  80. public static partial class Memory
  81. {
  82. #region Fields
  83. public const int PreferredViewportHeight = 720;
  84. //original resolution I am working on, therefore if user scales it we need to proportionally scale everything
  85. public const int PreferredViewportWidth = 1280;
  86. public const ScaleMode ScaleMode = OpenVIII.ScaleMode.Stretch;
  87. /// <summary>
  88. /// add. seems to work if colors are pre-blended like if they overlap the colors combined ahead of time. Used for light.
  89. /// </summary>
  90. /// <see cref="http://community.monogame.net/t/solved-custom-blendstate-advice/11006"/>
  91. public static readonly BlendState BlendStateAdd = new BlendState
  92. {
  93. ColorWriteChannels = ColorWriteChannels.Blue | ColorWriteChannels.Green | ColorWriteChannels.Red,
  94. ColorSourceBlend = Blend.One,
  95. //AlphaSourceBlend = Blend.One,
  96. ColorDestinationBlend = Blend.One,
  97. //AlphaDestinationBlend = Blend.One,
  98. ColorBlendFunction = BlendFunction.Add
  99. };
  100. /// <summary>
  101. /// untested add with blend factor. You set the GraphicsDevice.BlendFactor before drawing.
  102. /// </summary>
  103. public static readonly BlendState BlendStateAddBlendFactor = new BlendState
  104. {
  105. ColorWriteChannels = ColorWriteChannels.Blue | ColorWriteChannels.Green | ColorWriteChannels.Red,
  106. ColorSourceBlend = Blend.BlendFactor,
  107. //AlphaSourceBlend = Blend.One,
  108. ColorDestinationBlend = Blend.One,
  109. //AlphaDestinationBlend = Blend.One,
  110. ColorBlendFunction = BlendFunction.Add
  111. };
  112. public static readonly BlendState BlendStateBasicAdd = new BlendState()
  113. {
  114. ColorSourceBlend = Blend.SourceColor,
  115. ColorDestinationBlend = Blend.DestinationColor,
  116. ColorBlendFunction = BlendFunction.Add,
  117. AlphaSourceBlend = Blend.SourceAlpha,
  118. AlphaDestinationBlend = Blend.DestinationAlpha,
  119. AlphaBlendFunction = BlendFunction.Add
  120. };
  121. public static readonly BlendState BlendStateForceDraw = new BlendState()
  122. {
  123. ColorSourceBlend = Blend.SourceColor,
  124. ColorDestinationBlend = Blend.SourceColor,
  125. ColorBlendFunction = BlendFunction.Add,
  126. AlphaSourceBlend = Blend.SourceAlpha,
  127. AlphaDestinationBlend = Blend.DestinationAlpha,
  128. AlphaBlendFunction = BlendFunction.Add,
  129. };
  130. /// <summary>
  131. /// subtract. Used for windows/glass makes color darker of things behind this layer.
  132. /// </summary>
  133. /// <see cref="http://community.monogame.net/t/solved-custom-blendstate-advice/11006"/>
  134. public static readonly BlendState BlendStateSubtract = new BlendState
  135. {
  136. ColorWriteChannels = ColorWriteChannels.Blue | ColorWriteChannels.Green | ColorWriteChannels.Red,
  137. ColorSourceBlend = Blend.One,
  138. //AlphaSourceBlend = Blend.One,
  139. ColorDestinationBlend = Blend.One,
  140. //AlphaDestinationBlend = Blend.One,
  141. ColorBlendFunction = BlendFunction.ReverseSubtract
  142. };
  143. public static readonly Dictionary<MusicId, List<string>> DicMusic = new Dictionary<MusicId, List<string>>();
  144. public static Card.Game CardGame;
  145. public static Cards Cards;
  146. public static ContentManager Content;
  147. public static GraphicModes CurrentGraphicMode;
  148. public static IReadOnlyDictionary<byte, FF8String> DrawPointMagic = new Dictionary<byte, FF8String>()
  149. {
  150. {0, "Cure - Balamb Garden courtyard"},
  151. {1, "Blizzard - Balamb Garden training center"},
  152. {2, "Full-Life - Balamb Garden MD level"},
  153. {3, "Esuna - Balamb Garden library next to the book shelf"},
  154. {4, "Demi - Balamb Garden cafeteria (only during Garden Riot)"},
  155. {5, "Bio - Balamb Garden B2 floor"},
  156. {6, "Thunder - Balamb outside junk shop"},
  157. {7, "Cure - Balamb harbor"},
  158. {8, "Fire - Fire Cavern"},
  159. {9, "Silence - Dollet town square"},
  160. {10, "Blind - Dollet Communications Tower"},
  161. {11, "Scan - Timber Pub Aurora back alley"},
  162. {12, "Cure - Timber outside the pub"},
  163. {13, "Blizzaga - Timber Maniacs Building left room"},
  164. {14, "Haste - Galbadia Garden lobby"},
  165. {15, "Life - Galbadia Garden changing rooms"},
  166. {16, "Shell - Galbadia Garden courtyard"},
  167. {17, "Protect - Galbadia Garden ice rink"},
  168. {18, "Double - Galbadia Garden auditorium"},
  169. {19, "Aura - Outside Galbadia Garden during Garden war"},
  170. {20, "Cure - Timber forests in a Laguna dream"},
  171. {21, "Water - Timber forests in a Laguna dream"},
  172. {22, "Thundara - Deling City park"},
  173. {23, "Zombie - Deling City Sewers"},
  174. {24, "Esuna - Deling City Sewers"},
  175. {25, "Bio - Deling City Sewers"},
  176. {26, "Fira"},
  177. {27, "Berserk - D-District Prison Floor 9 - right cell"},
  178. {28, "Thundaga - D-District Prison Floor 11 - right cell"},
  179. {29, "Aero - Outside D-District Prison"},
  180. {30, "Blizzara - Missile Base - control room"},
  181. {31, "Blind - Missile Base room with G-Soldiers who ask to deliver a message"},
  182. {32, "Full-Life - Missile Base - silo room"},
  183. {33, "Drain - Winhill road south from town square"},
  184. {34, "Dispel - Winhill town square"},
  185. {35, "Curaga - Winhill Laguna's room in the dream"},
  186. {36, "Reflect - Winhill east road"},
  187. {37, "Protect - Tomb of the Unknown King - outside"},
  188. {38, "Float - Tomb of the Unknown King - north room"},
  189. {39, "Cura - Tomb of the Unknown King - east room"},
  190. {40, "Haste - Fishermans Horizon abandoned train station"},
  191. {41, "Shell - Fishermans Horizon junk shop"},
  192. {42, "Regen - Fishermans Horizon overlooking the sun panel"},
  193. {43, "Full-Life - Fishermans Horizon Master Fisherman's fishing spot"},
  194. {44, "Ultima - Fishermans Horizon mayor's house"},
  195. {45, "Thundaga - Great Salt Lake past the dinosaur skeleton"},
  196. {46, "Meteor - Great Salt Lake dinosaur skeleton"},
  197. {47, "Curaga - Esthar city streets near city entrance"},
  198. {48, "Blizzard - Esthar outside palace"},
  199. {49, "Quake - Esthar outside Odine's Lab"},
  200. {50, "Tornado - Esthar shopping mall"},
  201. {51, "Double - Esthar Odine's Lab in a Laguna dream"},
  202. {52, "Pain"},
  203. {53, "Flare - Esthar Odine's Lab in a Laguna dream"},
  204. {54, "Stop - Sorceress Memorial"},
  205. {55, "Stop"},
  206. {56, "Life - Tears' Point entrance"},
  207. {57, "Reflect - Tears' Point middle"},
  208. {58, "Death - Lunatic Pandora Laboratory in a Laguna dream"},
  209. {59, "Holy - Lunatic Pandora near Elevator #1"},
  210. {60, "Silence - Lunatic Pandora"},
  211. {61, "Ultima - Lunatic Pandora"},
  212. {62, "Confuse"},
  213. {63, "Break - Lunatic Pandora on the way to fight Adel"},
  214. {64, "Meteor - Lunatic Pandora entrance"},
  215. {65, "Curaga - Lunatic Pandora elevator room"},
  216. {66, "Slow"},
  217. {67, "Curaga - Edea's Orphanage"},
  218. {68, "Flare"},
  219. {69, "Holy"},
  220. {70, "Sleep - Centra Excavation Site"},
  221. {71, "Confuse - Centra Excavation Site"},
  222. {72, "Aero - Centra Ruins right ladder after the lift"},
  223. {73, "Drain - Centra Ruins platform after the first staircase"},
  224. {74, "Pain - Centra Ruins next to the dome"},
  225. {75, "Thundaga - Trabia Garden in front of the statue"},
  226. {76, "Zombie - Trabia Garden cemetery"},
  227. {77, "Aura - Trabia Garden stage"},
  228. {78, "Ultima - Shumi Village - above ground"},
  229. {79, "Blizzaga - Shumi Village - outside elder's house"},
  230. {80, "Firaga - Shumi Village workshop"},
  231. {81, "Tornado"},
  232. {82, "Holy - White SeeD Ship"},
  233. {83, "Cura - Ragnarok room with a red Propagator"},
  234. {84, "Life - Ragnarok hangar upstairs"},
  235. {85, "Full-Life - Ragnarok room with save point"},
  236. {86, "Dispel - Deep Sea Research Center second level"},
  237. {87, "Esuna - Deep Sea Research Center secret room"},
  238. {88, "Triple - Deep Sea Research Center third screen on the way to Ultima Weapon's lair"},
  239. {89, "Ultima - Deep Sea Research Center fifth screen on the way to Ultima Weapon's lair"},
  240. {90, "Meltdown - Lunar Base room before the escape pods"},
  241. {91, "Meteor - Lunar Base Ellone's room"},
  242. {92, "Haste"},
  243. {93, "Slow"},
  244. {94, "Curaga"},
  245. {95, "Life"},
  246. {96, "Stop"},
  247. {97, "Regen"},
  248. {98, "Double"},
  249. {99, "Triple"},
  250. {100, "Flare - Ultimecia Castle outside"},
  251. {101, "Curaga - Ultimecia Castle storage room"},
  252. {102, "Cura - Ultimecia Castle passageway"},
  253. {103, "Scan"},
  254. {104, "Esuna"},
  255. {105, "Slow - Ultimecia Castle courtyard"},
  256. {106, "Dispel - Ultimecia Castle chapel"},
  257. {107, "Stop - Ultimecia Castle clock tower"},
  258. {108, "Life"},
  259. {109, "Flare"},
  260. {110, "Aura - Ultimecia Castle wine cellar"},
  261. {111, "Holy - Ultimecia Castle treasure room"},
  262. {112, "Meteor"},
  263. {113, "Meltdown - Ultimecia Castle art gallery"},
  264. {114, "Ultima - Ultimecia Castle armory"},
  265. {115, "Full-Life - Ultimecia Castle prison"},
  266. {116, "Triple"},
  267. {117, "Fire"},
  268. {118, "Fire"},
  269. {119, "Fire"},
  270. {120, "Fire"},
  271. {121, "Fire"},
  272. {122, "Fire"},
  273. {123, "Fire"},
  274. {124, "Fire"},
  275. {125, "Fire"},
  276. {126, "Fire"},
  277. {127, "Fire"},
  278. {128, "Cure"},
  279. {129, "Esuna"},
  280. {130, "Thunder"},
  281. {131, "Fira"},
  282. {132, "Thundara"},
  283. {133, "Blizzara"},
  284. {134, "Blizzard"},
  285. {135, "Fire"},
  286. {136, "Cure"},
  287. {137, "Water"},
  288. {138, "Cura"},
  289. {139, "Esuna"},
  290. {140, "Scan"},
  291. {141, "Shell"},
  292. {142, "Haste"},
  293. {143, "Aero"},
  294. {144, "Bio"},
  295. {145, "Life"},
  296. {146, "Demi"},
  297. {147, "Protect"},
  298. {148, "Holy"},
  299. {149, "Thundaga"},
  300. {150, "Stop"},
  301. {151, "Firaga"},
  302. {152, "Regen"},
  303. {153, "Blizzaga"},
  304. {154, "Confuse"},
  305. {155, "Flare"},
  306. {156, "Dispel"},
  307. {157, "Slow"},
  308. {158, "Quake"},
  309. {159, "Curaga"},
  310. {160, "Tornado"},
  311. {161, "Full-Life"},
  312. {162, "Reflect"},
  313. {163, "Aura"},
  314. {164, "Quake"},
  315. {165, "Double"},
  316. {166, "Break"},
  317. {167, "Meteor"},
  318. {168, "Ultima"},
  319. {169, "Triple"},
  320. {170, "Confuse"},
  321. {171, "Blind"},
  322. {172, "Quake"},
  323. {173, "Sleep"},
  324. {174, "Silence"},
  325. {175, "Flare"},
  326. {176, "Death"},
  327. {177, "Drain"},
  328. {178, "Pain"},
  329. {179, "Berserk"},
  330. {180, "Float"},
  331. {181, "Zombie"},
  332. {182, "Meltdown"},
  333. {183, "Ultima"},
  334. {184, "Tornado"},
  335. {185, "Quake"},
  336. {186, "Meteor"},
  337. {187, "Holy"},
  338. {188, "Flare"},
  339. {189, "Aura"},
  340. {190, "Ultima"},
  341. {191, "Triple"},
  342. {192, "Full-Life"},
  343. {193, "Tornado"},
  344. {194, "Quake"},
  345. {195, "Meteor"},
  346. {196, "Holy"},
  347. {197, "Flare"},
  348. {198, "Aura"},
  349. {199, "Ultima"},
  350. {200, "Triple"},
  351. {201, "Full-Life"},
  352. {202, "Tornado"},
  353. {203, "Quake"},
  354. {204, "Meteor"},
  355. {205, "Holy"},
  356. {206, "Flare"},
  357. {207, "Aura"},
  358. {208, "Ultima"},
  359. {209, "Triple"},
  360. {210, "Full-Life"},
  361. {211, "Ultima"},
  362. {212, "Meteor"},
  363. {213, "Holy"},
  364. {214, "Flare"},
  365. {215, "Aura"},
  366. {216, "Ultima"},
  367. {217, "Triple"},
  368. {218, "Full-Life"},
  369. {219, "Meteor"},
  370. {220, "Holy"},
  371. {221, "Triple"},
  372. {222, "Aura"},
  373. {223, "Ultima"},
  374. {224, "Triple"},
  375. {225, "Full-Life"},
  376. {226, "Meteor"},
  377. {227, "Holy"},
  378. {228, "Flare"},
  379. {229, "Aura"},
  380. {230, "Ultima"},
  381. {231, "Triple"},
  382. {232, "Full-Life"},
  383. {233, "Meteor"},
  384. {234, "Triple"},
  385. {235, "Flare"},
  386. {236, "Aura"},
  387. {237, "Ultima"},
  388. {238, "Triple"},
  389. {239, "Full-Life"},
  390. {240, "Meteor"},
  391. {241, "Holy"},
  392. {242, "Flare"},
  393. {243, "Aura"},
  394. {244, "Ultima"},
  395. {245, "Blizzard"},
  396. {246, "Cure"},
  397. {247, "Dispel"},
  398. {248, "Confuse"},
  399. {249, "Meteor"},
  400. {250, "Double"},
  401. {251, "Aura"},
  402. {252, "Holy"},
  403. {253, "Flare"},
  404. {254, "Ultima"},
  405. {255, "Scan"}
  406. };
  407. public static bool EnableDumpingData = false;
  408. public static Faces Faces;
  409. public static List<Task> FfccLeftOverTask = new List<Task>();
  410. public static Font Font;
  411. public static GraphicsDeviceManager Graphics;
  412. public static Icons Icons;
  413. public static Core.ImGuiRenderer ImGui;
  414. public static Task InitTask;
  415. public static Input2 Input2;
  416. public static bool IsActive = true;
  417. public static KernelBin KernelBin;
  418. public static Extended.Languages Languages = Extended.Languages.en;
  419. public static Log Log;
  420. public static ConcurrentQueue<Action> MainThreadOnlyActions;
  421. /// <summary>
  422. /// Random number generator seeded with time.
  423. /// </summary>
  424. /// <remarks>creates global random class for all sort of things</remarks>
  425. public static Random Random;
  426. /// <summary>
  427. /// Battle music pointer. Set by SET BATTLE MUSIC in field module or by world module. Default=6
  428. /// </summary>
  429. public static int SetBattleMusic = 6;
  430. public static VertexPositionTexture[] ShadowGeometry;
  431. public static Texture2D ShadowTexture;
  432. public static IReadOnlyDictionary<ushort, FF8String> SongsOGG = new Dictionary<ushort, FF8String>()
  433. {
  434. {0,"Lose" },
  435. {1,"The Winner" },
  436. {4,"Never Look Back" },
  437. {5,"Don't Be Afraid" },
  438. {7,"Dead End" },
  439. {8,"Starting Up" },
  440. {9,"Intruders" },
  441. {12,"Don't Be Afraid (X-ATM092)" },
  442. {13,"Force Your Way" },
  443. {14,"FITHOS LUSEC WECOS VINOSEC (No Intro)" },
  444. {15,"Unrest" },
  445. {16,"The Stage is Set" },
  446. {17,"The Landing" },
  447. {18,"Love Grows" },
  448. {19,"Waltz for the Moon" },
  449. {20,"Ami" },
  450. {21,"Find Your Way" },
  451. {22,"Julia" },
  452. {23,"FITHOS LUSEC WECOS VINOSEC" },
  453. {24,"SeeD" },
  454. {25,"Tell Me" },
  455. {26,"Balamb GARDEN" },
  456. {27,"Fear" },
  457. {28,"Dance with the Balamb-Fish" },
  458. {29,"Cactus Jack" },
  459. {35,"The Mission" },
  460. {36,"SUCCESSION OF WITCHES" },
  461. {41,"Blue Fields" },
  462. {42,"Breezy" },
  463. {43,"Concert" },
  464. {46,"Timber Owls" },
  465. {47,"Fragments of Memories" },
  466. {48,"Fisherman's Horizon" },
  467. {49,"Heresy" },
  468. {51,"My Mind" },
  469. {52,"Where I Belong" },
  470. {53,"Starting Up (Looped)" },
  471. {54,"Truth" },
  472. {55,"Trust Me" },
  473. {56,"Galbadia GARDEN" },
  474. {57,"Martial Law" },
  475. {58,"Under Her Control" },
  476. {59,"Only a Plank Between One and Perdition" },
  477. {60,"Junction" },
  478. {61,"Roses and Wine" },
  479. {62,"The Man with the Machine Gun" },
  480. {63,"A Sacrifice" },
  481. {64,"ODEKA ke Chocobo" },
  482. {65,"Drifting" },
  483. {66,"Wounded" },
  484. {67,"Jailed" },
  485. {68,"Retaliation" },
  486. {69,"The Oath" },
  487. {70,"Shuffle or Boogie" },
  488. {71,"Rivals" },
  489. {72,"Blue Sky" },
  490. {73,"Premonition" },
  491. {75,"Galbadia GARDEN (No Intro)" },
  492. {76,"Maybe I'm a Lion" },
  493. {77,"The Castle" },
  494. {78,"Movin'" },
  495. {79,"Overture" },
  496. {80,"The Spy" },
  497. {81,"Mods de Chocobo" },
  498. {82,"The Salt Flats" },
  499. {83,"The Residents" },
  500. {84,"Lunatic Pandora" },
  501. {85,"Silence and Motion" },
  502. {86,"Tears of the Moon" },
  503. {88,"Tears of the Moon (Alternate)" },
  504. {89,"Ride On" },
  505. {90,"The Legendary Beast" },
  506. {91,"Slide Show Part 1" },
  507. {92,"Slide Show Part 2" },
  508. {93,"The Extreme" },
  509. {96,"The Successor" },
  510. {97,"Compression of Time" },
  511. {99,"The Landing (No Intro)" },
  512. {512,"The Loser" },
  513. {513,"Eyes on Me" },
  514. {514,"Irish Jig (Concert)" },
  515. {515,"Eyes on Me (Concert)" },
  516. {516,"Movin' (No Intro)" },
  517. {517,"The Landing (Alternate)" },
  518. {518,"The Landing (Alternate - No Intro)" },
  519. {519,"Galbadia GARDEN (Alternate)" },
  520. };
  521. public static IReadOnlyDictionary<ushort, string> SongsSGT = new Dictionary<ushort, string>()
  522. {
  523. {0, "Lose" },
  524. {1, "Win" },
  525. {2, "Open" },
  526. {3, "Combat" },
  527. {4, "Run" },
  528. {5, "Battle" },
  529. {6, "Funsui" },
  530. {7, "End" },
  531. {8, "Antenna" },
  532. {9, "Waiting" },
  533. {10, "Ante " },
  534. {11, "Wind" },
  535. {12, "Crab" },
  536. {13, "Battle2" },
  537. {14, "Friend2" },
  538. {15, "Fuan2" },
  539. {16, "March2" },
  540. {17, "Land" },
  541. {18, "Julia" },
  542. {19, "Waltz" },
  543. {20, "Friend " },
  544. {21, "Dungeon" },
  545. {22, "Pianosolo" },
  546. {23, "Parade" },
  547. {24, "March1" },
  548. {25, "Secret" },
  549. {26, "Garden" },
  550. {27, "Fuan " },
  551. {28, "Polka2" },
  552. {29, "Anthem" },
  553. {30, "FlangChorus" },
  554. {31, "DubChorus" },
  555. {32, "SoloChorus" },
  556. {33, "FemaleChorus" },
  557. {34, "Chorus" },
  558. {35, "M7F5" },
  559. {36, "Sorceress" },
  560. {37, "Reet" },
  561. {38, "Soyo" },
  562. {39, "Rouka" },
  563. {40, "Night" },
  564. {41, "Field" },
  565. {42, "Guitar" },
  566. {43, "Concert" },
  567. {44, "Sea" },
  568. {45, "Silent" },
  569. {46, "Resistance" },
  570. {47, "Kaiso" },
  571. {48, "Horizon" },
  572. {49, "Master" },
  573. {50, "Battle2" },
  574. {51, "Rinoa" },
  575. {52, "Trabia" },
  576. {53, "Horizon2" },
  577. {54, "Truth" },
  578. {55, "Prison" },
  579. {56, "GalbadiaGarden" },
  580. {57, "Timber" },
  581. {58, "Galbadia " },
  582. {59, "Pinchi" },
  583. {60, "Scene1" },
  584. {61, "Pub" },
  585. {62, "Bat3" },
  586. {63, "Stage" },
  587. {64, "Choco" },
  588. {65, "White" },
  589. {66, "Majomv" },
  590. {67, "Musho" },
  591. {68, "Missile" },
  592. {69, "Speech" },
  593. {70, "Card" },
  594. {71, "Gomon" },
  595. {72, "Soto" },
  596. {73, "Majobat" },
  597. {74, "Train" },
  598. {75, "Garden2" },
  599. {76, "Bossbat2" },
  600. {77, "LastDungeon" },
  601. {78, "Gafly" },
  602. {79, "Demo" },
  603. {80, "Spy" },
  604. {81, "VoiceDeChocobo" },
  605. {82, "Salt" },
  606. {83, "Alien" },
  607. {84, "Sekichu" },
  608. {85, "Esta" },
  609. {86, "Moonmv" },
  610. {87, "Mdmotor" },
  611. {88, "Moonmv2" },
  612. {89, "Fly" },
  613. {90, "BossBat1" },
  614. {91, "Rag1" },
  615. {92, "Rag2" },
  616. {93, "LastBoss" },
  617. {94, "Lastwhite" },
  618. {95, "Lasbl" },
  619. {96, "Keisho" },
  620. {97, "Compression" },
  621. };
  622. public static SpriteBatch SpriteBatch;
  623. public static Strings Strings;
  624. public static int Year = 2013;
  625. private static ushort _currentMusic;
  626. // need to dynamically detect if 2000/2013/2019, maybe need 2000 1.2 as well.
  627. private static string _ff8Dir;
  628. private static string _ff8DirData;
  629. private static int _mainThreadID;
  630. private static Module _module = Module.OvertureDebug;
  631. private static ushort _previousMusic;
  632. /// <summary>
  633. /// Stores current save state. When you save this is wrote. When you load this is replaced.
  634. /// </summary>
  635. private static Saves.Data _state = new Saves.Data();
  636. #endregion Fields
  637. #region Events
  638. public static event EventHandler<Module> ModuleChangeEvent;
  639. #endregion Events
  640. #region Enums
  641. public enum GraphicModes
  642. {
  643. OpenGL,
  644. DirectX
  645. };
  646. #endregion Enums
  647. #region Properties
  648. public static string[] Arguments { get; set; }
  649. public static float BattleStageScale { get; internal set; } = 100f;
  650. public static float CameraScale { get; internal set; } = 100f;
  651. public static Point Center => new Point(Graphics.GraphicsDevice.Viewport.Width / 2, Graphics.GraphicsDevice.Viewport.Height / 2);
  652. public static BattleSpeed CurrentBattleSpeed => State?.Configuration?.BattleSpeed ?? BattleSpeed.Normal;
  653. public static TimeSpan DateTimeNow => TimeSpan.FromTicks(DateTime.Now.Ticks);
  654. public static TimeSpan ElapsedGameTime => GameTime?.ElapsedGameTime ?? TimeSpan.Zero;
  655. /// <summary>
  656. /// Active battle encounter. Set by field or battle module. You shouldn't change it in-battle.
  657. /// </summary>
  658. public static Battle.Encounters Encounters { get; set; }
  659. public static float EnemyCoordinateScale { get; internal set; } = 100f;
  660. public static string FF8Dir
  661. {
  662. get => _ff8Dir;
  663. private set => _ff8Dir = value;
  664. }
  665. public static string FF8DirData
  666. {
  667. get => _ff8DirData;
  668. private set => _ff8DirData = value;
  669. }
  670. public static string FF8DirDataLang { get; private set; }
  671. /// <summary>
  672. /// Game time value. Could be null check for null.
  673. /// </summary>
  674. public static GameTime GameTime { get; set; }
  675. public static bool Initiated { get; private set; }
  676. public static Saves.Data InitState { get; private set; }
  677. public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == _mainThreadID;
  678. public static bool IsMouseVisible { get; set; } = false;
  679. public static Magazine Magazines { get; private set; }
  680. public static ItemsInMenu MItems { get; private set; }
  681. public static Module Module
  682. {
  683. get => _module; set
  684. {
  685. if (_module == value) return;
  686. _module = value;
  687. ModuleChangeEvent?.Invoke(null, value);
  688. }
  689. }
  690. public static ushort MusicIndex
  691. {
  692. get
  693. {
  694. if (DicMusic.Count > 0)
  695. {
  696. var max = (ushort)DicMusic.Keys.Max();
  697. var min = (ushort)DicMusic.Keys.Min();
  698. while ((_previousMusic > _currentMusic || _previousMusic == ushort.MinValue && _currentMusic == ushort.MaxValue) &&
  699. !DicMusic.ContainsKey((MusicId)_currentMusic))
  700. {
  701. if (max < _currentMusic)
  702. {
  703. _currentMusic = max;
  704. }
  705. else
  706. {
  707. _currentMusic--;
  708. }
  709. }
  710. while (DicMusic.Count > 0 && _previousMusic < _currentMusic && !DicMusic.ContainsKey((MusicId)_currentMusic))
  711. {
  712. if (max < _currentMusic)
  713. {
  714. _currentMusic = min;
  715. }
  716. else
  717. {
  718. _currentMusic++;
  719. }
  720. }
  721. return _currentMusic;
  722. }
  723. else return 0;
  724. }
  725. set
  726. {
  727. _previousMusic = _currentMusic;
  728. _currentMusic = value;
  729. }
  730. }
  731. public static Saves.Data PrevState { get; set; }
  732. public static Saves.Data State
  733. {
  734. get => _state; set
  735. {
  736. _state = value;
  737. if (_state != null)
  738. _state.LoadTime = GameTime?.TotalGameTime ?? new TimeSpan();
  739. }
  740. }
  741. /// <summary>
  742. /// If true by the end of Update() will skip the next Draw()
  743. /// </summary>
  744. public static bool SuppressDraw { get; set; }
  745. public static bool Threaded { get; private set; } = true;
  746. public static CancellationToken Token { get; private set; }
  747. public static CancellationTokenSource TokenSource { get; private set; }
  748. public static TimeSpan TotalGameTime => GameTime?.TotalGameTime ?? TimeSpan.Zero;
  749. #endregion Properties
  750. #region Methods
  751. public static void Init(GraphicsDeviceManager graphics, SpriteBatch spriteBatch, ContentManager content, string[] arguments)
  752. {
  753. if (Log == null) Log = new Log();
  754. Log.WriteLine($"{nameof(Memory)} :: {nameof(Init)}");
  755. Log.WriteLine($"{nameof(GraphicsDeviceManager)} :: {graphics}");
  756. Log.WriteLine($"{nameof(GraphicsDeviceManager)} :: {nameof(graphics.GraphicsDevice.Adapter.CurrentDisplayMode)} :: {graphics?.GraphicsDevice.Adapter.CurrentDisplayMode}");
  757. if (graphics != null)
  758. foreach (var i in graphics.GraphicsDevice.Adapter.SupportedDisplayModes)
  759. Log.WriteLine($"{nameof(GraphicsDeviceManager)} :: {nameof(graphics.GraphicsDevice.Adapter.SupportedDisplayModes)} :: {i}");
  760. //Log.WriteLine($"{nameof(GraphicsDeviceManager)} :: {graphics.GraphicsDevice.Adapter.DeviceName}");
  761. //Log.WriteLine($"{nameof(SpriteBatch)} :: {spriteBatch}");
  762. Log.WriteLine($"{nameof(ContentManager)} :: {content}");
  763. Log.WriteLine($"{nameof(Random)} :: new");
  764. Random = new Random((int)DateTime.Now.Ticks);
  765. Log.WriteLine($"{nameof(Memory)} :: {nameof(_mainThreadID)} = {nameof(Thread)} :: {nameof(Thread.CurrentThread)} :: {nameof(Thread.ManagedThreadId)} = {Thread.CurrentThread.ManagedThreadId}");
  766. _mainThreadID = Thread.CurrentThread.ManagedThreadId;
  767. Log.WriteLine($"{nameof(Memory)} :: {nameof(MainThreadOnlyActions)}");
  768. MainThreadOnlyActions = new ConcurrentQueue<Action>();
  769. FF8Dir = GameDirectoryFinder.FindRootGameDirectory();
  770. void SetData() => FF8DirData = Extended.GetUnixFullPath(Path.Combine(FF8Dir, "Data"));
  771. SetData();
  772. var languageSet = false;
  773. void setLang(string lang)
  774. {
  775. switch (lang.ToLower())
  776. {
  777. case "2":
  778. case "de":
  779. Languages = Extended.Languages.de;
  780. break;
  781. case "0":
  782. case "en":
  783. Languages = Extended.Languages.en;
  784. break;
  785. case "3":
  786. case "es":
  787. Languages = Extended.Languages.es;
  788. break;
  789. case "1":
  790. case "fr":
  791. Languages = Extended.Languages.fr;
  792. break;
  793. case "4":
  794. case "it":
  795. Languages = Extended.Languages.it;
  796. break;
  797. case "5":
  798. case "jp":
  799. Languages = Extended.Languages.jp;
  800. break;
  801. default:
  802. throw new InvalidEnumArgumentException($"{nameof(Memory)}::{nameof(Init)}::{nameof(lang)} ({lang}) is not a supported language code. (de,en,es,fr,it,jp)");
  803. }
  804. languageSet = true;
  805. }
  806. if (arguments != null && arguments.Length > 0)
  807. {
  808. IEnumerable<string[]> splitArguments = (from a in arguments
  809. where a.Contains('=')
  810. select a.Trim().Split(new[] { '=' }, 2)).OrderByDescending(x => x[0], StringComparer.OrdinalIgnoreCase);
  811. foreach (var s in splitArguments)
  812. {
  813. bool test(string @in, ref string @out)
  814. {
  815. if (!s[0].Equals(@in, StringComparison.OrdinalIgnoreCase)) return false;
  816. @out = s[1].Trim(('"'));
  817. return true;
  818. }
  819. var lang = "";
  820. if (test("dir", ref _ff8Dir)) //override ff8 directory
  821. {
  822. if (!Directory.Exists(_ff8Dir))
  823. throw new DirectoryNotFoundException(
  824. $"{nameof(Memory)}::{nameof(Init)}::{nameof(arguments)}::{nameof(_ff8Dir)} ({s[0]}) Cannot find path: \"{_ff8Dir}\"");
  825. SetData();
  826. }
  827. else if (test("data", ref _ff8DirData)) //override data folder location
  828. {
  829. if (!Directory.Exists(_ff8DirData))
  830. throw new DirectoryNotFoundException(
  831. $"{nameof(Memory)}::{nameof(Init)}::{nameof(arguments)}::{nameof(_ff8DirData)} ({s[0]}) Cannot find path: \"{_ff8DirData}\"");
  832. }
  833. else if (test("lang", ref lang)) //override language
  834. {
  835. setLang(lang);
  836. }
  837. }
  838. }
  839. Log.WriteLine($"{nameof(Memory)} :: {nameof(FF8Dir)} = {FF8Dir}");
  840. Log.WriteLine($"{nameof(Memory)} :: {nameof(FF8DirData)} = {FF8DirData}");
  841. var langDatPath = Path.Combine(FF8Dir, "lang.dat");
  842. if (!languageSet && File.Exists(langDatPath))
  843. using (var streamReader = new StreamReader(
  844. new FileStream(langDatPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), System.Text.Encoding.UTF8))
  845. {
  846. var lang = streamReader.ReadLine()?.Trim();
  847. setLang(lang);
  848. }
  849. Log.WriteLine($"{nameof(Extended)} :: {nameof(Extended.GetLanguageShort)} = {Extended.GetLanguageShort()}");
  850. var testDir = Extended.GetUnixFullPath(Path.Combine(FF8DirData, $"lang-{Extended.GetLanguageShort()}"));
  851. FF8DirDataLang = Directory.Exists(testDir) ? testDir : FF8DirData;
  852. Log.WriteLine($"{nameof(Memory)} :: {nameof(FF8DirDataLang)} = {FF8DirDataLang}");
  853. Archives.Init();
  854. Graphics = graphics;
  855. SpriteBatch = spriteBatch;
  856. Content = content;
  857. Arguments = arguments;
  858. TokenSource = new CancellationTokenSource();
  859. Token = TokenSource.Token;
  860. Threaded = false;
  861. if (Threaded)
  862. {
  863. InitTask = new Task<int>(InitTaskMethod, Token);
  864. InitTask.Start();
  865. }
  866. else
  867. InitTaskMethod(Token);
  868. }
  869. public static int InitTaskMethod(object obj)
  870. {
  871. Log.WriteLine($"{nameof(Memory)} :: {nameof(Memory)} :: {nameof(Init)}");
  872. var token = (CancellationToken)obj;
  873. if (!token.IsCancellationRequested)
  874. Strings = new Strings();
  875. // requires strings because it uses an array generated in strings.
  876. // saves data will reference kernel_bin.
  877. if (!token.IsCancellationRequested)
  878. KernelBin = KernelBin.CreateInstance();
  879. var actions = new List<Action>()
  880. {
  881. // this has a soft requirement on kernel_bin. It checks for null so should work without it.
  882. () => {MItems = ItemsInMenu.Read(); },
  883. Saves.Init,
  884. //loads all save games from steam2013 or cd2000 or steam2019 directories. first come first serve.
  885. //TODO allow choosing of which save folder to use.
  886. //this initializes the field module, it's worth to have this at the beginning
  887. Fields.Initializer.Init,
  888. //this initializes the encounters
  889. InitDebuggerBattle.Init,
  890. };
  891. if (Graphics?.GraphicsDevice != null) // all below require graphics to work. to load textures graphics device needed.
  892. {
  893. actions.AddRange(new Action[]
  894. {
  895. //this initializes the fonts and drawing system- holds fonts in-memory
  896. () => { Font = new Font(); },
  897. // card images in menu.
  898. () => { Cards = Cards.Load(); },
  899. () => { CardGame = new Card.Game(); },
  900. () => { Faces = Faces.Load(); },
  901. () => { Icons = Icons.Load(); },
  902. () => { Magazines = Magazine.Load(); }
  903. });
  904. }
  905. actions.Add(() =>
  906. {
  907. InitState = Saves.Data.LoadInitOut();
  908. State = InitState?.Clone();
  909. });
  910. var tasks = new List<Task>();
  911. if (!token.IsCancellationRequested)
  912. {
  913. if (Threaded)
  914. {
  915. tasks.AddRange(from a in actions where !token.IsCancellationRequested select Task.Run(a, token));
  916. Task.WhenAll(tasks.ToArray()).GetAwaiter().GetResult();
  917. }
  918. else
  919. foreach (var a in actions.Where(a => !token.IsCancellationRequested))
  920. {
  921. a.Invoke();
  922. }
  923. if (Graphics?.GraphicsDevice != null) // all below require graphics to work. to load textures graphics device needed.
  924. {
  925. // requires font, faces, and icons. currently cards only used in debug menu. will
  926. // have support for cards when added to menu.
  927. if (!token.IsCancellationRequested)
  928. Menu.InitStaticMembers();
  929. }
  930. }
  931. //EXE_Offsets test = new EXE_Offsets();
  932. Initiated = true;
  933. //ArchiveBase.PurgeCache();//remove files probably no longer needed.
  934. return 0;
  935. }
  936. public static bool ProcessActions(Action[] actions)
  937. {
  938. if (Threaded)
  939. {
  940. var tasks = new List<Task>(actions.Length);
  941. actions.ForEach(x => { if (!Token.IsCancellationRequested) tasks.Add(Task.Run(x, Token)); });
  942. //Some code that cannot be threaded on init.
  943. if (!Task.WaitAll(tasks.ToArray(), 10000))
  944. throw new TimeoutException("Task took too long!");
  945. }
  946. else actions.ForEach(x => x.Invoke());
  947. return !Token.IsCancellationRequested;
  948. }
  949. public static bool[] ProcessFunctions(Func<bool>[] functions)
  950. {
  951. if (!Threaded) return functions.Select(x => x.Invoke()).ToArray();
  952. //var tasks = new List<Task<bool>>(functions.Length);
  953. //functions.ForEach(x => { if (!Token.IsCancellationRequested) tasks.Add(Task.Run(x, Token)); });
  954. var tasks = functions.Select(x => Task.Run(x, Token));
  955. //Some code that cannot be threaded on init.
  956. return Task.WhenAll(tasks.ToArray()).GetAwaiter().GetResult();
  957. //if (!Task.WaitAll(tasks.ToArray(), 10000))
  958. // throw new TimeoutException("Task took too long!");
  959. }
  960. public static Vector2 Scale(float width = PreferredViewportWidth, float height = PreferredViewportHeight, ScaleMode scaleMode = ScaleMode, int targetX = 0, int targetY = 0)
  961. {
  962. if (targetX == 0)
  963. targetX = Graphics.GraphicsDevice.Viewport.Width;
  964. if (targetY == 0)
  965. targetY = Graphics.GraphicsDevice.Viewport.Height;
  966. var h = targetX / width;
  967. var v = targetY / height;
  968. switch (scaleMode)
  969. {
  970. case ScaleMode.FitHorizontal:
  971. return new Vector2(h, h);
  972. case ScaleMode.FitVertical:
  973. return new Vector2(v, v);
  974. case ScaleMode.FitBoth:
  975. return (v * width > targetX) ? new Vector2(h, h) : new Vector2(v, v);
  976. case ScaleMode.Stretch:
  977. return new Vector2(h, v);
  978. default:
  979. throw new ArgumentOutOfRangeException(nameof(scaleMode), scaleMode, null);
  980. }
  981. }
  982. //ogg and sgt files have same 3 digit prefix.
  983. public static void SpriteBatchEnd() => SpriteBatch.End();
  984. public static void SpriteBatchStart(BlendState bs = null, SamplerState ss = null) =>
  985. SpriteBatch.Begin(SpriteSortMode.Deferred, bs ?? BlendState.AlphaBlend, ss ?? SamplerState.PointClamp, Graphics.GraphicsDevice.DepthStencilState);
  986. public static void SpriteBatchStartAlpha(SpriteSortMode sortMode = SpriteSortMode.Deferred, SamplerState ss = null, Matrix? tm = null) =>
  987. SpriteBatch.Begin(sortMode: sortMode, blendState: BlendState.AlphaBlend, samplerState: ss ?? SamplerState.PointClamp, transformMatrix: tm);
  988. public static void SpriteBatchStartStencil(SamplerState ss = null) =>
  989. SpriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Opaque, ss ?? SamplerState.PointClamp, Graphics.GraphicsDevice.DepthStencilState);
  990. public static void Update()
  991. {
  992. Action a = null;
  993. while (IsMainThread && (MainThreadOnlyActions?.TryDequeue(out a) ?? false))
  994. { a.Invoke(); }
  995. for (var i = 0; IsMainThread && i < FfccLeftOverTask.Count; i++)
  996. {
  997. if (!FfccLeftOverTask[i].IsCompleted) continue;
  998. FfccLeftOverTask[i].Dispose();
  999. FfccLeftOverTask.RemoveAt(i--);
  1000. }
  1001. }
  1002. #endregion Methods
  1003. #region Classes
  1004. public static class FieldHolder
  1005. {
  1006. #region Fields
  1007. //public static string[] MapList;
  1008. public static ushort FieldID = 756;
  1009. public static string[] Fields;
  1010. #endregion Fields
  1011. //public static int[] FieldMemory;
  1012. #region Methods
  1013. public static string GetString(ushort? inputFieldID = null) => Fields?.ElementAtOrDefault(inputFieldID ?? FieldID);
  1014. #endregion Methods
  1015. }
  1016. #endregion Classes
  1017. }
  1018. }