improve ep3 data formatting
This commit is contained in:
@@ -399,7 +399,7 @@ newserv has many CLI options, which can be used to access functionality other th
|
|||||||
* Convert quests in .gci, .vms, .dlq, or .qst format to .bin/.dat format (`decode-gci`, `decode-vms`, `decode-dlq`, `decode-qst`)
|
* Convert quests in .gci, .vms, .dlq, or .qst format to .bin/.dat format (`decode-gci`, `decode-vms`, `decode-dlq`, `decode-qst`)
|
||||||
* Convert quests in .bin/.dat to .qst format (`encode-qst`)
|
* Convert quests in .bin/.dat to .qst format (`encode-qst`)
|
||||||
* Disassemble quest scripts (`disassemble-quest-script`)
|
* Disassemble quest scripts (`disassemble-quest-script`)
|
||||||
* Format Episode 3 game data in a human-readable manner (`show-ep3-data`)
|
* Format Episode 3 game data in a human-readable manner (`show-ep3-maps`, `show-ep3-cards`)
|
||||||
* Convert item data to a human-readable description, or vice versa (`describe-item`, `encode-item`)
|
* Convert item data to a human-readable description, or vice versa (`describe-item`, `encode-item`)
|
||||||
* Connect to another PSO server and pretend to be a client (`cat-client`)
|
* Connect to another PSO server and pretend to be a client (`cat-client`)
|
||||||
* Replay a session log for testing (`replay-log`)
|
* Replay a session log for testing (`replay-log`)
|
||||||
|
|||||||
+299
-48
@@ -18,6 +18,99 @@ using namespace std;
|
|||||||
|
|
||||||
namespace Episode3 {
|
namespace Episode3 {
|
||||||
|
|
||||||
|
const char* name_for_link_color(uint8_t color) {
|
||||||
|
switch (color) {
|
||||||
|
case 1:
|
||||||
|
return "blue"; // HP halver
|
||||||
|
case 2:
|
||||||
|
return "red"; // Physical attacks
|
||||||
|
case 3:
|
||||||
|
return "yellow"; // Techniques
|
||||||
|
case 4:
|
||||||
|
return "brown"; // Leukon Knight
|
||||||
|
case 5:
|
||||||
|
return "orange"; // Penetrate/confuse
|
||||||
|
case 6:
|
||||||
|
return "purple"; // Instant death
|
||||||
|
case 7:
|
||||||
|
return "white"; // Castor
|
||||||
|
case 8:
|
||||||
|
return "gray"; // Pollux
|
||||||
|
case 9:
|
||||||
|
return "green"; // Status effects
|
||||||
|
default:
|
||||||
|
throw invalid_argument("unknown color");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name_for_card_type(CardType type) {
|
||||||
|
switch (type) {
|
||||||
|
case CardType::HUNTERS_SC:
|
||||||
|
return "HUNTERS_SC";
|
||||||
|
case CardType::ARKZ_SC:
|
||||||
|
return "ARKZ_SC";
|
||||||
|
case CardType::ITEM:
|
||||||
|
return "ITEM";
|
||||||
|
case CardType::CREATURE:
|
||||||
|
return "CREATURE";
|
||||||
|
case CardType::ACTION:
|
||||||
|
return "ACTION";
|
||||||
|
case CardType::ASSIST:
|
||||||
|
return "ASSIST";
|
||||||
|
case CardType::INVALID_FF:
|
||||||
|
return "INVALID_FF";
|
||||||
|
default:
|
||||||
|
throw invalid_argument("invalid card type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name_for_card_class(CardClass cc) {
|
||||||
|
switch (cc) {
|
||||||
|
case CardClass::HU_SC:
|
||||||
|
return "HU_SC";
|
||||||
|
case CardClass::RA_SC:
|
||||||
|
return "RA_SC";
|
||||||
|
case CardClass::FO_SC:
|
||||||
|
return "FO_SC";
|
||||||
|
case CardClass::NATIVE_CREATURE:
|
||||||
|
return "NATIVE_CREATURE";
|
||||||
|
case CardClass::A_BEAST_CREATURE:
|
||||||
|
return "A_BEAST_CREATURE";
|
||||||
|
case CardClass::MACHINE_CREATURE:
|
||||||
|
return "MACHINE_CREATURE";
|
||||||
|
case CardClass::DARK_CREATURE:
|
||||||
|
return "DARK_CREATURE";
|
||||||
|
case CardClass::GUARD_ITEM:
|
||||||
|
return "GUARD_ITEM";
|
||||||
|
case CardClass::MAG_ITEM:
|
||||||
|
return "MAG_ITEM";
|
||||||
|
case CardClass::SWORD_ITEM:
|
||||||
|
return "SWORD_ITEM";
|
||||||
|
case CardClass::GUN_ITEM:
|
||||||
|
return "GUN_ITEM";
|
||||||
|
case CardClass::CANE_ITEM:
|
||||||
|
return "CANE_ITEM";
|
||||||
|
case CardClass::ATTACK_ACTION:
|
||||||
|
return "ATTACK_ACTION";
|
||||||
|
case CardClass::DEFENSE_ACTION:
|
||||||
|
return "DEFENSE_ACTION";
|
||||||
|
case CardClass::TECH:
|
||||||
|
return "TECH";
|
||||||
|
case CardClass::PHOTON_BLAST:
|
||||||
|
return "PHOTON_BLAST";
|
||||||
|
case CardClass::CONNECT_ONLY_ATTACK_ACTION:
|
||||||
|
return "CONNECT_ONLY_ATTACK_ACTION";
|
||||||
|
case CardClass::BOSS_ATTACK_ACTION:
|
||||||
|
return "BOSS_ATTACK_ACTION";
|
||||||
|
case CardClass::BOSS_TECH:
|
||||||
|
return "BOSS_TECH";
|
||||||
|
case CardClass::ASSIST:
|
||||||
|
return "ASSIST";
|
||||||
|
default:
|
||||||
|
throw invalid_argument("invalid card class");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* name_for_attack_medium(AttackMedium medium) {
|
const char* name_for_attack_medium(AttackMedium medium) {
|
||||||
switch (medium) {
|
switch (medium) {
|
||||||
case AttackMedium::UNKNOWN:
|
case AttackMedium::UNKNOWN:
|
||||||
@@ -35,6 +128,83 @@ const char* name_for_attack_medium(AttackMedium medium) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* name_for_criterion_code(CriterionCode code) {
|
||||||
|
switch (code) {
|
||||||
|
case CriterionCode::NONE:
|
||||||
|
return "NONE";
|
||||||
|
case CriterionCode::HU_CLASS_SC:
|
||||||
|
return "HU_CLASS_SC";
|
||||||
|
case CriterionCode::RA_CLASS_SC:
|
||||||
|
return "RA_CLASS_SC";
|
||||||
|
case CriterionCode::FO_CLASS_SC:
|
||||||
|
return "FO_CLASS_SC";
|
||||||
|
case CriterionCode::SAME_TEAM:
|
||||||
|
return "SAME_TEAM";
|
||||||
|
case CriterionCode::SAME_PLAYER:
|
||||||
|
return "SAME_PLAYER";
|
||||||
|
case CriterionCode::SAME_TEAM_NOT_SAME_PLAYER:
|
||||||
|
return "SAME_TEAM_NOT_SAME_PLAYER";
|
||||||
|
case CriterionCode::UNKNOWN_07:
|
||||||
|
return "UNKNOWN_07";
|
||||||
|
case CriterionCode::NOT_SC:
|
||||||
|
return "NOT_SC";
|
||||||
|
case CriterionCode::SC:
|
||||||
|
return "SC";
|
||||||
|
case CriterionCode::HU_OR_RA_CLASS_SC:
|
||||||
|
return "HU_OR_RA_CLASS_SC";
|
||||||
|
case CriterionCode::HUNTER_HUMAN_SC:
|
||||||
|
return "HUNTER_HUMAN_SC";
|
||||||
|
case CriterionCode::HUNTER_HU_CLASS_MALE_SC:
|
||||||
|
return "HUNTER_HU_CLASS_MALE_SC";
|
||||||
|
case CriterionCode::HUNTER_FEMALE_SC:
|
||||||
|
return "HUNTER_FEMALE_SC";
|
||||||
|
case CriterionCode::HUNTER_HU_OR_FO_CLASS_HUMAN_SC:
|
||||||
|
return "HUNTER_HU_OR_FO_CLASS_HUMAN_SC";
|
||||||
|
case CriterionCode::HUNTER_HU_CLASS_ANDROID_SC:
|
||||||
|
return "HUNTER_HU_CLASS_ANDROID_SC";
|
||||||
|
case CriterionCode::UNKNOWN_10:
|
||||||
|
return "UNKNOWN_10";
|
||||||
|
case CriterionCode::UNKNOWN_11:
|
||||||
|
return "UNKNOWN_11";
|
||||||
|
case CriterionCode::HUNTER_HUNEWEARL_CLASS_SC:
|
||||||
|
return "HUNTER_HUNEWEARL_CLASS_SC";
|
||||||
|
case CriterionCode::HUNTER_RA_CLASS_MALE_SC:
|
||||||
|
return "HUNTER_RA_CLASS_MALE_SC";
|
||||||
|
case CriterionCode::HUNTER_RA_CLASS_FEMALE_SC:
|
||||||
|
return "HUNTER_RA_CLASS_FEMALE_SC";
|
||||||
|
case CriterionCode::HUNTER_RA_OR_FO_CLASS_FEMALE_SC:
|
||||||
|
return "HUNTER_RA_OR_FO_CLASS_FEMALE_SC";
|
||||||
|
case CriterionCode::HUNTER_HU_OR_RA_CLASS_HUMAN_SC:
|
||||||
|
return "HUNTER_HU_OR_RA_CLASS_HUMAN_SC";
|
||||||
|
case CriterionCode::HUNTER_RA_CLASS_ANDROID_SC:
|
||||||
|
return "HUNTER_RA_CLASS_ANDROID_SC";
|
||||||
|
case CriterionCode::HUNTER_FO_CLASS_FEMALE_SC:
|
||||||
|
return "HUNTER_FO_CLASS_FEMALE_SC";
|
||||||
|
case CriterionCode::HUNTER_FEMALE_HUMAN_SC:
|
||||||
|
return "HUNTER_FEMALE_HUMAN_SC";
|
||||||
|
case CriterionCode::HUNTER_ANDROID_SC:
|
||||||
|
return "HUNTER_ANDROID_SC";
|
||||||
|
case CriterionCode::HU_OR_FO_CLASS_SC:
|
||||||
|
return "HU_OR_FO_CLASS_SC";
|
||||||
|
case CriterionCode::RA_OR_FO_CLASS_SC:
|
||||||
|
return "RA_OR_FO_CLASS_SC";
|
||||||
|
case CriterionCode::PHYSICAL_OR_UNKNOWN_ATTACK_MEDIUM:
|
||||||
|
return "PHYSICAL_OR_UNKNOWN_ATTACK_MEDIUM";
|
||||||
|
case CriterionCode::TECH_OR_UNKNOWN_ATTACK_MEDIUM:
|
||||||
|
return "TECH_OR_UNKNOWN_ATTACK_MEDIUM";
|
||||||
|
case CriterionCode::PHYSICAL_OR_TECH_OR_UNKNOWN_ATTACK_MEDIUM:
|
||||||
|
return "PHYSICAL_OR_TECH_OR_UNKNOWN_ATTACK_MEDIUM";
|
||||||
|
case CriterionCode::UNKNOWN_20:
|
||||||
|
return "UNKNOWN_20";
|
||||||
|
case CriterionCode::UNKNOWN_21:
|
||||||
|
return "UNKNOWN_21";
|
||||||
|
case CriterionCode::UNKNOWN_22:
|
||||||
|
return "UNKNOWN_22";
|
||||||
|
default:
|
||||||
|
throw invalid_argument("invalid criterion code");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Location::Location() : Location(0, 0) {}
|
Location::Location() : Location(0, 0) {}
|
||||||
Location::Location(uint8_t x, uint8_t y) : Location(x, y, Direction::RIGHT) {}
|
Location::Location(uint8_t x, uint8_t y) : Location(x, y, Direction::RIGHT) {}
|
||||||
Location::Location(uint8_t x, uint8_t y, Direction direction)
|
Location::Location(uint8_t x, uint8_t y, Direction direction)
|
||||||
@@ -140,15 +310,6 @@ bool card_class_is_tech_like(CardClass cc) {
|
|||||||
(cc == CardClass::BOSS_TECH);
|
(cc == CardClass::BOSS_TECH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const vector<const char*> name_for_card_type({
|
|
||||||
"HunterSC",
|
|
||||||
"ArkzSC",
|
|
||||||
"Item",
|
|
||||||
"Creature",
|
|
||||||
"Action",
|
|
||||||
"Assist",
|
|
||||||
});
|
|
||||||
|
|
||||||
static const unordered_map<string, const char*> description_for_expr_token({
|
static const unordered_map<string, const char*> description_for_expr_token({
|
||||||
{"f", "Number of FCs controlled by current SC"},
|
{"f", "Number of FCs controlled by current SC"},
|
||||||
{"d", "Die roll"},
|
{"d", "Die roll"},
|
||||||
@@ -724,7 +885,14 @@ string string_for_colors(const parray<uint8_t, 8>& colors) {
|
|||||||
string ret;
|
string ret;
|
||||||
for (size_t x = 0; x < 8; x++) {
|
for (size_t x = 0; x < 8; x++) {
|
||||||
if (colors[x]) {
|
if (colors[x]) {
|
||||||
ret += '0' + colors[x];
|
if (!ret.empty()) {
|
||||||
|
ret += ",";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ret += name_for_link_color(colors[x]);
|
||||||
|
} catch (const invalid_argument) {
|
||||||
|
ret += string_printf("%02hhX", colors[x]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret.empty()) {
|
if (ret.empty()) {
|
||||||
@@ -757,16 +925,27 @@ string string_for_range(const parray<be_uint32_t, 6>& range) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
string CardDefinition::str() const {
|
string CardDefinition::str(bool single_line) const {
|
||||||
string type_str;
|
string type_str;
|
||||||
try {
|
try {
|
||||||
type_str = name_for_card_type.at(static_cast<uint8_t>(this->type));
|
type_str = name_for_card_type(this->type);
|
||||||
} catch (const out_of_range&) {
|
} catch (const invalid_argument&) {
|
||||||
type_str = string_printf("%02hhX", static_cast<uint8_t>(this->type));
|
type_str = string_printf("%02hhX", static_cast<uint8_t>(this->type));
|
||||||
}
|
}
|
||||||
|
string criterion_str;
|
||||||
|
try {
|
||||||
|
criterion_str = name_for_criterion_code(this->usable_criterion);
|
||||||
|
} catch (const invalid_argument&) {
|
||||||
|
criterion_str = string_printf("%02hhX", static_cast<uint8_t>(this->usable_criterion));
|
||||||
|
}
|
||||||
|
string card_class_str;
|
||||||
|
try {
|
||||||
|
card_class_str = name_for_card_class(this->card_class());
|
||||||
|
} catch (const invalid_argument&) {
|
||||||
|
card_class_str = string_printf("%04hX", this->be_card_class.load());
|
||||||
|
}
|
||||||
string rarity_str = name_for_rarity(this->rarity);
|
string rarity_str = name_for_rarity(this->rarity);
|
||||||
string target_mode_str = name_for_target_mode(this->target_mode);
|
string target_mode_str = name_for_target_mode(this->target_mode);
|
||||||
string range_str = string_for_range(this->range);
|
|
||||||
string assist_turns_str = string_for_assist_turns(this->assist_turns);
|
string assist_turns_str = string_for_assist_turns(this->assist_turns);
|
||||||
string hp_str = this->hp.str();
|
string hp_str = this->hp.str();
|
||||||
string ap_str = this->ap.str();
|
string ap_str = this->ap.str();
|
||||||
@@ -780,44 +959,115 @@ string CardDefinition::str() const {
|
|||||||
if (this->effects[x].is_empty()) {
|
if (this->effects[x].is_empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!effects_str.empty()) {
|
if (!single_line) {
|
||||||
|
effects_str += "\n ";
|
||||||
|
} else if (!effects_str.empty()) {
|
||||||
effects_str += ", ";
|
effects_str += ", ";
|
||||||
}
|
}
|
||||||
effects_str += this->effects[x].str();
|
effects_str += this->effects[x].str();
|
||||||
}
|
}
|
||||||
return string_printf(
|
if (!single_line && effects_str.empty()) {
|
||||||
"[Card: %04" PRIX32 " name=%s type=%s usable_condition=%02hhX rare=%s "
|
effects_str = " (none)";
|
||||||
"cost=%hhX+%hhX target=%s range=%s assist_turns=%s cannot_move=%s "
|
}
|
||||||
"cannot_attack=%s cannot_drop=%s hp=%s ap=%s tp=%s mv=%s left=%s right=%s "
|
|
||||||
"top=%s a2=%04hX class=%04hX assist_effect=[%hu, %hu] "
|
if (single_line) {
|
||||||
"drop_rates=[%hu, %hu] effects=[%s]]",
|
string range_str = string_for_range(this->range);
|
||||||
this->card_id.load(),
|
return string_printf(
|
||||||
this->en_name.data(),
|
"[Card: %04" PRIX32 " name=%s type=%s usable_condition=%s rare=%s "
|
||||||
type_str.c_str(),
|
"cost=%hhX+%hhX target=%s range=%s assist_turns=%s cannot_move=%s "
|
||||||
static_cast<uint8_t>(this->usable_criterion),
|
"cannot_attack=%s cannot_drop=%s hp=%s ap=%s tp=%s mv=%s left=%s right=%s "
|
||||||
rarity_str.c_str(),
|
"top=%s a2=%04hX class=%s assist_effect=[%hu, %hu] "
|
||||||
this->self_cost,
|
"drop_rates=[%hu, %hu] effects=[%s]]",
|
||||||
this->ally_cost,
|
this->card_id.load(),
|
||||||
target_mode_str.c_str(),
|
this->en_name.data(),
|
||||||
range_str.c_str(),
|
type_str.c_str(),
|
||||||
assist_turns_str.c_str(),
|
criterion_str.c_str(),
|
||||||
this->cannot_move ? "true" : "false",
|
rarity_str.c_str(),
|
||||||
this->cannot_attack ? "true" : "false",
|
this->self_cost,
|
||||||
this->cannot_drop ? "true" : "false",
|
this->ally_cost,
|
||||||
hp_str.c_str(),
|
target_mode_str.c_str(),
|
||||||
ap_str.c_str(),
|
range_str.c_str(),
|
||||||
tp_str.c_str(),
|
assist_turns_str.c_str(),
|
||||||
mv_str.c_str(),
|
this->cannot_move ? "true" : "false",
|
||||||
left_str.c_str(),
|
this->cannot_attack ? "true" : "false",
|
||||||
right_str.c_str(),
|
this->cannot_drop ? "true" : "false",
|
||||||
top_str.c_str(),
|
hp_str.c_str(),
|
||||||
this->unknown_a2.load(),
|
ap_str.c_str(),
|
||||||
this->be_card_class.load(),
|
tp_str.c_str(),
|
||||||
this->assist_effect[0].load(),
|
mv_str.c_str(),
|
||||||
this->assist_effect[1].load(),
|
left_str.c_str(),
|
||||||
this->drop_rates[0].load(),
|
right_str.c_str(),
|
||||||
this->drop_rates[1].load(),
|
top_str.c_str(),
|
||||||
effects_str.c_str());
|
this->unknown_a2.load(),
|
||||||
|
card_class_str.c_str(),
|
||||||
|
this->assist_effect[0].load(),
|
||||||
|
this->assist_effect[1].load(),
|
||||||
|
this->drop_rates[0].load(),
|
||||||
|
this->drop_rates[1].load(),
|
||||||
|
effects_str.c_str());
|
||||||
|
|
||||||
|
} else { // Not single-line
|
||||||
|
string range_str;
|
||||||
|
if (this->range[0] == 0x000FFFFF) {
|
||||||
|
range_str = " (entire field)";
|
||||||
|
} else {
|
||||||
|
for (size_t x = 0; x < 6; x++) {
|
||||||
|
range_str += "\n ";
|
||||||
|
for (size_t z = 0; z < 5; z++) {
|
||||||
|
bool is_included = ((this->range[x] >> (16 - (z * 4))) & 0xF);
|
||||||
|
if (x == 4 && z == 2) {
|
||||||
|
range_str += is_included ? "@" : "#";
|
||||||
|
} else {
|
||||||
|
range_str += is_included ? "*" : "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string_printf(
|
||||||
|
"\
|
||||||
|
Card: %04" PRIX32 " \"%s\"\n\
|
||||||
|
Type: %s, class: %s\n\
|
||||||
|
Usability condition: %s\n\
|
||||||
|
Rarity: %s\n\
|
||||||
|
Cost: %hhX (self) + %hhX (ally)\n\
|
||||||
|
Target mode: %s\n\
|
||||||
|
Range:%s\n\
|
||||||
|
Assist turns: %s\n\
|
||||||
|
Capabilities: %s move, %s attack\n\
|
||||||
|
HP: %s, AP: %s, TP: %s, MV: %s\n\
|
||||||
|
Left colors: %s; right colors: %s; top colors: %s\n\
|
||||||
|
Unknown a2: %04hX\n\
|
||||||
|
Assist effect: [%hu, %hu]\n\
|
||||||
|
Drop rates: [%hu, %hu] (%s drop)\n\
|
||||||
|
Effects:%s",
|
||||||
|
this->card_id.load(),
|
||||||
|
this->en_name.data(),
|
||||||
|
type_str.c_str(),
|
||||||
|
card_class_str.c_str(),
|
||||||
|
criterion_str.c_str(),
|
||||||
|
rarity_str.c_str(),
|
||||||
|
this->self_cost,
|
||||||
|
this->ally_cost,
|
||||||
|
target_mode_str.c_str(),
|
||||||
|
range_str.c_str(),
|
||||||
|
assist_turns_str.c_str(),
|
||||||
|
this->cannot_move ? "cannot" : "can",
|
||||||
|
this->cannot_attack ? "cannot" : "can",
|
||||||
|
hp_str.c_str(),
|
||||||
|
ap_str.c_str(),
|
||||||
|
tp_str.c_str(),
|
||||||
|
mv_str.c_str(),
|
||||||
|
left_str.c_str(),
|
||||||
|
right_str.c_str(),
|
||||||
|
top_str.c_str(),
|
||||||
|
this->unknown_a2.load(),
|
||||||
|
this->assist_effect[0].load(),
|
||||||
|
this->assist_effect[1].load(),
|
||||||
|
this->drop_rates[0].load(),
|
||||||
|
this->drop_rates[1].load(),
|
||||||
|
this->cannot_drop ? "cannot" : "can",
|
||||||
|
effects_str.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HPType hp_type_for_name(const char* name) {
|
HPType hp_type_for_name(const char* name) {
|
||||||
@@ -1514,6 +1764,7 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
|
|||||||
tags.emplace_back(std::move(tag));
|
tags.emplace_back(std::move(tag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strip_leading_whitespace(orig_text);
|
||||||
|
|
||||||
if (!card_text.emplace(card_id, std::move(orig_text)).second) {
|
if (!card_text.emplace(card_id, std::move(orig_text)).second) {
|
||||||
throw runtime_error("duplicate card text id");
|
throw runtime_error("duplicate card text id");
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ namespace Episode3 {
|
|||||||
|
|
||||||
class DataIndex;
|
class DataIndex;
|
||||||
|
|
||||||
|
const char* name_for_link_color(uint8_t color);
|
||||||
|
|
||||||
enum BehaviorFlag {
|
enum BehaviorFlag {
|
||||||
SKIP_DECK_VERIFY = 0x00000001,
|
SKIP_DECK_VERIFY = 0x00000001,
|
||||||
IGNORE_CARD_COUNTS = 0x00000002,
|
IGNORE_CARD_COUNTS = 0x00000002,
|
||||||
@@ -93,6 +95,8 @@ enum class CriterionCode : uint8_t {
|
|||||||
UNKNOWN_22 = 0x22,
|
UNKNOWN_22 = 0x22,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* name_for_criterion_code(CriterionCode code);
|
||||||
|
|
||||||
enum class CardRarity : uint8_t {
|
enum class CardRarity : uint8_t {
|
||||||
N1 = 0x01,
|
N1 = 0x01,
|
||||||
R1 = 0x02,
|
R1 = 0x02,
|
||||||
@@ -121,6 +125,8 @@ enum class CardType : uint8_t {
|
|||||||
END_CARD_LIST = 0xFF,
|
END_CARD_LIST = 0xFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* name_for_card_type(CardType type);
|
||||||
|
|
||||||
enum class CardClass : uint16_t {
|
enum class CardClass : uint16_t {
|
||||||
HU_SC = 0x0000,
|
HU_SC = 0x0000,
|
||||||
RA_SC = 0x0001,
|
RA_SC = 0x0001,
|
||||||
@@ -144,6 +150,7 @@ enum class CardClass : uint16_t {
|
|||||||
ASSIST = 0x0028,
|
ASSIST = 0x0028,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* name_for_card_class(CardClass cc);
|
||||||
bool card_class_is_tech_like(CardClass cc);
|
bool card_class_is_tech_like(CardClass cc);
|
||||||
|
|
||||||
enum class TargetMode : uint8_t {
|
enum class TargetMode : uint8_t {
|
||||||
@@ -552,7 +559,7 @@ struct CardDefinition {
|
|||||||
CardClass card_class() const;
|
CardClass card_class() const;
|
||||||
|
|
||||||
void decode_range();
|
void decode_range();
|
||||||
std::string str() const;
|
std::string str(bool single_line = true) const;
|
||||||
} __attribute__((packed)); // 0x128 bytes in total
|
} __attribute__((packed)); // 0x128 bytes in total
|
||||||
|
|
||||||
struct CardDefinitionsFooter {
|
struct CardDefinitionsFooter {
|
||||||
|
|||||||
+19
-19
@@ -205,9 +205,12 @@ The actions are:\n\
|
|||||||
--gc, and --bb options can be used to select the command format and\n\
|
--gc, and --bb options can be used to select the command format and\n\
|
||||||
encryption. If --bb is used, the --key=KEY-NAME option is also required (as\n\
|
encryption. If --bb is used, the --key=KEY-NAME option is also required (as\n\
|
||||||
in decrypt-data above).\n\
|
in decrypt-data above).\n\
|
||||||
show-ep3-data\n\
|
show-ep3-maps\n\
|
||||||
Print the Episode 3 maps and card definitions from the system/ep3 directory\n\
|
Print the Episode 3 maps from the system/ep3 directory in a (sort of)\n\
|
||||||
in a (sort of) human-readable format.\n\
|
human-readable format.\n\
|
||||||
|
show-ep3-cards\n\
|
||||||
|
Print the Episode 3 card definitions from the system/ep3 directory in a\n\
|
||||||
|
human-readable format.\n\
|
||||||
describe-item DATA\n\
|
describe-item DATA\n\
|
||||||
Print the name of the item given by DATA (in hex). DATA must not contain\n\
|
Print the name of the item given by DATA (in hex). DATA must not contain\n\
|
||||||
spaces. If DATA is 20 bytes, newserv assumes it contains an unused item ID\n\
|
spaces. If DATA is 20 bytes, newserv assumes it contains an unused item ID\n\
|
||||||
@@ -276,7 +279,8 @@ enum class Behavior {
|
|||||||
EXTRACT_BML,
|
EXTRACT_BML,
|
||||||
FORMAT_RARE_ITEM_SET,
|
FORMAT_RARE_ITEM_SET,
|
||||||
CONVERT_ITEMRT_REL_TO_JSON,
|
CONVERT_ITEMRT_REL_TO_JSON,
|
||||||
SHOW_EP3_DATA,
|
SHOW_EP3_MAPS,
|
||||||
|
SHOW_EP3_CARDS,
|
||||||
DESCRIBE_ITEM,
|
DESCRIBE_ITEM,
|
||||||
ENCODE_ITEM,
|
ENCODE_ITEM,
|
||||||
PARSE_OBJECT_GRAPH,
|
PARSE_OBJECT_GRAPH,
|
||||||
@@ -378,7 +382,6 @@ int main(int argc, char** argv) {
|
|||||||
const char* replay_required_access_key = "";
|
const char* replay_required_access_key = "";
|
||||||
const char* replay_required_password = "";
|
const char* replay_required_password = "";
|
||||||
uint32_t root_object_address = 0;
|
uint32_t root_object_address = 0;
|
||||||
uint16_t ep3_card_id = 0xFFFF;
|
|
||||||
uint8_t domain = 1;
|
uint8_t domain = 1;
|
||||||
uint8_t subdomain = 0xFF;
|
uint8_t subdomain = 0xFF;
|
||||||
for (int x = 1; x < argc; x++) {
|
for (int x = 1; x < argc; x++) {
|
||||||
@@ -538,8 +541,10 @@ int main(int argc, char** argv) {
|
|||||||
behavior = Behavior::FORMAT_RARE_ITEM_SET;
|
behavior = Behavior::FORMAT_RARE_ITEM_SET;
|
||||||
} else if (!strcmp(argv[x], "convert-itemrt-rel-to-json")) {
|
} else if (!strcmp(argv[x], "convert-itemrt-rel-to-json")) {
|
||||||
behavior = Behavior::CONVERT_ITEMRT_REL_TO_JSON;
|
behavior = Behavior::CONVERT_ITEMRT_REL_TO_JSON;
|
||||||
} else if (!strcmp(argv[x], "show-ep3-data")) {
|
} else if (!strcmp(argv[x], "show-ep3-maps")) {
|
||||||
behavior = Behavior::SHOW_EP3_DATA;
|
behavior = Behavior::SHOW_EP3_MAPS;
|
||||||
|
} else if (!strcmp(argv[x], "show-ep3-cards")) {
|
||||||
|
behavior = Behavior::SHOW_EP3_CARDS;
|
||||||
} else if (!strcmp(argv[x], "describe-item")) {
|
} else if (!strcmp(argv[x], "describe-item")) {
|
||||||
behavior = Behavior::DESCRIBE_ITEM;
|
behavior = Behavior::DESCRIBE_ITEM;
|
||||||
} else if (!strcmp(argv[x], "encode-item")) {
|
} else if (!strcmp(argv[x], "encode-item")) {
|
||||||
@@ -1438,11 +1443,12 @@ int main(int argc, char** argv) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Behavior::SHOW_EP3_DATA: {
|
case Behavior::SHOW_EP3_MAPS:
|
||||||
|
case Behavior::SHOW_EP3_CARDS: {
|
||||||
config_log.info("Collecting Episode 3 data");
|
config_log.info("Collecting Episode 3 data");
|
||||||
Episode3::DataIndex index("system/ep3", Episode3::BehaviorFlag::LOAD_CARD_TEXT);
|
Episode3::DataIndex index("system/ep3", Episode3::BehaviorFlag::LOAD_CARD_TEXT);
|
||||||
|
|
||||||
if (ep3_card_id == 0xFFFF) {
|
if (behavior == Behavior::SHOW_EP3_MAPS) {
|
||||||
auto map_ids = index.all_map_ids();
|
auto map_ids = index.all_map_ids();
|
||||||
log_info("%zu maps", map_ids.size());
|
log_info("%zu maps", map_ids.size());
|
||||||
for (uint32_t map_id : map_ids) {
|
for (uint32_t map_id : map_ids) {
|
||||||
@@ -1451,22 +1457,16 @@ int main(int argc, char** argv) {
|
|||||||
fprintf(stdout, "%s\n", s.c_str());
|
fprintf(stdout, "%s\n", s.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
auto card_ids = index.all_card_ids();
|
auto card_ids = index.all_card_ids();
|
||||||
log_info("%zu card definitions", card_ids.size());
|
log_info("%zu card definitions", card_ids.size());
|
||||||
for (uint32_t card_id : card_ids) {
|
for (uint32_t card_id : card_ids) {
|
||||||
auto entry = index.definition_for_card_id(card_id);
|
auto entry = index.definition_for_card_id(card_id);
|
||||||
string s = entry->def.str();
|
string s = entry->def.str(false);
|
||||||
string tags = entry->debug_tags.empty() ? "(none)" : join(entry->debug_tags, ", ");
|
string tags = entry->debug_tags.empty() ? "(none)" : join(entry->debug_tags, ", ");
|
||||||
string text = entry->text.empty() ? "(No text available)" : entry->text;
|
string text = entry->text.empty() ? "(No text available)" : str_replace_all(entry->text, "\n", "\n ");
|
||||||
fprintf(stdout, "%s\nTags: %s\n%s\n\n", s.c_str(), tags.c_str(), text.c_str());
|
fprintf(stdout, "%s\n Tags: %s\n Text:\n %s\n\n", s.c_str(), tags.c_str(), text.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
auto entry = index.definition_for_card_id(ep3_card_id);
|
|
||||||
string s = entry->def.str();
|
|
||||||
string tags = entry->debug_tags.empty() ? "(none)" : join(entry->debug_tags, ", ");
|
|
||||||
string text = entry->text.empty() ? "(No text available)" : entry->text;
|
|
||||||
fprintf(stdout, "%s\nTags: %s\n%s\n", s.c_str(), tags.c_str(), text.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user