From f8d1d08e9c13d39ccb6d0c50ae74e7bbe9ed52c8 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sat, 15 Aug 2020 00:14:05 +0200 Subject: [PATCH] (finally) build the goddamn cheat interface --- src/ARCodeFile.cpp | 61 +++-- src/ARCodeFile.h | 7 +- src/Config.cpp | 2 +- src/frontend/FrontendUtil.h | 6 + src/frontend/Util_ROM.cpp | 49 ++++ src/frontend/qt_sdl/CheatsDialog.cpp | 357 ++++++++++++++++++++++++- src/frontend/qt_sdl/CheatsDialog.h | 33 ++- src/frontend/qt_sdl/CheatsDialog.ui | 4 +- src/frontend/qt_sdl/PlatformConfig.cpp | 4 + src/frontend/qt_sdl/PlatformConfig.h | 2 + src/frontend/qt_sdl/main.cpp | 16 +- 11 files changed, 506 insertions(+), 35 deletions(-) diff --git a/src/ARCodeFile.cpp b/src/ARCodeFile.cpp index d2f47ffc..57c710d4 100644 --- a/src/ARCodeFile.cpp +++ b/src/ARCodeFile.cpp @@ -35,8 +35,21 @@ ARCodeFile::ARCodeFile(const char* filename) Categories.clear(); + if (!Load()) + Error = true; +} + +ARCodeFile::~ARCodeFile() +{ + Categories.clear(); +} + +bool ARCodeFile::Load() +{ FILE* f = Platform::OpenFile(Filename, "r"); - if (!f) return; + if (!f) return true; + + Categories.clear(); bool isincat = false; ARCodeCat curcat; @@ -60,15 +73,14 @@ ARCodeFile::ARCodeFile(const char* filename) if (!strncasecmp(start, "CAT", 3)) { char catname[128]; - int ret = sscanf(start, "CAT %127[^\n]", catname); + int ret = sscanf(start, "CAT %127[^\r\n]", catname); catname[127] = '\0'; if (ret < 1) { printf("AR: malformed CAT line: %s\n", start); fclose(f); - Error = true; - return; + return false; } if (isincode) curcat.Codes.push_back(curcode); @@ -84,23 +96,21 @@ ARCodeFile::ARCodeFile(const char* filename) { int enable; char codename[128]; - int ret = sscanf(start, "CODE %d %127[^\n]", &enable, codename); + int ret = sscanf(start, "CODE %d %127[^\r\n]", &enable, codename); codename[127] = '\0'; if (ret < 2) { printf("AR: malformed CODE line: %s\n", start); fclose(f); - Error = true; - return; + return false; } if (!isincat) { printf("AR: encountered CODE line with no category started\n"); fclose(f); - Error = true; - return; + return false; } if (isincode) curcat.Codes.push_back(curcode); @@ -119,24 +129,21 @@ ARCodeFile::ARCodeFile(const char* filename) { printf("AR: malformed data line: %s\n", start); fclose(f); - Error = true; - return; + return false; } if (!isincode) { printf("AR: encountered data line with no code started\n"); fclose(f); - Error = true; - return; + return false; } if (curcode.CodeLen >= 2*64) { printf("AR: code too long!\n"); fclose(f); - Error = true; - return; + return false; } u32 idx = curcode.CodeLen; @@ -150,27 +157,35 @@ ARCodeFile::ARCodeFile(const char* filename) if (isincat) Categories.push_back(curcat); fclose(f); + return true; +} + +bool ARCodeFile::Save() +{ + FILE* f = Platform::OpenFile(Filename, "w"); + if (!f) return false; - printf("PARSED OUTPUT\n"); for (ARCodeCatList::iterator it = Categories.begin(); it != Categories.end(); it++) { ARCodeCat& cat = *it; - printf("CAT %s\n", cat.Name); + + if (it != Categories.begin()) fprintf(f, "\n"); + fprintf(f, "CAT %s\n\n", cat.Name); for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++) { ARCode& code = *jt; - printf("CODE %d %s\n", code.Enabled, code.Name); + fprintf(f, "CODE %d %s\n", code.Enabled, code.Name); for (u32 i = 0; i < code.CodeLen; i+=2) { - printf("%08X %08X\n", code.Code[i], code.Code[i+1]); + fprintf(f, "%08X %08X\n", code.Code[i], code.Code[i+1]); } + + fprintf(f, "\n"); } } -} -ARCodeFile::~ARCodeFile() -{ - // + fclose(f); + return true; } diff --git a/src/ARCodeFile.h b/src/ARCodeFile.h index 548bfeb8..374c56e5 100644 --- a/src/ARCodeFile.h +++ b/src/ARCodeFile.h @@ -19,7 +19,7 @@ #ifndef ARCODEFILE_H #define ARCODEFILE_H -#include +#include #include "types.h" @@ -32,7 +32,7 @@ typedef struct } ARCode; -typedef std::vector ARCodeList; +typedef std::list ARCodeList; typedef struct { @@ -41,7 +41,7 @@ typedef struct } ARCodeCat; -typedef std::vector ARCodeCatList; +typedef std::list ARCodeCatList; class ARCodeFile @@ -52,6 +52,7 @@ public: bool Error; + bool Load(); bool Save(); ARCodeCatList Categories; diff --git a/src/Config.cpp b/src/Config.cpp index de1c70d6..d198093e 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -104,7 +104,7 @@ void Load() while (!feof(f)) { fgets(linebuf, 1024, f); - int ret = sscanf(linebuf, "%31[A-Za-z_0-9]=%[^\t\n]", entryname, entryval); + int ret = sscanf(linebuf, "%31[A-Za-z_0-9]=%[^\t\r\n]", entryname, entryval); entryname[31] = '\0'; if (ret < 2) continue; diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index 099583fb..d30c4e16 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -67,6 +67,9 @@ extern bool SavestateLoaded; // initialize the ROM handling utility void Init_ROM(); +// deinitialize the ROM handling utility +void DeInit_ROM(); + // load the BIOS/firmware and boot from it int LoadBIOS(); @@ -97,6 +100,9 @@ bool SaveState(const char* filename); // undo the latest savestate load void UndoStateLoad(); +// enable or disable cheats +void EnableCheats(bool enable); + // setup the display layout based on the provided display size and parameters // * screenWidth/screenHeight: size of the host display diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp index 8116a932..421a6e68 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -27,6 +27,8 @@ #include "NDS.h" #include "GBACart.h" +#include "AREngine.h" + namespace Frontend { @@ -37,6 +39,9 @@ char PrevSRAMPath[ROMSlot_MAX][1024]; // for savestate 'undo load' bool SavestateLoaded; +ARCodeFile* CheatFile; +bool CheatsOn; + void Init_ROM() { @@ -48,6 +53,18 @@ void Init_ROM() memset(SRAMPath[ROMSlot_GBA], 0, 1024); memset(PrevSRAMPath[ROMSlot_NDS], 0, 1024); memset(PrevSRAMPath[ROMSlot_GBA], 0, 1024); + + CheatFile = nullptr; + CheatsOn = false; +} + +void DeInit_ROM() +{ + if (CheatFile) + { + delete CheatFile; + CheatFile = nullptr; + } } // TODO: currently, when failing to load a ROM for whatever reason, we attempt @@ -198,6 +215,25 @@ int VerifyDSiNAND() return Load_OK; } +void LoadCheats() +{ + if (CheatFile) + { + delete CheatFile; + CheatFile = nullptr; + } + + char filename[1024]; + strncpy(filename, ROMPath[ROMSlot_NDS], 1023); + filename[1023] = '\0'; + strncpy(filename + strlen(ROMPath[ROMSlot_NDS]) - 3, "mch", 3); + + // TODO: check for error (malformed cheat file, ...) + CheatFile = new ARCodeFile(filename); + + AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr); +} + int LoadBIOS() { int res; @@ -235,6 +271,8 @@ int LoadBIOS() SavestateLoaded = false; + LoadCheats(); + return Load_OK; } @@ -295,6 +333,8 @@ int LoadROM(const char* file, int slot) { SavestateLoaded = false; + LoadCheats(); + // Reload the inserted GBA cartridge (if any) // TODO: report failure there?? if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]); @@ -387,6 +427,8 @@ int Reset() return Load_ROMLoadError; } + LoadCheats(); + return Load_OK; } @@ -539,4 +581,11 @@ void UndoStateLoad() } } +void EnableCheats(bool enable) +{ + CheatsOn = enable; + if (CheatFile) + AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr); +} + } diff --git a/src/frontend/qt_sdl/CheatsDialog.cpp b/src/frontend/qt_sdl/CheatsDialog.cpp index 2654e758..05fedc54 100644 --- a/src/frontend/qt_sdl/CheatsDialog.cpp +++ b/src/frontend/qt_sdl/CheatsDialog.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "types.h" #include "Platform.h" @@ -32,30 +33,380 @@ CheatsDialog* CheatsDialog::currentDlg = nullptr; extern char* EmuDirectory; +namespace Frontend { extern ARCodeFile* CheatFile; } + CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); - // setup UI here + codeFile = Frontend::CheatFile; + + QStandardItemModel* model = new QStandardItemModel(); + ui->tvCodeList->setModel(model); + connect(model, &QStandardItemModel::itemChanged, this, &CheatsDialog::onCheatEntryModified); + connect(ui->tvCodeList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CheatsDialog::onCheatSelectionChanged); + + { + QStandardItem* root = model->invisibleRootItem(); + + for (ARCodeCatList::iterator i = codeFile->Categories.begin(); i != codeFile->Categories.end(); i++) + { + ARCodeCat& cat = *i; + + QStandardItem* catitem = new QStandardItem(cat.Name); + catitem->setEditable(true); + catitem->setData(QVariant::fromValue(i)); + root->appendRow(catitem); + + for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++) + { + ARCode& code = *j; + + QStandardItem* codeitem = new QStandardItem(code.Name); + codeitem->setEditable(true); + codeitem->setCheckable(true); + codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked); + codeitem->setData(QVariant::fromValue(j)); + catitem->appendRow(codeitem); + } + } + } + + ui->txtCode->setPlaceholderText(""); + codeChecker = new ARCodeChecker(ui->txtCode->document()); + + ui->btnNewARCode->setEnabled(false); + ui->btnDeleteCode->setEnabled(false); + ui->txtCode->setEnabled(false); } CheatsDialog::~CheatsDialog() { + QAbstractItemModel* model = ui->tvCodeList->model(); + ui->tvCodeList->setModel(nullptr); + delete model; + + delete codeChecker; + delete ui; } void CheatsDialog::on_CheatsDialog_accepted() { - // save shit here + codeFile->Save(); closeDlg(); } void CheatsDialog::on_CheatsDialog_rejected() { - // don't save shit here + codeFile->Load(); closeDlg(); } + +void CheatsDialog::on_btnNewCat_clicked() +{ + QStandardItem* root = ((QStandardItemModel*)ui->tvCodeList->model())->invisibleRootItem(); + + ARCodeCat cat; + cat.Codes.clear(); + memset(cat.Name, 0, 128); + strncpy(cat.Name, "(new category)", 127); + + codeFile->Categories.push_back(cat); + ARCodeCatList::iterator id = codeFile->Categories.end(); id--; + + QStandardItem* catitem = new QStandardItem(cat.Name); + catitem->setEditable(true); + catitem->setData(QVariant::fromValue(id)); + root->appendRow(catitem); + + ui->tvCodeList->selectionModel()->select(catitem->index(), QItemSelectionModel::ClearAndSelect); + ui->tvCodeList->edit(catitem->index()); +} + +void CheatsDialog::on_btnNewARCode_clicked() +{ + QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes(); + if (indices.isEmpty()) + { + // ???? + return; + } + + QStandardItemModel* model = (QStandardItemModel*)ui->tvCodeList->model(); + QStandardItem* item = model->itemFromIndex(indices.first()); + QStandardItem* parentitem; + + QVariant data = item->data(); + if (data.canConvert()) + { + parentitem = item; + } + else if (data.canConvert()) + { + parentitem = item->parent(); + } + else + { + printf("what?? :(\n"); + return; + } + + ARCodeCatList::iterator it_cat = parentitem->data().value(); + ARCodeCat& cat = *it_cat; + + ARCode code; + memset(code.Name, 0, 128); + strncpy(code.Name, "(new AR code)", 127); + code.Enabled = true; + code.CodeLen = 0; + memset(code.Code, 0, sizeof(code.Code)); + + cat.Codes.push_back(code); + ARCodeList::iterator id = cat.Codes.end(); id--; + + QStandardItem* codeitem = new QStandardItem(code.Name); + codeitem->setEditable(true); + codeitem->setCheckable(true); + codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked); + codeitem->setData(QVariant::fromValue(id)); + parentitem->appendRow(codeitem); + + ui->tvCodeList->selectionModel()->select(codeitem->index(), QItemSelectionModel::ClearAndSelect); + ui->tvCodeList->edit(codeitem->index()); +} + +void CheatsDialog::on_btnDeleteCode_clicked() +{ + QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes(); + if (indices.isEmpty()) + { + // ???? + return; + } + + QMessageBox::StandardButton res = QMessageBox::question(this, + "Confirm deletion", + "Really delete the selected item?", + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + if (res != QMessageBox::Yes) return; + + QStandardItemModel* model = (QStandardItemModel*)ui->tvCodeList->model(); + QStandardItem* item = model->itemFromIndex(indices.first()); + + QVariant data = item->data(); + if (data.canConvert()) + { + ARCodeCatList::iterator it_cat = data.value(); + + (*it_cat).Codes.clear(); + codeFile->Categories.erase(it_cat); + + model->invisibleRootItem()->removeRow(item->row()); + } + else if (data.canConvert()) + { + ARCodeList::iterator it_code = data.value(); + ARCodeCatList::iterator it_cat = item->parent()->data().value(); + + (*it_cat).Codes.erase(it_code); + + item->parent()->removeRow(item->row()); + } +} + +void CheatsDialog::onCheatSelectionChanged(const QItemSelection& sel, const QItemSelection& desel) +{ + QModelIndexList indices = sel.indexes(); + if (indices.isEmpty()) + { + ui->btnNewARCode->setEnabled(false); + ui->btnDeleteCode->setEnabled(false); + ui->txtCode->setEnabled(false); + ui->txtCode->setPlaceholderText(""); + ui->txtCode->clear(); + } + else + { + QStandardItem* item = ((QStandardItemModel*)ui->tvCodeList->model())->itemFromIndex(indices.first()); + + QVariant data = item->data(); + if (data.canConvert()) + { + ui->btnDeleteCode->setEnabled(true); + ui->txtCode->setEnabled(false); + ui->txtCode->setPlaceholderText(""); + ui->txtCode->clear(); + } + else if (data.canConvert()) + { + ARCode& code = *(data.value()); + + ui->btnDeleteCode->setEnabled(true); + ui->txtCode->setEnabled(true); + ui->txtCode->setPlaceholderText("(enter AR code here)"); + + QString codestr = ""; + for (u32 i = 0; i < code.CodeLen; i += 2) + { + u32 c0 = code.Code[i+0]; + u32 c1 = code.Code[i+1]; + //codestr += QString("%1 %2\n").arg(c0, 8, 16, '0').arg(c1, 8, 16, '0').toUpper(); + codestr += QString::asprintf("%08X %08X\n", c0, c1); + } + ui->txtCode->setPlainText(codestr); + } + + ui->btnNewARCode->setEnabled(true); + } +} + +void CheatsDialog::onCheatEntryModified(QStandardItem* item) +{ + QVariant data = item->data(); + if (data.canConvert()) + { + ARCodeCat& cat = *(data.value()); + + if (item->text().isEmpty()) + { + QString oldname = QString(cat.Name); + item->setText(oldname.isEmpty() ? "(blank category name??)" : oldname); + } + else + { + strncpy(cat.Name, item->text().toStdString().c_str(), 127); + cat.Name[127] = '\0'; + } + } + else if (data.canConvert()) + { + ARCode& code = *(data.value()); + + if (item->text().isEmpty()) + { + QString oldname = QString(code.Name); + item->setText(oldname.isEmpty() ? "(blank code name??)" : oldname); + } + else + { + strncpy(code.Name, item->text().toStdString().c_str(), 127); + code.Name[127] = '\0'; + } + + code.Enabled = (item->checkState() == Qt::Checked); + } +} + +void CheatsDialog::on_txtCode_textChanged() +{ + QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes(); + if (indices.isEmpty()) + return; + + QStandardItem* item = ((QStandardItemModel*)ui->tvCodeList->model())->itemFromIndex(indices.first()); + QVariant data = item->data(); + if (!data.canConvert()) + return; + + bool error = false; + u32 codeout[2*64]; + u32 codelen = 0; + + QString text = ui->txtCode->document()->toPlainText(); + QStringList lines = text.split('\n', QString::SkipEmptyParts); + for (QStringList::iterator it = lines.begin(); it != lines.end(); it++) + { + QString line = *it; + line = line.trimmed(); + if (line.isEmpty()) continue; + + if (line.length() > 17) + { + error = true; + break; + } + + QStringList numbers = line.split(' '); + if (numbers.length() != 2) + { + error = true; + break; + } + + QStringList::iterator jt = numbers.begin(); + QString s0 = *jt++; + QString s1 = *jt++; + + bool c0good, c1good; + u32 c0, c1; + + c0 = s0.toUInt(&c0good, 16); + c1 = s1.toUInt(&c1good, 16); + + if (!c0good || !c1good) + { + error = true; + break; + } + + if (codelen >= 2*64) + { + error = true; + break; + } + + codeout[codelen++] = c0; + codeout[codelen++] = c1; + } + + ui->btnNewCat->setEnabled(!error); + ui->btnNewARCode->setEnabled(!error); + ui->btnDeleteCode->setEnabled(!error); + ui->tvCodeList->setEnabled(!error); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!error); + + if (error) return; + + ARCode& code = *(data.value()); + memcpy(code.Code, codeout, codelen*sizeof(u32)); + code.CodeLen = codelen; +} + +void ARCodeChecker::highlightBlock(const QString& text) +{ + QTextCharFormat errformat; errformat.setForeground(Qt::red); + + { + QRegularExpression expr("^\\s*[0-9A-Fa-f]{1,8} [0-9A-Fa-f]{1,8}\\s*$"); + QRegularExpressionMatchIterator it = expr.globalMatch(text); + if (!it.hasNext()) + { + setFormat(0, text.length(), errformat); + } + } + + /*{ + QRegularExpression expr("[^0-9A-Fa-f\\s]+"); + QRegularExpressionMatchIterator it = expr.globalMatch(text); + while (it.hasNext()) + { + QRegularExpressionMatch match = it.next(); + setFormat(match.capturedStart(), match.capturedLength(), errformat); + } + } + { + QRegularExpression expr("[0-9A-Fa-f]{9,}"); + QRegularExpressionMatchIterator it = expr.globalMatch(text); + while (it.hasNext()) + { + QRegularExpressionMatch match = it.next(); + setFormat(match.capturedStart(), match.capturedLength(), errformat); + } + }*/ +} diff --git a/src/frontend/qt_sdl/CheatsDialog.h b/src/frontend/qt_sdl/CheatsDialog.h index 99582c80..20f2c65e 100644 --- a/src/frontend/qt_sdl/CheatsDialog.h +++ b/src/frontend/qt_sdl/CheatsDialog.h @@ -20,10 +20,31 @@ #define CHEATSDIALOG_H #include +#include +#include +#include +#include + +#include "ARCodeFile.h" + +Q_DECLARE_METATYPE(ARCodeList::iterator) +Q_DECLARE_METATYPE(ARCodeCatList::iterator) namespace Ui { class CheatsDialog; } class CheatsDialog; +class ARCodeChecker : public QSyntaxHighlighter +{ + Q_OBJECT + +public: + ARCodeChecker(QTextDocument* parent) : QSyntaxHighlighter(parent) {} + ~ARCodeChecker() {} + +protected: + void highlightBlock(const QString& text) override; +}; + class CheatsDialog : public QDialog { Q_OBJECT @@ -54,12 +75,20 @@ private slots: void on_CheatsDialog_accepted(); void on_CheatsDialog_rejected(); - // + void on_btnNewCat_clicked(); + void on_btnNewARCode_clicked(); + void on_btnDeleteCode_clicked(); + + void onCheatSelectionChanged(const QItemSelection& sel, const QItemSelection& desel); + void onCheatEntryModified(QStandardItem* item); + + void on_txtCode_textChanged(); private: Ui::CheatsDialog* ui; - // + ARCodeFile* codeFile; + ARCodeChecker* codeChecker; }; #endif // CHEATSDIALOG_H diff --git a/src/frontend/qt_sdl/CheatsDialog.ui b/src/frontend/qt_sdl/CheatsDialog.ui index 493111db..d0bc586a 100644 --- a/src/frontend/qt_sdl/CheatsDialog.ui +++ b/src/frontend/qt_sdl/CheatsDialog.ui @@ -11,7 +11,7 @@ - AR cheat code editor - melonDS + Cheat code editor - melonDS @@ -36,7 +36,7 @@ - Delete code + Delete diff --git a/src/frontend/qt_sdl/PlatformConfig.cpp b/src/frontend/qt_sdl/PlatformConfig.cpp index bfb3f97b..76c5f4be 100644 --- a/src/frontend/qt_sdl/PlatformConfig.cpp +++ b/src/frontend/qt_sdl/PlatformConfig.cpp @@ -72,6 +72,8 @@ char MicWavPath[1024]; char LastROMFolder[1024]; +int EnableCheats; + bool EnableJIT; ConfigEntry PlatformConfigFile[] = @@ -162,6 +164,8 @@ ConfigEntry PlatformConfigFile[] = {"LastROMFolder", 1, LastROMFolder, 0, "", 1023}, + {"EnableCheats", 0, &EnableCheats, 0, NULL, 0}, + {"", -1, NULL, 0, NULL, 0} }; diff --git a/src/frontend/qt_sdl/PlatformConfig.h b/src/frontend/qt_sdl/PlatformConfig.h index 791bb071..bc9bba41 100644 --- a/src/frontend/qt_sdl/PlatformConfig.h +++ b/src/frontend/qt_sdl/PlatformConfig.h @@ -85,6 +85,8 @@ extern char MicWavPath[1024]; extern char LastROMFolder[1024]; +extern int EnableCheats; + } #endif // PLATFORMCONFIG_H diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 903e654b..f91f8790 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1067,6 +1067,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) menu->addSeparator(); actEnableCheats = menu->addAction("Enable cheats"); + actEnableCheats->setCheckable(true); connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats); actSetupCheats = menu->addAction("Setup cheat codes"); @@ -1218,6 +1219,10 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) actReset->setEnabled(false); actStop->setEnabled(false); + actSetupCheats->setEnabled(false); + + + actEnableCheats->setChecked(Config::EnableCheats != 0); actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0); @@ -1662,7 +1667,8 @@ void MainWindow::onStop() void MainWindow::onEnableCheats(bool checked) { - // + Config::EnableCheats = checked?1:0; + Frontend::EnableCheats(Config::EnableCheats != 0); } void MainWindow::onSetupCheats() @@ -1881,6 +1887,8 @@ void MainWindow::onEmuStart() actPause->setChecked(false); actReset->setEnabled(true); actStop->setEnabled(true); + + actSetupCheats->setEnabled(true); } void MainWindow::onEmuStop() @@ -1897,6 +1905,8 @@ void MainWindow::onEmuStop() actPause->setEnabled(false); actReset->setEnabled(false); actStop->setEnabled(false); + + actSetupCheats->setEnabled(false); } void MainWindow::onUpdateVideoSettings(bool glchange) @@ -2028,6 +2038,8 @@ int main(int argc, char** argv) micWavBuffer = nullptr; Frontend::Init_ROM(); + Frontend::EnableCheats(Config::EnableCheats != 0); + Frontend::Init_Audio(audioFreq); if (Config::MicInputType == 1) @@ -2084,6 +2096,8 @@ int main(int argc, char** argv) Input::CloseJoystick(); + Frontend::DeInit_ROM(); + if (audioDevice) SDL_CloseAudioDevice(audioDevice); if (micDevice) SDL_CloseAudioDevice(micDevice);