Merge upstream newserv master

This commit is contained in:
2026-05-09 01:02:34 -04:00
71 changed files with 17519 additions and 495 deletions
+1 -1
View File
@@ -486,7 +486,7 @@ void ItemData::encode_for_version(Version to_version, shared_ptr<const ItemParam
if (should_encode_v2_data && (this->data1[1] > 0x26)) {
if (this->data1[1] < 0x89) {
this->data1[5] = this->data1[1];
this->data1[1] = item_parameter_table->get_weapon_class(this->data1[1]);
this->data1[1] = item_parameter_table->get_weapon_kind(this->data1[1]);
if (this->data1[1] == 0x00) {
this->data1[1] = 0x0F;
}
+195 -11
View File
@@ -1,5 +1,7 @@
#include "ItemNameIndex.hh"
#include <algorithm>
#include "StaticGameData.hh"
using namespace std;
@@ -787,9 +789,9 @@ void ItemNameIndex::print_table(FILE* stream) const {
auto pmt = this->item_parameter_table;
phosg::fwrite_fmt(stream, "WEAPONS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS FLAG ATPLO ATPHI ATPRQ MSTRQ ATARQ -MST- GND PH SP ATA SB(S1:AMT1,S2:AMT2) PJ 1X 1Y 2X 2Y CR --A1-- A4 A5 TB BF CL ST* USL ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS FLAG ATPLO ATPHI ATPRQ MSTRQ ATARQ -MST- GND PH SP ATA SB(S1:AMT1,S2:AMT2) PJ 1X 1Y 2X 2Y CR --A1-- A4 A5 TB(TN:FL:AMOUNT, ... ) BF CL ST* USL ---DIVISOR--- NAME\n");
for (size_t data1_1 = 0; data1_1 < pmt->num_weapon_classes(); data1_1++) {
uint8_t weapon_class = pmt->get_weapon_class(data1_1);
uint8_t weapon_class = pmt->get_weapon_kind(data1_1);
float sale_divisor = pmt->get_sale_divisor(0x00, data1_1);
string divisor_str = std::format("{:g}", sale_divisor);
divisor_str.resize(13, ' ');
@@ -806,8 +808,24 @@ void ItemNameIndex::print_table(FILE* stream) const {
item.data1[2] = data1_2;
string name = this->describe_item(item);
auto& stat_boost = pmt->get_stat_boost(w.stat_boost_entry_index);
phosg::fwrite_fmt(stream, " 00{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:04X} {:5} {:5} {:5} {:5} {:5} {:5} {:3} {:02X} {:02X} {:3} {:02X}({:02X}:{:04X},{:02X}:{:04X}) {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X}{:02X}{:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:2}* {} {} {}\n",
const auto& stat_boost = pmt->get_stat_boost(w.stat_boost_entry_index);
string tech_boost_str;
if (w.tech_boost_entry_index < pmt->num_tech_boosts()) {
const auto& tech_boost = pmt->get_tech_boost(w.tech_boost_entry_index);
tech_boost_str = std::format("({:02X}:{:02X}:{:g},{:02X}:{:02X}:{:g},{:02X}:{:02X}:{:g})",
tech_boost.tech_num1, tech_boost.flags1, tech_boost.amount1, tech_boost.tech_num2, tech_boost.flags2,
tech_boost.amount2, tech_boost.tech_num3, tech_boost.flags3, tech_boost.amount3);
}
tech_boost_str.resize(40, ' ');
phosg::fwrite_fmt(stream,
// CODE => ID TYPE SKIN PTS FLAG ATP- ATP+ ATPR MSTR ATAR MST GND PH SP ATA
" 00{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:04X} {:5} {:5} {:5} {:5} {:5} {:5} {:3} {:02X} {:02X} {:3} "
// SB( S1:AMT1 , S2:AMT2 ) PJ 1X 1Y 2X 2Y CR --------A1-------- A4
"{:02X}({:02X}:{:04X},{:02X}:{:04X}) {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X}{:02X}{:02X} {:02X} "
// A5 TB( TN: FL: AMT, TN: FL: AMT, TN: FL: AMT) BF CL ST* US DV NAME\n"
"{:02X} {:02X}{} {:02X} {:02X} {:2}* {} {} {}\n",
data1_1,
data1_2,
w.id,
@@ -841,7 +859,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
w.unknown_a1[2],
w.unknown_a4,
w.unknown_a5,
w.tech_boost,
w.tech_boost_entry_index,
tech_boost_str,
w.behavior_flags,
weapon_class,
stars,
@@ -852,7 +871,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
phosg::fwrite_fmt(stream, "ARMORS\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS -DFP- -EVP- BP BE FLAG LVL EFR ETH EIC EDK ELT DFR EVR SB(S1:AMT1,S2:AMT2) TB FT A4 ST* ---DIVISOR--- NAME\n");
phosg::fwrite_fmt(stream, " CODE => ---ID--- TYPE SKIN POINTS -DFP- -EVP- BP BE FLAG LVL EFR ETH EIC EDK ELT DFR EVR SB(S1:AMT1,S2:AMT2) TB(TN:FL:AMOUNT, ... ) FT A4 ST* ---DIVISOR--- NAME\n");
for (size_t data1_1 = 1; data1_1 < 3; data1_1++) {
float sale_divisor = pmt->get_sale_divisor(0x01, data1_1);
string divisor_str = std::format("{:g}", sale_divisor);
@@ -870,7 +889,17 @@ void ItemNameIndex::print_table(FILE* stream) const {
string name = this->describe_item(item);
auto& stat_boost = pmt->get_stat_boost(a.stat_boost_entry_index);
phosg::fwrite_fmt(stream, " 01{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:5} {:5} {:02X} {:02X} {:04X} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:02X}({:02X}:{:04X},{:02X}:{:04X}) {:02X} {:02X} {:02X} {:2}* {} {}\n",
string tech_boost_str;
if (a.tech_boost_entry_index < pmt->num_tech_boosts()) {
const auto& tech_boost = pmt->get_tech_boost(a.tech_boost_entry_index);
tech_boost_str = std::format("({:02X}:{:02X}:{:g},{:02X}:{:02X}:{:g},{:02X}:{:02X}:{:g})",
tech_boost.tech_num1, tech_boost.flags1, tech_boost.amount1, tech_boost.tech_num2, tech_boost.flags2,
tech_boost.amount2, tech_boost.tech_num3, tech_boost.flags3, tech_boost.amount3);
}
tech_boost_str.resize(40, ' ');
phosg::fwrite_fmt(stream, " 01{:02X}{:02X} => {:08X} {:04X} {:04X} {:6} {:5} {:5} {:02X} {:02X} {:04X} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:3} {:02X}({:02X}:{:04X},{:02X}:{:04X}) {:02X}{} {:02X} {:02X} {:2}* {} {}\n",
data1_1,
data1_2,
a.id,
@@ -895,7 +924,8 @@ void ItemNameIndex::print_table(FILE* stream) const {
stat_boost.amount1,
stat_boost.stat2,
stat_boost.amount2,
a.tech_boost,
a.tech_boost_entry_index,
tech_boost_str,
a.flags_type,
a.unknown_a4,
stars,
@@ -1040,7 +1070,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
}
phosg::fwrite_fmt(stream, "SPECIAL DEFINITIONS\n");
phosg::fwrite_fmt(stream, " SPECIAL => TYPE COUNT ST* NAME\n");
phosg::fwrite_fmt(stream, " SP => TYPE COUNT ST* NAME\n");
for (size_t index = 0; index < pmt->num_specials(); index++) {
const auto& sp = pmt->get_special(index);
uint8_t stars = pmt->get_special_stars(index);
@@ -1051,12 +1081,12 @@ void ItemNameIndex::print_table(FILE* stream) const {
} catch (const out_of_range&) {
}
}
phosg::fwrite_fmt(stream, " {:02X} => {:04X} {:5} {:2}* {}\n", index, sp.type, sp.amount, stars, name);
phosg::fwrite_fmt(stream, " {:02X} => {:04X} {:5} {:2}* {}\n", index, sp.type, sp.amount, stars, name);
}
phosg::fwrite_fmt(stream, "ITEM COMBINATIONS\n");
phosg::fwrite_fmt(stream, " ---USE + -EQUIP => RESULT MLV GND LVL CLS\n");
for (const auto& combo_list_it : pmt->get_all_item_combinations()) {
for (const auto& combo_list_it : pmt->item_combinations_index()) {
for (const auto& combo : combo_list_it.second) {
phosg::fwrite_fmt(stream, " {:02X}{:02X}{:02X} + {:02X}{:02X}{:02X} => {:02X}{:02X}{:02X}",
combo.used_item[0], combo.used_item[1], combo.used_item[2],
@@ -1096,4 +1126,158 @@ void ItemNameIndex::print_table(FILE* stream) const {
event_item.item[0], event_item.item[1], event_item.item[2], event_item.probability);
}
}
phosg::fwrite_fmt(stream, "PHOTON COLORS\n");
phosg::fwrite_fmt(stream, " ## => ---A1--- (A2) (A3)\n");
for (size_t z = 0; z < pmt->num_photon_colors(); z++) {
const auto& pc = pmt->get_photon_color(z);
phosg::fwrite_fmt(stream, " {:02X} => {:08X} ({:g}, {:g}, {:g}, {:g}) ({:g}, {:g}, {:g}, {:g})\n",
z, pc.unknown_a1, pc.unknown_a2.x, pc.unknown_a2.y, pc.unknown_a2.z, pc.unknown_a2.t,
pc.unknown_a3.x, pc.unknown_a3.y, pc.unknown_a3.z, pc.unknown_a3.t);
}
phosg::fwrite_fmt(stream, "WEAPON RANGES\n");
phosg::fwrite_fmt(stream, " ## => ---A3--- ---A4--- ---A5--- (A1) (A2)\n");
for (size_t z = 0; z < pmt->num_weapon_ranges(); z++) {
const auto& wr = pmt->get_weapon_range(z);
phosg::fwrite_fmt(stream, " {:02X} => {:08X} {:08X} {:08X} ({:g}) ({:g})\n",
z, wr.unknown_a3, wr.unknown_a4, wr.unknown_a5, wr.unknown_a1, wr.unknown_a2);
}
phosg::fwrite_fmt(stream, "SALE DIVISORS\n");
phosg::fwrite_fmt(stream, " ARMOR = {:g}\n", pmt->get_sale_divisor(1, 1));
phosg::fwrite_fmt(stream, " SHIELD = {:g}\n", pmt->get_sale_divisor(1, 2));
phosg::fwrite_fmt(stream, " UNIT = {:g}\n", pmt->get_sale_divisor(1, 3));
phosg::fwrite_fmt(stream, " MAG = {:g}\n", pmt->get_sale_divisor(2, 0));
auto write_data_string = [&](const std::string& data, size_t addr = 0) -> void {
if (data.empty()) {
phosg::fwrite_fmt(stream, " (no data)\n");
} else {
auto data_str = phosg::format_data(data, addr);
phosg::strip_trailing_whitespace(data_str);
phosg::fwrite_fmt(stream, " {}\n", phosg::str_replace_all(data_str, "\n", "\n "));
}
};
phosg::fwrite_fmt(stream, "STAR VALUES\n");
write_data_string(pmt->get_star_value_table(), pmt->get_star_value_index_range().first);
phosg::fwrite_fmt(stream, "UNKNOWN_A1\n");
write_data_string(pmt->get_unknown_a1());
phosg::fwrite_fmt(stream, "WEAPON EFFECTS\n");
phosg::fwrite_fmt(stream, " ## => -SOUND1- -VALUE1- -SOUND2- -VALUE2- ----------------A5---------------\n");
for (size_t z = 0; z < pmt->num_weapon_effects(); z++) {
const auto& we = pmt->get_weapon_effect(z);
auto a5_str = phosg::format_data_string(we.unknown_a5.data(), we.unknown_a5.size());
phosg::fwrite_fmt(stream, " {:02X} => {:08X} {:08X} {:08X} {:08X} {}\n",
z, we.sound_id1, we.eff_value1, we.sound_id2, we.eff_value2, a5_str);
}
phosg::fwrite_fmt(stream, "WEAPON STAT BOOST INDEX TABLE\n");
write_data_string(pmt->get_weapon_stat_boost_index_table());
phosg::fwrite_fmt(stream, "ARMOR STAT BOOST INDEX TABLE\n");
write_data_string(pmt->get_armor_stat_boost_index_table());
phosg::fwrite_fmt(stream, "SHIELD STAT BOOST INDEX TABLE\n");
write_data_string(pmt->get_shield_stat_boost_index_table());
phosg::fwrite_fmt(stream, "STAT BOOSTS\n");
phosg::fwrite_fmt(stream, " ## => BOOSTS\n");
for (size_t z = 0; z < pmt->num_stat_boosts(); z++) {
const auto& sb = pmt->get_stat_boost(z);
static constexpr std::array<const char*, 0x10> stat_names{
"ATP+", "ATA+", "EVP+", "DFP+", "MST+", "HP+", "LCK+", "ALL+",
"ATP-", "ATA-", "EVP-", "DFP-", "MST-", "HP-", "LCK-", "ALL-"};
string s;
if (sb.stat1 > 0x10) {
s = std::format("[{:02X}:{:04X}]", sb.stat1, sb.amount1);
} else if (sb.stat1 > 0) {
s = std::format("{}{}", stat_names[sb.stat1 - 1], sb.amount1);
}
if (sb.stat2) {
if (!s.empty()) {
s += ", ";
}
if (sb.stat2 > 0x10) {
s += std::format("[{:02X}:{:04X}]", sb.stat2, sb.amount2);
} else if (sb.stat2 > 0) {
s += std::format("{}{}", stat_names[sb.stat2 - 1], sb.amount2);
}
}
if (s.empty()) {
s = "(none)";
}
phosg::fwrite_fmt(stream, " {:02X} => {}\n", z, s);
}
phosg::fwrite_fmt(stream, "SHIELD EFFECTS\n");
phosg::fwrite_fmt(stream, " ## => -SOUND1- ---A1---\n");
for (size_t z = 0; z < pmt->num_shield_effects(); z++) {
const auto& se = pmt->get_shield_effect(z);
phosg::fwrite_fmt(stream, " {:02X} => {:08X} {:08X}\n", z, se.sound_id, se.unknown_a1);
}
phosg::fwrite_fmt(stream, "SOUND REMAPS\n");
phosg::fwrite_fmt(stream, " -SOUND1- => RT:[...] CC:[...]\n");
for (const auto& remap : pmt->get_all_sound_remaps()) {
std::string rt_str;
for (uint32_t rt_sound_id : remap.by_rt_index) {
if (!rt_str.empty()) {
rt_str += ",";
}
rt_str += std::format("{:08X}", rt_sound_id);
}
std::string cc_str;
for (uint32_t cc_sound_id : remap.by_char_class) {
if (!cc_str.empty()) {
cc_str += ",";
}
cc_str += std::format("{:08X}", cc_sound_id);
}
phosg::fwrite_fmt(stream, " {:08X} => RT:[{}] CC:[{}]\n", remap.sound_id, rt_str, cc_str);
}
phosg::fwrite_fmt(stream, "TECH BOOSTS\n");
phosg::fwrite_fmt(stream, " ## => BOOSTS\n");
for (size_t z = 0; z < pmt->num_tech_boosts(); z++) {
const auto& tb = pmt->get_tech_boost(z);
string s;
if (tb.amount1) {
s += std::format("{:02X}:{:02X}:{:g}", tb.tech_num1, tb.flags1, tb.amount1);
}
if (tb.amount2) {
s += std::format("{:02X}:{:02X}:{:g}", tb.tech_num2, tb.flags2, tb.amount2);
}
if (tb.amount3) {
s += std::format("{:02X}:{:02X}:{:g}", tb.tech_num3, tb.flags3, tb.amount3);
}
phosg::fwrite_fmt(stream, " {:02X} => {}\n", z, s);
}
phosg::fwrite_fmt(stream, "UNSEALABLE ITEMS\n");
phosg::fwrite_fmt(stream, " -ITEM- NAME\n");
std::vector<uint32_t> unsealable_items;
for (uint32_t item_code : pmt->all_unsealable_items()) {
unsealable_items.emplace_back(item_code);
}
std::sort(unsealable_items.begin(), unsealable_items.end());
for (uint32_t item_code : unsealable_items) {
ItemData item;
item.data1[0] = item_code >> 16;
item.data1[1] = item_code >> 8;
item.data1[2] = item_code;
string name = this->describe_item(item);
phosg::fwrite_fmt(stream, " {:06X} {}\n", item_code, name);
}
phosg::fwrite_fmt(stream, "RANGED SPECIALS\n");
phosg::fwrite_fmt(stream, " ## => 11 12 WR A1\n");
for (size_t z = 0; z < pmt->num_ranged_specials(); z++) {
const auto& rs = pmt->get_ranged_special(z);
phosg::fwrite_fmt(stream, " {:02X} => {:02X} {:02X} {:02X} {:02X}\n",
z, rs.data1_1, rs.data1_2, rs.weapon_range_index, rs.unknown_a1);
}
}
+2329 -279
View File
File diff suppressed because it is too large Load Diff
+207 -67
View File
@@ -51,6 +51,9 @@ public:
uint16_t type = 0; // "Model" in Soly's ItemPMT editor
uint16_t skin = 0; // "Texture" in Soly's ItemPMT editor
uint32_t team_points = 0;
void parse_base_from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct Weapon : ItemBase {
uint16_t class_flags = 0;
@@ -64,7 +67,8 @@ public:
uint8_t photon = 0;
uint8_t special = 0;
uint8_t ata = 0;
uint8_t stat_boost_entry_index = 0; // TODO: This could be larger (16 or 32 bits)
uint8_t stat_boost_entry_index = 0;
parray<uint8_t, 3> v2_unknown_a9;
uint8_t projectile = 0;
int8_t trail1_x = 0;
int8_t trail1_y = 0;
@@ -74,13 +78,16 @@ public:
parray<uint8_t, 3> unknown_a1 = 0;
uint8_t unknown_a4 = 0;
uint8_t unknown_a5 = 0;
uint8_t tech_boost = 0;
uint8_t tech_boost_entry_index = 0;
// Bits in behavior_flags:
// 01 = disable combos (weapon can only be used once in a row)
// 02 = TODO (sets TItemWeapon flag 40000; used in TItemWeapon_v1E)
// 04 = TODO (sets TItemWeapon flag 80000; used in TItemWeapon_v1E)
// 08 = weapon cannot have attributes (they are ignored if present)
uint8_t behavior_flags = 0;
static Weapon from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct ArmorOrShield : ItemBase {
@@ -98,7 +105,7 @@ public:
uint8_t dfp_range = 0;
uint8_t evp_range = 0;
uint8_t stat_boost_entry_index = 0;
uint8_t tech_boost = 0;
uint8_t tech_boost_entry_index = 0;
// TODO: Figure out what this does. Only a few values appear to do anything:
// Armors:
// 01 sets item->flags |= 1 (used in TItemProArmor_v10)
@@ -108,12 +115,18 @@ public:
// 03 sets item->flags |= 8 (used in TItemProShield_v1A)
uint8_t flags_type = 0;
uint8_t unknown_a4 = 0;
static ArmorOrShield from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct Unit : ItemBase {
uint16_t stat = 0;
uint16_t stat_amount = 0;
int16_t modifier_amount = 0;
static Unit from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct Mag : ItemBase {
@@ -142,6 +155,9 @@ public:
uint8_t on_death_flag = 0;
uint8_t on_boss_flag = 0;
uint16_t class_flags = 0x00FF;
static Mag from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct Tool : ItemBase {
@@ -157,7 +173,10 @@ public:
// 00000020 - usable in boss arenas
// 00000040 - usable in Challenge mode
// 00000080 - is rare (renders as red box; V3+ only)
/* 0C */ uint32_t item_flags = 0;
uint32_t item_flags = 0;
static Tool from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct MagFeedResult {
@@ -168,11 +187,17 @@ public:
int8_t iq = 0;
int8_t synchro = 0;
parray<uint8_t, 2> unused;
static MagFeedResult from_json(const phosg::JSON& json);
phosg::JSON json() const;
} __packed_ws__(MagFeedResult, 8);
struct Special {
uint16_t type = 0xFFFF;
uint16_t amount = 0;
static Special from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct StatBoost {
@@ -201,6 +226,9 @@ public:
uint16_t amount1 = 0;
uint8_t stat2 = 0;
uint16_t amount2 = 0;
static StatBoost from_json(const phosg::JSON& json);
phosg::JSON json() const;
} __attribute__((packed));
// Indexed as [tech_num][char_class]
@@ -215,23 +243,41 @@ public:
uint8_t level = 0;
uint8_t char_class = 0;
parray<uint8_t, 3> unused;
static ItemCombination from_json(const phosg::JSON& json);
phosg::JSON json() const;
} __packed_ws__(ItemCombination, 0x10);
struct TechniqueBoost {
uint8_t tech_num = 0;
// It appears that only one bit in the flags field is used: 01 = enable piercing (for Megid)
uint8_t flags = 0;
float amount = 0.0f;
struct TechBoost {
// It appears that only one bit in the flags fields is used: 01 = enable piercing (for Megid)
uint8_t tech_num1 = 0;
uint8_t flags1 = 0;
float amount1 = 0.0f;
uint8_t tech_num2 = 0;
uint8_t flags2 = 0;
float amount2 = 0.0f;
uint8_t tech_num3 = 0;
uint8_t flags3 = 0;
float amount3 = 0.0f;
static TechBoost from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct EventItem {
parray<uint8_t, 3> item;
uint8_t probability = 0;
static EventItem from_json(const phosg::JSON& json);
phosg::JSON json() const;
} __packed_ws__(EventItem, 4);
struct UnsealableItem {
parray<uint8_t, 3> item;
uint8_t unused = 0;
static UnsealableItem from_json(const phosg::JSON& json);
phosg::JSON json() const;
} __packed_ws__(UnsealableItem, 4);
struct NonWeaponSaleDivisors {
@@ -239,119 +285,213 @@ public:
float shield_divisor = 0.0f;
float unit_divisor = 0.0f;
float mag_divisor = 0.0f;
static NonWeaponSaleDivisors from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct ShieldEffect {
uint32_t sound_id;
uint32_t unknown_a1;
uint32_t sound_id = 0;
uint32_t unknown_a1 = 0;
static ShieldEffect from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct PhotonColorEntry {
uint32_t unknown_a1;
uint32_t unknown_a1 = 0;
VectorXYZTF unknown_a2;
VectorXYZTF unknown_a3;
static PhotonColorEntry from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct UnknownA1 {
uint16_t unknown_a1;
uint16_t unknown_a2;
};
uint16_t unknown_a1 = 0;
uint16_t unknown_a2 = 0;
struct UnknownA5 {
uint32_t target_param; // For players, char_class; for enemies, rt_index; for objects, 0x30
uint32_t unknown_a2;
uint32_t unknown_a3;
static UnknownA1 from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct WeaponEffect {
uint32_t sound_id1;
uint32_t eff_value1;
uint32_t sound_id2;
uint32_t eff_value2;
uint32_t sound_id1 = 0;
uint32_t eff_value1 = 0;
uint32_t sound_id2 = 0;
uint32_t eff_value2 = 0;
parray<uint8_t, 0x10> unknown_a5;
static WeaponEffect from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct WeaponRange {
float unknown_a1;
float unknown_a2;
uint32_t unknown_a3; // Angle
uint32_t unknown_a4; // Angle
uint32_t unknown_a5;
float unknown_a1 = 0;
float unknown_a2 = 0;
uint32_t unknown_a3 = 0; // Angle
uint32_t unknown_a4 = 0; // Angle
uint32_t unknown_a5 = 0;
static WeaponRange from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
struct RangedSpecial {
uint8_t data1_1;
uint8_t data1_2;
uint8_t weapon_range_index;
uint8_t unknown_a1;
uint8_t data1_1 = 0;
uint8_t data1_2 = 0;
uint8_t weapon_range_index = 0;
uint8_t unknown_a1 = 0;
static RangedSpecial from_json(const phosg::JSON& json);
phosg::JSON json() const;
} __packed_ws__(RangedSpecial, 4);
ItemParameterTable() = delete;
struct SoundRemaps {
uint32_t sound_id = 0;
std::vector<uint32_t> by_rt_index;
std::vector<uint32_t> by_char_class;
static SoundRemaps from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
virtual ~ItemParameterTable() = default;
static std::shared_ptr<ItemParameterTable> create(std::shared_ptr<const std::string> data, Version version);
static std::shared_ptr<ItemParameterTable> from_binary(std::shared_ptr<const std::string> data, Version version);
static std::shared_ptr<ItemParameterTable> from_json(const phosg::JSON& json);
phosg::JSON json() const;
std::string serialize_binary(Version version) const;
std::set<uint32_t> compute_all_valid_primary_identifiers() const;
// weapon_table accessors
virtual size_t num_weapon_classes() const = 0;
virtual size_t num_weapons_in_class(uint8_t data1_1) const = 0;
virtual const Weapon& get_weapon(uint8_t data1_1, uint8_t data1_2) const = 0;
// armor_table accessors
virtual size_t num_armors_or_shields_in_class(uint8_t data1_1) const = 0;
virtual const ArmorOrShield& get_armor_or_shield(uint8_t data1_1, uint8_t data1_2) const = 0;
// unit_table accessors
virtual size_t num_units() const = 0;
virtual const Unit& get_unit(uint8_t data1_2) const = 0;
virtual size_t num_mags() const = 0;
virtual const Mag& get_mag(uint8_t data1_1) const = 0;
// tool_table accessors
virtual size_t num_tool_classes() const = 0;
virtual size_t num_tools_in_class(uint8_t data1_1) const = 0;
virtual const Tool& get_tool(uint8_t data1_1, uint8_t data1_2) const = 0;
virtual std::pair<uint8_t, uint8_t> find_tool_by_id(uint32_t id) const = 0;
std::variant<const Weapon*, const ArmorOrShield*, const Unit*, const Mag*, const Tool*>
definition_for_primary_identifier(uint32_t primary_identifier) const;
// mag_table accessors
virtual size_t num_mags() const = 0;
virtual const Mag& get_mag(uint8_t data1_1) const = 0;
// weapon_kind_table accessors (data1_1 in [0, num_weapon_classes()])
virtual size_t num_weapon_kinds() const = 0;
virtual uint8_t get_weapon_kind(uint8_t data1_1) const = 0;
// photon_color_table accessors
virtual size_t num_photon_colors() const = 0;
virtual const PhotonColorEntry& get_photon_color(size_t index) const = 0;
// weapon_range_table accessors
virtual size_t num_weapon_ranges() const = 0;
virtual const WeaponRange& get_weapon_range(size_t index) const = 0;
// weapon_sale_divisor_table and non_weapon_sale_divisor_table accessors (data1_0 in [0, 1, 2]; data1_1 in [0,
// num_weapon_classes()] for weapons or ignored otherwise)
virtual size_t num_weapon_sale_divisors() const = 0;
virtual float get_sale_divisor(uint8_t data1_0, uint8_t data1_1) const = 0;
virtual const MagFeedResult& get_mag_feed_result(uint8_t table_index, uint8_t which) const = 0;
// mag_feed_table accessors (table_index in [0, 7], item_index in [0, 10])
virtual const MagFeedResult& get_mag_feed_result(uint8_t table_index, uint8_t item_index) const = 0;
// star_value_table accessors
virtual std::pair<uint32_t, uint32_t> get_star_value_index_range() const = 0;
virtual uint32_t get_special_stars_base_index() const = 0;
virtual uint8_t get_item_stars(uint32_t id) const = 0;
virtual uint8_t get_special_stars(uint8_t special) const = 0;
std::string get_star_value_table() const;
// unknown_a1 accessors
virtual std::string get_unknown_a1() const = 0;
// special_table accessors
virtual size_t num_specials() const = 0;
virtual const Special& get_special(uint8_t special) const = 0;
virtual const StatBoost& get_stat_boost(uint8_t entry_index) const = 0;
virtual uint8_t get_max_tech_level(uint8_t char_class, uint8_t tech_num) const = 0;
virtual uint8_t get_weapon_class(uint8_t data1_1) const = 0;
// weapon_effect_table accessors
virtual size_t num_weapon_effects() const = 0;
virtual const WeaponEffect& get_weapon_effect(size_t index) const = 0;
// weapon_stat_boost_index_table accessors
virtual size_t num_weapon_stat_boost_indexes() const = 0;
virtual uint8_t get_weapon_stat_boost_index(size_t index) const = 0;
std::string get_weapon_stat_boost_index_table() const;
// armor_stat_boost_index_table accessors
virtual size_t num_armor_stat_boost_indexes() const = 0;
virtual uint8_t get_armor_stat_boost_index(size_t index) const = 0;
std::string get_armor_stat_boost_index_table() const;
// shield_stat_boost_index_table accessors
virtual size_t num_shield_stat_boost_indexes() const = 0;
virtual uint8_t get_shield_stat_boost_index(size_t index) const = 0;
std::string get_shield_stat_boost_index_table() const;
// stat_boost_table accessors
virtual size_t num_stat_boosts() const = 0;
virtual const StatBoost& get_stat_boost(size_t index) const = 0;
// shield_effect_table accessors
virtual size_t num_shield_effects() const = 0;
virtual const ShieldEffect& get_shield_effect(size_t index) const = 0;
// max_tech_level_table accessors
virtual uint8_t get_max_tech_level(uint8_t char_class, uint8_t tech_num) const = 0;
// combination_table accessors
virtual size_t num_item_combinations() const = 0;
virtual const ItemCombination& get_item_combination(size_t index) const = 0;
const std::map<uint32_t, std::vector<ItemCombination>>& item_combinations_index() const;
const std::vector<ItemCombination>& all_combinations_for_used_item(const ItemData& used_item) const;
const ItemCombination& get_item_combination(const ItemData& used_item, const ItemData& equipped_item) const;
// sound_remap_table accessors
virtual const std::vector<SoundRemaps>& get_all_sound_remaps() const = 0;
// tech_boost_table accessors
virtual size_t num_tech_boosts() const = 0;
virtual const TechBoost& get_tech_boost(size_t index) const = 0;
// unwrap_table accessors
virtual size_t num_events() const = 0;
virtual std::pair<const EventItem*, size_t> get_event_items(uint8_t event_number) const = 0;
// unsealable_table accessors
virtual const std::unordered_set<uint32_t>& all_unsealable_items() const = 0;
bool is_unsealable_item(uint8_t data1_0, uint8_t data1_1, uint8_t data1_2) const;
bool is_unsealable_item(const ItemData& item) const;
// ranged_special_table accessors
virtual size_t num_ranged_specials() const = 0;
virtual const RangedSpecial& get_ranged_special(size_t index) const = 0;
// Composite accessors
std::variant<const Weapon*, const ArmorOrShield*, const Unit*, const Mag*, const Tool*>
definition_for_primary_identifier(uint32_t primary_identifier) const;
uint32_t get_item_id(const ItemData& item) const;
uint32_t get_item_team_points(const ItemData& item) const;
uint8_t get_item_base_stars(const ItemData& item) const;
uint8_t get_item_adjusted_stars(const ItemData& item, bool ignore_unidentified = false) const;
bool is_item_rare(const ItemData& item) const;
virtual bool is_unsealable_item(uint8_t data1_0, uint8_t data1_1, uint8_t data1_2) const = 0;
bool is_unsealable_item(const ItemData& item) const;
const ItemCombination& get_item_combination(const ItemData& used_item, const ItemData& equipped_item) const;
const std::vector<ItemCombination>& get_all_combinations_for_used_item(const ItemData& used_item) const;
virtual const std::map<uint32_t, std::vector<ItemCombination>>& get_all_item_combinations() const = 0;
virtual size_t num_events() const = 0;
virtual std::pair<const EventItem*, size_t> get_event_items(uint8_t event_number) const = 0;
size_t price_for_item(const ItemData& item) const;
protected:
std::shared_ptr<const std::string> data;
phosg::StringReader r;
ItemParameterTable() = default;
mutable std::unordered_map<uint16_t, Weapon> weapons;
mutable std::vector<ArmorOrShield> armors;
mutable std::vector<ArmorOrShield> shields;
mutable std::vector<Unit> units;
mutable std::vector<Mag> mags;
mutable std::unordered_map<uint16_t, Tool> tools;
mutable std::vector<Special> specials;
mutable std::vector<StatBoost> stat_boosts;
// Key is used_item. We can't index on (used_item, equipped_item) because equipped_item may contain wildcards, and
// the matching order matters.
mutable std::map<uint32_t, std::vector<ItemCombination>> item_combination_index;
explicit ItemParameterTable(std::shared_ptr<const std::string> data);
mutable std::optional<std::map<uint32_t, std::vector<ItemCombination>>> item_combination_index;
};
+4 -4
View File
@@ -46,18 +46,18 @@ ItemTranslationTable::ItemTranslationTable(
uint32_t e_id = this->entries[z].id_for_version[v_s];
if (is_canonical(e_id)) {
if (!entry_index.count(e_id)) {
throw logic_error(std::format("(row {} version {}) canonical ID {:X} is missing from the index", z, phosg::name_for_enum(v), e_id));
throw logic_error(std::format("(row {} version {}) canonical ID {:08X} is missing from the index", z, phosg::name_for_enum(v), e_id));
}
try {
item_parameter_table->definition_for_primary_identifier(e_id);
} catch (const out_of_range&) {
throw runtime_error(std::format("(row {} version {}) ID {:X} not defined in item parameter table", z, phosg::name_for_enum(v), e_id));
throw runtime_error(std::format("(row {} version {}) ID {:08X} not defined in item parameter table", z, phosg::name_for_enum(v), e_id));
}
if (!remaining_identifiers.erase(e_id)) {
throw runtime_error(std::format("(row {} version {}) ID {:X} not in item parameter table's primary identifier list", z, phosg::name_for_enum(v), e_id));
throw runtime_error(std::format("(row {} version {}) ID {:08X} not in item parameter table's primary identifier list", z, phosg::name_for_enum(v), e_id));
}
} else if (!entry_index.count(make_canonical(e_id))) {
throw runtime_error(std::format("(row {} version {}) ID {:X} refers to nonexistent canonical ID", z, phosg::name_for_enum(v), e_id));
throw runtime_error(std::format("(row {} version {}) ID {:08X} refers to nonexistent canonical ID", z, phosg::name_for_enum(v), e_id));
}
}
+41
View File
@@ -2387,6 +2387,47 @@ Action a_compare_common_item_set(
cs1->print_diff(stdout, *cs2);
});
Action a_decode_item_parameter_table(
"decode-item-parameter-table", "\
decode-item-parameter-table [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS...]\n\
Converts an ItemPMT file into a JSON item parameter table. A version\n\
option is required. Use --hex to make item codes in the output readable;\n\
however, this option also uses nonstandard JSON syntax - newserv can parse\n\
it, but many other JSON parsers can\'t. Expects compressed input (a .prs\n\
file) by default; use --decompressed if the input is not compressed.\n",
+[](phosg::Arguments& args) {
auto input_data = read_input_data(args);
if (!args.get<bool>("decompressed")) {
input_data = prs_decompress(input_data);
}
auto data = std::make_shared<string>(std::move(input_data));
auto pmt = ItemParameterTable::from_binary(data, get_cli_version(args, Version::BB_V4));
auto json = pmt->json();
uint32_t serialize_options = phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS;
if (args.get<bool>("hex")) {
serialize_options |= phosg::JSON::SerializeOption::HEX_INTEGERS;
}
string json_data = json.serialize(serialize_options);
write_output_data(args, json_data.data(), json_data.size(), nullptr);
});
Action a_encode_item_parameter_table(
"encode-item-parameter-table", "\
encode-item-parameter-table [INPUT-FILENAME [OUTPUT-FILENAME]] [OPTIONS...]\n\
Converts a JSON item parameter table into an ItemPMT file compatible with\n\
the game client. A version option is required. By default the output will\n\
be compressed, as the client expects; use --decompressed to get\n\
uncompressed output.\n",
+[](phosg::Arguments& args) {
auto json = phosg::JSON::parse(read_input_data(args));
auto pmt = ItemParameterTable::from_json(json);
string data = pmt->serialize_binary(get_cli_version(args, Version::BB_V4));
if (!args.get<bool>("decompressed")) {
data = prs_compress_optimal(data);
}
write_output_data(args, data.data(), data.size(), nullptr);
});
Action a_describe_item(
"describe-item", "\
describe-item DATA-OR-DESCRIPTION\n\
+48 -50
View File
@@ -692,6 +692,7 @@ void send_guild_card_chunk_bb(shared_ptr<Client> c, size_t chunk_index) {
}
static bool is_battle_param_stream_file_for_blueballz(const string& filename) {
return (filename == "BattleParamEntry.dat") ||
(filename == "BattleParamEntry_on.dat") ||
@@ -701,31 +702,23 @@ static bool is_battle_param_stream_file_for_blueballz(const string& filename) {
(filename == "BattleParamEntry_ep4_on.dat");
}
static shared_ptr<const string> bb_stream_file_data_for_client(shared_ptr<Client> c, const string& filename) {
static string bb_stream_file_data_for_client(shared_ptr<Client> c) {
auto s = c->require_server_state();
auto raw_data = s->bb_stream_files_cache->get_or_load("system/blueburst/" + filename).file->data;
int64_t effective_blueballz_hp_scale_tier = (c->selected_blueballz_tier >= 0)
? c->selected_blueballz_tier
: s->blueballz_enemy_hp_scale_tier;
if (!is_battle_param_stream_file_for_blueballz(filename) || (effective_blueballz_hp_scale_tier < 0)) {
return raw_data;
if (effective_blueballz_hp_scale_tier < 0) {
return s->bb_stream_file->data;
}
effective_blueballz_hp_scale_tier = std::min<int64_t>(
s->blueballz_max_tier,
effective_blueballz_hp_scale_tier);
string scaled_data = *raw_data;
if (scaled_data.size() < sizeof(BattleParamsIndex::Table)) {
c->log.warning_f("Blueballz enemy HP scaling skipped for {}; file is too small", filename);
return raw_data;
}
string scaled_data = s->bb_stream_file->data;
double mult = 1.0 + (static_cast<double>(effective_blueballz_hp_scale_tier) * 0.25);
auto* table = reinterpret_cast<BattleParamsIndex::Table*>(scaled_data.data());
size_t ultimate_index = static_cast<size_t>(Difficulty::ULTIMATE);
auto scale_u16 = [mult](uint32_t v) -> uint16_t {
@@ -742,28 +735,39 @@ static shared_ptr<const string> bb_stream_file_data_for_client(shared_ptr<Client
return static_cast<uint16_t>(scaled);
};
for (size_t z = 0; z < 0x60; z++) {
auto& stats = table->stats[ultimate_index][z];
stats.char_stats.hp = scale_u16(stats.char_stats.hp);
for (const auto& sf_entry : s->bb_stream_file->entries) {
if (!is_battle_param_stream_file_for_blueballz(sf_entry.filename)) {
continue;
}
if ((sf_entry.offset > scaled_data.size()) ||
(sf_entry.size > (scaled_data.size() - sf_entry.offset))) {
c->log.warning_f("Blueballz enemy HP scaling skipped for {}; invalid stream-file range",
sf_entry.filename);
continue;
}
if (sf_entry.size < sizeof(BattleParamsIndex::Table)) {
c->log.warning_f("Blueballz enemy HP scaling skipped for {}; file is too small",
sf_entry.filename);
continue;
}
auto* table = reinterpret_cast<BattleParamsIndex::Table*>(
scaled_data.data() + sf_entry.offset);
for (size_t z = 0; z < 0x60; z++) {
auto& stats = table->stats[ultimate_index][z];
stats.char_stats.hp = scale_u16(stats.char_stats.hp);
}
c->log.info_f("Blueballz enemy HP scaling: serving {} with tier {} ({:g}x Ultimate HP)",
sf_entry.filename, effective_blueballz_hp_scale_tier, mult);
}
c->log.info_f("Blueballz enemy HP scaling: serving {} with tier {} ({:g}x Ultimate HP)",
filename, effective_blueballz_hp_scale_tier, mult);
return make_shared<string>(std::move(scaled_data));
return scaled_data;
}
static const vector<string> stream_file_entries = {
"ItemMagEdit.prs",
"ItemPMT.prs",
"BattleParamEntry.dat",
"BattleParamEntry_on.dat",
"BattleParamEntry_lab.dat",
"BattleParamEntry_lab_on.dat",
"BattleParamEntry_ep4.dat",
"BattleParamEntry_ep4_on.dat",
"PlyLevelTbl.prs",
};
void send_stream_file_index_bb(shared_ptr<Client> c) {
auto s = c->require_server_state();
@@ -771,15 +775,19 @@ void send_stream_file_index_bb(shared_ptr<Client> c) {
c->log.info_f("PSO Peeps BBZ stream debug: send_stream_file_index_bb called");
vector<S_StreamFileIndexEntry_BB_01EB> entries;
size_t offset = 0;
for (const string& filename : stream_file_entries) {
auto file_data = bb_stream_file_data_for_client(c, filename);
string contents = bb_stream_file_data_for_client(c);
for (const auto& sf_entry : s->bb_stream_file->entries) {
if ((sf_entry.offset > contents.size()) ||
(sf_entry.size > (contents.size() - sf_entry.offset))) {
throw runtime_error("invalid BB stream file entry range");
}
auto& e = entries.emplace_back();
e.size = file_data->size();
e.checksum = crc32(file_data->data(), e.size);
e.offset = offset;
e.filename.encode(filename);
offset += e.size;
e.size = sf_entry.size;
e.checksum = crc32(contents.data() + sf_entry.offset, e.size);
e.offset = sf_entry.offset;
e.filename.encode(sf_entry.filename);
}
send_command_vt(c, 0x01EB, entries.size(), entries);
}
@@ -787,18 +795,7 @@ void send_stream_file_index_bb(shared_ptr<Client> c) {
void send_stream_file_chunk_bb(shared_ptr<Client> c, uint32_t chunk_index) {
auto s = c->require_server_state();
c->log.info_f("PSO Peeps BBZ stream debug: send_stream_file_chunk_bb called for chunk {}", chunk_index);
size_t total_bytes = 0;
for (const auto& name : stream_file_entries) {
total_bytes += bb_stream_file_data_for_client(c, name)->size();
}
string contents;
contents.reserve(total_bytes);
for (const auto& name : stream_file_entries) {
contents += *bb_stream_file_data_for_client(c, name);
}
string contents = bb_stream_file_data_for_client(c);
S_StreamFileChunk_BB_02EB chunk_cmd;
chunk_cmd.chunk_index = chunk_index;
@@ -809,6 +806,7 @@ void send_stream_file_chunk_bb(shared_ptr<Client> c, uint32_t chunk_index) {
size_t bytes = min<size_t>(contents.size() - offset, sizeof(chunk_cmd.data));
chunk_cmd.data.assign_range(reinterpret_cast<const uint8_t*>(contents.data() + offset), bytes, 0);
size_t cmd_size = offsetof(S_StreamFileChunk_BB_02EB, data) + bytes;
cmd_size = (cmd_size + 3) & ~3;
send_command(c, 0x02EB, 0x00000000, &chunk_cmd, cmd_size);
+36 -6
View File
@@ -79,7 +79,6 @@ ServerState::ServerState(const string& config_filename, bool is_replay)
config_filename(config_filename),
is_replay(is_replay),
thread_pool(make_unique<asio::thread_pool>()),
bb_stream_files_cache(new FileContentsCache(3600000000ULL)),
bb_system_cache(new FileContentsCache(3600000000ULL)),
gba_files_cache(new FileContentsCache(3600000000ULL)) {}
@@ -1847,8 +1846,6 @@ vector<shared_ptr<const SuperMap>> ServerState::supermaps_for_variations(
}
void ServerState::clear_file_caches() {
config_log.info_f("Clearing BB stream file cache");
this->bb_stream_files_cache.reset(new FileContentsCache(3600000000ULL));
config_log.info_f("Clearing BB system cache");
this->bb_system_cache.reset(new FileContentsCache(3600000000ULL));
config_log.info_f("Clearing GBA file cache");
@@ -2164,10 +2161,9 @@ void ServerState::load_item_definitions() {
config_log.info_f("Loading item definition tables");
for (size_t v_s = NUM_PATCH_VERSIONS; v_s < NUM_VERSIONS; v_s++) {
Version v = static_cast<Version>(v_s);
string path = std::format("system/item-tables/ItemPMT-{}.prs", file_path_token_for_version(v));
string path = std::format("system/item-tables/item-parameter-table-{}.json", file_path_token_for_version(v));
config_log.debug_f("Loading item definition table {}", path);
auto data = make_shared<string>(prs_decompress(phosg::load_file(path)));
new_item_parameter_tables[v_s] = ItemParameterTable::create(data, v);
new_item_parameter_tables[v_s] = ItemParameterTable::from_json(phosg::JSON::parse(phosg::load_file(path)));
}
auto json = phosg::JSON::parse(phosg::load_file("system/item-tables/translation-table.json"));
@@ -2243,6 +2239,39 @@ void ServerState::load_dol_files() {
this->dol_file_index = make_shared<DOLFileIndex>("system/dol");
}
void ServerState::generate_bb_stream_file() {
config_log.info_f("Generating BB stream file");
auto sf = std::make_shared<BBStreamFile>();
auto add_file = [&](const std::string& filename, std::string&& file_data = "") -> void {
if (file_data.empty()) {
file_data = phosg::load_file("system/blueburst/" + filename);
}
auto& e = sf->entries.emplace_back();
e.size = file_data.size();
e.checksum = phosg::crc32(file_data.data(), file_data.size());
e.offset = sf->data.size();
e.filename = filename;
sf->data += file_data;
config_log.debug_f(
"[BBStreamFile] Added file {} at offset {:08X} ({:08X} bytes) with checksum {:08X}; total size is now {:08X}",
filename, e.offset, e.size, e.checksum, sf->data.size());
};
add_file("BattleParamEntry.dat");
add_file("BattleParamEntry_on.dat");
add_file("BattleParamEntry_lab.dat");
add_file("BattleParamEntry_lab_on.dat");
add_file("BattleParamEntry_ep4.dat");
add_file("BattleParamEntry_ep4_on.dat");
add_file("PlyLevelTbl.prs");
add_file("ItemMagEdit.prs");
auto pmt = this->item_parameter_table(Version::BB_V4);
add_file("ItemPMT.prs", prs_compress_optimal(pmt->serialize_binary(Version::BB_V4)));
this->bb_stream_file = sf;
}
void ServerState::create_default_lobbies() {
if (this->default_lobbies_created) {
return;
@@ -2322,6 +2351,7 @@ void ServerState::load_all(bool enable_thread_pool) {
this->load_config_late();
this->load_teams();
this->load_quest_index();
this->generate_bb_stream_file();
}
void ServerState::disconnect_all_banned_clients() {
+13 -1
View File
@@ -65,6 +65,17 @@ struct CheatFlags {
explicit CheatFlags(const phosg::JSON& json);
};
struct BBStreamFile {
struct Entry {
uint32_t offset;
uint32_t size;
uint32_t checksum; // crc32
std::string filename;
};
std::vector<Entry> entries;
std::string data;
};
struct ServerState : public std::enable_shared_from_this<ServerState> {
enum class RunShellBehavior {
DEFAULT = 0,
@@ -188,7 +199,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
std::unordered_map<uint64_t, std::shared_ptr<const SuperMap>> supermap_for_source_hash_sum;
std::unordered_map<uint32_t, std::shared_ptr<const SuperMap>> supermap_for_free_play_key;
std::shared_ptr<const RoomLayoutIndex> room_layout_index;
std::shared_ptr<FileContentsCache> bb_stream_files_cache;
std::shared_ptr<const BBStreamFile> bb_stream_file;
std::shared_ptr<FileContentsCache> bb_system_cache;
std::shared_ptr<FileContentsCache> gba_files_cache;
std::shared_ptr<const DOLFileIndex> dol_file_index;
@@ -450,6 +461,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
void load_quest_index(bool raise_on_any_failure = false);
void compile_functions(bool raise_on_any_failure = false);
void load_dol_files();
void generate_bb_stream_file();
void load_all(bool enable_thread_pool);
+3
View File
@@ -211,14 +211,17 @@ ShellCommand c_reload(
args.s->load_set_data_tables();
} else if (type == "battle-params") {
args.s->load_battle_params();
args.s->generate_bb_stream_file();
} else if (type == "level-tables") {
args.s->load_level_tables();
args.s->generate_bb_stream_file();
} else if (type == "text-index") {
args.s->load_text_index();
} else if (type == "word-select") {
args.s->load_word_select_table();
} else if (type == "item-definitions") {
args.s->load_item_definitions();
args.s->generate_bb_stream_file();
} else if (type == "item-name-index") {
args.s->load_item_name_indexes();
} else if (type == "drop-tables") {
+3 -3
View File
@@ -478,8 +478,8 @@ Language language_for_name(const string& name) {
}
const vector<string> tech_id_to_name = {
"foie", "gifoie", "rafoie", "barta", "gibarta", "rabarta", "zonde", "gizonde", "razonde", "grants", "deband",
"jellen", "zalure", "shifta", "ryuker", "resta", "anti", "reverser", "megid"};
"Foie", "Gifoie", "Rafoie", "Barta", "Gibarta", "Rabarta", "Zonde", "Gizonde", "Razonde", "Grants", "Deband",
"Jellen", "Zalure", "Shifta", "Ryuker", "Resta", "Anti", "Reverser", "Megid"};
const unordered_map<string, uint8_t> name_to_tech_id = {
{"foie", 0}, {"gifoie", 1}, {"rafoie", 2}, {"barta", 3}, {"gibarta", 4}, {"rabarta", 5}, {"zonde", 6},
@@ -497,7 +497,7 @@ const string& name_for_technique(uint8_t tech) {
uint8_t technique_for_name(const string& name) {
try {
return name_to_tech_id.at(name);
return name_to_tech_id.at(phosg::tolower(name));
} catch (const out_of_range&) {
}
try {