Ver Fonte

DB structure for runs. SWEX plugin draft.

Inigo Valentin há 6 anos atrás
pai
commit
25b4992cc2
3 ficheiros alterados com 952 adições e 0 exclusões
  1. 203 0
      data.sql
  2. 96 0
      install_base.py
  3. 653 0
      swex-plugin/swdb.js

+ 203 - 0
data.sql

@@ -328,6 +328,209 @@ INSERT INTO k_decoration VALUES (5, 1, null, null, 'Mana Fountain', '', 10);
 INSERT INTO k_decoration VALUES (10, 1, null, null, 'Sanctum of Energy', '', 10);
 INSERT INTO k_decoration VALUES (35, 1, null, null, 'Fairy Tree', '', 10);
 
+
+INSERT INTO k_decoration_level VALUES (4, 1, 2, 100);
+INSERT INTO k_decoration_level VALUES (4, 2, 4, 280);
+INSERT INTO k_decoration_level VALUES (4, 3, 6, 460);
+INSERT INTO k_decoration_level VALUES (4, 4, 8, 640);
+INSERT INTO k_decoration_level VALUES (4, 5, 10, 820);
+INSERT INTO k_decoration_level VALUES (4, 6, 12, 1000);
+INSERT INTO k_decoration_level VALUES (4, 7, 14, 1180);
+INSERT INTO k_decoration_level VALUES (4, 8, 16, 1360);
+INSERT INTO k_decoration_level VALUES (4, 9, 18, 1540);
+INSERT INTO k_decoration_level VALUES (4, 10, 20, 1720);
+INSERT INTO k_decoration_level VALUES (15, 1, 3, 120);
+INSERT INTO k_decoration_level VALUES (15, 2, 5, 240);
+INSERT INTO k_decoration_level VALUES (15, 3, 7, 360);
+INSERT INTO k_decoration_level VALUES (15, 4, 9, 480);
+INSERT INTO k_decoration_level VALUES (15, 5, 11, 600);
+INSERT INTO k_decoration_level VALUES (15, 6, 13, 720);
+INSERT INTO k_decoration_level VALUES (15, 7, 15, 840);
+INSERT INTO k_decoration_level VALUES (15, 8, 17, 960);
+INSERT INTO k_decoration_level VALUES (15, 9, 19, 1080);
+INSERT INTO k_decoration_level VALUES (15, 10, 21, 1200);
+INSERT INTO k_decoration_level VALUES (16, 1, 3, 120);
+INSERT INTO k_decoration_level VALUES (16, 2, 5, 240);
+INSERT INTO k_decoration_level VALUES (16, 3, 7, 360);
+INSERT INTO k_decoration_level VALUES (16, 4, 9, 480);
+INSERT INTO k_decoration_level VALUES (16, 5, 11, 600);
+INSERT INTO k_decoration_level VALUES (16, 6, 13, 720);
+INSERT INTO k_decoration_level VALUES (16, 7, 15, 840);
+INSERT INTO k_decoration_level VALUES (16, 8, 17, 960);
+INSERT INTO k_decoration_level VALUES (16, 9, 19, 1080);
+INSERT INTO k_decoration_level VALUES (16, 10, 21, 1200);
+INSERT INTO k_decoration_level VALUES (17, 1, 3, 120);
+INSERT INTO k_decoration_level VALUES (17, 2, 5, 240);
+INSERT INTO k_decoration_level VALUES (17, 3, 7, 360);
+INSERT INTO k_decoration_level VALUES (17, 4, 9, 480);
+INSERT INTO k_decoration_level VALUES (17, 5, 11, 600);
+INSERT INTO k_decoration_level VALUES (17, 6, 13, 720);
+INSERT INTO k_decoration_level VALUES (17, 7, 15, 840);
+INSERT INTO k_decoration_level VALUES (17, 8, 17, 960);
+INSERT INTO k_decoration_level VALUES (17, 9, 19, 1080);
+INSERT INTO k_decoration_level VALUES (17, 10, 21, 1200);
+INSERT INTO k_decoration_level VALUES (18, 1, 3, 120);
+INSERT INTO k_decoration_level VALUES (18, 2, 5, 240);
+INSERT INTO k_decoration_level VALUES (18, 3, 7, 360);
+INSERT INTO k_decoration_level VALUES (18, 4, 9, 480);
+INSERT INTO k_decoration_level VALUES (18, 5, 11, 600);
+INSERT INTO k_decoration_level VALUES (18, 6, 13, 720);
+INSERT INTO k_decoration_level VALUES (18, 7, 15, 840);
+INSERT INTO k_decoration_level VALUES (18, 8, 17, 960);
+INSERT INTO k_decoration_level VALUES (18, 9, 19, 1080);
+INSERT INTO k_decoration_level VALUES (18, 10, 21, 1200);
+INSERT INTO k_decoration_level VALUES (19, 1, 3, 120);
+INSERT INTO k_decoration_level VALUES (19, 2, 5, 240);
+INSERT INTO k_decoration_level VALUES (19, 3, 7, 360);
+INSERT INTO k_decoration_level VALUES (19, 4, 9, 480);
+INSERT INTO k_decoration_level VALUES (19, 5, 11, 600);
+INSERT INTO k_decoration_level VALUES (19, 6, 13, 720);
+INSERT INTO k_decoration_level VALUES (19, 7, 15, 840);
+INSERT INTO k_decoration_level VALUES (19, 8, 17, 960);
+INSERT INTO k_decoration_level VALUES (19, 9, 19, 1080);
+INSERT INTO k_decoration_level VALUES (19, 10, 21, 1200);
+INSERT INTO k_decoration_level VALUES (31, 1, 2, 120);
+INSERT INTO k_decoration_level VALUES (31, 2, 5, 240);
+INSERT INTO k_decoration_level VALUES (31, 3, 7, 360);
+INSERT INTO k_decoration_level VALUES (31, 4, 10, 480);
+INSERT INTO k_decoration_level VALUES (31, 5, 12, 600);
+INSERT INTO k_decoration_level VALUES (31, 6, 15, 720);
+INSERT INTO k_decoration_level VALUES (31, 7, 17, 840);
+INSERT INTO k_decoration_level VALUES (31, 8, 20, 960);
+INSERT INTO k_decoration_level VALUES (31, 9, 22, 1080);
+INSERT INTO k_decoration_level VALUES (31, 10, 25, 1200);
+INSERT INTO k_decoration_level VALUES (6, 1, 2, 240);
+INSERT INTO k_decoration_level VALUES (6, 2, 3, 440);
+INSERT INTO k_decoration_level VALUES (6, 3, 5, 640);
+INSERT INTO k_decoration_level VALUES (6, 4, 6, 840);
+INSERT INTO k_decoration_level VALUES (6, 5, 8, 1040);
+INSERT INTO k_decoration_level VALUES (6, 6, 9, 1240);
+INSERT INTO k_decoration_level VALUES (6, 7, 11, 1440);
+INSERT INTO k_decoration_level VALUES (6, 8, 12, 1640);
+INSERT INTO k_decoration_level VALUES (6, 9, 14, 1840);
+INSERT INTO k_decoration_level VALUES (6, 10, 15, 2040);
+INSERT INTO k_decoration_level VALUES (8, 1, 2, 200);
+INSERT INTO k_decoration_level VALUES (8, 2, 4, 400);
+INSERT INTO k_decoration_level VALUES (8, 3, 6, 600);
+INSERT INTO k_decoration_level VALUES (8, 4, 8, 800);
+INSERT INTO k_decoration_level VALUES (8, 5, 10, 1000);
+INSERT INTO k_decoration_level VALUES (8, 6, 12, 1200);
+INSERT INTO k_decoration_level VALUES (8, 7, 14, 1400);
+INSERT INTO k_decoration_level VALUES (8, 8, 16, 1600);
+INSERT INTO k_decoration_level VALUES (8, 9, 18, 1800);
+INSERT INTO k_decoration_level VALUES (8, 10, 20, 2000);
+INSERT INTO k_decoration_level VALUES (36, 1, 2, 280);
+INSERT INTO k_decoration_level VALUES (36, 2, 4, 460);
+INSERT INTO k_decoration_level VALUES (36, 3, 6, 800);
+INSERT INTO k_decoration_level VALUES (36, 4, 8, 1250);
+INSERT INTO k_decoration_level VALUES (36, 5, 10, 1810);
+INSERT INTO k_decoration_level VALUES (36, 6, 12, 2320);
+INSERT INTO k_decoration_level VALUES (36, 7, 14, 2910);
+INSERT INTO k_decoration_level VALUES (36, 8, 16, 3590);
+INSERT INTO k_decoration_level VALUES (36, 9, 18, 4350);
+INSERT INTO k_decoration_level VALUES (36, 10, 20, 5200);
+INSERT INTO k_decoration_level VALUES (37, 1, 2, 260);
+INSERT INTO k_decoration_level VALUES (37, 2, 5, 410);
+INSERT INTO k_decoration_level VALUES (37, 3, 7, 700);
+INSERT INTO k_decoration_level VALUES (37, 4, 9, 1080);
+INSERT INTO k_decoration_level VALUES (37, 5, 12, 1560);
+INSERT INTO k_decoration_level VALUES (37, 6, 15, 1990);
+INSERT INTO k_decoration_level VALUES (37, 7, 17, 2490);
+INSERT INTO k_decoration_level VALUES (37, 8, 20, 3070);
+INSERT INTO k_decoration_level VALUES (37, 9, 22, 3720);
+INSERT INTO k_decoration_level VALUES (37, 10, 25, 4440);
+INSERT INTO k_decoration_level VALUES (38, 1, 2, 330);
+INSERT INTO k_decoration_level VALUES (38, 2, 4, 540);
+INSERT INTO k_decoration_level VALUES (38, 3, 6, 930);
+INSERT INTO k_decoration_level VALUES (38, 4, 8, 1450);
+INSERT INTO k_decoration_level VALUES (38, 5, 10, 2100);
+INSERT INTO k_decoration_level VALUES (38, 6, 12, 2680);
+INSERT INTO k_decoration_level VALUES (38, 7, 14, 3360);
+INSERT INTO k_decoration_level VALUES (38, 8, 16, 4140);
+INSERT INTO k_decoration_level VALUES (38, 9, 18, 5020);
+INSERT INTO k_decoration_level VALUES (38, 10, 20, 5990);
+INSERT INTO k_decoration_level VALUES (39, 1, 2, 300);
+INSERT INTO k_decoration_level VALUES (39, 2, 4, 460);
+INSERT INTO k_decoration_level VALUES (39, 3, 6, 760);
+INSERT INTO k_decoration_level VALUES (39, 4, 8, 1160);
+INSERT INTO k_decoration_level VALUES (39, 5, 10, 1670);
+INSERT INTO k_decoration_level VALUES (39, 6, 12, 2130);
+INSERT INTO k_decoration_level VALUES (39, 7, 14, 2660);
+INSERT INTO k_decoration_level VALUES (39, 8, 16, 3270);
+INSERT INTO k_decoration_level VALUES (39, 9, 18, 3960);
+INSERT INTO k_decoration_level VALUES (39, 10, 20, 4720);
+INSERT INTO k_decoration_level VALUES (9, 1, 2, 150);
+INSERT INTO k_decoration_level VALUES (9, 2, 4, 375);
+INSERT INTO k_decoration_level VALUES (9, 3, 6, 600);
+INSERT INTO k_decoration_level VALUES (9, 4, 8, 825);
+INSERT INTO k_decoration_level VALUES (9, 5, 10, 1050);
+INSERT INTO k_decoration_level VALUES (9, 6, 12, 1275);
+INSERT INTO k_decoration_level VALUES (9, 7, 14, 1500);
+INSERT INTO k_decoration_level VALUES (9, 8, 16, 1725);
+INSERT INTO k_decoration_level VALUES (9, 9, 18, 1950);
+INSERT INTO k_decoration_level VALUES (9, 10, 20, 2175);
+INSERT INTO k_decoration_level VALUES (7, 1, 2, 80);
+INSERT INTO k_decoration_level VALUES (7, 2, 4, 130);
+INSERT INTO k_decoration_level VALUES (7, 3, 6, 180);
+INSERT INTO k_decoration_level VALUES (7, 4, 8, 230);
+INSERT INTO k_decoration_level VALUES (7, 5, 10, 280);
+INSERT INTO k_decoration_level VALUES (7, 6, 12, 330);
+INSERT INTO k_decoration_level VALUES (7, 7, 14, 380);
+INSERT INTO k_decoration_level VALUES (7, 8, 16, 430);
+INSERT INTO k_decoration_level VALUES (7, 9, 18, 480);
+INSERT INTO k_decoration_level VALUES (7, 10, 20, 530);
+INSERT INTO k_decoration_level VALUES (34, 1, 1, 80);
+INSERT INTO k_decoration_level VALUES (34, 2, 2, 130);
+INSERT INTO k_decoration_level VALUES (34, 3, 3, 180);
+INSERT INTO k_decoration_level VALUES (34, 4, 4, 230);
+INSERT INTO k_decoration_level VALUES (34, 5, 5, 280);
+INSERT INTO k_decoration_level VALUES (34, 6, 6, 330);
+INSERT INTO k_decoration_level VALUES (34, 7, 7, 380);
+INSERT INTO k_decoration_level VALUES (34, 8, 8, 430);
+INSERT INTO k_decoration_level VALUES (34, 9, 9, 480);
+INSERT INTO k_decoration_level VALUES (34, 10, 10, 530);
+INSERT INTO k_decoration_level VALUES (11, 1, 3, 50);
+INSERT INTO k_decoration_level VALUES (11, 2, 6, 100);
+INSERT INTO k_decoration_level VALUES (11, 3, 9, 150);
+INSERT INTO k_decoration_level VALUES (11, 4, 12, 200);
+INSERT INTO k_decoration_level VALUES (11, 5, 15, 250);
+INSERT INTO k_decoration_level VALUES (11, 6, 18, 300);
+INSERT INTO k_decoration_level VALUES (11, 7, 21, 350);
+INSERT INTO k_decoration_level VALUES (11, 8, 24, 400);
+INSERT INTO k_decoration_level VALUES (11, 9, 27, 450);
+INSERT INTO k_decoration_level VALUES (11, 10, 30, 500);
+INSERT INTO k_decoration_level VALUES (5, 1, 5, 40);
+INSERT INTO k_decoration_level VALUES (5, 2, 10, 90);
+INSERT INTO k_decoration_level VALUES (5, 3, 15, 140);
+INSERT INTO k_decoration_level VALUES (5, 4, 20, 190);
+INSERT INTO k_decoration_level VALUES (5, 5, 25, 240);
+INSERT INTO k_decoration_level VALUES (5, 6, 30, 290);
+INSERT INTO k_decoration_level VALUES (5, 7, 35, 340);
+INSERT INTO k_decoration_level VALUES (5, 8, 40, 390);
+INSERT INTO k_decoration_level VALUES (5, 9, 45, 440);
+INSERT INTO k_decoration_level VALUES (5, 10, 50, 490);
+INSERT INTO k_decoration_level VALUES (10, 1, 1, 30);
+INSERT INTO k_decoration_level VALUES (10, 2, 2, 80);
+INSERT INTO k_decoration_level VALUES (10, 3, 3, 140);
+INSERT INTO k_decoration_level VALUES (10, 4, 4, 200);
+INSERT INTO k_decoration_level VALUES (10, 5, 5, 260);
+INSERT INTO k_decoration_level VALUES (10, 6, 6, 320);
+INSERT INTO k_decoration_level VALUES (10, 7, 7, 380);
+INSERT INTO k_decoration_level VALUES (10, 8, 8, 440);
+INSERT INTO k_decoration_level VALUES (10, 9, 9, 500);
+INSERT INTO k_decoration_level VALUES (10, 10, 10, 560);
+INSERT INTO k_decoration_level VALUES (35, 1, 200, 30);
+INSERT INTO k_decoration_level VALUES (35, 2, 400, 80);
+INSERT INTO k_decoration_level VALUES (35, 3, 600, 130);
+INSERT INTO k_decoration_level VALUES (35, 4, 800, 180);
+INSERT INTO k_decoration_level VALUES (35, 5, 1000, 230);
+INSERT INTO k_decoration_level VALUES (35, 6, 1200, 280);
+INSERT INTO k_decoration_level VALUES (35, 7, 1400, 330);
+INSERT INTO k_decoration_level VALUES (35, 8, 1600, 380);
+INSERT INTO k_decoration_level VALUES (35, 9, 1800, 430);
+INSERT INTO k_decoration_level VALUES (35, 10, 2000, 480);
+
+
 INSERT INTO k_building VALUES(1, 'Summoners Tower', '');
 INSERT INTO k_building VALUES(2, 'Summonhenge', '');
 INSERT INTO k_building VALUES(3, 'Pond of Mana', '');

