SMS: bring controllers in line with other cores and fix virtual pads
This commit is contained in:
parent
bed5cc66ab
commit
bcd47a1ad9
|
@ -93,16 +93,11 @@ namespace BizHawk.Client.Common.movie.import
|
|||
byte[] md5 = r.ReadBytes(16);
|
||||
Result.Movie.HeaderEntries[Md5] = md5.BytesToHexString().ToLower();
|
||||
|
||||
var ss = new SMS.SmsSyncSettings
|
||||
{
|
||||
ControllerType = SMS.SmsSyncSettings.ControllerTypes.Standard
|
||||
};
|
||||
|
||||
var ss = new SMS.SmsSyncSettings();
|
||||
var cd = new SMSControllerDeck(ss.Port1, ss.Port2, isGameGear, ss.UseKeyboard);
|
||||
var controllers = new SimpleController
|
||||
{
|
||||
Definition = isGameGear
|
||||
? SMS.SmsController
|
||||
: SMS.GGController
|
||||
Definition = cd.Definition
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -7,38 +7,6 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsGameGear_C)
|
||||
{
|
||||
return GGController;
|
||||
}
|
||||
|
||||
// Sorta a hack but why not
|
||||
PortDEEnabled = SyncSettings.ControllerType == SmsSyncSettings.ControllerTypes.Keyboard;
|
||||
|
||||
switch(SyncSettings.ControllerType)
|
||||
{
|
||||
case SmsSyncSettings.ControllerTypes.Paddle:
|
||||
return SMSPaddleController;
|
||||
case SmsSyncSettings.ControllerTypes.LightPhaser:
|
||||
// scale the vertical to the display mode
|
||||
var axisName = SMSLightPhaserController.Axes[1];
|
||||
SMSLightPhaserController.Axes[axisName] = SMSLightPhaserController.Axes[axisName]
|
||||
.With(0.RangeTo(Vdp.FrameHeight - 1), Vdp.FrameHeight / 2);
|
||||
return SMSLightPhaserController;
|
||||
case SmsSyncSettings.ControllerTypes.SportsPad:
|
||||
return SMSSportsPadController;
|
||||
case SmsSyncSettings.ControllerTypes.Keyboard:
|
||||
return SMSKeyboardController;
|
||||
default:
|
||||
return SmsController;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not savestated variables
|
||||
private int s_L, s_R;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.ComponentModel;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||
{
|
||||
|
@ -80,9 +81,21 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
[DisplayName("Display Type")]
|
||||
public DisplayTypes DisplayType { get; set; } = DisplayTypes.Auto;
|
||||
|
||||
[DisplayName("Controller Type")]
|
||||
[Description("Currently controllers can not be configured separately")]
|
||||
public ControllerTypes ControllerType { get; set; } = ControllerTypes.Standard;
|
||||
[DisplayName("Use keyboard")]
|
||||
[Description("Enables keyboard for non-GG systems")]
|
||||
public bool UseKeyboard { get; set; } = false;
|
||||
|
||||
[DefaultValue(SMSControllerTypes.Standard)]
|
||||
[DisplayName("Port 1 Device")]
|
||||
[Description("The type of controller plugged into the first controller port")]
|
||||
[TypeConverter(typeof(DescribableEnumConverter))]
|
||||
public SMSControllerTypes Port1 { get; set; } = SMSControllerTypes.Standard;
|
||||
|
||||
[DefaultValue(SMSControllerTypes.Standard)]
|
||||
[DisplayName("Port 2 Device")]
|
||||
[Description("The type of controller plugged into the second controller port")]
|
||||
[TypeConverter(typeof(DescribableEnumConverter))]
|
||||
public SMSControllerTypes Port2 { get; set; } = SMSControllerTypes.Standard;
|
||||
|
||||
public SmsSyncSettings Clone() => (SmsSyncSettings)MemberwiseClone();
|
||||
|
||||
|
@ -94,7 +107,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
|| x.UseBios != y.UseBios
|
||||
|| x.ConsoleRegion != y.ConsoleRegion
|
||||
|| x.DisplayType != y.DisplayType
|
||||
|| x.ControllerType != y.ControllerType;
|
||||
|| x.UseKeyboard != y.UseKeyboard
|
||||
|| x.Port1 != y.Port1
|
||||
|| x.Port2 != y.Port2;
|
||||
}
|
||||
|
||||
public enum ControllerTypes
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
Cpu.SyncState(ser);
|
||||
Vdp.SyncState(ser);
|
||||
PSG.SyncState(ser);
|
||||
_controllerDeck.SyncState(ser);
|
||||
ser.Sync("RAM", ref SystemRam, false);
|
||||
ser.Sync(nameof(RomBank0), ref RomBank0);
|
||||
ser.Sync(nameof(RomBank1), ref RomBank1);
|
||||
|
@ -32,9 +33,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
ser.Sync(nameof(Port05), ref Port05);
|
||||
ser.Sync(nameof(Port3E), ref Port3E);
|
||||
ser.Sync(nameof(Port3F), ref Port3F);
|
||||
ser.Sync(nameof(Controller1SelectHigh), ref Controller1SelectHigh);
|
||||
ser.Sync(nameof(Controller2SelectHigh), ref Controller2SelectHigh);
|
||||
ser.Sync(nameof(LatchLightPhaser), ref LatchLightPhaser);
|
||||
ser.Sync(nameof(LatchLightPhaser1), ref LatchLightPhaser1);
|
||||
ser.Sync(nameof(LatchLightPhaser2), ref LatchLightPhaser2);
|
||||
ser.Sync(nameof(ControllerTick), ref ControllerTick);
|
||||
ser.Sync(nameof(start_pressed), ref start_pressed);
|
||||
ser.Sync(nameof(cntr_rd_0), ref cntr_rd_0);
|
||||
ser.Sync(nameof(cntr_rd_1), ref cntr_rd_1);
|
||||
|
|
|
@ -6,78 +6,6 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
{
|
||||
public partial class SMS
|
||||
{
|
||||
public static readonly ControllerDefinition SmsController = new ControllerDefinition
|
||||
{
|
||||
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
|
||||
{
|
||||
Name = "GG Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"Reset",
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 B1", "P1 B2", "P1 Start"
|
||||
}
|
||||
};
|
||||
|
||||
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",
|
||||
}
|
||||
}.AddAxis("P1 Paddle", 0.RangeTo(255), 128)
|
||||
.AddAxis("P2 Paddle", 0.RangeTo(255), 128);
|
||||
|
||||
public static readonly ControllerDefinition SMSLightPhaserController = new ControllerDefinition
|
||||
{
|
||||
Name = "SMS Light Phaser Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"Reset", "Pause",
|
||||
"P1 Trigger"
|
||||
}
|
||||
}.AddXYPair("P1 {0}", AxisPairOrientation.RightAndUp, 0.RangeTo(127), 64, 0.RangeTo(1000), 500); //TODO verify direction against hardware
|
||||
|
||||
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"
|
||||
}
|
||||
}.AddXYPair("P1 {0}", AxisPairOrientation.RightAndUp, (-64).RangeTo(63), 0) //TODO verify direction against hardware
|
||||
.AddXYPair("P2 {0}", AxisPairOrientation.RightAndUp, (-64).RangeTo(63), 0); //TODO ditto
|
||||
|
||||
public static readonly ControllerDefinition SMSKeyboardController = new ControllerDefinition
|
||||
{
|
||||
Name = "SMS Keyboard Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
"Key 1", "Key 2", "Key 3", "Key 4", "Key 5", "Key 6", "Key 7", "Key 8", "Key 9", "Key 0", "Key Minus", "Key Caret", "Key Yen", "Key Break",
|
||||
"Key Function", "Key Q", "Key W", "Key E", "Key R", "Key T", "Key Y", "Key U", "Key I", "Key O", "Key P", "Key At", "Key Left Bracket", "Key Return", "Key Up Arrow",
|
||||
"Key Control", "Key A", "Key S", "Key D", "Key F", "Key G", "Key H", "Key J", "Key K", "Key L", "Key Semicolon", "Key Colon", "Key Right Bracket", "Key Left Arrow", "Key Right Arrow",
|
||||
"Key Shift", "Key Z", "Key X", "Key C", "Key V", "Key B", "Key N", "Key M", "Key Comma", "Key Period", "Key Slash", "Key PI", "Key Down Arrow",
|
||||
"Key Graph", "Key Kana", "Key Space", "Key Home/Clear", "Key Insert/Delete",
|
||||
|
||||
"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"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly string[] KeyboardMap =
|
||||
{
|
||||
"Key 1", "Key Q", "Key A", "Key Z", "Key Kana", "Key Comma", "Key K", "Key I", "Key 8", null, null, null,
|
||||
|
@ -90,20 +18,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 B1", "P1 B2", "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 B1", "P2 B2"
|
||||
};
|
||||
|
||||
private const int PaddleMin = 0;
|
||||
private const int PaddleMax = 255;
|
||||
private const int SportsPadMin = -64;
|
||||
private const int SportsPadMax = 63;
|
||||
private bool LatchLightPhaser1 = false;
|
||||
private bool LatchLightPhaser2 = false;
|
||||
|
||||
// The paddles and sports pads have data select states
|
||||
private bool Controller1SelectHigh = true;
|
||||
private bool Controller2SelectHigh = true;
|
||||
|
||||
private bool LatchLightPhaser = false;
|
||||
|
||||
// further state value for sports pad, may be useful for other controllers in future
|
||||
private int Controller1State = 3;
|
||||
private int Controller2State = 3;
|
||||
private int ControllerTick = 0; // for timing in japan
|
||||
|
||||
private byte ReadControls1()
|
||||
|
@ -112,247 +29,32 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
_lagged = false;
|
||||
byte value = 0xFF;
|
||||
|
||||
switch (SyncSettings.ControllerType)
|
||||
PresetControllerState(1);
|
||||
// Hard-wired together for paddles?
|
||||
_controllerDeck.SetPin_c2(_controller, _controllerDeck.GetPin_c1(_controller));
|
||||
|
||||
value &= _controllerDeck.ReadPort1_c1(_controller);
|
||||
value &= _controllerDeck.ReadPort1_c2(_controller);
|
||||
|
||||
PostsetControllerState(1);
|
||||
|
||||
if (!IsGameGear_C && SyncSettings.UseKeyboard)
|
||||
{
|
||||
case SmsSyncSettings.ControllerTypes.Paddle:
|
||||
// 7 represents ordinary controller reads
|
||||
if ((PortDE & 7) != 7)
|
||||
{
|
||||
value = 0xFF;
|
||||
|
||||
for (int bit = 0; bit < 8; ++bit)
|
||||
{
|
||||
// use analog values from a controller, see http://www.smspower.org/Development/Paddle
|
||||
string key = KeyboardMap[(PortDE & 0x07) * 12 + bit];
|
||||
|
||||
int paddle1Pos;
|
||||
if (_controller.IsPressed("P1 Left"))
|
||||
paddle1Pos = PaddleMin;
|
||||
else if (_controller.IsPressed("P1 Right"))
|
||||
paddle1Pos = PaddleMax;
|
||||
else
|
||||
paddle1Pos = (int)_controller.AxisValue("P1 Paddle");
|
||||
|
||||
int paddle2Pos;
|
||||
if (_controller.IsPressed("P2 Left"))
|
||||
paddle2Pos = PaddleMin;
|
||||
else if (_controller.IsPressed("P2 Right"))
|
||||
paddle2Pos = PaddleMax;
|
||||
else
|
||||
paddle2Pos = (int)_controller.AxisValue("P2 Paddle");
|
||||
|
||||
PresetControllerState(1);
|
||||
// Hard-wired together?
|
||||
Controller2SelectHigh = Controller1SelectHigh;
|
||||
|
||||
if (Controller1SelectHigh)
|
||||
if (key != null && _controller.IsPressed(key))
|
||||
{
|
||||
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 (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;
|
||||
}
|
||||
|
||||
PostsetControllerState(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case SmsSyncSettings.ControllerTypes.LightPhaser:
|
||||
if (_controller.IsPressed("P1 Trigger")) value &= 0xEF;
|
||||
break;
|
||||
|
||||
case SmsSyncSettings.ControllerTypes.SportsPad:
|
||||
{
|
||||
int p1X;
|
||||
if (_controller.IsPressed("P1 Left"))
|
||||
p1X = SportsPadMin;
|
||||
else if (_controller.IsPressed("P1 Right"))
|
||||
p1X = SportsPadMax;
|
||||
else
|
||||
p1X = (int)_controller.AxisValue("P1 X");
|
||||
|
||||
int p1Y;
|
||||
if (_controller.IsPressed("P1 Up"))
|
||||
p1Y = SportsPadMin;
|
||||
else if (_controller.IsPressed("P1 Down"))
|
||||
p1Y = SportsPadMax;
|
||||
else
|
||||
p1Y = (int)_controller.AxisValue("P1 Y");
|
||||
|
||||
int p2X;
|
||||
if (_controller.IsPressed("P2 Left"))
|
||||
p2X = SportsPadMin;
|
||||
else if (_controller.IsPressed("P2 Right"))
|
||||
p2X = SportsPadMax;
|
||||
else
|
||||
p2X = (int)_controller.AxisValue("P2 X");
|
||||
|
||||
int p2Y;
|
||||
if (_controller.IsPressed("P2 Up"))
|
||||
p2Y = SportsPadMin;
|
||||
else if (_controller.IsPressed("P2 Down"))
|
||||
p2Y = SportsPadMax;
|
||||
else
|
||||
p2Y = (int)_controller.AxisValue("P2 Y");
|
||||
|
||||
if (_region == SmsSyncSettings.Regions.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 == SmsSyncSettings.Regions.Japan ? 6 : 4))
|
||||
Controller1State = 0;
|
||||
}
|
||||
if (Controller2SelectHigh && (Controller2State % 2 == 0))
|
||||
{
|
||||
++Controller2State;
|
||||
}
|
||||
else if (!Controller2SelectHigh && (Controller2State % 2 == 1))
|
||||
{
|
||||
if (++Controller2State == (_region == SmsSyncSettings.Regions.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 != SmsSyncSettings.Regions.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;
|
||||
|
||||
case SmsSyncSettings.ControllerTypes.Keyboard:
|
||||
{
|
||||
// use keyboard map to get each bit
|
||||
|
||||
for (int bit = 0; bit < 8; ++bit)
|
||||
{
|
||||
string key = KeyboardMap[(PortDE & 0x07) * 12 + bit];
|
||||
|
||||
if (key != null && _controller.IsPressed(key))
|
||||
{
|
||||
value &= (byte)~(1 << bit);
|
||||
}
|
||||
value &= (byte)~(1 << bit);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -364,150 +66,12 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
_lagged = false;
|
||||
byte value = 0xFF;
|
||||
|
||||
switch (SyncSettings.ControllerType)
|
||||
{
|
||||
case SmsSyncSettings.ControllerTypes.Paddle:
|
||||
{
|
||||
// use analog values from a controller, see http://www.smspower.org/Development/Paddle
|
||||
PresetControllerState(2);
|
||||
|
||||
int paddle2Pos;
|
||||
if (_controller.IsPressed("P2 Left"))
|
||||
paddle2Pos = PaddleMin;
|
||||
else if (_controller.IsPressed("P2 Right"))
|
||||
paddle2Pos = PaddleMax;
|
||||
else
|
||||
paddle2Pos = (int)_controller.AxisValue("P2 Paddle");
|
||||
value &= _controllerDeck.ReadPort2_c1(_controller);
|
||||
value &= _controllerDeck.ReadPort2_c2(_controller);
|
||||
|
||||
PresetControllerState(2);
|
||||
|
||||
if (Controller2SelectHigh)
|
||||
{
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
case SmsSyncSettings.ControllerTypes.LightPhaser:
|
||||
if (LatchLightPhaser)
|
||||
{
|
||||
value &= 0xBF;
|
||||
LatchLightPhaser = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SmsSyncSettings.ControllerTypes.SportsPad:
|
||||
{
|
||||
int p2X;
|
||||
if (_controller.IsPressed("P2 Left"))
|
||||
p2X = SportsPadMin;
|
||||
else if (_controller.IsPressed("P2 Right"))
|
||||
p2X = SportsPadMax;
|
||||
else
|
||||
p2X = (int)_controller.AxisValue("P2 X");
|
||||
|
||||
int p2Y;
|
||||
if (_controller.IsPressed("P2 Down"))
|
||||
p2Y = SportsPadMin;
|
||||
else if (_controller.IsPressed("P2 Up"))
|
||||
p2Y = SportsPadMax;
|
||||
else
|
||||
p2Y = (int)_controller.AxisValue("P2 Y");
|
||||
|
||||
if (_region == SmsSyncSettings.Regions.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 == SmsSyncSettings.Regions.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 != SmsSyncSettings.Regions.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;
|
||||
|
||||
case SmsSyncSettings.ControllerTypes.Keyboard:
|
||||
{
|
||||
value &= 0x7F;
|
||||
|
||||
// use keyboard map to get each bit
|
||||
|
||||
for (int bit = 0; bit < 4; ++bit)
|
||||
{
|
||||
string key = KeyboardMap[(PortDE & 0x07) * 12 + bit + 8];
|
||||
|
||||
if (key != null && _controller.IsPressed(key))
|
||||
{
|
||||
value &= (byte)~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
PostsetControllerState(2);
|
||||
|
||||
if (_controller.IsPressed("Reset")) value &= 0xEF;
|
||||
|
||||
|
@ -526,6 +90,37 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
}
|
||||
}
|
||||
|
||||
if (LatchLightPhaser1)
|
||||
{
|
||||
value &= 0xBF;
|
||||
LatchLightPhaser1 = false;
|
||||
}
|
||||
|
||||
if (LatchLightPhaser2)
|
||||
{
|
||||
value &= 0x7F;
|
||||
LatchLightPhaser2 = false;
|
||||
}
|
||||
|
||||
if (!IsGameGear_C && SyncSettings.UseKeyboard)
|
||||
{
|
||||
// 7 represents ordinary controller reads
|
||||
if ((PortDE & 7) != 7)
|
||||
{
|
||||
value = 0x7F;
|
||||
|
||||
for (int bit = 0; bit < 4; ++bit)
|
||||
{
|
||||
string key = KeyboardMap[(PortDE & 0x07) * 12 + bit + 8];
|
||||
|
||||
if (key != null && _controller.IsPressed(key))
|
||||
{
|
||||
value &= (byte)~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -534,24 +129,48 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
const int phaserRadius = 4;
|
||||
|
||||
// specifically lightgun needs to do things on a per-line basis
|
||||
if (SyncSettings.ControllerType == SmsSyncSettings.ControllerTypes.LightPhaser)
|
||||
if (!IsGameGear_C)
|
||||
{
|
||||
byte phaserX = (byte)(_controller.AxisValue("P1 X") + 20);
|
||||
int phaserY = (int)_controller.AxisValue("P1 Y");
|
||||
int scanline = Vdp.ScanLine;
|
||||
|
||||
if (!LatchLightPhaser && phaserY >= scanline - phaserRadius && phaserY <= scanline + phaserRadius)
|
||||
if (SyncSettings.Port1 == SMSControllerTypes.Phaser)
|
||||
{
|
||||
if (scanline >= Vdp.FrameHeight)
|
||||
return;
|
||||
byte phaserX = (byte)(_controller.AxisValue("P1 X") + 20);
|
||||
int phaserY = (int)_controller.AxisValue("P1 Y");
|
||||
int scanline = Vdp.ScanLine;
|
||||
|
||||
// latch HCounter via TH
|
||||
Vdp.HCounter = phaserX;
|
||||
LatchLightPhaser = true;
|
||||
if (!LatchLightPhaser1 && phaserY >= scanline - phaserRadius && phaserY <= scanline + phaserRadius)
|
||||
{
|
||||
if (scanline >= Vdp.FrameHeight)
|
||||
return;
|
||||
|
||||
// latch HCounter via TH
|
||||
Vdp.HCounter = phaserX;
|
||||
LatchLightPhaser1 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LatchLightPhaser1 = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (SyncSettings.Port2 == SMSControllerTypes.Phaser)
|
||||
{
|
||||
LatchLightPhaser = false;
|
||||
byte phaserX = (byte)(_controller.AxisValue("P2 X") + 20);
|
||||
int phaserY = (int)_controller.AxisValue("P2 Y");
|
||||
int scanline = Vdp.ScanLine;
|
||||
|
||||
if (!LatchLightPhaser2 && phaserY >= scanline - phaserRadius && phaserY <= scanline + phaserRadius)
|
||||
{
|
||||
if (scanline >= Vdp.FrameHeight)
|
||||
return;
|
||||
|
||||
// latch HCounter via TH
|
||||
Vdp.HCounter = phaserX;
|
||||
LatchLightPhaser2 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LatchLightPhaser2 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -589,18 +208,18 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
{
|
||||
if ((Port3F & 0x02) == 0x00)
|
||||
{
|
||||
Controller1SelectHigh = (Port3F & 0x20) != 0;
|
||||
_controllerDeck.SetPin_c1(_controller, (Port3F & 0x20) != 0);
|
||||
|
||||
// resync
|
||||
Controller2State = 3;
|
||||
_controllerDeck.SetCounter_c2(_controller, 3);
|
||||
}
|
||||
|
||||
if ((Port3F & 0x08) == 0x00)
|
||||
{
|
||||
Controller2SelectHigh = (Port3F & 0x80) != 0;
|
||||
_controllerDeck.SetPin_c2(_controller, (Port3F & 0x80) != 0);
|
||||
|
||||
// resync
|
||||
Controller1State = 3;
|
||||
_controllerDeck.SetCounter_c1(_controller, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -614,12 +233,15 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
|
||||
if (pin == 1)
|
||||
{
|
||||
Controller1SelectHigh ^= true;
|
||||
bool temp = _controllerDeck.GetPin_c1(_controller);
|
||||
_controllerDeck.SetPin_c1(_controller, temp ^ true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Controller1SelectHigh = false;
|
||||
Controller2SelectHigh ^= true;
|
||||
_controllerDeck.SetPin_c1(_controller, false);
|
||||
|
||||
bool temp = _controllerDeck.GetPin_c2(_controller);
|
||||
_controllerDeck.SetPin_c2(_controller, temp ^ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,6 +213,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
{
|
||||
ser.Register<ISmsGpuView>(new SmsGpuView(Vdp));
|
||||
}
|
||||
|
||||
_controllerDeck = new SMSControllerDeck(syncSettings.Port1, syncSettings.Port2, IsGameGear_C, syncSettings.UseKeyboard);
|
||||
|
||||
// Sorta a hack but why not
|
||||
PortDEEnabled = syncSettings.UseKeyboard && !IsGameGear_C;
|
||||
|
||||
_controllerDeck.SetRegion(_controller, _region == SmsSyncSettings.Regions.Japan);
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
|
@ -421,6 +428,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
|||
else if (port == 0xF2 && HasYM2413) YM2413.DetectionValue = value;
|
||||
}
|
||||
|
||||
private readonly SMSControllerDeck _controllerDeck;
|
||||
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
|
||||
|
||||
private readonly SmsSyncSettings.Regions _region;
|
||||
|
||||
public class SmsGpuView : ISmsGpuView
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||
{
|
||||
public class SMSControllerDeck
|
||||
{
|
||||
public SMSControllerDeck(SMSControllerTypes controller1, SMSControllerTypes controller2, bool is_GG, bool use_keyboard)
|
||||
{
|
||||
if (is_GG)
|
||||
{
|
||||
Port1 = new GGController(1);
|
||||
// Port 2 is defined, but not used for Game Gear
|
||||
Port2 = new GGController(2);
|
||||
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = Port1.Definition.Name,
|
||||
|
||||
BoolButtons = new[] { "Reset" }
|
||||
.Concat(Port1.Definition.BoolButtons)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
Port1 = ControllerCtors[controller1](1);
|
||||
Port2 = ControllerCtors[controller2](2);
|
||||
|
||||
if (!use_keyboard)
|
||||
{
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = Port1.Definition.Name,
|
||||
|
||||
BoolButtons = new[] { "Reset", "Pause" }
|
||||
.Concat(Port1.Definition.BoolButtons)
|
||||
.Concat(Port2.Definition.BoolButtons)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = Port1.Definition.Name,
|
||||
|
||||
BoolButtons = new[] { "Reset", "Pause" }
|
||||
.Concat(Port1.Definition.BoolButtons)
|
||||
.Concat(Port2.Definition.BoolButtons)
|
||||
.Concat(KeyboardMap)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var kvp in Port1.Definition.Axes) Definition.Axes.Add(kvp);
|
||||
foreach (var kvp in Port2.Definition.Axes) Definition.Axes.Add(kvp);
|
||||
}
|
||||
}
|
||||
|
||||
public byte ReadPort1_c1(IController c)
|
||||
{
|
||||
return Port1.Read_p1_c1(c);
|
||||
}
|
||||
|
||||
public byte ReadPort1_c2(IController c)
|
||||
{
|
||||
return Port2.Read_p1_c2(c);
|
||||
}
|
||||
|
||||
public byte ReadPort2_c1(IController c)
|
||||
{
|
||||
return Port1.Read_p2_c1(c);
|
||||
}
|
||||
|
||||
public byte ReadPort2_c2(IController c)
|
||||
{
|
||||
return Port2.Read_p2_c2(c);
|
||||
}
|
||||
|
||||
public bool GetPin_c1(IController c)
|
||||
{
|
||||
return Port1.PinStateGet(c);
|
||||
}
|
||||
|
||||
public bool GetPin_c2(IController c)
|
||||
{
|
||||
return Port2.PinStateGet(c);
|
||||
}
|
||||
|
||||
public void SetPin_c1(IController c, bool val)
|
||||
{
|
||||
Port1.PinStateSet(c, val);
|
||||
}
|
||||
|
||||
public void SetPin_c2(IController c, bool val)
|
||||
{
|
||||
Port2.PinStateSet(c, val);
|
||||
}
|
||||
|
||||
public void SetCounter_c1(IController c, int val)
|
||||
{
|
||||
Port1.CounterSet(c, val);
|
||||
}
|
||||
|
||||
public void SetCounter_c2(IController c, int val)
|
||||
{
|
||||
Port2.CounterSet(c, val);
|
||||
}
|
||||
|
||||
public void SetRegion(IController c, bool val)
|
||||
{
|
||||
Port1.RegionSet(c, val);
|
||||
Port2.RegionSet(c, val);
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection(nameof(Port1));
|
||||
Port1.SyncState(ser);
|
||||
Port2.SyncState(ser);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
private readonly IPort Port1, Port2;
|
||||
|
||||
private static IReadOnlyDictionary<SMSControllerTypes, Func<int, IPort>> _controllerCtors;
|
||||
|
||||
public static IReadOnlyDictionary<SMSControllerTypes, Func<int, IPort>> ControllerCtors => _controllerCtors
|
||||
??= new Dictionary<SMSControllerTypes, Func<int, IPort>>
|
||||
{
|
||||
[SMSControllerTypes.Standard] = portNum => new SmsController(portNum),
|
||||
[SMSControllerTypes.Paddle] = portNum => new SMSPaddleController(portNum),
|
||||
[SMSControllerTypes.SportsPad] = portNum => new SMSSportsPadController(portNum),
|
||||
[SMSControllerTypes.Phaser] = portNum => new SMSLightPhaserController(portNum),
|
||||
};
|
||||
|
||||
public static string DefaultControllerName => typeof(SmsController).DisplayName();
|
||||
|
||||
private static readonly string[] KeyboardMap =
|
||||
{
|
||||
"Key 1", "Key Q", "Key A", "Key Z", "Key Kana", "Key Comma", "Key K", "Key I", "Key 8", null, null, null,
|
||||
"Key 2", "Key W", "Key S", "Key X", "Key Space", "Key Period", "Key L", "Key O", "Key 9", null, null, null,
|
||||
"Key 3", "Key E", "Key D", "Key C", "Key Home/Clear", "Key Slash", "Key Semicolon", "Key P", "Key 0", null, null, null,
|
||||
"Key 4", "Key R", "Key F", "Key V", "Key Insert/Delete", "Key PI", "Key Colon", "Key At", "Key Minus", null, null, null,
|
||||
"Key 5", "Key T", "Key G", "Key B", null, "Key Down Arrow", "Key Right Bracket", "Key Left Bracket", "Key Caret", null, null, null,
|
||||
"Key 6", "Key Y", "Key H", "Key N", null, "Key Left Arrow", "Key Return", null, "Key Yen", null, null, "Key Function",
|
||||
"Key 7", "Key U", "Key J", "Key M", null, "Key Right Arrow", "Key Up Arrow", null, "Key Break", "Key Graph", "Key Control", "Key Shift",
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 B1", "P1 B2", "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 B1", "P2 B2"
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,690 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||
{
|
||||
public enum SMSControllerTypes
|
||||
{
|
||||
Standard,
|
||||
Paddle,
|
||||
SportsPad,
|
||||
Phaser
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a SMS controller
|
||||
/// </summary>
|
||||
public interface IPort
|
||||
{
|
||||
byte Read_p1_c1(IController c);
|
||||
|
||||
byte Read_p1_c2(IController c);
|
||||
|
||||
byte Read_p2_c1(IController c);
|
||||
|
||||
byte Read_p2_c2(IController c);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
void SyncState(Serializer ser);
|
||||
|
||||
int PortNum { get; }
|
||||
|
||||
bool PinStateGet(IController c);
|
||||
|
||||
void PinStateSet(IController c, bool val);
|
||||
|
||||
void CounterSet(IController c, int val);
|
||||
|
||||
void RegionSet(IController c, bool val);
|
||||
}
|
||||
|
||||
[DisplayName("Standarad Controller")]
|
||||
public class SmsController : IPort
|
||||
{
|
||||
public SmsController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "SMS Controller",
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read_p1_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0])) result &= 0xFE;
|
||||
if (c.IsPressed(Definition.BoolButtons[1])) result &= 0xFD;
|
||||
if (c.IsPressed(Definition.BoolButtons[2])) result &= 0xFB;
|
||||
if (c.IsPressed(Definition.BoolButtons[3])) result &= 0xF7;
|
||||
if (c.IsPressed(Definition.BoolButtons[4])) result &= 0xEF;
|
||||
if (c.IsPressed(Definition.BoolButtons[5])) result &= 0xDF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p1_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0])) result &= 0xBF;
|
||||
if (c.IsPressed(Definition.BoolButtons[1])) result &= 0x7F;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[2])) result &= 0xFE;
|
||||
if (c.IsPressed(Definition.BoolButtons[3])) result &= 0xFD;
|
||||
if (c.IsPressed(Definition.BoolButtons[4])) result &= 0xFB;
|
||||
if (c.IsPressed(Definition.BoolButtons[5])) result &= 0xF7;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool PinStateGet(IController c) { return false; }
|
||||
|
||||
public void PinStateSet(IController c, bool val) { }
|
||||
|
||||
public void CounterSet(IController c, int val) { }
|
||||
|
||||
public void RegionSet(IController c, bool val) { }
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "B1", "B2"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("Game Gear Controller")]
|
||||
public class GGController : IPort
|
||||
{
|
||||
public GGController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "GG Controller",
|
||||
BoolButtons = BaseDefinition
|
||||
.Select(b => "P" + PortNum + " " + b)
|
||||
.ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read_p1_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0])) result &= 0xFE;
|
||||
if (c.IsPressed(Definition.BoolButtons[1])) result &= 0xFD;
|
||||
if (c.IsPressed(Definition.BoolButtons[2])) result &= 0xFB;
|
||||
if (c.IsPressed(Definition.BoolButtons[3])) result &= 0xF7;
|
||||
if (c.IsPressed(Definition.BoolButtons[4])) result &= 0xEF;
|
||||
if (c.IsPressed(Definition.BoolButtons[5])) result &= 0xDF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p1_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool PinStateGet(IController c) { return false; }
|
||||
|
||||
public void PinStateSet(IController c, bool val) { }
|
||||
|
||||
public void CounterSet(IController c, int val) { }
|
||||
|
||||
public void RegionSet(IController c, bool val) { }
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "B1", "B2", "Start"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("SMS Paddle Controller")]
|
||||
public class SMSPaddleController : IPort
|
||||
{
|
||||
public SMSPaddleController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "SMS Paddle Controller",
|
||||
BoolButtons = BaseDefinition.Select(b => $"P{PortNum} {b}").ToList()
|
||||
}.AddAxis($"P{PortNum} Paddle", 0.RangeTo(255), 128);
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public bool pin;
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read_p1_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
int paddle1Pos;
|
||||
if (c.IsPressed("P1 Left"))
|
||||
paddle1Pos = 0;
|
||||
else if (c.IsPressed("P1 Right"))
|
||||
paddle1Pos = 255;
|
||||
else
|
||||
paddle1Pos = (int)c.AxisValue("P1 Paddle");
|
||||
|
||||
if (pin)
|
||||
{
|
||||
if ((paddle1Pos & 0x10) == 0) result &= 0xFE;
|
||||
if ((paddle1Pos & 0x20) == 0) result &= 0xFD;
|
||||
if ((paddle1Pos & 0x40) == 0) result &= 0xFB;
|
||||
if ((paddle1Pos & 0x80) == 0) result &= 0xF7;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((paddle1Pos & 0x01) == 0) result &= 0xFE;
|
||||
if ((paddle1Pos & 0x02) == 0) result &= 0xFD;
|
||||
if ((paddle1Pos & 0x04) == 0) result &= 0xFB;
|
||||
if ((paddle1Pos & 0x08) == 0) result &= 0xF7;
|
||||
}
|
||||
|
||||
if (c.IsPressed("P1 B1")) result &= 0xEF;
|
||||
if (!pin) result &= 0xDF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p1_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
int paddle2Pos;
|
||||
if (c.IsPressed("P2 Left"))
|
||||
paddle2Pos = 0;
|
||||
else if (c.IsPressed("P2 Right"))
|
||||
paddle2Pos = 255;
|
||||
else
|
||||
paddle2Pos = (int)c.AxisValue("P2 Paddle");
|
||||
|
||||
if (pin)
|
||||
{
|
||||
if ((paddle2Pos & 0x10) == 0) result &= 0xBF;
|
||||
if ((paddle2Pos & 0x20) == 0) result &= 0x7F;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((paddle2Pos & 0x01) == 0) result &= 0xBF;
|
||||
if ((paddle2Pos & 0x02) == 0) result &= 0x7F;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
int paddle2Pos;
|
||||
if (c.IsPressed("P2 Left"))
|
||||
paddle2Pos = 0;
|
||||
else if (c.IsPressed("P2 Right"))
|
||||
paddle2Pos = 255;
|
||||
else
|
||||
paddle2Pos = (int)c.AxisValue("P2 Paddle");
|
||||
|
||||
if (pin)
|
||||
{
|
||||
if ((paddle2Pos & 0x40) == 0) result &= 0xFE;
|
||||
if ((paddle2Pos & 0x80) == 0) result &= 0xFD;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((paddle2Pos & 0x04) == 0) result &= 0xFE;
|
||||
if ((paddle2Pos & 0x08) == 0) result &= 0xFD;
|
||||
}
|
||||
|
||||
if (c.IsPressed("P2 B1")) result &= 0xFB;
|
||||
if (!pin) result &= 0xF7;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool PinStateGet(IController c) { return pin; }
|
||||
|
||||
public void PinStateSet(IController c, bool val) { pin = val;}
|
||||
|
||||
public void CounterSet(IController c, int val) { }
|
||||
|
||||
public void RegionSet(IController c, bool val) { }
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Left", "Right", "B1"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(pin), ref pin);
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("SMS Sports Pad Controller")]
|
||||
public class SMSSportsPadController : IPort
|
||||
{
|
||||
public SMSSportsPadController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "SMS Sports Pad Controller",
|
||||
BoolButtons = BaseDefinition.Select(b => $"P{PortNum} {b}").ToList()
|
||||
}.AddXYPair($"P{PortNum} {{0}}", AxisPairOrientation.RightAndUp, (-64).RangeTo(63), 0); //TODO verify direction against hardware
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
private const int SportsPadMin = -64;
|
||||
private const int SportsPadMax = 63;
|
||||
|
||||
public bool pin;
|
||||
// further state value for sports pad, may be useful for other controllers in future
|
||||
private int ControllerCounter = 3;
|
||||
private bool is_JPN;
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read_p1_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
int p1X;
|
||||
if (c.IsPressed("P1 Left"))
|
||||
p1X = SportsPadMin;
|
||||
else if (c.IsPressed("P1 Right"))
|
||||
p1X = SportsPadMax;
|
||||
else
|
||||
p1X = (int)c.AxisValue("P1 X");
|
||||
|
||||
int p1Y;
|
||||
if (c.IsPressed("P1 Up"))
|
||||
p1Y = SportsPadMin;
|
||||
else if (c.IsPressed("P1 Down"))
|
||||
p1Y = SportsPadMax;
|
||||
else
|
||||
p1Y = (int)c.AxisValue("P1 Y");
|
||||
|
||||
if (is_JPN)
|
||||
{
|
||||
p1X += 128;
|
||||
p1Y += 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1X *= -1;
|
||||
p1Y *= -1;
|
||||
}
|
||||
|
||||
// advance state
|
||||
if (pin && (ControllerCounter % 2 == 0))
|
||||
{
|
||||
++ControllerCounter;
|
||||
}
|
||||
else if (!pin && (ControllerCounter % 2 == 1))
|
||||
{
|
||||
if (++ControllerCounter == (is_JPN ? 6 : 4))
|
||||
ControllerCounter = 0;
|
||||
}
|
||||
|
||||
switch (ControllerCounter)
|
||||
{
|
||||
case 0:
|
||||
if ((p1X & 0x10) == 0) result &= 0xFE;
|
||||
if ((p1X & 0x20) == 0) result &= 0xFD;
|
||||
if ((p1X & 0x40) == 0) result &= 0xFB;
|
||||
if ((p1X & 0x80) == 0) result &= 0xF7;
|
||||
break;
|
||||
case 1:
|
||||
if ((p1X & 0x01) == 0) result &= 0xFE;
|
||||
if ((p1X & 0x02) == 0) result &= 0xFD;
|
||||
if ((p1X & 0x04) == 0) result &= 0xFB;
|
||||
if ((p1X & 0x08) == 0) result &= 0xF7;
|
||||
break;
|
||||
case 2:
|
||||
if ((p1Y & 0x10) == 0) result &= 0xFE;
|
||||
if ((p1Y & 0x20) == 0) result &= 0xFD;
|
||||
if ((p1Y & 0x40) == 0) result &= 0xFB;
|
||||
if ((p1Y & 0x80) == 0) result &= 0xF7;
|
||||
break;
|
||||
case 3:
|
||||
if ((p1Y & 0x01) == 0) result &= 0xFE;
|
||||
if ((p1Y & 0x02) == 0) result &= 0xFD;
|
||||
if ((p1Y & 0x04) == 0) result &= 0xFB;
|
||||
if ((p1Y & 0x08) == 0) result &= 0xF7;
|
||||
break;
|
||||
case 4:
|
||||
// specific to Japan: sync via TR
|
||||
result &= 0xDF;
|
||||
break;
|
||||
case 5:
|
||||
// specific to Japan: buttons
|
||||
if (c.IsPressed("P1 B1")) result &= 0xFE;
|
||||
if (c.IsPressed("P1 B2")) result &= 0xFD;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_JPN)
|
||||
{
|
||||
// Buttons like normal in Export
|
||||
if (c.IsPressed("P1 B1")) result &= 0xEF;
|
||||
if (c.IsPressed("P1 B2")) result &= 0xDF;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In Japan, it contains selectHigh
|
||||
if (!pin) result &= 0xEF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p1_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
int p2X;
|
||||
if (c.IsPressed("P2 Left"))
|
||||
p2X = SportsPadMin;
|
||||
else if (c.IsPressed("P2 Right"))
|
||||
p2X = SportsPadMax;
|
||||
else
|
||||
p2X = (int)c.AxisValue("P2 X");
|
||||
|
||||
int p2Y;
|
||||
if (c.IsPressed("P2 Up"))
|
||||
p2Y = SportsPadMin;
|
||||
else if (c.IsPressed("P2 Down"))
|
||||
p2Y = SportsPadMax;
|
||||
else
|
||||
p2Y = (int)c.AxisValue("P2 Y");
|
||||
|
||||
if (is_JPN)
|
||||
{
|
||||
p2X += 128;
|
||||
p2Y += 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
p2X *= -1;
|
||||
p2Y *= -1;
|
||||
}
|
||||
|
||||
if (pin && (ControllerCounter % 2 == 0))
|
||||
{
|
||||
++ControllerCounter;
|
||||
}
|
||||
else if (!pin && (ControllerCounter % 2 == 1))
|
||||
{
|
||||
if (++ControllerCounter == (is_JPN ? 6 : 4))
|
||||
ControllerCounter = 0;
|
||||
}
|
||||
|
||||
switch (ControllerCounter)
|
||||
{
|
||||
case 0:
|
||||
if ((p2X & 0x10) == 0) result &= 0xBF;
|
||||
if ((p2X & 0x20) == 0) result &= 0x7F;
|
||||
break;
|
||||
case 1:
|
||||
if ((p2X & 0x01) == 0) result &= 0xBF;
|
||||
if ((p2X & 0x02) == 0) result &= 0x7F;
|
||||
break;
|
||||
case 2:
|
||||
if ((p2Y & 0x10) == 0) result &= 0xBF;
|
||||
if ((p2Y & 0x20) == 0) result &= 0x7F;
|
||||
break;
|
||||
case 3:
|
||||
if ((p2Y & 0x01) == 0) result &= 0xBF;
|
||||
if ((p2Y & 0x02) == 0) result &= 0x7F;
|
||||
break;
|
||||
case 5:
|
||||
// specific to Japan: buttons
|
||||
if (c.IsPressed("P2 B1")) result &= 0xBF;
|
||||
if (c.IsPressed("P2 B2")) result &= 0x7F;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
int p2X;
|
||||
if (c.IsPressed("P2 Left"))
|
||||
p2X = SportsPadMin;
|
||||
else if (c.IsPressed("P2 Right"))
|
||||
p2X = SportsPadMax;
|
||||
else
|
||||
p2X = (int)c.AxisValue("P2 X");
|
||||
|
||||
int p2Y;
|
||||
if (c.IsPressed("P2 Down"))
|
||||
p2Y = SportsPadMin;
|
||||
else if (c.IsPressed("P2 Up"))
|
||||
p2Y = SportsPadMax;
|
||||
else
|
||||
p2Y = (int)c.AxisValue("P2 Y");
|
||||
|
||||
if (is_JPN)
|
||||
{
|
||||
p2X += 128;
|
||||
p2Y += 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
p2X *= -1;
|
||||
p2Y *= -1;
|
||||
}
|
||||
|
||||
if (pin && (ControllerCounter % 2 == 0))
|
||||
{
|
||||
++ControllerCounter;
|
||||
}
|
||||
else if (!pin && (ControllerCounter % 2 == 1))
|
||||
{
|
||||
if (++ControllerCounter == (is_JPN ? 6 : 4))
|
||||
ControllerCounter = 0;
|
||||
}
|
||||
|
||||
switch (ControllerCounter)
|
||||
{
|
||||
case 0:
|
||||
if ((p2X & 0x40) == 0) result &= 0xFE;
|
||||
if ((p2X & 0x80) == 0) result &= 0xFD;
|
||||
break;
|
||||
case 1:
|
||||
if ((p2X & 0x04) == 0) result &= 0xFE;
|
||||
if ((p2X & 0x08) == 0) result &= 0xFD;
|
||||
break;
|
||||
case 2:
|
||||
if ((p2Y & 0x40) == 0) result &= 0xFE;
|
||||
if ((p2Y & 0x80) == 0) result &= 0xFD;
|
||||
break;
|
||||
case 3:
|
||||
if ((p2Y & 0x04) == 0) result &= 0xFE;
|
||||
if ((p2Y & 0x08) == 0) result &= 0xFD;
|
||||
break;
|
||||
}
|
||||
if (is_JPN)
|
||||
{
|
||||
// Buttons like normal in Export
|
||||
if (c.IsPressed("P2 B1")) result &= 0xFB;
|
||||
if (c.IsPressed("P2 B2")) result &= 0xF7;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pin) result &= 0xF7;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool PinStateGet(IController c) { return pin; }
|
||||
|
||||
public void PinStateSet(IController c, bool val) { pin = val; }
|
||||
|
||||
public void CounterSet(IController c, int val) { ControllerCounter = val; }
|
||||
|
||||
public void RegionSet(IController c, bool val) { is_JPN = val; }
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Up", "Down", "Left", "Right", "B1", "B2"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(pin), ref pin);
|
||||
ser.Sync(nameof(ControllerCounter), ref ControllerCounter);
|
||||
ser.Sync(nameof(is_JPN), ref is_JPN);
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("SMS Light Phaser Controller")]
|
||||
public class SMSLightPhaserController : IPort
|
||||
{
|
||||
public SMSLightPhaserController(int portNum)
|
||||
{
|
||||
PortNum = portNum;
|
||||
Definition = new ControllerDefinition
|
||||
{
|
||||
Name = "SMS Light Phaser Controller",
|
||||
BoolButtons = BaseDefinition.Select(b => $"P{PortNum} {b}").ToList()
|
||||
}.AddXYPair($"P{PortNum} {{0}}", AxisPairOrientation.RightAndUp, 0.RangeTo(127), 64, 0.RangeTo(192), 96); //TODO verify direction against hardware
|
||||
}
|
||||
|
||||
public int PortNum { get; }
|
||||
|
||||
public ControllerDefinition Definition { get; }
|
||||
|
||||
public byte Read_p1_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0])) result &= 0xEF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p1_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c1(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte Read_p2_c2(IController c)
|
||||
{
|
||||
byte result = 0xFF;
|
||||
|
||||
if (c.IsPressed(Definition.BoolButtons[0])) result &= 0xFB;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool PinStateGet(IController c) { return false; }
|
||||
|
||||
public void PinStateSet(IController c, bool val) { }
|
||||
|
||||
public void CounterSet(IController c, int val) { }
|
||||
|
||||
public void RegionSet(IController c, bool val) { }
|
||||
|
||||
private static readonly string[] BaseDefinition =
|
||||
{
|
||||
"Trigger"
|
||||
};
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,22 +2,35 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Cores.Sega.MasterSystem;
|
||||
|
||||
namespace BizHawk.Emulation.Cores
|
||||
{
|
||||
internal abstract class SmsSchemaControls
|
||||
|
||||
[Schema("GG")]
|
||||
public class GameGearSchema : IVirtualPadSchema
|
||||
{
|
||||
public static PadSchema StandardController(int controller, bool isSms)
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core, Action<string> showMessageBox)
|
||||
{
|
||||
yield return GGSchemaControls.StandardController(1);
|
||||
yield return GGSchemaControls.Console();
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class GGSchemaControls
|
||||
{
|
||||
public static PadSchema StandardController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
Size = new Size(174, 90),
|
||||
Buttons = StandardButtons(controller, isSms)
|
||||
Buttons = StandardButtons(controller)
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<ButtonSchema> StandardButtons(int controller, bool isSms)
|
||||
public static IEnumerable<ButtonSchema> StandardButtons(int controller)
|
||||
{
|
||||
|
||||
yield return ButtonSchema.Up(14, 12, controller);
|
||||
|
@ -26,52 +39,170 @@ namespace BizHawk.Emulation.Cores
|
|||
yield return ButtonSchema.Right(24, 34, controller);
|
||||
yield return new ButtonSchema(122, 34, controller, "B1", "1");
|
||||
yield return new ButtonSchema(146, 34, controller, "B2", "2");
|
||||
if (!isSms)
|
||||
{
|
||||
yield return new ButtonSchema(134, 12, controller, "Start", "S");
|
||||
}
|
||||
yield return new ButtonSchema(134, 12, controller, "Start", "S");
|
||||
}
|
||||
|
||||
public static PadSchema Console(bool isSms)
|
||||
public static PadSchema Console()
|
||||
{
|
||||
return new ConsoleSchema
|
||||
{
|
||||
Size = new Size(150, 50),
|
||||
Buttons = ConsoleButtons(isSms)
|
||||
Buttons = ConsoleButtons()
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<ButtonSchema> ConsoleButtons(bool isSms)
|
||||
public static IEnumerable<ButtonSchema> ConsoleButtons()
|
||||
{
|
||||
yield return new ButtonSchema(10, 15, "Reset");
|
||||
if (isSms)
|
||||
{
|
||||
yield return new ButtonSchema(58, 15, "Pause");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Schema("GG")]
|
||||
public class GameGearSchema : IVirtualPadSchema
|
||||
{
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core, Action<string> showMessageBox)
|
||||
{
|
||||
yield return SmsSchemaControls.StandardController(1, false);
|
||||
yield return SmsSchemaControls.Console(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Schema("SG")]
|
||||
public class SG1000Schema : SMSSchema {} // are these really the same controller layouts? --yoshi
|
||||
public class SG1000Schema : SMSSchema { } // are these really the same controller layouts? --yoshi
|
||||
|
||||
[Schema("SMS")]
|
||||
public class SMSSchema : IVirtualPadSchema
|
||||
{
|
||||
private static string StandardControllerName => typeof(SmsController).DisplayName();
|
||||
private static string PaddleControllerName => typeof(SMSPaddleController).DisplayName();
|
||||
private static string SportControllerName => typeof(SMSSportsPadController).DisplayName();
|
||||
private static string LightGunControllerName => typeof(SMSLightPhaserController).DisplayName();
|
||||
|
||||
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core, Action<string> showMessageBox)
|
||||
{
|
||||
yield return SmsSchemaControls.StandardController(1, true);
|
||||
yield return SmsSchemaControls.StandardController(2, true);
|
||||
yield return SmsSchemaControls.Console(true);
|
||||
var ss = ((SMS)core).GetSyncSettings().Clone();
|
||||
|
||||
var port1 = SchemaFor(ss.Port1, 1);
|
||||
if (port1 != null)
|
||||
{
|
||||
yield return port1;
|
||||
}
|
||||
|
||||
var port2 = SchemaFor(ss.Port2, 2);
|
||||
if (port2 != null)
|
||||
{
|
||||
yield return port2;
|
||||
}
|
||||
|
||||
yield return ConsoleButtons();
|
||||
}
|
||||
|
||||
private static PadSchema SchemaFor(SMSControllerTypes controllerName, int portNum)
|
||||
{
|
||||
if (controllerName == SMSControllerTypes.Standard)
|
||||
{
|
||||
return JoystickController(portNum);
|
||||
}
|
||||
|
||||
if (controllerName == SMSControllerTypes.Paddle)
|
||||
{
|
||||
return PaddleController(portNum);
|
||||
}
|
||||
|
||||
if (controllerName == SMSControllerTypes.SportsPad)
|
||||
{
|
||||
return SportController(portNum);
|
||||
}
|
||||
|
||||
if (controllerName == SMSControllerTypes.Phaser)
|
||||
{
|
||||
return LightGunController(portNum);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PadSchema JoystickController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = $"Player {controller}",
|
||||
Size = new Size(174, 90),
|
||||
Buttons = new[]
|
||||
{
|
||||
ButtonSchema.Up(14, 12, controller),
|
||||
ButtonSchema.Down(14, 56, controller),
|
||||
ButtonSchema.Left(2, 34, controller),
|
||||
ButtonSchema.Right(24, 34, controller),
|
||||
new ButtonSchema(122, 34, controller, "B1", "1"),
|
||||
new ButtonSchema(146, 34, controller, "B2", "2")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema PaddleController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = $"Player {controller}",
|
||||
Size = new Size(334, 94),
|
||||
Buttons = new PadSchemaControl[]
|
||||
{
|
||||
new ButtonSchema(5, 24, controller, "B1", "1"),
|
||||
new SingleAxisSchema(55, 17, controller, "Paddle")
|
||||
{
|
||||
TargetSize = new Size(128, 69),
|
||||
MaxValue = 255,
|
||||
MinValue = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema SportController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = $"Player {controller}",
|
||||
Size = new Size(334, 94),
|
||||
Buttons = new PadSchemaControl[]
|
||||
{
|
||||
new ButtonSchema(5, 24, controller, "B1", "1"),
|
||||
new ButtonSchema(5, 48, controller, "B2", "2"),
|
||||
new SingleAxisSchema(55, 17, controller, "X")
|
||||
{
|
||||
TargetSize = new Size(128, 69),
|
||||
MaxValue = 63,
|
||||
MinValue = -64
|
||||
},
|
||||
new SingleAxisSchema(193, 17, controller, "Y")
|
||||
{
|
||||
TargetSize = new Size(128, 69),
|
||||
MaxValue = 63,
|
||||
MinValue = -64
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema LightGunController(int controller)
|
||||
{
|
||||
return new PadSchema
|
||||
{
|
||||
DisplayName = "Light Gun",
|
||||
Size = new Size(356, 290),
|
||||
Buttons = new PadSchemaControl[]
|
||||
{
|
||||
new TargetedPairSchema(14, 17, $"P{controller} X")
|
||||
{
|
||||
TargetSize = new Size(127, 192)
|
||||
},
|
||||
new ButtonSchema(284, 17, controller, "Trigger")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static PadSchema ConsoleButtons()
|
||||
{
|
||||
return new ConsoleSchema
|
||||
{
|
||||
Size = new Size(150, 50),
|
||||
Buttons = new[]
|
||||
{
|
||||
new ButtonSchema(10, 15, "Reset"),
|
||||
new ButtonSchema(60, 15, "Pause")
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue