656 lines
18 KiB
C#
656 lines
18 KiB
C#
using System;
|
|
|
|
using BizHawk.Emulation.Common;
|
|
|
|
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",
|
|
},
|
|
FloatControls =
|
|
{
|
|
"P1 Paddle",
|
|
"P2 Paddle"
|
|
},
|
|
FloatRanges =
|
|
{
|
|
new ControllerDefinition.FloatRange(0, 128, 255),
|
|
new ControllerDefinition.FloatRange(0, 128, 255)
|
|
}
|
|
};
|
|
|
|
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)
|
|
}
|
|
};
|
|
|
|
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)
|
|
}
|
|
};
|
|
|
|
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,
|
|
"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"
|
|
};
|
|
|
|
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 (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");
|
|
|
|
PresetControllerState(1);
|
|
// Hard-wired together?
|
|
Controller2SelectHigh = Controller1SelectHigh;
|
|
|
|
if (Controller1SelectHigh)
|
|
{
|
|
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 "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;
|
|
|
|
case "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);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
private byte ReadControls2()
|
|
{
|
|
InputCallbacks.Call();
|
|
_lagged = false;
|
|
byte value = 0xFF;
|
|
|
|
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");
|
|
|
|
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 "Light Phaser":
|
|
if (LatchLightPhaser)
|
|
{
|
|
value &= 0xBF;
|
|
LatchLightPhaser = false;
|
|
}
|
|
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;
|
|
|
|
case "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;
|
|
}
|
|
|
|
if (_controller.IsPressed("Reset")) value &= 0xEF;
|
|
|
|
if ((Port3F & 0x0F) == 5)
|
|
{
|
|
if (_region == "Japan")
|
|
{
|
|
value &= 0x3F;
|
|
}
|
|
else // US / Europe
|
|
{
|
|
if (Port3F >> 4 == 0x0F)
|
|
value |= 0xC0;
|
|
else
|
|
value &= 0x3F;
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
internal void ProcessLineControls()
|
|
{
|
|
const int phaserRadius = 4;
|
|
|
|
// specifically lightgun needs to do things on a per-line basis
|
|
if (SyncSettings.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_C == false)
|
|
{
|
|
return 0xFF;
|
|
}
|
|
|
|
_lagged = false;
|
|
|
|
byte value = 0xFF;
|
|
if ((_controller.IsPressed("Pause") && !IsGameGear) ||
|
|
(_controller.IsPressed("P1 Start") && IsGameGear_C))
|
|
{
|
|
value ^= 0x80;
|
|
}
|
|
|
|
if (RegionStr == "Japan")
|
|
{
|
|
value ^= 0x40;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |