diff --git a/Data/Sys/GameSettings/GHAE08.ini b/Data/Sys/GameSettings/GHAE08.ini new file mode 100644 index 0000000000..373cbb45e3 --- /dev/null +++ b/Data/Sys/GameSettings/GHAE08.ini @@ -0,0 +1,16 @@ +# GHAE08 - Resident Evil 2 + +[OnFrame] +# Work around a game bug that causes background sounds to be zeroed during load. +# The bug was masked on real hardware by dcache. This patch fully fixes the bug +# and should also work on real hardware. Dolphin doesn't emulate dcache because +# the performance hit would be huge. +$Fix audio issues +# main.dol +0x800339E4:dword:0x60000000 +# leon.rel +0x8055ACBC:dword:0x60000000:0x4BAA8445 +# claire.rel +0x8055AB54:dword:0x60000000:0x4BAA85AD +[OnFrame_Enabled] +$Fix audio issues diff --git a/Data/Sys/GameSettings/GHAJ08.ini b/Data/Sys/GameSettings/GHAJ08.ini new file mode 100644 index 0000000000..9bb3feec95 --- /dev/null +++ b/Data/Sys/GameSettings/GHAJ08.ini @@ -0,0 +1,16 @@ +# GHAJ08 - Biohazard 2 + +[OnFrame] +# Work around a game bug that causes background sounds to be zeroed during load. +# The bug was masked on real hardware by dcache. This patch fully fixes the bug +# and should also work on real hardware. Dolphin doesn't emulate dcache because +# the performance hit would be huge. +$Fix audio issues +# main.dol +0x80065FFC:dword:0x60000000 +# leon.rel +0x805C5CC4:dword:0x60000000:0x4BA3D43D +# claire.rel +0x805C5BFC:dword:0x60000000:0x4BA3D505 +[OnFrame_Enabled] +$Fix audio issues diff --git a/Data/Sys/GameSettings/GHAP08.ini b/Data/Sys/GameSettings/GHAP08.ini new file mode 100644 index 0000000000..d6e39d5c17 --- /dev/null +++ b/Data/Sys/GameSettings/GHAP08.ini @@ -0,0 +1,32 @@ +# GHAP08 - Resident Evil 2 + +[OnFrame] +# Work around a game bug that causes background sounds to be zeroed during load. +# The bug was masked on real hardware by dcache. This patch fully fixes the bug +# and should also work on real hardware. Dolphin doesn't emulate dcache because +# the performance hit would be huge. +$Fix audio issues +# main.dol +0x80033D60:dword:0x60000000 +# leon.rel +0x8055C5F8:dword:0x60000000:0x4BAA6B09 +# claire.rel +0x8055C490:dword:0x60000000:0x4BAA6C71 +# leon_g.rel +0x8055C3B8:dword:0x60000000:0x4BAA6D49 +# claire_g.rel +0x8055C328:dword:0x60000000:0x4BAA6DD9 +# leon_f.rel +0x8055D188:dword:0x60000000:0x4BAA5F79 +# claire_f.rel +0x8055D068:dword:0x60000000:0x4BAA6099 +# leon_s.rel +0x8055D100:dword:0x60000000:0x4BAA6001 +# claire_s.rel +0x8055D064:dword:0x60000000:0x4BAA609D +# leon_i.rel +0x8055CFDC:dword:0x60000000:0x4BAA6125 +# claire_i.rel +0x8055CEBC:dword:0x60000000:0x4BAA6245 +[OnFrame_Enabled] +$Fix audio issues diff --git a/Data/Sys/GameSettings/GLEE08.ini b/Data/Sys/GameSettings/GLEE08.ini new file mode 100644 index 0000000000..90759a99a9 --- /dev/null +++ b/Data/Sys/GameSettings/GLEE08.ini @@ -0,0 +1,12 @@ +# GLEE08 - Resident Evil 3: Nemesis + +[OnFrame] +# Work around a game bug that causes background sounds to be zeroed during load. +# The bug was masked on real hardware by dcache. This patch fully fixes the bug +# and should also work on real hardware. Dolphin doesn't emulate dcache because +# the performance hit would be huge. +$Fix audio issues +# main.dol +0x80150E94:dword:0x60000000 +[OnFrame_Enabled] +$Fix audio issues diff --git a/Data/Sys/GameSettings/GLEJ08.ini b/Data/Sys/GameSettings/GLEJ08.ini new file mode 100644 index 0000000000..5c8ebc84fc --- /dev/null +++ b/Data/Sys/GameSettings/GLEJ08.ini @@ -0,0 +1,12 @@ +# GLEJ08 - BioHazard 3: Last Escape + +[OnFrame] +# Work around a game bug that causes background sounds to be zeroed during load. +# The bug was masked on real hardware by dcache. This patch fully fixes the bug +# and should also work on real hardware. Dolphin doesn't emulate dcache because +# the performance hit would be huge. +$Fix audio issues +# main.dol +0x8015110C:dword:0x60000000 +[OnFrame_Enabled] +$Fix audio issues diff --git a/Data/Sys/GameSettings/GLEP08.ini b/Data/Sys/GameSettings/GLEP08.ini new file mode 100644 index 0000000000..9c947103ac --- /dev/null +++ b/Data/Sys/GameSettings/GLEP08.ini @@ -0,0 +1,20 @@ +# GLEP08 - Resident Evil 3: Nemesis + +[OnFrame] +# Work around a game bug that causes background sounds to be zeroed during load. +# The bug was masked on real hardware by dcache. This patch fully fixes the bug +# and should also work on real hardware. Dolphin doesn't emulate dcache because +# the performance hit would be huge. +$Fix audio issues +# eng.rel +0x8058C174:dword:0x60000000:0x4BA76F8D +# ger.rel +0x8058CE40:dword:0x60000000:0x4BA762C1 +# fra.rel +0x8058D03C:dword:0x60000000:0x4BA760C5 +# spa.rel +0x8058D024:dword:0x60000000:0x4BA760DD +# ita.rel +0x8058CEA4:dword:0x60000000:0x4BA7625D +[OnFrame_Enabled] +$Fix audio issues diff --git a/Source/Core/Core/PatchEngine.cpp b/Source/Core/Core/PatchEngine.cpp index 4f4daafcd7..a3b13c14d3 100644 --- a/Source/Core/Core/PatchEngine.cpp +++ b/Source/Core/Core/PatchEngine.cpp @@ -90,6 +90,11 @@ void LoadPatchSection(const std::string& section, std::vector& patches, I bool success = true; success &= TryParse(items[0], &pE.address); success &= TryParse(items[2], &pE.value); + if (items.size() >= 4) + { + success &= TryParse(items[3], &pE.comparand); + pE.conditional = true; + } const auto iter = std::find(s_patch_type_strings.begin(), s_patch_type_strings.end(), items[1]); @@ -184,16 +189,20 @@ static void ApplyPatches(const std::vector& patches) { u32 addr = entry.address; u32 value = entry.value; + u32 comparand = entry.comparand; switch (entry.type) { case PatchType::Patch8Bit: - PowerPC::HostWrite_U8(static_cast(value), addr); + if (!entry.conditional || PowerPC::HostRead_U8(addr) == static_cast(comparand)) + PowerPC::HostWrite_U8(static_cast(value), addr); break; case PatchType::Patch16Bit: - PowerPC::HostWrite_U16(static_cast(value), addr); + if (!entry.conditional || PowerPC::HostRead_U16(addr) == static_cast(comparand)) + PowerPC::HostWrite_U16(static_cast(value), addr); break; case PatchType::Patch32Bit: - PowerPC::HostWrite_U32(value, addr); + if (!entry.conditional || PowerPC::HostRead_U32(addr) == comparand) + PowerPC::HostWrite_U32(value, addr); break; default: // unknown patchtype diff --git a/Source/Core/Core/PatchEngine.h b/Source/Core/Core/PatchEngine.h index a496f04936..490fb2e646 100644 --- a/Source/Core/Core/PatchEngine.h +++ b/Source/Core/Core/PatchEngine.h @@ -27,6 +27,8 @@ struct PatchEntry PatchType type = PatchType::Patch8Bit; u32 address = 0; u32 value = 0; + u32 comparand = 0; + bool conditional = false; }; struct Patch diff --git a/Source/Core/DolphinQt/Config/NewPatchDialog.cpp b/Source/Core/DolphinQt/Config/NewPatchDialog.cpp index b0f45afc49..95d0eb7621 100644 --- a/Source/Core/DolphinQt/Config/NewPatchDialog.cpp +++ b/Source/Core/DolphinQt/Config/NewPatchDialog.cpp @@ -4,6 +4,7 @@ #include "DolphinQt/Config/NewPatchDialog.h" +#include #include #include #include @@ -84,6 +85,25 @@ void NewPatchDialog::AddEntry() m_entry_layout->addWidget(CreateEntry(m_patch.entries[m_patch.entries.size() - 1])); } +static u32 OnTextEdited(QLineEdit* edit, const QString& text) +{ + bool okay = false; + u32 value = text.toUInt(&okay, 16); + + QFont font; + QPalette palette; + + font.setBold(!okay); + + if (!okay) + palette.setColor(QPalette::Text, Qt::red); + + edit->setFont(font); + edit->setPalette(palette); + + return value; +} + static bool PatchEq(const PatchEngine::PatchEntry& a, const PatchEngine::PatchEntry& b) { if (a.address != b.address) @@ -95,6 +115,12 @@ static bool PatchEq(const PatchEngine::PatchEntry& a, const PatchEngine::PatchEn if (a.value != b.value) return false; + if (a.comparand != b.comparand) + return false; + + if (a.conditional != b.conditional) + return false; + return true; } @@ -115,56 +141,41 @@ QGroupBox* NewPatchDialog::CreateEntry(PatchEngine::PatchEntry& entry) type_layout->addWidget(dword); type->setLayout(type_layout); - auto* offset = new QLineEdit; + auto* address = new QLineEdit; auto* value = new QLineEdit; + auto* comparand = new QLineEdit; - m_edits.push_back(offset); + m_edits.push_back(address); m_edits.push_back(value); + m_edits.push_back(comparand); + + auto* conditional = new QCheckBox(tr("Conditional")); + auto* comparand_label = new QLabel(tr("Comparand:")); auto* layout = new QGridLayout; layout->addWidget(type, 0, 0, 1, -1); - layout->addWidget(new QLabel(tr("Offset:")), 1, 0); - layout->addWidget(offset, 1, 1); + layout->addWidget(new QLabel(tr("Address:")), 1, 0); + layout->addWidget(address, 1, 1); layout->addWidget(new QLabel(tr("Value:")), 2, 0); layout->addWidget(value, 2, 1); - layout->addWidget(remove, 3, 0, 1, -1); + layout->addWidget(conditional, 3, 0, 1, -1); + layout->addWidget(comparand_label, 4, 0); + layout->addWidget(comparand, 4, 1); + layout->addWidget(remove, 5, 0, 1, -1); box->setLayout(layout); - connect(offset, qOverload(&QLineEdit::textEdited), - [&entry, offset](const QString& text) { - bool okay = true; - entry.address = text.toUInt(&okay, 16); - - QFont font; - QPalette palette; - - font.setBold(!okay); - - if (!okay) - palette.setColor(QPalette::Text, Qt::red); - - offset->setFont(font); - offset->setPalette(palette); - }); + connect(address, qOverload(&QLineEdit::textEdited), + [&entry, address](const QString& text) { entry.address = OnTextEdited(address, text); }); connect(value, qOverload(&QLineEdit::textEdited), - [&entry, value](const QString& text) { - bool okay; - entry.value = text.toUInt(&okay, 16); + [&entry, value](const QString& text) { entry.value = OnTextEdited(value, text); }); - QFont font; - QPalette palette; - - font.setBold(!okay); - - if (!okay) - palette.setColor(QPalette::Text, Qt::red); - - value->setFont(font); - value->setPalette(palette); + connect(comparand, qOverload(&QLineEdit::textEdited), + [&entry, comparand](const QString& text) { + entry.comparand = OnTextEdited(comparand, text); }); - connect(remove, &QPushButton::clicked, [this, box, offset, value, entry] { + connect(remove, &QPushButton::clicked, [this, box, address, value, comparand, entry] { if (m_patch.entries.size() > 1) { box->setVisible(false); @@ -175,9 +186,9 @@ QGroupBox* NewPatchDialog::CreateEntry(PatchEngine::PatchEntry& entry) std::find_if(m_patch.entries.begin(), m_patch.entries.end(), [entry](const PatchEngine::PatchEntry& e) { return PatchEq(e, entry); })); - const auto it = - std::remove_if(m_edits.begin(), m_edits.end(), [offset, value](QLineEdit* line_edit) { - return line_edit == offset || line_edit == value; + const auto it = std::remove_if( + m_edits.begin(), m_edits.end(), [address, value, comparand](QLineEdit* line_edit) { + return line_edit == address || line_edit == value || line_edit == comparand; }); m_edits.erase(it, m_edits.end()); } @@ -202,8 +213,19 @@ QGroupBox* NewPatchDialog::CreateEntry(PatchEngine::PatchEntry& entry) word->setChecked(entry.type == PatchEngine::PatchType::Patch16Bit); dword->setChecked(entry.type == PatchEngine::PatchType::Patch32Bit); - offset->setText(QStringLiteral("%1").arg(entry.address, 8, 16, QLatin1Char('0'))); + connect(conditional, &QCheckBox::toggled, [&entry, comparand_label, comparand](bool checked) { + entry.conditional = checked; + comparand_label->setVisible(checked); + comparand->setVisible(checked); + }); + + conditional->setChecked(entry.conditional); + comparand_label->setVisible(entry.conditional); + comparand->setVisible(entry.conditional); + + address->setText(QStringLiteral("%1").arg(entry.address, 8, 16, QLatin1Char('0'))); value->setText(QStringLiteral("%1").arg(entry.value, 8, 16, QLatin1Char('0'))); + comparand->setText(QStringLiteral("%1").arg(entry.comparand, 8, 16, QLatin1Char('0'))); return box; } diff --git a/Source/Core/DolphinQt/Config/PatchesWidget.cpp b/Source/Core/DolphinQt/Config/PatchesWidget.cpp index 43dd4a415e..8628f1997a 100644 --- a/Source/Core/DolphinQt/Config/PatchesWidget.cpp +++ b/Source/Core/DolphinQt/Config/PatchesWidget.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "Common/FileUtil.h" #include "Common/IniFile.h" #include "Common/StringUtil.h" @@ -143,8 +145,17 @@ void PatchesWidget::SavePatches() for (const auto& entry : patch.entries) { - lines.emplace_back(StringFromFormat("0x%08X:%s:0x%08X", entry.address, - PatchEngine::PatchTypeAsString(entry.type), entry.value)); + if (!entry.conditional) + { + lines.emplace_back(fmt::format("0x{:08X}:{}:0x{:08X}", entry.address, + PatchEngine::PatchTypeAsString(entry.type), entry.value)); + } + else + { + lines.emplace_back(fmt::format("0x{:08X}:{}:0x{:08X}:0x{:08X}", entry.address, + PatchEngine::PatchTypeAsString(entry.type), entry.value, + entry.comparand)); + } } }