|
|
@@ -34,10 +34,6 @@ int KernelDataInstaller::ReadCommands(){
|
|
|
int desc_offset = 0;
|
|
|
int command_count = 0;
|
|
|
|
|
|
- std::cout <<
|
|
|
- "-- Commands ------------------\n" <<
|
|
|
- "| ID | cur | c_s | c_m| tar |\n";
|
|
|
-
|
|
|
// There are exactly 32 commands. Some of them are blank, so there is not really a
|
|
|
// reliable exit condition.
|
|
|
for (int i = 0; i < 32; i ++){
|
|
|
@@ -116,14 +112,6 @@ int KernelDataInstaller::ReadCommands(){
|
|
|
commands_.push_back(data);
|
|
|
command_count ++;
|
|
|
}
|
|
|
-
|
|
|
- printf(
|
|
|
- "| %3d | %3d | %3d | %3d | ",
|
|
|
- i, data.camera_single, data.camera_multiple, data.target_raw
|
|
|
- );
|
|
|
- std::cout << data.name << ": " << data.description << std::endl;
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
|
|
|
return command_count;
|
|
|
@@ -153,10 +141,6 @@ int KernelDataInstaller::ReadAttacks(){
|
|
|
File attacks_file = kernel_.ExtractGZip(KERNEL_ATTACK_DATA);
|
|
|
int attack_count = 0;
|
|
|
|
|
|
- std::cout <<
|
|
|
- "-- Attacks ---------------------------------------------------------------------\n" <<
|
|
|
- "| ID | acc |tar | eff | dmg | pow | con | sch | eff | efm | sta | elm | spe |\n";
|
|
|
-
|
|
|
for (int i = 0; i < 128; i ++){
|
|
|
|
|
|
AttackData data;
|
|
|
@@ -309,15 +293,6 @@ int KernelDataInstaller::ReadAttacks(){
|
|
|
// Add to the list of items.
|
|
|
attacks_.push_back(data);
|
|
|
attack_count ++;
|
|
|
-
|
|
|
- printf(
|
|
|
- "| %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %5d |\n",
|
|
|
- i, data.accuracy, data.target_raw, data.effect, data.damage_raw, data.power, data.condition_raw,
|
|
|
- data.status_change_raw, data.additional_effects_raw, data.additional_effects_mod_raw,
|
|
|
- data.status_raw, data.element_raw, data.special_raw
|
|
|
- );
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
|
|
|
return attack_count;
|
|
|
@@ -389,10 +364,6 @@ int KernelDataInstaller::ReadCharacters(){
|
|
|
File characters_file = kernel_.ExtractGZip(KERNEL_BATTLE_AND_GROWTH_DATA);
|
|
|
int character_count = 0;
|
|
|
|
|
|
- std::cout <<
|
|
|
- "-- Chars ----\n" <<
|
|
|
- "| ID | lvl |\n";
|
|
|
-
|
|
|
for (int i = 0; i < 10; i ++){ // 9 characters
|
|
|
|
|
|
CharacterData data;
|
|
|
@@ -442,11 +413,6 @@ int KernelDataInstaller::ReadCharacters(){
|
|
|
// Add to the list of characters.
|
|
|
characters_.push_back(data);
|
|
|
character_count ++;
|
|
|
-
|
|
|
- printf("| %3d | %3d |", i, data.initial_level);
|
|
|
- std::cout << data.name << std::endl;
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
|
|
|
return character_count;
|
|
|
@@ -660,10 +626,6 @@ int KernelDataInstaller::ReadItems(){
|
|
|
int desc_offset = 0;
|
|
|
int item_count = 0;
|
|
|
|
|
|
- std::cout <<
|
|
|
- "-- Items ------------------------------------------------------------------\n" <<
|
|
|
- "| ID | tar | eff | dmg | pow | con | sch | eff | efm | sta | elm | spe |\n";
|
|
|
-
|
|
|
for (int i = 0; i < 128; i ++){
|
|
|
|
|
|
ItemData data;
|
|
|
@@ -736,17 +698,6 @@ int KernelDataInstaller::ReadItems(){
|
|
|
data.sellable = !(data.restrict_raw & (1 << 0));
|
|
|
data.useable_battle = !(data.restrict_raw & (2 << 0));
|
|
|
data.useable_menu = !(data.restrict_raw & (4 << 0));
|
|
|
- // TODO: XOR, not individual bits
|
|
|
- /*
|
|
|
- data.target.selection_enabled = data.target_raw & (0 << 0); // First bit...
|
|
|
- data.target.default_enemy = data.target_raw & (1 << 0);
|
|
|
- data.target.default_multiple = data.target_raw & (2 << 0);
|
|
|
- data.target.toggle_multiple = data.target_raw & (3 << 0);
|
|
|
- data.target.fixed_row = data.target_raw & (4 << 0);
|
|
|
- data.target.short_range = data.target_raw & (5 << 0);
|
|
|
- data.target.all_rows = data.target_raw & (6 << 0);
|
|
|
- data.target.random = data.target_raw & (7 << 0); // ... last bit.
|
|
|
- */
|
|
|
if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
|
|
|
else data.target.selection_enabled = false;
|
|
|
if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
|
|
|
@@ -763,21 +714,14 @@ int KernelDataInstaller::ReadItems(){
|
|
|
else data.target.all_rows = false;
|
|
|
if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
|
|
|
else data.target.random = false;
|
|
|
-
|
|
|
-
|
|
|
data.damage_formula = data.damage_raw >> 4; // Upper nybble.
|
|
|
data.damage_modifier = data.damage_raw & 15; // Lower nybble.
|
|
|
- /*data.condition.party_hp = data.condition_raw & (0 << 0); //First bit...
|
|
|
- data.condition.mp = data.condition_raw & (1 << 0);
|
|
|
- data.condition.party_status = data.condition_raw & (2 << 0); // ... last bit.*/
|
|
|
-
|
|
|
data.status.chance = 63 - (data.status_change_raw ^ 63); // Out of 63;
|
|
|
if (data.status_change_raw == (data.status_change_raw | 0x00000080))
|
|
|
data.status.mode = TOGGLE;
|
|
|
else if (data.status_change_raw == (data.status_change_raw | 0x00000040))
|
|
|
data.status.mode = CURE;
|
|
|
else data.status.mode = INFLICT;
|
|
|
-
|
|
|
switch (data.condition_raw){
|
|
|
case 0: data.restore_type = RESTORE_HP; break;
|
|
|
case 1: data.restore_type = RESTORE_MP; break;
|
|
|
@@ -878,20 +822,9 @@ int KernelDataInstaller::ReadItems(){
|
|
|
// If that happens, clear them all.
|
|
|
if (data.elements.size() == 16) data.elements.clear();
|
|
|
|
|
|
-
|
|
|
// Add to the list of items.
|
|
|
items_.push_back(data);
|
|
|
item_count ++;
|
|
|
-
|
|
|
- printf(
|
|
|
- "| %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d | %5d | ",
|
|
|
- i, data.target_raw, data.effect, data.damage_raw, data.power, data.condition_raw,
|
|
|
- data.status_change_raw, data.additional_effects_raw, data.additional_effects_mod_raw,
|
|
|
- data.status_raw, data.element_raw, data.special_raw
|
|
|
- );
|
|
|
- std::cout << data.name << ": " << data.description << std::endl;
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
|
|
|
return item_count;
|
|
|
@@ -964,10 +897,6 @@ int KernelDataInstaller::ReadWeapons(){
|
|
|
int desc_offset = 0;
|
|
|
int weapon_count = 0;
|
|
|
|
|
|
- std::cout <<
|
|
|
- "-- Weapons ----------------------------------------------------------------\n" <<
|
|
|
- "| ID | tar | eff | dmg | pow | con | sch | eff | efm | sta | elm | spe |\n";
|
|
|
-
|
|
|
for (int i = 0; i < 128; i ++){
|
|
|
|
|
|
WeaponData data;
|
|
|
@@ -1018,7 +947,7 @@ int KernelDataInstaller::ReadWeapons(){
|
|
|
// break the loop.
|
|
|
if ("" == data.name) break;
|
|
|
|
|
|
- // Read data from the item data section.
|
|
|
+ // Read data from the weapon data section.
|
|
|
data.target_raw = weapons_file.readU8();
|
|
|
data.unused_0 = weapons_file.readU8();
|
|
|
data.damage_raw = weapons_file.readU8();
|
|
|
@@ -1035,8 +964,8 @@ int KernelDataInstaller::ReadWeapons(){
|
|
|
data.equip_raw = weapons_file.readU16LE();
|
|
|
data.element_raw = weapons_file.readU16LE();
|
|
|
data.unused_3 = weapons_file.readU16LE();
|
|
|
- data.stat_raw = weapons_file.readU32LE();
|
|
|
- data.stat_bonus_raw = weapons_file.readU32LE();
|
|
|
+ for (int i = 0; i < 4; i ++) data.stat_raw[i] = weapons_file.readU8();
|
|
|
+ for (int i = 0; i < 4; i ++) data.stat_bonus_raw[i] = weapons_file.readU8();
|
|
|
for (int i = 0; i < 8; i ++) data.slots_raw[i] = weapons_file.readU8();
|
|
|
data.sound = weapons_file.readU8();
|
|
|
data.sound_critical = weapons_file.readU8();
|
|
|
@@ -1084,11 +1013,13 @@ int KernelDataInstaller::ReadWeapons(){
|
|
|
if (data.equip_raw == (data.equip_raw | 0x0100)) data.equip.push_back(9);
|
|
|
if (data.equip_raw == (data.equip_raw | 0x0200)) data.equip.push_back(10);
|
|
|
if (data.equip_raw == (data.equip_raw | 0x0400)) data.equip.push_back(11);
|
|
|
- if (data.stat_raw < 0XFF){
|
|
|
- StatBonus stat_bonus;
|
|
|
- stat_bonus.stat = data.stat_raw;
|
|
|
- stat_bonus.bonus = data.stat_bonus_raw;
|
|
|
- data.stat_bonus.push_back(stat_bonus);
|
|
|
+ for (int i = 0; i < 4; i ++){
|
|
|
+ if (data.stat_raw[i] < 0XFF && data.stat_bonus_raw[i] > 0){
|
|
|
+ StatBonus stat_bonus;
|
|
|
+ stat_bonus.stat = data.stat_raw[i];
|
|
|
+ stat_bonus.bonus = data.stat_bonus_raw[i];
|
|
|
+ data.stat_bonus.push_back(stat_bonus);
|
|
|
+ }
|
|
|
}
|
|
|
for (int i = 0; i < 8; i ++){
|
|
|
if (data.slots_raw[i] == 1 || data.slots_raw[i] == 5){
|
|
|
@@ -1186,6 +1117,16 @@ void KernelDataInstaller::WriteWeapons(std::string file){
|
|
|
}
|
|
|
xml_weapon->LinkEndChild(xml_slots.release());
|
|
|
}
|
|
|
+ if (weapon.stat_bonus.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stats(new TiXmlElement("stat_bonuses"));
|
|
|
+ for (StatBonus s : weapon.stat_bonus){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", s.stat);
|
|
|
+ xml_stat->SetAttribute("bonus", s.bonus);
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ xml_weapon->LinkEndChild(xml_stats.release());
|
|
|
+ }
|
|
|
if (weapon.equip.size() > 0){
|
|
|
std::unique_ptr<TiXmlElement> xml_characters(new TiXmlElement("characters"));
|
|
|
for (int s : weapon.equip){
|
|
|
@@ -1201,3 +1142,1074 @@ void KernelDataInstaller::WriteWeapons(std::string file){
|
|
|
xml.LinkEndChild(container.release());
|
|
|
xml.SaveFile(file);
|
|
|
}
|
|
|
+
|
|
|
+int KernelDataInstaller::ReadArmors(){
|
|
|
+
|
|
|
+ // Empty the item list
|
|
|
+ armors_.clear();
|
|
|
+
|
|
|
+ File armor_file = kernel_.ExtractGZip(KERNEL_ARMOR_DATA);
|
|
|
+ armor_file.WriteFile("/home/ivalentin/armor");
|
|
|
+ File armor_name_file = kernel_.ExtractGZip(KERNEL_ARMOR_NAMES);
|
|
|
+ File armor_desc_file = kernel_.ExtractGZip(KERNEL_ARMOR_DESCRIPTIONS);
|
|
|
+ int name_offset = 0;
|
|
|
+ int desc_offset = 0;
|
|
|
+ int armor_count = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < 32; i ++){ // There are exactly 32.
|
|
|
+
|
|
|
+ ArmorData data;
|
|
|
+
|
|
|
+ // From the current name file offset, read 16 bytes.
|
|
|
+ // This is the pointer to the offset for the item name.
|
|
|
+ // Start reading there until 0xFF is found.
|
|
|
+ data.name = "";
|
|
|
+ u8 ch = 1;
|
|
|
+ name_offset = armor_name_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = armor_name_file.GetU8(name_offset);
|
|
|
+ if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
|
|
|
+ name_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // For descriptions, do the same as for names.
|
|
|
+ data.description = "";
|
|
|
+ ch = 1;
|
|
|
+ desc_offset = armor_desc_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = armor_desc_file.GetU8(desc_offset);
|
|
|
+ if (ch != 0xFF){
|
|
|
+ // Warning: If the char is 0xF9, special function!
|
|
|
+ // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
|
|
|
+ // This is to compress information in the kernel.
|
|
|
+ if (ch == 0xF9){
|
|
|
+ // Get how much to read, two upper bits of the next byte.
|
|
|
+ // Multiply by 2 and add 4. That's just how it is.
|
|
|
+ u8 comp_size = (armor_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
|
|
|
+ // Get new offset, lower six bits of the next byte.
|
|
|
+ // The offset goes backwards from the position of the 0xF9 byte.
|
|
|
+ u8 comp_offset = armor_desc_file.GetU8(desc_offset + 1) & 63;
|
|
|
+
|
|
|
+ for (int i = 0; i < comp_size; i ++){
|
|
|
+ data.description += ENGLISH_CHARS[
|
|
|
+ armor_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+ else data.description += ENGLISH_CHARS[ch];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the item doesn't have a name, it means all items have been read.
|
|
|
+ // break the loop.
|
|
|
+ if ("" == data.name) break;
|
|
|
+
|
|
|
+ // Read data from the weapon data section.
|
|
|
+ data.unknown_0 = armor_file.readU8();
|
|
|
+ data.element_defense_mode = armor_file.readU8();
|
|
|
+ data.defense = armor_file.readU8();
|
|
|
+ data.m_defense = armor_file.readU8();
|
|
|
+ data.evasion = armor_file.readU8();
|
|
|
+ data.m_evasion = armor_file.readU8();
|
|
|
+ data.status = armor_file.readU8();
|
|
|
+ data.unknown_1 = armor_file.readU16LE();
|
|
|
+ for (int i = 0; i < 8; i ++) data.slots_raw[i] = armor_file.readU8();
|
|
|
+ data.growth = armor_file.readU8();
|
|
|
+ data.equip_raw = armor_file.readU16LE();
|
|
|
+ data.element_raw = armor_file.readU16LE();
|
|
|
+ data.unknown_2 = armor_file.readU16LE();
|
|
|
+ for (int i = 0; i < 4; i ++) data.stat_raw[i] = armor_file.readU8();
|
|
|
+ for (int i = 0; i < 4; i ++) data.stat_bonus_raw[i] = armor_file.readU8();
|
|
|
+ data.restrict_raw = armor_file.readU16LE();
|
|
|
+ data.unknown_3 = armor_file.readU16LE();
|
|
|
+
|
|
|
+ // Derive data from the read data.
|
|
|
+ data.id = i;
|
|
|
+ if (data.growth != 0 && data.growth != 2 && data.growth != 3) data.growth = 1;
|
|
|
+ data.sellable = !(data.restrict_raw & (1 << 0));
|
|
|
+ data.useable_battle = !(data.restrict_raw & (2 << 0));
|
|
|
+ data.useable_menu = !(data.restrict_raw & (4 << 0));
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0001)) data.equip.push_back(1);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0002)) data.equip.push_back(2);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0004)) data.equip.push_back(3);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0008)) data.equip.push_back(4);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0010)) data.equip.push_back(5);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0020)) data.equip.push_back(6);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0040)) data.equip.push_back(7);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0080)) data.equip.push_back(8);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0100)) data.equip.push_back(9);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0200)) data.equip.push_back(10);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0400)) data.equip.push_back(11);
|
|
|
+ for (int i = 0; i < 4; i ++){
|
|
|
+ if (data.stat_raw[i] < 0XFF && data.stat_bonus_raw[i] > 0){
|
|
|
+ StatBonus stat_bonus;
|
|
|
+ stat_bonus.stat = data.stat_raw[i];
|
|
|
+ stat_bonus.bonus = data.stat_bonus_raw[i];
|
|
|
+ data.stat_bonus.push_back(stat_bonus);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (int i = 0; i < 8; i ++){
|
|
|
+ if (data.slots_raw[i] == 1 || data.slots_raw[i] == 5){
|
|
|
+ data.materia_slots.push_back(SLOT_UNLINKED);
|
|
|
+ }
|
|
|
+ else if (
|
|
|
+ data.slots_raw[i] == 2 || data.slots_raw[i] == 3
|
|
|
+ || data.slots_raw[i] == 6 || data.slots_raw[i] == 7
|
|
|
+ ){
|
|
|
+ data.materia_slots.push_back(SLOT_LINKED);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // In KERNEL.BIN, items with no elemental defense actually do have all elements marked,
|
|
|
+ // with mode 255. If, that's the case, consider that there are no elements.
|
|
|
+ if (data.element_defense_mode != 0xFF){
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0200))
|
|
|
+ data.elements.push_back(RESTORATIVE);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
|
|
|
+ }
|
|
|
+ // In KERNEL.BIN, Non elemental item actually have all elements marked.
|
|
|
+ // If that happens, clear them all.
|
|
|
+ if (data.elements.size() == 16) data.elements.clear();
|
|
|
+
|
|
|
+ // Add to the list of weapons.
|
|
|
+ armors_.push_back(data);
|
|
|
+ armor_count ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return armor_count;
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::WriteArmors(std::string file){
|
|
|
+ TiXmlDocument xml;
|
|
|
+ std::unique_ptr<TiXmlElement> container(new TiXmlElement("armors"));
|
|
|
+ for (ArmorData armor : armors_){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_armor(new TiXmlElement("armor"));
|
|
|
+ xml_armor->SetAttribute("id", armor.id);
|
|
|
+ xml_armor->SetAttribute("name", armor.name);
|
|
|
+ xml_armor->SetAttribute("description", armor.description);
|
|
|
+ xml_armor->SetAttribute("sell", armor.sellable);
|
|
|
+ xml_armor->SetAttribute("battle", armor.useable_battle);
|
|
|
+ xml_armor->SetAttribute("menu", armor.useable_menu);
|
|
|
+ xml_armor->SetAttribute("phi_defense", armor.defense);
|
|
|
+ xml_armor->SetAttribute("mag_defense", armor.m_defense);
|
|
|
+ xml_armor->SetAttribute("phi_evasion", armor.evasion);
|
|
|
+ xml_armor->SetAttribute("mag_evasion", armor.m_evasion);
|
|
|
+ xml_armor->SetAttribute("growth", armor.growth);
|
|
|
+ // Statuses.
|
|
|
+ if (armor.status != 0XFF){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("statuses"));
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status_status(new TiXmlElement("status"));
|
|
|
+ xml_status_status->SetAttribute("id", armor.status);
|
|
|
+ xml_status->LinkEndChild(xml_status_status.release());
|
|
|
+ xml_armor->LinkEndChild(xml_status.release());
|
|
|
+ }
|
|
|
+ // Add elements.
|
|
|
+ if (armor.elements.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_elements(new TiXmlElement("elements"));
|
|
|
+ for (int s : armor.elements){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("element"));
|
|
|
+ xml_element->SetAttribute("id", s);
|
|
|
+ xml_element->SetAttribute("mode", armor.element_defense_mode);
|
|
|
+ xml_elements->LinkEndChild(xml_element.release());
|
|
|
+ }
|
|
|
+ xml_armor->LinkEndChild(xml_elements.release());
|
|
|
+ }
|
|
|
+ if (armor.materia_slots.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_slots(new TiXmlElement("slots"));
|
|
|
+ for (u8 slot : armor.materia_slots){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_slot(new TiXmlElement("slot"));
|
|
|
+ xml_slot->SetAttribute("type", slot);
|
|
|
+ xml_slots->LinkEndChild(xml_slot.release());
|
|
|
+ }
|
|
|
+ xml_armor->LinkEndChild(xml_slots.release());
|
|
|
+ }
|
|
|
+ if (armor.stat_bonus.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stats(new TiXmlElement("stat_bonuses"));
|
|
|
+ for (StatBonus s : armor.stat_bonus){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", s.stat);
|
|
|
+ xml_stat->SetAttribute("bonus", s.bonus);
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ xml_armor->LinkEndChild(xml_stats.release());
|
|
|
+ }
|
|
|
+ if (armor.equip.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_characters(new TiXmlElement("characters"));
|
|
|
+ for (int s : armor.equip){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_character(new TiXmlElement("character"));
|
|
|
+ xml_character->SetAttribute("id", s);
|
|
|
+ xml_characters->LinkEndChild(xml_character.release());
|
|
|
+ }
|
|
|
+ xml_armor->LinkEndChild(xml_characters.release());
|
|
|
+ }
|
|
|
+ container->LinkEndChild(xml_armor.release());
|
|
|
+
|
|
|
+ }
|
|
|
+ xml.LinkEndChild(container.release());
|
|
|
+ xml.SaveFile(file);
|
|
|
+}
|
|
|
+
|
|
|
+int KernelDataInstaller::ReadAccessories(){
|
|
|
+
|
|
|
+ // Empty the item list
|
|
|
+ accessories_.clear();
|
|
|
+
|
|
|
+ File accessory_file = kernel_.ExtractGZip(KERNEL_ACCESSORY_DATA);
|
|
|
+ File accessory_name_file = kernel_.ExtractGZip(KERNEL_ACCESSORY_NAMES);
|
|
|
+ File accessory_desc_file = kernel_.ExtractGZip(KERNEL_ACCESSORY_DESCRIPTIONS);
|
|
|
+ int name_offset = 0;
|
|
|
+ int desc_offset = 0;
|
|
|
+ int accessory_count = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < 32; i ++){ // There are exactly 32.
|
|
|
+
|
|
|
+ AccessoryData data;
|
|
|
+
|
|
|
+ // From the current name file offset, read 16 bytes.
|
|
|
+ // This is the pointer to the offset for the item name.
|
|
|
+ // Start reading there until 0xFF is found.
|
|
|
+ data.name = "";
|
|
|
+ u8 ch = 1;
|
|
|
+ name_offset = accessory_name_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = accessory_name_file.GetU8(name_offset);
|
|
|
+ if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
|
|
|
+ name_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // For descriptions, do the same as for names.
|
|
|
+ data.description = "";
|
|
|
+ ch = 1;
|
|
|
+ desc_offset = accessory_desc_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = accessory_desc_file.GetU8(desc_offset);
|
|
|
+ if (ch != 0xFF){
|
|
|
+ // Warning: If the char is 0xF9, special function!
|
|
|
+ // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
|
|
|
+ // This is to compress information in the kernel.
|
|
|
+ if (ch == 0xF9){
|
|
|
+ // Get how much to read, two upper bits of the next byte.
|
|
|
+ // Multiply by 2 and add 4. That's just how it is.
|
|
|
+ u8 comp_size = (accessory_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
|
|
|
+ // Get new offset, lower six bits of the next byte.
|
|
|
+ // The offset goes backwards from the position of the 0xF9 byte.
|
|
|
+ u8 comp_offset = accessory_desc_file.GetU8(desc_offset + 1) & 63;
|
|
|
+
|
|
|
+ for (int i = 0; i < comp_size; i ++){
|
|
|
+ data.description += ENGLISH_CHARS[
|
|
|
+ accessory_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+ else data.description += ENGLISH_CHARS[ch];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the item doesn't have a name, it means all items have been read.
|
|
|
+ // break the loop.
|
|
|
+ if ("" == data.name) break;
|
|
|
+
|
|
|
+ // Read data from the accessory data section.
|
|
|
+ for (int i = 0; i < 2; i ++) data.stat_raw[i] = accessory_file.readU8();
|
|
|
+ for (int i = 0; i < 2; i ++) data.stat_bonus_raw[i] = accessory_file.readU8();
|
|
|
+ data.element_defense_mode = accessory_file.readU8();
|
|
|
+ data.effect = accessory_file.readU8();
|
|
|
+ data.element_raw = accessory_file.readU16LE();
|
|
|
+ data.status_raw = accessory_file.readU32LE();
|
|
|
+ data.equip_raw = accessory_file.readU16LE();
|
|
|
+ data.restrict_raw = accessory_file.readU16LE();
|
|
|
+
|
|
|
+ // Derive data from the read data.
|
|
|
+ data.id = i;
|
|
|
+ data.sellable = !(data.restrict_raw & (1 << 0));
|
|
|
+ data.useable_battle = !(data.restrict_raw & (2 << 0));
|
|
|
+ data.useable_menu = !(data.restrict_raw & (4 << 0));
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000001)) data.status.push_back(DEATH);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000002)) data.status.push_back(NEAR_DEATH);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000004)) data.status.push_back(SLEEP);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000008)) data.status.push_back(POISONED);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000010)) data.status.push_back(SADNESS);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000020)) data.status.push_back(FURY);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000040)) data.status.push_back(CONFU);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000080)) data.status.push_back(SILENCE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000100)) data.status.push_back(HASTE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000200)) data.status.push_back(SLOW);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000400)) data.status.push_back(STOP);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00000800)) data.status.push_back(FROG);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00001000)) data.status.push_back(SMALL);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00002000)) data.status.push_back(SLOW_NUMB);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00004000)) data.status.push_back(PETRIFY);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00008000)) data.status.push_back(REGEN);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00010000)) data.status.push_back(BARRIER);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00020000)) data.status.push_back(M_BARRIER);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00040000)) data.status.push_back(REFLECT);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00080000)) data.status.push_back(DUAL);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00100000)) data.status.push_back(SHIELD);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00200000)) data.status.push_back(D_SENTENCE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00400000)) data.status.push_back(MANIPULATE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x00800000)) data.status.push_back(BERSERK);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x01000000)) data.status.push_back(PEERLESS);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x02000000)) data.status.push_back(PARALYSIS);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x04000000)) data.status.push_back(DARKNESS);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x08000000)) data.status.push_back(DUAL_DRAIN);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x10000000)) data.status.push_back(DEATH_FORCE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x20000000)) data.status.push_back(RESIST);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x40000000)) data.status.push_back(LUCKY_GIRL);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x80000000)) data.status.push_back(IMPRISONED);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0001)) data.equip.push_back(1);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0002)) data.equip.push_back(2);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0004)) data.equip.push_back(3);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0008)) data.equip.push_back(4);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0010)) data.equip.push_back(5);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0020)) data.equip.push_back(6);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0040)) data.equip.push_back(7);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0080)) data.equip.push_back(8);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0100)) data.equip.push_back(9);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0200)) data.equip.push_back(10);
|
|
|
+ if (data.equip_raw == (data.equip_raw | 0x0400)) data.equip.push_back(11);
|
|
|
+ for (int i = 0; i < 2; i ++){
|
|
|
+ if (data.stat_raw[i] < 0XFF && data.stat_bonus_raw[i] > 0){
|
|
|
+ StatBonus stat_bonus;
|
|
|
+ stat_bonus.stat = data.stat_raw[i];
|
|
|
+ stat_bonus.bonus = data.stat_bonus_raw[i];
|
|
|
+ data.stat_bonus.push_back(stat_bonus);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // In KERNEL.BIN, items with no elemental defense actually do have all elements marked,
|
|
|
+ // with mode 255. If that's the case, consider that there are no elements.
|
|
|
+ if (data.element_defense_mode != 0xFF){
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0200))
|
|
|
+ data.elements.push_back(RESTORATIVE);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
|
|
|
+ if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
|
|
|
+ }
|
|
|
+ // In KERNEL.BIN, Non elemental item actually have all elements marked.
|
|
|
+ // If that happens, clear them all.
|
|
|
+ if (data.elements.size() == 16) data.elements.clear();
|
|
|
+
|
|
|
+ // Add to the list of weapons.
|
|
|
+ accessories_.push_back(data);
|
|
|
+ accessory_count ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return accessory_count;
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::WriteAccessories(std::string file){
|
|
|
+ TiXmlDocument xml;
|
|
|
+ std::unique_ptr<TiXmlElement> container(new TiXmlElement("accessories"));
|
|
|
+ for (AccessoryData accessory : accessories_){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_accessory(new TiXmlElement("accessory"));
|
|
|
+ xml_accessory->SetAttribute("id", accessory.id);
|
|
|
+ xml_accessory->SetAttribute("name", accessory.name);
|
|
|
+ xml_accessory->SetAttribute("description", accessory.description);
|
|
|
+ xml_accessory->SetAttribute("sell", accessory.sellable);
|
|
|
+ xml_accessory->SetAttribute("battle", accessory.useable_battle);
|
|
|
+ xml_accessory->SetAttribute("menu", accessory.useable_menu);
|
|
|
+ // Special effect
|
|
|
+ if (accessory.effect != 0XFF){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("special_effects"));
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status_status(new TiXmlElement("effect"));
|
|
|
+ xml_status_status->SetAttribute("id", accessory.effect);
|
|
|
+ xml_status->LinkEndChild(xml_status_status.release());
|
|
|
+ xml_accessory->LinkEndChild(xml_status.release());
|
|
|
+ }
|
|
|
+ // Statuses.
|
|
|
+ if (accessory.status.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("statuses"));
|
|
|
+ for (int s : accessory.status){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status_status(new TiXmlElement("status"));
|
|
|
+ xml_status_status->SetAttribute("id", s);
|
|
|
+ xml_status->LinkEndChild(xml_status_status.release());
|
|
|
+ }
|
|
|
+ xml_accessory->LinkEndChild(xml_status.release());
|
|
|
+ }
|
|
|
+ // Add elements.
|
|
|
+ if (accessory.elements.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_elements(new TiXmlElement("elements"));
|
|
|
+ for (int s : accessory.elements){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("element"));
|
|
|
+ xml_element->SetAttribute("id", s);
|
|
|
+ xml_element->SetAttribute("mode", accessory.element_defense_mode);
|
|
|
+ xml_elements->LinkEndChild(xml_element.release());
|
|
|
+ }
|
|
|
+ xml_accessory->LinkEndChild(xml_elements.release());
|
|
|
+ }
|
|
|
+ if (accessory.stat_bonus.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stats(new TiXmlElement("stat_bonuses"));
|
|
|
+ for (StatBonus s : accessory.stat_bonus){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", s.stat);
|
|
|
+ xml_stat->SetAttribute("bonus", s.bonus);
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ xml_accessory->LinkEndChild(xml_stats.release());
|
|
|
+ }
|
|
|
+ if (accessory.equip.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_characters(new TiXmlElement("characters"));
|
|
|
+ for (int s : accessory.equip){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_character(new TiXmlElement("character"));
|
|
|
+ xml_character->SetAttribute("id", s);
|
|
|
+ xml_characters->LinkEndChild(xml_character.release());
|
|
|
+ }
|
|
|
+ xml_accessory->LinkEndChild(xml_characters.release());
|
|
|
+ }
|
|
|
+ container->LinkEndChild(xml_accessory.release());
|
|
|
+
|
|
|
+ }
|
|
|
+ xml.LinkEndChild(container.release());
|
|
|
+ xml.SaveFile(file);
|
|
|
+}
|
|
|
+
|
|
|
+int KernelDataInstaller::ReadMateria(){
|
|
|
+
|
|
|
+ // Empty the item list
|
|
|
+ materia_.clear();
|
|
|
+
|
|
|
+ File materia_file = kernel_.ExtractGZip(KERNEL_MATERIA_DATA);
|
|
|
+ File materia_name_file = kernel_.ExtractGZip(KERNEL_MATERIA_NAMES);
|
|
|
+ File materia_desc_file = kernel_.ExtractGZip(KERNEL_MATERIA_DESCRIPTIONS);
|
|
|
+ int name_offset = 0;
|
|
|
+ int desc_offset = 0;
|
|
|
+ int materia_count = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < 96; i ++){ // There are exactly 96.
|
|
|
+
|
|
|
+ MateriaData data;
|
|
|
+
|
|
|
+ // From the current name file offset, read 16 bytes.
|
|
|
+ // This is the pointer to the offset for the item name.
|
|
|
+ // Start reading there until 0xFF is found.
|
|
|
+ data.name = "";
|
|
|
+ u8 ch = 1;
|
|
|
+ name_offset = materia_name_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = materia_name_file.GetU8(name_offset);
|
|
|
+ if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
|
|
|
+ name_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // For descriptions, do the same as for names.
|
|
|
+ data.description = "";
|
|
|
+ ch = 1;
|
|
|
+ desc_offset = materia_desc_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = materia_desc_file.GetU8(desc_offset);
|
|
|
+ if (ch != 0xFF){
|
|
|
+ // Warning: If the char is 0xF9, special function!
|
|
|
+ // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
|
|
|
+ // This is to compress information in the kernel.
|
|
|
+ if (ch == 0xF9){
|
|
|
+ // Get how much to read, two upper bits of the next byte.
|
|
|
+ // Multiply by 2 and add 4. That's just how it is.
|
|
|
+ u8 comp_size = (materia_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
|
|
|
+ // Get new offset, lower six bits of the next byte.
|
|
|
+ // The offset goes backwards from the position of the 0xF9 byte.
|
|
|
+ u8 comp_offset = materia_desc_file.GetU8(desc_offset + 1) & 63;
|
|
|
+
|
|
|
+ for (int i = 0; i < comp_size; i ++){
|
|
|
+ data.description += ENGLISH_CHARS[
|
|
|
+ materia_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+ else data.description += ENGLISH_CHARS[ch];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read data from the materia data section.
|
|
|
+ for (int i = 0; i < 4; i ++) data.level_up_ap[i] = materia_file.readU16LE();
|
|
|
+ data.stat_raw = materia_file.readU8();
|
|
|
+ data.status_raw // WARNING: Status has only three bytes.
|
|
|
+ = materia_file.readU8() + (materia_file.readU8() << 8) + (materia_file.readU8() << 16);
|
|
|
+ data.element = materia_file.readU8();
|
|
|
+ data.type_raw = materia_file.readU8();
|
|
|
+ for (int i = 0; i < 6; i ++) data.attribute[i] = materia_file.readU8();
|
|
|
+
|
|
|
+ // If the materia doesn't have a name, don't bother processing the rest of the data,
|
|
|
+ // it's not going to be added to the list.
|
|
|
+ if ("" == data.name) continue;
|
|
|
+
|
|
|
+ // Derive data from the read data.
|
|
|
+ data.id = i;
|
|
|
+ // Status. 3 bytes, so only the first 24 can be present.
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000001)) data.status.push_back(DEATH);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000002)) data.status.push_back(NEAR_DEATH);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000004)) data.status.push_back(SLEEP);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000008)) data.status.push_back(POISONED);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000010)) data.status.push_back(SADNESS);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000020)) data.status.push_back(FURY);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000040)) data.status.push_back(CONFU);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000080)) data.status.push_back(SILENCE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000100)) data.status.push_back(HASTE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000200)) data.status.push_back(SLOW);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000400)) data.status.push_back(STOP);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x000800)) data.status.push_back(FROG);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x001000)) data.status.push_back(SMALL);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x002000)) data.status.push_back(SLOW_NUMB);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x004000)) data.status.push_back(PETRIFY);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x008000)) data.status.push_back(REGEN);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x010000)) data.status.push_back(BARRIER);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x020000)) data.status.push_back(M_BARRIER);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x040000)) data.status.push_back(REFLECT);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x080000)) data.status.push_back(DUAL);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x100000)) data.status.push_back(SHIELD);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x200000)) data.status.push_back(D_SENTENCE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x400000)) data.status.push_back(MANIPULATE);
|
|
|
+ if (data.status_raw == (data.status_raw | 0x800000)) data.status.push_back(BERSERK);
|
|
|
+ // Limit type to materia color.
|
|
|
+ data.type = data.type_raw & 15; // Lower nybble.
|
|
|
+ switch (data.type){
|
|
|
+ case 0x09:
|
|
|
+ case 0x0A:
|
|
|
+ data.type = static_cast<int>(MATERIA_TYPE::MAGIC);
|
|
|
+ break;
|
|
|
+ case 0x05:
|
|
|
+ data.type = static_cast<int>(MATERIA_TYPE::SUPPORT);
|
|
|
+ break;
|
|
|
+ case 0x02:
|
|
|
+ case 0x03:
|
|
|
+ case 0x06:
|
|
|
+ case 0x07:
|
|
|
+ case 0x08:
|
|
|
+ data.type = static_cast<int>(MATERIA_TYPE::COMMAND);
|
|
|
+ break;
|
|
|
+ case 0x0B:
|
|
|
+ case 0x0C:
|
|
|
+ data.type = static_cast<int>(MATERIA_TYPE::SUMMON);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ data.type = static_cast<int>(MATERIA_TYPE::INDEPENDENT);
|
|
|
+ }
|
|
|
+ // Stat bonuses. Manually done.
|
|
|
+ data.stats.str = 0;
|
|
|
+ data.stats.vit = 0;
|
|
|
+ data.stats.mag = 0;
|
|
|
+ data.stats.spr = 0;
|
|
|
+ data.stats.dex = 0;
|
|
|
+ data.stats.lck = 0;
|
|
|
+ data.stats.hp = 0;
|
|
|
+ data.stats.mp = 0;
|
|
|
+ data.stats.change = false;
|
|
|
+ switch (data.stat_raw){
|
|
|
+ case 0x01:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.str = -2;
|
|
|
+ data.stats.vit = -1;
|
|
|
+ data.stats.mag = 2;
|
|
|
+ data.stats.spr = 1;
|
|
|
+ data.stats.dex = 0;
|
|
|
+ data.stats.lck = 0;
|
|
|
+ data.stats.hp = -5;
|
|
|
+ data.stats.mp = 5;
|
|
|
+ break;
|
|
|
+ case 0x02:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.str = -4;
|
|
|
+ data.stats.vit = -2;
|
|
|
+ data.stats.mag = 4;
|
|
|
+ data.stats.spr = 2;
|
|
|
+ data.stats.hp = -10;
|
|
|
+ data.stats.mp = 10;
|
|
|
+ break;
|
|
|
+ case 0x03:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.dex = 2;
|
|
|
+ data.stats.lck = -2;
|
|
|
+ break;
|
|
|
+ case 0x04:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.str = -1;
|
|
|
+ data.stats.vit = -1;
|
|
|
+ data.stats.mag = 1;
|
|
|
+ data.stats.spr = 1;
|
|
|
+ break;
|
|
|
+ case 0x05:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.str = 1;
|
|
|
+ data.stats.vit = 1;
|
|
|
+ data.stats.mag = -1;
|
|
|
+ data.stats.spr = -1;
|
|
|
+ break;
|
|
|
+ case 0x06:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.vit = 1;
|
|
|
+ break;
|
|
|
+ case 0x07:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.lck = 1;
|
|
|
+ break;
|
|
|
+ case 0x08:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.lck = -1;
|
|
|
+ break;
|
|
|
+ case 0x09:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.dex = -2;
|
|
|
+ break;
|
|
|
+ case 0x0A:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.dex = 2;
|
|
|
+ break;
|
|
|
+ case 0x0B:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.str = -1;
|
|
|
+ data.stats.mag = 1;
|
|
|
+ data.stats.hp = -2;
|
|
|
+ data.stats.mp = 2;
|
|
|
+ break;
|
|
|
+ case 0x0C:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.mag = 1;
|
|
|
+ data.stats.hp = -2;
|
|
|
+ data.stats.mp = 2;
|
|
|
+ break;
|
|
|
+ case 0x0D:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.mag = 1;
|
|
|
+ data.stats.spr = 1;
|
|
|
+ data.stats.hp = -5;
|
|
|
+ data.stats.mp = 5;
|
|
|
+ break;
|
|
|
+ case 0x0E:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.mag = 2;
|
|
|
+ data.stats.spr = 2;
|
|
|
+ data.stats.hp = -10;
|
|
|
+ data.stats.mp = 10;
|
|
|
+ break;
|
|
|
+ case 0x0F:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.mag = 4;
|
|
|
+ data.stats.spr = 4;
|
|
|
+ data.stats.hp = -10;
|
|
|
+ data.stats.mp = 15;
|
|
|
+ break;
|
|
|
+ case 0x10:
|
|
|
+ data.stats.change = true;
|
|
|
+ data.stats.mag = 8;
|
|
|
+ data.stats.spr = 8;
|
|
|
+ data.stats.hp = -10;
|
|
|
+ data.stats.mp = 20;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add to the list of materia.
|
|
|
+ materia_.push_back(data);
|
|
|
+ materia_count ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return materia_count;
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::WriteMateria(std::string file){
|
|
|
+ TiXmlDocument xml;
|
|
|
+ std::unique_ptr<TiXmlElement> container(new TiXmlElement("materias"));
|
|
|
+ for (MateriaData materia : materia_){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_materia(new TiXmlElement("materia"));
|
|
|
+ xml_materia->SetAttribute("id", materia.id);
|
|
|
+ xml_materia->SetAttribute("name", materia.name);
|
|
|
+ xml_materia->SetAttribute("description", materia.description);
|
|
|
+ xml_materia->SetAttribute("type", materia.type);
|
|
|
+ // Levels.
|
|
|
+ std::unique_ptr<TiXmlElement> xml_levels(new TiXmlElement("levels"));
|
|
|
+ std::unique_ptr<TiXmlElement> xml_level(new TiXmlElement("level"));
|
|
|
+ xml_level->SetAttribute("level", 1);
|
|
|
+ xml_level->SetAttribute("ap", 0);
|
|
|
+ xml_levels->LinkEndChild(xml_level.release());
|
|
|
+ for (int i = 0; i < 4; i ++){
|
|
|
+ if (materia.level_up_ap[i] < 65535){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_level(new TiXmlElement("level"));
|
|
|
+ xml_level->SetAttribute("level", i + 2);
|
|
|
+ xml_level->SetAttribute("ap", materia.level_up_ap[i] * 100);
|
|
|
+ xml_levels->LinkEndChild(xml_level.release());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ xml_materia->LinkEndChild(xml_levels.release());
|
|
|
+
|
|
|
+ // Statuses.
|
|
|
+ if (materia.status.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("statuses"));
|
|
|
+ for (int s : materia.status){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status_status(new TiXmlElement("status"));
|
|
|
+ xml_status_status->SetAttribute("id", s);
|
|
|
+ xml_status->LinkEndChild(xml_status_status.release());
|
|
|
+ }
|
|
|
+ xml_materia->LinkEndChild(xml_status.release());
|
|
|
+ }
|
|
|
+ // Add elements.
|
|
|
+ if (materia.element != 0xFF){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_elements(new TiXmlElement("elements"));
|
|
|
+ std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("element"));
|
|
|
+ xml_element->SetAttribute("id", materia.element);
|
|
|
+ xml_elements->LinkEndChild(xml_element.release());
|
|
|
+ xml_materia->LinkEndChild(xml_elements.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.change == true){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stats(new TiXmlElement("stat_bonuses"));
|
|
|
+ // TODO: Lookup stat IDs.
|
|
|
+ if (materia.stats.str != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 0);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.str);
|
|
|
+ xml_stat->SetAttribute("mode", "abs");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.vit != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 1);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.vit);
|
|
|
+ xml_stat->SetAttribute("mode", "abs");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.mag != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 2);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.mag);
|
|
|
+ xml_stat->SetAttribute("mode", "abs");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.spr != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 3);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.spr);
|
|
|
+ xml_stat->SetAttribute("mode", "abs");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.dex != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 4);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.dex);
|
|
|
+ xml_stat->SetAttribute("mode", "abs");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.lck != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 5);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.lck);
|
|
|
+ xml_stat->SetAttribute("mode", "abs");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.hp != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 6);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.hp);
|
|
|
+ xml_stat->SetAttribute("mode", "rel");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ if (materia.stats.mp != 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_stat(new TiXmlElement("stat_bonus"));
|
|
|
+ xml_stat->SetAttribute("stat", 7);
|
|
|
+ xml_stat->SetAttribute("bonus", materia.stats.mp);
|
|
|
+ xml_stat->SetAttribute("mode", "rel");
|
|
|
+ xml_stats->LinkEndChild(xml_stat.release());
|
|
|
+ }
|
|
|
+ xml_materia->LinkEndChild(xml_stats.release());
|
|
|
+ }
|
|
|
+ container->LinkEndChild(xml_materia.release());
|
|
|
+
|
|
|
+ }
|
|
|
+ xml.LinkEndChild(container.release());
|
|
|
+ xml.SaveFile(file);
|
|
|
+}
|
|
|
+
|
|
|
+int KernelDataInstaller::ReadKeyItems(){
|
|
|
+
|
|
|
+ // Empty the item list
|
|
|
+ key_items_.clear();
|
|
|
+
|
|
|
+ File key_items_name_file = kernel_.ExtractGZip(KERNEL_KEY_ITEM_NAMES);
|
|
|
+ File key_items_desc_file = kernel_.ExtractGZip(KERNEL_KEY_ITEM_DESCRIPTIONS);
|
|
|
+ int name_offset = 0;
|
|
|
+ int desc_offset = 0;
|
|
|
+ int key_item_count = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < 128; i ++){
|
|
|
+
|
|
|
+ KeyItemData data;
|
|
|
+
|
|
|
+ // From the current name file offset, read 16 bytes.
|
|
|
+ // This is the pointer to the offset for the item name.
|
|
|
+ // Start reading there until 0xFF is found.
|
|
|
+ data.name = "";
|
|
|
+ u8 ch = 1;
|
|
|
+ name_offset = key_items_name_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = key_items_name_file.GetU8(name_offset);
|
|
|
+ if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
|
|
|
+ name_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // For descriptions, do the same as for names.
|
|
|
+ data.description = "";
|
|
|
+ ch = 1;
|
|
|
+ desc_offset = key_items_desc_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = key_items_desc_file.GetU8(desc_offset);
|
|
|
+ if (ch != 0xFF){
|
|
|
+ // Warning: If the char is 0xF9, special function!
|
|
|
+ // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
|
|
|
+ // This is to compress information in the kernel.
|
|
|
+ if (ch == 0xF9){
|
|
|
+ // Get how much to read, two upper bits of the next byte.
|
|
|
+ // Multiply by 2 and add 4. That's just how it is.
|
|
|
+ u8 comp_size = (key_items_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
|
|
|
+ // Get new offset, lower six bits of the next byte.
|
|
|
+ // The offset goes backwards from the position of the 0xF9 byte.
|
|
|
+ u8 comp_offset = key_items_desc_file.GetU8(desc_offset + 1) & 63;
|
|
|
+
|
|
|
+ for (int i = 0; i < comp_size; i ++){
|
|
|
+ data.description += ENGLISH_CHARS[
|
|
|
+ key_items_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+ else data.description += ENGLISH_CHARS[ch];
|
|
|
+ }
|
|
|
+ desc_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the key item doesn't have a name, it means all key items have been read.
|
|
|
+ // break the loop.
|
|
|
+ if ("" == data.name) break;
|
|
|
+
|
|
|
+ // Add to the list of items.
|
|
|
+ data.id = i;
|
|
|
+ key_items_.push_back(data);
|
|
|
+ key_item_count ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return key_item_count;
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::WriteKeyItems(std::string file){
|
|
|
+ TiXmlDocument xml;
|
|
|
+ std::unique_ptr<TiXmlElement> container(new TiXmlElement("key_items"));
|
|
|
+ for (KeyItemData key_item : key_items_){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_key_item(new TiXmlElement("key_item"));
|
|
|
+ xml_key_item->SetAttribute("id", key_item.id);
|
|
|
+ xml_key_item->SetAttribute("name", key_item.name);
|
|
|
+ xml_key_item->SetAttribute("description", key_item.description);
|
|
|
+ container->LinkEndChild(xml_key_item.release());
|
|
|
+
|
|
|
+ }
|
|
|
+ xml.LinkEndChild(container.release());
|
|
|
+ xml.SaveFile(file);
|
|
|
+}
|
|
|
+
|
|
|
+int KernelDataInstaller::ReadSummonNames(){
|
|
|
+
|
|
|
+ // Empty the summon list
|
|
|
+ key_items_.clear();
|
|
|
+
|
|
|
+ File summon_name_file = kernel_.ExtractGZip(KERNEL_SUMMON_ATTACK_NAMES);
|
|
|
+ int name_offset = 0;
|
|
|
+ int summon_count = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < 16; i ++){ // There are exactly 16.
|
|
|
+
|
|
|
+ SummonNameData data;
|
|
|
+
|
|
|
+ // From the current name file offset, read 16 bytes.
|
|
|
+ // This is the pointer to the offset for the item name.
|
|
|
+ // Start reading there until 0xFF is found.
|
|
|
+ data.name = "";
|
|
|
+ u8 ch = 1;
|
|
|
+ name_offset = summon_name_file.readU16LE();
|
|
|
+ while (ch != 0xFF){
|
|
|
+ ch = summon_name_file.GetU8(name_offset);
|
|
|
+ if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
|
|
|
+ name_offset ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the key item doesn't have a name, it means all key items have been read.
|
|
|
+ // break the loop.
|
|
|
+ if ("" == data.name) break;
|
|
|
+
|
|
|
+ // Add to the list of items.
|
|
|
+ data.id = i;
|
|
|
+ summon_names_.push_back(data);
|
|
|
+ summon_count ++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return summon_count;
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::WriteSummonNames(std::string file){
|
|
|
+ TiXmlDocument xml;
|
|
|
+ std::unique_ptr<TiXmlElement> container(new TiXmlElement("summons"));
|
|
|
+ for (SummonNameData summon : summon_names_){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_summon(new TiXmlElement("summon"));
|
|
|
+ xml_summon->SetAttribute("id", summon.id);
|
|
|
+ xml_summon->SetAttribute("name", summon.name);
|
|
|
+ container->LinkEndChild(xml_summon.release());
|
|
|
+
|
|
|
+ }
|
|
|
+ xml.LinkEndChild(container.release());
|
|
|
+ xml.SaveFile(file);
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::ReadInitialSaveMap(){
|
|
|
+
|
|
|
+ // Empty the item list
|
|
|
+ attacks_.clear();
|
|
|
+
|
|
|
+ File savemap_file = kernel_.ExtractGZip(KERNEL_ATTACK_DATA);
|
|
|
+
|
|
|
+ savemap_.checksum = savemap_file.readU32LE();
|
|
|
+ for (int i = 0; i < 68; i ++) savemap_.preview[i] = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_left.red = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_left.green = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_left.blue = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_right.red = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_right.green = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_right.blue = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.top_left.red = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.bottom_left.green = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.bottom_left.blue = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.bottom_right.red = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.bottom_right.green = savemap_file.readU8();
|
|
|
+ savemap_.window_colour.bottom_right.blue = savemap_file.readU8();
|
|
|
+ for (int i = 0; i < 9; i ++){
|
|
|
+ savemap_.characters[i].identifier = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].level = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].str = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].vit = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].mag = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].spr = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].dex = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].lck = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].str_bonus = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].vit_bonus = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].mag_bonus = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].spr_bonus = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].dex_bonus = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].lck_bonus = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].limit_level = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].limit_bar = savemap_file.readU8();
|
|
|
+ bool name_end = false;
|
|
|
+ savemap_.characters[i].name = "";
|
|
|
+ for (int j = 0; j < 12; j ++){
|
|
|
+ savemap_.characters[i].name_raw[i] = savemap_file.readU8();
|
|
|
+ if (name_end == false){
|
|
|
+ if (savemap_.characters[i].name_raw[i] != 0XFF){
|
|
|
+ savemap_.characters[i].name
|
|
|
+ += ENGLISH_CHARS[savemap_.characters[i].name_raw[i]];
|
|
|
+ }
|
|
|
+ else name_end = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ savemap_.characters[i].weapon = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].armor = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].accessory = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].status_raw = savemap_file.readU8();
|
|
|
+ if (savemap_.characters[i].status_raw == (savemap_.characters[i].status_raw | 0x10)){
|
|
|
+ savemap_.characters[i].sadness = true;
|
|
|
+ savemap_.characters[i].fury = false;
|
|
|
+ }
|
|
|
+ else if (savemap_.characters[i].status_raw == (savemap_.characters[i].status_raw | 0x20)){
|
|
|
+ savemap_.characters[i].sadness = false;
|
|
|
+ savemap_.characters[i].fury = true;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ savemap_.characters[i].sadness = false;
|
|
|
+ savemap_.characters[i].fury = false;
|
|
|
+ }
|
|
|
+ savemap_.characters[i].row_raw = savemap_file.readU8();
|
|
|
+ if (savemap_.characters[i].row_raw == 0xFE) savemap_.characters[i].back_row = true;
|
|
|
+ else savemap_.characters[i].back_row = false;
|
|
|
+ savemap_.characters[i].level_progress = savemap_file.readU8();
|
|
|
+ savemap_.characters[i].learned_limits_raw = savemap_file.readU16LE();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void KernelDataInstaller::WriteInitialSaveMap(std::string file){
|
|
|
+ TiXmlDocument xml;
|
|
|
+ std::unique_ptr<TiXmlElement> container(new TiXmlElement("attacks"));
|
|
|
+ for (AttackData attack : attacks_){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_attack(new TiXmlElement("attack"));
|
|
|
+ xml_attack->SetAttribute("id", attack.id);
|
|
|
+ xml_attack->SetAttribute("accuracy", attack.accuracy);
|
|
|
+ xml_attack->SetAttribute("impact_effect", attack.impact_effect);
|
|
|
+ xml_attack->SetAttribute("hurt_anim", attack.hurt_anim);
|
|
|
+ xml_attack->SetAttribute("mp", attack.mp);
|
|
|
+ xml_attack->SetAttribute("sounds", attack.sound);
|
|
|
+ xml_attack->SetAttribute("camera_1", attack.camera_single);
|
|
|
+ xml_attack->SetAttribute("camera_x", attack.camera_multiple);
|
|
|
+ xml_attack->SetAttribute("effect", attack.effect);
|
|
|
+ xml_attack->SetAttribute("dmg_formula", attack.damage_formula);
|
|
|
+ xml_attack->SetAttribute("dmg_modifier", attack.damage_modifier);
|
|
|
+ xml_attack->SetAttribute("power", attack.power);
|
|
|
+ xml_attack->SetAttribute("restore", attack.restore_type);
|
|
|
+ xml_attack->SetAttribute("target_select", attack.target.selection_enabled);
|
|
|
+ xml_attack->SetAttribute("target_default_enemy", attack.target.default_enemy);
|
|
|
+ xml_attack->SetAttribute("target_default_multiple", attack.target.default_multiple);
|
|
|
+ xml_attack->SetAttribute("target_toggle_multiple", attack.target.toggle_multiple);
|
|
|
+ xml_attack->SetAttribute("target_fixed", attack.target.fixed_row);
|
|
|
+ xml_attack->SetAttribute("target_short_range", attack.target.short_range);
|
|
|
+ xml_attack->SetAttribute("target_all", attack.target.all_rows);
|
|
|
+ xml_attack->SetAttribute("target_random", attack.target.random);
|
|
|
+ // Statuses.
|
|
|
+ if (attack.status.status.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status(new TiXmlElement("statuses"));
|
|
|
+ xml_status->SetAttribute("mode", attack.status.mode);
|
|
|
+ xml_status->SetAttribute("chance", attack.status.chance);
|
|
|
+ for (int s : attack.status.status){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_status_status(new TiXmlElement("status"));
|
|
|
+ xml_status_status->SetAttribute("id", s);
|
|
|
+ xml_status->LinkEndChild(xml_status_status.release());
|
|
|
+ }
|
|
|
+ xml_attack->LinkEndChild(xml_status.release());
|
|
|
+ }
|
|
|
+ // Add elements.
|
|
|
+ if (attack.elements.size() > 0){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_elements(new TiXmlElement("elements"));
|
|
|
+ for (int s : attack.elements){
|
|
|
+ std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("element"));
|
|
|
+ xml_element->SetAttribute("id", s);
|
|
|
+ xml_elements->LinkEndChild(xml_element.release());
|
|
|
+ }
|
|
|
+ xml_attack->LinkEndChild(xml_elements.release());
|
|
|
+ }
|
|
|
+
|
|
|
+ container->LinkEndChild(xml_attack.release());
|
|
|
+
|
|
|
+ }
|
|
|
+ xml.LinkEndChild(container.release());
|
|
|
+ xml.SaveFile(file);
|
|
|
+}
|