BizHawk/BizHawk.Client.EmuHawk/tools/Genesis/GenGameGenie.cs

379 lines
9.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using BizHawk.Client.Common;
#pragma warning disable 675 //TOOD: fix the potential problem this is masking
namespace BizHawk.Client.EmuHawk
{
public partial class GenGameGenie : Form, IToolForm
{
private readonly Dictionary<char, int> _gameGenieTable = new Dictionary<char, int>
{
{ 'A', 0 },
{ 'B', 1 },
{ 'C', 2 },
{ 'D', 3 },
{ 'E', 4 },
{ 'F', 5 },
{ 'G', 6 },
{ 'H', 7 },
{ 'J', 8 },
{ 'K', 9 },
{ 'L', 10 },
{ 'M', 11 },
{ 'N', 12 },
{ 'P', 13 },
{ 'R', 14 },
{ 'S', 15 },
{ 'T', 16 },
{ 'V', 17 },
{ 'W', 18 },
{ 'X', 19 },
{ 'Y', 20 },
{ 'Z', 21 },
{ '0', 22 },
{ '1', 23 },
{ '2', 24 },
{ '3', 25 },
{ '4', 26 },
{ '5', 27 },
{ '6', 28 },
{ '7', 29 },
{ '8', 30 },
{ '9', 31 }
};
private bool _processing;
private void GenGameGenie_Load(object sender, EventArgs e)
{
if (Global.Config.GenGGSettings.UseWindowPosition)
{
Location = Global.Config.GenGGSettings.WindowPosition;
}
}
#region Public API
public bool AskSave() { return true; }
public bool UpdateBefore { get { return false; } }
public void Restart()
{
if (Global.Emulator.SystemId != "GEN")
{
Close();
}
}
public void UpdateValues()
{
if (Global.Emulator.SystemId != "GEN")
{
Close();
}
}
public GenGameGenie()
{
InitializeComponent();
Closing += (o, e) => SaveConfigSettings();
TopMost = Global.Config.GenGGSettings.TopMost;
}
#endregion
// code is code to be converted, val is pointer to value, add is pointer to address
private void GenGGDecode(string code, ref int val, ref int add)
{
long hexcode = 0;
// convert code to a long binary string
foreach (var t in code)
{
hexcode <<= 5;
int y;
_gameGenieTable.TryGetValue(t, out y);
hexcode |= y;
}
long decoded = (hexcode & 0xFF00000000) >> 32;
decoded |= hexcode & 0x00FF000000;
decoded |= (hexcode & 0x0000FF0000) << 16;
decoded |= (hexcode & 0x00000000700) << 5;
decoded |= (hexcode & 0x000000F800) >> 3;
decoded |= (hexcode & 0x00000000FF) << 16;
val = (int)(decoded & 0x000000FFFF);
add = (int)((decoded & 0xFFFFFF0000) >> 16);
}
private static string GenGGEncode(int val, int add)
{
long encoded;
string code = null;
encoded = (long)(val & 0x00FF) << 32;
encoded |= (val & 0xE000) >> 5;
encoded |= (val & 0x1F00) << 3;
encoded |= add & 0xFF0000;
encoded |= (add & 0x00FF00) << 16;
encoded |= add & 0x0000FF;
char[] letters = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
for (var i = 0; i < 8; i++)
{
var chr = (int)(encoded & 0x1F);
code += letters[chr];
encoded >>= 5;
}
// reverse string, as its build backward
var array = code.ToCharArray();
Array.Reverse(array);
return new string(array);
}
private void SaveConfigSettings()
{
Global.Config.GenGGSettings.Wndx = Location.X;
Global.Config.GenGGSettings.Wndy = Location.Y;
}
private void RefreshFloatingWindowControl()
{
Owner = Global.Config.GenGGSettings.FloatingWindow ? null : GlobalWin.MainForm;
}
#region Events
#region Menu
private void OptionsSubMenu_DropDownOpened(object sender, EventArgs e)
{
AutoloadMenuItem.Checked = Global.Config.GenGGAutoload;
SaveWindowPositionMenuItem.Checked = Global.Config.GenGGSettings.SaveWindowPosition;
AlwaysOnTopMenuItem.Checked = Global.Config.GenGGSettings.TopMost;
FloatingWindowMenuItem.Checked = Global.Config.GenGGSettings.FloatingWindow;
}
private void AutoloadMenuItem_Click(object sender, EventArgs e)
{
Global.Config.GenGGAutoload ^= true;
}
private void SaveWindowPositionMenuItem_Click(object sender, EventArgs e)
{
Global.Config.GenGGSettings.SaveWindowPosition ^= true;
}
private void AlwaysOnTopMenuItem_Click(object sender, EventArgs e)
{
Global.Config.GenGGSettings.TopMost ^= true;
TopMost = Global.Config.GenGGSettings.TopMost;
}
private void FloatingWindowMenuItem_Click(object sender, EventArgs e)
{
Global.Config.GenGGSettings.FloatingWindow ^= true;
RefreshFloatingWindowControl();
}
private void ExitMenuItem_Click(object sender, EventArgs e)
{
Close();
}
#endregion
#region Dialog and Controls
private void GGCodeMaskBox_KeyPress(object sender, KeyPressEventArgs e)
{
// ignore I O Q U
if ((e.KeyChar == 73) || (e.KeyChar == 79) || (e.KeyChar == 81) || (e.KeyChar == 85) ||
(e.KeyChar == 105) || (e.KeyChar == 111) || (e.KeyChar == 113) || (e.KeyChar == 117))
{
e.KeyChar = '\n';
}
}
private void GGCodeMaskBox_TextChanged(object sender, EventArgs e)
{
if (_processing == false)
{
_processing = true;
// remove Invalid I O Q P if pasted
GGCodeMaskBox.Text = GGCodeMaskBox.Text.Replace("I", string.Empty);
GGCodeMaskBox.Text = GGCodeMaskBox.Text.Replace("O", string.Empty);
GGCodeMaskBox.Text = GGCodeMaskBox.Text.Replace("Q", string.Empty);
GGCodeMaskBox.Text = GGCodeMaskBox.Text.Replace("U", string.Empty);
if (GGCodeMaskBox.Text.Length > 0)
{
int val = 0;
int add = 0;
GenGGDecode(GGCodeMaskBox.Text, ref val, ref add);
AddressBox.Text = string.Format("{0:X6}", add);
ValueBox.Text = string.Format("{0:X4}", val);
AddCheatButton.Enabled = true;
}
else
{
AddressBox.Text = string.Empty;
ValueBox.Text = string.Empty;
AddCheatButton.Enabled = false;
}
_processing = false;
}
}
private void AddressBox_TextChanged(object sender, EventArgs e)
{
// remove invalid character when pasted
if (_processing == false)
{
_processing = true;
if (Regex.IsMatch(AddressBox.Text, @"[^a-fA-F0-9]"))
{
AddressBox.Text = Regex.Replace(AddressBox.Text, @"[^a-fA-F0-9]", string.Empty);
}
if ((AddressBox.Text.Length > 0) || (ValueBox.Text.Length > 0))
{
int val = 0;
int add = 0;
if (ValueBox.Text.Length > 0)
{
val = int.Parse(ValueBox.Text, NumberStyles.HexNumber);
}
if (AddressBox.Text.Length > 0)
{
add = int.Parse(AddressBox.Text, NumberStyles.HexNumber);
}
GGCodeMaskBox.Text = GenGGEncode(val, add);
AddCheatButton.Enabled = true;
}
else
{
GGCodeMaskBox.Text = string.Empty;
AddCheatButton.Enabled = false;
}
_processing = false;
}
}
private void ValueBox_TextChanged(object sender, EventArgs e)
{
if (_processing == false)
{
_processing = true;
// remove invalid character when pasted
if (Regex.IsMatch(ValueBox.Text, @"[^a-fA-F0-9]"))
{
ValueBox.Text = Regex.Replace(ValueBox.Text, @"[^a-fA-F0-9]", string.Empty);
}
if ((AddressBox.Text.Length > 0) || (ValueBox.Text.Length > 0))
{
int val = 0;
int add = 0;
if (ValueBox.Text.Length > 0)
{
val = int.Parse(ValueBox.Text, NumberStyles.HexNumber);
}
if (AddressBox.Text.Length > 0)
{
add = int.Parse(AddressBox.Text, NumberStyles.HexNumber);
}
GGCodeMaskBox.Text = GenGGEncode(val, add);
AddCheatButton.Enabled = true;
}
else
{
GGCodeMaskBox.Text = string.Empty;
AddCheatButton.Enabled = false;
}
_processing = false;
}
}
private void ClearButton_Click(object sender, EventArgs e)
{
AddressBox.Text = string.Empty;
ValueBox.Text = string.Empty;
GGCodeMaskBox.Text = string.Empty;
AddCheatButton.Enabled = false;
}
private void AddCheatButton_Click(object sender, EventArgs e)
{
string name;
var address = 0;
var value = 0;
if (!string.IsNullOrWhiteSpace(cheatname.Text))
{
name = cheatname.Text;
}
else
{
_processing = true;
GGCodeMaskBox.TextMaskFormat = MaskFormat.IncludeLiterals;
name = GGCodeMaskBox.Text;
GGCodeMaskBox.TextMaskFormat = MaskFormat.ExcludePromptAndLiterals;
_processing = false;
}
if (!string.IsNullOrWhiteSpace(AddressBox.Text))
{
address = int.Parse(AddressBox.Text, NumberStyles.HexNumber);
}
if (!string.IsNullOrWhiteSpace(ValueBox.Text))
{
value = ValueBox.ToRawInt() ?? 0;
}
var watch = Watch.GenerateWatch(
Global.Emulator.MemoryDomains["MD CART"],
address,
Watch.WatchSize.Word,
Watch.DisplayType.Hex,
name,
true
);
Global.CheatList.Add(new Cheat(
watch,
value
));
}
protected override void OnShown(EventArgs e)
{
RefreshFloatingWindowControl();
base.OnShown(e);
}
#endregion
#endregion
}
}