KernelDataInstaller.cpp 99 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <tinyxml.h>
  16. #include <fstream>
  17. #include <iostream>
  18. #include "KernelDataInstaller.h"
  19. #include "common/FinalFantasy7/FF7NameLookup.h"
  20. #include <boost/algorithm/string/replace.hpp>
  21. KernelDataInstaller::KernelDataInstaller(std::string path): kernel_(path){
  22. for (int i = 0; i < 416; i ++) prices_[i] = 50;
  23. }
  24. KernelDataInstaller::~KernelDataInstaller(){}
  25. void KernelDataInstaller::ReadPrices(std::string exe_path){
  26. File exe_file(exe_path);
  27. exe_file.SetOffset(0x00514518); // Items, weapons, armors, accessories start here
  28. for (int i = 0; i < 320; i ++) prices_[i] = exe_file.readU32LE();
  29. exe_file.SetOffset(0x00514B18); // Materias start here
  30. for (int i = 320; i < 416; i ++) prices_[i] = exe_file.readU32LE();
  31. }
  32. int KernelDataInstaller::ReadCommands(){
  33. // Empty the item list
  34. commands_.clear();
  35. File command_file = kernel_.ExtractGZip(KERNEL_COMMAND_DATA);
  36. File command_name_file = kernel_.ExtractGZip(KERNEL_COMMAND_NAMES);
  37. File command_desc_file = kernel_.ExtractGZip(KERNEL_COMMAND_DESCRIPTIONS);
  38. int name_offset = 0;
  39. int desc_offset = 0;
  40. int command_count = 0;
  41. // There are exactly 32 commands. Some of them are blank, so there is not really a
  42. // reliable exit condition.
  43. for (int i = 0; i < 32; i ++){
  44. CommandData data;
  45. // From the current name file offset, read 16 bytes.
  46. // This is the pointer to the offset for the item name.
  47. // Start reading there until 0xFF is found.
  48. data.name = "";
  49. u8 ch = 1;
  50. name_offset = command_name_file.readU16LE();
  51. while (ch != 0xFF){
  52. ch = command_name_file.GetU8(name_offset);
  53. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  54. name_offset ++;
  55. }
  56. boost::replace_all(data.name, "\"", "'");
  57. // For descriptions, do the same as for names.
  58. data.description = "";
  59. ch = 1;
  60. desc_offset = command_desc_file.readU16LE();
  61. while (ch != 0xFF){
  62. ch = command_desc_file.GetU8(desc_offset);
  63. if (ch != 0xFF){
  64. // Warning: If the char is 0xF9, special function!
  65. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  66. // This is to compress information in the kernel.
  67. if (ch == 0xF9){
  68. // Get how much to read, two upper bits of the next byte.
  69. // Multiply by 2 and add 4. That's just how it is.
  70. u8 comp_size = (command_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  71. // Get new offset, lower six bits of the next byte.
  72. // The offset goes backwards from the position of the 0xF9 byte.
  73. u8 comp_offset = command_desc_file.GetU8(desc_offset + 1) & 63;
  74. for (int i = 0; i < comp_size; i ++){
  75. data.description += ENGLISH_CHARS[
  76. command_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  77. ];
  78. }
  79. desc_offset ++;
  80. }
  81. else data.description += ENGLISH_CHARS[ch];
  82. }
  83. desc_offset ++;
  84. }
  85. boost::replace_all(data.description, "\"", "'");
  86. // Read data from the item data section.
  87. data.cursor_action = command_file.readU8();
  88. data.target_raw = command_file.readU8();
  89. data.camera_single = command_file.readU16LE();
  90. data.camera_multiple = command_file.readU16LE();
  91. // Derive data from the read data.
  92. data.id = i;
  93. if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
  94. else data.target.selection_enabled = false;
  95. if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
  96. else data.target.default_enemy = false;
  97. if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
  98. else data.target.default_multiple = false;
  99. if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
  100. else data.target.toggle_multiple = false;
  101. if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
  102. else data.target.fixed_row = false;
  103. if (data.target_raw == (data.target_raw | 0x20)) data.target.short_range = true;
  104. else data.target.short_range = false;
  105. if (data.target_raw == (data.target_raw | 0x40)) data.target.default_enemy = true;
  106. else data.target.all_rows = false;
  107. if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
  108. else data.target.random = false;
  109. // Add to the list of items.
  110. if (data.name != ""){
  111. commands_.push_back(data);
  112. command_count ++;
  113. }
  114. }
  115. return command_count;
  116. }
  117. void KernelDataInstaller::WriteCommands(std::string file_name){
  118. std::fstream file;
  119. file.open(file_name, std::ios::out);
  120. if (!file) return;
  121. for (CommandData command : commands_){
  122. file << "Game.Commands[" << command.id << "] = {\n"
  123. << " name = \"" << command.name << "\",\n"
  124. << " description = \"" << command.description << "\",\n"
  125. << " camera = {single = " << command.camera_single << ", "
  126. << "multiple = " << command.camera_multiple << "}\n}\n";
  127. }
  128. file.close();
  129. }
  130. int KernelDataInstaller::ReadAttacks(){
  131. // Empty the item list
  132. attacks_.clear();
  133. File attacks_file = kernel_.ExtractGZip(KERNEL_ATTACK_DATA);
  134. int attack_count = 0;
  135. for (int i = 0; i < 128; i ++){
  136. AttackData data;
  137. // Read data from the item data section.
  138. data.accuracy = attacks_file.readU8();
  139. data.impact_effect = attacks_file.readU8();
  140. data.hurt_anim = attacks_file.readU8();
  141. data.unknown = attacks_file.readU8();
  142. data.mp = attacks_file.readU16LE();
  143. data.sound = attacks_file.readU16LE();
  144. data.camera_single = attacks_file.readU16LE();
  145. data.camera_multiple = attacks_file.readU16LE();
  146. data.target_raw = attacks_file.readU8();
  147. data.effect = attacks_file.readU8();
  148. data.damage_raw = attacks_file.readU8();
  149. data.power = attacks_file.readU8();
  150. data.condition_raw = attacks_file.readU8();
  151. data.status_change_raw = attacks_file.readU8();
  152. data.additional_effects_raw = attacks_file.readU8();
  153. data.additional_effects_mod_raw = attacks_file.readU8();
  154. data.status_raw = attacks_file.readU32LE();
  155. data.element_raw = attacks_file.readU16LE();
  156. data.special_raw = attacks_file.readU16LE();
  157. // Derive data from the read data.
  158. data.id = i;
  159. if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
  160. else data.target.selection_enabled = false;
  161. if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
  162. else data.target.default_enemy = false;
  163. if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
  164. else data.target.default_multiple = false;
  165. if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
  166. else data.target.toggle_multiple = false;
  167. if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
  168. else data.target.fixed_row = false;
  169. if (data.target_raw == (data.target_raw | 0x20)) data.target.short_range = true;
  170. else data.target.short_range = false;
  171. if (data.target_raw == (data.target_raw | 0x40)) data.target.default_enemy = true;
  172. else data.target.all_rows = false;
  173. if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
  174. else data.target.random = false;
  175. data.damage_formula = data.damage_raw >> 4; // Upper nybble.
  176. data.damage_modifier = data.damage_raw & 15; // Lower nybble.
  177. data.status.chance = 63 - (data.status_change_raw ^ 63); // Out of 63;
  178. if (data.status_change_raw == (data.status_change_raw | 0x00000080))
  179. data.status.mode = TOGGLE;
  180. else if (data.status_change_raw == (data.status_change_raw | 0x00000040))
  181. data.status.mode = CURE;
  182. else data.status.mode = INFLICT;
  183. switch (data.condition_raw){
  184. case 0: data.restore_type = RESTORE_HP; break;
  185. case 1: data.restore_type = RESTORE_MP; break;
  186. case 2: data.restore_type = RESTORE_STATUS; break;
  187. default: data.restore_type = RESTORE_NONE;
  188. }
  189. // In KERNEL.BIN, items that don't induce statuses actually have all statuses marked, and
  190. // a chance of 255. If it's the case, skip statuses altogether.
  191. if (data.status.chance <= 64){
  192. // TODO: Im fairly sure that this can be done with a single-line loop...
  193. // ... but I don't know how
  194. if (data.status_raw == (data.status_raw | 0x00000001))
  195. data.status.status.push_back(DEATH);
  196. if (data.status_raw == (data.status_raw | 0x00000002))
  197. data.status.status.push_back(NEAR_DEATH);
  198. if (data.status_raw == (data.status_raw | 0x00000004))
  199. data.status.status.push_back(SLEEP);
  200. if (data.status_raw == (data.status_raw | 0x00000008))
  201. data.status.status.push_back(POISONED);
  202. if (data.status_raw == (data.status_raw | 0x00000010))
  203. data.status.status.push_back(SADNESS);
  204. if (data.status_raw == (data.status_raw | 0x00000020))
  205. data.status.status.push_back(FURY);
  206. if (data.status_raw == (data.status_raw | 0x00000040))
  207. data.status.status.push_back(CONFU);
  208. if (data.status_raw == (data.status_raw | 0x00000080))
  209. data.status.status.push_back(SILENCE);
  210. if (data.status_raw == (data.status_raw | 0x00000100))
  211. data.status.status.push_back(HASTE);
  212. if (data.status_raw == (data.status_raw | 0x00000200))
  213. data.status.status.push_back(SLOW);
  214. if (data.status_raw == (data.status_raw | 0x00000400))
  215. data.status.status.push_back(STOP);
  216. if (data.status_raw == (data.status_raw | 0x00000800))
  217. data.status.status.push_back(FROG);
  218. if (data.status_raw == (data.status_raw | 0x00001000))
  219. data.status.status.push_back(SMALL);
  220. if (data.status_raw == (data.status_raw | 0x00002000))
  221. data.status.status.push_back(SLOW_NUMB);
  222. if (data.status_raw == (data.status_raw | 0x00004000))
  223. data.status.status.push_back(PETRIFY);
  224. if (data.status_raw == (data.status_raw | 0x00008000))
  225. data.status.status.push_back(REGEN);
  226. if (data.status_raw == (data.status_raw | 0x00010000))
  227. data.status.status.push_back(BARRIER);
  228. if (data.status_raw == (data.status_raw | 0x00020000))
  229. data.status.status.push_back(M_BARRIER);
  230. if (data.status_raw == (data.status_raw | 0x00040000))
  231. data.status.status.push_back(REFLECT);
  232. if (data.status_raw == (data.status_raw | 0x00080000))
  233. data.status.status.push_back(DUAL);
  234. if (data.status_raw == (data.status_raw | 0x00100000))
  235. data.status.status.push_back(SHIELD);
  236. if (data.status_raw == (data.status_raw | 0x00200000))
  237. data.status.status.push_back(D_SENTENCE);
  238. if (data.status_raw == (data.status_raw | 0x00400000))
  239. data.status.status.push_back(MANIPULATE);
  240. if (data.status_raw == (data.status_raw | 0x00800000))
  241. data.status.status.push_back(BERSERK);
  242. if (data.status_raw == (data.status_raw | 0x01000000))
  243. data.status.status.push_back(PEERLESS);
  244. if (data.status_raw == (data.status_raw | 0x02000000))
  245. data.status.status.push_back(PARALYSIS);
  246. if (data.status_raw == (data.status_raw | 0x04000000))
  247. data.status.status.push_back(DARKNESS);
  248. if (data.status_raw == (data.status_raw | 0x08000000))
  249. data.status.status.push_back(DUAL_DRAIN);
  250. if (data.status_raw == (data.status_raw | 0x10000000))
  251. data.status.status.push_back(DEATH_FORCE);
  252. if (data.status_raw == (data.status_raw | 0x20000000))
  253. data.status.status.push_back(RESIST);
  254. if (data.status_raw == (data.status_raw | 0x40000000))
  255. data.status.status.push_back(LUCKY_GIRL);
  256. if (data.status_raw == (data.status_raw | 0x80000000))
  257. data.status.status.push_back(IMPRISONED);
  258. }
  259. // Get elements
  260. if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
  261. if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
  262. if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
  263. if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
  264. if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
  265. if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
  266. if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
  267. if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
  268. if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
  269. if (data.element_raw == (data.element_raw | 0x0200)) data.elements.push_back(RESTORATIVE);
  270. if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
  271. if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
  272. if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
  273. if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
  274. if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
  275. if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
  276. // In KERNEL.BIN, Non elemental item actually have all elements marked.
  277. // If that happens, clear them all.
  278. if (data.elements.size() == 16) data.elements.clear();
  279. // Add to the list of items.
  280. attacks_.push_back(data);
  281. attack_count ++;
  282. }
  283. return attack_count;
  284. }
  285. void KernelDataInstaller::WriteAttacks(std::string file_name){
  286. std::fstream file;
  287. file.open(file_name, std::ios::out);
  288. if (!file) return;
  289. for (AttackData attack : attacks_){
  290. file << "Game.Attacks[" << attack.id << "] = {\n"
  291. << " accuracy = " << static_cast<int>(attack.accuracy) << ",\n"
  292. << " impact_effect = " << static_cast<int>(attack.impact_effect) << ",\n"
  293. << " hurt_anim = " << static_cast<int>(attack.hurt_anim) << ",\n"
  294. << " mp = " << attack.mp << ",\n"
  295. << " sound = " << attack.sound << ",\n"
  296. << " camera = {single = " << attack.camera_single << ", "
  297. << "multiple = " << attack.camera_multiple << "},\n"
  298. << " effect = " << static_cast<int>(attack.effect) << ",\n"
  299. << " dmg_formula = " << static_cast<int>(attack.damage_formula) << ",\n"
  300. << " dmg_modifier = " << static_cast<int>(attack.damage_modifier) << ",\n"
  301. << " power = " << static_cast<int>(attack.power) << ",\n"
  302. << " restore = " << attack.restore_type << ",\n"
  303. << " target = {selectable = " << attack.target.selection_enabled
  304. << ", default_enemy = " << attack.target.default_enemy
  305. << ", default_multiple = " << attack.target.default_multiple
  306. << ", toggle_multiple = " << attack.target.toggle_multiple
  307. << ", fixed_row = " << attack.target.fixed_row
  308. << ", short_range = " << attack.target.short_range
  309. << ", all_rows = " << attack.target.all_rows
  310. << ", random = " << attack.target.random << "}\n}\n";
  311. }
  312. file.close();
  313. }
  314. int KernelDataInstaller::ReadCharacters(){
  315. // TODO: Do something about young Cloud and Sephiroth.
  316. // Empty the item list
  317. characters_.clear();
  318. File characters_file = kernel_.ExtractGZip(KERNEL_BATTLE_AND_GROWTH_DATA);
  319. int character_count = 0;
  320. for (int i = 0; i < 10; i ++){ // 9 characters
  321. CharacterData data;
  322. // Read data from the item data section.
  323. data.curve_str = characters_file.readU8();
  324. data.curve_vit = characters_file.readU8();
  325. data.curve_mag = characters_file.readU8();
  326. data.curve_spr = characters_file.readU8();
  327. data.curve_dex = characters_file.readU8();
  328. data.curve_lck = characters_file.readU8();
  329. data.curve_hp = characters_file.readU8();
  330. data.curve_mp = characters_file.readU8();
  331. data.curve_exp = characters_file.readU8();
  332. data.unused_0 = characters_file.readU8();
  333. data.initial_level = characters_file.readU8();
  334. data.unused_1 = characters_file.readU8();
  335. data.limit_1_1 = characters_file.readU8();
  336. data.limit_1_2 = characters_file.readU8();
  337. data.limit_1_3 = characters_file.readU8();
  338. data.limit_2_1 = characters_file.readU8();
  339. data.limit_2_2 = characters_file.readU8();
  340. data.limit_2_3 = characters_file.readU8();
  341. data.limit_3_1 = characters_file.readU8();
  342. data.limit_3_2 = characters_file.readU8();
  343. data.limit_3_3 = characters_file.readU8();
  344. data.limit_4_1 = characters_file.readU8();
  345. data.limit_4_2 = characters_file.readU8();
  346. data.limit_4_3 = characters_file.readU8();
  347. data.limit_2_kills = characters_file.readU16LE();
  348. data.limit_3_kills = characters_file.readU16LE();
  349. data.limit_1_2_uses = characters_file.readU16LE();
  350. data.limit_1_3_uses = characters_file.readU16LE();
  351. data.limit_2_2_uses = characters_file.readU16LE();
  352. data.limit_2_3_uses = characters_file.readU16LE();
  353. data.limit_3_2_uses = characters_file.readU16LE();
  354. data.limit_3_3_uses = characters_file.readU16LE();
  355. data.limit_1_div = characters_file.readU32LE();
  356. data.limit_2_div = characters_file.readU32LE();
  357. data.limit_3_div = characters_file.readU32LE();
  358. data.limit_4_div = characters_file.readU32LE();
  359. // Derive data from the read data.
  360. data.id = i;
  361. data.name = VGears::NameLookup::CharName(i);
  362. // Add to the list of characters.
  363. characters_.push_back(data);
  364. character_count ++;
  365. }
  366. return character_count;
  367. }
  368. void KernelDataInstaller::WriteCharacters(std::string file_name){
  369. std::fstream file;
  370. file.open(file_name, std::ios::out);
  371. if (!file) return;
  372. for (CharacterData character : characters_){
  373. file
  374. << "Game.Characters[" << character.id << "] = {\n"
  375. << " id = " << character.id << ",\n"
  376. << " name = \"" << character.name << "\",\n"
  377. << " initial_level = \"" << static_cast<int>(character.initial_level) << "\",\n"
  378. << " curves = {\n"
  379. << " str = " << static_cast<int>(character.curve_str) << ",\n"
  380. << " vit = " << static_cast<int>(character.curve_vit) << ",\n"
  381. << " mag = " << static_cast<int>(character.curve_mag) << ",\n"
  382. << " spr = " << static_cast<int>(character.curve_spr) << ",\n"
  383. << " dex = " << static_cast<int>(character.curve_dex) << ",\n"
  384. << " lck = " << static_cast<int>(character.curve_lck) << ",\n"
  385. << " hp = " << static_cast<int>(character.curve_hp) << ",\n"
  386. << " mp = " << static_cast<int>(character.curve_mp) << ",\n"
  387. << " exp = " << static_cast<int>(character.curve_exp) << ",\n"
  388. << " },\n"
  389. << " limits = {\n"
  390. << " [1] = {\n"
  391. << " kills = 0,\n"
  392. << " techniques = {\n"
  393. << " [1] = {\n"
  394. << " command = " << static_cast<int>(character.limit_1_1) << ",\n"
  395. << " uses = 0\n"
  396. << " },\n";
  397. if (character.limit_1_2 < 255){ // Some characters only have 1 limit per level.
  398. file
  399. << " [2] = {\n"
  400. << " command = " << static_cast<int>(character.limit_1_2) << ",\n"
  401. << " uses = " << character.limit_1_2_uses << "\n"
  402. << " },\n";
  403. }
  404. file
  405. << " }\n"
  406. << " },\n";
  407. // Limit level 2.
  408. if (character.limit_2_kills < 65535){
  409. file
  410. << " [2] = {\n"
  411. << " kills = " << character.limit_2_kills << ",\n"
  412. << " techniques = {\n"
  413. << " [1] = {\n"
  414. << " command = " << static_cast<int>(character.limit_2_1) << ",\n"
  415. << " uses = 0\n"
  416. << " },\n";
  417. if (character.limit_2_2 < 255){ // Some characters only have 1 limit per level.
  418. file
  419. << " [2] = {\n"
  420. << " command = "
  421. << static_cast<int>(character.limit_2_2) << ",\n"
  422. << " uses = " << character.limit_2_2_uses << "\n"
  423. << " },\n";
  424. }
  425. file
  426. << " }\n"
  427. << " },\n";
  428. }
  429. // Limit level 3.
  430. if (character.limit_3_kills < 65535){
  431. file
  432. << " [3] = {\n"
  433. << " kills = " << character.limit_3_kills << ",\n"
  434. << " techniques = {\n"
  435. << " [1] = {\n"
  436. << " command = " << static_cast<int>(character.limit_3_1) << ",\n"
  437. << " uses = 0\n"
  438. << " },\n";
  439. if (character.limit_3_2 < 255){ // Some characters only have 1 limit per level.
  440. file
  441. << " [2] = {\n"
  442. << " command = "
  443. << static_cast<int>(character.limit_3_2) << ",\n"
  444. << " uses = " << character.limit_3_2_uses << "\n"
  445. << " },\n";
  446. }
  447. file
  448. << " }\n"
  449. << " },\n";
  450. }
  451. // Limit level 4.
  452. if (character.limit_4_1 < 255){
  453. file
  454. << " [4] = {\n"
  455. << " kills = 0,\n"
  456. << " techniques = {\n"
  457. << " [1] = {\n"
  458. << " command = " << static_cast<int>(character.limit_4_1) << ",\n"
  459. << " uses = 0\n"
  460. << " },\n"
  461. << " }\n"
  462. << " },\n";
  463. }
  464. file
  465. << " }\n}\n";
  466. }
  467. file.close();
  468. }
  469. void KernelDataInstaller::ReadGrowth(){
  470. File growth_file = kernel_.ExtractGZip(KERNEL_BATTLE_AND_GROWTH_DATA);
  471. growth_file.SetOffset(0x01F8); //Skip character data.
  472. for (int i = 0; i < 12; i ++) growth_.bonus_stat[i] = growth_file.readU8();
  473. for (int i = 0; i < 12; i ++) growth_.bonus_hp[i] = growth_file.readU8();
  474. for (int i = 0; i < 12; i ++) growth_.bonus_mp[i] = growth_file.readU8();
  475. for (int i = 0; i < 64; i ++){
  476. growth_.curves[i].id = i;
  477. if (i >=0 && i < 37) growth_.curves[i].type = CURVE_PRIMARY;
  478. else if (i >=37 && i < 46) growth_.curves[i].type = CURVE_HP;
  479. else if (i >=46 && i < 55) growth_.curves[i].type = CURVE_MP;
  480. else growth_.curves[i].type = CURVE_EXP;
  481. for (int j = 0; j < 8; j ++){
  482. growth_.curves[i].gradient[j] = growth_file.readU8();
  483. growth_.curves[i].base[j] = growth_file.readU8();
  484. }
  485. }
  486. }
  487. void KernelDataInstaller::WriteGrowth(std::string file_name){
  488. std::fstream file;
  489. file.open(file_name, std::ios::out);
  490. if (!file) return;
  491. file << "Game.Growth.bonus.primary = {";
  492. for (int i = 0; i < 12; i ++)
  493. file << "[" << i << "] = " << static_cast<int>(growth_.bonus_stat[i]) << ", ";
  494. file << "}\nGame.Growth.bonus.hp = {";
  495. for (int i = 0; i < 12; i ++)
  496. file << "[" << i << "] = " << static_cast<int>(growth_.bonus_hp[i]) << ", ";
  497. file << "}\nGame.Growth.bonus.mp = {";
  498. for (int i = 0; i < 12; i ++)
  499. file << "[" << i << "] = " << static_cast<int>(growth_.bonus_mp[i]) << ", ";
  500. file << "}\n";
  501. for (int i = 0; i < 64; i ++){
  502. file << "Game.Growth.curves[" << i << "] = {\n";
  503. for (int j = 0; j < 8; j ++){
  504. file << " [" << j << "] = {gradient = "
  505. << static_cast<int>(growth_.curves[i].gradient[j])
  506. << ", base = " << static_cast<int>(growth_.curves[i].gradient[j]) << "},\n";
  507. }
  508. file << "}\n";
  509. }
  510. file.close();
  511. }
  512. int KernelDataInstaller::ReadItems(){
  513. // Empty the item list
  514. items_.clear();
  515. File items_file = kernel_.ExtractGZip(KERNEL_ITEM_DATA);
  516. File items_name_file = kernel_.ExtractGZip(KERNEL_ITEM_NAMES);
  517. File items_desc_file = kernel_.ExtractGZip(KERNEL_ITEM_DESCRIPTIONS);
  518. int name_offset = 0;
  519. int desc_offset = 0;
  520. int item_count = 0;
  521. for (int i = 0; i < 128; i ++){
  522. ItemData data;
  523. // From the current name file offset, read 16 bytes.
  524. // This is the pointer to the offset for the item name.
  525. // Start reading there until 0xFF is found.
  526. data.name = "";
  527. u8 ch = 1;
  528. name_offset = items_name_file.readU16LE();
  529. while (ch != 0xFF){
  530. ch = items_name_file.GetU8(name_offset);
  531. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  532. name_offset ++;
  533. }
  534. boost::replace_all(data.name, "\"", "'");
  535. // For descriptions, do the same as for names.
  536. data.description = "";
  537. ch = 1;
  538. desc_offset = items_desc_file.readU16LE();
  539. while (ch != 0xFF){
  540. ch = items_desc_file.GetU8(desc_offset);
  541. if (ch != 0xFF){
  542. // Warning: If the char is 0xF9, special function!
  543. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  544. // This is to compress information in the kernel.
  545. if (ch == 0xF9){
  546. // Get how much to read, two upper bits of the next byte.
  547. // Multiply by 2 and add 4. That's just how it is.
  548. u8 comp_size = (items_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  549. // Get new offset, lower six bits of the next byte.
  550. // The offset goes backwards from the position of the 0xF9 byte.
  551. u8 comp_offset = items_desc_file.GetU8(desc_offset + 1) & 63;
  552. for (int i = 0; i < comp_size; i ++){
  553. data.description += ENGLISH_CHARS[
  554. items_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  555. ];
  556. }
  557. desc_offset ++;
  558. }
  559. else data.description += ENGLISH_CHARS[ch];
  560. }
  561. desc_offset ++;
  562. }
  563. boost::replace_all(data.description, "\"", "'");
  564. // If the item doesn't have a name, it means all items have been read.
  565. // break the loop.
  566. if ("" == data.name) break;
  567. // Read data from the item data section.
  568. data.unknown_0 = items_file.readU32LE();
  569. data.unknown_1 = items_file.readU32LE();
  570. data.camera = items_file.readU16LE();
  571. data.restrict_raw = items_file.readU16LE();
  572. data.target_raw = items_file.readU8();
  573. data.effect = items_file.readU8();
  574. data.damage_raw = items_file.readU8();
  575. data.power = items_file.readU8();
  576. data.condition_raw = items_file.readU8();
  577. data.status_change_raw = items_file.readU8();
  578. data.additional_effects_raw = items_file.readU8();
  579. data.additional_effects_mod_raw = items_file.readU8();
  580. data.status_raw = items_file.readU32LE();
  581. data.element_raw = items_file.readU16LE();
  582. data.special_raw = items_file.readU16LE();
  583. // Derive data from the read data.
  584. data.id = i;
  585. data.sellable = !(data.restrict_raw & (1 << 0));
  586. data.useable_battle = !(data.restrict_raw & (2 << 0));
  587. data.useable_menu = !(data.restrict_raw & (4 << 0));
  588. if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
  589. else data.target.selection_enabled = false;
  590. if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
  591. else data.target.default_enemy = false;
  592. if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
  593. else data.target.default_multiple = false;
  594. if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
  595. else data.target.toggle_multiple = false;
  596. if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
  597. else data.target.fixed_row = false;
  598. if (data.target_raw == (data.target_raw | 0x20)) data.target.short_range = true;
  599. else data.target.short_range = false;
  600. if (data.target_raw == (data.target_raw | 0x40)) data.target.default_enemy = true;
  601. else data.target.all_rows = false;
  602. if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
  603. else data.target.random = false;
  604. data.damage_formula = data.damage_raw >> 4; // Upper nybble.
  605. data.damage_modifier = data.damage_raw & 15; // Lower nybble.
  606. data.status.chance = 63 - (data.status_change_raw ^ 63); // Out of 63;
  607. if (data.status_change_raw == (data.status_change_raw | 0x00000080))
  608. data.status.mode = TOGGLE;
  609. else if (data.status_change_raw == (data.status_change_raw | 0x00000040))
  610. data.status.mode = CURE;
  611. else data.status.mode = INFLICT;
  612. switch (data.condition_raw){
  613. case 0: data.restore_type = RESTORE_HP; break;
  614. case 1: data.restore_type = RESTORE_MP; break;
  615. case 2: data.restore_type = RESTORE_STATUS; break;
  616. default: data.restore_type = RESTORE_NONE;
  617. }
  618. // In KERNEL.BIN, items that don't induce statuses actually have all statuses marked, and
  619. // a chance of 255. If it's the case, skip statuses altogether.
  620. if (data.status.chance <= 64){
  621. // TODO: Im fairly sure that this can be done with a single-line loop...
  622. // ... but I don't know how
  623. if (data.status_raw == (data.status_raw | 0x00000001))
  624. data.status.status.push_back(DEATH);
  625. if (data.status_raw == (data.status_raw | 0x00000002))
  626. data.status.status.push_back(NEAR_DEATH);
  627. if (data.status_raw == (data.status_raw | 0x00000004))
  628. data.status.status.push_back(SLEEP);
  629. if (data.status_raw == (data.status_raw | 0x00000008))
  630. data.status.status.push_back(POISONED);
  631. if (data.status_raw == (data.status_raw | 0x00000010))
  632. data.status.status.push_back(SADNESS);
  633. if (data.status_raw == (data.status_raw | 0x00000020))
  634. data.status.status.push_back(FURY);
  635. if (data.status_raw == (data.status_raw | 0x00000040))
  636. data.status.status.push_back(CONFU);
  637. if (data.status_raw == (data.status_raw | 0x00000080))
  638. data.status.status.push_back(SILENCE);
  639. if (data.status_raw == (data.status_raw | 0x00000100))
  640. data.status.status.push_back(HASTE);
  641. if (data.status_raw == (data.status_raw | 0x00000200))
  642. data.status.status.push_back(SLOW);
  643. if (data.status_raw == (data.status_raw | 0x00000400))
  644. data.status.status.push_back(STOP);
  645. if (data.status_raw == (data.status_raw | 0x00000800))
  646. data.status.status.push_back(FROG);
  647. if (data.status_raw == (data.status_raw | 0x00001000))
  648. data.status.status.push_back(SMALL);
  649. if (data.status_raw == (data.status_raw | 0x00002000))
  650. data.status.status.push_back(SLOW_NUMB);
  651. if (data.status_raw == (data.status_raw | 0x00004000))
  652. data.status.status.push_back(PETRIFY);
  653. if (data.status_raw == (data.status_raw | 0x00008000))
  654. data.status.status.push_back(REGEN);
  655. if (data.status_raw == (data.status_raw | 0x00010000))
  656. data.status.status.push_back(BARRIER);
  657. if (data.status_raw == (data.status_raw | 0x00020000))
  658. data.status.status.push_back(M_BARRIER);
  659. if (data.status_raw == (data.status_raw | 0x00040000))
  660. data.status.status.push_back(REFLECT);
  661. if (data.status_raw == (data.status_raw | 0x00080000))
  662. data.status.status.push_back(DUAL);
  663. if (data.status_raw == (data.status_raw | 0x00100000))
  664. data.status.status.push_back(SHIELD);
  665. if (data.status_raw == (data.status_raw | 0x00200000))
  666. data.status.status.push_back(D_SENTENCE);
  667. if (data.status_raw == (data.status_raw | 0x00400000))
  668. data.status.status.push_back(MANIPULATE);
  669. if (data.status_raw == (data.status_raw | 0x00800000))
  670. data.status.status.push_back(BERSERK);
  671. if (data.status_raw == (data.status_raw | 0x01000000))
  672. data.status.status.push_back(PEERLESS);
  673. if (data.status_raw == (data.status_raw | 0x02000000))
  674. data.status.status.push_back(PARALYSIS);
  675. if (data.status_raw == (data.status_raw | 0x04000000))
  676. data.status.status.push_back(DARKNESS);
  677. if (data.status_raw == (data.status_raw | 0x08000000))
  678. data.status.status.push_back(DUAL_DRAIN);
  679. if (data.status_raw == (data.status_raw | 0x10000000))
  680. data.status.status.push_back(DEATH_FORCE);
  681. if (data.status_raw == (data.status_raw | 0x20000000))
  682. data.status.status.push_back(RESIST);
  683. if (data.status_raw == (data.status_raw | 0x40000000))
  684. data.status.status.push_back(LUCKY_GIRL);
  685. if (data.status_raw == (data.status_raw | 0x80000000))
  686. data.status.status.push_back(IMPRISONED);
  687. }
  688. // Get elements
  689. if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
  690. if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
  691. if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
  692. if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
  693. if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
  694. if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
  695. if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
  696. if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
  697. if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
  698. if (data.element_raw == (data.element_raw | 0x0200)) data.elements.push_back(RESTORATIVE);
  699. if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
  700. if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
  701. if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
  702. if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
  703. if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
  704. if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
  705. // In KERNEL.BIN, Non elemental item actually have all elements marked.
  706. // If that happens, clear them all.
  707. if (data.elements.size() == 16) data.elements.clear();
  708. // Add to the list of items.
  709. items_.push_back(data);
  710. item_count ++;
  711. }
  712. return item_count;
  713. }
  714. void KernelDataInstaller::WriteItems(std::string file_name){
  715. std::fstream file;
  716. file.open(file_name, std::ios::out);
  717. if (!file) return;
  718. for (ItemData item : items_){
  719. file << "Game.Items[" << item.id << "] = {\n"
  720. << " type = Inventory.ITEM_TYPE.ITEM,\n"
  721. << " id = " << item.id << ",\n"
  722. << " price = " << prices_[item.id] << ",\n"
  723. << " name = \"" << item.name << "\",\n"
  724. << " description = \"" << item.description << "\",\n"
  725. << " camera = " << item.camera << ",\n"
  726. << " sell = " << item.sellable << ",\n"
  727. << " battle = " << item.useable_battle << ",\n"
  728. << " menu = " << item.useable_menu << ",\n"
  729. << " throw = 0,\n"
  730. << " effect = " << static_cast<int>(item.effect) << ",\n"
  731. << " dmg_formula = " << static_cast<int>(item.damage_formula) << ",\n"
  732. << " dmg_modifier = " << static_cast<int>(item.damage_modifier) << ",\n"
  733. << " power = " << static_cast<int>(item.power) << ",\n"
  734. << " restore = " << item.restore_type << ",\n"
  735. << " target = {selectable = " << item.target.selection_enabled
  736. << ", default_enemy = " << item.target.default_enemy
  737. << ", default_multiple = " << item.target.default_multiple
  738. << ", toggle_multiple = " << item.target.toggle_multiple
  739. << ", fixed_row = " << item.target.fixed_row
  740. << ", short_range = " << item.target.short_range
  741. << ", all_rows = " << item.target.all_rows
  742. << ", random = " << item.target.random << "},\n"
  743. << " status = {";
  744. for (int s : item.status.status){
  745. file << "\n {status = " << s << ", mode = " << item.status.mode
  746. << ", chance = " << item.status.chance << "},";
  747. }
  748. if (item.status.status.size() > 0) file << "\n },\n";
  749. else file << "},\n";
  750. file << " elements = {";
  751. for (int e : item.elements) file << e << ", ";
  752. file << "},\n}\n";
  753. }
  754. file.close();
  755. }
  756. int KernelDataInstaller::ReadWeapons(){
  757. // Empty the item list
  758. weapons_.clear();
  759. File weapons_file = kernel_.ExtractGZip(KERNEL_WEAPON_DATA);
  760. File weapons_name_file = kernel_.ExtractGZip(KERNEL_WEAPON_NAMES);
  761. File weapons_desc_file = kernel_.ExtractGZip(KERNEL_WEAPON_DESCRIPTIONS);
  762. int name_offset = 0;
  763. int desc_offset = 0;
  764. int weapon_count = 0;
  765. for (int i = 0; i < 128; i ++){
  766. WeaponData data;
  767. // From the current name file offset, read 16 bytes.
  768. // This is the pointer to the offset for the item name.
  769. // Start reading there until 0xFF is found.
  770. data.name = "";
  771. u8 ch = 1;
  772. name_offset = weapons_name_file.readU16LE();
  773. while (ch != 0xFF){
  774. ch = weapons_name_file.GetU8(name_offset);
  775. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  776. name_offset ++;
  777. }
  778. boost::replace_all(data.name, "\"", "'");
  779. // For descriptions, do the same as for names.
  780. data.description = "";
  781. ch = 1;
  782. desc_offset = weapons_desc_file.readU16LE();
  783. while (ch != 0xFF){
  784. ch = weapons_desc_file.GetU8(desc_offset);
  785. if (ch != 0xFF){
  786. // Warning: If the char is 0xF9, special function!
  787. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  788. // This is to compress information in the kernel.
  789. if (ch == 0xF9){
  790. // Get how much to read, two upper bits of the next byte.
  791. // Multiply by 2 and add 4. That's just how it is.
  792. u8 comp_size = (weapons_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  793. // Get new offset, lower six bits of the next byte.
  794. // The offset goes backwards from the position of the 0xF9 byte.
  795. u8 comp_offset = weapons_desc_file.GetU8(desc_offset + 1) & 63;
  796. for (int i = 0; i < comp_size; i ++){
  797. data.description += ENGLISH_CHARS[
  798. weapons_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  799. ];
  800. }
  801. desc_offset ++;
  802. }
  803. else data.description += ENGLISH_CHARS[ch];
  804. }
  805. desc_offset ++;
  806. }
  807. boost::replace_all(data.description, "\"", "'");
  808. // If the item doesn't have a name, it means all items have been read.
  809. // break the loop.
  810. if ("" == data.name) break;
  811. // Read data from the weapon data section.
  812. data.target_raw = weapons_file.readU8();
  813. data.unused_0 = weapons_file.readU8();
  814. data.damage_raw = weapons_file.readU8();
  815. data.unused_1 = weapons_file.readU8();
  816. data.power = weapons_file.readU8();
  817. data.status = weapons_file.readU8();
  818. data.growth = weapons_file.readU8();
  819. data.critical = weapons_file.readU8();
  820. data.accuracy = weapons_file.readU8();
  821. data.model_raw = weapons_file.readU8();
  822. data.unused_2 = weapons_file.readU8();
  823. data.high_sound = weapons_file.readU8();
  824. data.camera = weapons_file.readU16LE();
  825. data.equip_raw = weapons_file.readU16LE();
  826. data.element_raw = weapons_file.readU16LE();
  827. data.unused_3 = weapons_file.readU16LE();
  828. for (int i = 0; i < 4; i ++) data.stat_raw[i] = weapons_file.readU8();
  829. for (int i = 0; i < 4; i ++) data.stat_bonus_raw[i] = weapons_file.readU8();
  830. for (int i = 0; i < 8; i ++) data.slots_raw[i] = weapons_file.readU8();
  831. data.sound = weapons_file.readU8();
  832. data.sound_critical = weapons_file.readU8();
  833. data.sound_miss = weapons_file.readU8();
  834. data.effect = weapons_file.readU8();
  835. data.special_raw = weapons_file.readU16LE();
  836. data.restrict_raw = weapons_file.readU16LE();
  837. // Derive data from the read data.
  838. data.id = i;
  839. if (data.growth != 0 && data.growth != 2 && data.growth != 3) data.growth = 1;
  840. data.sellable = !(data.restrict_raw & (1 << 0));
  841. data.useable_battle = !(data.restrict_raw & (2 << 0));
  842. data.useable_menu = !(data.restrict_raw & (4 << 0));
  843. data.throwable = !(data.restrict_raw & (8 << 0));
  844. if (data.target_raw == (data.target_raw | 0x01)) data.target.selection_enabled = true;
  845. else data.target.selection_enabled = false;
  846. if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
  847. else data.target.default_enemy = false;
  848. if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
  849. else data.target.default_multiple = false;
  850. if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
  851. else data.target.toggle_multiple = false;
  852. if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
  853. else data.target.fixed_row = false;
  854. if (data.target_raw == (data.target_raw | 0x20)) data.target.short_range = true;
  855. else data.target.short_range = false;
  856. if (data.target_raw == (data.target_raw | 0x40)) data.target.default_enemy = true;
  857. else data.target.all_rows = false;
  858. if (data.target_raw == (data.target_raw | 0x80)) data.target.random = true;
  859. else data.target.random = false;
  860. data.damage_formula = data.damage_raw >> 4; // Upper nybble.
  861. data.damage_modifier = data.damage_raw & 15; // Lower nybble.
  862. data.animation_index = data.model_raw >> 4; // Upper nybble.
  863. data.model = data.model_raw & 15; // Lower nybble.
  864. if (data.equip_raw == (data.equip_raw | 0x0001)) data.equip.push_back(1);
  865. if (data.equip_raw == (data.equip_raw | 0x0002)) data.equip.push_back(2);
  866. if (data.equip_raw == (data.equip_raw | 0x0004)) data.equip.push_back(3);
  867. if (data.equip_raw == (data.equip_raw | 0x0008)) data.equip.push_back(4);
  868. if (data.equip_raw == (data.equip_raw | 0x0010)) data.equip.push_back(5);
  869. if (data.equip_raw == (data.equip_raw | 0x0020)) data.equip.push_back(6);
  870. if (data.equip_raw == (data.equip_raw | 0x0040)) data.equip.push_back(7);
  871. if (data.equip_raw == (data.equip_raw | 0x0080)) data.equip.push_back(8);
  872. if (data.equip_raw == (data.equip_raw | 0x0100)) data.equip.push_back(9);
  873. if (data.equip_raw == (data.equip_raw | 0x0200)) data.equip.push_back(10);
  874. if (data.equip_raw == (data.equip_raw | 0x0400)) data.equip.push_back(11);
  875. for (int i = 0; i < 4; i ++){
  876. if (data.stat_raw[i] < 0XFF && data.stat_bonus_raw[i] > 0){
  877. StatBonus stat_bonus;
  878. stat_bonus.stat = data.stat_raw[i];
  879. stat_bonus.bonus = data.stat_bonus_raw[i];
  880. data.stat_bonus.push_back(stat_bonus);
  881. }
  882. }
  883. for (int i = 0; i < 8; i ++){
  884. if (data.slots_raw[i] == 1 || data.slots_raw[i] == 5){
  885. data.materia_slots.push_back(SLOT_UNLINKED);
  886. }
  887. else if (
  888. data.slots_raw[i] == 2 || data.slots_raw[i] == 3
  889. || data.slots_raw[i] == 6 || data.slots_raw[i] == 7
  890. ){
  891. data.materia_slots.push_back(SLOT_LINKED);
  892. }
  893. }
  894. if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
  895. if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
  896. if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
  897. if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
  898. if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
  899. if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
  900. if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
  901. if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
  902. if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
  903. if (data.element_raw == (data.element_raw | 0x0200)) data.elements.push_back(RESTORATIVE);
  904. if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
  905. if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
  906. if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
  907. if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
  908. if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
  909. if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
  910. // In KERNEL.BIN, Non elemental item actually have all elements marked.
  911. // If that happens, clear them all.
  912. if (data.elements.size() == 16) data.elements.clear();
  913. // Add to the list of weapons.
  914. weapons_.push_back(data);
  915. weapon_count ++;
  916. }
  917. return weapon_count;
  918. }
  919. void KernelDataInstaller::WriteWeapons(std::string file_name){
  920. std::fstream file;
  921. file.open(file_name, std::ios::out);
  922. if (!file) return;
  923. for (WeaponData weapon : weapons_){
  924. file << "Game.Items[" << weapon.id + 128 << "] = {\n"
  925. << " type = Inventory.ITEM_TYPE.WEAPON,\n"
  926. << " id = " << weapon.id + 128 << ",\n"
  927. << " price = " << prices_[weapon.id + 128] << ",\n"
  928. << " name = \"" << weapon.name << "\",\n"
  929. << " description = \"" << weapon.description << "\",\n"
  930. << " camera = " << weapon.camera << ",\n"
  931. << " sell = " << weapon.sellable << ",\n"
  932. << " battle = " << weapon.useable_battle << ",\n"
  933. << " menu = " << weapon.useable_menu << ",\n"
  934. << " throw = " << weapon.throwable << ",\n"
  935. << " effect = " << static_cast<int>(weapon.effect) << ",\n"
  936. << " dmg_formula = " << static_cast<int>(weapon.damage_formula) << ",\n"
  937. << " dmg_modifier = " << static_cast<int>(weapon.damage_modifier) << ",\n"
  938. << " power = " << static_cast<int>(weapon.power) << ",\n"
  939. << " growth = " << static_cast<int>(weapon.growth) << ",\n"
  940. << " accuracy = " << static_cast<int>(weapon.accuracy) << ",\n"
  941. << " critical = " << static_cast<int>(weapon.critical) << ",\n"
  942. << " model = " << static_cast<int>(weapon.model) << ",\n"
  943. << " animation = " << static_cast<int>(weapon.animation_index) << ",\n"
  944. << " target = {selectable = " << weapon.target.selection_enabled
  945. << ", default_enemy = " << weapon.target.default_enemy
  946. << ", default_multiple = " << weapon.target.default_multiple
  947. << ", toggle_multiple = " << weapon.target.toggle_multiple
  948. << ", fixed_row = " << weapon.target.fixed_row
  949. << ", short_range = " << weapon.target.short_range
  950. << ", all_rows = " << weapon.target.all_rows
  951. << ", random = " << weapon.target.random << "},\n"
  952. << " elements = {";
  953. for (int s : weapon.elements) file << s << ", ";
  954. file << "},\n";
  955. file << " slots = {";
  956. for (u8 slot : weapon.materia_slots) file << static_cast<int>(slot) << ", ";
  957. file << "},\n stats = {";
  958. for (StatBonus s : weapon.stat_bonus){
  959. file << "\n {stat = " << static_cast<int>(s.stat) << ", bonus = "
  960. << static_cast<int>(s.bonus) << "},";
  961. }
  962. if (weapon.stat_bonus.size() > 0) file << "\n },\n";
  963. else file << "},\n";
  964. file << " users = {";
  965. for (int s : weapon.equip) file << s << ", ";
  966. file << "}\n}\n";
  967. }
  968. file.close();
  969. }
  970. int KernelDataInstaller::ReadArmors(){
  971. // Empty the item list
  972. armors_.clear();
  973. File armor_file = kernel_.ExtractGZip(KERNEL_ARMOR_DATA);
  974. File armor_name_file = kernel_.ExtractGZip(KERNEL_ARMOR_NAMES);
  975. File armor_desc_file = kernel_.ExtractGZip(KERNEL_ARMOR_DESCRIPTIONS);
  976. int name_offset = 0;
  977. int desc_offset = 0;
  978. int armor_count = 0;
  979. for (int i = 0; i < 32; i ++){ // There are exactly 32.
  980. ArmorData data;
  981. // From the current name file offset, read 16 bytes.
  982. // This is the pointer to the offset for the item name.
  983. // Start reading there until 0xFF is found.
  984. data.name = "";
  985. u8 ch = 1;
  986. name_offset = armor_name_file.readU16LE();
  987. while (ch != 0xFF){
  988. ch = armor_name_file.GetU8(name_offset);
  989. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  990. name_offset ++;
  991. }
  992. boost::replace_all(data.name, "\"", "'");
  993. // For descriptions, do the same as for names.
  994. data.description = "";
  995. ch = 1;
  996. desc_offset = armor_desc_file.readU16LE();
  997. while (ch != 0xFF){
  998. ch = armor_desc_file.GetU8(desc_offset);
  999. if (ch != 0xFF){
  1000. // Warning: If the char is 0xF9, special function!
  1001. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  1002. // This is to compress information in the kernel.
  1003. if (ch == 0xF9){
  1004. // Get how much to read, two upper bits of the next byte.
  1005. // Multiply by 2 and add 4. That's just how it is.
  1006. u8 comp_size = (armor_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  1007. // Get new offset, lower six bits of the next byte.
  1008. // The offset goes backwards from the position of the 0xF9 byte.
  1009. u8 comp_offset = armor_desc_file.GetU8(desc_offset + 1) & 63;
  1010. for (int i = 0; i < comp_size; i ++){
  1011. data.description += ENGLISH_CHARS[
  1012. armor_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  1013. ];
  1014. }
  1015. desc_offset ++;
  1016. }
  1017. else data.description += ENGLISH_CHARS[ch];
  1018. }
  1019. desc_offset ++;
  1020. }
  1021. boost::replace_all(data.description, "\"", "'");
  1022. // If the item doesn't have a name, it means all items have been read.
  1023. // break the loop.
  1024. if ("" == data.name) break;
  1025. // Read data from the weapon data section.
  1026. data.unknown_0 = armor_file.readU8();
  1027. data.element_defense_mode = armor_file.readU8();
  1028. data.defense = armor_file.readU8();
  1029. data.m_defense = armor_file.readU8();
  1030. data.evasion = armor_file.readU8();
  1031. data.m_evasion = armor_file.readU8();
  1032. data.status = armor_file.readU8();
  1033. data.unknown_1 = armor_file.readU16LE();
  1034. for (int i = 0; i < 8; i ++) data.slots_raw[i] = armor_file.readU8();
  1035. data.growth = armor_file.readU8();
  1036. data.equip_raw = armor_file.readU16LE();
  1037. data.element_raw = armor_file.readU16LE();
  1038. data.unknown_2 = armor_file.readU16LE();
  1039. for (int i = 0; i < 4; i ++) data.stat_raw[i] = armor_file.readU8();
  1040. for (int i = 0; i < 4; i ++) data.stat_bonus_raw[i] = armor_file.readU8();
  1041. data.restrict_raw = armor_file.readU16LE();
  1042. data.unknown_3 = armor_file.readU16LE();
  1043. // Derive data from the read data.
  1044. data.id = i;
  1045. if (data.growth != 0 && data.growth != 2 && data.growth != 3) data.growth = 1;
  1046. data.sellable = !(data.restrict_raw & (1 << 0));
  1047. data.useable_battle = !(data.restrict_raw & (2 << 0));
  1048. data.useable_menu = !(data.restrict_raw & (4 << 0));
  1049. if (data.equip_raw == (data.equip_raw | 0x0001)) data.equip.push_back(1);
  1050. if (data.equip_raw == (data.equip_raw | 0x0002)) data.equip.push_back(2);
  1051. if (data.equip_raw == (data.equip_raw | 0x0004)) data.equip.push_back(3);
  1052. if (data.equip_raw == (data.equip_raw | 0x0008)) data.equip.push_back(4);
  1053. if (data.equip_raw == (data.equip_raw | 0x0010)) data.equip.push_back(5);
  1054. if (data.equip_raw == (data.equip_raw | 0x0020)) data.equip.push_back(6);
  1055. if (data.equip_raw == (data.equip_raw | 0x0040)) data.equip.push_back(7);
  1056. if (data.equip_raw == (data.equip_raw | 0x0080)) data.equip.push_back(8);
  1057. if (data.equip_raw == (data.equip_raw | 0x0100)) data.equip.push_back(9);
  1058. if (data.equip_raw == (data.equip_raw | 0x0200)) data.equip.push_back(10);
  1059. if (data.equip_raw == (data.equip_raw | 0x0400)) data.equip.push_back(11);
  1060. for (int i = 0; i < 4; i ++){
  1061. if (data.stat_raw[i] < 0XFF && data.stat_bonus_raw[i] > 0){
  1062. StatBonus stat_bonus;
  1063. stat_bonus.stat = data.stat_raw[i];
  1064. stat_bonus.bonus = data.stat_bonus_raw[i];
  1065. data.stat_bonus.push_back(stat_bonus);
  1066. }
  1067. }
  1068. for (int i = 0; i < 8; i ++){
  1069. if (data.slots_raw[i] == 1 || data.slots_raw[i] == 5){
  1070. data.materia_slots.push_back(SLOT_UNLINKED);
  1071. }
  1072. else if (
  1073. data.slots_raw[i] == 2 || data.slots_raw[i] == 3
  1074. || data.slots_raw[i] == 6 || data.slots_raw[i] == 7
  1075. ){
  1076. data.materia_slots.push_back(SLOT_LINKED);
  1077. }
  1078. }
  1079. // In KERNEL.BIN, items with no elemental defense actually do have all elements marked,
  1080. // with mode 255. If, that's the case, consider that there are no elements.
  1081. if (data.element_defense_mode != 0xFF){
  1082. if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
  1083. if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
  1084. if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
  1085. if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
  1086. if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
  1087. if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
  1088. if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
  1089. if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
  1090. if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
  1091. if (data.element_raw == (data.element_raw | 0x0200))
  1092. data.elements.push_back(RESTORATIVE);
  1093. if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
  1094. if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
  1095. if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
  1096. if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
  1097. if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
  1098. if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
  1099. }
  1100. // In KERNEL.BIN, Non elemental item actually have all elements marked.
  1101. // If that happens, clear them all.
  1102. if (data.elements.size() == 16) data.elements.clear();
  1103. // Add to the list of weapons.
  1104. armors_.push_back(data);
  1105. armor_count ++;
  1106. }
  1107. return armor_count;
  1108. }
  1109. void KernelDataInstaller::WriteArmors(std::string file_name){
  1110. std::fstream file;
  1111. file.open(file_name, std::ios::out);
  1112. if (!file) return;
  1113. for (ArmorData armor : armors_){
  1114. file << "Game.Items[" << armor.id + 256 << "] = {\n"
  1115. << " type = Inventory.ITEM_TYPE.ARMOR,\n"
  1116. << " id = " << armor.id + 256 << ",\n"
  1117. << " price = " << prices_[armor.id + 256] << ",\n"
  1118. << " name = \"" << armor.name << "\",\n"
  1119. << " description = \"" << armor.description << "\",\n"
  1120. << " sell = " << armor.sellable << ",\n"
  1121. << " battle = " << armor.useable_battle << ",\n"
  1122. << " menu = " << armor.useable_menu << ",\n"
  1123. << " throw = 0,\n"
  1124. << " defense = {physical = " << static_cast<int>(armor.defense) << ", magical = "
  1125. << static_cast<int>(armor.m_defense) << "},\n"
  1126. << " evasion = {physical = " << static_cast<int>(armor.evasion) << ", magical = "
  1127. << static_cast<int>(armor.m_evasion) << "},\n"
  1128. << " growth = " << static_cast<int>(armor.growth) << ",\n"
  1129. << " status = {";
  1130. if (armor.status != 0XFF) file << armor.status;
  1131. file
  1132. << "},\n"
  1133. << " elements = {";
  1134. for (int s : armor.elements){
  1135. file << "\n {id = " << s << ", mode = "
  1136. << static_cast<int>(armor.element_defense_mode) << "},";
  1137. }
  1138. if (armor.elements.size() > 0) file << "\n },\n";
  1139. else file << "},\n";
  1140. file << " slots = {";
  1141. for (u8 slot : armor.materia_slots) file << static_cast<int>(slot) << ", ";
  1142. file << "},\n stats = {";
  1143. for (StatBonus s : armor.stat_bonus){
  1144. file << "\n {stat = " << static_cast<int>(s.stat) << ", bonus = "
  1145. << static_cast<int>(s.bonus) << "},";
  1146. }
  1147. if (armor.stat_bonus.size() > 0) file << "\n },\n";
  1148. else file << "},\n";
  1149. file << " users = {";
  1150. for (int s : armor.equip) file << s << ", ";
  1151. file << "}\n}\n";
  1152. }
  1153. file.close();
  1154. }
  1155. int KernelDataInstaller::ReadAccessories(){
  1156. // Empty the item list
  1157. accessories_.clear();
  1158. File accessory_file = kernel_.ExtractGZip(KERNEL_ACCESSORY_DATA);
  1159. File accessory_name_file = kernel_.ExtractGZip(KERNEL_ACCESSORY_NAMES);
  1160. File accessory_desc_file = kernel_.ExtractGZip(KERNEL_ACCESSORY_DESCRIPTIONS);
  1161. int name_offset = 0;
  1162. int desc_offset = 0;
  1163. int accessory_count = 0;
  1164. for (int i = 0; i < 32; i ++){ // There are exactly 32.
  1165. AccessoryData data;
  1166. // From the current name file offset, read 16 bytes.
  1167. // This is the pointer to the offset for the item name.
  1168. // Start reading there until 0xFF is found.
  1169. data.name = "";
  1170. u8 ch = 1;
  1171. name_offset = accessory_name_file.readU16LE();
  1172. while (ch != 0xFF){
  1173. ch = accessory_name_file.GetU8(name_offset);
  1174. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  1175. name_offset ++;
  1176. }
  1177. boost::replace_all(data.name, "\"", "'");
  1178. // For descriptions, do the same as for names.
  1179. data.description = "";
  1180. ch = 1;
  1181. desc_offset = accessory_desc_file.readU16LE();
  1182. while (ch != 0xFF){
  1183. ch = accessory_desc_file.GetU8(desc_offset);
  1184. if (ch != 0xFF){
  1185. // Warning: If the char is 0xF9, special function!
  1186. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  1187. // This is to compress information in the kernel.
  1188. if (ch == 0xF9){
  1189. // Get how much to read, two upper bits of the next byte.
  1190. // Multiply by 2 and add 4. That's just how it is.
  1191. u8 comp_size = (accessory_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  1192. // Get new offset, lower six bits of the next byte.
  1193. // The offset goes backwards from the position of the 0xF9 byte.
  1194. u8 comp_offset = accessory_desc_file.GetU8(desc_offset + 1) & 63;
  1195. for (int i = 0; i < comp_size; i ++){
  1196. data.description += ENGLISH_CHARS[
  1197. accessory_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  1198. ];
  1199. }
  1200. desc_offset ++;
  1201. }
  1202. else data.description += ENGLISH_CHARS[ch];
  1203. }
  1204. desc_offset ++;
  1205. }
  1206. boost::replace_all(data.description, "\"", "'");
  1207. // If the item doesn't have a name, it means all items have been read.
  1208. // break the loop.
  1209. if ("" == data.name) break;
  1210. // Read data from the accessory data section.
  1211. for (int i = 0; i < 2; i ++) data.stat_raw[i] = accessory_file.readU8();
  1212. for (int i = 0; i < 2; i ++) data.stat_bonus_raw[i] = accessory_file.readU8();
  1213. data.element_defense_mode = accessory_file.readU8();
  1214. data.effect = accessory_file.readU8();
  1215. data.element_raw = accessory_file.readU16LE();
  1216. data.status_raw = accessory_file.readU32LE();
  1217. data.equip_raw = accessory_file.readU16LE();
  1218. data.restrict_raw = accessory_file.readU16LE();
  1219. // Derive data from the read data.
  1220. data.id = i;
  1221. data.sellable = !(data.restrict_raw & (1 << 0));
  1222. data.useable_battle = !(data.restrict_raw & (2 << 0));
  1223. data.useable_menu = !(data.restrict_raw & (4 << 0));
  1224. if (data.status_raw == (data.status_raw | 0x00000001)) data.status.push_back(DEATH);
  1225. if (data.status_raw == (data.status_raw | 0x00000002)) data.status.push_back(NEAR_DEATH);
  1226. if (data.status_raw == (data.status_raw | 0x00000004)) data.status.push_back(SLEEP);
  1227. if (data.status_raw == (data.status_raw | 0x00000008)) data.status.push_back(POISONED);
  1228. if (data.status_raw == (data.status_raw | 0x00000010)) data.status.push_back(SADNESS);
  1229. if (data.status_raw == (data.status_raw | 0x00000020)) data.status.push_back(FURY);
  1230. if (data.status_raw == (data.status_raw | 0x00000040)) data.status.push_back(CONFU);
  1231. if (data.status_raw == (data.status_raw | 0x00000080)) data.status.push_back(SILENCE);
  1232. if (data.status_raw == (data.status_raw | 0x00000100)) data.status.push_back(HASTE);
  1233. if (data.status_raw == (data.status_raw | 0x00000200)) data.status.push_back(SLOW);
  1234. if (data.status_raw == (data.status_raw | 0x00000400)) data.status.push_back(STOP);
  1235. if (data.status_raw == (data.status_raw | 0x00000800)) data.status.push_back(FROG);
  1236. if (data.status_raw == (data.status_raw | 0x00001000)) data.status.push_back(SMALL);
  1237. if (data.status_raw == (data.status_raw | 0x00002000)) data.status.push_back(SLOW_NUMB);
  1238. if (data.status_raw == (data.status_raw | 0x00004000)) data.status.push_back(PETRIFY);
  1239. if (data.status_raw == (data.status_raw | 0x00008000)) data.status.push_back(REGEN);
  1240. if (data.status_raw == (data.status_raw | 0x00010000)) data.status.push_back(BARRIER);
  1241. if (data.status_raw == (data.status_raw | 0x00020000)) data.status.push_back(M_BARRIER);
  1242. if (data.status_raw == (data.status_raw | 0x00040000)) data.status.push_back(REFLECT);
  1243. if (data.status_raw == (data.status_raw | 0x00080000)) data.status.push_back(DUAL);
  1244. if (data.status_raw == (data.status_raw | 0x00100000)) data.status.push_back(SHIELD);
  1245. if (data.status_raw == (data.status_raw | 0x00200000)) data.status.push_back(D_SENTENCE);
  1246. if (data.status_raw == (data.status_raw | 0x00400000)) data.status.push_back(MANIPULATE);
  1247. if (data.status_raw == (data.status_raw | 0x00800000)) data.status.push_back(BERSERK);
  1248. if (data.status_raw == (data.status_raw | 0x01000000)) data.status.push_back(PEERLESS);
  1249. if (data.status_raw == (data.status_raw | 0x02000000)) data.status.push_back(PARALYSIS);
  1250. if (data.status_raw == (data.status_raw | 0x04000000)) data.status.push_back(DARKNESS);
  1251. if (data.status_raw == (data.status_raw | 0x08000000)) data.status.push_back(DUAL_DRAIN);
  1252. if (data.status_raw == (data.status_raw | 0x10000000)) data.status.push_back(DEATH_FORCE);
  1253. if (data.status_raw == (data.status_raw | 0x20000000)) data.status.push_back(RESIST);
  1254. if (data.status_raw == (data.status_raw | 0x40000000)) data.status.push_back(LUCKY_GIRL);
  1255. if (data.status_raw == (data.status_raw | 0x80000000)) data.status.push_back(IMPRISONED);
  1256. if (data.equip_raw == (data.equip_raw | 0x0001)) data.equip.push_back(1);
  1257. if (data.equip_raw == (data.equip_raw | 0x0002)) data.equip.push_back(2);
  1258. if (data.equip_raw == (data.equip_raw | 0x0004)) data.equip.push_back(3);
  1259. if (data.equip_raw == (data.equip_raw | 0x0008)) data.equip.push_back(4);
  1260. if (data.equip_raw == (data.equip_raw | 0x0010)) data.equip.push_back(5);
  1261. if (data.equip_raw == (data.equip_raw | 0x0020)) data.equip.push_back(6);
  1262. if (data.equip_raw == (data.equip_raw | 0x0040)) data.equip.push_back(7);
  1263. if (data.equip_raw == (data.equip_raw | 0x0080)) data.equip.push_back(8);
  1264. if (data.equip_raw == (data.equip_raw | 0x0100)) data.equip.push_back(9);
  1265. if (data.equip_raw == (data.equip_raw | 0x0200)) data.equip.push_back(10);
  1266. if (data.equip_raw == (data.equip_raw | 0x0400)) data.equip.push_back(11);
  1267. for (int i = 0; i < 2; i ++){
  1268. if (data.stat_raw[i] < 0XFF && data.stat_bonus_raw[i] > 0){
  1269. StatBonus stat_bonus;
  1270. stat_bonus.stat = data.stat_raw[i];
  1271. stat_bonus.bonus = data.stat_bonus_raw[i];
  1272. data.stat_bonus.push_back(stat_bonus);
  1273. }
  1274. }
  1275. // In KERNEL.BIN, items with no elemental defense actually do have all elements marked,
  1276. // with mode 255. If that's the case, consider that there are no elements.
  1277. if (data.element_defense_mode != 0xFF){
  1278. if (data.element_raw == (data.element_raw | 0x0001)) data.elements.push_back(FIRE);
  1279. if (data.element_raw == (data.element_raw | 0x0002)) data.elements.push_back(ICE);
  1280. if (data.element_raw == (data.element_raw | 0x0004)) data.elements.push_back(BOLT);
  1281. if (data.element_raw == (data.element_raw | 0x0008)) data.elements.push_back(EARTH);
  1282. if (data.element_raw == (data.element_raw | 0x0010)) data.elements.push_back(POISON);
  1283. if (data.element_raw == (data.element_raw | 0x0020)) data.elements.push_back(GRAVITY);
  1284. if (data.element_raw == (data.element_raw | 0x0040)) data.elements.push_back(WATER);
  1285. if (data.element_raw == (data.element_raw | 0x0080)) data.elements.push_back(WIND);
  1286. if (data.element_raw == (data.element_raw | 0x0100)) data.elements.push_back(HOLY);
  1287. if (data.element_raw == (data.element_raw | 0x0200))
  1288. data.elements.push_back(RESTORATIVE);
  1289. if (data.element_raw == (data.element_raw | 0x0400)) data.elements.push_back(CUT);
  1290. if (data.element_raw == (data.element_raw | 0x0800)) data.elements.push_back(HIT);
  1291. if (data.element_raw == (data.element_raw | 0x1000)) data.elements.push_back(PUNCH);
  1292. if (data.element_raw == (data.element_raw | 0x2000)) data.elements.push_back(SHOOT);
  1293. if (data.element_raw == (data.element_raw | 0x4000)) data.elements.push_back(SHOUT);
  1294. if (data.element_raw == (data.element_raw | 0x8000)) data.elements.push_back(HIDDEN);
  1295. }
  1296. // In KERNEL.BIN, Non elemental item actually have all elements marked.
  1297. // If that happens, clear them all.
  1298. if (data.elements.size() == 16) data.elements.clear();
  1299. // Add to the list of weapons.
  1300. accessories_.push_back(data);
  1301. accessory_count ++;
  1302. }
  1303. return accessory_count;
  1304. }
  1305. void KernelDataInstaller::WriteAccessories(std::string file_name){
  1306. std::fstream file;
  1307. file.open(file_name, std::ios::out);
  1308. if (!file) return;
  1309. for (AccessoryData accessory : accessories_){
  1310. file << "Game.Items[" << accessory.id + 287 << "] = {\n"
  1311. << " type = Inventory.ITEM_TYPE.ACCESSORY,\n"
  1312. << " id = " << accessory.id + 287 << ",\n"
  1313. << " price = " << prices_[accessory.id + 287] << ",\n"
  1314. << " name = \"" << accessory.name << "\",\n"
  1315. << " description = \"" << accessory.description << "\",\n"
  1316. << " sell = " << accessory.sellable << ",\n"
  1317. << " battle = " << accessory.useable_battle << ",\n"
  1318. << " menu = " << accessory.useable_menu << ",\n"
  1319. << " throw = 0,\n"
  1320. << " special_effect = {";
  1321. if (accessory.effect != 0XFF) file << static_cast<int>(accessory.effect);
  1322. file
  1323. << "},\n"
  1324. << " status = {";
  1325. for (int s : accessory.status) file << s << ", ";
  1326. file
  1327. << "},\n"
  1328. << " elements = {";
  1329. for (int s : accessory.elements) file << s << ", ";
  1330. file << "},\n stats = {";
  1331. for (StatBonus s : accessory.stat_bonus){
  1332. file << "\n {stat = " << static_cast<int>(s.stat) << ", bonus = "
  1333. << static_cast<int>(s.bonus) << "},";
  1334. }
  1335. if (accessory.stat_bonus.size() > 0) file << "\n },\n";
  1336. else file << "},\n";
  1337. file << " users = {";
  1338. for (int s : accessory.equip) file << s << ", ";
  1339. file << "}\n}\n";
  1340. }
  1341. file.close();
  1342. }
  1343. int KernelDataInstaller::ReadMateria(){
  1344. // Empty the item list
  1345. materia_.clear();
  1346. File materia_file = kernel_.ExtractGZip(KERNEL_MATERIA_DATA);
  1347. File materia_name_file = kernel_.ExtractGZip(KERNEL_MATERIA_NAMES);
  1348. File materia_desc_file = kernel_.ExtractGZip(KERNEL_MATERIA_DESCRIPTIONS);
  1349. int name_offset = 0;
  1350. int desc_offset = 0;
  1351. int materia_count = 0;
  1352. for (int i = 0; i < 96; i ++){ // There are exactly 96.
  1353. MateriaData data;
  1354. // From the current name file offset, read 16 bytes.
  1355. // This is the pointer to the offset for the item name.
  1356. // Start reading there until 0xFF is found.
  1357. data.name = "";
  1358. u8 ch = 1;
  1359. name_offset = materia_name_file.readU16LE();
  1360. while (ch != 0xFF){
  1361. ch = materia_name_file.GetU8(name_offset);
  1362. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  1363. name_offset ++;
  1364. }
  1365. boost::replace_all(data.name, "\"", "'");
  1366. // For descriptions, do the same as for names.
  1367. data.description = "";
  1368. ch = 1;
  1369. desc_offset = materia_desc_file.readU16LE();
  1370. while (ch != 0xFF){
  1371. ch = materia_desc_file.GetU8(desc_offset);
  1372. if (ch != 0xFF){
  1373. // Warning: If the char is 0xF9, special function!
  1374. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  1375. // This is to compress information in the kernel.
  1376. if (ch == 0xF9){
  1377. // Get how much to read, two upper bits of the next byte.
  1378. // Multiply by 2 and add 4. That's just how it is.
  1379. u8 comp_size = (materia_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  1380. // Get new offset, lower six bits of the next byte.
  1381. // The offset goes backwards from the position of the 0xF9 byte.
  1382. u8 comp_offset = materia_desc_file.GetU8(desc_offset + 1) & 63;
  1383. for (int i = 0; i < comp_size; i ++){
  1384. data.description += ENGLISH_CHARS[
  1385. materia_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  1386. ];
  1387. }
  1388. desc_offset ++;
  1389. }
  1390. else data.description += ENGLISH_CHARS[ch];
  1391. }
  1392. desc_offset ++;
  1393. }
  1394. boost::replace_all(data.description, "\"", "'");
  1395. // Read data from the materia data section.
  1396. for (int i = 0; i < 4; i ++) data.level_up_ap[i] = materia_file.readU16LE();
  1397. data.stat_raw = materia_file.readU8();
  1398. data.status_raw // WARNING: Status has only three bytes.
  1399. = materia_file.readU8() + (materia_file.readU8() << 8) + (materia_file.readU8() << 16);
  1400. data.element = materia_file.readU8();
  1401. data.type_raw = materia_file.readU8();
  1402. for (int i = 0; i < 6; i ++) data.attribute[i] = materia_file.readU8();
  1403. // If the materia doesn't have a name, don't bother processing the rest of the data,
  1404. // it's not going to be added to the list.
  1405. if ("" == data.name) continue;
  1406. // Derive data from the read data.
  1407. data.id = i;
  1408. // Status. 3 bytes, so only the first 24 can be present.
  1409. if (data.status_raw == (data.status_raw | 0x000001)) data.status.push_back(DEATH);
  1410. if (data.status_raw == (data.status_raw | 0x000002)) data.status.push_back(NEAR_DEATH);
  1411. if (data.status_raw == (data.status_raw | 0x000004)) data.status.push_back(SLEEP);
  1412. if (data.status_raw == (data.status_raw | 0x000008)) data.status.push_back(POISONED);
  1413. if (data.status_raw == (data.status_raw | 0x000010)) data.status.push_back(SADNESS);
  1414. if (data.status_raw == (data.status_raw | 0x000020)) data.status.push_back(FURY);
  1415. if (data.status_raw == (data.status_raw | 0x000040)) data.status.push_back(CONFU);
  1416. if (data.status_raw == (data.status_raw | 0x000080)) data.status.push_back(SILENCE);
  1417. if (data.status_raw == (data.status_raw | 0x000100)) data.status.push_back(HASTE);
  1418. if (data.status_raw == (data.status_raw | 0x000200)) data.status.push_back(SLOW);
  1419. if (data.status_raw == (data.status_raw | 0x000400)) data.status.push_back(STOP);
  1420. if (data.status_raw == (data.status_raw | 0x000800)) data.status.push_back(FROG);
  1421. if (data.status_raw == (data.status_raw | 0x001000)) data.status.push_back(SMALL);
  1422. if (data.status_raw == (data.status_raw | 0x002000)) data.status.push_back(SLOW_NUMB);
  1423. if (data.status_raw == (data.status_raw | 0x004000)) data.status.push_back(PETRIFY);
  1424. if (data.status_raw == (data.status_raw | 0x008000)) data.status.push_back(REGEN);
  1425. if (data.status_raw == (data.status_raw | 0x010000)) data.status.push_back(BARRIER);
  1426. if (data.status_raw == (data.status_raw | 0x020000)) data.status.push_back(M_BARRIER);
  1427. if (data.status_raw == (data.status_raw | 0x040000)) data.status.push_back(REFLECT);
  1428. if (data.status_raw == (data.status_raw | 0x080000)) data.status.push_back(DUAL);
  1429. if (data.status_raw == (data.status_raw | 0x100000)) data.status.push_back(SHIELD);
  1430. if (data.status_raw == (data.status_raw | 0x200000)) data.status.push_back(D_SENTENCE);
  1431. if (data.status_raw == (data.status_raw | 0x400000)) data.status.push_back(MANIPULATE);
  1432. if (data.status_raw == (data.status_raw | 0x800000)) data.status.push_back(BERSERK);
  1433. // Limit type to materia color.
  1434. data.type = data.type_raw & 15; // Lower nybble.
  1435. switch (data.type){
  1436. case 0x09:
  1437. case 0x0A:
  1438. data.type = static_cast<int>(MATERIA_TYPE::MAGIC);
  1439. break;
  1440. case 0x05:
  1441. data.type = static_cast<int>(MATERIA_TYPE::SUPPORT);
  1442. break;
  1443. case 0x02:
  1444. case 0x03:
  1445. case 0x06:
  1446. case 0x07:
  1447. case 0x08:
  1448. data.type = static_cast<int>(MATERIA_TYPE::COMMAND);
  1449. break;
  1450. case 0x0B:
  1451. case 0x0C:
  1452. data.type = static_cast<int>(MATERIA_TYPE::SUMMON);
  1453. break;
  1454. default:
  1455. data.type = static_cast<int>(MATERIA_TYPE::INDEPENDENT);
  1456. }
  1457. // Stat bonuses. Manually done.
  1458. data.stats.str = 0;
  1459. data.stats.vit = 0;
  1460. data.stats.mag = 0;
  1461. data.stats.spr = 0;
  1462. data.stats.dex = 0;
  1463. data.stats.lck = 0;
  1464. data.stats.hp = 0;
  1465. data.stats.mp = 0;
  1466. data.stats.change = false;
  1467. switch (data.stat_raw){
  1468. case 0x01:
  1469. data.stats.change = true;
  1470. data.stats.str = -2;
  1471. data.stats.vit = -1;
  1472. data.stats.mag = 2;
  1473. data.stats.spr = 1;
  1474. data.stats.dex = 0;
  1475. data.stats.lck = 0;
  1476. data.stats.hp = -5;
  1477. data.stats.mp = 5;
  1478. break;
  1479. case 0x02:
  1480. data.stats.change = true;
  1481. data.stats.str = -4;
  1482. data.stats.vit = -2;
  1483. data.stats.mag = 4;
  1484. data.stats.spr = 2;
  1485. data.stats.hp = -10;
  1486. data.stats.mp = 10;
  1487. break;
  1488. case 0x03:
  1489. data.stats.change = true;
  1490. data.stats.dex = 2;
  1491. data.stats.lck = -2;
  1492. break;
  1493. case 0x04:
  1494. data.stats.change = true;
  1495. data.stats.str = -1;
  1496. data.stats.vit = -1;
  1497. data.stats.mag = 1;
  1498. data.stats.spr = 1;
  1499. break;
  1500. case 0x05:
  1501. data.stats.change = true;
  1502. data.stats.str = 1;
  1503. data.stats.vit = 1;
  1504. data.stats.mag = -1;
  1505. data.stats.spr = -1;
  1506. break;
  1507. case 0x06:
  1508. data.stats.change = true;
  1509. data.stats.vit = 1;
  1510. break;
  1511. case 0x07:
  1512. data.stats.change = true;
  1513. data.stats.lck = 1;
  1514. break;
  1515. case 0x08:
  1516. data.stats.change = true;
  1517. data.stats.lck = -1;
  1518. break;
  1519. case 0x09:
  1520. data.stats.change = true;
  1521. data.stats.dex = -2;
  1522. break;
  1523. case 0x0A:
  1524. data.stats.change = true;
  1525. data.stats.dex = 2;
  1526. break;
  1527. case 0x0B:
  1528. data.stats.change = true;
  1529. data.stats.str = -1;
  1530. data.stats.mag = 1;
  1531. data.stats.hp = -2;
  1532. data.stats.mp = 2;
  1533. break;
  1534. case 0x0C:
  1535. data.stats.change = true;
  1536. data.stats.mag = 1;
  1537. data.stats.hp = -2;
  1538. data.stats.mp = 2;
  1539. break;
  1540. case 0x0D:
  1541. data.stats.change = true;
  1542. data.stats.mag = 1;
  1543. data.stats.spr = 1;
  1544. data.stats.hp = -5;
  1545. data.stats.mp = 5;
  1546. break;
  1547. case 0x0E:
  1548. data.stats.change = true;
  1549. data.stats.mag = 2;
  1550. data.stats.spr = 2;
  1551. data.stats.hp = -10;
  1552. data.stats.mp = 10;
  1553. break;
  1554. case 0x0F:
  1555. data.stats.change = true;
  1556. data.stats.mag = 4;
  1557. data.stats.spr = 4;
  1558. data.stats.hp = -10;
  1559. data.stats.mp = 15;
  1560. break;
  1561. case 0x10:
  1562. data.stats.change = true;
  1563. data.stats.mag = 8;
  1564. data.stats.spr = 8;
  1565. data.stats.hp = -10;
  1566. data.stats.mp = 20;
  1567. break;
  1568. }
  1569. // Add to the list of materia.
  1570. materia_.push_back(data);
  1571. materia_count ++;
  1572. }
  1573. return materia_count;
  1574. }
  1575. void KernelDataInstaller::WriteMateria(std::string file_name){
  1576. std::fstream file;
  1577. file.open(file_name, std::ios::out);
  1578. if (!file) return;
  1579. for (MateriaData materia : materia_){
  1580. file << "Game.Materia[" << materia.id << "] = {\n"
  1581. << " price = " << prices_[materia.id + 320] << ",\n"
  1582. << " name = \"" << materia.name << "\",\n"
  1583. << " description = \"" << materia.description << "\",\n"
  1584. << " type = " << materia.type << ",\n"
  1585. << " levels_ap = {[1] = 0, ";
  1586. for (int i = 0; i < 4; i ++){
  1587. if (materia.level_up_ap[i] < 65535)
  1588. file << "[" << (i + 2) << "] = " << (materia.level_up_ap[i] * 100) << ", ";
  1589. }
  1590. file
  1591. << "},\n"
  1592. << " status = {";
  1593. for (int s : materia.status) file << s << ", ";
  1594. file
  1595. << "}\n"
  1596. << " elements = {";
  1597. if (materia.element != 0xFF) file << static_cast<int>(materia.element);
  1598. file << "}\n stats = {";
  1599. if (materia.stats.str != 0)
  1600. file
  1601. << "\n {stat = \"str\", bonus = " << materia.stats.str << ", mode = \"abs\"},";
  1602. if (materia.stats.vit != 0)
  1603. file
  1604. << "\n {stat = \"vit\", bonus = " << materia.stats.vit << ", mode = \"abs\"},";
  1605. if (materia.stats.mag != 0)
  1606. file
  1607. << "\n {stat = \"mag\", bonus = " << materia.stats.mag << ", mode = \"abs\"},";
  1608. if (materia.stats.spr != 0)
  1609. file
  1610. << "\n {stat = \"spr\", bonus = " << materia.stats.spr << ", mode = \"abs\"},";
  1611. if (materia.stats.dex != 0)
  1612. file
  1613. << "\n {stat = \"dex\", bonus = " << materia.stats.dex << ", mode = \"abs\"},";
  1614. if (materia.stats.lck != 0)
  1615. file
  1616. << "\n {stat = \"lck\", bonus = " << materia.stats.lck << ", mode = \"abs\"},";
  1617. if (materia.stats.hp != 0)
  1618. file
  1619. << "\n {stat = \"hp\", bonus = " << materia.stats.hp << ", mode = \"rel\"},";
  1620. if (materia.stats.mp != 0)
  1621. file
  1622. << "\n {stat = \"mp\", bonus = " << materia.stats.mp << ", mode = \"rel\"},";
  1623. if (materia.stats.change) file << "\n }\n";
  1624. else file << "}\n";
  1625. file << "}\n";
  1626. }
  1627. file.close();
  1628. }
  1629. int KernelDataInstaller::ReadKeyItems(){
  1630. // Empty the item list
  1631. key_items_.clear();
  1632. File key_items_name_file = kernel_.ExtractGZip(KERNEL_KEY_ITEM_NAMES);
  1633. File key_items_desc_file = kernel_.ExtractGZip(KERNEL_KEY_ITEM_DESCRIPTIONS);
  1634. int name_offset = 0;
  1635. int desc_offset = 0;
  1636. int key_item_count = 0;
  1637. for (int i = 0; i < 128; i ++){
  1638. KeyItemData data;
  1639. // From the current name file offset, read 16 bytes.
  1640. // This is the pointer to the offset for the item name.
  1641. // Start reading there until 0xFF is found.
  1642. data.name = "";
  1643. u8 ch = 1;
  1644. name_offset = key_items_name_file.readU16LE();
  1645. while (ch != 0xFF){
  1646. ch = key_items_name_file.GetU8(name_offset);
  1647. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  1648. name_offset ++;
  1649. }
  1650. boost::replace_all(data.name, "\"", "'");
  1651. // For descriptions, do the same as for names.
  1652. data.description = "";
  1653. ch = 1;
  1654. desc_offset = key_items_desc_file.readU16LE();
  1655. while (ch != 0xFF){
  1656. ch = key_items_desc_file.GetU8(desc_offset);
  1657. if (ch != 0xFF){
  1658. // Warning: If the char is 0xF9, special function!
  1659. // the next byte (in bits, aaoooooo) means to read aa data at offset oooooo.
  1660. // This is to compress information in the kernel.
  1661. if (ch == 0xF9){
  1662. // Get how much to read, two upper bits of the next byte.
  1663. // Multiply by 2 and add 4. That's just how it is.
  1664. u8 comp_size = (key_items_desc_file.GetU8(desc_offset + 1) >> 6) * 2 + 4;
  1665. // Get new offset, lower six bits of the next byte.
  1666. // The offset goes backwards from the position of the 0xF9 byte.
  1667. u8 comp_offset = key_items_desc_file.GetU8(desc_offset + 1) & 63;
  1668. for (int i = 0; i < comp_size; i ++){
  1669. data.description += ENGLISH_CHARS[
  1670. key_items_desc_file.GetU8(desc_offset - 1 - comp_offset + i)
  1671. ];
  1672. }
  1673. desc_offset ++;
  1674. }
  1675. else data.description += ENGLISH_CHARS[ch];
  1676. }
  1677. desc_offset ++;
  1678. }
  1679. boost::replace_all(data.description, "\"", "'");
  1680. // If the key item doesn't have a name, it means all key items have been read.
  1681. // break the loop.
  1682. if ("" == data.name) break;
  1683. // Add to the list of items.
  1684. data.id = i;
  1685. key_items_.push_back(data);
  1686. key_item_count ++;
  1687. }
  1688. return key_item_count;
  1689. }
  1690. void KernelDataInstaller::WriteKeyItems(std::string file_name){
  1691. std::fstream file;
  1692. file.open(file_name, std::ios::out);
  1693. if (!file) return;
  1694. for (KeyItemData key_item : key_items_){
  1695. file << "Game.Key_Items[" << key_item.id << "] = {\n"
  1696. << " name = \"" << key_item.name << "\",\n"
  1697. << " description = \"" << key_item.description << "\"\n}\n";
  1698. }
  1699. file.close();
  1700. }
  1701. int KernelDataInstaller::ReadSummonNames(){
  1702. // Empty the summon list
  1703. key_items_.clear();
  1704. File summon_name_file = kernel_.ExtractGZip(KERNEL_SUMMON_ATTACK_NAMES);
  1705. int name_offset = 0;
  1706. int summon_count = 0;
  1707. for (int i = 0; i < 16; i ++){ // There are exactly 16.
  1708. SummonNameData data;
  1709. // From the current name file offset, read 16 bytes.
  1710. // This is the pointer to the offset for the item name.
  1711. // Start reading there until 0xFF is found.
  1712. data.name = "";
  1713. u8 ch = 1;
  1714. name_offset = summon_name_file.readU16LE();
  1715. while (ch != 0xFF){
  1716. ch = summon_name_file.GetU8(name_offset);
  1717. if (ch != 0xFF) data.name += ENGLISH_CHARS[ch];
  1718. name_offset ++;
  1719. }
  1720. boost::replace_all(data.name, "\"", "'");
  1721. // If the key item doesn't have a name, it means all key items have been read.
  1722. // break the loop.
  1723. if ("" == data.name) break;
  1724. // Add to the list of items.
  1725. data.id = i;
  1726. summon_names_.push_back(data);
  1727. summon_count ++;
  1728. }
  1729. return summon_count;
  1730. }
  1731. void KernelDataInstaller::WriteSummonNames(std::string file_name){
  1732. std::fstream file;
  1733. file.open(file_name, std::ios::out);
  1734. if (!file) return;
  1735. for (SummonNameData summon : summon_names_)
  1736. file << "Game.Summon_Names[" << summon.id << "] = {\"" << summon.name << "\"}\n";
  1737. file.close();
  1738. }
  1739. void KernelDataInstaller::ReadInitialSaveMap(){
  1740. // Empty the item list
  1741. attacks_.clear();
  1742. File savemap_file = kernel_.ExtractGZip(KERNEL_INITIALIZATION_DATA);
  1743. savemap_file.WriteFile("/home/ivalentin/initialsavemap");
  1744. // The initial savemap in KERNEL.BIN startas at 0x0054, directly into Cloud's level.
  1745. // It skips the header (PC and PSX, checksum, preview data and window colour).
  1746. for (int i = 0; i < 9; i ++){
  1747. savemap_.characters[i].identifier = savemap_file.readU8();
  1748. savemap_.characters[i].level = savemap_file.readU8();
  1749. savemap_.characters[i].str = savemap_file.readU8();
  1750. savemap_.characters[i].vit = savemap_file.readU8();
  1751. savemap_.characters[i].mag = savemap_file.readU8();
  1752. savemap_.characters[i].spr = savemap_file.readU8();
  1753. savemap_.characters[i].dex = savemap_file.readU8();
  1754. savemap_.characters[i].lck = savemap_file.readU8();
  1755. savemap_.characters[i].str_bonus = savemap_file.readU8();
  1756. savemap_.characters[i].vit_bonus = savemap_file.readU8();
  1757. savemap_.characters[i].mag_bonus = savemap_file.readU8();
  1758. savemap_.characters[i].spr_bonus = savemap_file.readU8();
  1759. savemap_.characters[i].dex_bonus = savemap_file.readU8();
  1760. savemap_.characters[i].lck_bonus = savemap_file.readU8();
  1761. savemap_.characters[i].limit_level = savemap_file.readU8();
  1762. savemap_.characters[i].limit_bar = savemap_file.readU8();
  1763. bool name_end = false;
  1764. savemap_.characters[i].name = "";
  1765. for (int j = 0; j < 12; j ++){
  1766. savemap_.characters[i].name_raw[i] = savemap_file.readU8();
  1767. if (name_end == false){
  1768. if (savemap_.characters[i].name_raw[i] != 0XFF){
  1769. savemap_.characters[i].name
  1770. += ENGLISH_CHARS[savemap_.characters[i].name_raw[i]];
  1771. }
  1772. else name_end = true;
  1773. }
  1774. }
  1775. savemap_.characters[i].weapon = savemap_file.readU8();
  1776. savemap_.characters[i].armor = savemap_file.readU8();
  1777. savemap_.characters[i].accessory = savemap_file.readU8();
  1778. savemap_.characters[i].status_raw = savemap_file.readU8();
  1779. if (savemap_.characters[i].status_raw == (savemap_.characters[i].status_raw | 0x10)){
  1780. savemap_.characters[i].sadness = true;
  1781. savemap_.characters[i].fury = false;
  1782. }
  1783. else if (savemap_.characters[i].status_raw == (savemap_.characters[i].status_raw | 0x20)){
  1784. savemap_.characters[i].sadness = false;
  1785. savemap_.characters[i].fury = true;
  1786. }
  1787. else{
  1788. savemap_.characters[i].sadness = false;
  1789. savemap_.characters[i].fury = false;
  1790. }
  1791. savemap_.characters[i].row_raw = savemap_file.readU8();
  1792. if (savemap_.characters[i].row_raw == 0xFE) savemap_.characters[i].back_row = true;
  1793. else savemap_.characters[i].back_row = false;
  1794. savemap_.characters[i].level_progress = savemap_file.readU8();
  1795. savemap_.characters[i].learned_limits_raw = savemap_file.readU16LE();
  1796. for (int j = 0; j < 4; j ++){
  1797. savemap_.characters[i].limits_learned[j][0] = false;
  1798. savemap_.characters[i].limits_learned[j][1] = false;
  1799. }
  1800. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0001))
  1801. savemap_.characters[i].limits_learned[0][0] = true;
  1802. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0002))
  1803. savemap_.characters[i].limits_learned[0][1] = true;
  1804. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0008))
  1805. savemap_.characters[i].limits_learned[1][0] = true;
  1806. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0010))
  1807. savemap_.characters[i].limits_learned[1][1] = true;
  1808. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0040))
  1809. savemap_.characters[i].limits_learned[2][0] = true;
  1810. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0080))
  1811. savemap_.characters[i].limits_learned[2][1] = true;
  1812. if (savemap_.characters[i].learned_limits_raw == (savemap_.characters[i].learned_limits_raw | 0x0200))
  1813. savemap_.characters[i].limits_learned[3][0] = true;
  1814. savemap_.characters[i].kills = savemap_file.readU16LE();
  1815. savemap_.characters[i].limit_uses[0] = savemap_file.readU16LE();
  1816. savemap_.characters[i].limit_uses[1] = savemap_file.readU16LE();
  1817. savemap_.characters[i].limit_uses[2] = savemap_file.readU16LE();
  1818. savemap_.characters[i].hp = savemap_file.readU16LE();
  1819. savemap_.characters[i].base_hp = savemap_file.readU16LE();
  1820. savemap_.characters[i].mp = savemap_file.readU16LE();
  1821. savemap_.characters[i].base_mp = savemap_file.readU16LE();
  1822. savemap_.characters[i].unknown = savemap_file.readU32LE();
  1823. savemap_.characters[i].max_hp = savemap_file.readU16LE();
  1824. savemap_.characters[i].max_mp = savemap_file.readU16LE();
  1825. savemap_.characters[i].exp = savemap_file.readU32LE();
  1826. for (int m = 0; m < 8; m ++){
  1827. savemap_.characters[i].weapon_materia[m].id = savemap_file.readU8();
  1828. // TODO: Identify Enemy Skill, do special treatment
  1829. savemap_.characters[i].weapon_materia[m].ap // WARNING: AP has only three bytes.
  1830. = savemap_file.readU8()
  1831. + (savemap_file.readU8() << 8)
  1832. + (savemap_file.readU8() << 16);
  1833. }
  1834. for (int m = 0; m < 8; m ++){
  1835. savemap_.characters[i].armor_materia[m].id = savemap_file.readU8();
  1836. // TODO: Identify Enemy Skill, do special treatment
  1837. savemap_.characters[i].armor_materia[m].ap // WARNING: AP has only three bytes.
  1838. = savemap_file.readU8()
  1839. + (savemap_file.readU8() << 8)
  1840. + (savemap_file.readU8() << 16);
  1841. }
  1842. savemap_.characters[i].exp_to_next = savemap_file.readU32LE();
  1843. }
  1844. // The initial savemap ends up after character data, end now.
  1845. }
  1846. void KernelDataInstaller::WriteInitialSaveMap(std::string file_name){
  1847. // The initial save map only contains character data.
  1848. std::fstream file;
  1849. file.open(file_name, std::ios::out);
  1850. if (!file) return;
  1851. int total_count = 0; // Utility to count in loops.
  1852. for (int c = 0; c < 9; c ++){
  1853. SaveMap::Character character = savemap_.characters[c];
  1854. file
  1855. << "Characters[" << c << "] = {\n"
  1856. << " char_id = " << static_cast<int>(character.identifier) << ",\n"
  1857. << " name = \"" << character.name << "\",\n"
  1858. << " level = " << static_cast<int>(character.level) << ",\n"
  1859. << " kills = " << character.kills << ",\n"
  1860. << " back_row = " << character.back_row << ",\n"
  1861. << " exp = " << character.exp << ",\n"
  1862. << " exp_to_next = " << character.exp_to_next << ",\n"
  1863. << " stats = {\n"
  1864. << " str = {base = " << static_cast<int>(character.str)
  1865. << ", bonus = " << static_cast<int>(character.str_bonus)
  1866. << ", total = " << static_cast<int>(character.str + character.str_bonus) << "},\n"
  1867. << " vit = {base = " << static_cast<int>(character.vit)
  1868. << ", bonus = " << static_cast<int>(character.vit_bonus)
  1869. << ", total = " << static_cast<int>(character.vit + character.vit_bonus) << "},\n"
  1870. << " mag = {base = " << static_cast<int>(character.mag)
  1871. << ", bonus = " << static_cast<int>(character.mag_bonus)
  1872. << ", total = " << static_cast<int>(character.mag + character.mag_bonus) << "},\n"
  1873. << " spr = {base = " << static_cast<int>(character.spr)
  1874. << ", bonus = " << static_cast<int>(character.spr_bonus)
  1875. << ", total = " << static_cast<int>(character.spr + character.spr_bonus) << "},\n"
  1876. << " dex = {base = " << static_cast<int>(character.dex)
  1877. << ", bonus = " << static_cast<int>(character.dex_bonus)
  1878. << ", total = " << static_cast<int>(character.dex + character.dex_bonus) << "},\n"
  1879. << " lck = {base = " << static_cast<int>(character.lck)
  1880. << ", bonus = " << static_cast<int>(character.lck_bonus)
  1881. << ", total = " << static_cast<int>(character.lck + character.lck_bonus) << "},\n"
  1882. << " hp = {current = " << character.hp << ", base = " << character.base_hp
  1883. << ", max = " << character.max_hp << "},\n"
  1884. << " mp = {current = " << character.mp << ", base = " << character.base_mp
  1885. << ", max = " << character.max_mp << "}\n"
  1886. << " },\n"
  1887. << " limit = {\n"
  1888. << " current = " << static_cast<int>(character.limit_level) << ",\n"
  1889. << " bar = " << static_cast<int>(character.limit_bar) << ",\n"
  1890. << " learned = {\n"
  1891. << " [1] = {[1] = " << character.limits_learned[0][0] << ", [2] = "
  1892. << character.limits_learned[0][1] << "},\n"
  1893. << " [2] = {[1] = " << character.limits_learned[1][0] << ", [2] = "
  1894. << character.limits_learned[1][1] << "},\n"
  1895. << " [3] = {[1] = " << character.limits_learned[2][0] << ", [2] = "
  1896. << character.limits_learned[2][1] << "},\n"
  1897. << " [4] = {[1] = " << character.limits_learned[3][0] << ", [2] = "
  1898. << character.limits_learned[3][1] << "}\n"
  1899. << " },\n"
  1900. << " uses = {[1] = " << character.limit_uses[0] << ", [2] = "
  1901. << character.limit_uses[1] << ", [3] = " << character.limit_uses[2] << ", [4] = 0}\n"
  1902. << " },\n"
  1903. << " weapon = {\n"
  1904. << " id = " << static_cast<int>(character.weapon) << ",\n"
  1905. << " materia = {";
  1906. total_count = 0;
  1907. for (int m = 0; m < 8; m ++){
  1908. if (character.weapon_materia[m].id < 255){
  1909. total_count ++;
  1910. file << "\n [" << m << "] = {id = "
  1911. << static_cast<int>(character.weapon_materia[m].id) << ", ap = "
  1912. << character.weapon_materia[m].ap << "},";
  1913. }
  1914. }
  1915. if (total_count > 0) file << "\n }\n },\n";
  1916. else file << "}\n },\n";
  1917. file
  1918. << " armor = {\n"
  1919. << " id = " << static_cast<int>(character.armor) << ",\n"
  1920. << " materia = {";
  1921. total_count = 0;
  1922. for (int m = 0; m < 8; m ++){
  1923. if (character.armor_materia[m].id < 255){
  1924. total_count ++;
  1925. file << "\n [" << m << "] = {id = "
  1926. << static_cast<int>(character.armor_materia[m].id) << ", ap = "
  1927. << character.armor_materia[m].ap << "},";
  1928. }
  1929. }
  1930. if (total_count > 0) file << "\n }\n },\n";
  1931. else file << "}\n },\n";
  1932. file << " accessory = ";
  1933. if (character.accessory < 0xFF) file << static_cast<int>(character.accessory);
  1934. else file << "nil";
  1935. file << ",\n status = {";
  1936. if (character.fury) file << FURY;
  1937. if (character.sadness) file << SADNESS;
  1938. file << "}\n}\n";
  1939. }
  1940. file.close();
  1941. }