Add CheatEngine and support for Gateway cheats (#4406)
* Add CheatEngine; Add support for Gateway cheats; Add Cheat UI * fix a potential crash on some systems * fix substr with negative length * Add Joker to the NonOp comp handling * Fixup JokerOp * minor fixup in patchop; add todo for nested loops * Add comment for PadState member variable in HID * fix: stol to stoul in parsing cheat file * fix misplaced parsing of values; fix patchop code * add missing break * Make read_func and write_func a template parameter
This commit is contained in:
@@ -24,6 +24,8 @@ add_executable(citra-qt
|
||||
camera/qt_camera_base.h
|
||||
camera/qt_multimedia_camera.cpp
|
||||
camera/qt_multimedia_camera.h
|
||||
cheats.cpp
|
||||
cheats.h
|
||||
citra-qt.rc
|
||||
configuration/config.cpp
|
||||
configuration/config.h
|
||||
@@ -134,6 +136,7 @@ set(UIS
|
||||
multiplayer/client_room.ui
|
||||
multiplayer/host_room.ui
|
||||
aboutdialog.ui
|
||||
cheats.ui
|
||||
hotkeys.ui
|
||||
main.ui
|
||||
compatdb.ui
|
||||
|
75
src/citra_qt/cheats.cpp
Normal file
75
src/citra_qt/cheats.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2018 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QTableWidgetItem>
|
||||
#include "citra_qt/cheats.h"
|
||||
#include "core/cheats/cheat_base.h"
|
||||
#include "core/cheats/cheats.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "ui_cheats.h"
|
||||
|
||||
CheatDialog::CheatDialog(QWidget* parent)
|
||||
: QDialog(parent), ui(std::make_unique<Ui::CheatDialog>()) {
|
||||
// Setup gui control settings
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
|
||||
ui->tableCheats->setColumnWidth(0, 30);
|
||||
ui->tableCheats->setColumnWidth(2, 85);
|
||||
ui->tableCheats->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||
ui->tableCheats->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
ui->tableCheats->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
|
||||
ui->textDetails->setEnabled(false);
|
||||
ui->textNotes->setEnabled(false);
|
||||
const auto game_id = fmt::format(
|
||||
"{:016X}", Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id);
|
||||
ui->labelTitle->setText(tr("Title ID: %1").arg(QString::fromStdString(game_id)));
|
||||
|
||||
connect(ui->buttonClose, &QPushButton::released, this, &CheatDialog::OnCancel);
|
||||
connect(ui->tableCheats, &QTableWidget::cellClicked, this, &CheatDialog::OnRowSelected);
|
||||
|
||||
LoadCheats();
|
||||
}
|
||||
|
||||
CheatDialog::~CheatDialog() = default;
|
||||
|
||||
void CheatDialog::LoadCheats() {
|
||||
const auto& cheats = Core::System::GetInstance().CheatEngine().GetCheats();
|
||||
|
||||
ui->tableCheats->setRowCount(cheats.size());
|
||||
|
||||
for (size_t i = 0; i < cheats.size(); i++) {
|
||||
QCheckBox* enabled = new QCheckBox();
|
||||
enabled->setChecked(cheats[i]->IsEnabled());
|
||||
enabled->setStyleSheet("margin-left:7px;");
|
||||
ui->tableCheats->setItem(i, 0, new QTableWidgetItem());
|
||||
ui->tableCheats->setCellWidget(i, 0, enabled);
|
||||
ui->tableCheats->setItem(
|
||||
i, 1, new QTableWidgetItem(QString::fromStdString(cheats[i]->GetName())));
|
||||
ui->tableCheats->setItem(
|
||||
i, 2, new QTableWidgetItem(QString::fromStdString(cheats[i]->GetType())));
|
||||
enabled->setProperty("row", static_cast<int>(i));
|
||||
|
||||
connect(enabled, &QCheckBox::stateChanged, this, &CheatDialog::OnCheckChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void CheatDialog::OnCancel() {
|
||||
close();
|
||||
}
|
||||
|
||||
void CheatDialog::OnRowSelected(int row, int column) {
|
||||
ui->textDetails->setEnabled(true);
|
||||
ui->textNotes->setEnabled(true);
|
||||
const auto& current_cheat = Core::System::GetInstance().CheatEngine().GetCheats()[row];
|
||||
ui->textNotes->setPlainText(QString::fromStdString(current_cheat->GetComments()));
|
||||
ui->textDetails->setPlainText(QString::fromStdString(current_cheat->ToString()));
|
||||
}
|
||||
|
||||
void CheatDialog::OnCheckChanged(int state) {
|
||||
const QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
|
||||
int row = static_cast<int>(checkbox->property("row").toInt());
|
||||
Core::System::GetInstance().CheatEngine().GetCheats()[row]->SetEnabled(state);
|
||||
}
|
30
src/citra_qt/cheats.h
Normal file
30
src/citra_qt/cheats.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2018 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class CheatDialog;
|
||||
} // namespace Ui
|
||||
|
||||
class CheatDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CheatDialog(QWidget* parent = nullptr);
|
||||
~CheatDialog();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::CheatDialog> ui;
|
||||
|
||||
void LoadCheats();
|
||||
|
||||
private slots:
|
||||
void OnCancel();
|
||||
void OnRowSelected(int row, int column);
|
||||
void OnCheckChanged(int state);
|
||||
};
|
204
src/citra_qt/cheats.ui
Normal file
204
src/citra_qt/cheats.ui
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CheatDialog</class>
|
||||
<widget class="QDialog" name="CheatDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>862</width>
|
||||
<height>612</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Cheats</string>
|
||||
</property>
|
||||
<widget class="QLabel" name="labelTitle">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>300</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Title ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>570</y>
|
||||
<width>841</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonClose">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>80</y>
|
||||
<width>551</width>
|
||||
<height>471</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableCheats">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QLabel" name="labelAvailableCheats">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>60</y>
|
||||
<width>121</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Available Cheats:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>580</x>
|
||||
<y>440</y>
|
||||
<width>271</width>
|
||||
<height>111</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="textNotes">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QLabel" name="labelNotes">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>580</x>
|
||||
<y>420</y>
|
||||
<width>111</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Notes:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>580</x>
|
||||
<y>80</y>
|
||||
<width>271</width>
|
||||
<height>311</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="textDetails">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QLabel" name="labelDetails">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>580</x>
|
||||
<y>60</y>
|
||||
<width>55</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Code:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@@ -20,6 +20,7 @@
|
||||
#include "citra_qt/bootmanager.h"
|
||||
#include "citra_qt/camera/qt_multimedia_camera.h"
|
||||
#include "citra_qt/camera/still_image_camera.h"
|
||||
#include "citra_qt/cheats.h"
|
||||
#include "citra_qt/compatdb.h"
|
||||
#include "citra_qt/compatibility_list.h"
|
||||
#include "citra_qt/configuration/config.h"
|
||||
@@ -467,6 +468,7 @@ void GMainWindow::RestoreUIState() {
|
||||
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
|
||||
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
|
||||
#endif
|
||||
ui.action_Cheats->setEnabled(false);
|
||||
|
||||
game_list->LoadInterfaceLayout();
|
||||
|
||||
@@ -527,6 +529,7 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
connect(ui.action_Report_Compatibility, &QAction::triggered, this,
|
||||
&GMainWindow::OnMenuReportCompatibility);
|
||||
connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
|
||||
connect(ui.action_Cheats, &QAction::triggered, this, &GMainWindow::OnCheats);
|
||||
|
||||
// View
|
||||
connect(ui.action_Single_Window_Mode, &QAction::triggered, this,
|
||||
@@ -870,6 +873,7 @@ void GMainWindow::ShutdownGame() {
|
||||
ui.action_Pause->setEnabled(false);
|
||||
ui.action_Stop->setEnabled(false);
|
||||
ui.action_Restart->setEnabled(false);
|
||||
ui.action_Cheats->setEnabled(false);
|
||||
ui.action_Load_Amiibo->setEnabled(false);
|
||||
ui.action_Remove_Amiibo->setEnabled(false);
|
||||
ui.action_Report_Compatibility->setEnabled(false);
|
||||
@@ -1159,6 +1163,7 @@ void GMainWindow::OnStartGame() {
|
||||
ui.action_Pause->setEnabled(true);
|
||||
ui.action_Stop->setEnabled(true);
|
||||
ui.action_Restart->setEnabled(true);
|
||||
ui.action_Cheats->setEnabled(true);
|
||||
ui.action_Load_Amiibo->setEnabled(true);
|
||||
ui.action_Report_Compatibility->setEnabled(true);
|
||||
ui.action_Enable_Frame_Advancing->setEnabled(true);
|
||||
@@ -1294,6 +1299,11 @@ void GMainWindow::OnSwapScreens() {
|
||||
Settings::Apply();
|
||||
}
|
||||
|
||||
void GMainWindow::OnCheats() {
|
||||
CheatDialog cheat_dialog(this);
|
||||
cheat_dialog.exec();
|
||||
}
|
||||
|
||||
void GMainWindow::OnConfigure() {
|
||||
ConfigureDialog configureDialog(this, hotkey_registry);
|
||||
connect(&configureDialog, &ConfigureDialog::languageChanged, this,
|
||||
|
@@ -174,6 +174,7 @@ private slots:
|
||||
void ChangeScreenLayout();
|
||||
void ToggleScreenLayout();
|
||||
void OnSwapScreens();
|
||||
void OnCheats();
|
||||
void ShowFullscreen();
|
||||
void HideFullscreen();
|
||||
void ToggleWindowMode();
|
||||
|
@@ -85,6 +85,7 @@
|
||||
<addaction name="action_Report_Compatibility"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Configure"/>
|
||||
<addaction name="action_Cheats"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_View">
|
||||
<property name="title">
|
||||
@@ -227,6 +228,11 @@
|
||||
<string>Configure...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Cheats">
|
||||
<property name="text">
|
||||
<string>Cheats...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Display_Dock_Widget_Headers">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
Reference in New Issue
Block a user