diff --git a/Assets/defctrl.json b/Assets/defctrl.json index b7454b80f0..e213cfae5f 100644 --- a/Assets/defctrl.json +++ b/Assets/defctrl.json @@ -754,6 +754,22 @@ "P1 Trigger": "Z, J1 B1, X1 X, WMouse L", "Reset": "J1 B9, X1 Back", "Pause": "J1 B10, X1 Start" + }, + "SMS Sports Pad Controller": { + "P1 Up": "UpArrow, J1 POV1U", + "P1 Down": "DownArrow, J1 POV1D", + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "P1 B2": "X, J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" }, "GG Controller": { "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", @@ -1598,6 +1614,28 @@ "Mult": 1.0, "Deadzone": 0.0 } + }, + "SMS Sports Pad Controller": { + "P1 X": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "P1 Y": { + "Value": "X1 LeftThumbY", + "Mult": -1.0, + "Deadzone": 0.1 + }, + "P2 X": { + "Value": "X2 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "P2 Y": { + "Value": "X2 LeftThumbY", + "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 f497c44fca..9d6774638e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -446,7 +446,8 @@ this.SMSControllerStandardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SMSControllerPaddleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SMSControllerLightPhaserToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.MainformMenu.SuspendLayout(); + this.SMSControllerSportsPadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); this.SuspendLayout(); @@ -2480,7 +2481,7 @@ this.SMSregionToolStripMenuItem, this.SMSdisplayToolStripMenuItem, this.SMSControllerToolStripMenuItem, - this.SMStoolStripMenuItem2, + this.SMStoolStripMenuItem2, this.SMSenableBIOSToolStripMenuItem, this.SMSEnableFMChipMenuItem, this.SMSOverclockMenuItem, @@ -2554,7 +2555,8 @@ this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.SMSControllerStandardToolStripMenuItem, this.SMSControllerPaddleToolStripMenuItem, - this.SMSControllerLightPhaserToolStripMenuItem}); + this.SMSControllerLightPhaserToolStripMenuItem, + this.SMSControllerSportsPadToolStripMenuItem}); // // SMSControllerStandardToolStripMenuItem // @@ -2573,10 +2575,17 @@ this.SMSControllerLightPhaserToolStripMenuItem.Name = "SMSControllerLightPhaserToolStripMenuItem"; this.SMSControllerLightPhaserToolStripMenuItem.Text = "Light Phaser"; this.SMSControllerLightPhaserToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerLightPhaserToolStripMenuItem_Click); - // - // SMSdisplayPalToolStripMenuItem - // - this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; + // + // SMSControllerSportsPadToolStripMenuItem + // + this.SMSControllerSportsPadToolStripMenuItem.Name = "SMSControllerSportsPadToolStripMenuItem"; + this.SMSControllerSportsPadToolStripMenuItem.Text = "Sports Pad"; + this.SMSControllerSportsPadToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerSportsPadToolStripMenuItem_Click); + + // + // SMSdisplayPalToolStripMenuItem + // + this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; this.SMSdisplayPalToolStripMenuItem.Size = new System.Drawing.Size(104, 22); this.SMSdisplayPalToolStripMenuItem.Text = "PAL"; this.SMSdisplayPalToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayPAL_Click); @@ -4404,5 +4413,6 @@ private System.Windows.Forms.ToolStripMenuItem SMSControllerStandardToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SMSControllerPaddleToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerSportsPadToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index c5f4bc22dd..fd1d42f241 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1745,9 +1745,10 @@ 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"; - SMSControllerLightPhaserToolStripMenuItem.Checked = s.ControllerType == "Light Phaser"; + SMSControllerStandardToolStripMenuItem.Checked = ss.ControllerType == "Standard"; + SMSControllerPaddleToolStripMenuItem.Checked = ss.ControllerType == "Paddle"; + SMSControllerLightPhaserToolStripMenuItem.Checked = ss.ControllerType == "Light Phaser"; + SMSControllerSportsPadToolStripMenuItem.Checked = ss.ControllerType == "Sports Pad"; SMSenableBIOSToolStripMenuItem.Checked = ss.UseBIOS; SMSEnableFMChipMenuItem.Checked = ss.EnableFM; SMSOverclockMenuItem.Checked = ss.AllowOverlock; @@ -1904,23 +1905,30 @@ namespace BizHawk.Client.EmuHawk private void SMSControllerStandardToolStripMenuItem_Click(object sender, EventArgs e) { - var s = ((SMS)Emulator).GetSettings(); + var s = ((SMS)Emulator).GetSyncSettings(); s.ControllerType = "Standard"; - PutCoreSettings(s); + PutCoreSyncSettings(s); } private void SMSControllerPaddleToolStripMenuItem_Click(object sender, EventArgs e) { - var s = ((SMS)Emulator).GetSettings(); + var s = ((SMS)Emulator).GetSyncSettings(); s.ControllerType = "Paddle"; - PutCoreSettings(s); + PutCoreSyncSettings(s); } private void SMSControllerLightPhaserToolStripMenuItem_Click(object sender, EventArgs e) { - var s = ((SMS)Emulator).GetSettings(); + var s = ((SMS)Emulator).GetSyncSettings(); s.ControllerType = "Light Phaser"; - PutCoreSettings(s); + PutCoreSyncSettings(s); + } + + private void SMSControllerSportsPadToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Sports Pad"; + PutCoreSyncSettings(s); } #endregion diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt index 128e46f9f8..122814b815 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt @@ -9,10 +9,6 @@ Korean games currently not booting: * Desert Strike - you can enter the map screen but cannot leave. -- Light Gun emulation -- Paddle emulation -- Sports pad emulation? - ======= Game Gear compatibility issues ======= * Outrun has raster effect on the wrong line. I've been able to modify interrupt code to diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs index fe2a9222a3..e49a75ddad 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return GGController; } - switch(Settings.ControllerType) + switch(SyncSettings.ControllerType) { case "Paddle": return SMSPaddleController; @@ -24,6 +24,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem SMSLightPhaserController.FloatRanges[1] = new ControllerDefinition.FloatRange(0, Vdp.FrameHeight / 2, Vdp.FrameHeight - 1); return SMSLightPhaserController; + case "Sports Pad": + return SMSSportsPadController; 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 a69d726e37..d2112e2dab 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs @@ -38,7 +38,6 @@ 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; @@ -66,6 +65,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public bool UseBIOS = true; public string ConsoleRegion = "Export"; public string DisplayType = "NTSC"; + public string ControllerType = "Standard"; public SMSSyncSettings Clone() { @@ -79,7 +79,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem x.AllowOverlock != y.AllowOverlock || x.UseBIOS != y.UseBIOS || x.ConsoleRegion != y.ConsoleRegion || - x.DisplayType != y.DisplayType; + x.DisplayType != y.DisplayType || + x.ControllerType != y.ControllerType; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs index 0ba7d4293d..87564dfe64 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs @@ -65,8 +65,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); + ser.Sync("Controller1SelectHigh", ref Controller1SelectHigh); + ser.Sync("ControllerSelect2High", ref Controller2SelectHigh); ser.Sync("LatchLightPhaser", ref LatchLightPhaser); 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 fda3dcaa68..c76dab5789 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs @@ -67,95 +67,262 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } }; - // The paddles have a nibble select state - bool Paddle1High = false; - bool Paddle2High = false; + public static readonly ControllerDefinition SMSSportsPadController = new ControllerDefinition + { + Name = "SMS Sports Pad Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Left", "P1 Right", "P1 Up", "P1 Down", "P1 B1", "P1 B2", + "P2 Left", "P2 Right", "P2 Up", "P2 Down", "P2 B1", "P2 B2" + }, + FloatControls = + { + "P1 X", "P1 Y", + "P2 X", "P2 Y" + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63) + } + }; const int PaddleMin = 0; const int PaddleMax = 255; + const int SportsPadMin = -64; + const int SportsPadMax = 63; + + // The paddles and sports pads have data select states + bool Controller1SelectHigh = true; + bool Controller2SelectHigh = true; bool LatchLightPhaser = false; - + + // further state value for sports pad, may be useful for other controllers in future + int Controller1State = 3; + int Controller2State = 3; + int ControllerTick = 0; // for timing in japan + private byte ReadControls1() { InputCallbacks.Call(); _lagged = false; byte value = 0xFF; - switch (Settings.ControllerType) + switch (SyncSettings.ControllerType) { case "Paddle": - // use analog values from a controller, see http://www.smspower.org/Development/Paddle - - 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) + // use analog values from a controller, see http://www.smspower.org/Development/Paddle + + 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"); + + PresetControllerState(1); + // Hard-wired together? + Controller2SelectHigh = Controller1SelectHigh; + + if (Controller1SelectHigh) { - Paddle1High = (Port3F & 0x20) != 0; - Paddle2High = 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; } - if ((Port3F & 0x08) == 0x00) + else { - Paddle2High = (Port3F & 0x80) != 0; + 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 (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 (!Controller1SelectHigh) value &= 0xDF; - if (_controller.IsPressed("P1 B1")) value &= 0xEF; - if (!Paddle1High) value &= 0xDF; + if (Controller2SelectHigh) + { + 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; + } - if (Paddle2High) - { - if ((paddle2Pos & 0x10) == 0) value &= 0xBF; - if ((paddle2Pos & 0x20) == 0) value &= 0x7F; + PostsetControllerState(1); } - else - { - if ((paddle2Pos & 0x01) == 0) value &= 0xBF; - if ((paddle2Pos & 0x02) == 0) value &= 0x7F; - } - - // toggle state for Japanese region controllers - Paddle1High = !Paddle1High; - break; case "Light Phaser": if (_controller.IsPressed("P1 Trigger")) value &= 0xEF; break; + case "Sports Pad": + { + int p1X; + if (_controller.IsPressed("P1 Left")) + p1X = SportsPadMin; + else if (_controller.IsPressed("P1 Right")) + p1X = SportsPadMax; + else + p1X = (int)_controller.GetFloat("P1 X"); + + int p1Y; + if (_controller.IsPressed("P1 Up")) + p1Y = SportsPadMin; + else if (_controller.IsPressed("P1 Down")) + p1Y = SportsPadMax; + else + p1Y = (int)_controller.GetFloat("P1 Y"); + + int p2X; + if (_controller.IsPressed("P2 Left")) + p2X = SportsPadMin; + else if (_controller.IsPressed("P2 Right")) + p2X = SportsPadMax; + else + p2X = (int)_controller.GetFloat("P2 X"); + + int p2Y; + if (_controller.IsPressed("P2 Up")) + p2Y = SportsPadMin; + else if (_controller.IsPressed("P2 Down")) + p2Y = SportsPadMax; + else + p2Y = (int)_controller.GetFloat("P2 Y"); + + if(_region == "Japan") + { + p1X += 128; + p1Y += 128; + p2X += 128; + p2Y += 128; + } else + { + p1X *= -1; + p1Y *= -1; + p2X *= -1; + p2Y *= -1; + } + + PresetControllerState(1); + + // advance state + if (Controller1SelectHigh && (Controller1State % 2 == 0)) + { + ++Controller1State; + } + else if (!Controller1SelectHigh && (Controller1State % 2 == 1)) + { + if (++Controller1State == (_region == "Japan" ? 6 : 4)) + Controller1State = 0; + } + if (Controller2SelectHigh && (Controller2State % 2 == 0)) + { + ++Controller2State; + } + else if (!Controller2SelectHigh && (Controller2State % 2 == 1)) + { + if (++Controller2State == (_region == "Japan" ? 6 : 4)) + Controller2State = 0; + } + + switch (Controller1State) + { + case 0: + if ((p1X & 0x10) == 0) value &= 0xFE; + if ((p1X & 0x20) == 0) value &= 0xFD; + if ((p1X & 0x40) == 0) value &= 0xFB; + if ((p1X & 0x80) == 0) value &= 0xF7; + break; + case 1: + if ((p1X & 0x01) == 0) value &= 0xFE; + if ((p1X & 0x02) == 0) value &= 0xFD; + if ((p1X & 0x04) == 0) value &= 0xFB; + if ((p1X & 0x08) == 0) value &= 0xF7; + break; + case 2: + if ((p1Y & 0x10) == 0) value &= 0xFE; + if ((p1Y & 0x20) == 0) value &= 0xFD; + if ((p1Y & 0x40) == 0) value &= 0xFB; + if ((p1Y & 0x80) == 0) value &= 0xF7; + break; + case 3: + if ((p1Y & 0x01) == 0) value &= 0xFE; + if ((p1Y & 0x02) == 0) value &= 0xFD; + if ((p1Y & 0x04) == 0) value &= 0xFB; + if ((p1Y & 0x08) == 0) value &= 0xF7; + break; + case 4: + // specific to Japan: sync via TR + value &= 0xDF; + break; + case 5: + // specific to Japan: buttons + if (_controller.IsPressed("P1 B1")) value &= 0xFE; + if (_controller.IsPressed("P1 B2")) value &= 0xFD; + break; + } + + if (_region != "Japan") + { + // Buttons like normal in Export + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (_controller.IsPressed("P1 B2")) value &= 0xDF; + } + else + { + // In Japan, it contains selectHigh + if (!Controller1SelectHigh) value &= 0xEF; + } + + switch (Controller2State) + { + case 0: + if ((p2X & 0x10) == 0) value &= 0xBF; + if ((p2X & 0x20) == 0) value &= 0x7F; + break; + case 1: + if ((p2X & 0x01) == 0) value &= 0xBF; + if ((p2X & 0x02) == 0) value &= 0x7F; + break; + case 2: + if ((p2Y & 0x10) == 0) value &= 0xBF; + if ((p2Y & 0x20) == 0) value &= 0x7F; + break; + case 3: + if ((p2Y & 0x01) == 0) value &= 0xBF; + if ((p2Y & 0x02) == 0) value &= 0x7F; + break; + case 5: + // specific to Japan: buttons + if (_controller.IsPressed("P2 B1")) value &= 0xBF; + if (_controller.IsPressed("P2 B2")) value &= 0x7F; + break; + } + + PostsetControllerState(1); + } + break; + default: // Normal controller @@ -180,43 +347,38 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem _lagged = false; byte value = 0xFF; - switch (Settings.ControllerType) + switch (SyncSettings.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) + // 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"); + + PresetControllerState(2); + + if (Controller2SelectHigh) { - Paddle2High = (Port3F & 0x80) != 0; + 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 (!Controller2SelectHigh) value &= 0xF7; + + PostsetControllerState(2); } - - 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; case "Light Phaser": @@ -227,6 +389,81 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } break; + case "Sports Pad": + { + int p2X; + if (_controller.IsPressed("P2 Left")) + p2X = SportsPadMin; + else if (_controller.IsPressed("P2 Right")) + p2X = SportsPadMax; + else + p2X = (int)_controller.GetFloat("P2 X"); + + int p2Y; + if (_controller.IsPressed("P2 Down")) + p2Y = SportsPadMin; + else if (_controller.IsPressed("P2 Up")) + p2Y = SportsPadMax; + else + p2Y = (int)_controller.GetFloat("P2 Y"); + + if (_region == "Japan") + { + p2X += 128; + p2Y += 128; + } + else + { + p2X *= -1; + p2Y *= -1; + } + + PresetControllerState(2); + + if (Controller2SelectHigh && (Controller2State % 2 == 0)) + { + ++Controller2State; + } + else if (!Controller2SelectHigh && (Controller2State % 2 == 1)) + { + if (++Controller2State == (_region == "Japan" ? 6 : 4)) + Controller2State = 0; + } + + switch (Controller2State) + { + case 0: + if ((p2X & 0x40) == 0) value &= 0xFE; + if ((p2X & 0x80) == 0) value &= 0xFD; + break; + case 1: + if ((p2X & 0x04) == 0) value &= 0xFE; + if ((p2X & 0x08) == 0) value &= 0xFD; + break; + case 2: + if ((p2Y & 0x40) == 0) value &= 0xFE; + if ((p2Y & 0x80) == 0) value &= 0xFD; + break; + case 3: + if ((p2Y & 0x04) == 0) value &= 0xFE; + if ((p2Y & 0x08) == 0) value &= 0xFD; + break; + } + if (_region != "Japan") + { + // Buttons like normal in Export + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (_controller.IsPressed("P2 B2")) value &= 0xF7; + } + else + { + if (!Controller2SelectHigh) value &= 0xF7; + } + + PostsetControllerState(2); + } + break; + default: // Normal controller @@ -262,7 +499,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem const int phaserRadius = 4; // specifically lightgun needs to do things on a per-line basis - if (Settings.ControllerType == "Light Phaser") + if (SyncSettings.ControllerType == "Light Phaser") { byte phaserX = (byte)(_controller.GetFloat("P1 X") + 20); int phaserY = (int)_controller.GetFloat("P1 Y"); @@ -305,5 +542,49 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return value; } + + private void PresetControllerState(int pin) + { + // The 3F port's TH slot is also used on games in some games in Export BIOS to clock the paddle state + // Re: the paddle: Yes it's silly considering the paddle was never released outside Japan but the games think otherwise + + if (_region != "Japan") + { + if ((Port3F & 0x02) == 0x00) + { + Controller1SelectHigh = (Port3F & 0x20) != 0; + + // resync + Controller2State = 3; + } + + if ((Port3F & 0x08) == 0x00) + { + Controller2SelectHigh = (Port3F & 0x80) != 0; + + // resync + Controller1State = 3; + } + } + } + + private void PostsetControllerState(int pin) + { + // for the benefit of the Japan region + if (_region == "Japan" && (++ControllerTick) == 2) + { + ControllerTick = 0; + + if (pin == 1) + { + Controller1SelectHigh ^= true; + } + else + { + Controller1SelectHigh = false; + Controller2SelectHigh ^= true; + } + } + } } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs index 76fe7b8474..c751ca3623 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs @@ -10,7 +10,6 @@ using BizHawk.Emulation.Cores.Components.Z80A; TODO: + HCounter (Manually set for light phaser emulation... should be only case it's polled) + Try to clean up the organization of the source code. - + Lightgun/Paddle/etc if I get really bored (first 2 done!) + Mode 1 not implemented in VDP TMS modes. (I dont have a test case in SG1000 or Coleco) **********************************************************/