#include "stdafx.h" #include "VsControlManager.h" #include "VsSystem.h" #include "SystemActionManager.h" #include "VsSystemActionManager.h" ControllerType VsControlManager::GetControllerType(uint8_t port) { ControllerType type = ControlManager::GetControllerType(port); if(type == ControllerType::Zapper) { type = ControllerType::VsZapper; } return type; } void VsControlManager::Reset(bool softReset) { ControlManager::Reset(softReset); _protectionCounter = 0; //Unsure about this, needed for VS Wrecking Crew UpdateSlaveMasterBit(_console->IsMaster() ? 0x00 : 0x02); _vsSystemType = _console->GetRomInfo().VsType; if(!softReset && !_console->IsMaster() && _console->GetDualConsole()) { UnregisterInputProvider(this); RegisterInputProvider(this); } } VsControlManager::~VsControlManager() { UnregisterInputProvider(this); } void VsControlManager::StreamState(bool saving) { ControlManager::StreamState(saving); Stream(_prgChrSelectBit, _protectionCounter, _refreshState); } void VsControlManager::GetMemoryRanges(MemoryRanges &ranges) { ControlManager::GetMemoryRanges(ranges); ranges.AddHandler(MemoryOperation::Read, 0x4020, 0x5FFF); ranges.AddHandler(MemoryOperation::Write, 0x4020, 0x5FFF); } uint8_t VsControlManager::GetPrgChrSelectBit() { return _prgChrSelectBit; } void VsControlManager::RemapControllerButtons() { shared_ptr controllers[2]; controllers[0] = std::dynamic_pointer_cast(GetControlDevice(0)); controllers[1] = std::dynamic_pointer_cast(GetControlDevice(1)); if(!controllers[0] || !controllers[1]) { return; } GameInputType inputType = _console->GetRomInfo().InputType; if(inputType == GameInputType::VsSystemSwapped) { //Swap controllers 1 & 2 ControlDeviceState port1State = controllers[0]->GetRawState(); ControlDeviceState port2State = controllers[1]->GetRawState(); controllers[0]->SetRawState(port2State); controllers[1]->SetRawState(port1State); //But don't swap the start/select buttons BaseControlDevice::SwapButtons(controllers[0], StandardController::Buttons::Start, controllers[1], StandardController::Buttons::Start); BaseControlDevice::SwapButtons(controllers[0], StandardController::Buttons::Select, controllers[1], StandardController::Buttons::Select); } else if(inputType == GameInputType::VsSystemSwapAB) { //Swap buttons P1 A & P2 B (Pinball (Japan)) BaseControlDevice::SwapButtons(controllers[0], StandardController::Buttons::B, controllers[1], StandardController::Buttons::A); } //Swap Start/Select for all configurations (makes it more intuitive) BaseControlDevice::SwapButtons(controllers[0], StandardController::Buttons::Start, controllers[0], StandardController::Buttons::Select); BaseControlDevice::SwapButtons(controllers[1], StandardController::Buttons::Start, controllers[1], StandardController::Buttons::Select); if(_vsSystemType == VsSystemType::RaidOnBungelingBayProtection || _vsSystemType == VsSystemType::IceClimberProtection) { //Bit 3 of the input status must always be on controllers[0]->SetBit(StandardController::Buttons::Start); controllers[1]->SetBit(StandardController::Buttons::Start); } } uint8_t VsControlManager::GetOpenBusMask(uint8_t port) { return 0x00; } uint8_t VsControlManager::ReadRAM(uint16_t addr) { uint8_t value = 0; if(!_console->IsMaster()) { //Copy the insert coin 3/4 + service button "2" bits from the main console to this one shared_ptr masterConsole = _console->GetDualConsole(); _systemActionManager->SetBitValue(VsSystemActionManager::VsButtons::InsertCoin1, masterConsole->GetSystemActionManager()->IsPressed(VsSystemActionManager::VsButtons::InsertCoin3)); _systemActionManager->SetBitValue(VsSystemActionManager::VsButtons::InsertCoin2, masterConsole->GetSystemActionManager()->IsPressed(VsSystemActionManager::VsButtons::InsertCoin4)); _systemActionManager->SetBitValue(VsSystemActionManager::VsButtons::ServiceButton, masterConsole->GetSystemActionManager()->IsPressed(VsSystemActionManager::VsButtons::ServiceButton2)); } switch(addr) { case 0x4016: { uint32_t dipSwitches = _console->GetSettings()->GetDipSwitches(); if(!_console->IsMaster()) { dipSwitches >>= 8; } value = ControlManager::ReadRAM(addr) & 0x65; value |= ((dipSwitches & 0x01) ? 0x08 : 0x00); value |= ((dipSwitches & 0x02) ? 0x10 : 0x00); value |= (_console->IsMaster() ? 0x00 : 0x80); break; } case 0x4017: { value = ControlManager::ReadRAM(addr) & 0x01; uint32_t dipSwitches = _console->GetSettings()->GetDipSwitches(); if(!_console->IsMaster()) { dipSwitches >>= 8; } value |= ((dipSwitches & 0x04) ? 0x04 : 0x00); value |= ((dipSwitches & 0x08) ? 0x08 : 0x00); value |= ((dipSwitches & 0x10) ? 0x10 : 0x00); value |= ((dipSwitches & 0x20) ? 0x20 : 0x00); value |= ((dipSwitches & 0x40) ? 0x40 : 0x00); value |= ((dipSwitches & 0x80) ? 0x80 : 0x00); break; } case 0x5E00: _protectionCounter = 0; break; case 0x5E01: if(_vsSystemType == VsSystemType::TkoBoxingProtection) { value = _protectionData[0][_protectionCounter++ & 0x1F]; } else if(_vsSystemType == VsSystemType::RbiBaseballProtection) { value = _protectionData[1][_protectionCounter++ & 0x1F]; } break; default: if(_vsSystemType == VsSystemType::SuperXeviousProtection) { return _protectionData[2][_protectionCounter++ & 0x1F]; } break; } return value; } void VsControlManager::WriteRAM(uint16_t addr, uint8_t value) { ControlManager::WriteRAM(addr, value); _refreshState = (value & 0x01) == 0x01; if(addr == 0x4016) { _prgChrSelectBit = (value >> 2) & 0x01; //Bit 2: DualSystem-only uint8_t slaveMasterBit = (value & 0x02); if(slaveMasterBit != _slaveMasterBit) { UpdateSlaveMasterBit(slaveMasterBit); } } } void VsControlManager::UpdateSlaveMasterBit(uint8_t slaveMasterBit) { shared_ptr dualConsole = _console->GetDualConsole(); if(dualConsole) { VsSystem* mapper = dynamic_cast(_console->GetMapper()); if(_console->IsMaster()) { mapper->UpdateMemoryAccess(slaveMasterBit); } if(slaveMasterBit) { dualConsole->GetCpu()->ClearIrqSource(IRQSource::External); } else { //When low, asserts /IRQ on the other CPU dualConsole->GetCpu()->SetIrqSource(IRQSource::External); } } _slaveMasterBit = slaveMasterBit; } void VsControlManager::UpdateControlDevices() { if(_console->GetDualConsole()) { auto lock = _deviceLock.AcquireSafe(); _controlDevices.clear(); RegisterControlDevice(_systemActionManager); //Force 4x standard controllers //P3 & P4 will be sent to the slave CPU - see SetInput() below. for(int i = 0; i < 4; i++) { shared_ptr device = CreateControllerDevice(ControllerType::StandardController, i, _console); if(device) { RegisterControlDevice(device); } } } else { ControlManager::UpdateControlDevices(); } } bool VsControlManager::SetInput(BaseControlDevice* device) { uint8_t port = device->GetPort(); ControlManager* masterControlManager = _console->GetDualConsole()->GetControlManager(); if(masterControlManager && port <= 1) { shared_ptr controlDevice = masterControlManager->GetControlDevice(port + 2); if(controlDevice) { ControlDeviceState state = controlDevice->GetRawState(); device->SetRawState(state); } } return true; }