Fix one shot paddle timers (fixes #985)

This commit is contained in:
tomcw 2021-10-04 22:08:37 +01:00
parent e43d188e0f
commit aa7d0cf240
3 changed files with 51 additions and 20 deletions

View file

@ -99,10 +99,10 @@ static DWORD joytype[2] = {J0C_JOYSTICK1, J1C_DISABLED}; // Emulation
static BOOL setbutton[3] = {0,0,0}; // Used when a mouse button is pressed/released static BOOL setbutton[3] = {0,0,0}; // Used when a mouse button is pressed/released
static int xpos[2] = {PDL_CENTRAL,PDL_CENTRAL}; static int xpos[2] = { PDL_MAX,PDL_MAX };
static int ypos[2] = {PDL_CENTRAL,PDL_CENTRAL}; static int ypos[2] = { PDL_MAX,PDL_MAX };
static unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick counters were reset static UINT64 g_paddleInactiveCycle[4] = { 0 }; // Abs cycle that each paddle becomes inactive after PTRIG strobe
static short g_nPdlTrimX = 0; static short g_nPdlTrimX = 0;
static short g_nPdlTrimY = 0; static short g_nPdlTrimY = 0;
@ -671,20 +671,13 @@ static const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS)
BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, ULONG nExecutedCycles) BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, ULONG nExecutedCycles)
{ {
int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067
CpuCalcCycles(nExecutedCycles); CpuCalcCycles(nExecutedCycles);
ULONG nPdlPos = (address & 1) ? ypos[nJoyNum] : xpos[nJoyNum]; BOOL nPdlCntrActive = g_nCumulativeCycles <= g_paddleInactiveCycle[address & 3];
// This is from KEGS. It helps games like Championship Lode Runner & Boulderdash
if(nPdlPos >= 255)
nPdlPos = 280;
BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL));
// If no joystick connected, then this is always active (GH#778) // If no joystick connected, then this is always active (GH#778)
if (joyinfo[joytype[nJoyNum]] == DEVICE_NONE) const UINT joyNum = (address & 2) ? 1 : 0; // $C064..$C067
if (joyinfo[joytype[joyNum]] == DEVICE_NONE)
nPdlCntrActive = TRUE; nPdlCntrActive = TRUE;
return MemReadFloatingBus(nPdlCntrActive, nExecutedCycles); return MemReadFloatingBus(nPdlCntrActive, nExecutedCycles);
@ -702,12 +695,27 @@ void JoyReset()
void JoyResetPosition(ULONG nExecutedCycles) void JoyResetPosition(ULONG nExecutedCycles)
{ {
CpuCalcCycles(nExecutedCycles); CpuCalcCycles(nExecutedCycles);
g_nJoyCntrResetCycle = g_nCumulativeCycles;
if(joyinfo[joytype[0]] == DEVICE_JOYSTICK) if(joyinfo[joytype[0]] == DEVICE_JOYSTICK)
CheckJoystick0(); CheckJoystick0();
if((joyinfo[joytype[1]] == DEVICE_JOYSTICK) || (joyinfo[joytype[1]] == DEVICE_JOYSTICK_THUMBSTICK2)) if((joyinfo[joytype[1]] == DEVICE_JOYSTICK) || (joyinfo[joytype[1]] == DEVICE_JOYSTICK_THUMBSTICK2))
CheckJoystick1(); CheckJoystick1();
// If any of the timers are still running then strobe has no effect (GH#985)
for (UINT pdl = 0; pdl < 4; pdl++)
{
if (g_nCumulativeCycles <= g_paddleInactiveCycle[pdl])
continue;
const UINT joyNum = (pdl & 2) ? 1 : 0;
UINT pdlPos = (pdl & 1) ? ypos[joyNum] : xpos[joyNum];
// This is from KEGS. It helps games like Championship Lode Runner & Boulderdash
if (pdlPos >= 255)
pdlPos = 280;
g_paddleInactiveCycle[pdl] = g_nCumulativeCycles + (UINT64)((double)pdlPos * PDL_CNTR_INTERVAL);
}
} }
//=========================================================================== //===========================================================================
@ -990,6 +998,7 @@ void JoyportControl(const UINT uControl)
#define SS_YAML_KEY_JOY0TRIMY "Joystick0 TrimY" #define SS_YAML_KEY_JOY0TRIMY "Joystick0 TrimY"
#define SS_YAML_KEY_JOY1TRIMX "Joystick1 TrimX" #define SS_YAML_KEY_JOY1TRIMX "Joystick1 TrimX"
#define SS_YAML_KEY_JOY1TRIMY "Joystick1 TrimY" #define SS_YAML_KEY_JOY1TRIMY "Joystick1 TrimY"
#define SS_YAML_KEY_PDL_INACTIVE_CYCLE "Paddle%1d Inactive Cycle"
static std::string JoyGetSnapshotStructName(void) static std::string JoyGetSnapshotStructName(void)
{ {
@ -1000,23 +1009,44 @@ static std::string JoyGetSnapshotStructName(void)
void JoySaveSnapshot(YamlSaveHelper& yamlSaveHelper) void JoySaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{ {
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", JoyGetSnapshotStructName().c_str()); YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", JoyGetSnapshotStructName().c_str());
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COUNTERRESETCYCLE, g_nJoyCntrResetCycle);
yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMX, JoyGetTrim(true)); yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMX, JoyGetTrim(true));
yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMY, JoyGetTrim(false)); yamlSaveHelper.SaveInt(SS_YAML_KEY_JOY0TRIMY, JoyGetTrim(false));
yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMX, 0); // not implemented yet yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMX, 0); // not implemented yet
yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMY, 0); // not implemented yet yamlSaveHelper.Save("%s: %d # not implemented yet\n", SS_YAML_KEY_JOY1TRIMY, 0); // not implemented yet
for (UINT n = 0; n < 4; n++)
{
char str[sizeof(SS_YAML_KEY_PDL_INACTIVE_CYCLE)+1];
sprintf_s(str, sizeof(str), SS_YAML_KEY_PDL_INACTIVE_CYCLE, n);
yamlSaveHelper.SaveHexUint64(str, g_paddleInactiveCycle[n]);
}
} }
void JoyLoadSnapshot(YamlLoadHelper& yamlLoadHelper) void JoyLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{ {
if (!yamlLoadHelper.GetSubMap(JoyGetSnapshotStructName())) if (!yamlLoadHelper.GetSubMap(JoyGetSnapshotStructName()))
return; return;
g_nJoyCntrResetCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COUNTERRESETCYCLE);
JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMX), true); JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMX), true);
JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMY), false); JoySetTrim(yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY0TRIMY), false);
yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMX); // dump value yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMX); // dump value
yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMY); // dump value yamlLoadHelper.LoadInt(SS_YAML_KEY_JOY1TRIMY); // dump value
if (version >= 7)
{
for (UINT n = 0; n < 4; n++)
{
char str[sizeof(SS_YAML_KEY_PDL_INACTIVE_CYCLE) + 1];
sprintf_s(str, sizeof(str), SS_YAML_KEY_PDL_INACTIVE_CYCLE, n);
g_paddleInactiveCycle[n] = yamlLoadHelper.LoadUint64(str);
}
}
else
{
UINT64 resetCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COUNTERRESETCYCLE);
for (UINT n = 0; n < 4; n++)
g_paddleInactiveCycle[n] = resetCycle;
}
yamlLoadHelper.PopMap(); yamlLoadHelper.PopMap();
} }

