diff --git a/src/BattleParamsIndex.cc b/src/BattleParamsIndex.cc index 05020b5c..8d97d08b 100644 --- a/src/BattleParamsIndex.cc +++ b/src/BattleParamsIndex.cc @@ -9,10 +9,9 @@ using namespace std; -string BattleParamsIndex::Entry::str() const { - string a1str = format_data_string(this->unknown_a1.data(), this->unknown_a1.bytes()); +string BattleParamsIndex::PhysicalData::str() const { return string_printf( - "BattleParamsEntry[ATP=%hu PSV=%hu EVP=%hu HP=%hu DFP=%hu ATA=%hu LCK=%hu ESP=%hu a1=%s EXP=%" PRIu32 " diff=%" PRIu32 "]", + "PhysicalData[ATP=%hu PSV=%hu EVP=%hu HP=%hu DFP=%hu ATA=%hu LCK=%hu ESP=%hu a1=[%g, %g] a2=%" PRIu32 " EXP=%" PRIu32 " diff=%" PRIu32 "]", this->atp.load(), this->psv.load(), this->evp.load(), @@ -21,16 +20,17 @@ string BattleParamsIndex::Entry::str() const { this->ata.load(), this->lck.load(), this->esp.load(), - a1str.c_str(), + this->unknown_a1[0].load(), + this->unknown_a1[1].load(), + this->unknown_a2.load(), this->experience.load(), this->difficulty.load()); } void BattleParamsIndex::Table::print(FILE* stream) const { - auto print_entry = +[](FILE* stream, const Entry& e) { - string a1str = format_data_string(e.unknown_a1.data(), e.unknown_a1.bytes()); + auto print_entry = +[](FILE* stream, const PhysicalData& e) { fprintf(stream, - "%5hu %5hu %5hu %5hu %5hu %5hu %5hu %5hu %s %5" PRIu32 " %5" PRIu32, + "%5hu %5hu %5hu %5hu %5hu %5hu %5hu %5hu %5" PRIu32 " %5" PRIu32, e.atp.load(), e.psv.load(), e.evp.load(), @@ -39,17 +39,16 @@ void BattleParamsIndex::Table::print(FILE* stream) const { e.ata.load(), e.lck.load(), e.esp.load(), - a1str.c_str(), e.experience.load(), e.difficulty.load()); }; for (size_t diff = 0; diff < 4; diff++) { - fprintf(stream, "%c ZZ ATP PSV EVP HP DFP ATA LCK ESP A1 EXP DIFF\n", + fprintf(stream, "%c ZZ ATP PSV EVP HP DFP ATA LCK ESP EXP DIFF\n", abbreviation_for_difficulty(diff)); for (size_t z = 0; z < 0x60; z++) { fprintf(stream, " %02zX ", z); - print_entry(stream, this->difficulty[diff][z]); + print_entry(stream, this->physical_data[diff][z]); fputc('\n', stream); } } @@ -82,20 +81,7 @@ BattleParamsIndex::BattleParamsIndex( } } -const BattleParamsIndex::Entry& BattleParamsIndex::get( - bool solo, Episode episode, uint8_t difficulty, EnemyType type) const { - return this->get(solo, episode, difficulty, battle_param_index_for_enemy_type(episode, type)); -} - -const BattleParamsIndex::Entry& BattleParamsIndex::get( - bool solo, Episode episode, uint8_t difficulty, size_t index) const { - if (difficulty > 4) { - throw invalid_argument("incorrect difficulty"); - } - if (index >= 0x60) { - throw invalid_argument("incorrect monster type"); - } - +const BattleParamsIndex::Table& BattleParamsIndex::get_table(bool solo, Episode episode) const { uint8_t ep_index; switch (episode) { case Episode::EP1: @@ -111,5 +97,5 @@ const BattleParamsIndex::Entry& BattleParamsIndex::get( throw invalid_argument("invalid episode"); } - return this->files[!!solo][ep_index].table->difficulty[difficulty][index]; + return *this->files[!!solo][ep_index].table; } diff --git a/src/BattleParamsIndex.hh b/src/BattleParamsIndex.hh index c950ef6c..5ccdef79 100644 --- a/src/BattleParamsIndex.hh +++ b/src/BattleParamsIndex.hh @@ -14,24 +14,83 @@ class BattleParamsIndex { public: - struct Entry { - le_uint16_t atp; - le_uint16_t psv; // Perseverance (intelligence?) - le_uint16_t evp; - le_uint16_t hp; - le_uint16_t dfp; - le_uint16_t ata; - le_uint16_t lck; - le_uint16_t esp; // Unknown - parray unknown_a1; - le_uint32_t experience; - le_uint32_t difficulty; + // These files are little-endian, even on PSO GC. + + struct PhysicalData { + /* 00 */ le_uint16_t atp; + /* 02 */ le_uint16_t psv; // Perseverance (intelligence?) + /* 04 */ le_uint16_t evp; + /* 06 */ le_uint16_t hp; + /* 08 */ le_uint16_t dfp; + /* 0A */ le_uint16_t ata; + /* 0C */ le_uint16_t lck; + /* 0E */ le_uint16_t esp; // Unknown + /* 10 */ parray unknown_a1; + /* 18 */ le_uint32_t unknown_a2; + /* 1C */ le_uint32_t experience; + /* 20 */ le_uint32_t difficulty; + /* 24 */ std::string str() const; } __attribute__((packed)); + struct AttackData { + /* 00 */ le_int16_t unknown_a1; + /* 02 */ le_int16_t unknown_a2; + /* 04 */ le_uint16_t unknown_a3; + /* 06 */ le_uint16_t unknown_a4; + /* 08 */ le_float distance_x; + /* 0C */ le_float angle_x; + /* 10 */ le_float distance_y; + /* 14 */ le_uint16_t unknown_a8; + /* 16 */ le_uint16_t unknown_a9; + /* 18 */ le_uint16_t unknown_a10; + /* 1A */ le_uint16_t unknown_a11; + /* 1C */ le_uint32_t unknown_a12; + /* 20 */ le_uint32_t unknown_a13; + /* 24 */ le_uint32_t unknown_a14; + /* 28 */ le_uint32_t unknown_a15; + /* 2C */ le_uint32_t unknown_a16; + /* 30 */ + } __attribute__((packed)); + + struct ResistData { + /* 00 */ le_int16_t evp_bonus; + /* 02 */ le_uint16_t efr; + /* 04 */ le_uint16_t eic; + /* 06 */ le_uint16_t eth; + /* 08 */ le_uint16_t elt; + /* 0A */ le_uint16_t edk; + /* 0C */ le_uint32_t unknown_a6; + /* 10 */ le_uint32_t unknown_a7; + /* 14 */ le_uint32_t unknown_a8; + /* 18 */ le_uint32_t unknown_a9; + /* 1C */ le_int32_t dfp_bonus; + /* 20 */ + } __attribute__((packed)); + + struct MovementData { + /* 00 */ le_float idle_move_speed; + /* 04 */ le_float idle_animation_speed; + /* 08 */ le_float move_speed; + /* 0C */ le_float animation_speed; + /* 10 */ le_float unknown_a1; + /* 14 */ le_float unknown_a2; + /* 18 */ le_uint32_t unknown_a3; + /* 1C */ le_uint32_t unknown_a4; + /* 20 */ le_uint32_t unknown_a5; + /* 24 */ le_uint32_t unknown_a6; + /* 28 */ le_uint32_t unknown_a7; + /* 2C */ le_uint32_t unknown_a8; + /* 30 */ + } __attribute__((packed)); + struct Table { - parray, 4> difficulty; + /* 0000 */ parray, 4> physical_data; + /* 3600 */ parray, 4> attack_data; + /* 7E00 */ parray, 4> resist_data; + /* AE00 */ parray, 4> movement_data; + /* F600 */ void print(FILE* stream) const; } __attribute__((packed)); @@ -44,17 +103,14 @@ public: std::shared_ptr data_off_ep2, // BattleParamEntry_lab.dat std::shared_ptr data_off_ep4); // BattleParamEntry_ep4.dat - const Entry& get( - bool solo, Episode episode, uint8_t difficulty, EnemyType type) const; - const Entry& get( - bool solo, Episode episode, uint8_t difficulty, size_t entry_index) const; + const Table& get_table(bool solo, Episode episode) const; private: - struct LoadedFile { + struct File { std::shared_ptr data; const Table* table; }; - // online/offline, episode - LoadedFile files[2][3]; + // Indexed as [online/offline][episode] + std::array, 2> files; }; diff --git a/src/CommonItemSet.hh b/src/CommonItemSet.hh index 17db9b35..f788f91b 100644 --- a/src/CommonItemSet.hh +++ b/src/CommonItemSet.hh @@ -70,7 +70,7 @@ public: // This index probability table determines the types of non-rare weapons. // The indexes in this table correspond to the non-rare weapon types 01 // through 0C (Saber through Wand). - // V2/GC: -> parray + // V2/V3: -> parray /* 00 */ U32T base_weapon_type_prob_table_offset; // This table specifies the base subtype for each weapon type. Negative @@ -80,7 +80,7 @@ public: // and specify the base subtype (usually in the range [0, 4]). The subtype // of weapon that actually appears depends on this value and a value from // the following table. - // V2/GC: -> parray + // V2/V3: -> parray /* 04 */ U32T subtype_base_table_offset; // This table specifies how many areas each weapon subtype appears in. For @@ -89,7 +89,7 @@ public: // then Sword items can be found when area - 1 is 2, 3, 4, or 5 (Cave 1 // through Mine 1), and Gigush (the next sword subtype) can be found in Mine // 1 through Ruins 3. - // V2/GC: -> parray + // V2/V3: -> parray /* 08 */ U32T subtype_area_length_table_offset; // This index probability table specifies how likely each possible grind @@ -104,28 +104,28 @@ public: // [00 14 14 0E] // Chance of getting a grind +2 // ... // C1 C2 C3 M1 // (Episode 1 area values from the example for reference) - // V2/GC: -> parray, 9> + // V2/V3: -> parray, 9> /* 0C */ U32T grind_prob_table_offset; // TODO: Figure out exactly how this table is used. Anchor: 80106D34 - // V2/GC: -> parray + // V2/V3: -> parray /* 10 */ U32T armor_shield_type_index_prob_table_offset; // This index probability table specifies how common each possible slot // count is for armor drops. - // V2/GC: -> parray + // V2/V3: -> parray /* 14 */ U32T armor_slot_count_prob_table_offset; // This array (indexed by enemy_id) specifies the range of meseta values // that each enemy can drop. - // V2/GC: -> parray, 0x64> + // V2/V3: -> parray, 0x64> /* 18 */ U32T enemy_meseta_ranges_offset; // Each byte in this table (indexed by enemy_type) represents the percent // chance that the enemy drops anything at all. (This check is done before // the rare drop check, so the chance of getting a rare item from an enemy // is essentially this probability multiplied by the rare drop rate.) - // V2/GC: -> parray + // V2/V3: -> parray /* 1C */ U32T enemy_type_drop_probs_offset; // Each byte in this table (indexed by enemy_type) represents the class of @@ -137,12 +137,12 @@ public: // 04 = tool // 05 = meseta // Anything else = no item - // V2/GC: -> parray + // V2/V3: -> parray /* 20 */ U32T enemy_item_classes_offset; // This table (indexed by area - 1) specifies the ranges of meseta values // that can drop from boxes. - // V2/GC: -> parray, 0x0A> + // V2/V3: -> parray, 0x0A> /* 24 */ U32T box_meseta_ranges_offset; // This array specifies the chance that a rare weapon will have each @@ -152,7 +152,7 @@ public: // non-rare items, spec is determined randomly based on the following field; // for rare items, spec is always 5. // V2: -> parray, 0x17> - // GC: -> parray, 0x17> + // V3: -> parray, 0x17> /* 28 */ U32T bonus_value_prob_table_offset; // This array specifies the value of spec to be used in the above lookup for @@ -168,7 +168,7 @@ public: // a bonus. In Forest 1 and 2 and Cave 1, weapons may have at most one // bonus; in all other areas except Ruins 3, they can have at most two // bonuses, and in Ruins 3, they can have up to three bonuses. - // V2/GC: // -> parray, 3> + // V2/V3: // -> parray, 3> /* 2C */ U32T nonrare_bonus_prob_spec_offset; // This array specifies the chance that a weapon will have each bonus type. @@ -183,37 +183,37 @@ public: // [00 00 00 01 01 08 0A 13 13 13] // Chance of getting Dark bonus // [00 00 00 00 00 01 01 01 01 01] // Chance of getting Hit bonus // F1 F2 C1 C2 C3 M1 M2 R1 R2 R3 // (Episode 1 areas, for reference) - // V2/GC: -> parray, 6> + // V2/V3: -> parray, 6> /* 30 */ U32T bonus_type_prob_table_offset; // This array (indexed by area - 1) specifies a multiplier of used in // special ability determination. It seems this uses the star values from // ItemPMT, but not yet clear exactly in what way. // TODO: Figure out exactly what this does. Anchor: 80106FEC - // V2/GC: -> parray + // V2/V3: -> parray /* 34 */ U32T special_mult_offset; // This array (indexed by area - 1) specifies the probability that any // non-rare weapon will have a special ability. - // V2/GC: -> parray + // V2/V3: -> parray /* 38 */ U32T special_percent_offset; // This index probability table is indexed by [tool_class][area - 1]. The // tool class refers to an entry in ItemPMT, which links it to the actual // item code. - // V2/GC: -> parray, 0x1C> + // V2/V3: -> parray, 0x1C> /* 3C */ U32T tool_class_prob_table_offset; // This index probability table determines how likely each technique is to // appear. The table is indexed as [technique_num][area - 1]. - // V2/GC: -> parray, 0x13> + // V2/V3: -> parray, 0x13> /* 40 */ U32T technique_index_prob_table_offset; // This table specifies the ranges for technique disk levels. The table is // indexed as [technique_num][area - 1]. If either min or max in the range // is 0xFF, or if max < min, technique disks are not dropped for that // technique and area pair. - // V2/GC: -> parray, 0x0A>, 0x13> + // V2/V3: -> parray, 0x0A>, 0x13> /* 44 */ U32T technique_level_ranges_offset; /* 48 */ uint8_t armor_or_shield_type_bias; @@ -224,7 +224,7 @@ public: // the range [0, n] to look up the value in the secondary array, which is // what ends up determining the unit type. // TODO: Figure out and document the exact logic here. Anchor: 80106364 - // V2/GC: -> parray + // V2/V3: -> parray /* 4C */ U32T unit_maxes_offset; // This index probability table determines which type of items drop from @@ -243,7 +243,7 @@ public: // [32 32 32 32 32 32 32 32 32 32] // Chances per area of a meseta drop // [16 16 11 11 11 11 11 0F 0C 0B] // Chances per area of an empty box // F1 F2 C1 C2 C3 M1 M2 R1 R2 R3 // (Episode 1 areas, for reference) - // V2/GC: -> parray, 7> + // V2/V3: -> parray, 7> /* 50 */ U32T box_item_class_prob_table_offset; // There are several unused fields here. @@ -481,7 +481,7 @@ private: // This table specifies how likely a special is to be upgraded or // downgraded by one level. - // In PSO GC, the special upgrade table is: + // In PSO V3, the special upgrade table is: // Viridia => (D) +1=10%, 0=60%, -1=30% // Viridia => (F) +1=25%, 0=50%, -1=25% // Greennill => (D) +1=25%, 0=65%, -1=10% @@ -507,7 +507,7 @@ private: // This table specifies how likely a weapon's grind is to be upgraded or // downgraded, and by how much. The final grind value is clamped to the // range between 0 and the weapon's maximum grind from ItemPMT, inclusive. - // In PSO GC, the grind delta table is: + // In PSO V3, the grind delta table is: // Viridia => (D) +3=3%, +2=7%, +1=13%, 0=60%, -1=10%, -2=7%, -3=0% // Viridia => (F) +3=5%, +2=13%, +1=25%, 0=50%, -1=7%, -2=0%, -3=0% // Greennill => (D) +3=0%, +2=5%, +1=10%, 0=70%, -1=10%, -2=5%, -3=0% @@ -533,7 +533,7 @@ private: // This table specifies how likely a weapon's bonuses are to be upgraded // or downgraded, and by how much. The final bonuses are capped above at // 100, but there is no lower limit (so negative results are possible). - // In PSO GC, the bonus delta table is: + // In PSO V3, the bonus delta table is: // Viridia => (D) +10=5%, +5=15%, 0=60%, -5=15%, -10=5% // Viridia => (F) +10=8%, +5=20%, 0=60%, -5=10%, -10=2% // Greennill => (D) +10=5%, +5=10%, 0=50%, -5=25%, -10=10% @@ -562,15 +562,15 @@ private: // plays a jingle when the tekker result is accepted. These tables describe // how much each delta affects this value, which we call luck. - // In PSO GC, the special upgrade luck table is: + // In PSO V3, the special upgrade luck table is: // +1 => +20, 0 => 0, -1 => -20 be_uint32_t special_upgrade_luck_table_offset; // LuckTableEntry[...]; ending with FF FF - // In PSO GC, the grind delta luck table is: + // In PSO V3, the grind delta luck table is: // +3 => +10, +2 => +5, +1 => +3, 0 => 0, -1 => -3, -2 => -5, -3 => -10 be_uint32_t grind_delta_luck_table_offset; // LuckTableEntry[...]; ending with FF FF - // In PSO GC, the bonus delta luck table is: + // In PSO V3, the bonus delta luck table is: // +10 => +15, +5 => +8, 0 => 0, -5 => -8, -10 => -15 be_uint32_t bonus_delta_luck_offset; // LuckTableEntry[...]; ending with FF FF } __attribute__((packed)); diff --git a/src/QuestScript.cc b/src/QuestScript.cc index 8b34337d..48f92304 100644 --- a/src/QuestScript.cc +++ b/src/QuestScript.cc @@ -12,12 +12,17 @@ #include #include +#include "BattleParamsIndex.hh" #include "CommandFormats.hh" #include "Compression.hh" #include "StaticGameData.hh" using namespace std; +using AttackData = BattleParamsIndex::AttackData; +using ResistData = BattleParamsIndex::ResistData; +using MovementData = BattleParamsIndex::MovementData; + template <> const char* name_for_enum(QuestScriptVersion v) { switch (v) { @@ -78,44 +83,6 @@ static string format_and_indent_data(const void* data, size_t size, uint64_t sta return ret; } -struct ResistData { - le_int16_t evp_bonus; - le_uint16_t unknown_a1; - le_uint16_t unknown_a2; - le_uint16_t unknown_a3; - le_uint16_t unknown_a4; - le_uint16_t unknown_a5; - le_uint32_t unknown_a6; - le_uint32_t unknown_a7; - le_uint32_t unknown_a8; - le_uint32_t unknown_a9; - le_int32_t dfp_bonus; -} __attribute__((packed)); - -struct AttackData { - le_int16_t unknown_a1; - le_int16_t unknown_a2; - le_uint16_t unknown_a3; - le_uint16_t unknown_a4; - le_float unknown_a5; - le_uint32_t unknown_a6; - le_float unknown_a7; - le_uint16_t unknown_a8; - le_uint16_t unknown_a9; - le_uint16_t unknown_a10; - le_uint16_t unknown_a11; - le_uint32_t unknown_a12; - le_uint32_t unknown_a13; - le_uint32_t unknown_a14; - le_uint32_t unknown_a15; - le_uint32_t unknown_a16; -} __attribute__((packed)); - -struct MovementData { - parray unknown_a1; - parray unknown_a2; -} __attribute__((packed)); - struct UnknownF8F2Entry { parray unknown_a1; } __attribute__((packed)); @@ -1425,11 +1392,11 @@ std::string disassemble_quest_script(const void* data, size_t size, QuestScriptV print_as_struct.template operator()([&](const ResistData& resist) -> void { lines.emplace_back(" // As ResistData"); lines.emplace_back(string_printf(" %04zX evp_bonus %04hX /* %hu */", l->offset + offsetof(ResistData, evp_bonus), resist.evp_bonus.load(), resist.evp_bonus.load())); - lines.emplace_back(string_printf(" %04zX a1 %04hX /* %hu */", l->offset + offsetof(ResistData, unknown_a1), resist.unknown_a1.load(), resist.unknown_a1.load())); - lines.emplace_back(string_printf(" %04zX a2 %04hX /* %hu */", l->offset + offsetof(ResistData, unknown_a2), resist.unknown_a2.load(), resist.unknown_a2.load())); - lines.emplace_back(string_printf(" %04zX a3 %04hX /* %hu */", l->offset + offsetof(ResistData, unknown_a3), resist.unknown_a3.load(), resist.unknown_a3.load())); - lines.emplace_back(string_printf(" %04zX a4 %04hX /* %hu */", l->offset + offsetof(ResistData, unknown_a4), resist.unknown_a4.load(), resist.unknown_a4.load())); - lines.emplace_back(string_printf(" %04zX a5 %04hX /* %hu */", l->offset + offsetof(ResistData, unknown_a5), resist.unknown_a5.load(), resist.unknown_a5.load())); + lines.emplace_back(string_printf(" %04zX efr %04hX /* %hu */", l->offset + offsetof(ResistData, efr), resist.efr.load(), resist.efr.load())); + lines.emplace_back(string_printf(" %04zX eic %04hX /* %hu */", l->offset + offsetof(ResistData, eic), resist.eic.load(), resist.eic.load())); + lines.emplace_back(string_printf(" %04zX eth %04hX /* %hu */", l->offset + offsetof(ResistData, eth), resist.eth.load(), resist.eth.load())); + lines.emplace_back(string_printf(" %04zX elt %04hX /* %hu */", l->offset + offsetof(ResistData, elt), resist.elt.load(), resist.elt.load())); + lines.emplace_back(string_printf(" %04zX edk %04hX /* %hu */", l->offset + offsetof(ResistData, edk), resist.edk.load(), resist.edk.load())); lines.emplace_back(string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a6), resist.unknown_a6.load(), resist.unknown_a6.load())); lines.emplace_back(string_printf(" %04zX a7 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a7), resist.unknown_a7.load(), resist.unknown_a7.load())); lines.emplace_back(string_printf(" %04zX a8 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a8), resist.unknown_a8.load(), resist.unknown_a8.load())); @@ -1442,9 +1409,9 @@ std::string disassemble_quest_script(const void* data, size_t size, QuestScriptV lines.emplace_back(string_printf(" %04zX a2 %04hX /* %hd */", l->offset + offsetof(AttackData, unknown_a2), attack.unknown_a2.load(), attack.unknown_a2.load())); lines.emplace_back(string_printf(" %04zX a3 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a3), attack.unknown_a3.load(), attack.unknown_a3.load())); lines.emplace_back(string_printf(" %04zX a4 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a4), attack.unknown_a4.load(), attack.unknown_a4.load())); - lines.emplace_back(string_printf(" %04zX a5 %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, unknown_a5), attack.unknown_a5.load_raw(), attack.unknown_a5.load())); - lines.emplace_back(string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a6), attack.unknown_a6.load(), attack.unknown_a6.load())); - lines.emplace_back(string_printf(" %04zX a7 %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, unknown_a7), attack.unknown_a7.load_raw(), attack.unknown_a7.load())); + lines.emplace_back(string_printf(" %04zX distance_x %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, distance_x), attack.distance_x.load_raw(), attack.distance_x.load())); + lines.emplace_back(string_printf(" %04zX angle_x %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, angle_x), attack.angle_x.load_raw(), attack.angle_x.load())); + lines.emplace_back(string_printf(" %04zX distance_y %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, distance_y), attack.distance_y.load_raw(), attack.distance_y.load())); lines.emplace_back(string_printf(" %04zX a8 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a8), attack.unknown_a8.load(), attack.unknown_a8.load())); lines.emplace_back(string_printf(" %04zX a9 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a9), attack.unknown_a9.load(), attack.unknown_a9.load())); lines.emplace_back(string_printf(" %04zX a10 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a10), attack.unknown_a10.load(), attack.unknown_a10.load())); @@ -1457,16 +1424,18 @@ std::string disassemble_quest_script(const void* data, size_t size, QuestScriptV }); print_as_struct.template operator()([&](const MovementData& movement) -> void { lines.emplace_back(" // As MovementData"); - for (size_t z = 0; z < 6; z++) { - size_t offset = l->offset + z * sizeof(movement.unknown_a1[0]); - lines.emplace_back(string_printf(" %04zX a1[%zu] %08" PRIX32 " /* %g */", - offset, z, movement.unknown_a1[z].load_raw(), movement.unknown_a1[z].load())); - } - for (size_t z = 0; z < 6; z++) { - size_t offset = l->offset + sizeof(movement.unknown_a1) + z * sizeof(movement.unknown_a2[0]); - lines.emplace_back(string_printf(" %04zX a2[%zu] %08" PRIX32 " /* %g */", - offset, z, movement.unknown_a2[z].load_raw(), movement.unknown_a2[z].load())); - } + lines.emplace_back(string_printf(" %04zX idle_move_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, idle_move_speed), movement.idle_move_speed.load_raw(), movement.idle_move_speed.load())); + lines.emplace_back(string_printf(" %04zX idle_animation_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, idle_animation_speed), movement.idle_animation_speed.load_raw(), movement.idle_animation_speed.load())); + lines.emplace_back(string_printf(" %04zX move_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, move_speed), movement.move_speed.load_raw(), movement.move_speed.load())); + lines.emplace_back(string_printf(" %04zX animation_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, animation_speed), movement.animation_speed.load_raw(), movement.animation_speed.load())); + lines.emplace_back(string_printf(" %04zX a1 %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, unknown_a1), movement.unknown_a1.load_raw(), movement.unknown_a1.load())); + lines.emplace_back(string_printf(" %04zX a2 %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, unknown_a2), movement.unknown_a2.load_raw(), movement.unknown_a2.load())); + lines.emplace_back(string_printf(" %04zX a3 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a3), movement.unknown_a3.load(), movement.unknown_a3.load())); + lines.emplace_back(string_printf(" %04zX a4 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a4), movement.unknown_a4.load(), movement.unknown_a4.load())); + lines.emplace_back(string_printf(" %04zX a5 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a5), movement.unknown_a5.load(), movement.unknown_a5.load())); + lines.emplace_back(string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a6), movement.unknown_a6.load(), movement.unknown_a6.load())); + lines.emplace_back(string_printf(" %04zX a7 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a7), movement.unknown_a7.load(), movement.unknown_a7.load())); + lines.emplace_back(string_printf(" %04zX a8 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a8), movement.unknown_a8.load(), movement.unknown_a8.load())); }); if (l->has_data_type(Arg::DataType::IMAGE_DATA)) { const void* data = cmd_r.pgetv(l->offset, size); diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 0e7b0b01..a46f2a53 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -1521,8 +1521,10 @@ static void on_steal_exp_bb(shared_ptr c, uint8_t, uint8_t, const void* if (special >= 0x09 && special <= 0x0B) { // Master's = 8, Lord's = 10, King's = 12 + uint32_t bp_index = battle_param_index_for_enemy_type(l->episode, enemy.type); + const auto& bp_table = s->battle_params->get_table(l->mode == GameMode::SOLO, l->episode); uint32_t percent = 8 + ((special - 9) << 1) + (char_class_is_android(p->disp.visual.char_class) ? 30 : 0); - uint32_t enemy_exp = s->battle_params->get(l->mode == GameMode::SOLO, l->episode, l->difficulty, enemy.type).experience; + uint32_t enemy_exp = bp_table.physical_data[l->difficulty][bp_index].experience; uint32_t stolen_exp = min((enemy_exp * percent) / 100, 80); if (c->options.debug) { send_text_message_printf(c, "$C5+%" PRIu32 " E-%hX %s", @@ -1567,7 +1569,9 @@ static void on_enemy_killed_bb(shared_ptr c, uint8_t command, uint8_t fl uint32_t experience = 0xFFFFFFFF; try { - experience = s->battle_params->get(l->mode == GameMode::SOLO, l->episode, l->difficulty, e.type).experience * l->exp_multiplier; + const auto& bp_table = s->battle_params->get_table(l->mode == GameMode::SOLO, l->episode); + uint32_t bp_index = battle_param_index_for_enemy_type(l->episode, e.type); + experience = bp_table.physical_data[l->difficulty][bp_index].experience * l->exp_multiplier; } catch (const exception& e) { if (c->options.debug) { send_text_message_printf(c, "$C5E-%hX __MISSING__\n%s", cmd.enemy_id.load(), e.what());