add action for debugging random enemy sections

This commit is contained in:
Martin Michelsen
2025-12-11 00:20:39 -08:00
parent 8953ffc2b5
commit 342b4df8c4
3 changed files with 29 additions and 11 deletions
+15
View File
@@ -3064,6 +3064,21 @@ Action a_check_supermaps(
phosg::fwrite_fmt(stderr, "ALL QUEST MAPS: {}\n", all_quests_eff_str); phosg::fwrite_fmt(stderr, "ALL QUEST MAPS: {}\n", all_quests_eff_str);
}); });
Action a_materialize_map(
"materialize-map", nullptr,
+[](phosg::Arguments& args) {
if (args.get<bool>("debug")) {
static_game_data_log.min_level = phosg::LogLevel::L_DEBUG;
}
auto map_data = make_shared<string>(prs_decompress(read_input_data(args)));
auto map_file = make_shared<MapFile>(map_data);
uint32_t seed = args.get<uint32_t>("seed", phosg::Arguments::IntFormat::HEX);
Version version = get_cli_version(args);
auto materialized = map_file->materialize_random_sections(seed);
auto disassembly = materialized->disassemble(false, version);
write_output_data(args, disassembly.data(), disassembly.size(), "txt");
});
Action a_print_free_supermap( Action a_print_free_supermap(
"print-free-supermap", "\ "print-free-supermap", "\
print-free-supermap [--psov2] [--seed=SEED] [--episode=1|2|4]\n\ print-free-supermap [--psov2] [--seed=SEED] [--episode=1|2|4]\n\
+9 -7
View File
@@ -3345,7 +3345,7 @@ string MapFile::RandomEnemyLocation::str() const {
} }
string MapFile::RandomEnemyDefinition::str() const { string MapFile::RandomEnemyDefinition::str() const {
return std::format("[RandomEnemyDefinition params=[{:g} {:g} {:g} {:g} {:g} {:04X} {:04X}] entry_num={:08X} min_children={:04X} max_children={:04X}]", return std::format("[RandomEnemyDefinition params=[{:g} {:g} {:g} {:g} {:g} {:04X} {:04X}] entry_index={:08X} min_children={:04X} max_children={:04X}]",
this->param1, this->param1,
this->param2, this->param2,
this->param3, this->param3,
@@ -3353,7 +3353,7 @@ string MapFile::RandomEnemyDefinition::str() const {
this->param5, this->param5,
this->param6, this->param6,
this->param7, this->param7,
this->entry_num, this->entry_index,
this->min_children, this->min_children,
this->max_children); this->max_children);
} }
@@ -3364,10 +3364,10 @@ string MapFile::RandomEnemyWeight::str() const {
base_type_index_str = std::format("(->{:04X})", MapFile::RAND_ENEMY_BASE_TYPES.at(this->base_type_index)); base_type_index_str = std::format("(->{:04X})", MapFile::RAND_ENEMY_BASE_TYPES.at(this->base_type_index));
} catch (const std::out_of_range&) { } catch (const std::out_of_range&) {
} }
return std::format("[RandomEnemyWeight base_type_index={:02X}{} def_entry_num={} weight={:02X} a4={:02X}]", return std::format("[RandomEnemyWeight base_type_index={:02X}{} def_entry_index={} weight={:02X} a4={:02X}]",
this->base_type_index, this->base_type_index,
base_type_index_str, base_type_index_str,
this->def_entry_num, this->def_entry_index,
this->weight, this->weight,
this->unknown_a4); this->unknown_a4);
} }
@@ -3735,7 +3735,7 @@ std::shared_ptr<MapFile> MapFile::materialize_random_sections(uint32_t random_se
if (det < weight_entry.weight) { if (det < weight_entry.weight) {
static_game_data_log.debug_f("(Floor {} event {} wave {} enemy {}) This results in weight entry {}", static_game_data_log.debug_f("(Floor {} event {} wave {} enemy {}) This results in weight entry {}",
floor, source_event_index, remaining_waves, remaining_enemies, weight_entry.str()); floor, source_event_index, remaining_waves, remaining_enemies, weight_entry.str());
if ((weight_entry.base_type_index != 0xFF) && (weight_entry.def_entry_num != 0xFF)) { if ((weight_entry.base_type_index != 0xFF) && (weight_entry.def_entry_index != 0xFF)) {
if (definitions_header.entry_count == 0) { if (definitions_header.entry_count == 0) {
throw runtime_error("no available random enemy definitions"); throw runtime_error("no available random enemy definitions");
} }
@@ -3750,7 +3750,7 @@ std::shared_ptr<MapFile> MapFile::materialize_random_sections(uint32_t random_se
size_t bs_max = definitions_header.entry_count - 1; size_t bs_max = definitions_header.entry_count - 1;
do { do {
size_t bs_mid = (bs_min + bs_max) / 2; size_t bs_mid = (bs_min + bs_max) / 2;
if (definitions_r.pget<RandomEnemyDefinition>(bs_mid * sizeof(RandomEnemyDefinition)).entry_num < weight_entry.def_entry_num) { if (definitions_r.pget<RandomEnemyDefinition>(bs_mid * sizeof(RandomEnemyDefinition)).entry_index < weight_entry.def_entry_index) {
bs_min = bs_mid + 1; bs_min = bs_mid + 1;
} else { } else {
bs_max = bs_mid; bs_max = bs_mid;
@@ -3758,7 +3758,7 @@ std::shared_ptr<MapFile> MapFile::materialize_random_sections(uint32_t random_se
} while (bs_min < bs_max); } while (bs_min < bs_max);
const auto& def = definitions_r.pget<RandomEnemyDefinition>(bs_min * sizeof(RandomEnemyDefinition)); const auto& def = definitions_r.pget<RandomEnemyDefinition>(bs_min * sizeof(RandomEnemyDefinition));
if (def.entry_num == weight_entry.def_entry_num) { if (def.entry_index == weight_entry.def_entry_index) {
static_game_data_log.debug_f("(Floor {} event {} wave {} enemy {}) Using parameters from {}", static_game_data_log.debug_f("(Floor {} event {} wave {} enemy {}) Using parameters from {}",
floor, source_event_index, remaining_waves, remaining_enemies, def.str()); floor, source_event_index, remaining_waves, remaining_enemies, def.str());
e.param1 = def.param1; e.param1 = def.param1;
@@ -3768,6 +3768,8 @@ std::shared_ptr<MapFile> MapFile::materialize_random_sections(uint32_t random_se
e.param5 = def.param5; e.param5 = def.param5;
e.param6 = def.param6; e.param6 = def.param6;
e.param7 = def.param7; e.param7 = def.param7;
// Note: The original code calls this with (min_children, max_children + 1); we add 1 inside the
// function instead, which is functionally equivalent.
e.num_children = random_state.rand_int_biased(def.min_children, def.max_children); e.num_children = random_state.rand_int_biased(def.min_children, def.max_children);
} else { } else {
throw runtime_error("random enemy definition not found"); throw runtime_error("random enemy definition not found");
+5 -4
View File
@@ -337,8 +337,8 @@ public:
} __packed_ws__(RandomEnemyDefinitionsHeader, 0x10); } __packed_ws__(RandomEnemyDefinitionsHeader, 0x10);
struct RandomEnemyDefinition { // Section type 5 (RANDOM_ENEMY_DEFINITIONS) struct RandomEnemyDefinition { // Section type 5 (RANDOM_ENEMY_DEFINITIONS)
// All fields through entry_num map to the corresponding fields in EnemySetEntry. Note that the order of param6 and // All fields through entry_index map to the corresponding fields in EnemySetEntry. Note that the order of param6
// param7 is switched! // and param7 is switched!
/* 00 */ le_float param1; /* 00 */ le_float param1;
/* 04 */ le_float param2; /* 04 */ le_float param2;
/* 08 */ le_float param3; /* 08 */ le_float param3;
@@ -346,7 +346,8 @@ public:
/* 10 */ le_float param5; /* 10 */ le_float param5;
/* 14 */ le_int16_t param7; /* 14 */ le_int16_t param7;
/* 16 */ le_int16_t param6; /* 16 */ le_int16_t param6;
/* 18 */ le_uint32_t entry_num; /* 18 */ le_uint16_t entry_index;
/* 1A */ le_uint16_t unknown_a1;
/* 1C */ le_uint16_t min_children; /* 1C */ le_uint16_t min_children;
/* 1E */ le_uint16_t max_children; /* 1E */ le_uint16_t max_children;
/* 20 */ /* 20 */
@@ -356,7 +357,7 @@ public:
struct RandomEnemyWeight { // Section type 5 (RANDOM_ENEMY_DEFINITIONS) struct RandomEnemyWeight { // Section type 5 (RANDOM_ENEMY_DEFINITIONS)
/* 00 */ uint8_t base_type_index; /* 00 */ uint8_t base_type_index;
/* 01 */ uint8_t def_entry_num; /* 01 */ uint8_t def_entry_index;
/* 02 */ uint8_t weight; /* 02 */ uint8_t weight;
/* 03 */ uint8_t unknown_a4; /* 03 */ uint8_t unknown_a4;
/* 04 */ /* 04 */