View file

@ -28,7 +28,7 @@ void JoyportControl(const UINT uControl);
void JoySetHookAltKeys(bool hook); void JoySetHookAltKeys(bool hook);
void JoySetButtonVirtualKey(UINT button, UINT virtKey); void JoySetButtonVirtualKey(UINT button, UINT virtKey);
void JoySaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void JoySaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);
BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);

View file

@ -74,7 +74,8 @@ static YamlHelper yamlHelper;
// v4: Extended: video (added 'Video Refresh Rate') // v4: Extended: video (added 'Video Refresh Rate')
// v5: Extended: cpu (added 'Defer IRQ By 1 Opcode') // v5: Extended: cpu (added 'Defer IRQ By 1 Opcode')
// v6: Added 'Unit Miscellaneous' for NoSlotClock(NSC) // v6: Added 'Unit Miscellaneous' for NoSlotClock(NSC)
#define UNIT_APPLE2_VER 6 // v7: Extended: joystick (added 'Paddle Inactive Cycle')
#define UNIT_APPLE2_VER 7
#define UNIT_SLOTS_VER 1 #define UNIT_SLOTS_VER 1
@ -283,7 +284,7 @@ static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version)
CpuLoadSnapshot(yamlLoadHelper, version); // NB. Overrides default main CPU type CpuLoadSnapshot(yamlLoadHelper, version); // NB. Overrides default main CPU type
m_ConfigNew.m_CpuType = GetMainCpu(); m_ConfigNew.m_CpuType = GetMainCpu();
JoyLoadSnapshot(yamlLoadHelper); JoyLoadSnapshot(yamlLoadHelper, version);
KeybLoadSnapshot(yamlLoadHelper, version); KeybLoadSnapshot(yamlLoadHelper, version);
SpkrLoadSnapshot(yamlLoadHelper); SpkrLoadSnapshot(yamlLoadHelper);
GetVideo().VideoLoadSnapshot(yamlLoadHelper, version); GetVideo().VideoLoadSnapshot(yamlLoadHelper, version);