refine BattleParamEntry format
This commit is contained in:
+11
-25
@@ -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;
|
||||
}
|
||||
|
||||
+76
-20
@@ -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<uint8_t, 0x0C> 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<le_float, 2> 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<parray<Entry, 0x60>, 4> difficulty;
|
||||
/* 0000 */ parray<parray<PhysicalData, 0x60>, 4> physical_data;
|
||||
/* 3600 */ parray<parray<AttackData, 0x60>, 4> attack_data;
|
||||
/* 7E00 */ parray<parray<ResistData, 0x60>, 4> resist_data;
|
||||
/* AE00 */ parray<parray<MovementData, 0x60>, 4> movement_data;
|
||||
/* F600 */
|
||||
|
||||
void print(FILE* stream) const;
|
||||
} __attribute__((packed));
|
||||
@@ -44,17 +103,14 @@ public:
|
||||
std::shared_ptr<const std::string> data_off_ep2, // BattleParamEntry_lab.dat
|
||||
std::shared_ptr<const std::string> 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<const std::string> data;
|
||||
const Table* table;
|
||||
};
|
||||
|
||||
// online/offline, episode
|
||||
LoadedFile files[2][3];
|
||||
// Indexed as [online/offline][episode]
|
||||
std::array<std::array<File, 3>, 2> files;
|
||||
};
|
||||
|
||||
+26
-26
@@ -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<uint8_t, 0x0C>
|
||||
// V2/V3: -> parray<uint8_t, 0x0C>
|
||||
/* 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<int8_t, 0x0C>
|
||||
// V2/V3: -> parray<int8_t, 0x0C>
|
||||
/* 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<uint8_t, 0x0C>
|
||||
// V2/V3: -> parray<uint8_t, 0x0C>
|
||||
/* 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<parray<uint8_t, 4>, 9>
|
||||
// V2/V3: -> parray<parray<uint8_t, 4>, 9>
|
||||
/* 0C */ U32T grind_prob_table_offset;
|
||||
|
||||
// TODO: Figure out exactly how this table is used. Anchor: 80106D34
|
||||
// V2/GC: -> parray<uint8_t, 0x05>
|
||||
// V2/V3: -> parray<uint8_t, 0x05>
|
||||
/* 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<uint8_t, 0x05>
|
||||
// V2/V3: -> parray<uint8_t, 0x05>
|
||||
/* 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<Range<U16T>, 0x64>
|
||||
// V2/V3: -> parray<Range<U16T>, 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<uint8_t, 0x64>
|
||||
// V2/V3: -> parray<uint8_t, 0x64>
|
||||
/* 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<uint8_t, 0x64>
|
||||
// V2/V3: -> parray<uint8_t, 0x64>
|
||||
/* 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<Range<U16T>, 0x0A>
|
||||
// V2/V3: -> parray<Range<U16T>, 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<parray<uint8_t, 5>, 0x17>
|
||||
// GC: -> parray<parray<U16T, 6>, 0x17>
|
||||
// V3: -> parray<parray<U16T, 6>, 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<parray<uint8_t, 10>, 3>
|
||||
// V2/V3: // -> parray<parray<uint8_t, 10>, 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<parray<uint8_t, 10>, 6>
|
||||
// V2/V3: -> parray<parray<uint8_t, 10>, 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<uint8_t, 0x0A>
|
||||
// V2/V3: -> parray<uint8_t, 0x0A>
|
||||
/* 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<uint8_t, 0x0A>
|
||||
// V2/V3: -> parray<uint8_t, 0x0A>
|
||||
/* 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<parray<U16T, 0x0A>, 0x1C>
|
||||
// V2/V3: -> parray<parray<U16T, 0x0A>, 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<parray<uint8_t, 0x0A>, 0x13>
|
||||
// V2/V3: -> parray<parray<uint8_t, 0x0A>, 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<parray<Range<uint8_t>, 0x0A>, 0x13>
|
||||
// V2/V3: -> parray<parray<Range<uint8_t>, 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<uint8_t, 0x0A>
|
||||
// V2/V3: -> parray<uint8_t, 0x0A>
|
||||
/* 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<parray<uint8_t, 10>, 7>
|
||||
// V2/V3: -> parray<parray<uint8_t, 10>, 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));
|
||||
|
||||
+25
-56
@@ -12,12 +12,17 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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>(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<le_float, 6> unknown_a1;
|
||||
parray<le_float, 6> unknown_a2;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct UnknownF8F2Entry {
|
||||
parray<le_float, 4> 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()<Arg::DataType::RESIST_DATA, ResistData>([&](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()<Arg::DataType::MOVEMENT_DATA, MovementData>([&](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);
|
||||
|
||||
@@ -1521,8 +1521,10 @@ static void on_steal_exp_bb(shared_ptr<Client> 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<uint32_t>((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<Client> 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());
|
||||
|
||||
Reference in New Issue
Block a user