add support for cross-episode quests

This commit is contained in:
Martin Michelsen
2025-11-28 12:40:14 -08:00
parent 23eb6b29a5
commit e02a006b60
12 changed files with 504 additions and 407 deletions
+27 -23
View File
@@ -206,52 +206,56 @@ void VersionedQuest::assert_valid() const {
if (this->meta.language == Language::UNKNOWN) {
throw runtime_error("language is not set");
}
uint8_t num_floors = is_v1(this->meta.version) ? 0x10 : 0x12;
uint8_t num_areas;
if (is_v1(this->meta.version)) {
num_areas = 0x10;
} else if (is_v2(this->meta.version) && (this->meta.version != Version::GC_NTE)) {
num_areas = 0x12;
} else if (is_v3(this->meta.version) || (this->meta.version == Version::GC_NTE)) {
num_areas = 0x24;
} else if (is_ep3(this->meta.version)) {
num_areas = 0x00; // Floor overrides not allowed on Ep3
} else if (is_v4(this->meta.version)) {
num_areas = 0x2F;
} else {
throw std::logic_error("unhandled quest version");
}
for (size_t floor = 0; floor < num_floors; floor++) {
const auto& fa = this->meta.floor_assignments[floor];
if (fa.floor != floor) {
throw logic_error("floor assignment is inconsistent");
}
if ((fa.area != 0xFF) && (fa.area > num_areas)) {
throw runtime_error(std::format("floor assignment 0x{:02X} specifies invalid area 0x{:02X}", floor, fa.area));
}
}
switch (this->meta.episode) {
case Episode::EP1:
for (size_t floor = 0; floor < this->meta.area_for_floor.size(); floor++) {
uint8_t area = this->meta.area_for_floor[floor];
if (area >= 0x12) {
throw runtime_error("Episode 1 quest specifies invalid area");
}
}
break;
case Episode::EP2:
if (is_v1_or_v2(this->meta.version)) {
throw runtime_error("v1 or v2 quest specifies Episode 2");
}
for (size_t floor = 0; floor < this->meta.area_for_floor.size(); floor++) {
uint8_t area = this->meta.area_for_floor[floor];
if ((area < 0x12) || (area >= 0x24)) {
throw runtime_error("Episode 2 quest specifies invalid area");
}
}
break;
case Episode::EP3:
if (!is_ep3(this->meta.version)) {
throw runtime_error("non-Ep3 quest specifies Episode 3");
}
for (size_t floor = 0; floor < this->meta.area_for_floor.size(); floor++) {
if (this->meta.area_for_floor[floor] != 0xFF) {
throw runtime_error("Episode 3 quest specifies floor overrides");
}
}
break;
case Episode::EP4:
if (!is_v4(this->meta.version)) {
throw runtime_error("non-v4 quest specifies Episode 4");
}
for (size_t floor = 0; floor < this->meta.area_for_floor.size(); floor++) {
uint8_t area = this->meta.area_for_floor[floor];
if (area != 0xFF && (area < 0x24 || area >= 0x2F)) {
throw runtime_error("Episode 4 quest specifies invalid floor");
}
}
break;
case Episode::NONE:
throw runtime_error("episode is not set");
default:
throw runtime_error("episode is not valid");
}
if (!this->bin_contents) {
throw runtime_error("bin file is missing");
}