troptrop

code5

May 22nd, 2023
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.80 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5. using System.IO;
  6. using System.Reflection;
  7.  
  8. using BizHawk.Client.Common;
  9. using BizHawk.Client.EmuHawk;
  10. using BizHawk.Emulation.Common;
  11.  
  12. namespace PokemonGBTASTool
  13. {
  14. [ExternalTool("Pokemon Link GB TAS Tool", Description = "A tool to help with TASing Link GB Pokemon games.")]
  15. [ExternalToolApplicability.SingleSystem(CoreSystem.GameBoyLink)]
  16. [ExternalToolEmbeddedIcon("PokemonGBTASTool.res.icon.ico")]
  17. public partial class PokemonGBTASToolForm : ToolFormBase, IExternalToolForm
  18. {
  19. public ApiContainer? ApiContainer { get; set; }
  20. private ApiContainer APIs => ApiContainer ?? throw new NullReferenceException();
  21.  
  22. private CrystalSYM CrystalSym { get; }
  23. private SilverSYM SilverSym { get; }
  24. private YellowSYM YellowSym { get; }
  25.  
  26. private List<Callbacks> Callbacks { get; } = new(3);
  27.  
  28. private Gen2Callbacks CrystalCBs => Callbacks[0] as Gen2Callbacks ?? throw new NullReferenceException();
  29. private Gen2Callbacks SilverCBs => Callbacks[1] as Gen2Callbacks ?? throw new NullReferenceException();
  30. private Gen1Callbacks YellowCBs => Callbacks[2] as Gen1Callbacks ?? throw new NullReferenceException();
  31.  
  32. private PokemonData PkmnData { get; }
  33.  
  34. protected override string WindowTitleStatic => "Pokemon GB TAS Tool";
  35.  
  36. public PokemonGBTASToolForm()
  37. {
  38. InitializeComponent();
  39. CrystalSym = new CrystalSYM(ShowMessage, "P1 ");
  40. SilverSym = new SilverSYM(ShowMessage, "P2 ");
  41. YellowSym = new YellowSYM(ShowMessage, "P3 ");
  42. PkmnData = new PokemonData(ShowMessage);
  43. Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream("PokemonGBTASTool.res.icon.ico"));
  44. Closing += (sender, args) => APIs.EmuClient.SetGameExtraPadding(0, 0, 0, 0);
  45. }
  46.  
  47. /// <remarks>This is called once when the form is opened, and every time a new movie session starts.</remarks>
  48. public override void Restart()
  49. {
  50. if (string.IsNullOrEmpty(APIs.GameInfo.GetBoardType()))
  51. {
  52. ShowMessage("Only GambatteLink is supported with this tool");
  53. Close();
  54. }
  55. checkedListBox1.Items.Clear();
  56. checkedListBox1.Items.AddRange(Gen2Callbacks.BreakpointList);
  57. checkedListBox1.CheckOnClick = true;
  58. checkedListBox2.Items.Clear();
  59. checkedListBox2.Items.AddRange(Gen2Callbacks.BreakpointList);
  60. checkedListBox2.CheckOnClick = true;
  61. checkedListBox3.Items.Clear();
  62. checkedListBox3.Items.AddRange(Gen1Callbacks.BreakpointList);
  63. checkedListBox3.CheckOnClick = true;
  64. comboBox1.SelectedIndex = 0;
  65. Callbacks.Clear();
  66. Callbacks.Add(new Gen2Callbacks(APIs, CrystalSym, () => checkBox1.Checked && comboBox1.SelectedIndex is 0, "P1 "));
  67. Callbacks.Add(new Gen2Callbacks(APIs, SilverSym, () => checkBox1.Checked && comboBox1.SelectedIndex is 1, "P2 "));
  68. Callbacks.Add(new Gen1Callbacks(APIs, YellowSym, () => checkBox1.Checked && comboBox1.SelectedIndex is 2, "P3 "));
  69. APIs.EmuClient.SetGameExtraPadding(0, 0, 105, 0);
  70. }
  71.  
  72. private byte CpuReadU8(string symbol, SYM GBSym) => (byte)APIs.Memory.ReadU8(GBSym.GetSYMDomAddr(symbol), GBSym.GetSYMDomain(symbol));
  73.  
  74. private ushort CpuReadBigU16(string symbol, SYM GBSym)
  75. {
  76. APIs.Memory.SetBigEndian();
  77. return (ushort)APIs.Memory.ReadU16(GBSym.GetSYMDomAddr(symbol), GBSym.GetSYMDomain(symbol));
  78. }
  79.  
  80. private string GetEnemyMonName(SYM GBSym) => PkmnData.GetPokemonSpeciesName(CpuReadU8("wEnemyMonSpecies", GBSym), GBSym.IsGen2);
  81. private string GetEggMon(SYM GBSym) => PkmnData.GetPokemonSpeciesName(CpuReadU8("wEggMonSpecies", GBSym), GBSym.IsGen2);
  82. private string OddEggSpecies(SYM GBSym) => PkmnData.GetPokemonSpeciesName(CpuReadU8("wOddEggSpecies", GBSym), GBSym.IsGen2);
  83. private string GetEnemyMonMove(SYM GBSym) => PkmnData.GetPokemonMoveName(CpuReadU8(GBSym.IsGen2 ? "wCurEnemyMove" : "wEnemySelectedMove", GBSym));
  84. private byte GetDSUM(SYM GBSym) => (byte)((CpuReadU8("hRandomAdd", GBSym) + CpuReadU8("hRandomSub", GBSym)) & 0xFF);
  85.  
  86. public override void UpdateValues(ToolFormUpdateType type)
  87. {
  88. if (type is ToolFormUpdateType.PreFrame or ToolFormUpdateType.FastPreFrame)
  89. {
  90. CrystalCBs.UpdateCallbacks(checkedListBox1, checkBox2.Checked || comboBox1.SelectedIndex is not 0);
  91. SilverCBs.UpdateCallbacks(checkedListBox2, checkBox2.Checked || comboBox1.SelectedIndex is not 1);
  92. YellowCBs.UpdateCallbacks(checkedListBox3, checkBox2.Checked || comboBox1.SelectedIndex is not 2);
  93. switch (comboBox1.SelectedIndex)
  94. {
  95. case 0:
  96. {
  97. APIs.Gui.Text(5, 5, $"{GetEnemyMonName(CrystalSym)}'s Max HP: {CpuReadBigU16("wEnemyMonMaxHP", CrystalSym)}", Color.White, "topright");
  98. APIs.Gui.Text(5, 25, $"{GetEnemyMonName(CrystalSym)}'s Cur HP: {CpuReadBigU16("wEnemyMonHP", CrystalSym)}", Color.White, "topright");
  99. APIs.Gui.Text(5, 55, $"{GetEnemyMonName(CrystalSym)}'s Move: {GetEnemyMonMove(CrystalSym)}", Color.White, "topright");
  100. APIs.Gui.Text(5, 85, $"Crit Roll: {CrystalCBs.CritRng.Roll}", Color.White, "topright");
  101. APIs.Gui.Text(5, 105, $"Crit Chance: {CrystalCBs.CritRng.Chance}", Color.White, "topright");
  102. APIs.Gui.Text(5, 135, $"Damage Roll: {CrystalCBs.DamageRng.Roll}", Color.White, "topright");
  103. APIs.Gui.Text(5, 165, $"Accuracy Roll: {CrystalCBs.AccuracyRng.Roll}", Color.White, "topright");
  104. APIs.Gui.Text(5, 185, $"Move Accuracy: {CrystalCBs.AccuracyRng.Chance}", Color.White, "topright");
  105. APIs.Gui.Text(5, 215, $"Effect Roll: {CrystalCBs.EffectRng.Roll}", Color.White, "topright");
  106. APIs.Gui.Text(5, 235, $"Effect Chance: {CrystalCBs.EffectRng.Chance}", Color.White, "topright");
  107. APIs.Gui.Text(5, 265, $"Catch Roll: {CrystalCBs.CatchRng.Roll}", Color.White, "topright");
  108. APIs.Gui.Text(5, 285, $"Catch Chance: {CrystalCBs.CatchRng.Chance}", Color.White, "topright");
  109. APIs.Gui.Text(5, 315, $"Quick Claw Roll: {CrystalCBs.QuickClawRng.Roll}", Color.White, "topright");
  110. APIs.Gui.Text(5, 345, $"Random Sub: {CpuReadU8("hRandomSub", CrystalSym)}", Color.White, "topright");
  111. APIs.Gui.Text(5, 365, $"egg: {CpuReadBigU16("wDayCareMan", CrystalSym):X7}", Color.White, "topright");
  112. APIs.Gui.Text(5, 385, $"partymon1 happiness: {CpuReadU8("wPartyMon1Happiness", CrystalSym)}", Color.White, "topright");
  113. APIs.Gui.Text(5, 405, $"partymon2 happiness: {CpuReadU8("wPartyMon2Happiness", CrystalSym)}", Color.White, "topright");
  114. APIs.Gui.Text(5, 425, $"partymon3 happiness: {CpuReadU8("wPartyMon3Happiness", CrystalSym)}", Color.White, "topright");
  115. APIs.Gui.Text(5, 445, $"partymon4 happiness: {CpuReadU8("wPartyMon4Happiness", CrystalSym)}", Color.White, "topright");
  116. APIs.Gui.Text(5, 465, $"partymon5 happiness: {CpuReadU8("wPartyMon5Happiness", CrystalSym)}", Color.White, "topright");
  117. APIs.Gui.Text(5, 485, $"partymon6 happiness: {CpuReadU8("wPartyMon6Happiness", CrystalSym)}", Color.White, "topright");
  118. APIs.Gui.Text(5, 505, $"step count: {CpuReadU8("wStepCount", CrystalSym)}", Color.White, "topright");
  119. APIs.Gui.Text(5, 525, $"egg step count: {CpuReadU8("wStepsToEgg", CrystalSym)}", Color.White, "topright");
  120. APIs.Gui.Text(5, 545, $"Coordinates: ({CpuReadU8("wXCoord", CrystalSym)} {CpuReadU8("wYCoord", CrystalSym)})", Color.White, "topright");
  121. APIs.Gui.Text(5, 565, $"{GetEnemyMonName(CrystalSym)}'s DVs: {CpuReadBigU16("wEnemyMonDVs", CrystalSym):X4}", Color.White, "topright");
  122. APIs.Gui.Text(5, 585, $"{GetEnemyMonName(CrystalSym)}'s Item: {CpuReadBigU16("wEnemyMonItem", CrystalSym):X4}", Color.White, "topright");
  123. APIs.Gui.Text(5, 605, $"TID: {CpuReadBigU16("wPlayerID", CrystalSym):X8}", Color.White, "topright");
  124. APIs.Gui.Text(5, 625, $"odd egg: {OddEggSpecies(CrystalSym)}", Color.White, "topright");
  125. APIs.Gui.Text(5, 645, $"time cycles since last call: {CpuReadU8("wTimeCyclesSinceLastCall", CrystalSym)}", Color.White, "topright");
  126. APIs.Gui.Text(5, 665, $"minutes remaining for cycle: {CpuReadU8("wReceiveCallDelay_MinsRemaining", CrystalSym)}", Color.White, "topright");
  127. APIs.Gui.Text(5, 685, $"start time: {CpuReadU8("wReceiveCallDelay_StartTime", CrystalSym)}", Color.White, "topright");
  128. APIs.Gui.Text(5, 705, $"Raikou Location: {CpuReadU8("wRoamMon1MapGroup", CrystalSym)} : {CpuReadU8("wRoamMon1MapNumber", CrystalSym)}", Color.White, "topright");
  129. APIs.Gui.Text(5, 725, $"Entei Location: {CpuReadU8("wRoamMon2MapGroup", CrystalSym)} : {CpuReadU8("wRoamMon2MapNumber", CrystalSym)}", Color.White, "topright");
  130. APIs.Gui.Text(5, 745, $"Bias Symbol: {CpuReadU8("wSlotBias", CrystalSym)}", Color.White, "topright");
  131. APIs.Gui.Text(5, 765, $"partymon1's DVs: {CpuReadBigU16("wPartyMon1DVs", CrystalSym):X4}", Color.White, "topright");
  132. APIs.Gui.Text(5, 785, $"partymon2's DVs: {CpuReadBigU16("wPartyMon2DVs", CrystalSym):X4}", Color.White, "topright");
  133. APIs.Gui.Text(5, 805, $"partymon3's DVs: {CpuReadBigU16("wPartyMon3DVs", CrystalSym):X4}", Color.White, "topright");
  134. APIs.Gui.Text(5, 825, $"partymon4's DVs: {CpuReadBigU16("wPartyMon4DVs", CrystalSym):X4}", Color.White, "topright");
  135. APIs.Gui.Text(5, 845, $"partymon5's DVs: {CpuReadBigU16("wPartyMon5DVs", CrystalSym):X4}", Color.White, "topright");
  136. APIs.Gui.Text(5, 865, $"partymon6's DVs: {CpuReadBigU16("wPartyMon6DVs", CrystalSym):X4}", Color.White, "topright");
  137. APIs.Gui.Text(5, 885, $"eggmon DVs: {CpuReadBigU16("wEggMonDVs", CrystalSym):X4}", Color.White, "topright");
  138.  
  139. break;
  140. }
  141. case 1:
  142. {
  143. APIs.Gui.Text(5, 5, $"{GetEnemyMonName(SilverSym)}'s Max HP: {CpuReadBigU16("wEnemyMonMaxHP", SilverSym)}", Color.White, "topright");
  144. APIs.Gui.Text(5, 25, $"{GetEnemyMonName(SilverSym)}'s Cur HP: {CpuReadBigU16("wEnemyMonHP", SilverSym)}", Color.White, "topright");
  145. APIs.Gui.Text(5, 55, $"{GetEnemyMonName(SilverSym)}'s Move: {GetEnemyMonMove(SilverSym)}", Color.White, "topright");
  146. APIs.Gui.Text(5, 85, $"Crit Roll: {SilverCBs.CritRng.Roll}", Color.White, "topright");
  147. APIs.Gui.Text(5, 105, $"Crit Chance: {SilverCBs.CritRng.Chance}", Color.White, "topright");
  148. APIs.Gui.Text(5, 135, $"Damage Roll: {SilverCBs.DamageRng.Roll}", Color.White, "topright");
  149. APIs.Gui.Text(5, 165, $"Accuracy Roll: {SilverCBs.AccuracyRng.Roll}", Color.White, "topright");
  150. APIs.Gui.Text(5, 185, $"Move Accuracy: {SilverCBs.AccuracyRng.Chance}", Color.White, "topright");
  151. APIs.Gui.Text(5, 215, $"Effect Roll: {SilverCBs.EffectRng.Roll}", Color.White, "topright");
  152. APIs.Gui.Text(5, 235, $"Effect Chance: {SilverCBs.EffectRng.Chance}", Color.White, "topright");
  153. APIs.Gui.Text(5, 265, $"Catch Roll: {SilverCBs.CatchRng.Roll}", Color.White, "topright");
  154. APIs.Gui.Text(5, 285, $"Catch Chance: {SilverCBs.CatchRng.Chance}", Color.White, "topright");
  155. APIs.Gui.Text(5, 315, $"Quick Claw Roll: {SilverCBs.QuickClawRng.Roll}", Color.White, "topright");
  156. APIs.Gui.Text(5, 345, $"Random Sub: {CpuReadU8("hRandomSub", SilverSym)}", Color.White, "topright");
  157. APIs.Gui.Text(5, 365, $"Linked: {GetLinkerNums()}", Color.White, "topright");
  158. APIs.Gui.Text(5, 385, $"Coordinates: ({CpuReadU8("wXCoord", SilverSym)} {CpuReadU8("wYCoord", SilverSym)})", Color.White, "topright");
  159. APIs.Gui.Text(5, 405, $"{GetEnemyMonName(SilverSym)}'s DVs: {CpuReadBigU16("wEnemyMonDVs", SilverSym):X4}", Color.White, "topright");
  160. APIs.Gui.Text(5, 425, $"partymon1 happiness: {CpuReadU8("wPartyMon1Happiness", SilverSym)}", Color.White, "topright");
  161. APIs.Gui.Text(5, 445, $"partymon2 happiness: {CpuReadU8("wPartyMon2Happiness", SilverSym)}", Color.White, "topright");
  162. APIs.Gui.Text(5, 465, $"partymon3 happiness: {CpuReadU8("wPartyMon3Happiness", SilverSym)}", Color.White, "topright");
  163. APIs.Gui.Text(5, 485, $"partymon4 happiness: {CpuReadU8("wPartyMon4Happiness", SilverSym)}", Color.White, "topright");
  164. APIs.Gui.Text(5, 505, $"partymon5 happiness: {CpuReadU8("wPartyMon5Happiness", SilverSym)}", Color.White, "topright");
  165. APIs.Gui.Text(5, 525, $"partymon6 happiness: {CpuReadU8("wPartyMon6Happiness", SilverSym)}", Color.White, "topright");
  166. APIs.Gui.Text(5, 545, $"{GetEnemyMonName(SilverSym)}'s Item: {CpuReadBigU16("wEnemyMonItem", SilverSym):X4}", Color.White, "topright");
  167. APIs.Gui.Text(5, 565, $"step count: {CpuReadU8("wStepCount", SilverSym)}", Color.White, "topright");
  168. APIs.Gui.Text(5, 585, $"TID: {CpuReadBigU16("wPlayerID", SilverSym):X8}", Color.White, "topright");
  169. APIs.Gui.Text(5, 605, $"Raikou Location: {CpuReadU8("wRoamMon1MapGroup", SilverSym)} : {CpuReadU8("wRoamMon1MapNumber", SilverSym)}", Color.White, "topright");
  170. APIs.Gui.Text(5, 625, $"Entei Location: {CpuReadU8("wRoamMon2MapGroup", SilverSym)} : {CpuReadU8("wRoamMon2MapNumber", SilverSym)}", Color.White, "topright");
  171. APIs.Gui.Text(5, 645, $"Suicune Location: {CpuReadU8("wRoamMon3MapGroup", SilverSym)} : {CpuReadU8("wRoamMon3MapNumber", SilverSym)}", Color.White, "topright");
  172. APIs.Gui.Text(5, 665, $"partymon1's DVs: {CpuReadBigU16("wPartyMon1DVs", SilverSym):X4}", Color.White, "topright");
  173. APIs.Gui.Text(5, 685, $"partymon2's DVs: {CpuReadBigU16("wPartyMon2DVs", SilverSym):X4}", Color.White, "topright");
  174. APIs.Gui.Text(5, 705, $"partymon3's DVs: {CpuReadBigU16("wPartyMon3DVs", SilverSym):X4}", Color.White, "topright");
  175. APIs.Gui.Text(5, 725, $"partymon4's DVs: {CpuReadBigU16("wPartyMon4DVs", SilverSym):X4}", Color.White, "topright");
  176. APIs.Gui.Text(5, 745, $"partymon5's DVs: {CpuReadBigU16("wPartyMon5DVs", SilverSym):X4}", Color.White, "topright");
  177. APIs.Gui.Text(5, 765, $"partymon6's DVs: {CpuReadBigU16("wPartyMon6DVs", SilverSym):X4}", Color.White, "topright");
  178.  
  179.  
  180.  
  181. break;
  182. }
  183. case 2:
  184. {
  185. APIs.Gui.Text(5, 5, $"Random Add: {CpuReadU8("hRandomAdd", YellowSym)}", Color.White, "bottomright");
  186. APIs.Gui.Text(5, 35, $"DSUM: {GetDSUM(YellowSym)}", Color.White, "bottomright");
  187. APIs.Gui.Text(5, 5, $"Crit Roll: {YellowCBs.CritRng.Roll}", Color.White, "topright");
  188. APIs.Gui.Text(5, 25, $"Crit Chance: {YellowCBs.CritRng.Chance}", Color.White, "topright");
  189. APIs.Gui.Text(5, 55, $"Damage Roll: {YellowCBs.DamageRng.Roll}", Color.White, "topright");
  190. APIs.Gui.Text(5, 85, $"Accuracy Roll: {YellowCBs.AccuracyRng.Roll}", Color.White, "topright");
  191. APIs.Gui.Text(5, 105, $"Move Accuracy: {YellowCBs.AccuracyRng.Chance}", Color.White, "topright");
  192. APIs.Gui.Text(5, 135, $"Enemy Move: {GetEnemyMonMove(YellowSym)}", Color.White, "topright");
  193. APIs.Gui.Text(5, 165, $"1st Catch Roll: {YellowCBs.Catch1Rng.Roll}", Color.White, "topright");
  194. APIs.Gui.Text(5, 185, $"1st Catch Chance: {YellowCBs.Catch1Rng.Chance}", Color.White, "topright");
  195. APIs.Gui.Text(5, 215, $"2nd Catch Roll: {YellowCBs.Catch2Rng.Roll}", Color.White, "topright");
  196. APIs.Gui.Text(5, 235, $"2nd Catch Chance: {YellowCBs.Catch2Rng.Chance}", Color.White, "topright");
  197. APIs.Gui.Text(5, 255, $"Enemy Mon DVs: {CpuReadBigU16("wEnemyMonDVs", YellowSym):X4}", Color.White, "topright");
  198. APIs.Gui.Text(5, 275, $"BS Counter: {CpuReadU8("wSlotMachineAllowMatchesCounter", YellowSym)}", Color.White, "topright");
  199. APIs.Gui.Text(5, 295, $"BS Flags: {CpuReadU8("wSlotMachineFlags", YellowSym)}", Color.White, "topright");
  200. APIs.Gui.Text(5, 315, $"BS Roll: {YellowCBs.SlotRng.Roll}", Color.White, "topright");
  201. APIs.Gui.Text(5, 335, $"Bag: {CpuReadU8("wNumBagItems", YellowSym)}", Color.White, "topright");
  202. APIs.Gui.Text(5, 355, $"Can 1: {CpuReadU8("wFirstLockTrashCanIndex", YellowSym)}", Color.White, "topright");
  203. APIs.Gui.Text(5, 375, $"Can 2: {CpuReadU8("wSecondLockTrashCanIndex", YellowSym)}", Color.White, "topright");
  204. APIs.Gui.Text(5, 395, $"Happiness: {CpuReadU8("wPikachuHappiness", YellowSym)}", Color.White, "topright");
  205. APIs.Gui.Text(5, 405, $"{GetEnemyMonName(YellowSym)}'s Cur HP: {CpuReadBigU16("wEnemyMonHP", YellowSym)}", Color.White, "topright");
  206. APIs.Gui.Text(5, 425, $"partymon1's DVs: {CpuReadBigU16("wPartyMon1DVs", YellowSym):X4}", Color.White, "topright");
  207. APIs.Gui.Text(5, 445, $"partymon2's DVs: {CpuReadBigU16("wPartyMon2DVs", YellowSym):X4}", Color.White, "topright");
  208. APIs.Gui.Text(5, 465, $"partymon3's DVs: {CpuReadBigU16("wPartyMon3DVs", YellowSym):X4}", Color.White, "topright");
  209. APIs.Gui.Text(5, 485, $"partymon4's DVs: {CpuReadBigU16("wPartyMon4DVs", YellowSym):X4}", Color.White, "topright");
  210. APIs.Gui.Text(5, 505, $"partymon5's DVs: {CpuReadBigU16("wPartyMon5DVs", YellowSym):X4}", Color.White, "topright");
  211. APIs.Gui.Text(5, 525, $"partymon6's DVs: {CpuReadBigU16("wPartyMon6DVs", YellowSym):X4}", Color.White, "topright");
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218. break;
  219. }
  220. default:
  221. throw new Exception();
  222. }
  223. }
  224. }
  225.  
  226. private void ShowMessage(string message) => DialogController.ShowMessageBox(message);
  227.  
  228. private void linkLabel1_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
  229. {
  230. try
  231. {
  232. linkLabel1.LinkVisited = true;
  233. Process.Start("https://github.com/CasualPokePlayer/Gen2TASTool");
  234. }
  235. catch (Exception ex)
  236. {
  237. ShowMessage($"Caught {ex.GetType().FullName} while trying to open link to source code");
  238. }
  239. }
  240.  
  241.  
  242. [RequiredService]
  243. private IEmulator? Emulator { get; set; }
  244.  
  245. private IEmulator Emu => Emulator ?? throw new NullReferenceException();
  246.  
  247. private (int, int) GetLinkerNums()
  248. {
  249. using var state = new MemoryStream();
  250. Emu.AsStatable().SaveStateBinary(new BinaryWriter(state));
  251. state.Seek(-4, SeekOrigin.End);
  252. var shifted = state.ReadByte() != 0;
  253. state.ReadByte(); // signal
  254. var spaced = state.ReadByte() != 0;
  255. if (spaced)
  256. {
  257. return (1, 3);
  258. }
  259. else if (shifted)
  260. {
  261. return (2, 3);
  262. }
  263. else
  264. {
  265. return (1, 2);
  266. }
  267. }
  268. }
  269. }
Advertisement
Add Comment
Please, Sign In to add comment