From e8d8b94ffabf48168d95178c2b71fc50c7e43dc2 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Wed, 18 Oct 2023 17:16:51 -0700 Subject: [PATCH] implement character overlays for challenge mode --- TODO.md | 3 +- src/Player.cc | 65 ++++++++++++++++++++++++++ src/Player.hh | 5 ++ src/PlayerSubordinates.cc | 97 ++++++++++++++++++++++++++++++++++++++- src/PlayerSubordinates.hh | 19 +++++++- src/Quest.cc | 32 +++++++++---- src/Quest.hh | 5 +- src/QuestScript.cc | 2 +- src/ReceiveCommands.cc | 16 ++++++- system/quests/b88001.json | 12 +++++ system/quests/b88002.json | 14 ++++++ system/quests/b88003.json | 14 ++++++ system/quests/b88004.json | 14 ++++++ system/quests/b88005.json | 12 +++++ system/quests/b88006.json | 14 ++++++ system/quests/b88007.json | 14 ++++++ system/quests/b88008.json | 14 ++++++ system/quests/c88101.json | 3 ++ system/quests/c88102.json | 3 ++ system/quests/c88103.json | 3 ++ system/quests/c88104.json | 3 ++ system/quests/c88105.json | 3 ++ system/quests/c88106.json | 3 ++ system/quests/c88107.json | 3 ++ system/quests/c88108.json | 3 ++ system/quests/c88109.json | 3 ++ system/quests/d88201.json | 3 ++ system/quests/d88202.json | 3 ++ system/quests/d88203.json | 3 ++ system/quests/d88204.json | 3 ++ system/quests/d88205.json | 3 ++ 31 files changed, 378 insertions(+), 16 deletions(-) create mode 100644 system/quests/b88001.json create mode 100644 system/quests/b88002.json create mode 100644 system/quests/b88003.json create mode 100644 system/quests/b88004.json create mode 100644 system/quests/b88005.json create mode 100644 system/quests/b88006.json create mode 100644 system/quests/b88007.json create mode 100644 system/quests/b88008.json create mode 100644 system/quests/c88101.json create mode 100644 system/quests/c88102.json create mode 100644 system/quests/c88103.json create mode 100644 system/quests/c88104.json create mode 100644 system/quests/c88105.json create mode 100644 system/quests/c88106.json create mode 100644 system/quests/c88107.json create mode 100644 system/quests/c88108.json create mode 100644 system/quests/c88109.json create mode 100644 system/quests/d88201.json create mode 100644 system/quests/d88202.json create mode 100644 system/quests/d88203.json create mode 100644 system/quests/d88204.json create mode 100644 system/quests/d88205.json diff --git a/TODO.md b/TODO.md index de444a16..f5ec262e 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ - Implement server-side drops on non-BB game versions - Find a way to silence audio in RunDOL.s - Encapsulate BB server-side random state and make replays deterministic -- Implement character and inventory replacement for battle and challenge modes - Implement choice search - Write a simple status API - Implement per-game logging @@ -15,6 +14,8 @@ - Implement decrypt/encrypt actions for VMS files - Fix Word Select mapping across versions - Make UI strings localizable (e.g. entries in menus, welcome message, etc.) +- Figure out what causes the corruption message on PC proxy sessions and fix it +- Enable item tracking in battle/challenge games (everything should already be set up for it to work) ## Episode 3 diff --git a/src/Player.cc b/src/Player.cc index 569c8f07..df382268 100644 --- a/src/Player.cc +++ b/src/Player.cc @@ -110,6 +110,63 @@ void ClientGameData::create_battle_overlay(shared_ptr rules, } } +void ClientGameData::create_challenge_overlay(size_t template_index, shared_ptr level_table) { + const auto& tpl = get_challenge_template_definition(this->player(true, false)->disp.visual.class_flags, template_index); + + this->overlay_player_data.reset(new SavedPlayerDataBB(*this->player(true, false))); + auto overlay = this->overlay_player_data; + + for (size_t z = 0; z < overlay->inventory.items.size(); z++) { + auto& i = overlay->inventory.items[z]; + i.present = 0; + i.extension_data1 = 0; + i.extension_data2 = 0; + i.flags = 0; + i.data = ItemData(); + } + + overlay->inventory.items[13].extension_data2 = 1; + + overlay->disp.stats.char_stats = level_table->base_stats_for_class(overlay->disp.visual.char_class); + for (overlay->disp.stats.level = 0; + overlay->disp.stats.level < tpl.level; + overlay->disp.stats.level++) { + const auto& level_stats = level_table->stats_delta_for_level( + overlay->disp.visual.char_class, overlay->disp.stats.level + 1); + // The original code clamps the resulting stat values to [0, max_stat]; we + // don't have max_stat handy so we just allow them to be unbounded + overlay->disp.stats.char_stats.atp += level_stats.atp; + overlay->disp.stats.char_stats.mst += level_stats.mst; + overlay->disp.stats.char_stats.evp += level_stats.evp; + overlay->disp.stats.char_stats.hp += level_stats.hp; + overlay->disp.stats.char_stats.dfp += level_stats.dfp; + overlay->disp.stats.char_stats.ata += level_stats.ata; + // Note: It is not a bug that lck is ignored here; the original code + // ignores it too. + } + + overlay->disp.stats.unknown_a1 = 40; + overlay->disp.stats.unknown_a3 = 10.0; + overlay->disp.stats.experience = level_table->stats_delta_for_level(overlay->disp.visual.char_class, overlay->disp.stats.level).experience; + overlay->disp.stats.meseta = 0; + overlay->clear_all_material_usage(); + for (size_t z = 0; z < 0x13; z++) { + overlay->set_technique_level(z, 0xFF); + } + + for (size_t z = 0; z < tpl.items.size(); z++) { + auto& inv_item = overlay->inventory.items[z]; + inv_item.present = tpl.items[z].present; + inv_item.flags = tpl.items[z].flags; + inv_item.data = tpl.items[z].data; + } + overlay->inventory.num_items = tpl.items.size(); + + for (const auto& tech_level : tpl.tech_levels) { + overlay->set_technique_level(tech_level.tech_num, tech_level.level); + } +} + shared_ptr ClientGameData::account(bool allow_load) { if (!this->account_data.get() && allow_load) { if (this->bb_username.empty()) { @@ -446,6 +503,14 @@ void SavedPlayerDataBB::set_material_usage(MaterialType which, uint8_t usage) { } } +void SavedPlayerDataBB::clear_all_material_usage() { + this->inventory.hp_materials_used = 0; + this->inventory.tp_materials_used = 0; + for (size_t z = 0; z < 5; z++) { + this->inventory.items[z + 8].extension_data2 = 0; + } +} + void SavedPlayerDataBB::print_inventory(FILE* stream) const { fprintf(stream, "[PlayerInventory] Meseta: %" PRIu32 "\n", this->disp.stats.meseta.load()); fprintf(stream, "[PlayerInventory] %hhu items\n", this->inventory.num_items); diff --git a/src/Player.hh b/src/Player.hh index b4d77293..0cd53041 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -70,6 +70,7 @@ struct SavedPlayerDataBB { // .nsc file format uint8_t get_material_usage(MaterialType which) const; void set_material_usage(MaterialType which, uint8_t usage); + void clear_all_material_usage(); void print_inventory(FILE* stream) const; } __attribute__((packed)); @@ -124,9 +125,13 @@ public: ~ClientGameData(); void create_battle_overlay(std::shared_ptr rules, std::shared_ptr level_table); + void create_challenge_overlay(size_t template_index, std::shared_ptr level_table); inline void delete_overlay() { this->overlay_player_data.reset(); } + inline bool has_overlay() const { + return this->overlay_player_data.get() != nullptr; + } std::shared_ptr account(bool allow_load = true); std::shared_ptr player(bool allow_load = true, bool allow_overlay = true); diff --git a/src/PlayerSubordinates.cc b/src/PlayerSubordinates.cc index 432a502a..103a39b3 100644 --- a/src/PlayerSubordinates.cc +++ b/src/PlayerSubordinates.cc @@ -94,7 +94,7 @@ void PlayerDispDataBB::apply_dressing_room(const PlayerDispDataBBPreview& pre) { this->visual.char_class = pre.visual.char_class; this->visual.v2_flags = pre.visual.v2_flags; this->visual.version = pre.visual.version; - this->visual.v1_flags = pre.visual.v1_flags; + this->visual.class_flags = pre.visual.class_flags; this->visual.costume = pre.visual.costume; this->visual.skin = pre.visual.skin; this->visual.face = pre.visual.face; @@ -606,3 +606,98 @@ BattleRules::MesetaDropMode enum_for_name(const cha throw invalid_argument("invalid BattleRules::MesetaDropMode name"); } } + +const ChallengeTemplateDefinition& get_challenge_template_definition(uint32_t class_flags, size_t index) { + static auto make_template_item = +[](bool equipped, uint64_t first_data, uint64_t second_data = 0) -> PlayerInventoryItem { + PlayerInventoryItem ret = { + .present = 1, + .extension_data1 = 0, + .extension_data2 = 0, + .flags = (equipped ? 8 : 0), + .data = ItemData()}; + ret.data.data1[0] = first_data >> 56; + ret.data.data1[1] = first_data >> 48; + ret.data.data1[2] = first_data >> 40; + ret.data.data1[3] = first_data >> 32; + ret.data.data1[4] = first_data >> 24; + ret.data.data1[5] = first_data >> 16; + ret.data.data1[6] = first_data >> 8; + ret.data.data1[7] = first_data >> 0; + ret.data.data1[8] = second_data >> 56; + ret.data.data1[9] = second_data >> 48; + ret.data.data1[10] = second_data >> 40; + ret.data.data1[11] = second_data >> 32; + ret.data.data2[0] = second_data >> 24; + ret.data.data2[1] = second_data >> 16; + ret.data.data2[2] = second_data >> 8; + ret.data.data2[3] = second_data >> 0; + return ret; + }; + + // clang-format off + static const vector hunter_templates({ + {0, {make_template_item(true, 0x0001000000000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x02000500F4010000, 0x0000000028000012), make_template_item(false, 0x0300000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {4, {make_template_item(true, 0x0001000500000000, 0x0000000000000000), make_template_item(true, 0x0101010000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x02010D002003F401, 0x0000000028000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {6, {make_template_item(true, 0x0002000000000000, 0x0000000000000000), make_template_item(true, 0x0101020000000000, 0x0000000000000000), make_template_item(true, 0x0102010000000000, 0x0000000000000000), make_template_item(true, 0x0201100020032003, 0x0000000028000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {9, {make_template_item(true, 0x0002000500000000, 0x0000000000000000), make_template_item(true, 0x0101030000000000, 0x0000000000000000), make_template_item(true, 0x0102020000000000, 0x0000000000000000), make_template_item(true, 0x02011300E8032003, 0x0000640028000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0301000000020000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {12, {make_template_item(true, 0x0001010000000000, 0x0000000000000000), make_template_item(true, 0x0101030000000000, 0x0000000000000000), make_template_item(true, 0x0102030000000000, 0x0000000000000000), make_template_item(true, 0x020116004C04E803, 0x0000640028000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0300010000030000, 0x0000000000000000), make_template_item(false, 0x0301000000020000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {14, {make_template_item(true, 0x0001010500000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102030000000000, 0x0000000000000000), make_template_item(true, 0x020118004C04E803, 0x6400C80028000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0300010000030000, 0x0000000000000000), make_template_item(false, 0x0301000000020000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {17, {make_template_item(true, 0x0002010000000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x02012700DC056C07, 0xC8002C0128000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301000000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {19, {make_template_item(true, 0x0002010500000000, 0x0000000000000000), make_template_item(true, 0x0101050000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x02012200DC057805, 0xC8002C0128000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301000000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {22, {make_template_item(true, 0x0001020000000000, 0x0000000000000000), make_template_item(true, 0x0101050000000000, 0x0000000000000000), make_template_item(true, 0x0102050000000000, 0x0000000000000000), make_template_item(true, 0x020E260008071405, 0x2C01900128000012), make_template_item(false, 0x03000000000A0000, 0x0000000000000000), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301000000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {24, {make_template_item(true, 0x0001030000000000, 0x0000000000000000), make_template_item(true, 0x0101070000000000, 0x0000000000000000), make_template_item(true, 0x0102070000000000, 0x0000000000000000), make_template_item(true, 0x02054600D007B80B, 0xE803E80328000012), make_template_item(false, 0x03000100000A0000, 0x0000000000000000), make_template_item(false, 0x0301010000050000, 0x0000000000000000), make_template_item(false, 0x0306010000050000, 0x0000000000000000), make_template_item(false, 0x0306000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {50, {make_template_item(true, 0x0001040000000000, 0x0000000000000000), make_template_item(true, 0x01010E0000000000, 0x0000000000000000), make_template_item(true, 0x01020E0000000000, 0x0000000000000000), make_template_item(true, 0x02058C00A00F7017, 0xD007D00728000012), make_template_item(false, 0x03000200000A0000, 0x0000000000000000), make_template_item(false, 0x0301020000050000, 0x0000000000000000), make_template_item(false, 0x0306010000050000, 0x0000000000000000), make_template_item(false, 0x0306000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {99, {make_template_item(true, 0x0001050000000000, 0x0000000000000000), make_template_item(true, 0x0101160000000000, 0x0000000000000000), make_template_item(true, 0x0102120000000000, 0x0000000000000000), make_template_item(true, 0x0205B40070177017, 0xB80BB80B28000012), make_template_item(false, 0x03000200000A0000, 0x0000000000000000), make_template_item(false, 0x0301020000050000, 0x0000000000000000), make_template_item(false, 0x0306010000050000, 0x0000000000000000), make_template_item(false, 0x0306000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {0, {make_template_item(true, 0x02000500F4010000, 0x0000000028000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {24, {make_template_item(true, 0x02054600D007B80B, 0xE803E80328000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {50, {make_template_item(true, 0x02058200A00F8813, 0xD007D00728000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {99, {make_template_item(true, 0x0205BE007017581B, 0xB80BB80B28000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + }); + static const vector ranger_templates({ + {0, {make_template_item(true, 0x0006000000000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x02000500F4010000, 0x0000000028000012), make_template_item(false, 0x0300000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {4, {make_template_item(true, 0x0006000500000000, 0x0000000000000000), make_template_item(true, 0x0101010000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x020D0C00F401C800, 0xF401000028000012), make_template_item(false, 0x0300000000050000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {5, {make_template_item(true, 0x0006000500000000, 0x0000000000000000), make_template_item(true, 0x0101010000000000, 0x0000000000000000), make_template_item(true, 0x0102010000000000, 0x0000000000000000), make_template_item(true, 0x020D0E00F401C800, 0xBC02000028000012), make_template_item(false, 0x0300000000050000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {8, {make_template_item(true, 0x0006000500000000, 0x0000000000000000), make_template_item(true, 0x0101020000000000, 0x0000000000000000), make_template_item(true, 0x0102020000000000, 0x0000000000000000), make_template_item(true, 0x020D1000F4012C01, 0x2003000028000012), make_template_item(false, 0x0300000000050000, 0x0000000000000000), make_template_item(false, 0x0301000000010000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {10, {make_template_item(true, 0x0006000500000000, 0x0000000000000000), make_template_item(true, 0x0101020000000000, 0x0000000000000000), make_template_item(true, 0x0102030000000000, 0x0000000000000000), make_template_item(true, 0x020D120058029001, 0x2003000028000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0300010000020000, 0x0000000000000000), make_template_item(false, 0x0301000000010000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {12, {make_template_item(true, 0x0006010000000000, 0x0000000000000000), make_template_item(true, 0x0101030000000000, 0x0000000000000000), make_template_item(true, 0x0102030000000000, 0x0000000000000000), make_template_item(true, 0x020D140058029001, 0x2003C80028000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0300010000020000, 0x0000000000000000), make_template_item(false, 0x0301000000010000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {14, {make_template_item(true, 0x0006010500000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x020D1700BC02F401, 0x8403C80028000012), make_template_item(false, 0x0300000000070000, 0x0000000000000000), make_template_item(false, 0x0300010000030000, 0x0000000000000000), make_template_item(false, 0x0301000000020000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {15, {make_template_item(true, 0x0006010500000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x020D190020035802, 0x8403C80028000012), make_template_item(false, 0x0300000000070000, 0x0000000000000000), make_template_item(false, 0x0300010000030000, 0x0000000000000000), make_template_item(false, 0x0301000000020000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {18, {make_template_item(true, 0x0006020000000000, 0x0000000000000000), make_template_item(true, 0x0101050000000000, 0x0000000000000000), make_template_item(true, 0x0102050000000000, 0x0000000000000000), make_template_item(true, 0x020D1E002003BC02, 0xB0042C0128000012), make_template_item(false, 0x0300000000070000, 0x0000000000000000), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301000000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {24, {make_template_item(true, 0x0006030000000000, 0x0000000000000000), make_template_item(true, 0x0101070000000000, 0x0000000000000000), make_template_item(true, 0x0102070000000000, 0x0000000000000000), make_template_item(true, 0x020C4600D007E803, 0xB80BE80328000012), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301010000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {50, {make_template_item(true, 0x0006040000000000, 0x0000000000000000), make_template_item(true, 0x01010E0000000000, 0x0000000000000000), make_template_item(true, 0x01020E0000000000, 0x0000000000000000), make_template_item(true, 0x020C8C00B80BC409, 0x7017C40928000012), make_template_item(false, 0x0300020000050000, 0x0000000000000000), make_template_item(false, 0x0301020000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {99, {make_template_item(true, 0x0006050000000000, 0x0000000000000000), make_template_item(true, 0x0101160000000000, 0x0000000000000000), make_template_item(true, 0x0102120000000000, 0x0000000000000000), make_template_item(true, 0x0206B400B80BB80B, 0x2823B80B28000012), make_template_item(false, 0x0300020000080000, 0x0000000000000000), make_template_item(false, 0x0301020000050000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0308000000050000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {0, {make_template_item(true, 0x02000500F4010000, 0x0000000028000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {24, {make_template_item(true, 0x020C4600D007E803, 0xB80BE80328000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {50, {make_template_item(true, 0x020C8C00B80BC409, 0x7017C40928000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {99, {make_template_item(true, 0x0206B400B80BB80B, 0x2823B80B28000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + }); + static const vector force_templates({ + {0, {make_template_item(true, 0x000A000000000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x02000500F4010000, 0x0000000028000012), make_template_item(false, 0x0300000000040000, 0x0000000000000000), make_template_item(false, 0x0301000000040000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {4, {make_template_item(true, 0x000A000500000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x02190D0020036400, 0x0000900128000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0301000000060000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 2}, {0x03, 2}, {0x0D, 2}, {0x0A, 2}}}, + {6, {make_template_item(true, 0x000B000000000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x02190F002003C800, 0x0000F40128000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0301000000060000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 2}, {0x03, 2}, {0x0D, 2}, {0x0A, 2}}}, + {9, {make_template_item(true, 0x000B000500000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x0219120084032C01, 0x0000580228000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0301000000060000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 2}, {0x03, 2}, {0x0D, 2}, {0x0A, 2}}}, + {11, {make_template_item(true, 0x000B000500000000, 0x0000000000000000), make_template_item(true, 0x0101000000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x02191400E8032C01, 0x0000BC0228000012), make_template_item(false, 0x0300000000060000, 0x0000000000000000), make_template_item(false, 0x0300010000020000, 0x0000000000000000), make_template_item(false, 0x0301000000080000, 0x0000000000000000), make_template_item(false, 0x0301010000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 4}, {0x06, 4}, {0x03, 4}, {0x0D, 2}, {0x0A, 2}, {0x0B, 2}, {0x0C, 2}}}, + {12, {make_template_item(true, 0x000B000500000000, 0x0000000000000000), make_template_item(true, 0x0101030000000000, 0x0000000000000000), make_template_item(true, 0x0102000000000000, 0x0000000000000000), make_template_item(true, 0x02191600E8039001, 0x6400BC0228000012), make_template_item(false, 0x0300000000070000, 0x0000000000000000), make_template_item(false, 0x0300010000020000, 0x0000000000000000), make_template_item(false, 0x0301000000070000, 0x0000000000000000), make_template_item(false, 0x0301010000030000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 4}, {0x06, 4}, {0x03, 4}, {0x0D, 2}, {0x0A, 2}, {0x0B, 2}, {0x0C, 2}}}, + {15, {make_template_item(true, 0x000B000A00000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x02191B00B004F401, 0xC800200328000012), make_template_item(false, 0x0300000000070000, 0x0000000000000000), make_template_item(false, 0x0300010000030000, 0x0000000000000000), make_template_item(false, 0x0301000000080000, 0x0000000000000000), make_template_item(false, 0x0301010000040000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 6}, {0x06, 6}, {0x03, 6}, {0x01, 0}, {0x04, 0}, {0x0D, 3}, {0x0A, 3}, {0x0B, 3}, {0x0C, 3}, {0x0F, 2}}}, + {16, {make_template_item(true, 0x000B000A00000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x02191D00B0045802, 0xC800840328000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0300010000030000, 0x0000000000000000), make_template_item(false, 0x03010000000A0000, 0x0000000000000000), make_template_item(false, 0x0301010000040000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 6}, {0x06, 6}, {0x03, 6}, {0x01, 0}, {0x04, 0}, {0x0D, 3}, {0x0A, 3}, {0x0B, 3}, {0x0C, 3}, {0x0F, 2}}}, + {19, {make_template_item(true, 0x000A010000000000, 0x0000000000000000), make_template_item(true, 0x0101040000000000, 0x0000000000000000), make_template_item(true, 0x0102040000000000, 0x0000000000000000), make_template_item(true, 0x02192200DC05BC02, 0xC800E80328000012), make_template_item(false, 0x0300000000080000, 0x0000000000000000), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301010000050000, 0x0000000000000000), make_template_item(false, 0x03010000000A0000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 6}, {0x06, 6}, {0x03, 6}, {0x01, 0}, {0x04, 0}, {0x0D, 3}, {0x0A, 3}, {0x0B, 3}, {0x0C, 3}, {0x0F, 2}}}, + {24, {make_template_item(true, 0x000A010A00000000, 0x0000000000000000), make_template_item(true, 0x0101060000000000, 0x0000000000000000), make_template_item(true, 0x0102060000000000, 0x0000000000000000), make_template_item(true, 0x021C4600D007E803, 0xE803B80B28000012), make_template_item(false, 0x0300010000050000, 0x0000000000000000), make_template_item(false, 0x0301010000080000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 7}, {0x06, 7}, {0x03, 7}, {0x01, 4}, {0x04, 4}, {0x0D, 7}, {0x0A, 7}, {0x0B, 7}, {0x0C, 7}, {0x0F, 6}}}, + {50, {make_template_item(true, 0x000A020000000000, 0x0000000000000000), make_template_item(true, 0x01010E0000000000, 0x0000000000000000), make_template_item(true, 0x01020D0000000000, 0x0000000000000000), make_template_item(true, 0x021C8C00B80BD007, 0xD007581B28000012), make_template_item(false, 0x0300020000050000, 0x0000000000000000), make_template_item(false, 0x0301020000080000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 9}, {0x06, 9}, {0x03, 9}, {0x01, 9}, {0x04, 9}, {0x0D, 9}, {0x0A, 9}, {0x0B, 9}, {0x0C, 9}, {0x0F, 9}}}, + {99, {make_template_item(true, 0x000A040000000000, 0x0000000000000000), make_template_item(true, 0x0101160000000000, 0x0000000000000000), make_template_item(true, 0x0102110000000000, 0x0000000000000000), make_template_item(true, 0x021CB400AC0DD007, 0xC409102728000012), make_template_item(false, 0x0300020000050000, 0x0000000000000000), make_template_item(false, 0x03010200000A0000, 0x0000000000000000), make_template_item(false, 0x0306010000030000, 0x0000000000000000), make_template_item(false, 0x0306000000030000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {{0x00, 14}, {0x06, 14}, {0x03, 14}, {0x01, 14}, {0x04, 14}, {0x0D, 14}, {0x0A, 14}, {0x0B, 14}, {0x0C, 14}, {0x0F, 14}}}, + {0, {make_template_item(true, 0x02000500F4010000, 0x0000000028000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {24, {make_template_item(true, 0x021C4600D007E803, 0xE803B80B28000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {50, {make_template_item(true, 0x021C8C00B80BD007, 0xD007581B28000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + {99, {make_template_item(true, 0x021CB400AC0DD007, 0xC409102728000012), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000), make_template_item(false, 0x0309000000000000, 0x0000000000000000)}, {}}, + }); + // clang-format on + + if ((class_flags & 0xE0) == 0x20) { + return hunter_templates.at(index); + } else if ((class_flags & 0xE0) == 0x40) { + return ranger_templates.at(index); + } else if ((class_flags & 0xE0) == 0x80) { + return force_templates.at(index); + } else { + throw runtime_error("invalid class flags on original player"); + } +} diff --git a/src/PlayerSubordinates.hh b/src/PlayerSubordinates.hh index 12f2bacf..bfc09822 100644 --- a/src/PlayerSubordinates.hh +++ b/src/PlayerSubordinates.hh @@ -108,7 +108,12 @@ struct PlayerVisualConfig { /* 31 */ uint8_t char_class = 0; /* 32 */ uint8_t v2_flags = 0; /* 33 */ uint8_t version = 0; - /* 34 */ le_uint32_t v1_flags = 0; + // class_flags specifies features of the character's class. The bits are: + // -------- -------- -------- FRHANMfm + // F = force, R = ranger, H = hunter + // A = android, N = newman, M = human + // f = female, m = male + /* 34 */ le_uint32_t class_flags = 0; /* 38 */ le_uint16_t costume = 0; /* 3A */ le_uint16_t skin = 0; /* 3C */ le_uint16_t face = 0; @@ -483,3 +488,15 @@ struct BattleRules { bool operator==(const BattleRules& other) const = default; bool operator!=(const BattleRules& other) const = default; }; + +struct ChallengeTemplateDefinition { + uint32_t level; + std::vector items; + struct TechLevel { + uint8_t tech_num; + uint8_t level; + }; + std::vector tech_levels; +}; + +const ChallengeTemplateDefinition& get_challenge_template_definition(uint32_t class_flags, size_t index); diff --git a/src/Quest.cc b/src/Quest.cc index ca474319..a1f70a86 100644 --- a/src/Quest.cc +++ b/src/Quest.cc @@ -223,7 +223,8 @@ VersionedQuest::VersionedQuest( uint8_t language, std::shared_ptr bin_contents, std::shared_ptr dat_contents, - std::shared_ptr battle_rules) + std::shared_ptr battle_rules, + ssize_t challenge_template_index) : quest_number(quest_number), category_id(category_id), episode(Episode::NONE), @@ -233,7 +234,8 @@ VersionedQuest::VersionedQuest( is_dlq_encoded(false), bin_contents(bin_contents), dat_contents(dat_contents), - battle_rules(battle_rules) { + battle_rules(battle_rules), + challenge_template_index(challenge_template_index) { auto bin_decompressed = prs_decompress(*this->bin_contents); @@ -378,7 +380,8 @@ Quest::Quest(shared_ptr initial_version) episode(initial_version->episode), joinable(initial_version->joinable), name(initial_version->name), - battle_rules(initial_version->battle_rules) { + battle_rules(initial_version->battle_rules), + challenge_template_index(initial_version->challenge_template_index) { this->versions.emplace(this->versions_key(initial_version->version, initial_version->language), initial_version); } @@ -405,6 +408,9 @@ void Quest::add_version(shared_ptr vq) { if (this->battle_rules && (*this->battle_rules != *vq->battle_rules)) { throw runtime_error("quest version has different battle rules"); } + if (this->challenge_template_index != vq->challenge_template_index) { + throw runtime_error("quest version has different challenge template index"); + } this->versions.emplace(this->versions_key(vq->version, vq->language), vq); } @@ -654,35 +660,42 @@ QuestIndex::QuestIndex( metadata_json_cache.emplace(json_filename, metadata_json); shared_ptr battle_rules; + ssize_t challenge_template_index = -1; if (metadata_json) { try { battle_rules.reset(new BattleRules(metadata_json->at("battle_rules"))); } catch (const out_of_range&) { } + try { + challenge_template_index = metadata_json->at("challenge_template_index").as_int(); + } catch (const out_of_range&) { + } } shared_ptr vq(new VersionedQuest( - quest_number, category_id, version, language, bin_contents, dat_contents, battle_rules)); + quest_number, category_id, version, language, bin_contents, dat_contents, battle_rules, challenge_template_index)); string ascii_name = format_data_string(encode_sjis(vq->name)); auto category_name = encode_sjis(this->category_index->at(vq->category_id).name); string dat_str = dat_filename.empty() ? "" : (" with layout " + dat_filename); - string metadata_json_str = battle_rules ? (" with battle rules from " + json_filename) : ""; + string battle_rules_str = battle_rules ? (" with battle rules from " + json_filename) : ""; + string challenge_template_str = (challenge_template_index >= 0) ? string_printf(" with challenge template index %zd", vq->challenge_template_index) : ""; auto q_it = this->quests_by_number.find(vq->quest_number); if (q_it != this->quests_by_number.end()) { q_it->second->add_version(vq); - static_game_data_log.info("(%s) Added %s %c version of quest %" PRIu32 " %s%s%s", + static_game_data_log.info("(%s) Added %s %c version of quest %" PRIu32 " %s%s%s%s", bin_filename.c_str(), name_for_enum(vq->version), char_for_language_code(vq->language), vq->quest_number, ascii_name.c_str(), dat_str.c_str(), - metadata_json_str.c_str()); + battle_rules_str.c_str(), + challenge_template_str.c_str()); } else { this->quests_by_number.emplace(vq->quest_number, new Quest(vq)); - static_game_data_log.info("(%s) Created %s %c quest %" PRIu32 " %s (%s, %s (%" PRIu32 "), %s)%s%s", + static_game_data_log.info("(%s) Created %s %c quest %" PRIu32 " %s (%s, %s (%" PRIu32 "), %s)%s%s%s", bin_filename.c_str(), name_for_enum(vq->version), char_for_language_code(vq->language), @@ -693,7 +706,8 @@ QuestIndex::QuestIndex( vq->category_id, vq->joinable ? "joinable" : "not joinable", dat_str.c_str(), - metadata_json_str.c_str()); + battle_rules_str.c_str(), + challenge_template_str.c_str()); } } catch (const exception& e) { static_game_data_log.warning("(%s) Failed to index quest file: (%s)", bin_filename.c_str(), e.what()); diff --git a/src/Quest.hh b/src/Quest.hh index 72503f49..16240815 100644 --- a/src/Quest.hh +++ b/src/Quest.hh @@ -67,6 +67,7 @@ struct VersionedQuest { std::shared_ptr bin_contents; std::shared_ptr dat_contents; std::shared_ptr battle_rules; + ssize_t challenge_template_index; VersionedQuest( uint32_t quest_number, @@ -75,7 +76,8 @@ struct VersionedQuest { uint8_t language, std::shared_ptr bin_contents, std::shared_ptr dat_contents, - std::shared_ptr battle_rules = nullptr); + std::shared_ptr battle_rules = nullptr, + ssize_t challenge_template_index = -1); std::string bin_filename() const; std::string dat_filename() const; @@ -105,6 +107,7 @@ public: bool joinable; std::u16string name; std::shared_ptr battle_rules; + ssize_t challenge_template_index; std::map> versions; }; diff --git a/src/QuestScript.cc b/src/QuestScript.cc index f28d595d..7e3be3b1 100644 --- a/src/QuestScript.cc +++ b/src/QuestScript.cc @@ -1411,7 +1411,7 @@ std::string disassemble_quest_script(const void* data, size_t size, QuestScriptV lines.emplace_back(string_printf(" %04zX char_class %02hhX (%s)", l->offset + offsetof(PlayerVisualConfig, char_class), visual.char_class, name_for_char_class(visual.char_class))); lines.emplace_back(string_printf(" %04zX v2_flags %02hhX", l->offset + offsetof(PlayerVisualConfig, v2_flags), visual.v2_flags)); lines.emplace_back(string_printf(" %04zX version %02hhX", l->offset + offsetof(PlayerVisualConfig, version), visual.version)); - lines.emplace_back(string_printf(" %04zX v1_flags %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, v1_flags), visual.v1_flags.load())); + lines.emplace_back(string_printf(" %04zX class_flags %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, class_flags), visual.class_flags.load())); lines.emplace_back(string_printf(" %04zX costume %04hX", l->offset + offsetof(PlayerVisualConfig, costume), visual.costume.load())); lines.emplace_back(string_printf(" %04zX skin %04hX", l->offset + offsetof(PlayerVisualConfig, skin), visual.skin.load())); lines.emplace_back(string_printf(" %04zX face %04hX", l->offset + offsetof(PlayerVisualConfig, face), visual.face.load())); diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 0c591f86..d8a7846a 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -2026,8 +2026,8 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, const string& data) l->item_creator->set_restrictions(q->battle_rules); } - for (size_t x = 0; x < l->max_clients; x++) { - auto lc = l->clients[x]; + for (size_t client_id = 0; client_id < l->max_clients; client_id++) { + auto lc = l->clients[client_id]; if (!lc) { continue; } @@ -2043,6 +2043,18 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, const string& data) 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); + } 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); + } + + // If an overlay was created, item IDs need to be assigned + if (lc->game_data.has_overlay()) { + auto overlay = lc->game_data.player(); + for (size_t z = 0; z < overlay->inventory.num_items; z++) { + overlay->inventory.items[z].data.id = l->generate_item_id(client_id); + } } string bin_filename = vq->bin_filename(); diff --git a/system/quests/b88001.json b/system/quests/b88001.json new file mode 100644 index 00000000..7873de8a --- /dev/null +++ b/system/quests/b88001.json @@ -0,0 +1,12 @@ +{ + "battle_rules": { + "tech_disk_mode": "FORBID_ALL", + "weapon_and_armor_mode": "CLEAR_AND_ALLOW", + "forbid_mags": false, + "tool_mode": "CLEAR_AND_ALLOW", + "meseta_drop_mode": "ALLOW", + "forbid_scape_dolls": true, + "replace_char": false, + "box_drop_area": 10 + } +} diff --git a/system/quests/b88002.json b/system/quests/b88002.json new file mode 100644 index 00000000..7e9fa474 --- /dev/null +++ b/system/quests/b88002.json @@ -0,0 +1,14 @@ +{ + "battle_rules": { + "tech_disk_mode": "LIMIT_LEVEL", + "weapon_and_armor_mode": "FORBID_ALL", + "forbid_mags": false, + "tool_mode": "FORBID_ALL", + "meseta_drop_mode": "CLEAR_AND_ALLOW", + "forbid_scape_dolls": true, + "max_tech_disk_level": 0, + "replace_char": true, + "char_level": 0, + "box_drop_area": 1 + } +} diff --git a/system/quests/b88003.json b/system/quests/b88003.json new file mode 100644 index 00000000..1844b318 --- /dev/null +++ b/system/quests/b88003.json @@ -0,0 +1,14 @@ +{ + "battle_rules": { + "tech_disk_mode": "LIMIT_LEVEL", + "weapon_and_armor_mode": "FORBID_ALL", + "forbid_mags": false, + "tool_mode": "FORBID_ALL", + "meseta_drop_mode": "FORBID_ALL", + "forbid_scape_dolls": true, + "max_tech_disk_level": 0, + "replace_char": true, + "char_level": 4, + "box_drop_area": 3 + } +} diff --git a/system/quests/b88004.json b/system/quests/b88004.json new file mode 100644 index 00000000..d6e03aac --- /dev/null +++ b/system/quests/b88004.json @@ -0,0 +1,14 @@ +{ + "battle_rules": { + "tech_disk_mode": "LIMIT_LEVEL", + "weapon_and_armor_mode": "FORBID_ALL", + "forbid_mags": false, + "tool_mode": "FORBID_ALL", + "meseta_drop_mode": "CLEAR_AND_ALLOW", + "forbid_scape_dolls": true, + "max_tech_disk_level": 1, + "replace_char": true, + "char_level": 1, + "box_drop_area": 1 + } +} diff --git a/system/quests/b88005.json b/system/quests/b88005.json new file mode 100644 index 00000000..551b8fe7 --- /dev/null +++ b/system/quests/b88005.json @@ -0,0 +1,12 @@ +{ + "battle_rules": { + "tech_disk_mode": "FORBID_ALL", + "weapon_and_armor_mode": "CLEAR_AND_ALLOW", + "forbid_mags": false, + "tool_mode": "CLEAR_AND_ALLOW", + "meseta_drop_mode": "CLEAR_AND_ALLOW", + "forbid_scape_dolls": true, + "replace_char": false, + "box_drop_area": 10 + } +} diff --git a/system/quests/b88006.json b/system/quests/b88006.json new file mode 100644 index 00000000..0657baf5 --- /dev/null +++ b/system/quests/b88006.json @@ -0,0 +1,14 @@ +{ + "battle_rules": { + "tech_disk_mode": "LIMIT_LEVEL", + "weapon_and_armor_mode": "FORBID_ALL", + "forbid_mags": false, + "tool_mode": "FORBID_ALL", + "meseta_drop_mode": "CLEAR_AND_ALLOW", + "forbid_scape_dolls": true, + "max_tech_disk_level": 4, + "replace_char": true, + "char_level": 19, + "box_drop_area": 6 + } +} diff --git a/system/quests/b88007.json b/system/quests/b88007.json new file mode 100644 index 00000000..f7c1ef5a --- /dev/null +++ b/system/quests/b88007.json @@ -0,0 +1,14 @@ +{ + "battle_rules": { + "tech_disk_mode": "LIMIT_LEVEL", + "weapon_and_armor_mode": "FORBID_ALL", + "forbid_mags": false, + "tool_mode": "FORBID_ALL", + "meseta_drop_mode": "CLEAR_AND_ALLOW", + "forbid_scape_dolls": false, + "max_tech_disk_level": 0, + "replace_char": true, + "char_level": 0, + "box_drop_area": 2 + } +} diff --git a/system/quests/b88008.json b/system/quests/b88008.json new file mode 100644 index 00000000..204edbe6 --- /dev/null +++ b/system/quests/b88008.json @@ -0,0 +1,14 @@ +{ + "battle_rules": { + "tech_disk_mode": "LIMIT_LEVEL", + "weapon_and_armor_mode": "FORBID_ALL", + "forbid_mags": false, + "tool_mode": "FORBID_ALL", + "meseta_drop_mode": "FORBID_ALL", + "forbid_scape_dolls": true, + "max_tech_disk_level": 0, + "replace_char": true, + "char_level": 19, + "box_drop_area": 1 + } +} diff --git a/system/quests/c88101.json b/system/quests/c88101.json new file mode 100644 index 00000000..f196012f --- /dev/null +++ b/system/quests/c88101.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 0 +} diff --git a/system/quests/c88102.json b/system/quests/c88102.json new file mode 100644 index 00000000..7ea02225 --- /dev/null +++ b/system/quests/c88102.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 1 +} diff --git a/system/quests/c88103.json b/system/quests/c88103.json new file mode 100644 index 00000000..261da30a --- /dev/null +++ b/system/quests/c88103.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 2 +} diff --git a/system/quests/c88104.json b/system/quests/c88104.json new file mode 100644 index 00000000..c9024661 --- /dev/null +++ b/system/quests/c88104.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 3 +} diff --git a/system/quests/c88105.json b/system/quests/c88105.json new file mode 100644 index 00000000..42795483 --- /dev/null +++ b/system/quests/c88105.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 4 +} diff --git a/system/quests/c88106.json b/system/quests/c88106.json new file mode 100644 index 00000000..83e8ff50 --- /dev/null +++ b/system/quests/c88106.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 5 +} diff --git a/system/quests/c88107.json b/system/quests/c88107.json new file mode 100644 index 00000000..b6d3ba32 --- /dev/null +++ b/system/quests/c88107.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 6 +} diff --git a/system/quests/c88108.json b/system/quests/c88108.json new file mode 100644 index 00000000..40925e01 --- /dev/null +++ b/system/quests/c88108.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 7 +} diff --git a/system/quests/c88109.json b/system/quests/c88109.json new file mode 100644 index 00000000..c1bc8eeb --- /dev/null +++ b/system/quests/c88109.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 8 +} diff --git a/system/quests/d88201.json b/system/quests/d88201.json new file mode 100644 index 00000000..7ea02225 --- /dev/null +++ b/system/quests/d88201.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 1 +} diff --git a/system/quests/d88202.json b/system/quests/d88202.json new file mode 100644 index 00000000..42795483 --- /dev/null +++ b/system/quests/d88202.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 4 +} diff --git a/system/quests/d88203.json b/system/quests/d88203.json new file mode 100644 index 00000000..83e8ff50 --- /dev/null +++ b/system/quests/d88203.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 5 +} diff --git a/system/quests/d88204.json b/system/quests/d88204.json new file mode 100644 index 00000000..c1bc8eeb --- /dev/null +++ b/system/quests/d88204.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 8 +} diff --git a/system/quests/d88205.json b/system/quests/d88205.json new file mode 100644 index 00000000..c1bc8eeb --- /dev/null +++ b/system/quests/d88205.json @@ -0,0 +1,3 @@ +{ + "challenge_template_index": 8 +}