Preliminary support for Project Demi-inspired innate ability mods

main
Síle Ekaterin Liszka 2021-05-22 01:29:51 -05:00
parent 2116465775
commit 557a8a5d83
4 changed files with 90 additions and 19 deletions

View File

@ -12,7 +12,9 @@ body {
<head> <head>
<body> <body>
<h2>Exdeath</h2> <h2>Exdeath</h2>
<p>Exdeath is a patch compactor, a tool that applies multiple patches to a single target file. This version (0.2) provides the following options:</p> <p>Exdeath is a patch compactor, a tool that applies multiple patches to a single target file. You will need the US version of the Gameboy Advance release, which you can find through your favourite search engine. This version provides the following features:</p>
<h3>Main</h3>
<p>The real meat of the program: the patches.</p>
<ul> <ul>
<li>Base:<ul> <li>Base:<ul>
<li>None &mdash; The base game.</li> <li>None &mdash; The base game.</li>
@ -24,7 +26,8 @@ body {
<li><a href="https://drive.google.com/file/d/1kQeTEu55-Pt_0-fLSYIeUW50LxW6CcLN/view?usp=sharing">Double AP</a>: This option doubles the ABP gains, making it faster to master Jobs (most relevant for !Dualcast).</li> <li><a href="https://drive.google.com/file/d/1kQeTEu55-Pt_0-fLSYIeUW50LxW6CcLN/view?usp=sharing">Double AP</a>: This option doubles the ABP gains, making it faster to master Jobs (most relevant for !Dualcast).</li>
<li><a href="http://www.romhacking.net/hacks/563/">Sound Restoration</a>: This option modifies the soundfont and corrects some slow-down issues. It can cause artifacting, however. Older versions of VisualBoyAdvance will require the GBA BIOS file in order to run normally with this option.</li> <li><a href="http://www.romhacking.net/hacks/563/">Sound Restoration</a>: This option modifies the soundfont and corrects some slow-down issues. It can cause artifacting, however. Older versions of VisualBoyAdvance will require the GBA BIOS file in order to run normally with this option.</li>
</ul> </ul>
<p>You will need the US version of the Gameboy Advance release, which you can find through your favourite search engine.</p> <h3>Innate abilities</h3>
<p>Each checkbox applies the listed innate ability to all Jobs.</p>
</body> </body>
</html> </html>

9
src/data.hh Normal file
View File

@ -0,0 +1,9 @@
enum Job {
Passages = 0x01,
Pitfalls = 0x02,
LiteStep = 0x04,
Dash = 0x08,
Learning = 0x10
};
const long int job_innates = 0x156138;

View File

@ -34,9 +34,20 @@ Exdeath::Exdeath(QWidget *parent) : QWidget(parent) {
error = new QErrorMessage(); error = new QErrorMessage();
filename = nullptr; filename = nullptr;
layContainer = new QVBoxLayout(this);
layMain = new QGridLayout(this); layMain = new QGridLayout(this);
layMode = new QVBoxLayout(this); layMode = new QVBoxLayout(this);
layDemi = new QVBoxLayout(this);
grpMain = new QGroupBox("Main");
grpMain->setLayout(layMain);
grpDemi = new QGroupBox("Innate abilities");
grpDemi->setLayout(layDemi);
layContainer->addWidget(grpMain);
layContainer->addWidget(grpDemi);
// Main options
txtROM = new QLabel("ROM:"); txtROM = new QLabel("ROM:");
txtMode = new QLabel("Mode:"); txtMode = new QLabel("Mode:");
txtPortraits = new QLabel("FFT-style Portraits:"); txtPortraits = new QLabel("FFT-style Portraits:");
@ -46,6 +57,7 @@ Exdeath::Exdeath(QWidget *parent) : QWidget(parent) {
btnROM = new QPushButton("Select ROM"); btnROM = new QPushButton("Select ROM");
btnApply = new QPushButton("Apply"); btnApply = new QPushButton("Apply");
layContainer->addWidget(btnApply);
radBase = new QRadioButton("Base"); radBase = new QRadioButton("Base");
radFiesta = new QRadioButton("Fiesta"); radFiesta = new QRadioButton("Fiesta");
@ -71,8 +83,18 @@ Exdeath::Exdeath(QWidget *parent) : QWidget(parent) {
layMain->addWidget(chkAP, 3, 1); layMain->addWidget(chkAP, 3, 1);
layMain->addWidget(txtSound, 4, 0); layMain->addWidget(txtSound, 4, 0);
layMain->addWidget(chkSound, 4, 1); layMain->addWidget(chkSound, 4, 1);
layMain->addWidget(btnApply, 5, 1);
// Project Demi options
chkPassages = new QCheckBox("Innate Passages");
chkPitfalls = new QCheckBox("Innate Pitfalls");
chkLiteStep = new QCheckBox("Innate Light Step");
chkDash = new QCheckBox("Innate Dash");
chkLearning = new QCheckBox("Innate Learning");
layDemi->addWidget(chkPassages);
layDemi->addWidget(chkPitfalls);
layDemi->addWidget(chkLiteStep);
layDemi->addWidget(chkDash);
layDemi->addWidget(chkLearning);
connect(btnROM, &QPushButton::clicked, this, &Exdeath::btnROM_clicked); connect(btnROM, &QPushButton::clicked, this, &Exdeath::btnROM_clicked);
connect(btnApply, &QPushButton::clicked, this, &Exdeath::btnApply_clicked); connect(btnApply, &QPushButton::clicked, this, &Exdeath::btnApply_clicked);
} }
@ -129,17 +151,16 @@ void Exdeath::btnApply_clicked(bool trigger) {
patches << ":/patches/sound_restoration.ips"; patches << ":/patches/sound_restoration.ips";
} }
if (patches.size() == 0) {
return;
}
target = new QFile(output); target = new QFile(output);
target->open(QIODevice::ReadWrite); target->open(QIODevice::ReadWrite);
if (patches.size() != 0) {
for (int i = 0; i < patches.size(); i++) { for (int i = 0; i < patches.size(); i++) {
applyPatch(target, patches[i]); applyPatch(target, patches[i]);
}
}
if (chkPassages->isChecked() || chkPitfalls->isChecked() || chkLiteStep->isChecked() || chkDash->isChecked() || chkLearning->isChecked()) {
applyDemi(target);
} }
target->close(); target->close();
} }
@ -183,3 +204,26 @@ void Exdeath::applyPatch(QFile *file, QString patch) {
file->flush(); file->flush();
data->close(); data->close();
} }
void Exdeath::applyDemi(QFile *file) {
unsigned char base = 0;
if (!(radBase->isChecked() || radFiesta->isChecked())) {
error->showMessage("You must use Base or Fiesta to use these options.");
return;
}
if (chkPassages->isChecked()) base |= Job::Passages;
if (chkPitfalls->isChecked()) base |= Job::Pitfalls;
if (chkLiteStep->isChecked()) base |= Job::LiteStep;
if (chkDash->isChecked()) base |= Job::Dash;
if (chkLearning->isChecked()) base |= Job::Learning;
for (int i = 0; i < 26; i++) {
char temp[2];
file->seek(job_innates + (i * 2));
file->read(temp, 2);
temp[0] |= base;
file->seek(job_innates + (i * 2));
file->write(temp, 2);
}
}

