diff --git a/Assets/defctrl.json b/Assets/defctrl.json index 97a6a89116..b7454b80f0 100644 --- a/Assets/defctrl.json +++ b/Assets/defctrl.json @@ -748,7 +748,12 @@ "P1 Right": "RightArrow, J1 POV1R", "P1 B1": "Z, J1 B1, X1 X", "Reset": "J1 B9, X1 Back", - "Pause": "J1 B10, X1 Start", + "Pause": "J1 B10, X1 Start" + }, + "SMS Light Phaser Controller": { + "P1 Trigger": "Z, J1 B1, X1 X, WMouse L", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" }, "GG Controller": { "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", @@ -1581,6 +1586,18 @@ "Mult": 1.0, "Deadzone": 0.1 } + }, + "SMS Light Phaser Controller": { + "P1 X": { + "Value": "WMouse X", + "Mult": 1.0, + "Deadzone": 0.0 + }, + "P1 Y": { + "Value": "WMouse Y", + "Mult": 1.0, + "Deadzone": 0.0 + } } } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 82b6530b92..f497c44fca 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -445,6 +445,7 @@ this.SMSControllerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 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.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); @@ -2552,7 +2553,8 @@ this.SMSControllerToolStripMenuItem.Text = "&Controller Type"; this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.SMSControllerStandardToolStripMenuItem, - this.SMSControllerPaddleToolStripMenuItem}); + this.SMSControllerPaddleToolStripMenuItem, + this.SMSControllerLightPhaserToolStripMenuItem}); // // SMSControllerStandardToolStripMenuItem // @@ -2566,6 +2568,12 @@ this.SMSControllerPaddleToolStripMenuItem.Text = "Paddle"; this.SMSControllerPaddleToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerPaddleToolStripMenuItem_Click); // + // SMSControllerLightPhaserToolStripMenuItem + // + this.SMSControllerLightPhaserToolStripMenuItem.Name = "SMSControllerLightPhaserToolStripMenuItem"; + this.SMSControllerLightPhaserToolStripMenuItem.Text = "Light Phaser"; + this.SMSControllerLightPhaserToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerLightPhaserToolStripMenuItem_Click); + // // SMSdisplayPalToolStripMenuItem // this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; @@ -4395,5 +4403,6 @@ private System.Windows.Forms.ToolStripMenuItem SMSControllerToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SMSControllerStandardToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem SMSControllerPaddleToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index 8d1abdce5c..c5f4bc22dd 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1747,6 +1747,7 @@ namespace BizHawk.Client.EmuHawk SMSdisplayAutoToolStripMenuItem.Checked = ss.DisplayType == "Auto"; SMSControllerStandardToolStripMenuItem.Checked = s.ControllerType == "Standard"; SMSControllerPaddleToolStripMenuItem.Checked = s.ControllerType == "Paddle"; + SMSControllerLightPhaserToolStripMenuItem.Checked = s.ControllerType == "Light Phaser"; SMSenableBIOSToolStripMenuItem.Checked = ss.UseBIOS; SMSEnableFMChipMenuItem.Checked = ss.EnableFM; SMSOverclockMenuItem.Checked = ss.AllowOverlock; @@ -1915,6 +1916,13 @@ namespace BizHawk.Client.EmuHawk PutCoreSettings(s); } + private void SMSControllerLightPhaserToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSettings(); + s.ControllerType = "Light Phaser"; + 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 7b91f0bfba..86582d24ce 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -19,6 +19,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { case "Paddle": return SMSPaddleController; + case "Light Phaser": + // scale the vertical to the display mode + SMSLightPhaserController.FloatRanges[1] = new ControllerDefinition.FloatRange(0, Vdp.FrameHeight / 2, Vdp.FrameHeight - 1); + + return SMSLightPhaserController; default: return SmsController; } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs index 219612fb00..72f703980d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs @@ -73,6 +73,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ser.Sync("Port3F", ref Port3F); ser.Sync("Paddle1High", ref Paddle1High); ser.Sync("Paddle2High", ref Paddle2High); + 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 f2ec7ff6cd..fda3dcaa68 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs @@ -7,15 +7,15 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public partial class SMS { public static readonly ControllerDefinition SmsController = new ControllerDefinition - { - Name = "SMS Controller", - BoolButtons = + { + Name = "SMS Controller", + BoolButtons = { "Reset", "Pause", "P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 B1", "P1 B2", "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 B1", "P2 B2" } - }; + }; public static readonly ControllerDefinition GGController = new ControllerDefinition { @@ -48,6 +48,25 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } }; + public static readonly ControllerDefinition SMSLightPhaserController = new ControllerDefinition + { + Name = "SMS Light Phaser Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Trigger", + }, + FloatControls = + { + "P1 X", "P1 Y", + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(0, 64, 127), + new ControllerDefinition.FloatRange(0, 500, 1000) + } + }; + // The paddles have a nibble select state bool Paddle1High = false; bool Paddle2High = false; @@ -55,6 +74,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem const int PaddleMin = 0; const int PaddleMax = 255; + bool LatchLightPhaser = false; + private byte ReadControls1() { InputCallbacks.Call(); @@ -131,6 +152,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem break; + case "Light Phaser": + if (_controller.IsPressed("P1 Trigger")) value &= 0xEF; + break; + default: // Normal controller @@ -194,6 +219,14 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem break; + case "Light Phaser": + if (LatchLightPhaser) + { + value &= 0xBF; + LatchLightPhaser = false; + } + break; + default: // Normal controller @@ -224,6 +257,33 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return value; } + internal void ProcessLineControls() + { + const int phaserRadius = 4; + + // specifically lightgun needs to do things on a per-line basis + if (Settings.ControllerType == "Light Phaser") + { + byte phaserX = (byte)(_controller.GetFloat("P1 X") + 20); + int phaserY = (int)_controller.GetFloat("P1 Y"); + int scanline = Vdp.ScanLine; + + if (!LatchLightPhaser && phaserY >= scanline - phaserRadius && phaserY <= scanline + phaserRadius) + { + if (scanline >= Vdp.FrameHeight) + return; + + // latch HCounter via TH + Vdp.HCounter = phaserX; + LatchLightPhaser = true; + } + else + { + LatchLightPhaser = false; + } + } + } + byte ReadPort0() { if (IsGameGear == false) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs index 974c0f73b3..b3f51ba047 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs @@ -8,9 +8,9 @@ using BizHawk.Emulation.Cores.Components.Z80; /***************************************************** TODO: - + HCounter + + 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 + + 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) **********************************************************/ @@ -281,7 +281,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem if ((port & 1) == 0) return Vdp.ReadVLineCounter(); else - return 0x50; // TODO Vdp.ReadHLineCounter(); + return Vdp.ReadHLineCounter(); } if (port < 0xC0) // VDP data/control ports { diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs index 75d6d33625..7dcf21971b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs @@ -47,6 +47,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public int FrameHeight = 192; public int ScanLine; + public byte HCounter = 0x90; public int[] FrameBuffer = new int[256 * 192]; public int[] GameGearFrameBuffer = new int[160 * 144]; public int[] OverscanFrameBuffer = null; @@ -136,6 +137,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } } + public byte ReadHLineCounter() + { + return HCounter; + } + public void WriteVdpControl(byte value) { if (VdpWaitingForLatchByte) @@ -375,6 +381,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ProcessFrameInterrupt(); ProcessLineInterrupt(); + Sms.ProcessLineControls(); Cpu.ExecuteCycles(IPeriod); @@ -428,6 +435,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ser.Sync("Registers", ref Registers, false); ser.Sync("CRAM", ref CRAM, false); ser.Sync("VRAM", ref VRAM, false); + ser.Sync("HCounter", ref HCounter); ser.EndSection(); if (ser.IsReader)