From 313340198e27cdef8dd44719f1239027527f4533 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sun, 10 Jul 2016 09:05:41 -0400 Subject: [PATCH] Vs System: Automatically select proper PPU & input mapping based on rom name/CRC + implemented support for vs system input remappings (some games change the buttons around) --- Core/BaseControlDevice.h | 12 ++ Core/BaseMapper.cpp | 6 + Core/BaseMapper.h | 4 +- Core/Console.cpp | 9 + Core/Console.h | 1 + Core/ControlManager.h | 4 +- Core/EmulationSettings.cpp | 2 +- Core/EmulationSettings.h | 3 +- Core/RomData.h | 1 + Core/StandardController.cpp | 10 ++ Core/StandardController.h | 4 + Core/VsControlManager.h | 71 ++++++++ Core/VsSystem.h | 20 ++- Core/iNesLoader.cpp | 2 + GUI.NET/Config/VsConfigInfo.cs | 104 +++++++++-- GUI.NET/Dependencies/VsSystem.xml | 162 +++++++++++++++--- .../Forms/Config/frmVsGameConfig.Designer.cs | 18 ++ GUI.NET/Forms/Config/frmVsGameConfig.cs | 31 +++- GUI.NET/InteropEmu.cs | 18 +- InteropDLL/ConsoleWrapper.cpp | 7 +- 20 files changed, 426 insertions(+), 63 deletions(-) diff --git a/Core/BaseControlDevice.h b/Core/BaseControlDevice.h index df6b246a..2a6c4520 100644 --- a/Core/BaseControlDevice.h +++ b/Core/BaseControlDevice.h @@ -23,6 +23,18 @@ struct ButtonState return (uint8_t)A | ((uint8_t)B << 1) | ((uint8_t)Select << 2) | ((uint8_t)Start << 3) | ((uint8_t)Up << 4) | ((uint8_t)Down << 5) | ((uint8_t)Left << 6) | ((uint8_t)Right << 7); } + + void FromByte(uint8_t stateData) + { + A = (stateData & 0x01) == 0x01; + B = (stateData & 0x02) == 0x02; + Select = (stateData & 0x04) == 0x04; + Start = (stateData & 0x08) == 0x08; + Up = (stateData & 0x10) == 0x10; + Down = (stateData & 0x20) == 0x20; + Left = (stateData & 0x40) == 0x40; + Right = (stateData & 0x80) == 0x80; + } }; class BaseControlDevice : public Snapshotable diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 932e781d..d35a367d 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -371,6 +371,7 @@ void BaseMapper::Initialize(RomData &romData) _hasBattery = romData.HasBattery || ForceBattery(); _gameSystem = romData.System; _crc32 = romData.Crc32; + _prgCrc32 = romData.PrgCrc32; _hasBusConflicts = HasBusConflicts(); _saveRam = new uint8_t[_saveRamSize]; @@ -547,6 +548,11 @@ uint32_t BaseMapper::GetCrc32() return _crc32; } +uint32_t BaseMapper::GetPrgCrc32() +{ + return _prgCrc32; +} + MirroringType BaseMapper::GetMirroringType() { return _mirroringType; diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index f21adcfd..153d287e 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -53,7 +53,6 @@ private: uint8_t _nametableIndexes[4]; bool _onlyChrRam = false; - GameSystem _gameSystem; bool _hasBusConflicts = false; string _romFilename; @@ -72,6 +71,7 @@ private: uint32_t _chrPageNumbers[64]; uint32_t _crc32 = 0; + uint32_t _prgCrc32 = 0; vector _originalPrgRom; @@ -79,6 +79,7 @@ protected: NESHeader _nesHeader; uint16_t _mapperID; uint8_t _subMapperID; + GameSystem _gameSystem; uint8_t* _prgRom = nullptr; uint8_t* _chrRom = nullptr; @@ -176,6 +177,7 @@ public: GameSystem GetGameSystem(); uint32_t GetCrc32(); + uint32_t GetPrgCrc32(); string GetRomName(); uint8_t ReadRAM(uint16_t addr); diff --git a/Core/Console.cpp b/Core/Console.cpp index 8ca9a11c..b508c693 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -163,6 +163,15 @@ uint32_t Console::GetCrc32() } } +uint32_t Console::GetPrgCrc32() +{ + if(Instance->_mapper) { + return Instance->_mapper->GetPrgCrc32(); + } else { + return 0; + } +} + NesModel Console::GetModel() { return Instance->_model; diff --git a/Core/Console.h b/Core/Console.h index dd17ca64..a6e50c3b 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -70,6 +70,7 @@ class Console static string GetROMPath(); static string GetRomName(); static uint32_t GetCrc32(); + static uint32_t GetPrgCrc32(); static NesModel GetModel(); static bool IsRunning(); diff --git a/Core/ControlManager.h b/Core/ControlManager.h index c4526464..2ee61e27 100644 --- a/Core/ControlManager.h +++ b/Core/ControlManager.h @@ -28,8 +28,6 @@ class ControlManager : public Snapshotable, public IMemoryHandler bool _refreshState = false; - void RefreshAllPorts(); - virtual shared_ptr GetZapper(uint8_t port); static void RegisterControlDevice(shared_ptr controlDevice, uint8_t port); @@ -37,6 +35,8 @@ class ControlManager : public Snapshotable, public IMemoryHandler protected: uint8_t GetPortValue(uint8_t port); + virtual void RefreshAllPorts(); + virtual void StreamState(bool saving); public: diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp index 62935fa2..2338f4ce 100644 --- a/Core/EmulationSettings.cpp +++ b/Core/EmulationSettings.cpp @@ -22,7 +22,7 @@ double EmulationSettings::_reverbStrength = 0; double EmulationSettings::_reverbDelay = 0; NesModel EmulationSettings::_model = NesModel::Auto; -PpuModel EmulationSettings::_ppuModel = PpuModel::Ppu2C03; +PpuModel EmulationSettings::_ppuModel = PpuModel::Ppu2C02; uint32_t EmulationSettings::_emulationSpeed = 100; uint32_t EmulationSettings::_overclockRate = 100; diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index d903807c..9b6767a7 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -140,8 +140,7 @@ struct NtscFilterSettings enum class ConsoleType { Nes = 0, - Famicom = 1, - VsSystem = 2, + Famicom = 1 }; enum class ControllerType diff --git a/Core/RomData.h b/Core/RomData.h index 0417597a..2914647f 100644 --- a/Core/RomData.h +++ b/Core/RomData.h @@ -244,6 +244,7 @@ struct RomData vector RawData; uint32_t Crc32 = 0; + uint32_t PrgCrc32 = 0; bool Error = false; diff --git a/Core/StandardController.cpp b/Core/StandardController.cpp index 9bde0a9c..11cb5ae7 100644 --- a/Core/StandardController.cpp +++ b/Core/StandardController.cpp @@ -127,3 +127,13 @@ void StandardController::AddAdditionalController(shared_ptr c } _additionalController = controller; } + +uint32_t StandardController::GetInternalState() +{ + return _stateBuffer; +} + +void StandardController::SetInternalState(uint32_t state) +{ + _stateBuffer = state; +} \ No newline at end of file diff --git a/Core/StandardController.h b/Core/StandardController.h index 6be90908..19b28011 100644 --- a/Core/StandardController.h +++ b/Core/StandardController.h @@ -26,5 +26,9 @@ public: uint8_t GetPortOutput(); void RefreshStateBuffer(); + //Used for VS System button unscrambling + uint32_t GetInternalState(); + void SetInternalState(uint32_t state); + void AddAdditionalController(shared_ptr controller); }; \ No newline at end of file diff --git a/Core/VsControlManager.h b/Core/VsControlManager.h index cda73a83..68430565 100644 --- a/Core/VsControlManager.h +++ b/Core/VsControlManager.h @@ -5,6 +5,17 @@ #include "Console.h" #include "VsZapper.h" #include +#include "StandardController.h" + +enum class VsInputType +{ + Default = 0, + TypeA = 1, + TypeB = 2, + TypeC = 3, + TypeD = 4, + TypeE = 5 +}; class VsControlManager : public ControlManager { @@ -15,6 +26,7 @@ private: bool _serviceButton = false; bool _coinInserted[2] = { }; int32_t _coinInsertCycle[2] = { }; + VsInputType _inputType = VsInputType::Default; uint32_t _protectionCounter = 0; uint32_t _protectionData[3][32] = { @@ -96,6 +108,11 @@ public: _dipSwitches = dipSwitches; } + void SetInputType(VsInputType inputType) + { + _inputType = inputType; + } + void SetServiceButtonState(bool pushed) { _serviceButton = pushed; @@ -113,6 +130,60 @@ public: return _prgChrSelectBit; } + void RemapControllerButtons() + { + ButtonState ports[2]; + shared_ptr controllers[2]; + controllers[0] = std::dynamic_pointer_cast(GetControlDevice(0)); + controllers[1] = std::dynamic_pointer_cast(GetControlDevice(1)); + if(controllers[0]) { + ports[0].FromByte(controllers[0]->GetInternalState()); + } + if(controllers[1]) { + ports[1].FromByte(controllers[1]->GetInternalState()); + } + + if(_inputType == VsInputType::TypeA) { + std::swap(ports[0], ports[1]); + + std::swap(ports[0].Select, ports[0].Start); + std::swap(ports[1].Select, ports[1].Start); + } else if(_inputType == VsInputType::TypeB) { + std::swap(ports[1].Select, ports[0].Start); + std::swap(ports[1].Start, ports[0].Select); + } else if(_inputType == VsInputType::TypeC) { + ports[1].Select = ports[0].Start; + ports[0].Select = false; + ports[0].Start = false; + } else if(_inputType == VsInputType::TypeD) { + std::swap(ports[1].Select, ports[0].Start); + std::swap(ports[1].Start, ports[0].Select); + ports[0].Select = !ports[0].Select; + ports[1].Select = !ports[1].Select; + } else if(_inputType == VsInputType::TypeE) { + std::swap(ports[0], ports[1]); + + std::swap(ports[0].B, ports[1].A); + std::swap(ports[1].Select, ports[1].Start); + std::swap(ports[0].Select, ports[0].Start); + } + + if(controllers[0]) { + controllers[0]->SetInternalState((controllers[0]->GetInternalState() & ~0xFF) | ports[0].ToByte()); + } + if(controllers[1]) { + controllers[1]->SetInternalState((controllers[1]->GetInternalState() & ~0xFF) | ports[1].ToByte()); + } + } + + void RefreshAllPorts() + { + ControlManager::RefreshAllPorts(); + if(_inputType != VsInputType::Default) { + RemapControllerButtons(); + } + } + uint8_t ReadRAM(uint16_t addr) { UpdateCoinInsertedFlags(); diff --git a/Core/VsSystem.h b/Core/VsSystem.h index c154860f..65035bc1 100644 --- a/Core/VsSystem.h +++ b/Core/VsSystem.h @@ -14,14 +14,17 @@ protected: virtual void InitMapper() { - if(_prgSize > 0x6000) { - SelectPRGPage(0, 0); - } + //"Note: unlike all other mappers, an undersize mapper 99 image implies open bus instead of mirroring." + //However, it doesn't look like any game actually rely on this behavior? So not implemented for now. + SelectPRGPage(0, 0); SelectPRGPage(1, 1); SelectPRGPage(2, 2); SelectPRGPage(3, 3); SelectCHRPage(0, 0); + + //Force VS system if mapper 99 (since we assume VsControlManager exists below) + _gameSystem = GameSystem::VsUniSystem; } void StreamState(bool saving) @@ -31,13 +34,18 @@ protected: Stream(_prgChrSelectBit); } - uint8_t ReadVRAM(uint16_t addr, MemoryOperationType memoryOperationType) + void ProcessCpuClock() { if(_prgChrSelectBit != VsControlManager::GetInstance()->GetPrgChrSelectBit()) { _prgChrSelectBit = VsControlManager::GetInstance()->GetPrgChrSelectBit(); + + if(_prgSize > 0x8000) { + //"Note: In case of games with 40KiB PRG - ROM(as found in VS Gumshoe), the above bit additionally changes 8KiB PRG - ROM at $8000 - $9FFF." + //"Only Vs. Gumshoe uses the 40KiB PRG variant; in the iNES encapsulation, the 8KiB banks are arranged as 0, 1, 2, 3, 0alternate, empty" + SelectPRGPage(0, _prgChrSelectBit << 2); + } + SelectCHRPage(0, _prgChrSelectBit); } - - return BaseMapper::ReadVRAM(addr, memoryOperationType); } }; diff --git a/Core/iNesLoader.cpp b/Core/iNesLoader.cpp index ffe035eb..d452d869 100644 --- a/Core/iNesLoader.cpp +++ b/Core/iNesLoader.cpp @@ -42,6 +42,8 @@ RomData iNesLoader::LoadRom(vector& romFile) buffer += header.GetPrgSize(); romData.ChrRom.insert(romData.ChrRom.end(), buffer, buffer + header.GetChrSize()); + romData.PrgCrc32 = CRC32::GetCRC(romData.PrgRom.data(), romData.PrgRom.size()); + stringstream crcHex; crcHex << std::hex << std::uppercase << std::setfill('0') << std::setw(8) << romCrc; MessageManager::Log("PRG+CHR CRC32: 0x" + crcHex.str()); diff --git a/GUI.NET/Config/VsConfigInfo.cs b/GUI.NET/Config/VsConfigInfo.cs index 1d01eaf0..cacc4d89 100644 --- a/GUI.NET/Config/VsConfigInfo.cs +++ b/GUI.NET/Config/VsConfigInfo.cs @@ -13,6 +13,7 @@ namespace Mesen.GUI.Config public string GameCrc; public InteropEmu.PpuModel PpuModel; public byte DipSwitches; + public InteropEmu.VsInputType InputType; public static VsConfigInfo GetCurrentGameConfig(bool createNew) { @@ -23,40 +24,100 @@ namespace Mesen.GUI.Config } } + VsConfigInfo newConfig = new VsConfigInfo(); + newConfig.GameCrc = crc; + newConfig.GameID = VsGameConfig.GetGameID(); + VsGameConfig gameConfig = VsGameConfig.GetGameConfig(newConfig.GameID); + if(gameConfig != null) { + newConfig.PpuModel = gameConfig.PpuModel; + newConfig.DipSwitches = gameConfig.DefaultDipSwitches; + newConfig.InputType = gameConfig.InputType; + } + if(createNew) { - VsConfigInfo newConfig = new VsConfigInfo(); - newConfig.GameCrc = crc; ConfigManager.Config.VsConfig.Add(newConfig); - return newConfig; - } else { - return null; - } + } + + return newConfig; } public static void ApplyConfig() { VsConfigInfo configInfo = GetCurrentGameConfig(false); - if(configInfo != null) { - InteropEmu.VsSetGameConfig(configInfo.PpuModel, configInfo.DipSwitches); - } + InteropEmu.VsSetGameConfig(configInfo.PpuModel, configInfo.InputType, configInfo.DipSwitches); } } public class VsGameConfig { public string GameName; + public string GameID; + public InteropEmu.VsInputType InputType; + public InteropEmu.PpuModel PpuModel; + public byte DefaultDipSwitches; + public List> DipSwitches; private static Dictionary _gameConfigs = new Dictionary(); - public static string GetGameID(string romName) + public static string GetGameIdByCrc(UInt32 prgCrc32) { - romName = romName.ToLowerInvariant().Replace(" ", ""); - foreach(KeyValuePair kvp in _gameConfigs) { - if(romName.Contains(kvp.Key.ToLowerInvariant().Replace(" ", "")) || romName.Contains(kvp.Value.GameName.ToLowerInvariant().Replace(" ", ""))) { - return kvp.Key; + switch(prgCrc32) { + case 0xEB2DBA63: return "TKOBoxing"; + case 0x135ADF7C: return "RBIBaseball"; + case 0xED588F00: return "DuckHunt"; + case 0x16D3F469: return "NinjaJajamaruKun"; + case 0x8850924B: return "Tetris"; + case 0x8C0C2DF5: return "TopGun"; + case 0x70901B25: return "Slalom"; + case 0xCF36261E: return "SuperSkyKid"; + case 0xE1AA8214: return "StarLuster"; + case 0xD5D7EAC4: return "DrMario"; + case 0xFFBEF374: return "Castlevania"; + case 0xE2C0A2BE: return "Platoon"; + case 0x29155E0C: return "ExciteBike"; + case 0xCBE85490: return "ExciteBikeB"; + case 0x07138C06: return "CluCluLand"; + case 0x43A357EF: return "IceClimber"; + case 0xD4EB5923: return "IceClimberB"; + case 0x737DD1BF: case 0x4BF3972D: case 0x8B60CC58: case 0x8192C804: return "SuperMarioBros"; + case 0xE528F651: return "Pinball"; + case 0xEC461DB9: return "PinballB"; + case 0xAE8063EF: return "MachRiderFightingCourse"; + case 0x0B65A917: case 0x8A6A9848: return "MachRider"; + case 0x46914E3E: return "Soccer"; + case 0x70433F2C: return "BattleCity"; + case 0xD99A2087: return "Gradius"; + case 0x1E438D52: return "Goonies"; + case 0xFF5135A3: return "HoganAlley"; + case 0x17AE56BE: return "FreedomForce"; + case 0xC99EC059: return "RaidBungelingBay"; + case 0xF9D3B0A3: case 0x66BB838F: case 0x9924980A: return "SuperXevious"; + case 0xA93A5AEE: return "Golf"; + case 0xCC2C4B5D: case 0x86167220: return "GolfB"; + case 0xCA85E56D: return "MightyBombJack"; + case 0xFE446787: return "Gumshoe"; + } + + return null; + } + + public static string GetGameID() + { + string gameID = GetGameIdByCrc(InteropEmu.GetRomInfo().PrgCrc32); + + if(gameID != null) { + return gameID; + } else { + //Try to guess the game based on filename + string romName = InteropEmu.GetRomInfo().GetRomName().ToLowerInvariant().Replace(" ", ""); + foreach(KeyValuePair kvp in _gameConfigs) { + if(romName.Contains(kvp.Key.ToLowerInvariant().Replace(" ", "")) || romName.Contains(kvp.Value.GameName.ToLowerInvariant().Replace(" ", ""))) { + return kvp.Key; + } } } + return "Unknown"; } @@ -81,8 +142,23 @@ namespace Mesen.GUI.Config foreach(XmlNode gameNode in config.SelectNodes("/VsSystemGames/Game")) { var gameConfig = new VsGameConfig(); + gameConfig.GameID = gameNode.Attributes["ID"].Value; gameConfig.GameName = gameNode.Attributes["Localization"].Value; + if(gameNode.Attributes["DefaultDip"] != null) { + gameConfig.DefaultDipSwitches = (byte)Int32.Parse(gameNode.Attributes["DefaultDip"].Value); + } + if(gameNode.Attributes["PpuModel"] != null) { + gameConfig.PpuModel = (InteropEmu.PpuModel)Enum.Parse(typeof(InteropEmu.PpuModel), gameNode.Attributes["PpuModel"].Value); + } else { + gameConfig.PpuModel = InteropEmu.PpuModel.Ppu2C03; + } + if(gameNode.Attributes["InputType"] != null) { + gameConfig.InputType = (InteropEmu.VsInputType)Enum.Parse(typeof(InteropEmu.VsInputType), "Type" + gameNode.Attributes["InputType"].Value); + } else { + gameConfig.InputType = InteropEmu.VsInputType.Default; + } gameConfig.DipSwitches = new List>(); + foreach(XmlNode dipSwitch in gameNode.SelectNodes("DipSwitch")) { if(dipSwitch.Attributes["Localization"] != null) { var list = new List(); diff --git a/GUI.NET/Dependencies/VsSystem.xml b/GUI.NET/Dependencies/VsSystem.xml index 5b5f3af6..5ea57f40 100644 --- a/GUI.NET/Dependencies/VsSystem.xml +++ b/GUI.NET/Dependencies/VsSystem.xml @@ -1,6 +1,6 @@  - + @@ -23,7 +23,7 @@ - + @@ -49,7 +49,7 @@ - + @@ -70,7 +70,7 @@ - + @@ -126,7 +126,7 @@ - + @@ -152,7 +152,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -169,7 +195,7 @@ - + @@ -199,7 +225,37 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -225,7 +281,7 @@ - + @@ -255,7 +311,7 @@ - + @@ -285,7 +341,7 @@ - + @@ -313,7 +369,7 @@ - + @@ -339,7 +395,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -379,7 +461,7 @@ - + @@ -400,7 +482,7 @@ - + @@ -424,7 +506,7 @@ - + @@ -448,7 +530,31 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -468,7 +574,7 @@ - + @@ -495,7 +601,7 @@ - + @@ -515,7 +621,7 @@ - + @@ -545,7 +651,7 @@ - + @@ -569,7 +675,7 @@ - + @@ -587,7 +693,7 @@ - + @@ -617,7 +723,7 @@ - + @@ -641,7 +747,7 @@ - + @@ -659,7 +765,7 @@ - + @@ -677,7 +783,7 @@ - + @@ -694,7 +800,7 @@ - + diff --git a/GUI.NET/Forms/Config/frmVsGameConfig.Designer.cs b/GUI.NET/Forms/Config/frmVsGameConfig.Designer.cs index 53242bc4..8fd9e8fc 100644 --- a/GUI.NET/Forms/Config/frmVsGameConfig.Designer.cs +++ b/GUI.NET/Forms/Config/frmVsGameConfig.Designer.cs @@ -33,13 +33,17 @@ this.lblPpuModel = new System.Windows.Forms.Label(); this.cboPpuModel = new System.Windows.Forms.ComboBox(); this.grpDipSwitches = new System.Windows.Forms.GroupBox(); + this.btnReset = new System.Windows.Forms.Button(); + this.baseConfigPanel.SuspendLayout(); this.tlpMain.SuspendLayout(); this.SuspendLayout(); // // baseConfigPanel // + this.baseConfigPanel.Controls.Add(this.btnReset); this.baseConfigPanel.Location = new System.Drawing.Point(0, 295); this.baseConfigPanel.Size = new System.Drawing.Size(305, 29); + this.baseConfigPanel.Controls.SetChildIndex(this.btnReset, 0); // // tlpMain // @@ -112,6 +116,17 @@ this.grpDipSwitches.TabStop = false; this.grpDipSwitches.Text = "DIP Switches"; // + // btnReset + // + this.btnReset.AutoSize = true; + this.btnReset.Location = new System.Drawing.Point(6, 3); + this.btnReset.Name = "btnReset"; + this.btnReset.Size = new System.Drawing.Size(94, 23); + this.btnReset.TabIndex = 3; + this.btnReset.Text = "Reset to Default"; + this.btnReset.UseVisualStyleBackColor = true; + this.btnReset.Click += new System.EventHandler(this.btnReset_Click); + // // frmVsGameConfig // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -126,6 +141,8 @@ this.Text = "Game Configuration"; this.Controls.SetChildIndex(this.tlpMain, 0); this.Controls.SetChildIndex(this.baseConfigPanel, 0); + this.baseConfigPanel.ResumeLayout(false); + this.baseConfigPanel.PerformLayout(); this.tlpMain.ResumeLayout(false); this.tlpMain.PerformLayout(); this.ResumeLayout(false); @@ -140,5 +157,6 @@ private System.Windows.Forms.GroupBox grpDipSwitches; private System.Windows.Forms.ComboBox cboGame; private System.Windows.Forms.Label lblGame; + private System.Windows.Forms.Button btnReset; } } \ No newline at end of file diff --git a/GUI.NET/Forms/Config/frmVsGameConfig.cs b/GUI.NET/Forms/Config/frmVsGameConfig.cs index 831bd332..00aa7d3d 100644 --- a/GUI.NET/Forms/Config/frmVsGameConfig.cs +++ b/GUI.NET/Forms/Config/frmVsGameConfig.cs @@ -13,20 +13,31 @@ namespace Mesen.GUI.Forms.Config { public partial class frmVsGameConfig : BaseConfigForm { + private class DropdownElement + { + public string Name; + public string ID; + + public override string ToString() + { + return Name; + } + } + public frmVsGameConfig(VsConfigInfo configInfo) { InitializeComponent(); Entity = configInfo; - if(string.IsNullOrWhiteSpace(configInfo.GameID)) { - configInfo.GameID = VsGameConfig.GetGameID(InteropEmu.GetRomInfo().GetRomName()); + if(VsGameConfig.GetGameIdByCrc(InteropEmu.GetRomInfo().PrgCrc32) != null) { + cboGame.Enabled = false; } AddBinding("PpuModel", cboPpuModel); foreach(KeyValuePair kvp in VsGameConfig.GetGameConfigs()) { - cboGame.Items.Add(kvp.Value.GameName); + cboGame.Items.Add(new DropdownElement { Name = kvp.Value.GameName, ID = kvp.Value.GameID }); if(kvp.Key == configInfo.GameID) { cboGame.SelectedIndex = cboGame.Items.Count - 1; } @@ -35,7 +46,7 @@ namespace Mesen.GUI.Forms.Config private void cboGame_SelectedIndexChanged(object sender, EventArgs e) { - VsGameConfig config = VsGameConfig.GetGameConfig(VsGameConfig.GetGameID(cboGame.SelectedItem.ToString())); + VsGameConfig config = VsGameConfig.GetGameConfig(((DropdownElement)cboGame.SelectedItem).ID); UpdateDipSwitches(config, false); } @@ -125,7 +136,17 @@ namespace Mesen.GUI.Forms.Config base.UpdateConfig(); ((VsConfigInfo)Entity).DipSwitches = (byte)GetDipSwitchValue(); - ((VsConfigInfo)Entity).GameID = VsGameConfig.GetGameID(cboGame.SelectedItem.ToString()); + ((VsConfigInfo)Entity).GameID = ((DropdownElement)cboGame.SelectedItem).ID; + } + + private void btnReset_Click(object sender, EventArgs e) + { + VsGameConfig defaultConfig = VsGameConfig.GetGameConfig(((DropdownElement)cboGame.SelectedItem).ID); + ((VsConfigInfo)Entity).DipSwitches = defaultConfig.DefaultDipSwitches; + ((VsConfigInfo)Entity).PpuModel = defaultConfig.PpuModel; + ((VsConfigInfo)Entity).InputType = defaultConfig.InputType; + UpdateUI(); + UpdateDipSwitches(defaultConfig, false); } } diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index aec474ce..4a8bb705 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -114,7 +114,7 @@ namespace Mesen.GUI [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsVsSystem(); [DllImport(DLLPath)] public static extern void VsInsertCoin(UInt32 port); - [DllImport(DLLPath)] public static extern void VsSetGameConfig(PpuModel model, byte dipSwitches); + [DllImport(DLLPath)] public static extern void VsSetGameConfig(PpuModel model, VsInputType inputType, byte dipSwitches); [DllImport(DLLPath)] public static extern void CheatAddCustom(UInt32 address, Byte value, Int32 compareValue, [MarshalAs(UnmanagedType.I1)]bool isRelativeAddress); [DllImport(DLLPath)] public static extern void CheatAddGameGenie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string code); @@ -387,6 +387,16 @@ namespace Mesen.GUI ArkanoidController = 3, } + public enum VsInputType + { + Default = 0, + TypeA = 1, + TypeB = 2, + TypeC = 3, + TypeD = 4, + TypeE = 5 + } + public enum PpuModel { Ppu2C02 = 0, @@ -627,17 +637,20 @@ namespace Mesen.GUI { public IntPtr RomNamePointer; public UInt32 Crc32; + public UInt32 PrgCrc32; } public class RomInfo { public string RomName; public UInt32 Crc32; + public UInt32 PrgCrc32; public RomInfo(InteropRomInfo romInfo) { this.RomName = UTF8Marshaler.GetStringFromIntPtr(romInfo.RomNamePointer); this.Crc32 = romInfo.Crc32; + this.PrgCrc32 = romInfo.PrgCrc32; } public string GetRomName() @@ -779,8 +792,7 @@ namespace Mesen.GUI public enum ConsoleType { Nes = 0, - Famicom = 1, - //VsSystem = 2, + Famicom = 1 } public enum AudioChannel diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 2fa37dfe..c2dc3d82 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -49,6 +49,7 @@ namespace InteropEmu { { const char* RomName; uint32_t Crc32; + uint32_t PrgCrc32; }; extern "C" { @@ -141,6 +142,7 @@ namespace InteropEmu { _returnString = Console::GetRomName(); romInfo.RomName = _returnString.c_str(); romInfo.Crc32 = Console::GetCrc32(); + romInfo.PrgCrc32 = Console::GetPrgCrc32(); } else { RomLoader romLoader; if(romLoader.LoadFile(filename, nullptr, "", archiveFileIndex)) { @@ -149,10 +151,12 @@ namespace InteropEmu { _returnString = romData.RomName; romInfo.RomName = _returnString.c_str(); romInfo.Crc32 = romData.Crc32; + romInfo.PrgCrc32 = romData.PrgCrc32; } else { _returnString = ""; romInfo.RomName = _returnString.c_str(); romInfo.Crc32 = 0; + romInfo.PrgCrc32 = 0; } } } @@ -373,12 +377,13 @@ namespace InteropEmu { } } - DllExport void __stdcall VsSetGameConfig(PpuModel model, uint8_t dipSwitches) + DllExport void __stdcall VsSetGameConfig(PpuModel model, VsInputType inputType, uint8_t dipSwitches) { VsControlManager* vs = VsControlManager::GetInstance(); if(vs) { EmulationSettings::SetPpuModel(model); vs->SetDipSwitches(dipSwitches); + vs->SetInputType(inputType); } } }