abstract supermap construction across entity types
This commit is contained in:
+32
-15
@@ -2639,6 +2639,7 @@ Action a_load_maps_test(
|
||||
s->load_set_data_tables(false);
|
||||
s->load_maps(false);
|
||||
|
||||
SuperMap::EfficiencyStats all_free_maps_eff;
|
||||
for (const auto& it : s->supermaps) {
|
||||
auto episode = static_cast<Episode>((it.first >> 28) & 7);
|
||||
auto mode = static_cast<GameMode>((it.first >> 26) & 3);
|
||||
@@ -2647,12 +2648,7 @@ Action a_load_maps_test(
|
||||
uint8_t layout = (it.first >> 8) & 0xFF;
|
||||
uint8_t entities = (it.first >> 0) & 0xFF;
|
||||
|
||||
fprintf(stderr, "FREE MAP: %08" PRIX32 " => %s %s %c floor=%02hhX layout=%02hhX entities=%02hhX\n",
|
||||
it.first,
|
||||
abbreviation_for_episode(episode),
|
||||
abbreviation_for_mode(mode),
|
||||
abbreviation_for_difficulty(difficulty),
|
||||
floor, layout, entities);
|
||||
string filename_token;
|
||||
if (save_disassembly) {
|
||||
string filename = phosg::string_printf(
|
||||
"supermap_%s_%s_%c_%02hhX_%02hhx_%02hhX.txt",
|
||||
@@ -2662,8 +2658,21 @@ Action a_load_maps_test(
|
||||
floor, layout, entities);
|
||||
auto f = phosg::fopen_unique(filename, "wt");
|
||||
it.second->print(f.get());
|
||||
filename_token = " => " + filename;
|
||||
}
|
||||
|
||||
auto eff = it.second->efficiency();
|
||||
all_free_maps_eff += eff;
|
||||
auto eff_str = eff.str();
|
||||
fprintf(stderr, "FREE MAP: %08" PRIX32 " => %s %s %c floor=%02hhX layout=%02hhX entities=%02hhX => %s%s\n",
|
||||
it.first,
|
||||
abbreviation_for_episode(episode),
|
||||
abbreviation_for_mode(mode),
|
||||
abbreviation_for_difficulty(difficulty),
|
||||
floor, layout, entities, eff_str.c_str(), filename_token.c_str());
|
||||
}
|
||||
string all_free_maps_eff_str = all_free_maps_eff.str();
|
||||
fprintf(stderr, "ALL FREE MAPS: %s\n", all_free_maps_eff_str.c_str());
|
||||
|
||||
// Generate MapStates for a few random variations
|
||||
for (size_t z = 0; z < 0x20; z++) {
|
||||
@@ -2696,21 +2705,27 @@ Action a_load_maps_test(
|
||||
|
||||
s->load_quest_index(false);
|
||||
|
||||
SuperMap::EfficiencyStats all_quests_eff;
|
||||
uint32_t random_seed = args.get<uint32_t>("random-seed", 0, phosg::Arguments::IntFormat::HEX);
|
||||
for (const auto& it : s->default_quest_index->quests_by_number) {
|
||||
auto supermap = it.second->get_supermap(random_seed);
|
||||
if (!supermap) {
|
||||
fprintf(stderr, "QUEST MAP: %08" PRIX32 " => (no supermap)\n", it.first);
|
||||
} else {
|
||||
string filename = phosg::string_printf("supermap_quest_%" PRIu32 "_%08" PRIX32 ".txt", it.first, random_seed);
|
||||
fprintf(stderr, "QUEST MAP: %08" PRIX32 " => %s\n", it.first, filename.c_str());
|
||||
if (save_disassembly) {
|
||||
auto f = phosg::fopen_unique(filename, "wt");
|
||||
fprintf(f.get(), "QUEST %" PRIu32 " (%s)\n", it.first, it.second->name.c_str());
|
||||
supermap->print(f.get());
|
||||
}
|
||||
throw logic_error("quest does not have a supermap, even with a specified random seed");
|
||||
}
|
||||
|
||||
string filename_token;
|
||||
if (save_disassembly) {
|
||||
string filename = phosg::string_printf("supermap_quest_%" PRIu32 "_%08" PRIX32 ".txt", it.first, random_seed);
|
||||
auto f = phosg::fopen_unique(filename, "wt");
|
||||
fprintf(f.get(), "QUEST %" PRIu32 " (%s)\n", it.first, it.second->name.c_str());
|
||||
supermap->print(f.get());
|
||||
filename_token = " => " + filename;
|
||||
}
|
||||
auto eff = supermap->efficiency();
|
||||
all_quests_eff += eff;
|
||||
auto eff_str = eff.str();
|
||||
fprintf(stderr, "QUEST MAP: %08" PRIX32 " => %s%s\n", it.first, eff_str.c_str(), filename_token.c_str());
|
||||
|
||||
auto map_state = make_shared<MapState>(
|
||||
0,
|
||||
phosg::random_object<uint8_t>() & 3,
|
||||
@@ -2727,6 +2742,8 @@ Action a_load_maps_test(
|
||||
map_state->enemy_set_states.size(),
|
||||
map_state->event_states.size());
|
||||
}
|
||||
string all_quests_eff_str = all_quests_eff.str();
|
||||
fprintf(stderr, "ALL QUEST MAPS: %s\n", all_quests_eff_str.c_str());
|
||||
});
|
||||
|
||||
Action a_parse_object_graph(
|
||||
|
||||
+168
-102
@@ -1745,8 +1745,12 @@ string MapFile::disassemble() const {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Super map
|
||||
|
||||
string SuperMap::Object::id_str() const {
|
||||
return phosg::string_printf("KS-%02hhX-%03zX", this->floor, this->super_id);
|
||||
}
|
||||
|
||||
string SuperMap::Object::str() const {
|
||||
string ret = phosg::string_printf("[Object KS-%02hhX-%03zX", this->floor, this->super_id);
|
||||
string ret = "[Object " + this->id_str();
|
||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||
const auto& def = this->version(v);
|
||||
if (def.relative_object_index != 0xFFFF) {
|
||||
@@ -1759,6 +1763,10 @@ string SuperMap::Object::str() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
string SuperMap::Enemy::id_str() const {
|
||||
return phosg::string_printf("ES-%02hhX-%03zX-%03zX", this->floor, this->super_set_id, this->super_id);
|
||||
}
|
||||
|
||||
string SuperMap::Enemy::str() const {
|
||||
string ret = phosg::string_printf("[Enemy ES-%02hhX-%03zX-%03zX type=%s child_index=%hX alias_enemy_index_delta=%hX is_default_rare_v123=%s is_default_rare_bb=%s",
|
||||
this->floor,
|
||||
@@ -1785,8 +1793,12 @@ string SuperMap::Enemy::str() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
string SuperMap::Event::id_str() const {
|
||||
return phosg::string_printf("WS-%02hhX-%03zX", this->floor, this->super_id);
|
||||
}
|
||||
|
||||
string SuperMap::Event::str() const {
|
||||
string ret = phosg::string_printf("[Event WS-%02hhX-%03zX", this->floor, this->super_id);
|
||||
string ret = "[Event " + this->id_str();
|
||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||
const auto& def = this->version(v);
|
||||
if (def.relative_event_index != 0xFFFF) {
|
||||
@@ -1864,6 +1876,10 @@ void SuperMap::link_object_version(std::shared_ptr<Object> obj, Version version,
|
||||
|
||||
entities.objects.emplace_back(obj);
|
||||
|
||||
// Add to semantic hash index
|
||||
uint64_t semantic_hash = set_entry->semantic_hash();
|
||||
this->objects_for_semantic_hash[semantic_hash].emplace_back(obj);
|
||||
|
||||
// Add to room/group index
|
||||
uint64_t k = room_index_key(obj->floor, set_entry->room, set_entry->group);
|
||||
entities.object_for_floor_room_and_group.emplace(k, obj);
|
||||
@@ -2380,6 +2396,10 @@ void SuperMap::link_enemy_version_and_children(
|
||||
entities.enemies.emplace_back(ene);
|
||||
if (ene->child_index == 0) {
|
||||
entities.enemy_sets.emplace_back(ene);
|
||||
|
||||
// Add to semantic hash index (but only for the root ene)
|
||||
uint64_t semantic_hash = set_entry->semantic_hash();
|
||||
this->enemy_sets_for_semantic_hash[semantic_hash].emplace_back(ene);
|
||||
}
|
||||
|
||||
// Add to room/group index
|
||||
@@ -2470,6 +2490,11 @@ void SuperMap::link_event_version(
|
||||
|
||||
entities.events.emplace_back(ev);
|
||||
|
||||
// Add to semantic hash index
|
||||
uint64_t semantic_hash = entry->semantic_hash();
|
||||
this->events_for_semantic_hash[semantic_hash].emplace_back(ev);
|
||||
|
||||
// Add to room index
|
||||
uint64_t k = room_index_key(ev->floor, entry->room, entry->wave_number);
|
||||
entities.event_for_floor_room_and_wave_number.emplace(k, ev);
|
||||
k = (static_cast<uint64_t>(ev->floor) << 32) | entry->event_id;
|
||||
@@ -2616,6 +2641,35 @@ vector<EditAction> compute_edit_path(
|
||||
return reverse_path;
|
||||
}
|
||||
|
||||
template <typename EntityT>
|
||||
vector<shared_ptr<EntityT>> compute_prev_entities(
|
||||
const vector<shared_ptr<EntityT>>& existing_prev_entities,
|
||||
size_t prev_entities_offset,
|
||||
const vector<EditAction>& edit_path) {
|
||||
vector<shared_ptr<EntityT>> ret;
|
||||
for (auto action : edit_path) {
|
||||
switch (action) {
|
||||
case EditAction::ADD:
|
||||
// This object doesn't match any object from the previous version
|
||||
ret.emplace_back(nullptr);
|
||||
break;
|
||||
case EditAction::DELETE:
|
||||
// There is an object in the previous version that doesn't match any in this version; skip it
|
||||
prev_entities_offset++;
|
||||
break;
|
||||
case EditAction::EDIT: {
|
||||
// The current object in this_sf matches the current object in prev_sf; link them together
|
||||
ret.emplace_back(existing_prev_entities.at(prev_entities_offset));
|
||||
prev_entities_offset++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw logic_error("invalid edit path action");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static double object_set_add_cost(const MapFile::ObjectSetEntry&) {
|
||||
return 100.0;
|
||||
}
|
||||
@@ -2710,6 +2764,37 @@ void SuperMap::add_map_file(Version this_v, shared_ptr<const MapFile> this_map_f
|
||||
}
|
||||
|
||||
for (uint8_t floor = 0; floor < 0x12; floor++) {
|
||||
auto link_or_add_entities = [this_v, floor]<typename EntityT, typename EntryT>(
|
||||
const EntryT* prev_sets,
|
||||
size_t prev_set_count,
|
||||
const EntryT* this_sets,
|
||||
size_t this_set_count,
|
||||
double (*add_cost)(const EntryT&),
|
||||
double (*delete_cost)(const EntryT&),
|
||||
double (*edit_cost)(const EntryT&, const EntryT& current),
|
||||
const vector<EntityT>& prev_entities,
|
||||
size_t prev_entities_start_index,
|
||||
auto&& link_existing,
|
||||
auto&& add_new) {
|
||||
auto edit_path = compute_edit_path(
|
||||
prev_sets, prev_set_count, this_sets, this_set_count, add_cost, delete_cost, edit_cost);
|
||||
|
||||
auto used_prev_entities = compute_prev_entities(prev_entities, prev_entities_start_index, edit_path);
|
||||
if (used_prev_entities.size() != this_set_count) {
|
||||
throw std::logic_error("incorrect previous entity list length");
|
||||
}
|
||||
|
||||
// TODO; // Use semantic hash index to fill in the gaps
|
||||
for (size_t z = 0; z < this_set_count; z++) {
|
||||
auto& prev_ent = used_prev_entities[z];
|
||||
if (prev_ent) {
|
||||
link_existing(prev_ent, this_v, this_sets + z);
|
||||
} else {
|
||||
add_new(this_v, floor, this_sets + z);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this_entities.object_floor_start_indexes[floor] = this_entities.objects.size();
|
||||
this_entities.enemy_floor_start_indexes[floor] = this_entities.enemies.size();
|
||||
this_entities.enemy_set_floor_start_indexes[floor] = this_entities.enemy_sets.size();
|
||||
@@ -2726,42 +2811,20 @@ void SuperMap::add_map_file(Version this_v, shared_ptr<const MapFile> this_map_f
|
||||
|
||||
} else if (this_sf.object_sets) {
|
||||
const auto& prev_sf = prev_map_file->floor(floor);
|
||||
auto edit_path = compute_edit_path(
|
||||
auto& prev_entities = this->version(prev_v);
|
||||
|
||||
link_or_add_entities(
|
||||
prev_sf.object_sets,
|
||||
prev_sf.object_set_count,
|
||||
this_sf.object_sets,
|
||||
this_sf.object_set_count,
|
||||
object_set_add_cost,
|
||||
object_set_delete_cost,
|
||||
object_set_edit_cost);
|
||||
|
||||
auto& prev_entities = this->version(prev_v);
|
||||
|
||||
size_t prev_entities_offset = prev_entities.object_floor_start_indexes.at(floor);
|
||||
size_t this_sf_offset = 0;
|
||||
for (auto action : edit_path) {
|
||||
switch (action) {
|
||||
case EditAction::ADD:
|
||||
// This object doesn't match any object from the previous version; create a new object
|
||||
this->add_object(this_v, floor, this_sf.object_sets + this_sf_offset);
|
||||
this_sf_offset++;
|
||||
break;
|
||||
case EditAction::DELETE:
|
||||
// There is an object in the previous version that doesn't match any in this version; skip it
|
||||
prev_entities_offset++;
|
||||
break;
|
||||
case EditAction::EDIT: {
|
||||
// The current object in this_sf matches the current object in prev_sf; link them together
|
||||
auto prev_obj = prev_entities.objects.at(prev_entities_offset);
|
||||
this->link_object_version(prev_obj, this_v, this_sf.object_sets + this_sf_offset);
|
||||
prev_entities_offset++;
|
||||
this_sf_offset++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw logic_error("invalid edit path action");
|
||||
}
|
||||
}
|
||||
object_set_edit_cost,
|
||||
prev_entities.objects,
|
||||
prev_entities.object_floor_start_indexes.at(floor),
|
||||
bind(&SuperMap::link_object_version, this, placeholders::_1, placeholders::_2, placeholders::_3),
|
||||
bind(&SuperMap::add_object, this, placeholders::_1, placeholders::_2, placeholders::_3));
|
||||
}
|
||||
|
||||
if (!prev_map_file || !prev_map_file->floor(floor).enemy_sets) {
|
||||
@@ -2770,42 +2833,20 @@ void SuperMap::add_map_file(Version this_v, shared_ptr<const MapFile> this_map_f
|
||||
}
|
||||
} else if (this_sf.enemy_sets) {
|
||||
const auto& prev_sf = prev_map_file->floor(floor);
|
||||
auto edit_path = compute_edit_path(
|
||||
auto& prev_entities = this->version(prev_v);
|
||||
|
||||
link_or_add_entities(
|
||||
prev_sf.enemy_sets,
|
||||
prev_sf.enemy_set_count,
|
||||
this_sf.enemy_sets,
|
||||
this_sf.enemy_set_count,
|
||||
enemy_set_add_cost,
|
||||
enemy_set_delete_cost,
|
||||
enemy_set_edit_cost);
|
||||
|
||||
auto& prev_entities = this->version(prev_v);
|
||||
|
||||
size_t prev_entities_offset = prev_entities.enemy_set_floor_start_indexes.at(floor);
|
||||
size_t this_sf_offset = 0;
|
||||
for (auto action : edit_path) {
|
||||
switch (action) {
|
||||
case EditAction::ADD:
|
||||
// This object doesn't match any object from the previous version; create a new object
|
||||
this->add_enemy_and_children(this_v, floor, this_sf.enemy_sets + this_sf_offset);
|
||||
this_sf_offset++;
|
||||
break;
|
||||
case EditAction::DELETE:
|
||||
// There is an object in the previous version that doesn't match any in this version; skip it
|
||||
prev_entities_offset++;
|
||||
break;
|
||||
case EditAction::EDIT: {
|
||||
// The current object in this_sf matches the current object in prev_sf; link them together
|
||||
auto prev_ene = prev_entities.enemy_sets.at(prev_entities_offset);
|
||||
this->link_enemy_version_and_children(prev_ene, this_v, this_sf.enemy_sets + this_sf_offset);
|
||||
prev_entities_offset++;
|
||||
this_sf_offset++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw logic_error("invalid edit path action");
|
||||
}
|
||||
}
|
||||
enemy_set_edit_cost,
|
||||
prev_entities.enemy_sets,
|
||||
prev_entities.enemy_set_floor_start_indexes.at(floor),
|
||||
bind(&SuperMap::link_enemy_version_and_children, this, placeholders::_1, placeholders::_2, placeholders::_3),
|
||||
bind(&SuperMap::add_enemy_and_children, this, placeholders::_1, placeholders::_2, placeholders::_3));
|
||||
}
|
||||
|
||||
if (!prev_map_file || !prev_map_file->floor(floor).events1) {
|
||||
@@ -2814,52 +2855,20 @@ void SuperMap::add_map_file(Version this_v, shared_ptr<const MapFile> this_map_f
|
||||
}
|
||||
} else if (this_sf.events1) {
|
||||
const auto& prev_sf = prev_map_file->floor(floor);
|
||||
auto edit_path = compute_edit_path(
|
||||
auto& prev_entities = this->version(prev_v);
|
||||
|
||||
link_or_add_entities(
|
||||
prev_sf.events1,
|
||||
prev_sf.event_count,
|
||||
this_sf.events1,
|
||||
this_sf.event_count,
|
||||
event_add_cost,
|
||||
event_delete_cost,
|
||||
event_edit_cost);
|
||||
|
||||
auto& prev_entities = this->version(prev_v);
|
||||
|
||||
size_t prev_entities_offset = prev_entities.event_floor_start_indexes.at(floor);
|
||||
size_t this_sf_offset = 0;
|
||||
for (auto action : edit_path) {
|
||||
switch (action) {
|
||||
case EditAction::ADD:
|
||||
// This object doesn't match any object from the previous version; try to look it up in the semantic hash index
|
||||
this->add_event(
|
||||
this_v,
|
||||
floor,
|
||||
this_sf.events1 + this_sf_offset,
|
||||
this_sf.event_action_stream,
|
||||
this_sf.event_action_stream_bytes);
|
||||
this_sf_offset++;
|
||||
break;
|
||||
case EditAction::DELETE:
|
||||
// There is an object in the previous version that doesn't match any in this version; skip it
|
||||
prev_entities_offset++;
|
||||
break;
|
||||
case EditAction::EDIT: {
|
||||
// The current object in this_sf matches the current object in prev_sf; link them together
|
||||
auto prev_ev = prev_entities.events.at(prev_entities_offset);
|
||||
this->link_event_version(
|
||||
prev_ev,
|
||||
this_v,
|
||||
this_sf.events1 + this_sf_offset,
|
||||
this_sf.event_action_stream,
|
||||
this_sf.event_action_stream_bytes);
|
||||
prev_entities_offset++;
|
||||
this_sf_offset++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw logic_error("invalid edit path action");
|
||||
}
|
||||
}
|
||||
event_edit_cost,
|
||||
prev_entities.events,
|
||||
prev_entities.event_floor_start_indexes.at(floor),
|
||||
bind(&SuperMap::link_event_version, this, placeholders::_1, placeholders::_2, placeholders::_3, this_sf.event_action_stream, this_sf.event_action_stream_bytes),
|
||||
bind(&SuperMap::add_event, this, placeholders::_1, placeholders::_2, placeholders::_3, this_sf.event_action_stream, this_sf.event_action_stream_bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2970,6 +2979,63 @@ vector<shared_ptr<const SuperMap::Event>> SuperMap::events_for_floor_room_wave(
|
||||
return ret;
|
||||
}
|
||||
|
||||
SuperMap::EfficiencyStats& SuperMap::EfficiencyStats::operator+=(const EfficiencyStats& other) {
|
||||
this->filled_object_slots += other.filled_object_slots;
|
||||
this->total_object_slots += other.total_object_slots;
|
||||
this->filled_enemy_set_slots += other.filled_enemy_set_slots;
|
||||
this->total_enemy_set_slots += other.total_enemy_set_slots;
|
||||
this->filled_event_slots += other.filled_event_slots;
|
||||
this->total_event_slots += other.total_event_slots;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string SuperMap::EfficiencyStats::str() const {
|
||||
return phosg::string_printf(
|
||||
"EfficiencyStats[K = %zu/%zu (%lg%%), E = %zu/%zu (%lg%%), W = %zu/%zu (%g%%)]",
|
||||
this->filled_object_slots, this->total_object_slots,
|
||||
static_cast<double>(this->filled_object_slots * 100) / static_cast<double>(this->total_object_slots),
|
||||
this->filled_enemy_set_slots, this->total_enemy_set_slots,
|
||||
static_cast<double>(this->filled_enemy_set_slots * 100) / static_cast<double>(this->total_enemy_set_slots),
|
||||
this->filled_event_slots, this->total_event_slots,
|
||||
static_cast<double>(this->filled_event_slots * 100) / static_cast<double>(this->total_event_slots));
|
||||
}
|
||||
|
||||
SuperMap::EfficiencyStats SuperMap::efficiency() const {
|
||||
EfficiencyStats ret;
|
||||
|
||||
for (const auto& obj : this->objects) {
|
||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||
const auto& obj_ver = obj->version(v);
|
||||
if (obj_ver.relative_object_index != 0xFFFF) {
|
||||
ret.filled_object_slots++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.total_object_slots = this->objects.size() * ALL_ARPG_SEMANTIC_VERSIONS.size();
|
||||
|
||||
for (const auto& ene : this->enemy_sets) {
|
||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||
const auto& ene_ver = ene->version(v);
|
||||
if (ene_ver.relative_enemy_index != 0xFFFF) {
|
||||
ret.filled_enemy_set_slots++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.total_enemy_set_slots = this->enemy_sets.size() * ALL_ARPG_SEMANTIC_VERSIONS.size();
|
||||
|
||||
for (const auto& ev : this->events) {
|
||||
for (Version v : ALL_ARPG_SEMANTIC_VERSIONS) {
|
||||
const auto& ev_ver = ev->version(v);
|
||||
if (ev_ver.relative_event_index != 0xFFFF) {
|
||||
ret.filled_event_slots++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.total_event_slots = this->events.size() * ALL_ARPG_SEMANTIC_VERSIONS.size();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SuperMap::verify() const {
|
||||
for (size_t super_id = 0; super_id < this->objects.size(); super_id++) {
|
||||
if (this->objects[super_id]->super_id != super_id) {
|
||||
|
||||
+20
-2
@@ -446,7 +446,8 @@ protected:
|
||||
// responsible for all entities on all floors in a quest, or all entities on a
|
||||
// single floor in free play. Each entity is assigned a "super ID", which
|
||||
// uniquely identifies the entity on all PSO versions. (These are the IDs which
|
||||
// newserv formats as K-XXX, E-XXX, and W-XXX.)
|
||||
// newserv formats as K-XXX, E-XXX, and W-XXX, though they are offset as needed
|
||||
// for floors beyond the first.)
|
||||
// There must not be any random enemy sections in any MapFile passed to
|
||||
// SuperMap; to resolve them, materialize_random_sections must be called on all
|
||||
// MapFiles first. This generally only is of concern in Challenge mode.
|
||||
@@ -469,6 +470,7 @@ public:
|
||||
return this->def_for_version.at(static_cast<size_t>(v));
|
||||
}
|
||||
|
||||
std::string id_str() const;
|
||||
std::string str() const;
|
||||
};
|
||||
|
||||
@@ -495,6 +497,7 @@ public:
|
||||
return this->def_for_version.at(static_cast<size_t>(v));
|
||||
}
|
||||
|
||||
std::string id_str() const;
|
||||
std::string str() const;
|
||||
};
|
||||
|
||||
@@ -516,6 +519,7 @@ public:
|
||||
return this->def_for_version.at(static_cast<size_t>(v));
|
||||
}
|
||||
|
||||
std::string id_str() const;
|
||||
std::string str() const;
|
||||
};
|
||||
|
||||
@@ -584,8 +588,19 @@ public:
|
||||
std::vector<std::shared_ptr<const Event>> events_for_floor_room_wave(
|
||||
Version version, uint8_t floor, uint16_t room, uint16_t wave_number) const;
|
||||
|
||||
void verify() const;
|
||||
struct EfficiencyStats {
|
||||
size_t filled_object_slots = 0;
|
||||
size_t total_object_slots = 0;
|
||||
size_t filled_enemy_set_slots = 0;
|
||||
size_t total_enemy_set_slots = 0;
|
||||
size_t filled_event_slots = 0;
|
||||
size_t total_event_slots = 0;
|
||||
|
||||
EfficiencyStats& operator+=(const EfficiencyStats& other);
|
||||
std::string str() const;
|
||||
};
|
||||
EfficiencyStats efficiency() const;
|
||||
void verify() const;
|
||||
void print(FILE* stream) const;
|
||||
|
||||
protected:
|
||||
@@ -597,6 +612,9 @@ protected:
|
||||
std::vector<std::shared_ptr<Enemy>> enemies;
|
||||
std::vector<std::shared_ptr<Enemy>> enemy_sets;
|
||||
std::vector<std::shared_ptr<Event>> events;
|
||||
std::unordered_map<uint64_t, std::vector<std::shared_ptr<Object>>> objects_for_semantic_hash;
|
||||
std::unordered_map<uint64_t, std::vector<std::shared_ptr<Enemy>>> enemy_sets_for_semantic_hash;
|
||||
std::unordered_map<uint64_t, std::vector<std::shared_ptr<Event>>> events_for_semantic_hash;
|
||||
std::array<EntitiesForVersion, NUM_VERSIONS> entities_for_version;
|
||||
|
||||
std::shared_ptr<Object> add_object(Version version, uint8_t floor, const MapFile::ObjectSetEntry* set_entry);
|
||||
|
||||
Reference in New Issue
Block a user