diff --git a/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs b/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs new file mode 100644 index 0000000000..3ce4d5172e --- /dev/null +++ b/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs @@ -0,0 +1,555 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public class BkmControllerAdapter : IMovieController + { + #region IController Implementation + + public bool this[string button] + { + get { return MyBoolButtons[button]; } + } + + public bool IsPressed(string button) + { + return MyBoolButtons[button]; + } + + public float GetFloat(string name) + { + return MyFloatControls[name]; + } + + #endregion + + #region IMovieController Implementation + + public ControllerDefinition Type { get; set; } + + /// + /// latches one player from the source + /// + public void LatchPlayerFromSource(IController playerSource, int playerNum) + { + foreach (string button in playerSource.Type.BoolButtons) + { + var bnp = ButtonNameParser.Parse(button); + if (bnp == null) + { + continue; + } + + if (bnp.PlayerNum != playerNum) + { + continue; + } + + bool val = playerSource[button]; + MyBoolButtons[button] = val; + } + } + + /// + /// latches all buttons from the provided source + /// + public void LatchFromSource(IController source) + { + foreach (string button in Type.BoolButtons) + { + MyBoolButtons[button] = source[button]; + } + + foreach (string name in Type.FloatControls) + { + MyFloatControls[name] = source.GetFloat(name); + } + } + + /// + /// latches all buttons from the supplied mnemonic string + /// + public void SetControllersAsMnemonic(string mnemonic) + { + if (ControlType == "Null Controller") + { + return; + } + else if (ControlType == "SNES Controller") + { + SetSNESControllersAsMnemonic(mnemonic); + return; + } + else if (ControlType == "Commodore 64 Controller") + { + SetC64ControllersAsMnemonic(mnemonic); + return; + } + else if (ControlType == "GBA Controller") + { + SetGBAControllersAsMnemonic(mnemonic); + return; + } + else if (ControlType == "Atari 7800 ProLine Joystick Controller") + { + SetAtari7800AsMnemonic(mnemonic); + return; + } + else if (ControlType == "Dual Gameboy Controller") + { + SetDualGameBoyControllerAsMnemonic(mnemonic); + return; + } + else if (ControlType == "WonderSwan Controller") + { + SetWonderSwanControllerAsMnemonic(mnemonic); + return; + } + else if (ControlType == "Nintento 64 Controller") + { + SetN64ControllersAsMnemonic(mnemonic); + return; + } + else if (ControlType == "Saturn Controller") + { + SetSaturnControllersAsMnemonic(mnemonic); + return; + } + else if (ControlType == "PSP Controller") + { + // TODO + return; + } + else if (ControlType == "GPGX Genesis Controller") + { + SetGensis6ControllersAsMnemonic(mnemonic); + return; + } + + MnemonicChecker c = new MnemonicChecker(mnemonic); + + MyBoolButtons.Clear(); + + int start = 3; + if (ControlType == "NES Controller") + { + if (mnemonic.Length < 2) + { + return; + } + else if (mnemonic[1] == 'P') + { + Force("Power", true); + } + else if (mnemonic[1] == 'E') + { + Force("FDS Eject", true); + } + else if (mnemonic[1] == '0') + { + Force("FDS Insert 0", true); + } + else if (mnemonic[1] == '1') + { + Force("FDS Insert 1", true); + } + else if (mnemonic[1] == '2') + { + Force("FDS Insert 2", true); + } + else if (mnemonic[1] == '3') + { + Force("FDS Insert 3", true); + } + else if (mnemonic[1] == 'c') + { + Force("VS Coin 1", true); + } + else if (mnemonic[1] == 'C') + { + Force("VS Coin 2", true); + } + else if (mnemonic[1] != '.') + { + Force("Reset", true); + } + } + if (ControlType == "Gameboy Controller") + { + if (mnemonic.Length < 2) return; + Force("Power", mnemonic[1] != '.'); + } + if (ControlType == "Genesis 3-Button Controller") + { + if (mnemonic.Length < 2) return; + Force("Reset", mnemonic[1] != '.'); + } + if (ControlType == "SMS Controller" || ControlType == "TI83 Controller" || ControlType == "ColecoVision Basic Controller") + { + start = 1; + } + if (ControlType == "Atari 2600 Basic Controller") + { + if (mnemonic.Length < 2) return; + Force("Reset", mnemonic[1] != '.' && mnemonic[1] != '0'); + Force("Select", mnemonic[2] != '.' && mnemonic[2] != '0'); + start = 4; + } + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + int ctr = start; + if (mnemonic.Length < srcindex + ctr + BkmMnemonicConstants.BUTTONS[ControlType].Count - 1) + { + return; + } + string prefix = ""; + if (ControlType != "Gameboy Controller" && ControlType != "TI83 Controller") + { + prefix = "P" + player + " "; + } + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force(prefix + button, c[srcindex + ctr++]); + } + } + if (ControlType == "SMS Controller") + { + int srcindex = BkmMnemonicConstants.PLAYERS[ControlType] * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + int ctr = start; + foreach (string command in BkmMnemonicConstants.COMMANDS[ControlType].Keys) + { + Force(command, c[srcindex + ctr++]); + } + } + } + + #endregion + + private readonly WorkingDictionary MyBoolButtons = new WorkingDictionary(); + private readonly WorkingDictionary MyFloatControls = new WorkingDictionary(); + + private void Force(string button, bool state) + { + MyBoolButtons[button] = state; + } + + private void Force(string name, float state) + { + MyFloatControls[name] = state; + } + + private string ControlType { get { return Type.Name; } } + + private void SetGBAControllersAsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + if (mnemonic.Length < 2) + { + return; + } + if (mnemonic[1] == 'P') + { + Force("Power", true); + } + int start = 3; + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force(button, c[start++]); + } + } + + private void SetGensis6ControllersAsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + + if (mnemonic.Length < 2) + { + return; + } + + if (mnemonic[1] == 'P') + { + Force("Power", true); + } + else if (mnemonic[1] != '.' && mnemonic[1] != '0') + { + Force("Reset", true); + } + + if (mnemonic.Length < 9) + { + return; + } + + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + + if (mnemonic.Length < srcindex + 3 + BkmMnemonicConstants.BUTTONS[ControlType].Count - 1) + { + return; + } + + int start = 3; + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force("P" + player + " " + button, c[srcindex + start++]); + } + } + } + + private void SetSNESControllersAsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + + if (mnemonic.Length < 2) + { + return; + } + + if (mnemonic[1] == 'P') + { + Force("Power", true); + } + else if (mnemonic[1] != '.' && mnemonic[1] != '0') + { + Force("Reset", true); + } + + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + + if (mnemonic.Length < srcindex + 3 + BkmMnemonicConstants.BUTTONS[ControlType].Count - 1) + { + return; + } + + int start = 3; + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force("P" + player + " " + button, c[srcindex + start++]); + } + } + } + + private void SetN64ControllersAsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + + if (mnemonic.Length < 2) + { + return; + } + + if (mnemonic[1] == 'P') + { + Force("Power", true); + } + else if (mnemonic[1] != '.' && mnemonic[1] != '0') + { + Force("Reset", true); + } + + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + BkmMnemonicConstants.ANALOGS[ControlType].Count * 4 + 1 + 1); + + if (mnemonic.Length < srcindex + 3 + BkmMnemonicConstants.BUTTONS[ControlType].Count - 1) + { + return; + } + + int start = 3; + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force("P" + player + " " + button, c[srcindex + start++]); + } + + foreach (string name in BkmMnemonicConstants.ANALOGS[ControlType].Keys) + { + Force("P" + player + " " + name, Int32.Parse(mnemonic.Substring(srcindex + start, 4))); + start += 5; + } + } + } + + private void SetSaturnControllersAsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + + if (mnemonic.Length < 2) + { + return; + } + + if (mnemonic[1] == 'P') + { + Force("Power", true); + } + else if (mnemonic[1] != '.' && mnemonic[1] != '0') + { + Force("Reset", true); + } + + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + + if (mnemonic.Length < srcindex + 3 + BkmMnemonicConstants.BUTTONS[ControlType].Count - 1) + { + return; + } + + int start = 3; + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force("P" + player + " " + button, c[srcindex + start++]); + } + } + } + + private void SetAtari7800AsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + + if (mnemonic.Length < 5) + { + return; + } + if (mnemonic[1] == 'P') + { + Force("Power", true); + } + if (mnemonic[2] == 'r') + { + Force("Reset", true); + } + if (mnemonic[3] == 's') + { + Force("Select", true); + } + if (mnemonic[4] == 'p') + { + Force("Pause", true); + } + + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + int start = 6; + if (mnemonic.Length < srcindex + start + BkmMnemonicConstants.BUTTONS[ControlType].Count) + { + return; + } + + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force("P" + player + " " + button, c[srcindex + start++]); + } + } + } + + private void SetDualGameBoyControllerAsMnemonic(string mnemonic) + { + var checker = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + for (int i = 0; i < BkmMnemonicConstants.DGBMnemonic.Length; i++) + { + var t = BkmMnemonicConstants.DGBMnemonic[i]; + if (t.Item1 != null) + { + Force(t.Item1, checker[i]); + } + } + } + + private void SetWonderSwanControllerAsMnemonic(string mnemonic) + { + var checker = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + for (int i = 0; i < BkmMnemonicConstants.WSMnemonic.Length; i++) + { + var t = BkmMnemonicConstants.WSMnemonic[i]; + if (t.Item1 != null) + { + Force(t.Item1, checker[i]); + } + } + } + + private void SetC64ControllersAsMnemonic(string mnemonic) + { + MnemonicChecker c = new MnemonicChecker(mnemonic); + MyBoolButtons.Clear(); + + + for (int player = 1; player <= BkmMnemonicConstants.PLAYERS[ControlType]; player++) + { + int srcindex = (player - 1) * (BkmMnemonicConstants.BUTTONS[ControlType].Count + 1); + + if (mnemonic.Length < srcindex + 1 + BkmMnemonicConstants.BUTTONS[ControlType].Count - 1) + { + return; + } + + int start = 1; + foreach (string button in BkmMnemonicConstants.BUTTONS[ControlType].Keys) + { + Force("P" + player + " " + button, c[srcindex + start++]); + } + } + + int startk = 13; + foreach (string button in BkmMnemonicConstants.BUTTONS["Commodore 64 Keyboard"].Keys) + { + Force(button, c[startk++]); + } + } + + private class MnemonicChecker + { + private readonly string _mnemonic; + + public MnemonicChecker(string mnemonic) + { + _mnemonic = mnemonic; + } + + public bool this[int c] + { + get + { + if (string.IsNullOrEmpty(_mnemonic)) + { + return false; + } + + if (_mnemonic[c] == '.') + { + return false; + } + + if (_mnemonic[c] == '?') + { + return new Random((int)DateTime.Now.Ticks).Next(0, 10) > 5; + } + + return true; + } + } + } + } +} diff --git a/BizHawk.Client.Common/movie/interfaces/IMovieController.cs b/BizHawk.Client.Common/movie/interfaces/IMovieController.cs new file mode 100644 index 0000000000..d9040a472f --- /dev/null +++ b/BizHawk.Client.Common/movie/interfaces/IMovieController.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public interface IMovieController: IController + { + new ControllerDefinition Type { get; set; } + + void LatchPlayerFromSource(IController playerSource, int playerNum); + + void LatchFromSource(IController source); + + void SetControllersAsMnemonic(string mnemonic); + } +}