diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 40787070..fae7e930 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -44,6 +44,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -51,6 +74,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 1b8d670d..703975c1 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -734,6 +734,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/Gameboy/Gameboy.cpp b/Core/Gameboy/Gameboy.cpp
index 21debb2d..fae62de1 100644
--- a/Core/Gameboy/Gameboy.cpp
+++ b/Core/Gameboy/Gameboy.cpp
@@ -463,3 +463,8 @@ uint64_t Gameboy::GetMasterClock()
{
return _memoryManager->GetCycleCount();
}
+
+uint32_t Gameboy::GetMasterClockRate()
+{
+ return 20971520;
+}
diff --git a/Core/Gameboy/Gameboy.h b/Core/Gameboy/Gameboy.h
index 97114e54..2acda52c 100644
--- a/Core/Gameboy/Gameboy.h
+++ b/Core/Gameboy/Gameboy.h
@@ -117,5 +117,6 @@ public:
virtual AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType) override;
// Inherited via IConsole
- virtual uint64_t GetMasterClock() override;
+ uint64_t GetMasterClock() override;
+ uint32_t GetMasterClockRate() override;
};
\ No newline at end of file
diff --git a/Core/NES/Input/ArkanoidController.h b/Core/NES/Input/ArkanoidController.h
new file mode 100644
index 00000000..3b824256
--- /dev/null
+++ b/Core/NES/Input/ArkanoidController.h
@@ -0,0 +1,90 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/KeyManager.h"
+#include "Shared/Emulator.h"
+#include "Shared/EmuSettings.h"
+#include "Utilities/Serializer.h"
+
+class ArkanoidController : public BaseControlDevice
+{
+private:
+ uint32_t _currentValue = (0xF4 - 0x54) / 2;
+ uint32_t _stateBuffer = 0;
+ enum Buttons { Fire };
+
+protected:
+ bool HasCoordinates() override { return true; }
+
+ string GetKeyNames() override
+ {
+ return "F";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ if(_emu->GetSettings()->IsInputEnabled()) {
+ SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+ SetMovement(KeyManager::GetMouseMovement(
+ _emu->GetSettings()->GetVideoConfig().VideoScale,
+ _emu->GetSettings()->GetInputConfig().MouseSensitivity + 1
+ ));
+ }
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_stateBuffer, _currentValue);
+ }
+
+ void RefreshStateBuffer() override
+ {
+ MouseMovement mov = GetMovement();
+
+ _currentValue += mov.dx;
+ if(_currentValue < 0x54) {
+ _currentValue = 0x54;
+ } else if(_currentValue > 0xF4) {
+ _currentValue = 0xF4;
+ }
+
+ _stateBuffer = _currentValue;
+ }
+
+public:
+ ArkanoidController(Emulator* emu, ControllerType type, uint8_t port) : BaseControlDevice(emu, type, port)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if(IsExpansionDevice()) {
+ if(addr == 0x4016) {
+ //Fire button is on port 1
+ if(IsPressed(ArkanoidController::Buttons::Fire)) {
+ output |= 0x02;
+ }
+ } else if(addr == 0x4017) {
+ //Serial data is on port 2
+ output |= ((~_stateBuffer) >> 6) & 0x02;
+ _stateBuffer <<= 1;
+ }
+ } else if(IsCurrentPort(addr)) {
+ output = ((~_stateBuffer) >> 3) & 0x10;
+ _stateBuffer <<= 1;
+
+ if(IsPressed(ArkanoidController::Buttons::Fire)) {
+ output |= 0x08;
+ }
+ }
+
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/AsciiTurboFile.h b/Core/NES/Input/AsciiTurboFile.h
new file mode 100644
index 00000000..b0aa78a1
--- /dev/null
+++ b/Core/NES/Input/AsciiTurboFile.h
@@ -0,0 +1,66 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/Emulator.h"
+#include "Shared/EmuSettings.h"
+#include "Shared/BatteryManager.h"
+#include "Shared/Interfaces/IBattery.h"
+#include "Utilities/Serializer.h"
+
+class AsciiTurboFile : public BaseControlDevice, public IBattery
+{
+private:
+ static constexpr int FileSize = 0x2000;
+ static constexpr int BitCount = FileSize * 8;
+ uint8_t _lastWrite = 0;
+ uint16_t _position = 0;
+ uint8_t _data[AsciiTurboFile::FileSize];
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ ArrayInfo data { _data, AsciiTurboFile::FileSize };
+ s.Stream(_position, _lastWrite, data);
+ }
+
+public:
+ AsciiTurboFile(Emulator* emu) : BaseControlDevice(emu, ControllerType::AsciiTurboFile, BaseControlDevice::ExpDevicePort)
+ {
+ _emu->GetBatteryManager()->LoadBattery(".tf", _data, AsciiTurboFile::FileSize);
+ }
+
+ ~AsciiTurboFile()
+ {
+ SaveBattery();
+ }
+
+ void SaveBattery() override
+ {
+ _emu->GetBatteryManager()->SaveBattery(".tf", _data, AsciiTurboFile::FileSize);
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ return ((_data[_position / 8] >> (_position % 8)) & 0x01) << 2;
+ }
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ if(!(value & 0x02)) {
+ _position = 0;
+ }
+
+ if(!(value & 0x04) && (_lastWrite & 0x04)) {
+ //Clock, perform write, increase position
+ _data[_position / 8] &= ~(1 << (_position % 8));
+ _data[_position / 8] |= (value & 0x01) << (_position % 8);
+ _position = (_position + 1) & (AsciiTurboFile::BitCount - 1);
+ }
+
+ _lastWrite = value;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/BandaiHyperShot.h b/Core/NES/Input/BandaiHyperShot.h
new file mode 100644
index 00000000..ac851440
--- /dev/null
+++ b/Core/NES/Input/BandaiHyperShot.h
@@ -0,0 +1,77 @@
+#pragma once
+#include "stdafx.h"
+#include "NES/Input/NesController.h"
+#include "NES/Input/Zapper.h"
+#include "NES/NesConsole.h"
+#include "Shared/KeyManager.h"
+
+class BandaiHyperShot : public NesController
+{
+private:
+ NesConsole* _console;
+ uint32_t _stateBuffer = 0;
+
+protected:
+ enum ZapperButtons { Fire = 9 };
+
+ bool HasCoordinates() override { return true; }
+
+ string GetKeyNames() override
+ {
+ return NesController::GetKeyNames() + "F";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ NesController::InternalSetStateFromInput();
+
+ if(_emu->GetSettings()->IsInputEnabled()) {
+ SetPressedState(ZapperButtons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+
+ MousePosition pos = KeyManager::GetMousePosition();
+ if(KeyManager::IsMouseButtonPressed(MouseButton::RightButton)) {
+ pos.X = -1;
+ pos.Y = -1;
+ }
+ SetCoordinates(pos);
+ }
+ }
+
+ bool IsLightFound()
+ {
+ return Zapper::StaticIsLightFound(GetCoordinates(), _console);
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_stateBuffer);
+ }
+
+public:
+ BandaiHyperShot(NesConsole* console, KeyMappingSet keyMappings) : NesController(console->GetEmulator(), ControllerType::BandaiHyperShot, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ void RefreshStateBuffer() override
+ {
+ _stateBuffer = (uint32_t)ToByte();
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4016) {
+ StrobeProcessRead();
+ uint8_t output = (_stateBuffer & 0x01) << 1;
+ _stateBuffer >>= 1;
+ return output;
+ } else {
+ return (IsLightFound() ? 0 : 0x08) | (IsPressed(ZapperButtons::Fire) ? 0x10 : 0x00);
+ }
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/BarcodeBattlerReader.h b/Core/NES/Input/BarcodeBattlerReader.h
new file mode 100644
index 00000000..5f8a532b
--- /dev/null
+++ b/Core/NES/Input/BarcodeBattlerReader.h
@@ -0,0 +1,106 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/Emulator.h"
+#include "Utilities/Serializer.h"
+#include "NES/Input/IBarcodeReader.h"
+
+class BarcodeBattlerReader : public BaseControlDevice, public IBarcodeReader
+{
+private:
+ static constexpr int StreamSize = 200;
+ uint64_t _newBarcode = 0;
+ uint32_t _newBarcodeDigitCount = 0;
+
+ uint8_t _barcodeStream[BarcodeBattlerReader::StreamSize];
+ uint64_t _insertCycle = 0;
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+
+ ArrayInfo bitStream{ _barcodeStream, BarcodeBattlerReader::StreamSize };
+ s.Stream(_newBarcode, _newBarcodeDigitCount, _insertCycle, bitStream);
+ }
+
+ bool IsRawString() override
+ {
+ return true;
+ }
+
+ void InitBarcodeStream()
+ {
+ vector state = GetRawState().State;
+ string barcodeText(state.begin(), state.end());
+
+ //Signature at the end, needed for code to be recognized
+ barcodeText += "EPOCH\xD\xA";
+ //Pad to 20 characters with spaces
+ barcodeText.insert(0, 20 - barcodeText.size(), ' ');
+
+ int pos = 0;
+ vector bits;
+ for(int i = 0; i < 20; i++) {
+ _barcodeStream[pos++] = 1;
+ for(int j = 0; j < 8; j++) {
+ _barcodeStream[pos++] = ~((barcodeText[i] >> j) & 0x01);
+ }
+ _barcodeStream[pos++] = 0;
+ }
+ }
+
+public:
+ BarcodeBattlerReader(Emulator* emu) : BaseControlDevice(emu, ControllerType::BarcodeBattler, BaseControlDevice::ExpDevicePort)
+ {
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ ClearState();
+
+ if(_newBarcodeDigitCount > 0) {
+ string barcodeText = std::to_string(_newBarcode);
+ //Pad 8 or 13 character barcode with 0s at start
+ barcodeText.insert(0, _newBarcodeDigitCount - barcodeText.size(), '0');
+ SetTextState(barcodeText);
+
+ _newBarcode = 0;
+ _newBarcodeDigitCount = 0;
+ }
+ }
+
+ void OnAfterSetState() override
+ {
+ if(GetRawState().State.size() > 0) {
+ InitBarcodeStream();
+ if(_emu) {
+ _insertCycle = _emu->GetMasterClock();
+ }
+ }
+ }
+
+ void InputBarcode(uint64_t barcode, uint32_t digitCount) override
+ {
+ _newBarcode = barcode;
+ _newBarcodeDigitCount = digitCount;
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ uint64_t elapsedCycles = _emu->GetMasterClock() - _insertCycle;
+ uint32_t cyclesPerBit = _emu->GetMasterClockRate() / 1200;
+
+ uint32_t streamPosition = (uint32_t)(elapsedCycles / cyclesPerBit);
+ if(streamPosition < BarcodeBattlerReader::StreamSize) {
+ return _barcodeStream[streamPosition] << 2;
+ }
+ }
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/BattleBox.h b/Core/NES/Input/BattleBox.h
new file mode 100644
index 00000000..b334bfd6
--- /dev/null
+++ b/Core/NES/Input/BattleBox.h
@@ -0,0 +1,118 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/Emulator.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/BatteryManager.h"
+#include "Shared/Interfaces/IBattery.h"
+#include "Utilities/Serializer.h"
+
+class BattleBox : public BaseControlDevice, public IBattery
+{
+private:
+ static constexpr int FileSize = 0x200;
+ uint8_t _lastWrite = 0;
+ uint8_t _address = 0;
+ uint8_t _chipSelect = 0;
+ uint16_t _data[BattleBox::FileSize/2];
+ uint8_t _output = 0;
+ bool _writeEnabled = false;
+
+ uint8_t _inputBitPosition = 0;
+ uint16_t _inputData = 0;
+ bool _isWrite = false;
+ bool _isRead = false;
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ ArrayInfo data{ (uint8_t*)_data, BattleBox::FileSize };
+ s.Stream(_lastWrite, _address, _chipSelect, _output, _writeEnabled, _inputBitPosition, _isWrite, _isRead, _inputData, data);
+ }
+
+public:
+ BattleBox(Emulator* emu) : BaseControlDevice(emu, ControllerType::BattleBox, BaseControlDevice::ExpDevicePort)
+ {
+ _emu->GetBatteryManager()->LoadBattery(".bb", (uint8_t*)_data, BattleBox::FileSize);
+ }
+
+ ~BattleBox()
+ {
+ SaveBattery();
+ }
+
+ void SaveBattery() override
+ {
+ _emu->GetBatteryManager()->SaveBattery(".bb", (uint8_t*)_data, BattleBox::FileSize);
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ if(_lastWrite & 0x01) {
+ _chipSelect ^= 0x01;
+ _inputData = 0;
+ _inputBitPosition = 0;
+ }
+ _output ^= 0x01;
+
+ uint8_t readBit = 0;
+ if(_isRead) {
+ readBit = ((_data[(_chipSelect ? 0x80 : 0) | _address] >> _inputBitPosition) & 0x01) << 3;
+ }
+ uint8_t writeBit = (_output << 4);
+ return readBit | writeBit;
+ }
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ if(value & 0x01 && !(_lastWrite & 0x01)) {
+ //Clock
+ _inputData &= ~(1 << _inputBitPosition);
+ _inputData |= (_output << _inputBitPosition);
+ _inputBitPosition++;
+
+ if(_inputBitPosition > 15) {
+ if(_isWrite) {
+ _data[(_chipSelect ? 0x80 : 0) | _address] = _inputData;
+ _isWrite = false;
+ } else {
+ _isRead = false;
+
+ //done reading addr/command or write data
+ uint8_t address = (_inputData & 0x7F);
+
+ uint8_t cmd = ((_inputData & 0x7F00) >> 8) ^ 0x7F;
+ switch(cmd) {
+ case 0x01:
+ //read
+ _address = address;
+ _isRead = true;
+ break;
+ case 0x06:
+ //program
+ if(_writeEnabled) {
+ _address = address;
+ _isWrite = true;
+ }
+ break;
+ case 0x0C:
+ //chip erase
+ if(_writeEnabled) {
+ memset(_data, 0, BattleBox::FileSize);
+ }
+ break;
+
+ case 0x0D: break; //busy monitor
+ case 0x09: _writeEnabled = true; break; //erase/write enable
+ case 0x0B: _writeEnabled = false; break; //erase/write disable
+ }
+ }
+ _inputBitPosition = 0;
+ }
+ }
+ _lastWrite = value;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/ExcitingBoxingController.h b/Core/NES/Input/ExcitingBoxingController.h
new file mode 100644
index 00000000..43fbfbf2
--- /dev/null
+++ b/Core/NES/Input/ExcitingBoxingController.h
@@ -0,0 +1,64 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class Emulator;
+
+class ExcitingBoxingController : public BaseControlDevice
+{
+private:
+ uint8_t _selectedSensors = 0;
+ enum Buttons { LeftHook = 0, MoveRight, MoveLeft, RightHook, LeftJab, HitBody, RightJab, Straight };
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_selectedSensors);
+ }
+
+ string GetKeyNames() override
+ {
+ return "HRLhJBjS";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 8; i++) {
+ SetPressedState(i, keyMapping.CustomKeys[i]);
+ }
+ }
+ }
+
+public:
+ ExcitingBoxingController(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::ExcitingBoxing, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ if(_selectedSensors == 0) {
+ return
+ (IsPressed(ExcitingBoxingController::Buttons::LeftHook) ? 0 : 0x02) |
+ (IsPressed(ExcitingBoxingController::Buttons::MoveRight) ? 0 : 0x04) |
+ (IsPressed(ExcitingBoxingController::Buttons::MoveLeft) ? 0 : 0x08) |
+ (IsPressed(ExcitingBoxingController::Buttons::RightHook) ? 0 : 0x10);
+ } else {
+ return
+ (IsPressed(ExcitingBoxingController::Buttons::LeftJab) ? 0 : 0x02) |
+ (IsPressed(ExcitingBoxingController::Buttons::HitBody) ? 0 : 0x04) |
+ (IsPressed(ExcitingBoxingController::Buttons::RightJab) ? 0 : 0x08) |
+ (IsPressed(ExcitingBoxingController::Buttons::Straight) ? 0 : 0x10);
+ }
+ }
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ _selectedSensors = (value & 0x02) >> 1;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/FamilyBasicDataRecorder.h b/Core/NES/Input/FamilyBasicDataRecorder.h
new file mode 100644
index 00000000..ae4d690f
--- /dev/null
+++ b/Core/NES/Input/FamilyBasicDataRecorder.h
@@ -0,0 +1,141 @@
+#pragma once
+#include "stdafx.h"
+#include "../Utilities/Base64.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/Emulator.h"
+#include "Utilities/Serializer.h"
+
+class FamilyBasicDataRecorder : public BaseControlDevice
+{
+private:
+ static constexpr int32_t SamplingRate = 88;
+ vector _data;
+ vector _fileData;
+ bool _enabled = false;
+ bool _isPlaying = false;
+ uint64_t _cycle = 0;
+
+ bool _isRecording = false;
+ string _recordFilePath;
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ VectorInfo data { &_data };
+ s.Stream(_enabled, _isPlaying, _cycle, data);
+
+ if(!s.IsSaving() && _isRecording) {
+ StopRecording();
+ }
+ }
+
+ bool IsRawString() override
+ {
+ return true;
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ if(_fileData.size() > 0) {
+ SetTextState(Base64::Encode(_fileData));
+ _fileData.clear();
+ }
+ }
+
+public:
+ FamilyBasicDataRecorder(Emulator* emu) : BaseControlDevice(emu, ControllerType::None, BaseControlDevice::ExpDevicePort2)
+ {
+ }
+
+ ~FamilyBasicDataRecorder()
+ {
+ if(_isRecording) {
+ StopRecording();
+ }
+ }
+
+ void OnAfterSetState() override
+ {
+ if(GetRawState().State.size() > 0) {
+ _data = Base64::Decode(GetTextState());
+ _cycle = _emu->GetMasterClock();
+ _isPlaying = true;
+ _isRecording = false;
+ }
+ }
+
+ void LoadFromFile(VirtualFile file)
+ {
+ if(file.IsValid()) {
+ vector fileData;
+ file.ReadFile(fileData);
+ _fileData = fileData;
+ }
+ }
+
+ bool IsRecording()
+ {
+ return _isRecording;
+ }
+
+ void StartRecording(string filePath)
+ {
+ _isPlaying = false;
+ _recordFilePath = filePath;
+ _data.clear();
+ _cycle = _emu->GetMasterClock();
+ _isRecording = true;
+ }
+
+ void StopRecording()
+ {
+ _isRecording = false;
+
+ vector fileData;
+
+ int bitPos = 0;
+ uint8_t currentByte = 0;
+ for(uint8_t bitValue : _data) {
+ currentByte |= (bitValue & 0x01) << bitPos;
+ bitPos = (bitPos + 1) % 8;
+ if(bitPos == 0) {
+ fileData.push_back(currentByte);
+ currentByte = 0;
+ }
+ }
+
+ ofstream out(_recordFilePath, ios::binary);
+ if(out) {
+ out.write((char*)fileData.data(), fileData.size());
+ }
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4016 && _isPlaying) {
+ uint32_t readPos = (uint32_t)((_emu->GetMasterClock() - _cycle) / FamilyBasicDataRecorder::SamplingRate);
+
+ if((uint32_t)_data.size() > readPos / 8) {
+ uint8_t value = ((_data[readPos / 8] >> (readPos % 8)) & 0x01) << 1;
+ return _enabled ? value : 0;
+ } else {
+ _isPlaying = false;
+ }
+ }
+
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ _enabled = (value & 0x04) != 0;
+
+ if(_isRecording) {
+ while(_emu->GetMasterClock() - _cycle > FamilyBasicDataRecorder::SamplingRate) {
+ _data.push_back(value & 0x01);
+ _cycle += 88;
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/FamilyBasicKeyboard.h b/Core/NES/Input/FamilyBasicKeyboard.h
new file mode 100644
index 00000000..d67024c4
--- /dev/null
+++ b/Core/NES/Input/FamilyBasicKeyboard.h
@@ -0,0 +1,123 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class FamilyBasicKeyboard : public BaseControlDevice
+{
+private:
+ uint8_t _row = 0;
+ uint8_t _column = 0;
+ bool _enabled = false;
+
+ const uint32_t _keyMatrix[72] = {
+ F8, Return, LeftBracket, RightBracket,
+ Kana, RightShift, Yen, Stop,
+ F7, AtSign, Colon, SemiColon,
+ Underscore, Slash, Minus, Caret,
+ F6, O, L, K,
+ Dot, Comma, P, Num0,
+ F5, I, U, J,
+ M, N, Num9, Num8,
+ F4, Y, G, H,
+ B, V, Num7, Num6,
+ F3, T, R, D,
+ F, C, Num5, Num4,
+ F2, W, S, A,
+ X, Z, E, Num3,
+ F1, Esc, Q, Ctrl,
+ LeftShift, Grph, Num1, Num2,
+ ClrHome, Up, Right, Left,
+ Down, Space, Del, Ins
+ };
+
+ enum Buttons
+ {
+ A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
+ Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9,
+ Return, Space, Del, Ins, Esc,
+ Ctrl, RightShift, LeftShift,
+ RightBracket, LeftBracket,
+ Up, Down, Left, Right,
+ Dot, Comma, Colon, SemiColon, Underscore, Slash, Minus, Caret,
+ F1, F2, F3, F4, F5, F6, F7, F8,
+ Yen, Stop, AtSign, Grph, ClrHome, Kana
+ };
+
+ string GetKeyNames() override
+ {
+ return "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789rsdiecSs[]udlrd,:;_/-^12345678ysagck";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ //TODO
+ bool allowInput = false; // _emu->GetSettings()->IsKeyboardMode();
+
+ if(allowInput) {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 72; i++) {
+ SetPressedState(i, keyMapping.CustomKeys[i]);
+ }
+ }
+ }
+ }
+
+ uint8_t GetActiveKeys(uint8_t row, uint8_t column)
+ {
+ if(row == 9) {
+ //10th row has no keys
+ return 0;
+ }
+
+ uint8_t result = 0;
+ uint32_t baseIndex = row * 8 + (column ? 4 : 0);
+ for(int i = 0; i < 4; i++) {
+ if(IsPressed(_keyMatrix[baseIndex + i])) {
+ result |= 0x10;
+ }
+ result >>= 1;
+ }
+ return result;
+ }
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_row, _column, _enabled);
+ }
+
+public:
+ FamilyBasicKeyboard(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::FamilyBasicKeyboard, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ if(_enabled) {
+ return ((~GetActiveKeys(_row, _column)) << 1) & 0x1E;
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ uint8_t prevColumn = _column;
+ _column = (value & 0x02) >> 1;
+ if(!_column && prevColumn) {
+ //"Incrementing the row from the (keyless) 10th row will cause it to wrap back to the first row."
+ _row = (_row + 1) % 10;
+ }
+
+ if(value & 0x01) {
+ _row = 0;
+ }
+
+ _enabled = (value & 0x04) != 0;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/FamilyMatTrainer.h b/Core/NES/Input/FamilyMatTrainer.h
new file mode 100644
index 00000000..7958d94d
--- /dev/null
+++ b/Core/NES/Input/FamilyMatTrainer.h
@@ -0,0 +1,46 @@
+#pragma once
+#include "stdafx.h"
+#include "NES/Input/PowerPad.h"
+#include "Utilities/Serializer.h"
+
+class FamilyMatTrainer : public PowerPad
+{
+private:
+ uint8_t _ignoreRows = 0;
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_ignoreRows);
+ }
+
+public:
+ FamilyMatTrainer(Emulator* emu, KeyMappingSet keyMappings) : PowerPad(emu, ControllerType::FamilyTrainerMat, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if(addr == 0x4017) {
+ uint8_t pressedKeys[4] = {};
+ for(int j = 0; j < 3; j++) {
+ if((_ignoreRows >> (2 - j)) & 0x01) {
+ //Ignore this row
+ continue;
+ }
+ for(int i = 0; i < 4; i++) {
+ pressedKeys[i] |= IsPressed(j * 4 + i) ? 1 : 0;
+ }
+ }
+ output = ~((pressedKeys[0] << 4) | (pressedKeys[1] << 3) | (pressedKeys[2] << 2) | (pressedKeys[3] << 1)) & 0x1E;
+ }
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ _ignoreRows = value & 0x07;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/FourScore.h b/Core/NES/Input/FourScore.h
new file mode 100644
index 00000000..b4bfb5d1
--- /dev/null
+++ b/Core/NES/Input/FourScore.h
@@ -0,0 +1,50 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class FourScore : public BaseControlDevice
+{
+private:
+ uint32_t _signature4016 = 0;
+ uint32_t _signature4017 = 0;
+
+protected:
+ void Serialize(Serializer &s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_signature4016, _signature4017);
+ }
+
+ void RefreshStateBuffer() override
+ {
+ //Signature for port 0 = 0x10, reversed bit order => 0x08
+ //Signature for port 1 = 0x20, reversed bit order => 0x04
+ _signature4016 = (0x08 << 16);
+ _signature4017 = (0x04 << 16);
+ }
+
+public:
+ FourScore(Emulator* emu) : BaseControlDevice(emu, ControllerType::FourScore, BaseControlDevice::ExpDevicePort)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ StrobeProcessRead();
+ uint8_t output = 0;
+ if(addr == 0x4016) {
+ output = _signature4016 & 0x01;
+ _signature4016 >>= 1;
+ } else if(addr == 0x4017) {
+ output = _signature4017 & 0x01;
+ _signature4017 >>= 1;
+ }
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
diff --git a/Core/NES/Input/HoriTrack.h b/Core/NES/Input/HoriTrack.h
new file mode 100644
index 00000000..e99ea6dc
--- /dev/null
+++ b/Core/NES/Input/HoriTrack.h
@@ -0,0 +1,54 @@
+#pragma once
+#include "stdafx.h"
+#include "NES/Input/NesController.h"
+#include "Shared/KeyManager.h"
+
+class HoriTrack : public NesController
+{
+protected:
+ bool HasCoordinates() override { return true; }
+
+ void InternalSetStateFromInput() override
+ {
+ NesController::InternalSetStateFromInput();
+ SetPressedState(NesController::Buttons::A, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+ SetPressedState(NesController::Buttons::B, KeyManager::IsMouseButtonPressed(MouseButton::RightButton));
+ SetMovement(KeyManager::GetMouseMovement(
+ _emu->GetSettings()->GetVideoConfig().VideoScale,
+ _emu->GetSettings()->GetInputConfig().MouseSensitivity + 1
+ ));
+ }
+
+public:
+ HoriTrack(Emulator* emu, KeyMappingSet keyMappings) : NesController(emu, ControllerType::HoriTrack, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if(addr == 0x4016) {
+ StrobeProcessRead();
+ output = (_stateBuffer & 0x01) << 1;
+ _stateBuffer >>= 1;
+ }
+ return output;
+ }
+
+ void RefreshStateBuffer() override
+ {
+ MouseMovement mov = GetMovement();
+
+ mov.dx = std::max(-8, std::min((int)mov.dx, 7));
+ mov.dy = std::max(-8, std::min((int)mov.dy, 7));
+
+ mov.dx = ((mov.dx & 0x08) >> 3) | ((mov.dx & 0x04) >> 1) | ((mov.dx & 0x02) << 1) | ((mov.dx & 0x01) << 3);
+ mov.dy = ((mov.dy & 0x08) >> 3) | ((mov.dy & 0x04) >> 1) | ((mov.dy & 0x02) << 1) | ((mov.dy & 0x01) << 3);
+
+ uint8_t byte1 = (~mov.dy & 0x0F) | ((~mov.dx & 0x0F) << 4);
+ uint8_t byte2 = 0x09;
+
+ NesController::RefreshStateBuffer();
+ _stateBuffer = (_stateBuffer & 0xFF) | (byte1 << 8) | (byte2 << 16);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/IBarcodeReader.h b/Core/NES/Input/IBarcodeReader.h
new file mode 100644
index 00000000..dededbf9
--- /dev/null
+++ b/Core/NES/Input/IBarcodeReader.h
@@ -0,0 +1,8 @@
+#pragma once
+#include "stdafx.h"
+
+class IBarcodeReader
+{
+public:
+ virtual void InputBarcode(uint64_t barcode, uint32_t digitCount) = 0;
+};
diff --git a/Core/NES/Input/JissenMahjongController.h b/Core/NES/Input/JissenMahjongController.h
new file mode 100644
index 00000000..bcec2f28
--- /dev/null
+++ b/Core/NES/Input/JissenMahjongController.h
@@ -0,0 +1,99 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class JissenMahjongController : public BaseControlDevice
+{
+private:
+ uint8_t _row = 0;
+ uint32_t _stateBuffer = 0;
+
+protected:
+ enum Buttons { A = 0, B, C, D, E, F, G, H, I, J, K, L, M, N, Select, Start, Kan, Pon, Chii, Riichi, Ron };
+
+ string GetKeyNames() override
+ {
+ return "ABCDEFGHIJKLMNSTkpcir";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 21; i++) {
+ SetPressedState(i, keyMapping.CustomKeys[i]);
+ }
+ }
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_row, _stateBuffer);
+ }
+
+public:
+ JissenMahjongController(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::JissenMahjong, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ StrobeProcessRead();
+ uint8_t value = (_stateBuffer & 0x01) << 1;
+ _stateBuffer >>= 1;
+ return value;
+ }
+ return 0;
+ }
+
+ void RefreshStateBuffer() override
+ {
+ switch(_row) {
+ default:
+ case 0:
+ _stateBuffer = 0;
+ break;
+
+ case 1:
+ _stateBuffer =
+ (IsPressed(JissenMahjongController::Buttons::N) ? 0x04 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::M) ? 0x08 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::L) ? 0x10 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::K) ? 0x20 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::J) ? 0x40 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::I) ? 0x80 : 0);
+ break;
+
+ case 2:
+ _stateBuffer =
+ (IsPressed(JissenMahjongController::Buttons::H) ? 0x01 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::G) ? 0x02 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::F) ? 0x04 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::E) ? 0x08 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::D) ? 0x10 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::C) ? 0x20 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::B) ? 0x40 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::A) ? 0x80 : 0);
+ break;
+
+ case 3:
+ _stateBuffer =
+ (IsPressed(JissenMahjongController::Buttons::Ron) ? 0x02 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::Riichi) ? 0x04 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::Chii) ? 0x08 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::Pon) ? 0x10 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::Kan) ? 0x20 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::Start) ? 0x40 : 0) |
+ (IsPressed(JissenMahjongController::Buttons::Select) ? 0x80 : 0);
+ break;
+ }
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ _row = (value & 0x6) >> 1;
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/KonamiHyperShot.h b/Core/NES/Input/KonamiHyperShot.h
new file mode 100644
index 00000000..16f84d0d
--- /dev/null
+++ b/Core/NES/Input/KonamiHyperShot.h
@@ -0,0 +1,86 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/Emulator.h"
+#include "Utilities/Serializer.h"
+
+class KonamiHyperShot : public BaseControlDevice
+{
+private:
+ bool _enableP1 = true;
+ bool _enableP2 = true;
+ uint32_t _p1TurboSpeed;
+ uint32_t _p2TurboSpeed;
+ vector _p2KeyMappings;
+
+protected:
+ enum Buttons { Player1Run = 0, Player1Jump, Player2Run, Player2Jump };
+
+ string GetKeyNames() override
+ {
+ return "RJrj";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ for(KeyMapping keyMapping : _keyMappings) {
+ SetPressedState(Buttons::Player1Jump, keyMapping.A);
+ SetPressedState(Buttons::Player1Run, keyMapping.B);
+
+ uint8_t turboFreq = 1 << (4 - _p1TurboSpeed);
+ bool turboOn = (uint8_t)(_emu->GetFrameCount() % turboFreq) < turboFreq / 2;
+ if(turboOn) {
+ SetPressedState(Buttons::Player1Jump, keyMapping.TurboA);
+ SetPressedState(Buttons::Player1Run, keyMapping.TurboB);
+ }
+ }
+
+ for(KeyMapping keyMapping : _p2KeyMappings) {
+ SetPressedState(Buttons::Player2Jump, keyMapping.A);
+ SetPressedState(Buttons::Player2Run, keyMapping.B);
+
+ uint8_t turboFreq = 1 << (4 - _p2TurboSpeed);
+ bool turboOn = (uint8_t)(_emu->GetFrameCount() % turboFreq) < turboFreq / 2;
+ if(turboOn) {
+ SetPressedState(Buttons::Player2Jump, keyMapping.TurboA);
+ SetPressedState(Buttons::Player2Run, keyMapping.TurboB);
+ }
+ }
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_enableP1, _enableP2);
+ }
+
+public:
+ KonamiHyperShot(Emulator* emu, KeyMappingSet p1, KeyMappingSet p2) : BaseControlDevice(emu, ControllerType::KonamiHyperShot, BaseControlDevice::ExpDevicePort, p1)
+ {
+ _p1TurboSpeed = p1.TurboSpeed;
+ _p2TurboSpeed = p2.TurboSpeed;
+ _p2KeyMappings = p2.GetKeyMappingArray();
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if(addr == 0x4017) {
+ if(_enableP1) {
+ output |= IsPressed(KonamiHyperShot::Buttons::Player1Jump) ? 0x02 : 0;
+ output |= IsPressed(KonamiHyperShot::Buttons::Player1Run) ? 0x04 : 0;
+ }
+ if(_enableP2) {
+ output |= IsPressed(KonamiHyperShot::Buttons::Player2Jump) ? 0x08 : 0;
+ output |= IsPressed(KonamiHyperShot::Buttons::Player2Run) ? 0x10 : 0;
+ }
+ }
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ _enableP2 = (value & 0x02) == 0;
+ _enableP1 = (value & 0x04) == 0;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/NesController.h b/Core/NES/Input/NesController.h
index 46f7ba67..04d497bb 100644
--- a/Core/NES/Input/NesController.h
+++ b/Core/NES/Input/NesController.h
@@ -89,11 +89,10 @@ protected:
public:
enum Buttons { Up = 0, Down, Left, Right, Start, Select, B, A, Microphone };
- NesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, port, keyMappings)
+ NesController(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, type, port, keyMappings)
{
_turboSpeed = keyMappings.TurboSpeed;
- _microphoneEnabled = false;
- //_microphoneEnabled = port == 1 && _console->GetSettings()->GetConsoleType() == ConsoleType::Famicom;
+ _microphoneEnabled = port == 1 && type == ControllerType::FamicomController;
}
uint8_t ToByte()
diff --git a/Core/NES/Input/OekaKidsTablet.h b/Core/NES/Input/OekaKidsTablet.h
new file mode 100644
index 00000000..fb219023
--- /dev/null
+++ b/Core/NES/Input/OekaKidsTablet.h
@@ -0,0 +1,82 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/Emulator.h"
+#include "Shared/EmuSettings.h"
+#include "Shared/KeyManager.h"
+#include "Utilities/Serializer.h"
+
+class OekaKidsTablet : public BaseControlDevice
+{
+private:
+ bool _strobe = false;
+ bool _shift = false;
+ uint32_t _stateBuffer = 0;
+
+protected:
+ enum Buttons { Click, Touch };
+ bool HasCoordinates() override { return true; }
+
+ string GetKeyNames() override
+ {
+ return "CT";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ if(_emu->GetSettings()->IsInputEnabled()) {
+ MousePosition pos = KeyManager::GetMousePosition();
+ SetPressedState(Buttons::Click, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+ SetPressedState(Buttons::Touch, pos.Y >= 48 || KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+ SetCoordinates(pos);
+ }
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_strobe, _shift, _stateBuffer);
+ }
+
+public:
+ OekaKidsTablet(Emulator* emu) : BaseControlDevice(emu, ControllerType::OekaKidsTablet, BaseControlDevice::ExpDevicePort)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ if(_strobe) {
+ if(_shift) {
+ return (_stateBuffer & 0x40000) ? 0x00 : 0x08;
+ } else {
+ return 0x04;
+ }
+ } else {
+ return 0x00;
+ }
+ }
+
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ _strobe = (value & 0x01) == 0x01;
+ bool shift = ((value >> 1) & 0x01) == 0x01;
+
+ if(_strobe) {
+ if(!_shift && shift) {
+ _stateBuffer <<= 1;
+ }
+ _shift = shift;
+ } else {
+ MousePosition pos = GetCoordinates();
+
+ uint8_t xPosition = (uint8_t)((double)std::max(0, pos.X + 8) / 256.0 * 240);
+ uint8_t yPosition = (uint8_t)((double)std::max(0, pos.Y - 14) / 240.0 * 256);
+
+ _stateBuffer = (xPosition << 10) | (yPosition << 2) | (IsPressed(OekaKidsTablet::Buttons::Touch) ? 0x02 : 0x00) | (IsPressed(OekaKidsTablet::Buttons::Click) ? 0x01 : 0x00);
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/PachinkoController.h b/Core/NES/Input/PachinkoController.h
new file mode 100644
index 00000000..22f2b27a
--- /dev/null
+++ b/Core/NES/Input/PachinkoController.h
@@ -0,0 +1,60 @@
+#pragma once
+#include "stdafx.h"
+#include "NES/Input/NesController.h"
+
+class PachinkoController : public NesController
+{
+private:
+ uint8_t _analogData = 0;
+
+protected:
+ enum PachinkoButtons { Press = 8, Release = 9 };
+
+ void InternalSetStateFromInput() override
+ {
+ NesController::InternalSetStateFromInput();
+
+ for(KeyMapping keyMapping : _keyMappings) {
+ SetPressedState(PachinkoButtons::Press, keyMapping.CustomKeys[0]);
+ SetPressedState(PachinkoButtons::Release, keyMapping.CustomKeys[1]);
+ }
+ }
+
+public:
+ PachinkoController(Emulator* emu, KeyMappingSet keyMappings) : NesController(emu, ControllerType::Pachinko, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if(addr == 0x4016) {
+ StrobeProcessRead();
+ output = (_stateBuffer & 0x01) << 1;
+ _stateBuffer >>= 1;
+ }
+ return output;
+ }
+
+ void RefreshStateBuffer() override
+ {
+ if(_analogData < 63 && IsPressed(PachinkoController::PachinkoButtons::Press)) {
+ _analogData++;
+ } else if(_analogData > 0 && IsPressed(PachinkoController::PachinkoButtons::Release)) {
+ _analogData--;
+ }
+
+ uint8_t analogData =
+ ((_analogData & 0x01) << 7) |
+ ((_analogData & 0x02) << 5) |
+ ((_analogData & 0x04) << 3) |
+ ((_analogData & 0x08) << 1) |
+ ((_analogData & 0x10) >> 1) |
+ ((_analogData & 0x20) >> 3) |
+ ((_analogData & 0x40) >> 5) |
+ ((_analogData & 0x80) >> 7);
+
+ NesController::RefreshStateBuffer();
+ _stateBuffer = (_stateBuffer & 0xFF) | (~analogData << 8);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/PartyTap.h b/Core/NES/Input/PartyTap.h
new file mode 100644
index 00000000..2d223e9a
--- /dev/null
+++ b/Core/NES/Input/PartyTap.h
@@ -0,0 +1,76 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class Emulator;
+
+class PartyTap : public BaseControlDevice
+{
+private:
+ uint8_t _stateBuffer = 0;
+ uint8_t _readCount = 0;
+ bool _enabled = false;
+
+protected:
+ enum Buttons { B1 = 0, B2, B3, B4, B5, B6 };
+
+ string GetKeyNames() override
+ {
+ return "123456";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 6; i++) {
+ SetPressedState(i, keyMapping.CustomKeys[i]);
+ }
+ }
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_stateBuffer, _readCount, _enabled);
+ }
+
+public:
+ PartyTap(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::PartyTap, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ StrobeProcessRead();
+ if(_readCount < 2) {
+ uint8_t value = (_stateBuffer & 0x7) << 2;
+ _stateBuffer >>= 3;
+ _readCount++;
+ return value;
+ } else {
+ //"After 1st/2nd reads, a detection value can be read : $4017 & $1C == $14"
+ return 0x14;
+ }
+ }
+ return 0;
+ }
+
+ void RefreshStateBuffer() override
+ {
+ _readCount = 0;
+ _stateBuffer =
+ IsPressed(PartyTap::Buttons::B1) ? 1 : 0 |
+ IsPressed(PartyTap::Buttons::B2) ? 2 : 0 |
+ IsPressed(PartyTap::Buttons::B3) ? 4 : 0 |
+ IsPressed(PartyTap::Buttons::B4) ? 8 : 0 |
+ IsPressed(PartyTap::Buttons::B5) ? 16 : 0 |
+ IsPressed(PartyTap::Buttons::B6) ? 32 : 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/PowerPad.h b/Core/NES/Input/PowerPad.h
new file mode 100644
index 00000000..6cec30ae
--- /dev/null
+++ b/Core/NES/Input/PowerPad.h
@@ -0,0 +1,81 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class Emulator;
+
+class PowerPad : public BaseControlDevice
+{
+private:
+ uint8_t _stateBufferL = 0;
+ uint8_t _stateBufferH = 0;
+
+protected:
+ string GetKeyNames() override
+ {
+ return "123456789ABC";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 3; i++) {
+ for(int j = 0; j < 4; j++) {
+ if(false) { //TODO
+ //Invert the order of each row
+ SetPressedState(i*4+j, keyMapping.CustomKeys[i*4+(3-j)]);
+ } else {
+ SetPressedState(i*4+j, keyMapping.CustomKeys[i*4+j]);
+ }
+ }
+ }
+ }
+ }
+
+ void RefreshStateBuffer() override
+ {
+ uint8_t pressedKeys[12] = {};
+ for(int i = 0; i < 12; i++) {
+ pressedKeys[i] |= IsPressed(i) ? 1 : 0;
+ }
+
+ //"Serial data from buttons 2, 1, 5, 9, 6, 10, 11, 7"
+ _stateBufferL = pressedKeys[1] | (pressedKeys[0] << 1) | (pressedKeys[4] << 2) | (pressedKeys[8] << 3) | (pressedKeys[5] << 4) | (pressedKeys[9] << 5) | (pressedKeys[10] << 6) | (pressedKeys[6] << 7);
+
+ //"Serial data from buttons 4, 3, 12, 8 (following 4 bits read as H=1)"
+ _stateBufferH = pressedKeys[3] | (pressedKeys[2] << 1) | (pressedKeys[11] << 2) | (pressedKeys[7] << 3) | 0xF0;
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_stateBufferL, _stateBufferH);
+ }
+
+public:
+ PowerPad(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, type, port, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if(IsCurrentPort(addr)) {
+ StrobeProcessRead();
+
+ output = ((_stateBufferH & 0x01) << 4) | ((_stateBufferL & 0x01) << 3);
+ _stateBufferL >>= 1;
+ _stateBufferH >>= 1;
+
+ _stateBufferL |= 0x80;
+ _stateBufferH |= 0x80;
+ }
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/SuborKeyboard.h b/Core/NES/Input/SuborKeyboard.h
new file mode 100644
index 00000000..6b0059ef
--- /dev/null
+++ b/Core/NES/Input/SuborKeyboard.h
@@ -0,0 +1,126 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Utilities/Serializer.h"
+
+class SuborKeyboard : public BaseControlDevice
+{
+private:
+ uint8_t _row = 0;
+ uint8_t _column = 0;
+ bool _enabled = false;
+
+protected:
+ string GetKeyNames() override
+ {
+ return "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567891234567890120123456789edpmdmncdsasbemglrcpcsasbteeehidududlr123";
+ }
+
+ enum Buttons
+ {
+ A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
+ Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9,
+ F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
+ Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
+ NumpadEnter, NumpadDot, NumpadPlus, NumpadMultiply, NumpadDivide, NumpadMinus, NumLock,
+ Comma, Dot, SemiColon, Apostrophe,
+ Slash, Backslash,
+ Equal, Minus, Grave,
+ LeftBracket, RightBracket,
+ CapsLock, Pause,
+ Ctrl, Shift, Alt,
+ Space, Backspace, Tab, Esc, Enter,
+ End, Home,
+ Ins, Delete,
+ PageUp, PageDown,
+ Up, Down, Left, Right,
+ Unknown1, Unknown2, Unknown3,
+ };
+
+ Buttons _keyboardMatrix[104] = {
+ Num4, G, F, C, F2, E, Num5, V,
+ Num2, D, S, End, F1, W, Num3, X,
+ Ins, Backspace, PageDown, Right, F8, PageUp, Delete, Home,
+ Num9, I, L, Comma, F5, O, Num0, Dot,
+ RightBracket, Enter, Up, Left, F7, LeftBracket, Backslash, Down,
+ Q, CapsLock, Z, Tab, Esc, A, Num1, Ctrl,
+ Num7, Y, K, M, F4, U, Num8, J,
+ Minus, SemiColon, Apostrophe, Slash, F6, P, Equal, Shift,
+ T, H, N, Space, F3, R, Num6, B,
+ Numpad6, NumpadEnter, Numpad4, Numpad8, Numpad2, Unknown1, Unknown2, Unknown3,
+ Alt, Numpad4, Numpad7, F11, F12, Numpad1, Numpad2, Numpad8,
+ NumpadMinus, NumpadPlus, NumpadMultiply, Numpad9, F10, Numpad5, NumpadDivide, NumLock,
+ Grave, Numpad6, Pause, Space, F9, Numpad3, NumpadDot, Numpad0
+ };
+
+ void InternalSetStateFromInput() override
+ {
+ //TODO
+ bool allowInput = false; // _emu->GetSettings()->IsKeyboardMode();
+ if(allowInput) {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 99; i++) {
+ SetPressedState(i, keyMapping.CustomKeys[i]);
+ }
+ }
+ }
+ }
+
+ uint8_t GetActiveKeys(uint8_t row, uint8_t column)
+ {
+ uint8_t result = 0;
+ uint32_t baseIndex = row * 8 + (column ? 4 : 0);
+ for(int i = 0; i < 4; i++) {
+ if(IsPressed(_keyboardMatrix[baseIndex + i])) {
+ result |= 0x10;
+ }
+ result >>= 1;
+ }
+ return result;
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_row, _column, _enabled);
+ }
+
+ void RefreshStateBuffer() override
+ {
+ _row = 0;
+ _column = 0;
+ }
+
+public:
+ SuborKeyboard(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::SuborKeyboard, BaseControlDevice::ExpDevicePort, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(addr == 0x4017) {
+ if(_enabled) {
+ uint8_t value = ((~GetActiveKeys(_row, _column)) << 1) & 0x1E;
+ return value;
+ } else {
+ return 0x1E;
+ }
+ }
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+
+ uint8_t prevColumn = _column;
+ _column = (value & 0x02) >> 1;
+ _enabled = (value & 0x04) != 0;
+
+ if(_enabled) {
+ if(!_column && prevColumn) {
+ _row = (_row + 1) % 13;
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/SuborMouse.h b/Core/NES/Input/SuborMouse.h
new file mode 100644
index 00000000..cac1fbaf
--- /dev/null
+++ b/Core/NES/Input/SuborMouse.h
@@ -0,0 +1,110 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/KeyManager.h"
+#include "Shared/EmuSettings.h"
+#include "Shared/Emulator.h"
+#include "Utilities/Serializer.h"
+
+class SuborMouse : public BaseControlDevice
+{
+private:
+ uint32_t _stateBuffer = 0;
+ uint8_t _packetBytes[3] = {};
+ uint8_t _packetPos = 0;
+ uint8_t _packetSize = 1;
+
+protected:
+ bool HasCoordinates() override { return true; }
+ enum Buttons { Left = 0, Right };
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ ArrayInfo packetBytes { _packetBytes, 3 };
+ s.Stream(_stateBuffer, _packetPos, _packetSize, packetBytes);
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ SetPressedState(Buttons::Left, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+ SetPressedState(Buttons::Right, KeyManager::IsMouseButtonPressed(MouseButton::RightButton));
+ SetMovement(KeyManager::GetMouseMovement(
+ _emu->GetSettings()->GetVideoConfig().VideoScale,
+ _emu->GetSettings()->GetInputConfig().MouseSensitivity + 1
+ ));
+ }
+
+public:
+ SuborMouse(Emulator* emu, uint8_t port) : BaseControlDevice(emu, ControllerType::SuborMouse, port)
+ {
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) {
+ StrobeProcessRead();
+ output = (_stateBuffer & 0x80) >> 7;
+ if(_port >= 2) {
+ output <<= 1;
+ }
+ _stateBuffer <<= 1;
+ }
+ return output;
+ }
+
+ void RefreshStateBuffer() override
+ {
+ if(_packetPos < _packetSize - 1) {
+ //3-byte packet is not done yet, move to next byte
+ _packetPos++;
+ _stateBuffer = _packetBytes[_packetPos];
+ return;
+ }
+
+ MouseMovement mov = GetMovement();
+
+ uint32_t upFlag = mov.dy < 0 ? 0x80 : 0;
+ uint32_t leftFlag = mov.dx < 0 ? 0x80 : 0;
+
+ mov.dx = std::min(std::abs(mov.dx), 31);
+ mov.dy = std::min(std::abs(mov.dy), 31);
+
+ if(mov.dx <= 1 && mov.dy <= 1) {
+ //1-byte packet
+ _packetBytes[0] =
+ (IsPressed(SuborMouse::Buttons::Left) ? 0x80 : 0) |
+ (IsPressed(SuborMouse::Buttons::Right) ? 0x40 : 0) |
+ (leftFlag && mov.dx ? 0x30 : (mov.dx ? 0x10 : 0)) |
+ (upFlag && mov.dy ? 0x0C : (mov.dy ? 0x04 : 0));
+ _packetBytes[1] = 0;
+ _packetBytes[2] = 0;
+
+ _packetSize = 1;
+ } else {
+ //3-byte packet
+ _packetBytes[0] =
+ (IsPressed(SuborMouse::Buttons::Left) ? 0x80 : 0) |
+ (IsPressed(SuborMouse::Buttons::Right) ? 0x40 : 0) |
+ (leftFlag ? 0x20 : 0) |
+ (mov.dx & 0x10) |
+ (upFlag ? 0x08 : 0) |
+ ((mov.dy & 0x10) >> 2) |
+ 0x01;
+
+ _packetBytes[1] = ((mov.dx & 0x0F) << 2) | 0x02;
+ _packetBytes[2] = ((mov.dy & 0x0F) << 2) | 0x03;
+
+ _packetSize = 3;
+ }
+
+ _packetPos = 0;
+ _stateBuffer = _packetBytes[0];
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/VirtualBoyController.h b/Core/NES/Input/VirtualBoyController.h
new file mode 100644
index 00000000..d397b49e
--- /dev/null
+++ b/Core/NES/Input/VirtualBoyController.h
@@ -0,0 +1,109 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "Shared/Emulator.h"
+#include "Shared/EmuSettings.h"
+#include "Utilities/Serializer.h"
+
+class VirtualBoyController : public BaseControlDevice
+{
+private:
+ uint32_t _stateBuffer = 0;
+
+protected:
+ enum Buttons { Down1 = 0, Left1, Select, Start, Up0, Down0, Left0, Right0, Right1, Up1, L, R, B, A };
+
+ string GetKeyNames() override
+ {
+ return "dlSTUDLRruLRBA";
+ }
+
+ void InternalSetStateFromInput() override
+ {
+ for(KeyMapping keyMapping : _keyMappings) {
+ for(int i = 0; i < 14; i++) {
+ SetPressedState(i, keyMapping.CustomKeys[i]);
+ }
+
+ if(!_emu->GetSettings()->GetNesConfig().AllowInvalidInput) {
+ //If both U+D or L+R are pressed at the same time, act as if neither is pressed
+ if(IsPressed(Buttons::Up0) && IsPressed(Buttons::Down0)) {
+ ClearBit(Buttons::Down0);
+ ClearBit(Buttons::Up0);
+ }
+ if(IsPressed(Buttons::Left0) && IsPressed(Buttons::Right0)) {
+ ClearBit(Buttons::Left0);
+ ClearBit(Buttons::Right0);
+ }
+ if (IsPressed(Buttons::Up1) && IsPressed(Buttons::Down1)) {
+ ClearBit(Buttons::Down1);
+ ClearBit(Buttons::Up1);
+ }
+ if (IsPressed(Buttons::Left1) && IsPressed(Buttons::Right1)) {
+ ClearBit(Buttons::Left1);
+ ClearBit(Buttons::Right1);
+ }
+ }
+ }
+ }
+
+ uint16_t ToByte()
+ {
+ //"A Virtual Boy controller returns a 16-bit report in a similar order as SNES, with two additional buttons."
+
+ return
+ (uint8_t)IsPressed(Buttons::Down1) |
+ ((uint8_t)IsPressed(Buttons::Left1) << 1) |
+ ((uint8_t)IsPressed(Buttons::Select) << 2) |
+ ((uint8_t)IsPressed(Buttons::Start) << 3) |
+ ((uint8_t)IsPressed(Buttons::Up0) << 4) |
+ ((uint8_t)IsPressed(Buttons::Down0) << 5) |
+ ((uint8_t)IsPressed(Buttons::Left0) << 6) |
+ ((uint8_t)IsPressed(Buttons::Right0) << 7) |
+ ((uint8_t)IsPressed(Buttons::Right1) << 8) |
+ ((uint8_t)IsPressed(Buttons::Up1) << 9) |
+ ((uint8_t)IsPressed(Buttons::L) << 10) |
+ ((uint8_t)IsPressed(Buttons::R) << 11) |
+ ((uint8_t)IsPressed(Buttons::B) << 12) |
+ ((uint8_t)IsPressed(Buttons::A) << 13) |
+ (1 << 14);
+ }
+
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_stateBuffer);
+ }
+
+ void RefreshStateBuffer() override
+ {
+ _stateBuffer = (uint32_t)ToByte();
+ }
+
+public:
+ VirtualBoyController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::VirtualBoyController, port, keyMappings)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+
+ if(IsCurrentPort(addr)) {
+ StrobeProcessRead();
+
+ output = _stateBuffer & 0x01;
+ _stateBuffer >>= 1;
+
+ //"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
+ _stateBuffer |= 0x8000;
+ }
+
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/VsZapper.h b/Core/NES/Input/VsZapper.h
new file mode 100644
index 00000000..39855b4a
--- /dev/null
+++ b/Core/NES/Input/VsZapper.h
@@ -0,0 +1,45 @@
+#pragma once
+#include "stdafx.h"
+#include "NES/Input/Zapper.h"
+
+class NesConsole;
+
+class VsZapper : public Zapper
+{
+private:
+ uint32_t _stateBuffer = 0;
+
+protected:
+ void Serialize(Serializer& s) override
+ {
+ BaseControlDevice::Serialize(s);
+ s.Stream(_stateBuffer);
+ }
+
+ void RefreshStateBuffer() override
+ {
+ _stateBuffer = 0x10 | (IsLightFound() ? 0x40 : 0x00) | (IsPressed(Zapper::Buttons::Fire) ? 0x80 : 0x00);
+ }
+
+public:
+ VsZapper(NesConsole* console, uint8_t port) : Zapper(console, ControllerType::VsZapper, port)
+ {
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ if(IsCurrentPort(addr)) {
+ StrobeProcessRead();
+ uint8_t returnValue = _stateBuffer & 0x01;
+ _stateBuffer >>= 1;
+ return returnValue;
+ }
+
+ return 0;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ StrobeProcessWrite(value);
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/Input/Zapper.h b/Core/NES/Input/Zapper.h
new file mode 100644
index 00000000..9e32d1b5
--- /dev/null
+++ b/Core/NES/Input/Zapper.h
@@ -0,0 +1,98 @@
+#pragma once
+#include "stdafx.h"
+#include "Shared/BaseControlDevice.h"
+#include "NES/NesPpu.h"
+#include "NES/NesConsole.h"
+#include "Shared/Emulator.h"
+#include "Shared/Emulator.h"
+#include "Shared/EmuSettings.h"
+#include "Shared/KeyManager.h"
+#include "Utilities/Serializer.h"
+
+class Zapper : public BaseControlDevice
+{
+private:
+ NesConsole* _console;
+
+protected:
+ bool HasCoordinates() override { return true; }
+
+ string GetKeyNames() override
+ {
+ return "F";
+ }
+
+ ControllerType GetControllerType()
+ {
+ return ControllerType::NesController;
+ }
+
+ enum Buttons { Fire };
+
+ void InternalSetStateFromInput() override
+ {
+ SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
+
+ MousePosition pos = KeyManager::GetMousePosition();
+ if(KeyManager::IsMouseButtonPressed(MouseButton::RightButton)) {
+ pos.X = -1;
+ pos.Y = -1;
+ }
+ SetCoordinates(pos);
+ }
+
+ bool IsLightFound()
+ {
+ return StaticIsLightFound(GetCoordinates(), _console);
+ }
+
+public:
+ Zapper(NesConsole* console, ControllerType type, uint8_t port) : BaseControlDevice(console->GetEmulator(), type, port)
+ {
+ _console = console;
+ }
+
+ uint8_t ReadRam(uint16_t addr) override
+ {
+ uint8_t output = 0;
+ if((IsExpansionDevice() && addr == 0x4017) || IsCurrentPort(addr)) {
+ output = (IsLightFound() ? 0 : 0x08) | (IsPressed(Zapper::Buttons::Fire) ? 0x10 : 0x00);
+ }
+ return output;
+ }
+
+ void WriteRam(uint16_t addr, uint8_t value) override
+ {
+ }
+
+ static bool StaticIsLightFound(MousePosition pos, NesConsole* console)
+ {
+ NesPpu* ppu = console ? console->GetPpu() : nullptr;
+ if(!ppu) {
+ return false;
+ }
+
+ int32_t scanline = ppu->GetCurrentScanline();
+ int32_t cycle = ppu->GetCurrentCycle();
+ int radius = (int)console->GetNesConfig().ZapperDetectionRadius;
+
+ if(pos.X >= 0 && pos.Y >= 0) {
+ for(int yOffset = -radius; yOffset <= radius; yOffset++) {
+ int yPos = pos.Y + yOffset;
+ if(yPos >= 0 && yPos < NesPpu::ScreenHeight) {
+ for(int xOffset = -radius; xOffset <= radius; xOffset++) {
+ int xPos = pos.X + xOffset;
+ if(xPos >= 0 && xPos < NesPpu::ScreenWidth) {
+ if(scanline >= yPos && (scanline - yPos <= 20) && (scanline != yPos || cycle > xPos) && ppu->GetPixelBrightness(xPos, yPos) >= 85) {
+ //Light cannot be detected if the Y/X position is further ahead than the PPU, or if the PPU drew a dark color
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+};
\ No newline at end of file
diff --git a/Core/NES/NesConsole.cpp b/Core/NES/NesConsole.cpp
index 75642e21..ec8fb409 100644
--- a/Core/NES/NesConsole.cpp
+++ b/Core/NES/NesConsole.cpp
@@ -249,3 +249,8 @@ uint64_t NesConsole::GetMasterClock()
{
return _cpu->GetCycleCount();
}
+
+uint32_t NesConsole::GetMasterClockRate()
+{
+ return NesCpu::ClockRateNtsc;
+}
diff --git a/Core/NES/NesConsole.h b/Core/NES/NesConsole.h
index bfc5811d..8a29a469 100644
--- a/Core/NES/NesConsole.h
+++ b/Core/NES/NesConsole.h
@@ -77,5 +77,6 @@ public:
virtual AddressInfo GetAbsoluteAddress(AddressInfo relAddress) override;
virtual AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType) override;
- virtual uint64_t GetMasterClock() override;
+ uint64_t GetMasterClock() override;
+ uint32_t GetMasterClockRate() override;
};
diff --git a/Core/NES/NesControlManager.cpp b/Core/NES/NesControlManager.cpp
index f65b52a2..3c32df36 100644
--- a/Core/NES/NesControlManager.cpp
+++ b/Core/NES/NesControlManager.cpp
@@ -3,8 +3,6 @@
#include "NES/BaseMapper.h"
#include "NES/NesConsole.h"
#include "NES/NesMemoryManager.h"
-#include "NES/Input/NesController.h"
-#include "SNES/Input/SnesController.h"
#include "Shared/EmuSettings.h"
#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/Interfaces/IInputProvider.h"
@@ -13,30 +11,31 @@
#include "Shared/Emulator.h"
#include "Shared/KeyManager.h"
#include "Shared/SystemActionManager.h"
-/*#include "Zapper.h"
-#include "ArkanoidController.h"
-#include "OekaKidsTablet.h"
-#include "FourScore.h"
-#include "SnesController.h"
-#include "SnesMouse.h"
-#include "PowerPad.h"
-#include "FamilyMatTrainer.h"
-#include "KonamiHyperShot.h"
-#include "FamilyBasicKeyboard.h"
-#include "FamilyBasicDataRecorder.h"
-#include "PartyTap.h"
-#include "PachinkoController.h"
-#include "ExcitingBoxingController.h"
-#include "SuborKeyboard.h"
-#include "SuborMouse.h"
-#include "JissenMahjongController.h"
-#include "BarcodeBattlerReader.h"
-#include "HoriTrack.h"
-#include "BandaiHyperShot.h"
-#include "VsZapper.h"
-#include "AsciiTurboFile.h"
-#include "BattleBox.h"
-#include "VbController.h"*/
+#include "NES/Input/NesController.h"
+#include "SNES/Input/SnesController.h"
+#include "SNES/Input/SnesMouse.h"
+#include "NES/Input/Zapper.h"
+#include "NES/Input/ArkanoidController.h"
+#include "NES/Input/OekaKidsTablet.h"
+#include "NES/Input/FourScore.h"
+#include "NES/Input/PowerPad.h"
+#include "NES/Input/FamilyMatTrainer.h"
+#include "NES/Input/KonamiHyperShot.h"
+#include "NES/Input/FamilyBasicKeyboard.h"
+#include "NES/Input/FamilyBasicDataRecorder.h"
+#include "NES/Input/PartyTap.h"
+#include "NES/Input/PachinkoController.h"
+#include "NES/Input/ExcitingBoxingController.h"
+#include "NES/Input/SuborKeyboard.h"
+#include "NES/Input/SuborMouse.h"
+#include "NES/Input/JissenMahjongController.h"
+#include "NES/Input/BarcodeBattlerReader.h"
+#include "NES/Input/HoriTrack.h"
+#include "NES/Input/BandaiHyperShot.h"
+#include "NES/Input/VsZapper.h"
+#include "NES/Input/AsciiTurboFile.h"
+#include "NES/Input/BattleBox.h"
+#include "NES/Input/VirtualBoyController.h"
NesControlManager::NesControlManager(shared_ptr console, shared_ptr mapperControlDevice) : BaseControlManager(console->GetEmulator())
{
@@ -58,48 +57,43 @@ shared_ptr NesControlManager::CreateControllerDevice(Controll
shared_ptr device;
NesConfig cfg = _emu->GetSettings()->GetNesConfig();
+ KeyMappingSet keys = cfg.Controllers[port].Keys;
switch(type) {
case ControllerType::None: break;
- case ControllerType::NesController: device.reset(new NesController(_emu, port, cfg.Controllers[port].Keys)); break;
- //case ControllerType::Zapper: device.reset(new Zapper(console, port)); break;
- //case ControllerType::ArkanoidController: device.reset(new ArkanoidController(console, port)); break;
- case ControllerType::SnesController: device.reset(new SnesController(_emu, port, cfg.Controllers[port].Keys)); break;
- /*case ControllerType::PowerPad: device.reset(new PowerPad(console, port, console->GetSettings()->GetControllerKeys(port))); break;
- case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port)); break;
- case ControllerType::SuborMouse: device.reset(new SuborMouse(console, port)); break;
- case ControllerType::VsZapper: device.reset(new VsZapper(console, port)); break;
- case ControllerType::VbController: device.reset(new VbController(console, port, console->GetSettings()->GetControllerKeys(port))); break;*/
- }
-
- return device;
-}
+ case ControllerType::NesController: device.reset(new NesController(_emu, type, port, keys)); break;
+ case ControllerType::FamicomController: device.reset(new NesController(_emu, type, port, keys)); break;
+ case ControllerType::NesZapper: device.reset(new Zapper(_console.get(), type, port)); break;
+ case ControllerType::NesArkanoidController: device.reset(new ArkanoidController(_emu, type, port)); break;
+ case ControllerType::SnesController: device.reset(new SnesController(_emu, port, keys)); break;
+ case ControllerType::PowerPad: device.reset(new PowerPad(_emu, type, port, keys)); break;
+ case ControllerType::SnesMouse: device.reset(new SnesMouse(_emu, port)); break;
+ case ControllerType::SuborMouse: device.reset(new SuborMouse(_emu, port)); break;
+ case ControllerType::VsZapper: device.reset(new VsZapper(_console.get(), port)); break;
+ case ControllerType::VirtualBoyController: device.reset(new VirtualBoyController(_emu, port, keys)); break;
-shared_ptr NesControlManager::CreateExpansionDevice(ExpansionPortDevice type)
-{
- shared_ptr device;
+ //Exp port devices
+ case ControllerType::FamicomZapper: device.reset(new Zapper(_console.get(), type, BaseControlDevice::ExpDevicePort)); break;
+ case ControllerType::FamicomArkanoidController: device.reset(new ArkanoidController(_emu, type, BaseControlDevice::ExpDevicePort)); break;
+ case ControllerType::OekaKidsTablet: device.reset(new OekaKidsTablet(_emu)); break;
+ case ControllerType::FamilyTrainerMat: device.reset(new FamilyMatTrainer(_emu, keys)); break;
+ case ControllerType::KonamiHyperShot: device.reset(new KonamiHyperShot(_emu, keys, cfg.Controllers[1].Keys)); break;
+ case ControllerType::FamilyBasicKeyboard: device.reset(new FamilyBasicKeyboard(_emu, keys)); break;
+ case ControllerType::PartyTap: device.reset(new PartyTap(_emu, keys)); break;
+ case ControllerType::Pachinko: device.reset(new PachinkoController(_emu, keys)); break;
+ case ControllerType::ExcitingBoxing: device.reset(new ExcitingBoxingController(_emu, keys)); break;
+ case ControllerType::JissenMahjong: device.reset(new JissenMahjongController(_emu, keys)); break;
+ case ControllerType::SuborKeyboard: device.reset(new SuborKeyboard(_emu, keys)); break;
+ case ControllerType::BarcodeBattler: device.reset(new BarcodeBattlerReader(_emu)); break;
+ case ControllerType::HoriTrack: device.reset(new HoriTrack(_emu, keys)); break;
+ case ControllerType::BandaiHyperShot: device.reset(new BandaiHyperShot(_console.get(), keys)); break;
+ case ControllerType::AsciiTurboFile: device.reset(new AsciiTurboFile(_emu)); break;
+ case ControllerType::BattleBox: device.reset(new BattleBox(_emu)); break;
- /*switch(type) {
- case ExpansionPortDevice::Zapper: device.reset(new Zapper(console, BaseControlDevice::ExpDevicePort)); break;
- case ExpansionPortDevice::ArkanoidController: device.reset(new ArkanoidController(console, BaseControlDevice::ExpDevicePort)); break;
- case ExpansionPortDevice::OekaKidsTablet: device.reset(new OekaKidsTablet(console)); break;
- case ExpansionPortDevice::FamilyTrainerMat: device.reset(new FamilyMatTrainer(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::KonamiHyperShot: device.reset(new KonamiHyperShot(console, console->GetSettings()->GetControllerKeys(0), console->GetSettings()->GetControllerKeys(1))); break;
- case ExpansionPortDevice::FamilyBasicKeyboard: device.reset(new FamilyBasicKeyboard(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::PartyTap: device.reset(new PartyTap(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::Pachinko: device.reset(new PachinkoController(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::ExcitingBoxing: device.reset(new ExcitingBoxingController(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::JissenMahjong: device.reset(new JissenMahjongController(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::SuborKeyboard: device.reset(new SuborKeyboard(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::BarcodeBattler: device.reset(new BarcodeBattlerReader(console)); break;
- case ExpansionPortDevice::HoriTrack: device.reset(new HoriTrack(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::BandaiHyperShot: device.reset(new BandaiHyperShot(console, console->GetSettings()->GetControllerKeys(0))); break;
- case ExpansionPortDevice::AsciiTurboFile: device.reset(new AsciiTurboFile(console)); break;
- case ExpansionPortDevice::BattleBox: device.reset(new BattleBox(console)); break;
-
- case ExpansionPortDevice::FourPlayerAdapter:
+ case ControllerType::FourScore: //TODO
+ case ControllerType::FourPlayerAdapter: //TODO
default: break;
- }*/
+ }
return device;
}
diff --git a/Core/SNES/ControlManager.cpp b/Core/SNES/ControlManager.cpp
index 8c7e4623..4ef59963 100644
--- a/Core/SNES/ControlManager.cpp
+++ b/Core/SNES/ControlManager.cpp
@@ -41,7 +41,7 @@ shared_ptr ControlManager::CreateControllerDevice(ControllerT
switch(type) {
case ControllerType::None: break;
case ControllerType::SnesController: device.reset(new SnesController(_emu, port, cfg.Controllers[port].Keys)); break;
- case ControllerType::SnesMouse: device.reset(new SnesMouse(_console, port)); break;
+ case ControllerType::SnesMouse: device.reset(new SnesMouse(_emu, port)); break;
case ControllerType::SuperScope: device.reset(new SuperScope(_console, port, cfg.Controllers[port].Keys)); break;
case ControllerType::Multitap: device.reset(new Multitap(_console, port, cfg.Controllers[port].Keys, cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, cfg.Controllers[4].Keys)); break;
}
diff --git a/Core/SNES/Input/Multitap.cpp b/Core/SNES/Input/Multitap.cpp
index b99f001c..ea1f5c5c 100644
--- a/Core/SNES/Input/Multitap.cpp
+++ b/Core/SNES/Input/Multitap.cpp
@@ -94,7 +94,7 @@ void Multitap::RefreshStateBuffer()
}
}
-Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console->GetEmulator(), port, keyMappings1)
+Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console->GetEmulator(), ControllerType::Multitap, port, keyMappings1)
{
_turboSpeed[0] = keyMappings1.TurboSpeed;
_turboSpeed[1] = keyMappings2.TurboSpeed;
@@ -108,11 +108,6 @@ Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, K
_internalRegs = console->GetInternalRegisters().get();
}
-ControllerType Multitap::GetControllerType()
-{
- return ControllerType::Multitap;
-}
-
void Multitap::SetControllerState(uint8_t controllerNumber, ControlDeviceState state)
{
SnesController controller(_emu, 0, KeyMappingSet());
diff --git a/Core/SNES/Input/Multitap.h b/Core/SNES/Input/Multitap.h
index 6038d652..599df24e 100644
--- a/Core/SNES/Input/Multitap.h
+++ b/Core/SNES/Input/Multitap.h
@@ -29,8 +29,6 @@ protected:
public:
Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4);
- ControllerType GetControllerType() override;
-
void SetControllerState(uint8_t controllerNumber, ControlDeviceState state);
uint8_t ReadRam(uint16_t addr) override;
diff --git a/Core/SNES/Input/SnesController.cpp b/Core/SNES/Input/SnesController.cpp
index c267a79a..d616af01 100644
--- a/Core/SNES/Input/SnesController.cpp
+++ b/Core/SNES/Input/SnesController.cpp
@@ -2,7 +2,7 @@
#include "SNES/Input/SnesController.h"
#include "Shared/Emulator.h"
-SnesController::SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, port, keyMappings)
+SnesController::SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::SnesController, port, keyMappings)
{
_turboSpeed = keyMappings.TurboSpeed;
}
@@ -71,11 +71,6 @@ void SnesController::RefreshStateBuffer()
_stateBuffer = (uint32_t)ToByte();
}
-ControllerType SnesController::GetControllerType()
-{
- return ControllerType::SnesController;
-}
-
uint8_t SnesController::ReadRam(uint16_t addr)
{
uint8_t output = 0;
diff --git a/Core/SNES/Input/SnesController.h b/Core/SNES/Input/SnesController.h
index fc4b712d..71e9250e 100644
--- a/Core/SNES/Input/SnesController.h
+++ b/Core/SNES/Input/SnesController.h
@@ -21,7 +21,6 @@ public:
SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings);
- ControllerType GetControllerType() override;
uint8_t ReadRam(uint16_t addr) override;
void WriteRam(uint16_t addr, uint8_t value) override;
};
\ No newline at end of file
diff --git a/Core/SNES/Input/SnesMouse.h b/Core/SNES/Input/SnesMouse.h
index e7936576..2eeafd9d 100644
--- a/Core/SNES/Input/SnesMouse.h
+++ b/Core/SNES/Input/SnesMouse.h
@@ -1,6 +1,5 @@
#pragma once
#include "stdafx.h"
-#include "SNES/Console.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/KeyManager.h"
@@ -42,16 +41,11 @@ protected:
public:
enum Buttons { Left = 0, Right };
- SnesMouse(Console* console, uint8_t port) : BaseControlDevice(console->GetEmulator(), port)
+ SnesMouse(Emulator* emu, uint8_t port) : BaseControlDevice(emu, ControllerType::SnesMouse, port)
{
_settings = _emu->GetSettings();
}
- ControllerType GetControllerType() override
- {
- return ControllerType::SnesMouse;
- }
-
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
diff --git a/Core/SNES/Input/SuperScope.h b/Core/SNES/Input/SuperScope.h
index 7517661d..bfbbfa10 100644
--- a/Core/SNES/Input/SuperScope.h
+++ b/Core/SNES/Input/SuperScope.h
@@ -93,16 +93,11 @@ protected:
}
public:
- SuperScope(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console->GetEmulator(), port, keyMappings)
+ SuperScope(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console->GetEmulator(), ControllerType::SuperScope, port, keyMappings)
{
_ppu = console->GetPpu().get();
}
- ControllerType GetControllerType() override
- {
- return ControllerType::SuperScope;
- }
-
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
diff --git a/Core/Shared/BaseControlDevice.cpp b/Core/Shared/BaseControlDevice.cpp
index 2cd283ce..0f56f794 100644
--- a/Core/Shared/BaseControlDevice.cpp
+++ b/Core/Shared/BaseControlDevice.cpp
@@ -5,9 +5,10 @@
#include "Utilities/StringUtilities.h"
#include "Utilities/Serializer.h"
-BaseControlDevice::BaseControlDevice(Emulator* emu, uint8_t port, KeyMappingSet keyMappingSet)
+BaseControlDevice::BaseControlDevice(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappingSet)
{
_emu = emu;
+ _type = type;
_port = port;
_strobe = false;
_keyMappings = keyMappingSet.GetKeyMappingArray();
@@ -22,6 +23,11 @@ uint8_t BaseControlDevice::GetPort()
return _port;
}
+ControllerType BaseControlDevice::GetControllerType()
+{
+ return _type;
+}
+
void BaseControlDevice::SetStateFromInput()
{
ClearState();
diff --git a/Core/Shared/BaseControlDevice.h b/Core/Shared/BaseControlDevice.h
index 599f7030..86bfa708 100644
--- a/Core/Shared/BaseControlDevice.h
+++ b/Core/Shared/BaseControlDevice.h
@@ -17,6 +17,7 @@ protected:
Emulator* _emu;
vector _keyMappings;
bool _strobe;
+ ControllerType _type;
uint8_t _port;
SimpleLock _stateLock;
@@ -51,10 +52,11 @@ public:
static constexpr uint8_t ExpDevicePort2 = 7;
static constexpr uint8_t PortCount = ExpDevicePort2 + 1;
- BaseControlDevice(Emulator* emu, uint8_t port, KeyMappingSet keyMappingSet = KeyMappingSet());
+ BaseControlDevice(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappingSet = KeyMappingSet());
virtual ~BaseControlDevice();
uint8_t GetPort();
+ ControllerType GetControllerType();
bool IsPressed(uint8_t bit);
MousePosition GetCoordinates();
@@ -74,7 +76,6 @@ public:
void SetRawState(ControlDeviceState state);
ControlDeviceState GetRawState();
- virtual ControllerType GetControllerType() = 0;
virtual uint8_t ReadRam(uint16_t addr) = 0;
virtual void WriteRam(uint16_t addr, uint8_t value) = 0;
diff --git a/Core/Shared/Emulator.cpp b/Core/Shared/Emulator.cpp
index be7a9a9a..e14b2efe 100644
--- a/Core/Shared/Emulator.cpp
+++ b/Core/Shared/Emulator.cpp
@@ -331,8 +331,7 @@ bool Emulator::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
}
if(patchFile.IsValid()) {
- //TODO
- //_patchPath = patchFile;
+ _patchFile = patchFile;
if(romFile.ApplyPatch(patchFile)) {
MessageManager::DisplayMessage("Patch", "ApplyingPatch", patchFile.GetFileName());
}
@@ -478,6 +477,11 @@ uint64_t Emulator::GetMasterClock()
return _console->GetMasterClock();
}
+uint32_t Emulator::GetMasterClockRate()
+{
+ return _console->GetMasterClockRate();
+}
+
uint32_t Emulator::GetFrameCount()
{
return _console->GetPpuFrame().FrameCount;
diff --git a/Core/Shared/Emulator.h b/Core/Shared/Emulator.h
index ee429573..ec1e950a 100644
--- a/Core/Shared/Emulator.h
+++ b/Core/Shared/Emulator.h
@@ -129,6 +129,7 @@ public:
ConsoleType GetConsoleType();
vector GetCpuTypes();
uint64_t GetMasterClock();
+ uint32_t GetMasterClockRate();
EmulatorLock AcquireLock();
void Lock();
diff --git a/Core/Shared/Interfaces/IBattery.h b/Core/Shared/Interfaces/IBattery.h
new file mode 100644
index 00000000..c79cb13e
--- /dev/null
+++ b/Core/Shared/Interfaces/IBattery.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class IBattery
+{
+public:
+ virtual void SaveBattery() = 0;
+};
\ No newline at end of file
diff --git a/Core/Shared/Interfaces/IConsole.h b/Core/Shared/Interfaces/IConsole.h
index 64ee0e00..66c77687 100644
--- a/Core/Shared/Interfaces/IConsole.h
+++ b/Core/Shared/Interfaces/IConsole.h
@@ -37,6 +37,7 @@ public:
virtual vector GetCpuTypes() = 0;
virtual uint64_t GetMasterClock() = 0;
+ virtual uint32_t GetMasterClockRate() = 0;
virtual double GetFrameDelay() = 0;
virtual double GetFps() = 0;
diff --git a/Core/Shared/SettingTypes.h b/Core/Shared/SettingTypes.h
index 1675cea1..7b4eefe9 100644
--- a/Core/Shared/SettingTypes.h
+++ b/Core/Shared/SettingTypes.h
@@ -144,12 +144,46 @@ struct AudioConfig
//Update ControllerTypeNames when changing this
enum class ControllerType
{
- None = 0,
- SnesController = 1,
- SnesMouse = 2,
- SuperScope = 3,
- Multitap = 4,
- NesController = 5
+ None,
+
+ //SNES controllers
+ SnesController,
+ SnesMouse,
+ SuperScope,
+ Multitap,
+
+ //NES controllers
+ NesController,
+ FamicomController,
+ NesZapper,
+ NesArkanoidController,
+ PowerPad,
+ SuborMouse,
+ VsZapper,
+ VirtualBoyController,
+
+ //NES/Famicon expansion devices
+ FourScore,
+ FamicomZapper,
+ FourPlayerAdapter,
+ FamicomArkanoidController,
+ OekaKidsTablet,
+ FamilyTrainerMat,
+ KonamiHyperShot,
+ FamilyBasicKeyboard,
+ PartyTap,
+ Pachinko,
+ ExcitingBoxing,
+ JissenMahjong,
+ SuborKeyboard,
+ BarcodeBattler,
+ HoriTrack,
+ BandaiHyperShot,
+ AsciiTurboFile,
+ BattleBox,
+
+ //Game Boy
+ GameboyController,
};
struct KeyMapping
@@ -354,6 +388,7 @@ enum class VsDualOutputOption
struct NesConfig
{
ControllerConfig Controllers[5];
+ uint32_t ZapperDetectionRadius = 0;
bool EnableHdPacks = true;
bool DisableGameDatabase = false;
diff --git a/Core/Shared/SystemActionManager.h b/Core/Shared/SystemActionManager.h
index 786630c8..80887d67 100644
--- a/Core/Shared/SystemActionManager.h
+++ b/Core/Shared/SystemActionManager.h
@@ -18,15 +18,10 @@ protected:
public:
enum Buttons { ResetButton = 0, PowerButton = 1 };
- SystemActionManager(Emulator* emu) : BaseControlDevice(emu, BaseControlDevice::ConsoleInputPort)
+ SystemActionManager(Emulator* emu) : BaseControlDevice(emu, ControllerType::None, BaseControlDevice::ConsoleInputPort)
{
}
- ControllerType GetControllerType() override
- {
- return ControllerType::None;
- }
-
uint8_t ReadRam(uint16_t addr) override
{
return 0;
diff --git a/NewUI/Config/NesConfig.cs b/NewUI/Config/NesConfig.cs
index d640c0d5..e30cf12f 100644
--- a/NewUI/Config/NesConfig.cs
+++ b/NewUI/Config/NesConfig.cs
@@ -12,6 +12,7 @@ namespace Mesen.GUI.Config
{
//Input
[Reactive] public List Controllers { get; set; } = new List { new ControllerConfig(), new ControllerConfig(), new ControllerConfig(), new ControllerConfig(), new ControllerConfig() };
+ [Reactive] public UInt32 ZapperDetectionRadius { get; set; } = 0;
//Video
[Reactive] public bool EnableHdPacks { get; set; } = true;
@@ -117,6 +118,7 @@ namespace Mesen.GUI.Config
this.Controllers[3].ToInterop(),
this.Controllers[4].ToInterop()
},
+ ZapperDetectionRadius = ZapperDetectionRadius,
EnableHdPacks = EnableHdPacks,
DisableGameDatabase = DisableGameDatabase,
@@ -246,6 +248,7 @@ namespace Mesen.GUI.Config
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public InteropControllerConfig[] Controllers;
+ public UInt32 ZapperDetectionRadius;
[MarshalAs(UnmanagedType.I1)] public bool EnableHdPacks;
[MarshalAs(UnmanagedType.I1)] public bool DisableGameDatabase;