diff --git a/pcsx2-qt/Settings/EmulationSettingsWidget.cpp b/pcsx2-qt/Settings/EmulationSettingsWidget.cpp
index aca06ea4d7..34c200f403 100644
--- a/pcsx2-qt/Settings/EmulationSettingsWidget.cpp
+++ b/pcsx2-qt/Settings/EmulationSettingsWidget.cpp
@@ -46,6 +46,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cheats, "EmuCore", "EnableCheats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false);
+ SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.noInterlacingPatches, "EmuCore", "EnableNoInterlacingPatches", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.perGameSettings, "EmuCore", "EnablePerGameSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hostFilesystem, "EmuCore", "HostFs", false);
diff --git a/pcsx2-qt/Settings/EmulationSettingsWidget.ui b/pcsx2-qt/Settings/EmulationSettingsWidget.ui
index d0a7fb7a21..4541674fb1 100644
--- a/pcsx2-qt/Settings/EmulationSettingsWidget.ui
+++ b/pcsx2-qt/Settings/EmulationSettingsWidget.ui
@@ -125,13 +125,20 @@
Game Settings
- -
+
-
Enable Per-Game Settings
+ -
+
+
+ Enable Widescreen Patches
+
+
+
-
@@ -139,20 +146,20 @@
- -
-
-
- Enable Widescreen Patches
-
-
-
- -
+
-
Enable Host Filesystem
+ -
+
+
+ Enable No-Interlacing Patches
+
+
+
diff --git a/pcsx2/Config.h b/pcsx2/Config.h
index 786e407276..7120b3b814 100644
--- a/pcsx2/Config.h
+++ b/pcsx2/Config.h
@@ -940,6 +940,7 @@ struct Pcsx2Config
EnableCheats : 1, // enables cheat detection and application
EnablePINE : 1, // enables inter-process communication
EnableWideScreenPatches : 1,
+ EnableNoInterlacingPatches : 1,
// TODO - Vaser - where are these settings exposed in the Qt UI?
EnableRecordingTools : 1,
#ifdef PCSX2_CORE
@@ -1032,6 +1033,7 @@ namespace EmuFolders
extern std::string Logs;
extern std::string Cheats;
extern std::string CheatsWS;
+ extern std::string CheatsNI;
extern std::string Resources;
extern std::string Cache;
extern std::string Covers;
diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp
index 6dab8c6a7e..3b3d759b3a 100644
--- a/pcsx2/Pcsx2Config.cpp
+++ b/pcsx2/Pcsx2Config.cpp
@@ -44,6 +44,7 @@ namespace EmuFolders
std::string Logs;
std::string Cheats;
std::string CheatsWS;
+ std::string CheatsNI;
std::string Resources;
std::string Cache;
std::string Covers;
@@ -1040,6 +1041,7 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(EnableCheats);
SettingsWrapBitBool(EnablePINE);
SettingsWrapBitBool(EnableWideScreenPatches);
+ SettingsWrapBitBool(EnableNoInterlacingPatches);
SettingsWrapBitBool(EnableRecordingTools);
#ifdef PCSX2_CORE
SettingsWrapBitBool(EnableGameFixes);
@@ -1189,6 +1191,7 @@ void Pcsx2Config::CopyConfig(const Pcsx2Config& cfg)
EnableCheats = cfg.EnableCheats;
EnablePINE = cfg.EnablePINE;
EnableWideScreenPatches = cfg.EnableWideScreenPatches;
+ EnableNoInterlacingPatches = cfg.EnableNoInterlacingPatches;
EnableRecordingTools = cfg.EnableRecordingTools;
UseBOOT2Injection = cfg.UseBOOT2Injection;
PatchBios = cfg.PatchBios;
@@ -1216,6 +1219,7 @@ void EmuFolders::SetDefaults()
Logs = Path::Combine(DataRoot, "logs");
Cheats = Path::Combine(DataRoot, "cheats");
CheatsWS = Path::Combine(DataRoot, "cheats_ws");
+ CheatsNI = Path::Combine(DataRoot, "cheats_ni");
Covers = Path::Combine(DataRoot, "covers");
GameSettings = Path::Combine(DataRoot, "gamesettings");
Cache = Path::Combine(DataRoot, "cache");
@@ -1239,6 +1243,7 @@ void EmuFolders::LoadConfig(SettingsInterface& si)
Logs = LoadPathFromSettings(si, DataRoot, "Logs", "logs");
Cheats = LoadPathFromSettings(si, DataRoot, "Cheats", "cheats");
CheatsWS = LoadPathFromSettings(si, DataRoot, "CheatsWS", "cheats_ws");
+ CheatsNI = LoadPathFromSettings(si, DataRoot, "CheatsNI", "cheats_ni");
Covers = LoadPathFromSettings(si, DataRoot, "Covers", "covers");
GameSettings = LoadPathFromSettings(si, DataRoot, "GameSettings", "gamesettings");
Cache = LoadPathFromSettings(si, DataRoot, "Cache", "cache");
@@ -1251,6 +1256,7 @@ void EmuFolders::LoadConfig(SettingsInterface& si)
Console.WriteLn("Logs Directory: %s", Logs.c_str());
Console.WriteLn("Cheats Directory: %s", Cheats.c_str());
Console.WriteLn("CheatsWS Directory: %s", CheatsWS.c_str());
+ Console.WriteLn("CheatsNI Directory: %s", CheatsNI.c_str());
Console.WriteLn("Covers Directory: %s", Covers.c_str());
Console.WriteLn("Game Settings Directory: %s", GameSettings.c_str());
Console.WriteLn("Cache Directory: %s", Cache.c_str());
@@ -1267,6 +1273,7 @@ void EmuFolders::Save(SettingsInterface& si)
si.SetStringValue("Folders", "Logs", Path::MakeRelative(Logs, DataRoot).c_str());
si.SetStringValue("Folders", "Cheats", Path::MakeRelative(Cheats, DataRoot).c_str());
si.SetStringValue("Folders", "CheatsWS", Path::MakeRelative(CheatsWS, DataRoot).c_str());
+ si.SetStringValue("Folders", "CheatsNI", Path::MakeRelative(CheatsNI, DataRoot).c_str());
si.SetStringValue("Folders", "Cache", Path::MakeRelative(Cache, DataRoot).c_str());
si.SetStringValue("Folders", "Textures", Path::MakeRelative(Textures, DataRoot).c_str());
}
@@ -1281,6 +1288,7 @@ bool EmuFolders::EnsureFoldersExist()
result = FileSystem::CreateDirectoryPath(Logs.c_str(), false) && result;
result = FileSystem::CreateDirectoryPath(Cheats.c_str(), false) && result;
result = FileSystem::CreateDirectoryPath(CheatsWS.c_str(), false) && result;
+ result = FileSystem::CreateDirectoryPath(CheatsNI.c_str(), false) && result;
result = FileSystem::CreateDirectoryPath(Covers.c_str(), false) && result;
result = FileSystem::CreateDirectoryPath(GameSettings.c_str(), false) && result;
result = FileSystem::CreateDirectoryPath(Cache.c_str(), false) && result;
diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp
index b2b24419f0..57bcc600fe 100644
--- a/pcsx2/VMManager.cpp
+++ b/pcsx2/VMManager.cpp
@@ -119,6 +119,9 @@ static std::string s_elf_override;
static u32 s_active_game_fixes = 0;
static std::vector s_widescreen_cheats_data;
static bool s_widescreen_cheats_loaded = false;
+static std::vector s_no_interlacing_cheats_data;
+static bool s_no_interlacing_cheats_loaded = false;
+static u32 s_active_no_interlacing_patches = 0;
static s32 s_current_save_slot = 1;
static u32 s_frame_advance_count = 0;
static u32 s_mxcsr_saved;
@@ -234,6 +237,8 @@ void VMManager::Internal::ReleaseMemory()
{
std::vector().swap(s_widescreen_cheats_data);
s_widescreen_cheats_loaded = false;
+ std::vector().swap(s_no_interlacing_cheats_data);
+ s_no_interlacing_cheats_loaded = false;
s_vm_memory->DecommitAll();
s_vm_memory->ReleaseAll();
@@ -265,6 +270,10 @@ void VMManager::LoadSettings()
EmuConfig.GS.MaskUserHacks();
EmuConfig.GS.MaskUpscalingHacks();
+ // Disable interlacing if we have no-interlacing patches active.
+ if (s_active_no_interlacing_patches > 0 && EmuConfig.GS.InterlaceMode == GSInterlaceMode::Automatic)
+ EmuConfig.GS.InterlaceMode = GSInterlaceMode::Off;
+
// Force MTVU off when playing back GS dumps, it doesn't get used.
if (GSDumpReplayer::IsReplayingDump())
EmuConfig.Speedhacks.vuThread = false;
@@ -436,9 +445,52 @@ static void LoadPatches(const std::string& crc_string, bool show_messages, bool
fmt::format_to(std::back_inserter(message), "{}{} widescreen patches", (patch_count > 0 || cheat_count > 0) ? " and " : "", ws_patch_count);
}
+ // no-interlacing patches
+ if (EmuConfig.EnableNoInterlacingPatches && s_game_crc != 0)
+ {
+ if (s_active_no_interlacing_patches = LoadPatchesFromDir(crc_string, EmuFolders::CheatsNI, "No-interlacing patches", false))
+ {
+ Console.WriteLn(Color_Gray, "Found no-interlacing patches in the cheats_ni folder --> skipping cheats_ni.zip");
+ }
+ else
+ {
+ // No ws cheat files found at the cheats_ws folder, try the ws cheats zip file.
+ if (!s_no_interlacing_cheats_loaded)
+ {
+ s_no_interlacing_cheats_loaded = true;
+
+ std::optional> data = Host::ReadResourceFile("cheats_ni.zip");
+ if (data.has_value())
+ s_no_interlacing_cheats_data = std::move(data.value());
+ }
+
+ if (!s_no_interlacing_cheats_data.empty())
+ {
+ s_active_no_interlacing_patches = LoadPatchesFromZip(crc_string, s_no_interlacing_cheats_data.data(), s_no_interlacing_cheats_data.size());
+ PatchesCon->WriteLn(Color_Green, "(No-Interlacing Cheats DB) Patches Loaded: %u", s_active_no_interlacing_patches);
+ }
+ }
+
+ if (s_active_no_interlacing_patches > 0)
+ {
+ fmt::format_to(std::back_inserter(message), "{}{} no-interlacing patches", (patch_count > 0 || cheat_count > 0 || ws_patch_count > 0) ? " and " : "", s_active_no_interlacing_patches);
+
+ // Disable interlacing in GS if active.
+ if (EmuConfig.GS.InterlaceMode == GSInterlaceMode::Automatic)
+ {
+ EmuConfig.GS.InterlaceMode = GSInterlaceMode::Off;
+ GetMTGS().ApplySettings();
+ }
+ }
+ }
+ else
+ {
+ s_active_no_interlacing_patches = 0;
+ }
+
if (show_messages)
{
- if (cheat_count > 0 || ws_patch_count > 0)
+ if (cheat_count > 0 || ws_patch_count > 0 || s_active_no_interlacing_patches > 0)
{
message += " are active.";
Host::AddKeyedOSDMessage("LoadPatches", std::move(message), 5.0f);
@@ -823,6 +875,8 @@ void VMManager::Shutdown(bool save_resume_state)
s_game_name.clear();
Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, 0);
}
+ s_active_game_fixes = 0;
+ s_active_no_interlacing_patches = 0;
UpdateGameSettingsLayer();
std::string().swap(s_elf_override);
@@ -859,6 +913,9 @@ void VMManager::Reset()
{
const bool game_was_started = g_GameStarted;
+ s_active_game_fixes = 0;
+ s_active_no_interlacing_patches = 0;
+
SysClearExecutionCache();
memBindConditionalHandlers();
UpdateVSyncRate();
@@ -1375,8 +1432,12 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
CheckForDEV9ConfigChanges(old_config);
CheckForMemoryCardConfigChanges(old_config);
- if (EmuConfig.EnableCheats != old_config.EnableCheats || EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches)
+ if (EmuConfig.EnableCheats != old_config.EnableCheats ||
+ EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches ||
+ EmuConfig.EnableNoInterlacingPatches != old_config.EnableNoInterlacingPatches)
+ {
VMManager::ReloadPatches(true);
+ }
}
void VMManager::ApplySettings()