+ 96 - 0
install_base.py

@@ -388,6 +388,102 @@ def createDatabase(name):
                 value INT
             );
         ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run(
+                uid TEXT,
+                id INT,
+                dtime TIMESTAMP,
+                area INT,
+                stage INT,
+                difficulty INT,
+                win INT,
+                value INT,
+                time INT,
+                mana INT,
+                energy INT,
+                crystal INT,
+
+                sd INT,
+                unit_pieces INT,
+                unit_pieces_id INT,
+                unit_pieces_quantity INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_party(
+                run INT,
+                unit INT,
+                k_unit INT,
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_rune(
+                run INT,
+                id INT,
+                type TEXT,
+                slot INT,
+                stars INT,
+                ancient INT,
+                quality INT,
+                value INT,
+                efficiency INT,
+                main_stat TEXT,
+                main_stat_value INT,
+                innate_stat TEXT,
+                innate_stat_value INT,
+                substat_1 TEXT,
+                substat_1_value INT,
+                substat_2 TEXT,
+                substat_2_value INT,
+                substat_3 TEXT,
+                substat_3_value INT,
+                substat_4 TEXT,
+                substat_4_value INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_rune_craft(
+                run INT,
+                id INT,
+                type INT,
+                quality INT,
+                rune INT,
+                stat INT,
+                value INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_item(
+                run INT,
+                item INT,
+                quantity INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_unit(
+                run INT,
+                unit INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_sd(
+                run INT,
+                unit INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_unit_pieces(
+                run INT,
+                unit INT,
+                quantity INT
+            );
+        ''')
+        cursor.execute('''
+            CREATE TABLE IF NOT EXISTS run_drop_shapeshifting(
+                run INT,
+                quantity INT
+            );
+        ''')
         db.commit()
         cursor.close()
         return db

+ 653 - 0
swex-plugin/swdb.js

@@ -0,0 +1,653 @@
+//const fs = require('fs-extra');
+//const csv = require('fast-csv');
+const dateFormat = require('dateformat');
+//const path = require('path');
+//const sanitize = require('sanitize-filename');
+
+module.exports = {
+    defaultConfig: {
+        enabled: true,
+        debug: true
+    },
+    pluginName: 'SWDB',
+    pluginDescription: 'Saves runs to SWDB.',
+    target_host: 'localhost',
+    target_port: '80',
+    target_url: 'upload/run',
+    temp: {},
+    proxy: null,
+    config: null,
+
+    /**
+     * Initializes he plugin.
+     * 
+     * @param proxy The proxy.
+     * @param Global configurations.
+     */
+    init(proxy, config) {
+        this.proxy = proxy;
+        this.config = config;
+        proxy.on('apiCommand', (req, resp) => {
+            try {
+                if (config.Config.Plugins[this.pluginName].enabled) {
+                    const { command, wizard_id: wizardID } = req;
+
+                if (!this.temp[wizardID]) {
+                    this.temp[wizardID] = {};
+                }
+
+                if (command === 'BattleScenarioStart') {
+                    proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUN START: ${resp}` })
+                    for (var key in req) {
+                        proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV REQ: ${key}: ${req[key]}` })
+                    }
+                    this.temp[wizardID].area = req.region_id;
+                    this.temp[wizardID].stage = req.stage_no;
+                    this.temp[wizardID].difficulty = req.difficulty;
+                }
+
+                if (command === 'BattleScenarioResult' || command === 'BattleDungeonResult' || command === 'BattleDimensionHoleDungeonResult') {
+                    proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUN RESULT: ${resp}` })
+                    //for (var key in req) {
+                    //    this.log("info", `IVV REQ: ${key}: ${req[key]}`);
+                    //}
+                    //for (var key in resp) {
+                    //    this.log("info", `IVV RES: ${key}: ${resp[key]}`);
+                    //}
+                    this.parse(req, resp);
+                }
+
+                if (command === 'BattleRiftOfWorldsRaidResult') {
+                    this.parse_raid_rift(req, resp);
+                }
+
+                if (command === 'BattleRiftDungeonResult') {
+                    this.parse_elemental_rift(req, resp);
+                }
+            }
+            catch (e) {
+                proxy.log({ type: 'error', source: 'plugin', name: this.pluginName, message: `An unexpected error occured: ${e.message}` });
+            }
+        });
+    },
+
+    /**
+     * Parses a reward item (no runes!).
+     * 
+     * @param crate The crate object.
+     * @return array of {item, unit, pieces, quantity, shapeshifting}
+     */
+    getItem(crate) {
+        item = 0;
+        unit = 0;
+        pieces = 0;
+        quantity = 0;
+        shapeshifting = 0;
+        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)){
+            // 1: Unknown scroll
+            // 2: Mystical Scroll
+            // 8: Summoning Stones
+            item = crate.random_scroll.item_master_id;
+            quantity = crate.random_scroll.item_quantity;
+        }
+        if (crate.costume_point) {
+            shapeshifting = crate.costume_point;
+        }
+        if (crate.rune_upgrade_stone) {
+            item = 'Power Stone'; // TODO: Do they exist?
+            quantity = crate.rune_upgrade_stone.item_quantity;
+        }
+        if (crate.unit_info) {
+            unit = crate.unit_info.unit_master_id;
+        }
+        if (crate.material) {
+            item = crate.material.item_master_id;
+            quantity = crate.material.item_quantity;
+        }
+        if (crate.summon_pieces) {
+            pieces = crate.summon_pieces.item_master_id;
+            quantity = crate.summon_pieces.item_quantity;
+        }
+        if (crate.craft_stuff) {
+            item = crate.craft_stuff.item_master_id;
+            quantity = crate.craft_stuff.item_quantity;
+        }
+        //this.log('debug', `Item: ${item}, ${unit}, ${pieces}, ${quantity}, ${shapeshifting}`);
+        drop = {item, unit, pieces, quantity, shapeshifting}
+        return drop;
+    },
+
+    /**
+     * TODO! Unaddapted.
+     * Parses a rift reward item (no runes!).
+     * 
+     * @param crate The crate object.
+     * @return array of {item, unit, pieces, quantity}
+     */
+    getItemRift(item, entry) {
+        if (item.type === 8) {
+            const rune = item.info;
+            entry.drop = 'Rune';
+            entry.grade = `${rune.class}*`;
+            entry.sell_value = rune.sell_value;
+            entry.set = gMapping.rune.sets[rune.set_id];
+            entry.slot = rune.slot_no;
+            entry.efficiency = gMapping.getRuneEfficiency(rune).current;
+            entry.rarity = gMapping.rune.class[rune.sec_eff.length];
+            entry.main_stat = gMapping.getRuneEffect(rune.pri_eff);
+            entry.prefix_stat = gMapping.getRuneEffect(rune.prefix_eff);
+
+            rune.sec_eff.forEach((substat, i) => {
+                entry[`sub${i + 1}`] = gMapping.getRuneEffect(substat);
+            });
+        }
+        if (item.info.craft_type_id) {
+            enhancement = this.getEnchantVals(item.info.craft_type_id, item.info.craft_type);
+            entry.drop = enhancement.drop;
+            entry.sell_value = item.sell_value;
+            entry.set = enhancement.set;
+            entry.main_stat = enhancement.type;
+            entry.sub1 = enhancement.min;
+            entry.sub2 = enhancement.max;
+        }
+        return entry;
+    },
+
+    /**
+     * TODO! Will I need this.
+     * Saves run data to a file in CSV format.
+     * 
+     */
+    saveToFile(entry, filename, headers, proxy) {
+        const csvData = [];
+        const self = this;
+        fs.ensureFile(path.join(config.Config.App.filesPath, filename), err => {
+        if (err) {
+            return;
+        }
+        csv
+            .fromPath(path.join(config.Config.App.filesPath, filename), { ignoreEmpty: true, headers, renameHeaders: true })
+            .on('data', data => {
+            csvData.push(data);
+            })
+            .on('end', () => {
+            csvData.push(entry);
+            csv.writeToPath(path.join(config.Config.App.filesPath, filename), csvData, { headers }).on('finish', () => {
+                proxy.log({ type: 'success', source: 'plugin', name: self.pluginName, message: `Saved run data to ${filename}` });
+            });
+            });
+        });
+    },
+
+    /**
+     * Parses a battle data.
+     * Valid for scenario, dungeons and Dimensional Hole.
+     *
+     * @param req The request
+     * @param resp The response.
+     */
+    parse_normal(req, resp) {
+        const { command } = req;
+        const { wizard_id: wizardID, wizard_name: wizardName } = resp.wizard_info;
+
+        const run = {};
+        const run_party = {};
+        const run_k_party = {};
+        log = true;
+
+        run.uid = wizardID;
+
+        if (command === 'BattleDungeonResult') {
+            if (eq.dungeon_id > 10000){
+                // Hall of Heroes or unknown
+                log = false;
+            }
+            run.area = req.dungeon_id;
+            run.stage = req.stage_id;
+            run.difficulty = 0
+        }
+
+        if (command === 'BattleScenarioResult') {
+            for (var key in this.temp[wizardID]) {
+                this.log("debug", `IVV TEMP: ${key}: ${this.temp[wizardID][key]}`);
+            }
+            run.area = this.temp[wizardID].area;
+            run.stage = this.temp[wizardID].stage;
+            run.difficulty = this.temp[wizardID].difficulty;
+        }
+
+        if (command === 'BattleDimensionHoleDungeonResult') {
+            //if (gMapping.dungeon[resp.dungeon_id]) {
+            //    run.dungeon = `${gMapping.dungeon[resp.dungeon_id]} Level ${resp.difficulty}`;
+            //}
+            run.area = req.dungeon_id;
+            run.stage = req.stage_id;
+            run.difficulty = 0
+        }
+
+        run.win = resp.win_lose; // 1/0 2 is lost in scenario
+
+        run.dtime = dateFormat(new Date(), 'yyyy-mm-dd HH:MM:SS');
+
+        const reward = resp.reward ? resp.reward : {};
+        run.time = req.clear_time ? req.clear_time : 0;
+
+        run.mana = reward.mana ? reward.mana : 0;
+        run.energy = reward.energy ? reward.energy : 0;
+        run.crystal = reward.crystal ? reward.crystal : 0;
+
+        run.rune = {};
+        run.unit = 0;
+        run.unit_pieces = {};
+        run.sd = 0;
+        run.item = {};
+        run.shapeshifting = 0;
+
+        if (reward.crate) {
+            run.mana = reward.crate.mana ? run.mana + reward.crate.mana : run.mana;
+            run.energy = reward.crate.energy ? run.energy + reward.crate.energy : run.energy;
+            run.crystal = reward.crate.crystal ? run.crystal + reward.crate.crystal : run.crystal;
+
+            if (reward.crate.rune) {
+                const rune = reward.crate.rune;
+                for (var key in rune) {
+                    this.proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUNE: ${key}: ${rune[key]}` })
+                }
+                run.rune.id = rune.rune_id;
+                run.rune.grade = rune.class;
+                run.rune.value = rune.sell_value;
+                run.rune.set = rune.set_id;
+                run.rune.slot = rune.slot_no;
+                run.rune.efficiency = gMapping.getRuneEfficiency(rune).current;
+                run.rune.quality = rune.rank;
+                // TODO: Maybe i need to do substrings to get stat and value
+                run.rune.main = rune.pri_eff[0];
+                run.rune.main_value = rune.pri_eff[1];
+                if (rune.prefix_eff){
+                    run.rune.innate = rune.prefix_eff[0];
+                    run.rune.innate_value = rune.prefix_eff[1];
+                }
+                rune.sec_eff.forEach((substat, i) => {
+                    run.rune[`substat_${i + 1}`] = substat[0];
+                    run.rune[`substat_${i + 1}_value`] = substat[1];
+                });
+            }
+            else {
+                drop = this.getItem(reward.crate);
+                if (drop.unit){
+                    run.unit.id = drop.unit;
+                }
+                if (drop.pieces){
+                    run.unit_pieces.id = drop.pieces;
+                    run.unit_pieces.quantity = drop.quantity;
+                }
+                if (drop.item){
+                    run.item.id = drop.item;
+                    run.item.quantity = drop.quantity;
+                }
+                run.shapeshifting = drop.shapeshifting;
+            }
+        }
+        if (resp.instance_info) {
+            run.sd = resp.instance_info;
+        }
+
+        if (resp.unit_list && resp.unit_list.length > 0) {
+            resp.unit_list.forEach((unit, i) => {
+                run_party[i] = unit.unit_master_id;
+                run_k_party[i] = unit.unit_id;
+            });
+        }
+
+        json_rune = '[';
+        if (run.rune.length() > 0){
+            json_rune += `"id": "${run.rune.id}", `;
+            json_rune += `"grade": "${run.rune.grade}", `;
+            json_rune += `"set": "${run.rune.set}", `;
+            json_rune += `"slot": "${run.rune.slot}", `;
+            json_rune += `"efficiency": "${run.rune.efficiency}", `;
+            json_rune += `"quality": "${run.rune.quality}", `;
+            json_rune += `"value": "${run.rune.value}", `;
+            json_rune += `"main_stat": "${run.rune.main}", `;
+            json_rune += `"main_stat_value": "${run.rune.main_value}", `;
+            json_rune += `"innate_stat": "${run.rune.innate}", `;
+            json_rune += `"innate_stat_value": "${run.rune.innate_value}", `;
+            json_rune += `"substat_1": "${run.rune.substat_1}", `;
+            json_rune += `"substat_1_value": "${run.rune.substat_1_value}", `;
+            json_rune += `"substat_2": "${run.rune.substat_2}", `;
+            json_rune += `"substat_2_value": "${run.rune.substat_2_value}", `;
+            json_rune += `"substat_3": "${run.rune.substat_3}", `;
+            json_rune += `"substat_4_value": "${run.rune.substat_3_value}", `;
+            json_rune += `"substat_4": "${run.rune.substat_4}", `;
+            json_rune += `"substat_4_value": "${run.rune.substat_4_value}", `;
+        }
+        json_rune = json_party.slice(0, -1) + "]";
+
+        json_item = '[';
+        if (run.item.length() > 0){
+            json_item += `"id": "${run.item.id}", `;
+            json_item += `"quantity": "${run.item.quantity}", `;
+        }
+        json_item = json_party.slice(0, -1) + "]";
+
+        json_unit_pieces = '[';
+        if (run.unit_pieces.length() > 0){
+            json_unit_pieces += `"id": "${run.unit_pieces.id}", `;
+            json_unit_pieces += `"quantity": "${run.unit_pieces.quantity}", `;
+        }
+        json_unit_pieces = json_party.slice(0, -1) + "]";
+
+        json_party = '[';
+        resp.unit_list.forEach((unit, i) => {
+            json_party = json_party + '{"unit_id": ' + run_party[i] + ', "unit_master_id": ' + run_k_party[i] + '},';
+        });
+        json_party = json_party.slice(0, -1) + "]";
+
+        //this.log('debug', `IVV json_party: ${json_party}`)
+
+        json = `{`;
+        json += `"dtime": "${run.dtime}", `;
+        json += `"area": "${run.dungeon}", `;
+        json += `"stage": "${run.stage}", `;
+        json += `"difficulty": "${run.difficulty}", `;
+        json += `"win": "${run.win}", `;
+        json += `"time": "${run.time}", `;
+        json += `"mana": "${run.mana}", `;
+        json += `"energy": "${run.energy}", `;
+        json += `"crystal": "${run.crystal}", `;
+        json += `"rune": ${json_rune}, `;
+        json += `"sd": ${run.sd}, `;
+        json += `"item": ${json_item}, `;
+        json += `"unit": ${run.unit}, `;
+        json += `"unit_pieces": ${json_unit_pieces}, `;
+        json += `"sapeshifting": ${run.sapeshifting}, `;
+        json += `"party": ${json_party}`;
+        json += `}`;
+        this.log('DEBUG', `json: ${json}` })
+        //const filename = sanitize(`${wizardName}-${wizardID}-runs.csv`);
+        //const filename = sanitize(`IVV-${wizardName}-${wizardID}-runs.csv`);
+        //this.saveToFile(entry, filename, headers, proxy);
+    },
+
+    /**
+     * TODO Unaddapted.
+     * Parses a battle data.
+     * Valid for Rift Raids.
+     *
+     * @param req The request
+     * @param resp The response.
+     */
+    parse_raid_rift(req, resp) {
+        const { wizard_id: wizardID, wizard_name: wizardName } = resp.wizard_info;
+
+        let run = {};
+        if (gMapping.dungeon[req.dungeon_id]) {
+            run.dungeon = `${gMapping.elemental_rift_dungeon[req.dungeon_id]}`;
+            isElemental = true;
+        }
+
+        //const winLost = resp.win_lose === 1 ? 'Win' : 'Did not kill';
+
+        run.dtime = dateFormat(new Date(), 'yyyy-mm-dd HH:MM:SS');
+        //run.result = winLost;
+
+        run.win  = resp.win_lose;
+        run.rune = {};
+        run.unit = 0;
+        run.unit_pieces = {};
+        run.sd = 0;
+        run.item = {};
+        run.shapeshifting = 0;
+        run.time = req.clear_time ? req.clear_time : 0;
+
+        const reward = resp.reward ? resp.reward : {};
+
+        if (resp.win_lose === 1) {
+            // No crate: Mana of shapeshifting stones
+            if (!reward.crate) {
+                const reward = resp.battle_reward_list.find(value => value.wizard_id === resp.wizard_info.wizard_id).reward_list[0];
+                if (reward.item_master_id === 6) {
+                    run.shapeshifting = reward.item_quantity;
+                }
+                else {
+                    run.mana = reward.item_quantity;
+                }
+            }
+            // Rune craft item
+            else if (reward.crate.changestones) {
+                const item = {
+                    info: {
+                        craft_type: reward.crate.changestones[0].craft_type,
+                        craft_type_id: reward.crate.changestones[0].craft_type_id
+                    },
+                    sell_value: reward.crate.changestones[0].sell_value
+                };
+                run.drop= this.getItemRift(item, run.;
+            }
+            // Rune
+            else if (reward.crate.rune) {
+                const rune = reward.crate.rune;
+                //for (var key in rune) {
+                //    this.proxy.log({ type: 'info', source: 'plugin', name: this.pluginName, message: `IVV RUNE: ${key}: ${rune[key]}` })
+                //}
+                run.rune.id = rune.rune_id;
+                run.rune.grade = rune.class;
+                run.rune.value = rune.sell_value;
+                run.rune.set = rune.set_id;
+                run.rune.slot = rune.slot_no;
+                run.rune.efficiency = gMapping.getRuneEfficiency(rune).current;
+                run.rune.quality = rune.rank;
+                run.rune.main = rune.pri_eff[0];
+                run.rune.main_value = rune.pri_eff[1];
+                if (rune.prefix_eff){
+                    run.rune.innate = rune.prefix_eff[0];
+                    run.rune.innate_value = rune.prefix_eff[1];
+                }
+                rune.sec_eff.forEach((substat, i) => {
+                    run.rune[`substat_${i + 1}`] = substat[0];
+                    run.rune[`substat_${i + 1}_value`] = substat[1];
+                });
+            }
+            // Unit (Rainbowmon)
+            else if (reward.crate.unit_info && reward.crate.unit_info.unit_master_id > 0) {
+                run.unit.id = reward.crate.unit_info.unit_master_id;
+            }
+            // Item
+            else if (!run.drop && resp.reward.crate) {
+                //run.drop = this.getItem(reward.resp.reward.crate);
+                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)){
+                    // 1: Unknown scroll
+                    // 2: Mystical Scroll
+                    // 8: Summoning Stones
+                    run.item.id = resp.reward.crate.random_scroll.item_master_id;
+                    run.item.quantity = resp.reward.crate.random_scroll.item_quantity;
+                }
+                //if (resp.reward.crate.costume_point) {
+                //    shapeshifting = resp.reward.crate.costume_point;
+                //}
+                //if (resp.reward.crate.rune_upgrade_stone) {
+                //    item = 'Power Stone'; // TODO: Do they exist?
+                //    quantity = resp.reward.crate.rune_upgrade_stone.item_quantity;
+                //}
+                //if (resp.reward.crate.unit_info) {
+                //    unit = resp.reward.crate.unit_info.unit_master_id;
+                //}
+                if (resp.reward.crate.material) {
+                    item = resp.reward.crate.material.item_master_id;
+                    quantity = resp.reward.crate.material.item_quantity;
+                //}
+                //if (resp.reward.crate.summon_pieces) {
+                //    pieces = resp.reward.crate.summon_pieces.item_master_id;
+                //    quantity = resp.reward.crate.summon_pieces.item_quantity;
+                //}
+                if (resp.reward.crate.craft_stuff) {
+                    item = resp.reward.crate.craft_stuff.item_master_id;
+                    quantity = resp.reward.crate.craft_stuff.item_quantity;
+                }
+            }
+            else {
+                run.drop = 'unknown';
+            }
+        }
+
+        if (resp.unit_list && resp.unit_list.length > 0) {
+            resp.unit_list.forEach((unit, i) => {
+                run_party[i] = unit.unit_master_id;
+                run_k_party[i] = unit.unit_id;
+            });
+        }
+
+
+        //const filename = sanitize(`${wizardName}-${wizardID}-raid-runs.csv`);
+        //this.saveToFile(run. filename, headers, proxy);
+    },
+
+    /**
+     * TODO Unaddapted.
+     * Parses a battle data.
+     * Valid for Rift Dungeons.
+     *
+     * @param req The request
+     * @param resp The response.
+     */
+    parse_elemental_rift(req, resp) {
+        const { wizard_id: wizardID, wizard_name: wizardName } = resp.wizard_info;
+
+        let entry = {};
+        if (gMapping.dungeon[req.dungeon_id]) {
+            entry.dungeon = `${gMapping.elemental_rift_dungeon[req.dungeon_id]}`;
+            isElemental = true;
+        }
+
+        const winLost = req.battle_result === 1 ? 'Win' : 'Did not kill';
+
+        entry.date = dateFormat(new Date(), 'yyyy-mm-dd HH:MM');
+        entry.result = winLost;
+
+        if (resp.item_list && resp.item_list.length > 0) {
+            resp.item_list.forEach((item, i) => {
+                if (item.is_boxing !== 1 || item.id === 2001) {
+                entry[`item${i + 1}`] = `${gMapping.craftMaterial[item.id]} x${item.quantity}`;
+                } else {
+                if (item.id === 2) {
+                    entry.drop = 'Mystical Scroll';
+                }
+                if (item.id === 8) {
+                    entry.drop = `Summoning Stones x${item.item_quantity}`;
+                }
+                if (item.info && item.info.unit_master_id > 0) {
+                    entry.drop = `${gMapping.getMonsterName(item.info.unit_master_id)} ${item.class}`;
+                }
+                if ((item.info && item.info.craft_type_id) || item.type === 8) {
+                    entry = this.getItemRift(item, entry);
+                }
+                }
+            });
+        }
+
+        if (resp.unit_list && resp.unit_list.length > 0) {
+            resp.unit_list.forEach((unit, i) => {
+                entry[`team${i + 1}`] = gMapping.getMonsterName(unit.unit_master_id);
+            });
+        }
+        json_rune = '[';
+        if (run.rune.length() > 0){
+            json_rune += `"id": "${run.rune.id}", `;
+            json_rune += `"grade": "${run.rune.grade}", `;
+            json_rune += `"set": "${run.rune.set}", `;
+            json_rune += `"slot": "${run.rune.slot}", `;
+            json_rune += `"efficiency": "${run.rune.efficiency}", `;
+            json_rune += `"quality": "${run.rune.quality}", `;
+            json_rune += `"value": "${run.rune.value}", `;
+            json_rune += `"main_stat": "${run.rune.main}", `;
+            json_rune += `"main_stat_value": "${run.rune.main_value}", `;
+            json_rune += `"innate_stat": "${run.rune.innate}", `;
+            json_rune += `"innate_stat_value": "${run.rune.innate_value}", `;
+            json_rune += `"substat_1": "${run.rune.substat_1}", `;
+            json_rune += `"substat_1_value": "${run.rune.substat_1_value}", `;
+            json_rune += `"substat_2": "${run.rune.substat_2}", `;
+            json_rune += `"substat_2_value": "${run.rune.substat_2_value}", `;
+            json_rune += `"substat_3": "${run.rune.substat_3}", `;
+            json_rune += `"substat_4_value": "${run.rune.substat_3_value}", `;
+            json_rune += `"substat_4": "${run.rune.substat_4}", `;
+            json_rune += `"substat_4_value": "${run.rune.substat_4_value}", `;
+        }
+        json_rune = json_party.slice(0, -1) + "]";
+
+        json_item = '[';
+        if (run.item.length() > 0){
+            json_item += `"id": "${run.item.id}", `;
+            json_item += `"quantity": "${run.item.quantity}", `;
+        }
+        json_item = json_party.slice(0, -1) + "]";
+
+        json_unit_pieces = '[';
+        if (run.unit_pieces.length() > 0){
+            json_unit_pieces += `"id": "${run.unit_pieces.id}", `;
+            json_unit_pieces += `"quantity": "${run.unit_pieces.quantity}", `;
+        }
+        json_unit_pieces = json_party.slice(0, -1) + "]";
+
+        json_party = '[';
+        resp.unit_list.forEach((unit, i) => {
+            json_party = json_party + '{"unit_id": ' + run_party[i] + ', "unit_master_id": ' + run_k_party[i] + '},';
+        });
+        json_party = json_party.slice(0, -1) + "]";
+
+        //this.log('debug', `IVV json_party: ${json_party}`)
+
+        json = `{`;
+        json += `"dtime": "${run.dtime}", `;
+        json += `"area": "${run.dungeon}", `;
+        json += `"stage": "${run.stage}", `;
+        json += `"difficulty": "${run.difficulty}", `;
+        json += `"win": "${run.win}", `;
+        json += `"time": "${run.time}", `;
+        json += `"mana": "${run.mana}", `;
+        json += `"energy": "${run.energy}", `;
+        json += `"crystal": "${run.crystal}", `;
+        json += `"rune": ${json_rune}, `;
+        json += `"sd": ${run.sd}, `;
+        json += `"item": ${json_item}, `;
+        json += `"unit": ${run.unit}, `;
+        json += `"unit_pieces": ${json_unit_pieces}, `;
+        json += `"sapeshifting": ${run.sapeshifting}, `;
+        json += `"party": ${json_party}`;
+        json += `}`;
+        this.log('DEBUG', `json: ${json}` })
+    },
+
+    /**
+     * TODO ???
+     */
+    getEnchantVals(craftID, craftType) {
+        const map = {};
+        const typeNumber = Number(craftID.toString().slice(-4, -2));
+        map.set = gMapping.rune.sets[Number(craftID.toString().slice(0, -4))];
+        map.grade = gMapping.rune.quality[Number(craftID.toString().slice(-1))];
+        map.type = gMapping.rune.effectTypes[typeNumber];
+
+        if (craftType === 2) {
+            map.min = gMapping.grindstone[typeNumber].range[Number(craftID.toString().slice(-1))].min;
+            map.max = gMapping.grindstone[typeNumber].range[Number(craftID.toString().slice(-1))].max;
+            map.drop = 'Grindstone';
+        } else {
+            map.min = gMapping.enchanted_gem[typeNumber].range[Number(craftID.toString().slice(-1))].min;
+            map.max = gMapping.enchanted_gem[typeNumber].range[Number(craftID.toString().slice(-1))].max;
+            map.drop = 'Enchanted Gem';
+        }
+        return map;
+    }
+
+    /**
+     * Prints a messageto the SWEX output.
+     * 
+     * @param type Log type. Debug type will be printed depending on config.
+     * @param msg The message to log.
+     */
+    log(type, msg){
+        if (type != "debug" || this.config.Config.Plugins[this.pluginName].debug == true){
+            proxy.log({ type: type, source: 'plugin', name: this.pluginName, message: msg });
+        }
+    }
+};