swdb.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. //const fs = require('fs-extra');
  2. //const csv = require('fast-csv');
  3. const dateFormat = require('dateformat');
  4. //const path = require('path');
  5. //const sanitize = require('sanitize-filename');
  6. module.exports = {
  7. defaultConfig: {
  8. enabled: true,
  9. debug: true
  10. },
  11. pluginName: 'SWDB',
  12. pluginDescription: 'Saves runs to SWDB.',
  13. target_host: 'localhost',
  14. target_port: '80',
  15. target_url: 'upload/run',
  16. temp: {},
  17. proxy: null,
  18. config: null,
  19. /**
  20. * Initializes he plugin.
  21. *
  22. * @param proxy The proxy.
  23. * @param Global configurations.
  24. */
  25. init(proxy, config) {
  26. this.proxy = proxy;
  27. this.config = config;
  28. proxy.on('apiCommand', (req, resp) => {
  29. try {
  30. if (config.Config.Plugins[this.pluginName].enabled) {
  31. const { command, wizard_id: wizardID } = req;
  32. if (!this.temp[wizardID]) {
  33. this.temp[wizardID] = {};
  34. }
  35. if (command === 'BattleScenarioStart') {
  36. proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUN START: ${resp}` })
  37. for (var key in req) {
  38. proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV REQ: ${key}: ${req[key]}` })
  39. }
  40. this.temp[wizardID].area = req.region_id;
  41. this.temp[wizardID].stage = req.stage_no;
  42. this.temp[wizardID].difficulty = req.difficulty;
  43. }
  44. if (command === 'BattleScenarioResult' || command === 'BattleDungeonResult' || command === 'BattleDimensionHoleDungeonResult') {
  45. proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUN RESULT: ${resp}` })
  46. //for (var key in req) {
  47. // this.log("info", `IVV REQ: ${key}: ${req[key]}`);
  48. //}
  49. //for (var key in resp) {
  50. // this.log("info", `IVV RES: ${key}: ${resp[key]}`);
  51. //}
  52. this.parse(req, resp);
  53. }
  54. if (command === 'BattleRiftOfWorldsRaidResult') {
  55. this.parse_raid_rift(req, resp);
  56. }
  57. if (command === 'BattleRiftDungeonResult') {
  58. this.parse_elemental_rift(req, resp);
  59. }
  60. }
  61. catch (e) {
  62. proxy.log({ type: 'error', source: 'plugin', name: this.pluginName, message: `An unexpected error occured: ${e.message}` });
  63. }
  64. });
  65. },
  66. /**
  67. * Parses a reward item (no runes!).
  68. *
  69. * @param crate The crate object.
  70. * @return array of {item, unit, pieces, quantity, shapeshifting}
  71. */
  72. getItem(crate) {
  73. item = 0;
  74. unit = 0;
  75. pieces = 0;
  76. quantity = 0;
  77. shapeshifting = 0;
  78. if (crate.random_scroll && (crate.random_scroll.item_master_id === 1 || crate.random_scroll.item_master_id === 8 || crate.random_scroll.item_master_id === 2)){
  79. // 1: Unknown scroll
  80. // 2: Mystical Scroll
  81. // 8: Summoning Stones
  82. item = crate.random_scroll.item_master_id;
  83. quantity = crate.random_scroll.item_quantity;
  84. }
  85. if (crate.costume_point) {
  86. shapeshifting = crate.costume_point;
  87. }
  88. if (crate.rune_upgrade_stone) {
  89. item = 'Power Stone'; // TODO: Do they exist?
  90. quantity = crate.rune_upgrade_stone.item_quantity;
  91. }
  92. if (crate.unit_info) {
  93. unit = crate.unit_info.unit_master_id;
  94. }
  95. if (crate.material) {
  96. item = crate.material.item_master_id;
  97. quantity = crate.material.item_quantity;
  98. }
  99. if (crate.summon_pieces) {
  100. pieces = crate.summon_pieces.item_master_id;
  101. quantity = crate.summon_pieces.item_quantity;
  102. }
  103. if (crate.craft_stuff) {
  104. item = crate.craft_stuff.item_master_id;
  105. quantity = crate.craft_stuff.item_quantity;
  106. }
  107. //this.log('debug', `Item: ${item}, ${unit}, ${pieces}, ${quantity}, ${shapeshifting}`);
  108. drop = {item, unit, pieces, quantity, shapeshifting}
  109. return drop;
  110. },
  111. /**
  112. * TODO! Unaddapted.
  113. * Parses a rift reward item (no runes!).
  114. *
  115. * @param crate The crate object.
  116. * @return array of {item, unit, pieces, quantity}
  117. */
  118. getItemRift(item, entry) {
  119. if (item.type === 8) {
  120. const rune = item.info;
  121. entry.drop = 'Rune';
  122. entry.grade = `${rune.class}*`;
  123. entry.sell_value = rune.sell_value;
  124. entry.set = gMapping.rune.sets[rune.set_id];
  125. entry.slot = rune.slot_no;
  126. entry.efficiency = gMapping.getRuneEfficiency(rune).current;
  127. entry.rarity = gMapping.rune.class[rune.sec_eff.length];
  128. entry.main_stat = gMapping.getRuneEffect(rune.pri_eff);
  129. entry.prefix_stat = gMapping.getRuneEffect(rune.prefix_eff);
  130. rune.sec_eff.forEach((substat, i) => {
  131. entry[`sub${i + 1}`] = gMapping.getRuneEffect(substat);
  132. });
  133. }
  134. if (item.info.craft_type_id) {
  135. enhancement = this.getEnchantVals(item.info.craft_type_id, item.info.craft_type);
  136. entry.drop = enhancement.drop;
  137. entry.sell_value = item.sell_value;
  138. entry.set = enhancement.set;
  139. entry.main_stat = enhancement.type;
  140. entry.sub1 = enhancement.min;
  141. entry.sub2 = enhancement.max;
  142. }
  143. return entry;
  144. },
  145. /**
  146. * TODO! Will I need this.
  147. * Saves run data to a file in CSV format.
  148. *
  149. */
  150. saveToFile(entry, filename, headers, proxy) {
  151. const csvData = [];
  152. const self = this;
  153. fs.ensureFile(path.join(config.Config.App.filesPath, filename), err => {
  154. if (err) {
  155. return;
  156. }
  157. csv
  158. .fromPath(path.join(config.Config.App.filesPath, filename), { ignoreEmpty: true, headers, renameHeaders: true })
  159. .on('data', data => {
  160. csvData.push(data);
  161. })
  162. .on('end', () => {
  163. csvData.push(entry);
  164. csv.writeToPath(path.join(config.Config.App.filesPath, filename), csvData, { headers }).on('finish', () => {
  165. proxy.log({ type: 'success', source: 'plugin', name: self.pluginName, message: `Saved run data to ${filename}` });
  166. });
  167. });
  168. });
  169. },
  170. /**
  171. * Parses a battle data.
  172. * Valid for scenario, dungeons and Dimensional Hole.
  173. *
  174. * @param req The request
  175. * @param resp The response.
  176. */
  177. parse_normal(req, resp) {
  178. const { command } = req;
  179. const { wizard_id: wizardID, wizard_name: wizardName } = resp.wizard_info;
  180. const run = {};
  181. const run_party = {};
  182. const run_k_party = {};
  183. log = true;
  184. run.uid = wizardID;
  185. if (command === 'BattleDungeonResult') {
  186. if (eq.dungeon_id > 10000){
  187. // Hall of Heroes or unknown
  188. log = false;
  189. }
  190. run.area = req.dungeon_id;
  191. run.stage = req.stage_id;
  192. run.difficulty = 0
  193. }
  194. if (command === 'BattleScenarioResult') {
  195. for (var key in this.temp[wizardID]) {
  196. this.log("debug", `IVV TEMP: ${key}: ${this.temp[wizardID][key]}`);
  197. }
  198. run.area = this.temp[wizardID].area;
  199. run.stage = this.temp[wizardID].stage;
  200. run.difficulty = this.temp[wizardID].difficulty;
  201. }
  202. if (command === 'BattleDimensionHoleDungeonResult') {
  203. //if (gMapping.dungeon[resp.dungeon_id]) {
  204. // run.dungeon = `${gMapping.dungeon[resp.dungeon_id]} Level ${resp.difficulty}`;
  205. //}
  206. run.area = req.dungeon_id;
  207. run.stage = req.stage_id;
  208. run.difficulty = 0
  209. }
  210. run.win = resp.win_lose; // 1/0 2 is lost in scenario
  211. run.dtime = dateFormat(new Date(), 'yyyy-mm-dd HH:MM:SS');
  212. const reward = resp.reward ? resp.reward : {};
  213. run.time = req.clear_time ? req.clear_time : 0;
  214. run.mana = reward.mana ? reward.mana : 0;
  215. run.energy = reward.energy ? reward.energy : 0;
  216. run.crystal = reward.crystal ? reward.crystal : 0;
  217. run.rune = {};
  218. run.unit = 0;
  219. run.unit_pieces = {};
  220. run.sd = 0;
  221. run.item = {};
  222. run.shapeshifting = 0;
  223. if (reward.crate) {
  224. run.mana = reward.crate.mana ? run.mana + reward.crate.mana : run.mana;
  225. run.energy = reward.crate.energy ? run.energy + reward.crate.energy : run.energy;
  226. run.crystal = reward.crate.crystal ? run.crystal + reward.crate.crystal : run.crystal;
  227. if (reward.crate.rune) {
  228. const rune = reward.crate.rune;
  229. for (var key in rune) {
  230. this.proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUNE: ${key}: ${rune[key]}` })
  231. }
  232. run.rune.id = rune.rune_id;
  233. run.rune.grade = rune.class;
  234. run.rune.value = rune.sell_value;
  235. run.rune.set = rune.set_id;
  236. run.rune.slot = rune.slot_no;
  237. run.rune.efficiency = gMapping.getRuneEfficiency(rune).current;
  238. run.rune.quality = rune.rank;
  239. // TODO: Maybe i need to do substrings to get stat and value
  240. run.rune.main = rune.pri_eff[0];
  241. run.rune.main_value = rune.pri_eff[1];
  242. if (rune.prefix_eff){
  243. run.rune.innate = rune.prefix_eff[0];
  244. run.rune.innate_value = rune.prefix_eff[1];
  245. }
  246. rune.sec_eff.forEach((substat, i) => {
  247. run.rune[`substat_${i + 1}`] = substat[0];
  248. run.rune[`substat_${i + 1}_value`] = substat[1];
  249. });
  250. }
  251. else {
  252. drop = this.getItem(reward.crate);
  253. if (drop.unit){
  254. run.unit.id = drop.unit;
  255. }
  256. if (drop.pieces){
  257. run.unit_pieces.id = drop.pieces;
  258. run.unit_pieces.quantity = drop.quantity;
  259. }
  260. if (drop.item){
  261. run.item.id = drop.item;
  262. run.item.quantity = drop.quantity;
  263. }
  264. run.shapeshifting = drop.shapeshifting;
  265. }
  266. }
  267. if (resp.instance_info) {
  268. run.sd = resp.instance_info;
  269. }
  270. if (resp.unit_list && resp.unit_list.length > 0) {
  271. resp.unit_list.forEach((unit, i) => {
  272. run_party[i] = unit.unit_master_id;
  273. run_k_party[i] = unit.unit_id;
  274. });
  275. }
  276. json_rune = '[';
  277. if (run.rune.length() > 0){
  278. json_rune += `"id": "${run.rune.id}", `;
  279. json_rune += `"grade": "${run.rune.grade}", `;
  280. json_rune += `"set": "${run.rune.set}", `;
  281. json_rune += `"slot": "${run.rune.slot}", `;
  282. json_rune += `"efficiency": "${run.rune.efficiency}", `;
  283. json_rune += `"quality": "${run.rune.quality}", `;
  284. json_rune += `"value": "${run.rune.value}", `;
  285. json_rune += `"main_stat": "${run.rune.main}", `;
  286. json_rune += `"main_stat_value": "${run.rune.main_value}", `;
  287. json_rune += `"innate_stat": "${run.rune.innate}", `;
  288. json_rune += `"innate_stat_value": "${run.rune.innate_value}", `;
  289. json_rune += `"substat_1": "${run.rune.substat_1}", `;
  290. json_rune += `"substat_1_value": "${run.rune.substat_1_value}", `;
  291. json_rune += `"substat_2": "${run.rune.substat_2}", `;
  292. json_rune += `"substat_2_value": "${run.rune.substat_2_value}", `;
  293. json_rune += `"substat_3": "${run.rune.substat_3}", `;
  294. json_rune += `"substat_4_value": "${run.rune.substat_3_value}", `;
  295. json_rune += `"substat_4": "${run.rune.substat_4}", `;
  296. json_rune += `"substat_4_value": "${run.rune.substat_4_value}", `;
  297. }
  298. json_rune = json_party.slice(0, -1) + "]";
  299. json_item = '[';
  300. if (run.item.length() > 0){
  301. json_item += `"id": "${run.item.id}", `;
  302. json_item += `"quantity": "${run.item.quantity}", `;
  303. }
  304. json_item = json_party.slice(0, -1) + "]";
  305. json_unit_pieces = '[';
  306. if (run.unit_pieces.length() > 0){
  307. json_unit_pieces += `"id": "${run.unit_pieces.id}", `;
  308. json_unit_pieces += `"quantity": "${run.unit_pieces.quantity}", `;
  309. }
  310. json_unit_pieces = json_party.slice(0, -1) + "]";
  311. json_party = '[';
  312. resp.unit_list.forEach((unit, i) => {
  313. json_party = json_party + '{"unit_id": ' + run_party[i] + ', "unit_master_id": ' + run_k_party[i] + '},';
  314. });
  315. json_party = json_party.slice(0, -1) + "]";
  316. //this.log('debug', `IVV json_party: ${json_party}`)
  317. json = `{`;
  318. json += `"dtime": "${run.dtime}", `;
  319. json += `"area": "${run.dungeon}", `;
  320. json += `"stage": "${run.stage}", `;
  321. json += `"difficulty": "${run.difficulty}", `;
  322. json += `"win": "${run.win}", `;
  323. json += `"time": "${run.time}", `;
  324. json += `"mana": "${run.mana}", `;
  325. json += `"energy": "${run.energy}", `;
  326. json += `"crystal": "${run.crystal}", `;
  327. json += `"rune": ${json_rune}, `;
  328. json += `"sd": ${run.sd}, `;
  329. json += `"item": ${json_item}, `;
  330. json += `"unit": ${run.unit}, `;
  331. json += `"unit_pieces": ${json_unit_pieces}, `;
  332. json += `"sapeshifting": ${run.sapeshifting}, `;
  333. json += `"party": ${json_party}`;
  334. json += `}`;
  335. this.log('DEBUG', `json: ${json}` })
  336. //const filename = sanitize(`${wizardName}-${wizardID}-runs.csv`);
  337. //const filename = sanitize(`IVV-${wizardName}-${wizardID}-runs.csv`);
  338. //this.saveToFile(entry, filename, headers, proxy);
  339. },
  340. /**
  341. * TODO Unaddapted.
  342. * Parses a battle data.
  343. * Valid for Rift Raids.
  344. *
  345. * @param req The request
  346. * @param resp The response.
  347. */
  348. parse_raid_rift(req, resp) {
  349. const { wizard_id: wizardID, wizard_name: wizardName } = resp.wizard_info;
  350. let run = {};
  351. if (gMapping.dungeon[req.dungeon_id]) {
  352. run.dungeon = `${gMapping.elemental_rift_dungeon[req.dungeon_id]}`;
  353. isElemental = true;
  354. }
  355. //const winLost = resp.win_lose === 1 ? 'Win' : 'Did not kill';
  356. run.dtime = dateFormat(new Date(), 'yyyy-mm-dd HH:MM:SS');
  357. //run.result = winLost;
  358. run.win = resp.win_lose;
  359. run.rune = {};
  360. run.unit = 0;
  361. run.unit_pieces = {};
  362. run.sd = 0;
  363. run.item = {};
  364. run.shapeshifting = 0;
  365. run.time = req.clear_time ? req.clear_time : 0;
  366. const reward = resp.reward ? resp.reward : {};
  367. if (resp.win_lose === 1) {
  368. // No crate: Mana of shapeshifting stones
  369. if (!reward.crate) {
  370. const reward = resp.battle_reward_list.find(value => value.wizard_id === resp.wizard_info.wizard_id).reward_list[0];
  371. if (reward.item_master_id === 6) {
  372. run.shapeshifting = reward.item_quantity;
  373. }
  374. else {
  375. run.mana = reward.item_quantity;
  376. }
  377. }
  378. // Rune craft item
  379. else if (reward.crate.changestones) {
  380. const item = {
  381. info: {
  382. craft_type: reward.crate.changestones[0].craft_type,
  383. craft_type_id: reward.crate.changestones[0].craft_type_id
  384. },
  385. sell_value: reward.crate.changestones[0].sell_value
  386. };
  387. run.drop= this.getItemRift(item, run.;
  388. }
  389. // Rune
  390. else if (reward.crate.rune) {
  391. const rune = reward.crate.rune;
  392. //for (var key in rune) {
  393. // this.proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUNE: ${key}: ${rune[key]}` })
  394. //}
  395. run.rune.id = rune.rune_id;
  396. run.rune.grade = rune.class;
  397. run.rune.value = rune.sell_value;
  398. run.rune.set = rune.set_id;
  399. run.rune.slot = rune.slot_no;
  400. run.rune.efficiency = gMapping.getRuneEfficiency(rune).current;
  401. run.rune.quality = rune.rank;
  402. run.rune.main = rune.pri_eff[0];
  403. run.rune.main_value = rune.pri_eff[1];
  404. if (rune.prefix_eff){
  405. run.rune.innate = rune.prefix_eff[0];
  406. run.rune.innate_value = rune.prefix_eff[1];
  407. }
  408. rune.sec_eff.forEach((substat, i) => {
  409. run.rune[`substat_${i + 1}`] = substat[0];
  410. run.rune[`substat_${i + 1}_value`] = substat[1];
  411. });
  412. }
  413. // Unit (Rainbowmon)
  414. else if (reward.crate.unit_info && reward.crate.unit_info.unit_master_id > 0) {
  415. run.unit.id = reward.crate.unit_info.unit_master_id;
  416. }
  417. // Item
  418. else if (!run.drop && resp.reward.crate) {
  419. //run.drop = this.getItem(reward.resp.reward.crate);
  420. if (resp.reward.crate.random_scroll && (resp.reward.crate.random_scroll.item_master_id === 1 || resp.reward.crate.random_scroll.item_master_id === 8 || resp.reward.crate.random_scroll.item_master_id === 2)){
  421. // 1: Unknown scroll
  422. // 2: Mystical Scroll
  423. // 8: Summoning Stones
  424. run.item.id = resp.reward.crate.random_scroll.item_master_id;
  425. run.item.quantity = resp.reward.crate.random_scroll.item_quantity;
  426. }
  427. //if (resp.reward.crate.costume_point) {
  428. // shapeshifting = resp.reward.crate.costume_point;
  429. //}
  430. //if (resp.reward.crate.rune_upgrade_stone) {
  431. // item = 'Power Stone'; // TODO: Do they exist?
  432. // quantity = resp.reward.crate.rune_upgrade_stone.item_quantity;
  433. //}
  434. //if (resp.reward.crate.unit_info) {
  435. // unit = resp.reward.crate.unit_info.unit_master_id;
  436. //}
  437. if (resp.reward.crate.material) {
  438. item = resp.reward.crate.material.item_master_id;
  439. quantity = resp.reward.crate.material.item_quantity;
  440. //}
  441. //if (resp.reward.crate.summon_pieces) {
  442. // pieces = resp.reward.crate.summon_pieces.item_master_id;
  443. // quantity = resp.reward.crate.summon_pieces.item_quantity;
  444. //}
  445. if (resp.reward.crate.craft_stuff) {
  446. item = resp.reward.crate.craft_stuff.item_master_id;
  447. quantity = resp.reward.crate.craft_stuff.item_quantity;
  448. }
  449. }
  450. else {
  451. run.drop = 'unknown';
  452. }
  453. }
  454. if (resp.unit_list && resp.unit_list.length > 0) {
  455. resp.unit_list.forEach((unit, i) => {
  456. run_party[i] = unit.unit_master_id;
  457. run_k_party[i] = unit.unit_id;
  458. });
  459. }
  460. //const filename = sanitize(`${wizardName}-${wizardID}-raid-runs.csv`);
  461. //this.saveToFile(run. filename, headers, proxy);
  462. },
  463. /**
  464. * TODO Unaddapted.
  465. * Parses a battle data.
  466. * Valid for Rift Dungeons.
  467. *
  468. * @param req The request
  469. * @param resp The response.
  470. */
  471. parse_elemental_rift(req, resp) {
  472. const { wizard_id: wizardID, wizard_name: wizardName } = resp.wizard_info;
  473. let entry = {};
  474. if (gMapping.dungeon[req.dungeon_id]) {
  475. entry.dungeon = `${gMapping.elemental_rift_dungeon[req.dungeon_id]}`;
  476. isElemental = true;
  477. }
  478. const winLost = req.battle_result === 1 ? 'Win' : 'Did not kill';
  479. entry.date = dateFormat(new Date(), 'yyyy-mm-dd HH:MM');
  480. entry.result = winLost;
  481. if (resp.item_list && resp.item_list.length > 0) {
  482. resp.item_list.forEach((item, i) => {
  483. if (item.is_boxing !== 1 || item.id === 2001) {
  484. entry[`item${i + 1}`] = `${gMapping.craftMaterial[item.id]} x${item.quantity}`;
  485. } else {
  486. if (item.id === 2) {
  487. entry.drop = 'Mystical Scroll';
  488. }
  489. if (item.id === 8) {
  490. entry.drop = `Summoning Stones x${item.item_quantity}`;
  491. }
  492. if (item.info && item.info.unit_master_id > 0) {
  493. entry.drop = `${gMapping.getMonsterName(item.info.unit_master_id)} ${item.class}`;
  494. }
  495. if ((item.info && item.info.craft_type_id) || item.type === 8) {
  496. entry = this.getItemRift(item, entry);
  497. }
  498. }
  499. });
  500. }
  501. if (resp.unit_list && resp.unit_list.length > 0) {
  502. resp.unit_list.forEach((unit, i) => {
  503. entry[`team${i + 1}`] = gMapping.getMonsterName(unit.unit_master_id);
  504. });
  505. }
  506. json_rune = '[';
  507. if (run.rune.length() > 0){
  508. json_rune += `"id": "${run.rune.id}", `;
  509. json_rune += `"grade": "${run.rune.grade}", `;
  510. json_rune += `"set": "${run.rune.set}", `;
  511. json_rune += `"slot": "${run.rune.slot}", `;
  512. json_rune += `"efficiency": "${run.rune.efficiency}", `;
  513. json_rune += `"quality": "${run.rune.quality}", `;
  514. json_rune += `"value": "${run.rune.value}", `;
  515. json_rune += `"main_stat": "${run.rune.main}", `;
  516. json_rune += `"main_stat_value": "${run.rune.main_value}", `;
  517. json_rune += `"innate_stat": "${run.rune.innate}", `;
  518. json_rune += `"innate_stat_value": "${run.rune.innate_value}", `;
  519. json_rune += `"substat_1": "${run.rune.substat_1}", `;
  520. json_rune += `"substat_1_value": "${run.rune.substat_1_value}", `;
  521. json_rune += `"substat_2": "${run.rune.substat_2}", `;
  522. json_rune += `"substat_2_value": "${run.rune.substat_2_value}", `;
  523. json_rune += `"substat_3": "${run.rune.substat_3}", `;
  524. json_rune += `"substat_4_value": "${run.rune.substat_3_value}", `;
  525. json_rune += `"substat_4": "${run.rune.substat_4}", `;
  526. json_rune += `"substat_4_value": "${run.rune.substat_4_value}", `;
  527. }
  528. json_rune = json_party.slice(0, -1) + "]";
  529. json_item = '[';
  530. if (run.item.length() > 0){
  531. json_item += `"id": "${run.item.id}", `;
  532. json_item += `"quantity": "${run.item.quantity}", `;
  533. }
  534. json_item = json_party.slice(0, -1) + "]";
  535. json_unit_pieces = '[';
  536. if (run.unit_pieces.length() > 0){
  537. json_unit_pieces += `"id": "${run.unit_pieces.id}", `;
  538. json_unit_pieces += `"quantity": "${run.unit_pieces.quantity}", `;
  539. }
  540. json_unit_pieces = json_party.slice(0, -1) + "]";
  541. json_party = '[';
  542. resp.unit_list.forEach((unit, i) => {
  543. json_party = json_party + '{"unit_id": ' + run_party[i] + ', "unit_master_id": ' + run_k_party[i] + '},';
  544. });
  545. json_party = json_party.slice(0, -1) + "]";
  546. //this.log('debug', `IVV json_party: ${json_party}`)
  547. json = `{`;
  548. json += `"dtime": "${run.dtime}", `;
  549. json += `"area": "${run.dungeon}", `;
  550. json += `"stage": "${run.stage}", `;
  551. json += `"difficulty": "${run.difficulty}", `;
  552. json += `"win": "${run.win}", `;
  553. json += `"time": "${run.time}", `;
  554. json += `"mana": "${run.mana}", `;
  555. json += `"energy": "${run.energy}", `;
  556. json += `"crystal": "${run.crystal}", `;
  557. json += `"rune": ${json_rune}, `;
  558. json += `"sd": ${run.sd}, `;
  559. json += `"item": ${json_item}, `;
  560. json += `"unit": ${run.unit}, `;
  561. json += `"unit_pieces": ${json_unit_pieces}, `;
  562. json += `"sapeshifting": ${run.sapeshifting}, `;
  563. json += `"party": ${json_party}`;
  564. json += `}`;
  565. this.log('DEBUG', `json: ${json}` })
  566. },
  567. /**
  568. * TODO ???
  569. */
  570. getEnchantVals(craftID, craftType) {
  571. const map = {};
  572. const typeNumber = Number(craftID.toString().slice(-4, -2));
  573. map.set = gMapping.rune.sets[Number(craftID.toString().slice(0, -4))];
  574. map.grade = gMapping.rune.quality[Number(craftID.toString().slice(-1))];
  575. map.type = gMapping.rune.effectTypes[typeNumber];
  576. if (craftType === 2) {
  577. map.min = gMapping.grindstone[typeNumber].range[Number(craftID.toString().slice(-1))].min;
  578. map.max = gMapping.grindstone[typeNumber].range[Number(craftID.toString().slice(-1))].max;
  579. map.drop = 'Grindstone';
  580. } else {
  581. map.min = gMapping.enchanted_gem[typeNumber].range[Number(craftID.toString().slice(-1))].min;
  582. map.max = gMapping.enchanted_gem[typeNumber].range[Number(craftID.toString().slice(-1))].max;
  583. map.drop = 'Enchanted Gem';
  584. }
  585. return map;
  586. }
  587. /**
  588. * Prints a messageto the SWEX output.
  589. *
  590. * @param type Log type. Debug type will be printed depending on config.
  591. * @param msg The message to log.
  592. */
  593. log(type, msg){
  594. if (type != "debug" || this.config.Config.Plugins[this.pluginName].debug == true){
  595. proxy.log({ type: type, source: 'plugin', name: this.pluginName, message: msg });
  596. }
  597. }
  598. };