View File

@ -1,19 +1,22 @@
#ifndef EXDEATH_HH_GUARD #ifndef EXDEATH_HH_GUARD
#define EXDEATH_HH_GUARD #define EXDEATH_HH_GUARD
#include <QWidget> #include <QCheckBox>
#include <QCryptographicHash>
#include <QErrorMessage>
#include <QFile>
#include <QFileDialog>
#include <QGridLayout> #include <QGridLayout>
#include <QVBoxLayout> #include <QGroupBox>
#include <QIODevice>
#include <QLabel> #include <QLabel>
#include <QPushButton> #include <QPushButton>
#include <QRadioButton> #include <QRadioButton>
#include <QCheckBox>
#include <QFileDialog>
#include <QStandardPaths> #include <QStandardPaths>
#include <QFile> #include <QVBoxLayout>
#include <QIODevice> #include <QWidget>
#include <QCryptographicHash>
#include <QErrorMessage> #include "data.hh"
class Exdeath : public QWidget { class Exdeath : public QWidget {
public: public:
@ -25,8 +28,10 @@ private:
QErrorMessage *error; QErrorMessage *error;
QVBoxLayout *layContainer;
QGridLayout *layMain; QGridLayout *layMain;
QVBoxLayout *layMode; QVBoxLayout *layMode;
QGroupBox *grpMain;
QLabel *txtROM; QLabel *txtROM;
QLabel *txtMode; QLabel *txtMode;
@ -46,9 +51,19 @@ private:
QCheckBox *chkAP; QCheckBox *chkAP;
QCheckBox *chkSound; QCheckBox *chkSound;
QGroupBox *grpDemi;
QVBoxLayout *layDemi;
QCheckBox *chkPassages;
QCheckBox *chkPitfalls;
QCheckBox *chkLiteStep;
QCheckBox *chkDash;
QCheckBox *chkLearning;
void btnROM_clicked(bool trigger); void btnROM_clicked(bool trigger);
void btnApply_clicked(bool trigger); void btnApply_clicked(bool trigger);
void applyPatch(QFile *file, QString patch); void applyPatch(QFile *file, QString patch);
void applyDemi(QFile *file);
}; };
#endif #endif