add information about Ep3 camera and AI data in map files

This commit is contained in:
Martin Michelsen
2023-09-18 00:20:49 -07:00
parent 8952a4d56b
commit 83ecbf77ab
3 changed files with 127 additions and 84 deletions
+51 -52
View File
@@ -1359,12 +1359,26 @@ void StateFlags::clear_FF() {
this->client_sc_card_types.clear(CardType::INVALID_FF);
}
string MapDefinition::CameraSpec::str() const {
return string_printf(
"CameraSpec[a1=(%g %g %g %g %g %g %g %g %g) camera=(%g %g %g) focus=(%g %g %g) a2=(%g %g %g)]",
this->unknown_a1[0].load(), this->unknown_a1[1].load(),
this->unknown_a1[2].load(), this->unknown_a1[3].load(),
this->unknown_a1[4].load(), this->unknown_a1[5].load(),
this->unknown_a1[6].load(), this->unknown_a1[7].load(),
this->unknown_a1[8].load(), this->camera_x.load(),
this->camera_y.load(), this->camera_z.load(),
this->focus_x.load(), this->focus_y.load(),
this->focus_z.load(), this->unknown_a2[0].load(),
this->unknown_a2[1].load(), this->unknown_a2[2].load());
}
string MapDefinition::str(const CardIndex* card_index) const {
deque<string> lines;
auto add_map = [&](const parray<parray<uint8_t, 0x10>, 0x10>& tiles) {
for (size_t y = 0; y < 0x10; y++) {
for (size_t y = 0; y < this->height; y++) {
string line = " ";
for (size_t x = 0; x < 0x10; x++) {
for (size_t x = 0; x < this->height; x++) {
line += string_printf(" %02hhX", tiles[y][x]);
}
lines.emplace_back(std::move(line));
@@ -1375,7 +1389,7 @@ string MapDefinition::str(const CardIndex* card_index) const {
this->map_number.load(), this->width, this->height));
lines.emplace_back(string_printf(" a1=%08" PRIX32, this->unknown_a1.load()));
lines.emplace_back(string_printf(" environment_number=%02hhX", this->environment_number));
lines.emplace_back(string_printf(" num_alt_maps=%02hhX", this->num_alt_maps));
lines.emplace_back(string_printf(" num_camera_zones=%02hhX", this->num_camera_zones));
lines.emplace_back(" tiles:");
add_map(this->map_tiles);
lines.emplace_back(string_printf(
@@ -1386,32 +1400,19 @@ string MapDefinition::str(const CardIndex* card_index) const {
this->start_tile_definitions[1][0], this->start_tile_definitions[1][1],
this->start_tile_definitions[1][2], this->start_tile_definitions[1][3],
this->start_tile_definitions[1][4], this->start_tile_definitions[1][5]));
for (size_t z = 0; z < this->num_alt_maps; z++) {
for (size_t z = 0; z < this->num_camera_zones; z++) {
for (size_t w = 0; w < 2; w++) {
lines.emplace_back(string_printf(" alt tiles %zu/%zu:", z, w));
add_map(this->alt_maps1[w][z]);
lines.emplace_back(string_printf(" camera zone %zu (team %zu):", z, w));
add_map(this->camera_zone_maps[w][z]);
}
for (size_t w = 0; w < 2; w++) {
lines.emplace_back(string_printf(
" alt tiles a3 %zu/%zu=%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", z, w,
this->alt_maps_unknown_a3[w][z][0x00].load(), this->alt_maps_unknown_a3[w][z][0x01].load(),
this->alt_maps_unknown_a3[w][z][0x02].load(), this->alt_maps_unknown_a3[w][z][0x03].load(),
this->alt_maps_unknown_a3[w][z][0x04].load(), this->alt_maps_unknown_a3[w][z][0x05].load(),
this->alt_maps_unknown_a3[w][z][0x06].load(), this->alt_maps_unknown_a3[w][z][0x07].load(),
this->alt_maps_unknown_a3[w][z][0x08].load(), this->alt_maps_unknown_a3[w][z][0x09].load(),
this->alt_maps_unknown_a3[w][z][0x0A].load(), this->alt_maps_unknown_a3[w][z][0x0B].load(),
this->alt_maps_unknown_a3[w][z][0x0C].load(), this->alt_maps_unknown_a3[w][z][0x0D].load(),
this->alt_maps_unknown_a3[w][z][0x0E].load(), this->alt_maps_unknown_a3[w][z][0x0F].load(),
this->alt_maps_unknown_a3[w][z][0x10].load(), this->alt_maps_unknown_a3[w][z][0x11].load()));
lines.emplace_back(" " + this->camera_zone_specs[w][z].str());
}
}
for (size_t w = 0; w < 3; w++) {
for (size_t z = 0; z < 0x24; z += 3) {
lines.emplace_back(string_printf(
" a4[%zu][0x%02zX:0x%02zX]=%g %g %g", w, z, z + 3,
this->unknown_a4[w][z + 0].load(),
this->unknown_a4[w][z + 1].load(),
this->unknown_a4[w][z + 2].load()));
for (size_t z = 0; z < 2; z++) {
string spec_str = this->overview_specs[w][z].str();
lines.emplace_back(string_printf(" overview_specs[%zu][team %zu]=%s", w, z, spec_str.c_str()));
}
}
lines.emplace_back(" modification tiles:");
@@ -1438,28 +1439,26 @@ string MapDefinition::str(const CardIndex* card_index) const {
lines.emplace_back(string_printf(" map_xy: %hu %hu", this->map_x.load(), this->map_y.load()));
for (size_t z = 0; z < 3; z++) {
lines.emplace_back(string_printf(" npc_chars[%zu]:", z));
lines.emplace_back(" name: " + string(this->npc_ai_params[z].name));
lines.emplace_back(string_printf(
" a1=%04hX %04hX",
this->npc_chars[z].unknown_a1[0].load(), this->npc_chars[z].unknown_a1[1].load()));
lines.emplace_back(string_printf(
" a2=%02hX %02hX %02hX %02hX",
this->npc_chars[z].unknown_a2[0], this->npc_chars[z].unknown_a2[1],
this->npc_chars[z].unknown_a2[2], this->npc_chars[z].unknown_a2[3]));
lines.emplace_back(" name: " + string(this->npc_chars[z].name));
" ai_params=(a1=%04hX %04hX, is_arkz=%02hhX, a2=%02hX %02hX %02hX)",
this->npc_ai_params[z].unknown_a1[0].load(), this->npc_ai_params[z].unknown_a1[1].load(),
this->npc_ai_params[z].is_arkz, this->npc_ai_params[z].unknown_a2[0],
this->npc_ai_params[z].unknown_a2[1], this->npc_ai_params[z].unknown_a2[2]));
for (size_t w = 0; w < 0x78; w += 0x08) {
lines.emplace_back(string_printf(
" a3[0x%02zX:0x%02zX]=%04hX %04hX %04hX %04hX %04hX %04hX %04hX %04hX",
" ai_params.a3[0x%02zX:0x%02zX]=%04hX %04hX %04hX %04hX %04hX %04hX %04hX %04hX",
w, w + 0x08,
this->npc_chars[z].unknown_a3[w + 0x00].load(), this->npc_chars[z].unknown_a3[w + 0x01].load(),
this->npc_chars[z].unknown_a3[w + 0x02].load(), this->npc_chars[z].unknown_a3[w + 0x03].load(),
this->npc_chars[z].unknown_a3[w + 0x04].load(), this->npc_chars[z].unknown_a3[w + 0x05].load(),
this->npc_chars[z].unknown_a3[w + 0x06].load(), this->npc_chars[z].unknown_a3[w + 0x07].load()));
this->npc_ai_params[z].params[w + 0x00].load(), this->npc_ai_params[z].params[w + 0x01].load(),
this->npc_ai_params[z].params[w + 0x02].load(), this->npc_ai_params[z].params[w + 0x03].load(),
this->npc_ai_params[z].params[w + 0x04].load(), this->npc_ai_params[z].params[w + 0x05].load(),
this->npc_ai_params[z].params[w + 0x06].load(), this->npc_ai_params[z].params[w + 0x07].load()));
}
lines.emplace_back(string_printf(
" a3[0x78:0x7E]=%04hX %04hX %04hX %04hX %04hX %04hX",
this->npc_chars[z].unknown_a3[0x78].load(), this->npc_chars[z].unknown_a3[0x79].load(),
this->npc_chars[z].unknown_a3[0x7A].load(), this->npc_chars[z].unknown_a3[0x7B].load(),
this->npc_chars[z].unknown_a3[0x7C].load(), this->npc_chars[z].unknown_a3[0x7D].load()));
" ai_params.a3[0x78:0x7E]=%04hX %04hX %04hX %04hX %04hX %04hX",
this->npc_ai_params[z].params[0x78].load(), this->npc_ai_params[z].params[0x79].load(),
this->npc_ai_params[z].params[0x7A].load(), this->npc_ai_params[z].params[0x7B].load(),
this->npc_ai_params[z].params[0x7C].load(), this->npc_ai_params[z].params[0x7D].load()));
lines.emplace_back(string_printf(" npc_decks[%zu]:", z));
lines.emplace_back(" name: " + string(this->npc_decks[z].name));
for (size_t w = 0; w < 0x20; w++) {
@@ -1490,9 +1489,9 @@ string MapDefinition::str(const CardIndex* card_index) const {
}
}
}
lines.emplace_back(" a7a=" + format_data_string(this->unknown_a7_a.data(), this->unknown_a7_a.bytes()));
lines.emplace_back(string_printf(" a7b=[%08" PRIX32 " %08" PRIX32 " %08" PRIX32 "]",
this->unknown_a7_b[0].load(), this->unknown_a7_b[1].load(), this->unknown_a7_b[2].load()));
lines.emplace_back(" a7=" + format_data_string(this->unknown_a7.data(), this->unknown_a7.bytes()));
lines.emplace_back(string_printf(" npc_ai_params_entry_index=[%08" PRIX32 " %08" PRIX32 " %08" PRIX32 "]",
this->npc_ai_params_entry_index[0].load(), this->npc_ai_params_entry_index[1].load(), this->npc_ai_params_entry_index[2].load()));
if (this->before_message[0]) {
lines.emplace_back(" before_message: " + string(this->before_message));
}
@@ -1520,7 +1519,7 @@ string MapDefinition::str(const CardIndex* card_index) const {
}
lines.emplace_back(string_printf(" level_overrides=[win=%" PRId32 ", loss=%" PRId32 "]",
this->win_level_override.load(), this->loss_level_override.load()));
lines.emplace_back(string_printf(" a9=[%04hX %04hX]", this->unknown_a9_c.load(), this->unknown_a9_d.load()));
lines.emplace_back(string_printf(" field_offset=(x: %hd units, y:%hd units) (x: %lg tiles, y: %lg tiles)", this->field_offset_x.load(), this->field_offset_y.load(), static_cast<double>(this->field_offset_x) / 25.0, static_cast<double>(this->field_offset_y) / 25.0));
lines.emplace_back(string_printf(" map_category=%02hhX", this->map_category));
lines.emplace_back(string_printf(" cyber_block_type=%02hhX", this->cyber_block_type));
lines.emplace_back(string_printf(" a11=%02hhX%02hhX", this->unknown_a11[0], this->unknown_a11[1]));
@@ -1618,12 +1617,12 @@ MapDefinitionTrial::MapDefinitionTrial(const MapDefinition& map)
width(map.width),
height(map.height),
environment_number(map.environment_number),
num_alt_maps(map.num_alt_maps),
num_camera_zones(map.num_camera_zones),
map_tiles(map.map_tiles),
start_tile_definitions(map.start_tile_definitions),
alt_maps1(map.alt_maps1),
alt_maps_unknown_a3(map.alt_maps_unknown_a3),
unknown_a4(map.unknown_a4),
camera_zone_maps(map.camera_zone_maps),
camera_zone_specs(map.camera_zone_specs),
overview_specs(map.overview_specs),
modification_tiles(map.modification_tiles),
unknown_a5(map.unknown_a5),
default_rules(map.default_rules),
@@ -1635,9 +1634,9 @@ MapDefinitionTrial::MapDefinitionTrial(const MapDefinition& map)
map_x(map.map_x),
map_y(map.map_y),
npc_decks(map.npc_decks),
npc_chars(map.npc_chars),
unknown_a7_a(map.unknown_a7_a),
unknown_a7_b(map.unknown_a7_b),
npc_ai_params(map.npc_ai_params),
unknown_a7(map.unknown_a7),
npc_ai_params_entry_index(map.npc_ai_params_entry_index),
before_message(map.before_message),
after_message(map.after_message),
dispatch_message(map.dispatch_message),
@@ -1645,8 +1644,8 @@ MapDefinitionTrial::MapDefinitionTrial(const MapDefinition& map)
reward_card_ids(map.reward_card_ids),
win_level_override(map.win_level_override),
loss_level_override(map.loss_level_override),
unknown_a9_c(map.unknown_a9_c),
unknown_a9_d(map.unknown_a9_d),
field_offset_x(map.field_offset_x),
field_offset_y(map.field_offset_y),
map_category(map.map_category),
cyber_block_type(map.cyber_block_type),
unknown_a11(map.unknown_a11),
+76 -32
View File
@@ -864,7 +864,7 @@ struct CompressedMapHeader { // .mnm file format
} __attribute__((packed));
struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
/* 0000 */ be_uint32_t unknown_a1;
/* 0000 */ be_uint32_t unknown_a1; // Should be 0x00000100
/* 0004 */ be_uint32_t map_number; // Must be unique across all maps
/* 0008 */ uint8_t width;
/* 0009 */ uint8_t height;
@@ -909,10 +909,8 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
// TCard00_Select is accessible on newserv with the $ep3battledebug command.
/* 000A */ uint8_t environment_number;
// All alt_maps fields (including the floats) past num_alt_maps are filled in
// with FF. For example, if num_alt_maps == 8, the last two fields in each
// alt_maps array are filled with FF.
/* 000B */ uint8_t num_alt_maps; // TODO: What are the alt maps for?
// This field specifies how many of the camera_zone_maps are used.
/* 000B */ uint8_t num_camera_zones;
// In the map_tiles array, the values are usually:
// 00 = not a valid tile (blocked)
@@ -936,9 +934,44 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
// - If the team has 3 players, bytes [3] through [5] are used.
/* 010C */ parray<parray<uint8_t, 6>, 2> start_tile_definitions;
/* 0118 */ parray<parray<parray<parray<uint8_t, 0x10>, 0x10>, 0x0A>, 2> alt_maps1;
/* 1518 */ parray<parray<parray<be_float, 0x12>, 0x0A>, 2> alt_maps_unknown_a3;
/* 1AB8 */ parray<parray<be_float, 0x24>, 3> unknown_a4;
struct CameraSpec {
parray<be_float, 9> unknown_a1;
be_float camera_x;
be_float camera_y;
be_float camera_z;
// It appears that the camera always aligns its +Y raster axis with +Y in
// the virtual world. If the focus point is directly beneath the camera
// point, the logic for deciding which direction should be "up" from the
// camera's perspective can get confused and jitter back and forth as the
// camera moves into position.
be_float focus_x;
be_float focus_y;
be_float focus_z;
parray<be_float, 3> unknown_a2;
std::string str() const;
} __attribute__((packed));
// This array specifies the camera zone maps. A camera zone map is a subset of
// the main map (specified in map_tiles). Tiles that are part of each camera
// zone are 1 in these arrays; all other tiles are 0. The game evaluates each
// camera zone in order; if all SCs and FCs are within a particular camera
// zone, then the corresponding camera location is used as the default camera
// location. If the player doesn't move the camera with the C stick, then the
// camera zones are evaluated continuously during the battle, and the camera
// will move to focus on the part of the field where the SCs/FCs are. (Or,
// more accurately, where the corresponding entry in camera_zone_specs says
// to focus.) camera_zone_maps is indexed as [team_id][camera_zone_num][x][y];
// camera_zone_specs is indexed as [team_id][camera_zone_num]. Unused entries
// (beyond num_camera_zones) in both arrays should be filled with FF bytes.
/* 0118 */ parray<parray<parray<parray<uint8_t, 0x10>, 0x10>, 10>, 2> camera_zone_maps;
/* 1518 */ parray<parray<CameraSpec, 10>, 2> camera_zone_specs;
// These camera specs are used in the Move phase, when the player has chosen
// an SC or FC to move, or when the player presses Start/Z. Normally these are
// defined such that the camera is placed high above the map, giving an
// overhead view of the entire playfield. This is indexed as [???][team_id]
// (it is not yet known what the major index represents).
/* 1AB8 */ parray<parray<CameraSpec, 2>, 3> overview_specs;
// In the modification_tiles array, the values are:
// 10 = blocked by rock (as if the corresponding map_tiles value was 00)
@@ -971,17 +1004,26 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
} __attribute__((packed));
/* 1FE8 */ parray<NPCDeck, 3> npc_decks; // Unused if name[0] == 0
struct NPCCharacter {
// These are almost (but not quite) the same format as the entries in
// aiprm.dat. Unlike in that file, the name field is relevant here (and is
// shown to the player).
struct AIParams {
/* 0000 */ parray<be_uint16_t, 2> unknown_a1;
/* 0004 */ parray<uint8_t, 4> unknown_a2;
/* 0004 */ uint8_t is_arkz;
/* 0005 */ parray<uint8_t, 3> unknown_a2;
/* 0008 */ ptext<char, 0x10> name;
/* 0018 */ parray<be_uint16_t, 0x7E> unknown_a3;
// TODO: Figure out exactly how these are used and document here.
/* 0018 */ parray<be_uint16_t, 0x7E> params;
/* 0114 */
} __attribute__((packed));
/* 20F0 */ parray<NPCCharacter, 3> npc_chars; // Unused if name[0] == 0
/* 20F0 */ parray<AIParams, 3> npc_ai_params; // Unused if name[0] == 0
/* 242C */ parray<uint8_t, 8> unknown_a7_a; // Always FF?
/* 2434 */ parray<be_uint32_t, 3> unknown_a7_b; // Always FF?
/* 242C */ parray<uint8_t, 8> unknown_a7; // Always FF?
// This array specifies which set of AI parameters to use from aiprm.dat. If
// it's -1, then the corresponding NPC's AI parameters are defined in the
// NPCCharacter structure above.
/* 2434 */ parray<be_int32_t, 3> npc_ai_params_entry_index;
// In story mode, before_message appears before the battle if it's not blank;
// in free battle and online mode, before_message is ignored. after_message
@@ -1010,14 +1052,16 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
/* 59D0 */ be_int32_t win_level_override;
/* 59D4 */ be_int32_t loss_level_override;
/* 59D8 */ be_uint16_t unknown_a9_c;
/* 59DA */ be_uint16_t unknown_a9_d;
// These fields specify where the battlefield should appear relative to the
// center of the environment. THe size of one tile on the field is 25 units
// in these fields.
/* 59D8 */ be_int16_t field_offset_x;
/* 59DA */ be_int16_t field_offset_y;
// map_category specifies where in the menu the map should appear in the maps
// menu. If this is FF, the map appears in the Free Battle section; if it's a
// small number (usually 0 or 2), the map appears in the Quest section
// instead. It's not known if this controls anything else; the values 0, 1,
// and 2 appear to all do the same thing here.
// map_category specifies where the map should appear in the maps menu. If
// this is 0, 1, or 2, the map appears in the Quest section; otherwise, it
// appears in the Free Battle section instead. It's not known if this controls
// anything else.
/* 59DC */ uint8_t map_category;
// This field determines block graphics to be used in the Cyber environment.
@@ -1087,12 +1131,12 @@ struct MapDefinitionTrial {
/* 0008 */ uint8_t width;
/* 0009 */ uint8_t height;
/* 000A */ uint8_t environment_number;
/* 000B */ uint8_t num_alt_maps;
/* 000B */ uint8_t num_camera_zones;
/* 000C */ parray<parray<uint8_t, 0x10>, 0x10> map_tiles;
/* 010C */ parray<parray<uint8_t, 6>, 2> start_tile_definitions;
/* 0118 */ parray<parray<parray<parray<uint8_t, 0x10>, 0x10>, 0x0A>, 2> alt_maps1;
/* 1518 */ parray<parray<parray<be_float, 0x12>, 0x0A>, 2> alt_maps_unknown_a3;
/* 1AB8 */ parray<parray<be_float, 0x24>, 3> unknown_a4;
/* 0118 */ parray<parray<parray<parray<uint8_t, 0x10>, 0x10>, 10>, 2> camera_zone_maps;
/* 1518 */ parray<parray<MapDefinition::CameraSpec, 10>, 2> camera_zone_specs;
/* 1AB8 */ parray<parray<MapDefinition::CameraSpec, 2>, 3> overview_specs;
/* 1C68 */ parray<parray<uint8_t, 0x10>, 0x10> modification_tiles;
/* 1D68 */ parray<uint8_t, 0x6C> unknown_a5;
/* 1DD4 */ Rules default_rules;
@@ -1104,18 +1148,18 @@ struct MapDefinitionTrial {
/* 1FDC */ be_uint16_t map_x;
/* 1FDE */ be_uint16_t map_y;
/* 1FE0 */ parray<MapDefinition::NPCDeck, 3> npc_decks;
/* 20E8 */ parray<MapDefinition::NPCCharacter, 3> npc_chars;
/* 2424 */ parray<uint8_t, 8> unknown_a7_a;
/* 242C */ parray<be_uint32_t, 3> unknown_a7_b;
/* 20E8 */ parray<MapDefinition::AIParams, 3> npc_ai_params;
/* 2424 */ parray<uint8_t, 8> unknown_a7;
/* 242C */ parray<be_int32_t, 3> npc_ai_params_entry_index;
/* 2438 */ ptext<char, 0x190> before_message;
/* 25C8 */ ptext<char, 0x190> after_message;
/* 2758 */ ptext<char, 0x190> dispatch_message;
/* 28E8 */ parray<parray<MapDefinition::DialogueSet, 8>, 3> dialogue_sets;
/* 4148 */ parray<be_uint16_t, 0x10> reward_card_ids;
/* 4168 */ be_uint32_t win_level_override;
/* 416C */ be_uint32_t loss_level_override;
/* 4170 */ be_uint16_t unknown_a9_c;
/* 4172 */ be_uint16_t unknown_a9_d;
/* 4168 */ be_int32_t win_level_override;
/* 416C */ be_int32_t loss_level_override;
/* 4170 */ be_int16_t field_offset_x;
/* 4172 */ be_int16_t field_offset_y;
/* 4174 */ uint8_t map_category;
/* 4175 */ uint8_t cyber_block_type;
/* 4176 */ parray<uint8_t, 2> unknown_a11;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB