Fixes HP/SP table issues (#6361)

* Fixes #6360.
* Adds missing HP/SP values for Rebellion, Baby Rebellion, Expanded Super Novice, Expanded Super Baby, Baby Summoner, Star Emperor, Baby Star Emperor, Soul Reaper, and Baby Soul Reaper.
* Adds official HP/SP values for Summoner, Baby Summoner, Star Emperor, Baby Star Emperor, Soul Reaper, and Baby Soul Reaper. These are missing levels 176-200 though.
* Fixes the BonusStats parser to properly check for the max job level.
* Adds several logical checks for blocking level 0 during parse.
* Adds several logical checks for skipping content over a job's max level for HP/SP and BEXP/JEXP.
* Fixes the SP values being filled against the max job level instead of base level if the HP/SP Table wasn't being used.
* The parser will now properly fill the HP/SP array with 0's so that the loadingFinished() function can properly calculate a value to insert if something is missing.
* Adds a better solution to CSV2YAML when checking for the max base level when converting HP/SP.
* Fixes the CSV2YAML generating bad job bonus stat conversions.
Thanks to @kaninhot004 and @Lemongrass3110!
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
This commit is contained in:
Aleos 2021-11-22 15:49:28 -05:00 committed by GitHub
parent 9d6a78cf68
commit fe0d445500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1553 additions and 530 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8535,24 +8535,6 @@ Body:
Str: 1
- Level: 50
Dex: 1
- Level: 59
Str: 1
- Level: 63
Str: 1
- Level: 64
Str: 1
- Level: 65
Str: 1
- Level: 66
Str: 1
- Level: 67
Str: 1
- Level: 68
Str: 1
- Level: 69
Str: 1
- Level: 70
Str: 1
- Jobs:
Oboro: true
MaxWeight: 26000
@ -8634,20 +8616,6 @@ Body:
Str: 1
- Level: 50
Dex: 1
- Level: 59
Str: 1
- Level: 63
Agi: 1
- Level: 64
Agi: 1
- Level: 65
Agi: 1
- Level: 66
Int: 1
- Level: 68
Vit: 1
- Level: 70
Vit: 1
- Jobs:
Rebellion: true
MaxWeight: 28000
@ -8812,8 +8780,6 @@ Body:
Agi: 1
- Level: 50
Dex: 1
- Level: 59
Str: 1
- Jobs:
Baby_Summoner: true
HpFactor: 100
@ -8892,8 +8858,6 @@ Body:
Agi: 1
- Level: 50
Dex: 1
- Level: 59
Str: 1
- Jobs:
Baby_Ninja: true
MaxWeight: 26000
@ -9036,18 +9000,6 @@ Body:
Str: 1
- Level: 50
Dex: 1
- Level: 59
Str: 1
- Level: 63
Str: 1
- Level: 64
Str: 1
- Level: 65
Str: 1
- Level: 69
Agi: 1
- Level: 70
Agi: 1
- Jobs:
Baby_Oboro: true
MaxWeight: 26000
@ -9129,20 +9081,6 @@ Body:
Str: 1
- Level: 50
Dex: 1
- Level: 59
Str: 1
- Level: 63
Str: 1
- Level: 64
Str: 1
- Level: 65
Str: 1
- Level: 66
Str: 1
- Level: 67
Str: 1
- Level: 68
Str: 1
- Jobs:
Baby_Taekwon: true
MaxWeight: 28000
@ -9915,108 +9853,3 @@ Body:
Int: 1
- Level: 59
Int: 1
MaxWeight: 28000
HpFactor: 90
HpMultiplicator: 650
SpFactor: 470
BaseASPD:
Fist: 40
Dagger: 50
1hSword: 50
2hSword: 50
1hSpear: 50
2hSpear: 50
1hAxe: 50
2hAxe: 50
Mace: 50
2hMace: 50
Staff: 50
Bow: 50
Knuckle: 50
Musical: 50
Whip: 50
Book: 50
Katar: 50
Revolver: 50
Rifle: 50
Gatling: 50
Shotgun: 50
Grenade: 50
Huuma: 50
2hStaff: 50
Shield: 6
BonusStats:
- Level: 1
Str: 1
- Level: 2
Dex: 1
- Level: 5
Agi: 1
- Level: 7
Int: 1
- Level: 8
Str: 1
- Level: 9
Luk: 1
- Level: 11
Dex: 1
- Level: 12
Str: 1
- Level: 13
Agi: 1
- Level: 15
Int: 1
- Level: 16
Luk: 1
- Level: 17
Vit: 1
- Level: 19
Str: 1
- Level: 20
Dex: 1
- Level: 21
Agi: 1
- Level: 23
Str: 1
- Level: 24
Vit: 1
- Level: 25
Int: 1
- Level: 27
Dex: 1
- Level: 29
Agi: 1
- Level: 30
Dex: 1
- Level: 31
Str: 1
- Level: 34
Dex: 1
- Level: 35
Agi: 1
- Level: 36
Luk: 1
- Level: 37
Vit: 1
- Level: 38
Dex: 1
- Level: 39
Str: 1
- Level: 41
Agi: 1
- Level: 42
Vit: 1
- Level: 43
Str: 1
- Level: 45
Dex: 1
- Level: 47
Agi: 1
- Level: 48
Str: 1
- Level: 50
Dex: 1
- Level: 56
Str: 1
- Level: 59
Agi: 1

View File

@ -12249,9 +12249,22 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
std::shared_ptr<s_job_info> job = job_db.find(static_cast<uint16>(job_id));
bool exists = job != nullptr;
if (!exists)
if (!exists) {
job = std::make_shared<s_job_info>();
job->job_bonus.resize(MAX_LEVEL);
std::fill(job->job_bonus.begin(), job->job_bonus.end(), std::array<uint16, PARAM_MAX> { 0 });
job->base_hp.resize(MAX_LEVEL);
std::fill(job->base_hp.begin(), job->base_hp.end(), 0);
job->base_sp.resize(MAX_LEVEL);
std::fill(job->base_sp.begin(), job->base_sp.end(), 0);
job->base_ap.resize(MAX_LEVEL);
std::fill(job->base_ap.begin(), job->base_ap.end(), 0);
}
if (this->nodeExists(node, "MaxWeight")) {
uint32 weight;
@ -12336,34 +12349,6 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
}
}
if (this->nodeExists(node, "BonusStats")) {
const YAML::Node &bonusNode = node["BonusStats"];
job->job_bonus.resize(MAX_LEVEL);
for (const YAML::Node &levelNode : bonusNode) {
uint16 level;
if (!this->asUInt16(levelNode, "Level", level))
return 0;
if (level > MAX_LEVEL) {
this->invalidWarning(levelNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
for (uint8 idx = PARAM_STR; idx < PARAM_MAX; idx++) {
if (this->nodeExists(levelNode, parameter_names[idx])) {
int16 change;
if (!this->asInt16(levelNode, parameter_names[idx], change))
return 0;
job->job_bonus[level - 1][idx] = change;
}
}
}
}
if (this->nodeExists(node, "MaxStats")) {
const YAML::Node &statNode = node["MaxStats"];
@ -12396,7 +12381,7 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asUInt16(node, "MaxBaseLevel", level))
return 0;
if (level > MAX_LEVEL) {
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(node["MaxBaseLevel"], "MaxBaseLevel must be between 1~MAX_LEVEL for %s, capping to MAX_LEVEL.\n", job_name.c_str());
level = MAX_LEVEL;
}
@ -12414,7 +12399,10 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asUInt16(bexpNode, "Level", level))
return 0;
if (level < 1 || level > MAX_LEVEL) {
if (level > job->max_base_level)
continue;
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(bexpNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
@ -12436,13 +12424,12 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asUInt16(node, "MaxJobLevel", level))
return 0;
if (level > MAX_LEVEL) {
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(node["MaxJobLevel"], "MaxJobLevel must be between 1~MAX_LEVEL for %s, capping to MAX_LEVEL.\n", job_name.c_str());
level = MAX_LEVEL;
}
job->max_job_level = level;
job->job_bonus.resize(level);
} else {
if (!exists)
job->max_job_level = MAX_LEVEL;
@ -12455,7 +12442,10 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asUInt16(jexpNode, "Level", level))
return 0;
if (level < 1 || level > MAX_LEVEL) {
if (level > job->max_job_level)
continue;
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(jexpNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
@ -12471,17 +12461,45 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
}
}
if (this->nodeExists(node, "BonusStats")) {
const YAML::Node &bonusNode = node["BonusStats"];
for (const YAML::Node &levelNode : bonusNode) {
uint16 level;
if (!this->asUInt16(levelNode, "Level", level))
return 0;
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(levelNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
for (uint8 idx = PARAM_STR; idx < PARAM_MAX; idx++) {
if (this->nodeExists(levelNode, parameter_names[idx])) {
int16 change;
if (!this->asInt16(levelNode, parameter_names[idx], change))
return 0;
job->job_bonus[level - 1][idx] = change;
}
}
}
}
#ifdef HP_SP_TABLES
if (this->nodeExists(node, "BaseHp")) {
job->base_hp.resize(job->max_base_level, 1);
for (const YAML::Node &bhpNode : node["BaseHp"]) {
uint16 level;
if (!this->asUInt16(bhpNode, "Level", level))
return 0;
if (level > MAX_LEVEL) {
if (level > job->max_base_level)
continue;
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(bhpNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
@ -12498,15 +12516,16 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
}
if (this->nodeExists(node, "BaseSp")) {
job->base_sp.resize(job->max_base_level, 1);
for (const YAML::Node &bspNode : node["BaseSp"]) {
uint16 level;
if (!this->asUInt16(bspNode, "Level", level))
return 0;
if (level > MAX_LEVEL) {
if (level > job->max_base_level)
continue;
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(bspNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
@ -12523,15 +12542,16 @@ uint64 JobDatabase::parseBodyNode(const YAML::Node &node) {
}
if (this->nodeExists(node, "BaseAp")) {
job->base_ap.resize(job->max_base_level, 1);
for (const YAML::Node &bapNode : node["BaseAp"]) {
uint16 level;
if (!this->asUInt16(bapNode, "Level", level))
return 0;
if (level > MAX_LEVEL) {
if (level > job->max_base_level)
continue;
if (level == 0 || level > MAX_LEVEL) {
this->invalidWarning(bapNode["Level"], "Level must be between 1~MAX_LEVEL for %s.\n", job_name.c_str());
return 0;
}
@ -12575,21 +12595,30 @@ void JobDatabase::loadingFinished() {
ShowWarning("Class %s (%d) does not have a job exp table.\n", job_name(job_id), job_id);
// Init and checking the empty value of Base HP/SP [Cydh]
if (job->base_hp.size() == 0)
if (job->base_hp.empty())
job->base_hp.resize(maxBaseLv);
for (uint16 j = 0; j < maxBaseLv; j++) {
if (job->base_hp[j] == 0)
job->base_hp[j] = pc_calc_basehp(j + 1, job_id);
}
if (job->base_sp.size() == 0)
job->base_sp.resize(maxJobLv);
for (uint16 j = 0; j < maxJobLv; j++) {
if (job->base_sp.empty())
job->base_sp.resize(maxBaseLv);
for (uint16 j = 0; j < maxBaseLv; j++) {
if (job->base_sp[j] == 0)
job->base_sp[j] = pc_calc_basesp(j + 1, job_id);
}
// Resize for the maximum job level
job->job_bonus.resize(maxJobLv);
// Resize to the maximum base level
if (job->base_hp.capacity() > maxBaseLv)
job->base_hp.erase(job->base_hp.begin() + maxBaseLv, job->base_hp.end());
if (job->base_sp.capacity() > maxBaseLv)
job->base_sp.erase(job->base_sp.begin() + maxBaseLv, job->base_sp.end());
if (job->base_ap.capacity() > maxBaseLv)
job->base_ap.erase(job->base_ap.begin() + maxBaseLv, job->base_ap.end());
// Resize to the maximum job level
if (job->job_bonus.capacity() > maxJobLv)
job->job_bonus.erase(job->job_bonus.begin() + maxJobLv, job->job_bonus.end());
for (uint16 parameter = PARAM_STR; parameter < PARAM_MAX; parameter++) {
// Store total

View File

@ -4162,8 +4162,11 @@ static bool read_constdb(char* fields[], int columns, int current) {
static bool pc_readdb_job2(char* fields[], int columns, int current) {
std::vector<int> stats;
stats.resize(MAX_LEVEL);
std::fill(stats.begin(), stats.end(), 0); // Fill with 0 so we don't produce arbitrary stats
for (int i = 1; i < columns; i++)
stats.insert(stats.begin() + i - 1, atoi(fields[i]));
stats[i - 1] = atoi(fields[i]);
job_db2.insert({ atoi(fields[0]), stats });
return true;
@ -4258,17 +4261,25 @@ static bool pc_readdb_job_basehpsp(char* fields[], int columns, int current) {
body << YAML::BeginSeq;
int j = 0, job_id = jobs[0], endlvl = 0;
auto it_level = exp_base_level.find(job_id);
if (it_level != exp_base_level.end())
endlvl = it_level->second;
else {
ShowError("pc_readdb_job_basehpsp: The job_exp database needs to be imported into memory before converting the job_basehpsp_db database.\n");
return false;
// Find the highest level in the group of jobs
for (int i = 0; i < job_count; i++) {
auto it_level = exp_base_level.find(jobs[i]);
int tmplvl;
if (it_level != exp_base_level.end())
tmplvl = it_level->second;
else {
ShowError("pc_readdb_job_basehpsp: The job_exp database needs to be imported into memory before converting the job_basehpsp_db database.\n");
return false;
}
if (endlvl < tmplvl)
endlvl = tmplvl;
}
// These jobs don't have values less than level 99
if ((job_id >= JOB_RUNE_KNIGHT && job_id <= JOB_BABY_MECHANIC2) || job_id == JOB_KAGEROU || job_id == JOB_OBORO || job_id == JOB_REBELLION || job_id == JOB_BABY_KAGEROU || job_id == JOB_BABY_OBORO || job_id == JOB_BABY_REBELLION)
if ((job_id >= JOB_RUNE_KNIGHT && job_id <= JOB_BABY_MECHANIC2) || job_id == JOB_KAGEROU || job_id == JOB_OBORO || job_id == JOB_REBELLION || job_id == JOB_BABY_KAGEROU || job_id == JOB_BABY_OBORO || job_id == JOB_BABY_REBELLION || job_id >= JOB_STAR_EMPEROR)
j = 98;
if (type == 0) { // HP