csv2yaml.cpp 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <fstream>
  4. #include <functional>
  5. #include <iostream>
  6. #include <locale>
  7. #include <unordered_map>
  8. #include <vector>
  9. #ifdef WIN32
  10. #include <conio.h>
  11. #else
  12. #include <termios.h>
  13. #include <unistd.h>
  14. #include <stdio.h>
  15. #endif
  16. #include <yaml-cpp/yaml.h>
  17. #include "../common/cbasetypes.hpp"
  18. #include "../common/core.hpp"
  19. #include "../common/malloc.hpp"
  20. #include "../common/mmo.hpp"
  21. #include "../common/nullpo.hpp"
  22. #include "../common/showmsg.hpp"
  23. #include "../common/strlib.hpp"
  24. #include "../common/utilities.hpp"
  25. #include "../common/utils.hpp"
  26. #ifdef WIN32
  27. #include "../common/winapi.hpp"
  28. #endif
  29. // Only for constants - do not use functions of it or linking will fail
  30. #include "../map/achievement.hpp"
  31. #include "../map/battle.hpp"
  32. #include "../map/battleground.hpp"
  33. #include "../map/channel.hpp"
  34. #include "../map/chat.hpp"
  35. #include "../map/date.hpp"
  36. #include "../map/instance.hpp"
  37. #include "../map/mercenary.hpp"
  38. #include "../map/mob.hpp"
  39. #include "../map/npc.hpp"
  40. #include "../map/pc.hpp"
  41. #include "../map/pet.hpp"
  42. #include "../map/quest.hpp"
  43. #include "../map/script.hpp"
  44. #include "../map/skill.hpp"
  45. #include "../map/storage.hpp"
  46. using namespace rathena;
  47. #define MAX_MAP_PER_INSTANCE 255
  48. #ifndef WIN32
  49. int getch( void ){
  50. struct termios oldattr, newattr;
  51. int ch;
  52. tcgetattr( STDIN_FILENO, &oldattr );
  53. newattr = oldattr;
  54. newattr.c_lflag &= ~( ICANON | ECHO );
  55. tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
  56. ch = getchar();
  57. tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
  58. return ch;
  59. }
  60. #endif
  61. // Required constant and structure definitions
  62. #define MAX_GUILD_SKILL_REQUIRE 5
  63. #define MAX_SKILL_ITEM_REQUIRE 10
  64. #define MAX_SKILL_STATUS_REQUIRE 3
  65. #define MAX_SKILL_EQUIP_REQUIRE 10
  66. #define MAX_QUEST_DROPS 3
  67. struct s_skill_unit_csv : s_skill_db {
  68. std::string target_str;
  69. int unit_flag_csv;
  70. };
  71. std::unordered_map<uint16, s_skill_require> skill_require;
  72. std::unordered_map<uint16, s_skill_db> skill_cast;
  73. std::unordered_map<uint16, s_skill_db> skill_castnodex;
  74. std::unordered_map<uint16, s_skill_unit_csv> skill_unit;
  75. std::unordered_map<uint16, s_skill_copyable> skill_copyable;
  76. std::unordered_map<uint16, s_skill_db> skill_nearnpc;
  77. // Forward declaration of conversion functions
  78. static bool guild_read_guildskill_tree_db( char* split[], int columns, int current );
  79. static bool pet_read_db( const char* file );
  80. static bool skill_parse_row_magicmushroomdb(char *split[], int column, int current);
  81. static bool skill_parse_row_abradb(char* split[], int columns, int current);
  82. static bool skill_parse_row_spellbookdb(char* split[], int columns, int current);
  83. static bool mob_readdb_mobavail(char *str[], int columns, int current);
  84. static bool skill_parse_row_requiredb(char* split[], int columns, int current);
  85. static bool skill_parse_row_castdb(char* split[], int columns, int current);
  86. static bool skill_parse_row_castnodexdb(char* split[], int columns, int current);
  87. static bool skill_parse_row_unitdb(char* split[], int columns, int current);
  88. static bool skill_parse_row_copyabledb(char* split[], int columns, int current);
  89. static bool skill_parse_row_nonearnpcrangedb(char* split[], int columns, int current);
  90. static bool skill_parse_row_skilldb(char* split[], int columns, int current);
  91. static bool quest_read_db(char *split[], int columns, int current);
  92. static bool instance_readdb_sub(char* str[], int columns, int current);
  93. // Constants for conversion
  94. std::unordered_map<uint16, std::string> aegis_itemnames;
  95. std::unordered_map<uint16, uint16> aegis_itemviewid;
  96. std::unordered_map<uint16, std::string> aegis_mobnames;
  97. std::unordered_map<uint16, std::string> aegis_skillnames;
  98. std::unordered_map<const char*, int64> constants;
  99. // Forward declaration of constant loading functions
  100. static bool parse_item_constants( const char* path );
  101. static bool parse_mob_constants( char* split[], int columns, int current );
  102. static bool parse_skill_constants_txt( char* split[], int columns, int current );
  103. static bool parse_skill_constants_yml(std::string path, std::string filename);
  104. bool fileExists( const std::string& path );
  105. bool askConfirmation( const char* fmt, ... );
  106. // Skill database data to memory
  107. static void skill_txt_data(const std::string& modePath, const std::string& fixedPath) {
  108. skill_require.clear();
  109. skill_cast.clear();
  110. skill_castnodex.clear();
  111. skill_unit.clear();
  112. skill_copyable.clear();
  113. skill_nearnpc.clear();
  114. if (fileExists(modePath + "/skill_require_db.txt"))
  115. sv_readdb(modePath.c_str(), "skill_require_db.txt", ',', 34, 34, -1, skill_parse_row_requiredb, false);
  116. if (fileExists(modePath + "/skill_cast_db.txt"))
  117. sv_readdb(modePath.c_str(), "skill_cast_db.txt", ',', 7, 8, -1, skill_parse_row_castdb, false);
  118. if (fileExists(modePath + "/skill_castnodex_db.txt"))
  119. sv_readdb(modePath.c_str(), "skill_castnodex_db.txt", ',', 2, 3, -1, skill_parse_row_castnodexdb, false);
  120. if (fileExists(modePath + "/skill_unit_db.txt"))
  121. sv_readdb(modePath.c_str(), "skill_unit_db.txt", ',', 8, 8, -1, skill_parse_row_unitdb, false);
  122. if (fileExists(fixedPath + "/skill_copyable_db.txt"))
  123. sv_readdb(fixedPath.c_str(), "skill_copyable_db.txt", ',', 2, 4, -1, skill_parse_row_copyabledb, false);
  124. if (fileExists(fixedPath + "/skill_nonearnpc_db.txt"))
  125. sv_readdb(fixedPath.c_str(), "skill_nonearnpc_db.txt", ',', 2, 3, -1, skill_parse_row_nonearnpcrangedb, false);
  126. }
  127. YAML::Emitter body;
  128. // Implement the function instead of including the original version by linking
  129. void script_set_constant_( const char* name, int64 value, const char* constant_name, bool isparameter, bool deprecated ){
  130. constants[name] = value;
  131. }
  132. const char* constant_lookup( int32 value, const char* prefix ){
  133. nullpo_retr( nullptr, prefix );
  134. for( auto const& pair : constants ){
  135. // Same prefix group and same value
  136. if( strncasecmp( pair.first, prefix, strlen( prefix ) ) == 0 && pair.second == value ){
  137. return pair.first;
  138. }
  139. }
  140. return nullptr;
  141. }
  142. int64 constant_lookup_int(const char* constant) {
  143. nullpo_retr(-100, constant);
  144. for (auto const &pair : constants) {
  145. if (strlen(pair.first) == strlen(constant) && strncasecmp(pair.first, constant, strlen(constant)) == 0) {
  146. return pair.second;
  147. }
  148. }
  149. return -100;
  150. }
  151. void copyFileIfExists( std::ofstream& file,const std::string& name, bool newLine ){
  152. std::string path = "doc/yaml/db/" + name + ".yml";
  153. if( fileExists( path ) ){
  154. std::ifstream source( path, std::ios::binary );
  155. std::istreambuf_iterator<char> begin_source( source );
  156. std::istreambuf_iterator<char> end_source;
  157. std::ostreambuf_iterator<char> begin_dest( file );
  158. copy( begin_source, end_source, begin_dest );
  159. source.close();
  160. if( newLine ){
  161. file << "\n";
  162. }
  163. }
  164. }
  165. void prepareHeader(std::ofstream &file, const std::string& type, uint32 version, const std::string& name) {
  166. copyFileIfExists( file, "license", false );
  167. copyFileIfExists( file, name, true );
  168. YAML::Emitter header(file);
  169. header << YAML::BeginMap;
  170. header << YAML::Key << "Header";
  171. header << YAML::BeginMap;
  172. header << YAML::Key << "Type" << YAML::Value << type;
  173. header << YAML::Key << "Version" << YAML::Value << version;
  174. header << YAML::EndMap;
  175. header << YAML::EndMap;
  176. file << "\n";
  177. file << "\n";
  178. }
  179. void prepareBody(void) {
  180. body << YAML::BeginMap;
  181. body << YAML::Key << "Body";
  182. body << YAML::BeginSeq;
  183. }
  184. void finalizeBody(void) {
  185. body << YAML::EndSeq;
  186. body << YAML::EndMap;
  187. }
  188. template<typename Func>
  189. bool process( const std::string& type, uint32 version, const std::vector<std::string>& paths, const std::string& name, Func lambda, const std::string& rename = "" ){
  190. for( const std::string& path : paths ){
  191. const std::string name_ext = name + ".txt";
  192. const std::string from = path + "/" + name_ext;
  193. const std::string to = path + "/" + (rename.size() > 0 ? rename : name) + ".yml";
  194. if( fileExists( from ) ){
  195. if( !askConfirmation( "Found the file \"%s\", which requires migration to yml.\nDo you want to convert it now? (Y/N)\n", from.c_str() ) ){
  196. continue;
  197. }
  198. if (fileExists(to)) {
  199. if (!askConfirmation("The file \"%s\" already exists.\nDo you want to replace it? (Y/N)\n", to.c_str())) {
  200. continue;
  201. }
  202. }
  203. std::ofstream out;
  204. body.~Emitter();
  205. new (&body) YAML::Emitter();
  206. out.open(to);
  207. if (!out.is_open()) {
  208. ShowError("Can not open file \"%s\" for writing.\n", to.c_str());
  209. return false;
  210. }
  211. prepareHeader(out, type, version, (rename.size() > 0 ? rename : name));
  212. prepareBody();
  213. if( !lambda( path, name_ext ) ){
  214. out.close();
  215. return false;
  216. }
  217. finalizeBody();
  218. out << body.c_str();
  219. // Make sure there is an empty line at the end of the file for git
  220. out << "\n";
  221. out.close();
  222. // TODO: do you want to delete?
  223. }
  224. }
  225. return true;
  226. }
  227. int do_init( int argc, char** argv ){
  228. const std::string path_db = std::string( db_path );
  229. const std::string path_db_mode = path_db + "/" + DBPATH;
  230. const std::string path_db_import = path_db + "/" + DBIMPORT;
  231. // Loads required conversion constants
  232. parse_item_constants( ( path_db_mode + "/item_db.txt" ).c_str() );
  233. parse_item_constants( ( path_db_import + "/item_db.txt" ).c_str() );
  234. sv_readdb( path_db_mode.c_str(), "mob_db.txt", ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &parse_mob_constants, false );
  235. sv_readdb( path_db_import.c_str(), "mob_db.txt", ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &parse_mob_constants, false );
  236. if (fileExists(path_db + "/" + "skill_db.yml")) {
  237. parse_skill_constants_yml(path_db_mode, "skill_db.yml");
  238. parse_skill_constants_yml(path_db_import + "/", "skill_db.yml");
  239. } else {
  240. sv_readdb(path_db_mode.c_str(), "skill_db.txt", ',', 18, 18, -1, parse_skill_constants_txt, false);
  241. sv_readdb(path_db_import.c_str(), "skill_db.txt", ',', 18, 18, -1, parse_skill_constants_txt, false);
  242. }
  243. // Load constants
  244. #define export_constant_npc(a) export_constant(a)
  245. #include "../map/script_constants.hpp"
  246. std::vector<std::string> root_paths = {
  247. path_db,
  248. path_db_mode,
  249. path_db_import
  250. };
  251. if( !process( "GUILD_SKILL_TREE_DB", 1, root_paths, "guild_skill_tree", []( const std::string& path, const std::string& name_ext ) -> bool {
  252. return sv_readdb( path.c_str(), name_ext.c_str(), ',', 2 + MAX_GUILD_SKILL_REQUIRE * 2, 2 + MAX_GUILD_SKILL_REQUIRE * 2, -1, &guild_read_guildskill_tree_db, false );
  253. } ) ){
  254. return 0;
  255. }
  256. if( !process( "PET_DB", 1, root_paths, "pet_db", []( const std::string& path, const std::string& name_ext ) -> bool {
  257. return pet_read_db( ( path + name_ext ).c_str() );
  258. } ) ){
  259. return 0;
  260. }
  261. if (!process("MAGIC_MUSHROOM_DB", 1, root_paths, "magicmushroom_db", [](const std::string &path, const std::string &name_ext) -> bool {
  262. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 1, 1, -1, &skill_parse_row_magicmushroomdb, false);
  263. })) {
  264. return 0;
  265. }
  266. if (!process("ABRA_DB", 1, root_paths, "abra_db", [](const std::string& path, const std::string& name_ext) -> bool {
  267. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 3, 3, -1, &skill_parse_row_abradb, false);
  268. })) {
  269. return 0;
  270. }
  271. if (!process("READING_SPELLBOOK_DB", 1, root_paths, "spellbook_db", [](const std::string& path, const std::string& name_ext) -> bool {
  272. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 3, 3, -1, &skill_parse_row_spellbookdb, false);
  273. })) {
  274. return 0;
  275. }
  276. if (!process("MOB_AVAIL_DB", 1, root_paths, "mob_avail", [](const std::string& path, const std::string& name_ext) -> bool {
  277. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 2, 12, -1, &mob_readdb_mobavail, false);
  278. })) {
  279. return 0;
  280. }
  281. skill_txt_data( path_db_mode, path_db );
  282. if (!process("SKILL_DB", 1, { path_db_mode }, "skill_db", [](const std::string& path, const std::string& name_ext) -> bool {
  283. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 18, 18, -1, &skill_parse_row_skilldb, false);
  284. })){
  285. return 0;
  286. }
  287. skill_txt_data( path_db_import, path_db_import );
  288. if (!process("SKILL_DB", 1, { path_db_import }, "skill_db", [](const std::string& path, const std::string& name_ext) -> bool {
  289. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 18, 18, -1, &skill_parse_row_skilldb, false);
  290. })){
  291. return 0;
  292. }
  293. if (!process("QUEST_DB", 1, root_paths, "quest_db", [](const std::string &path, const std::string &name_ext) -> bool {
  294. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 3 + MAX_QUEST_OBJECTIVES * 2 + MAX_QUEST_DROPS * 3, 100, -1, &quest_read_db, false);
  295. })) {
  296. return 0;
  297. }
  298. if (process("INSTANCE_DB", 1, root_paths, "instance_db", [](const std::string& path, const std::string& name_ext) -> bool {
  299. return sv_readdb(path.c_str(), name_ext.c_str(), ',', 7, 7 + MAX_MAP_PER_INSTANCE, -1, &instance_readdb_sub, false);
  300. })) {
  301. return 0;
  302. }
  303. // TODO: add implementations ;-)
  304. return 0;
  305. }
  306. void do_final(void){
  307. }
  308. bool fileExists( const std::string& path ){
  309. std::ifstream in;
  310. in.open( path );
  311. if( in.is_open() ){
  312. in.close();
  313. return true;
  314. }else{
  315. return false;
  316. }
  317. }
  318. bool askConfirmation( const char* fmt, ... ){
  319. va_list ap;
  320. va_start( ap, fmt );
  321. _vShowMessage( MSG_NONE, fmt, ap );
  322. va_end( ap );
  323. char c = getch();
  324. if( c == 'Y' || c == 'y' ){
  325. return true;
  326. }else{
  327. return false;
  328. }
  329. }
  330. // Constant loading functions
  331. static bool parse_item_constants( const char* path ){
  332. uint32 lines = 0, count = 0;
  333. char line[1024];
  334. FILE* fp;
  335. fp = fopen(path, "r");
  336. if (fp == NULL) {
  337. ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path);
  338. return false;
  339. }
  340. // process rows one by one
  341. while (fgets(line, sizeof(line), fp))
  342. {
  343. char *str[32], *p;
  344. int i;
  345. lines++;
  346. if (line[0] == '/' && line[1] == '/')
  347. continue;
  348. memset(str, 0, sizeof(str));
  349. p = strstr(line, "//");
  350. if (p != nullptr) {
  351. *p = '\0';
  352. }
  353. p = line;
  354. while (ISSPACE(*p))
  355. ++p;
  356. if (*p == '\0')
  357. continue;// empty line
  358. for (i = 0; i < 19; ++i)
  359. {
  360. str[i] = p;
  361. p = strchr(p, ',');
  362. if (p == NULL)
  363. break;// comma not found
  364. *p = '\0';
  365. ++p;
  366. }
  367. if (p == NULL)
  368. {
  369. ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  370. continue;
  371. }
  372. // Script
  373. if (*p != '{')
  374. {
  375. ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  376. continue;
  377. }
  378. str[19] = p + 1;
  379. p = strstr(p + 1, "},");
  380. if (p == NULL)
  381. {
  382. ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  383. continue;
  384. }
  385. *p = '\0';
  386. p += 2;
  387. // OnEquip_Script
  388. if (*p != '{')
  389. {
  390. ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  391. continue;
  392. }
  393. str[20] = p + 1;
  394. p = strstr(p + 1, "},");
  395. if (p == NULL)
  396. {
  397. ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  398. continue;
  399. }
  400. *p = '\0';
  401. p += 2;
  402. // OnUnequip_Script (last column)
  403. if (*p != '{')
  404. {
  405. ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  406. continue;
  407. }
  408. str[21] = p;
  409. p = &str[21][strlen(str[21]) - 2];
  410. if (*p != '}') {
  411. /* lets count to ensure it's not something silly e.g. a extra space at line ending */
  412. int lcurly = 0, rcurly = 0;
  413. for (size_t v = 0; v < strlen(str[21]); v++) {
  414. if (str[21][v] == '{')
  415. lcurly++;
  416. else if (str[21][v] == '}') {
  417. rcurly++;
  418. p = &str[21][v];
  419. }
  420. }
  421. if (lcurly != rcurly) {
  422. ShowError("itemdb_readdb: Mismatching curly braces in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
  423. continue;
  424. }
  425. }
  426. str[21] = str[21] + 1; //skip the first left curly
  427. *p = '\0'; //null the last right curly
  428. uint16 item_id = atoi( str[0] );
  429. char* name = trim( str[1] );
  430. aegis_itemnames[item_id] = std::string(name);
  431. if (atoi(str[14]) & (EQP_HELM | EQP_COSTUME_HELM) && util::umap_find(aegis_itemviewid, (uint16)atoi(str[18])) == nullptr)
  432. aegis_itemviewid[atoi(str[18])] = item_id;
  433. count++;
  434. }
  435. fclose(fp);
  436. ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, path);
  437. return true;
  438. }
  439. static bool parse_mob_constants( char* split[], int columns, int current ){
  440. uint16 mob_id = atoi( split[0] );
  441. char* name = trim( split[1] );
  442. aegis_mobnames[mob_id] = std::string( name );
  443. return true;
  444. }
  445. static bool parse_skill_constants_txt( char* split[], int columns, int current ){
  446. uint16 skill_id = atoi( split[0] );
  447. char* name = trim( split[16] );
  448. aegis_skillnames[skill_id] = std::string( name );
  449. return true;
  450. }
  451. static bool parse_skill_constants_yml(std::string path, std::string filename) {
  452. YAML::Node rootNode;
  453. try {
  454. rootNode = YAML::LoadFile(path + filename);
  455. } catch (YAML::Exception &e) {
  456. ShowError("Failed to read file from '" CL_WHITE "%s%s" CL_RESET "'.\n", path.c_str(), filename.c_str());
  457. ShowError("%s (Line %d: Column %d)\n", e.msg.c_str(), e.mark.line, e.mark.column);
  458. return false;
  459. }
  460. uint64 count = 0;
  461. for (const YAML::Node &body : rootNode["Body"]) {
  462. aegis_skillnames[body["Id"].as<uint16>()] = body["Name"].as<std::string>();
  463. count++;
  464. }
  465. ShowStatus("Done reading '" CL_WHITE "%" PRIu64 CL_RESET "' entries in '" CL_WHITE "%s%s" CL_RESET "'" CL_CLL "\n", count, path.c_str(), filename.c_str());
  466. return true;
  467. }
  468. /**
  469. * Split the string with ':' as separator and put each value for a skilllv
  470. * @param str: String to split
  471. * @param val: Array of MAX_SKILL_LEVEL to put value into
  472. * @return 0:error, x:number of value assign (should be MAX_SKILL_LEVEL)
  473. */
  474. int skill_split_atoi(char *str, int *val) {
  475. int i;
  476. for (i = 0; i < MAX_SKILL_LEVEL; i++) {
  477. if (!str)
  478. break;
  479. val[i] = atoi(str);
  480. str = strchr(str, ':');
  481. if (str)
  482. *str++ = 0;
  483. }
  484. if (i == 0) // No data found.
  485. return 0;
  486. if (i == 1) // Single value, have the whole range have the same value.
  487. return 1;
  488. return i;
  489. }
  490. /**
  491. * Split string to int by constant value (const.txt) or atoi()
  492. * @param *str: String input
  493. * @param *val: Temporary storage
  494. * @param *delim: Delimiter (for multiple value support)
  495. * @param min_value: Minimum value. If the splitted value is less or equal than this, will be skipped
  496. * @param max: Maximum number that can be allocated
  497. * @return count: Number of success
  498. */
  499. uint8 skill_split_atoi2(char *str, int64 *val, const char *delim, int min_value, uint16 max) {
  500. uint8 i = 0;
  501. char *p = strtok(str, delim);
  502. while (p != NULL) {
  503. int64 n = min_value;
  504. trim(p);
  505. if (ISDIGIT(p[0])) // If using numeric
  506. n = atoi(p);
  507. else {
  508. n = constant_lookup_int(p);
  509. p = strtok(NULL, delim);
  510. }
  511. if (n > min_value) {
  512. val[i] = n;
  513. i++;
  514. if (i >= max)
  515. break;
  516. }
  517. p = strtok(NULL, delim);
  518. }
  519. return i;
  520. }
  521. // Implementation of the conversion functions
  522. // Copied and adjusted from guild.cpp
  523. // <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>
  524. static bool guild_read_guildskill_tree_db( char* split[], int columns, int current ){
  525. uint16 skill_id = (uint16)atoi(split[0]);
  526. std::string* name = util::umap_find( aegis_skillnames, skill_id );
  527. if( name == nullptr ){
  528. ShowError( "Skill name for skill id %hu is not known.\n", skill_id );
  529. return false;
  530. }
  531. body << YAML::BeginMap;
  532. body << YAML::Key << "Id" << YAML::Value << *name;
  533. body << YAML::Key << "MaxLevel" << YAML::Value << atoi(split[1]);
  534. if (atoi(split[2]) > 0) {
  535. body << YAML::Key << "Required";
  536. body << YAML::BeginSeq;
  537. for (int i = 0, j = 0; i < MAX_GUILD_SKILL_REQUIRE; i++) {
  538. uint16 required_skill_id = atoi(split[i * 2 + 2]);
  539. uint16 required_skill_level = atoi(split[i * 2 + 3]);
  540. if (required_skill_id == 0 || required_skill_level == 0) {
  541. continue;
  542. }
  543. std::string* required_name = util::umap_find(aegis_skillnames, required_skill_id);
  544. if (required_name == nullptr) {
  545. ShowError("Skill name for required skill id %hu is not known.\n", required_skill_id);
  546. return false;
  547. }
  548. body << YAML::BeginMap;
  549. body << YAML::Key << "Id" << YAML::Value << *required_name;
  550. body << YAML::Key << "Level" << YAML::Value << required_skill_level;
  551. body << YAML::EndMap;
  552. }
  553. body << YAML::EndSeq;
  554. }
  555. body << YAML::EndMap;
  556. return true;
  557. }
  558. // Copied and adjusted from pet.cpp
  559. static bool pet_read_db( const char* file ){
  560. FILE* fp = fopen( file, "r" );
  561. if( fp == nullptr ){
  562. ShowError( "can't read %s\n", file );
  563. return false;
  564. }
  565. int lines = 0;
  566. size_t entries = 0;
  567. char line[1024];
  568. while( fgets( line, sizeof(line), fp ) ) {
  569. char *str[22], *p;
  570. unsigned k;
  571. lines++;
  572. if(line[0] == '/' && line[1] == '/')
  573. continue;
  574. memset(str, 0, sizeof(str));
  575. p = line;
  576. while( ISSPACE(*p) )
  577. ++p;
  578. if( *p == '\0' )
  579. continue; // empty line
  580. for( k = 0; k < 20; ++k ) {
  581. str[k] = p;
  582. p = strchr(p,',');
  583. if( p == NULL )
  584. break; // comma not found
  585. *p = '\0';
  586. ++p;
  587. }
  588. if( p == NULL ) {
  589. ShowError("read_petdb: Insufficient columns in line %d, skipping.\n", lines);
  590. continue;
  591. }
  592. // Pet Script
  593. if( *p != '{' ) {
  594. ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines);
  595. continue;
  596. }
  597. str[20] = p;
  598. p = strstr(p+1,"},");
  599. if( p == NULL ) {
  600. ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines);
  601. continue;
  602. }
  603. p[1] = '\0';
  604. p += 2;
  605. // Equip Script
  606. if( *p != '{' ) {
  607. ShowError("read_petdb: Invalid format (Equip Script column) in line %d, skipping.\n", lines);
  608. continue;
  609. }
  610. str[21] = p;
  611. uint16 mob_id = atoi( str[0] );
  612. std::string* mob_name = util::umap_find( aegis_mobnames, mob_id );
  613. if( mob_name == nullptr ){
  614. ShowWarning( "pet_db reading: Invalid mob-class %hu, pet not read.\n", mob_id );
  615. continue;
  616. }
  617. body << YAML::BeginMap;
  618. body << YAML::Key << "Mob" << YAML::Value << *mob_name;
  619. uint16 tame_item_id = (uint16)atoi( str[3] );
  620. if( tame_item_id > 0 ){
  621. std::string* tame_item_name = util::umap_find( aegis_itemnames, tame_item_id );
  622. if( tame_item_name == nullptr ){
  623. ShowError( "Item name for item id %hu is not known.\n", tame_item_id );
  624. return false;
  625. }
  626. body << YAML::Key << "TameItem" << YAML::Value << *tame_item_name;
  627. }
  628. uint16 egg_item_id = (uint16)atoi( str[4] );
  629. std::string* egg_item_name = util::umap_find( aegis_itemnames, egg_item_id );
  630. if( egg_item_name == nullptr ){
  631. ShowError( "Item name for item id %hu is not known.\n", egg_item_id );
  632. return false;
  633. }
  634. body << YAML::Key << "EggItem" << YAML::Value << *egg_item_name;
  635. uint16 equip_item_id = (uint16)atoi( str[5] );
  636. if( equip_item_id > 0 ){
  637. std::string* equip_item_name = util::umap_find( aegis_itemnames, equip_item_id );
  638. if( equip_item_name == nullptr ){
  639. ShowError( "Item name for item id %hu is not known.\n", equip_item_id );
  640. return false;
  641. }
  642. body << YAML::Key << "EquipItem" << YAML::Value << *equip_item_name;
  643. }
  644. uint16 food_item_id = (uint16)atoi( str[6] );
  645. if( food_item_id > 0 ){
  646. std::string* food_item_name = util::umap_find( aegis_itemnames, food_item_id );
  647. if( food_item_name == nullptr ){
  648. ShowError( "Item name for item id %hu is not known.\n", food_item_id );
  649. return false;
  650. }
  651. body << YAML::Key << "FoodItem" << YAML::Value << *food_item_name;
  652. }
  653. body << YAML::Key << "Fullness" << YAML::Value << atoi(str[7]);
  654. // Default: 60
  655. if( atoi( str[8] ) != 60 ){
  656. body << YAML::Key << "HungryDelay" << YAML::Value << atoi(str[8]);
  657. }
  658. // Default: 250
  659. if( atoi( str[11] ) != 250 ){
  660. body << YAML::Key << "IntimacyStart" << YAML::Value << atoi(str[11]);
  661. }
  662. body << YAML::Key << "IntimacyFed" << YAML::Value << atoi(str[9]);
  663. // Default: -100
  664. if( atoi( str[10] ) != 100 ){
  665. body << YAML::Key << "IntimacyOverfed" << YAML::Value << -atoi(str[10]);
  666. }
  667. // pet_hungry_friendly_decrease battle_conf
  668. //body << YAML::Key << "IntimacyHungry" << YAML::Value << -5;
  669. // Default: -20
  670. if( atoi( str[12] ) != 20 ){
  671. body << YAML::Key << "IntimacyOwnerDie" << YAML::Value << -atoi(str[12]);
  672. }
  673. body << YAML::Key << "CaptureRate" << YAML::Value << atoi(str[13]);
  674. // Default: true
  675. if( atoi( str[15] ) == 0 ){
  676. body << YAML::Key << "SpecialPerformance" << YAML::Value << "false";
  677. }
  678. body << YAML::Key << "AttackRate" << YAML::Value << atoi(str[17]);
  679. body << YAML::Key << "RetaliateRate" << YAML::Value << atoi(str[18]);
  680. body << YAML::Key << "ChangeTargetRate" << YAML::Value << atoi(str[19]);
  681. if( *str[21] ){
  682. body << YAML::Key << "Script" << YAML::Value << YAML::Literal << str[21];
  683. }
  684. if( *str[20] ){
  685. body << YAML::Key << "SupportScript" << YAML::Value << YAML::Literal << str[20];
  686. }
  687. body << YAML::EndMap;
  688. entries++;
  689. }
  690. fclose(fp);
  691. ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' pets in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file );
  692. return true;
  693. }
  694. // Copied and adjusted from skill.cpp
  695. static bool skill_parse_row_magicmushroomdb(char *split[], int column, int current)
  696. {
  697. uint16 skill_id = atoi(split[0]);
  698. std::string *skill_name = util::umap_find(aegis_skillnames, skill_id);
  699. if (skill_name == nullptr) {
  700. ShowError("Skill name for Magic Mushroom skill ID %hu is not known.\n", skill_id);
  701. return false;
  702. }
  703. body << YAML::BeginMap;
  704. body << YAML::Key << "Skill" << YAML::Value << *skill_name;
  705. body << YAML::EndMap;
  706. return true;
  707. }
  708. // Copied and adjusted from skill.cpp
  709. static bool skill_parse_row_abradb(char* split[], int columns, int current)
  710. {
  711. uint16 skill_id = atoi(split[0]);
  712. std::string *skill_name = util::umap_find(aegis_skillnames, skill_id);
  713. if (skill_name == nullptr) {
  714. ShowError("Skill name for Abra skill ID %hu is not known.\n", skill_id);
  715. return false;
  716. }
  717. body << YAML::BeginMap;
  718. body << YAML::Key << "Skill" << YAML::Value << *skill_name;
  719. int arr[MAX_SKILL_LEVEL];
  720. int arr_size = skill_split_atoi(split[2], arr);
  721. if (arr_size == 1) {
  722. if (arr[0] != 500)
  723. body << YAML::Key << "Probability" << YAML::Value << arr[0];
  724. } else {
  725. body << YAML::Key << "Probability";
  726. body << YAML::BeginSeq;
  727. for (int i = 0; i < arr_size; i++) {
  728. if (arr[i] > 0) {
  729. body << YAML::BeginMap;
  730. body << YAML::Key << "Level" << YAML::Value << i + 1;
  731. body << YAML::Key << "Probability" << YAML::Value << arr[i];
  732. body << YAML::EndMap;
  733. }
  734. }
  735. body << YAML::EndSeq;
  736. }
  737. body << YAML::EndMap;
  738. return true;
  739. }
  740. // Copied and adjusted from skill.cpp
  741. static bool skill_parse_row_spellbookdb(char* split[], int columns, int current)
  742. {
  743. uint16 skill_id = atoi(split[0]);
  744. std::string *skill_name = util::umap_find(aegis_skillnames, skill_id);
  745. if (skill_name == nullptr) {
  746. ShowError("Skill name for Spell Book skill ID %hu is not known.\n", skill_id);
  747. return false;
  748. }
  749. uint16 nameid = atoi(split[2]);
  750. std::string *book_name = util::umap_find(aegis_itemnames, nameid);
  751. if (book_name == nullptr) {
  752. ShowError("Book name for item ID %hu is not known.\n", nameid);
  753. return false;
  754. }
  755. body << YAML::BeginMap;
  756. body << YAML::Key << "Skill" << YAML::Value << *skill_name;
  757. body << YAML::Key << "Book" << YAML::Value << *book_name;
  758. body << YAML::Key << "PreservePoints" << YAML::Value << atoi(split[1]);
  759. body << YAML::EndMap;
  760. return true;
  761. }
  762. // Copied and adjusted from mob.cpp
  763. static bool mob_readdb_mobavail(char* str[], int columns, int current) {
  764. uint16 mob_id = atoi(str[0]);
  765. std::string *mob_name = util::umap_find(aegis_mobnames, mob_id);
  766. if (mob_name == nullptr) {
  767. ShowWarning("mob_avail reading: Invalid mob-class %hu, Mob not read.\n", mob_id);
  768. return false;
  769. }
  770. body << YAML::BeginMap;
  771. body << YAML::Key << "Mob" << YAML::Value << *mob_name;
  772. uint16 sprite_id = atoi(str[1]);
  773. std::string *sprite_name = util::umap_find(aegis_mobnames, sprite_id);
  774. if (sprite_name == nullptr) {
  775. char *sprite = const_cast<char *>(constant_lookup(sprite_id, "JOB_"));
  776. if (sprite == nullptr) {
  777. sprite = const_cast<char *>(constant_lookup(sprite_id, "JT_"));
  778. if (sprite == nullptr) {
  779. ShowError("Sprite name for id %d is not known.\n", sprite_id);
  780. return false;
  781. }
  782. sprite += 3; // Strip JT_ here because the script engine doesn't send this prefix for NPC.
  783. body << YAML::Key << "Sprite" << YAML::Value << sprite;
  784. } else
  785. body << YAML::Key << "Sprite" << YAML::Value << sprite;
  786. } else
  787. body << YAML::Key << "Sprite" << YAML::Value << *sprite_name;
  788. if (columns == 12) {
  789. body << YAML::Key << "Sex" << YAML::Value << (atoi(str[2]) ? "Male" : "Female");
  790. if (atoi(str[3]) != 0)
  791. body << YAML::Key << "HairStyle" << YAML::Value << atoi(str[3]);
  792. if (atoi(str[4]) != 0)
  793. body << YAML::Key << "HairColor" << YAML::Value << atoi(str[4]);
  794. if (atoi(str[11]) != 0)
  795. body << YAML::Key << "ClothColor" << YAML::Value << atoi(str[11]);
  796. if (atoi(str[5]) != 0) {
  797. uint16 weapon_item_id = atoi(str[5]);
  798. std::string *weapon_item_name = util::umap_find(aegis_itemnames, weapon_item_id);
  799. if (weapon_item_name == nullptr) {
  800. ShowError("Item name for item ID %hu (weapon) is not known.\n", weapon_item_id);
  801. return false;
  802. }
  803. body << YAML::Key << "Weapon" << YAML::Value << *weapon_item_name;
  804. }
  805. if (atoi(str[6]) != 0) {
  806. uint16 shield_item_id = atoi(str[6]);
  807. std::string *shield_item_name = util::umap_find(aegis_itemnames, shield_item_id);
  808. if (shield_item_name == nullptr) {
  809. ShowError("Item name for item ID %hu (shield) is not known.\n", shield_item_id);
  810. return false;
  811. }
  812. body << YAML::Key << "Shield" << YAML::Value << *shield_item_name;
  813. }
  814. if (atoi(str[7]) != 0) {
  815. uint16 *headtop_item_id = util::umap_find(aegis_itemviewid, (uint16)atoi(str[7]));
  816. if (headtop_item_id == nullptr) {
  817. ShowError("Item ID for view ID %hu (head top) is not known.\n", atoi(str[7]));
  818. return false;
  819. }
  820. std::string *headtop_item_name = util::umap_find(aegis_itemnames, *headtop_item_id);
  821. if (headtop_item_name == nullptr) {
  822. ShowError("Item name for item ID %hu (head top) is not known.\n", *headtop_item_id);
  823. return false;
  824. }
  825. body << YAML::Key << "HeadTop" << YAML::Value << *headtop_item_name;
  826. }
  827. if (atoi(str[8]) != 0) {
  828. uint16 *headmid_item_id = util::umap_find(aegis_itemviewid, (uint16)atoi(str[8]));
  829. if (headmid_item_id == nullptr) {
  830. ShowError("Item ID for view ID %hu (head mid) is not known.\n", atoi(str[8]));
  831. return false;
  832. }
  833. std::string *headmid_item_name = util::umap_find(aegis_itemnames, *headmid_item_id);
  834. if (headmid_item_name == nullptr) {
  835. ShowError("Item name for item ID %hu (head mid) is not known.\n", *headmid_item_id);
  836. return false;
  837. }
  838. body << YAML::Key << "HeadMid" << YAML::Value << *headmid_item_name;
  839. }
  840. if (atoi(str[9]) != 0) {
  841. uint16 *headlow_item_id = util::umap_find(aegis_itemviewid, (uint16)atoi(str[9]));
  842. if (headlow_item_id == nullptr) {
  843. ShowError("Item ID for view ID %hu (head low) is not known.\n", atoi(str[9]));
  844. return false;
  845. }
  846. std::string *headlow_item_name = util::umap_find(aegis_itemnames, *headlow_item_id);
  847. if (headlow_item_name == nullptr) {
  848. ShowError("Item name for item ID %hu (head low) is not known.\n", *headlow_item_id);
  849. return false;
  850. }
  851. body << YAML::Key << "HeadLow" << YAML::Value << *headlow_item_name;
  852. }
  853. if (atoi(str[10]) != 0) {
  854. uint32 options = atoi(str[10]);
  855. body << YAML::Key << "Options";
  856. body << YAML::BeginMap;
  857. while (options > OPTION_NOTHING && options <= OPTION_SUMMER2) {
  858. if (options & OPTION_SIGHT) {
  859. body << YAML::Key << "Sight" << YAML::Value << "true";
  860. options &= ~OPTION_SIGHT;
  861. } else if (options & OPTION_CART1) {
  862. body << YAML::Key << "Cart1" << YAML::Value << "true";
  863. options &= ~OPTION_CART1;
  864. } else if (options & OPTION_FALCON) {
  865. body << YAML::Key << "Falcon" << YAML::Value << "true";
  866. options &= ~OPTION_FALCON;
  867. } else if (options & OPTION_RIDING) {
  868. body << YAML::Key << "Riding" << YAML::Value << "true";
  869. options &= ~OPTION_RIDING;
  870. } else if (options & OPTION_CART2) {
  871. body << YAML::Key << "Cart2" << YAML::Value << "true";
  872. options &= ~OPTION_CART2;
  873. } else if (options & OPTION_CART3) {
  874. body << YAML::Key << "Cart2" << YAML::Value << "true";
  875. options &= ~OPTION_CART3;
  876. } else if (options & OPTION_CART4) {
  877. body << YAML::Key << "Cart4" << YAML::Value << "true";
  878. options &= ~OPTION_CART4;
  879. } else if (options & OPTION_CART5) {
  880. body << YAML::Key << "Cart5" << YAML::Value << "true";
  881. options &= ~OPTION_CART5;
  882. } else if (options & OPTION_ORCISH) {
  883. body << YAML::Key << "Orcish" << YAML::Value << "true";
  884. options &= ~OPTION_ORCISH;
  885. } else if (options & OPTION_WEDDING) {
  886. body << YAML::Key << "Wedding" << YAML::Value << "true";
  887. options &= ~OPTION_WEDDING;
  888. } else if (options & OPTION_RUWACH) {
  889. body << YAML::Key << "Ruwach" << YAML::Value << "true";
  890. options &= ~OPTION_RUWACH;
  891. } else if (options & OPTION_FLYING) {
  892. body << YAML::Key << "Flying" << YAML::Value << "true";
  893. options &= ~OPTION_FLYING;
  894. } else if (options & OPTION_XMAS) {
  895. body << YAML::Key << "Xmas" << YAML::Value << "true";
  896. options &= ~OPTION_XMAS;
  897. } else if (options & OPTION_TRANSFORM) {
  898. body << YAML::Key << "Transform" << YAML::Value << "true";
  899. options &= ~OPTION_TRANSFORM;
  900. } else if (options & OPTION_SUMMER) {
  901. body << YAML::Key << "Summer" << YAML::Value << "true";
  902. options &= ~OPTION_SUMMER;
  903. } else if (options & OPTION_DRAGON1) {
  904. body << YAML::Key << "Dragon1" << YAML::Value << "true";
  905. options &= ~OPTION_DRAGON1;
  906. } else if (options & OPTION_WUG) {
  907. body << YAML::Key << "Wug" << YAML::Value << "true";
  908. options &= ~OPTION_WUG;
  909. } else if (options & OPTION_WUGRIDER) {
  910. body << YAML::Key << "WugRider" << YAML::Value << "true";
  911. options &= ~OPTION_WUGRIDER;
  912. } else if (options & OPTION_MADOGEAR) {
  913. body << YAML::Key << "MadoGear" << YAML::Value << "true";
  914. options &= ~OPTION_MADOGEAR;
  915. } else if (options & OPTION_DRAGON2) {
  916. body << YAML::Key << "Dragon2" << YAML::Value << "true";
  917. options &= ~OPTION_DRAGON2;
  918. } else if (options & OPTION_DRAGON3) {
  919. body << YAML::Key << "Dragon3" << YAML::Value << "true";
  920. options &= ~OPTION_DRAGON3;
  921. } else if (options & OPTION_DRAGON4) {
  922. body << YAML::Key << "Dragon4" << YAML::Value << "true";
  923. options &= ~OPTION_DRAGON4;
  924. } else if (options & OPTION_DRAGON5) {
  925. body << YAML::Key << "Dragon5" << YAML::Value << "true";
  926. options &= ~OPTION_DRAGON5;
  927. } else if (options & OPTION_HANBOK) {
  928. body << YAML::Key << "Hanbok" << YAML::Value << "true";
  929. options &= ~OPTION_HANBOK;
  930. } else if (options & OPTION_OKTOBERFEST) {
  931. body << YAML::Key << "Oktoberfest" << YAML::Value << "true";
  932. options &= ~OPTION_OKTOBERFEST;
  933. } else if (options & OPTION_SUMMER2) {
  934. body << YAML::Key << "Summer2" << YAML::Value << "true";
  935. options &= ~OPTION_SUMMER2;
  936. }
  937. }
  938. body << YAML::EndMap;
  939. }
  940. } else if (columns == 3) {
  941. if (atoi(str[5]) != 0) {
  942. uint16 peteq_item_id = atoi(str[5]);
  943. std::string *peteq_item_name = util::umap_find(aegis_itemnames, peteq_item_id);
  944. if (peteq_item_name == nullptr) {
  945. ShowError("Item name for item ID %hu (pet equip) is not known.\n", peteq_item_id);
  946. return false;
  947. }
  948. body << YAML::Key << "PetEquip" << YAML::Value << *peteq_item_name;
  949. }
  950. }
  951. body << YAML::EndMap;
  952. return true;
  953. }
  954. // skill_db.yml function
  955. //----------------------
  956. static bool skill_parse_row_requiredb(char* split[], int columns, int current)
  957. {
  958. s_skill_require entry = {};
  959. skill_split_atoi(split[1], entry.hp);
  960. skill_split_atoi(split[2], entry.mhp);
  961. skill_split_atoi(split[3], entry.sp);
  962. skill_split_atoi(split[4], entry.hp_rate);
  963. skill_split_atoi(split[5], entry.sp_rate);
  964. skill_split_atoi(split[6], entry.zeny);
  965. char *p;
  966. p = split[7];
  967. while (p) {
  968. int l = atoi(p);
  969. if (l == 99) { // Any weapon
  970. entry.weapon = 0;
  971. break;
  972. } else
  973. entry.weapon |= 1 << l;
  974. p = strchr(p, ':');
  975. if (!p)
  976. break;
  977. p++;
  978. }
  979. p = split[8];
  980. while (p) {
  981. int l = atoi(p);
  982. if (l == 99) { // Any ammo type
  983. entry.ammo = AMMO_TYPE_ALL;
  984. break;
  985. } else if (l) // 0 stands for no requirement
  986. entry.ammo |= 1 << l;
  987. p = strchr(p, ':');
  988. if (!p)
  989. break;
  990. p++;
  991. }
  992. skill_split_atoi(split[9], entry.ammo_qty);
  993. if (strcmpi(split[10], "hidden") == 0) entry.state = ST_HIDDEN;
  994. else if (strcmpi(split[10], "riding") == 0) entry.state = ST_RIDING;
  995. else if (strcmpi(split[10], "falcon") == 0) entry.state = ST_FALCON;
  996. else if (strcmpi(split[10], "cart") == 0) entry.state = ST_CART;
  997. else if (strcmpi(split[10], "shield") == 0) entry.state = ST_SHIELD;
  998. else if (strcmpi(split[10], "recover_weight_rate") == 0) entry.state = ST_RECOVER_WEIGHT_RATE;
  999. else if (strcmpi(split[10], "move_enable") == 0) entry.state = ST_MOVE_ENABLE;
  1000. else if (strcmpi(split[10], "water") == 0) entry.state = ST_WATER;
  1001. else if (strcmpi(split[10], "dragon") == 0) entry.state = ST_RIDINGDRAGON;
  1002. else if (strcmpi(split[10], "warg") == 0) entry.state = ST_WUG;
  1003. else if (strcmpi(split[10], "ridingwarg") == 0) entry.state = ST_RIDINGWUG;
  1004. else if (strcmpi(split[10], "mado") == 0) entry.state = ST_MADO;
  1005. else if (strcmpi(split[10], "elementalspirit") == 0) entry.state = ST_ELEMENTALSPIRIT;
  1006. else if (strcmpi(split[10], "elementalspirit2") == 0) entry.state = ST_ELEMENTALSPIRIT2;
  1007. else if (strcmpi(split[10], "peco") == 0) entry.state = ST_PECO;
  1008. else if (strcmpi(split[10], "sunstance") == 0) entry.state = ST_SUNSTANCE;
  1009. else if (strcmpi(split[10], "moonstance") == 0) entry.state = ST_MOONSTANCE;
  1010. else if (strcmpi(split[10], "starstance") == 0) entry.state = ST_STARSTANCE;
  1011. else if (strcmpi(split[10], "universestance") == 0) entry.state = ST_UNIVERSESTANCE;
  1012. else entry.state = ST_NONE; // Unknown or no state
  1013. trim(split[11]);
  1014. if (split[11][0] != '\0' || atoi(split[11])) {
  1015. int64 require[MAX_SKILL_STATUS_REQUIRE];
  1016. int32 count;
  1017. if ((count = skill_split_atoi2(split[11], require, ":", SC_STONE, ARRAYLENGTH(require)))) {
  1018. for (int i = 0; i < count; i++) {
  1019. entry.status.push_back((sc_type)require[i]);
  1020. }
  1021. }
  1022. }
  1023. skill_split_atoi(split[12], entry.spiritball);
  1024. for (int i = 0; i < MAX_SKILL_ITEM_REQUIRE; i++) {
  1025. if (atoi(split[13 + 2 * i]) > 0) {
  1026. uint16 item_id = atoi(split[13 + 2 * i]);
  1027. std::string *item_name = util::umap_find(aegis_itemnames, item_id);
  1028. if (item_name == nullptr) {
  1029. ShowError("Item name for item id %hu is not known.\n", item_id);
  1030. return false;
  1031. }
  1032. entry.itemid[i] = item_id;
  1033. entry.amount[i] = atoi(split[14 + 2 * i]);
  1034. }
  1035. }
  1036. trim(split[33]);
  1037. if (split[33][0] != '\0' || atoi(split[33])) {
  1038. int64 require[MAX_SKILL_EQUIP_REQUIRE];
  1039. int32 count;
  1040. if ((count = skill_split_atoi2(split[33], require, ":", 500, ARRAYLENGTH(require)))) {
  1041. for (int i = 0; i < count; i++) {
  1042. if (require[i] > 0)
  1043. entry.eqItem.push_back(static_cast<int32>(require[i]));
  1044. }
  1045. }
  1046. }
  1047. skill_require.insert({ atoi(split[0]), entry });
  1048. return true;
  1049. }
  1050. // skill_db.yml function
  1051. //----------------------
  1052. static bool skill_parse_row_castdb(char* split[], int columns, int current)
  1053. {
  1054. s_skill_db entry = {};
  1055. skill_split_atoi(split[1], entry.cast);
  1056. skill_split_atoi(split[2], entry.delay);
  1057. skill_split_atoi(split[3], entry.walkdelay);
  1058. skill_split_atoi(split[4], entry.upkeep_time);
  1059. skill_split_atoi(split[5], entry.upkeep_time2);
  1060. skill_split_atoi(split[6], entry.cooldown);
  1061. #ifdef RENEWAL_CAST
  1062. skill_split_atoi(split[7], (int *)entry.fixed_cast);
  1063. #endif
  1064. skill_cast.insert({ atoi(split[0]), entry });
  1065. return true;
  1066. }
  1067. // skill_db.yml function
  1068. //----------------------
  1069. static bool skill_parse_row_castnodexdb(char* split[], int columns, int current)
  1070. {
  1071. s_skill_db entry = {};
  1072. entry.castnodex = atoi(split[1]);
  1073. if (split[2]) // optional column
  1074. entry.delaynodex = atoi(split[2]);
  1075. skill_castnodex.insert({ atoi(split[0]), entry });
  1076. return true;
  1077. }
  1078. // skill_db.yml function
  1079. //----------------------
  1080. static bool skill_parse_row_unitdb(char* split[], int columns, int current)
  1081. {
  1082. s_skill_unit_csv entry = {};
  1083. entry.unit_id = (uint16)strtol(split[1], NULL, 16);
  1084. entry.unit_id2 = (uint16)strtol(split[2], NULL, 16);
  1085. skill_split_atoi(split[3], entry.unit_layout_type);
  1086. skill_split_atoi(split[4], entry.unit_range);
  1087. entry.unit_interval = atoi(split[5]);
  1088. entry.target_str = trim(split[6]);
  1089. entry.unit_flag_csv = strtol(split[7], NULL, 16);
  1090. skill_unit.insert({ atoi(split[0]), entry });
  1091. return true;
  1092. }
  1093. // skill_db.yml function
  1094. //----------------------
  1095. static bool skill_parse_row_copyabledb(char* split[], int column, int current)
  1096. {
  1097. s_skill_copyable entry = {};
  1098. int skill_id = -1;
  1099. trim(split[0]);
  1100. if (ISDIGIT(split[0][0]))
  1101. skill_id = atoi(split[0]);
  1102. else {
  1103. for (const auto &it : aegis_skillnames) {
  1104. if (it.second == split[0])
  1105. skill_id = it.first;
  1106. }
  1107. if (skill_id == -1) {
  1108. ShowError("Skill %s is unknown.\n", split[0]);
  1109. return false;
  1110. }
  1111. }
  1112. entry.option = atoi(split[1]);
  1113. entry.req_opt = cap_value(atoi(split[3]), 0, (0x2000) - 1);
  1114. skill_copyable.insert({ skill_id, entry });
  1115. return true;
  1116. }
  1117. // skill_db.yml function
  1118. //----------------------
  1119. static bool skill_parse_row_nonearnpcrangedb(char* split[], int column, int current)
  1120. {
  1121. s_skill_db entry = {};
  1122. int skill_id = -1;
  1123. trim(split[0]);
  1124. if (ISDIGIT(split[0][0]))
  1125. skill_id = atoi(split[0]);
  1126. else {
  1127. for (const auto &it : aegis_skillnames) {
  1128. if (it.second == split[0])
  1129. skill_id = it.first;
  1130. }
  1131. if (skill_id == -1) {
  1132. ShowError("Skill %s is unknown.\n", split[0]);
  1133. return false;
  1134. }
  1135. }
  1136. entry.unit_nonearnpc_range = max(atoi(split[1]), 0);
  1137. entry.unit_nonearnpc_type = (atoi(split[2])) ? cap_value(atoi(split[2]), 1, 15) : 15;
  1138. skill_nearnpc.insert({ skill_id, entry });
  1139. return true;
  1140. }
  1141. static bool isMultiLevel(int arr[]) {
  1142. int count = 0;
  1143. for (int i = 0; i < MAX_SKILL_LEVEL; i++) {
  1144. if (arr[i] != 0)
  1145. count++;
  1146. }
  1147. return (count == 0 || count == 1 ? false : true);
  1148. }
  1149. std::string name2Upper(std::string name) {
  1150. std::transform(name.begin(), name.end(), name.begin(), ::tolower);
  1151. name[0] = toupper(name[0]);
  1152. for (size_t i = 0; i < name.size(); i++) {
  1153. if (name[i - 1] == '_' || (name[i - 2] == '1' && name[i - 1] == 'h') || (name[i - 2] == '2' && name[i - 1] == 'h'))
  1154. name[i] = toupper(name[i]);
  1155. }
  1156. return name;
  1157. }
  1158. // Copied and adjusted from skill.cpp
  1159. static bool skill_parse_row_skilldb(char* split[], int columns, int current) {
  1160. int arr[MAX_SKILL_LEVEL], arr_size, skill_id = atoi(split[0]);
  1161. body << YAML::BeginMap;
  1162. body << YAML::Key << "Id" << YAML::Value << skill_id;
  1163. body << YAML::Key << "Name" << YAML::Value << trim(split[16]);
  1164. body << YAML::Key << "Description" << YAML::Value << trim(split[17]);
  1165. body << YAML::Key << "MaxLevel" << YAML::Value << atoi(split[7]);
  1166. if (strcmpi(split[13], "weapon") == 0)
  1167. body << YAML::Key << "Type" << YAML::Value << "Weapon";
  1168. else if (strcmpi(split[13], "magic") == 0)
  1169. body << YAML::Key << "Type" << YAML::Value << "Magic";
  1170. else if (strcmpi(split[13], "misc") == 0)
  1171. body << YAML::Key << "Type" << YAML::Value << "Misc";
  1172. std::string constant;
  1173. if (atoi(split[3]) != 0) {
  1174. constant = constant_lookup(atoi(split[3]), "INF_");
  1175. constant.erase(0, 4);
  1176. constant.erase(constant.size() - 6);
  1177. body << YAML::Key << "TargetType" << YAML::Value << name2Upper(constant);
  1178. }
  1179. uint64 nk_val = strtol(split[5], NULL, 0);
  1180. if (nk_val) {
  1181. body << YAML::Key << "DamageFlags";
  1182. body << YAML::BeginMap;
  1183. if (nk_val & 0x1)
  1184. body << YAML::Key << "NoDamage" << YAML::Value << "true";
  1185. if (nk_val & 0x2)
  1186. body << YAML::Key << "Splash" << YAML::Value << "true";
  1187. if (nk_val & 0x4)
  1188. body << YAML::Key << "SplashSplit" << YAML::Value << "true";
  1189. if (nk_val & 0x8)
  1190. body << YAML::Key << "IgnoreAtkCard" << YAML::Value << "true";
  1191. if (nk_val & 0x10)
  1192. body << YAML::Key << "IgnoreElement" << YAML::Value << "true";
  1193. if (nk_val & 0x20)
  1194. body << YAML::Key << "IgnoreDefense" << YAML::Value << "true";
  1195. if (nk_val & 0x40)
  1196. body << YAML::Key << "IgnoreFlee" << YAML::Value << "true";
  1197. if (nk_val & 0x80)
  1198. body << YAML::Key << "IgnoreDefCard" << YAML::Value << "true";
  1199. if (nk_val & 0x100)
  1200. body << YAML::Key << "Critical" << YAML::Value << "true";
  1201. body << YAML::EndMap;
  1202. }
  1203. uint64 inf2_val = strtol(split[11], nullptr, 0);
  1204. uint64 inf3_val = strtol(split[15], nullptr, 0);
  1205. if (inf2_val || inf3_val) {
  1206. body << YAML::Key << "Flags";
  1207. body << YAML::BeginMap;
  1208. if (inf2_val & 0x1)
  1209. body << YAML::Key << "IsQuest" << YAML::Value << "true";
  1210. if (inf2_val & 0x2)
  1211. body << YAML::Key << "IsNpc" << YAML::Value << "true";
  1212. if (inf2_val & 0x4)
  1213. body << YAML::Key << "IsWedding" << YAML::Value << "true";
  1214. if (inf2_val & 0x8)
  1215. body << YAML::Key << "IsSpirit" << YAML::Value << "true";
  1216. if (inf2_val & 0x10)
  1217. body << YAML::Key << "IsGuild" << YAML::Value << "true";
  1218. if (inf2_val & 0x20)
  1219. body << YAML::Key << "IsSong" << YAML::Value << "true";
  1220. if (inf2_val & 0x40)
  1221. body << YAML::Key << "IsEnsemble" << YAML::Value << "true";
  1222. if (inf2_val & 0x80)
  1223. body << YAML::Key << "IsTrap" << YAML::Value << "true";
  1224. if (inf2_val & 0x100)
  1225. body << YAML::Key << "TargetSelf" << YAML::Value << "true";
  1226. if (inf2_val & 0x200)
  1227. body << YAML::Key << "NoTargetSelf" << YAML::Value << "true";
  1228. if (inf2_val & 0x400)
  1229. body << YAML::Key << "PartyOnly" << YAML::Value << "true";
  1230. if (inf2_val & 0x800)
  1231. body << YAML::Key << "GuildOnly" << YAML::Value << "true";
  1232. if (inf2_val & 0x1000)
  1233. body << YAML::Key << "NoTargetEnemy" << YAML::Value << "true";
  1234. if (inf2_val & 0x2000)
  1235. body << YAML::Key << "IsAutoShadowSpell" << YAML::Value << "true";
  1236. if (inf2_val & 0x4000)
  1237. body << YAML::Key << "IsChorus" << YAML::Value << "true";
  1238. if (inf2_val & 0x8000)
  1239. body << YAML::Key << "IgnoreBgReduction" << YAML::Value << "true";
  1240. if (inf2_val & 0x10000)
  1241. body << YAML::Key << "IgnoreGvgReduction" << YAML::Value << "true";
  1242. if (inf2_val & 0x20000)
  1243. body << YAML::Key << "DisableNearNpc" << YAML::Value << "true";
  1244. if (inf2_val & 0x40000)
  1245. body << YAML::Key << "TargetTrap" << YAML::Value << "true"; // ?
  1246. if (inf3_val & 0x1)
  1247. body << YAML::Key << "IgnoreLandProtector" << YAML::Value << "true";
  1248. if (inf3_val & 0x4)
  1249. body << YAML::Key << "AllowWhenHidden" << YAML::Value << "true";
  1250. if (inf3_val & 0x8)
  1251. body << YAML::Key << "AllowWhenPerforming" << YAML::Value << "true";
  1252. if (inf3_val & 0x10)
  1253. body << YAML::Key << "TargetEmperium" << YAML::Value << "true";
  1254. if (inf3_val & 0x20)
  1255. body << YAML::Key << "IgnoreStasis" << YAML::Value << "true";
  1256. if (inf3_val & 0x40)
  1257. body << YAML::Key << "IgnoreKagehumi" << YAML::Value << "true";
  1258. if (inf3_val & 0x80)
  1259. body << YAML::Key << "AlterRangeVulture" << YAML::Value << "true";
  1260. if (inf3_val & 0x100)
  1261. body << YAML::Key << "AlterRangeSnakeEye" << YAML::Value << "true";
  1262. if (inf3_val & 0x200)
  1263. body << YAML::Key << "AlterRangeShadowJump" << YAML::Value << "true";
  1264. if (inf3_val & 0x400)
  1265. body << YAML::Key << "AlterRangeRadius" << YAML::Value << "true";
  1266. if (inf3_val & 0x800)
  1267. body << YAML::Key << "AlterRangeResearchTrap" << YAML::Value << "true";
  1268. if (inf3_val & 0x1000)
  1269. body << YAML::Key << "IgnoreHovering" << YAML::Value << "true";
  1270. if (inf3_val & 0x2000)
  1271. body << YAML::Key << "AllowOnWarg" << YAML::Value << "true";
  1272. if (inf3_val & 0x4000)
  1273. body << YAML::Key << "AllowOnMado" << YAML::Value << "true";
  1274. if (inf3_val & 0x8000)
  1275. body << YAML::Key << "TargetManHole" << YAML::Value << "true";
  1276. if (inf3_val & 0x10000)
  1277. body << YAML::Key << "TargetHidden" << YAML::Value << "true";
  1278. if (inf3_val & 0x40000)
  1279. body << YAML::Key << "IncreaseDanceWithWugDamage" << YAML::Value << "true";
  1280. if (inf3_val & 0x80000)
  1281. body << YAML::Key << "IgnoreWugBite" << YAML::Value << "true";
  1282. if (inf3_val & 0x100000)
  1283. body << YAML::Key << "IgnoreAutoGuard" << YAML::Value << "true";
  1284. if (inf3_val & 0x200000)
  1285. body << YAML::Key << "IgnoreCicada" << YAML::Value << "true";
  1286. body << YAML::EndMap;
  1287. }
  1288. memset(arr, 0, sizeof(arr));
  1289. arr_size = skill_split_atoi(split[1], arr);
  1290. if (arr_size != 0) {
  1291. if (arr_size == 1) {
  1292. if (arr[0] != 0) {
  1293. body << YAML::Key << "Range";
  1294. body << YAML::Value << arr[0];
  1295. }
  1296. } else {
  1297. body << YAML::Key << "Range";
  1298. body << YAML::BeginSeq;
  1299. for (int i = 0; i < arr_size; i++) {
  1300. body << YAML::BeginMap;
  1301. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1302. body << YAML::Key << "Size" << YAML::Value << arr[i];
  1303. body << YAML::EndMap;
  1304. }
  1305. body << YAML::EndSeq;
  1306. }
  1307. }
  1308. if (atoi(split[2]) != 0) {
  1309. constant = constant_lookup(atoi(split[2]), "DMG_");
  1310. constant.erase(0, 4);
  1311. body << YAML::Key << "Hit" << YAML::Value << name2Upper(constant);
  1312. }
  1313. memset(arr, 0, sizeof(arr));
  1314. arr_size = skill_split_atoi(split[8], arr);
  1315. if (arr_size != 0) {
  1316. if (arr_size == 1) {
  1317. if (arr[0] != 0) {
  1318. body << YAML::Key << "HitCount";
  1319. body << YAML::Value << arr[0];
  1320. }
  1321. } else {
  1322. body << YAML::Key << "HitCount";
  1323. body << YAML::BeginSeq;
  1324. for (int i = 0; i < arr_size; i++) {
  1325. body << YAML::BeginMap;
  1326. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1327. body << YAML::Key << "Count" << YAML::Value << arr[i];
  1328. body << YAML::EndMap;
  1329. }
  1330. body << YAML::EndSeq;
  1331. }
  1332. }
  1333. memset(arr, 0, sizeof(arr));
  1334. arr_size = skill_split_atoi(split[4], arr);
  1335. if (arr_size != 0) {
  1336. if (arr_size == 1) {
  1337. if (arr[0] != 0){
  1338. body << YAML::Key << "Element";
  1339. if (arr[0] == -1)
  1340. body << YAML::Value << "Weapon";
  1341. else if (arr[0] == -2)
  1342. body << YAML::Value << "Endowed";
  1343. else if (arr[0] == -3)
  1344. body << YAML::Value << "Random";
  1345. else {
  1346. constant = constant_lookup(arr[0], "ELE_");
  1347. constant.erase(0, 4);
  1348. body << YAML::Value << name2Upper(constant);
  1349. }
  1350. }
  1351. } else {
  1352. body << YAML::Key << "Element";
  1353. body << YAML::BeginSeq;
  1354. for (int i = 0; i < arr_size; i++) {
  1355. body << YAML::BeginMap;
  1356. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1357. if (arr[i] == -1)
  1358. body << YAML::Key << "Element" << YAML::Value << "Weapon";
  1359. else if (arr[i] == -2)
  1360. body << YAML::Key << "Element" << YAML::Value << "Endowed";
  1361. else if (arr[i] == -3)
  1362. body << YAML::Key << "Element" << YAML::Value << "Random";
  1363. else {
  1364. constant = constant_lookup(arr[i], "ELE_");
  1365. constant.erase(0, 4);
  1366. body << YAML::Key << "Element" << YAML::Value << name2Upper(constant);
  1367. }
  1368. body << YAML::EndMap;
  1369. }
  1370. body << YAML::EndSeq;
  1371. }
  1372. }
  1373. memset(arr, 0, sizeof(arr));
  1374. arr_size = skill_split_atoi(split[6], arr);
  1375. if (arr_size != 0) {
  1376. if (arr_size == 1) {
  1377. if (arr[0] != 0) {
  1378. body << YAML::Key << "SplashArea";
  1379. body << YAML::Value << arr[0];
  1380. }
  1381. } else {
  1382. body << YAML::Key << "SplashArea";
  1383. body << YAML::BeginSeq;
  1384. for (int i = 0; i < arr_size; i++) {
  1385. body << YAML::BeginMap;
  1386. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1387. body << YAML::Key << "Area" << YAML::Value << arr[i];
  1388. body << YAML::EndMap;
  1389. }
  1390. body << YAML::EndSeq;
  1391. }
  1392. }
  1393. memset(arr, 0, sizeof(arr));
  1394. arr_size = skill_split_atoi(split[12], arr);
  1395. if (arr_size != 0) {
  1396. if (arr_size == 1) {
  1397. if (arr[0] != 0) {
  1398. body << YAML::Key << "ActiveInstance";
  1399. body << YAML::Value << arr[0];
  1400. }
  1401. } else {
  1402. body << YAML::Key << "ActiveInstance";
  1403. body << YAML::BeginSeq;
  1404. for (int i = 0; i < arr_size; i++) {
  1405. body << YAML::BeginMap;
  1406. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1407. body << YAML::Key << "Max" << YAML::Value << arr[i];
  1408. body << YAML::EndMap;
  1409. }
  1410. body << YAML::EndSeq;
  1411. }
  1412. }
  1413. memset(arr, 0, sizeof(arr));
  1414. arr_size = skill_split_atoi(split[14], arr);
  1415. if (arr_size != 0) {
  1416. if (arr_size == 1) {
  1417. if (arr[0] != 0) {
  1418. body << YAML::Key << "Knockback";
  1419. body << YAML::Value << arr[0];
  1420. }
  1421. } else {
  1422. body << YAML::Key << "Knockback";
  1423. body << YAML::BeginSeq;
  1424. for (int i = 0; i < arr_size; i++) {
  1425. body << YAML::BeginMap;
  1426. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1427. body << YAML::Key << "Amount" << YAML::Value << arr[i];
  1428. body << YAML::EndMap;
  1429. }
  1430. body << YAML::EndSeq;
  1431. }
  1432. }
  1433. auto it_copyable = skill_copyable.find(skill_id);
  1434. if (it_copyable != skill_copyable.end()) {
  1435. body << YAML::Key << "CopyFlags";
  1436. body << YAML::BeginMap;
  1437. body << YAML::Key << "Skill";
  1438. body << YAML::BeginMap;
  1439. if (it_copyable->second.option & 1)
  1440. body << YAML::Key << "Plagiarism" << YAML::Value << "true";
  1441. if (it_copyable->second.option & 2)
  1442. body << YAML::Key << "Reproduce" << YAML::Value << "true";
  1443. body << YAML::EndMap;
  1444. if (it_copyable->second.req_opt > 0) {
  1445. body << YAML::Key << "RemoveRequirement";
  1446. body << YAML::BeginMap;
  1447. if (it_copyable->second.req_opt & 0x1)
  1448. body << YAML::Key << "HpCost" << YAML::Value << "true";
  1449. if (it_copyable->second.req_opt & 0x4)
  1450. body << YAML::Key << "SpCost" << YAML::Value << "true";
  1451. if (it_copyable->second.req_opt & 0x8)
  1452. body << YAML::Key << "HpRateCost" << YAML::Value << "true";
  1453. if (it_copyable->second.req_opt & 0x10)
  1454. body << YAML::Key << "SpRateCost" << YAML::Value << "true";
  1455. if (it_copyable->second.req_opt & 0x2)
  1456. body << YAML::Key << "MaxHpTrigger" << YAML::Value << "true";
  1457. if (it_copyable->second.req_opt & 0x20)
  1458. body << YAML::Key << "ZenyCost" << YAML::Value << "true";
  1459. if (it_copyable->second.req_opt & 0x40)
  1460. body << YAML::Key << "Weapon" << YAML::Value << "true";
  1461. if (it_copyable->second.req_opt & 0x80)
  1462. body << YAML::Key << "Ammo" << YAML::Value << "true";
  1463. if (it_copyable->second.req_opt & 0x100)
  1464. body << YAML::Key << "State" << YAML::Value << "true";
  1465. if (it_copyable->second.req_opt & 0x200)
  1466. body << YAML::Key << "Status" << YAML::Value << "true";
  1467. if (it_copyable->second.req_opt & 0x400)
  1468. body << YAML::Key << "SpiritSphereCost" << YAML::Value << "true";
  1469. if (it_copyable->second.req_opt & 0x800)
  1470. body << YAML::Key << "ItemCost" << YAML::Value << "true";
  1471. if (it_copyable->second.req_opt & 0x1000)
  1472. body << YAML::Key << "Equipment" << YAML::Value << "true";
  1473. body << YAML::EndMap;
  1474. }
  1475. body << YAML::EndMap;
  1476. }
  1477. auto it_nearnpc = skill_nearnpc.find(skill_id);
  1478. if (it_nearnpc != skill_nearnpc.end()) {
  1479. body << YAML::Key << "NoNearNPC";
  1480. body << YAML::BeginMap;
  1481. if (it_nearnpc->second.unit_nonearnpc_range > 0)
  1482. body << YAML::Key << "AdditionalRange" << YAML::Value << it_nearnpc->second.unit_nonearnpc_range;
  1483. if (it_nearnpc->second.unit_nonearnpc_type > 0) {
  1484. body << YAML::Key << "Type";
  1485. body << YAML::BeginMap;
  1486. if (it_nearnpc->second.unit_nonearnpc_type & 1)
  1487. body << YAML::Key << "WarpPortal" << YAML::Value << "true";
  1488. if (it_nearnpc->second.unit_nonearnpc_type & 2)
  1489. body << YAML::Key << "Shop" << YAML::Value << "true";
  1490. if (it_nearnpc->second.unit_nonearnpc_type & 4)
  1491. body << YAML::Key << "Npc" << YAML::Value << "true";
  1492. if (it_nearnpc->second.unit_nonearnpc_type & 8)
  1493. body << YAML::Key << "Tomb" << YAML::Value << "true";
  1494. body << YAML::EndMap;
  1495. }
  1496. body << YAML::EndMap;
  1497. }
  1498. if (strcmpi(split[9], "yes") == 0)
  1499. body << YAML::Key << "CastCancel" << YAML::Value << "true";
  1500. if (atoi(split[10]) != 0)
  1501. body << YAML::Key << "CastDefenseReduction" << YAML::Value << atoi(split[10]);
  1502. auto it_cast = skill_cast.find(skill_id);
  1503. if (it_cast != skill_cast.end()) {
  1504. if (!isMultiLevel(it_cast->second.cast)) {
  1505. if (it_cast->second.cast[0] > 0)
  1506. body << YAML::Key << "CastTime" << YAML::Value << it_cast->second.cast[0];
  1507. } else {
  1508. body << YAML::Key << "CastTime";
  1509. body << YAML::BeginSeq;
  1510. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.cast); i++) {
  1511. if (it_cast->second.cast[i] > 0) {
  1512. body << YAML::BeginMap;
  1513. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1514. body << YAML::Key << "Time" << YAML::Value << it_cast->second.cast[i];
  1515. body << YAML::EndMap;
  1516. }
  1517. }
  1518. body << YAML::EndSeq;
  1519. }
  1520. if (!isMultiLevel(it_cast->second.delay)) {
  1521. if (it_cast->second.delay[0] > 0)
  1522. body << YAML::Key << "AfterCastActDelay" << YAML::Value << it_cast->second.delay[0];
  1523. } else {
  1524. body << YAML::Key << "AfterCastActDelay";
  1525. body << YAML::BeginSeq;
  1526. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.delay); i++) {
  1527. if (it_cast->second.delay[i] > 0) {
  1528. body << YAML::BeginMap;
  1529. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1530. body << YAML::Key << "Time" << YAML::Value << it_cast->second.delay[i];
  1531. body << YAML::EndMap;
  1532. }
  1533. }
  1534. body << YAML::EndSeq;
  1535. }
  1536. if (!isMultiLevel(it_cast->second.walkdelay)) {
  1537. if (it_cast->second.walkdelay[0] > 0)
  1538. body << YAML::Key << "AfterCastWalkDelay" << YAML::Value << it_cast->second.walkdelay[0];
  1539. } else {
  1540. body << YAML::Key << "AfterCastWalkDelay";
  1541. body << YAML::BeginSeq;
  1542. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.walkdelay); i++) {
  1543. if (it_cast->second.walkdelay[i] > 0) {
  1544. body << YAML::BeginMap;
  1545. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1546. body << YAML::Key << "Time" << YAML::Value << it_cast->second.walkdelay[i];
  1547. body << YAML::EndMap;
  1548. }
  1549. }
  1550. body << YAML::EndSeq;
  1551. }
  1552. if (!isMultiLevel(it_cast->second.upkeep_time)) {
  1553. if (it_cast->second.upkeep_time[0] != 0)
  1554. body << YAML::Key << "Duration1" << YAML::Value << it_cast->second.upkeep_time[0];
  1555. } else {
  1556. body << YAML::Key << "Duration1";
  1557. body << YAML::BeginSeq;
  1558. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.upkeep_time); i++) {
  1559. if (it_cast->second.upkeep_time[i] != 0) {
  1560. body << YAML::BeginMap;
  1561. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1562. body << YAML::Key << "Time" << YAML::Value << it_cast->second.upkeep_time[i];
  1563. body << YAML::EndMap;
  1564. }
  1565. }
  1566. body << YAML::EndSeq;
  1567. }
  1568. if (!isMultiLevel(it_cast->second.upkeep_time2)) {
  1569. if (it_cast->second.upkeep_time2[0] != 0)
  1570. body << YAML::Key << "Duration2" << YAML::Value << it_cast->second.upkeep_time2[0];
  1571. } else {
  1572. body << YAML::Key << "Duration2";
  1573. body << YAML::BeginSeq;
  1574. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.upkeep_time2); i++) {
  1575. if (it_cast->second.upkeep_time2[i] != 0) {
  1576. body << YAML::BeginMap;
  1577. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1578. body << YAML::Key << "Time" << YAML::Value << it_cast->second.upkeep_time2[i];
  1579. body << YAML::EndMap;
  1580. }
  1581. }
  1582. body << YAML::EndSeq;
  1583. }
  1584. if (!isMultiLevel(it_cast->second.cooldown)) {
  1585. if (it_cast->second.cooldown[0] > 0)
  1586. body << YAML::Key << "Cooldown" << YAML::Value << it_cast->second.cooldown[0];
  1587. } else {
  1588. body << YAML::Key << "Cooldown";
  1589. body << YAML::BeginSeq;
  1590. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.cooldown); i++) {
  1591. if (it_cast->second.cooldown[i] > 0) {
  1592. body << YAML::BeginMap;
  1593. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1594. body << YAML::Key << "Time" << YAML::Value << it_cast->second.cooldown[i];
  1595. body << YAML::EndMap;
  1596. }
  1597. }
  1598. body << YAML::EndSeq;
  1599. }
  1600. #ifdef RENEWAL_CAST
  1601. if (!isMultiLevel(it_cast->second.fixed_cast)) {
  1602. if (it_cast->second.fixed_cast[0] != 0)
  1603. body << YAML::Key << "FixedCastTime" << YAML::Value << it_cast->second.fixed_cast[0];
  1604. } else {
  1605. body << YAML::Key << "FixedCastTime";
  1606. body << YAML::BeginSeq;
  1607. for (size_t i = 0; i < ARRAYLENGTH(it_cast->second.fixed_cast); i++) {
  1608. if (it_cast->second.fixed_cast[i] != 0) {
  1609. body << YAML::BeginMap;
  1610. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1611. body << YAML::Key << "Time" << YAML::Value << it_cast->second.fixed_cast[i];
  1612. body << YAML::EndMap;
  1613. }
  1614. }
  1615. body << YAML::EndSeq;
  1616. }
  1617. #endif
  1618. }
  1619. auto it_castdex = skill_castnodex.find(skill_id);
  1620. if (it_castdex != skill_castnodex.end()) {
  1621. if (it_castdex->second.castnodex > 0) {
  1622. body << YAML::Key << "CastTimeFlags";
  1623. body << YAML::BeginMap;
  1624. if (it_castdex->second.castnodex & 1)
  1625. body << YAML::Key << "IgnoreDex" << YAML::Value << "true";
  1626. if (it_castdex->second.castnodex & 2)
  1627. body << YAML::Key << "IgnoreStatus" << YAML::Value << "true";
  1628. if (it_castdex->second.castnodex & 4)
  1629. body << YAML::Key << "IgnoreItemBonus" << YAML::Value << "true";
  1630. body << YAML::EndMap;
  1631. }
  1632. if (it_castdex->second.delaynodex > 0) {
  1633. body << YAML::Key << "CastDelayFlags";
  1634. body << YAML::BeginMap;
  1635. if (it_castdex->second.delaynodex & 1)
  1636. body << YAML::Key << "IgnoreDex" << YAML::Value << "true";
  1637. if (it_castdex->second.delaynodex & 2)
  1638. body << YAML::Key << "IgnoreStatus" << YAML::Value << "true";
  1639. if (it_castdex->second.delaynodex & 4)
  1640. body << YAML::Key << "IgnoreItemBonus" << YAML::Value << "true";
  1641. body << YAML::EndMap;
  1642. }
  1643. }
  1644. auto it_req = skill_require.find(skill_id);
  1645. if (it_req != skill_require.end()) {
  1646. body << YAML::Key << "Requires";
  1647. body << YAML::BeginMap;
  1648. if (!isMultiLevel(it_req->second.hp)) {
  1649. if (it_req->second.hp[0] > 0)
  1650. body << YAML::Key << "HpCost" << YAML::Value << it_req->second.hp[0];
  1651. } else {
  1652. body << YAML::Key << "HpCost";
  1653. body << YAML::BeginSeq;
  1654. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.hp); i++) {
  1655. if (it_req->second.hp[i] > 0) {
  1656. body << YAML::BeginMap;
  1657. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1658. body << YAML::Key << "Amount" << YAML::Value << it_req->second.hp[i];
  1659. body << YAML::EndMap;
  1660. }
  1661. }
  1662. body << YAML::EndSeq;
  1663. }
  1664. if (!isMultiLevel(it_req->second.sp)) {
  1665. if (it_req->second.sp[0] > 0)
  1666. body << YAML::Key << "SpCost" << YAML::Value << it_req->second.sp[0];
  1667. } else {
  1668. body << YAML::Key << "SpCost";
  1669. body << YAML::BeginSeq;
  1670. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.sp); i++) {
  1671. if (it_req->second.sp[i] > 0) {
  1672. body << YAML::BeginMap;
  1673. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1674. body << YAML::Key << "Amount" << YAML::Value << it_req->second.sp[i];
  1675. body << YAML::EndMap;
  1676. }
  1677. }
  1678. body << YAML::EndSeq;
  1679. }
  1680. if (!isMultiLevel(it_req->second.hp_rate)) {
  1681. if (it_req->second.hp_rate[0] != 0)
  1682. body << YAML::Key << "HpRateCost" << YAML::Value << it_req->second.hp_rate[0];
  1683. } else {
  1684. body << YAML::Key << "HpRateCost";
  1685. body << YAML::BeginSeq;
  1686. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.hp_rate); i++) {
  1687. if (it_req->second.hp_rate[i] != 0) {
  1688. body << YAML::BeginMap;
  1689. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1690. body << YAML::Key << "Amount" << YAML::Value << it_req->second.hp_rate[i];
  1691. body << YAML::EndMap;
  1692. }
  1693. }
  1694. body << YAML::EndSeq;
  1695. }
  1696. if (!isMultiLevel(it_req->second.sp_rate)) {
  1697. if (it_req->second.sp_rate[0] != 0)
  1698. body << YAML::Key << "SpRateCost" << YAML::Value << it_req->second.sp_rate[0];
  1699. } else {
  1700. body << YAML::Key << "SpRateCost";
  1701. body << YAML::BeginSeq;
  1702. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.sp_rate); i++) {
  1703. if (it_req->second.sp_rate[i] != 0) {
  1704. body << YAML::BeginMap;
  1705. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1706. body << YAML::Key << "Amount" << YAML::Value << it_req->second.sp_rate[i];
  1707. body << YAML::EndMap;
  1708. }
  1709. }
  1710. body << YAML::EndSeq;
  1711. }
  1712. if (!isMultiLevel(it_req->second.mhp)) {
  1713. if (it_req->second.mhp[0] > 0)
  1714. body << YAML::Key << "MaxHpTrigger" << YAML::Value << it_req->second.mhp[0];
  1715. } else {
  1716. body << YAML::Key << "MaxHpTrigger";
  1717. body << YAML::BeginSeq;
  1718. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.mhp); i++) {
  1719. if (it_req->second.mhp[i] > 0) {
  1720. body << YAML::BeginMap;
  1721. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1722. body << YAML::Key << "Amount" << YAML::Value << it_req->second.mhp[i];
  1723. body << YAML::EndMap;
  1724. }
  1725. }
  1726. body << YAML::EndSeq;
  1727. }
  1728. if (!isMultiLevel(it_req->second.zeny)) {
  1729. if (it_req->second.zeny[0] > 0)
  1730. body << YAML::Key << "ZenyCost" << YAML::Value << it_req->second.zeny[0];
  1731. } else {
  1732. body << YAML::Key << "ZenyCost";
  1733. body << YAML::BeginSeq;
  1734. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.zeny); i++) {
  1735. if (it_req->second.zeny[i] > 0) {
  1736. body << YAML::BeginMap;
  1737. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1738. body << YAML::Key << "Amount" << YAML::Value << it_req->second.zeny[i];
  1739. body << YAML::EndMap;
  1740. }
  1741. }
  1742. body << YAML::EndSeq;
  1743. }
  1744. if (it_req->second.weapon != 0) {
  1745. body << YAML::Key << "Weapon";
  1746. body << YAML::BeginMap;
  1747. int temp = it_req->second.weapon;
  1748. if (temp != 99) { // Not "All"
  1749. for (int i = 0; i < MAX_WEAPON_TYPE_ALL; i++) {
  1750. if (i == MAX_WEAPON_TYPE)
  1751. continue;
  1752. if (temp & 1 << i) {
  1753. constant = constant_lookup(i, "W_");
  1754. constant.erase(0, 2);
  1755. body << YAML::Key << name2Upper(constant) << YAML::Value << "true";
  1756. temp ^= 1 << i;
  1757. }
  1758. }
  1759. }
  1760. body << YAML::EndMap;
  1761. }
  1762. if (it_req->second.ammo != 0) {
  1763. body << YAML::Key << "Ammo";
  1764. body << YAML::BeginMap;
  1765. int temp = it_req->second.ammo;
  1766. for (int i = 1; i < MAX_AMMO_TYPE; i++) {
  1767. if (temp & 1 << i) {
  1768. constant = constant_lookup(i, "A_");
  1769. constant.erase(0, 2);
  1770. body << YAML::Key << name2Upper(constant) << YAML::Value << "true";
  1771. temp ^= 1 << i;
  1772. }
  1773. }
  1774. body << YAML::EndMap;
  1775. }
  1776. if (!isMultiLevel(it_req->second.ammo_qty)) {
  1777. if (it_req->second.ammo_qty[0] > 0)
  1778. body << YAML::Key << "AmmoAmount" << YAML::Value << it_req->second.ammo_qty[0];
  1779. } else {
  1780. body << YAML::Key << "AmmoAmount";
  1781. body << YAML::BeginSeq;
  1782. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.ammo_qty); i++) {
  1783. if (it_req->second.ammo_qty[i] > 0) {
  1784. body << YAML::BeginMap;
  1785. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1786. body << YAML::Key << "Amount" << YAML::Value << it_req->second.ammo_qty[i];
  1787. body << YAML::EndMap;
  1788. }
  1789. }
  1790. body << YAML::EndSeq;
  1791. }
  1792. if (it_req->second.state) {
  1793. constant = constant_lookup(it_req->second.state, "ST_");
  1794. constant.erase(0, 3);
  1795. body << YAML::Key << "State" << YAML::Value << name2Upper(constant);
  1796. }
  1797. if (it_req->second.status.size() > 0) {
  1798. body << YAML::Key << "Status";
  1799. body << YAML::BeginMap;
  1800. for (const auto &it : it_req->second.status) {
  1801. constant = constant_lookup(it, "SC_");
  1802. constant.erase(0, 3);
  1803. body << YAML::Key << name2Upper(constant) << YAML::Value << "true";
  1804. }
  1805. body << YAML::EndMap;
  1806. }
  1807. if (!isMultiLevel(it_req->second.spiritball)) {
  1808. if (it_req->second.spiritball[0] != 0)
  1809. body << YAML::Key << "SpiritSphereCost" << YAML::Value << it_req->second.spiritball[0];
  1810. } else {
  1811. body << YAML::Key << "SpiritSphereCost";
  1812. body << YAML::BeginSeq;
  1813. for (size_t i = 0; i < ARRAYLENGTH(it_req->second.spiritball); i++) {
  1814. if (it_req->second.spiritball[i] != 0) {
  1815. body << YAML::BeginMap;
  1816. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1817. body << YAML::Key << "Amount" << YAML::Value << it_req->second.spiritball[i];
  1818. body << YAML::EndMap;
  1819. }
  1820. }
  1821. body << YAML::EndSeq;
  1822. }
  1823. if (it_req->second.itemid[0] > 0) {
  1824. body << YAML::Key << "ItemCost";
  1825. body << YAML::BeginSeq;
  1826. for (uint8 i = 0; i < ARRAYLENGTH(it_req->second.itemid); i++) {
  1827. if (it_req->second.itemid[i] > 0) {
  1828. body << YAML::BeginMap;
  1829. std::string *item_name = util::umap_find(aegis_itemnames, static_cast<uint16>(it_req->second.itemid[i]));
  1830. if (item_name == nullptr) {
  1831. ShowError("Item name for item id %hu is not known (itemcost).\n", it_req->second.itemid[i]);
  1832. return false;
  1833. }
  1834. body << YAML::Key << "Item" << YAML::Value << *item_name;
  1835. body << YAML::Key << "Amount" << YAML::Value << it_req->second.amount[i];
  1836. body << YAML::EndMap;
  1837. }
  1838. }
  1839. body << YAML::EndSeq;
  1840. }
  1841. if (it_req->second.eqItem.size() > 0) {
  1842. body << YAML::Key << "Equipment";
  1843. body << YAML::BeginMap;
  1844. for (const auto &it : it_req->second.eqItem) {
  1845. std::string *item_name = util::umap_find(aegis_itemnames, static_cast<uint16>(it));
  1846. if (item_name == nullptr) {
  1847. ShowError("Item name for item id %hu is not known (equipment).\n", it);
  1848. return false;
  1849. }
  1850. body << YAML::Key << *item_name << YAML::Value << "true";
  1851. }
  1852. body << YAML::EndMap;
  1853. }
  1854. body << YAML::EndMap;
  1855. }
  1856. auto it_unit = skill_unit.find(skill_id);
  1857. if (it_unit != skill_unit.end()) {
  1858. body << YAML::Key << "Unit";
  1859. body << YAML::BeginMap;
  1860. constant = constant_lookup(it_unit->second.unit_id, "UNT_");
  1861. constant.erase(0, 4);
  1862. body << YAML::Key << "Id" << YAML::Value << name2Upper(constant);
  1863. if (it_unit->second.unit_id2 > 0) {
  1864. constant = constant_lookup(it_unit->second.unit_id2, "UNT_");
  1865. constant.erase(0, 4);
  1866. body << YAML::Key << "AlternateId" << YAML::Value << name2Upper(constant);
  1867. }
  1868. if (!isMultiLevel(it_unit->second.unit_layout_type)) {
  1869. if (it_unit->second.unit_layout_type[0] != 0)
  1870. body << YAML::Key << "Layout" << YAML::Value << it_unit->second.unit_layout_type[0];
  1871. } else {
  1872. body << YAML::Key << "Layout";
  1873. body << YAML::BeginSeq;
  1874. for (size_t i = 0; i < ARRAYLENGTH(it_unit->second.unit_layout_type); i++) {
  1875. if (it_unit->second.unit_layout_type[i] == 0 && i + 1 > 5)
  1876. continue;
  1877. body << YAML::BeginMap;
  1878. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1879. body << YAML::Key << "Size" << YAML::Value << it_unit->second.unit_layout_type[i];
  1880. body << YAML::EndMap;
  1881. }
  1882. body << YAML::EndSeq;
  1883. }
  1884. if (!isMultiLevel(it_unit->second.unit_range)) {
  1885. if (it_unit->second.unit_range[0] != 0)
  1886. body << YAML::Key << "Range" << YAML::Value << it_unit->second.unit_range[0];
  1887. } else {
  1888. body << YAML::Key << "Range";
  1889. body << YAML::BeginSeq;
  1890. for (size_t i = 0; i < ARRAYLENGTH(it_unit->second.unit_range); i++) {
  1891. if (it_unit->second.unit_range[i] == 0 && i + 1 > 5)
  1892. continue;
  1893. body << YAML::BeginMap;
  1894. body << YAML::Key << "Level" << YAML::Value << i + 1;
  1895. body << YAML::Key << "Size" << YAML::Value << it_unit->second.unit_range[i];
  1896. body << YAML::EndMap;
  1897. }
  1898. body << YAML::EndSeq;
  1899. }
  1900. if (it_unit->second.unit_interval != 0)
  1901. body << YAML::Key << "Interval" << YAML::Value << it_unit->second.unit_interval;
  1902. if (it_unit->second.target_str.size() > 0) {
  1903. if (it_unit->second.target_str.compare("noenemy") == 0 || it_unit->second.target_str.compare("friend") == 0)
  1904. body << YAML::Key << "Target" << YAML::Value << "Friend";
  1905. //else if (it_unit->second.target_str.compare("noenemy") == 0) // Same as Friend
  1906. // body << YAML::Key << "Target" << YAML::Value << "NoEnemy";
  1907. else if (it_unit->second.target_str.compare("party") == 0)
  1908. body << YAML::Key << "Target" << YAML::Value << "Party";
  1909. else if (it_unit->second.target_str.compare("ally") == 0)
  1910. body << YAML::Key << "Target" << YAML::Value << "Ally";
  1911. else if (it_unit->second.target_str.compare("guild") == 0)
  1912. body << YAML::Key << "Target" << YAML::Value << "Guild";
  1913. //else if (it_unit->second.target_str.compare("all") == 0)
  1914. // body << YAML::Key << "Target" << YAML::Value << "All";
  1915. else if (it_unit->second.target_str.compare("enemy") == 0)
  1916. body << YAML::Key << "Target" << YAML::Value << "Enemy";
  1917. else if (it_unit->second.target_str.compare("self") == 0)
  1918. body << YAML::Key << "Target" << YAML::Value << "Self";
  1919. else if (it_unit->second.target_str.compare("sameguild") == 0)
  1920. body << YAML::Key << "Target" << YAML::Value << "SameGuild";
  1921. }
  1922. if (it_unit->second.unit_flag_csv > 0) {
  1923. body << YAML::Key << "Flag";
  1924. body << YAML::BeginMap;
  1925. if (it_unit->second.unit_flag_csv & 0x1)
  1926. body << YAML::Value << "NoEnemy" << YAML::Value << "true";
  1927. if (it_unit->second.unit_flag_csv & 0x2)
  1928. body << YAML::Value << "NoReiteration" << YAML::Value << "true";
  1929. if (it_unit->second.unit_flag_csv & 0x4)
  1930. body << YAML::Value << "NoFootSet" << YAML::Value << "true";
  1931. if (it_unit->second.unit_flag_csv & 0x8)
  1932. body << YAML::Value << "NoOverlap" << YAML::Value << "true";
  1933. if (it_unit->second.unit_flag_csv & 0x10)
  1934. body << YAML::Value << "PathCheck" << YAML::Value << "true";
  1935. if (it_unit->second.unit_flag_csv & 0x20)
  1936. body << YAML::Value << "NoPc" << YAML::Value << "true";
  1937. if (it_unit->second.unit_flag_csv & 0x40)
  1938. body << YAML::Value << "NoMob" << YAML::Value << "true";
  1939. if (it_unit->second.unit_flag_csv & 0x80)
  1940. body << YAML::Value << "Skill" << YAML::Value << "true";
  1941. if (it_unit->second.unit_flag_csv & 0x100)
  1942. body << YAML::Value << "Dance" << YAML::Value << "true";
  1943. if (it_unit->second.unit_flag_csv & 0x200)
  1944. body << YAML::Value << "Ensemble" << YAML::Value << "true";
  1945. if (it_unit->second.unit_flag_csv & 0x400)
  1946. body << YAML::Value << "Song" << YAML::Value << "true";
  1947. if (it_unit->second.unit_flag_csv & 0x800)
  1948. body << YAML::Value << "DualMode" << YAML::Value << "true";
  1949. if (it_unit->second.unit_flag_csv & 0x1000)
  1950. body << YAML::Value << "NoKnockback" << YAML::Value << "true";
  1951. if (it_unit->second.unit_flag_csv & 0x2000)
  1952. body << YAML::Value << "RangedSingleUnit" << YAML::Value << "true";
  1953. if (it_unit->second.unit_flag_csv & 0x4000)
  1954. body << YAML::Value << "CrazyWeedImmune" << YAML::Value << "true";
  1955. if (it_unit->second.unit_flag_csv & 0x8000)
  1956. body << YAML::Value << "RemovedByFireRain" << YAML::Value << "true";
  1957. if (it_unit->second.unit_flag_csv & 0x10000)
  1958. body << YAML::Value << "KnockbackGroup" << YAML::Value << "true";
  1959. if (it_unit->second.unit_flag_csv & 0x20000)
  1960. body << YAML::Value << "HiddenTrap" << YAML::Value << "true";
  1961. body << YAML::EndMap;
  1962. }
  1963. body << YAML::EndMap;
  1964. }
  1965. body << YAML::EndMap;
  1966. return true;
  1967. }
  1968. // Copied and adjusted from quest.cpp
  1969. static bool quest_read_db(char *split[], int columns, int current) {
  1970. int quest_id = atoi(split[0]);
  1971. if (quest_id < 0 || quest_id >= INT_MAX) {
  1972. ShowError("quest_read_db: Invalid quest ID '%d'.\n", quest_id);
  1973. return false;
  1974. }
  1975. body << YAML::BeginMap;
  1976. body << YAML::Key << "Id" << YAML::Value << quest_id;
  1977. std::string title = split[17];
  1978. if (columns > 18) { // If the title has a comma in it, concatenate
  1979. int col = 18;
  1980. while (col < columns) {
  1981. title += ',' + std::string(split[col]);
  1982. col++;
  1983. }
  1984. }
  1985. title.erase(std::remove(title.begin(), title.end(), '"'), title.end()); // Strip double quotes out
  1986. body << YAML::Key << "Title" << YAML::Value << title;
  1987. if (strchr(split[1], ':') == NULL) {
  1988. uint32 time = atoi(split[1]);
  1989. if (time > 0) {
  1990. int day = time / 86400;
  1991. time %= (24 * 3600);
  1992. int hour = time / 3600;
  1993. time %= 3600;
  1994. int minute = time / 60;
  1995. time %= 60;
  1996. int second = time;
  1997. std::string output = "+";
  1998. if (day > 0)
  1999. output += std::to_string(day) + "d";
  2000. if (hour > 0)
  2001. output += std::to_string(hour) + "h";
  2002. if (minute > 0)
  2003. output += std::to_string(minute) + "mn";
  2004. if (second > 0)
  2005. output += std::to_string(second) + "s";
  2006. body << YAML::Key << "TimeLimit" << YAML::Value << output;
  2007. }
  2008. } else {
  2009. if (*split[1]) {
  2010. std::string time_str(split[1]), hour = time_str.substr(0, time_str.find(':')), output = {};
  2011. time_str.erase(0, 3); // Remove "HH:"
  2012. if (std::stoi(hour) > 0)
  2013. output = std::to_string(std::stoi(hour)) + "h";
  2014. if (std::stoi(time_str) > 0)
  2015. output += std::to_string(std::stoi(time_str)) + "mn";
  2016. body << YAML::Key << "TimeLimit" << YAML::Value << output; // No quests in TXT format had days, default to 0
  2017. }
  2018. }
  2019. if (atoi(split[2]) > 0) {
  2020. body << YAML::Key << "Targets";
  2021. body << YAML::BeginSeq;
  2022. for (size_t i = 0; i < MAX_QUEST_OBJECTIVES; i++) {
  2023. int32 mob_id = (int32)atoi(split[i * 2 + 2]), count = atoi(split[i * 2 + 3]);
  2024. if (!mob_id || !count)
  2025. continue;
  2026. std::string *mob_name = util::umap_find(aegis_mobnames, static_cast<uint16>(mob_id));
  2027. if (!mob_name) {
  2028. ShowError("quest_read_db: Invalid mob-class %hu, target not read.\n", mob_id);
  2029. continue;
  2030. }
  2031. body << YAML::BeginMap;
  2032. body << YAML::Key << "Mob" << YAML::Value << *mob_name;
  2033. body << YAML::Key << "Count" << YAML::Value << count;
  2034. body << YAML::EndMap;
  2035. }
  2036. body << YAML::EndSeq;
  2037. }
  2038. if (atoi(split[2 * MAX_QUEST_OBJECTIVES + 2]) > 0) {
  2039. body << YAML::Key << "Drops";
  2040. body << YAML::BeginSeq;
  2041. for (size_t i = 0; i < MAX_QUEST_DROPS; i++) {
  2042. int32 mob_id = (int32)atoi(split[3 * i + (2 * MAX_QUEST_OBJECTIVES + 2)]), nameid = (uint16)atoi(split[3 * i + (2 * MAX_QUEST_OBJECTIVES + 3)]);
  2043. if (!mob_id || !nameid)
  2044. continue;
  2045. std::string *mob_name = util::umap_find(aegis_mobnames, static_cast<uint16>(mob_id));
  2046. if (!mob_name) {
  2047. ShowError("quest_read_db: Invalid mob-class %hu, drop not read.\n", mob_id);
  2048. continue;
  2049. }
  2050. std::string *item_name = util::umap_find(aegis_itemnames, static_cast<uint16>(nameid));
  2051. if (!item_name) {
  2052. ShowError("quest_read_db: Invalid item name %hu, drop not read.\n", nameid);
  2053. return false;
  2054. }
  2055. body << YAML::BeginMap;
  2056. body << YAML::Key << "Mob" << YAML::Value << *mob_name;
  2057. body << YAML::Key << "Item" << YAML::Value << *item_name;
  2058. //body << YAML::Key << "Count" << YAML::Value << 1; // Default is 1
  2059. body << YAML::Key << "Rate" << YAML::Value << atoi(split[3 * i + (2 * MAX_QUEST_OBJECTIVES + 4)]);
  2060. body << YAML::EndMap;
  2061. }
  2062. body << YAML::EndSeq;
  2063. }
  2064. body << YAML::EndMap;
  2065. return true;
  2066. }
  2067. // Copied and adjusted from instance.cpp
  2068. static bool instance_readdb_sub(char* str[], int columns, int current) {
  2069. body << YAML::BeginMap;
  2070. body << YAML::Key << "Id" << YAML::Value << atoi(str[0]);
  2071. body << YAML::Key << "Name" << YAML::Value << str[1];
  2072. if (atoi(str[2]) != 3600)
  2073. body << YAML::Key << "TimeLimit" << YAML::Value << atoi(str[2]);
  2074. if (atoi(str[3]) != 300)
  2075. body << YAML::Key << "IdleTimeOut" << YAML::Value << atoi(str[3]);
  2076. body << YAML::Key << "Enter";
  2077. body << YAML::BeginMap;
  2078. body << YAML::Key << "Map" << YAML::Value << str[4];
  2079. body << YAML::Key << "X" << YAML::Value << atoi(str[5]);
  2080. body << YAML::Key << "Y" << YAML::Value << atoi(str[6]);
  2081. body << YAML::EndMap;
  2082. if (columns > 7) {
  2083. body << YAML::Key << "AdditionalMaps";
  2084. body << YAML::BeginMap;
  2085. for (int i = 7; i < columns; i++) {
  2086. if (!strlen(str[i]))
  2087. continue;
  2088. if (strcmpi(str[4], str[i]) == 0)
  2089. continue;
  2090. body << YAML::Key << str[i] << YAML::Value << "true";
  2091. }
  2092. body << YAML::EndMap;
  2093. }
  2094. body << YAML::EndMap;
  2095. return true;
  2096. }