From 1c2786ef43dff3f475cfe54282dd5511e32425cc Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Fri, 27 Oct 2023 21:08:04 -0700 Subject: [PATCH] support v2 and v3 ItemPMT files --- CMakeLists.txt | 1 + src/ChatCommands.cc | 13 +- src/ItemCreator.cc | 4 +- src/ItemData.cc | 1569 +---------------------------- src/ItemData.hh | 4 - src/ItemNameIndex.cc | 673 +++++++++++++ src/ItemNameIndex.hh | 38 + src/ItemParameterTable.cc | 693 ++++++++++--- src/ItemParameterTable.hh | 465 ++++++--- src/Items.cc | 21 +- src/Lobby.cc | 5 +- src/Main.cc | 36 +- src/Player.cc | 4 +- src/Player.hh | 3 +- src/RareItemSet.cc | 7 +- src/RareItemSet.hh | 4 +- src/ReceiveCommands.cc | 4 +- src/ReceiveSubcommands.cc | 107 +- src/ServerShell.cc | 7 +- src/ServerState.cc | 51 +- src/ServerState.hh | 9 +- system/item-tables/ItemPMT-gc.prs | Bin 0 -> 15673 bytes system/item-tables/ItemPMT-v2.prs | Bin 0 -> 8776 bytes system/item-tables/names-v2.json | 549 ++++++++++ system/item-tables/names-v3.json | 1264 +++++++++++++++++++++++ system/item-tables/names-v4.json | 1518 ++++++++++++++++++++++++++++ 26 files changed, 5106 insertions(+), 1943 deletions(-) create mode 100644 src/ItemNameIndex.cc create mode 100644 src/ItemNameIndex.hh create mode 100755 system/item-tables/ItemPMT-gc.prs create mode 100644 system/item-tables/ItemPMT-v2.prs create mode 100755 system/item-tables/names-v2.json create mode 100755 system/item-tables/names-v3.json create mode 100755 system/item-tables/names-v4.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 903631b3..63b06d84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ add_executable(newserv src/IPStackSimulator.cc src/ItemCreator.cc src/ItemData.cc + src/ItemNameIndex.cc src/ItemParameterTable.cc src/Items.cc src/LevelTable.cc diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index c8a98501..d43f3494 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -1148,8 +1148,9 @@ static void server_command_what(shared_ptr c, const std::string&) { if (nearest_item_id == 0xFFFFFFFF) { send_text_message(c, "$C4No items are near you"); } else { + auto s = c->require_server_state(); const auto& item = l->item_id_to_floor_item.at(nearest_item_id); - string name = item.data.name(true); + string name = s->describe_item(c->version(), item.data, true); send_text_message(c, name); } } @@ -1264,13 +1265,13 @@ static void server_command_item(shared_ptr c, const std::string& args) { check_is_game(l, true); check_cheats_enabled(l); - ItemData item(args); + ItemData item = s->item_name_index->parse_item_description(c->version(), args); item.id = l->generate_item_id(c->lobby_client_id); l->add_item(item, c->area, c->x, c->z); send_drop_stacked_item(l, item, c->area, c->x, c->z); - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message(c, "$C7Item created:\n" + name); } @@ -1292,20 +1293,20 @@ static void proxy_command_item(shared_ptr ses, const bool set_drop = (!args.empty() && (args[0] == '!')); - ItemData item(set_drop ? args.substr(1) : args); + ItemData item = s->item_name_index->parse_item_description(ses->version(), (set_drop ? args.substr(1) : args)); item.id = random_object(); if (set_drop) { ses->next_drop_item = item; - string name = ses->next_drop_item.name(true); + string name = s->describe_item(ses->version(), item, true); send_text_message(ses->client_channel, "$C7Next drop:\n" + name); } else { send_drop_stacked_item(ses->client_channel, item, ses->area, ses->x, ses->z); send_drop_stacked_item(ses->server_channel, item, ses->area, ses->x, ses->z); - string name = item.name(true); + string name = s->describe_item(ses->version(), item, true); send_text_message(ses->client_channel, "$C7Item created:\n" + name); } } diff --git a/src/ItemCreator.cc b/src/ItemCreator.cc index cb293aec..a377268a 100644 --- a/src/ItemCreator.cc +++ b/src/ItemCreator.cc @@ -614,8 +614,8 @@ uint8_t ItemCreator::generate_tech_disk_level(uint32_t tech_num, uint32_t area_n return range.min; } -void ItemCreator::generate_common_tool_type(uint8_t tool_class, ItemData& item) const { - auto data = this->item_parameter_table->find_tool_by_class(tool_class); +void ItemCreator::generate_common_tool_type(uint8_t id, ItemData& item) const { + auto data = this->item_parameter_table->find_tool_by_id(id); item.data1[0] = 0x03; item.data1[1] = data.first; item.data1[2] = data.second; diff --git a/src/ItemData.cc b/src/ItemData.cc index bf819c54..2788b0c1 100644 --- a/src/ItemData.cc +++ b/src/ItemData.cc @@ -6,8 +6,6 @@ using namespace std; -static string S_RANK_NAME_CHARACTERS("\0ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_", 0x20); - ItemData::ItemData() { this->clear(); } @@ -18,44 +16,6 @@ ItemData::ItemData(const ItemData& other) { this->data2d = other.data2d; } -ItemData::ItemData(const string& desc, bool allow_raw_data) { - this->clear(); - try { - this->parse(desc, false); - return; - } catch (const exception&) { - this->clear(); - } - try { - this->parse(desc, true); - return; - } catch (const exception&) { - if (!allow_raw_data) { - throw; - } - this->clear(); - } - - string data = parse_data_string(desc); - if (data.size() < 2) { - throw runtime_error("item code too short"); - } - if (data[0] > 4) { - throw runtime_error("invalid item class"); - } - if (data.size() > 16) { - throw runtime_error("item code too long"); - } - - ItemData ret; - if (data.size() <= 12) { - memcpy(this->data1.data(), data.data(), data.size()); - } else { - memcpy(this->data1.data(), data.data(), 12); - memcpy(this->data2.data(), data.data() + 12, data.size() - 12); - } -} - ItemData& ItemData::operator=(const ItemData& other) { this->data1d = other.data1d; this->id = other.id; @@ -98,6 +58,8 @@ uint32_t ItemData::primary_identifier() const { return 0x030200; // Tech disk (data1[2] is level, so omit it) } else if (this->data1[0] == 0x02) { return 0x020000 | (this->data1[1] << 8); // Mag + } else if (this->is_s_rank_weapon()) { + return (this->data1[0] << 16) | (this->data1[1] << 8); } else { return (this->data1[0] << 16) | (this->data1[1] << 8) | this->data1[2]; } @@ -489,1301 +451,6 @@ bool ItemData::compare_for_sort(const ItemData& a, const ItemData& b) { return false; } -const unordered_map name_for_weapon_special({ - {0x00, nullptr}, - {0x01, "Draw"}, - {0x02, "Drain"}, - {0x03, "Fill"}, - {0x04, "Gush"}, - {0x05, "Heart"}, - {0x06, "Mind"}, - {0x07, "Soul"}, - {0x08, "Geist"}, - {0x09, "Master\'s"}, - {0x0A, "Lord\'s"}, - {0x0B, "King\'s"}, - {0x0C, "Charge"}, - {0x0D, "Spirit"}, - {0x0E, "Berserk"}, - {0x0F, "Ice"}, - {0x10, "Frost"}, - {0x11, "Freeze"}, - {0x12, "Blizzard"}, - {0x13, "Bind"}, - {0x14, "Hold"}, - {0x15, "Seize"}, - {0x16, "Arrest"}, - {0x17, "Heat"}, - {0x18, "Fire"}, - {0x19, "Flame"}, - {0x1A, "Burning"}, - {0x1B, "Shock"}, - {0x1C, "Thunder"}, - {0x1D, "Storm"}, - {0x1E, "Tempest"}, - {0x1F, "Dim"}, - {0x20, "Shadow"}, - {0x21, "Dark"}, - {0x22, "Hell"}, - {0x23, "Panic"}, - {0x24, "Riot"}, - {0x25, "Havoc"}, - {0x26, "Chaos"}, - {0x27, "Devil\'s"}, - {0x28, "Demon\'s"}, -}); - -const unordered_map name_for_s_rank_special({ - {0x01, "Jellen"}, - {0x02, "Zalure"}, - {0x05, "Burning"}, - {0x06, "Tempest"}, - {0x07, "Blizzard"}, - {0x08, "Arrest"}, - {0x09, "Chaos"}, - {0x0A, "Hell"}, - {0x0B, "Spirit"}, - {0x0C, "Berserk"}, - {0x0D, "Demon\'s"}, - {0x0E, "Gush"}, - {0x0F, "Geist"}, - {0x10, "King\'s"}, -}); - -struct ItemNameInfo { - const char* name; - bool is_rare; - - ItemNameInfo(const char* name, bool is_rare = true) - : name(name), - is_rare(is_rare) {} -}; - -const unordered_map name_info_for_primary_identifier({ - // Weapons (00xxxx) - {0x000100, {"Saber", false}}, - {0x000101, {"Brand", false}}, - {0x000102, {"Buster", false}}, - {0x000103, {"Pallasch", false}}, - {0x000104, {"Gladius", false}}, - {0x000105, "DB\'s SABER"}, - {0x000106, "KALADBOLG"}, - {0x000107, "DURANDAL"}, - {0x000108, "GALATINE"}, - {0x000200, {"Sword", false}}, - {0x000201, {"Gigush", false}}, - {0x000202, {"Breaker", false}}, - {0x000203, {"Claymore", false}}, - {0x000204, {"Calibur", false}}, - {0x000205, "FLOWEN\'S SWORD"}, - {0x000206, "LAST SURVIVOR"}, - {0x000207, "DRAGON SLAYER"}, - {0x000300, {"Dagger", false}}, - {0x000301, {"Knife", false}}, - {0x000302, {"Blade", false}}, - {0x000303, {"Edge", false}}, - {0x000304, {"Ripper", false}}, - {0x000305, "BLADE DANCE"}, - {0x000306, "BLOODY ART"}, - {0x000307, "CROSS SCAR"}, - {0x000308, "ZERO DIVIDE"}, - {0x000309, "TWIN KAMUI"}, - {0x000400, {"Partisan", false}}, - {0x000401, {"Halbert", false}}, - {0x000402, {"Glaive", false}}, - {0x000403, {"Berdys", false}}, - {0x000404, {"Gungnir", false}}, - {0x000405, "BRIONAC"}, - {0x000406, "VJAYA"}, - {0x000407, "GAE BOLG"}, - {0x000408, "ASTERON BELT"}, - {0x000500, {"Slicer", false}}, - {0x000501, {"Spinner", false}}, - {0x000502, {"Cutter", false}}, - {0x000503, {"Sawcer", false}}, - {0x000504, {"Diska", false}}, - {0x000505, "SLICER OF ASSASSIN"}, - {0x000506, "DISKA OF LIBERATOR"}, - {0x000507, "DISKA OF BRAVEMAN"}, - {0x000508, "IZMAELA"}, - {0x000600, {"Handgun", false}}, - {0x000601, {"Autogun", false}}, - {0x000602, {"Lockgun", false}}, - {0x000603, {"Railgun", false}}, - {0x000604, {"Raygun", false}}, - {0x000605, "VARISTA"}, - {0x000606, "CUSTOM RAY ver.00"}, - {0x000607, "BRAVACE"}, - {0x000608, "TENSION BLASTER"}, - {0x000700, {"Rifle", false}}, - {0x000701, {"Sniper", false}}, - {0x000702, {"Blaster", false}}, - {0x000703, {"Beam", false}}, - {0x000704, {"Laser", false}}, - {0x000705, "VISK-235W"}, - {0x000706, "WALS-MK2"}, - {0x000707, "JUSTY-23ST"}, - {0x000708, "RIANOV 303SNR"}, - {0x000709, "RIANOV 303SNR-1"}, - {0x00070A, "RIANOV 303SNR-2"}, - {0x00070B, "RIANOV 303SNR-3"}, - {0x00070C, "RIANOV 303SNR-4"}, - {0x00070D, "RIANOV 303SNR-5"}, - {0x000800, {"Mechgun", false}}, - {0x000801, {"Assault", false}}, - {0x000802, {"Repeater", false}}, - {0x000803, {"Gatling", false}}, - {0x000804, {"Vulcan", false}}, - {0x000805, "M&A60 VISE"}, - {0x000806, "H&S25 JUSTICE"}, - {0x000807, "L&K14 COMBAT"}, - {0x000900, {"Shot", false}}, - {0x000901, {"Spread", false}}, - {0x000902, {"Cannon", false}}, - {0x000903, {"Launcher", false}}, - {0x000904, {"Arms", false}}, - {0x000905, "CRUSH BULLET"}, - {0x000906, "METEOR SMASH"}, - {0x000907, "FINAL IMPACT"}, - {0x000A00, {"Cane", false}}, - {0x000A01, {"Stick", false}}, - {0x000A02, {"Mace", false}}, - {0x000A03, {"Club", false}}, - {0x000A04, "CLUB OF LACONIUM"}, - {0x000A05, "MACE OF ADAMAN"}, - {0x000A06, "CLUB OF ZUMIURAN"}, - {0x000A07, "LOLLIPOP"}, - {0x000B00, {"Rod", false}}, - {0x000B01, {"Pole", false}}, - {0x000B02, {"Pillar", false}}, - {0x000B03, {"Striker", false}}, - {0x000B04, "BATTLE VERGE"}, - {0x000B05, "BRAVE HAMMER"}, - {0x000B06, "ALIVE AQHU"}, - {0x000B07, "VALKYRIE"}, - {0x000C00, {"Wand", false}}, - {0x000C01, {"Staff", false}}, - {0x000C02, {"Baton", false}}, - {0x000C03, {"Scepter", false}}, - {0x000C04, "FIRE SCEPTER:AGNI"}, - {0x000C05, "ICE STAFF:DAGON"}, - {0x000C06, "STORM WAND:INDRA"}, - {0x000C07, "EARTH WAND BROWNIE"}, - {0x000D00, "PHOTON CLAW"}, - {0x000D01, "SILENCE CLAW"}, - {0x000D02, "NEI\'S CLAW (REPLICA)"}, - {0x000D03, "PHOENIX CLAW"}, - {0x000E00, "DOUBLE SABER"}, - {0x000E01, "STAG CUTLERY"}, - {0x000E02, "TWIN BRAND"}, - {0x000F00, "BRAVE KNUCKLE"}, - {0x000F01, "ANGRY FIST"}, - {0x000F02, "GOD HAND"}, - {0x000F03, "SONIC KNUCKLE"}, - {0x001000, "OROTIAGITO"}, - {0x001001, "AGITO (AUW 1975)"}, - {0x001002, "AGITO (AUW 1983)"}, - {0x001003, "AGITO (AUW 2001)"}, - {0x001004, "AGITO (AUW 1991)"}, - {0x001005, "AGITO (AUW 1977)"}, - {0x001006, "AGITO (AUW 1980)"}, - {0x001007, "RAIKIRI"}, - {0x001100, "SOUL EATER"}, - {0x001101, "SOUL BANISH"}, - {0x001200, "SPREAD NEEDLE"}, - {0x001300, "HOLY RAY"}, - {0x001400, "INFERNO BAZOOKA"}, - {0x001401, "RAMBLING MAY"}, - {0x001402, "L&K38 COMBAT"}, - {0x001500, "FLAME VISIT"}, - {0x001501, "BURNING VISIT"}, - {0x001600, "AKIKO\'S FRYING PAN"}, - {0x001700, "SORCERER\'S CANE"}, - {0x001800, "S-BEAT\'S BLADE"}, - {0x001900, "P-ARMS\'S BLADE"}, - {0x001A00, "DELSABER\'S BUSTER"}, - {0x001B00, "BRINGER\'S RIFLE"}, - {0x001C00, "EGG BLASTER"}, - {0x001D00, "PSYCHO WAND"}, - {0x001E00, "HEAVEN PUNISHER"}, - {0x001F00, "LAVIS CANNON"}, - {0x002000, "VICTOR AXE"}, - {0x002001, "LACONIUM AXE"}, - {0x002100, "CHAIN SAWD"}, - {0x002200, "CADUCEUS"}, - {0x002201, "MERCURIUS ROD"}, - {0x002300, "STING TIP"}, - {0x002400, "MAGICAL PIECE"}, - {0x002500, "TECHNICAL CROZIER"}, - {0x002600, "SUPPRESSED GUN"}, - {0x002700, "ANCIENT SABER"}, - {0x002800, "HARISEN BATTLE FAN"}, - {0x002900, "YAMIGARASU"}, - {0x002A00, "AKIKO\'S WOK"}, - {0x002B00, "TOY HAMMER"}, - {0x002C00, "ELYSION"}, - {0x002D00, "RED SABER"}, - {0x002E00, "METEOR CUDGEL"}, - {0x002F00, "MONKEY KING BAR"}, - {0x002F01, "BLACK KING BAR"}, - {0x003000, "DOUBLE CANNON"}, - {0x003001, "GIRASOLE"}, - {0x003100, "HUGE BATTLE FAN"}, - {0x003200, "TSUMIKIRI J-SWORD"}, - {0x003300, "SEALED J-SWORD"}, - {0x003400, "RED SWORD"}, - {0x003500, "CRAZY TUNE"}, - {0x003600, "TWIN CHAKRAM"}, - {0x003700, "WOK OF AKIKO\'S SHOP"}, - {0x003800, "LAVIS BLADE"}, - {0x003900, "RED DAGGER"}, - {0x003A00, "MADAM\'S PARASOL"}, - {0x003B00, "MADAM\'S UMBRELLA"}, - {0x003C00, "IMPERIAL PICK"}, - {0x003D00, "BERDYSH"}, - {0x003E00, "RED PARTISAN"}, - {0x003F00, "FLIGHT CUTTER"}, - {0x004000, "FLIGHT FAN"}, - {0x004100, "RED SLICER"}, - {0x004200, "HANDGUN:GULD"}, - {0x004201, "MASTER RAVEN"}, - {0x004300, "HANDGUN:MILLA"}, - {0x004301, "LAST SWAN"}, - {0x004400, "RED HANDGUN"}, - {0x004500, "FROZEN SHOOTER"}, - {0x004501, "SNOW QUEEN"}, - {0x004600, "ANTI ANDROID RIFLE"}, - {0x004700, "ROCKET PUNCH"}, - {0x004800, "SAMBA MARACAS"}, - {0x004900, "TWIN PSYCHOGUN"}, - {0x004A00, "DRILL LAUNCHER"}, - {0x004B00, "GULD MILLA"}, - {0x004B01, "DUAL BIRD"}, - {0x004C00, "RED MECHGUN"}, - {0x004D00, "BELRA CANNON"}, - {0x004E00, "PANZER FAUST"}, - {0x004E01, "IRON FAUST"}, - {0x004F00, "SUMMIT MOON"}, - {0x005000, "WINDMILL"}, - {0x005100, "EVIL CURST"}, - {0x005200, "FLOWER CANE"}, - {0x005300, "HILDEBEAR\'S CANE"}, - {0x005400, "HILDEBLUE\'S CANE"}, - {0x005500, "RABBIT WAND"}, - {0x005600, "PLANTAIN LEAF"}, - {0x005601, "FATSIA"}, - {0x005700, "DEMONIC FORK"}, - {0x005800, "STRIKER OF CHAO"}, - {0x005900, "BROOM"}, - {0x005A00, "PROPHETS OF MOTAV"}, - {0x005B00, "THE SIGH OF A GOD"}, - {0x005C00, "TWINKLE STAR"}, - {0x005D00, "PLANTAIN FAN"}, - {0x005E00, "TWIN BLAZE"}, - {0x005F00, "MARINA\'S BAG"}, - {0x006000, "DRAGON\'S CLAW"}, - {0x006100, "PANTHER\'S CLAW"}, - {0x006200, "S-RED\'S BLADE"}, - {0x006300, "PLANTAIN HUGE FAN"}, - {0x006400, "CHAMELEON SCYTHE"}, - {0x006500, "YASMINKOV 3000R"}, - {0x006600, "ANO RIFLE"}, - {0x006700, "BARANZ LAUNCHER"}, - {0x006800, "BRANCH OF PAKUPAKU"}, - {0x006900, "HEART OF POUMN"}, - {0x006A00, "YASMINKOV 2000H"}, - {0x006B00, "YASMINKOV 7000V"}, - {0x006C00, "YASMINKOV 9000M"}, - {0x006D00, "MASER BEAM"}, - {0x006D01, "POWER MASER"}, - {0x006E00, "GAME MAGAZINE"}, - {0x006F00, "FLOWER BOUQUET"}, - {0x007000, {"S-RANK SABER", true}}, - {0x007100, {"S-RANK SWORD", true}}, - {0x007200, {"S-RANK BLADE", true}}, - {0x007300, {"S-RANK PARTISAN", true}}, - {0x007400, {"S-RANK SLICER", true}}, - {0x007500, {"S-RANK GUN", true}}, - {0x007600, {"S-RANK RIFLE", true}}, - {0x007700, {"S-RANK MECHGUN", true}}, - {0x007800, {"S-RANK SHOT", true}}, - {0x007900, {"S-RANK CANE", true}}, - {0x007A00, {"S-RANK ROD", true}}, - {0x007B00, {"S-RANK WAND", true}}, - {0x007C00, {"S-RANK TWIN", true}}, - {0x007D00, {"S-RANK CLAW", true}}, - {0x007E00, {"S-RANK BAZOOKA", true}}, - {0x007F00, {"S-RANK NEEDLE", true}}, - {0x008000, {"S-RANK SCYTHE", true}}, - {0x008100, {"S-RANK HAMMER", true}}, - {0x008200, {"S-RANK MOON", true}}, - {0x008300, {"S-RANK PSYCHOGUN", true}}, - {0x008400, {"S-RANK PUNCH", true}}, - {0x008500, {"S-RANK WINDMILL", true}}, - {0x008600, {"S-RANK HARISEN", true}}, - {0x008700, {"S-RANK KATANA", true}}, - {0x008800, {"S-RANK J-CUTTER", true}}, - {0x008900, "MUSASHI"}, - {0x008901, "YAMATO"}, - {0x008902, "ASUKA"}, - {0x008903, "SANGE & YASHA"}, - {0x008A00, "SANGE"}, - {0x008A01, "YASHA"}, - {0x008A02, "KAMUI"}, - {0x008B00, "PHOTON LAUNCHER"}, - {0x008B01, "GUILTY LIGHT"}, - {0x008B02, "RED SCORPIO"}, - {0x008B03, "PHONON MASER"}, - {0x008C00, "TALIS"}, - {0x008C01, "MAHU"}, - {0x008C02, "HITOGATA"}, - {0x008C03, "DANCING HITOGATA"}, - {0x008C04, "KUNAI"}, - {0x008D00, "NUG-2000 BAZOOKA"}, - {0x008E00, "S-BERILL\'S HANDS #0"}, - {0x008E01, "S-BERILL\'S HANDS #1"}, - {0x008F00, "FLOWEN\'S SWORD (AUW 3060; GREENILL)"}, - {0x008F01, "FLOWEN\'S SWORD (AUW 3064; SKYLY)"}, - {0x008F02, "FLOWEN\'S SWORD (AUW 3067; BLUEFULL)"}, - {0x008F03, "FLOWEN\'S SWORD (AUW 3073; PURPLENUM)"}, - {0x008F04, "FLOWEN\'S SWORD (AUW 3077; PINKAL)"}, - {0x008F05, "FLOWEN\'S SWORD (AUW 3082; REDRIA)"}, - {0x008F06, "FLOWEN\'S SWORD (AUW 3083; ORAN)"}, - {0x008F07, "FLOWEN\'S SWORD (AUW 3084; YELLOWBOZE)"}, - {0x008F08, "FLOWEN\'S SWORD (AUW 3079; WHITILL)"}, - {0x009000, "DB\'S SWORD (AUW 3062; GREENILL)"}, - {0x009001, "DB\'S SWORD (AUW 3067; SKYLY)"}, - {0x009002, "DB\'S SWORD (AUW 3069; BLUEFULL)"}, - {0x009003, "DB\'S SWORD (AUW 3064; PURPLENUM)"}, - {0x009004, "DB\'S SWORD (AUW 3069; PINKAL)"}, - {0x009005, "DB\'S SWORD (AUW 3073; REDRIA)"}, - {0x009006, "DB\'S SWORD (AUW 3070; ORAN)"}, - {0x009007, "DB\'S SWORD (AUW 3075; YELLOWBOZE)"}, - {0x009008, "DB\'S SWORD (AUW 3077; WHITILL)"}, - {0x009100, "GI GUE BAZOOKA"}, - {0x009200, "GUARDIANNA"}, - {0x009300, "VIRIDIA CARD"}, - {0x009301, "GREENILL CARD"}, - {0x009302, "SKYLY CARD"}, - {0x009303, "BLUEFULL CARD"}, - {0x009304, "PURPLENUM CARD"}, - {0x009305, "PINKAL CARD"}, - {0x009306, "REDRIA CARD"}, - {0x009307, "ORAN CARD"}, - {0x009308, "YELLOWBOZE CARD"}, - {0x009309, "WHITILL CARD"}, - {0x009400, "MORNING GLORY"}, - {0x009500, "PARTISAN OF LIGHTING"}, - {0x009600, "GAL WIND"}, - {0x009700, "ZANBA"}, - {0x009800, "RIKA\'S CLAW"}, - {0x009900, "ANGEL HARP"}, - {0x009A00, "DEMOLITION COMET"}, - {0x009B00, "NEI\'S CLAW"}, - {0x009C00, "RAINBOW BATON"}, - {0x009D00, "DARK FLOW"}, - {0x009E00, "DARK METEOR"}, - {0x009F00, "DARK BRIDGE"}, - {0x00A000, "G-ASSASSIN\'S SABERS"}, - {0x00A100, "RAPPY\'S FAN"}, - {0x00A200, "BOOMA\'S CLAW"}, - {0x00A201, "GOBOOMA\'S CLAW"}, - {0x00A202, "GIGOBOOMA\'S CLAW"}, - {0x00A300, "RUBY BULLET"}, - {0x00A400, "AMORE ROSE"}, - {0x00A500, {"S-RANK SWORDS", true}}, - {0x00A600, {"S-RANK LAUNCHER", true}}, - {0x00A700, {"S-RANK CARD", true}}, - {0x00A800, {"S-RANK KNUCKLE", true}}, - {0x00A900, {"S-RANK AXE", true}}, - {0x00AA00, "SLICER OF FANATIC"}, - {0x00AB00, "LAME D\'ARGENT"}, - {0x00AC00, "EXCALIBUR"}, - {0x00AD03, "RAGE DE FEU"}, - {0x00AE00, "DAISY CHAIN"}, - {0x00AF00, "OPHELIE SEIZE"}, - {0x00B000, "MILLE MARTEAUX"}, - {0x00B100, "LE COGNEUR"}, - {0x00B200, "COMMANDER BLADE"}, - {0x00B300, "VIVIENNE"}, - {0x00B400, "KUSANAGI"}, - {0x00B500, "SACRED DUSTER"}, - {0x00B600, "GUREN"}, - {0x00B700, "SHOUREN"}, - {0x00B800, "JIZAI"}, - {0x00B900, "FLAMBERGE"}, - {0x00BA00, "YUNCHANG"}, - {0x00BB00, "SNAKE SPIRE"}, - {0x00BC00, "FLAPJACK FLAPPER"}, - {0x00BD00, "GETSUGASAN"}, - {0x00BE00, "MAGUWA"}, - {0x00BF00, "HEAVEN STRIKER"}, - {0x00C000, "CANNON ROUGE"}, - {0x00C100, "METEOR ROUGE"}, - {0x00C200, "SOLFERINO"}, - {0x00C300, "CLIO"}, - {0x00C400, "SIREN GLASS HAMMER"}, - {0x00C500, "GLIDE DIVINE"}, - {0x00C600, "SHICHISHITO"}, - {0x00C700, "MURASAME"}, - {0x00C800, "DAYLIGHT SCAR"}, - {0x00C900, "DECALOG"}, - {0x00CA00, "5TH ANNIV. BLADE"}, - {0x00CB00, "PRINCIPAL\'S GIFT PARASOL"}, - {0x00CC00, "AKIKO\'S CLEAVER"}, - {0x00CD00, "TANEGASHIMA"}, - {0x00CE00, "TREE CLIPPERS"}, - {0x00CF00, "NICE SHOT"}, - {0x00D200, "ANO BAZOOKA"}, - {0x00D300, "SYNTHESIZER"}, - {0x00D400, "BAMBOO SPEAR"}, - {0x00D500, "KAN\'EI TSUHO"}, - {0x00D600, "JITTE"}, - {0x00D700, "BUTTERFLY NET"}, - {0x00D800, "SYRINGE"}, - {0x00D900, "BATTLEDORE"}, - {0x00DA00, "RACKET"}, - {0x00DB00, "HAMMER"}, - {0x00DC00, "GREAT BOUQUET"}, - {0x00DD00, "TypeSA/Saber"}, - {0x00DE00, "TypeSL/Saber"}, - {0x00DE01, "TypeSL/Slicer"}, - {0x00DE02, "TypeSL/Claw"}, - {0x00DE03, "TypeSL/Katana"}, - {0x00DF00, "TypeJS/Saber"}, - {0x00DF01, "TypeJS/Slicer"}, - {0x00DF02, "TypeJS/J-Sword"}, - {0x00E000, "TypeSW/Sword"}, - {0x00E001, "TypeSW/Slicer"}, - {0x00E002, "TypeSW/J-Sword"}, - {0x00E100, "TypeRO/Sword"}, - {0x00E101, "TypeRO/Halbert"}, - {0x00E102, "TypeRO/Rod"}, - {0x00E200, "TypeBL/BLADE"}, - {0x00E300, "TypeKN/Blade"}, - {0x00E301, "TypeKN/Claw"}, - {0x00E400, "TypeHA/Halbert"}, - {0x00E401, "TypeHA/Rod"}, - {0x00E500, "TypeDS/D.Saber"}, - {0x00E501, "TypeDS/Rod"}, - {0x00E502, "TypeDS"}, - {0x00E600, "TypeCL/Claw"}, - {0x00E700, "TypeSS/SW"}, - {0x00E800, "TypeGU/Handgun"}, - {0x00E801, "TypeGU/Mechgun"}, - {0x00E900, "TypeRI/Rifle"}, - {0x00EA00, "TypeME/Mechgun"}, - {0x00EB00, "TypeSH/Shot"}, - {0x00EC00, "TypeWA/Wand"}, - - // Armors (0101xx) - {0x010100, {"Frame", false}}, - {0x010101, {"Armor", false}}, - {0x010102, {"Psy Armor", false}}, - {0x010103, {"Giga Frame", false}}, - {0x010104, {"Soul Frame", false}}, - {0x010105, {"Cross Armor", false}}, - {0x010106, {"Solid Frame", false}}, - {0x010107, {"Brave Armor", false}}, - {0x010108, {"Hyper Frame", false}}, - {0x010109, {"Grand Armor", false}}, - {0x01010A, {"Shock Frame", false}}, - {0x01010B, {"King\'s Frame", false}}, - {0x01010C, {"Dragon Frame", false}}, - {0x01010D, {"Absorb Armor", false}}, - {0x01010E, {"Protect Frame", false}}, - {0x01010F, {"General Armor", false}}, - {0x010110, {"Perfect Frame", false}}, - {0x010111, {"Valiant Frame", false}}, - {0x010112, {"Imperial Armor", false}}, - {0x010113, {"Holiness Armor", false}}, - {0x010114, {"Guardian Armor", false}}, - {0x010115, {"Divinity Armor", false}}, - {0x010116, {"Ultimate Frame", false}}, - {0x010117, {"Celestial Armor", false}}, - {0x010118, "HUNTER FIELD"}, - {0x010119, "RANGER FIELD"}, - {0x01011A, "FORCE FIELD"}, - {0x01011B, "REVIVAL GARMENT"}, - {0x01011C, "SPIRIT GARMENT"}, - {0x01011D, "STINK FRAME"}, - {0x01011E, "D-PARTS Ver1.01"}, - {0x01011F, "D-PARTS Ver2.10"}, - {0x010120, "PARASITE WEAR:De Rol"}, - {0x010121, "PARASITE WEAR:Nelgal"}, - {0x010122, "PARASITE WEAR:Vajulla"}, - {0x010123, "SENSE PLATE"}, - {0x010124, "GRAVITON PLATE"}, - {0x010125, "ATTRIBUTE PLATE"}, - {0x010126, "FLOWEN\'S FRAME"}, - {0x010127, "CUSTOM FRAME Ver.00"}, - {0x010128, "DB\'s ARMOR"}, - {0x010129, "GUARD WAVE"}, - {0x01012A, "DF FIELD"}, - {0x01012B, "LUMINOUS FIELD"}, - {0x01012C, "CHU CHU FEVER"}, - {0x01012D, "LOVE HEART"}, - {0x01012E, "FLAME GARMENT"}, - {0x01012F, "VIRUS ARMOR:Lafuteria"}, - {0x010130, "BRIGHTNESS CIRCLE"}, - {0x010131, "AURA FIELD"}, - {0x010132, "ELECTRO FRAME"}, - {0x010133, "SACRED CLOTH"}, - {0x010134, "SMOKING PLATE"}, - {0x010135, "STAR CUIRASS"}, - {0x010136, "BLACK HOUND CUIRASS"}, - {0x010137, "MORNING PRAYER"}, - {0x010138, "BLACK ODOSHI DOMARU"}, - {0x010139, "RED ODOSHI DOMARU"}, - {0x01013A, "BLACK ODOSHI RED NIMAIDOU"}, - {0x01013B, "BLUE ODOSHI VIOLET NIMAIDOU"}, - {0x01013C, "DIRTY LIFE JACKET"}, - {0x01013E, "WEDDING DRESS"}, - {0x010140, "RED COAT"}, - {0x010141, "THIRTEEN"}, - {0x010142, "MOTHER GARB"}, - {0x010143, "MOTHER GARB+"}, - {0x010144, "DRESS PLATE"}, - {0x010145, "SWEETHEART"}, - {0x010146, "IGNITION CLOAK"}, - {0x010147, "CONGEAL CLOAK"}, - {0x010148, "TEMPEST CLOAK"}, - {0x010149, "CURSED CLOAK"}, - {0x01014A, "SELECT CLOAK"}, - {0x01014B, "SPIRIT CUIRASS"}, - {0x01014C, "REVIVAL CUIRASS"}, - {0x01014D, "ALLIANCE UNIFORM"}, - {0x01014E, "OFFICER UNIFORM"}, - {0x01014F, "COMMANDER UNIFORM"}, - {0x010150, "CRIMSON COAT"}, - {0x010151, "INFANTRY GEAR"}, - {0x010152, "LIEUTENANT GEAR"}, - {0x010153, "INFANTRY MANTLE"}, - {0x010154, "LIEUTENANT MANTLE"}, - {0x010155, "UNION FIELD"}, - {0x010156, "SAMURAI ARMOR"}, - {0x010157, "STEALTH SUIT"}, - - // Shields (0102xx) - {0x010200, {"Barrier", false}}, - {0x010201, {"Shield", false}}, - {0x010202, {"Core Shield", false}}, - {0x010203, {"Giga Shield", false}}, - {0x010204, {"Soul Barrier", false}}, - {0x010205, {"Hard Shield", false}}, - {0x010206, {"Brave Barrier", false}}, - {0x010207, {"Solid Shield", false}}, - {0x010208, {"Flame Barrier", false}}, - {0x010209, {"Plasma Barrier", false}}, - {0x01020A, {"Freeze Barrier", false}}, - {0x01020B, {"Psychic Barrier", false}}, - {0x01020C, {"General Shield", false}}, - {0x01020D, {"Protect Barrier", false}}, - {0x01020E, {"Glorious Shield", false}}, - {0x01020F, {"Imperial Barrier", false}}, - {0x010210, {"Guardian Shield", false}}, - {0x010211, {"Divinity Barrier", false}}, - {0x010212, {"Ultimate Shield", false}}, - {0x010213, {"Spiritual Shield", false}}, - {0x010214, {"Celestial Shield", false}}, - {0x010215, "INVISIBLE GUARD"}, - {0x010216, "SACRED GUARD"}, - {0x010217, "S-PARTS Ver1.16"}, - {0x010218, "S-PARTS Ver2.01"}, - {0x010219, "LIGHT RELIEF"}, - {0x01021A, "SHIELD OF DELSABER"}, - {0x01021B, "FORCE WALL"}, - {0x01021C, "RANGER WALL"}, - {0x01021D, "HUNTER WALL"}, - {0x01021E, "ATTRIBUTE WALL"}, - {0x01021F, "SECRET GEAR"}, - {0x010220, "COMBAT GEAR"}, - {0x010221, "PROTO REGENE GEAR"}, - {0x010222, "REGENERATE GEAR"}, - {0x010223, "REGENE GEAR ADV."}, - {0x010224, "FLOWEN\'S SHIELD"}, - {0x010225, "CUSTOM BARRIER Ver.00"}, - {0x010226, "DB\'S SHIELD"}, - {0x010227, "RED RING"}, - {0x010228, "TRIPOLIC SHIELD"}, - {0x010229, "STANDSTILL SHIELD"}, - {0x01022A, "SAFETY HEART"}, - {0x01022B, "KASAMI BRACER"}, - {0x01022C, "GODS SHIELD SUZAKU"}, - {0x01022D, "GODS SHIELD GENBU"}, - {0x01022E, "GODS SHIELD BYAKKO"}, - {0x01022F, "GODS SHIELD SEIRYU"}, - {0x010230, "HUNTER\'S SHELL"}, - {0x010231, "RICO\'S GLASSES"}, - {0x010232, "RICO\'S EARRING"}, - {0x010235, {"SECURE FEET", false}}, - {0x01023A, {"RESTA MERGE", false}}, - {0x01023B, {"ANTI MERGE", false}}, - {0x01023C, {"SHIFTA MERGE", false}}, - {0x01023D, {"DEBAND MERGE", false}}, - {0x01023E, {"FOIE MERGE", false}}, - {0x01023F, {"GIFOIE MERGE", false}}, - {0x010240, {"RAFOIE MERGE", false}}, - {0x010241, {"RED MERGE", false}}, - {0x010242, {"BARTA MERGE", false}}, - {0x010243, {"GIBARTA MERGE", false}}, - {0x010244, {"RABARTA MERGE", false}}, - {0x010245, {"BLUE MERGE", false}}, - {0x010246, {"ZONDE MERGE", false}}, - {0x010247, {"GIZONDE MERGE", false}}, - {0x010248, {"RAZONDE MERGE", false}}, - {0x010249, {"YELLOW MERGE", false}}, - {0x01024A, {"RECOVERY BARRIER", false}}, - {0x01024B, {"ASSIST BARRIER", false}}, - {0x01024C, {"RED BARRIER", false}}, - {0x01024D, {"BLUE BARRIER", false}}, - {0x01024E, {"YELLOW BARRIER", false}}, - {0x01024F, "WEAPONS GOLD SHIELD"}, - {0x010250, "BLACK GEAR"}, - {0x010251, "WORKS GUARD"}, - {0x010252, "RAGOL RING"}, - {0x010253, "BLUE RING (7 Colors)"}, - {0x010259, "BLUE RING"}, - {0x01025F, "GREEN RING"}, - {0x010266, "YELLOW RING"}, - {0x01026C, "PURPLE RING"}, - {0x010275, "WHITE RING"}, - {0x010280, "BLACK RING"}, - {0x010283, "WEAPONS SILVER SHIELD"}, - {0x010284, "WEAPONS COPPER SHIELD"}, - {0x010285, "GRATIA"}, - {0x010286, "TRIPOLIC REFLECTOR"}, - {0x010287, "STRIKER PLUS"}, - {0x010288, "REGENERATE GEAR B.P."}, - {0x010289, "RUPIKA"}, - {0x01028A, "YATA MIRROR"}, - {0x01028B, "BUNNY EARS"}, - {0x01028C, "CAT EARS"}, - {0x01028D, "THREE SEALS"}, - {0x01028F, "DF SHIELD"}, - {0x010290, "FROM THE DEPTHS"}, - {0x010291, "DE ROL LE SHIELD"}, - {0x010292, "HONEYCOMB REFLECTOR"}, - {0x010293, "EPSIGUARD"}, - {0x010294, "ANGEL RING"}, - {0x010295, "UNION GUARD"}, - {0x010297, "UNION"}, - {0x010298, "BLACK SHIELD UNION GUARD"}, - {0x010299, "STINK SHIELD"}, - {0x01029A, "BLACK"}, - {0x01029B, "GENPEI Heightened"}, - {0x01029C, "GENPEI Greenill"}, - {0x01029D, "GENPEI Skyly"}, - {0x01029E, "GENPEI Bluefull"}, - {0x01029F, "GENPEI Purplenum"}, - {0x0102A0, "GENPEI Pinkal"}, - {0x0102A1, "GENPEI Redria"}, - {0x0102A2, "GENPEI Oran"}, - {0x0102A3, "GENPEI Yellowboze"}, - {0x0102A4, "GENPEI Whitill"}, - - // Units (0103xx) - {0x010300, {"Knight/Power", false}}, - {0x010301, {"General/Power", false}}, - {0x010302, {"Ogre/Power", false}}, - {0x010303, "God/Power"}, - {0x010304, {"Priest/Mind", false}}, - {0x010305, {"General/Mind", false}}, - {0x010306, {"Angel/Mind", false}}, - {0x010307, "God/Mind"}, - {0x010308, {"Marksman/Arm", false}}, - {0x010309, {"General/Arm", false}}, - {0x01030A, {"Elf/Arm", false}}, - {0x01030B, "God/Arm"}, - {0x01030C, {"Thief/Legs", false}}, - {0x01030D, {"General/Legs", false}}, - {0x01030E, {"Elf/Legs", false}}, - {0x01030F, "God/Legs"}, - {0x010310, {"Digger/HP", false}}, - {0x010311, {"General/HP", false}}, - {0x010312, {"Dragon/HP", false}}, - {0x010313, "God/HP"}, - {0x010314, {"Magician/TP", false}}, - {0x010315, {"General/TP", false}}, - {0x010316, {"Angel/TP", false}}, - {0x010317, "God/TP"}, - {0x010318, {"Warrior/Body", false}}, - {0x010319, {"General/Body", false}}, - {0x01031A, {"Metal/Body", false}}, - {0x01031B, "God/Body"}, - {0x01031C, {"Angel/Luck", false}}, - {0x01031D, "God/Luck"}, - {0x01031E, {"Master/Ability", false}}, - {0x01031F, {"Hero/Ability", false}}, - {0x010320, "God/Ability"}, - {0x010321, {"Resist/Fire", false}}, - {0x010322, {"Resist/Flame", false}}, - {0x010323, {"Resist/Burning", false}}, - {0x010324, {"Resist/Cold", false}}, - {0x010325, {"Resist/Freeze", false}}, - {0x010326, {"Resist/Blizzard", false}}, - {0x010327, {"Resist/Shock", false}}, - {0x010328, {"Resist/Thunder", false}}, - {0x010329, {"Resist/Storm", false}}, - {0x01032A, {"Resist/Light", false}}, - {0x01032B, {"Resist/Saint", false}}, - {0x01032C, {"Resist/Holy", false}}, - {0x01032D, {"Resist/Dark", false}}, - {0x01032E, {"Resist/Evil", false}}, - {0x01032F, {"Resist/Devil", false}}, - {0x010330, {"All/Resist", false}}, - {0x010331, {"Super/Resist", false}}, - {0x010332, "Perfect/Resist"}, - {0x010333, {"HP/Restorate", false}}, - {0x010334, {"HP/Generate", false}}, - {0x010335, {"HP/Revival", false}}, - {0x010336, {"TP/Restorate", false}}, - {0x010337, {"TP/Generate", false}}, - {0x010338, {"TP/Revival", false}}, - {0x010339, {"PB/Amplifier", false}}, - {0x01033A, {"PB/Generate", false}}, - {0x01033B, {"PB/Create", false}}, - {0x01033C, {"Wizard/Technique", false}}, - {0x01033D, {"Devil/Technique", false}}, - {0x01033E, "God/Technique"}, - {0x01033F, {"General/Battle", false}}, - {0x010340, {"Devil/Battle", false}}, - {0x010341, "God/Battle"}, - {0x010342, "Cure/Poison"}, - {0x010343, "Cure/Paralysis"}, - {0x010344, "Cure/Slow"}, - {0x010345, "Cure/Confuse"}, - {0x010346, "Cure/Freeze"}, - {0x010347, "Cure/Shock"}, - {0x010348, "Yasakani Magatama"}, - {0x010349, "V101"}, - {0x01034A, "V501"}, - {0x01034B, "V502"}, - {0x01034C, "V801"}, - {0x01034D, "LIMITER"}, - {0x01034E, "ADEPT"}, - {0x01034F, "SWORDSMAN LORE"}, - {0x010350, "PROOF OF SWORD-SAINT"}, - {0x010351, "SMARTLINK"}, - {0x010352, "DIVINE PROTECTION"}, - {0x010353, "Heavenly/Battle"}, - {0x010354, "Heavenly/Power"}, - {0x010355, "Heavenly/Mind"}, - {0x010356, "Heavenly/Arms"}, - {0x010357, "Heavenly/Legs"}, - {0x010358, "Heavenly/Body"}, - {0x010359, "Heavenly/Luck"}, - {0x01035A, "Heavenly/Ability"}, - {0x01035B, "Centurion/Ability"}, - {0x01035C, "Friend Ring"}, - {0x01035D, "Heavenly/HP"}, - {0x01035E, "Heavenly/TP"}, - {0x01035F, "Heavenly/Resist"}, - {0x010360, "Heavenly/Technique"}, - {0x010361, "HP/Resurrection"}, - {0x010362, "TP/Resurrection"}, - {0x010363, "PB/Increase"}, - - // Mags (02xxxx) - {0x020000, {"Mag", false}}, - {0x020100, {"Varuna", false}}, - {0x020200, {"Mitra", false}}, - {0x020300, {"Surya", false}}, - {0x020400, {"Vayu", false}}, - {0x020500, {"Varaha", false}}, - {0x020600, {"Kama", false}}, - {0x020700, {"Ushasu", false}}, - {0x020800, {"Apsaras", false}}, - {0x020900, {"Kumara", false}}, - {0x020A00, {"Kaitabha", false}}, - {0x020B00, {"Tapas", false}}, - {0x020C00, {"Bhirava", false}}, - {0x020D00, {"Kalki", false}}, - {0x020E00, {"Rudra", false}}, - {0x020F00, {"Marutah", false}}, - {0x021000, {"Yaksa", false}}, - {0x021100, {"Sita", false}}, - {0x021200, {"Garuda", false}}, - {0x021300, {"Nandin", false}}, - {0x021400, {"Ashvinau", false}}, - {0x021500, {"Ribhava", false}}, - {0x021600, {"Soma", false}}, - {0x021700, {"Ila", false}}, - {0x021800, {"Durga", false}}, - {0x021900, {"Vritra", false}}, - {0x021A00, {"Namuci", false}}, - {0x021B00, {"Sumba", false}}, - {0x021C00, {"Naga", false}}, - {0x021D00, {"Pitri", false}}, - {0x021E00, {"Kabanda", false}}, - {0x021F00, {"Ravana", false}}, - {0x022000, {"Marica", false}}, - {0x022100, {"Soniti", false}}, - {0x022200, {"Preta", false}}, - {0x022300, {"Andhaka", false}}, - {0x022400, {"Bana", false}}, - {0x022500, {"Naraka", false}}, - {0x022600, {"Madhu", false}}, - {0x022700, {"Churel", false}}, - {0x022800, "ROBOCHAO"}, - {0x022900, "OPA-OPA"}, - {0x022A00, "PIAN"}, - {0x022B00, "CHAO"}, - {0x022C00, "CHU CHU"}, - {0x022D00, "KAPU KAPU"}, - {0x022E00, "ANGEL\'S WING"}, - {0x022F00, "DEVIL\'S WING"}, - {0x023000, "ELENOR"}, - {0x023100, "MARK3"}, - {0x023200, "MASTER SYSTEM"}, - {0x023300, "GENESIS"}, - {0x023400, "SEGA SATURN"}, - {0x023500, "DREAMCAST"}, - {0x023600, "HAMBURGER"}, - {0x023700, "PANZER\'S TAIL"}, - {0x023800, "DAVIL\'S TAIL"}, - {0x023900, "Deva"}, - {0x023A00, "Rati"}, - {0x023B00, "Savitri"}, - {0x023C00, "Rukmin"}, - {0x023D00, "Pushan"}, - {0x023E00, "Diwari"}, - {0x023F00, "Sato"}, - {0x024000, "Bhima"}, - {0x024100, "Nidra"}, - - // Tools (03xxxx) - {0x030000, {"Monomate", false}}, - {0x030001, {"Dimate", false}}, - {0x030002, {"Trimate", false}}, - {0x030100, {"Monofluid", false}}, - {0x030101, {"Difluid", false}}, - {0x030102, {"Trifluid", false}}, - {0x030200, {"", false}}, // Special-cased in name_for_item - {0x030300, {"Sol Atomizer", false}}, - {0x030400, {"Moon Atomizer", false}}, - {0x030500, {"Star Atomizer", false}}, - {0x030600, {"Antidote", false}}, - {0x030601, {"Antiparalysis", false}}, - {0x030700, {"Telepipe", false}}, - {0x030800, {"Trap Vision", false}}, - {0x030900, {"Scape Doll", false}}, - {0x030A00, {"Monogrinder", false}}, - {0x030A01, {"Digrinder", false}}, - {0x030A02, {"Trigrinder", false}}, - {0x030B00, {"Power Material", false}}, - {0x030B01, {"Mind Material", false}}, - {0x030B02, {"Evade Material", false}}, - {0x030B03, {"HP Material", false}}, - {0x030B04, {"TP Material", false}}, - {0x030B05, {"Def Material", false}}, - {0x030B06, {"Luck Material", false}}, - {0x030C00, "Cell of MAG 502"}, - {0x030C01, "Cell of MAG 213"}, - {0x030C02, "Parts of RoboChao"}, - {0x030C03, "Heart of Opa Opa"}, - {0x030C04, "Heart of Pian"}, - {0x030C05, "Heart of Chao"}, - {0x030D00, "Sorcerer\'s Right Arm"}, - {0x030D01, "S-beat\'s Arms"}, - {0x030D02, "P-arm\'s Arms"}, - {0x030D03, "Delsaber\'s Right Arm"}, - {0x030D04, "C-bringer\'s Right Arm"}, - {0x030D05, "Delsaber\'s Left Arm"}, - {0x030D06, "S-red\'s Arms"}, - {0x030D07, "Dragon\'s Claw"}, - {0x030D08, "Hildebear\'s Head"}, - {0x030D09, "Hildeblue\'s Head"}, - {0x030D0A, "Parts of Baranz"}, - {0x030D0B, "Belra\'s Right Arm"}, - {0x030D0C, "Gi Gue\'s Body"}, - {0x030D0D, "Sinow Berill\'s Arms"}, - {0x030D0E, "G-Assassin\'s Arms"}, - {0x030D0F, "Booma\'s Right Arm"}, - {0x030D10, "Gobooma\'s Right Arm"}, - {0x030D11, "Gigobooma\'s Right Arm"}, - {0x030D12, "Gal Gryphon's Wing"}, - {0x030D13, "Rappy\'s Wing"}, - {0x030D14, "Cladding of Epsilon"}, - {0x030D15, "De Rol Le Shell"}, - {0x030E00, "Berill Photon"}, - {0x030E01, "Parasitic gene \"Flow\""}, - {0x030E02, "Magic stone \"Iritista\""}, - {0x030E03, "Blue-black stone"}, - {0x030E04, "Syncesta"}, - {0x030E05, "Magic Water"}, - {0x030E06, "Parasitic cell Type-D"}, - {0x030E07, "magic rock \"Heart Key\""}, - {0x030E08, "magic rock \"Moola\""}, - {0x030E09, "Star Amplifier"}, - {0x030E0A, "Book of HITOGATA"}, - {0x030E0B, "Heart of Chu Chu"}, - {0x030E0C, "Parts of EGG BLASTER"}, - {0x030E0D, "Heart of Angel"}, - {0x030E0E, "Heart of Devil"}, - {0x030E0F, "Kit of Hamburger"}, - {0x030E10, "Panther\'s Spirit"}, - {0x030E11, "Kit of MARK3"}, - {0x030E12, "Kit of MASTER SYSTEM"}, - {0x030E13, "Kit of GENESIS"}, - {0x030E14, "Kit of SEGA SATURN"}, - {0x030E15, "Kit of DREAMCAST"}, - {0x030E16, {"Amplifier of Resta", false}}, - {0x030E17, {"Amplifier of Anti", false}}, - {0x030E18, {"Amplifier of Shifta", false}}, - {0x030E19, {"Amplifier of Deband", false}}, - {0x030E1A, {"Amplifier of Foie", false}}, - {0x030E1B, {"Amplifier of Gifoie", false}}, - {0x030E1C, {"Amplifier of Rafoie", false}}, - {0x030E1D, {"Amplifier of Barta", false}}, - {0x030E1E, {"Amplifier of Gibarta", false}}, - {0x030E1F, {"Amplifier of Rabarta", false}}, - {0x030E20, {"Amplifier of Zonde", false}}, - {0x030E21, {"Amplifier of Gizonde", false}}, - {0x030E22, {"Amplifier of Razonde", false}}, - {0x030E23, {"Amplifier of Red", false}}, - {0x030E24, {"Amplifier of Blue", false}}, - {0x030E25, {"Amplifier of Yellow", false}}, - {0x030E26, "Heart of KAPU KAPU"}, - {0x030E27, "Photon Booster"}, - {0x030F00, "AddSlot"}, - {0x031000, "Photon Drop"}, - {0x031001, "Photon Sphere"}, - {0x031002, "Photon Crystal"}, - {0x031003, "Secret Lottery Ticket"}, - {0x031100, "Book of KATANA1"}, - {0x031101, "Book of KATANA2"}, - {0x031102, "Book of KATANA3"}, - {0x031200, "Weapons Bronze Badge"}, - {0x031201, "Weapons Silver Badge"}, - {0x031202, "Weapons Gold Badge"}, - {0x031203, "Weapons Crystal Badge"}, - {0x031204, "Weapons Steel Badge"}, - {0x031205, "Weapons Aluminum Badge"}, - {0x031206, "Weapons Leather Badge"}, - {0x031207, "Weapons Bone Badge"}, - {0x031208, "Letter of appreciation"}, - {0x031209, "Autograph Album"}, - {0x03120A, "Valentine\'s Chocolate"}, - {0x03120B, "New Year\'s Card"}, - {0x03120C, "Christmas Card"}, - {0x03120D, "Birthday Card"}, - {0x03120E, "Proof of Sonic Team"}, - {0x03120F, "Special Event Ticket"}, - {0x031210, "Flower Bouquet"}, - {0x031211, "Cake"}, - {0x031212, "Accessories"}, - {0x031213, "Mr.Naka\'s Business Card"}, - {0x031300, "Present"}, - {0x031400, "Chocolate"}, - {0x031401, "Candy"}, - {0x031402, "Cake"}, - {0x031403, "Silver Badge"}, - {0x031404, "Gold Badge"}, - {0x031405, "Crystal Badge"}, - {0x031406, "Iron Badge"}, - {0x031407, "Aluminum Badge"}, - {0x031408, "Leather Badge"}, - {0x031409, "Bone Badge"}, - {0x03140A, "Bouquet"}, - {0x03140B, "Decoction"}, - {0x031500, "Christmas Present"}, - {0x031501, "Easter Egg"}, - {0x031502, "Jack-O\'-Lantern"}, - {0x031600, "DISK Vol.1"}, - {0x031601, "DISK Vol.2"}, - {0x031602, "DISK Vol.3"}, - {0x031603, "DISK Vol.4"}, - {0x031604, "DISK Vol.5"}, - {0x031605, "DISK Vol.6"}, - {0x031606, "DISK Vol.7"}, - {0x031607, "DISK Vol.8"}, - {0x031608, "DISK Vol.9"}, - {0x031609, "DISK Vol.10"}, - {0x03160A, "DISK Vol.11"}, - {0x03160B, "DISK Vol.12"}, - {0x031700, "Hunters Report"}, - {0x031701, "Hunters Report (Rank A)"}, - {0x031702, "Hunters Report (Rank B)"}, - {0x031703, "Hunters Report (Rank C)"}, - {0x031704, "Hunters Report (Rank F)"}, - {0x031800, "Tablet"}, - {0x031802, "Dragon Scale"}, - {0x031803, "Heaven Striker Coat"}, - {0x031804, "Pioneer Parts"}, - {0x031805, "Amitie\'s Memo"}, - {0x031806, "Heart of Morolian"}, - {0x031807, "Rappy\'s Beak"}, - {0x031809, "D-Photon Core"}, - {0x03180A, "Liberta Kit"}, - {0x03180B, "Cell of MAG 0503"}, - {0x03180C, "Cell of MAG 0504"}, - {0x03180D, "Cell of MAG 0505"}, - {0x03180E, "Cell of MAG 0506"}, - {0x03180F, "Cell of MAG 0507"}, - {0x031900, "Team Points 500"}, - {0x031901, "Team Points 1000"}, - {0x031902, "Team Points 5000"}, - {0x031903, "Team Points 10000"}, -}); - -void ItemData::parse(const string& orig_description, bool skip_special) { - this->data1d.clear(0); - this->id = 0xFFFFFFFF; - this->data2d = 0; - - string desc = tolower(orig_description); - if (ends_with(desc, " meseta")) { - this->data1[0] = 0x04; - this->data2d = stol(desc, nullptr, 10); - return; - } - - if (starts_with(desc, "disk:")) { - auto tokens = split(desc, ' '); - tokens[0] = tokens[0].substr(5); // Trim off "disk:" - if ((tokens[0] == "reverser") || (tokens[0] == "ryuker")) { - uint8_t tech = technique_for_name(tokens[0]); - this->data1[0] = 0x03; - this->data1[1] = 0x02; - this->data1[2] = 0x00; - this->data1[4] = tech; - } else { - if (tokens.size() != 2) { - throw runtime_error("invalid tech disk format"); - } - if (!starts_with(tokens[1], "lv.")) { - throw runtime_error("invalid tech disk level"); - } - uint8_t tech = technique_for_name(tokens[0]); - uint8_t level = stoul(tokens[1].substr(3), nullptr, 10) - 1; - this->data1[0] = 0x03; - this->data1[1] = 0x02; - this->data1[2] = level; - this->data1[4] = tech; - } - return; - } - - bool is_wrapped = starts_with(desc, "wrapped "); - if (is_wrapped) { - desc = desc.substr(8); - } - - uint8_t weapon_special = 0; - if (!skip_special) { - for (const auto& it : name_for_weapon_special) { - if (!it.second) { - continue; - } - string prefix = tolower(it.second); - prefix += ' '; - if (starts_with(desc, prefix)) { - weapon_special = it.first; - desc = desc.substr(prefix.size()); - break; - } - } - } - - static map primary_identifier_for_name; - if (primary_identifier_for_name.empty()) { - for (const auto& it : name_info_for_primary_identifier) { - primary_identifier_for_name.emplace(tolower(it.second.name), it.first); - } - } - auto name_it = primary_identifier_for_name.lower_bound(desc); - // Look up to 3 places before the lower bound. We have to do this to catch - // cases like Sange vs. Sange & Yasha - if the input is like "Sange 0/...", - // then we'll see Sange & Yasha first, which we should skip. - size_t lookback = 0; - while (lookback < 4) { - if (name_it != primary_identifier_for_name.end() && - desc.starts_with(name_it->first)) { - break; - } else if (name_it == primary_identifier_for_name.begin()) { - throw runtime_error("no such item"); - } else { - name_it--; - lookback++; - } - } - if (lookback >= 4) { - throw runtime_error("item not found: " + desc); - } - - desc = desc.substr(name_it->first.size()); - if (starts_with(desc, " ")) { - desc = desc.substr(1); - } - - uint32_t primary_identifier = name_it->second; - this->data1[0] = (primary_identifier >> 16) & 0xFF; - this->data1[1] = (primary_identifier >> 8) & 0xFF; - this->data1[2] = primary_identifier & 0xFF; - - if (this->data1[0] == 0x00) { - // Weapons: add special, grind and percentages (or name, if S-rank) - this->data1[4] = weapon_special | (is_wrapped ? 0x40 : 0x00); - - auto tokens = split(desc, ' '); - for (auto& token : tokens) { - if (token.empty()) { - continue; - } - if (starts_with(token, "+")) { - token = token.substr(1); - this->data1[3] = stoul(token, nullptr, 10); - - } else if (this->is_s_rank_weapon()) { - if (token.size() > 8) { - throw runtime_error("s-rank name too long"); - } - - uint8_t char_indexes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - for (size_t z = 0; z < token.size(); z++) { - char ch = toupper(token[z]); - size_t pos = S_RANK_NAME_CHARACTERS.find(ch); - if (pos == string::npos) { - throw runtime_error(string_printf("s-rank name contains invalid character %02hhX (%c)", ch, ch)); - } - char_indexes[z] = pos; - } - - this->data1w[3] = (char_indexes[1] & 0x1F) | ((char_indexes[0] & 0x1F) << 5); - this->data1w[4] = (char_indexes[4] & 0x1F) | ((char_indexes[3] & 0x1F) << 5) | ((char_indexes[2] & 0x1F) << 10); - this->data1w[5] = (char_indexes[7] & 0x1F) | ((char_indexes[6] & 0x1F) << 5) | ((char_indexes[5] & 0x1F) << 10); - - } else { - auto p_tokens = split(token, '/'); - if (p_tokens.size() > 5) { - throw runtime_error("invalid bonuses token"); - } - uint8_t bonus_index = 0; - for (size_t z = 0; z < p_tokens.size(); z++) { - int8_t bonus_value = stol(p_tokens[z], nullptr, 10); - if (bonus_value == 0) { - continue; - } - if (bonus_index >= 3) { - throw runtime_error("weapon has too many bonuses"); - } - this->data1[6 + (2 * bonus_index)] = z + 1; - this->data1[7 + (2 * bonus_index)] = static_cast(bonus_value); - bonus_index++; - } - } - } - - } else if (this->data1[0] == 0x01) { - if (this->data1[1] == 0x03) { // Unit - static const unordered_map modifiers({ - {"--", 0xFFFC}, - {"-", 0xFFFE}, - {"", 0x0000}, - {"+", 0x0002}, - {"++", 0x0004}, - }); - uint16_t modifier = modifiers.at(desc); - this->data1[7] = modifier & 0xFF; - this->data1[8] = (modifier >> 8) & 0xFF; - - } else { // Armor/shield - for (const auto& token : split(desc, ' ')) { - if (token.empty()) { - continue; - } else if (!starts_with(token, "+")) { - throw runtime_error("invalid armor/shield modifier"); - } - if (ends_with(token, "def")) { - this->data1w[3] = static_cast(stol(token.substr(1, token.size() - 4), nullptr, 10)); - } else if (ends_with(token, "evp")) { - this->data1w[4] = static_cast(stol(token.substr(1, token.size() - 4), nullptr, 10)); - } else { - this->data1[5] = stoul(token.substr(1), nullptr, 10); - } - } - } - - if (is_wrapped) { - this->data1[4] |= 0x40; - } - - } else if (this->data1[0] == 0x02) { - for (const auto& token : split(desc, ' ')) { - if (token.empty()) { - continue; - } else if (starts_with(token, "pb:")) { // Photon blasts - auto pb_tokens = split(token.substr(3), ','); - if (pb_tokens.size() > 3) { - throw runtime_error("too many photon blasts specified"); - } - static const unordered_map name_to_pb_num({ - {"f", 0}, - {"e", 1}, - {"g", 2}, - {"p", 3}, - {"l", 4}, - {"m&y", 5}, - }); - for (const auto& pb_token : pb_tokens) { - this->add_mag_photon_blast(name_to_pb_num.at(pb_token)); - } - } else if (ends_with(token, "%")) { // Synchro - this->data2[0] = stoul(token.substr(0, token.size() - 1), nullptr, 10); - } else if (ends_with(token, "iq")) { // IQ - this->data2[1] = stoul(token.substr(0, token.size() - 2), nullptr, 10); - } else if (!token.empty() && isdigit(token[0])) { // Stats - auto s_tokens = split(token, '/'); - if (s_tokens.size() != 4) { - throw runtime_error("incorrect stat count"); - } - for (size_t z = 0; z < 4; z++) { - auto n_tokens = split(s_tokens[z], '.'); - if (n_tokens.size() == 0 || n_tokens.size() > 2) { - throw logic_error("incorrect stats argument format"); - } else if ((n_tokens.size() == 1) || (n_tokens[1].size() == 0)) { - this->data1w[z + 2] = stoul(n_tokens[0], nullptr, 10) * 100; - } else if (n_tokens[1].size() == 1) { - this->data1w[z + 2] = stoul(n_tokens[0], nullptr, 10) * 100 + stoul(n_tokens[1], nullptr, 10) * 10; - } else if (n_tokens[1].size() == 2) { - this->data1w[z + 2] = stoul(n_tokens[0], nullptr, 10) * 100 + stoul(n_tokens[1], nullptr, 10); - } else { - throw runtime_error("incorrect stat format"); - } - } - this->data1[2] = this->compute_mag_level(); - } else { // Color - this->data2[3] = mag_color_for_name.at(token); - } - } - - if (is_wrapped) { - this->data2[2] |= 0x40; - } - } else if (this->data1[0] == 0x03) { - if (this->max_stack_size() > 1) { - if (starts_with(desc, "x")) { - this->data1[5] = stoul(desc.substr(1), nullptr, 10); - } else { - this->data1[5] = 1; - } - } else if (!desc.empty()) { - throw runtime_error("item cannot be stacked"); - } - - if (is_wrapped) { - if (this->is_stackable()) { - throw runtime_error("stackable items cannot be wrapped"); - } else { - this->data1[3] |= 0x40; - } - } - } else { - throw logic_error("invalid item class"); - } -} - string ItemData::hex() const { return string_printf("%02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX (%08" PRIX32 ") %02hhX%02hhX%02hhX%02hhX", this->data1[0], this->data1[1], this->data1[2], this->data1[3], @@ -1792,235 +459,3 @@ string ItemData::hex() const { this->id.load(), this->data2[0], this->data2[1], this->data2[2], this->data2[3]); } - -string ItemData::name(bool include_color_codes) const { - if (this->data1[0] == 0x04) { - return string_printf("%s%" PRIu32 " Meseta", - include_color_codes ? "$C7" : "", this->data2d.load()); - } - - vector ret_tokens; - - // For weapons, specials appear before the weapon name - if ((this->data1[0] == 0x00) && (this->data1[4] != 0x00)) { - // 0x80 is the unidentified flag, but we always return the identified name - // of the item here, so we ignore it - bool is_present = this->data1[4] & 0x40; - uint8_t special_id = this->data1[4] & 0x3F; - if (is_present) { - ret_tokens.emplace_back("Wrapped"); - } - if (special_id) { - try { - ret_tokens.emplace_back(name_for_weapon_special.at(special_id)); - } catch (const out_of_range&) { - ret_tokens.emplace_back(string_printf("!SP:%02hhX", special_id)); - } - } - } - // Armors, shields, and units (0x01) can be wrapped, as can mags (0x02) and - // non-stackable tools (0x03). However, each of these item classes has its - // flags in a different location. - if (((this->data1[1] == 0x01) && (this->data1[4] & 0x40)) || - ((this->data1[0] == 0x02) && (this->data2[2] & 0x40)) || - ((this->data1[0] == 0x03) && !this->is_stackable() && (this->data1[3] & 0x40))) { - ret_tokens.emplace_back("Wrapped"); - } - - // Add the item name. Technique disks are special because the level is part of - // the primary identifier, so we manually generate the name instead of looking - // it up. - bool is_rare = false; - uint32_t primary_identifier = this->primary_identifier(); - if ((primary_identifier & 0xFFFFFF00) == 0x00030200) { - string technique_name; - try { - technique_name = tech_id_to_name.at(this->data1[4]); - technique_name[0] = toupper(technique_name[0]); - } catch (const out_of_range&) { - technique_name = string_printf("!TECH:%02hhX", this->data1[4]); - } - // Hide the level for Reverser and Ryuker, unless the level isn't 1 - if ((this->data1[2] == 0) && ((this->data1[4] == 0x0E) || (this->data1[4] == 0x11))) { - ret_tokens.emplace_back(string_printf("Disk:%s", technique_name.c_str())); - } else { - ret_tokens.emplace_back(string_printf("Disk:%s Lv.%d", technique_name.c_str(), this->data1[2] + 1)); - } - } else { - try { - const auto& name_info = name_info_for_primary_identifier.at(primary_identifier); - ret_tokens.emplace_back(name_info.name); - is_rare = name_info.is_rare; - } catch (const out_of_range&) { - ret_tokens.emplace_back(string_printf("!ID:%06" PRIX32, primary_identifier)); - } - } - - // For weapons, add the grind and percentages, or S-rank name if applicable - if (this->data1[0] == 0x00) { - if (this->data1[3] > 0) { - ret_tokens.emplace_back(string_printf("+%hhu", this->data1[3])); - } - - if (this->is_s_rank_weapon()) { - // S-rank (has name instead of percent bonuses) - uint8_t char_indexes[8] = { - static_cast((this->data1w[3] >> 5) & 0x1F), - static_cast(this->data1w[3] & 0x1F), - static_cast((this->data1w[4] >> 10) & 0x1F), - static_cast((this->data1w[4] >> 5) & 0x1F), - static_cast(this->data1w[4] & 0x1F), - static_cast((this->data1w[5] >> 10) & 0x1F), - static_cast((this->data1w[5] >> 5) & 0x1F), - static_cast(this->data1w[5] & 0x1F), - }; - - string name; - for (size_t x = 0; x < 8; x++) { - char ch = S_RANK_NAME_CHARACTERS[char_indexes[x]]; - if (ch == 0) { - break; - } - name += ch; - } - if (!name.empty()) { - ret_tokens.emplace_back("(" + name + ")"); - } - - } else { // Not S-rank (extended name bits not set) - parray percentages(0); - for (size_t x = 0; x < 3; x++) { - uint8_t which = this->data1[6 + 2 * x]; - uint8_t value = this->data1[7 + 2 * x]; - if (which == 0) { - continue; - } - if (which > 5) { - ret_tokens.emplace_back(string_printf("!PC:%02hhX%02hhX", which, value)); - } else { - percentages[which - 1] = value; - } - } - if (!percentages.is_filled_with(0)) { - ret_tokens.emplace_back(string_printf("%hhd/%hhd/%hhd/%hhd/%hhd", - percentages[0], percentages[1], percentages[2], percentages[3], percentages[4])); - } - } - - // For armors, add the slots, unit modifiers, and/or DEF/EVP bonuses - } else if (this->data1[0] == 0x01) { - if (this->data1[1] == 0x03) { // Units - uint16_t modifier = (this->data1[8] << 8) | this->data1[7]; - if (modifier == 0x0001 || modifier == 0x0002) { - ret_tokens.back().append("+"); - } else if (modifier == 0x0003 || modifier == 0x0004) { - ret_tokens.back().append("++"); - } else if (modifier == 0xFFFF || modifier == 0xFFFE) { - ret_tokens.back().append("-"); - } else if (modifier == 0xFFFD || modifier == 0xFFFC) { - ret_tokens.back().append("--"); - } else if (modifier != 0x0000) { - ret_tokens.emplace_back(string_printf("!MD:%04hX", modifier)); - } - - } else { // Armor/shields - if (this->data1[5] > 0) { - if (this->data1[5] == 1) { - ret_tokens.emplace_back("(1 slot)"); - } else { - ret_tokens.emplace_back(string_printf("(%hhu slots)", this->data1[5])); - } - } - if (this->data1w[3] != 0) { - ret_tokens.emplace_back(string_printf("+%hdDEF", - static_cast(this->data1w[3].load()))); - } - if (this->data1w[4] != 0) { - ret_tokens.emplace_back(string_printf("+%hdEVP", - static_cast(this->data1w[4].load()))); - } - } - - // For mags, add tons of info - } else if (this->data1[0] == 0x02) { - ret_tokens.emplace_back(string_printf("LV%hhu", this->data1[2])); - - uint16_t def = this->data1w[2]; - uint16_t pow = this->data1w[3]; - uint16_t dex = this->data1w[4]; - uint16_t mind = this->data1w[5]; - auto format_stat = +[](uint16_t stat) -> string { - uint16_t level = stat / 100; - uint8_t partial = stat % 100; - if (partial == 0) { - return string_printf("%hu", level); - } else if (partial % 10 == 0) { - return string_printf("%hu.%hhu", level, static_cast(partial / 10)); - } else { - return string_printf("%hu.%02hhu", level, partial); - } - }; - ret_tokens.emplace_back(format_stat(def) + "/" + format_stat(pow) + "/" + format_stat(dex) + "/" + format_stat(mind)); - ret_tokens.emplace_back(string_printf("%hhu%%", this->data2[0])); - ret_tokens.emplace_back(string_printf("%hhuIQ", this->data2[1])); - - uint8_t flags = this->data2[2]; - if (flags & 7) { - static const vector pb_shortnames = { - "F", "E", "G", "P", "L", "M&Y", "MG", "GR"}; - - const char* pb_names[3] = {nullptr, nullptr, nullptr}; - uint8_t left_pb = this->mag_photon_blast_for_slot(2); - uint8_t center_pb = this->mag_photon_blast_for_slot(0); - uint8_t right_pb = this->mag_photon_blast_for_slot(1); - if (left_pb != 0xFF) { - pb_names[0] = pb_shortnames[left_pb]; - } - if (center_pb != 0xFF) { - pb_names[1] = pb_shortnames[center_pb]; - } - if (right_pb != 0xFF) { - pb_names[2] = pb_shortnames[right_pb]; - } - - string token = "PB:"; - for (size_t x = 0; x < 3; x++) { - if (pb_names[x] == nullptr) { - continue; - } - if (token.size() > 3) { - token += ','; - } - token += pb_names[x]; - } - ret_tokens.emplace_back(std::move(token)); - } - - try { - ret_tokens.emplace_back(string_printf("(%s)", name_for_mag_color.at(this->data2[3]))); - } catch (const out_of_range&) { - ret_tokens.emplace_back(string_printf("(!CL:%02hhX)", this->data2[3])); - } - - // For tools, add the amount (if applicable) - } else if (this->data1[0] == 0x03) { - if (this->max_stack_size() > 1) { - ret_tokens.emplace_back(string_printf("x%hhu", this->data1[5])); - } - } - - string ret = join(ret_tokens, " "); - if (include_color_codes) { - if (this->is_s_rank_weapon()) { - return "$C4" + ret; - } else if (is_rare) { - return "$C6" + ret; - } else if (this->has_bonuses()) { - return "$C2" + ret; - } else { - return "$C7" + ret; - } - } else { - return ret; - } -} diff --git a/src/ItemData.hh b/src/ItemData.hh index 2e7f2921..2427ba65 100644 --- a/src/ItemData.hh +++ b/src/ItemData.hh @@ -101,19 +101,15 @@ struct ItemData { // 0x14 bytes } __attribute__((packed)); ItemData(); - explicit ItemData(const std::string& orig_description, bool allow_raw_data = true); ItemData(const ItemData& other); ItemData& operator=(const ItemData& other); - void parse(const std::string& desc, bool skip_specials); - bool operator==(const ItemData& other) const; bool operator!=(const ItemData& other) const; void clear(); std::string hex() const; - std::string name(bool include_color_codes) const; uint32_t primary_identifier() const; bool is_wrapped() const; diff --git a/src/ItemNameIndex.cc b/src/ItemNameIndex.cc new file mode 100644 index 00000000..9b722e8b --- /dev/null +++ b/src/ItemNameIndex.cc @@ -0,0 +1,673 @@ +#include "ItemNameIndex.hh" + +#include "StaticGameData.hh" + +using namespace std; + +ItemNameIndex::ItemNameIndex(JSON&& v2_names, JSON&& v3_names, JSON&& v4_names) { + auto get_or_create_meta = [&](uint32_t primary_identifier) { + shared_ptr meta; + try { + return this->primary_identifier_index.at(primary_identifier); + } catch (const out_of_range&) { + auto meta = make_shared(); + meta->primary_identifier = primary_identifier; + this->primary_identifier_index.emplace(primary_identifier, meta); + return meta; + } + }; + + for (const auto& it : v2_names.as_dict()) { + uint32_t primary_identifier = stoul(it.first, nullptr, 16); + auto meta = get_or_create_meta(primary_identifier); + meta->v2_name = std::move(it.second->as_string()); + this->v2_name_index.emplace(tolower(meta->v2_name), meta); + } + for (const auto& it : v3_names.as_dict()) { + uint32_t primary_identifier = stoul(it.first, nullptr, 16); + auto meta = get_or_create_meta(primary_identifier); + meta->v3_name = std::move(it.second->as_string()); + this->v3_name_index.emplace(tolower(meta->v3_name), meta); + } + for (const auto& it : v4_names.as_dict()) { + uint32_t primary_identifier = stoul(it.first, nullptr, 16); + auto meta = get_or_create_meta(primary_identifier); + meta->v4_name = std::move(it.second->as_string()); + this->v4_name_index.emplace(tolower(meta->v4_name), meta); + } +} + +static const char* s_rank_name_characters = "\0ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; + +static constexpr array name_for_weapon_special = { + nullptr, + "Draw", + "Drain", + "Fill", + "Gush", + "Heart", + "Mind", + "Soul", + "Geist", + "Master\'s", + "Lord\'s", + "King\'s", + "Charge", + "Spirit", + "Berserk", + "Ice", + "Frost", + "Freeze", + "Blizzard", + "Bind", + "Hold", + "Seize", + "Arrest", + "Heat", + "Fire", + "Flame", + "Burning", + "Shock", + "Thunder", + "Storm", + "Tempest", + "Dim", + "Shadow", + "Dark", + "Hell", + "Panic", + "Riot", + "Havoc", + "Chaos", + "Devil\'s", + "Demon\'s", +}; + +const array name_for_s_rank_special = { + nullptr, + "Jellen", + "Zalure", + "HP-Revival", + "TP-Revival", + "Burning", + "Tempest", + "Blizzard", + "Arrest", + "Chaos", + "Hell", + "Spirit", + "Berserk", + "Demon\'s", + "Gush", + "Geist", + "King\'s", +}; + +std::string ItemNameIndex::describe_item( + GameVersion version, + const ItemData& item, + std::shared_ptr item_parameter_table) const { + if (item.data1[0] == 0x04) { + return string_printf("%s%" PRIu32 " Meseta", item_parameter_table ? "$C7" : "", item.data2d.load()); + } + + vector ret_tokens; + + // For weapons, specials appear before the weapon name + if ((item.data1[0] == 0x00) && (item.data1[4] != 0x00) && !item.is_s_rank_weapon()) { + // 0x80 is the unidentified flag, but we always return the identified name + // of the item here, so we ignore it + bool is_present = item.data1[4] & 0x40; + uint8_t special_id = item.data1[4] & 0x3F; + if (is_present) { + ret_tokens.emplace_back("Wrapped"); + } + if (special_id) { + try { + ret_tokens.emplace_back(name_for_weapon_special.at(special_id)); + } catch (const out_of_range&) { + ret_tokens.emplace_back(string_printf("!SP:%02hhX", special_id)); + } + } + } + if ((item.data1[0] == 0x00) && (item.data1[2] != 0x00) && item.is_s_rank_weapon()) { + try { + ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2])); + } catch (const out_of_range&) { + ret_tokens.emplace_back(string_printf("!SSP:%02hhX", item.data1[2])); + } + } + + // Armors, shields, and units (0x01) can be wrapped, as can mags (0x02) and + // non-stackable tools (0x03). However, each of these item classes has its + // flags in a different location. + if (((item.data1[1] == 0x01) && (item.data1[4] & 0x40)) || + ((item.data1[0] == 0x02) && (item.data2[2] & 0x40)) || + ((item.data1[0] == 0x03) && !item.is_stackable() && (item.data1[3] & 0x40))) { + ret_tokens.emplace_back("Wrapped"); + } + + // Add the item name. Technique disks are special because the level is part of + // the primary identifier, so we manually generate the name instead of looking + // it up. + uint32_t primary_identifier = item.primary_identifier(); + if ((primary_identifier & 0xFFFFFF00) == 0x00030200) { + string technique_name; + try { + technique_name = tech_id_to_name.at(item.data1[4]); + technique_name[0] = toupper(technique_name[0]); + } catch (const out_of_range&) { + technique_name = string_printf("!TECH:%02hhX", item.data1[4]); + } + // Hide the level for Reverser and Ryuker, unless the level isn't 1 + if ((item.data1[2] == 0) && ((item.data1[4] == 0x0E) || (item.data1[4] == 0x11))) { + ret_tokens.emplace_back(string_printf("Disk:%s", technique_name.c_str())); + } else { + ret_tokens.emplace_back(string_printf("Disk:%s Lv.%d", technique_name.c_str(), item.data1[2] + 1)); + } + } else { + try { + auto meta = this->primary_identifier_index.at(primary_identifier); + const string* name; + switch (version) { + case GameVersion::DC: + case GameVersion::PC: + name = &meta->v2_name; + break; + case GameVersion::GC: + case GameVersion::XB: + name = &meta->v3_name; + break; + case GameVersion::BB: + name = &meta->v4_name; + break; + default: + throw logic_error("invalid game version"); + } + if (name->empty()) { + throw out_of_range("item does not exist"); + } + ret_tokens.emplace_back(*name); + + } catch (const out_of_range&) { + ret_tokens.emplace_back(string_printf("!ID:%06" PRIX32, primary_identifier)); + } + } + + // For weapons, add the grind and percentages, or S-rank name if applicable + if (item.data1[0] == 0x00) { + if (item.data1[3] > 0) { + ret_tokens.emplace_back(string_printf("+%hhu", item.data1[3])); + } + + if (item.is_s_rank_weapon()) { + // S-rank (has name instead of percent bonuses) + uint8_t char_indexes[8] = { + static_cast((item.data1w[3] >> 5) & 0x1F), + static_cast(item.data1w[3] & 0x1F), + static_cast((item.data1w[4] >> 10) & 0x1F), + static_cast((item.data1w[4] >> 5) & 0x1F), + static_cast(item.data1w[4] & 0x1F), + static_cast((item.data1w[5] >> 10) & 0x1F), + static_cast((item.data1w[5] >> 5) & 0x1F), + static_cast(item.data1w[5] & 0x1F), + }; + + string name; + for (size_t x = 0; x < 8; x++) { + char ch = s_rank_name_characters[char_indexes[x]]; + if (ch == 0) { + break; + } + name += ch; + } + if (!name.empty()) { + ret_tokens.emplace_back("(" + name + ")"); + } + + } else { // Not S-rank (extended name bits not set) + parray percentages(0); + for (size_t x = 0; x < 3; x++) { + uint8_t which = item.data1[6 + 2 * x]; + uint8_t value = item.data1[7 + 2 * x]; + if (which == 0) { + continue; + } + if (which > 5) { + ret_tokens.emplace_back(string_printf("!PC:%02hhX%02hhX", which, value)); + } else { + percentages[which - 1] = value; + } + } + if (!percentages.is_filled_with(0)) { + ret_tokens.emplace_back(string_printf("%hhd/%hhd/%hhd/%hhd/%hhd", + percentages[0], percentages[1], percentages[2], percentages[3], percentages[4])); + } + } + + // For armors, add the slots, unit modifiers, and/or DEF/EVP bonuses + } else if (item.data1[0] == 0x01) { + if (item.data1[1] == 0x03) { // Units + uint16_t modifier = (item.data1[8] << 8) | item.data1[7]; + if (modifier == 0x0001 || modifier == 0x0002) { + ret_tokens.back().append("+"); + } else if (modifier == 0x0003 || modifier == 0x0004) { + ret_tokens.back().append("++"); + } else if (modifier == 0xFFFF || modifier == 0xFFFE) { + ret_tokens.back().append("-"); + } else if (modifier == 0xFFFD || modifier == 0xFFFC) { + ret_tokens.back().append("--"); + } else if (modifier != 0x0000) { + ret_tokens.emplace_back(string_printf("!MD:%04hX", modifier)); + } + + } else { // Armor/shields + if (item.data1[5] > 0) { + if (item.data1[5] == 1) { + ret_tokens.emplace_back("(1 slot)"); + } else { + ret_tokens.emplace_back(string_printf("(%hhu slots)", item.data1[5])); + } + } + if (item.data1w[3] != 0) { + ret_tokens.emplace_back(string_printf("+%hdDEF", + static_cast(item.data1w[3].load()))); + } + if (item.data1w[4] != 0) { + ret_tokens.emplace_back(string_printf("+%hdEVP", + static_cast(item.data1w[4].load()))); + } + } + + // For mags, add tons of info + } else if (item.data1[0] == 0x02) { + ret_tokens.emplace_back(string_printf("LV%hhu", item.data1[2])); + + uint16_t def = item.data1w[2]; + uint16_t pow = item.data1w[3]; + uint16_t dex = item.data1w[4]; + uint16_t mind = item.data1w[5]; + auto format_stat = +[](uint16_t stat) -> string { + uint16_t level = stat / 100; + uint8_t partial = stat % 100; + if (partial == 0) { + return string_printf("%hu", level); + } else if (partial % 10 == 0) { + return string_printf("%hu.%hhu", level, static_cast(partial / 10)); + } else { + return string_printf("%hu.%02hhu", level, partial); + } + }; + ret_tokens.emplace_back(format_stat(def) + "/" + format_stat(pow) + "/" + format_stat(dex) + "/" + format_stat(mind)); + ret_tokens.emplace_back(string_printf("%hhu%%", item.data2[0])); + ret_tokens.emplace_back(string_printf("%hhuIQ", item.data2[1])); + + uint8_t flags = item.data2[2]; + if (flags & 7) { + static const vector pb_shortnames = { + "F", "E", "G", "P", "L", "M&Y", "MG", "GR"}; + + const char* pb_names[3] = {nullptr, nullptr, nullptr}; + uint8_t left_pb = item.mag_photon_blast_for_slot(2); + uint8_t center_pb = item.mag_photon_blast_for_slot(0); + uint8_t right_pb = item.mag_photon_blast_for_slot(1); + if (left_pb != 0xFF) { + pb_names[0] = pb_shortnames[left_pb]; + } + if (center_pb != 0xFF) { + pb_names[1] = pb_shortnames[center_pb]; + } + if (right_pb != 0xFF) { + pb_names[2] = pb_shortnames[right_pb]; + } + + string token = "PB:"; + for (size_t x = 0; x < 3; x++) { + if (pb_names[x] == nullptr) { + continue; + } + if (token.size() > 3) { + token += ','; + } + token += pb_names[x]; + } + ret_tokens.emplace_back(std::move(token)); + } + + try { + ret_tokens.emplace_back(string_printf("(%s)", name_for_mag_color.at(item.data2[3]))); + } catch (const out_of_range&) { + ret_tokens.emplace_back(string_printf("(!CL:%02hhX)", item.data2[3])); + } + + // For tools, add the amount (if applicable) + } else if (item.data1[0] == 0x03) { + if (item.max_stack_size() > 1) { + ret_tokens.emplace_back(string_printf("x%hhu", item.data1[5])); + } + } + + string ret = join(ret_tokens, " "); + if (item_parameter_table) { + if (item.is_s_rank_weapon()) { + return "$C4" + ret; + } else if (item_parameter_table->is_item_rare(item)) { + return "$C6" + ret; + } else if (item.has_bonuses()) { + return "$C2" + ret; + } else { + return "$C7" + ret; + } + } else { + return ret; + } +} + +ItemData ItemNameIndex::parse_item_description(GameVersion version, const std::string& desc) const { + try { + return this->parse_item_description_phase(version, desc, false); + } catch (const exception& e1) { + try { + return this->parse_item_description_phase(version, desc, true); + } catch (const exception& e2) { + try { + string data = parse_data_string(desc); + if (data.size() < 2) { + throw runtime_error("item code too short"); + } + if (data[0] > 4) { + throw runtime_error("invalid item class"); + } + if (data.size() > 16) { + throw runtime_error("item code too long"); + } + + ItemData ret; + if (data.size() <= 12) { + memcpy(ret.data1.data(), data.data(), data.size()); + } else { + memcpy(ret.data1.data(), data.data(), 12); + memcpy(ret.data2.data(), data.data() + 12, data.size() - 12); + } + return ret; + } catch (const exception& ed) { + if (strcmp(e1.what(), e2.what())) { + throw runtime_error(string_printf("cannot parse item description (as text 1: %s) (as text 2: %s) (as data: %s)", e1.what(), e2.what(), ed.what())); + } else { + throw runtime_error(string_printf("cannot parse item description (as text: %s) (as data: %s)", e1.what(), ed.what())); + } + } + } + } +} + +ItemData ItemNameIndex::parse_item_description_phase(GameVersion version, const std::string& description, bool skip_special) const { + ItemData ret; + ret.data1d.clear(0); + ret.id = 0xFFFFFFFF; + ret.data2d = 0; + + string desc = tolower(description); + if (ends_with(desc, " meseta")) { + ret.data1[0] = 0x04; + ret.data2d = stol(desc, nullptr, 10); + return ret; + } + + if (starts_with(desc, "disk:")) { + auto tokens = split(desc, ' '); + tokens[0] = tokens[0].substr(5); // Trim off "disk:" + if ((tokens[0] == "reverser") || (tokens[0] == "ryuker")) { + uint8_t tech = technique_for_name(tokens[0]); + ret.data1[0] = 0x03; + ret.data1[1] = 0x02; + ret.data1[2] = 0x00; + ret.data1[4] = tech; + } else { + if (tokens.size() != 2) { + throw runtime_error("invalid tech disk format"); + } + if (!starts_with(tokens[1], "lv.")) { + throw runtime_error("invalid tech disk level"); + } + uint8_t tech = technique_for_name(tokens[0]); + uint8_t level = stoul(tokens[1].substr(3), nullptr, 10) - 1; + ret.data1[0] = 0x03; + ret.data1[1] = 0x02; + ret.data1[2] = level; + ret.data1[4] = tech; + } + return ret; + } + + bool is_wrapped = starts_with(desc, "wrapped "); + if (is_wrapped) { + desc = desc.substr(8); + } + + // TODO: It'd be nice to be able to parse S-rank weapon specials here too. + uint8_t weapon_special = 0; + if (!skip_special) { + for (size_t z = 0; z < name_for_weapon_special.size(); z++) { + if (!name_for_weapon_special[z]) { + continue; + } + string prefix = tolower(name_for_weapon_special[z]); + prefix += ' '; + if (starts_with(desc, prefix)) { + weapon_special = z; + desc = desc.substr(prefix.size()); + break; + } + } + } + + const map>* name_index; + switch (version) { + case GameVersion::DC: + case GameVersion::PC: + name_index = &this->v2_name_index; + break; + case GameVersion::GC: + case GameVersion::XB: + name_index = &this->v3_name_index; + break; + case GameVersion::BB: + name_index = &this->v4_name_index; + break; + default: + throw logic_error("invalid game version"); + } + + auto name_it = name_index->lower_bound(desc); + // Look up to 3 places before the lower bound. We have to do this to catch + // cases like Sange vs. Sange & Yasha - if the input is like "Sange 0/...", + // then we'll see Sange & Yasha first, which we should skip. + size_t lookback = 0; + while (lookback < 4) { + if (name_it != name_index->end() && desc.starts_with(name_it->first)) { + break; + } else if (name_it == name_index->begin()) { + throw runtime_error("no such item"); + } else { + name_it--; + lookback++; + } + } + if (lookback >= 4) { + throw runtime_error("item not found: " + desc); + } + + desc = desc.substr(name_it->first.size()); + if (starts_with(desc, " ")) { + desc = desc.substr(1); + } + + uint32_t primary_identifier = name_it->second->primary_identifier; + ret.data1[0] = (primary_identifier >> 16) & 0xFF; + ret.data1[1] = (primary_identifier >> 8) & 0xFF; + ret.data1[2] = primary_identifier & 0xFF; + + if (ret.data1[0] == 0x00) { + // Weapons: add special, grind and percentages (or name, if S-rank) + ret.data1[4] = weapon_special | (is_wrapped ? 0x40 : 0x00); + + auto tokens = split(desc, ' '); + for (auto& token : tokens) { + if (token.empty()) { + continue; + } + if (starts_with(token, "+")) { + token = token.substr(1); + ret.data1[3] = stoul(token, nullptr, 10); + + } else if (ret.is_s_rank_weapon()) { + if (token.size() > 8) { + throw runtime_error("s-rank name too long"); + } + + uint8_t char_indexes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + for (size_t z = 0; z < token.size(); z++) { + char ch = toupper(token[z]); + const char* pos = strchr(s_rank_name_characters, ch); + if (!pos) { + throw runtime_error(string_printf("s-rank name contains invalid character %02hhX (%c)", ch, ch)); + } + char_indexes[z] = (pos - s_rank_name_characters); + } + + ret.data1w[3] = (char_indexes[1] & 0x1F) | ((char_indexes[0] & 0x1F) << 5); + ret.data1w[4] = (char_indexes[4] & 0x1F) | ((char_indexes[3] & 0x1F) << 5) | ((char_indexes[2] & 0x1F) << 10); + ret.data1w[5] = (char_indexes[7] & 0x1F) | ((char_indexes[6] & 0x1F) << 5) | ((char_indexes[5] & 0x1F) << 10); + + } else { + auto p_tokens = split(token, '/'); + if (p_tokens.size() > 5) { + throw runtime_error("invalid bonuses token"); + } + uint8_t bonus_index = 0; + for (size_t z = 0; z < p_tokens.size(); z++) { + int8_t bonus_value = stol(p_tokens[z], nullptr, 10); + if (bonus_value == 0) { + continue; + } + if (bonus_index >= 3) { + throw runtime_error("weapon has too many bonuses"); + } + ret.data1[6 + (2 * bonus_index)] = z + 1; + ret.data1[7 + (2 * bonus_index)] = static_cast(bonus_value); + bonus_index++; + } + } + } + + } else if (ret.data1[0] == 0x01) { + if (ret.data1[1] == 0x03) { // Unit + static const unordered_map modifiers({ + {"--", 0xFFFC}, + {"-", 0xFFFE}, + {"", 0x0000}, + {"+", 0x0002}, + {"++", 0x0004}, + }); + uint16_t modifier = modifiers.at(desc); + ret.data1[7] = modifier & 0xFF; + ret.data1[8] = (modifier >> 8) & 0xFF; + + } else { // Armor/shield + for (const auto& token : split(desc, ' ')) { + if (token.empty()) { + continue; + } else if (!starts_with(token, "+")) { + throw runtime_error("invalid armor/shield modifier"); + } + if (ends_with(token, "def")) { + ret.data1w[3] = static_cast(stol(token.substr(1, token.size() - 4), nullptr, 10)); + } else if (ends_with(token, "evp")) { + ret.data1w[4] = static_cast(stol(token.substr(1, token.size() - 4), nullptr, 10)); + } else { + ret.data1[5] = stoul(token.substr(1), nullptr, 10); + } + } + } + + if (is_wrapped) { + ret.data1[4] |= 0x40; + } + + } else if (ret.data1[0] == 0x02) { + for (const auto& token : split(desc, ' ')) { + if (token.empty()) { + continue; + } else if (starts_with(token, "pb:")) { // Photon blasts + auto pb_tokens = split(token.substr(3), ','); + if (pb_tokens.size() > 3) { + throw runtime_error("too many photon blasts specified"); + } + static const unordered_map name_to_pb_num({ + {"f", 0}, + {"e", 1}, + {"g", 2}, + {"p", 3}, + {"l", 4}, + {"m&y", 5}, + }); + for (const auto& pb_token : pb_tokens) { + ret.add_mag_photon_blast(name_to_pb_num.at(pb_token)); + } + } else if (ends_with(token, "%")) { // Synchro + ret.data2[0] = stoul(token.substr(0, token.size() - 1), nullptr, 10); + } else if (ends_with(token, "iq")) { // IQ + ret.data2[1] = stoul(token.substr(0, token.size() - 2), nullptr, 10); + } else if (!token.empty() && isdigit(token[0])) { // Stats + auto s_tokens = split(token, '/'); + if (s_tokens.size() != 4) { + throw runtime_error("incorrect stat count"); + } + for (size_t z = 0; z < 4; z++) { + auto n_tokens = split(s_tokens[z], '.'); + if (n_tokens.size() == 0 || n_tokens.size() > 2) { + throw logic_error("incorrect stats argument format"); + } else if ((n_tokens.size() == 1) || (n_tokens[1].size() == 0)) { + ret.data1w[z + 2] = stoul(n_tokens[0], nullptr, 10) * 100; + } else if (n_tokens[1].size() == 1) { + ret.data1w[z + 2] = stoul(n_tokens[0], nullptr, 10) * 100 + stoul(n_tokens[1], nullptr, 10) * 10; + } else if (n_tokens[1].size() == 2) { + ret.data1w[z + 2] = stoul(n_tokens[0], nullptr, 10) * 100 + stoul(n_tokens[1], nullptr, 10); + } else { + throw runtime_error("incorrect stat format"); + } + } + ret.data1[2] = ret.compute_mag_level(); + } else { // Color + ret.data2[3] = mag_color_for_name.at(token); + } + } + + if (is_wrapped) { + ret.data2[2] |= 0x40; + } + } else if (ret.data1[0] == 0x03) { + if (ret.max_stack_size() > 1) { + if (starts_with(desc, "x")) { + ret.data1[5] = stoul(desc.substr(1), nullptr, 10); + } else { + ret.data1[5] = 1; + } + } else if (!desc.empty()) { + throw runtime_error("item cannot be stacked"); + } + + if (is_wrapped) { + if (ret.is_stackable()) { + throw runtime_error("stackable items cannot be wrapped"); + } else { + ret.data1[3] |= 0x40; + } + } + } else { + throw logic_error("invalid item class"); + } + + return ret; +} diff --git a/src/ItemNameIndex.hh b/src/ItemNameIndex.hh new file mode 100644 index 00000000..d94e576a --- /dev/null +++ b/src/ItemNameIndex.hh @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "ItemData.hh" +#include "ItemParameterTable.hh" + +class ItemNameIndex { +public: + ItemNameIndex(JSON&& v2_names, JSON&& v3_names, JSON&& v4_names); + + std::string describe_item( + GameVersion version, + const ItemData& item, + std::shared_ptr item_parameter_table = nullptr) const; + ItemData parse_item_description(GameVersion version, const std::string& description) const; + +private: + ItemData parse_item_description_phase(GameVersion version, const std::string& description, bool skip_special) const; + + struct ItemMetadata { + uint32_t primary_identifier; + std::string v2_name; + std::string v3_name; + std::string v4_name; + }; + + std::unordered_map> primary_identifier_index; + std::map> v2_name_index; + std::map> v3_name_index; + std::map> v4_name_index; +}; diff --git a/src/ItemParameterTable.cc b/src/ItemParameterTable.cc index 7117d43c..97749647 100644 --- a/src/ItemParameterTable.cc +++ b/src/ItemParameterTable.cc @@ -2,70 +2,404 @@ using namespace std; -ItemParameterTable::ItemParameterTable(shared_ptr data) +ItemParameterTable::ItemParameterTable(shared_ptr data, Version version) : data(data), - r(*data) { - size_t offset_table_offset = this->r.pget_u32l(this->data->size() - 0x10); - this->offsets = &r.pget(offset_table_offset); + r(*data), + offsets_v2(nullptr), + offsets_v3(nullptr), + offsets_v4(nullptr) { + switch (version) { + case Version::V2: { + size_t offset_table_offset = this->r.pget_u32l(this->data->size() - 0x10); + this->offsets_v2 = &this->r.pget(offset_table_offset); + this->num_weapon_classes = 0x89; + this->num_tool_classes = 0x10; + this->item_stars_first_id = 0x4E; + this->item_stars_last_id = 0x215; + this->special_stars_begin_index = 0x138; + this->star_value_table_size = 0x1C7; + break; + } + case Version::V3: { + size_t offset_table_offset = this->r.pget_u32b(this->data->size() - 0x10); + this->offsets_v3 = &this->r.pget>(offset_table_offset); + this->num_weapon_classes = 0xAA; + this->num_tool_classes = 0x18; + this->item_stars_first_id = 0x94; + this->item_stars_last_id = 0x2F7; + this->special_stars_begin_index = 0x1CB; + this->star_value_table_size = 0x263; + break; + } + case Version::V4: { + size_t offset_table_offset = this->r.pget_u32l(this->data->size() - 0x10); + this->offsets_v4 = &this->r.pget>(offset_table_offset); + this->num_weapon_classes = 0xED; + this->num_tool_classes = 0x1B; + this->item_stars_first_id = 0xB1; + this->item_stars_last_id = 0x437; + this->special_stars_begin_index = 0x256; + this->star_value_table_size = 0x330; + break; + } + default: + throw logic_error("invalid item parameter table version"); + } + + this->num_specials = 0x29; + this->first_rare_mag_index = 0x28; } -const ItemParameterTable::Weapon& ItemParameterTable::get_weapon( - uint8_t data1_1, uint8_t data1_2) const { - if (data1_1 >= 0xED) { +const ItemParameterTable::WeaponV4& ItemParameterTable::get_weapon(uint8_t data1_1, uint8_t data1_2) const { + if (data1_1 >= this->num_weapon_classes) { throw runtime_error("weapon ID out of range"); } - const auto& co = this->r.pget( - this->offsets->weapon_table + sizeof(CountAndOffset) * data1_1); - if (data1_2 >= co.count) { - throw runtime_error("weapon ID out of range"); + + if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->weapon_table + sizeof(ArrayRefLE) * data1_1); + if (data1_2 >= co.count) { + throw runtime_error("weapon ID out of range"); + } + return this->r.pget(co.offset + sizeof(WeaponV4) * data1_2); + } + + uint16_t key = (data1_1 << 8) | data1_2; + try { + return this->parsed_weapons.at(key); + } catch (const std::out_of_range&) { + auto& def_v4 = this->parsed_weapons.emplace(key, WeaponV4{}).first->second; + + if (this->offsets_v2) { + const auto& co = this->r.pget(this->offsets_v2->weapon_table + sizeof(ArrayRefLE) * data1_1); + if (data1_2 >= co.count) { + throw runtime_error("weapon ID out of range"); + } + const auto& def_v2 = this->r.pget(co.offset + sizeof(WeaponV2) * data1_2); + def_v4.base.id = def_v2.base.id; + def_v4.class_flags = def_v2.class_flags; + def_v4.atp_min = def_v2.atp_min; + def_v4.atp_max = def_v2.atp_max; + def_v4.atp_required = def_v2.atp_required; + def_v4.mst_required = def_v2.mst_required; + def_v4.ata_required = def_v2.ata_required; + def_v4.max_grind = def_v2.max_grind; + def_v4.photon = def_v2.photon; + def_v4.special = def_v2.special; + def_v4.ata = def_v2.ata; + + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->weapon_table + sizeof(ArrayRefBE) * data1_1); + if (data1_2 >= co.count) { + throw runtime_error("weapon ID out of range"); + } + const auto& def_v3 = this->r.pget>(co.offset + sizeof(WeaponV3) * data1_2); + def_v4.base.id = def_v3.base.id.load(); + def_v4.base.type = def_v3.base.type.load(); + def_v4.base.skin = def_v3.base.skin.load(); + def_v4.class_flags = def_v3.class_flags.load(); + def_v4.atp_min = def_v3.atp_min.load(); + def_v4.atp_max = def_v3.atp_max.load(); + def_v4.atp_required = def_v3.atp_required.load(); + def_v4.mst_required = def_v3.mst_required.load(); + def_v4.ata_required = def_v3.ata_required.load(); + def_v4.mst = def_v3.mst.load(); + def_v4.max_grind = def_v3.max_grind; + def_v4.photon = def_v3.photon; + def_v4.special = def_v3.special; + def_v4.ata = def_v3.ata; + def_v4.stat_boost = def_v3.stat_boost; + def_v4.projectile = def_v3.projectile; + def_v4.trail1_x = def_v3.trail1_x; + def_v4.trail1_y = def_v3.trail1_y; + def_v4.trail2_x = def_v3.trail2_x; + def_v4.trail2_y = def_v3.trail2_y; + def_v4.color = def_v3.color; + def_v4.unknown_a1 = def_v3.unknown_a1; + def_v4.unknown_a2 = def_v3.unknown_a2; + def_v4.unknown_a3 = def_v3.unknown_a3; + def_v4.unknown_a4 = def_v3.unknown_a4; + def_v4.unknown_a5 = def_v3.unknown_a5; + def_v4.tech_boost = def_v3.tech_boost; + def_v4.combo_type = def_v3.combo_type; + + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + return def_v4; } - return this->r.pget(co.offset + sizeof(Weapon) * data1_2); } -const ItemParameterTable::ArmorOrShield& ItemParameterTable::get_armor_or_shield( - uint8_t data1_1, uint8_t data1_2) const { +const ItemParameterTable::ArmorOrShieldV4& ItemParameterTable::get_armor_or_shield(uint8_t data1_1, uint8_t data1_2) const { if ((data1_1 < 1) || (data1_1 > 2)) { - throw runtime_error("armor/shield ID out of range"); + throw runtime_error("armor/shield class ID out of range"); } - const auto& co = this->r.pget( - this->offsets->armor_table + sizeof(CountAndOffset) * (data1_1 - 1)); - if (data1_2 >= co.count) { - throw runtime_error("armor/shield ID out of range"); + + if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->armor_table + sizeof(ArrayRefLE) * (data1_1 - 1)); + if (data1_2 >= co.count) { + throw runtime_error("armor/shield ID out of range"); + } + return this->r.pget(co.offset + sizeof(ArmorOrShieldV4) * data1_2); + } + + auto& parsed_vec = (data1_1 == 2) ? this->parsed_shields : this->parsed_armors; + try { + const auto& ret = parsed_vec.at(data1_2); + if (ret.base.id == 0xFFFFFFFF) { + throw out_of_range("cache entry not populated"); + } + return ret; + } catch (const std::out_of_range&) { + if (data1_2 <= parsed_vec.size()) { + parsed_vec.resize(data1_2 + 1); + } + auto& def_v4 = parsed_vec[data1_2]; + + if (this->offsets_v2) { + const auto& co = this->r.pget(this->offsets_v2->armor_table + sizeof(ArrayRefLE) * (data1_1 - 1)); + if (data1_2 >= co.count) { + throw runtime_error("armor/shield ID out of range"); + } + const auto& def_v2 = this->r.pget(co.offset + sizeof(ArmorOrShieldV2) * data1_2); + def_v4.base.id = def_v2.base.id; + def_v4.dfp = def_v2.dfp; + def_v4.evp = def_v2.evp; + def_v4.block_particle = def_v2.block_particle; + def_v4.block_effect = def_v2.block_effect; + def_v4.class_flags = def_v2.class_flags; + def_v4.required_level = def_v2.required_level; + def_v4.efr = def_v2.efr; + def_v4.eth = def_v2.eth; + def_v4.eic = def_v2.eic; + def_v4.edk = def_v2.edk; + def_v4.elt = def_v2.elt; + def_v4.dfp_range = def_v2.dfp_range; + def_v4.evp_range = def_v2.evp_range; + def_v4.stat_boost = def_v2.stat_boost; + def_v4.tech_boost = def_v2.tech_boost; + def_v4.unknown_a2 = def_v2.unknown_a2; + + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->armor_table + sizeof(ArrayRefBE) * (data1_1 - 1)); + if (data1_2 >= co.count) { + throw runtime_error("armor/shield ID out of range"); + } + const auto& def_v3 = this->r.pget(co.offset + sizeof(ArmorOrShieldV3) * data1_2); + def_v4.base.id = def_v3.base.id.load(); + def_v4.base.type = def_v3.base.type.load(); + def_v4.base.skin = def_v3.base.skin.load(); + def_v4.dfp = def_v3.dfp.load(); + def_v4.evp = def_v3.evp.load(); + def_v4.block_particle = def_v3.block_particle; + def_v4.block_effect = def_v3.block_effect; + def_v4.class_flags = def_v3.class_flags.load(); + def_v4.required_level = def_v3.required_level; + def_v4.efr = def_v3.efr; + def_v4.eth = def_v3.eth; + def_v4.eic = def_v3.eic; + def_v4.edk = def_v3.edk; + def_v4.elt = def_v3.elt; + def_v4.dfp_range = def_v3.dfp_range; + def_v4.evp_range = def_v3.evp_range; + def_v4.stat_boost = def_v3.stat_boost; + def_v4.tech_boost = def_v3.tech_boost; + def_v4.unknown_a2 = def_v3.unknown_a2.load(); + + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + return def_v4; } - return this->r.pget(co.offset + sizeof(ArmorOrShield) * data1_2); } -const ItemParameterTable::Unit& ItemParameterTable::get_unit( - uint8_t data1_2) const { - const auto& co = this->r.pget(this->offsets->unit_table); - if (data1_2 >= co.count) { - throw runtime_error("unit ID out of range"); +const ItemParameterTable::UnitV4& ItemParameterTable::get_unit(uint8_t data1_2) const { + if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->unit_table); + if (data1_2 >= co.count) { + throw runtime_error("unit ID out of range"); + } + return this->r.pget(co.offset + sizeof(UnitV4) * data1_2); + } + + try { + const auto& ret = this->parsed_units.at(data1_2); + if (ret.base.id == 0xFFFFFFFF) { + throw out_of_range("cache entry not populated"); + } + return ret; + } catch (const std::out_of_range&) { + if (data1_2 <= this->parsed_units.size()) { + this->parsed_units.resize(data1_2 + 1); + } + auto& def_v4 = this->parsed_units[data1_2]; + + if (this->offsets_v2) { + const auto& co = this->r.pget(this->offsets_v2->unit_table); + if (data1_2 >= co.count) { + throw runtime_error("unit ID out of range"); + } + const auto& def_v2 = this->r.pget(co.offset + sizeof(UnitV2) * data1_2); + def_v4.base.id = def_v2.base.id; + def_v4.stat = def_v2.stat; + def_v4.stat_amount = def_v2.stat_amount; + def_v4.modifier_amount = def_v2.modifier_amount; + + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->unit_table); + if (data1_2 >= co.count) { + throw runtime_error("unit ID out of range"); + } + const auto& def_v3 = this->r.pget(co.offset + sizeof(UnitV3) * data1_2); + def_v4.base.id = def_v3.base.id.load(); + def_v4.base.type = def_v3.base.type.load(); + def_v4.base.skin = def_v3.base.skin.load(); + def_v4.stat = def_v3.stat.load(); + def_v4.stat_amount = def_v3.stat_amount.load(); + def_v4.modifier_amount = def_v3.modifier_amount.load(); + + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + return def_v4; } - return this->r.pget(co.offset + sizeof(Unit) * data1_2); } -const ItemParameterTable::Tool& ItemParameterTable::get_tool( - uint8_t data1_1, uint8_t data1_2) const { - if (data1_1 > 0x1A) { - throw runtime_error("tool ID out of range"); +const ItemParameterTable::MagV4& ItemParameterTable::get_mag(uint8_t data1_1) const { + if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->mag_table); + if (data1_1 >= co.count) { + throw runtime_error("mag ID out of range"); + } + return this->r.pget(co.offset + sizeof(MagV4) * data1_1); } - const auto& co = this->r.pget( - this->offsets->tool_table + sizeof(CountAndOffset) * data1_1); - if (data1_2 >= co.count) { - throw runtime_error("tool ID out of range"); + + try { + const auto& ret = this->parsed_mags.at(data1_1); + if (ret.base.id == 0xFFFFFFFF) { + throw out_of_range("cache entry not populated"); + } + return ret; + } catch (const std::out_of_range&) { + if (data1_1 <= this->parsed_mags.size()) { + this->parsed_mags.resize(data1_1 + 1); + } + auto& def_v4 = this->parsed_mags[data1_1]; + + if (this->offsets_v2) { + const auto& co = this->r.pget(this->offsets_v2->mag_table); + if (data1_1 >= co.count) { + throw runtime_error("mag ID out of range"); + } + const auto& def_v2 = this->r.pget(co.offset + sizeof(MagV2) * data1_1); + def_v4.base.id = def_v2.base.id; + def_v4.feed_table = def_v2.feed_table; + def_v4.photon_blast = def_v2.photon_blast; + def_v4.activation = def_v2.activation; + def_v4.on_pb_full = def_v2.on_pb_full; + def_v4.on_low_hp = def_v2.on_low_hp; + def_v4.on_death = def_v2.on_death; + def_v4.on_boss = def_v2.on_boss; + def_v4.on_pb_full_flag = def_v2.on_pb_full_flag; + def_v4.on_low_hp_flag = def_v2.on_low_hp_flag; + def_v4.on_death_flag = def_v2.on_death_flag; + def_v4.on_boss_flag = def_v2.on_boss_flag; + def_v4.class_flags = def_v2.class_flags; + + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->mag_table); + if (data1_1 >= co.count) { + throw runtime_error("mag ID out of range"); + } + const auto& def_v3 = this->r.pget(co.offset + sizeof(MagV3) * data1_1); + def_v4.base.id = def_v3.base.id.load(); + def_v4.base.type = def_v3.base.type.load(); + def_v4.base.skin = def_v3.base.skin.load(); + def_v4.feed_table = def_v3.feed_table.load(); + def_v4.photon_blast = def_v3.photon_blast; + def_v4.activation = def_v3.activation; + def_v4.on_pb_full = def_v3.on_pb_full; + def_v4.on_low_hp = def_v3.on_low_hp; + def_v4.on_death = def_v3.on_death; + def_v4.on_boss = def_v3.on_boss; + def_v4.on_pb_full_flag = def_v3.on_pb_full_flag; + def_v4.on_low_hp_flag = def_v3.on_low_hp_flag; + def_v4.on_death_flag = def_v3.on_death_flag; + def_v4.on_boss_flag = def_v3.on_boss_flag; + def_v4.class_flags = def_v3.class_flags.load(); + + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + return def_v4; } - return this->r.pget(co.offset + sizeof(Tool) * data1_2); } -pair ItemParameterTable::find_tool_by_class( - uint8_t tool_class) const { - const auto& cos = this->r.pget>( - this->offsets->tool_table); - for (size_t z = 0; z < cos.size(); z++) { +const ItemParameterTable::ToolV4& ItemParameterTable::get_tool(uint8_t data1_1, uint8_t data1_2) const { + if (data1_1 >= this->num_tool_classes) { + throw runtime_error("tool class ID out of range"); + } + + if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->tool_table + sizeof(ArrayRefLE) * data1_1); + if (data1_2 >= co.count) { + throw runtime_error("tool ID out of range"); + } + return this->r.pget(co.offset + sizeof(ToolV4) * data1_2); + } + + uint16_t key = (data1_1 << 8) | data1_2; + try { + return this->parsed_tools.at(key); + } catch (const std::out_of_range&) { + auto& def_v4 = this->parsed_tools.emplace(key, ToolV4{}).first->second; + + if (this->offsets_v2) { + const auto& co = this->r.pget(this->offsets_v2->tool_table + sizeof(ArrayRefLE) * data1_1); + if (data1_2 >= co.count) { + throw runtime_error("tool ID out of range"); + } + const auto& def_v2 = this->r.pget(co.offset + sizeof(ToolV2) * data1_2); + def_v4.base.id = def_v2.base.id; + def_v4.amount = def_v2.amount; + def_v4.tech = def_v2.tech; + def_v4.cost = def_v2.cost; + def_v4.item_flag = def_v2.item_flag; + + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->tool_table + sizeof(ArrayRefBE) * data1_1); + if (data1_2 >= co.count) { + throw runtime_error("tool ID out of range"); + } + const auto& def_v3 = this->r.pget(co.offset + sizeof(ToolV3) * data1_2); + def_v4.base.id = def_v3.base.id.load(); + def_v4.base.type = def_v3.base.type.load(); + def_v4.base.skin = def_v3.base.skin.load(); + def_v4.amount = def_v3.amount.load(); + def_v4.tech = def_v3.tech.load(); + def_v4.cost = def_v3.cost.load(); + def_v4.item_flag = def_v3.item_flag; + + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + return def_v4; + } +} + +template +pair ItemParameterTable::find_tool_by_id_t(uint32_t tool_table_offset, uint32_t item_id) const { + const auto* cos = &this->r.pget>( + tool_table_offset, this->num_tool_classes * sizeof(ArrayRef)); + for (size_t z = 0; z < this->num_tool_classes; z++) { const auto& co = cos[z]; - const auto* defs = &this->r.pget(co.offset, sizeof(Tool) * co.count); + const auto* defs = &this->r.pget(co.offset, sizeof(ToolT) * co.count); for (size_t y = 0; y < co.count; y++) { - if (defs[y].base.id == tool_class) { + if (defs[y].base.id == item_id) { return make_pair(z, y); } } @@ -73,43 +407,66 @@ pair ItemParameterTable::find_tool_by_class( throw runtime_error("invalid tool class"); } -const ItemParameterTable::Mag& ItemParameterTable::get_mag( - uint8_t data1_1) const { - const auto& co = this->r.pget(this->offsets->mag_table); - if (data1_1 >= co.count) { - throw runtime_error("unit ID out of range"); +pair ItemParameterTable::find_tool_by_id(uint32_t item_id) const { + if (this->offsets_v2) { + return this->find_tool_by_id_t(this->offsets_v2->tool_table, item_id); + } else if (this->offsets_v3) { + return this->find_tool_by_id_t(this->offsets_v3->tool_table, item_id); + } else if (this->offsets_v4) { + return this->find_tool_by_id_t(this->offsets_v4->tool_table, item_id); + } else { + throw logic_error("table is not v2, v3, or v4"); + } +} + +template +float ItemParameterTable::get_sale_divisor_t( + uint32_t weapon_table_offset, uint32_t non_weapon_table_offset, uint8_t data1_0, uint8_t data1_1) const { + using FloatT = typename std::conditional::type; + + switch (data1_0) { + case 0: + if (data1_1 >= this->num_weapon_classes) { + return 0.0f; + } + return this->r.pget(weapon_table_offset + data1_1 * sizeof(FloatT)); + + case 1: { + const auto& divisors = this->r.pget>(non_weapon_table_offset); + switch (data1_1) { + case 1: + return divisors.armor_divisor; + case 2: + return divisors.shield_divisor; + case 3: + return divisors.unit_divisor; + } + return 0.0f; + } + + case 2: { + const auto& divisors = this->r.pget>(non_weapon_table_offset); + return divisors.mag_divisor; + } + + default: + return 0.0f; } - return this->r.pget(co.offset + sizeof(Mag) * data1_1); } float ItemParameterTable::get_sale_divisor(uint8_t data1_0, uint8_t data1_1) const { - if (data1_0 == 0) { // Weapon - if (data1_1 < 0xED) { - return this->r.pget_f32l( - this->offsets->weapon_sale_divisor_table + data1_1 * sizeof(float)); - } - return 0.0f; + if (this->offsets_v2) { + return this->get_sale_divisor_t( + this->offsets_v2->weapon_sale_divisor_table, this->offsets_v2->sale_divisor_table, data1_0, data1_1); + } else if (this->offsets_v3) { + return this->get_sale_divisor_t( + this->offsets_v3->weapon_sale_divisor_table, this->offsets_v3->sale_divisor_table, data1_0, data1_1); + } else if (this->offsets_v4) { + return this->get_sale_divisor_t( + this->offsets_v4->weapon_sale_divisor_table, this->offsets_v4->sale_divisor_table, data1_0, data1_1); + } else { + throw logic_error("table is not v2, v3, or v4"); } - - const auto& divisors = this->r.pget( - this->offsets->sale_divisor_table); - if (data1_0 == 1) { - switch (data1_1) { - case 1: - return divisors.armor_divisor; - case 2: - return divisors.shield_divisor; - case 3: - return divisors.unit_divisor; - } - return 0.0f; - } - - if (data1_0 == 2) { - return divisors.mag_divisor; - } - - return 0.0f; } const ItemParameterTable::MagFeedResult& ItemParameterTable::get_mag_feed_result( @@ -120,33 +477,70 @@ const ItemParameterTable::MagFeedResult& ItemParameterTable::get_mag_feed_result if (item_index >= 11) { throw runtime_error("invalid mag feed item index"); } - const auto& table_offsets = this->r.pget(this->offsets->mag_feed_table); - const auto& results = this->r.pget(table_offsets.offsets[table_index]); - return results.results[item_index]; + + uint32_t offset; + if (this->offsets_v2) { + const auto& table_offsets = this->r.pget>(this->offsets_v2->mag_feed_table); + offset = table_offsets.offsets[table_index]; + } else if (this->offsets_v3) { + const auto& table_offsets = this->r.pget>(this->offsets_v3->mag_feed_table); + offset = table_offsets.offsets[table_index]; + } else if (this->offsets_v4) { + const auto& table_offsets = this->r.pget>(this->offsets_v4->mag_feed_table); + offset = table_offsets.offsets[table_index]; + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + return this->r.pget(offset)[item_index]; } -uint8_t ItemParameterTable::get_item_stars(uint16_t slot) const { - if ((slot >= 0xB1) && (slot < 0x437)) { - return this->r.pget_u8(this->offsets->star_value_table + slot - 0xB1); +uint8_t ItemParameterTable::get_item_stars(uint32_t item_id) const { + uint32_t base_offset; + if (this->offsets_v2) { + base_offset = this->offsets_v2->star_value_table; + } else if (this->offsets_v3) { + base_offset = this->offsets_v3->star_value_table; + } else if (this->offsets_v4) { + base_offset = this->offsets_v4->star_value_table; + } else { + throw logic_error("table is not v2, v3, or v4"); } - return 0; + + return ((item_id >= this->item_stars_first_id) && (item_id < this->item_stars_last_id)) + ? this->r.pget_u8(base_offset + item_id - this->item_stars_first_id) + : 0; } uint8_t ItemParameterTable::get_special_stars(uint8_t det) const { - if (!(det & 0x3F) || (det & 0x80)) { - return 0; - } - // Note: PSO GC uses 0x1CB here. 0x256 was chosen to point to the same data in - // PSO BB's ItemPMT file. - return this->get_item_stars(det + 0x0256); + return ((det & 0x3F) && !(det & 0x80)) + ? this->get_item_stars(det + this->special_stars_begin_index) + : 0; } -const ItemParameterTable::Special& ItemParameterTable::get_special(uint8_t special) const { +const ItemParameterTable::Special& ItemParameterTable::get_special(uint8_t special) const { special &= 0x3F; - if (special >= 0x29) { + if (special >= this->num_specials) { throw runtime_error("invalid special index"); } - return this->r.pget(this->offsets->special_data_table + sizeof(Special) * special); + + if (this->offsets_v2) { + return this->r.pget>(this->offsets_v2->special_data_table + sizeof(Special) * special); + } else if (this->offsets_v3) { + if ((this->parsed_specials.size() <= special) || (this->parsed_specials[special].type != 0xFFFF)) { + if (this->parsed_specials.size() <= special) { + this->parsed_specials.resize(special + 1); + } + const auto& sp_be = this->r.pget>(this->offsets_v3->special_data_table + sizeof(Special) * special); + this->parsed_specials[special].type = sp_be.type.load(); + this->parsed_specials[special].amount = sp_be.amount.load(); + } + return this->parsed_specials[special]; + } else if (this->offsets_v4) { + return this->r.pget>(this->offsets_v4->special_data_table + sizeof(Special) * special); + } else { + throw logic_error("table is not v2, v3, or v4"); + } } uint8_t ItemParameterTable::get_max_tech_level(uint8_t char_class, uint8_t tech_num) const { @@ -156,28 +550,42 @@ uint8_t ItemParameterTable::get_max_tech_level(uint8_t char_class, uint8_t tech_ if (tech_num >= 19) { throw runtime_error("invalid technique number"); } - return r.pget_u8(this->offsets->max_tech_level_table + tech_num * 12 + char_class); + + if (this->offsets_v2) { + if ((tech_num == 14) || (tech_num == 17)) { // Ryuker or Reverser + return 0; + } else if (tech_num == 16) { // Anti + return 7; + } else { + return ((char_class == 6) || (char_class == 7) || (char_class == 8) || (char_class == 10)) ? 29 : 14; + } + } else if (this->offsets_v3) { + return r.pget_u8(this->offsets_v3->max_tech_level_table + tech_num * 12 + char_class); + } else if (this->offsets_v4) { + return r.pget_u8(this->offsets_v4->max_tech_level_table + tech_num * 12 + char_class); + } else { + throw logic_error("table is not v2, v3, or v4"); + } } -const ItemParameterTable::ItemBase& ItemParameterTable::get_item_definition( - const ItemData& item) const { +uint32_t ItemParameterTable::get_item_id(const ItemData& item) const { switch (item.data1[0]) { case 0: - return this->get_weapon(item.data1[1], item.data1[2]).base; + return this->get_weapon(item.data1[1], item.data1[2]).base.id; case 1: if (item.data1[1] == 3) { - return this->get_unit(item.data1[2]).base; + return this->get_unit(item.data1[2]).base.id; } else if ((item.data1[1] == 1) || (item.data1[1] == 2)) { - return this->get_armor_or_shield(item.data1[1], item.data1[2]).base; + return this->get_armor_or_shield(item.data1[1], item.data1[2]).base.id; } throw runtime_error("invalid item"); case 2: - return this->get_mag(item.data1[1]).base; + return this->get_mag(item.data1[1]).base.id; case 3: if (item.data1[1] == 2) { - return this->get_tool(2, item.data1[4]).base; + return this->get_tool(2, item.data1[4]).base.id; } else { - return this->get_tool(item.data1[1], item.data1[2]).base; + return this->get_tool(item.data1[1], item.data1[2]).base.id; } throw logic_error("this should be impossible"); case 4: @@ -189,9 +597,9 @@ const ItemParameterTable::ItemBase& ItemParameterTable::get_item_definition( uint8_t ItemParameterTable::get_item_base_stars(const ItemData& item) const { if (item.data1[0] == 2) { - return (item.data1[1] > 0x27) ? 12 : 0; + return (item.data1[1] >= this->first_rare_mag_index) ? 12 : 0; } else if (item.data1[0] < 2) { - return this->get_item_stars(this->get_item_definition(item).id); + return this->get_item_stars(this->get_item_id(item)); } else if (item.data1[0] == 3) { const auto& def = (item.data1[1] == 2) ? this->get_tool(2, item.data1[4]) @@ -230,10 +638,23 @@ bool ItemParameterTable::is_item_rare(const ItemData& item) const { } bool ItemParameterTable::is_unsealable_item(const ItemData& item) const { - const auto& co = this->r.pget(this->offsets->unsealable_table); - const auto* defs = &this->r.pget( - co.offset, co.count * sizeof(UnsealableItem)); - for (size_t z = 0; z < co.count; z++) { + uint32_t offset, count; + if (this->offsets_v2) { + return false; + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->unsealable_table); + offset = co.offset; + count = co.count; + } else if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->unsealable_table); + offset = co.offset; + count = co.count; + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + const auto* defs = &this->r.pget(offset, count * sizeof(UnsealableItem)); + for (size_t z = 0; z < count; z++) { if ((defs[z].item[0] == item.data1[0]) && (defs[z].item[1] == item.data1[1]) && (defs[z].item[2] == item.data1[2])) { @@ -243,21 +664,6 @@ bool ItemParameterTable::is_unsealable_item(const ItemData& item) const { return false; } -void ItemParameterTable::populate_item_combination_index() const { - if (!this->item_combination_index.empty()) { - return; - } - - const auto& co = this->r.pget(this->offsets->combination_table); - const auto* defs = &this->r.pget( - co.offset, co.count * sizeof(ItemCombination)); - for (size_t z = 0; z < co.count; z++) { - const auto& def = defs[z]; - uint32_t key = (def.used_item[0] << 16) | (def.used_item[1] << 8) | def.used_item[2]; - this->item_combination_index[key].emplace_back(def); - } -} - const ItemParameterTable::ItemCombination& ItemParameterTable::get_item_combination( const ItemData& used_item, const ItemData& equipped_item) const { for (const auto& def : this->get_all_combinations_for_used_item(used_item)) { @@ -282,20 +688,57 @@ const std::vector& ItemParameterTable::get_ } const std::map>& ItemParameterTable::get_all_item_combinations() const { - this->populate_item_combination_index(); + if (this->item_combination_index.empty()) { + uint32_t offset, count; + if (this->offsets_v2) { + static const std::map> empty_map; + return empty_map; + } else if (this->offsets_v3) { + const auto& co = this->r.pget(this->offsets_v3->combination_table); + offset = co.offset; + count = co.count; + } else if (this->offsets_v4) { + const auto& co = this->r.pget(this->offsets_v4->combination_table); + offset = co.offset; + count = co.count; + } else { + throw logic_error("table is not v2, v3, or v4"); + } + + const auto* defs = &this->r.pget(offset, count * sizeof(ItemCombination)); + for (size_t z = 0; z < count; z++) { + const auto& def = defs[z]; + uint32_t key = (def.used_item[0] << 16) | (def.used_item[1] << 8) | def.used_item[2]; + this->item_combination_index[key].emplace_back(def); + } + } return this->item_combination_index; } -std::pair ItemParameterTable::get_event_items(uint8_t event_number) const { - const auto& co = this->r.pget(this->offsets->unwrap_table); +template +std::pair ItemParameterTable::get_event_items_t( + uint32_t base_offset, uint8_t event_number) const { + const auto& co = this->r.pget>(base_offset); if (event_number >= co.count) { throw runtime_error("invalid event number"); } - const auto& event_co = this->r.pget(co.offset + sizeof(CountAndOffset) * event_number); - const auto* defs = &this->r.pget(event_co.offset, event_co.count * sizeof(ItemCombination)); + const auto& event_co = this->r.pget>(co.offset + sizeof(ArrayRef) * event_number); + const auto* defs = &this->r.pget(event_co.offset, event_co.count * sizeof(EventItem)); return make_pair(defs, event_co.count); } +std::pair ItemParameterTable::get_event_items(uint8_t event_number) const { + if (this->offsets_v2) { + return make_pair(nullptr, 0); + } else if (this->offsets_v3) { + return this->get_event_items_t(this->offsets_v3->unwrap_table, event_number); + } else if (this->offsets_v4) { + return this->get_event_items_t(this->offsets_v4->unwrap_table, event_number); + } else { + throw logic_error("table is not v2, v3, or v4"); + } +} + size_t ItemParameterTable::price_for_item(const ItemData& item) const { switch (item.data1[0]) { case 0: { diff --git a/src/ItemParameterTable.hh b/src/ItemParameterTable.hh index 015d6935..3257ac71 100644 --- a/src/ItemParameterTable.hh +++ b/src/ItemParameterTable.hh @@ -13,58 +13,167 @@ class ItemParameterTable { public: - struct CountAndOffset { - le_uint32_t count; - le_uint32_t offset; + template + struct ArrayRef { + using U32T = typename std::conditional::type; + U32T count; + U32T offset; + } __attribute__((packed)); + struct ArrayRefLE : ArrayRef { + } __attribute__((packed)); + struct ArrayRefBE : ArrayRef { } __attribute__((packed)); - struct ItemBase { + template + struct ItemBaseV2 { + using U32T = typename std::conditional::type; // id specifies several things; notably, it doubles as the index of the // item's name in the text archive (e.g. TextEnglish) collection 0. - le_uint32_t id; - le_uint16_t type; - le_uint16_t skin; - le_uint32_t team_points; + U32T id = 0xFFFFFFFF; + } __attribute__((packed)); + template + struct ItemBaseV3 : ItemBaseV2 { + using U16T = typename std::conditional::type; + U16T type = 0; + U16T skin = 0; + } __attribute__((packed)); + template + struct ItemBaseV4 : ItemBaseV3 { + using U32T = typename std::conditional::type; + U32T team_points = 0; } __attribute__((packed)); + struct WeaponV2 { + ItemBaseV2 base; + le_uint16_t class_flags = 0; + le_uint16_t atp_min = 0; + le_uint16_t atp_max = 0; + le_uint16_t atp_required = 0; + le_uint16_t mst_required = 0; + le_uint16_t ata_required = 0; + uint8_t max_grind = 0; + uint8_t photon = 0; + uint8_t special = 0; + uint8_t ata = 0; + parray unknown_a9; + } __attribute__((packed)); + + template + struct WeaponV3 { + using U16T = typename std::conditional::type; + ItemBaseV3 base; + U16T class_flags = 0; + U16T atp_min = 0; + U16T atp_max = 0; + U16T atp_required = 0; + U16T mst_required = 0; + U16T ata_required = 0; + U16T mst = 0; + uint8_t max_grind = 0; + uint8_t photon = 0; + uint8_t special = 0; + uint8_t ata = 0; + uint8_t stat_boost = 0; + uint8_t projectile = 0; + int8_t trail1_x = 0; + int8_t trail1_y = 0; + int8_t trail2_x = 0; + int8_t trail2_y = 0; + int8_t color = 0; + uint8_t unknown_a1 = 0; + uint8_t unknown_a2 = 0; + uint8_t unknown_a3 = 0; + uint8_t unknown_a4 = 0; + uint8_t unknown_a5 = 0; + uint8_t tech_boost = 0; + uint8_t combo_type = 0; + } __attribute__((packed)); + + struct WeaponV4 { + ItemBaseV4 base; + le_uint16_t class_flags = 0x00FF; + le_uint16_t atp_min = 0; + le_uint16_t atp_max = 0; + le_uint16_t atp_required = 0; + le_uint16_t mst_required = 0; + le_uint16_t ata_required = 0; + le_uint16_t mst = 0; + uint8_t max_grind = 0; + uint8_t photon = 0; + uint8_t special = 0; + uint8_t ata = 0; + uint8_t stat_boost = 0; + uint8_t projectile = 0; + int8_t trail1_x = 0; + int8_t trail1_y = 0; + int8_t trail2_x = 0; + int8_t trail2_y = 0; + int8_t color = 0; + uint8_t unknown_a1 = 0; + uint8_t unknown_a2 = 0; + uint8_t unknown_a3 = 0; + uint8_t unknown_a4 = 0; + uint8_t unknown_a5 = 0; + uint8_t tech_boost = 0; + uint8_t combo_type = 0; + } __attribute__((packed)); + + template struct ArmorOrShield { - ItemBase base; - le_uint16_t dfp; - le_uint16_t evp; - uint8_t block_particle; - uint8_t block_effect; - uint8_t item_class; - uint8_t unknown_a1; - uint8_t required_level; - uint8_t efr; - uint8_t eth; - uint8_t eic; - uint8_t edk; - uint8_t elt; - uint8_t dfp_range; - uint8_t evp_range; - uint8_t stat_boost; - uint8_t tech_boost; - le_uint16_t unknown_a2; + using U16T = typename std::conditional::type; + BaseT base; + U16T dfp = 0; + U16T evp = 0; + uint8_t block_particle = 0; + uint8_t block_effect = 0; + U16T class_flags = 0x00FF; + uint8_t required_level = 0; + uint8_t efr = 0; + uint8_t eth = 0; + uint8_t eic = 0; + uint8_t edk = 0; + uint8_t elt = 0; + uint8_t dfp_range = 0; + uint8_t evp_range = 0; + uint8_t stat_boost = 0; + uint8_t tech_boost = 0; + U16T unknown_a2 = 0; + } __attribute__((packed)); + struct ArmorOrShieldV2 : ArmorOrShield, false> { + } __attribute__((packed)); + struct ArmorOrShieldV3 : ArmorOrShield, true> { + } __attribute__((packed)); + struct ArmorOrShieldV4 : ArmorOrShield, false> { } __attribute__((packed)); + template struct Unit { - ItemBase base; - le_uint16_t stat; - le_uint16_t stat_amount; - le_int16_t modifier_amount; + using U16T = typename std::conditional::type; + using S16T = typename std::conditional::type; + BaseT base; + U16T stat = 0; + U16T stat_amount = 0; + S16T modifier_amount = 0; parray unused; } __attribute__((packed)); + struct UnitV2 : Unit, false> { + } __attribute__((packed)); + struct UnitV3 : Unit, true> { + } __attribute__((packed)); + struct UnitV4 : Unit, false> { + } __attribute__((packed)); + template struct Mag { - ItemBase base; - le_uint16_t feed_table; - uint8_t photon_blast; - uint8_t activation; - uint8_t on_pb_full; - uint8_t on_low_hp; - uint8_t on_death; - uint8_t on_boss; + using U16T = typename std::conditional::type; + BaseT base; + U16T feed_table = 0; + uint8_t photon_blast = 0; + uint8_t activation = 0; + uint8_t on_pb_full = 0; + uint8_t on_low_hp = 0; + uint8_t on_death = 0; + uint8_t on_boss = 0; // These flags control how likely each effect is to activate. First, the // game computes step_synchro as follows: // if synchro in [0, 30], step_synchro = 0 @@ -80,172 +189,140 @@ public: // flag == 3 => activation - 10 // flag == 4 => step_synchro - 10 // anything else => 0 (effect never occurs) - uint8_t on_pb_full_flag; - uint8_t on_low_hp_flag; - uint8_t on_death_flag; - uint8_t on_boss_flag; - uint8_t item_class; - parray unused; + uint8_t on_pb_full_flag = 0; + uint8_t on_low_hp_flag = 0; + uint8_t on_death_flag = 0; + uint8_t on_boss_flag = 0; + U16T class_flags = 0x00FF; + parray unused; + } __attribute__((packed)); + struct MagV2 : Mag, false> { + } __attribute__((packed)); + struct MagV3 : Mag, true> { + } __attribute__((packed)); + struct MagV4 : Mag, false> { } __attribute__((packed)); + template struct Tool { - ItemBase base; - le_uint16_t amount; - le_uint16_t tech; - le_int32_t cost; - uint8_t item_flag; + using U16T = typename std::conditional::type; + using S32T = typename std::conditional::type; + BaseT base; + U16T amount = 0; + U16T tech = 0; + S32T cost = 0; + uint8_t item_flag = 0; parray unused; } __attribute__((packed)); - - struct Weapon { - ItemBase base; - uint8_t item_class; - uint8_t unknown_a0; - le_uint16_t atp_min; - le_uint16_t atp_max; - le_uint16_t atp_required; - le_uint16_t mst_required; - le_uint16_t ata_required; - le_uint16_t mst; - uint8_t max_grind; - uint8_t photon; - uint8_t special; - uint8_t ata; - uint8_t stat_boost; - uint8_t projectile; - int8_t trail1_x; - int8_t trail1_y; - int8_t trail2_x; - int8_t trail2_y; - int8_t color; - uint8_t unknown_a1; - uint8_t unknown_a2; - uint8_t unknown_a3; - uint8_t unknown_a4; - uint8_t unknown_a5; - uint8_t tech_boost; - uint8_t combo_type; + struct ToolV2 : Tool, false> { + } __attribute__((packed)); + struct ToolV3 : Tool, true> { + } __attribute__((packed)); + struct ToolV4 : Tool, false> { } __attribute__((packed)); struct MagFeedResult { - int8_t def; - int8_t pow; - int8_t dex; - int8_t mind; - int8_t iq; - int8_t synchro; + int8_t def = 0; + int8_t pow = 0; + int8_t dex = 0; + int8_t mind = 0; + int8_t iq = 0; + int8_t synchro = 0; parray unused; } __attribute__((packed)); - struct MagFeedResultsList { - parray results; - } __attribute__((packed)); + using MagFeedResultsList = parray; + template struct MagFeedResultsListOffsets { - parray offsets; // Offsets of MagFeedResultsList structs - } __attribute__((packed)); - - struct ItemStarValue { - uint8_t num_stars; + using U32T = typename std::conditional::type; + parray offsets; // Offsets of MagFeedResultsList objects } __attribute__((packed)); + template struct Special { - le_uint16_t type; - le_uint16_t amount; + using U16T = typename std::conditional::type; + U16T type = 0xFFFF; + U16T amount = 0; } __attribute__((packed)); + template struct StatBoost { - uint8_t stat1; - uint8_t stat2; - le_uint16_t amount1; - le_uint16_t amount2; + using U16T = typename std::conditional::type; + uint8_t stat1 = 0; + uint8_t stat2 = 0; + U16T amount1 = 0; + U16T amount2 = 0; } __attribute__((packed)); - struct MaxTechniqueLevels { - // Indexed as [tech_num][char_class] - parray, 19> max_level; - } __attribute__((packed)); + // Indexed as [tech_num][char_class] + using MaxTechniqueLevels = parray, 19>; struct ItemCombination { parray used_item; parray equipped_item; parray result_item; - uint8_t mag_level; - uint8_t grind; - uint8_t level; - uint8_t char_class; + uint8_t mag_level = 0; + uint8_t grind = 0; + uint8_t level = 0; + uint8_t char_class = 0; parray unused; } __attribute__((packed)); + template struct TechniqueBoost { - le_uint32_t tech1; - le_float boost1; - le_uint32_t tech2; - le_float boost2; - le_uint32_t tech3; - le_float boost3; + using U32T = typename std::conditional::type; + using FloatT = typename std::conditional::type; + U32T tech1 = 0; + FloatT boost1 = 0.0f; + U32T tech2 = 0; + FloatT boost2 = 0.0f; + U32T tech3 = 0; + FloatT boost3 = 0.0f; } __attribute__((packed)); struct EventItem { parray item; - uint8_t probability; + uint8_t probability = 0; } __attribute__((packed)); struct UnsealableItem { parray item; - uint8_t unused; + uint8_t unused = 0; } __attribute__((packed)); + template struct NonWeaponSaleDivisors { - le_float armor_divisor; - le_float shield_divisor; - le_float unit_divisor; - le_float mag_divisor; + using FloatT = typename std::conditional::type; + FloatT armor_divisor = 0.0f; + FloatT shield_divisor = 0.0f; + FloatT unit_divisor = 0.0f; + FloatT mag_divisor = 0.0f; } __attribute__((packed)); - struct TableOffsets { - /* 00 / 14884 */ le_uint32_t weapon_table; // -> [{count, offset -> [Weapon]}](0xED) - /* 04 / 1478C */ le_uint32_t armor_table; // -> [{count, offset -> [ArmorOrShield]}](2; armors and shields) - /* 08 / 1479C */ le_uint32_t unit_table; // -> {count, offset -> [Unit]} (last if out of range) - /* 0C / 147AC */ le_uint32_t tool_table; // -> [{count, offset -> [Tool]}](0x1A) (last if out of range) - /* 10 / 147A4 */ le_uint32_t mag_table; // -> {count, offset -> [Mag]} - /* 14 / 0F4B8 */ le_uint32_t attack_animation_table; // -> [uint8_t](0xED) - /* 18 / 0DE7C */ le_uint32_t photon_color_table; // -> [0x24-byte structs](0x20) - /* 1C / 0E194 */ le_uint32_t weapon_range_table; // -> ??? - /* 20 / 0F5A8 */ le_uint32_t weapon_sale_divisor_table; // -> [float](0xED) - /* 24 / 0F83C */ le_uint32_t sale_divisor_table; // -> NonWeaponSaleDivisors - /* 28 / 1502C */ le_uint32_t mag_feed_table; // -> MagFeedResultsTable - /* 2C / 0FB0C */ le_uint32_t star_value_table; // -> [uint8_t] (indexed by .id from weapon, armor, etc.) - /* 30 / 0FE3C */ le_uint32_t special_data_table; // -> [Special] - /* 34 / 0FEE0 */ le_uint32_t weapon_effect_table; // -> [16-byte structs] - /* 38 / 1275C */ le_uint32_t stat_boost_table; // -> [StatBoost] - /* 3C / 11C80 */ le_uint32_t shield_effect_table; // -> [8-byte structs] - /* 40 / 12894 */ le_uint32_t max_tech_level_table; // -> MaxTechniqueLevels - /* 44 / 14FF4 */ le_uint32_t combination_table; // -> {count, offset -> [ItemCombination]} - /* 48 / 12754 */ le_uint32_t unknown_a1; - /* 4C / 14278 */ le_uint32_t tech_boost_table; // -> [TechniqueBoost] (always 0x2C of them? from counts struct?) - /* 50 / 15014 */ le_uint32_t unwrap_table; // -> {count, offset -> [{count, offset -> [EventItem]}]} - /* 54 / 1501C */ le_uint32_t unsealable_table; // -> {count, offset -> [UnsealableItem]} - /* 58 / 15024 */ le_uint32_t ranged_special_table; // -> {count, offset -> [4-byte structs]} - } __attribute__((packed)); + enum class Version { + V2, + V3, + V4, + }; - ItemParameterTable(std::shared_ptr data); + ItemParameterTable(std::shared_ptr data, Version version); ~ItemParameterTable() = default; - const Weapon& get_weapon(uint8_t data1_1, uint8_t data1_2) const; - const ArmorOrShield& get_armor_or_shield(uint8_t data1_1, uint8_t data1_2) const; - const Unit& get_unit(uint8_t data1_2) const; - const Tool& get_tool(uint8_t data1_1, uint8_t data1_2) const; - std::pair find_tool_by_class(uint8_t tool_class) const; - const Mag& get_mag(uint8_t data1_1) const; + const WeaponV4& get_weapon(uint8_t data1_1, uint8_t data1_2) const; + const ArmorOrShieldV4& get_armor_or_shield(uint8_t data1_1, uint8_t data1_2) const; + const UnitV4& get_unit(uint8_t data1_2) const; + const MagV4& get_mag(uint8_t data1_1) const; + const ToolV4& get_tool(uint8_t data1_1, uint8_t data1_2) const; + std::pair find_tool_by_id(uint32_t id) const; float get_sale_divisor(uint8_t data1_0, uint8_t data1_1) const; const MagFeedResult& get_mag_feed_result(uint8_t table_index, uint8_t which) const; - uint8_t get_item_stars(uint16_t slot) const; + uint8_t get_item_stars(uint32_t id) const; uint8_t get_special_stars(uint8_t det) const; - const Special& get_special(uint8_t special) const; + const Special& get_special(uint8_t special) const; uint8_t get_max_tech_level(uint8_t char_class, uint8_t tech_num) const; - const ItemBase& get_item_definition(const ItemData& item) const; + uint32_t get_item_id(const ItemData& item) const; uint8_t get_item_base_stars(const ItemData& item) const; uint8_t get_item_adjusted_stars(const ItemData& item) const; bool is_item_rare(const ItemData& item) const; @@ -258,14 +335,92 @@ public: size_t price_for_item(const ItemData& item) const; private: + struct TableOffsetsV2 { + // TODO: Is weapon count 0x89 or 0x8A? It could be that the last entry in + // weapon_table is used for ???? items. + /* 00 / 0013 */ le_uint32_t unknown_a0; + /* 04 / 5AFC */ le_uint32_t weapon_table; // -> [{count, offset -> [WeaponV2]}](0x89) + /* 08 / 5A5C */ le_uint32_t armor_table; // -> [{count, offset -> [ArmorOrShieldV2]}](2; armors and shields) + /* 0C / 5A6C */ le_uint32_t unit_table; // -> {count, offset -> [UnitV2]} (last if out of range) + /* 10 / 5A7C */ le_uint32_t tool_table; // -> [{count, offset -> [ToolV2]}](0x10) (last if out of range) + /* 14 / 5A74 */ le_uint32_t mag_table; // -> {count, offset -> [MagV2]} + /* 18 / 3DF8 */ le_uint32_t attack_animation_table; // -> [uint8_t](0x89) + /* 1C / 2E4C */ le_uint32_t photon_color_table; // -> [0x24-byte structs](0x20) + /* 20 / 32CC */ le_uint32_t weapon_range_table; // -> ??? + /* 24 / 3E84 */ le_uint32_t weapon_sale_divisor_table; // -> [float](0x89) + /* 28 / 40A8 */ le_uint32_t sale_divisor_table; // -> NonWeaponSaleDivisors + /* 2C / 5F4C */ le_uint32_t mag_feed_table; // -> MagFeedResultsTable + /* 30 / 4378 */ le_uint32_t star_value_table; // -> [uint8_t](0x1C7) + /* 34 / 4540 */ le_uint32_t special_data_table; // -> [Special](0x29) + /* 38 / 45E4 */ le_uint32_t weapon_effect_table; // -> [16-byte structs] + /* 3C / 58DC */ le_uint32_t stat_boost_table; // -> [StatBoost] + /* 40 / 5704 */ le_uint32_t shield_effect_table; // -> [8-byte structs] + } __attribute__((packed)); + + template + struct TableOffsetsV3V4 { + using U32T = typename std::conditional::type; + /* ## / GC / BB */ + /* 00 / F078 / 14884 */ U32T weapon_table; // -> [{count, offset -> [WeaponV3/WeaponV4]}](0xED) + /* 04 / EF90 / 1478C */ U32T armor_table; // -> [{count, offset -> [ArmorOrShieldV3/ArmorOrShieldV4]}](2; armors and shields) + /* 08 / EFA0 / 1479C */ U32T unit_table; // -> {count, offset -> [UnitV3/UnitV4]} (last if out of range) + /* 0C / EFB0 / 147AC */ U32T tool_table; // -> [{count, offset -> [ToolV3/ToolV4]}](0x1A) (last if out of range) + /* 10 / EFA8 / 147A4 */ U32T mag_table; // -> {count, offset -> [MagV3/MagV4]} + /* 14 / B88C / 0F4B8 */ U32T attack_animation_table; // -> [uint8_t](0xED) + /* 18 / A7FC / 0DE7C */ U32T photon_color_table; // -> [0x24-byte structs](0x20) + /* 1C / AACC / 0E194 */ U32T weapon_range_table; // -> ??? + /* 20 / B938 / 0F5A8 */ U32T weapon_sale_divisor_table; // -> [float](0xED) + /* 24 / BBCC / 0F83C */ U32T sale_divisor_table; // -> NonWeaponSaleDivisors + /* 28 / F608 / 1502C */ U32T mag_feed_table; // -> MagFeedResultsTable + /* 2C / BE9C / 0FB0C */ U32T star_value_table; // -> [uint8_t](0x330) (indexed by .id from weapon, armor, etc.) + /* 30 / C100 / 0FE3C */ U32T special_data_table; // -> [Special] + /* 34 / C1A4 / 0FEE0 */ U32T weapon_effect_table; // -> [16-byte structs] + /* 38 / DE50 / 1275C */ U32T stat_boost_table; // -> [StatBoost] + /* 3C / D6E4 / 11C80 */ U32T shield_effect_table; // -> [8-byte structs] + /* 40 / DF88 / 12894 */ U32T max_tech_level_table; // -> MaxTechniqueLevels + /* 44 / F5D0 / 14FF4 */ U32T combination_table; // -> {count, offset -> [ItemCombination]} + /* 48 / DE48 / 12754 */ U32T unknown_a1; + /* 4C / EB8C / 14278 */ U32T tech_boost_table; // -> [TechniqueBoost] (always 0x2C of them? from counts struct?) + /* 50 / F5F0 / 15014 */ U32T unwrap_table; // -> {count, offset -> [{count, offset -> [EventItem]}]} + /* 54 / F5F8 / 1501C */ U32T unsealable_table; // -> {count, offset -> [UnsealableItem]} + /* 58 / F600 / 15024 */ U32T ranged_special_table; // -> {count, offset -> [4-byte structs]} + } __attribute__((packed)); + std::shared_ptr data; StringReader r; - const TableOffsets* offsets; + const TableOffsetsV2* offsets_v2; + const TableOffsetsV3V4* offsets_v3; + const TableOffsetsV3V4* offsets_v4; + + // These are unused if offsets_v4 is not null (in that case, we just return + // references pointing inside the data string) + mutable std::unordered_map parsed_weapons; + mutable std::vector parsed_armors; + mutable std::vector parsed_shields; + mutable std::vector parsed_units; + mutable std::vector parsed_mags; + mutable std::unordered_map parsed_tools; + mutable std::vector> parsed_specials; // Key is used_item. We can't index on (used_item, equipped_item) because // equipped_item may contain wildcards, and the matching order matters. - void populate_item_combination_index() const; mutable std::map> item_combination_index; + + template + std::pair find_tool_by_id_t(uint32_t tool_table_offset, uint32_t id) const; + template + float get_sale_divisor_t(uint32_t weapon_table_offset, uint32_t non_weapon_table_offset, uint8_t data1_0, uint8_t data1_1) const; + template + std::pair get_event_items_t(uint32_t base_offset, uint8_t event_number) const; + + size_t num_weapon_classes; + size_t num_tool_classes; + size_t item_stars_first_id; + size_t item_stars_last_id; + size_t special_stars_begin_index; + size_t num_specials; + size_t first_rare_mag_index; + size_t star_value_table_size; }; class MagEvolutionTable { diff --git a/src/Items.cc b/src/Items.cc index bcdcdc76..e1083bce 100644 --- a/src/Items.cc +++ b/src/Items.cc @@ -24,7 +24,8 @@ void player_use_item(shared_ptr c, size_t item_index) { // Nothing to do (it should be deleted) } else if (item_identifier == 0x030200) { // Technique disk - uint8_t max_level = s->item_parameter_table->get_max_tech_level(player->disp.visual.char_class, item.data.data1[4]); + auto item_parameter_table = s->item_parameter_table_for_version(c->version()); + uint8_t max_level = item_parameter_table->get_max_tech_level(player->disp.visual.char_class, item.data.data1[4]); if (item.data.data1[2] > max_level) { throw runtime_error("technique level too high"); } @@ -35,7 +36,8 @@ void player_use_item(shared_ptr c, size_t item_index) { throw runtime_error("incorrect grinder value"); } auto& weapon = player->inventory.items[player->inventory.find_equipped_weapon()]; - auto weapon_def = s->item_parameter_table->get_weapon(weapon.data.data1[1], weapon.data.data1[2]); + auto item_parameter_table = s->item_parameter_table_for_version(c->version()); + auto weapon_def = item_parameter_table->get_weapon(weapon.data.data1[1], weapon.data.data1[2]); if (weapon.data.data1[3] >= weapon_def.max_grind) { throw runtime_error("weapon already at maximum grind"); } @@ -159,7 +161,8 @@ void player_use_item(shared_ptr c, size_t item_index) { } else if ((item_identifier & 0xFFFF00) == 0x031500) { // Christmas Present, etc. - use unwrap_table + probabilities therein - auto table = s->item_parameter_table->get_event_items(item.data.data1[2]); + auto item_parameter_table = s->item_parameter_table_for_version(c->version()); + auto table = item_parameter_table->get_event_items(item.data.data1[2]); size_t sum = 0; for (size_t z = 0; z < table.second; z++) { sum += table.first[z].probability; @@ -197,8 +200,8 @@ void player_use_item(shared_ptr c, size_t item_index) { continue; } try { - const auto& combo = s->item_parameter_table->get_item_combination( - item.data, inv_item.data); + auto item_parameter_table = s->item_parameter_table_for_version(c->version()); + const auto& combo = item_parameter_table->get_item_combination(item.data, inv_item.data); if (combo.char_class != 0xFF && combo.char_class != player->disp.visual.char_class) { throw runtime_error("item combination requires specific char_class"); } @@ -269,8 +272,9 @@ void player_feed_mag(std::shared_ptr c, size_t mag_item_index, size_t fe auto& mag_item = player->inventory.items[mag_item_index]; size_t result_index = result_index_for_fed_item.at(fed_item.data.primary_identifier()); - const auto& mag_def = s->item_parameter_table->get_mag(mag_item.data.data1[1]); - const auto& feed_result = s->item_parameter_table->get_mag_feed_result(mag_def.feed_table, result_index); + auto item_parameter_table = s->item_parameter_table_for_version(c->version()); + const auto& mag_def = item_parameter_table->get_mag(mag_item.data.data1[1]); + const auto& feed_result = item_parameter_table->get_mag_feed_result(mag_def.feed_table, result_index); auto update_stat = +[](ItemData& data, size_t which, int8_t delta) -> void { uint16_t existing_stat = data.data1w[which] % 100; @@ -477,7 +481,8 @@ void player_feed_mag(std::shared_ptr c, size_t mag_item_index, size_t fe // If the mag has evolved, add its new photon blast if (mag_number != mag_item.data.data1[1]) { - const auto& new_mag_def = s->item_parameter_table->get_mag(mag_item.data.data1[1]); + auto item_parameter_table = s->item_parameter_table_for_version(c->version()); + const auto& new_mag_def = item_parameter_table->get_mag(mag_item.data.data1[1]); mag_item.data.add_mag_photon_blast(new_mag_def.photon_blast); } } diff --git a/src/Lobby.cc b/src/Lobby.cc index 9f3c5224..1d56bc6f 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -66,7 +66,7 @@ void Lobby::create_item_creator() { s->tool_random_set, s->weapon_random_sets.at(this->difficulty), s->tekker_adjustment_set, - s->item_parameter_table, + s->item_parameter_table_for_version(this->base_version), this->episode, (this->mode == GameMode::SOLO) ? GameMode::NORMAL : this->mode, this->difficulty, @@ -180,13 +180,14 @@ void Lobby::add_client(shared_ptr c, ssize_t required_client_id) { // If the lobby is a game and item tracking is enabled, assign the inventory's // item IDs if (this->is_game() && (this->flags & Lobby::Flag::ITEM_TRACKING_ENABLED)) { + auto s = this->require_server_state(); auto p = c->game_data.player(); auto& inv = p->inventory; size_t count = min(inv.num_items, 30); for (size_t x = 0; x < count; x++) { inv.items[x].data.id = this->generate_item_id(c->lobby_client_id); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); } // If the lobby is recording a battle record, add the player join event diff --git a/src/Main.cc b/src/Main.cc index ea1eafc8..fea88733 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -1551,20 +1551,25 @@ int main(int argc, char** argv) { } case Behavior::FORMAT_RARE_ITEM_SET: { + auto name_index = make_shared( + JSON::parse(load_file("system/item-tables/names-v2.json")), + JSON::parse(load_file("system/item-tables/names-v3.json")), + JSON::parse(load_file("system/item-tables/names-v4.json"))); + shared_ptr data(new string(read_input_data())); shared_ptr rs; if (json) { - rs.reset(new JSONRareItemSet(JSON::parse(read_input_data()))); + rs.reset(new JSONRareItemSet(JSON::parse(read_input_data()), cli_version, name_index)); } else { rs.reset(new RELRareItemSet(data)); } - auto format_drop = +[](const RareItemSet::ExpandedDrop& r) -> string { + auto format_drop = [&](const RareItemSet::ExpandedDrop& r) -> string { ItemData item; item.data1[0] = r.item_code[0]; item.data1[1] = r.item_code[1]; item.data1[2] = r.item_code[2]; - string name = item.name(false); + string name = name_index->describe_item(cli_version, item); auto frac = reduce_fraction(r.probability, 0x100000000); return string_printf( @@ -1631,6 +1636,11 @@ int main(int argc, char** argv) { case Behavior::CONVERT_ITEMRT_REL_TO_JSON: case Behavior::CONVERT_ITEMRT_GSL_TO_JSON: case Behavior::CONVERT_ITEMRT_AFS_TO_JSON: { + auto name_index = make_shared( + JSON::parse(load_file("system/item-tables/names-v2.json")), + JSON::parse(load_file("system/item-tables/names-v3.json")), + JSON::parse(load_file("system/item-tables/names-v4.json"))); + shared_ptr data(new string(read_input_data())); unique_ptr rs; if (behavior == Behavior::CONVERT_ITEMRT_GSL_TO_JSON) { @@ -1693,7 +1703,7 @@ int main(int argc, char** argv) { data.data1[0] = spec.item_code[0]; data.data1[1] = spec.item_code[1]; data.data1[2] = spec.item_code[2]; - id_json = data.name(false); + id_json = name_index->describe_item(cli_version, data); } else { id_json = primary_identifier; } @@ -1723,7 +1733,7 @@ int main(int argc, char** argv) { data.data1[0] = spec.item_code[0]; data.data1[1] = spec.item_code[1]; data.data1[2] = spec.item_code[2]; - id_json = data.name(false); + id_json = name_index->describe_item(cli_version, data); } else { id_json = primary_identifier; } @@ -1759,6 +1769,11 @@ int main(int argc, char** argv) { } case Behavior::DESCRIBE_ITEM: { + auto name_index = make_shared( + JSON::parse(load_file("system/item-tables/names-v2.json")), + JSON::parse(load_file("system/item-tables/names-v3.json")), + JSON::parse(load_file("system/item-tables/names-v4.json"))); + string data = parse_data_string(input_filename); ItemData item; @@ -1771,14 +1786,19 @@ int main(int argc, char** argv) { } } - string desc = item.name(false); + string desc = name_index->describe_item(cli_version, item); log_info("Item: %s", desc.c_str()); break; } case Behavior::ENCODE_ITEM: { - ItemData item(input_filename, false); - string desc = item.name(false); + auto name_index = make_shared( + JSON::parse(load_file("system/item-tables/names-v2.json")), + JSON::parse(load_file("system/item-tables/names-v3.json")), + JSON::parse(load_file("system/item-tables/names-v4.json"))); + + ItemData item = name_index->parse_item_description(cli_version, input_filename); + string desc = name_index->describe_item(cli_version, item); log_info("Data: %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX", item.data1[0], item.data1[1], item.data1[2], item.data1[3], item.data1[4], item.data1[5], item.data1[6], item.data1[7], diff --git a/src/Player.cc b/src/Player.cc index 2efd53fd..fd930ed7 100644 --- a/src/Player.cc +++ b/src/Player.cc @@ -482,12 +482,12 @@ void SavedPlayerDataBB::clear_all_material_usage() { } } -void SavedPlayerDataBB::print_inventory(FILE* stream) const { +void SavedPlayerDataBB::print_inventory(FILE* stream, GameVersion version, shared_ptr name_index) const { fprintf(stream, "[PlayerInventory] Meseta: %" PRIu32 "\n", this->disp.stats.meseta.load()); fprintf(stream, "[PlayerInventory] %hhu items\n", this->inventory.num_items); for (size_t x = 0; x < this->inventory.num_items; x++) { const auto& item = this->inventory.items[x]; - auto name = item.data.name(false); + auto name = name_index->describe_item(version, item.data); auto hex = item.data.hex(); fprintf(stream, "[PlayerInventory] %2zu: %s (%s)\n", x, hex.c_str(), name.c_str()); } diff --git a/src/Player.hh b/src/Player.hh index 88dcc5cd..a6913eb1 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -11,6 +11,7 @@ #include "Episode3/DataIndexes.hh" #include "ItemCreator.hh" +#include "ItemNameIndex.hh" #include "LevelTable.hh" #include "PlayerSubordinates.hh" #include "Text.hh" @@ -72,7 +73,7 @@ struct SavedPlayerDataBB { // .nsc file format void set_material_usage(MaterialType which, uint8_t usage); void clear_all_material_usage(); - void print_inventory(FILE* stream) const; + void print_inventory(FILE* stream, GameVersion version, std::shared_ptr name_index) const; } __attribute__((packed)); enum AccountFlag { diff --git a/src/RareItemSet.cc b/src/RareItemSet.cc index dda1265c..399ecbab 100644 --- a/src/RareItemSet.cc +++ b/src/RareItemSet.cc @@ -222,7 +222,7 @@ const RELRareItemSet::Table& RELRareItemSet::get_table( return tables[(ep_index * 10 * 4) + (difficulty * 10) + secid]; } -JSONRareItemSet::JSONRareItemSet(const JSON& json) { +JSONRareItemSet::JSONRareItemSet(const JSON& json, GameVersion version, shared_ptr name_index) { for (const auto& mode_it : json.as_dict()) { static const unordered_map mode_keys( {{"Normal", GameMode::NORMAL}, {"Battle", GameMode::BATTLE}, {"Challenge", GameMode::CHALLENGE}, {"Solo", GameMode::SOLO}}); @@ -285,7 +285,10 @@ JSONRareItemSet::JSONRareItemSet(const JSON& json) { d.item_code[1] = (item_code >> 8) & 0xFF; d.item_code[2] = item_code & 0xFF; } else if (item_desc.is_string()) { - ItemData data(item_desc.as_string()); + if (!name_index) { + throw runtime_error("item name index is not available"); + } + ItemData data = name_index->parse_item_description(version, item_desc.as_string()); d.item_code[0] = data.data1[0]; d.item_code[1] = data.data1[1]; d.item_code[2] = data.data1[2]; diff --git a/src/RareItemSet.hh b/src/RareItemSet.hh index cbd87804..579b6345 100644 --- a/src/RareItemSet.hh +++ b/src/RareItemSet.hh @@ -10,8 +10,10 @@ #include "AFSArchive.hh" #include "GSLArchive.hh" +#include "ItemNameIndex.hh" #include "StaticGameData.hh" #include "Text.hh" +#include "Version.hh" class RareItemSet { public: @@ -109,7 +111,7 @@ private: class JSONRareItemSet : public RareItemSet { public: - explicit JSONRareItemSet(const JSON& json); + explicit JSONRareItemSet(const JSON& json, GameVersion version, std::shared_ptr name_index = nullptr); virtual ~JSONRareItemSet() = default; virtual std::vector get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 7b927ebe..d164c997 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -2145,11 +2145,11 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, string& data) { if (vq->battle_rules) { lc->game_data.create_battle_overlay(vq->battle_rules, s->level_table); lc->log.info("Created battle overlay"); - lc->game_data.player()->print_inventory(stderr); + lc->game_data.player()->print_inventory(stderr, c->version(), s->item_name_index); } else if (vq->challenge_template_index >= 0) { lc->game_data.create_challenge_overlay(vq->challenge_template_index, s->level_table); lc->log.info("Created challenge overlay"); - lc->game_data.player()->print_inventory(stderr); + lc->game_data.player()->print_inventory(stderr, c->version(), s->item_name_index); } // If an overlay was created, item IDs need to be assigned diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index e704e5ac..0e7b0b01 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -687,15 +687,16 @@ static void on_player_drop_item(shared_ptr c, uint8_t command, uint8_t f auto item = p->remove_item(cmd.item_id, 0, c->version() != GameVersion::BB); l->add_item(item, cmd.area, cmd.x, cmd.z); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu dropped item %08" PRIX32 " (%s) at %hu:(%g, %g)", cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), cmd.area.load(), cmd.x.load(), cmd.z.load()); if (c->options.debug) { - string name = item.name(true); + auto name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5DROP %08" PRIX32 "\n%s", cmd.item_id.load(), name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand(c, command, flag, data, size); @@ -744,13 +745,14 @@ static void on_create_inventory_item_t(shared_ptr c, uint8_t command, ui l->on_item_id_generated_externally(c->lobby_client_id, item.id); p->add_item(item); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu created inventory item %08" PRIX32 " (%s)", c->lobby_client_id, item.id.load(), name.c_str()); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5CREATE %08" PRIX32 "\n%s", item.id.load(), name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); @@ -787,15 +789,16 @@ static void on_drop_partial_stack_t(shared_ptr c, uint8_t command, uint8 l->on_item_id_generated_externally(c->lobby_client_id, item.id); l->add_item(item, cmd.area, cmd.x, cmd.z); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu split stack to create floor item %08" PRIX32 " (%s) at %hu:(%g, %g)", cmd.header.client_id.load(), item.id.load(), name.c_str(), cmd.area.load(), cmd.x.load(), cmd.z.load()); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5SPLIT %08" PRIX32 "\n%s", item.id.load(), name.c_str()); } - c->game_data.player()->print_inventory(stderr); + c->game_data.player()->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); @@ -841,16 +844,17 @@ static void on_drop_partial_stack_bb(shared_ptr c, uint8_t command, uint l->add_item(item, cmd.area, cmd.x, cmd.z); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu split stack %08" PRIX32 " (removed: %s) at %hu:(%g, %g)", cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), cmd.area.load(), cmd.x.load(), cmd.z.load()); if (c->options.debug) { - string name = item.name(true); + auto name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5SPLIT/BB %08" PRIX32 "\n%s", cmd.item_id.load(), name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); send_drop_stacked_item(l, item, cmd.area, cmd.x, cmd.z); @@ -878,16 +882,16 @@ static void on_buy_shop_item(shared_ptr c, uint8_t command, uint8_t flag l->on_item_id_generated_externally(c->lobby_client_id, item.id); p->add_item(item); - size_t price = s->item_parameter_table->price_for_item(item); - auto name = item.name(false); + size_t price = s->item_parameter_table_for_version(c->version())->price_for_item(item); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu bought item %08" PRIX32 " (%s) from shop (%zu Meseta)", cmd.header.client_id.load(), item.id.load(), name.c_str(), price); if (c->options.debug) { - string name = item.name(true); + auto name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5BUY %08" PRIX32 "\n%s", item.id.load(), name.c_str()); } p->remove_meseta(price, c->version() != GameVersion::BB); - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand_with_mag_transcode_t(c, command, flag, cmd); @@ -917,11 +921,12 @@ static void on_box_or_enemy_item_drop_t(shared_ptr c, uint8_t command, u l->on_item_id_generated_externally(c->lobby_client_id, item.id); l->add_item(item, cmd.item.area, cmd.item.x, cmd.item.z); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hhu (leader) created floor item %08" PRIX32 " (%s) at %hhu:(%g, %g)", l->leader_id, item.id.load(), name.c_str(), cmd.item.area, cmd.item.x.load(), cmd.item.z.load()); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5DROP %08" PRIX32 "\n%s", item.id.load(), name.c_str()); } } @@ -971,14 +976,15 @@ static void on_pick_up_item(shared_ptr c, uint8_t command, uint8_t flag, auto item = l->remove_item(cmd.item_id); effective_p->add_item(item); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu picked up %08" PRIX32 " (%s)", cmd.header.client_id.load(), cmd.item_id.load(), name.c_str()); if (c->options.debug) { - string name = item.name(true); + auto name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5PICK %08" PRIX32 "\n%s", cmd.item_id.load(), name.c_str()); } - effective_p->print_inventory(stderr); + effective_p->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand(c, command, flag, data, size); @@ -1002,15 +1008,16 @@ static void on_pick_up_item_request(shared_ptr c, uint8_t command, uint8 auto item = l->remove_item(cmd.item_id); p->add_item(item); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hu picked up (BB) %08" PRIX32 " (%s)", cmd.header.client_id.load(), cmd.item_id.load(), name.c_str()); if (c->options.debug) { - string name = item.name(true); + auto name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5PICK/BB %08" PRIX32 "\n%s", cmd.item_id.load(), name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); send_pick_up_item(c, cmd.item_id, cmd.area); @@ -1055,6 +1062,7 @@ static void on_use_item( auto l = c->require_lobby(); if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) { + auto s = c->require_server_state(); auto p = c->game_data.player(); size_t index = p->inventory.find_item(cmd.item_id); string name, colored_name; @@ -1062,8 +1070,8 @@ static void on_use_item( // Note: We do this weird scoping thing because player_use_item will // likely delete the item, which will break the reference here. const auto& item = p->inventory.items[index].data; - name = item.name(false); - colored_name = item.name(true); + name = s->describe_item(c->version(), item, false); + colored_name = s->describe_item(c->version(), item, true); } player_use_item(c, index); @@ -1073,7 +1081,7 @@ static void on_use_item( send_text_message_printf(c, "$C5USE %08" PRIX32 "\n%s", cmd.item_id.load(), colored_name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand(c, command, flag, data, size); @@ -1092,6 +1100,7 @@ static void on_feed_mag( auto l = c->require_lobby(); if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) { + auto s = c->require_server_state(); auto p = c->game_data.player(); size_t mag_index = p->inventory.find_item(cmd.mag_item_id); @@ -1101,11 +1110,11 @@ static void on_feed_mag( // Note: We do this weird scoping thing because player_use_item will // likely delete the item, which will break the reference here. const auto& fed_item = p->inventory.items[fed_index].data; - fed_name = fed_item.name(false); - fed_colored_name = fed_item.name(true); + fed_name = s->describe_item(c->version(), fed_item, false); + fed_colored_name = s->describe_item(c->version(), fed_item, true); const auto& mag_item = p->inventory.items[mag_index].data; - mag_name = mag_item.name(false); - mag_colored_name = mag_item.name(true); + mag_name = s->describe_item(c->version(), mag_item, false); + mag_colored_name = s->describe_item(c->version(), mag_item, true); } player_feed_mag(c, mag_index, fed_index); @@ -1125,7 +1134,7 @@ static void on_feed_mag( cmd.fed_item_id.load(), fed_colored_name.c_str(), cmd.mag_item_id.load(), mag_colored_name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); } forward_subcommand(c, command, flag, data, size); @@ -1163,7 +1172,7 @@ static void on_open_shop_bb_or_ep3_battle_subs(shared_ptr c, uint8_t com } for (auto& item : c->game_data.shop_contents[cmd.shop_type]) { item.id = l->generate_item_id(c->lobby_client_id); - item.data2d = s->item_parameter_table->price_for_item(item); + item.data2d = s->item_parameter_table_for_version(c->version())->price_for_item(item); } send_shop(c, cmd.shop_type); @@ -1507,7 +1516,7 @@ static void on_steal_exp_bb(shared_ptr c, uint8_t, uint8_t, const void* ((weapon.data.data1[1] < 0x0D) && (weapon.data.data1[2] < 0x04))) { special = weapon.data.data1[4] & 0x3F; } else { - special = s->item_parameter_table->get_weapon(weapon.data.data1[1], weapon.data.data1[2]).special; + special = s->item_parameter_table_for_version(c->version())->get_weapon(weapon.data.data1[1], weapon.data.data1[2]).special; } if (special >= 0x09 && special <= 0x0B) { @@ -1598,7 +1607,7 @@ static void on_enemy_killed_bb(shared_ptr c, uint8_t command, uint8_t fl for (size_t z = 0; z < inventory.num_items; z++) { auto& item = inventory.items[z]; if ((item.flags & 0x08) && - s->item_parameter_table->is_unsealable_item(item.data)) { + s->item_parameter_table_for_version(c->version())->is_unsealable_item(item.data)) { item.data.set_sealed_item_kill_count(item.data.get_sealed_item_kill_count() + 1); } } @@ -1649,17 +1658,18 @@ static void on_destroy_inventory_item(shared_ptr c, uint8_t command, uin } if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) { + auto s = c->require_server_state(); auto p = c->game_data.player(); auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != GameVersion::BB); - auto name = item.name(false); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hhu destroyed inventory item %hu:%08" PRIX32 " (%s)", c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str()); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5DESTROY %08" PRIX32 "\n%s", cmd.item_id.load(), name.c_str()); } - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); forward_subcommand(c, command, flag, data, size); } } @@ -1673,12 +1683,13 @@ static void on_destroy_ground_item(shared_ptr c, uint8_t command, uint8_ } if (l->flags & Lobby::Flag::ITEM_TRACKING_ENABLED) { + auto s = c->require_server_state(); auto item = l->remove_item(cmd.item_id); - auto name = item.name(false); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hhu destroyed floor item %08" PRIX32 " (%s)", c->lobby_client_id, cmd.item_id.load(), name.c_str()); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5DESTROY/GND %08" PRIX32 "\n%s", cmd.item_id.load(), name.c_str()); } @@ -1751,17 +1762,18 @@ static void on_sell_item_at_shop_bb(shared_ptr c, uint8_t command, uint8 throw logic_error("item tracking not enabled in BB game"); } + auto s = c->require_server_state(); auto p = c->game_data.player(); auto item = p->remove_item(cmd.item_id, cmd.amount, c->version() != GameVersion::BB); - size_t price = (s->item_parameter_table->price_for_item(item) >> 3) * cmd.amount; + size_t price = (s->item_parameter_table_for_version(c->version())->price_for_item(item) >> 3) * cmd.amount; p->add_meseta(price); - auto name = item.name(false); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hhu sold inventory item %08" PRIX32 " (%s) for %zu Meseta", c->lobby_client_id, cmd.item_id.load(), name.c_str(), price); - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5DESTROY/SELL %08" PRIX32 "\n+%zu Meseta\n%s", cmd.item_id.load(), price, name.c_str()); } @@ -1795,12 +1807,13 @@ static void on_buy_shop_item_bb(shared_ptr c, uint8_t, uint8_t, const vo p->add_item(item); send_create_inventory_item(c, item); - auto name = item.name(false); + auto s = c->require_server_state(); + auto name = s->describe_item(c->version(), item, false); l->log.info("Player %hhu purchased item %08" PRIX32 " (%s) for %zu meseta", c->lobby_client_id, cmd.inventory_item_id.load(), name.c_str(), price); - p->print_inventory(stderr); + p->print_inventory(stderr, c->version(), s->item_name_index); if (c->options.debug) { - string name = item.name(true); + string name = s->describe_item(c->version(), item, true); send_text_message_printf(c, "$C5CREATE/BUY %08" PRIX32 "\n-%zu Meseta\n%s", cmd.inventory_item_id.load(), price, name.c_str()); } diff --git a/src/ServerShell.cc b/src/ServerShell.cc index 893b6afa..52b01065 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -815,20 +815,21 @@ Proxy session commands:\n\ throw runtime_error("proxy session is not game leader"); } - ItemData item(command_args); + auto s = session->require_server_state(); + ItemData item = s->item_name_index->parse_item_description(session->version(), command_args); item.id = random_object(); if (command_name == "set-next-item") { session->next_drop_item = item; - string name = session->next_drop_item.name(true); + string name = s->describe_item(session->version(), session->next_drop_item, true); send_text_message(session->client_channel, "$C7Next drop:\n" + name); } else { send_drop_stacked_item(session->client_channel, item, session->area, session->x, session->z); send_drop_stacked_item(session->server_channel, item, session->area, session->x, session->z); - string name = item.name(true); + string name = s->describe_item(session->version(), session->next_drop_item, true); send_text_message(session->client_channel, "$C7Item created:\n" + name); } diff --git a/src/ServerState.cc b/src/ServerState.cc index 4449c11e..b1d28c53 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -398,6 +398,28 @@ const vector>& ServerState::redirect_destinations_for_ver } } +std::shared_ptr ServerState::item_parameter_table_for_version(GameVersion version) const { + switch (version) { + case GameVersion::DC: + case GameVersion::PC: + return this->item_parameter_table_v2; + case GameVersion::GC: + case GameVersion::XB: + return this->item_parameter_table_v3; + case GameVersion::BB: + return this->item_parameter_table_v4; + default: + throw out_of_range("no item parameter table exists for this version"); + } +} + +std::string ServerState::describe_item(GameVersion version, const ItemData& item, bool include_color_codes) const { + return this->item_name_index->describe_item( + version, + item, + include_color_codes ? this->item_parameter_table_for_version(version) : nullptr); +} + void ServerState::set_port_configuration( const vector& port_configs) { this->name_to_port_config.clear(); @@ -926,6 +948,12 @@ void ServerState::load_word_select_table() { } void ServerState::load_item_tables() { + config_log.info("Loading item name index"); + this->item_name_index.reset(new ItemNameIndex( + JSON::parse(load_file("system/item-tables/names-v2.json")), + JSON::parse(load_file("system/item-tables/names-v3.json")), + JSON::parse(load_file("system/item-tables/names-v4.json")))); + config_log.info("Loading rare item sets"); for (const auto& filename : list_directory_sorted("system/item-tables")) { if (!starts_with(filename, "rare-table-")) { @@ -936,9 +964,15 @@ void ServerState::load_item_tables() { size_t ext_offset = filename.rfind('.'); string basename = (ext_offset == string::npos) ? filename : filename.substr(0, ext_offset); - if (ends_with(filename, ".json")) { - config_log.info("Loading JSON rare item table %s", filename.c_str()); - this->rare_item_sets.emplace(basename, new JSONRareItemSet(JSON::parse(load_file(path)))); + if (ends_with(filename, "-v2.json")) { + config_log.info("Loading v2 JSON rare item table %s", filename.c_str()); + this->rare_item_sets.emplace(basename, new JSONRareItemSet(JSON::parse(load_file(path)), GameVersion::PC, this->item_name_index)); + } else if (ends_with(filename, "-v3.json")) { + config_log.info("Loading v3 JSON rare item table %s", filename.c_str()); + this->rare_item_sets.emplace(basename, new JSONRareItemSet(JSON::parse(load_file(path)), GameVersion::GC, this->item_name_index)); + } else if (ends_with(filename, "-v4.json")) { + config_log.info("Loading v4 JSON rare item table %s", filename.c_str()); + this->rare_item_sets.emplace(basename, new JSONRareItemSet(JSON::parse(load_file(path)), GameVersion::BB, this->item_name_index)); } else if (ends_with(filename, ".afs")) { config_log.info("Loading AFS rare item table %s", filename.c_str()); @@ -1006,10 +1040,13 @@ void ServerState::load_item_tables() { "system/item-tables/JudgeItem-gc.rel"))); this->tekker_adjustment_set.reset(new TekkerAdjustmentSet(tekker_data)); - config_log.info("Loading item definition table"); - shared_ptr pmt_data(new string(prs_decompress(load_file( - "system/item-tables/ItemPMT-bb.prs")))); - this->item_parameter_table.reset(new ItemParameterTable(pmt_data)); + config_log.info("Loading item definition tables"); + shared_ptr pmt_data_v2(new string(prs_decompress(load_file("system/item-tables/ItemPMT-v2.prs")))); + this->item_parameter_table_v2.reset(new ItemParameterTable(pmt_data_v2, ItemParameterTable::Version::V2)); + shared_ptr pmt_data_v3(new string(prs_decompress(load_file("system/item-tables/ItemPMT-gc.prs")))); + this->item_parameter_table_v3.reset(new ItemParameterTable(pmt_data_v3, ItemParameterTable::Version::V3)); + shared_ptr pmt_data_v4(new string(prs_decompress(load_file("system/item-tables/ItemPMT-bb.prs")))); + this->item_parameter_table_v4.reset(new ItemParameterTable(pmt_data_v4, ItemParameterTable::Version::V4)); config_log.info("Loading mag evolution table"); shared_ptr mag_data(new string(prs_decompress(load_file( diff --git a/src/ServerState.hh b/src/ServerState.hh index 47fa24a9..bc04276d 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -15,6 +15,7 @@ #include "Episode3/Tournament.hh" #include "FunctionCompiler.hh" #include "GSLArchive.hh" +#include "ItemNameIndex.hh" #include "ItemParameterTable.hh" #include "LevelTable.hh" #include "License.hh" @@ -106,8 +107,11 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr tool_random_set; std::array, 4> weapon_random_sets; std::shared_ptr tekker_adjustment_set; - std::shared_ptr item_parameter_table; + std::shared_ptr item_parameter_table_v2; + std::shared_ptr item_parameter_table_v3; + std::shared_ptr item_parameter_table_v4; std::shared_ptr mag_evolution_table; + std::shared_ptr item_name_index; std::shared_ptr word_select_table; std::shared_ptr ep3_tournament_index; @@ -214,6 +218,9 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr proxy_destinations_menu_for_version(GameVersion version) const; const std::vector>& proxy_destinations_for_version(GameVersion version) const; + std::shared_ptr item_parameter_table_for_version(GameVersion version) const; + std::string describe_item(GameVersion version, const ItemData& item, bool include_color_codes) const; + std::shared_ptr quest_index_for_client(std::shared_ptr c) const; void set_port_configuration(const std::vector& port_configs); diff --git a/system/item-tables/ItemPMT-gc.prs b/system/item-tables/ItemPMT-gc.prs new file mode 100755 index 0000000000000000000000000000000000000000..315360b76f36923d0e1bce157666bba598e57e47 GIT binary patch literal 15673 zcmcJ$cU)A**FQe@Zex3)C<;q28Zm-3#+ZwUOBqmvq1!6R!QIl9A z*hNuP#71<%UBH&0LEKOj^iriPu(T~R-?Q=ge4gj^`~UZP-S@d?X3or7VYFPOvgvfTHYYM9Xv*j7wrW(9C-X&Osj2V$e@by->7L_AEyJZcJNxC-fGg*Op|FvU*j-Bs4H zd>4fZ3y0rhwvRw%l#!tiZVa-z zsj%2RjCplv?k+OuzOp5VjNHz+qQ#;)r0%iOn+QiSUIS1(;s-Lm=yg{R8O;nrsq2xD z2^{O@<_eXJImURRZDTeM^+5fiv0jWfO1kSohP%5MRg8D}D;Fi>qHufE z6GXxpS>uGeub#`KN~sD9+#?u4UO3gkycQ_EdAtxee-asmr=&|Ru-pC_!2tWT>%k_J zDP9m9L?Uk1Gf^oe%&y5uj%>kF-KG|S;IVWHj%H*R_eL@nMv>ga3>f22rUsDI;Y@$< z>o=pAf&S!!0nA5}+&tdJd>B9iRu{Zs@=5~8w7S}JhzVazO6D-`A2Dkp z=Xw)9uYdaCAOd|WoACt`f?~ai;$xqsO?VO>?}n`5?#gR!C#{japDb-c_%DQ;QON>N zhaqE-_W&FjhD&}ehS1DCr;<=vVHa7;p6lKkm~5NnT=^O5XxK?sxLkH;hg~qoFtZD4 z#^Dp_(szt?yNkVC}6!|R`kq^sBOVv z9R*$KVM@U%7j-u?zc8@^hoFTq%!$^@AhIC5ng^{AR9t-#Ko(Ljoz{GAXH^H0Sc-ay zUlqP!K3sR*ZLo*VB3QJvs$YNxp51D=iQ$CW(za`uAFEVT-Id6U`k3FS)9Kyu40kajW7%nCHq z3kML*03v-NU}ksI>Xo(6{Q`;f+i3hv4gERt&xK@hG+saWHN7hQnRiqmDYII>oZUmO zh9NH$YziQQm^EX8mrDc4;4hiAzz%TvHh^5Mqt_u{7s!6nzO;q$Sj?y$lVm~s-=6cC z^}xPYwS@WWwTb=$`0nuP(>wje!tw-ur;@ zVL~u&9;XZXzKHQpV<#T`K%TPnTDpsj!}0o&Ywd==id6Az&nX7?Cfo%rhyWAK3R zS0@><0A@1(n}UaHurL&Qo^z!!h-|Ml#o*O5D=skc;YC~jHZtF`7{81DB!*)nr;O_F zpt$b=8b>9GfF!_A9F}#05SpU z<3LUTPCBYNReMnmQl}jfX8>mb>T^J{0OuD0xd6y6DAr&m%uVxDaj~Gd84uK#f&-<@ z2hW@tG>(XdGToft>8G`QcA8!pKzf*G^p(P$C+-E2-tpR9iYHd?^#WEP>C+w>-h7+z zS7+xEb|C2wI9l;_(W_hFiv^a`D-O#qNXzyJf{1l7qdaVQLKVD*(Qg}Hm%i_&)otBg zmLSf~x9`?wZoEaPMH~?%Vr^#7tlL)Qf;W&vPVMXbgZSRq%jE_VT|eVF_Uc^{_{(O2 zB#6u?PT23qR1dAq=ePtB`ZVX4fb`+(3r>i|L4;+m`(@1m62{`7N|7{(unoTs^)K=1 z7?<79PjjX+G2<_kjQ70)BjP5PnY;H#BQvSCQ&I2mFHCHj@>SM4XtWcT0dbYcClqv4dKu9LCkG73=olr+l3*s2)!AR-Hk>fIbZyM%K% z#U|(UFK%SmF7CYYz?+H{cE9G)1Fdd{ZqE%M&VJ0MEHil?+bwk$Jmv))bYY^t-D_r& zzPKP*;&kCP?HbUh`H8eM7mUB~X}2TH-mw?j!=YaXTxSkX!3%)fGSE=x+icyHmp)bF ze#*L^Scj)8q)siT_A`SxovL&uylNAy0E3xXvzgA1ycHi6@ARm9Q*w?lFpl}Ho~O() z(OB#P22nEEzBAiPJjW_r!j8T-t)2Gzgn5WIGYQ+QayM8Cy_r8z_4a5ig&y!ZsQE`2 zAJ@y@X!B+COQ~ja<1j>iaA`Y zt8f%k0Hr`up_asG$+de?ttowaEm1=b17rYAivCS0j*XhhwUubeTCVLrRw9EwMS5$?Qy^-rLWRTn%-l;1>>Z?WN%ZZc7bl$kmcsE#ZUM ztGb&KPW@|Wg-}ZvM+2YNorEosn_dM<7>$!G1*nVJ@9iJz746TsF(vmh#tt8b>Y-e{uf3ZnlaDj=z+@pjeFqnkhP(*yTwJ zS#+2aH?9+yz;jv}7Zx<)#Ra6=w0CG8|yKx>XE6%_cR<;zYJ22a8x##G;)7#qpDvbd#%pqfSjDQUS*Td zRrsy%SOQh2<-1{l&Mtqo7O&-S!hh3PMXs%p(HbmwW4%wY^XOhK>JJ91|3aCel%@xld>T_~EQVn~RJpUcXO_o3G z9F{qOjb-^ES`3ZJAHE81!uFKL{CCefxG6-IKjN{2d)_F^4}Ayorc{DzQ}V-bPUGIw zNM#es@<(RkMkT8aD&Xgja=|)_+&6zTc4>@O5y|oVF^+;`^2aWd`+!~Z#|a$a{Lt~3 zBY;sL&cFOVh5;ax*^T+0`D+tFM^Chy6RuFfYO`y--6bBV1-?2_!(QhZubH0!2!DK?-sSY0G6l&}O^`}}QiZe-;yV!bf%pyUfzOK{uK6{h) z&4c9L@;AmU-#BjLf4#ke$TW67KW+t4%OR@*;Jg-y3)D>axK`@0VgLjOnHY(+;z0wj z9stigAWDE2V7E8OT5M_`;C%spptZsu5C9nBkQ@ql2cRAXBm^+rArc9g0*G>mL<6P* z)E@x(5HQUl@)2MbqtW1fLRWa*?>8Kxek$efcXIR0w4MtfGh>geJj<=fL#uVcSx@QtOR`SkX{8?4N$KE;;_p)hlm=m9`J=jWCI`} zu3Mqr3e3iue-xXpuOfUel>u*#1J621vw~~^W{Fz2f&|vs6hV#>f&uU9`V}J_C4>UP z0P2xIMgc}UM8*Kd0>(K+-UEyWsNV-N0Wi@aG6^slpmKWeUJtLWMm zN5o%2+}93)?SO9q>hFMj570QuNCYGSb~r?m0ovCa%Ta?kg$09HoLUhDWeU?^aQ@&B z*a`R%pxy;!H{hp5K=uIA!IYKDOnZUd2lzQQj>!G8P}~VYmT|w|%6&8D@*1*^&$%~v zQJhM!U%M^%2~&A0*Kc+%73x8SP{sHF7;IO3$^&nzwKG?TB?k?78>-8=Jd7ys)7cR5 z%XbExg{n}~^L1np>*+rb_3Ir2HcN3J4d4m#bXb05M_2#SBU>gE<^OO+ zI=DPdp)la1c?LX|>N&^j2~p^<>~{lRS8;P$6TX0U)tE z!+@WTl5idi*t4P`oSCA*#(JaV;yU7biGw`YdWUP3AHRrkKjln?Q{{I~Js>P4N7X8o zpZK%}8y8Y>R;p$l@s$ozUgOSGqaM-86UIEcCz$&@yz8)r#-J?!lmUmyvo3NkJvSa@Zp9}2;)z-J8 zTq-fDk>h$^$&;^=_vp-gPS#~J?lW#fm#8Bzc6AM91<4Q5*I0=ZIE(Wg-3S|BrlKn9 zuXV)3kL_v9`-cXTUbt7DZB2L;?B~vYm8bAwp$1X50jtA9Pv|&SO5M2^RJdrspEZu5 zv@hN1iilo_xMaXdU!uKKzzG-DTag^FXJvSAA+N<7tarJm!*ps#Qyx{>W-xPjR5gd4 zm)OQC##a*BK#lH<@ZKq{0x5M(w0EDXRdV%mJH$SDZsa^yUYE-Kf9n91Mb~ndKQ1hn zW}4UN`+we1Si=Ip#=mC3g3IPd-0szR^$P=@SgLerVZvTwiR_J}w>9y~SMh+6o!E;pZRGw$Q|@VScu zyikwqc4(spcOJ~iqT1^;uXz$9k83n?igA7fOW)~o-u2HZ@1)O+KK?QfSp|O>aLBV7 z^~bDNo>2asN&}8LaC8Cdl^1lm4D{JHl2!5g5cSFjg1QHwdy7fEj`hk9f(6vfo4BI$ z@a1yE9CLrpaSfc^tLhaN(h1k`k@anr&_$jLIG1VSZ@;obp z`7oHvUWZsJ!dr7seZVpXUPDit(ci*n2D~NARZs04OR44CK?p1sza;eaigh9M2m|#l~9Q;G6(!vmybb2w$Xq~qIzo|pKxb?4Pp5|=^5BqwdpAAkvOiSLj;;WX+_7S zGHjvrWuI?*5#GuT7zc)`q!Y67D5LLzf^R>~;RTI1;PWaQUw^{?iub5X*FKrC6j`MP zP=|Bvv&1Aml^rIBUMecaqn2GvOy$!XWe|K;T#Q}f3wHCbv93rVTvCh&%~|2|fFC9x$;^$SX%OM<|!Bf0_^jb3(r*{ zWRKAmN**mAY^hi_#Wt5^99-?Oqrl0j7(WK@pfohcvW#kQ2C_d5IQX{frj;zC(iz&V z{tM>lf#eO9ETb2smcnq#Gt_Kj86CaHc``EtYm6%GchSA>9G0(0sJbnE`lJ*iQR!yGC8+ z6L0 zFDs0?y(mZm!3OyO4K^kvg%%k%6?`TY1`TG<@(KMrCjkler}o~ zX;bLWFp{1om3}wMAZ4>cMu3H+&3?3T3+w8>r(bZS*_*~|9!lPTSIN&R+gNbpN)+^_ zx&@}TZwqy)^O96R)8`>7q!pBW&~;trlGvtn^hR649vp0p-uUTVnLD5B9mHb zbNgm@d%_;5^TUnHZ89ZaD8B}sC%j!|D(FJk*t+^&bF<()pSRZ27ovAO?Rd8I`9H5& zN1~>>SP}hXEsN%`i&UM0&We)q@S~rE9_7SHzo2}=9R1O?%Xr`TJc&v-oTTou)e|&! znK?5@{DyV+*QI98X|A#!6zevA(> zwVnF*Q4v-WmkF)OUC=Lm2Ko5$A_e?z=NRzjtA zV*$0Jq6mkS8sCK=zNN=AJ1v3!6cmucjmqy{^C@WjVl=+r#dR8xT!{aJauX#r^gr)3$8ap!Mp66 zhAs02`r_KdX}4X2H4mkfliW83w`=ORdvd!v>-Qp-A1jNwS~?#m->xnHE;*%an=B8nRNiRev|mDirXNieQ)1WQz%V9 zNqiEk2kvN+&?`Q1pU-uJVIhmSroruVzE0?hn#!j=-(+^PI=hRnQnEsyLl{$UrcvgI znfZM3Met;2TGua;FUtITFso-;5e`1?j(X%%;yv&OvLDCaW+ewSj~%J%6%1M
    gJ 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 Qx_4*IF$K$rkV5GH0jsF(cK`qY literal 0 HcmV?d00001 diff --git a/system/item-tables/ItemPMT-v2.prs b/system/item-tables/ItemPMT-v2.prs new file mode 100644 index 0000000000000000000000000000000000000000..a61299cb7d791d325d964e0192a8a8faace90037 GIT binary patch literal 8776 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 literal 0 HcmV?d00001 diff --git a/system/item-tables/names-v2.json b/system/item-tables/names-v2.json new file mode 100755 index 00000000..f0bae4fc --- /dev/null +++ b/system/item-tables/names-v2.json @@ -0,0 +1,549 @@ +{ + "000100": "Saber", + "000101": "Brand", + "000102": "Buster", + "000103": "Pallasch", + "000104": "Gladius", + "000105": "DB'S SABER", + "000106": "KALADBOLG", + "000107": "DURANDAL", + "000200": "Sword", + "000201": "Gigush", + "000202": "Breaker", + "000203": "Claymore", + "000204": "Calibur", + "000205": "FLOWEN'S SWORD", + "000206": "LAST SURVIVOR", + "000207": "DRAGON SLAYER", + "000300": "Dagger", + "000301": "Knife", + "000302": "Blade", + "000303": "Edge", + "000304": "Ripper", + "000305": "BLADE DANCE", + "000306": "BLOODY ART", + "000307": "CROSS SCAR", + "000400": "Partisan", + "000401": "Halbert", + "000402": "Glaive", + "000403": "Berdys", + "000404": "Gungnir", + "000405": "BRIONAC", + "000406": "VJAYA", + "000407": "GAE BOLG", + "000500": "Slicer", + "000501": "Spinner", + "000502": "Cutter", + "000503": "Sawcer", + "000504": "Diska", + "000505": "SLICER OF ASSASSIN", + "000506": "DISKA OF LIBERATOR", + "000507": "DISKA OF BRAVEMAN", + "000600": "Handgun", + "000601": "Autogun", + "000602": "Lockgun", + "000603": "Railgun", + "000604": "Raygun", + "000605": "VARISTA", + "000606": "CUSTOM RAY ver.OO", + "000607": "BRAVACE", + "000700": "Rifle", + "000701": "Sniper", + "000702": "Blaster", + "000703": "Beam", + "000704": "Laser", + "000705": "VISK-235W", + "000706": "WALS-MK2", + "000707": "JUSTY-23ST", + "000800": "Mechgun", + "000801": "Assault", + "000802": "Repeater", + "000803": "Gatling", + "000804": "Vulcan", + "000805": "M&A60 VISE", + "000806": "H&S25 JUSTICE", + "000807": "L&K14 COMBAT", + "000900": "Shot", + "000901": "Spread", + "000902": "Cannon", + "000903": "Launcher", + "000904": "Arms", + "000905": "CRUSH BULLET", + "000906": "METEOR SMASH", + "000907": "FINAL IMPACT", + "000A00": "Cane", + "000A01": "Stick", + "000A02": "Mace", + "000A03": "Club", + "000A04": "CLUB OF LACONIUM", + "000A05": "MACE OF ADAMAN", + "000A06": "CLUB OF ZUMIURAN", + "000B00": "Rod", + "000B01": "Pole", + "000B02": "Pillar", + "000B03": "Striker", + "000B04": "BATTLE VERGE", + "000B05": "BRAVE HAMMER", + "000B06": "ALIVE AQHU", + "000C00": "Wand", + "000C01": "Staff", + "000C02": "Baton", + "000C03": "Scepter", + "000C04": "FIRE SCEPTER:AGNI", + "000C05": "ICE STAFF:DAGON", + "000C06": "STORM WAND:INDRA", + "000D00": "PHOTON CLAW", + "000D01": "SILENCE CLAW", + "000D02": "NEI'S CLAW", + "000E00": "DOUBLE SABER", + "000E01": "STAG CUTLERY", + "000E02": "TWIN BRAND", + "000F00": "BRAVE KNUCKLE", + "000F01": "ANGRY FIST", + "000F02": "GOD HAND", + "000F03": "SONIC KNUCKLE", + "000F04": "OROTIAGITO", + "001000": "OROTIAGITO", + "001001": "AGITO", + "001002": "AGITO", + "001003": "AGITO", + "001004": "AGITO", + "001005": "AGITO", + "001006": "AGITO", + "001100": "SOUL EATER", + "001101": "SOUL BANISH", + "001200": "SPREAD NEEDLE", + "001300": "HOLY RAY", + "001400": "INFERNO BAZOOKA", + "001500": "FLAME VISIT", + "001600": "AKIKO'S FRYING PAN", + "001700": "C-SORCERER'S CANE", + "001800": "S-BEAT'S BLADE", + "001900": "P-ARMS'S BLADE", + "001A00": "DELSABER'S BUSTER", + "001B00": "C-BRINGER'S RIFLE", + "001C00": "EGG BLASTER", + "001D00": "PSYCHO WAND", + "001E00": "HEAVEN PUNISHER", + "001F00": "LAVIS CANNON", + "002000": "VICTOR AXE", + "002100": "CHAIN SAWD", + "002200": "CADUCEUS", + "002300": "STING TIP", + "002400": "MAGICAL PIECE", + "002500": "TECHNICAL CROZIER", + "002600": "SUPPRESSED GUN", + "002700": "ANCIENT SABER", + "002800": "HARISEN BATTLE FAN", + "002900": "YAMIGARASU", + "002A00": "AKIKO'S WOK", + "002B00": "TOY HAMMER", + "002C00": "ELYSION", + "002D00": "RED SABER", + "002E00": "METEOR CUDGEL", + "002F00": "MONKEY KING BAR", + "003000": "DOUBLE CANNON", + "003100": "HUGE BATTLE FAN", + "003200": "TSUMIKIRI J-SWORD", + "003300": "SEALED J-SWORD", + "003400": "RED SWORD", + "003500": "CRAZY TUNE", + "003600": "TWIN CHAKRAM", + "003700": "WOK OF AKIKO'S SHOP", + "003800": "LAVIS BLADE", + "003900": "RED DAGGER", + "003A00": "MADAM'S PARASOL", + "003B00": "MADAM'S UMBRELLA", + "003C00": "IMPERIAL PICK", + "003D00": "BERDYSH", + "003E00": "RED PARTISAN", + "003F00": "FLIGHT CUTTER", + "004000": "FLIGHT FAN", + "004100": "RED SLICER", + "004200": "HANDGUN:GULD", + "004300": "HANDGUN:MILLA", + "004400": "RED HANDGUN", + "004500": "FROZEN SHOOTER", + "004600": "ANTI ANDROID RIFLE", + "004700": "ROCKET PUNCH", + "004800": "SAMBA MARACAS", + "004900": "TWIN PSYCHOGUN", + "004A00": "DRILL LAUNCHER", + "004B00": "GULD MILLA", + "004C00": "RED MECHGUN", + "004D00": "BERLA CANNON", + "004E00": "PANZER FAUST", + "004F00": "SUMMIT MOON", + "005000": "WINDMILL", + "005100": "EVIL CURST", + "005200": "FLOWER CANE", + "005300": "HILDEBEAR'S CANE", + "005400": "HILDEBLUE'S CANE", + "005500": "RABBIT WAND", + "005600": "PLANTAIN LEAF", + "005700": "DEMONIC FORK", + "005800": "STRIKER OF CHAO", + "005900": "BROOM", + "005A00": "PROPHETS OF MOTAV", + "005B00": "THE SIGH OF A GOD", + "005C00": "TWINKLE STAR", + "005D00": "PLANTAIN FAN", + "005E00": "TWIN BLAZE", + "005F00": "MARINA'S BAG", + "006000": "DRAGON'S CLAW", + "006100": "PANTHER'S CLAW", + "006200": "S-RED'S BLADE", + "006300": "PLANTAIN HUGE FAN", + "006400": "CHAMELEON SCYTHE", + "006500": "YASMINKOV 3000R", + "006600": "ANO RIFLE", + "006700": "BARANZ LAUNCHER", + "006800": "BRANCH OF PAKUPAKU", + "006900": "HEART OF POUMN", + "006A00": "YASMINKOV 2000H", + "006B00": "YASMINKOV 7000V", + "006C00": "YASMINKOV 9200M", + "006D00": "MASER BEAM", + "006E00": "GAME MAGAZNE", + "006F00": "FLOWER BOUQUET", + "007000": "SABER", + "007100": "SWORD", + "007200": "BLADE", + "007300": "PARTISAN", + "007400": "SLICER", + "007500": "GUN", + "007600": "RIFLE", + "007700": "MECHGUN", + "007800": "SHOT", + "007900": "CANE", + "007A00": "ROD", + "007B00": "WAND", + "007C00": "TWIN", + "007D00": "CLAW", + "007E00": "BAZOOKA", + "007F00": "NEEDLE", + "008000": "SCYTHE", + "008100": "HAMMER", + "008200": "MOON", + "008300": "PSYCHOGUN", + "008400": "PUNCH", + "008500": "WINDMILL", + "008600": "HARISEN", + "008700": "J-BLADE", + "008800": "J-CUTTER", + "010100": "Frame", + "010101": "Armor", + "010102": "Psy Armor", + "010103": "Giga Frame", + "010104": "Soul Frame", + "010105": "Cross Armor", + "010106": "Solid Frame", + "010107": "Brave Armor", + "010108": "Hyper Frame", + "010109": "Grand Armor", + "01010A": "Shock Frame", + "01010B": "King's Frame", + "01010C": "Dragon Frame", + "01010D": "Absorb Armor", + "01010E": "Protect Frame", + "01010F": "General Armor", + "010110": "Perfect Frame", + "010111": "Valiant Frame", + "010112": "Imperial Armor", + "010113": "Holiness Armor", + "010114": "Guardian Armor", + "010115": "Divinity Armor", + "010116": "Ultimate Frame", + "010117": "Celestial Armor", + "010118": "HUNTER FIELD", + "010119": "RANGER FIELD", + "01011A": "FORCE FIELD", + "01011B": "REVIVAL GARMENT", + "01011C": "SPIRIT GARMENT", + "01011D": "STINK FRAME", + "01011E": "D-PARTS ver1.01", + "01011F": "D-PARTS ver2.10", + "010120": "PARASITE WEAR:De Rol", + "010121": "PARASITE WEAR:Nelgal", + "010122": "PARASITE WEAR:Vajulla", + "010123": "SENSE PLATE", + "010124": "GRAVITON PLATE", + "010125": "ATTRIBUTE PLATE", + "010126": "FLOWEN'S FRAME", + "010127": "CUSTOM FRAME ver.OO", + "010128": "DB'S ARMOR", + "010129": "GUARD WAVE", + "01012A": "DF FIELD", + "01012B": "LUMINOUS FIELD", + "01012C": "CHU CHU FEVER", + "01012D": "LOVE HEART", + "01012E": "FLAME GARMENT", + "01012F": "VIRUS ARMOR:Lafuteria", + "010130": "BRIGHTNESS CIRCLE", + "010131": "AURA FIELD", + "010132": "ELECTRO FRAME", + "010133": "SACRED CLOTH", + "010134": "SMOKING PLATE", + "010200": "Barrier", + "010201": "Shield", + "010202": "Core Shield", + "010203": "Giga Shield", + "010204": "Soul Barrier", + "010205": "Hard Shield", + "010206": "Brave Barrier", + "010207": "Solid Shield", + "010208": "Flame Barrier", + "010209": "Plasma Barrier", + "01020A": "Freeze Barrier", + "01020B": "Psychic Barrier", + "01020C": "General Shield", + "01020D": "Protect Barrier", + "01020E": "Glorious Shield", + "01020F": "Imperial Barrier", + "010210": "Guardian Shield", + "010211": "Divinity Barrier", + "010212": "Ultimate Shield", + "010213": "Spiritual Shield", + "010214": "Celestial Shield", + "010215": "INVISIBLE GUARD", + "010216": "SACRED GUARD", + "010217": "S-PARTS ver1.16", + "010218": "S-PARTS ver2.01", + "010219": "LIGHT RELIEF", + "01021A": "SHIELD OF DELSABER", + "01021B": "FORCE WALL", + "01021C": "RANGER WALL", + "01021D": "HUNTER WALL", + "01021E": "ATTRIBUTE WALL", + "01021F": "SECRET GEAR", + "010220": "COMBAT GEAR", + "010221": "PROTO REGENE GEAR", + "010222": "REGENERATE GEAR", + "010223": "REGENE GEAR ADV.", + "010224": "FLOWEN'S SHIELD", + "010225": "CUSTOM BARRIER ver.OO", + "010226": "DB'S SHIELD", + "010227": "RED RING", + "010228": "TRIPOLIC SHIELD", + "010229": "STANDSTILL SHIELD", + "01022A": "SAFETY HEART", + "01022B": "KASAMI BRACER", + "01022C": "GODS SHIELD SUZAKU", + "01022D": "GODS SHIELD GENBU", + "01022E": "GODS SHIELD BYAKKO", + "01022F": "GODS SHIELD SEIRYU", + "010230": "HANTER'S SHELL", + "010231": "RIKO'S GLASSES", + "010232": "RIKO'S EARRING", + "010233": "BLUE RING", + "010234": "YELLOW RING", + "010235": "SECURE FEET", + "010236": "PURPLE RING", + "010237": "GREEN RING", + "010238": "BLACK RING", + "010239": "WHITE RING", + "010300": "Knight/Power", + "010301": "General/Power", + "010302": "Ogre/Power", + "010303": "God/Power", + "010304": "Priest/Mind", + "010305": "General/Mind", + "010306": "Angel/Mind", + "010307": "God/Mind", + "010308": "Marksman/Arm", + "010309": "General/Arm", + "01030A": "Elf/Arm", + "01030B": "God/Arm", + "01030C": "Thief/Legs", + "01030D": "General/Legs", + "01030E": "Elf/Legs", + "01030F": "God/Legs", + "010310": "Digger/HP", + "010311": "General/HP", + "010312": "Dragon/HP", + "010313": "God/HP", + "010314": "Magician/TP", + "010315": "General/TP", + "010316": "Angel/TP", + "010317": "God/TP", + "010318": "Warrior/Body", + "010319": "General/Body", + "01031A": "Metal/Body", + "01031B": "God/Body", + "01031C": "Angel/Luck", + "01031D": "God/Luck", + "01031E": "Master/Ability", + "01031F": "Hero/Ability", + "010320": "God/Ability", + "010321": "Resist/Fire", + "010322": "Resist/Flame", + "010323": "Resist/Burning", + "010324": "Resist/Cold", + "010325": "Resist/Freeze", + "010326": "Resist/Blizzard", + "010327": "Resist/Shock", + "010328": "Resist/Thunder", + "010329": "Resist/Storm", + "01032A": "Resist/Light", + "01032B": "Resist/Saint", + "01032C": "Resist/Holy", + "01032D": "Resist/Dark", + "01032E": "Resist/Evil", + "01032F": "Resist/Devil", + "010330": "All/Resist", + "010331": "Super/Resist", + "010332": "Perfect/Resist", + "010333": "HP/Restorate", + "010334": "HP/Generate", + "010335": "HP/Revival", + "010336": "TP/Restorate", + "010337": "TP/Generate", + "010338": "TP/Revival", + "010339": "PB/Amplifier", + "01033A": "PB/Generate", + "01033B": "PB/Create", + "01033C": "Wizard/Technique", + "01033D": "Devil/Technique", + "01033E": "God/Technique", + "01033F": "General/Battle", + "010340": "Devil/Battle", + "010341": "God/Battle", + "010342": "State/Maintenance", + "010343": "Trap/Search", + "020000": "Mag", + "020100": "Varuna", + "020200": "Mitra", + "020300": "Surya", + "020400": "Vayu", + "020500": "Varaha", + "020600": "Kama", + "020700": "Ushasu", + "020800": "Apsaras", + "020900": "Kumara", + "020A00": "Kaitabha", + "020B00": "Tapas", + "020C00": "Bhirava", + "020D00": "Kalki", + "020E00": "Rudra", + "020F00": "Marutah", + "021000": "Yaksa", + "021100": "Sita", + "021200": "Garuda", + "021300": "Nandin", + "021400": "Ashvinau", + "021500": "Ribhava", + "021600": "Soma", + "021700": "Ila", + "021800": "Durga", + "021900": "Vritra", + "021A00": "Namuci", + "021B00": "Sumba", + "021C00": "Naga", + "021D00": "Pitri", + "021E00": "Kabanda", + "021F00": "Ravana", + "022000": "Marica", + "022100": "Soniti", + "022200": "Preta", + "022300": "Andhaka", + "022400": "Bana", + "022500": "Naraka", + "022600": "Madhu", + "022700": "Churel", + "022800": "ROBOCHAO", + "022900": "OPA-OPA", + "022A00": "PIAN", + "022B00": "CHAO", + "022C00": "CHU CHU", + "022D00": "KAPU KAPU", + "022E00": "ANGEL'S WING", + "022F00": "DEVIL'S WING", + "023000": "ELENOR", + "023100": "MARK3", + "023200": "MASTER SYSTEM", + "023300": "GENESIS", + "023400": "SEGA SATURN", + "023500": "DREAMCAST", + "023600": "HAMBURGER", + "023700": "PANZER'S TAIL", + "023800": "DAVIL'S TAIL", + "030000": "Monomate", + "030001": "Dimate", + "030002": "Trimate", + "030100": "Monofluid", + "030101": "Difluid", + "030102": "Trifluid", + "030200": "", + "030300": "Sol Atomizer", + "030400": "Moon Atomizer", + "030500": "Star Atomizer", + "030600": "Antidote", + "030601": "Antiparalysis", + "030700": "Telepipe", + "030800": "Trap Vision", + "030900": "Scape Doll", + "030A00": "Monogrinder", + "030A01": "Digrinder", + "030A02": "Trigrinder", + "030B00": "Power Material", + "030B01": "Mind Material", + "030B02": "Evade Material", + "030B03": "HP Material", + "030B04": "TP Material", + "030B05": "Def Material", + "030B06": "Hit Material", + "030B07": "Luck Material", + "030C00": "Cell of MAG 502", + "030C01": "Cell of MAG 213", + "030C02": "Parts of RoboChao", + "030C03": "Heart of Opa Opa", + "030C04": "Heart of Pian", + "030C05": "Heart of Chao", + "030D00": "Sorcerer's Right Arm", + "030D01": "S-beat's Arms", + "030D02": "P-arm's Arms", + "030D03": "Delsaber's Right Arm", + "030D04": "C-bringer's Right Arm", + "030D05": "Delsabre's Left Arm", + "030D06": "Book of KATANA1", + "030D07": "Book of KATANA2", + "030D08": "Book of KATANA3", + "030E00": "S-red's Arms", + "030E01": "Dragon's Claw", + "030E02": "Hildebear's Head", + "030E03": "Hildeblue's Head", + "030E04": "Parts of Baranz", + "030E05": "Belra's Right Arm", + "030E06": "Joint Parts", + "030E07": "Weapons Bronze Badge", + "030E08": "Weapons Silver Badge", + "030E09": "Weapons Gold Badge", + "030E0A": "Weapons Crystal Badge", + "030E0B": "Weapons Steel Badge", + "030E0C": "Weapons Aluminum Badge", + "030E0D": "Weapons Leather Badge", + "030E0E": "Weapons Bone Badge", + "030E0F": "Letter of appreciation", + "030E10": "Autograph Album", + "030E11": "High-level Mag Cell, Eno", + "030E12": "High-level Mag Armor, Uru", + "030E13": "Special Gene Flou", + "030E14": "Sound Source FM", + "030E15": "Parts of \"68000\"", + "030E16": "SH2", + "030E17": "SH4", + "030E18": "Modem", + "030E19": "Power VR", + "030E1A": "Glory in the past", + "030E1B": "Valentine's Chocolate", + "030E1C": "New Year's Card", + "030E1D": "Christmas Card", + "030E1E": "Birthday Card", + "030E1F": "Proof of Sonic Team", + "030E20": "Special Event Ticket", + "030E21": "Flower Bouquet", + "030E22": "Cake", + "030E23": "Accessories", + "030E24": "Mr.Naka's Business Card", + "030F00": "????" +} diff --git a/system/item-tables/names-v3.json b/system/item-tables/names-v3.json new file mode 100755 index 00000000..48fb2d50 --- /dev/null +++ b/system/item-tables/names-v3.json @@ -0,0 +1,1264 @@ +{ + "000100": "Saber", + "000101": "Brand", + "000102": "Buster", + "000103": "Pallasch", + "000104": "Gladius", + "000105": "DB'S SABER", + "000106": "KALADBOLG", + "000107": "DURANDAL", + "000200": "Sword", + "000201": "Gigush", + "000202": "Breaker", + "000203": "Claymore", + "000204": "Calibur", + "000205": "FLOWEN'S SWORD", + "000206": "LAST SURVIVOR", + "000207": "DRAGON SLAYER", + "000300": "Dagger", + "000301": "Knife", + "000302": "Blade", + "000303": "Edge", + "000304": "Ripper", + "000305": "BLADE DANCE", + "000306": "BLOODY ART", + "000307": "CROSS SCAR", + "000400": "Partisan", + "000401": "Halbert", + "000402": "Glaive", + "000403": "Berdys", + "000404": "Gungnir", + "000405": "BRIONAC", + "000406": "VJAYA", + "000407": "GAE BOLG", + "000500": "Slicer", + "000501": "Spinner", + "000502": "Cutter", + "000503": "Sawcer", + "000504": "Diska", + "000505": "SLICER OF ASSASSIN", + "000506": "DISKA OF LIBERATOR", + "000507": "DISKA OF BRAVEMAN", + "000600": "Handgun", + "000601": "Autogun", + "000602": "Lockgun", + "000603": "Railgun", + "000604": "Raygun", + "000605": "VARISTA", + "000606": "CUSTOM RAY ver.OO", + "000607": "BRAVACE", + "000700": "Rifle", + "000701": "Sniper", + "000702": "Blaster", + "000703": "Beam", + "000704": "Laser", + "000705": "VISK-235W", + "000706": "WALS-MK2", + "000707": "JUSTY-23ST", + "000800": "Mechgun", + "000801": "Assault", + "000802": "Repeater", + "000803": "Gatling", + "000804": "Vulcan", + "000805": "M&A60 VISE", + "000806": "H&S25 JUSTICE", + "000807": "L&K14 COMBAT", + "000900": "Shot", + "000901": "Spread", + "000902": "Cannon", + "000903": "Launcher", + "000904": "Arms", + "000905": "CRUSH BULLET", + "000906": "METEOR SMASH", + "000907": "FINAL IMPACT", + "000A00": "Cane", + "000A01": "Stick", + "000A02": "Mace", + "000A03": "Club", + "000A04": "CLUB OF LACONIUM", + "000A05": "MACE OF ADAMAN", + "000A06": "CLUB OF ZUMIURAN", + "000B00": "Rod", + "000B01": "Pole", + "000B02": "Pillar", + "000B03": "Striker", + "000B04": "BATTLE VERGE", + "000B05": "BRAVE HAMMER", + "000B06": "ALIVE AQHU", + "000C00": "Wand", + "000C01": "Staff", + "000C02": "Baton", + "000C03": "Scepter", + "000C04": "FIRE SCEPTER:AGNI", + "000C05": "ICE STAFF:DAGON", + "000C06": "STORM WAND:INDRA", + "000D00": "PHOTON CLAW", + "000D01": "SILENCE CLAW", + "000D02": "NEI'S CLAW", + "000E00": "DOUBLE SABER", + "000E01": "STAG CUTLERY", + "000E02": "TWIN BRAND", + "000F00": "BRAVE KNUCKLE", + "000F01": "ANGRY FIST", + "000F02": "GOD HAND", + "000F03": "SONIC KNUCKLE", + "001000": "OROTIAGITO", + "001001": "AGITO", + "001002": "AGITO", + "001003": "AGITO", + "001004": "AGITO", + "001005": "AGITO", + "001006": "AGITO", + "001100": "SOUL EATER", + "001101": "SOUL BANISH", + "001200": "SPREAD NEEDLE", + "001300": "HOLY RAY", + "001400": "INFERNO BAZOOKA", + "001500": "FLAME VISIT", + "001501": "BURNING VISIT", + "001600": "AKIKO'S FRYING PAN", + "001700": "SORCERER'S CANE", + "001800": "S-BEAT'S BLADE", + "001900": "P-ARMS'S BLADE", + "001A00": "DELSABER'S BUSTER", + "001B00": "BRINGER'S RIFLE", + "001C00": "EGG BLASTER", + "001D00": "PSYCHO WAND", + "001E00": "HEAVEN PUNISHER", + "001F00": "LAVIS CANNON", + "002000": "VICTOR AXE", + "002100": "CHAIN SAWD", + "002200": "CADUCEUS", + "002300": "STING TIP", + "002400": "MAGICAL PIECE", + "002500": "TECHNICAL CROZIER", + "002600": "SUPPRESSED GUN", + "002700": "ANCIENT SABER", + "002800": "HARISEN BATTLE FAN", + "002900": "YAMIGARASU", + "002A00": "AKIKO'S WOK", + "002B00": "TOY HAMMER", + "002C00": "ELYSION", + "002D00": "RED SABER", + "002E00": "METEOR CUDGEL", + "002F00": "MONKEY KING BAR", + "002F01": "BLACK KING BAR", + "003000": "DOUBLE CANNON", + "003100": "HUGE BATTLE FAN", + "003200": "TSUMIKIRI J-SWORD", + "003300": "SEALED J-SWORD", + "003400": "RED SWORD", + "003500": "CRAZY TUNE", + "003600": "TWIN CHAKRAM", + "003700": "WOK OF AKIKO'S SHOP", + "003800": "LAVIS BLADE", + "003900": "RED DAGGER", + "003A00": "MADAM'S PARASOL", + "003B00": "MADAM'S UMBRELLA", + "003C00": "IMPERIAL PICK", + "003D00": "BERDYSH", + "003E00": "RED PARTISAN", + "003F00": "FLIGHT CUTTER", + "004000": "FLIGHT FAN", + "004100": "RED SLICER", + "004200": "HANDGUN:GULD", + "004300": "HANDGUN:MILLA", + "004400": "RED HANDGUN", + "004500": "FROZEN SHOOTER", + "004501": "SNOW QUEEN", + "004600": "ANTI ANDROID RIFLE", + "004700": "ROCKET PUNCH", + "004800": "SAMBA MARACAS", + "004900": "TWIN PSYCHOGUN", + "004A00": "DRILL LAUNCHER", + "004B00": "GULD MILLA", + "004C00": "RED MECHGUN", + "004D00": "BELRA CANNON", + "004E00": "PANZER FAUST", + "004E01": "IRON FAUST", + "004F00": "SUMMIT MOON", + "005000": "WINDMILL", + "005100": "EVIL CURST", + "005200": "FLOWER CANE", + "005300": "HILDEBEAR'S CANE", + "005400": "HILDEBLUE'S CANE", + "005500": "RABBIT WAND", + "005600": "PLANTAIN LEAF", + "005601": "FATSIA", + "005700": "DEMONIC FORK", + "005800": "STRIKER OF CHAO", + "005900": "BROOM", + "005A00": "PROPHETS OF MOTAV", + "005B00": "THE SIGH OF A GOD", + "005C00": "TWINKLE STAR", + "005D00": "PLANTAIN FAN", + "005E00": "TWIN BLAZE", + "005F00": "MARINA'S BAG", + "006000": "DRAGON'S CLAW", + "006100": "PANTHER'S CLAW", + "006200": "S-RED'S BLADE", + "006300": "PLANTAIN HUGE FAN", + "006400": "CHAMELEON SCYTHE", + "006500": "YASMINKOV 3000R", + "006600": "ANO RIFLE", + "006700": "BARANZ LAUNCHER", + "006800": "BRANCH OF PAKUPAKU", + "006900": "HEART OF POUMN", + "006A00": "YASMINKOV 2000H", + "006B00": "YASMINKOV 7000V", + "006C00": "YASMINKOV 9000M", + "006D00": "MASER BEAM", + "006D01": "POWER MASER", + "006E00": "GAME MAGAZNE", + "006F00": "FLOWER BOUQUET", + "007000": "SABER", + "007001": "SABER", + "007002": "SABER", + "007003": "SABER", + "007004": "SABER", + "007005": "SABER", + "007006": "SABER", + "007007": "SABER", + "007008": "SABER", + "007009": "SABER", + "00700A": "SABER", + "00700B": "SABER", + "00700C": "SABER", + "00700D": "SABER", + "00700E": "SABER", + "00700F": "SABER", + "007010": "SABER", + "007100": "SWORD", + "007101": "SWORD", + "007102": "SWORD", + "007103": "SWORD", + "007104": "SWORD", + "007105": "SWORD", + "007106": "SWORD", + "007107": "SWORD", + "007108": "SWORD", + "007109": "SWORD", + "00710A": "SWORD", + "00710B": "SWORD", + "00710C": "SWORD", + "00710D": "SWORD", + "00710E": "SWORD", + "00710F": "SWORD", + "007110": "SWORD", + "007200": "BLADE", + "007201": "BLADE", + "007202": "BLADE", + "007203": "BLADE", + "007204": "BLADE", + "007205": "BLADE", + "007206": "BLADE", + "007207": "BLADE", + "007208": "BLADE", + "007209": "BLADE", + "00720A": "BLADE", + "00720B": "BLADE", + "00720C": "BLADE", + "00720D": "BLADE", + "00720E": "BLADE", + "00720F": "BLADE", + "007210": "BLADE", + "007300": "PARTISAN", + "007301": "PARTISAN", + "007302": "PARTISAN", + "007303": "PARTISAN", + "007304": "PARTISAN", + "007305": "PARTISAN", + "007306": "PARTISAN", + "007307": "PARTISAN", + "007308": "PARTISAN", + "007309": "PARTISAN", + "00730A": "PARTISAN", + "00730B": "PARTISAN", + "00730C": "PARTISAN", + "00730D": "PARTISAN", + "00730E": "PARTISAN", + "00730F": "PARTISAN", + "007310": "PARTISAN", + "007400": "SLICER", + "007401": "SLICER", + "007402": "SLICER", + "007403": "SLICER", + "007404": "SLICER", + "007405": "SLICER", + "007406": "SLICER", + "007407": "SLICER", + "007408": "SLICER", + "007409": "SLICER", + "00740A": "SLICER", + "00740B": "SLICER", + "00740C": "SLICER", + "00740D": "SLICER", + "00740E": "SLICER", + "00740F": "SLICER", + "007410": "SLICER", + "007500": "GUN", + "007501": "GUN", + "007502": "GUN", + "007503": "GUN", + "007504": "GUN", + "007505": "GUN", + "007506": "GUN", + "007507": "GUN", + "007508": "GUN", + "007509": "GUN", + "00750A": "GUN", + "00750B": "GUN", + "00750C": "GUN", + "00750D": "GUN", + "00750E": "GUN", + "00750F": "GUN", + "007510": "GUN", + "007600": "RIFLE", + "007601": "RIFLE", + "007602": "RIFLE", + "007603": "RIFLE", + "007604": "RIFLE", + "007605": "RIFLE", + "007606": "RIFLE", + "007607": "RIFLE", + "007608": "RIFLE", + "007609": "RIFLE", + "00760A": "RIFLE", + "00760B": "RIFLE", + "00760C": "RIFLE", + "00760D": "RIFLE", + "00760E": "RIFLE", + "00760F": "RIFLE", + "007610": "RIFLE", + "007700": "MECHGUN", + "007701": "MECHGUN", + "007702": "MECHGUN", + "007703": "MECHGUN", + "007704": "MECHGUN", + "007705": "MECHGUN", + "007706": "MECHGUN", + "007707": "MECHGUN", + "007708": "MECHGUN", + "007709": "MECHGUN", + "00770A": "MECHGUN", + "00770B": "MECHGUN", + "00770C": "MECHGUN", + "00770D": "MECHGUN", + "00770E": "MECHGUN", + "00770F": "MECHGUN", + "007710": "MECHGUN", + "007800": "SHOT", + "007801": "SHOT", + "007802": "SHOT", + "007803": "SHOT", + "007804": "SHOT", + "007805": "SHOT", + "007806": "SHOT", + "007807": "SHOT", + "007808": "SHOT", + "007809": "SHOT", + "00780A": "SHOT", + "00780B": "SHOT", + "00780C": "SHOT", + "00780D": "SHOT", + "00780E": "SHOT", + "00780F": "SHOT", + "007810": "SHOT", + "007900": "CANE", + "007901": "CANE", + "007902": "CANE", + "007903": "CANE", + "007904": "CANE", + "007905": "CANE", + "007906": "CANE", + "007907": "CANE", + "007908": "CANE", + "007909": "CANE", + "00790A": "CANE", + "00790B": "CANE", + "00790C": "CANE", + "00790D": "CANE", + "00790E": "CANE", + "00790F": "CANE", + "007910": "CANE", + "007A00": "ROD", + "007A01": "ROD", + "007A02": "ROD", + "007A03": "ROD", + "007A04": "ROD", + "007A05": "ROD", + "007A06": "ROD", + "007A07": "ROD", + "007A08": "ROD", + "007A09": "ROD", + "007A0A": "ROD", + "007A0B": "ROD", + "007A0C": "ROD", + "007A0D": "ROD", + "007A0E": "ROD", + "007A0F": "ROD", + "007A10": "ROD", + "007B00": "WAND", + "007B01": "WAND", + "007B02": "WAND", + "007B03": "WAND", + "007B04": "WAND", + "007B05": "WAND", + "007B06": "WAND", + "007B07": "WAND", + "007B08": "WAND", + "007B09": "WAND", + "007B0A": "WAND", + "007B0B": "WAND", + "007B0C": "WAND", + "007B0D": "WAND", + "007B0E": "WAND", + "007B0F": "WAND", + "007B10": "WAND", + "007C00": "TWIN", + "007C01": "TWIN", + "007C02": "TWIN", + "007C03": "TWIN", + "007C04": "TWIN", + "007C05": "TWIN", + "007C06": "TWIN", + "007C07": "TWIN", + "007C08": "TWIN", + "007C09": "TWIN", + "007C0A": "TWIN", + "007C0B": "TWIN", + "007C0C": "TWIN", + "007C0D": "TWIN", + "007C0E": "TWIN", + "007C0F": "TWIN", + "007C10": "TWIN", + "007D00": "CLAW", + "007D01": "CLAW", + "007D02": "CLAW", + "007D03": "CLAW", + "007D04": "CLAW", + "007D05": "CLAW", + "007D06": "CLAW", + "007D07": "CLAW", + "007D08": "CLAW", + "007D09": "CLAW", + "007D0A": "CLAW", + "007D0B": "CLAW", + "007D0C": "CLAW", + "007D0D": "CLAW", + "007D0E": "CLAW", + "007D0F": "CLAW", + "007D10": "CLAW", + "007E00": "BAZOOKA", + "007E01": "BAZOOKA", + "007E02": "BAZOOKA", + "007E03": "BAZOOKA", + "007E04": "BAZOOKA", + "007E05": "BAZOOKA", + "007E06": "BAZOOKA", + "007E07": "BAZOOKA", + "007E08": "BAZOOKA", + "007E09": "BAZOOKA", + "007E0A": "BAZOOKA", + "007E0B": "BAZOOKA", + "007E0C": "BAZOOKA", + "007E0D": "BAZOOKA", + "007E0E": "BAZOOKA", + "007E0F": "BAZOOKA", + "007E10": "BAZOOKA", + "007F00": "NEEDLE", + "007F01": "NEEDLE", + "007F02": "NEEDLE", + "007F03": "NEEDLE", + "007F04": "NEEDLE", + "007F05": "NEEDLE", + "007F06": "NEEDLE", + "007F07": "NEEDLE", + "007F08": "NEEDLE", + "007F09": "NEEDLE", + "007F0A": "NEEDLE", + "007F0B": "NEEDLE", + "007F0C": "NEEDLE", + "007F0D": "NEEDLE", + "007F0E": "NEEDLE", + "007F0F": "NEEDLE", + "007F10": "NEEDLE", + "008000": "SCYTHE", + "008001": "SCYTHE", + "008002": "SCYTHE", + "008003": "SCYTHE", + "008004": "SCYTHE", + "008005": "SCYTHE", + "008006": "SCYTHE", + "008007": "SCYTHE", + "008008": "SCYTHE", + "008009": "SCYTHE", + "00800A": "SCYTHE", + "00800B": "SCYTHE", + "00800C": "SCYTHE", + "00800D": "SCYTHE", + "00800E": "SCYTHE", + "00800F": "SCYTHE", + "008010": "SCYTHE", + "008100": "HAMMER", + "008101": "HAMMER", + "008102": "HAMMER", + "008103": "HAMMER", + "008104": "HAMMER", + "008105": "HAMMER", + "008106": "HAMMER", + "008107": "HAMMER", + "008108": "HAMMER", + "008109": "HAMMER", + "00810A": "HAMMER", + "00810B": "HAMMER", + "00810C": "HAMMER", + "00810D": "HAMMER", + "00810E": "HAMMER", + "00810F": "HAMMER", + "008110": "HAMMER", + "008200": "MOON", + "008201": "MOON", + "008202": "MOON", + "008203": "MOON", + "008204": "MOON", + "008205": "MOON", + "008206": "MOON", + "008207": "MOON", + "008208": "MOON", + "008209": "MOON", + "00820A": "MOON", + "00820B": "MOON", + "00820C": "MOON", + "00820D": "MOON", + "00820E": "MOON", + "00820F": "MOON", + "008210": "MOON", + "008300": "PSYCHOGUN", + "008301": "PSYCHOGUN", + "008302": "PSYCHOGUN", + "008303": "PSYCHOGUN", + "008304": "PSYCHOGUN", + "008305": "PSYCHOGUN", + "008306": "PSYCHOGUN", + "008307": "PSYCHOGUN", + "008308": "PSYCHOGUN", + "008309": "PSYCHOGUN", + "00830A": "PSYCHOGUN", + "00830B": "PSYCHOGUN", + "00830C": "PSYCHOGUN", + "00830D": "PSYCHOGUN", + "00830E": "PSYCHOGUN", + "00830F": "PSYCHOGUN", + "008310": "PSYCHOGUN", + "008400": "PUNCH", + "008401": "PUNCH", + "008402": "PUNCH", + "008403": "PUNCH", + "008404": "PUNCH", + "008405": "PUNCH", + "008406": "PUNCH", + "008407": "PUNCH", + "008408": "PUNCH", + "008409": "PUNCH", + "00840A": "PUNCH", + "00840B": "PUNCH", + "00840C": "PUNCH", + "00840D": "PUNCH", + "00840E": "PUNCH", + "00840F": "PUNCH", + "008410": "PUNCH", + "008500": "WINDMILL", + "008501": "WINDMILL", + "008502": "WINDMILL", + "008503": "WINDMILL", + "008504": "WINDMILL", + "008505": "WINDMILL", + "008506": "WINDMILL", + "008507": "WINDMILL", + "008508": "WINDMILL", + "008509": "WINDMILL", + "00850A": "WINDMILL", + "00850B": "WINDMILL", + "00850C": "WINDMILL", + "00850D": "WINDMILL", + "00850E": "WINDMILL", + "00850F": "WINDMILL", + "008510": "WINDMILL", + "008600": "HARISEN", + "008601": "HARISEN", + "008602": "HARISEN", + "008603": "HARISEN", + "008604": "HARISEN", + "008605": "HARISEN", + "008606": "HARISEN", + "008607": "HARISEN", + "008608": "HARISEN", + "008609": "HARISEN", + "00860A": "HARISEN", + "00860B": "HARISEN", + "00860C": "HARISEN", + "00860D": "HARISEN", + "00860E": "HARISEN", + "00860F": "HARISEN", + "008610": "HARISEN", + "008700": "KATANA", + "008701": "KATANA", + "008702": "KATANA", + "008703": "KATANA", + "008704": "KATANA", + "008705": "KATANA", + "008706": "KATANA", + "008707": "KATANA", + "008708": "KATANA", + "008709": "KATANA", + "00870A": "KATANA", + "00870B": "KATANA", + "00870C": "KATANA", + "00870D": "KATANA", + "00870E": "KATANA", + "00870F": "KATANA", + "008710": "KATANA", + "008800": "J-CUTTER", + "008801": "J-CUTTER", + "008802": "J-CUTTER", + "008803": "J-CUTTER", + "008804": "J-CUTTER", + "008805": "J-CUTTER", + "008806": "J-CUTTER", + "008807": "J-CUTTER", + "008808": "J-CUTTER", + "008809": "J-CUTTER", + "00880A": "J-CUTTER", + "00880B": "J-CUTTER", + "00880C": "J-CUTTER", + "00880D": "J-CUTTER", + "00880E": "J-CUTTER", + "00880F": "J-CUTTER", + "008810": "J-CUTTER", + "008900": "MUSASHI", + "008901": "YAMATO", + "008902": "ASUKA", + "008903": "SANGE & YASHA", + "008A00": "SANGE", + "008A01": "YASHA", + "008A02": "KAMUI", + "008B00": "PHOTON LAUNCHER", + "008B01": "GUILTY LIGHT", + "008B02": "RED SCORPIO", + "008C00": "TALIS", + "008C01": "MAHU", + "008C02": "HITOGATA", + "008C03": "DANCING HITOGATA", + "008D00": "NUG2000-BAZOOKA", + "008E00": "S-BERILL'S HANDS #0", + "008E01": "S-BERILL'S HANDS #1", + "008F00": "FLOWEN'S SWORD", + "008F01": "FLOWEN'S SWORD", + "008F02": "FLOWEN'S SWORD", + "008F03": "FLOWEN'S SWORD", + "008F04": "FLOWEN'S SWORD", + "008F05": "FLOWEN'S SWORD", + "008F06": "FLOWEN'S SWORD", + "008F07": "FLOWEN'S SWORD", + "008F08": "FLOWEN'S SWORD", + "009000": "DB's SWORD", + "009001": "DB's SWORD", + "009002": "DB's SWORD", + "009003": "DB's SWORD", + "009004": "DB's SWORD", + "009005": "DB's SWORD", + "009006": "DB's SWORD", + "009007": "DB's SWORD", + "009008": "DB's SWORD", + "009100": "GI GUE BAZOOKA", + "009200": "GUARDIANNA", + "009300": "VIRIDIA CARD", + "009301": "GREENILL CARD", + "009302": "SKYLY CARD", + "009303": "BLUEFULL CARD", + "009304": "PURPLENUM CARD", + "009305": "PINKAL CARD", + "009306": "REDRIA CARD", + "009307": "ORAN CARD", + "009308": "YELLOWBOZE CARD", + "009309": "WHITILL CARD", + "009400": "MORNING GLORY", + "009500": "PARTISAN of LIGHTNING", + "009600": "GAL WIND", + "009700": "ZANBA", + "009800": "RIKA'S CLAW", + "009900": "ANGEL HARP", + "009A00": "DEMOLITION COMET", + "009B00": "NEI'S CLAW", + "009C00": "RAINBOW BATON", + "009D00": "DARK FLOW", + "009E00": "DARK METEOR", + "009F00": "DARK BRIDGE", + "00A000": "G-ASSASSIN'S SABERS", + "00A100": "RAPPY'S FAN", + "00A200": "BOOMA'S CLAW", + "00A201": "GOBOOMA'S CLAW", + "00A202": "GIGOBOOMA'S CLAW", + "00A300": "RUBY BULLET", + "00A400": "AMORE ROSE", + "00A500": "SWORDS", + "00A501": "SWORDS", + "00A502": "SWORDS", + "00A503": "SWORDS", + "00A504": "SWORDS", + "00A505": "SWORDS", + "00A506": "SWORDS", + "00A507": "SWORDS", + "00A508": "SWORDS", + "00A509": "SWORDS", + "00A50A": "SWORDS", + "00A50B": "SWORDS", + "00A50C": "SWORDS", + "00A50D": "SWORDS", + "00A50E": "SWORDS", + "00A50F": "SWORDS", + "00A510": "SWORDS", + "00A600": "LAUNCHER", + "00A601": "LAUNCHER", + "00A602": "LAUNCHER", + "00A603": "LAUNCHER", + "00A604": "LAUNCHER", + "00A605": "LAUNCHER", + "00A606": "LAUNCHER", + "00A607": "LAUNCHER", + "00A608": "LAUNCHER", + "00A609": "LAUNCHER", + "00A60A": "LAUNCHER", + "00A60B": "LAUNCHER", + "00A60C": "LAUNCHER", + "00A60D": "LAUNCHER", + "00A60E": "LAUNCHER", + "00A60F": "LAUNCHER", + "00A610": "LAUNCHER", + "00A700": "CARDS", + "00A701": "CARDS", + "00A702": "CARDS", + "00A703": "CARDS", + "00A704": "CARDS", + "00A705": "CARDS", + "00A706": "CARDS", + "00A707": "CARDS", + "00A708": "CARDS", + "00A709": "CARDS", + "00A70A": "CARDS", + "00A70B": "CARDS", + "00A70C": "CARDS", + "00A70D": "CARDS", + "00A70E": "CARDS", + "00A70F": "CARDS", + "00A710": "CARDS", + "00A800": "KNUCKLE", + "00A801": "KNUCKLE", + "00A802": "KNUCKLE", + "00A803": "KNUCKLE", + "00A804": "KNUCKLE", + "00A805": "KNUCKLE", + "00A806": "KNUCKLE", + "00A807": "KNUCKLE", + "00A808": "KNUCKLE", + "00A809": "KNUCKLE", + "00A80A": "KNUCKLE", + "00A80B": "KNUCKLE", + "00A80C": "KNUCKLE", + "00A80D": "KNUCKLE", + "00A80E": "KNUCKLE", + "00A80F": "KNUCKLE", + "00A810": "KNUCKLE", + "00A900": "AXE", + "00A901": "AXE", + "00A902": "AXE", + "00A903": "AXE", + "00A904": "AXE", + "00A905": "AXE", + "00A906": "AXE", + "00A907": "AXE", + "00A908": "AXE", + "00A909": "AXE", + "00A90A": "AXE", + "00A90B": "AXE", + "00A90C": "AXE", + "00A90D": "AXE", + "00A90E": "AXE", + "00A90F": "AXE", + "00A910": "AXE", + "010100": "Frame", + "010101": "Armor", + "010102": "Psy Armor", + "010103": "Giga Frame", + "010104": "Soul Frame", + "010105": "Cross Armor", + "010106": "Solid Frame", + "010107": "Brave Armor", + "010108": "Hyper Frame", + "010109": "Grand Armor", + "01010A": "Shock Frame", + "01010B": "King's Frame", + "01010C": "Dragon Frame", + "01010D": "Absorb Armor", + "01010E": "Protect Frame", + "01010F": "General Armor", + "010110": "Perfect Frame", + "010111": "Valiant Frame", + "010112": "Imperial Armor", + "010113": "Holiness Armor", + "010114": "Guardian Armor", + "010115": "Divinity Armor", + "010116": "Ultimate Frame", + "010117": "Celestial Armor", + "010118": "HUNTER FIELD", + "010119": "RANGER FIELD", + "01011A": "FORCE FIELD", + "01011B": "REVIVAL GARMENT", + "01011C": "SPIRIT GARMENT", + "01011D": "STINK FRAME", + "01011E": "D-PARTS ver1.01", + "01011F": "D-PARTS ver2.10", + "010120": "PARASITE WEAR:De Rol", + "010121": "PARASITE WEAR:Nelgal", + "010122": "PARASITE WEAR:Vajulla", + "010123": "SENSE PLATE", + "010124": "GRAVITON PLATE", + "010125": "ATTRIBUTE PLATE", + "010126": "FLOWEN'S FRAME", + "010127": "CUSTOM FRAME ver.OO", + "010128": "DB'S ARMOR", + "010129": "GUARD WAVE", + "01012A": "DF FIELD", + "01012B": "LUMINOUS FIELD", + "01012C": "CHU CHU FEVER", + "01012D": "LOVE HEART", + "01012E": "FLAME GARMENT", + "01012F": "VIRUS ARMOR:Lafuteria", + "010130": "BRIGHTNESS CIRCLE", + "010131": "AURA FIELD", + "010132": "ELECTRO FRAME", + "010133": "SACRED CLOTH", + "010134": "SMOKING PLATE", + "010135": "????", + "010200": "Barrier", + "010201": "Shield", + "010202": "Core Shield", + "010203": "Giga Shield", + "010204": "Soul Barrier", + "010205": "Hard Shield", + "010206": "Brave Barrier", + "010207": "Solid Shield", + "010208": "Flame Barrier", + "010209": "Plasma Barrier", + "01020A": "Freeze Barrier", + "01020B": "Psychic Barrier", + "01020C": "General Shield", + "01020D": "Protect Barrier", + "01020E": "Glorious Shield", + "01020F": "Imperial Barrier", + "010210": "Guardian Shield", + "010211": "Divinity Barrier", + "010212": "Ultimate Shield", + "010213": "Spiritual Shield", + "010214": "Celestial Shield", + "010215": "INVISIBLE GUARD", + "010216": "SACRED GUARD", + "010217": "S-PARTS ver1.16", + "010218": "S-PARTS ver2.01", + "010219": "LIGHT RELIEF", + "01021A": "SHIELD OF DELSABER", + "01021B": "FORCE WALL", + "01021C": "RANGER WALL", + "01021D": "HUNTER WALL", + "01021E": "ATTRIBUTE WALL", + "01021F": "SECRET GEAR", + "010220": "COMBAT GEAR", + "010221": "PROTO REGENE GEAR", + "010222": "REGENERATE GEAR", + "010223": "REGENE GEAR ADV.", + "010224": "FLOWEN'S SHIELD", + "010225": "CUSTOM BARRIER ver.OO", + "010226": "DB'S SHIELD", + "010227": "RED RING", + "010228": "TRIPOLIC SHIELD", + "010229": "STANDSTILL SHIELD", + "01022A": "SAFETY HEART", + "01022B": "KASAMI BRACER", + "01022C": "GODS SHIELD SUZAKU", + "01022D": "GODS SHIELD GENBU", + "01022E": "GODS SHIELD BYAKKO", + "01022F": "GODS SHIELD SEIRYU", + "010230": "HUNTER'S SHELL", + "010231": "RICO'S GLASSES", + "010232": "RICO'S EARRING", + "010233": "BLUE RING", + "010234": "Barrier", + "010235": "SECURE FEET", + "010236": "Barrier", + "010237": "Barrier", + "010238": "Barrier", + "010239": "Barrier", + "01023A": "RESTA MERGE", + "01023B": "ANTI MERGE", + "01023C": "SHIFTA MERGE", + "01023D": "DEBAND MERGE", + "01023E": "FOIE MERGE", + "01023F": "GIFOIE MERGE", + "010240": "RAFOIE MERGE", + "010241": "RED MERGE", + "010242": "BARTA MERGE", + "010243": "GIBARTA MERGE", + "010244": "RABARTA MERGE", + "010245": "BLUE MERGE", + "010246": "ZONDE MERGE", + "010247": "GIZONDE MERGE", + "010248": "RAZONDE MERGE", + "010249": "YELLOW MERGE", + "01024A": "RECOVERY BARRIER", + "01024B": "ASSIST BARRIER", + "01024C": "RED BARRIER", + "01024D": "BLUE BARRIER", + "01024E": "YELLOW BARRIER", + "01024F": "WEAPONS GOLD SHIELD", + "010250": "BLACK GEAR", + "010251": "WORKS GUARD", + "010252": "RAGOL RING", + "010253": "BLUE RING", + "010254": "BLUE RING", + "010255": "BLUE RING", + "010256": "BLUE RING", + "010257": "BLUE RING", + "010258": "BLUE RING", + "010259": "BLUE RING", + "01025A": "BLUE RING", + "01025B": "GREEN RING", + "01025C": "GREEN RING", + "01025D": "GREEN RING", + "01025E": "GREEN RING", + "01025F": "GREEN RING", + "010260": "GREEN RING", + "010261": "GREEN RING", + "010262": "GREEN RING", + "010263": "YELLOW RING", + "010264": "YELLOW RING", + "010265": "YELLOW RING", + "010266": "YELLOW RING", + "010267": "YELLOW RING", + "010268": "YELLOW RING", + "010269": "YELLOW RING", + "01026A": "YELLOW RING", + "01026B": "PURPLE RING", + "01026C": "PURPLE RING", + "01026D": "PURPLE RING", + "01026E": "PURPLE RING", + "01026F": "PURPLE RING", + "010270": "PURPLE RING", + "010271": "PURPLE RING", + "010272": "PURPLE RING", + "010273": "WHITE RING", + "010274": "WHITE RING", + "010275": "WHITE RING", + "010276": "WHITE RING", + "010277": "WHITE RING", + "010278": "WHITE RING", + "010279": "WHITE RING", + "01027A": "WHITE RING", + "01027B": "BLACK RING", + "01027C": "BLACK RING", + "01027D": "BLACK RING", + "01027E": "BLACK RING", + "01027F": "BLACK RING", + "010280": "BLACK RING", + "010281": "BLACK RING", + "010282": "BLACK RING", + "010283": "WEAPONS SILVER SHIELD", + "010284": "WEAPONS COPPER SHIELD", + "010285": "????", + "010300": "Knight/Power", + "010301": "General/Power", + "010302": "Ogre/Power", + "010303": "God/Power", + "010304": "Priest/Mind", + "010305": "General/Mind", + "010306": "Angel/Mind", + "010307": "God/Mind", + "010308": "Marksman/Arm", + "010309": "General/Arm", + "01030A": "Elf/Arm", + "01030B": "God/Arm", + "01030C": "Thief/Legs", + "01030D": "General/Legs", + "01030E": "Elf/Legs", + "01030F": "God/Legs", + "010310": "Digger/HP", + "010311": "General/HP", + "010312": "Dragon/HP", + "010313": "God/HP", + "010314": "Magician/TP", + "010315": "General/TP", + "010316": "Angel/TP", + "010317": "God/TP", + "010318": "Warrior/Body", + "010319": "General/Body", + "01031A": "Metal/Body", + "01031B": "God/Body", + "01031C": "Angel/Luck", + "01031D": "God/Luck", + "01031E": "Master/Ability", + "01031F": "Hero/Ability", + "010320": "God/Ability", + "010321": "Resist/Fire", + "010322": "Resist/Flame", + "010323": "Resist/Burning", + "010324": "Resist/Cold", + "010325": "Resist/Freeze", + "010326": "Resist/Blizzard", + "010327": "Resist/Shock", + "010328": "Resist/Thunder", + "010329": "Resist/Storm", + "01032A": "Resist/Light", + "01032B": "Resist/Saint", + "01032C": "Resist/Holy", + "01032D": "Resist/Dark", + "01032E": "Resist/Evil", + "01032F": "Resist/Devil", + "010330": "All/Resist", + "010331": "Super/Resist", + "010332": "Perfect/Resist", + "010333": "HP/Restorate", + "010334": "HP/Generate", + "010335": "HP/Revival", + "010336": "TP/Restorate", + "010337": "TP/Generate", + "010338": "TP/Revival", + "010339": "PB/Amplifier", + "01033A": "PB/Generate", + "01033B": "PB/Create", + "01033C": "Wizard/Technique", + "01033D": "Devil/Technique", + "01033E": "God/Technique", + "01033F": "General/Battle", + "010340": "Devil/Battle", + "010341": "God/Battle", + "010342": "Cure/Poison", + "010343": "Cure/Paralysis", + "010344": "Cure/Slow", + "010345": "Cure/Confuse", + "010346": "Cure/Freeze", + "010347": "Cure/Shock", + "010348": "????", + "020000": "Mag", + "020100": "Varuna", + "020200": "Mitra", + "020300": "Surya", + "020400": "Vayu", + "020500": "Varaha", + "020600": "Kama", + "020700": "Ushasu", + "020800": "Apsaras", + "020900": "Kumara", + "020A00": "Kaitabha", + "020B00": "Tapas", + "020C00": "Bhirava", + "020D00": "Kalki", + "020E00": "Rudra", + "020F00": "Marutah", + "021000": "Yaksa", + "021100": "Sita", + "021200": "Garuda", + "021300": "Nandin", + "021400": "Ashvinau", + "021500": "Ribhava", + "021600": "Soma", + "021700": "Ila", + "021800": "Durga", + "021900": "Vritra", + "021A00": "Namuci", + "021B00": "Sumba", + "021C00": "Naga", + "021D00": "Pitri", + "021E00": "Kabanda", + "021F00": "Ravana", + "022000": "Marica", + "022100": "Soniti", + "022200": "Preta", + "022300": "Andhaka", + "022400": "Bana", + "022500": "Naraka", + "022600": "Madhu", + "022700": "Churel", + "022800": "ROBOCHAO", + "022900": "OPA-OPA", + "022A00": "PIAN", + "022B00": "CHAO", + "022C00": "CHU CHU", + "022D00": "KAPU KAPU", + "022E00": "ANGEL'S WING", + "022F00": "DEVIL'S WING", + "023000": "ELENOR", + "023100": "MARK3", + "023200": "MASTER SYSTEM", + "023300": "GENESIS", + "023400": "SEGA SATURN", + "023500": "DREAMCAST", + "023600": "HAMBURGER", + "023700": "PANZER'S TAIL", + "023800": "DAVIL'S TAIL", + "023900": "Deva", + "023A00": "Rati", + "023B00": "Savitri", + "023C00": "Rukmin", + "023D00": "Pushan", + "023E00": "Diwari", + "023F00": "Sato", + "024000": "Bhima", + "024100": "Nidra", + "024200": "????", + "030000": "Monomate", + "030001": "Dimate", + "030002": "Trimate", + "030100": "Monofluid", + "030101": "Difluid", + "030102": "Trifluid", + "030200": "", + "030300": "Sol Atomizer", + "030400": "Moon Atomizer", + "030500": "Star Atomizer", + "030600": "Antidote", + "030601": "Antiparalysis", + "030700": "Telepipe", + "030800": "Trap Vision", + "030900": "Scape Doll", + "030A00": "Monogrinder", + "030A01": "Digrinder", + "030A02": "Trigrinder", + "030B00": "Power Material", + "030B01": "Mind Material", + "030B02": "Evade Material", + "030B03": "HP Material", + "030B04": "TP Material", + "030B05": "Def Material", + "030B06": "Luck Material", + "030C00": "Cell of MAG 502", + "030C01": "Cell of MAG 213", + "030C02": "Parts of RoboChao", + "030C03": "Heart of Opa Opa", + "030C04": "Heart of Pian", + "030C05": "Heart of Chao", + "030D00": "Sorcerer's Right Arm", + "030D01": "S-beat's Arms", + "030D02": "P-arm's Arms", + "030D03": "Delsaber's Right Arm", + "030D04": "Bringer's Right Arm", + "030D05": "Delsaber's Left Arm", + "030D06": "S-red's Arms", + "030D07": "Dragon's Claw", + "030D08": "Hildebear's Head", + "030D09": "Hildeblue's Head", + "030D0A": "Parts of Baranz", + "030D0B": "Belra's Right Arm", + "030D0C": "Gi Gue's body", + "030D0D": "Sinow Berill's Arms", + "030D0E": "Grass Assassin's Arms", + "030D0F": "Booma's Right Arm", + "030D10": "Gobooma's Right Arm", + "030D11": "Gigobooma's Right Arm", + "030D12": "Gal Gryphon's Wing", + "030D13": "Rappy's Wing", + "030E00": "Berill Photon", + "030E01": "Parasitic gene \"Flow\"", + "030E02": "Magic Stone \"Iritista\"", + "030E03": "Blue-black stone", + "030E04": "Syncesta", + "030E05": "Magic Water", + "030E06": "Parasitic cell Type D ", + "030E07": "magic rock \"Heart Key\"", + "030E08": "magic rock \"Moola\"", + "030E09": "Star Amplifier", + "030E0A": "Book of HITOGATA", + "030E0B": "Heart of Chu Chu", + "030E0C": "Parts of EGG BLASTER", + "030E0D": "Heart of Angel", + "030E0E": "Heart of Devil", + "030E0F": "Kit of Hamburger", + "030E10": "Panther's Spirit", + "030E11": "Kit of MARK3", + "030E12": "Kit of MASTER SYSTEM", + "030E13": "Kit of GENESIS", + "030E14": "Kit of SEGA SATURN", + "030E15": "Kit of DREAMCAST", + "030E16": "Amplifier of Resta", + "030E17": "Amplifier of Anti", + "030E18": "Amplifier of Shifta", + "030E19": "Amplifier of Deband", + "030E1A": "Amplifier of Foie", + "030E1B": "Amplifier of Gifoie", + "030E1C": "Amplifier of Rafoie", + "030E1D": "Amplifier of Barta", + "030E1E": "Amplifier of Gibarta", + "030E1F": "Amplifier of Rabarta", + "030E20": "Amplifier of Zonde", + "030E21": "Amplifier of Gizonde", + "030E22": "Amplifier of Razonde", + "030E23": "Amplifier of Red ", + "030E24": "Amplifier of Blue", + "030E25": "Amplifier of Yellow", + "030E26": "Heart of KAPU KAPU", + "030E27": "Photon Booster", + "030F00": "AddSlot", + "031000": "Photon Drop", + "031001": "Photon Sphere", + "031002": "Photon Crystal", + "031100": "Book of KATANA1", + "031101": "Book of KATANA2", + "031102": "Book of KATANA3", + "031200": "Weapons Bronze Badge", + "031201": "Weapons Silver Badge", + "031202": "Weapons Gold Badge", + "031203": "Weapons Crystal Badge", + "031204": "Weapons Steel Badge", + "031205": "Weapons Aluminum Badge", + "031206": "Weapons Leather Badge", + "031207": "Weapons Bone Badge", + "031208": "Letter of appreciation", + "031209": "Autograph Album", + "03120A": "Valentine's Chocolate", + "03120B": "New Year's Card", + "03120C": "Christmas Card", + "03120D": "Birthday Card", + "03120E": "Proof of Sonic Team", + "03120F": "Special Event Ticket", + "031210": "Flower Bouquet", + "031211": "Cake", + "031212": "Accessories", + "031213": "Mr.Naka's Business Card", + "031300": "Present", + "031400": "Chocolate", + "031401": "Candy", + "031402": "Cake", + "031403": "Siver Badge", + "031404": "Gold Badge", + "031405": "Crystal Badge", + "031406": "Iron Badge", + "031407": "Aluminum Badge", + "031408": "Leather Badge", + "031409": "Bone Badge", + "03140A": "Bouquet", + "03140B": "Decoction", + "031500": "Christmas Present", + "031501": "Easter Egg", + "031502": "Jack-O'-Lantern", + "031600": "DISK Vol.1", + "031601": "DISK Vol.2", + "031602": "DISK Vol.3", + "031603": "DISK Vol.4", + "031604": "DISK Vol.5", + "031605": "DISK Vol.6", + "031606": "DISK Vol.7", + "031700": "Hunters Report", + "031701": "Hunters Report", + "031702": "Hunters Report", + "031703": "Hunters Report", + "031704": "Hunters Report" +} diff --git a/system/item-tables/names-v4.json b/system/item-tables/names-v4.json new file mode 100755 index 00000000..568409e0 --- /dev/null +++ b/system/item-tables/names-v4.json @@ -0,0 +1,1518 @@ +{ + "000100": "Saber", + "000101": "Brand", + "000102": "Buster", + "000103": "Pallasch", + "000104": "Gladius", + "000105": "DB'S SABER", + "000106": "KALADBOLG", + "000107": "DURANDAL", + "000108": "GALATINE", + "000200": "Sword", + "000201": "Gigush", + "000202": "Breaker", + "000203": "Claymore", + "000204": "Calibur", + "000205": "FLOWEN'S SWORD", + "000206": "LAST SURVIVOR", + "000207": "DRAGON SLAYER", + "000300": "Dagger", + "000301": "Knife", + "000302": "Blade", + "000303": "Edge", + "000304": "Ripper", + "000305": "BLADE DANCE", + "000306": "BLOODY ART", + "000307": "CROSS SCAR", + "000308": "ZERO DIVIDE", + "000309": "TWO KAMUI", + "000400": "Partisan", + "000401": "Halbert", + "000402": "Glaive", + "000403": "Berdys", + "000404": "Gungnir", + "000405": "BRIONAC", + "000406": "VJAYA", + "000407": "GAE BOLG", + "000408": "ASTERON BELT", + "000500": "Slicer", + "000501": "Spinner", + "000502": "Cutter", + "000503": "Sawcer", + "000504": "Diska", + "000505": "SLICER OF ASSASSIN", + "000506": "DISKA OF LIBERATOR", + "000507": "DISKA OF BRAVEMAN", + "000508": "IZMAELA", + "000600": "Handgun", + "000601": "Autogun", + "000602": "Lockgun", + "000603": "Railgun", + "000604": "Raygun", + "000605": "VARISTA", + "000606": "CUSTOM RAY ver.OO", + "000607": "BRAVACE", + "000608": "TENSION BLASTER", + "000700": "Rifle", + "000701": "Sniper", + "000702": "Blaster", + "000703": "Beam", + "000704": "Laser", + "000705": "VISK-235W", + "000706": "WALS-MK2", + "000707": "JUSTY-23ST", + "000708": "RIANOV 303SNR", + "000709": "RIANOV 303SNR-1", + "00070A": "RIANOV 303SNR-2", + "00070B": "RIANOV 303SNR-3", + "00070C": "RIANOV 303SNR-4", + "00070D": "RIANOV 303SNR-5", + "000800": "Mechgun", + "000801": "Assault", + "000802": "Repeater", + "000803": "Gatling", + "000804": "Vulcan", + "000805": "M&A60 VISE", + "000806": "H&S25 JUSTICE", + "000807": "L&K14 COMBAT", + "000900": "Shot", + "000901": "Spread", + "000902": "Cannon", + "000903": "Launcher", + "000904": "Arms", + "000905": "CRUSH BULLET", + "000906": "METEOR SMASH", + "000907": "FINAL IMPACT", + "000A00": "Cane", + "000A01": "Stick", + "000A02": "Mace", + "000A03": "Club", + "000A04": "CLUB OF LACONIUM", + "000A05": "MACE OF ADAMAN", + "000A06": "CLUB OF ZUMIURAN", + "000A07": "LOLLIPOP", + "000B00": "Rod", + "000B01": "Pole", + "000B02": "Pillar", + "000B03": "Striker", + "000B04": "BATTLE VERGE", + "000B05": "BRAVE HAMMER", + "000B06": "ALIVE AQHU", + "000B07": "VALKYRIE", + "000C00": "Wand", + "000C01": "Staff", + "000C02": "Baton", + "000C03": "Scepter", + "000C04": "FIRE SCEPTER:AGNI", + "000C05": "ICE STAFF:DAGON", + "000C06": "STORM WAND:INDRA", + "000C07": "EARTH WAND BROWNIE", + "000D00": "PHOTON CLAW", + "000D01": "SILENCE CLAW", + "000D02": "NEI'S CLAW", + "000D03": "PHOENIX CLAW", + "000E00": "DOUBLE SABER", + "000E01": "STAG CUTLERY", + "000E02": "TWIN BRAND", + "000F00": "BRAVE KNUCKLE", + "000F01": "ANGRY FIST", + "000F02": "GOD HAND", + "000F03": "SONIC KNUCKLE", + "000F04": "LOGiN", + "001000": "OROTIAGITO", + "001001": "AGITO", + "001002": "AGITO", + "001003": "AGITO", + "001004": "AGITO", + "001005": "AGITO", + "001006": "AGITO", + "001007": "RAIKIRI", + "001100": "SOUL EATER", + "001101": "SOUL BANISH", + "001200": "SPREAD NEEDLE", + "001300": "HOLY RAY", + "001400": "INFERNO BAZOOKA", + "001401": "RAMBLING MAY", + "001402": "L&K38 COMBAT", + "001500": "FLAME VISIT", + "001501": "BURNING VISIT", + "001600": "AKIKO'S FRYING PAN", + "001700": "SORCERER'S CANE", + "001800": "S-BEAT'S BLADE", + "001900": "P-ARMS'S BLADE", + "001A00": "DELSABER'S BUSTER", + "001B00": "BRINGER'S RIFLE", + "001C00": "EGG BLASTER", + "001D00": "PSYCHO WAND", + "001E00": "HEAVEN PUNISHER", + "001F00": "LAVIS CANNON", + "002000": "VICTOR AXE", + "002001": "LACONIUM AXE", + "002100": "CHAIN SAWD", + "002200": "CADUCEUS", + "002201": "MERCURIUS ROD", + "002300": "STING TIP", + "002400": "MAGICAL PIECE", + "002500": "TECHNICAL CROZIER", + "002600": "SUPPRESSED GUN", + "002700": "ANCIENT SABER", + "002800": "HARISEN BATTLE FAN", + "002900": "YAMIGARASU", + "002A00": "AKIKO'S WOK", + "002B00": "TOY HAMMER", + "002C00": "ELYSION", + "002D00": "RED SABER", + "002E00": "METEOR CUDGEL", + "002F00": "MONKEY KING BAR", + "002F01": "BLACK KING BAR", + "003000": "DOUBLE CANNON", + "003001": "GIRASOLE", + "003100": "HUGE BATTLE FAN", + "003200": "TSUMIKIRI J-SWORD", + "003300": "SEALED J-SWORD", + "003400": "RED SWORD", + "003500": "CRAZY TUNE", + "003600": "TWIN CHAKRAM", + "003700": "WOK OF AKIKO'S SHOP", + "003800": "LAVIS BLADE", + "003900": "RED DAGGER", + "003A00": "MADAM'S PARASOL", + "003B00": "MADAM'S UMBRELLA", + "003C00": "IMPERIAL PICK", + "003D00": "BERDYSH", + "003E00": "RED PARTISAN", + "003F00": "FLIGHT CUTTER", + "004000": "FLIGHT FAN", + "004100": "RED SLICER", + "004200": "HANDGUN:GULD", + "004201": "MASTER RAVEN", + "004300": "HANDGUN:MILLA", + "004301": "LAST SWAN", + "004400": "RED HANDGUN", + "004500": "FROZEN SHOOTER", + "004501": "SNOW QUEEN", + "004600": "ANTI ANDROID RIFLE", + "004700": "ROCKET PUNCH", + "004800": "SAMBA MARACAS", + "004900": "TWIN PSYCHOGUN", + "004A00": "DRILL LAUNCHER", + "004B00": "GULD MILLA", + "004B01": "DUAL BIRD", + "004C00": "RED MECHGUN", + "004D00": "BELRA CANNON", + "004E00": "PANZER FAUST", + "004E01": "IRON FAUST", + "004F00": "SUMMIT MOON", + "005000": "WINDMILL", + "005100": "EVIL CURST", + "005200": "FLOWER CANE", + "005300": "HILDEBEAR'S CANE", + "005400": "HILDEBLUE'S CANE", + "005500": "RABBIT WAND", + "005600": "PLANTAIN LEAF", + "005601": "FATSIA", + "005700": "DEMONIC FORK", + "005800": "STRIKER OF CHAO", + "005900": "BROOM", + "005A00": "PROPHETS OF MOTAV", + "005B00": "THE SIGH OF A GOD", + "005C00": "TWINKLE STAR", + "005D00": "PLANTAIN FAN", + "005E00": "TWIN BLAZE", + "005F00": "MARINA'S BAG", + "006000": "DRAGON'S CLAW", + "006100": "PANTHER'S CLAW", + "006200": "S-RED'S BLADE", + "006300": "PLANTAIN HUGE FAN", + "006400": "CHAMELEON SCYTHE", + "006500": "YASMINKOV 3000R", + "006600": "ANO RIFLE", + "006700": "BARANZ LAUNCHER", + "006800": "BRANCH OF PAKUPAKU", + "006900": "HEART OF POUMN", + "006A00": "YASMINKOV 2000H", + "006B00": "YASMINKOV 7000V", + "006C00": "YASMINKOV 9000M", + "006D00": "MASER BEAM", + "006D01": "POWER MASER", + "006E00": "GAME MAGAZNE", + "006E01": "LOGiN", + "006F00": "FLOWER BOUQUET", + "007000": "SABER", + "007001": "SABER", + "007002": "SABER", + "007003": "SABER", + "007004": "SABER", + "007005": "SABER", + "007006": "SABER", + "007007": "SABER", + "007008": "SABER", + "007009": "SABER", + "00700A": "SABER", + "00700B": "SABER", + "00700C": "SABER", + "00700D": "SABER", + "00700E": "SABER", + "00700F": "SABER", + "007010": "SABER", + "007100": "SWORD", + "007101": "SWORD", + "007102": "SWORD", + "007103": "SWORD", + "007104": "SWORD", + "007105": "SWORD", + "007106": "SWORD", + "007107": "SWORD", + "007108": "SWORD", + "007109": "SWORD", + "00710A": "SWORD", + "00710B": "SWORD", + "00710C": "SWORD", + "00710D": "SWORD", + "00710E": "SWORD", + "00710F": "SWORD", + "007110": "SWORD", + "007200": "BLADE", + "007201": "BLADE", + "007202": "BLADE", + "007203": "BLADE", + "007204": "BLADE", + "007205": "BLADE", + "007206": "BLADE", + "007207": "BLADE", + "007208": "BLADE", + "007209": "BLADE", + "00720A": "BLADE", + "00720B": "BLADE", + "00720C": "BLADE", + "00720D": "BLADE", + "00720E": "BLADE", + "00720F": "BLADE", + "007210": "BLADE", + "007300": "PARTISAN", + "007301": "PARTISAN", + "007302": "PARTISAN", + "007303": "PARTISAN", + "007304": "PARTISAN", + "007305": "PARTISAN", + "007306": "PARTISAN", + "007307": "PARTISAN", + "007308": "PARTISAN", + "007309": "PARTISAN", + "00730A": "PARTISAN", + "00730B": "PARTISAN", + "00730C": "PARTISAN", + "00730D": "PARTISAN", + "00730E": "PARTISAN", + "00730F": "PARTISAN", + "007310": "PARTISAN", + "007400": "SLICER", + "007401": "SLICER", + "007402": "SLICER", + "007403": "SLICER", + "007404": "SLICER", + "007405": "SLICER", + "007406": "SLICER", + "007407": "SLICER", + "007408": "SLICER", + "007409": "SLICER", + "00740A": "SLICER", + "00740B": "SLICER", + "00740C": "SLICER", + "00740D": "SLICER", + "00740E": "SLICER", + "00740F": "SLICER", + "007410": "SLICER", + "007500": "GUN", + "007501": "GUN", + "007502": "GUN", + "007503": "GUN", + "007504": "GUN", + "007505": "GUN", + "007506": "GUN", + "007507": "GUN", + "007508": "GUN", + "007509": "GUN", + "00750A": "GUN", + "00750B": "GUN", + "00750C": "GUN", + "00750D": "GUN", + "00750E": "GUN", + "00750F": "GUN", + "007510": "GUN", + "007600": "RIFLE", + "007601": "RIFLE", + "007602": "RIFLE", + "007603": "RIFLE", + "007604": "RIFLE", + "007605": "RIFLE", + "007606": "RIFLE", + "007607": "RIFLE", + "007608": "RIFLE", + "007609": "RIFLE", + "00760A": "RIFLE", + "00760B": "RIFLE", + "00760C": "RIFLE", + "00760D": "RIFLE", + "00760E": "RIFLE", + "00760F": "RIFLE", + "007610": "RIFLE", + "007700": "MECHGUN", + "007701": "MECHGUN", + "007702": "MECHGUN", + "007703": "MECHGUN", + "007704": "MECHGUN", + "007705": "MECHGUN", + "007706": "MECHGUN", + "007707": "MECHGUN", + "007708": "MECHGUN", + "007709": "MECHGUN", + "00770A": "MECHGUN", + "00770B": "MECHGUN", + "00770C": "MECHGUN", + "00770D": "MECHGUN", + "00770E": "MECHGUN", + "00770F": "MECHGUN", + "007710": "MECHGUN", + "007800": "SHOT", + "007801": "SHOT", + "007802": "SHOT", + "007803": "SHOT", + "007804": "SHOT", + "007805": "SHOT", + "007806": "SHOT", + "007807": "SHOT", + "007808": "SHOT", + "007809": "SHOT", + "00780A": "SHOT", + "00780B": "SHOT", + "00780C": "SHOT", + "00780D": "SHOT", + "00780E": "SHOT", + "00780F": "SHOT", + "007810": "SHOT", + "007900": "CANE", + "007901": "CANE", + "007902": "CANE", + "007903": "CANE", + "007904": "CANE", + "007905": "CANE", + "007906": "CANE", + "007907": "CANE", + "007908": "CANE", + "007909": "CANE", + "00790A": "CANE", + "00790B": "CANE", + "00790C": "CANE", + "00790D": "CANE", + "00790E": "CANE", + "00790F": "CANE", + "007910": "CANE", + "007A00": "ROD", + "007A01": "ROD", + "007A02": "ROD", + "007A03": "ROD", + "007A04": "ROD", + "007A05": "ROD", + "007A06": "ROD", + "007A07": "ROD", + "007A08": "ROD", + "007A09": "ROD", + "007A0A": "ROD", + "007A0B": "ROD", + "007A0C": "ROD", + "007A0D": "ROD", + "007A0E": "ROD", + "007A0F": "ROD", + "007A10": "ROD", + "007B00": "WAND", + "007B01": "WAND", + "007B02": "WAND", + "007B03": "WAND", + "007B04": "WAND", + "007B05": "WAND", + "007B06": "WAND", + "007B07": "WAND", + "007B08": "WAND", + "007B09": "WAND", + "007B0A": "WAND", + "007B0B": "WAND", + "007B0C": "WAND", + "007B0D": "WAND", + "007B0E": "WAND", + "007B0F": "WAND", + "007B10": "WAND", + "007C00": "TWIN", + "007C01": "TWIN", + "007C02": "TWIN", + "007C03": "TWIN", + "007C04": "TWIN", + "007C05": "TWIN", + "007C06": "TWIN", + "007C07": "TWIN", + "007C08": "TWIN", + "007C09": "TWIN", + "007C0A": "TWIN", + "007C0B": "TWIN", + "007C0C": "TWIN", + "007C0D": "TWIN", + "007C0E": "TWIN", + "007C0F": "TWIN", + "007C10": "TWIN", + "007D00": "CLAW", + "007D01": "CLAW", + "007D02": "CLAW", + "007D03": "CLAW", + "007D04": "CLAW", + "007D05": "CLAW", + "007D06": "CLAW", + "007D07": "CLAW", + "007D08": "CLAW", + "007D09": "CLAW", + "007D0A": "CLAW", + "007D0B": "CLAW", + "007D0C": "CLAW", + "007D0D": "CLAW", + "007D0E": "CLAW", + "007D0F": "CLAW", + "007D10": "CLAW", + "007E00": "BAZOOKA", + "007E01": "BAZOOKA", + "007E02": "BAZOOKA", + "007E03": "BAZOOKA", + "007E04": "BAZOOKA", + "007E05": "BAZOOKA", + "007E06": "BAZOOKA", + "007E07": "BAZOOKA", + "007E08": "BAZOOKA", + "007E09": "BAZOOKA", + "007E0A": "BAZOOKA", + "007E0B": "BAZOOKA", + "007E0C": "BAZOOKA", + "007E0D": "BAZOOKA", + "007E0E": "BAZOOKA", + "007E0F": "BAZOOKA", + "007E10": "BAZOOKA", + "007F00": "NEEDLE", + "007F01": "NEEDLE", + "007F02": "NEEDLE", + "007F03": "NEEDLE", + "007F04": "NEEDLE", + "007F05": "NEEDLE", + "007F06": "NEEDLE", + "007F07": "NEEDLE", + "007F08": "NEEDLE", + "007F09": "NEEDLE", + "007F0A": "NEEDLE", + "007F0B": "NEEDLE", + "007F0C": "NEEDLE", + "007F0D": "NEEDLE", + "007F0E": "NEEDLE", + "007F0F": "NEEDLE", + "007F10": "NEEDLE", + "008000": "SCYTHE", + "008001": "SCYTHE", + "008002": "SCYTHE", + "008003": "SCYTHE", + "008004": "SCYTHE", + "008005": "SCYTHE", + "008006": "SCYTHE", + "008007": "SCYTHE", + "008008": "SCYTHE", + "008009": "SCYTHE", + "00800A": "SCYTHE", + "00800B": "SCYTHE", + "00800C": "SCYTHE", + "00800D": "SCYTHE", + "00800E": "SCYTHE", + "00800F": "SCYTHE", + "008010": "SCYTHE", + "008100": "HAMMER", + "008101": "HAMMER", + "008102": "HAMMER", + "008103": "HAMMER", + "008104": "HAMMER", + "008105": "HAMMER", + "008106": "HAMMER", + "008107": "HAMMER", + "008108": "HAMMER", + "008109": "HAMMER", + "00810A": "HAMMER", + "00810B": "HAMMER", + "00810C": "HAMMER", + "00810D": "HAMMER", + "00810E": "HAMMER", + "00810F": "HAMMER", + "008110": "HAMMER", + "008200": "MOON", + "008201": "MOON", + "008202": "MOON", + "008203": "MOON", + "008204": "MOON", + "008205": "MOON", + "008206": "MOON", + "008207": "MOON", + "008208": "MOON", + "008209": "MOON", + "00820A": "MOON", + "00820B": "MOON", + "00820C": "MOON", + "00820D": "MOON", + "00820E": "MOON", + "00820F": "MOON", + "008210": "MOON", + "008300": "PSYCHOGUN", + "008301": "PSYCHOGUN", + "008302": "PSYCHOGUN", + "008303": "PSYCHOGUN", + "008304": "PSYCHOGUN", + "008305": "PSYCHOGUN", + "008306": "PSYCHOGUN", + "008307": "PSYCHOGUN", + "008308": "PSYCHOGUN", + "008309": "PSYCHOGUN", + "00830A": "PSYCHOGUN", + "00830B": "PSYCHOGUN", + "00830C": "PSYCHOGUN", + "00830D": "PSYCHOGUN", + "00830E": "PSYCHOGUN", + "00830F": "PSYCHOGUN", + "008310": "PSYCHOGUN", + "008400": "PUNCH", + "008401": "PUNCH", + "008402": "PUNCH", + "008403": "PUNCH", + "008404": "PUNCH", + "008405": "PUNCH", + "008406": "PUNCH", + "008407": "PUNCH", + "008408": "PUNCH", + "008409": "PUNCH", + "00840A": "PUNCH", + "00840B": "PUNCH", + "00840C": "PUNCH", + "00840D": "PUNCH", + "00840E": "PUNCH", + "00840F": "PUNCH", + "008410": "PUNCH", + "008500": "WINDMILL", + "008501": "WINDMILL", + "008502": "WINDMILL", + "008503": "WINDMILL", + "008504": "WINDMILL", + "008505": "WINDMILL", + "008506": "WINDMILL", + "008507": "WINDMILL", + "008508": "WINDMILL", + "008509": "WINDMILL", + "00850A": "WINDMILL", + "00850B": "WINDMILL", + "00850C": "WINDMILL", + "00850D": "WINDMILL", + "00850E": "WINDMILL", + "00850F": "WINDMILL", + "008510": "WINDMILL", + "008600": "HARISEN", + "008601": "HARISEN", + "008602": "HARISEN", + "008603": "HARISEN", + "008604": "HARISEN", + "008605": "HARISEN", + "008606": "HARISEN", + "008607": "HARISEN", + "008608": "HARISEN", + "008609": "HARISEN", + "00860A": "HARISEN", + "00860B": "HARISEN", + "00860C": "HARISEN", + "00860D": "HARISEN", + "00860E": "HARISEN", + "00860F": "HARISEN", + "008610": "HARISEN", + "008700": "KATANA", + "008701": "KATANA", + "008702": "KATANA", + "008703": "KATANA", + "008704": "KATANA", + "008705": "KATANA", + "008706": "KATANA", + "008707": "KATANA", + "008708": "KATANA", + "008709": "KATANA", + "00870A": "KATANA", + "00870B": "KATANA", + "00870C": "KATANA", + "00870D": "KATANA", + "00870E": "KATANA", + "00870F": "KATANA", + "008710": "KATANA", + "008800": "J-CUTTER", + "008801": "J-CUTTER", + "008802": "J-CUTTER", + "008803": "J-CUTTER", + "008804": "J-CUTTER", + "008805": "J-CUTTER", + "008806": "J-CUTTER", + "008807": "J-CUTTER", + "008808": "J-CUTTER", + "008809": "J-CUTTER", + "00880A": "J-CUTTER", + "00880B": "J-CUTTER", + "00880C": "J-CUTTER", + "00880D": "J-CUTTER", + "00880E": "J-CUTTER", + "00880F": "J-CUTTER", + "008810": "J-CUTTER", + "008900": "MUSASHI", + "008901": "YAMATO", + "008902": "ASUKA", + "008903": "SANGE & YASHA", + "008A00": "SANGE", + "008A01": "YASHA", + "008A02": "KAMUI", + "008B00": "PHOTON LAUNCHER", + "008B01": "GUILTY LIGHT", + "008B02": "RED SCORPIO", + "008B03": "PHONON MASER", + "008C00": "TALIS", + "008C01": "MAHU", + "008C02": "HITOGATA", + "008C03": "DANCING HITOGATA", + "008C04": "KUNAI", + "008D00": "NUG2000-BAZOOKA", + "008E00": "S-BERILL'S HANDS #0", + "008E01": "S-BERILL'S HANDS #1", + "008F00": "FLOWEN'S SWORD", + "008F01": "FLOWEN'S SWORD", + "008F02": "FLOWEN'S SWORD", + "008F03": "FLOWEN'S SWORD", + "008F04": "FLOWEN'S SWORD", + "008F05": "FLOWEN'S SWORD", + "008F06": "FLOWEN'S SWORD", + "008F07": "FLOWEN'S SWORD", + "008F08": "FLOWEN'S SWORD", + "009000": "DB'S SABER", + "009001": "DB'S SABER", + "009002": "DB'S SABER", + "009003": "DB'S SABER", + "009004": "DB'S SABER", + "009005": "DB'S SABER", + "009006": "DB'S SABER", + "009007": "DB'S SABER", + "009008": "DB'S SABER", + "009100": "GI GUE BAZOOKA", + "009200": "GUARDIANNA", + "009300": "VIRIDIA CARD", + "009301": "GREENILL CARD", + "009302": "SKYLY CARD", + "009303": "BLUEFULL CARD", + "009304": "PURPLENUM CARD", + "009305": "PINKAL CARD", + "009306": "REDRIA CARD", + "009307": "ORAN CARD", + "009308": "YELLOWBOZE CARD", + "009309": "WHITILL CARD", + "009400": "MORNING GLORY", + "009500": "PARTISAN of LIGHTNING", + "009600": "GAL WIND", + "009700": "ZANBA", + "009800": "RIKA'S CLAW", + "009900": "ANGEL HARP", + "009A00": "DEMOLITION COMET", + "009B00": "NEI'S CLAW", + "009C00": "RAINBOW BATON", + "009D00": "DARK FLOW", + "009E00": "DARK METEOR", + "009F00": "DARK BRIDGE", + "00A000": "G-ASSASSIN'S SABERS", + "00A100": "RAPPY'S FAN", + "00A200": "BOOMA'S CLAW", + "00A201": "GOBOOMA'S CLAW", + "00A202": "GIGOBOOMA'S CLAW", + "00A300": "RUBY BULLET", + "00A400": "AMORE ROSE", + "00A500": "SWORDS", + "00A501": "SWORDS", + "00A502": "SWORDS", + "00A503": "SWORDS", + "00A504": "SWORDS", + "00A505": "SWORDS", + "00A506": "SWORDS", + "00A507": "SWORDS", + "00A508": "SWORDS", + "00A509": "SWORDS", + "00A50A": "SWORDS", + "00A50B": "SWORDS", + "00A50C": "SWORDS", + "00A50D": "SWORDS", + "00A50E": "SWORDS", + "00A50F": "SWORDS", + "00A510": "SWORDS", + "00A600": "LAUNCHER", + "00A601": "LAUNCHER", + "00A602": "LAUNCHER", + "00A603": "LAUNCHER", + "00A604": "LAUNCHER", + "00A605": "LAUNCHER", + "00A606": "LAUNCHER", + "00A607": "LAUNCHER", + "00A608": "LAUNCHER", + "00A609": "LAUNCHER", + "00A60A": "LAUNCHER", + "00A60B": "LAUNCHER", + "00A60C": "LAUNCHER", + "00A60D": "LAUNCHER", + "00A60E": "LAUNCHER", + "00A60F": "LAUNCHER", + "00A610": "LAUNCHER", + "00A700": "CARDS", + "00A701": "CARDS", + "00A702": "CARDS", + "00A703": "CARDS", + "00A704": "CARDS", + "00A705": "CARDS", + "00A706": "CARDS", + "00A707": "CARDS", + "00A708": "CARDS", + "00A709": "CARDS", + "00A70A": "CARDS", + "00A70B": "CARDS", + "00A70C": "CARDS", + "00A70D": "CARDS", + "00A70E": "CARDS", + "00A70F": "CARDS", + "00A710": "CARDS", + "00A800": "KNUCKLE", + "00A801": "KNUCKLE", + "00A802": "KNUCKLE", + "00A803": "KNUCKLE", + "00A804": "KNUCKLE", + "00A805": "KNUCKLE", + "00A806": "KNUCKLE", + "00A807": "KNUCKLE", + "00A808": "KNUCKLE", + "00A809": "KNUCKLE", + "00A80A": "KNUCKLE", + "00A80B": "KNUCKLE", + "00A80C": "KNUCKLE", + "00A80D": "KNUCKLE", + "00A80E": "KNUCKLE", + "00A80F": "KNUCKLE", + "00A810": "KNUCKLE", + "00A900": "AXE", + "00A901": "AXE", + "00A902": "AXE", + "00A903": "AXE", + "00A904": "AXE", + "00A905": "AXE", + "00A906": "AXE", + "00A907": "AXE", + "00A908": "AXE", + "00A909": "AXE", + "00A90A": "AXE", + "00A90B": "AXE", + "00A90C": "AXE", + "00A90D": "AXE", + "00A90E": "AXE", + "00A90F": "AXE", + "00A910": "AXE", + "00AA00": "SLICER OF FANATIC", + "00AB00": "LAME D'ARGENT", + "00AC00": "EXCALIBUR", + "00AD00": "RAGE DE FEU", + "00AD01": "RAGE DE FEU", + "00AD02": "RAGE DE FEU", + "00AD03": "RAGE DE FEU", + "00AE00": "DAISY CHAIN", + "00AF00": "OPHELIE SEIZE", + "00B000": "MILLE MARTEAUX", + "00B100": "LE COGNEUR", + "00B200": "COMMANDER BLADE", + "00B300": "VIVIENNE", + "00B400": "KUSANAGI", + "00B500": "SACRED DUSTER", + "00B600": "GUREN", + "00B700": "SHOUREN", + "00B800": "JIZAI", + "00B900": "FLAMBERGE", + "00BA00": "YUNCHANG", + "00BB00": "SNAKE SPIRE", + "00BC00": "FLAPJACK FLAPPER", + "00BD00": "GETSUGASAN", + "00BE00": "MAGUWA", + "00BF00": "HEAVEN STRIKER", + "00C000": "CANNON ROUGE", + "00C100": "METEOR ROUGE", + "00C200": "SOLFERINO", + "00C300": "CLIO", + "00C400": "SIREN GLASS HAMMER", + "00C500": "GLIDE DIVINE", + "00C600": "SHICHISHITO", + "00C700": "MURASAME", + "00C800": "DAYLIGHT SCAR", + "00C900": "DECALOG", + "00CA00": "5TH ANNIV. BLADE", + "00CB00": "TYRELL'S PARASOL", + "00CC00": "AKIKO'S CLEAVER", + "00CD00": "TANEGASHIMA", + "00CE00": "TREE CLIPPERS", + "00CF00": "NICE SHOT", + "00D000": "UNKNOWN3", + "00D100": "UNKNOWN4", + "00D200": "ANO BAZOOKA", + "00D300": "SYNTHESIZER", + "00D400": "BAMBOO SPEAR", + "00D500": "KAN'EI TSUHO", + "00D600": "JITTE", + "00D700": "BUTTERFLY NET", + "00D800": "SYRINGE", + "00D900": "BATTLEDORE", + "00DA00": "RACKET", + "00DB00": "HAMMER", + "00DC00": "GREAT BOUQUET", + "00DD00": "TypeSA/SABER", + "00DE00": "TypeSL/SABER", + "00DE01": "TypeSL/SLICER", + "00DE02": "TypeSL/CLAW", + "00DE03": "TypeSL/KATANA", + "00DF00": "TypeJS/SABER", + "00DF01": "TypeJS/SLICER", + "00DF02": "TypeJS/J-SWORD", + "00E000": "TypeSW/SWORD", + "00E001": "TypeSW/SLICER", + "00E002": "TypeSW/J-SWORD", + "00E100": "TypeRO/SWORD", + "00E101": "TypeRO/HALBERT", + "00E102": "TypeRO/ROD", + "00E200": "TypeBL/BLADE", + "00E300": "TypeKN/BLADE", + "00E301": "TypeKN/CLAW", + "00E400": "TypeHA/HALBERT", + "00E401": "TypeHA/ROD", + "00E500": "TypeDS/D.SABER", + "00E501": "TypeDS/ROD", + "00E502": "TypeDS", + "00E600": "TypeCL/CLAW", + "00E700": "TypeSS/SW", + "00E800": "TypeGU/HAND", + "00E801": "TypeGU/MECHGUN", + "00E900": "TypeRI/RIFLE", + "00EA00": "TypeME/MECHGUN", + "00EB00": "TypeSH/SHOT", + "00EC00": "TypeWA/WAND", + "010100": "Frame", + "010101": "Armor", + "010102": "Psy Armor", + "010103": "Giga Frame", + "010104": "Soul Frame", + "010105": "Cross Armor", + "010106": "Solid Frame", + "010107": "Brave Armor", + "010108": "Hyper Frame", + "010109": "Grand Armor", + "01010A": "Shock Frame", + "01010B": "King's Frame", + "01010C": "Dragon Frame", + "01010D": "Absorb Armor", + "01010E": "Protect Frame", + "01010F": "General Armor", + "010110": "Perfect Frame", + "010111": "Valiant Frame", + "010112": "Imperial Armor", + "010113": "Holiness Armor", + "010114": "Guardian Armor", + "010115": "Divinity Armor", + "010116": "Ultimate Frame", + "010117": "Celestial Armor", + "010118": "HUNTER FIELD", + "010119": "RANGER FIELD", + "01011A": "FORCE FIELD", + "01011B": "REVIVAL GARMENT", + "01011C": "SPIRIT GARMENT", + "01011D": "STINK FRAME", + "01011E": "D-PARTS ver1.01", + "01011F": "D-PARTS ver2.10", + "010120": "PARASITE WEAR:De Rol", + "010121": "PARASITE WEAR:Nelgal", + "010122": "PARASITE WEAR:Vajulla", + "010123": "SENSE PLATE", + "010124": "GRAVITON PLATE", + "010125": "ATTRIBUTE PLATE", + "010126": "FLOWEN'S FRAME", + "010127": "CUSTOM FRAME ver.OO", + "010128": "DB'S ARMOR", + "010129": "GUARD WAVE", + "01012A": "DF FIELD", + "01012B": "LUMINOUS FIELD", + "01012C": "CHU CHU FEVER", + "01012D": "LOVE HEART", + "01012E": "FLAME GARMENT", + "01012F": "VIRUS ARMOR:Lafuteria", + "010130": "BRIGHTNESS CIRCLE", + "010131": "AURA FIELD", + "010132": "ELECTRO FRAME", + "010133": "SACRED CLOTH", + "010134": "SMOKING PLATE", + "010135": "STAR CUIRASS", + "010136": "BLACK HOUND CUIRASS", + "010137": "MORNING PRAYER", + "010138": "BLACK ODOSHI DOMARU", + "010139": "RED ODOSHI DOMARU", + "01013A": "BLACK ODOSHI RED NIMAIDOU", + "01013B": "BLUE ODOSHI VIOLET NIMAIDOU", + "01013C": "DIRTY LIFEJACKET", + "01013D": "KROE'S SWEATER", + "01013E": "WEDDING DRESS", + "01013F": "SONICTEAM ARMOR", + "010140": "RED COAT", + "010141": "THIRTEEN", + "010142": "MOTHER GARB", + "010143": "MOTHER GARB+", + "010144": "DRESS PLATE", + "010145": "SWEETHEART", + "010146": "IGNITION CLOAK", + "010147": "CONGEAL CLOAK", + "010148": "TEMPEST CLOAK", + "010149": "CURSED CLOAK", + "01014A": "SELECT CLOAK", + "01014B": "SPIRIT CUIRASS", + "01014C": "REVIVAL CURIASS", + "01014D": "ALLIANCE UNIFORM", + "01014E": "OFFICER UNIFORM", + "01014F": "COMMANDER UNIFORM", + "010150": "CRIMSON COAT", + "010151": "INFANTRY GEAR", + "010152": "LIEUTENANT GEAR", + "010153": "INFANTRY MANTLE", + "010154": "LIEUTENANT MANTLE", + "010155": "UNION FIELD", + "010156": "SAMURAI ARMOR", + "010157": "STEALTH SUIT", + "010158": "????", + "010200": "Barrier", + "010201": "Shield", + "010202": "Core Shield", + "010203": "Giga Shield", + "010204": "Soul Barrier", + "010205": "Hard Shield", + "010206": "Brave Barrier", + "010207": "Solid Shield", + "010208": "Flame Barrier", + "010209": "Plasma Barrier", + "01020A": "Freeze Barrier", + "01020B": "Psychic Barrier", + "01020C": "General Shield", + "01020D": "Protect Barrier", + "01020E": "Glorious Shield", + "01020F": "Imperial Barrier", + "010210": "Guardian Shield", + "010211": "Divinity Barrier", + "010212": "Ultimate Shield", + "010213": "Spiritual Shield", + "010214": "Celestial Shield", + "010215": "INVISIBLE GUARD", + "010216": "SACRED GUARD", + "010217": "S-PARTS ver1.16", + "010218": "S-PARTS ver2.01", + "010219": "LIGHT RELIEF", + "01021A": "SHIELD OF DELSABER", + "01021B": "FORCE WALL", + "01021C": "RANGER WALL", + "01021D": "HUNTER WALL", + "01021E": "ATTRIBUTE WALL", + "01021F": "SECRET GEAR", + "010220": "COMBAT GEAR", + "010221": "PROTO REGENE GEAR", + "010222": "REGENERATE GEAR", + "010223": "REGENE GEAR ADV.", + "010224": "FLOWEN'S SHIELD", + "010225": "CUSTOM BARRIER ver.OO", + "010226": "DB'S SHIELD", + "010227": "RED RING", + "010228": "TRIPOLIC SHIELD", + "010229": "STANDSTILL SHIELD", + "01022A": "SAFETY HEART", + "01022B": "KASAMI BRACER", + "01022C": "GODS SHIELD SUZAKU", + "01022D": "GODS SHIELD GENBU", + "01022E": "GODS SHIELD BYAKKO", + "01022F": "GODS SHIELD SEIRYU", + "010230": "HUNTER'S SHELL", + "010231": "RICO'S GLASSES", + "010232": "RICO'S EARRING", + "010233": "BLUE RING", + "010234": "Barrier", + "010235": "SECURE FEET", + "010236": "Barrier", + "010237": "Barrier", + "010238": "Barrier", + "010239": "Barrier", + "01023A": "RESTA MERGE", + "01023B": "ANTI MERGE", + "01023C": "SHIFTA MERGE", + "01023D": "DEBAND MERGE", + "01023E": "FOIE MERGE", + "01023F": "GIFOIE MERGE", + "010240": "RAFOIE MERGE", + "010241": "RED MERGE", + "010242": "BARTA MERGE", + "010243": "GIBARTA MERGE", + "010244": "RABARTA MERGE", + "010245": "BLUE MERGE", + "010246": "ZONDE MERGE", + "010247": "GIZONDE MERGE", + "010248": "RAZONDE MERGE", + "010249": "YELLOW MERGE", + "01024A": "RECOVERY BARRIER", + "01024B": "ASSIST BARRIER", + "01024C": "RED BARRIER", + "01024D": "BLUE BARRIER", + "01024E": "YELLOW BARRIER", + "01024F": "WEAPONS GOLD SHIELD", + "010250": "BLACK GEAR", + "010251": "WORKS GUARD", + "010252": "RAGOL RING", + "010253": "BLUE RING", + "010254": "BLUE RING", + "010255": "BLUE RING", + "010256": "BLUE RING", + "010257": "BLUE RING", + "010258": "BLUE RING", + "010259": "BLUE RING", + "01025A": "BLUE RING", + "01025B": "GREEN RING", + "01025C": "GREEN RING", + "01025D": "GREEN RING", + "01025E": "GREEN RING", + "01025F": "GREEN RING", + "010260": "GREEN RING", + "010261": "GREEN RING", + "010262": "GREEN RING", + "010263": "YELLOW RING", + "010264": "YELLOW RING", + "010265": "YELLOW RING", + "010266": "YELLOW RING", + "010267": "YELLOW RING", + "010268": "YELLOW RING", + "010269": "YELLOW RING", + "01026A": "YELLOW RING", + "01026B": "PURPLE RING", + "01026C": "PURPLE RING", + "01026D": "PURPLE RING", + "01026E": "PURPLE RING", + "01026F": "PURPLE RING", + "010270": "PURPLE RING", + "010271": "PURPLE RING", + "010272": "PURPLE RING", + "010273": "WHITE RING", + "010274": "WHITE RING", + "010275": "WHITE RING", + "010276": "WHITE RING", + "010277": "WHITE RING", + "010278": "WHITE RING", + "010279": "WHITE RING", + "01027A": "WHITE RING", + "01027B": "BLACK RING", + "01027C": "BLACK RING", + "01027D": "BLACK RING", + "01027E": "BLACK RING", + "01027F": "BLACK RING", + "010280": "BLACK RING", + "010281": "BLACK RING", + "010282": "BLACK RING", + "010283": "WEAPONS SILVER SHIELD", + "010284": "WEAPONS COPPER SHIELD", + "010285": "GRATIA", + "010286": "TRIPOLIC REFLECTOR", + "010287": "STRIKER PLUS", + "010288": "REGENERATE GEAR B.P.", + "010289": "RUPIKA", + "01028A": "YATA MIRROR", + "01028B": "BUNNY EARS", + "01028C": "CAT EARS", + "01028D": "THREE SEALS", + "01028E": "GOD'S SHIELD \"KOURYU\"", + "01028F": "DF SHIELD", + "010290": "FROM THE DEPTHS", + "010291": "DE ROL LE SHIELD", + "010292": "HONEYCOMB REFLECTOR", + "010293": "EPSIGUARD", + "010294": "ANGEL RING", + "010295": "UNION GUARD", + "010296": "UNION GUARD", + "010297": "UNION GUARD", + "010298": "UNION GUARD", + "010299": "STINK SHIELD", + "01029A": "UNKNOWN_B", + "01029B": "GENPEI", + "01029C": "GENPEI", + "01029D": "GENPEI", + "01029E": "GENPEI", + "01029F": "GENPEI", + "0102A0": "GENPEI", + "0102A1": "GENPEI", + "0102A2": "GENPEI", + "0102A3": "GENPEI", + "0102A4": "GENPEI", + "0102A5": "????", + "010300": "Knight/Power", + "010301": "General/Power", + "010302": "Ogre/Power", + "010303": "God/Power", + "010304": "Priest/Mind", + "010305": "General/Mind", + "010306": "Angel/Mind", + "010307": "God/Mind", + "010308": "Marksman/Arm", + "010309": "General/Arm", + "01030A": "Elf/Arm", + "01030B": "God/Arm", + "01030C": "Thief/Legs", + "01030D": "General/Legs", + "01030E": "Elf/Legs", + "01030F": "God/Legs", + "010310": "Digger/HP", + "010311": "General/HP", + "010312": "Dragon/HP", + "010313": "God/HP", + "010314": "Magician/TP", + "010315": "General/TP", + "010316": "Angel/TP", + "010317": "God/TP", + "010318": "Warrior/Body", + "010319": "General/Body", + "01031A": "Metal/Body", + "01031B": "God/Body", + "01031C": "Angel/Luck", + "01031D": "God/Luck", + "01031E": "Master/Ability", + "01031F": "Hero/Ability", + "010320": "God/Ability", + "010321": "Resist/Fire", + "010322": "Resist/Flame", + "010323": "Resist/Burning", + "010324": "Resist/Cold", + "010325": "Resist/Freeze", + "010326": "Resist/Blizzard", + "010327": "Resist/Shock", + "010328": "Resist/Thunder", + "010329": "Resist/Storm", + "01032A": "Resist/Light", + "01032B": "Resist/Saint", + "01032C": "Resist/Holy", + "01032D": "Resist/Dark", + "01032E": "Resist/Evil", + "01032F": "Resist/Devil", + "010330": "All/Resist", + "010331": "Super/Resist", + "010332": "Perfect/Resist", + "010333": "HP/Restorate", + "010334": "HP/Generate", + "010335": "HP/Revival", + "010336": "TP/Restorate", + "010337": "TP/Generate", + "010338": "TP/Revival", + "010339": "PB/Amplifier", + "01033A": "PB/Generate", + "01033B": "PB/Create", + "01033C": "Wizard/Technique", + "01033D": "Devil/Technique", + "01033E": "God/Technique", + "01033F": "General/Battle", + "010340": "Devil/Battle", + "010341": "God/Battle", + "010342": "Cure/Poison", + "010343": "Cure/Paralysis", + "010344": "Cure/Slow", + "010345": "Cure/Confuse", + "010346": "Cure/Freeze", + "010347": "Cure/Shock", + "010348": "YASAKANI MAGATAMA", + "010349": "V101", + "01034A": "V501", + "01034B": "V502", + "01034C": "V801", + "01034D": "LIMITER", + "01034E": "ADEPT", + "01034F": "SWORDSMAN LORE", + "010350": "PROOF OF SWORD-SAINT", + "010351": "SMARTLINK", + "010352": "DIVINE PROTECTION", + "010353": "Heavenly/Battle", + "010354": "Heavenly/Power", + "010355": "Heavenly/Mind", + "010356": "Heavenly/Arms", + "010357": "Heavenly/Legs", + "010358": "Heavenly/Body", + "010359": "Heavenly/Luck", + "01035A": "Heavenly/Ability", + "01035B": "Centurion/Ability", + "01035C": "Friend Ring", + "01035D": "Heavenly/HP", + "01035E": "Heavenly/TP", + "01035F": "Heavenly/Resist", + "010360": "Heavenly/Technique", + "010361": "HP/Resurrection", + "010362": "TP/Resurrection", + "010363": "PB/Increase", + "010364": "????", + "020000": "Mag", + "020100": "Varuna", + "020200": "Mitra", + "020300": "Surya", + "020400": "Vayu", + "020500": "Varaha", + "020600": "Kama", + "020700": "Ushasu", + "020800": "Apsaras", + "020900": "Kumara", + "020A00": "Kaitabha", + "020B00": "Tapas", + "020C00": "Bhirava", + "020D00": "Kalki", + "020E00": "Rudra", + "020F00": "Marutah", + "021000": "Yaksa", + "021100": "Sita", + "021200": "Garuda", + "021300": "Nandin", + "021400": "Ashvinau", + "021500": "Ribhava", + "021600": "Soma", + "021700": "Ila", + "021800": "Durga", + "021900": "Vritra", + "021A00": "Namuci", + "021B00": "Sumba", + "021C00": "Naga", + "021D00": "Pitri", + "021E00": "Kabanda", + "021F00": "Ravana", + "022000": "Marica", + "022100": "Soniti", + "022200": "Preta", + "022300": "Andhaka", + "022400": "Bana", + "022500": "Naraka", + "022600": "Madhu", + "022700": "Churel", + "022800": "ROBOCHAO", + "022900": "OPA-OPA", + "022A00": "PIAN", + "022B00": "CHAO", + "022C00": "CHU CHU", + "022D00": "KAPU KAPU", + "022E00": "ANGEL'S WING", + "022F00": "DEVIL'S WING", + "023000": "ELENOR", + "023100": "MARK3", + "023200": "MASTER SYSTEM", + "023300": "GENESIS", + "023400": "SEGA SATURN", + "023500": "DREAMCAST", + "023600": "HAMBURGER", + "023700": "PANZER'S TAIL", + "023800": "DEVIL'S TAIL", + "023900": "Deva", + "023A00": "Rati", + "023B00": "Savitri", + "023C00": "Rukmin", + "023D00": "Pushan", + "023E00": "Diwari", + "023F00": "Sato", + "024000": "Bhima", + "024100": "Nidra", + "024200": "Geung-si", + "024300": "\n", + "024400": "Tellusis", + "024500": "Striker Unit", + "024600": "Pioneer", + "024700": "Puyo", + "024800": "Moro", + "024900": "Rappy", + "024A00": "Yahoo!", + "024B00": "Gael Giel", + "024C00": "Agastya", + "024D00": "Cell of MAG 0503", + "024E00": "Cell of MAG 0504", + "024F00": "Cell of MAG 0505", + "025000": "Cell of MAG 0506", + "025100": "Cell of MAG 0507", + "025200": "????", + "030000": "Monomate", + "030001": "Dimate", + "030002": "Trimate", + "030100": "Monofluid", + "030101": "Difluid", + "030102": "Trifluid", + "030200": "", + "030300": "Sol Atomizer", + "030400": "Moon Atomizer", + "030500": "Star Atomizer", + "030600": "Antidote", + "030601": "Antiparalysis", + "030700": "Telepipe", + "030800": "Trap Vision", + "030900": "Scape Doll", + "030A00": "Monogrinder", + "030A01": "Digrinder", + "030A02": "Trigrinder", + "030B00": "Power Material", + "030B01": "Mind Material", + "030B02": "Evade Material", + "030B03": "HP Material", + "030B04": "TP Material", + "030B05": "Def Material", + "030B06": "Luck Material", + "030C00": "Cell of MAG 502", + "030C01": "Cell of MAG 213", + "030C02": "Parts of RoboChao", + "030C03": "Heart of Opa Opa", + "030C04": "Heart of Pian", + "030C05": "Heart of Chao", + "030D00": "Sorcerer's Right Arm", + "030D01": "S-beat's Arms", + "030D02": "P-arm's Arms", + "030D03": "Delsaber's Right Arm", + "030D04": "Bringer's Right Arm", + "030D05": "Delsaber's Left Arm", + "030D06": "S-red's Arms", + "030D07": "Dragon's Claw", + "030D08": "Hildebear's Head", + "030D09": "Hildeblue's Head", + "030D0A": "Parts of Baranz", + "030D0B": "Belra's Right Arm", + "030D0C": "Gi Gue's body", + "030D0D": "Sinow Berill's Arms", + "030D0E": "Grass Assassin's Arms", + "030D0F": "Booma's Right Arm", + "030D10": "Gobooma's Right Arm", + "030D11": "Gigobooma's Right Arm", + "030D12": "Gal Gryphon's Wing", + "030D13": "Rappy's Wing", + "030D14": "Cladding of Epsilon", + "030D15": "De Rol Le Shell", + "030E00": "Berill Photon", + "030E01": "Parasitic gene \"Flow\"", + "030E02": "Magic Stone \"Iritista\"", + "030E03": "Blue-black stone", + "030E04": "Syncesta", + "030E05": "Magic Water", + "030E06": "Parasitic cell Type D ", + "030E07": "magic rock \"Heart Key\"", + "030E08": "magic rock \"Moola\"", + "030E09": "Star Amplifier", + "030E0A": "Book of HITOGATA", + "030E0B": "Heart of Chu Chu", + "030E0C": "Parts of EGG BLASTER", + "030E0D": "Heart of Angel", + "030E0E": "Heart of Devil", + "030E0F": "Kit of Hamburger", + "030E10": "Panther's Spirit", + "030E11": "Kit of MARK3", + "030E12": "Kit of MASTER SYSTEM", + "030E13": "Kit of GENESIS", + "030E14": "Kit of SEGA SATURN", + "030E15": "Kit of DREAMCAST", + "030E16": "Amplifier of Resta", + "030E17": "Amplifier of Anti", + "030E18": "Amplifier of Shifta", + "030E19": "Amplifier of Deband", + "030E1A": "Amplifier of Foie", + "030E1B": "Amplifier of Gifoie", + "030E1C": "Amplifier of Rafoie", + "030E1D": "Amplifier of Barta", + "030E1E": "Amplifier of Gibarta", + "030E1F": "Amplifier of Rabarta", + "030E20": "Amplifier of Zonde", + "030E21": "Amplifier of Gizonde", + "030E22": "Amplifier of Razonde", + "030E23": "Amplifier of Red ", + "030E24": "Amplifier of Blue", + "030E25": "Amplifier of Yellow", + "030E26": "Heart of KAPU KAPU", + "030E27": "Photon Booster", + "030F00": "AddSlot", + "031000": "Photon Drop", + "031001": "Photon Sphere", + "031002": "Photon Crystal", + "031003": "Secret Ticket", + "031004": "Photon Ticket", + "031100": "Book of KATANA1", + "031101": "Book of KATANA2", + "031102": "Book of KATANA3", + "031200": "Weapons Bronze Badge", + "031201": "Weapons Silver Badge", + "031202": "Weapons Gold Badge", + "031203": "Weapons Crystal Badge", + "031204": "Weapons Steel Badge", + "031205": "Weapons Aluminum Badge", + "031206": "Weapons Leather Badge", + "031207": "Weapons Bone Badge", + "031208": "Letter of appreciation", + "031209": "Item Ticket", + "03120A": "Valentine's Chocolate", + "03120B": "New Year's Card", + "03120C": "Christmas Card", + "03120D": "Birthday Card", + "03120E": "Proof of Sonic Team", + "03120F": "Special Event Ticket", + "031210": "Flower Bouquet", + "031211": "Cake", + "031212": "Accessories", + "031213": "Mr.Naka's Business Card", + "031300": "Present", + "031400": "Chocolate", + "031401": "Candy", + "031402": "Cake", + "031403": "Weapons Silver Badge", + "031404": "Weapons Gold Badge", + "031405": "Weapons Crystal Badge", + "031406": "Weapons Steel Badge", + "031407": "Weapons Aluminum Badge", + "031408": "Weapons Leather Badge", + "031409": "Weapons Bone Badge", + "03140A": "Bouquet", + "03140B": "Decoction", + "031500": "Christmas Present", + "031501": "Easter Egg", + "031502": "Jack-O'-Lantern", + "031600": "DISK Vol.1 \"Wedding March\"", + "031601": "DISK Vol.2 \"Day Light\"", + "031602": "DISK Vol.3 \"Burning Rangers\"", + "031603": "DISK Vol.4 \"Open Your Heart\"", + "031604": "DISK Vol.5 \"Live & Learn\"", + "031605": "DISK Vol.6 \"NiGHTS\"", + "031606": "DISK Vol.7 \"Ending Theme (Piano ver.)\"", + "031607": "DISK Vol.8 \"Heart to Heart\"", + "031608": "DISK Vol.9 \"Strange Blue\"", + "031609": "DISK Vol.10 \"Reunion System\"", + "03160A": "DISK Vol.11 \"Pinnacles\"", + "03160B": "DISK Vol.12 \"Fight inside the Spaceship\"", + "031700": "Hunters Report", + "031701": "Hunters Report", + "031702": "Hunters Report", + "031703": "Hunters Report", + "031704": "Hunters Report", + "031800": "Tablet", + "031801": "UNKNOWN2", + "031802": "Dragon Scale", + "031803": "Heaven Striker Coat", + "031804": "Pioneer Parts", + "031805": "Amitie's Memo", + "031806": "Heart of Morolian", + "031807": "Rappy's Beak", + "031808": "Yahoo!'s engine", + "031809": "D-Photon Core", + "03180A": "Liberta Kit", + "03180B": "Cell of MAG 0503", + "03180C": "Cell of MAG 0504", + "03180D": "Cell of MAG 0505", + "03180E": "Cell of MAG 0506", + "03180F": "Cell of MAG 0507", + "031900": "Team Points 500", + "031901": "Team Points 1000", + "031902": "Team Points 5000", + "031903": "Team Points 10000", + "031A00": "????" +}