diff --git a/src/Map.cc b/src/Map.cc index f34fcbb8..a0f232bc 100644 --- a/src/Map.cc +++ b/src/Map.cc @@ -480,6 +480,32 @@ void Map::add_enemies_from_map_data( } } +void Map::add_enemies_from_quest_data( + Episode episode, + uint8_t difficulty, + uint8_t event, + const void* data, + size_t size) { + StringReader r(data, size); + while (!r.eof()) { + const auto& header = r.get(); + if (header.type == 0 && header.section_size == 0) { + break; + } + if (header.section_size < sizeof(header)) { + throw runtime_error(string_printf("quest layout has invalid section header at offset 0x%zX", r.where() - sizeof(header))); + } + if (header.type == 2) { + if (header.data_size % sizeof(EnemyEntry)) { + throw runtime_error("quest layout enemy section size is not a multiple of enemy entry size"); + } + this->add_enemies_from_map_data(episode, difficulty, event, r.getv(header.data_size), header.data_size); + } else { + r.skip(header.section_size - sizeof(header)); + } + } +} + SetDataTable::SetDataTable(shared_ptr data, bool big_endian) { if (big_endian) { this->load_table_t(data); diff --git a/src/Quest.hh b/src/Quest.hh index 42c2618d..7151780c 100644 --- a/src/Quest.hh +++ b/src/Quest.hh @@ -45,6 +45,13 @@ struct QuestCategoryIndex { class Quest { public: + struct DATSectionHeader { + le_uint32_t type; // 1 = objects, 2 = enemies. There are other types too + le_uint32_t section_size; // Includes this header + le_uint32_t area; + le_uint32_t data_size; + } __attribute__((packed)); + enum class FileFormat { BIN_DAT = 0, BIN_DAT_UNCOMPRESSED, diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 43b2b9ea..b9baba18 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -12,6 +12,7 @@ #include #include "ChatCommands.hh" +#include "Compression.hh" #include "Episode3/Tournament.hh" #include "FileContentsCache.hh" #include "ItemCreator.hh" @@ -1973,6 +1974,7 @@ static void on_10(shared_ptr s, shared_ptr c, l->flags |= Lobby::Flag::QUEST_IN_PROGRESS; } l->quest = q; + l->episode = q->episode; for (size_t x = 0; x < l->max_clients; x++) { if (!l->clients[x]) { continue;