Add randomizer mode
parent
592261df54
commit
b13975e589
|
@ -18,6 +18,7 @@ body {
|
|||
<ul>
|
||||
<li>Base:<ul>
|
||||
<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/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>
|
||||
|
|
|
@ -3,7 +3,7 @@ enum Job {
|
|||
Pitfalls = 0x02,
|
||||
LiteStep = 0x04,
|
||||
Dash = 0x08,
|
||||
Learning = 0x10
|
||||
ILearning = 0x10
|
||||
};
|
||||
|
||||
const long int job_innates = 0x156138;
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <climits>
|
||||
|
||||
Exdeath::Exdeath(QSettings *cfg, QWidget *parent) : QWidget(parent) {
|
||||
rand = new QRandomGenerator(time(NULL));
|
||||
error = new QErrorMessage();
|
||||
filename = nullptr;
|
||||
_cfg = cfg;
|
||||
|
@ -68,6 +68,7 @@ void Exdeath::initMain(void) {
|
|||
txtPortraits = new QLabel("FFT-style Portraits:");
|
||||
txtSound = new QLabel("Sound Restoration:");
|
||||
txtSound->setToolTip("Requires GBA BIOS if using VisualBoyAdvance");
|
||||
txtSeed = new QLabel("Seed:");
|
||||
txtNED = new QLabel("Neo ExDeath:");
|
||||
|
||||
btnROM = new QPushButton("Select ROM");
|
||||
|
@ -77,6 +78,7 @@ void Exdeath::initMain(void) {
|
|||
|
||||
selMode = new QComboBox();
|
||||
selMode->addItem("Base");
|
||||
selMode->addItem("Randomizer");
|
||||
selMode->addItem("Unlocked Jobs", "unlock.ips");
|
||||
selMode->addItem("Balance", "balance.ips");
|
||||
selMode->addItem("Custom Classes", "custom_classes.ips");
|
||||
|
@ -85,6 +87,11 @@ void Exdeath::initMain(void) {
|
|||
chkPortraits = 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->addItem("Random");
|
||||
selNED->addItem("Vanilla");
|
||||
|
@ -121,9 +128,11 @@ void Exdeath::initMain(void) {
|
|||
layMain->addWidget(chkPortraits, 2, 1);
|
||||
layMain->addWidget(txtSound, 3, 0);
|
||||
layMain->addWidget(chkSound, 3, 1);
|
||||
layMain->addWidget(txtNED, 4, 0);
|
||||
layMain->addWidget(selNED, 4, 1);
|
||||
layMain->addWidget(btnSave, 5, 1);
|
||||
layMain->addWidget(txtSeed, 4, 0);
|
||||
layMain->addWidget(numSeed, 4, 1);
|
||||
layMain->addWidget(txtNED, 5, 0);
|
||||
layMain->addWidget(selNED, 5, 1);
|
||||
layMain->addWidget(btnSave, 6, 1);
|
||||
}
|
||||
|
||||
void Exdeath::initInnates(void) {
|
||||
|
@ -256,8 +265,10 @@ void Exdeath::btnApply_clicked(bool trigger) {
|
|||
);
|
||||
QFile::copy(filename, output);
|
||||
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();
|
||||
}
|
||||
if (chkPortraits->isChecked()) {
|
||||
|
@ -268,10 +279,10 @@ void Exdeath::btnApply_clicked(bool trigger) {
|
|||
}
|
||||
int idx = selNED->currentIndex();
|
||||
if (idx == 0) {
|
||||
idx = rand->bounded(1, selNED->count() - 1);
|
||||
idx = dist(rand);
|
||||
}
|
||||
if ((idx == 1) && (mode == 2)) {
|
||||
error->showMessage("You can't set a custom NED with the Balance patch; it'll break.");
|
||||
if ((idx == 1) && ((mode > 2) && (mode < 5))) {
|
||||
error->showMessage("You can't set a custom NED with this mode; it'll break.");
|
||||
return;
|
||||
}
|
||||
if (idx > 1) {
|
||||
|
@ -303,19 +314,26 @@ void Exdeath::btnApply_clicked(bool trigger) {
|
|||
target->open(QIODevice::ReadWrite);
|
||||
if (patches.size() > 0) {
|
||||
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);
|
||||
}
|
||||
target->close();
|
||||
}
|
||||
|
||||
void Exdeath::applyPatch(QFile *file, QString patch) {
|
||||
QFile *data = new QFile(patch);
|
||||
data->open(QIODevice::ReadOnly);
|
||||
|
||||
void Exdeath::applyPatch(QFile *file, QIODevice *data) {
|
||||
// skipping header
|
||||
data->seek(5);
|
||||
|
||||
|
@ -365,7 +383,7 @@ void Exdeath::applyInnates(QFile *file) {
|
|||
if (chkPitfalls->isChecked()) base |= Job::Pitfalls;
|
||||
if (chkLiteStep->isChecked()) base |= Job::LiteStep;
|
||||
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++) {
|
||||
char temp[2];
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef EXDEATH_HH_GUARD
|
||||
#define EXDEATH_HH_GUARD
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
|
@ -15,13 +17,14 @@
|
|||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QRandomGenerator>
|
||||
#include <QSettings>
|
||||
#include <QSpinBox>
|
||||
#include <QStandardPaths>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "data.hh"
|
||||
#include "randomizer.hh"
|
||||
|
||||
class Exdeath : public QWidget {
|
||||
public:
|
||||
|
@ -31,7 +34,6 @@ public:
|
|||
private:
|
||||
QSettings *_cfg;
|
||||
QString filename;
|
||||
QRandomGenerator *rand;
|
||||
|
||||
QErrorMessage *error;
|
||||
|
||||
|
@ -48,6 +50,7 @@ private:
|
|||
QLabel *txtPortraits;
|
||||
QLabel *txtSound;
|
||||
QLabel *txtNED;
|
||||
QLabel *txtSeed;
|
||||
|
||||
QPushButton *btnROM;
|
||||
QPushButton *btnApply;
|
||||
|
@ -68,6 +71,7 @@ private:
|
|||
QCheckBox *chkLiteStep;
|
||||
QCheckBox *chkDash;
|
||||
QCheckBox *chkLearning;
|
||||
QSpinBox *numSeed;
|
||||
|
||||
QGroupBox *grpMulti;
|
||||
QFormLayout *layMulti;
|
||||
|
@ -88,7 +92,7 @@ private:
|
|||
void btnROM_clicked(bool trigger);
|
||||
void btnApply_clicked(bool trigger);
|
||||
void btnSave_clicked(bool trigger);
|
||||
void applyPatch(QFile *file, QString patch);
|
||||
void applyPatch(QFile *file, QIODevice *Data);
|
||||
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