From 1069a50219ffa843b7c8e82e8cf5bddbfe67ffb3 Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Wed, 30 Aug 2017 23:02:36 -0400 Subject: [PATCH] Adds Sega Master System paddle support --- Assets/defctrl.json | 14 ++ BizHawk.Client.EmuHawk/MainForm.Designer.cs | 27 +++ BizHawk.Client.EmuHawk/MainForm.Events.cs | 16 ++ .../Consoles/Sega/SMS/SMS.IEmulator.cs | 8 +- .../Consoles/Sega/SMS/SMS.ISettable.cs | 1 + .../Consoles/Sega/SMS/SMS.IStatable.cs | 2 + .../Consoles/Sega/SMS/SMS.Input.cs | 174 ++++++++++++++++-- 7 files changed, 228 insertions(+), 14 deletions(-) diff --git a/Assets/defctrl.json b/Assets/defctrl.json index 65c84b7fdb..97a6a89116 100644 --- a/Assets/defctrl.json +++ b/Assets/defctrl.json @@ -743,6 +743,13 @@ "P2 B1": "", "P2 B2": "" }, + "SMS Paddle Controller": { + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + }, "GG Controller": { "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", @@ -1567,6 +1574,13 @@ "Mult": 1.0, "Deadzone": 0.1 } + }, + "SMS Paddle Controller": { + "P1 Paddle": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + } } } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index aef505d11b..82b6530b92 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -442,6 +442,9 @@ this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timerMouseIdle = new System.Windows.Forms.Timer(this.components); + this.SMSControllerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerStandardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerPaddleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); @@ -2475,6 +2478,7 @@ this.SMSSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.SMSregionToolStripMenuItem, this.SMSdisplayToolStripMenuItem, + this.SMSControllerToolStripMenuItem, this.SMStoolStripMenuItem2, this.SMSenableBIOSToolStripMenuItem, this.SMSEnableFMChipMenuItem, @@ -2542,6 +2546,26 @@ this.SMSdisplayNtscToolStripMenuItem.Text = "NTSC"; this.SMSdisplayNtscToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayNTSC_Click); // + // SMSControllerToolStripMenuItem + // + this.SMSControllerToolStripMenuItem.Name = "SMSControllerToolStripMenuItem"; + this.SMSControllerToolStripMenuItem.Text = "&Controller Type"; + this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SMSControllerStandardToolStripMenuItem, + this.SMSControllerPaddleToolStripMenuItem}); + // + // SMSControllerStandardToolStripMenuItem + // + this.SMSControllerStandardToolStripMenuItem.Name = "SMSControllerStandardToolStripMenuItem"; + this.SMSControllerStandardToolStripMenuItem.Text = "Standard"; + this.SMSControllerStandardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerStandardToolStripMenuItem_Click); + // + // SMSControllerPaddleToolStripMenuItem + // + this.SMSControllerPaddleToolStripMenuItem.Name = "SMSControllerPaddleToolStripMenuItem"; + this.SMSControllerPaddleToolStripMenuItem.Text = "Paddle"; + this.SMSControllerPaddleToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerPaddleToolStripMenuItem_Click); + // // SMSdisplayPalToolStripMenuItem // this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; @@ -4368,5 +4392,8 @@ private System.Windows.Forms.ToolStripMenuItem SgbSameBoyMenuItem; private System.Windows.Forms.ToolStripMenuItem pCFXToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem preferencesToolStripMenuItem3; + private System.Windows.Forms.ToolStripMenuItem SMSControllerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerStandardToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerPaddleToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 9cd33d7a3d..8d1abdce5c 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1745,6 +1745,8 @@ namespace BizHawk.Client.EmuHawk SMSdisplayNtscToolStripMenuItem.Checked = ss.DisplayType == "NTSC"; SMSdisplayPalToolStripMenuItem.Checked = ss.DisplayType == "PAL"; SMSdisplayAutoToolStripMenuItem.Checked = ss.DisplayType == "Auto"; + SMSControllerStandardToolStripMenuItem.Checked = s.ControllerType == "Standard"; + SMSControllerPaddleToolStripMenuItem.Checked = s.ControllerType == "Paddle"; SMSenableBIOSToolStripMenuItem.Checked = ss.UseBIOS; SMSEnableFMChipMenuItem.Checked = ss.EnableFM; SMSOverclockMenuItem.Checked = ss.AllowOverlock; @@ -1899,6 +1901,20 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.Load(); } + private void SMSControllerStandardToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSettings(); + s.ControllerType = "Standard"; + PutCoreSettings(s); + } + + private void SMSControllerPaddleToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSettings(); + s.ControllerType = "Paddle"; + PutCoreSettings(s); + } + #endregion #region TI83 diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs index ae2dd35788..7b91f0bfba 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -15,7 +15,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return GGController; } - return SmsController; + switch(Settings.ControllerType) + { + case "Paddle": + return SMSPaddleController; + default: + return SmsController; + } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs index 90331a7528..a69d726e37 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs @@ -38,6 +38,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public bool SpriteLimit = false; public bool Fix3D = true; public bool DisplayOverscan = false; + public string ControllerType = "Standard"; // GG settings public bool ShowClippedRegions = false; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs index 961daa444b..219612fb00 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs @@ -71,6 +71,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ser.Sync("Port02", ref Port02); ser.Sync("Port3E", ref Port3E); ser.Sync("Port3F", ref Port3F); + ser.Sync("Paddle1High", ref Paddle1High); + ser.Sync("Paddle2High", ref Paddle2High); if (SaveRAM != null) { diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs index 06fa88e9ea..d48e9b3d06 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs @@ -1,4 +1,6 @@ -using BizHawk.Emulation.Common; +using System; + +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Sega.MasterSystem { @@ -25,21 +27,123 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } }; + public static readonly ControllerDefinition SMSPaddleController = new ControllerDefinition + { + Name = "SMS Paddle Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Left", "P1 Right", "P1 B1", + "P2 Left", "P2 Right", "P2 B1", + }, + FloatControls = + { + "P1 Paddle", + "P2 Paddle" + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(0, 128, 255), + new ControllerDefinition.FloatRange(0, 128, 255) + } + }; + + // The paddles have a nibble select state + bool Paddle1High = false; + bool Paddle2High = false; + + const int PaddleMin = 0; + const int PaddleMax = 255; + private byte ReadControls1() { InputCallbacks.Call(); _lagged = false; byte value = 0xFF; - if (_controller.IsPressed("P1 Up")) value &= 0xFE; - if (_controller.IsPressed("P1 Down")) value &= 0xFD; - if (_controller.IsPressed("P1 Left")) value &= 0xFB; - if (_controller.IsPressed("P1 Right")) value &= 0xF7; - if (_controller.IsPressed("P1 B1")) value &= 0xEF; - if (_controller.IsPressed("P1 B2")) value &= 0xDF; + switch (Settings.ControllerType) + { + case "Paddle": + // use analog values from a controller, see http://www.smspower.org/Development/Paddle - if (_controller.IsPressed("P2 Up")) value &= 0xBF; - if (_controller.IsPressed("P2 Down")) value &= 0x7F; + int paddle1Pos; + if (_controller.IsPressed("P1 Left")) + paddle1Pos = PaddleMin; + else if (_controller.IsPressed("P1 Right")) + paddle1Pos = PaddleMax; + else + paddle1Pos = (int)_controller.GetFloat("P1 Paddle"); + + int paddle2Pos; + if (_controller.IsPressed("P2 Left")) + paddle2Pos = PaddleMin; + else if (_controller.IsPressed("P2 Right")) + paddle2Pos = PaddleMax; + else + paddle2Pos = (int)_controller.GetFloat("P2 Paddle"); + + // The 3F port's TH slot is also used on games in some games in Export BIOS to clock the paddle state + // Yes it's silly considering the paddle was never released outside Japan but the games think otherwise + if (_region != "Japan") + { + if ((Port3F & 0x02) == 0x00) + { + Paddle1High = (Port3F & 0x20) != 0; + } + if ((Port3F & 0x08) == 0x00) + { + Paddle2High = (Port3F & 0x80) != 0; + } + } + + if (Paddle1High) + { + if ((paddle1Pos & 0x10) == 0) value &= 0xFE; + if ((paddle1Pos & 0x20) == 0) value &= 0xFD; + if ((paddle1Pos & 0x40) == 0) value &= 0xFB; + if ((paddle1Pos & 0x80) == 0) value &= 0xF7; + } + else + { + if ((paddle1Pos & 0x01) == 0) value &= 0xFE; + if ((paddle1Pos & 0x02) == 0) value &= 0xFD; + if ((paddle1Pos & 0x04) == 0) value &= 0xFB; + if ((paddle1Pos & 0x08) == 0) value &= 0xF7; + } + + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (!Paddle1High) value &= 0xDF; + + if (Paddle2High) + { + if ((paddle2Pos & 0x10) == 0) value &= 0xBF; + if ((paddle2Pos & 0x20) == 0) value &= 0x7F; + } + else + { + if ((paddle2Pos & 0x01) == 0) value &= 0xBF; + if ((paddle2Pos & 0x02) == 0) value &= 0x7F; + } + + // toggle state for Japanese region controllers + Paddle1High = !Paddle1High; + + break; + + default: + // Normal controller + + if (_controller.IsPressed("P1 Up")) value &= 0xFE; + if (_controller.IsPressed("P1 Down")) value &= 0xFD; + if (_controller.IsPressed("P1 Left")) value &= 0xFB; + if (_controller.IsPressed("P1 Right")) value &= 0xF7; + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (_controller.IsPressed("P1 B2")) value &= 0xDF; + + if (_controller.IsPressed("P2 Up")) value &= 0xBF; + if (_controller.IsPressed("P2 Down")) value &= 0x7F; + break; + } return value; } @@ -50,10 +154,54 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem _lagged = false; byte value = 0xFF; - if (_controller.IsPressed("P2 Left")) value &= 0xFE; - if (_controller.IsPressed("P2 Right")) value &= 0xFD; - if (_controller.IsPressed("P2 B1")) value &= 0xFB; - if (_controller.IsPressed("P2 B2")) value &= 0xF7; + switch (Settings.ControllerType) + { + case "Paddle": + // use analog values from a controller, see http://www.smspower.org/Development/Paddle + + int paddle2Pos; + if (_controller.IsPressed("P2 Left")) + paddle2Pos = PaddleMin; + else if (_controller.IsPressed("P2 Right")) + paddle2Pos = PaddleMax; + else + paddle2Pos = (int)_controller.GetFloat("P2 Paddle"); + + if (_region != "Japan") + { + if ((Port3F & 0x08) == 0x00) + { + Paddle2High = (Port3F & 0x80) != 0; + } + } + + if (Paddle2High) + { + if ((paddle2Pos & 0x40) == 0) value &= 0xFE; + if ((paddle2Pos & 0x80) == 0) value &= 0xFD; + } + else + { + if ((paddle2Pos & 0x04) == 0) value &= 0xFE; + if ((paddle2Pos & 0x08) == 0) value &= 0xFD; + } + + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (!Paddle2High) value &= 0xF7; + + Paddle2High = !Paddle2High; + + break; + + default: + // Normal controller + + if (_controller.IsPressed("P2 Left")) value &= 0xFE; + if (_controller.IsPressed("P2 Right")) value &= 0xFD; + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (_controller.IsPressed("P2 B2")) value &= 0xF7; + break; + } if (_controller.IsPressed("Reset")) value &= 0xEF;