KernelDataInstaller.cpp 99 KB

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