Add randomizer mode
parent
592261df54
commit
b13975e589
|
@ -18,6 +18,7 @@ body {
|
||||||
<ul>
|
<ul>
|
||||||
<li>Base:<ul>
|
<li>Base:<ul>
|
||||||
<li>None — The base game.</li>
|
<li>None — The base game.</li>
|
||||||
|
<li>Randomizer — Job skills are randomized.</li>
|
||||||
<li><a href="https://www.dropbox.com/s/ldlmpoepxk5nxgl/fiesta.ups?dl=0">Unlocked Jobs</a> — All Jobs are unlocked from the beginning.</li>
|
<li><a href="https://www.dropbox.com/s/ldlmpoepxk5nxgl/fiesta.ups?dl=0">Unlocked Jobs</a> — All Jobs are unlocked from the beginning.</li>
|
||||||
<li><a href="https://www.dropbox.com/s/g52xshu0juaa2c7/ffvamod-doc.txt?dl=0">Balance</a> — A remixed version which adds the Hero Job and changes things up.</li>
|
<li><a href="https://www.dropbox.com/s/g52xshu0juaa2c7/ffvamod-doc.txt?dl=0">Balance</a> — A remixed version which adds the Hero Job and changes things up.</li>
|
||||||
<li><a href="http://jeffludwig.com/ff5a/download.php">Custom Classes</a> — A different remixed version by ludmeister.</li>
|
<li><a href="http://jeffludwig.com/ff5a/download.php">Custom Classes</a> — A different remixed version by ludmeister.</li>
|
||||||
|
|
|
@ -3,7 +3,7 @@ enum Job {
|
||||||
Pitfalls = 0x02,
|
Pitfalls = 0x02,
|
||||||
LiteStep = 0x04,
|
LiteStep = 0x04,
|
||||||
Dash = 0x08,
|
Dash = 0x08,
|
||||||
Learning = 0x10
|
ILearning = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
const long int job_innates = 0x156138;
|
const long int job_innates = 0x156138;
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
Exdeath::Exdeath(QSettings *cfg, QWidget *parent) : QWidget(parent) {
|
Exdeath::Exdeath(QSettings *cfg, QWidget *parent) : QWidget(parent) {
|
||||||
rand = new QRandomGenerator(time(NULL));
|
|
||||||
error = new QErrorMessage();
|
error = new QErrorMessage();
|
||||||
filename = nullptr;
|
filename = nullptr;
|
||||||
_cfg = cfg;
|
_cfg = cfg;
|
||||||
|
@ -68,6 +68,7 @@ void Exdeath::initMain(void) {
|
||||||
txtPortraits = new QLabel("FFT-style Portraits:");
|
txtPortraits = new QLabel("FFT-style Portraits:");
|
||||||
txtSound = new QLabel("Sound Restoration:");
|
txtSound = new QLabel("Sound Restoration:");
|
||||||
txtSound->setToolTip("Requires GBA BIOS if using VisualBoyAdvance");
|
txtSound->setToolTip("Requires GBA BIOS if using VisualBoyAdvance");
|
||||||
|
txtSeed = new QLabel("Seed:");
|
||||||
txtNED = new QLabel("Neo ExDeath:");
|
txtNED = new QLabel("Neo ExDeath:");
|
||||||
|
|
||||||
btnROM = new QPushButton("Select ROM");
|
btnROM = new QPushButton("Select ROM");
|
||||||
|
@ -77,6 +78,7 @@ void Exdeath::initMain(void) {
|
||||||
|
|
||||||
selMode = new QComboBox();
|
selMode = new QComboBox();
|
||||||
selMode->addItem("Base");
|
selMode->addItem("Base");
|
||||||
|
selMode->addItem("Randomizer");
|
||||||
selMode->addItem("Unlocked Jobs", "unlock.ips");
|
selMode->addItem("Unlocked Jobs", "unlock.ips");
|
||||||
selMode->addItem("Balance", "balance.ips");
|
selMode->addItem("Balance", "balance.ips");
|
||||||
selMode->addItem("Custom Classes", "custom_classes.ips");
|
selMode->addItem("Custom Classes", "custom_classes.ips");
|
||||||
|
@ -85,6 +87,11 @@ void Exdeath::initMain(void) {
|
||||||
chkPortraits = new QCheckBox("Yes");
|
chkPortraits = new QCheckBox("Yes");
|
||||||
chkSound = new QCheckBox("Yes");
|
chkSound = new QCheckBox("Yes");
|
||||||
|
|
||||||
|
numSeed = new QSpinBox();
|
||||||
|
numSeed->setRange(0, INT_MAX);
|
||||||
|
// provide a default value so it's not just 0 all the time
|
||||||
|
numSeed->setValue(time(NULL) / 3600);
|
||||||
|
|
||||||
selNED = new QComboBox();
|
selNED = new QComboBox();
|
||||||
selNED->addItem("Random");
|
selNED->addItem("Random");
|
||||||
selNED->addItem("Vanilla");
|
selNED->addItem("Vanilla");
|
||||||
|
@ -121,9 +128,11 @@ void Exdeath::initMain(void) {
|
||||||
layMain->addWidget(chkPortraits, 2, 1);
|
layMain->addWidget(chkPortraits, 2, 1);
|
||||||
layMain->addWidget(txtSound, 3, 0);
|
layMain->addWidget(txtSound, 3, 0);
|
||||||
layMain->addWidget(chkSound, 3, 1);
|
layMain->addWidget(chkSound, 3, 1);
|
||||||
layMain->addWidget(txtNED, 4, 0);
|
layMain->addWidget(txtSeed, 4, 0);
|
||||||
layMain->addWidget(selNED, 4, 1);
|
layMain->addWidget(numSeed, 4, 1);
|
||||||
layMain->addWidget(btnSave, 5, 1);
|
layMain->addWidget(txtNED, 5, 0);
|
||||||
|
layMain->addWidget(selNED, 5, 1);
|
||||||
|
layMain->addWidget(btnSave, 6, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exdeath::initInnates(void) {
|
void Exdeath::initInnates(void) {
|
||||||
|
@ -256,8 +265,10 @@ void Exdeath::btnApply_clicked(bool trigger) {
|
||||||
);
|
);
|
||||||
QFile::copy(filename, output);
|
QFile::copy(filename, output);
|
||||||
int mode = selMode->currentIndex();
|
int mode = selMode->currentIndex();
|
||||||
|
std::mt19937 rand(numSeed->value());
|
||||||
|
std::uniform_int_distribution<> dist(1, selNED->count() - 1);
|
||||||
|
|
||||||
if (mode > 0) {
|
if (mode > 1) {
|
||||||
patches << ":/patches/" + selMode->itemData(mode).toString();
|
patches << ":/patches/" + selMode->itemData(mode).toString();
|
||||||
}
|
}
|
||||||
if (chkPortraits->isChecked()) {
|
if (chkPortraits->isChecked()) {
|
||||||
|
@ -268,10 +279,10 @@ void Exdeath::btnApply_clicked(bool trigger) {
|
||||||
}
|
}
|
||||||
int idx = selNED->currentIndex();
|
int idx = selNED->currentIndex();
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
idx = rand->bounded(1, selNED->count() - 1);
|
idx = dist(rand);
|
||||||
}
|
}
|
||||||
if ((idx == 1) && (mode == 2)) {
|
if ((idx == 1) && ((mode > 2) && (mode < 5))) {
|
||||||
error->showMessage("You can't set a custom NED with the Balance patch; it'll break.");
|
error->showMessage("You can't set a custom NED with this mode; it'll break.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (idx > 1) {
|
if (idx > 1) {
|
||||||
|
@ -303,19 +314,26 @@ void Exdeath::btnApply_clicked(bool trigger) {
|
||||||
target->open(QIODevice::ReadWrite);
|
target->open(QIODevice::ReadWrite);
|
||||||
if (patches.size() > 0) {
|
if (patches.size() > 0) {
|
||||||
for (int i = 0; i < patches.size(); i++) {
|
for (int i = 0; i < patches.size(); i++) {
|
||||||
applyPatch(target, patches[i]);
|
QFile *patch = new QFile(patches[i]);
|
||||||
|
patch->open(QIODevice::ReadOnly);
|
||||||
|
applyPatch(target, patch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chkPassages->isChecked() || chkPitfalls->isChecked() || chkLiteStep->isChecked() || chkDash->isChecked() || chkLearning->isChecked()) {
|
|
||||||
|
bool global_innates = (chkPassages->isChecked() || chkPitfalls->isChecked() || chkLiteStep->isChecked() || chkDash->isChecked() || chkLearning->isChecked());
|
||||||
|
// gyahahaha RANDOMIZER!!
|
||||||
|
if (mode == 1) {
|
||||||
|
Randomizer *rando = new Randomizer(rand);
|
||||||
|
QBuffer *patch = rando->makeRandom(global_innates);
|
||||||
|
applyPatch(target, patch);
|
||||||
|
}
|
||||||
|
if (global_innates) {
|
||||||
applyInnates(target);
|
applyInnates(target);
|
||||||
}
|
}
|
||||||
target->close();
|
target->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exdeath::applyPatch(QFile *file, QString patch) {
|
void Exdeath::applyPatch(QFile *file, QIODevice *data) {
|
||||||
QFile *data = new QFile(patch);
|
|
||||||
data->open(QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
// skipping header
|
// skipping header
|
||||||
data->seek(5);
|
data->seek(5);
|
||||||
|
|
||||||
|
@ -365,7 +383,7 @@ void Exdeath::applyInnates(QFile *file) {
|
||||||
if (chkPitfalls->isChecked()) base |= Job::Pitfalls;
|
if (chkPitfalls->isChecked()) base |= Job::Pitfalls;
|
||||||
if (chkLiteStep->isChecked()) base |= Job::LiteStep;
|
if (chkLiteStep->isChecked()) base |= Job::LiteStep;
|
||||||
if (chkDash->isChecked()) base |= Job::Dash;
|
if (chkDash->isChecked()) base |= Job::Dash;
|
||||||
if (chkLearning->isChecked()) base |= Job::Learning;
|
if (chkLearning->isChecked()) base |= Job::ILearning;
|
||||||
|
|
||||||
for (int i = 0; i < 26; i++) {
|
for (int i = 0; i < 26; i++) {
|
||||||
char temp[2];
|
char temp[2];
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef EXDEATH_HH_GUARD
|
#ifndef EXDEATH_HH_GUARD
|
||||||
#define EXDEATH_HH_GUARD
|
#define EXDEATH_HH_GUARD
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
@ -15,13 +17,14 @@
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QRandomGenerator>
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QSpinBox>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "data.hh"
|
#include "data.hh"
|
||||||
|
#include "randomizer.hh"
|
||||||
|
|
||||||
class Exdeath : public QWidget {
|
class Exdeath : public QWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -31,7 +34,6 @@ public:
|
||||||
private:
|
private:
|
||||||
QSettings *_cfg;
|
QSettings *_cfg;
|
||||||
QString filename;
|
QString filename;
|
||||||
QRandomGenerator *rand;
|
|
||||||
|
|
||||||
QErrorMessage *error;
|
QErrorMessage *error;
|
||||||
|
|
||||||
|
@ -48,6 +50,7 @@ private:
|
||||||
QLabel *txtPortraits;
|
QLabel *txtPortraits;
|
||||||
QLabel *txtSound;
|
QLabel *txtSound;
|
||||||
QLabel *txtNED;
|
QLabel *txtNED;
|
||||||
|
QLabel *txtSeed;
|
||||||
|
|
||||||
QPushButton *btnROM;
|
QPushButton *btnROM;
|
||||||
QPushButton *btnApply;
|
QPushButton *btnApply;
|
||||||
|
@ -68,6 +71,7 @@ private:
|
||||||
QCheckBox *chkLiteStep;
|
QCheckBox *chkLiteStep;
|
||||||
QCheckBox *chkDash;
|
QCheckBox *chkDash;
|
||||||
QCheckBox *chkLearning;
|
QCheckBox *chkLearning;
|
||||||
|
QSpinBox *numSeed;
|
||||||
|
|
||||||
QGroupBox *grpMulti;
|
QGroupBox *grpMulti;
|
||||||
QFormLayout *layMulti;
|
QFormLayout *layMulti;
|
||||||
|
@ -88,7 +92,7 @@ private:
|
||||||
void btnROM_clicked(bool trigger);
|
void btnROM_clicked(bool trigger);
|
||||||
void btnApply_clicked(bool trigger);
|
void btnApply_clicked(bool trigger);
|
||||||
void btnSave_clicked(bool trigger);
|
void btnSave_clicked(bool trigger);
|
||||||
void applyPatch(QFile *file, QString patch);
|
void applyPatch(QFile *file, QIODevice *Data);
|
||||||
void applyInnates(QFile *file);
|
void applyInnates(QFile *file);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum Skill {
|
||||||
|
// Action skills
|
||||||
|
Guard = 0x06,
|
||||||
|
Kick = 0x07,
|
||||||
|
Focus = 0x08,
|
||||||
|
Chakra = 0x09,
|
||||||
|
Flee = 0x0A,
|
||||||
|
Steal = 0x0B,
|
||||||
|
Mug = 0x0C,
|
||||||
|
Jump = 0x0D,
|
||||||
|
Lancet = 0x0E,
|
||||||
|
Smoke = 0x0F,
|
||||||
|
Image = 0x10,
|
||||||
|
Throw = 0x11,
|
||||||
|
Mineuchi = 0x12,
|
||||||
|
GilToss = 0x13,
|
||||||
|
Iainuki = 0x14,
|
||||||
|
Animals = 0x15,
|
||||||
|
Aim = 0x16,
|
||||||
|
RapidFire = 0x17,
|
||||||
|
Call = 0x18,
|
||||||
|
Check = 0x19,
|
||||||
|
Scan = 0x1A,
|
||||||
|
Calm = 0x1B,
|
||||||
|
Control = 0x1C,
|
||||||
|
Catch = 0x1D,
|
||||||
|
Mix = 0x1F,
|
||||||
|
Drink = 0x20,
|
||||||
|
Recover = 0x21,
|
||||||
|
Revive = 0x22,
|
||||||
|
Gaia = 0x23,
|
||||||
|
Hide = 0x25,
|
||||||
|
Sing = 0x28,
|
||||||
|
Flirt = 0x29,
|
||||||
|
Dance = 0x2A,
|
||||||
|
DualCast = 0x4C,
|
||||||
|
Blue = 0x4D,
|
||||||
|
|
||||||
|
// Magic-tier Action skills
|
||||||
|
Spellblade1 = 0x2C,
|
||||||
|
Spellblade2 = 0x2D,
|
||||||
|
Spellblade3 = 0x2E,
|
||||||
|
Spellblade4 = 0x2F,
|
||||||
|
Spellblade5 = 0x30,
|
||||||
|
Spellblade6 = 0x31,
|
||||||
|
White1 = 0x32,
|
||||||
|
White2 = 0x33,
|
||||||
|
White3 = 0x34,
|
||||||
|
White4 = 0x35,
|
||||||
|
White5 = 0x36,
|
||||||
|
White6 = 0x37,
|
||||||
|
Black1 = 0x38,
|
||||||
|
Black2 = 0x39,
|
||||||
|
Black3 = 0x3A,
|
||||||
|
Black4 = 0x3B,
|
||||||
|
Black5 = 0x3C,
|
||||||
|
Black6 = 0x3D,
|
||||||
|
Time1 = 0x3E,
|
||||||
|
Time2 = 0x3F,
|
||||||
|
Time3 = 0x40,
|
||||||
|
Time4 = 0x41,
|
||||||
|
Time5 = 0x42,
|
||||||
|
Time6 = 0x43,
|
||||||
|
Summon1 = 0x44,
|
||||||
|
Summon2 = 0x45,
|
||||||
|
Summon3 = 0x46,
|
||||||
|
Summon4 = 0x47,
|
||||||
|
Summon5 = 0x48,
|
||||||
|
Red1 = 0x49,
|
||||||
|
Red2 = 0x4A,
|
||||||
|
Red3 = 0x4B,
|
||||||
|
|
||||||
|
// Passive/innate skills
|
||||||
|
EquipShield = 0x80,
|
||||||
|
EquipArmor = 0x81,
|
||||||
|
EquipRibbon = 0x82,
|
||||||
|
EquipSword = 0x83,
|
||||||
|
EquipSpear = 0x84,
|
||||||
|
EquipKatana = 0x85,
|
||||||
|
EquipAxe = 0x86,
|
||||||
|
EquipBow = 0x87,
|
||||||
|
EquipWhip = 0x88,
|
||||||
|
EquipHarp = 0x89,
|
||||||
|
ArtfulDodger = 0x8A,
|
||||||
|
HP10 = 0x8B,
|
||||||
|
HP20 = 0x8C,
|
||||||
|
HP30 = 0x8D,
|
||||||
|
MP10 = 0x8E,
|
||||||
|
MP30 = 0x8F,
|
||||||
|
Barehanded = 0x90,
|
||||||
|
TwoHanded = 0x91,
|
||||||
|
DualWield = 0x92,
|
||||||
|
Pharmacology = 0x93,
|
||||||
|
Cover = 0x94,
|
||||||
|
Counter = 0x95,
|
||||||
|
Shirahadori = 0x96,
|
||||||
|
Learning = 0x97,
|
||||||
|
MagicShield = 0x98,
|
||||||
|
Berserk = 0x99,
|
||||||
|
Vigilance = 0x9A,
|
||||||
|
FirstStrike = 0x9B,
|
||||||
|
FindPassages = 0x9C,
|
||||||
|
LightStep = 0x9D,
|
||||||
|
FindPits = 0x9E,
|
||||||
|
EquipRods = 0x9F,
|
||||||
|
Sprint = 0xA0
|
||||||
|
};
|
||||||
|
|
||||||
|
#define JOB_COUNT 20
|
||||||
|
|
||||||
|
const int tier1_jobs[] = {9, 10, 11, 12, 16, 17, 18};
|
||||||
|
const int tier2_jobs[] = {2, 13, 14, 13, 1, 19};
|
||||||
|
const int tier3_jobs[] = {0, 3, 4, 5, 8, 7, 15};
|
|
@ -0,0 +1,400 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Sheila Aman.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the software nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "randomizer.hh"
|
||||||
|
|
||||||
|
Randomizer::Randomizer(std::mt19937 rand) {
|
||||||
|
rng = rand;
|
||||||
|
}
|
||||||
|
Randomizer::~Randomizer() {}
|
||||||
|
|
||||||
|
QByteArray Randomizer::int2byte(int num) {
|
||||||
|
QByteArray temp;
|
||||||
|
temp.append(num & 0xFF);
|
||||||
|
temp.append((num >> 8) & 0xFF);
|
||||||
|
temp.append((num >> 16) & 0xFF);
|
||||||
|
temp.append((num >> 24) & 0xFF);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::uniform_int_distribution<> dist_13(1, 3);
|
||||||
|
static std::uniform_int_distribution<> dist_14(1, 4);
|
||||||
|
static std::uniform_int_distribution<> dist_15(1, 5);
|
||||||
|
static std::uniform_int_distribution<> dist_16(1, 6);
|
||||||
|
static std::uniform_int_distribution<> dist_17(1, 7);
|
||||||
|
static std::uniform_int_distribution<> dist_1x(1, 10);
|
||||||
|
|
||||||
|
int Randomizer::tierCost(int tier, int minimum) {
|
||||||
|
int guess;
|
||||||
|
switch (tier) {
|
||||||
|
case 0:
|
||||||
|
guess = (1 + dist_15(rng)) * 5;
|
||||||
|
if ((guess <= (minimum + 10)) && (minimum != 0)) {
|
||||||
|
return minimum + (1 + dist_13(rng)) * 5;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
guess = (8 + dist_17(rng)) * 5;
|
||||||
|
if ((guess <= (minimum + 15)) && (minimum != 0)) {
|
||||||
|
return minimum + (2 + dist_13(rng)) * 5;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
guess = (15 + dist_15(rng)) * 5;
|
||||||
|
if ((guess <= (minimum + 25)) && (minimum != 0)) {
|
||||||
|
return minimum + (4 + dist_16(rng)) * 5;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
guess = (14 + dist_15(rng)) * 10;
|
||||||
|
if ((guess <= (minimum + 40)) && (minimum != 0)) {
|
||||||
|
return minimum + (3 + dist_13(rng)) * 10;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
guess = (24 + dist_16(rng)) * 10;
|
||||||
|
if ((guess <= (minimum + 50)) && (minimum != 0)) {
|
||||||
|
return minimum + (4 + dist_16(rng)) * 10;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
guess = (14 + dist_16(rng)) + (19 + dist_16(rng));
|
||||||
|
guess *= 10;
|
||||||
|
if (guess <= (minimum + 100)) {
|
||||||
|
return minimum + (10 + dist_1x(rng)) * 10;
|
||||||
|
}
|
||||||
|
return guess;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return minimum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Randomizer::setupData(bool global_innates) {
|
||||||
|
magic1 = new QVector<Skill>({
|
||||||
|
Spellblade1,
|
||||||
|
White1,
|
||||||
|
Black1,
|
||||||
|
Time1,
|
||||||
|
Red1,
|
||||||
|
Summon1
|
||||||
|
});
|
||||||
|
|
||||||
|
magic2 = new QVector<Skill>({
|
||||||
|
Spellblade2,
|
||||||
|
White2,
|
||||||
|
Black2,
|
||||||
|
Time2,
|
||||||
|
Red2,
|
||||||
|
Summon2
|
||||||
|
});
|
||||||
|
|
||||||
|
magic3 = new QVector<Skill>({
|
||||||
|
Spellblade3,
|
||||||
|
White3,
|
||||||
|
Black3,
|
||||||
|
Time3,
|
||||||
|
Red3,
|
||||||
|
Summon3
|
||||||
|
});
|
||||||
|
|
||||||
|
magic4 = new QVector<Skill>({
|
||||||
|
Spellblade4,
|
||||||
|
White4,
|
||||||
|
Black4,
|
||||||
|
Time4
|
||||||
|
});
|
||||||
|
|
||||||
|
magic5 = new QVector<Skill>({
|
||||||
|
Spellblade5,
|
||||||
|
White5,
|
||||||
|
Black5,
|
||||||
|
Time5,
|
||||||
|
Summon4
|
||||||
|
});
|
||||||
|
|
||||||
|
magic6 = new QVector<Skill>({
|
||||||
|
Spellblade6,
|
||||||
|
White6,
|
||||||
|
Black6,
|
||||||
|
Time6,
|
||||||
|
Summon5
|
||||||
|
});
|
||||||
|
|
||||||
|
action1 = new QVector<Skill>({
|
||||||
|
Guard,
|
||||||
|
Kick,
|
||||||
|
Chakra,
|
||||||
|
Lancet,
|
||||||
|
Image,
|
||||||
|
Mineuchi,
|
||||||
|
Aim,
|
||||||
|
Check,
|
||||||
|
Calm,
|
||||||
|
Recover,
|
||||||
|
Hide,
|
||||||
|
Flirt,
|
||||||
|
Scan
|
||||||
|
});
|
||||||
|
action2 = new QVector<Skill>({
|
||||||
|
Steal,
|
||||||
|
Jump,
|
||||||
|
Focus,
|
||||||
|
Smoke,
|
||||||
|
Flee,
|
||||||
|
Gaia,
|
||||||
|
Dance,
|
||||||
|
Blue,
|
||||||
|
Revive,
|
||||||
|
Animals,
|
||||||
|
Catch,
|
||||||
|
Sing,
|
||||||
|
Call
|
||||||
|
});
|
||||||
|
action3 = new QVector<Skill>({
|
||||||
|
Throw,
|
||||||
|
GilToss,
|
||||||
|
Iainuki,
|
||||||
|
RapidFire,
|
||||||
|
Control,
|
||||||
|
Mix,
|
||||||
|
Drink,
|
||||||
|
DualCast
|
||||||
|
});
|
||||||
|
passive1 = new QVector<Skill>({
|
||||||
|
HP10,
|
||||||
|
MP10,
|
||||||
|
Pharmacology,
|
||||||
|
Cover,
|
||||||
|
Counter,
|
||||||
|
Learning,
|
||||||
|
MagicShield,
|
||||||
|
Berserk,
|
||||||
|
FindPassages,
|
||||||
|
LightStep,
|
||||||
|
FindPits,
|
||||||
|
Sprint
|
||||||
|
});
|
||||||
|
passive2 = new QVector<Skill>({
|
||||||
|
EquipSpear,
|
||||||
|
EquipArmor,
|
||||||
|
EquipBow,
|
||||||
|
EquipKatana,
|
||||||
|
MP30,
|
||||||
|
HP20,
|
||||||
|
Barehanded,
|
||||||
|
Shirahadori,
|
||||||
|
Vigilance,
|
||||||
|
FirstStrike
|
||||||
|
});
|
||||||
|
passive3 = new QVector<Skill>({
|
||||||
|
EquipRods,
|
||||||
|
TwoHanded,
|
||||||
|
HP30,
|
||||||
|
EquipAxe,
|
||||||
|
EquipRibbon,
|
||||||
|
EquipSword,
|
||||||
|
ArtfulDodger,
|
||||||
|
EquipHarp,
|
||||||
|
EquipWhip,
|
||||||
|
EquipShield
|
||||||
|
});
|
||||||
|
field = new QVector<Skill>({
|
||||||
|
HP10,
|
||||||
|
MP10,
|
||||||
|
Pharmacology,
|
||||||
|
Cover,
|
||||||
|
Counter,
|
||||||
|
MagicShield,
|
||||||
|
Berserk
|
||||||
|
});
|
||||||
|
if (!global_innates) {
|
||||||
|
passive1->append(*field);
|
||||||
|
}
|
||||||
|
|
||||||
|
tier1 = new QVector<Skill>(*magic1 + *passive1);
|
||||||
|
tier2 = new QVector<Skill>(*magic2 + *action1);
|
||||||
|
tier3 = new QVector<Skill>(*magic3 + *passive2);
|
||||||
|
tier4 = new QVector<Skill>(*magic4 + *action2);
|
||||||
|
tier5 = new QVector<Skill>(*magic5 + *passive3);
|
||||||
|
tier6 = new QVector<Skill>(*magic6 + *action3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Randomizer::randomizeSkills(void) {
|
||||||
|
QVector<Skill> *l_tier1 = new QVector<Skill>(*tier1);
|
||||||
|
QVector<Skill> *l_tier2 = new QVector<Skill>(*tier2);
|
||||||
|
QVector<Skill> *l_tier3 = new QVector<Skill>(*tier3);
|
||||||
|
QVector<Skill> *l_tier4 = new QVector<Skill>(*tier4);
|
||||||
|
QVector<Skill> *l_tier5 = new QVector<Skill>(*tier5);
|
||||||
|
QVector<Skill> *l_tier6 = new QVector<Skill>(*tier6);
|
||||||
|
QVector<int> *jobs1 = new QVector<int>(*tier1_jobs);
|
||||||
|
QVector<int> *jobs2 = new QVector<int>(*tier2_jobs);
|
||||||
|
QVector<int> *jobs3 = new QVector<int>(*tier3_jobs);
|
||||||
|
actions = new QVector<Skill>(*l_tier6);
|
||||||
|
QVector<Skill> *skills[6];
|
||||||
|
commands = new QVector<Skill>(JOB_COUNT);
|
||||||
|
int tierpos = 0;
|
||||||
|
|
||||||
|
std::shuffle(l_tier1->begin(), l_tier1->end(), rng);
|
||||||
|
std::shuffle(l_tier2->begin(), l_tier2->end(), rng);
|
||||||
|
std::shuffle(l_tier3->begin(), l_tier3->end(), rng);
|
||||||
|
std::shuffle(l_tier4->begin(), l_tier4->end(), rng);
|
||||||
|
std::shuffle(l_tier5->begin(), l_tier5->end(), rng);
|
||||||
|
std::shuffle(l_tier6->begin(), l_tier6->end(), rng);
|
||||||
|
|
||||||
|
skills[0] = new QVector<Skill>(*l_tier1);
|
||||||
|
skills[1] = new QVector<Skill>(*l_tier2);
|
||||||
|
skills[2] = new QVector<Skill>(*l_tier3);
|
||||||
|
skills[3] = new QVector<Skill>(*l_tier4);
|
||||||
|
skills[4] = new QVector<Skill>(*l_tier5);
|
||||||
|
skills[5] = new QVector<Skill>(*l_tier6);
|
||||||
|
std::shuffle(l_tier6->begin(), l_tier6->end(), rng);
|
||||||
|
std::shuffle(l_tier4->begin(), l_tier4->end(), rng);
|
||||||
|
std::shuffle(l_tier2->begin(), l_tier2->end(), rng);
|
||||||
|
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
jobs[i] = new QVector<Skill>();
|
||||||
|
costs[i] = new QVector<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (tierpos < 6) {
|
||||||
|
if (skills[tierpos]->count() < 1) {
|
||||||
|
tierpos += 1;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < JOB_COUNT; i++) {
|
||||||
|
Skill temp = skills[i]->first();
|
||||||
|
int minimum = 0;
|
||||||
|
if (costs[i]->count() > 0) {
|
||||||
|
minimum = costs[i]->last();
|
||||||
|
}
|
||||||
|
skills[i]->removeFirst();
|
||||||
|
jobs[i]->append(temp);
|
||||||
|
costs[i]->append(tierCost(tierpos, minimum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shuffle(jobs1->begin(), jobs1->end(), rng);
|
||||||
|
std::shuffle(jobs2->begin(), jobs2->end(), rng);
|
||||||
|
std::shuffle(jobs3->begin(), jobs3->end(), rng);
|
||||||
|
|
||||||
|
commands->insert(6, Berserk);
|
||||||
|
for (int i = 0; i < jobs1->count(); i++) {
|
||||||
|
int job = jobs1->at(i);
|
||||||
|
Skill temp = actions->first();
|
||||||
|
actions->removeFirst();
|
||||||
|
commands->insert(job, temp);
|
||||||
|
}
|
||||||
|
actions->append(*l_tier4);
|
||||||
|
for (int i = 0; i < jobs2->count(); i++) {
|
||||||
|
int job = jobs2->at(i);
|
||||||
|
Skill temp = actions->first();
|
||||||
|
actions->removeFirst();
|
||||||
|
commands->insert(job, temp);
|
||||||
|
}
|
||||||
|
actions->append(*l_tier2);
|
||||||
|
for (int i = 0; i < jobs3->count(); i++) {
|
||||||
|
int job = jobs3->at(i);
|
||||||
|
Skill temp = actions->first();
|
||||||
|
actions->removeFirst();
|
||||||
|
commands->insert(job, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray be24(int num) {
|
||||||
|
QByteArray temp;
|
||||||
|
temp.append((num >> 16) & 0xFF);
|
||||||
|
temp.append((num >> 8) & 0xFF);
|
||||||
|
temp.append(num & 0xFF);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
QBuffer *Randomizer::writePatch(void) {
|
||||||
|
QBuffer *patch = new QBuffer();
|
||||||
|
patch->write("PATCH");
|
||||||
|
|
||||||
|
// job commands
|
||||||
|
for (int i = 0; i < JOB_COUNT; i++) {
|
||||||
|
// skip berserker
|
||||||
|
if (i == 6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
patch->write(be24(0x15616c + (i * 4) + 1));
|
||||||
|
patch->write("\x00\x01");
|
||||||
|
QByteArray temp;
|
||||||
|
temp.append(commands->at(i) & 0xFF);
|
||||||
|
patch->write(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ability counts
|
||||||
|
patch->write(be24(0x14b1fc));
|
||||||
|
patch->write("\x00\x14");
|
||||||
|
for (int i = 0; i < JOB_COUNT; i++) {
|
||||||
|
char count = jobs[i]->count();
|
||||||
|
patch->putChar(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// table offset
|
||||||
|
patch->write(be24(0x155484));
|
||||||
|
patch->write("\x00\x50");
|
||||||
|
for (int i = 0; i < JOB_COUNT; i++) {
|
||||||
|
patch->write("\xe8\x54\x15\x08");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ability lists
|
||||||
|
patch->write(be24(0x1554E8));
|
||||||
|
patch->write("\x00\x50");
|
||||||
|
for (int i = 0; i < JOB_COUNT; i++) {
|
||||||
|
QVector<Skill> *job = jobs[i];
|
||||||
|
char count = job->count();
|
||||||
|
for (int j = 0; j < count; j++) {
|
||||||
|
QByteArray data;
|
||||||
|
int cost = costs[i]->at(j);
|
||||||
|
|
||||||
|
// cost
|
||||||
|
data.append(cost & 0xFF);
|
||||||
|
data.append((cost >> 8) & 0xFF);
|
||||||
|
// skill
|
||||||
|
data.append(job->at(j) & 0xFF);
|
||||||
|
data.append((char)0);
|
||||||
|
patch->write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QBuffer *Randomizer::makeRandom(bool global_innates) {
|
||||||
|
setupData(global_innates);
|
||||||
|
randomizeSkills();
|
||||||
|
return writePatch();
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "randodata.hh"
|
||||||
|
|
||||||
|
class Randomizer {
|
||||||
|
public:
|
||||||
|
Randomizer(std::mt19937 rand);
|
||||||
|
~Randomizer();
|
||||||
|
|
||||||
|
QBuffer *makeRandom(bool global_innates = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mt19937 rng;
|
||||||
|
|
||||||
|
QVector<Skill> *magic1;
|
||||||
|
QVector<Skill> *magic2;
|
||||||
|
QVector<Skill> *magic3;
|
||||||
|
QVector<Skill> *magic4;
|
||||||
|
QVector<Skill> *magic5;
|
||||||
|
QVector<Skill> *magic6;
|
||||||
|
QVector<Skill> *action1;
|
||||||
|
QVector<Skill> *action2;
|
||||||
|
QVector<Skill> *action3;
|
||||||
|
QVector<Skill> *passive1;
|
||||||
|
QVector<Skill> *passive2;
|
||||||
|
QVector<Skill> *passive3;
|
||||||
|
// field passives; to be added to passive1 if they're not going to
|
||||||
|
// be assigned globally.
|
||||||
|
QVector<Skill> *field;
|
||||||
|
|
||||||
|
QVector<Skill> *tier1;
|
||||||
|
QVector<Skill> *tier2;
|
||||||
|
QVector<Skill> *tier3;
|
||||||
|
QVector<Skill> *tier4;
|
||||||
|
QVector<Skill> *tier5;
|
||||||
|
QVector<Skill> *tier6;
|
||||||
|
|
||||||
|
// final results
|
||||||
|
QVector<Skill> *jobs[JOB_COUNT];
|
||||||
|
QVector<int> *costs[JOB_COUNT];
|
||||||
|
QVector<Skill> *commands;
|
||||||
|
QVector<Skill> *actions;
|
||||||
|
|
||||||
|
QByteArray int2byte(int num);
|
||||||
|
void setupData(bool global_innates = false);
|
||||||
|
int tierCost(int tier, int minimum);
|
||||||
|
void randomizeSkills(void);
|
||||||
|
QBuffer *writePatch(void);
|
||||||
|
};
|
Loading…
Reference in New Issue